void E2ServerInterface::updateAppointment() { if(m_model->rowCount() == 0) { occurrenceText = "No meetings today"; } else { QAppointment appointment; bool found = false; int secs = 0; for(int ii = 0; !found && ii < m_model->rowCount(); ++ii) { appointment = m_model->appointment(ii); occurrenceText = appointment.description(); QOccurrence occurrence = appointment.nextOccurrence(QDate::currentDate()); secs = QDateTime::currentDateTime().secsTo(occurrence.start()); if(secs >= 0) { found = true; } } if(!found) { occurrenceText = "No meetings today"; } } update(); }
void QAppointmentIO::addAlarm(const QAppointment &appointment) { #ifdef Q_WS_QWS // TODO Needs to be able to set up the return to be a service. QDateTime when = nextAlarm(appointment); if (!when.isNull()) Qtopia::addAlarm(when, "Calendar", "alarm(QDateTime,int)", appointment.alarmDelay()); #else Q_UNUSED( appointment ); #endif }
QDateTime QAppointmentIO::nextAlarm( const QAppointment &appointment) { QDateTime now = QDateTime::currentDateTime(); // -1 days to make room for timezone shift. QOccurrence o = appointment.nextOccurrence(now.date().addDays(-1)); while (o.isValid()) { if (now <= o.alarmInCurrentTZ()) return o.alarmInCurrentTZ(); o = o.nextOccurrence(); } return QDateTime(); }
bool AlarmView::updateAlarms() { bool playSound = false; QIcon aicon(":icon/audible"); QIcon sicon(":icon/silent"); mStandardModel->clear(); mAlarmCount = 0; QString localDT; QString tzDT; // Filter out occurrences that do not have an alarm for (int i=0; i < mModel->rowCount(); i++) { QOccurrence o = mModel->occurrence(i); QAppointment a = o.appointment(); if (a.hasAlarm() && (o.startInCurrentTZ() == mStartTime) && (o.alarmDelay() == mDelay)) { if (!playSound && (a.alarm() == QAppointment::Audible)) { playSound = true; } QStandardItem* item = new QStandardItem(); if (a.alarm() == QAppointment::Audible) item->setData(aicon, Qt::DecorationRole); else item->setData(sicon, Qt::DecorationRole); if (!a.description().isEmpty()) item->setData(a.description(), Qt::DisplayRole); else item->setData(tr("No description", "no description for appointment"), Qt::DisplayRole); QList< StringPair > subList; if (!a.location().isEmpty()) { subList.append(qMakePair(QString(), a.location())); } formatDateTime(o, true, localDT, tzDT); if (a.isAllDay()) { subList.append(qMakePair(tr("All day: "), localDT)); } else { subList.append(qMakePair(tr("Starts: "), localDT)); if (!tzDT.isEmpty()) subList.append(qMakePair(QString(""), tzDT)); formatDateTime(o, false, localDT, tzDT); subList.append(qMakePair(tr("Ends: "), localDT)); if (!tzDT.isEmpty()) subList.append(qMakePair(QString(""), tzDT)); } item->setData(QVariant::fromValue(subList), TwoLevelDelegate::SubLabelsRole); item->setData(i, TwoLevelDelegate::TwoLevelDelegateUserRole); mStandardModel->appendRow(item); } } int rowCount = mStandardModel->rowCount(); // Select the first item mAlarmList->setCurrentIndex(mStandardModel->index(0,0)); // XXX i18n boneheadedness. if (rowCount < 2) { setWindowTitle(tr("Reminder")); } else { setWindowTitle(tr("Reminders")); } mSnoozeButton->setFocus(); // If we actually got any matching alarms... if (rowCount > 0) { if (playSound) { Qtopia::soundAlarm(); mAlarmTimer.start(5000,this); } return true; } else { emit closeView(); return false; } }
bool GoogleCalHandler::startElement( const QString & namespaceURI, const QString & localName, const QString & qName, const QXmlAttributes & atts ) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); // if we are in a tree we dont' recognize, ignore the lot of it. if (ignoreDepth) { ignoreDepth++; return true; } Element t = token(qName); switch(t) { case Entry: state = EntryState; break; case Feed: state = FeedState; break; case Category: if (atts.value("scheme").endsWith("#kind") && atts.value("term").endsWith("#event")) state = EventState; // TODO other kinds of categories? break; case Status: // this is how deleted events are detected if (atts.value("value").endsWith("#event.canceled")) { removeCurrentAppointment = true; } break; case Reminder: if (!atts.value("minutes").isEmpty()) { lastAppointment.setAlarm(atts.value("minutes").toInt(), QAppointment::Visible); } else if (!atts.value("hours").isEmpty()) { lastAppointment.setAlarm(atts.value("minutes").toInt()*60, QAppointment::Visible); } // TODO doesn't handle days or absolute time. break; case When: { QString st = atts.value("startTime"); QString et = atts.value("endTime"); if (st.isEmpty() || et.isEmpty()) { ignoreDepth++; } else { QTimeZone tz = parseTimeZone(st); QDateTime start = parseDateTime(st, tz); QDateTime end = parseDateTime(et, tz); if (st.length() < 19) lastAppointment.setAllDay(true); lastAppointment.setTimeZone(tz); lastAppointment.setStart(start); lastAppointment.setEnd(end); } } break; case Where: lastAppointment.setLocation(atts.value("valueString")); break; case Title: case Content: if (atts.value("type") != "text") { ignoreDepth++; } break; case Recurrence: case Id: case Published: case Updated: if (state != EntryState && state != EventState) { ignoreDepth++; break; } break; case Unrecognized: ignoreDepth++; } return true; }
bool GoogleCalHandler::endElement( const QString & namespaceURI, const QString & localName, const QString & qName ) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); if (ignoreDepth) { ignoreDepth--; Q_ASSERT(ignoreDepth >= 0); return true; } Element t = token(qName); switch(t) { case Entry: if (removeCurrentAppointment) { mRemoved.append(lastAppointment.uid()); removeCurrentAppointment = false; } else { mAppointments.append(lastAppointment); } lastAppointment = QAppointment(); state = FeedState; break; case Feed: state = StartState; case Title: if (state == FeedState) mName = lastText; else lastAppointment.setDescription(lastText); break; case Content: lastAppointment.setNotes(lastText); break; case Recurrence: { // this is the MAIN TODO, seeing as once this works, /* iCal format, is not compatible with vcard parsing. however it may be similar enough that we can still use existing vcard parser. NOTE: RRULE format is different in iCal to vCard */ /* Example RRULE text from recurrence section. can be given instead of when e.g. DTSTART;TZID=Australia/Brisbane:20060615T113000 DURATION:PT1800S RRULE:FREQ=WEEKLY;INTERVAL=2;BYDAY=TH BEGIN:VTIMEZONE TZID:Australia/Brisbane X-LIC-LOCATION:Australia/Brisbane BEGIN:STANDARD TZOFFSETFROM:+1000 TZOFFSETTO:+1000 TZNAME:EST DTSTART:19700101T000000 END:STANDARD END:VTIMEZONE */ // pad out data to make it look like a vcal and get through our parser // qappointment also has some special ical handling in it. QByteArray data = "BEGIN:VCALENDAR\r\nVERSION:1.0\r\nBEGIN:VEVENT\r\n" + lastText.toUtf8() + "END:VEVENT\r\nEND:VCALENDAR\r\n"; QList<QAppointment> result = QAppointment::readVCalendarData(data.constData(), data.length()); if (result.count() > 0) { QAppointment a = result[0]; lastAppointment.setStart(a.start()); lastAppointment.setEnd(a.end()); lastAppointment.setRepeatRule(a.repeatRule()); lastAppointment.setFrequency(a.frequency()); lastAppointment.setRepeatUntil(a.repeatUntil()); lastAppointment.setWeekFlags(a.weekFlags()); } } break; case Id: { QUniqueId u = parseId(lastText + mIdContext); lastAppointment.setUid(u); // a lot more redundency in a google id. lastAppointment.setCustomField("GoogleId", lastText); } break; case Published: { // TODO should support published/updated fields natively in PimRecords? QDateTime dt = parseDateTime(lastText, QTimeZone::utc()); lastAppointment.setCustomField("GooglePublished", dt.toString(Qt::ISODate)); } break; case Updated: { QDateTime dt = parseDateTime(lastText, QTimeZone::utc()); lastAppointment.setCustomField("GoogleUpdated", dt.toString(Qt::ISODate)); } break; case Category: case Reminder: case When: case Where: case Status: break; case Unrecognized: break; } return true; }