-rw-r--r-- | libkcal/recurrence.cpp | 34 |
1 files changed, 11 insertions, 23 deletions
diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp index 8a175c9..6ee5499 100644 --- a/libkcal/recurrence.cpp +++ b/libkcal/recurrence.cpp @@ -723,825 +723,822 @@ void Recurrence::setYearly(int type, int _rFreq, int _rDuration) 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)); + int after = mRecurStart.secsTo(QDateTime(qd)) - 1; 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 + QDate start = dStart.addDays(-((dStart.dayOfWeek() - rWeekStart + 7)%7)); // 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) + if (!weekday ) weekday = getFirstDayInWeek(rWeekStart) + rFreq*7; - if (weekday) - nextDate = start.addDays(weeksAhead*7 + weekday - 1); + 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) { + if (!nextDate.isValid() ) { // 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(); + QDate start = dStart.addDays(-((dStart.dayOfWeek() - rWeekStart + 7)%7)); // 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) { + if (!notThisWeek) + weeksAhead -= rFreq; int weekEnd = (rWeekStart + 5)%7 + 1; - if (latestDayOfWeek < weekEnd) { - if (!notThisWeek) - weeksAhead -= rFreq; - weekday = getLastDayInWeek(weekEnd); - } + 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: @@ -3147,267 +3144,258 @@ bool Recurrence::getYearlyMonthMonths(int day, QValueList<int> &list, QValueList * specified week which is >= the startDay. * Parameters: startDay = 1..7 (Monday..Sunday) * useWeekStart = true to end search at day before next rWeekStart * = false to search for a full 7 days * Reply = day of the week (1..7), or 0 if none found. */ int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const { int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7; for (int i = startDay - 1; ; i = (i + 1)%7) { if (rDays.testBit(i)) return i + 1; if (i == last) return 0; } } /* From the recurrence day of the week list, get the latest day in the * specified week which is <= the endDay. * Parameters: endDay = 1..7 (Monday..Sunday) * useWeekStart = true to end search at rWeekStart * = false to search for a full 7 days * Reply = day of the week (1..7), or 0 if none found. */ int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const { int last = useWeekStart ? rWeekStart - 1 : endDay%7; for (int i = endDay - 1; ; i = (i + 6)%7) { if (rDays.testBit(i)) return i + 1; if (i == last) return 0; } } /* From the recurrence monthly day number list or monthly day of week/week of * month list, get the earliest day in the specified month which is >= the * earliestDate. */ QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const { int earliestDay = earliestDate.day(); int daysInMonth = earliestDate.daysInMonth(); switch (recurs) { case rMonthlyDay: { int minday = daysInMonth + 1; for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { int day = *it.current(); if (day < 0) day = daysInMonth + day + 1; if (day >= earliestDay && day < minday) minday = day; } if (minday <= daysInMonth) return earliestDate.addDays(minday - earliestDay); break; } case rMonthlyPos: case rYearlyPos: { QDate monthBegin(earliestDate.addDays(1 - earliestDay)); QValueList<int> dayList; getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek()); for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) { if (*id >= earliestDay) return monthBegin.addDays(*id - 1); } break; } } return QDate(); } /* From the recurrence monthly day number list or monthly day of week/week of * month list, get the latest day in the specified month which is <= the * latestDate. */ QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const { int latestDay = latestDate.day(); int daysInMonth = latestDate.daysInMonth(); switch (recurs) { case rMonthlyDay: { int maxday = -1; for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { int day = *it.current(); if (day < 0) day = daysInMonth + day + 1; if (day <= latestDay && day > maxday) maxday = day; } if (maxday > 0) return QDate(latestDate.year(), latestDate.month(), maxday); break; } case rMonthlyPos: case rYearlyPos: { QDate monthBegin(latestDate.addDays(1 - latestDay)); QValueList<int> dayList; getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek()); for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) { if (*id <= latestDay) return monthBegin.addDays(*id - 1); } break; } } return QDate(); } /* From the recurrence yearly month list or yearly day list, get the earliest * month or day in the specified year which is >= the earliestDate. * Note that rYearNums is sorted in numerical order. */ QDate Recurrence::getFirstDateInYear(const QDate &earliestDate) const { QPtrListIterator<int> it(rYearNums); switch (recurs) { case rYearlyMonth: { int day = recurStart().date().day(); int earliestYear = earliestDate.year(); int earliestMonth = earliestDate.month(); int earliestDay = earliestDate.day(); if (earliestDay > day) { // The earliest date is later in the month than the recurrence date, // so skip to the next month before starting to check if (++earliestMonth > 12) return QDate(); } for ( ; it.current(); ++it) { int month = *it.current(); if (month >= earliestMonth) { if (day <= 28 || QDate::isValid(earliestYear, month, day)) return QDate(earliestYear, month, day); if (day == 29 && month == 2) { // It's a recurrence on February 29th, in a non-leap year switch (mFeb29YearlyType) { case rMar1: return QDate(earliestYear, 3, 1); case rFeb28: if (earliestDay <= 28) return QDate(earliestYear, 2, 28); break; case rFeb29: break; } } } } break; } case rYearlyPos: { QValueList<int> dayList; int earliestYear = earliestDate.year(); int earliestMonth = earliestDate.month(); int earliestDay = earliestDate.day(); for ( ; it.current(); ++it) { int month = *it.current(); if (month >= earliestMonth) { QDate monthBegin(earliestYear, month, 1); getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek()); for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) { if (*id >= earliestDay) return monthBegin.addDays(*id - 1); } earliestDay = 1; } } break; } case rYearlyDay: { int earliestDay = earliestDate.dayOfYear(); for ( ; it.current(); ++it) { int day = *it.current(); if (day >= earliestDay && (day <= 365 || day <= earliestDate.daysInYear())) return earliestDate.addDays(day - earliestDay); } break; } } return QDate(); } /* From the recurrence yearly month list or yearly day list, get the latest * month or day in the specified year which is <= the latestDate. * Note that rYearNums is sorted in numerical order. */ QDate Recurrence::getLastDateInYear(const QDate &latestDate) const { QPtrListIterator<int> it(rYearNums); switch (recurs) { case rYearlyMonth: { int day = recurStart().date().day(); int latestYear = latestDate.year(); int latestMonth = latestDate.month(); if (latestDate.day() > day) { // The latest date is earlier in the month than the recurrence date, // so skip to the previous month before starting to check if (--latestMonth <= 0) return QDate(); } for (it.toLast(); it.current(); --it) { int month = *it.current(); if (month <= latestMonth) { if (day <= 28 || QDate::isValid(latestYear, month, day)) return QDate(latestYear, month, day); if (day == 29 && month == 2) { // It's a recurrence on February 29th, in a non-leap year switch (mFeb29YearlyType) { case rMar1: if (latestMonth >= 3) return QDate(latestYear, 3, 1); break; case rFeb28: return QDate(latestYear, 2, 28); case rFeb29: break; } } } } break; } case rYearlyPos: { QValueList<int> dayList; int latestYear = latestDate.year(); int latestMonth = latestDate.month(); int latestDay = latestDate.day(); for (it.toLast(); it.current(); --it) { int month = *it.current(); if (month <= latestMonth) { QDate monthBegin(latestYear, month, 1); getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek()); for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) { if (*id <= latestDay) return monthBegin.addDays(*id - 1); } latestDay = 31; } } break; } case rYearlyDay: { int latestDay = latestDate.dayOfYear(); for (it.toLast(); it.current(); --it) { int day = *it.current(); if (day <= latestDay) return latestDate.addDays(day - latestDay); } break; } } return QDate(); } void Recurrence::dump() const { - kdDebug() << "Recurrence::dump():" << endl; - - kdDebug() << " type: " << recurs << endl; - - kdDebug() << " rDays: " << endl; - int i; - for( i = 0; i < 7; ++i ) { - kdDebug() << " " << i << ": " - << ( rDays.testBit( i ) ? "true" : "false" ) << endl; - } + ; } |