-rw-r--r-- | libkcal/kincidenceformatter.cpp | 24 | ||||
-rw-r--r-- | libkcal/recurrence.cpp | 2 |
2 files changed, 17 insertions, 9 deletions
diff --git a/libkcal/kincidenceformatter.cpp b/libkcal/kincidenceformatter.cpp index 6d07d4c..0d9c3f4 100644 --- a/libkcal/kincidenceformatter.cpp +++ b/libkcal/kincidenceformatter.cpp @@ -1,338 +1,344 @@ #include "kincidenceformatter.h" #include <kstaticdeleter.h> #include <kglobal.h> #include <klocale.h> #ifdef DEKTOP_VERSION #include <kabc/stdaddressbook.h> #define size count #endif KIncidenceFormatter* KIncidenceFormatter::mInstance = 0; static KStaticDeleter<KIncidenceFormatter> insd; QString KIncidenceFormatter::getFormattedText( Incidence * inc ) { // #ifndef QT_NO_INPUTDIALOG // return QInputDialog::getItem( caption, label, items, current, editable ); // #else // return QString::null; // #endif mText = ""; if ( inc->type() == "Event" ) setEvent((Event *) inc ); else if ( inc->type() == "Todo" ) setTodo((Todo *) inc ); return mText; } KIncidenceFormatter* KIncidenceFormatter::instance() { if (!mInstance) { mInstance = insd.setObject(new KIncidenceFormatter()); } return mInstance; } KIncidenceFormatter::~KIncidenceFormatter() { if (mInstance == this) mInstance = insd.setObject(0); //qDebug("KIncidenceFormatter::~KIncidenceFormatter "); } KIncidenceFormatter::KIncidenceFormatter() { mColorMode = 0; } void KIncidenceFormatter::setEvent(Event *event) { int mode = 0; mCurrentIncidence = event; bool shortDate = true; if ( mode == 0 ) { addTag("h3",event->summary()); } else { if ( mColorMode == 1 ) { mText +="<font color=\"#00A000\">"; } if ( mColorMode == 2 ) { mText +="<font color=\"#C00000\">"; } // mText +="<font color=\"#F00000\">" + i18n("O-due!") + "</font>"; if ( mode == 1 ) { addTag("h2",i18n( "Local: " ) +event->summary()); } else { addTag("h2",i18n( "Remote: " ) +event->summary()); } addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) ); if ( mColorMode ) mText += "</font>"; } if (event->cancelled ()) { mText +="<font color=\"#B00000\">"; addTag("i",i18n("This event has been cancelled!")); mText.append("<br>"); mText += "</font>"; } if (!event->location().isEmpty()) { addTag("b",i18n("Location: ")); mText.append(event->location()+"<br>"); } if (event->doesFloat()) { if (event->isMultiDay()) { mText.append(i18n("<p><b>From:</b> %1 </p><p><b>To:</b> %2</p>") .arg(event->dtStartDateStr(shortDate)) .arg(event->dtEndDateStr(shortDate))); } else { mText.append(i18n("<p><b>On:</b> %1</p>").arg(event->dtStartDateStr( shortDate ))); } } else { if (event->isMultiDay()) { mText.append(i18n("<p><b>From:</b> %1</p> ") .arg(event->dtStartStr( shortDate))); mText.append(i18n("<p><b>To:</b> %1</p>") .arg(event->dtEndStr(shortDate))); } else { mText.append(i18n("<p><b>On:</b> %1</p> ") .arg(event->dtStartDateStr( shortDate ))); mText.append(i18n("<p><b>From:</b> %1 <b>To:</b> %2</p>") .arg(event->dtStartTimeStr()) .arg(event->dtEndTimeStr())); } } if (event->recurrence()->doesRecur()) { QString recurText = event->recurrence()->recurrenceText(); addTag("p","<em>" + i18n("This is a %1 recurring event.").arg(recurText ) + "</em>"); - bool last; + + bool ok; QDate start = QDate::currentDate(); - QDate next; - next = event->recurrence()->getPreviousDate( start , &last ); - if ( !last ) { - next = event->recurrence()->getNextDate( start.addDays( - 1 ) ); - addTag("p",i18n("Next recurrence is on: ")+ KGlobal::locale()->formatDate( next, shortDate ) ); - //addTag("p", KGlobal::locale()->formatDate( next, shortDate )); + QDateTime next; + next = event->getNextOccurence( QDateTime::currentDateTime() , &ok ); + if ( ok ) { + addTag("p",i18n("<b>Next recurrence is on:</b>") ); + addTag("p", KGlobal::locale()->formatDate( next.date(), shortDate )); + } else { - addTag("p",i18n("<b>Last recurrence was on:</b>") ); - addTag("p", KGlobal::locale()->formatDate( next, shortDate )); + bool last; + QDate nextd; + nextd = event->recurrence()->getPreviousDate( QDate::currentDate() , &last ); + if ( last ) { + addTag("p",i18n("<b>Last recurrence was on:</b>") ); + addTag("p", KGlobal::locale()->formatDate( nextd, shortDate )); + } } } if (event->isAlarmEnabled()) { Alarm *alarm =event->alarms().first() ; QDateTime t = alarm->time(); int min = t.secsTo( event->dtStart() )/60; QString s =i18n("(%1 min before)").arg( min ); addTag("p",i18n("<b>Alarm on: </b>") + s + ": "+KGlobal::locale()->formatDateTime( t, shortDate )); //addTag("p", KGlobal::locale()->formatDateTime( t, shortDate )); //addTag("p",s); } addTag("p",i18n("<b>Access: </b>") +event->secrecyStr() ); // mText.append(event->secrecyStr()+"<br>"); formatCategories(event); if (!event->description().isEmpty()) { addTag("p",i18n("<b>Details: </b>")); addTag("p",event->description()); } formatReadOnly(event); formatAttendees(event); } void KIncidenceFormatter::setTodo(Todo *event ) { int mode = 0; mCurrentIncidence = event; bool shortDate = true; if (mode == 0 ) addTag("h3",event->summary()); else { if ( mColorMode == 1 ) { mText +="<font color=\"#00A000\">"; } if ( mColorMode == 2 ) { mText +="<font color=\"#B00000\">"; } if ( mode == 1 ) { addTag("h2",i18n( "Local: " ) +event->summary()); } else { addTag("h2",i18n( "Remote: " ) +event->summary()); } addTag("h3",i18n( "Last modified: " ) + KGlobal::locale()->formatDateTime(event->lastModified(),shortDate, true ) ); if ( mColorMode ) mText += "</font>"; } if ( event->percentComplete() == 100 && event->hasCompletedDate() ) { mText +="<font color=\"#B00000\">"; addTag("i", i18n("<p><i>Completed on %1</i></p>").arg( event->completedStr(shortDate) ) ); mText += "</font>"; } else { mText.append(i18n("<p><i>%1 % completed</i></p>") .arg(event->percentComplete())); } if (event->cancelled ()) { mText +="<font color=\"#B00000\">"; addTag("i",i18n("This todo has been cancelled!")); mText.append("<br>"); mText += "</font>"; } if (!event->location().isEmpty()) { addTag("b",i18n("Location: ")); mText.append(event->location()+"<br>"); } if (event->hasDueDate()) { mText.append(i18n("<p><b>Due on:</b> %1</p>").arg(event->dtDueStr(shortDate))); } mText.append(i18n("<p><b>Priority:</b> %2</p>") .arg(QString::number(event->priority()))); addTag("p",i18n("<b>Access: </b>") +event->secrecyStr() ); formatCategories(event); if (!event->description().isEmpty()) { addTag("p",i18n("<b>Details: </b>")); addTag("p",event->description()); } formatReadOnly(event); formatAttendees(event); } void KIncidenceFormatter::setJournal(Journal* ) { } void KIncidenceFormatter::formatCategories(Incidence *event) { if (!event->categoriesStr().isEmpty()) { addTag("p",i18n("<b>Categories: </b>")+event->categoriesStr() ); //mText.append(event->categoriesStr()); } } void KIncidenceFormatter::addTag(const QString & tag,const QString & text) { int number=text.contains("\n"); QString str = "<" + tag + ">"; QString tmpText=text; QString tmpStr=str; if(number !=-1) { if (number > 0) { int pos=0; QString tmp; for(int i=0;i<=number;i++) { pos=tmpText.find("\n"); tmp=tmpText.left(pos); tmpText=tmpText.right(tmpText.length()-pos-1); tmpStr+=tmp+"<br>"; } } else tmpStr += tmpText; tmpStr+="</" + tag + ">"; mText.append(tmpStr); } else { str += text + "</" + tag + ">"; mText.append(str); } } void KIncidenceFormatter::formatAttendees(Incidence *event) { QPtrList<Attendee> attendees = event->attendees(); if (attendees.count()) { QString iconPath = KGlobal::iconLoader()->iconPath("mailappt",KIcon::Small); QString NOiconPath = KGlobal::iconLoader()->iconPath("nomailappt",KIcon::Small); addTag("h3",i18n("Organizer")); mText.append("<ul><li>"); #if 0 //ndef KORG_NOKABC KABC::AddressBook *add_book = KABC::StdAddressBook::self(); KABC::Addressee::List addressList; addressList = add_book->findByEmail(event->organizer()); KABC::Addressee o = addressList.first(); if (!o.isEmpty() && addressList.size()<2) { mText += "<a href=\"uid:" + o.uid() + "\">"; mText += o.formattedName(); mText += "</a>\n"; } else { mText.append(event->organizer()); } #else mText.append(event->organizer()); #endif if (iconPath) { mText += " <a href=\"mailto:" + event->organizer() + "\">"; mText += "<IMG src=\"" + iconPath + "\">"; mText += "</a>\n"; } mText.append("</li></ul>"); addTag("h3",i18n("Attendees")); Attendee *a; mText.append("<ul>"); for(a=attendees.first();a;a=attendees.next()) { #if 0 //ndef KORG_NOKABC if (a->name().isEmpty()) { addressList = add_book->findByEmail(a->email()); KABC::Addressee o = addressList.first(); if (!o.isEmpty() && addressList.size()<2) { mText += "<a href=\"uid:" + o.uid() + "\">"; mText += o.formattedName(); mText += "</a>\n"; } else { mText += "<li>"; mText.append(a->email()); mText += "\n"; } } else { mText += "<li><a href=\"uid:" + a->uid() + "\">"; if (!a->name().isEmpty()) mText += a->name(); else mText += a->email(); mText += "</a>\n"; } #else //qDebug("nokabc "); mText += "<li><a href=\"uid:" + a->uid() + "\">"; if (!a->name().isEmpty()) mText += a->name(); else mText += a->email(); mText += "</a>\n"; #endif if (!a->email().isEmpty()) { if (iconPath) { mText += "<a href=\"mailto:" + a->name() +" "+ "<" + a->email() + ">" + "\">"; if ( a->RSVP() ) mText += "<IMG src=\"" + iconPath + "\">"; else mText += "<IMG src=\"" + NOiconPath + "\">"; mText += "</a>\n"; } } if (a->status() != Attendee::NeedsAction ) mText +="[" + a->statusStr() + "] "; if (a->role() == Attendee::Chair ) mText +="(" + a->roleStr().left(1) + ".)"; } mText.append("</li></ul>"); } } void KIncidenceFormatter::formatReadOnly(Incidence *event) { if (event->isReadOnly()) { addTag("p","<em>(" + i18n("read-only") + ")</em>"); } } diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp index e84f672..5181eaf 100644 --- a/libkcal/recurrence.cpp +++ b/libkcal/recurrence.cpp @@ -498,1055 +498,1057 @@ QString Recurrence::endDateStr(bool shortfmt) const const QBitArray &Recurrence::days() const { return rDays; } const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const { return rMonthPositions; } const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const { return rMonthPositions; } const QPtrList<int> &Recurrence::monthDays() const { return rMonthDays; } void Recurrence::setMinutely(int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; setDailySub(rMinutely, _rFreq, _rDuration); } void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime) { if (mRecurReadOnly) return; rEndDateTime = _rEndDateTime; setDailySub(rMinutely, _rFreq, 0); } void Recurrence::setHourly(int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; setDailySub(rHourly, _rFreq, _rDuration); } void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime) { if (mRecurReadOnly) return; rEndDateTime = _rEndDateTime; setDailySub(rHourly, _rFreq, 0); } void Recurrence::setDaily(int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; setDailySub(rDaily, _rFreq, _rDuration); } void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); setDailySub(rDaily, _rFreq, 0); } void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays, int _rDuration, int _rWeekStart) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; recurs = rWeekly; rFreq = _rFreq; rDays = _rDays; rWeekStart = _rWeekStart; rDuration = _rDuration; if (mCompatVersion < 310 && _rDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur, // with week start always on a Monday. // Convert this to the number of occurrences. mCompatDuration = _rDuration; int weeks = ((mCompatDuration-1+mRecurExDatesCount)*7) + (7 - mRecurStart.date().dayOfWeek()); QDate end(mRecurStart.date().addDays(weeks * rFreq)); rDuration = INT_MAX; // ensure that weeklyCalc() does its job correctly rDuration = weeklyCalc(COUNT_TO_DATE, end); } else { mCompatDuration = 0; } rMonthPositions.clear(); rMonthDays.clear(); if (mParent) mParent->updated(); } void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays, const QDate &_rEndDate, int _rWeekStart) { if (mRecurReadOnly) return; recurs = rWeekly; rFreq = _rFreq; rDays = _rDays; rWeekStart = _rWeekStart; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); rDuration = 0; // set to 0 because there is an end date mCompatDuration = 0; rMonthPositions.clear(); rMonthDays.clear(); rYearNums.clear(); if (mParent) mParent->updated(); } void Recurrence::setMonthly(short type, int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; recurs = type; rFreq = _rFreq; rDuration = _rDuration; if (mCompatVersion < 310) mCompatDuration = (_rDuration > 0) ? _rDuration : 0; rYearNums.clear(); if (mParent) mParent->updated(); } void Recurrence::setMonthly(short type, int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; recurs = type; rFreq = _rFreq; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); rDuration = 0; // set to 0 because there is an end date mCompatDuration = 0; rYearNums.clear(); if (mParent) mParent->updated(); } void Recurrence::addMonthlyPos(short _rPos, const QBitArray &_rDays) { if (recurs == rMonthlyPos) addMonthlyPos_(_rPos, _rDays); } void Recurrence::addMonthlyPos_(short _rPos, const QBitArray &_rDays) { if (mRecurReadOnly || _rPos == 0 || _rPos > 5 || _rPos < -5) // invalid week number return; for (rMonthPos* it = rMonthPositions.first(); it; it = rMonthPositions.next()) { int itPos = it->negative ? -it->rPos : it->rPos; if (_rPos == itPos) { // This week is already in the list. // Combine the specified days with those in the list. it->rDays |= _rDays; if (mParent) mParent->updated(); return; } } // Add the new position to the list rMonthPos *tmpPos = new rMonthPos; if (_rPos > 0) { tmpPos->rPos = _rPos; tmpPos->negative = false; } else { tmpPos->rPos = -_rPos; // take abs() tmpPos->negative = true; } tmpPos->rDays = _rDays; tmpPos->rDays.detach(); rMonthPositions.append(tmpPos); if (mCompatVersion < 310 && mCompatDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur. // Convert this to the number of occurrences. int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq; int month = mRecurStart.date().month() - 1 + monthsAhead; QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31); rDuration = INT_MAX; // ensure that recurCalc() does its job correctly rDuration = recurCalc(COUNT_TO_DATE, end); } if (mParent) mParent->updated(); } void Recurrence::addMonthlyDay(short _rDay) { if (mRecurReadOnly || (recurs != rMonthlyDay && recurs != rYearlyMonth) || _rDay == 0 || _rDay > 31 || _rDay < -31) // invalid day number return; for (int* it = rMonthDays.first(); it; it = rMonthDays.next()) { if (_rDay == *it) return; // this day is already in the list - avoid duplication } int *tmpDay = new int; *tmpDay = _rDay; rMonthDays.append(tmpDay); if (mCompatVersion < 310 && mCompatDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur. // Convert this to the number of occurrences. int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq; int month = mRecurStart.date().month() - 1 + monthsAhead; QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31); rDuration = INT_MAX; // ensure that recurCalc() does its job correctly rDuration = recurCalc(COUNT_TO_DATE, end); } if (mParent) mParent->updated(); } void Recurrence::setYearly(int type, int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; if (mCompatVersion < 310) mCompatDuration = (_rDuration > 0) ? _rDuration : 0; setYearly_(type, mFeb29YearlyDefaultType, _rFreq, _rDuration); } void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); mCompatDuration = 0; setYearly_(type, mFeb29YearlyDefaultType, _rFreq, 0); } void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, int _rDuration) { if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) return; if (mCompatVersion < 310) mCompatDuration = (_rDuration > 0) ? _rDuration : 0; setYearly_(rYearlyMonth, type, _rFreq, _rDuration); } void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, const QDate &_rEndDate) { if (mRecurReadOnly) return; rEndDateTime.setDate(_rEndDate); rEndDateTime.setTime(mRecurStart.time()); mCompatDuration = 0; setYearly_(rYearlyMonth, type, _rFreq, 0); } void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays) { if (recurs == rYearlyPos) addMonthlyPos_(_rPos, _rDays); } const QPtrList<int> &Recurrence::yearNums() const { return rYearNums; } void Recurrence::addYearlyMonth(short _rPos ) { if (mRecurReadOnly || recurs != rYearlyMonth) // invalid day/month number return; rMonthPos *tmpPos = new rMonthPos; if ( _rPos > 0) { tmpPos->rPos = _rPos; tmpPos->negative = false; } else { tmpPos->rPos = -_rPos; // take abs() tmpPos->negative = true; } rMonthPositions.append(tmpPos); } void Recurrence::addYearlyNum(short _rNum) { if (mRecurReadOnly || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos) || _rNum <= 0) // invalid day/month number return; if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) { // Backwards compatibility for KDE < 3.1. // Dates were stored as day numbers, with a fiddle to take account of leap years. // Convert the day number to a month. if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366)) return; // invalid day number _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month(); } else if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12 || recurs == rYearlyDay && _rNum > 366) return; // invalid day number uint i = 0; for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) { if (_rNum == *it) return; // this day/month is already in the list - avoid duplication ++i; } int *tmpNum = new int; *tmpNum = _rNum; rYearNums.insert(i, tmpNum); // insert the day/month in a sorted position if (mCompatVersion < 310 && mCompatDuration > 0) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur. // Convert this to the number of occurrences. QDate end(mRecurStart.date().year() + (mCompatDuration-1+mRecurExDatesCount)*rFreq, 12, 31); rDuration = INT_MAX; // ensure that recurCalc() does its job correctly rDuration = recurCalc(COUNT_TO_DATE, end); } if (mParent) mParent->updated(); } QDateTime Recurrence::getNextDateTime(const QDateTime &preDateTime, bool *last) const { if (last) *last = false; int freq; switch (recurs) { case rMinutely: freq = rFreq * 60; break; case rHourly: freq = rFreq * 3600; break; case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: { QDate preDate = preDateTime.date(); if (!mFloats && mRecurStart.time() > preDateTime.time()) preDate = preDate.addDays(-1); return QDateTime(getNextDateNoTime(preDate, last), mRecurStart.time()); } default: return QDateTime(); } // It's a sub-daily recurrence if (preDateTime < mRecurStart) return mRecurStart; int count = mRecurStart.secsTo(preDateTime) / freq + 2; if (rDuration > 0) { if (count > rDuration) return QDateTime(); if (last && count == rDuration) *last = true; } QDateTime endtime = mRecurStart.addSecs((count - 1)*freq); if (rDuration == 0) { if (endtime > rEndDateTime) return QDateTime(); if (last && endtime == rEndDateTime) *last = true; } return endtime; } QDate Recurrence::getNextDate(const QDate &preDate, bool *last) const { if (last) *last = false; switch (recurs) { case rMinutely: case rHourly: return getNextDateTime(QDateTime(preDate, QTime(23,59,59)), last).date(); case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: + qDebug("Recurrence::getNextDate: MAY BE BROKEN "); return getNextDateNoTime(preDate, last); default: return QDate(); } } QDateTime Recurrence::getPreviousDateTime(const QDateTime &afterDateTime, bool *last) const { if (last) *last = false; int freq; switch (recurs) { case rMinutely: freq = rFreq * 60; break; case rHourly: freq = rFreq * 3600; break; case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: { QDate afterDate = afterDateTime.date(); if (!mFloats && mRecurStart.time() < afterDateTime.time()) afterDate = afterDate.addDays(1); return QDateTime(getPreviousDateNoTime(afterDate, last), mRecurStart.time()); } default: return QDateTime(); } // It's a sub-daily recurrence if (afterDateTime <= mRecurStart) return QDateTime(); int count = (mRecurStart.secsTo(afterDateTime) - 1) / freq + 1; if (rDuration > 0) { if (count > rDuration) count = rDuration; if (last && count == rDuration) *last = true; } QDateTime endtime = mRecurStart.addSecs((count - 1)*freq); if (rDuration == 0) { if (endtime > rEndDateTime) endtime = rEndDateTime; if (last && endtime == rEndDateTime) *last = true; } return endtime; } QDate Recurrence::getPreviousDate(const QDate &afterDate, bool *last) const { if (last) *last = false; switch (recurs) { case rMinutely: case rHourly: return getPreviousDateTime(QDateTime(afterDate, QTime(0,0,0)), last).date(); case rDaily: case rWeekly: case rMonthlyPos: case rMonthlyDay: case rYearlyMonth: case rYearlyDay: case rYearlyPos: return getPreviousDateNoTime(afterDate, last); default: return QDate(); } } /***************************** PROTECTED FUNCTIONS ***************************/ bool Recurrence::recursSecondly(const QDate &qd, int secondFreq) const { if ((qd >= mRecurStart.date()) && ((rDuration > 0) && (qd <= endDate()) || ((rDuration == 0) && (qd <= rEndDateTime.date())) || (rDuration == -1))) { // The date queried falls within the range of the event. if (secondFreq < 24*3600) return true; // the event recurs at least once each day int after = mRecurStart.secsTo(QDateTime(qd)); if (after / secondFreq != (after + 24*3600) / secondFreq) return true; } return false; } bool Recurrence::recursMinutelyAt(const QDateTime &dt, int minuteFreq) const { if ((dt >= mRecurStart) && ((rDuration > 0) && (dt <= endDateTime()) || ((rDuration == 0) && (dt <= rEndDateTime)) || (rDuration == -1))) { // The time queried falls within the range of the event. if (((mRecurStart.secsTo(dt) / 60) % minuteFreq) == 0) return true; } return false; } bool Recurrence::recursDaily(const QDate &qd) const { QDate dStart = mRecurStart.date(); if ((dStart.daysTo(qd) % rFreq) == 0) { // The date is a day which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. return true; } } return false; } bool Recurrence::recursWeekly(const QDate &qd) const { QDate dStart = mRecurStart.date(); if ((dStart.daysTo(qd)/7) % rFreq == 0) { // The date is in a week which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. // check if the bits set match today. int i = qd.dayOfWeek()-1; if (rDays.testBit((uint) i)) return true; } } return false; } bool Recurrence::recursMonthly(const QDate &qd) const { QDate dStart = mRecurStart.date(); int year = qd.year(); int month = qd.month(); int day = qd.day(); // calculate how many months ahead this date is from the original // event's date int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month()); if ((monthsAhead % rFreq) == 0) { // The date is in a month which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. QValueList<int> days; int daysInMonth = qd.daysInMonth(); if (recurs == rMonthlyDay) getMonthlyDayDays(days, daysInMonth); else if (recurs == rMonthlyPos) getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek()); for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { if (*it == day) return true; } // no dates matched } } return false; } bool Recurrence::recursYearlyByMonth(const QDate &qd) const { QDate dStart = mRecurStart.date(); int startDay = dStart.day(); int qday = qd.day(); int qmonth = qd.month(); int qyear = qd.year(); bool match = (qday == startDay); if (!match && startDay == 29 && dStart.month() == 2) { // It's a recurrence on February 29th switch (mFeb29YearlyType) { case rFeb28: if (qday == 28 && qmonth == 2 && !QDate::leapYear(qyear)) match = true; break; case rMar1: if (qday == 1 && qmonth == 3 && !QDate::leapYear(qyear)) { qmonth = 2; match = true; } break; case rFeb29: break; } } if (match) { // The day of the month matches. Calculate how many years ahead // this date is from the original event's date. int yearsAhead = (qyear - dStart.year()); if (yearsAhead % rFreq == 0) { // The date is in a year which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. int i = qmonth; for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { if (i == *qlin.current()) return true; } } } } return false; } bool Recurrence::recursYearlyByPos(const QDate &qd) const { QDate dStart = mRecurStart.date(); int year = qd.year(); int month = qd.month(); int day = qd.day(); // calculate how many years ahead this date is from the original // event's date int yearsAhead = (year - dStart.year()); if (yearsAhead % rFreq == 0) { // The date is in a year which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { if (month == *qlin.current()) { // The month recurs QValueList<int> days; getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek()); for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { if (*it == day) return true; } } } } } return false; } bool Recurrence::recursYearlyByDay(const QDate &qd) const { QDate dStart = mRecurStart.date(); // calculate how many years ahead this date is from the original // event's date int yearsAhead = (qd.year() - dStart.year()); if (yearsAhead % rFreq == 0) { // The date is in a year which recurs if (qd >= dStart && ((rDuration > 0 && qd <= endDate()) || (rDuration == 0 && qd <= rEndDateTime.date()) || rDuration == -1)) { // The date queried falls within the range of the event. int i = qd.dayOfYear(); for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { if (i == *qlin.current()) return true; } } } return false; } /* Get the date of the next recurrence, after the specified date. * If 'last' is non-null, '*last' is set to true if the next recurrence is the * last recurrence, else false. * Reply = date of next recurrence, or invalid date if none. */ QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const { + if (last) *last = false; QDate dStart = mRecurStart.date(); if (preDate < dStart) return dStart; QDate earliestDate = preDate.addDays(1); QDate nextDate; switch (recurs) { case rDaily: nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq); break; case rWeekly: { QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart int earliestDayOfWeek = earliestDate.dayOfWeek(); int weeksAhead = start.daysTo(earliestDate) / 7; int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week weeksAhead -= notThisWeek; // latest week which recurred int weekday = 0; // First check for any remaining day this week, if this week is a recurring week if (!notThisWeek) weekday = getFirstDayInWeek(earliestDayOfWeek); // Check for a day in the next scheduled week if (!weekday && earliestDayOfWeek > 1) weekday = getFirstDayInWeek(rWeekStart) + rFreq*7; if (weekday) nextDate = start.addDays(weeksAhead*7 + weekday - 1); break; } case rMonthlyDay: case rMonthlyPos: { int startYear = dStart.year(); int startMonth = dStart.month(); // 1..12 int earliestYear = earliestDate.year(); int monthsAhead = (earliestYear - startYear)*12 + earliestDate.month() - startMonth; int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month monthsAhead -= notThisMonth; // latest month which recurred // Check for the first later day in the current month if (!notThisMonth) nextDate = getFirstDateInMonth(earliestDate); if (!nextDate.isValid() && earliestDate.day() > 1) { // Check for a day in the next scheduled month int months = startMonth - 1 + monthsAhead + rFreq; nextDate = getFirstDateInMonth(QDate(startYear + months/12, months%12 + 1, 1)); } break; } case rYearlyMonth: case rYearlyPos: case rYearlyDay: { int startYear = dStart.year(); int yearsAhead = earliestDate.year() - startYear; int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year yearsAhead -= notThisYear; // latest year which recurred // Check for the first later date in the current year if (!notThisYear) nextDate = getFirstDateInYear(earliestDate); // Check for a date in the next scheduled year if (!nextDate.isValid() && earliestDate.dayOfYear() > 1) nextDate = getFirstDateInYear(QDate(startYear + yearsAhead + rFreq, 1, 1)); break; } case rNone: default: return QDate(); } if (rDuration >= 0 && nextDate.isValid()) { // Check that the date found is within the range of the recurrence QDate end = endDate(); if (nextDate > end) return QDate(); if (last && nextDate == end) *last = true; } return nextDate; } /* Get the date of the last previous recurrence, before the specified date. * Reply = date of previous recurrence, or invalid date if none. */ QDate Recurrence::getPreviousDateNoTime(const QDate &afterDate, bool *last) const { if (last) *last = false; QDate dStart = mRecurStart.date(); QDate latestDate = afterDate.addDays(-1); if (latestDate < dStart) return QDate(); QDate prevDate; switch (recurs) { case rDaily: prevDate = dStart.addDays((dStart.daysTo(latestDate) / rFreq) * rFreq); break; case rWeekly: { QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart int latestDayOfWeek = latestDate.dayOfWeek(); int weeksAhead = start.daysTo(latestDate) / 7; int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week weeksAhead -= notThisWeek; // latest week which recurred int weekday = 0; // First check for any previous day this week, if this week is a recurring week if (!notThisWeek) weekday = getLastDayInWeek(latestDayOfWeek); // Check for a day in the previous scheduled week if (!weekday) { int weekEnd = (rWeekStart + 5)%7 + 1; if (latestDayOfWeek < weekEnd) { if (!notThisWeek) weeksAhead -= rFreq; weekday = getLastDayInWeek(weekEnd); } } if (weekday) prevDate = start.addDays(weeksAhead*7 + weekday - 1); break; } case rMonthlyDay: case rMonthlyPos: { int startYear = dStart.year(); int startMonth = dStart.month(); // 1..12 int latestYear = latestDate.year(); int monthsAhead = (latestYear - startYear)*12 + latestDate.month() - startMonth; int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month monthsAhead -= notThisMonth; // latest month which recurred // Check for the last earlier day in the current month if (!notThisMonth) prevDate = getLastDateInMonth(latestDate); if (!prevDate.isValid() && latestDate.day() < latestDate.daysInMonth()) { // Check for a day in the previous scheduled month if (!notThisMonth) monthsAhead -= rFreq; int months = startMonth + monthsAhead; // get the month after the one that recurs prevDate = getLastDateInMonth(QDate(startYear + months/12, months%12 + 1, 1).addDays(-1)); } break; } case rYearlyMonth: case rYearlyPos: case rYearlyDay: { int startYear = dStart.year(); int yearsAhead = latestDate.year() - startYear; int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year yearsAhead -= notThisYear; // latest year which recurred // Check for the first later date in the current year if (!notThisYear) prevDate = getLastDateInYear(latestDate); if (!prevDate.isValid() && latestDate.dayOfYear() < latestDate.daysInYear()) { // Check for a date in the next scheduled year if (!notThisYear) yearsAhead -= rFreq; prevDate = getLastDateInYear(QDate(startYear + yearsAhead, 12, 31)); } break; } case rNone: default: return QDate(); } if (prevDate.isValid()) { // Check that the date found is within the range of the recurrence if (prevDate < dStart) return QDate(); if (rDuration >= 0) { QDate end = endDate(); if (prevDate >= end) { if (last) *last = true; return end; } } } return prevDate; } void Recurrence::setDailySub(short type, int freq, int duration) { recurs = type; rFreq = freq; rDuration = duration; rMonthPositions.clear(); rMonthDays.clear(); rYearNums.clear(); if (type != rDaily) mFloats = false; // sub-daily types can't be floating if (mParent) mParent->updated(); } void Recurrence::setYearly_(short type, Feb29Type feb29type, int freq, int duration) { recurs = type; if (mCompatVersion < 310 && type == rYearlyDay) { mCompatRecurs = rYearlyDay; recurs = rYearlyMonth; // convert old yearly-by-day to yearly-by-month feb29type = rMar1; // retain the same day number in the year } mFeb29YearlyType = feb29type; rFreq = freq; rDuration = duration; if (type != rYearlyPos) rMonthPositions.clear(); rMonthDays.clear(); if (mParent) mParent->updated(); } int Recurrence::recurCalc(PeriodFunc func, QDateTime &endtime) const { QDate enddate = endtime.date(); switch (func) { case END_DATE_AND_COUNT: if (rDuration < 0) { endtime = QDateTime(); return 0; // infinite recurrence } if (rDuration == 0) { endtime = rEndDateTime; func = COUNT_TO_DATE; } break; case COUNT_TO_DATE: // Count recurrences up to and including the specified date/time. if (endtime < mRecurStart) return 0; if (rDuration == 0 && endtime > rEndDateTime) enddate = rEndDateTime.date(); else if (!mFloats && mRecurStart.time() > endtime.time()) enddate = enddate.addDays(-1); break; case NEXT_AFTER_DATE: // Find next recurrence AFTER endtime if (endtime < mRecurStart) { endtime = mRecurStart; return 1; } if (rDuration == 0 && endtime >= rEndDateTime) { endtime = QDateTime(); return 0; } if (!mFloats && mRecurStart.time() > endtime.time()) enddate = enddate.addDays(-1); break; default: endtime = QDateTime(); return 0; } int count = 0; // default = error bool timed = false; switch (recurs) { case rMinutely: timed = true; count = secondlyCalc(func, endtime, rFreq*60); break; case rHourly: timed = true; count = secondlyCalc(func, endtime, rFreq*3600); break; case rDaily: count = dailyCalc(func, enddate); break; case rWeekly: count = weeklyCalc(func, enddate); break; case rMonthlyPos: case rMonthlyDay: count = monthlyCalc(func, enddate); break; case rYearlyMonth: count = yearlyMonthCalc(func, enddate); break; case rYearlyPos: count = yearlyPosCalc(func, enddate); break; case rYearlyDay: count = yearlyDayCalc(func, enddate); break; default: break; } switch (func) { case END_DATE_AND_COUNT: case NEXT_AFTER_DATE: if (count == 0) endtime = QDateTime(); else if (!timed) { endtime.setDate(enddate); endtime.setTime(mRecurStart.time()); } break; case COUNT_TO_DATE: break; } return count; } int Recurrence::recurCalc(PeriodFunc func, QDate &enddate) const { QDateTime endtime(enddate, QTime(23,59,59)); switch (func) { case END_DATE_AND_COUNT: if (rDuration < 0) { enddate = QDate(); return 0; // infinite recurrence } if (rDuration == 0) { enddate = rEndDateTime.date(); func = COUNT_TO_DATE; } break; case COUNT_TO_DATE: // Count recurrences up to and including the specified date. if (enddate < mRecurStart.date()) return 0; if (rDuration == 0 && enddate > rEndDateTime.date()) { enddate = rEndDateTime.date(); endtime.setDate(enddate); } break; case NEXT_AFTER_DATE: if (enddate < mRecurStart.date()) { enddate = mRecurStart.date(); return 1; } if (rDuration == 0 && enddate >= rEndDateTime.date()) { enddate = QDate(); return 0; } break; default: enddate = QDate(); return 0; } int count = 0; // default = error bool timed = false; switch (recurs) { case rMinutely: timed = true; count = secondlyCalc(func, endtime, rFreq*60); break; case rHourly: timed = true; count = secondlyCalc(func, endtime, rFreq*3600); break; case rDaily: count = dailyCalc(func, enddate); break; case rWeekly: count = weeklyCalc(func, enddate); break; case rMonthlyPos: case rMonthlyDay: count = monthlyCalc(func, enddate); break; case rYearlyMonth: count = yearlyMonthCalc(func, enddate); break; case rYearlyPos: count = yearlyPosCalc(func, enddate); break; case rYearlyDay: count = yearlyDayCalc(func, enddate); break; default: break; } switch (func) { case END_DATE_AND_COUNT: case NEXT_AFTER_DATE: if (count == 0) endtime = QDate(); else if (timed) enddate = endtime.date(); break; case COUNT_TO_DATE: break; |