summaryrefslogtreecommitdiffabout
path: root/libkcal/recurrence.cpp
authorMichael Krelin <hacker@klever.net>2007-07-04 11:23:42 (UTC)
committer Michael Krelin <hacker@klever.net>2007-07-04 11:23:42 (UTC)
commita08aff328d4393031d5ba7d622c2b05705a89d73 (patch) (unidiff)
tree8ee90d686081c52e7c69b5ce946e9b1a7d690001 /libkcal/recurrence.cpp
parent11edc920afe4f274c0964436633aa632c8288a40 (diff)
downloadkdepimpi-a08aff328d4393031d5ba7d622c2b05705a89d73.zip
kdepimpi-a08aff328d4393031d5ba7d622c2b05705a89d73.tar.gz
kdepimpi-a08aff328d4393031d5ba7d622c2b05705a89d73.tar.bz2
initial public commit of qt4 portp1
Diffstat (limited to 'libkcal/recurrence.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libkcal/recurrence.cpp187
1 files changed, 95 insertions, 92 deletions
diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp
index 6ee5499..9a4e540 100644
--- a/libkcal/recurrence.cpp
+++ b/libkcal/recurrence.cpp
@@ -1,214 +1,217 @@
1/* 1/*
2 This file is part of libkcal. 2 This file is part of libkcal.
3 Copyright (c) 1998 Preston Brown 3 Copyright (c) 1998 Preston Brown
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> 4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (c) 2002 David Jarvie <software@astrojar.org.uk> 5 Copyright (c) 2002 David Jarvie <software@astrojar.org.uk>
6 6
7 This library is free software; you can redistribute it and/or 7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public 8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either 9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version. 10 version 2 of the License, or (at your option) any later version.
11 11
12 This library is distributed in the hope that it will be useful, 12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details. 15 Library General Public License for more details.
16 16
17 You should have received a copy of the GNU Library General Public License 17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to 18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. 20 Boston, MA 02111-1307, USA.
21*/ 21*/
22 22
23#include <limits.h> 23#include <limits.h>
24 24
25#include <kdebug.h> 25#include <kdebug.h>
26#include <kglobal.h> 26#include <kglobal.h>
27#include <klocale.h> 27#include <klocale.h>
28 28
29#include "incidence.h" 29#include "incidence.h"
30 30
31#include "recurrence.h" 31#include "recurrence.h"
32//Added by qt3to4:
33#include <Q3ValueList>
34#include <Q3PtrList>
32 35
33using namespace KCal; 36using namespace KCal;
34 37
35Recurrence::Feb29Type Recurrence::mFeb29YearlyDefaultType = Recurrence::rMar1; 38Recurrence::Feb29Type Recurrence::mFeb29YearlyDefaultType = Recurrence::rMar1;
36 39
37 40
38Recurrence::Recurrence(Incidence *parent, int compatVersion) 41Recurrence::Recurrence(Incidence *parent, int compatVersion)
39: recurs(rNone), // by default, it's not a recurring event 42: recurs(rNone), // by default, it's not a recurring event
40 rWeekStart(1), // default is Monday 43 rWeekStart(1), // default is Monday
41 rDays(7), 44 rDays(7),
42 mFloats(parent ? parent->doesFloat() : false), 45 mFloats(parent ? parent->doesFloat() : false),
43 mRecurReadOnly(false), 46 mRecurReadOnly(false),
44 mRecurExDatesCount(0), 47 mRecurExDatesCount(0),
45 mFeb29YearlyType(mFeb29YearlyDefaultType), 48 mFeb29YearlyType(mFeb29YearlyDefaultType),
46 mCompatVersion(compatVersion ? compatVersion : INT_MAX), 49 mCompatVersion(compatVersion ? compatVersion : INT_MAX),
47 mCompatRecurs(rNone), 50 mCompatRecurs(rNone),
48 mCompatDuration(0), 51 mCompatDuration(0),
49 mParent(parent) 52 mParent(parent)
50{ 53{
51 rMonthDays.setAutoDelete( true ); 54 rMonthDays.setAutoDelete( true );
52 rMonthPositions.setAutoDelete( true ); 55 rMonthPositions.setAutoDelete( true );
53 rYearNums.setAutoDelete( true ); 56 rYearNums.setAutoDelete( true );
54} 57}
55 58
56Recurrence::Recurrence(const Recurrence &r, Incidence *parent) 59Recurrence::Recurrence(const Recurrence &r, Incidence *parent)
57: recurs(r.recurs), 60: recurs(r.recurs),
58 rWeekStart(r.rWeekStart), 61 rWeekStart(r.rWeekStart),
59 rDays(r.rDays.copy()), 62 rDays(r.rDays),
60 rFreq(r.rFreq), 63 rFreq(r.rFreq),
61 rDuration(r.rDuration), 64 rDuration(r.rDuration),
62 rEndDateTime(r.rEndDateTime), 65 rEndDateTime(r.rEndDateTime),
63 mRecurStart(r.mRecurStart), 66 mRecurStart(r.mRecurStart),
64 mFloats(r.mFloats), 67 mFloats(r.mFloats),
65 mRecurReadOnly(r.mRecurReadOnly), 68 mRecurReadOnly(r.mRecurReadOnly),
66 mRecurExDatesCount(r.mRecurExDatesCount), 69 mRecurExDatesCount(r.mRecurExDatesCount),
67 mFeb29YearlyType(r.mFeb29YearlyType), 70 mFeb29YearlyType(r.mFeb29YearlyType),
68 mCompatVersion(r.mCompatVersion), 71 mCompatVersion(r.mCompatVersion),
69 mCompatRecurs(r.mCompatRecurs), 72 mCompatRecurs(r.mCompatRecurs),
70 mCompatDuration(r.mCompatDuration), 73 mCompatDuration(r.mCompatDuration),
71 mParent(parent) 74 mParent(parent)
72{ 75{
73 for (QPtrListIterator<rMonthPos> mp(r.rMonthPositions); mp.current(); ++mp) { 76 for (Q3PtrListIterator<rMonthPos> mp(r.rMonthPositions); mp.current(); ++mp) {
74 rMonthPos *tmp = new rMonthPos; 77 rMonthPos *tmp = new rMonthPos;
75 tmp->rPos = mp.current()->rPos; 78 tmp->rPos = mp.current()->rPos;
76 tmp->negative = mp.current()->negative; 79 tmp->negative = mp.current()->negative;
77 tmp->rDays = mp.current()->rDays.copy(); 80 tmp->rDays = mp.current()->rDays;
78 rMonthPositions.append(tmp); 81 rMonthPositions.append(tmp);
79 } 82 }
80 for (QPtrListIterator<int> md(r.rMonthDays); md.current(); ++md) { 83 for (Q3PtrListIterator<int> md(r.rMonthDays); md.current(); ++md) {
81 int *tmp = new int; 84 int *tmp = new int;
82 *tmp = *md.current(); 85 *tmp = *md.current();
83 rMonthDays.append(tmp); 86 rMonthDays.append(tmp);
84 } 87 }
85 for (QPtrListIterator<int> yn(r.rYearNums); yn.current(); ++yn) { 88 for (Q3PtrListIterator<int> yn(r.rYearNums); yn.current(); ++yn) {
86 int *tmp = new int; 89 int *tmp = new int;
87 *tmp = *yn.current(); 90 *tmp = *yn.current();
88 rYearNums.append(tmp); 91 rYearNums.append(tmp);
89 } 92 }
90 rMonthDays.setAutoDelete( true ); 93 rMonthDays.setAutoDelete( true );
91 rMonthPositions.setAutoDelete( true ); 94 rMonthPositions.setAutoDelete( true );
92 rYearNums.setAutoDelete( true ); 95 rYearNums.setAutoDelete( true );
93} 96}
94 97
95Recurrence::~Recurrence() 98Recurrence::~Recurrence()
96{ 99{
97} 100}
98 101
99 102
100bool Recurrence::operator==( const Recurrence& r2 ) const 103bool Recurrence::operator==( const Recurrence& r2 ) const
101{ 104{
102 105
103 // the following line is obvious 106 // the following line is obvious
104 if ( recurs == rNone && r2.recurs == rNone ) 107 if ( recurs == rNone && r2.recurs == rNone )
105 return true; 108 return true;
106 // we need the above line, because two non recurring events may 109 // we need the above line, because two non recurring events may
107 // differ in the other settings, because one (or both) 110 // differ in the other settings, because one (or both)
108 // may be not initialized properly 111 // may be not initialized properly
109 112
110 if ( recurs != r2.recurs 113 if ( recurs != r2.recurs
111 || rFreq != r2.rFreq 114 || rFreq != r2.rFreq
112 || rDuration != r2.rDuration 115 || rDuration != r2.rDuration
113 || !rDuration && rEndDateTime != r2.rEndDateTime 116 || !rDuration && rEndDateTime != r2.rEndDateTime
114 || mRecurStart != r2.mRecurStart 117 || mRecurStart != r2.mRecurStart
115 || mFloats != r2.mFloats 118 || mFloats != r2.mFloats
116 || mRecurReadOnly != r2.mRecurReadOnly 119 || mRecurReadOnly != r2.mRecurReadOnly
117 || mRecurExDatesCount != r2.mRecurExDatesCount ) 120 || mRecurExDatesCount != r2.mRecurExDatesCount )
118 return false; 121 return false;
119 // no need to compare mCompat* and mParent 122 // no need to compare mCompat* and mParent
120 // OK to compare the pointers 123 // OK to compare the pointers
121 switch ( recurs ) 124 switch ( recurs )
122 { 125 {
123 case rWeekly: 126 case rWeekly:
124 return rDays == r2.rDays 127 return rDays == r2.rDays
125 && rWeekStart == r2.rWeekStart; 128 && rWeekStart == r2.rWeekStart;
126 case rMonthlyPos: { 129 case rMonthlyPos: {
127 QPtrList<rMonthPos> MonthPositions = rMonthPositions; 130 Q3PtrList<rMonthPos> MonthPositions = rMonthPositions;
128 QPtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions; 131 Q3PtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions;
129 if ( !MonthPositions.count() ) 132 if ( !MonthPositions.count() )
130 return false; 133 return false;
131 if ( !MonthPositions2.count() ) 134 if ( !MonthPositions2.count() )
132 return false; 135 return false;
133 return MonthPositions.first()->rPos == MonthPositions2.first()->rPos; 136 return MonthPositions.first()->rPos == MonthPositions2.first()->rPos;
134 } 137 }
135 case rMonthlyDay: { 138 case rMonthlyDay: {
136 QPtrList<int> MonthDays = rMonthDays ; 139 Q3PtrList<int> MonthDays = rMonthDays ;
137 QPtrList<int> MonthDays2 = r2.rMonthDays ; 140 Q3PtrList<int> MonthDays2 = r2.rMonthDays ;
138 if ( !MonthDays.count() ) 141 if ( !MonthDays.count() )
139 return false; 142 return false;
140 if ( !MonthDays2.count() ) 143 if ( !MonthDays2.count() )
141 return false; 144 return false;
142 return *MonthDays.first() == *MonthDays2.first() ; 145 return *MonthDays.first() == *MonthDays2.first() ;
143 } 146 }
144 case rYearlyPos: { 147 case rYearlyPos: {
145 148
146 QPtrList<int> YearNums = rYearNums; 149 Q3PtrList<int> YearNums = rYearNums;
147 QPtrList<int> YearNums2 = r2.rYearNums; 150 Q3PtrList<int> YearNums2 = r2.rYearNums;
148 if ( *YearNums.first() != *YearNums2.first() ) 151 if ( *YearNums.first() != *YearNums2.first() )
149 return false; 152 return false;
150 QPtrList<rMonthPos> MonthPositions = rMonthPositions; 153 Q3PtrList<rMonthPos> MonthPositions = rMonthPositions;
151 QPtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions; 154 Q3PtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions;
152 if ( !MonthPositions.count() ) 155 if ( !MonthPositions.count() )
153 return false; 156 return false;
154 if ( !MonthPositions2.count() ) 157 if ( !MonthPositions2.count() )
155 return false; 158 return false;
156 return MonthPositions.first()->rPos == MonthPositions2.first()->rPos; 159 return MonthPositions.first()->rPos == MonthPositions2.first()->rPos;
157 160
158 } 161 }
159 case rYearlyMonth: { 162 case rYearlyMonth: {
160 QPtrList<int> YearNums = rYearNums; 163 Q3PtrList<int> YearNums = rYearNums;
161 QPtrList<int> YearNums2 = r2.rYearNums; 164 Q3PtrList<int> YearNums2 = r2.rYearNums;
162 return ( *YearNums.first() == *YearNums2.first() && mFeb29YearlyType == r2.mFeb29YearlyType); 165 return ( *YearNums.first() == *YearNums2.first() && mFeb29YearlyType == r2.mFeb29YearlyType);
163 } 166 }
164 case rYearlyDay: { 167 case rYearlyDay: {
165 QPtrList<int> YearNums = rYearNums; 168 Q3PtrList<int> YearNums = rYearNums;
166 QPtrList<int> YearNums2 = r2.rYearNums; 169 Q3PtrList<int> YearNums2 = r2.rYearNums;
167 return ( *YearNums.first() == *YearNums2.first() ); 170 return ( *YearNums.first() == *YearNums2.first() );
168 } 171 }
169 case rNone: 172 case rNone:
170 case rMinutely: 173 case rMinutely:
171 case rHourly: 174 case rHourly:
172 case rDaily: 175 case rDaily:
173 default: 176 default:
174 return true; 177 return true;
175 } 178 }
176} 179}
177/* 180/*
178bool Recurrence::compareLists( const QPtrList<int> &l1 ,const QPtrList<int> &l2) 181bool Recurrence::compareLists( const QPtrList<int> &l1 ,const QPtrList<int> &l2)
179{ 182{
180 if ( l1.count() != l2.count() ) 183 if ( l1.count() != l2.count() )
181 return false; 184 return false;
182 int count = l1.count(); 185 int count = l1.count();
183 int i; 186 int i;
184 for ( i = 0; i < count ; ++i ) { 187 for ( i = 0; i < count ; ++i ) {
185 // if ( l1.at(i) != l2.at(i) ) 188 // if ( l1.at(i) != l2.at(i) )
186 return false; 189 return false;
187 qDebug("compüare "); 190 qDebug("compüare ");
188 } 191 }
189 return true; 192 return true;
190} 193}
191*/ 194*/
192QString Recurrence::recurrenceText() const 195QString Recurrence::recurrenceText() const
193{ 196{
194 QString recurText; 197 QString recurText;
195 if ( recurs == Recurrence::rMinutely ) 198 if ( recurs == Recurrence::rMinutely )
196 recurText = i18n("minutely"); 199 recurText = i18n("minutely");
197 else if ( recurs == Recurrence::rHourly ) 200 else if ( recurs == Recurrence::rHourly )
198 recurText = i18n("hourly"); 201 recurText = i18n("hourly");
199 else if ( recurs == Recurrence::rDaily ) 202 else if ( recurs == Recurrence::rDaily )
200 recurText = i18n("daily"); 203 recurText = i18n("daily");
201 else if ( recurs == Recurrence::rWeekly ) 204 else if ( recurs == Recurrence::rWeekly )
202 recurText = i18n("weekly"); 205 recurText = i18n("weekly");
203 else if ( recurs == Recurrence::rMonthlyPos ) 206 else if ( recurs == Recurrence::rMonthlyPos )
204 recurText = i18n("monthly"); 207 recurText = i18n("monthly");
205 else if ( recurs == Recurrence::rMonthlyDay ) 208 else if ( recurs == Recurrence::rMonthlyDay )
206 recurText = i18n("monthly"); 209 recurText = i18n("monthly");
207 else if ( recurs == Recurrence::rYearlyMonth ) 210 else if ( recurs == Recurrence::rYearlyMonth )
208 recurText = i18n("yearly"); 211 recurText = i18n("yearly");
209 else if ( recurs == Recurrence::rYearlyDay ) 212 else if ( recurs == Recurrence::rYearlyDay )
210 recurText = i18n("day-yearly"); 213 recurText = i18n("day-yearly");
211 else if ( recurs == Recurrence::rYearlyPos ) 214 else if ( recurs == Recurrence::rYearlyPos )
212 recurText = i18n("position-yearly"); 215 recurText = i18n("position-yearly");
213 if ( !recurText.isEmpty() ) { 216 if ( !recurText.isEmpty() ) {
214 if ( rFreq > 1 ){ 217 if ( rFreq > 1 ){
@@ -312,97 +315,97 @@ QDate Recurrence::endDate() const
312 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq); 315 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
313 316
314 case rWeekly: 317 case rWeekly:
315 count = weeklyCalc(END_DATE_AND_COUNT, end); 318 count = weeklyCalc(END_DATE_AND_COUNT, end);
316 break; 319 break;
317 case rMonthlyPos: 320 case rMonthlyPos:
318 case rMonthlyDay: 321 case rMonthlyDay:
319 count = monthlyCalc(END_DATE_AND_COUNT, end); 322 count = monthlyCalc(END_DATE_AND_COUNT, end);
320 break; 323 break;
321 case rYearlyMonth: 324 case rYearlyMonth:
322 count = yearlyMonthCalc(END_DATE_AND_COUNT, end); 325 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
323 break; 326 break;
324 case rYearlyDay: 327 case rYearlyDay:
325 count = yearlyDayCalc(END_DATE_AND_COUNT, end); 328 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
326 break; 329 break;
327 case rYearlyPos: 330 case rYearlyPos:
328 count = yearlyPosCalc(END_DATE_AND_COUNT, end); 331 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
329 break; 332 break;
330 default: 333 default:
331 // catch-all. Should never get here. 334 // catch-all. Should never get here.
332 kdDebug(5800) << "Control should never reach here in endDate()!" << endl; 335 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
333 break; 336 break;
334 } 337 }
335 } 338 }
336 if (!count) 339 if (!count)
337 return QDate(); // error - there is no recurrence 340 return QDate(); // error - there is no recurrence
338 return end; 341 return end;
339} 342}
340 343
341QDateTime Recurrence::endDateTime() const 344QDateTime Recurrence::endDateTime() const
342{ 345{
343 int count = 0; 346 int count = 0;
344 QDate end; 347 QDate end;
345 if (recurs != rNone) { 348 if (recurs != rNone) {
346 if (rDuration < 0) 349 if (rDuration < 0)
347 return QDateTime(); // infinite recurrence 350 return QDateTime(); // infinite recurrence
348 if (rDuration == 0) 351 if (rDuration == 0)
349 return rEndDateTime; 352 return rEndDateTime;
350 353
351 // The end date is determined by the recurrence count 354 // The end date is determined by the recurrence count
352 QDate dStart = mRecurStart.date(); 355 QDate dStart = mRecurStart.date();
353 switch (recurs) 356 switch (recurs)
354 { 357 {
355 case rMinutely: 358 case rMinutely:
356 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60); 359 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60);
357 case rHourly: 360 case rHourly:
358 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600); 361 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600);
359 case rDaily: 362 case rDaily:
360 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq); 363 return (QDateTime)dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
361 364
362 case rWeekly: 365 case rWeekly:
363 count = weeklyCalc(END_DATE_AND_COUNT, end); 366 count = weeklyCalc(END_DATE_AND_COUNT, end);
364 break; 367 break;
365 case rMonthlyPos: 368 case rMonthlyPos:
366 case rMonthlyDay: 369 case rMonthlyDay:
367 count = monthlyCalc(END_DATE_AND_COUNT, end); 370 count = monthlyCalc(END_DATE_AND_COUNT, end);
368 break; 371 break;
369 case rYearlyMonth: 372 case rYearlyMonth:
370 count = yearlyMonthCalc(END_DATE_AND_COUNT, end); 373 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
371 break; 374 break;
372 case rYearlyDay: 375 case rYearlyDay:
373 count = yearlyDayCalc(END_DATE_AND_COUNT, end); 376 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
374 break; 377 break;
375 case rYearlyPos: 378 case rYearlyPos:
376 count = yearlyPosCalc(END_DATE_AND_COUNT, end); 379 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
377 break; 380 break;
378 default: 381 default:
379 // catch-all. Should never get here. 382 // catch-all. Should never get here.
380 kdDebug(5800) << "Control should never reach here in endDate()!" << endl; 383 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
381 break; 384 break;
382 } 385 }
383 } 386 }
384 if (!count) 387 if (!count)
385 return QDateTime(); // error - there is no recurrence 388 return QDateTime(); // error - there is no recurrence
386 return QDateTime(end, mRecurStart.time()); 389 return QDateTime(end, mRecurStart.time());
387} 390}
388 391
389int Recurrence::durationTo(const QDate &date) const 392int Recurrence::durationTo(const QDate &date) const
390{ 393{
391 QDate d = date; 394 QDate d = date;
392 return recurCalc(COUNT_TO_DATE, d); 395 return recurCalc(COUNT_TO_DATE, d);
393} 396}
394 397
395int Recurrence::durationTo(const QDateTime &datetime) const 398int Recurrence::durationTo(const QDateTime &datetime) const
396{ 399{
397 QDateTime dt = datetime; 400 QDateTime dt = datetime;
398 return recurCalc(COUNT_TO_DATE, dt); 401 return recurCalc(COUNT_TO_DATE, dt);
399} 402}
400 403
401void Recurrence::unsetRecurs() 404void Recurrence::unsetRecurs()
402{ 405{
403 if (mRecurReadOnly) return; 406 if (mRecurReadOnly) return;
404 recurs = rNone; 407 recurs = rNone;
405 rMonthPositions.clear(); 408 rMonthPositions.clear();
406 rMonthDays.clear(); 409 rMonthDays.clear();
407 rYearNums.clear(); 410 rYearNums.clear();
408} 411}
@@ -461,107 +464,107 @@ void Recurrence::setFloats(bool f)
461 case rMonthlyDay: 464 case rMonthlyDay:
462 case rYearlyMonth: 465 case rYearlyMonth:
463 case rYearlyDay: 466 case rYearlyDay:
464 case rYearlyPos: 467 case rYearlyPos:
465 break; 468 break;
466 case rMinutely: 469 case rMinutely:
467 case rHourly: 470 case rHourly:
468 default: 471 default:
469 return; // can't set sub-daily to floating 472 return; // can't set sub-daily to floating
470 } 473 }
471 mFloats = f; 474 mFloats = f;
472 if (f) { 475 if (f) {
473 mRecurStart.setTime(QTime(0,0,0)); 476 mRecurStart.setTime(QTime(0,0,0));
474 rEndDateTime.setTime(QTime(0,0,0)); 477 rEndDateTime.setTime(QTime(0,0,0));
475 } 478 }
476} 479}
477 480
478int Recurrence::frequency() const 481int Recurrence::frequency() const
479{ 482{
480 return rFreq; 483 return rFreq;
481} 484}
482 485
483int Recurrence::duration() const 486int Recurrence::duration() const
484{ 487{
485 return rDuration; 488 return rDuration;
486} 489}
487 490
488void Recurrence::setDuration(int _rDuration) 491void Recurrence::setDuration(int _rDuration)
489{ 492{
490 if (mRecurReadOnly) return; 493 if (mRecurReadOnly) return;
491 if (_rDuration > 0) { 494 if (_rDuration > 0) {
492 rDuration = _rDuration; 495 rDuration = _rDuration;
493 // Compatibility mode is only needed when reading the calendar in ICalFormatImpl, 496 // Compatibility mode is only needed when reading the calendar in ICalFormatImpl,
494 // so explicitly setting the duration means no backwards compatibility is needed. 497 // so explicitly setting the duration means no backwards compatibility is needed.
495 mCompatDuration = 0; 498 mCompatDuration = 0;
496 } 499 }
497} 500}
498 501
499QString Recurrence::endDateStr(bool shortfmt) const 502QString Recurrence::endDateStr(bool shortfmt) const
500{ 503{
501 return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt); 504 return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt);
502} 505}
503 506
504const QBitArray &Recurrence::days() const 507const QBitArray &Recurrence::days() const
505{ 508{
506 return rDays; 509 return rDays;
507} 510}
508 511
509const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const 512const Q3PtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const
510{ 513{
511 return rMonthPositions; 514 return rMonthPositions;
512} 515}
513 516
514const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const 517const Q3PtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const
515{ 518{
516 return rMonthPositions; 519 return rMonthPositions;
517} 520}
518 521
519const QPtrList<int> &Recurrence::monthDays() const 522const Q3PtrList<int> &Recurrence::monthDays() const
520{ 523{
521 return rMonthDays; 524 return rMonthDays;
522} 525}
523 526
524void Recurrence::setMinutely(int _rFreq, int _rDuration) 527void Recurrence::setMinutely(int _rFreq, int _rDuration)
525{ 528{
526 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 529 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
527 return; 530 return;
528 setDailySub(rMinutely, _rFreq, _rDuration); 531 setDailySub(rMinutely, _rFreq, _rDuration);
529} 532}
530 533
531void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime) 534void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime)
532{ 535{
533 if (mRecurReadOnly) return; 536 if (mRecurReadOnly) return;
534 rEndDateTime = _rEndDateTime; 537 rEndDateTime = _rEndDateTime;
535 setDailySub(rMinutely, _rFreq, 0); 538 setDailySub(rMinutely, _rFreq, 0);
536} 539}
537 540
538void Recurrence::setHourly(int _rFreq, int _rDuration) 541void Recurrence::setHourly(int _rFreq, int _rDuration)
539{ 542{
540 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 543 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
541 return; 544 return;
542 setDailySub(rHourly, _rFreq, _rDuration); 545 setDailySub(rHourly, _rFreq, _rDuration);
543} 546}
544 547
545void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime) 548void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime)
546{ 549{
547 if (mRecurReadOnly) return; 550 if (mRecurReadOnly) return;
548 rEndDateTime = _rEndDateTime; 551 rEndDateTime = _rEndDateTime;
549 setDailySub(rHourly, _rFreq, 0); 552 setDailySub(rHourly, _rFreq, 0);
550} 553}
551 554
552void Recurrence::setDaily(int _rFreq, int _rDuration) 555void Recurrence::setDaily(int _rFreq, int _rDuration)
553{ 556{
554 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 557 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
555 return; 558 return;
556 setDailySub(rDaily, _rFreq, _rDuration); 559 setDailySub(rDaily, _rFreq, _rDuration);
557} 560}
558 561
559void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate) 562void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate)
560{ 563{
561 if (mRecurReadOnly) return; 564 if (mRecurReadOnly) return;
562 rEndDateTime.setDate(_rEndDate); 565 rEndDateTime.setDate(_rEndDate);
563 rEndDateTime.setTime(mRecurStart.time()); 566 rEndDateTime.setTime(mRecurStart.time());
564 setDailySub(rDaily, _rFreq, 0); 567 setDailySub(rDaily, _rFreq, 0);
565} 568}
566 569
567void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays, 570void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays,
@@ -714,97 +717,97 @@ void Recurrence::addMonthlyDay(short _rDay)
714 rDuration = recurCalc(COUNT_TO_DATE, end); 717 rDuration = recurCalc(COUNT_TO_DATE, end);
715 } 718 }
716 719
717 if (mParent) mParent->updated(); 720 if (mParent) mParent->updated();
718} 721}
719 722
720void Recurrence::setYearly(int type, int _rFreq, int _rDuration) 723void Recurrence::setYearly(int type, int _rFreq, int _rDuration)
721{ 724{
722 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 725 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
723 return; 726 return;
724 if (mCompatVersion < 310) 727 if (mCompatVersion < 310)
725 mCompatDuration = (_rDuration > 0) ? _rDuration : 0; 728 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
726 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, _rDuration); 729 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, _rDuration);
727} 730}
728 731
729void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate) 732void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate)
730{ 733{
731 if (mRecurReadOnly) return; 734 if (mRecurReadOnly) return;
732 rEndDateTime.setDate(_rEndDate); 735 rEndDateTime.setDate(_rEndDate);
733 rEndDateTime.setTime(mRecurStart.time()); 736 rEndDateTime.setTime(mRecurStart.time());
734 mCompatDuration = 0; 737 mCompatDuration = 0;
735 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, 0); 738 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, 0);
736} 739}
737 740
738void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, int _rDuration) 741void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, int _rDuration)
739{ 742{
740 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 743 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
741 return; 744 return;
742 if (mCompatVersion < 310) 745 if (mCompatVersion < 310)
743 mCompatDuration = (_rDuration > 0) ? _rDuration : 0; 746 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
744 setYearly_(rYearlyMonth, type, _rFreq, _rDuration); 747 setYearly_(rYearlyMonth, type, _rFreq, _rDuration);
745} 748}
746 749
747void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, const QDate &_rEndDate) 750void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, const QDate &_rEndDate)
748{ 751{
749 if (mRecurReadOnly) return; 752 if (mRecurReadOnly) return;
750 rEndDateTime.setDate(_rEndDate); 753 rEndDateTime.setDate(_rEndDate);
751 rEndDateTime.setTime(mRecurStart.time()); 754 rEndDateTime.setTime(mRecurStart.time());
752 mCompatDuration = 0; 755 mCompatDuration = 0;
753 setYearly_(rYearlyMonth, type, _rFreq, 0); 756 setYearly_(rYearlyMonth, type, _rFreq, 0);
754} 757}
755 758
756void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays) 759void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays)
757{ 760{
758 if (recurs == rYearlyPos) 761 if (recurs == rYearlyPos)
759 addMonthlyPos_(_rPos, _rDays); 762 addMonthlyPos_(_rPos, _rDays);
760} 763}
761 764
762const QPtrList<int> &Recurrence::yearNums() const 765const Q3PtrList<int> &Recurrence::yearNums() const
763{ 766{
764 return rYearNums; 767 return rYearNums;
765} 768}
766void Recurrence::addYearlyMonth(short _rPos ) 769void Recurrence::addYearlyMonth(short _rPos )
767{ 770{
768 if (mRecurReadOnly || recurs != rYearlyMonth) // invalid day/month number 771 if (mRecurReadOnly || recurs != rYearlyMonth) // invalid day/month number
769 return; 772 return;
770 rMonthPos *tmpPos = new rMonthPos; 773 rMonthPos *tmpPos = new rMonthPos;
771 if ( _rPos > 0) { 774 if ( _rPos > 0) {
772 tmpPos->rPos = _rPos; 775 tmpPos->rPos = _rPos;
773 tmpPos->negative = false; 776 tmpPos->negative = false;
774 } else { 777 } else {
775 tmpPos->rPos = -_rPos; // take abs() 778 tmpPos->rPos = -_rPos; // take abs()
776 tmpPos->negative = true; 779 tmpPos->negative = true;
777 } 780 }
778 rMonthPositions.append(tmpPos); 781 rMonthPositions.append(tmpPos);
779} 782}
780void Recurrence::addYearlyNum(short _rNum) 783void Recurrence::addYearlyNum(short _rNum)
781{ 784{
782 if (mRecurReadOnly 785 if (mRecurReadOnly
783 || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos) 786 || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos)
784 || _rNum <= 0) // invalid day/month number 787 || _rNum <= 0) // invalid day/month number
785 return; 788 return;
786 789
787 if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) { 790 if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) {
788 // Backwards compatibility for KDE < 3.1. 791 // Backwards compatibility for KDE < 3.1.
789 // Dates were stored as day numbers, with a fiddle to take account of leap years. 792 // Dates were stored as day numbers, with a fiddle to take account of leap years.
790 // Convert the day number to a month. 793 // Convert the day number to a month.
791 if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366)) 794 if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366))
792 return; // invalid day number 795 return; // invalid day number
793 _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month(); 796 _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month();
794 } else 797 } else
795 if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12 798 if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12
796 || recurs == rYearlyDay && _rNum > 366) 799 || recurs == rYearlyDay && _rNum > 366)
797 return; // invalid day number 800 return; // invalid day number
798 801
799 uint i = 0; 802 uint i = 0;
800 for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) { 803 for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) {
801 if (_rNum == *it) 804 if (_rNum == *it)
802 return; // this day/month is already in the list - avoid duplication 805 return; // this day/month is already in the list - avoid duplication
803 ++i; 806 ++i;
804 } 807 }
805 808
806 int *tmpNum = new int; 809 int *tmpNum = new int;
807 *tmpNum = _rNum; 810 *tmpNum = _rNum;
808 rYearNums.insert(i, tmpNum); // insert the day/month in a sorted position 811 rYearNums.insert(i, tmpNum); // insert the day/month in a sorted position
809 812
810 if (mCompatVersion < 310 && mCompatDuration > 0) { 813 if (mCompatVersion < 310 && mCompatDuration > 0) {
@@ -1002,207 +1005,207 @@ bool Recurrence::recursDaily(const QDate &qd) const
1002 if ((dStart.daysTo(qd) % rFreq) == 0) { 1005 if ((dStart.daysTo(qd) % rFreq) == 0) {
1003 // The date is a day which recurs 1006 // The date is a day which recurs
1004 if (qd >= dStart 1007 if (qd >= dStart
1005 && ((rDuration > 0 && qd <= endDate()) || 1008 && ((rDuration > 0 && qd <= endDate()) ||
1006 (rDuration == 0 && qd <= rEndDateTime.date()) || 1009 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1007 rDuration == -1)) { 1010 rDuration == -1)) {
1008 // The date queried falls within the range of the event. 1011 // The date queried falls within the range of the event.
1009 return true; 1012 return true;
1010 } 1013 }
1011 } 1014 }
1012 return false; 1015 return false;
1013} 1016}
1014 1017
1015bool Recurrence::recursWeekly(const QDate &qd) const 1018bool Recurrence::recursWeekly(const QDate &qd) const
1016{ 1019{
1017 QDate dStart = mRecurStart.date(); 1020 QDate dStart = mRecurStart.date();
1018 if ((dStart.daysTo(qd)/7) % rFreq == 0) { 1021 if ((dStart.daysTo(qd)/7) % rFreq == 0) {
1019 // The date is in a week which recurs 1022 // The date is in a week which recurs
1020 if (qd >= dStart 1023 if (qd >= dStart
1021 && ((rDuration > 0 && qd <= endDate()) || 1024 && ((rDuration > 0 && qd <= endDate()) ||
1022 (rDuration == 0 && qd <= rEndDateTime.date()) || 1025 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1023 rDuration == -1)) { 1026 rDuration == -1)) {
1024 // The date queried falls within the range of the event. 1027 // The date queried falls within the range of the event.
1025 // check if the bits set match today. 1028 // check if the bits set match today.
1026 int i = qd.dayOfWeek()-1; 1029 int i = qd.dayOfWeek()-1;
1027 if (rDays.testBit((uint) i)) 1030 if (rDays.testBit((uint) i))
1028 return true; 1031 return true;
1029 } 1032 }
1030 } 1033 }
1031 return false; 1034 return false;
1032} 1035}
1033 1036
1034bool Recurrence::recursMonthly(const QDate &qd) const 1037bool Recurrence::recursMonthly(const QDate &qd) const
1035{ 1038{
1036 QDate dStart = mRecurStart.date(); 1039 QDate dStart = mRecurStart.date();
1037 int year = qd.year(); 1040 int year = qd.year();
1038 int month = qd.month(); 1041 int month = qd.month();
1039 int day = qd.day(); 1042 int day = qd.day();
1040 // calculate how many months ahead this date is from the original 1043 // calculate how many months ahead this date is from the original
1041 // event's date 1044 // event's date
1042 int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month()); 1045 int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month());
1043 if ((monthsAhead % rFreq) == 0) { 1046 if ((monthsAhead % rFreq) == 0) {
1044 // The date is in a month which recurs 1047 // The date is in a month which recurs
1045 if (qd >= dStart 1048 if (qd >= dStart
1046 && ((rDuration > 0 && qd <= endDate()) || 1049 && ((rDuration > 0 && qd <= endDate()) ||
1047 (rDuration == 0 && qd <= rEndDateTime.date()) || 1050 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1048 rDuration == -1)) { 1051 rDuration == -1)) {
1049 // The date queried falls within the range of the event. 1052 // The date queried falls within the range of the event.
1050 QValueList<int> days; 1053 Q3ValueList<int> days;
1051 int daysInMonth = qd.daysInMonth(); 1054 int daysInMonth = qd.daysInMonth();
1052 if (recurs == rMonthlyDay) 1055 if (recurs == rMonthlyDay)
1053 getMonthlyDayDays(days, daysInMonth); 1056 getMonthlyDayDays(days, daysInMonth);
1054 else if (recurs == rMonthlyPos) 1057 else if (recurs == rMonthlyPos)
1055 getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek()); 1058 getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek());
1056 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { 1059 for (Q3ValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
1057 if (*it == day) 1060 if (*it == day)
1058 return true; 1061 return true;
1059 } 1062 }
1060 // no dates matched 1063 // no dates matched
1061 } 1064 }
1062 } 1065 }
1063 return false; 1066 return false;
1064} 1067}
1065 1068
1066bool Recurrence::recursYearlyByMonth(const QDate &qd) const 1069bool Recurrence::recursYearlyByMonth(const QDate &qd) const
1067{ 1070{
1068 QDate dStart = mRecurStart.date(); 1071 QDate dStart = mRecurStart.date();
1069 int startDay = dStart.day(); 1072 int startDay = dStart.day();
1070 int qday = qd.day(); 1073 int qday = qd.day();
1071 int qmonth = qd.month(); 1074 int qmonth = qd.month();
1072 int qyear = qd.year(); 1075 int qyear = qd.year();
1073 bool match = (qday == startDay); 1076 bool match = (qday == startDay);
1074 if (!match && startDay == 29 && dStart.month() == 2) { 1077 if (!match && startDay == 29 && dStart.month() == 2) {
1075 // It's a recurrence on February 29th 1078 // It's a recurrence on February 29th
1076 switch (mFeb29YearlyType) { 1079 switch (mFeb29YearlyType) {
1077 case rFeb28: 1080 case rFeb28:
1078 if (qday == 28 && qmonth == 2 && !QDate::leapYear(qyear)) 1081 if (qday == 28 && qmonth == 2 && !QDate::leapYear(qyear))
1079 match = true; 1082 match = true;
1080 break; 1083 break;
1081 case rMar1: 1084 case rMar1:
1082 if (qday == 1 && qmonth == 3 && !QDate::leapYear(qyear)) { 1085 if (qday == 1 && qmonth == 3 && !QDate::leapYear(qyear)) {
1083 qmonth = 2; 1086 qmonth = 2;
1084 match = true; 1087 match = true;
1085 } 1088 }
1086 break; 1089 break;
1087 case rFeb29: 1090 case rFeb29:
1088 break; 1091 break;
1089 } 1092 }
1090 } 1093 }
1091 1094
1092 if (match) { 1095 if (match) {
1093 // The day of the month matches. Calculate how many years ahead 1096 // The day of the month matches. Calculate how many years ahead
1094 // this date is from the original event's date. 1097 // this date is from the original event's date.
1095 int yearsAhead = (qyear - dStart.year()); 1098 int yearsAhead = (qyear - dStart.year());
1096 if (yearsAhead % rFreq == 0) { 1099 if (yearsAhead % rFreq == 0) {
1097 // The date is in a year which recurs 1100 // The date is in a year which recurs
1098 if (qd >= dStart 1101 if (qd >= dStart
1099 && ((rDuration > 0 && qd <= endDate()) || 1102 && ((rDuration > 0 && qd <= endDate()) ||
1100 (rDuration == 0 && qd <= rEndDateTime.date()) || 1103 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1101 rDuration == -1)) { 1104 rDuration == -1)) {
1102 // The date queried falls within the range of the event. 1105 // The date queried falls within the range of the event.
1103 int i = qmonth; 1106 int i = qmonth;
1104 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { 1107 for (Q3PtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1105 if (i == *qlin.current()) 1108 if (i == *qlin.current())
1106 return true; 1109 return true;
1107 } 1110 }
1108 } 1111 }
1109 } 1112 }
1110 } 1113 }
1111 return false; 1114 return false;
1112} 1115}
1113 1116
1114bool Recurrence::recursYearlyByPos(const QDate &qd) const 1117bool Recurrence::recursYearlyByPos(const QDate &qd) const
1115{ 1118{
1116 QDate dStart = mRecurStart.date(); 1119 QDate dStart = mRecurStart.date();
1117 int year = qd.year(); 1120 int year = qd.year();
1118 int month = qd.month(); 1121 int month = qd.month();
1119 int day = qd.day(); 1122 int day = qd.day();
1120 // calculate how many years ahead this date is from the original 1123 // calculate how many years ahead this date is from the original
1121 // event's date 1124 // event's date
1122 int yearsAhead = (year - dStart.year()); 1125 int yearsAhead = (year - dStart.year());
1123 if (yearsAhead % rFreq == 0) { 1126 if (yearsAhead % rFreq == 0) {
1124 // The date is in a year which recurs 1127 // The date is in a year which recurs
1125 if (qd >= dStart 1128 if (qd >= dStart
1126 && ((rDuration > 0 && qd <= endDate()) || 1129 && ((rDuration > 0 && qd <= endDate()) ||
1127 (rDuration == 0 && qd <= rEndDateTime.date()) || 1130 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1128 rDuration == -1)) { 1131 rDuration == -1)) {
1129 // The date queried falls within the range of the event. 1132 // The date queried falls within the range of the event.
1130 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { 1133 for (Q3PtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1131 if (month == *qlin.current()) { 1134 if (month == *qlin.current()) {
1132 // The month recurs 1135 // The month recurs
1133 QValueList<int> days; 1136 Q3ValueList<int> days;
1134 getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek()); 1137 getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek());
1135 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { 1138 for (Q3ValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
1136 if (*it == day) 1139 if (*it == day)
1137 return true; 1140 return true;
1138 } 1141 }
1139 } 1142 }
1140 } 1143 }
1141 } 1144 }
1142 } 1145 }
1143 return false; 1146 return false;
1144} 1147}
1145 1148
1146bool Recurrence::recursYearlyByDay(const QDate &qd) const 1149bool Recurrence::recursYearlyByDay(const QDate &qd) const
1147{ 1150{
1148 QDate dStart = mRecurStart.date(); 1151 QDate dStart = mRecurStart.date();
1149 // calculate how many years ahead this date is from the original 1152 // calculate how many years ahead this date is from the original
1150 // event's date 1153 // event's date
1151 int yearsAhead = (qd.year() - dStart.year()); 1154 int yearsAhead = (qd.year() - dStart.year());
1152 if (yearsAhead % rFreq == 0) { 1155 if (yearsAhead % rFreq == 0) {
1153 // The date is in a year which recurs 1156 // The date is in a year which recurs
1154 if (qd >= dStart 1157 if (qd >= dStart
1155 && ((rDuration > 0 && qd <= endDate()) || 1158 && ((rDuration > 0 && qd <= endDate()) ||
1156 (rDuration == 0 && qd <= rEndDateTime.date()) || 1159 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1157 rDuration == -1)) { 1160 rDuration == -1)) {
1158 // The date queried falls within the range of the event. 1161 // The date queried falls within the range of the event.
1159 int i = qd.dayOfYear(); 1162 int i = qd.dayOfYear();
1160 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { 1163 for (Q3PtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1161 if (i == *qlin.current()) 1164 if (i == *qlin.current())
1162 return true; 1165 return true;
1163 } 1166 }
1164 } 1167 }
1165 } 1168 }
1166 return false; 1169 return false;
1167} 1170}
1168 1171
1169/* Get the date of the next recurrence, after the specified date. 1172/* Get the date of the next recurrence, after the specified date.
1170 * If 'last' is non-null, '*last' is set to true if the next recurrence is the 1173 * If 'last' is non-null, '*last' is set to true if the next recurrence is the
1171 * last recurrence, else false. 1174 * last recurrence, else false.
1172 * Reply = date of next recurrence, or invalid date if none. 1175 * Reply = date of next recurrence, or invalid date if none.
1173 */ 1176 */
1174QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const 1177QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const
1175{ 1178{
1176 1179
1177 if (last) 1180 if (last)
1178 *last = false; 1181 *last = false;
1179 QDate dStart = mRecurStart.date(); 1182 QDate dStart = mRecurStart.date();
1180 if (preDate < dStart) 1183 if (preDate < dStart)
1181 return dStart; 1184 return dStart;
1182 QDate earliestDate = preDate.addDays(1); 1185 QDate earliestDate = preDate.addDays(1);
1183 QDate nextDate; 1186 QDate nextDate;
1184 1187
1185 switch (recurs) { 1188 switch (recurs) {
1186 case rDaily: 1189 case rDaily:
1187 nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq); 1190 nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq);
1188 break; 1191 break;
1189 1192
1190 case rWeekly: { 1193 case rWeekly: {
1191 QDate start = dStart.addDays(-((dStart.dayOfWeek() - rWeekStart + 7)%7)); // start of week for dStart 1194 QDate start = dStart.addDays(-((dStart.dayOfWeek() - rWeekStart + 7)%7)); // start of week for dStart
1192 int earliestDayOfWeek = earliestDate.dayOfWeek(); 1195 int earliestDayOfWeek = earliestDate.dayOfWeek();
1193 int weeksAhead = start.daysTo(earliestDate) / 7; 1196 int weeksAhead = start.daysTo(earliestDate) / 7;
1194 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week 1197 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week
1195 weeksAhead -= notThisWeek; // latest week which recurred 1198 weeksAhead -= notThisWeek; // latest week which recurred
1196 int weekday = 0; 1199 int weekday = 0;
1197 // First check for any remaining day this week, if this week is a recurring week 1200 // First check for any remaining day this week, if this week is a recurring week
1198 if (!notThisWeek) 1201 if (!notThisWeek)
1199 weekday = getFirstDayInWeek(earliestDayOfWeek); 1202 weekday = getFirstDayInWeek(earliestDayOfWeek);
1200 // Check for a day in the next scheduled week 1203 // Check for a day in the next scheduled week
1201 if (!weekday ) 1204 if (!weekday )
1202 weekday = getFirstDayInWeek(rWeekStart) + rFreq*7; 1205 weekday = getFirstDayInWeek(rWeekStart) + rFreq*7;
1203 nextDate = start.addDays(weeksAhead*7 + weekday - 1); 1206 nextDate = start.addDays(weeksAhead*7 + weekday - 1);
1204 break; 1207 break;
1205 } 1208 }
1206 case rMonthlyDay: 1209 case rMonthlyDay:
1207 case rMonthlyPos: { 1210 case rMonthlyPos: {
1208 int startYear = dStart.year(); 1211 int startYear = dStart.year();
@@ -1504,97 +1507,97 @@ int Recurrence::recurCalc(PeriodFunc func, QDate &enddate) const
1504 if (rDuration == 0 && enddate >= rEndDateTime.date()) { 1507 if (rDuration == 0 && enddate >= rEndDateTime.date()) {
1505 enddate = QDate(); 1508 enddate = QDate();
1506 return 0; 1509 return 0;
1507 } 1510 }
1508 break; 1511 break;
1509 default: 1512 default:
1510 enddate = QDate(); 1513 enddate = QDate();
1511 return 0; 1514 return 0;
1512 } 1515 }
1513 1516
1514 int count = 0; // default = error 1517 int count = 0; // default = error
1515 bool timed = false; 1518 bool timed = false;
1516 switch (recurs) { 1519 switch (recurs) {
1517 case rMinutely: 1520 case rMinutely:
1518 timed = true; 1521 timed = true;
1519 count = secondlyCalc(func, endtime, rFreq*60); 1522 count = secondlyCalc(func, endtime, rFreq*60);
1520 break; 1523 break;
1521 case rHourly: 1524 case rHourly:
1522 timed = true; 1525 timed = true;
1523 count = secondlyCalc(func, endtime, rFreq*3600); 1526 count = secondlyCalc(func, endtime, rFreq*3600);
1524 break; 1527 break;
1525 case rDaily: 1528 case rDaily:
1526 count = dailyCalc(func, enddate); 1529 count = dailyCalc(func, enddate);
1527 break; 1530 break;
1528 case rWeekly: 1531 case rWeekly:
1529 count = weeklyCalc(func, enddate); 1532 count = weeklyCalc(func, enddate);
1530 break; 1533 break;
1531 case rMonthlyPos: 1534 case rMonthlyPos:
1532 case rMonthlyDay: 1535 case rMonthlyDay:
1533 count = monthlyCalc(func, enddate); 1536 count = monthlyCalc(func, enddate);
1534 break; 1537 break;
1535 case rYearlyMonth: 1538 case rYearlyMonth:
1536 count = yearlyMonthCalc(func, enddate); 1539 count = yearlyMonthCalc(func, enddate);
1537 break; 1540 break;
1538 case rYearlyPos: 1541 case rYearlyPos:
1539 count = yearlyPosCalc(func, enddate); 1542 count = yearlyPosCalc(func, enddate);
1540 break; 1543 break;
1541 case rYearlyDay: 1544 case rYearlyDay:
1542 count = yearlyDayCalc(func, enddate); 1545 count = yearlyDayCalc(func, enddate);
1543 break; 1546 break;
1544 default: 1547 default:
1545 break; 1548 break;
1546 } 1549 }
1547 1550
1548 switch (func) { 1551 switch (func) {
1549 case END_DATE_AND_COUNT: 1552 case END_DATE_AND_COUNT:
1550 case NEXT_AFTER_DATE: 1553 case NEXT_AFTER_DATE:
1551 if (count == 0) 1554 if (count == 0)
1552 endtime = QDate(); 1555 endtime = QDateTime();
1553 else if (timed) 1556 else if (timed)
1554 enddate = endtime.date(); 1557 enddate = endtime.date();
1555 break; 1558 break;
1556 case COUNT_TO_DATE: 1559 case COUNT_TO_DATE:
1557 break; 1560 break;
1558 } 1561 }
1559 return count; 1562 return count;
1560} 1563}
1561 1564
1562/* Find count and, depending on 'func', the end date/time of a secondly recurrence. 1565/* Find count and, depending on 'func', the end date/time of a secondly recurrence.
1563 * Reply = total number of occurrences up to 'endtime', or 0 if error. 1566 * Reply = total number of occurrences up to 'endtime', or 0 if error.
1564 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'endtime' is updated to the 1567 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'endtime' is updated to the
1565 * recurrence end date/time. 1568 * recurrence end date/time.
1566 */ 1569 */
1567int Recurrence::secondlyCalc(PeriodFunc func, QDateTime &endtime, int freq) const 1570int Recurrence::secondlyCalc(PeriodFunc func, QDateTime &endtime, int freq) const
1568{ 1571{
1569 switch (func) { 1572 switch (func) {
1570 case END_DATE_AND_COUNT: 1573 case END_DATE_AND_COUNT:
1571 endtime = mRecurStart.addSecs((rDuration + mRecurExDatesCount - 1) * freq); 1574 endtime = mRecurStart.addSecs((rDuration + mRecurExDatesCount - 1) * freq);
1572 return rDuration + mRecurExDatesCount; 1575 return rDuration + mRecurExDatesCount;
1573 case COUNT_TO_DATE: { 1576 case COUNT_TO_DATE: {
1574 int n = mRecurStart.secsTo(endtime)/freq + 1; 1577 int n = mRecurStart.secsTo(endtime)/freq + 1;
1575 if (rDuration > 0 && n > rDuration + mRecurExDatesCount) 1578 if (rDuration > 0 && n > rDuration + mRecurExDatesCount)
1576 return rDuration + mRecurExDatesCount; 1579 return rDuration + mRecurExDatesCount;
1577 return n; 1580 return n;
1578 } 1581 }
1579 case NEXT_AFTER_DATE: { 1582 case NEXT_AFTER_DATE: {
1580 int count = mRecurStart.secsTo(endtime) / freq + 2; 1583 int count = mRecurStart.secsTo(endtime) / freq + 2;
1581 if (rDuration > 0 && count > rDuration) 1584 if (rDuration > 0 && count > rDuration)
1582 return 0; 1585 return 0;
1583 endtime = mRecurStart.addSecs((count - 1)*freq); 1586 endtime = mRecurStart.addSecs((count - 1)*freq);
1584 return count; 1587 return count;
1585 } 1588 }
1586 } 1589 }
1587 return 0; 1590 return 0;
1588} 1591}
1589 1592
1590/* Find count and, depending on 'func', the end date of a daily recurrence. 1593/* Find count and, depending on 'func', the end date of a daily recurrence.
1591 * Reply = total number of occurrences up to 'enddate', or 0 if error. 1594 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1592 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 1595 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1593 * recurrence end date. 1596 * recurrence end date.
1594 */ 1597 */
1595int Recurrence::dailyCalc(PeriodFunc func, QDate &enddate) const 1598int Recurrence::dailyCalc(PeriodFunc func, QDate &enddate) const
1596{ 1599{
1597 QDate dStart = mRecurStart.date(); 1600 QDate dStart = mRecurStart.date();
1598 switch (func) { 1601 switch (func) {
1599 case END_DATE_AND_COUNT: 1602 case END_DATE_AND_COUNT:
1600 enddate = dStart.addDays((rDuration + mRecurExDatesCount - 1) * rFreq); 1603 enddate = dStart.addDays((rDuration + mRecurExDatesCount - 1) * rFreq);
@@ -1748,393 +1751,393 @@ int Recurrence::weeklyCalcNextAfter(QDate &enddate, int daysPerWeek) const
1748 return 0; 1751 return 0;
1749 } 1752 }
1750 } 1753 }
1751 daysGone += 7 * (rFreq - 1); 1754 daysGone += 7 * (rFreq - 1);
1752 } 1755 }
1753 1756
1754 // Skip the remaining whole weeks 1757 // Skip the remaining whole weeks
1755 recurWeeks = (totalDays - daysGone) / (7 * rFreq); 1758 recurWeeks = (totalDays - daysGone) / (7 * rFreq);
1756 if (recurWeeks) { 1759 if (recurWeeks) {
1757 int n = recurWeeks * daysPerWeek; 1760 int n = recurWeeks * daysPerWeek;
1758 if (static_cast<uint>(n) > countTogo) 1761 if (static_cast<uint>(n) > countTogo)
1759 return 0; // reached end of recurrence 1762 return 0; // reached end of recurrence
1760 countGone += n; 1763 countGone += n;
1761 countTogo -= n; 1764 countTogo -= n;
1762 daysGone += recurWeeks * 7 * rFreq; 1765 daysGone += recurWeeks * 7 * rFreq;
1763 } 1766 }
1764 1767
1765 // Check the last week or two in the recurrence 1768 // Check the last week or two in the recurrence
1766 for ( ; ; ) { 1769 for ( ; ; ) {
1767 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) { 1770 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
1768 ++daysGone; 1771 ++daysGone;
1769 if (rDays.testBit((uint)i)) { 1772 if (rDays.testBit((uint)i)) {
1770 ++countGone; 1773 ++countGone;
1771 if (daysGone > totalDays) 1774 if (daysGone > totalDays)
1772 goto ex; 1775 goto ex;
1773 if (--countTogo == 0) 1776 if (--countTogo == 0)
1774 return 0; 1777 return 0;
1775 } 1778 }
1776 } 1779 }
1777 daysGone += 7 * (rFreq - 1); 1780 daysGone += 7 * (rFreq - 1);
1778 } 1781 }
1779ex: 1782ex:
1780 enddate = dStart.addDays(daysGone); 1783 enddate = dStart.addDays(daysGone);
1781 return countGone; 1784 return countGone;
1782} 1785}
1783 1786
1784/* Find count and, depending on 'func', the end date of a monthly recurrence. 1787/* Find count and, depending on 'func', the end date of a monthly recurrence.
1785 * Reply = total number of occurrences up to 'enddate', or 0 if error. 1788 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1786 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 1789 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1787 * recurrence end date. 1790 * recurrence end date.
1788 */ 1791 */
1789struct Recurrence::MonthlyData { 1792struct Recurrence::MonthlyData {
1790 const Recurrence *recurrence; 1793 const Recurrence *recurrence;
1791 int year; // current year 1794 int year; // current year
1792 int month; // current month 0..11 1795 int month; // current month 0..11
1793 int day; // current day of month 1..31 1796 int day; // current day of month 1..31
1794 bool varies; // true if recurring days vary between different months 1797 bool varies; // true if recurring days vary between different months
1795 private: 1798 private:
1796 QValueList<int> days28, days29, days30, days31; // recurring days in months of each length 1799 Q3ValueList<int> days28, days29, days30, days31; // recurring days in months of each length
1797 QValueList<int> *recurDays[4]; 1800 Q3ValueList<int> *recurDays[4];
1798 public: 1801 public:
1799 MonthlyData(const Recurrence* r, const QDate &date) 1802 MonthlyData(const Recurrence* r, const QDate &date)
1800 : recurrence(r), year(date.year()), month(date.month()-1), day(date.day()) 1803 : recurrence(r), year(date.year()), month(date.month()-1), day(date.day())
1801 { recurDays[0] = &days28; 1804 { recurDays[0] = &days28;
1802 recurDays[1] = &days29; 1805 recurDays[1] = &days29;
1803 recurDays[2] = &days30; 1806 recurDays[2] = &days30;
1804 recurDays[3] = &days31; 1807 recurDays[3] = &days31;
1805 varies = (recurrence->recurs == rMonthlyPos) 1808 varies = (recurrence->recurs == rMonthlyPos)
1806 ? true : recurrence->getMonthlyDayDays(days31, 31); 1809 ? true : recurrence->getMonthlyDayDays(days31, 31);
1807 } 1810 }
1808 const QValueList<int>* dayList() const { 1811 const Q3ValueList<int>* dayList() const {
1809 if (!varies) 1812 if (!varies)
1810 return &days31; 1813 return &days31;
1811 QDate startOfMonth(year, month + 1, 1); 1814 QDate startOfMonth(year, month + 1, 1);
1812 int daysInMonth = startOfMonth.daysInMonth(); 1815 int daysInMonth = startOfMonth.daysInMonth();
1813 QValueList<int>* days = recurDays[daysInMonth - 28]; 1816 Q3ValueList<int>* days = recurDays[daysInMonth - 28];
1814 if (recurrence->recurs == rMonthlyPos) 1817 if (recurrence->recurs == rMonthlyPos)
1815 recurrence->getMonthlyPosDays(*days, daysInMonth, startOfMonth.dayOfWeek()); 1818 recurrence->getMonthlyPosDays(*days, daysInMonth, startOfMonth.dayOfWeek());
1816 else if (days->isEmpty()) 1819 else if (days->isEmpty())
1817 recurrence->getMonthlyDayDays(*days, daysInMonth); 1820 recurrence->getMonthlyDayDays(*days, daysInMonth);
1818 return days; 1821 return days;
1819 } 1822 }
1820 int yearMonth() const { return year*12 + month; } 1823 int yearMonth() const { return year*12 + month; }
1821 void addMonths(int diff) { month += diff; year += month / 12; month %= 12; } 1824 void addMonths(int diff) { month += diff; year += month / 12; month %= 12; }
1822 QDate date() const { return QDate(year, month + 1, day); } 1825 QDate date() const { return QDate(year, month + 1, day); }
1823}; 1826};
1824 1827
1825int Recurrence::monthlyCalc(PeriodFunc func, QDate &enddate) const 1828int Recurrence::monthlyCalc(PeriodFunc func, QDate &enddate) const
1826{ 1829{
1827 if (recurs == rMonthlyPos && rMonthPositions.isEmpty() 1830 if (recurs == rMonthlyPos && rMonthPositions.isEmpty()
1828 || recurs == rMonthlyDay && rMonthDays.isEmpty()) 1831 || recurs == rMonthlyDay && rMonthDays.isEmpty())
1829 return 0; 1832 return 0;
1830 1833
1831 MonthlyData data(this, mRecurStart.date()); 1834 MonthlyData data(this, mRecurStart.date());
1832 switch (func) { 1835 switch (func) {
1833 case END_DATE_AND_COUNT: 1836 case END_DATE_AND_COUNT:
1834 return monthlyCalcEndDate(enddate, data); 1837 return monthlyCalcEndDate(enddate, data);
1835 case COUNT_TO_DATE: 1838 case COUNT_TO_DATE:
1836 return monthlyCalcToDate(enddate, data); 1839 return monthlyCalcToDate(enddate, data);
1837 case NEXT_AFTER_DATE: 1840 case NEXT_AFTER_DATE:
1838 return monthlyCalcNextAfter(enddate, data); 1841 return monthlyCalcNextAfter(enddate, data);
1839 } 1842 }
1840 return 0; 1843 return 0;
1841} 1844}
1842 1845
1843int Recurrence::monthlyCalcEndDate(QDate &enddate, MonthlyData &data) const 1846int Recurrence::monthlyCalcEndDate(QDate &enddate, MonthlyData &data) const
1844{ 1847{
1845 uint countTogo = rDuration + mRecurExDatesCount; 1848 uint countTogo = rDuration + mRecurExDatesCount;
1846 int countGone = 0; 1849 int countGone = 0;
1847 QValueList<int>::ConstIterator it; 1850 Q3ValueList<int>::ConstIterator it;
1848 const QValueList<int>* days = data.dayList(); 1851 const Q3ValueList<int>* days = data.dayList();
1849 1852
1850 if (data.day > 1) { 1853 if (data.day > 1) {
1851 // Check what remains of the start month 1854 // Check what remains of the start month
1852 for (it = days->begin(); it != days->end(); ++it) { 1855 for (it = days->begin(); it != days->end(); ++it) {
1853 if (*it >= data.day) { 1856 if (*it >= data.day) {
1854 ++countGone; 1857 ++countGone;
1855 if (--countTogo == 0) { 1858 if (--countTogo == 0) {
1856 data.day = *it; 1859 data.day = *it;
1857 break; 1860 break;
1858 } 1861 }
1859 } 1862 }
1860 } 1863 }
1861 if (countTogo) { 1864 if (countTogo) {
1862 data.day = 1; 1865 data.day = 1;
1863 data.addMonths(rFreq); 1866 data.addMonths(rFreq);
1864 } 1867 }
1865 } 1868 }
1866 if (countTogo) { 1869 if (countTogo) {
1867 if (data.varies) { 1870 if (data.varies) {
1868 // The number of recurrence days varies from month to month, 1871 // The number of recurrence days varies from month to month,
1869 // so we need to check month by month. 1872 // so we need to check month by month.
1870 for ( ; ; ) { 1873 for ( ; ; ) {
1871 days = data.dayList(); 1874 days = data.dayList();
1872 uint n = days->count(); // number of recurrence days in this month 1875 uint n = days->count(); // number of recurrence days in this month
1873 if (n >= countTogo) 1876 if (n >= countTogo)
1874 break; 1877 break;
1875 countTogo -= n; 1878 countTogo -= n;
1876 countGone += n; 1879 countGone += n;
1877 data.addMonths(rFreq); 1880 data.addMonths(rFreq);
1878 } 1881 }
1879 } else { 1882 } else {
1880 // The number of recurrences is the same every month, 1883 // The number of recurrences is the same every month,
1881 // so skip the month-by-month check. 1884 // so skip the month-by-month check.
1882 // Skip the remaining whole months, but leave at least 1885 // Skip the remaining whole months, but leave at least
1883 // 1 recurrence remaining, in order to get its date. 1886 // 1 recurrence remaining, in order to get its date.
1884 int daysPerMonth = days->count(); 1887 int daysPerMonth = days->count();
1885 int wholeMonths = (countTogo - 1) / daysPerMonth; 1888 int wholeMonths = (countTogo - 1) / daysPerMonth;
1886 data.addMonths(wholeMonths * rFreq); 1889 data.addMonths(wholeMonths * rFreq);
1887 countGone += wholeMonths * daysPerMonth; 1890 countGone += wholeMonths * daysPerMonth;
1888 countTogo -= wholeMonths * daysPerMonth; 1891 countTogo -= wholeMonths * daysPerMonth;
1889 } 1892 }
1890 if (countTogo) { 1893 if (countTogo) {
1891 // Check the last month in the recurrence 1894 // Check the last month in the recurrence
1892 for (it = days->begin(); it != days->end(); ++it) { 1895 for (it = days->begin(); it != days->end(); ++it) {
1893 ++countGone; 1896 ++countGone;
1894 if (--countTogo == 0) { 1897 if (--countTogo == 0) {
1895 data.day = *it; 1898 data.day = *it;
1896 break; 1899 break;
1897 } 1900 }
1898 } 1901 }
1899 } 1902 }
1900 } 1903 }
1901 enddate = data.date(); 1904 enddate = data.date();
1902 return countGone; 1905 return countGone;
1903} 1906}
1904 1907
1905int Recurrence::monthlyCalcToDate(const QDate &enddate, MonthlyData &data) const 1908int Recurrence::monthlyCalcToDate(const QDate &enddate, MonthlyData &data) const
1906{ 1909{
1907 int countGone = 0; 1910 int countGone = 0;
1908 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 1911 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
1909 int endYear = enddate.year(); 1912 int endYear = enddate.year();
1910 int endMonth = enddate.month() - 1; // zero-based 1913 int endMonth = enddate.month() - 1; // zero-based
1911 int endDay = enddate.day(); 1914 int endDay = enddate.day();
1912 int endYearMonth = endYear*12 + endMonth; 1915 int endYearMonth = endYear*12 + endMonth;
1913 QValueList<int>::ConstIterator it; 1916 Q3ValueList<int>::ConstIterator it;
1914 const QValueList<int>* days = data.dayList(); 1917 const Q3ValueList<int>* days = data.dayList();
1915 1918
1916 if (data.day > 1) { 1919 if (data.day > 1) {
1917 // Check what remains of the start month 1920 // Check what remains of the start month
1918 for (it = days->begin(); it != days->end(); ++it) { 1921 for (it = days->begin(); it != days->end(); ++it) {
1919 if (*it >= data.day) { 1922 if (*it >= data.day) {
1920 if (data.yearMonth() == endYearMonth && *it > endDay) 1923 if (data.yearMonth() == endYearMonth && *it > endDay)
1921 return countGone; 1924 return countGone;
1922 if (++countGone >= countMax) 1925 if (++countGone >= countMax)
1923 return countMax; 1926 return countMax;
1924 } 1927 }
1925 } 1928 }
1926 data.day = 1; 1929 data.day = 1;
1927 data.addMonths(rFreq); 1930 data.addMonths(rFreq);
1928 } 1931 }
1929 1932
1930 if (data.varies) { 1933 if (data.varies) {
1931 // The number of recurrence days varies from month to month, 1934 // The number of recurrence days varies from month to month,
1932 // so we need to check month by month. 1935 // so we need to check month by month.
1933 while (data.yearMonth() < endYearMonth) { 1936 while (data.yearMonth() < endYearMonth) {
1934 countGone += data.dayList()->count(); 1937 countGone += data.dayList()->count();
1935 if (countGone >= countMax) 1938 if (countGone >= countMax)
1936 return countMax; 1939 return countMax;
1937 data.addMonths(rFreq); 1940 data.addMonths(rFreq);
1938 } 1941 }
1939 days = data.dayList(); 1942 days = data.dayList();
1940 } else { 1943 } else {
1941 // The number of recurrences is the same every month, 1944 // The number of recurrences is the same every month,
1942 // so skip the month-by-month check. 1945 // so skip the month-by-month check.
1943 // Skip the remaining whole months. 1946 // Skip the remaining whole months.
1944 int daysPerMonth = days->count(); 1947 int daysPerMonth = days->count();
1945 int wholeMonths = endYearMonth - data.yearMonth(); 1948 int wholeMonths = endYearMonth - data.yearMonth();
1946 countGone += (wholeMonths / rFreq) * daysPerMonth; 1949 countGone += (wholeMonths / rFreq) * daysPerMonth;
1947 if (countGone >= countMax) 1950 if (countGone >= countMax)
1948 return countMax; 1951 return countMax;
1949 if (wholeMonths % rFreq) 1952 if (wholeMonths % rFreq)
1950 return countGone; // end year isn't a recurrence year 1953 return countGone; // end year isn't a recurrence year
1951 data.year = endYear; 1954 data.year = endYear;
1952 data.month = endMonth; 1955 data.month = endMonth;
1953 } 1956 }
1954 1957
1955 // Check the last month in the recurrence 1958 // Check the last month in the recurrence
1956 for (it = days->begin(); it != days->end(); ++it) { 1959 for (it = days->begin(); it != days->end(); ++it) {
1957 if (*it > endDay) 1960 if (*it > endDay)
1958 return countGone; 1961 return countGone;
1959 if (++countGone >= countMax) 1962 if (++countGone >= countMax)
1960 return countMax; 1963 return countMax;
1961 } 1964 }
1962 return countGone; 1965 return countGone;
1963} 1966}
1964 1967
1965int Recurrence::monthlyCalcNextAfter(QDate &enddate, MonthlyData &data) const 1968int Recurrence::monthlyCalcNextAfter(QDate &enddate, MonthlyData &data) const
1966{ 1969{
1967 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 1970 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
1968 int countGone = 0; 1971 int countGone = 0;
1969 int endYear = enddate.year(); 1972 int endYear = enddate.year();
1970 int endDay = enddate.day(); 1973 int endDay = enddate.day();
1971 int endYearMonth = endYear*12 + enddate.month() - 1; 1974 int endYearMonth = endYear*12 + enddate.month() - 1;
1972 QValueList<int>::ConstIterator it; 1975 Q3ValueList<int>::ConstIterator it;
1973 const QValueList<int>* days = data.dayList(); 1976 const Q3ValueList<int>* days = data.dayList();
1974 1977
1975 if (data.day > 1) { 1978 if (data.day > 1) {
1976 // Check what remains of the start month 1979 // Check what remains of the start month
1977 for (it = days->begin(); it != days->end(); ++it) { 1980 for (it = days->begin(); it != days->end(); ++it) {
1978 if (*it >= data.day) { 1981 if (*it >= data.day) {
1979 ++countGone; 1982 ++countGone;
1980 if (data.yearMonth() == endYearMonth && *it > endDay) { 1983 if (data.yearMonth() == endYearMonth && *it > endDay) {
1981 data.day = *it; 1984 data.day = *it;
1982 goto ex; 1985 goto ex;
1983 } 1986 }
1984 if (--countTogo == 0) 1987 if (--countTogo == 0)
1985 return 0; 1988 return 0;
1986 } 1989 }
1987 } 1990 }
1988 data.day = 1; 1991 data.day = 1;
1989 data.addMonths(rFreq); 1992 data.addMonths(rFreq);
1990 } 1993 }
1991 1994
1992 if (data.varies) { 1995 if (data.varies) {
1993 // The number of recurrence days varies from month to month, 1996 // The number of recurrence days varies from month to month,
1994 // so we need to check month by month. 1997 // so we need to check month by month.
1995 while (data.yearMonth() <= endYearMonth) { 1998 while (data.yearMonth() <= endYearMonth) {
1996 days = data.dayList(); 1999 days = data.dayList();
1997 uint n = days->count(); // number of recurrence days in this month 2000 uint n = days->count(); // number of recurrence days in this month
1998 if (data.yearMonth() == endYearMonth && days->last() > endDay) 2001 if (data.yearMonth() == endYearMonth && days->last() > endDay)
1999 break; 2002 break;
2000 if (n >= countTogo) 2003 if (n >= countTogo)
2001 return 0; 2004 return 0;
2002 countGone += n; 2005 countGone += n;
2003 countTogo -= n; 2006 countTogo -= n;
2004 data.addMonths(rFreq); 2007 data.addMonths(rFreq);
2005 } 2008 }
2006 days = data.dayList(); 2009 days = data.dayList();
2007 } else { 2010 } else {
2008 // The number of recurrences is the same every month, 2011 // The number of recurrences is the same every month,
2009 // so skip the month-by-month check. 2012 // so skip the month-by-month check.
2010 // Skip the remaining whole months to at least end year/month. 2013 // Skip the remaining whole months to at least end year/month.
2011 int daysPerMonth = days->count(); 2014 int daysPerMonth = days->count();
2012 int elapsed = endYearMonth - data.yearMonth(); 2015 int elapsed = endYearMonth - data.yearMonth();
2013 int recurMonths = (elapsed + rFreq - 1) / rFreq; 2016 int recurMonths = (elapsed + rFreq - 1) / rFreq;
2014 if (elapsed % rFreq == 0 && days->last() <= endDay) 2017 if (elapsed % rFreq == 0 && days->last() <= endDay)
2015 ++recurMonths; // required month is after endYearMonth 2018 ++recurMonths; // required month is after endYearMonth
2016 if (recurMonths) { 2019 if (recurMonths) {
2017 int n = recurMonths * daysPerMonth; 2020 int n = recurMonths * daysPerMonth;
2018 if (static_cast<uint>(n) > countTogo) 2021 if (static_cast<uint>(n) > countTogo)
2019 return 0; // reached end of recurrence 2022 return 0; // reached end of recurrence
2020 countTogo -= n; 2023 countTogo -= n;
2021 countGone += n; 2024 countGone += n;
2022 data.addMonths(recurMonths * rFreq); 2025 data.addMonths(recurMonths * rFreq);
2023 } 2026 }
2024 } 2027 }
2025 2028
2026 // Check the last month in the recurrence 2029 // Check the last month in the recurrence
2027 for (it = days->begin(); it != days->end(); ++it) { 2030 for (it = days->begin(); it != days->end(); ++it) {
2028 ++countGone; 2031 ++countGone;
2029 if (data.yearMonth() > endYearMonth || *it > endDay) { 2032 if (data.yearMonth() > endYearMonth || *it > endDay) {
2030 data.day = *it; 2033 data.day = *it;
2031 break; 2034 break;
2032 } 2035 }
2033 if (--countTogo == 0) 2036 if (--countTogo == 0)
2034 return 0; 2037 return 0;
2035 } 2038 }
2036ex: 2039ex:
2037 enddate = data.date(); 2040 enddate = data.date();
2038 return countGone; 2041 return countGone;
2039} 2042}
2040 2043
2041 2044
2042/* Find count and, depending on 'func', the end date of an annual recurrence by date. 2045/* Find count and, depending on 'func', the end date of an annual recurrence by date.
2043 * Reply = total number of occurrences up to 'enddate', or 0 if error. 2046 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2044 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 2047 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2045 * recurrence end date. 2048 * recurrence end date.
2046 */ 2049 */
2047struct Recurrence::YearlyMonthData { 2050struct Recurrence::YearlyMonthData {
2048 const Recurrence *recurrence; 2051 const Recurrence *recurrence;
2049 int year; // current year 2052 int year; // current year
2050 int month; // current month 1..12 2053 int month; // current month 1..12
2051 int day; // current day of month 1..31 2054 int day; // current day of month 1..31
2052 bool leapyear; // true if February 29th recurs and current year is a leap year 2055 bool leapyear; // true if February 29th recurs and current year is a leap year
2053 bool feb29; // true if February 29th recurs 2056 bool feb29; // true if February 29th recurs
2054 private: 2057 private:
2055 QValueList<int> months; // recurring months in non-leap years 1..12 2058 Q3ValueList<int> months; // recurring months in non-leap years 1..12
2056 QValueList<int> leapMonths; // recurring months in leap years 1..12 2059 Q3ValueList<int> leapMonths; // recurring months in leap years 1..12
2057 public: 2060 public:
2058 YearlyMonthData(const Recurrence* r, const QDate &date) 2061 YearlyMonthData(const Recurrence* r, const QDate &date)
2059 : recurrence(r), year(date.year()), month(date.month()), day(date.day()) 2062 : recurrence(r), year(date.year()), month(date.month()), day(date.day())
2060 { feb29 = recurrence->getYearlyMonthMonths(day, months, leapMonths); 2063 { feb29 = recurrence->getYearlyMonthMonths(day, months, leapMonths);
2061 leapyear = feb29 && QDate::leapYear(year); 2064 leapyear = feb29 && QDate::leapYear(year);
2062 } 2065 }
2063 const QValueList<int>* monthList() const 2066 const Q3ValueList<int>* monthList() const
2064 { return leapyear ? &leapMonths : &months; } 2067 { return leapyear ? &leapMonths : &months; }
2065 const QValueList<int>* leapMonthList() const { return &leapMonths; } 2068 const Q3ValueList<int>* leapMonthList() const { return &leapMonths; }
2066 QDate date() const { return QDate(year, month, day); } 2069 QDate date() const { return QDate(year, month, day); }
2067}; 2070};
2068 2071
2069int Recurrence::yearlyMonthCalc(PeriodFunc func, QDate &enddate) const 2072int Recurrence::yearlyMonthCalc(PeriodFunc func, QDate &enddate) const
2070{ 2073{
2071 if (rYearNums.isEmpty()) 2074 if (rYearNums.isEmpty())
2072 return 0; 2075 return 0;
2073 YearlyMonthData data(this, mRecurStart.date()); 2076 YearlyMonthData data(this, mRecurStart.date());
2074 switch (func) { 2077 switch (func) {
2075 case END_DATE_AND_COUNT: 2078 case END_DATE_AND_COUNT:
2076 return yearlyMonthCalcEndDate(enddate, data); 2079 return yearlyMonthCalcEndDate(enddate, data);
2077 case COUNT_TO_DATE: 2080 case COUNT_TO_DATE:
2078 return yearlyMonthCalcToDate(enddate, data); 2081 return yearlyMonthCalcToDate(enddate, data);
2079 case NEXT_AFTER_DATE: 2082 case NEXT_AFTER_DATE:
2080 return yearlyMonthCalcNextAfter(enddate, data); 2083 return yearlyMonthCalcNextAfter(enddate, data);
2081 } 2084 }
2082 return 0; 2085 return 0;
2083} 2086}
2084 2087
2085// Find total count and end date of an annual recurrence by date. 2088// Find total count and end date of an annual recurrence by date.
2086// Reply = total number of occurrences. 2089// Reply = total number of occurrences.
2087int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) const 2090int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) const
2088{ 2091{
2089 uint countTogo = rDuration + mRecurExDatesCount; 2092 uint countTogo = rDuration + mRecurExDatesCount;
2090 int countGone = 0; 2093 int countGone = 0;
2091 QValueList<int>::ConstIterator it; 2094 Q3ValueList<int>::ConstIterator it;
2092 const QValueList<int>* mons = data.monthList(); // get recurring months for this year 2095 const Q3ValueList<int>* mons = data.monthList(); // get recurring months for this year
2093 2096
2094 if (data.month > 1) { 2097 if (data.month > 1) {
2095 // Check what remains of the start year 2098 // Check what remains of the start year
2096 for (it = mons->begin(); it != mons->end(); ++it) { 2099 for (it = mons->begin(); it != mons->end(); ++it) {
2097 if (*it >= data.month) { 2100 if (*it >= data.month) {
2098 ++countGone; 2101 ++countGone;
2099 if (--countTogo == 0) { 2102 if (--countTogo == 0) {
2100 data.month = *it; 2103 data.month = *it;
2101 if (data.month == 2 && data.feb29 && !data.leapyear) { 2104 if (data.month == 2 && data.feb29 && !data.leapyear) {
2102 // The recurrence should end on February 29th, but it's a non-leap year 2105 // The recurrence should end on February 29th, but it's a non-leap year
2103 switch (mFeb29YearlyType) { 2106 switch (mFeb29YearlyType) {
2104 case rFeb28: 2107 case rFeb28:
2105 data.day = 28; 2108 data.day = 28;
2106 break; 2109 break;
2107 case rMar1: 2110 case rMar1:
2108 data.month = 3; 2111 data.month = 3;
2109 data.day = 1; 2112 data.day = 1;
2110 break; 2113 break;
2111 case rFeb29: 2114 case rFeb29:
2112 break; 2115 break;
2113 } 2116 }
2114 } 2117 }
2115 break; 2118 break;
2116 } 2119 }
2117 } 2120 }
2118 } 2121 }
2119 if (countTogo) { 2122 if (countTogo) {
2120 data.month = 1; 2123 data.month = 1;
2121 data.year += rFreq; 2124 data.year += rFreq;
2122 } 2125 }
2123 } 2126 }
2124 if (countTogo) { 2127 if (countTogo) {
2125 if (data.feb29 && mFeb29YearlyType == rFeb29) { 2128 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2126 // The number of recurrences is different on leap years, 2129 // The number of recurrences is different on leap years,
2127 // so check year-by-year. 2130 // so check year-by-year.
2128 for ( ; ; ) { 2131 for ( ; ; ) {
2129 mons = data.monthList(); 2132 mons = data.monthList();
2130 uint n = mons->count(); 2133 uint n = mons->count();
2131 if (n >= countTogo) 2134 if (n >= countTogo)
2132 break; 2135 break;
2133 countTogo -= n; 2136 countTogo -= n;
2134 countGone += n; 2137 countGone += n;
2135 data.year += rFreq; 2138 data.year += rFreq;
2136 } 2139 }
2137 } else { 2140 } else {
2138 // The number of recurrences is the same every year, 2141 // The number of recurrences is the same every year,
2139 // so skip the year-by-year check. 2142 // so skip the year-by-year check.
2140 // Skip the remaining whole years, but leave at least 2143 // Skip the remaining whole years, but leave at least
@@ -2154,169 +2157,169 @@ int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) co
2154 if (data.month == 2 && data.feb29 && !QDate::leapYear(data.year)) { 2157 if (data.month == 2 && data.feb29 && !QDate::leapYear(data.year)) {
2155 // The recurrence should end on February 29th, but it's a non-leap year 2158 // The recurrence should end on February 29th, but it's a non-leap year
2156 switch (mFeb29YearlyType) { 2159 switch (mFeb29YearlyType) {
2157 case rFeb28: 2160 case rFeb28:
2158 data.day = 28; 2161 data.day = 28;
2159 break; 2162 break;
2160 case rMar1: 2163 case rMar1:
2161 data.month = 3; 2164 data.month = 3;
2162 data.day = 1; 2165 data.day = 1;
2163 break; 2166 break;
2164 case rFeb29: 2167 case rFeb29:
2165 break; 2168 break;
2166 } 2169 }
2167 } 2170 }
2168 break; 2171 break;
2169 } 2172 }
2170 } 2173 }
2171 } 2174 }
2172 } 2175 }
2173 enddate = data.date(); 2176 enddate = data.date();
2174 return countGone; 2177 return countGone;
2175} 2178}
2176 2179
2177// Find count of an annual recurrence by date. 2180// Find count of an annual recurrence by date.
2178// Reply = total number of occurrences up to 'enddate'. 2181// Reply = total number of occurrences up to 'enddate'.
2179int Recurrence::yearlyMonthCalcToDate(const QDate &enddate, YearlyMonthData &data) const 2182int Recurrence::yearlyMonthCalcToDate(const QDate &enddate, YearlyMonthData &data) const
2180{ 2183{
2181 int countGone = 0; 2184 int countGone = 0;
2182 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 2185 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2183 int endYear = enddate.year(); 2186 int endYear = enddate.year();
2184 int endMonth = enddate.month(); 2187 int endMonth = enddate.month();
2185 int endDay = enddate.day(); 2188 int endDay = enddate.day();
2186 if (endDay < data.day) { 2189 if (endDay < data.day) {
2187 /* The end day of the month is earlier than the recurrence day of the month. 2190 /* The end day of the month is earlier than the recurrence day of the month.
2188 * If Feb 29th recurs and: 2191 * If Feb 29th recurs and:
2189 * 1) it recurs on Feb 28th in non-leap years, don't adjust the end month 2192 * 1) it recurs on Feb 28th in non-leap years, don't adjust the end month
2190 * if enddate is Feb 28th on a non-leap year. 2193 * if enddate is Feb 28th on a non-leap year.
2191 * 2) it recurs on Mar 1st in non-leap years, allow the end month to be 2194 * 2) it recurs on Mar 1st in non-leap years, allow the end month to be
2192 * adjusted to February, to simplify calculations. 2195 * adjusted to February, to simplify calculations.
2193 */ 2196 */
2194 if (data.feb29 && !QDate::leapYear(endYear) 2197 if (data.feb29 && !QDate::leapYear(endYear)
2195 && mFeb29YearlyType == rFeb28 && endDay == 28 && endMonth == 2) { 2198 && mFeb29YearlyType == rFeb28 && endDay == 28 && endMonth == 2) {
2196 } 2199 }
2197 else if (--endMonth == 0) { 2200 else if (--endMonth == 0) {
2198 endMonth = 12; 2201 endMonth = 12;
2199 --endYear; 2202 --endYear;
2200 } 2203 }
2201 } 2204 }
2202 QValueList<int>::ConstIterator it; 2205 Q3ValueList<int>::ConstIterator it;
2203 const QValueList<int>* mons = data.monthList(); 2206 const Q3ValueList<int>* mons = data.monthList();
2204 2207
2205 if (data.month > 1) { 2208 if (data.month > 1) {
2206 // Check what remains of the start year 2209 // Check what remains of the start year
2207 for (it = mons->begin(); it != mons->end(); ++it) { 2210 for (it = mons->begin(); it != mons->end(); ++it) {
2208 if (*it >= data.month) { 2211 if (*it >= data.month) {
2209 if (data.year == endYear && *it > endMonth) 2212 if (data.year == endYear && *it > endMonth)
2210 return countGone; 2213 return countGone;
2211 if (++countGone >= countMax) 2214 if (++countGone >= countMax)
2212 return countMax; 2215 return countMax;
2213 } 2216 }
2214 } 2217 }
2215 data.month = 1; 2218 data.month = 1;
2216 data.year += rFreq; 2219 data.year += rFreq;
2217 } 2220 }
2218 if (data.feb29 && mFeb29YearlyType == rFeb29) { 2221 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2219 // The number of recurrences is different on leap years, 2222 // The number of recurrences is different on leap years,
2220 // so check year-by-year. 2223 // so check year-by-year.
2221 while (data.year < endYear) { 2224 while (data.year < endYear) {
2222 countGone += data.monthList()->count(); 2225 countGone += data.monthList()->count();
2223 if (countGone >= countMax) 2226 if (countGone >= countMax)
2224 return countMax; 2227 return countMax;
2225 data.year += rFreq; 2228 data.year += rFreq;
2226 } 2229 }
2227 mons = data.monthList(); 2230 mons = data.monthList();
2228 } else { 2231 } else {
2229 // The number of recurrences is the same every year, 2232 // The number of recurrences is the same every year,
2230 // so skip the year-by-year check. 2233 // so skip the year-by-year check.
2231 // Skip the remaining whole years. 2234 // Skip the remaining whole years.
2232 int monthsPerYear = mons->count(); 2235 int monthsPerYear = mons->count();
2233 int wholeYears = endYear - data.year; 2236 int wholeYears = endYear - data.year;
2234 countGone += (wholeYears / rFreq) * monthsPerYear; 2237 countGone += (wholeYears / rFreq) * monthsPerYear;
2235 if (countGone >= countMax) 2238 if (countGone >= countMax)
2236 return countMax; 2239 return countMax;
2237 if (wholeYears % rFreq) 2240 if (wholeYears % rFreq)
2238 return countGone; // end year isn't a recurrence year 2241 return countGone; // end year isn't a recurrence year
2239 data.year = endYear; 2242 data.year = endYear;
2240 } 2243 }
2241 2244
2242 // Check the last year in the recurrence 2245 // Check the last year in the recurrence
2243 for (it = mons->begin(); it != mons->end(); ++it) { 2246 for (it = mons->begin(); it != mons->end(); ++it) {
2244 if (*it > endMonth) 2247 if (*it > endMonth)
2245 return countGone; 2248 return countGone;
2246 if (++countGone >= countMax) 2249 if (++countGone >= countMax)
2247 return countMax; 2250 return countMax;
2248 } 2251 }
2249 return countGone; 2252 return countGone;
2250} 2253}
2251 2254
2252// Find count and date of first recurrence after 'enddate' of an annual recurrence by date. 2255// Find count and date of first recurrence after 'enddate' of an annual recurrence by date.
2253// Reply = total number of occurrences up to 'enddate'. 2256// Reply = total number of occurrences up to 'enddate'.
2254int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data) const 2257int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data) const
2255{ 2258{
2256 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 2259 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2257 int countGone = 0; 2260 int countGone = 0;
2258 int endYear = enddate.year(); 2261 int endYear = enddate.year();
2259 int endMonth = enddate.month(); 2262 int endMonth = enddate.month();
2260 int endDay = enddate.day(); 2263 int endDay = enddate.day();
2261 bool mar1TooEarly = false; 2264 bool mar1TooEarly = false;
2262 bool feb28ok = false; 2265 bool feb28ok = false;
2263 if (endDay < data.day) { 2266 if (endDay < data.day) {
2264 if (data.feb29 && mFeb29YearlyType == rMar1 && endMonth == 3) 2267 if (data.feb29 && mFeb29YearlyType == rMar1 && endMonth == 3)
2265 mar1TooEarly = true; 2268 mar1TooEarly = true;
2266 if (data.feb29 && mFeb29YearlyType == rFeb28 && endMonth == 2 && endDay == 28) 2269 if (data.feb29 && mFeb29YearlyType == rFeb28 && endMonth == 2 && endDay == 28)
2267 feb28ok = true; 2270 feb28ok = true;
2268 else if (--endMonth == 0) { 2271 else if (--endMonth == 0) {
2269 endMonth = 12; 2272 endMonth = 12;
2270 --endYear; 2273 --endYear;
2271 } 2274 }
2272 } 2275 }
2273 QValueList<int>::ConstIterator it; 2276 Q3ValueList<int>::ConstIterator it;
2274 const QValueList<int>* mons = data.monthList(); 2277 const Q3ValueList<int>* mons = data.monthList();
2275 2278
2276 if (data.month > 1) { 2279 if (data.month > 1) {
2277 // Check what remains of the start year 2280 // Check what remains of the start year
2278 for (it = mons->begin(); it != mons->end(); ++it) { 2281 for (it = mons->begin(); it != mons->end(); ++it) {
2279 if (*it >= data.month) { 2282 if (*it >= data.month) {
2280 ++countGone; 2283 ++countGone;
2281 if (data.year == endYear 2284 if (data.year == endYear
2282 && ( *it > endMonth && (*it > 3 || !mar1TooEarly) 2285 && ( *it > endMonth && (*it > 3 || !mar1TooEarly)
2283 || *it == 2 && feb28ok && data.leapyear)) { 2286 || *it == 2 && feb28ok && data.leapyear)) {
2284 if (*it == 2 && data.feb29 && !data.leapyear) { 2287 if (*it == 2 && data.feb29 && !data.leapyear) {
2285 // The next recurrence should be on February 29th, but it's a non-leap year 2288 // The next recurrence should be on February 29th, but it's a non-leap year
2286 switch (mFeb29YearlyType) { 2289 switch (mFeb29YearlyType) {
2287 case rFeb28: 2290 case rFeb28:
2288 data.month = 2; 2291 data.month = 2;
2289 data.day = 28; 2292 data.day = 28;
2290 break; 2293 break;
2291 case rMar1: 2294 case rMar1:
2292 data.month = 3; 2295 data.month = 3;
2293 data.day = 1; 2296 data.day = 1;
2294 break; 2297 break;
2295 case rFeb29: // impossible in this context! 2298 case rFeb29: // impossible in this context!
2296 break; 2299 break;
2297 } 2300 }
2298 } 2301 }
2299 else 2302 else
2300 data.month = *it; 2303 data.month = *it;
2301 goto ex; 2304 goto ex;
2302 } 2305 }
2303 if (--countTogo == 0) 2306 if (--countTogo == 0)
2304 return 0; 2307 return 0;
2305 } 2308 }
2306 } 2309 }
2307 data.month = 1; 2310 data.month = 1;
2308 data.year += rFreq; 2311 data.year += rFreq;
2309 } 2312 }
2310 2313
2311 if (data.feb29 && mFeb29YearlyType == rFeb29) { 2314 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2312 // The number of recurrences is different on leap years, 2315 // The number of recurrences is different on leap years,
2313 // so check year-by-year. 2316 // so check year-by-year.
2314 while (data.year <= endYear) { 2317 while (data.year <= endYear) {
2315 mons = data.monthList(); 2318 mons = data.monthList();
2316 if (data.year == endYear && mons->last() > endMonth) 2319 if (data.year == endYear && mons->last() > endMonth)
2317 break; 2320 break;
2318 uint n = mons->count(); 2321 uint n = mons->count();
2319 if (n >= countTogo) 2322 if (n >= countTogo)
2320 break; 2323 break;
2321 countTogo -= n; 2324 countTogo -= n;
2322 countGone += n; 2325 countGone += n;
@@ -2345,1057 +2348,1057 @@ int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data)
2345 // Check the last year in the recurrence 2348 // Check the last year in the recurrence
2346 for (it = mons->begin(); it != mons->end(); ++it) { 2349 for (it = mons->begin(); it != mons->end(); ++it) {
2347 ++countGone; 2350 ++countGone;
2348 if (data.year > endYear 2351 if (data.year > endYear
2349 || ( *it > endMonth && (*it > 3 || !mar1TooEarly) 2352 || ( *it > endMonth && (*it > 3 || !mar1TooEarly)
2350 || *it == 2 && feb28ok && QDate::leapYear(data.year))) { 2353 || *it == 2 && feb28ok && QDate::leapYear(data.year))) {
2351 if (*it == 2 && data.feb29 && !QDate::leapYear(data.year)) { 2354 if (*it == 2 && data.feb29 && !QDate::leapYear(data.year)) {
2352 // The next recurrence should be on February 29th, but it's a non-leap year 2355 // The next recurrence should be on February 29th, but it's a non-leap year
2353 switch (mFeb29YearlyType) { 2356 switch (mFeb29YearlyType) {
2354 case rFeb28: 2357 case rFeb28:
2355 data.month = 2; 2358 data.month = 2;
2356 data.day = 28; 2359 data.day = 28;
2357 break; 2360 break;
2358 case rMar1: 2361 case rMar1:
2359 data.month = 3; 2362 data.month = 3;
2360 data.day = 1; 2363 data.day = 1;
2361 break; 2364 break;
2362 case rFeb29: // impossible in this context! 2365 case rFeb29: // impossible in this context!
2363 break; 2366 break;
2364 } 2367 }
2365 } 2368 }
2366 else 2369 else
2367 data.month = *it; 2370 data.month = *it;
2368 break; 2371 break;
2369 } 2372 }
2370 if (--countTogo == 0) 2373 if (--countTogo == 0)
2371 return 0; 2374 return 0;
2372 } 2375 }
2373ex: 2376ex:
2374 enddate = data.date(); 2377 enddate = data.date();
2375 return countGone; 2378 return countGone;
2376} 2379}
2377 2380
2378 2381
2379/* Find count and, depending on 'func', the end date of an annual recurrence by date. 2382/* Find count and, depending on 'func', the end date of an annual recurrence by date.
2380 * Reply = total number of occurrences up to 'enddate', or 0 if error. 2383 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2381 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 2384 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2382 * recurrence end date. 2385 * recurrence end date.
2383 */ 2386 */
2384struct Recurrence::YearlyPosData { 2387struct Recurrence::YearlyPosData {
2385 const Recurrence *recurrence; 2388 const Recurrence *recurrence;
2386 int year; // current year 2389 int year; // current year
2387 int month; // current month 1..12 2390 int month; // current month 1..12
2388 int day; // current day of month 1..31 2391 int day; // current day of month 1..31
2389 int daysPerMonth; // number of days which recur each month, or -1 if variable 2392 int daysPerMonth; // number of days which recur each month, or -1 if variable
2390 int count; // number of days which recur each year, or -1 if variable 2393 int count; // number of days which recur each year, or -1 if variable
2391 bool varies; // true if number of days varies from year to year 2394 bool varies; // true if number of days varies from year to year
2392 private: 2395 private:
2393 mutable QValueList<int> days; 2396 mutable Q3ValueList<int> days;
2394 public: 2397 public:
2395 YearlyPosData(const Recurrence* r, const QDate &date) 2398 YearlyPosData(const Recurrence* r, const QDate &date)
2396 : recurrence(r), year(date.year()), month(date.month()), day(date.day()), count(-1) 2399 : recurrence(r), year(date.year()), month(date.month()), day(date.day()), count(-1)
2397 { if ((daysPerMonth = r->countMonthlyPosDays()) > 0) 2400 { if ((daysPerMonth = r->countMonthlyPosDays()) > 0)
2398 count = daysPerMonth * r->rYearNums.count(); 2401 count = daysPerMonth * r->rYearNums.count();
2399 varies = (daysPerMonth < 0); 2402 varies = (daysPerMonth < 0);
2400 } 2403 }
2401 const QValueList<int>* dayList() const { 2404 const Q3ValueList<int>* dayList() const {
2402 QDate startOfMonth(year, month, 1); 2405 QDate startOfMonth(year, month, 1);
2403 recurrence->getMonthlyPosDays(days, startOfMonth.daysInMonth(), startOfMonth.dayOfWeek()); 2406 recurrence->getMonthlyPosDays(days, startOfMonth.daysInMonth(), startOfMonth.dayOfWeek());
2404 return &days; 2407 return &days;
2405 } 2408 }
2406 int yearMonth() const { return year*12 + month - 1; } 2409 int yearMonth() const { return year*12 + month - 1; }
2407 void addMonths(int diff) { month += diff - 1; year += month / 12; month = month % 12 + 1; } 2410 void addMonths(int diff) { month += diff - 1; year += month / 12; month = month % 12 + 1; }
2408 QDate date() const { return QDate(year, month, day); } 2411 QDate date() const { return QDate(year, month, day); }
2409}; 2412};
2410 2413
2411int Recurrence::yearlyPosCalc(PeriodFunc func, QDate &enddate) const 2414int Recurrence::yearlyPosCalc(PeriodFunc func, QDate &enddate) const
2412{ 2415{
2413 if (rYearNums.isEmpty() || rMonthPositions.isEmpty()) 2416 if (rYearNums.isEmpty() || rMonthPositions.isEmpty())
2414 return 0; 2417 return 0;
2415 YearlyPosData data(this, mRecurStart.date()); 2418 YearlyPosData data(this, mRecurStart.date());
2416 switch (func) { 2419 switch (func) {
2417 case END_DATE_AND_COUNT: 2420 case END_DATE_AND_COUNT:
2418 return yearlyPosCalcEndDate(enddate, data); 2421 return yearlyPosCalcEndDate(enddate, data);
2419 case COUNT_TO_DATE: 2422 case COUNT_TO_DATE:
2420 return yearlyPosCalcToDate(enddate, data); 2423 return yearlyPosCalcToDate(enddate, data);
2421 case NEXT_AFTER_DATE: 2424 case NEXT_AFTER_DATE:
2422 return yearlyPosCalcNextAfter(enddate, data); 2425 return yearlyPosCalcNextAfter(enddate, data);
2423 } 2426 }
2424 return 0; 2427 return 0;
2425} 2428}
2426 2429
2427int Recurrence::yearlyPosCalcEndDate(QDate &enddate, YearlyPosData &data) const 2430int Recurrence::yearlyPosCalcEndDate(QDate &enddate, YearlyPosData &data) const
2428{ 2431{
2429 uint countTogo = rDuration + mRecurExDatesCount; 2432 uint countTogo = rDuration + mRecurExDatesCount;
2430 int countGone = 0; 2433 int countGone = 0;
2431 QValueList<int>::ConstIterator id; 2434 Q3ValueList<int>::ConstIterator id;
2432 const QValueList<int>* days; 2435 const Q3ValueList<int>* days;
2433 2436
2434 if (data.month > 1 || data.day > 1) { 2437 if (data.month > 1 || data.day > 1) {
2435 // Check what remains of the start year 2438 // Check what remains of the start year
2436 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2439 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2437 if (*im.current() >= data.month) { 2440 if (*im.current() >= data.month) {
2438 // Check what remains of the start month 2441 // Check what remains of the start month
2439 if (data.day > 1 || data.varies 2442 if (data.day > 1 || data.varies
2440 || static_cast<uint>(data.daysPerMonth) >= countTogo) { 2443 || static_cast<uint>(data.daysPerMonth) >= countTogo) {
2441 data.month = *im.current(); 2444 data.month = *im.current();
2442 days = data.dayList(); 2445 days = data.dayList();
2443 for (id = days->begin(); id != days->end(); ++id) { 2446 for (id = days->begin(); id != days->end(); ++id) {
2444 if (*id >= data.day) { 2447 if (*id >= data.day) {
2445 ++countGone; 2448 ++countGone;
2446 if (--countTogo == 0) { 2449 if (--countTogo == 0) {
2447 data.month = *im.current(); 2450 data.month = *im.current();
2448 data.day = *id; 2451 data.day = *id;
2449 goto ex; 2452 goto ex;
2450 } 2453 }
2451 } 2454 }
2452 } 2455 }
2453 data.day = 1; 2456 data.day = 1;
2454 } else { 2457 } else {
2455 // The number of days per month is constant, so skip 2458 // The number of days per month is constant, so skip
2456 // the whole month. 2459 // the whole month.
2457 countTogo -= data.daysPerMonth; 2460 countTogo -= data.daysPerMonth;
2458 countGone += data.daysPerMonth; 2461 countGone += data.daysPerMonth;
2459 } 2462 }
2460 } 2463 }
2461 } 2464 }
2462 data.month = 1; 2465 data.month = 1;
2463 data.year += rFreq; 2466 data.year += rFreq;
2464 } 2467 }
2465 2468
2466 if (data.varies) { 2469 if (data.varies) {
2467 // The number of recurrences varies from year to year. 2470 // The number of recurrences varies from year to year.
2468 for ( ; ; ) { 2471 for ( ; ; ) {
2469 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2472 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2470 data.month = *im.current(); 2473 data.month = *im.current();
2471 days = data.dayList(); 2474 days = data.dayList();
2472 int n = days->count(); 2475 int n = days->count();
2473 if (static_cast<uint>(n) >= countTogo) { 2476 if (static_cast<uint>(n) >= countTogo) {
2474 // Check the last month in the recurrence 2477 // Check the last month in the recurrence
2475 for (id = days->begin(); id != days->end(); ++id) { 2478 for (id = days->begin(); id != days->end(); ++id) {
2476 ++countGone; 2479 ++countGone;
2477 if (--countTogo == 0) { 2480 if (--countTogo == 0) {
2478 data.day = *id; 2481 data.day = *id;
2479 goto ex; 2482 goto ex;
2480 } 2483 }
2481 } 2484 }
2482 } 2485 }
2483 countTogo -= n; 2486 countTogo -= n;
2484 countGone += n; 2487 countGone += n;
2485 } 2488 }
2486 data.year += rFreq; 2489 data.year += rFreq;
2487 } 2490 }
2488 } else { 2491 } else {
2489 // The number of recurrences is the same every year, 2492 // The number of recurrences is the same every year,
2490 // so skip the year-by-year check. 2493 // so skip the year-by-year check.
2491 // Skip the remaining whole years, but leave at least 2494 // Skip the remaining whole years, but leave at least
2492 // 1 recurrence remaining, in order to get its date. 2495 // 1 recurrence remaining, in order to get its date.
2493 int wholeYears = (countTogo - 1) / data.count; 2496 int wholeYears = (countTogo - 1) / data.count;
2494 data.year += wholeYears * rFreq; 2497 data.year += wholeYears * rFreq;
2495 countGone += wholeYears * data.count; 2498 countGone += wholeYears * data.count;
2496 countTogo -= wholeYears * data.count; 2499 countTogo -= wholeYears * data.count;
2497 2500
2498 // Check the last year in the recurrence. 2501 // Check the last year in the recurrence.
2499 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2502 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2500 if (static_cast<uint>(data.daysPerMonth) >= countTogo) { 2503 if (static_cast<uint>(data.daysPerMonth) >= countTogo) {
2501 // Check the last month in the recurrence 2504 // Check the last month in the recurrence
2502 data.month = *im.current(); 2505 data.month = *im.current();
2503 days = data.dayList(); 2506 days = data.dayList();
2504 for (id = days->begin(); id != days->end(); ++id) { 2507 for (id = days->begin(); id != days->end(); ++id) {
2505 ++countGone; 2508 ++countGone;
2506 if (--countTogo == 0) { 2509 if (--countTogo == 0) {
2507 data.day = *id; 2510 data.day = *id;
2508 goto ex; 2511 goto ex;
2509 } 2512 }
2510 } 2513 }
2511 } 2514 }
2512 countTogo -= data.daysPerMonth; 2515 countTogo -= data.daysPerMonth;
2513 countGone += data.daysPerMonth; 2516 countGone += data.daysPerMonth;
2514 } 2517 }
2515 data.year += rFreq; 2518 data.year += rFreq;
2516 } 2519 }
2517ex: 2520ex:
2518 enddate = data.date(); 2521 enddate = data.date();
2519 return countGone; 2522 return countGone;
2520} 2523}
2521 2524
2522int Recurrence::yearlyPosCalcToDate(const QDate &enddate, YearlyPosData &data) const 2525int Recurrence::yearlyPosCalcToDate(const QDate &enddate, YearlyPosData &data) const
2523{ 2526{
2524 int countGone = 0; 2527 int countGone = 0;
2525 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 2528 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2526 int endYear = enddate.year(); 2529 int endYear = enddate.year();
2527 int endMonth = enddate.month(); 2530 int endMonth = enddate.month();
2528 int endDay = enddate.day(); 2531 int endDay = enddate.day();
2529 if (endDay < data.day && --endMonth == 0) { 2532 if (endDay < data.day && --endMonth == 0) {
2530 endMonth = 12; 2533 endMonth = 12;
2531 --endYear; 2534 --endYear;
2532 } 2535 }
2533 int endYearMonth = endYear*12 + endMonth; 2536 int endYearMonth = endYear*12 + endMonth;
2534 QValueList<int>::ConstIterator id; 2537 Q3ValueList<int>::ConstIterator id;
2535 const QValueList<int>* days; 2538 const Q3ValueList<int>* days;
2536 2539
2537 if (data.month > 1 || data.day > 1) { 2540 if (data.month > 1 || data.day > 1) {
2538 // Check what remains of the start year 2541 // Check what remains of the start year
2539 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2542 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2540 if (*im.current() >= data.month) { 2543 if (*im.current() >= data.month) {
2541 data.month = *im.current(); 2544 data.month = *im.current();
2542 if (data.yearMonth() > endYearMonth) 2545 if (data.yearMonth() > endYearMonth)
2543 return countGone; 2546 return countGone;
2544 // Check what remains of the start month 2547 // Check what remains of the start month
2545 bool lastMonth = (data.yearMonth() == endYearMonth); 2548 bool lastMonth = (data.yearMonth() == endYearMonth);
2546 if (lastMonth || data.day > 1 || data.varies) { 2549 if (lastMonth || data.day > 1 || data.varies) {
2547 days = data.dayList(); 2550 days = data.dayList();
2548 if (lastMonth || data.day > 1) { 2551 if (lastMonth || data.day > 1) {
2549 for (id = days->begin(); id != days->end(); ++id) { 2552 for (id = days->begin(); id != days->end(); ++id) {
2550 if (*id >= data.day) { 2553 if (*id >= data.day) {
2551 if (lastMonth && *id > endDay) 2554 if (lastMonth && *id > endDay)
2552 return countGone; 2555 return countGone;
2553 if (++countGone >= countMax) 2556 if (++countGone >= countMax)
2554 return countMax; 2557 return countMax;
2555 } 2558 }
2556 } 2559 }
2557 } else { 2560 } else {
2558 countGone += days->count(); 2561 countGone += days->count();
2559 if (countGone >= countMax) 2562 if (countGone >= countMax)
2560 return countMax; 2563 return countMax;
2561 } 2564 }
2562 data.day = 1; 2565 data.day = 1;
2563 } else { 2566 } else {
2564 // The number of days per month is constant, so skip 2567 // The number of days per month is constant, so skip
2565 // the whole month. 2568 // the whole month.
2566 countGone += data.daysPerMonth; 2569 countGone += data.daysPerMonth;
2567 if (countGone >= countMax) 2570 if (countGone >= countMax)
2568 return countMax; 2571 return countMax;
2569 } 2572 }
2570 } 2573 }
2571 } 2574 }
2572 data.month = 1; 2575 data.month = 1;
2573 data.year += rFreq; 2576 data.year += rFreq;
2574 } 2577 }
2575 2578
2576 if (data.varies) { 2579 if (data.varies) {
2577 // The number of recurrences varies from year to year. 2580 // The number of recurrences varies from year to year.
2578 for ( ; ; ) { 2581 for ( ; ; ) {
2579 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2582 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2580 data.month = *im.current(); 2583 data.month = *im.current();
2581 days = data.dayList(); 2584 days = data.dayList();
2582 if (data.yearMonth() >= endYearMonth) { 2585 if (data.yearMonth() >= endYearMonth) {
2583 if (data.yearMonth() > endYearMonth) 2586 if (data.yearMonth() > endYearMonth)
2584 return countGone; 2587 return countGone;
2585 // Check the last month in the recurrence 2588 // Check the last month in the recurrence
2586 for (id = days->begin(); id != days->end(); ++id) { 2589 for (id = days->begin(); id != days->end(); ++id) {
2587 if (*id > endDay) 2590 if (*id > endDay)
2588 return countGone; 2591 return countGone;
2589 if (++countGone >= countMax) 2592 if (++countGone >= countMax)
2590 return countMax; 2593 return countMax;
2591 } 2594 }
2592 } else { 2595 } else {
2593 countGone += days->count(); 2596 countGone += days->count();
2594 if (countGone >= countMax) 2597 if (countGone >= countMax)
2595 return countMax; 2598 return countMax;
2596 } 2599 }
2597 } 2600 }
2598 data.year += rFreq; 2601 data.year += rFreq;
2599 } 2602 }
2600 } else { 2603 } else {
2601 // The number of recurrences is the same every year, 2604 // The number of recurrences is the same every year,
2602 // so skip the year-by-year check. 2605 // so skip the year-by-year check.
2603 // Skip the remaining whole years, but leave at least 2606 // Skip the remaining whole years, but leave at least
2604 // 1 recurrence remaining, in order to get its date. 2607 // 1 recurrence remaining, in order to get its date.
2605 int wholeYears = endYear - data.year; 2608 int wholeYears = endYear - data.year;
2606 countGone += (wholeYears / rFreq) * data.count; 2609 countGone += (wholeYears / rFreq) * data.count;
2607 if (countGone >= countMax) 2610 if (countGone >= countMax)
2608 return countMax; 2611 return countMax;
2609 if (wholeYears % rFreq) 2612 if (wholeYears % rFreq)
2610 return countGone; // end year isn't a recurrence year 2613 return countGone; // end year isn't a recurrence year
2611 data.year = endYear; 2614 data.year = endYear;
2612 2615
2613 // Check the last year in the recurrence. 2616 // Check the last year in the recurrence.
2614 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2617 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2615 data.month = *im.current(); 2618 data.month = *im.current();
2616 if (data.month >= endMonth) { 2619 if (data.month >= endMonth) {
2617 if (data.month > endMonth) 2620 if (data.month > endMonth)
2618 return countGone; 2621 return countGone;
2619 // Check the last month in the recurrence 2622 // Check the last month in the recurrence
2620 days = data.dayList(); 2623 days = data.dayList();
2621 for (id = days->begin(); id != days->end(); ++id) { 2624 for (id = days->begin(); id != days->end(); ++id) {
2622 if (*id > endDay) 2625 if (*id > endDay)
2623 return countGone; 2626 return countGone;
2624 if (++countGone >= countMax) 2627 if (++countGone >= countMax)
2625 return countMax; 2628 return countMax;
2626 } 2629 }
2627 } else { 2630 } else {
2628 countGone += data.daysPerMonth; 2631 countGone += data.daysPerMonth;
2629 if (countGone >= countMax) 2632 if (countGone >= countMax)
2630 return countMax; 2633 return countMax;
2631 } 2634 }
2632 } 2635 }
2633 } 2636 }
2634 return countGone; 2637 return countGone;
2635} 2638}
2636 2639
2637int Recurrence::yearlyPosCalcNextAfter(QDate &enddate, YearlyPosData &data) const 2640int Recurrence::yearlyPosCalcNextAfter(QDate &enddate, YearlyPosData &data) const
2638{ 2641{
2639 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 2642 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2640 int countGone = 0; 2643 int countGone = 0;
2641 int endYear = enddate.year(); 2644 int endYear = enddate.year();
2642 int endMonth = enddate.month(); 2645 int endMonth = enddate.month();
2643 int endDay = enddate.day(); 2646 int endDay = enddate.day();
2644 if (endDay < data.day && --endMonth == 0) { 2647 if (endDay < data.day && --endMonth == 0) {
2645 endMonth = 12; 2648 endMonth = 12;
2646 --endYear; 2649 --endYear;
2647 } 2650 }
2648 int endYearMonth = endYear*12 + endMonth; 2651 int endYearMonth = endYear*12 + endMonth;
2649 QValueList<int>::ConstIterator id; 2652 Q3ValueList<int>::ConstIterator id;
2650 const QValueList<int>* days; 2653 const Q3ValueList<int>* days;
2651 2654
2652 if (data.varies) { 2655 if (data.varies) {
2653 // The number of recurrences varies from year to year. 2656 // The number of recurrences varies from year to year.
2654 for ( ; ; ) { 2657 for ( ; ; ) {
2655 // Check the next year 2658 // Check the next year
2656 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2659 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2657 if (*im.current() >= data.month) { 2660 if (*im.current() >= data.month) {
2658 // Check the next month 2661 // Check the next month
2659 data.month = *im.current(); 2662 data.month = *im.current();
2660 int ended = data.yearMonth() - endYearMonth; 2663 int ended = data.yearMonth() - endYearMonth;
2661 days = data.dayList(); 2664 days = data.dayList();
2662 if (ended >= 0 || data.day > 1) { 2665 if (ended >= 0 || data.day > 1) {
2663 // This is the start or end month, so check each day 2666 // This is the start or end month, so check each day
2664 for (id = days->begin(); id != days->end(); ++id) { 2667 for (id = days->begin(); id != days->end(); ++id) {
2665 if (*id >= data.day) { 2668 if (*id >= data.day) {
2666 ++countGone; 2669 ++countGone;
2667 if (ended > 0 || (ended == 0 && *id > endDay)) { 2670 if (ended > 0 || (ended == 0 && *id > endDay)) {
2668 data.day = *id; 2671 data.day = *id;
2669 goto ex; 2672 goto ex;
2670 } 2673 }
2671 if (--countTogo == 0) 2674 if (--countTogo == 0)
2672 return 0; 2675 return 0;
2673 } 2676 }
2674 } 2677 }
2675 } else { 2678 } else {
2676 // Skip the whole month 2679 // Skip the whole month
2677 uint n = days->count(); 2680 uint n = days->count();
2678 if (n >= countTogo) 2681 if (n >= countTogo)
2679 return 0; 2682 return 0;
2680 countGone += n; 2683 countGone += n;
2681 } 2684 }
2682 data.day = 1; // we've checked the start month now 2685 data.day = 1; // we've checked the start month now
2683 } 2686 }
2684 } 2687 }
2685 data.month = 1; // we've checked the start year now 2688 data.month = 1; // we've checked the start year now
2686 data.year += rFreq; 2689 data.year += rFreq;
2687 } 2690 }
2688 } else { 2691 } else {
2689 // The number of recurrences is the same every year. 2692 // The number of recurrences is the same every year.
2690 if (data.month > 1 || data.day > 1) { 2693 if (data.month > 1 || data.day > 1) {
2691 // Check what remains of the start year 2694 // Check what remains of the start year
2692 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2695 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2693 if (*im.current() >= data.month) { 2696 if (*im.current() >= data.month) {
2694 // Check what remains of the start month 2697 // Check what remains of the start month
2695 data.month = *im.current(); 2698 data.month = *im.current();
2696 int ended = data.yearMonth() - endYearMonth; 2699 int ended = data.yearMonth() - endYearMonth;
2697 if (ended >= 0 || data.day > 1) { 2700 if (ended >= 0 || data.day > 1) {
2698 // This is the start or end month, so check each day 2701 // This is the start or end month, so check each day
2699 days = data.dayList(); 2702 days = data.dayList();
2700 for (id = days->begin(); id != days->end(); ++id) { 2703 for (id = days->begin(); id != days->end(); ++id) {
2701 if (*id >= data.day) { 2704 if (*id >= data.day) {
2702 ++countGone; 2705 ++countGone;
2703 if (ended > 0 || (ended == 0 && *id > endDay)) { 2706 if (ended > 0 || (ended == 0 && *id > endDay)) {
2704 data.day = *id; 2707 data.day = *id;
2705 goto ex; 2708 goto ex;
2706 } 2709 }
2707 if (--countTogo == 0) 2710 if (--countTogo == 0)
2708 return 0; 2711 return 0;
2709 } 2712 }
2710 } 2713 }
2711 data.day = 1; // we've checked the start month now 2714 data.day = 1; // we've checked the start month now
2712 } else { 2715 } else {
2713 // Skip the whole month. 2716 // Skip the whole month.
2714 if (static_cast<uint>(data.daysPerMonth) >= countTogo) 2717 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
2715 return 0; 2718 return 0;
2716 countGone += data.daysPerMonth; 2719 countGone += data.daysPerMonth;
2717 } 2720 }
2718 } 2721 }
2719 } 2722 }
2720 data.year += rFreq; 2723 data.year += rFreq;
2721 } 2724 }
2722 // Skip the remaining whole years to at least endYear. 2725 // Skip the remaining whole years to at least endYear.
2723 int recurYears = (endYear - data.year + rFreq - 1) / rFreq; 2726 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2724 if ((endYear - data.year)%rFreq == 0 2727 if ((endYear - data.year)%rFreq == 0
2725 && *rYearNums.getLast() <= endMonth) 2728 && *rYearNums.getLast() <= endMonth)
2726 ++recurYears; // required year is after endYear 2729 ++recurYears; // required year is after endYear
2727 if (recurYears) { 2730 if (recurYears) {
2728 int n = recurYears * data.count; 2731 int n = recurYears * data.count;
2729 if (static_cast<uint>(n) > countTogo) 2732 if (static_cast<uint>(n) > countTogo)
2730 return 0; // reached end of recurrence 2733 return 0; // reached end of recurrence
2731 countTogo -= n; 2734 countTogo -= n;
2732 countGone += n; 2735 countGone += n;
2733 data.year += recurYears * rFreq; 2736 data.year += recurYears * rFreq;
2734 } 2737 }
2735 2738
2736 // Check the last year in the recurrence 2739 // Check the last year in the recurrence
2737 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2740 for (Q3PtrListIterator<int> im(rYearNums); im.current(); ++im) {
2738 data.month = *im.current(); 2741 data.month = *im.current();
2739 int ended = data.yearMonth() - endYearMonth; 2742 int ended = data.yearMonth() - endYearMonth;
2740 if (ended >= 0) { 2743 if (ended >= 0) {
2741 // This is the end month, so check each day 2744 // This is the end month, so check each day
2742 days = data.dayList(); 2745 days = data.dayList();
2743 for (id = days->begin(); id != days->end(); ++id) { 2746 for (id = days->begin(); id != days->end(); ++id) {
2744 ++countGone; 2747 ++countGone;
2745 if (ended > 0 || (ended == 0 && *id > endDay)) { 2748 if (ended > 0 || (ended == 0 && *id > endDay)) {
2746 data.day = *id; 2749 data.day = *id;
2747 goto ex; 2750 goto ex;
2748 } 2751 }
2749 if (--countTogo == 0) 2752 if (--countTogo == 0)
2750 return 0; 2753 return 0;
2751 } 2754 }
2752 } else { 2755 } else {
2753 // Skip the whole month. 2756 // Skip the whole month.
2754 if (static_cast<uint>(data.daysPerMonth) >= countTogo) 2757 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
2755 return 0; 2758 return 0;
2756 countGone += data.daysPerMonth; 2759 countGone += data.daysPerMonth;
2757 } 2760 }
2758 } 2761 }
2759 } 2762 }
2760ex: 2763ex:
2761 enddate = data.date(); 2764 enddate = data.date();
2762 return countGone; 2765 return countGone;
2763} 2766}
2764 2767
2765 2768
2766/* Find count and, depending on 'func', the end date of an annual recurrence by day. 2769/* Find count and, depending on 'func', the end date of an annual recurrence by day.
2767 * Reply = total number of occurrences up to 'enddate', or 0 if error. 2770 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2768 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 2771 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2769 * recurrence end date. 2772 * recurrence end date.
2770 */ 2773 */
2771struct Recurrence::YearlyDayData { 2774struct Recurrence::YearlyDayData {
2772 int year; // current year 2775 int year; // current year
2773 int day; // current day of year 1..366 2776 int day; // current day of year 1..366
2774 bool varies; // true if day 366 recurs 2777 bool varies; // true if day 366 recurs
2775 private: 2778 private:
2776 int daycount; 2779 int daycount;
2777 public: 2780 public:
2778 YearlyDayData(const Recurrence* r, const QDate &date) 2781 YearlyDayData(const Recurrence* r, const QDate &date)
2779 : year(date.year()), day(date.dayOfYear()), varies(*r->rYearNums.getLast() == 366), 2782 : year(date.year()), day(date.dayOfYear()), varies(*r->rYearNums.getLast() == 366),
2780 daycount(r->rYearNums.count()) { } 2783 daycount(r->rYearNums.count()) { }
2781 bool leapYear() const { return QDate::leapYear(year); } 2784 bool leapYear() const { return QDate::leapYear(year); }
2782 int dayCount() const { return daycount - (varies && !QDate::leapYear(year) ? 1 : 0); } 2785 int dayCount() const { return daycount - (varies && !QDate::leapYear(year) ? 1 : 0); }
2783 bool isMaxDayCount() const { return !varies || QDate::leapYear(year); } 2786 bool isMaxDayCount() const { return !varies || QDate::leapYear(year); }
2784 QDate date() const { return QDate(year, 1, 1).addDays(day - 1); } 2787 QDate date() const { return QDate(year, 1, 1).addDays(day - 1); }
2785}; 2788};
2786 2789
2787int Recurrence::yearlyDayCalc(PeriodFunc func, QDate &enddate) const 2790int Recurrence::yearlyDayCalc(PeriodFunc func, QDate &enddate) const
2788{ 2791{
2789 if (rYearNums.isEmpty()) 2792 if (rYearNums.isEmpty())
2790 return 0; 2793 return 0;
2791 YearlyDayData data(this, mRecurStart.date()); 2794 YearlyDayData data(this, mRecurStart.date());
2792 switch (func) { 2795 switch (func) {
2793 case END_DATE_AND_COUNT: 2796 case END_DATE_AND_COUNT:
2794 return yearlyDayCalcEndDate(enddate, data); 2797 return yearlyDayCalcEndDate(enddate, data);
2795 case COUNT_TO_DATE: 2798 case COUNT_TO_DATE:
2796 return yearlyDayCalcToDate(enddate, data); 2799 return yearlyDayCalcToDate(enddate, data);
2797 case NEXT_AFTER_DATE: 2800 case NEXT_AFTER_DATE:
2798 return yearlyDayCalcNextAfter(enddate, data); 2801 return yearlyDayCalcNextAfter(enddate, data);
2799 } 2802 }
2800 return 0; 2803 return 0;
2801} 2804}
2802 2805
2803int Recurrence::yearlyDayCalcEndDate(QDate &enddate, YearlyDayData &data) const 2806int Recurrence::yearlyDayCalcEndDate(QDate &enddate, YearlyDayData &data) const
2804{ 2807{
2805 uint countTogo = rDuration + mRecurExDatesCount; 2808 uint countTogo = rDuration + mRecurExDatesCount;
2806 int countGone = 0; 2809 int countGone = 0;
2807 2810
2808 if (data.day > 1) { 2811 if (data.day > 1) {
2809 // Check what remains of the start year 2812 // Check what remains of the start year
2810 bool leapOK = data.isMaxDayCount(); 2813 bool leapOK = data.isMaxDayCount();
2811 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2814 for (Q3PtrListIterator<int> it(rYearNums); it.current(); ++it) {
2812 int d = *it.current(); 2815 int d = *it.current();
2813 if (d >= data.day && (leapOK || d < 366)) { 2816 if (d >= data.day && (leapOK || d < 366)) {
2814 ++countGone; 2817 ++countGone;
2815 if (--countTogo == 0) { 2818 if (--countTogo == 0) {
2816 data.day = d; 2819 data.day = d;
2817 goto ex; 2820 goto ex;
2818 } 2821 }
2819 } 2822 }
2820 } 2823 }
2821 data.day = 1; 2824 data.day = 1;
2822 data.year += rFreq; 2825 data.year += rFreq;
2823 } 2826 }
2824 2827
2825 if (data.varies) { 2828 if (data.varies) {
2826 // The number of recurrences is different in leap years, 2829 // The number of recurrences is different in leap years,
2827 // so check year-by-year. 2830 // so check year-by-year.
2828 for ( ; ; ) { 2831 for ( ; ; ) {
2829 uint n = data.dayCount(); 2832 uint n = data.dayCount();
2830 if (n >= countTogo) 2833 if (n >= countTogo)
2831 break; 2834 break;
2832 countTogo -= n; 2835 countTogo -= n;
2833 countGone += n; 2836 countGone += n;
2834 data.year += rFreq; 2837 data.year += rFreq;
2835 } 2838 }
2836 } else { 2839 } else {
2837 // The number of recurrences is the same every year, 2840 // The number of recurrences is the same every year,
2838 // so skip the year-by-year check. 2841 // so skip the year-by-year check.
2839 // Skip the remaining whole years, but leave at least 2842 // Skip the remaining whole years, but leave at least
2840 // 1 recurrence remaining, in order to get its date. 2843 // 1 recurrence remaining, in order to get its date.
2841 int daysPerYear = rYearNums.count(); 2844 int daysPerYear = rYearNums.count();
2842 int wholeYears = (countTogo - 1) / daysPerYear; 2845 int wholeYears = (countTogo - 1) / daysPerYear;
2843 data.year += wholeYears * rFreq; 2846 data.year += wholeYears * rFreq;
2844 countGone += wholeYears * daysPerYear; 2847 countGone += wholeYears * daysPerYear;
2845 countTogo -= wholeYears * daysPerYear; 2848 countTogo -= wholeYears * daysPerYear;
2846 } 2849 }
2847 if (countTogo) { 2850 if (countTogo) {
2848 // Check the last year in the recurrence 2851 // Check the last year in the recurrence
2849 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2852 for (Q3PtrListIterator<int> it(rYearNums); it.current(); ++it) {
2850 ++countGone; 2853 ++countGone;
2851 if (--countTogo == 0) { 2854 if (--countTogo == 0) {
2852 data.day = *it.current(); 2855 data.day = *it.current();
2853 break; 2856 break;
2854 } 2857 }
2855 } 2858 }
2856 } 2859 }
2857ex: 2860ex:
2858 enddate = data.date(); 2861 enddate = data.date();
2859 return countGone; 2862 return countGone;
2860} 2863}
2861 2864
2862int Recurrence::yearlyDayCalcToDate(const QDate &enddate, YearlyDayData &data) const 2865int Recurrence::yearlyDayCalcToDate(const QDate &enddate, YearlyDayData &data) const
2863{ 2866{
2864 int countGone = 0; 2867 int countGone = 0;
2865 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 2868 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2866 int endYear = enddate.year(); 2869 int endYear = enddate.year();
2867 int endDay = enddate.dayOfYear(); 2870 int endDay = enddate.dayOfYear();
2868 2871
2869 if (data.day > 1) { 2872 if (data.day > 1) {
2870 // Check what remains of the start year 2873 // Check what remains of the start year
2871 bool leapOK = data.isMaxDayCount(); 2874 bool leapOK = data.isMaxDayCount();
2872 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2875 for (Q3PtrListIterator<int> it(rYearNums); it.current(); ++it) {
2873 int d = *it.current(); 2876 int d = *it.current();
2874 if (d >= data.day && (leapOK || d < 366)) { 2877 if (d >= data.day && (leapOK || d < 366)) {
2875 if (data.year == endYear && d > endDay) 2878 if (data.year == endYear && d > endDay)
2876 return countGone; 2879 return countGone;
2877 if (++countGone >= countMax) 2880 if (++countGone >= countMax)
2878 return countMax; 2881 return countMax;
2879 } 2882 }
2880 } 2883 }
2881 data.day = 1; 2884 data.day = 1;
2882 data.year += rFreq; 2885 data.year += rFreq;
2883 } 2886 }
2884 2887
2885 if (data.varies) { 2888 if (data.varies) {
2886 // The number of recurrences is different in leap years, 2889 // The number of recurrences is different in leap years,
2887 // so check year-by-year. 2890 // so check year-by-year.
2888 while (data.year < endYear) { 2891 while (data.year < endYear) {
2889 uint n = data.dayCount(); 2892 uint n = data.dayCount();
2890 countGone += n; 2893 countGone += n;
2891 if (countGone >= countMax) 2894 if (countGone >= countMax)
2892 return countMax; 2895 return countMax;
2893 data.year += rFreq; 2896 data.year += rFreq;
2894 } 2897 }
2895 if (data.year > endYear) 2898 if (data.year > endYear)
2896 return countGone; 2899 return countGone;
2897 } else { 2900 } else {
2898 // The number of recurrences is the same every year. 2901 // The number of recurrences is the same every year.
2899 // Skip the remaining whole years. 2902 // Skip the remaining whole years.
2900 int wholeYears = endYear - data.year; 2903 int wholeYears = endYear - data.year;
2901 countGone += (wholeYears / rFreq) * rYearNums.count(); 2904 countGone += (wholeYears / rFreq) * rYearNums.count();
2902 if (countGone >= countMax) 2905 if (countGone >= countMax)
2903 return countMax; 2906 return countMax;
2904 if (wholeYears % rFreq) 2907 if (wholeYears % rFreq)
2905 return countGone; // end year isn't a recurrence year 2908 return countGone; // end year isn't a recurrence year
2906 data.year = endYear; 2909 data.year = endYear;
2907 } 2910 }
2908 2911
2909 if (data.year <= endYear) { 2912 if (data.year <= endYear) {
2910 // Check the last year in the recurrence 2913 // Check the last year in the recurrence
2911 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2914 for (Q3PtrListIterator<int> it(rYearNums); it.current(); ++it) {
2912 if (*it.current() > endDay) 2915 if (*it.current() > endDay)
2913 return countGone; 2916 return countGone;
2914 if (++countGone >= countMax) 2917 if (++countGone >= countMax)
2915 return countMax; 2918 return countMax;
2916 } 2919 }
2917 } 2920 }
2918 return countGone; 2921 return countGone;
2919} 2922}
2920 2923
2921int Recurrence::yearlyDayCalcNextAfter(QDate &enddate, YearlyDayData &data) const 2924int Recurrence::yearlyDayCalcNextAfter(QDate &enddate, YearlyDayData &data) const
2922{ 2925{
2923 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 2926 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2924 int countGone = 0; 2927 int countGone = 0;
2925 int endYear = enddate.year(); 2928 int endYear = enddate.year();
2926 int endDay = enddate.dayOfYear(); 2929 int endDay = enddate.dayOfYear();
2927 2930
2928 if (data.day > 1) { 2931 if (data.day > 1) {
2929 // Check what remains of the start year 2932 // Check what remains of the start year
2930 bool leapOK = data.isMaxDayCount(); 2933 bool leapOK = data.isMaxDayCount();
2931 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2934 for (Q3PtrListIterator<int> it(rYearNums); it.current(); ++it) {
2932 int d = *it.current(); 2935 int d = *it.current();
2933 if (d >= data.day && (leapOK || d < 366)) { 2936 if (d >= data.day && (leapOK || d < 366)) {
2934 ++countGone; 2937 ++countGone;
2935 if (data.year == endYear && d > endDay) { 2938 if (data.year == endYear && d > endDay) {
2936 data.day = d; 2939 data.day = d;
2937 goto ex; 2940 goto ex;
2938 } 2941 }
2939 if (--countTogo == 0) 2942 if (--countTogo == 0)
2940 return 0; 2943 return 0;
2941 } 2944 }
2942 } 2945 }
2943 data.day = 1; 2946 data.day = 1;
2944 data.year += rFreq; 2947 data.year += rFreq;
2945 } 2948 }
2946 2949
2947 if (data.varies) { 2950 if (data.varies) {
2948 // The number of recurrences is different in leap years, 2951 // The number of recurrences is different in leap years,
2949 // so check year-by-year. 2952 // so check year-by-year.
2950 while (data.year <= endYear) { 2953 while (data.year <= endYear) {
2951 uint n = data.dayCount(); 2954 uint n = data.dayCount();
2952 if (data.year == endYear && *rYearNums.getLast() > endDay) 2955 if (data.year == endYear && *rYearNums.getLast() > endDay)
2953 break; 2956 break;
2954 if (n >= countTogo) 2957 if (n >= countTogo)
2955 break; 2958 break;
2956 countTogo -= n; 2959 countTogo -= n;
2957 countGone += n; 2960 countGone += n;
2958 data.year += rFreq; 2961 data.year += rFreq;
2959 } 2962 }
2960 } else { 2963 } else {
2961 // The number of recurrences is the same every year, 2964 // The number of recurrences is the same every year,
2962 // so skip the year-by-year check. 2965 // so skip the year-by-year check.
2963 // Skip the remaining whole years to at least endYear. 2966 // Skip the remaining whole years to at least endYear.
2964 int daysPerYear = rYearNums.count(); 2967 int daysPerYear = rYearNums.count();
2965 int recurYears = (endYear - data.year + rFreq - 1) / rFreq; 2968 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2966 if ((endYear - data.year)%rFreq == 0 2969 if ((endYear - data.year)%rFreq == 0
2967 && *rYearNums.getLast() <= endDay) 2970 && *rYearNums.getLast() <= endDay)
2968 ++recurYears; // required year is after endYear 2971 ++recurYears; // required year is after endYear
2969 if (recurYears) { 2972 if (recurYears) {
2970 int n = recurYears * daysPerYear; 2973 int n = recurYears * daysPerYear;
2971 if (static_cast<uint>(n) > countTogo) 2974 if (static_cast<uint>(n) > countTogo)
2972 return 0; // reached end of recurrence 2975 return 0; // reached end of recurrence
2973 countTogo -= n; 2976 countTogo -= n;
2974 countGone += n; 2977 countGone += n;
2975 data.year += recurYears * rFreq; 2978 data.year += recurYears * rFreq;
2976 } 2979 }
2977 } 2980 }
2978 2981
2979 // Check the last year in the recurrence 2982 // Check the last year in the recurrence
2980 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2983 for (Q3PtrListIterator<int> it(rYearNums); it.current(); ++it) {
2981 ++countGone; 2984 ++countGone;
2982 int d = *it.current(); 2985 int d = *it.current();
2983 if (data.year > endYear || d > endDay) { 2986 if (data.year > endYear || d > endDay) {
2984 data.day = d; 2987 data.day = d;
2985 break; 2988 break;
2986 } 2989 }
2987 if (--countTogo == 0) 2990 if (--countTogo == 0)
2988 return 0; 2991 return 0;
2989 } 2992 }
2990ex: 2993ex:
2991 enddate = data.date(); 2994 enddate = data.date();
2992 return countGone; 2995 return countGone;
2993} 2996}
2994 2997
2995// Get the days in this month which recur, in numerical order. 2998// Get the days in this month which recur, in numerical order.
2996// Parameters: daysInMonth = number of days in this month 2999// Parameters: daysInMonth = number of days in this month
2997// startDayOfWeek = day of week for first day of month. 3000// startDayOfWeek = day of week for first day of month.
2998void Recurrence::getMonthlyPosDays(QValueList<int> &list, int daysInMonth, int startDayOfWeek) const 3001void Recurrence::getMonthlyPosDays(Q3ValueList<int> &list, int daysInMonth, int startDayOfWeek) const
2999{ 3002{
3000 list.clear(); 3003 list.clear();
3001 int endDayOfWeek = (startDayOfWeek + daysInMonth - 2) % 7 + 1; 3004 int endDayOfWeek = (startDayOfWeek + daysInMonth - 2) % 7 + 1;
3002 // Go through the list, compiling a bit list of actual day numbers 3005 // Go through the list, compiling a bit list of actual day numbers
3003 Q_UINT32 days = 0; 3006 Q_UINT32 days = 0;
3004 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) { 3007 for (Q3PtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
3005 int weeknum = pos.current()->rPos - 1; // get 0-based week number 3008 int weeknum = pos.current()->rPos - 1; // get 0-based week number
3006 QBitArray &rdays = pos.current()->rDays; 3009 QBitArray &rdays = pos.current()->rDays;
3007 if (pos.current()->negative) { 3010 if (pos.current()->negative) {
3008 // nth days before the end of the month 3011 // nth days before the end of the month
3009 for (uint i = 1; i <= 7; ++i) { 3012 for (uint i = 1; i <= 7; ++i) {
3010 if (rdays.testBit(i - 1)) { 3013 if (rdays.testBit(i - 1)) {
3011 int day = daysInMonth - weeknum*7 - (endDayOfWeek - i + 7) % 7; 3014 int day = daysInMonth - weeknum*7 - (endDayOfWeek - i + 7) % 7;
3012 if (day > 0) 3015 if (day > 0)
3013 days |= 1 << (day - 1); 3016 days |= 1 << (day - 1);
3014 } 3017 }
3015 } 3018 }
3016 } else { 3019 } else {
3017 // nth days after the start of the month 3020 // nth days after the start of the month
3018 for (uint i = 1; i <= 7; ++i) { 3021 for (uint i = 1; i <= 7; ++i) {
3019 if (rdays.testBit(i - 1)) { 3022 if (rdays.testBit(i - 1)) {
3020 int day = 1 + weeknum*7 + (i - startDayOfWeek + 7) % 7; 3023 int day = 1 + weeknum*7 + (i - startDayOfWeek + 7) % 7;
3021 if (day <= daysInMonth) 3024 if (day <= daysInMonth)
3022 days |= 1 << (day - 1); 3025 days |= 1 << (day - 1);
3023 } 3026 }
3024 } 3027 }
3025 } 3028 }
3026 } 3029 }
3027 // Compile the ordered list 3030 // Compile the ordered list
3028 Q_UINT32 mask = 1; 3031 Q_UINT32 mask = 1;
3029 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) { 3032 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
3030 if (days & mask) 3033 if (days & mask)
3031 list.append(i + 1); 3034 list.append(i + 1);
3032 } 3035 }
3033} 3036}
3034 3037
3035// Get the number of days in the month which recur. 3038// Get the number of days in the month which recur.
3036// Reply = -1 if the number varies from month to month. 3039// Reply = -1 if the number varies from month to month.
3037int Recurrence::countMonthlyPosDays() const 3040int Recurrence::countMonthlyPosDays() const
3038{ 3041{
3039 int count = 0; 3042 int count = 0;
3040 Q_UINT8 positive[5] = { 0, 0, 0, 0, 0 }; 3043 Q_UINT8 positive[5] = { 0, 0, 0, 0, 0 };
3041 Q_UINT8 negative[4] = { 0, 0, 0, 0 }; 3044 Q_UINT8 negative[4] = { 0, 0, 0, 0 };
3042 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) { 3045 for (Q3PtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
3043 int weeknum = pos.current()->rPos; 3046 int weeknum = pos.current()->rPos;
3044 Q_UINT8* wk; 3047 Q_UINT8* wk;
3045 if (pos.current()->negative) { 3048 if (pos.current()->negative) {
3046 // nth days before the end of the month 3049 // nth days before the end of the month
3047 if (weeknum > 4) 3050 if (weeknum > 4)
3048 return -1; // days in 5th week are often missing 3051 return -1; // days in 5th week are often missing
3049 wk = &negative[4 - weeknum]; 3052 wk = &negative[4 - weeknum];
3050 } else { 3053 } else {
3051 // nth days after the start of the month 3054 // nth days after the start of the month
3052 if (weeknum > 4) 3055 if (weeknum > 4)
3053 return -1; // days in 5th week are often missing 3056 return -1; // days in 5th week are often missing
3054 wk = &positive[weeknum - 1]; 3057 wk = &positive[weeknum - 1];
3055 } 3058 }
3056 QBitArray &rdays = pos.current()->rDays; 3059 QBitArray &rdays = pos.current()->rDays;
3057 for (uint i = 0; i < 7; ++i) { 3060 for (uint i = 0; i < 7; ++i) {
3058 if (rdays.testBit(i)) { 3061 if (rdays.testBit(i)) {
3059 ++count; 3062 ++count;
3060 *wk |= (1 << i); 3063 *wk |= (1 << i);
3061 } 3064 }
3062 } 3065 }
3063 } 3066 }
3064 // Check for any possible days which could be duplicated by 3067 // Check for any possible days which could be duplicated by
3065 // a positive and a negative position. 3068 // a positive and a negative position.
3066 for (int i = 0; i < 4; ++i) { 3069 for (int i = 0; i < 4; ++i) {
3067 if (negative[i] & (positive[i] | positive[i+1])) 3070 if (negative[i] & (positive[i] | positive[i+1]))
3068 return -1; 3071 return -1;
3069 } 3072 }
3070 return count; 3073 return count;
3071} 3074}
3072 3075
3073// Get the days in this month which recur, in numerical order. 3076// Get the days in this month which recur, in numerical order.
3074// Reply = true if day numbers varies from month to month. 3077// Reply = true if day numbers varies from month to month.
3075bool Recurrence::getMonthlyDayDays(QValueList<int> &list, int daysInMonth) const 3078bool Recurrence::getMonthlyDayDays(Q3ValueList<int> &list, int daysInMonth) const
3076{ 3079{
3077 list.clear(); 3080 list.clear();
3078 bool variable = false; 3081 bool variable = false;
3079 Q_UINT32 days = 0; 3082 Q_UINT32 days = 0;
3080 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { 3083 for (Q3PtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3081 int day = *it.current(); 3084 int day = *it.current();
3082 if (day > 0) { 3085 if (day > 0) {
3083 // date in the month 3086 // date in the month
3084 if (day <= daysInMonth) 3087 if (day <= daysInMonth)
3085 days |= 1 << (day - 1); 3088 days |= 1 << (day - 1);
3086 if (day > 28 && day <= 31) 3089 if (day > 28 && day <= 31)
3087 variable = true; // this date does not appear in some months 3090 variable = true; // this date does not appear in some months
3088 } else if (day < 0) { 3091 } else if (day < 0) {
3089 // days before the end of the month 3092 // days before the end of the month
3090 variable = true; // this date varies depending on the month length 3093 variable = true; // this date varies depending on the month length
3091 day = daysInMonth + day; // zero-based day of month 3094 day = daysInMonth + day; // zero-based day of month
3092 if (day >= 0) 3095 if (day >= 0)
3093 days |= 1 << day; 3096 days |= 1 << day;
3094 } 3097 }
3095 } 3098 }
3096 // Compile the ordered list 3099 // Compile the ordered list
3097 Q_UINT32 mask = 1; 3100 Q_UINT32 mask = 1;
3098 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) { 3101 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
3099 if (days & mask) 3102 if (days & mask)
3100 list.append(i + 1); 3103 list.append(i + 1);
3101 } 3104 }
3102 return variable; 3105 return variable;
3103} 3106}
3104 3107
3105// Get the months which recur, in numerical order, for both leap years and non-leap years. 3108// Get the months which recur, in numerical order, for both leap years and non-leap years.
3106// N.B. If February 29th recurs on March 1st in non-leap years, February (not March) is 3109// N.B. If February 29th recurs on March 1st in non-leap years, February (not March) is
3107// included in the non-leap year month list. 3110// included in the non-leap year month list.
3108// Reply = true if February 29th also recurs. 3111// Reply = true if February 29th also recurs.
3109bool Recurrence::getYearlyMonthMonths(int day, QValueList<int> &list, QValueList<int> &leaplist) const 3112bool Recurrence::getYearlyMonthMonths(int day, Q3ValueList<int> &list, Q3ValueList<int> &leaplist) const
3110{ 3113{
3111 list.clear(); 3114 list.clear();
3112 leaplist.clear(); 3115 leaplist.clear();
3113 bool feb29 = false; 3116 bool feb29 = false;
3114 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 3117 for (Q3PtrListIterator<int> it(rYearNums); it.current(); ++it) {
3115 int month = *it.current(); 3118 int month = *it.current();
3116 if (month == 2) { 3119 if (month == 2) {
3117 if (day <= 28) { 3120 if (day <= 28) {
3118 list.append(month); // date appears in February 3121 list.append(month); // date appears in February
3119 leaplist.append(month); 3122 leaplist.append(month);
3120 } 3123 }
3121 else if (day == 29) { 3124 else if (day == 29) {
3122 // February 29th 3125 // February 29th
3123 leaplist.append(month); 3126 leaplist.append(month);
3124 switch (mFeb29YearlyType) { 3127 switch (mFeb29YearlyType) {
3125 case rFeb28: 3128 case rFeb28:
3126 case rMar1: 3129 case rMar1:
3127 list.append(2); 3130 list.append(2);
3128 break; 3131 break;
3129 case rFeb29: 3132 case rFeb29:
3130 break; 3133 break;
3131 } 3134 }
3132 feb29 = true; 3135 feb29 = true;
3133 } 3136 }
3134 } 3137 }
3135 else if (day <= 30 || QDate(2000, month, 1).daysInMonth() == 31) { 3138 else if (day <= 30 || QDate(2000, month, 1).daysInMonth() == 31) {
3136 list.append(month); // date appears in every month 3139 list.append(month); // date appears in every month
3137 leaplist.append(month); 3140 leaplist.append(month);
3138 } 3141 }
3139 } 3142 }
3140 return feb29; 3143 return feb29;
3141} 3144}
3142 3145
3143/* From the recurrence day of the week list, get the earliest day in the 3146/* From the recurrence day of the week list, get the earliest day in the
3144 * specified week which is >= the startDay. 3147 * specified week which is >= the startDay.
3145 * Parameters: startDay = 1..7 (Monday..Sunday) 3148 * Parameters: startDay = 1..7 (Monday..Sunday)
3146 * useWeekStart = true to end search at day before next rWeekStart 3149 * useWeekStart = true to end search at day before next rWeekStart
3147 * = false to search for a full 7 days 3150 * = false to search for a full 7 days
3148 * Reply = day of the week (1..7), or 0 if none found. 3151 * Reply = day of the week (1..7), or 0 if none found.
3149 */ 3152 */
3150int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const 3153int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const
3151{ 3154{
3152 int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7; 3155 int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7;
3153 for (int i = startDay - 1; ; i = (i + 1)%7) { 3156 for (int i = startDay - 1; ; i = (i + 1)%7) {
3154 if (rDays.testBit(i)) 3157 if (rDays.testBit(i))
3155 return i + 1; 3158 return i + 1;
3156 if (i == last) 3159 if (i == last)
3157 return 0; 3160 return 0;
3158 } 3161 }
3159} 3162}
3160 3163
3161/* From the recurrence day of the week list, get the latest day in the 3164/* From the recurrence day of the week list, get the latest day in the
3162 * specified week which is <= the endDay. 3165 * specified week which is <= the endDay.
3163 * Parameters: endDay = 1..7 (Monday..Sunday) 3166 * Parameters: endDay = 1..7 (Monday..Sunday)
3164 * useWeekStart = true to end search at rWeekStart 3167 * useWeekStart = true to end search at rWeekStart
3165 * = false to search for a full 7 days 3168 * = false to search for a full 7 days
3166 * Reply = day of the week (1..7), or 0 if none found. 3169 * Reply = day of the week (1..7), or 0 if none found.
3167 */ 3170 */
3168int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const 3171int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const
3169{ 3172{
3170 int last = useWeekStart ? rWeekStart - 1 : endDay%7; 3173 int last = useWeekStart ? rWeekStart - 1 : endDay%7;
3171 for (int i = endDay - 1; ; i = (i + 6)%7) { 3174 for (int i = endDay - 1; ; i = (i + 6)%7) {
3172 if (rDays.testBit(i)) 3175 if (rDays.testBit(i))
3173 return i + 1; 3176 return i + 1;
3174 if (i == last) 3177 if (i == last)
3175 return 0; 3178 return 0;
3176 } 3179 }
3177} 3180}
3178 3181
3179/* From the recurrence monthly day number list or monthly day of week/week of 3182/* From the recurrence monthly day number list or monthly day of week/week of
3180 * month list, get the earliest day in the specified month which is >= the 3183 * month list, get the earliest day in the specified month which is >= the
3181 * earliestDate. 3184 * earliestDate.
3182 */ 3185 */
3183QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const 3186QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const
3184{ 3187{
3185 int earliestDay = earliestDate.day(); 3188 int earliestDay = earliestDate.day();
3186 int daysInMonth = earliestDate.daysInMonth(); 3189 int daysInMonth = earliestDate.daysInMonth();
3187 switch (recurs) { 3190 switch (recurs) {
3188 case rMonthlyDay: { 3191 case rMonthlyDay: {
3189 int minday = daysInMonth + 1; 3192 int minday = daysInMonth + 1;
3190 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { 3193 for (Q3PtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3191 int day = *it.current(); 3194 int day = *it.current();
3192 if (day < 0) 3195 if (day < 0)
3193 day = daysInMonth + day + 1; 3196 day = daysInMonth + day + 1;
3194 if (day >= earliestDay && day < minday) 3197 if (day >= earliestDay && day < minday)
3195 minday = day; 3198 minday = day;
3196 } 3199 }
3197 if (minday <= daysInMonth) 3200 if (minday <= daysInMonth)
3198 return earliestDate.addDays(minday - earliestDay); 3201 return earliestDate.addDays(minday - earliestDay);
3199 break; 3202 break;
3200 } 3203 }
3201 case rMonthlyPos: 3204 case rMonthlyPos:
3202 case rYearlyPos: { 3205 case rYearlyPos: {
3203 QDate monthBegin(earliestDate.addDays(1 - earliestDay)); 3206 QDate monthBegin(earliestDate.addDays(1 - earliestDay));
3204 QValueList<int> dayList; 3207 Q3ValueList<int> dayList;
3205 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek()); 3208 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
3206 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) { 3209 for (Q3ValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
3207 if (*id >= earliestDay) 3210 if (*id >= earliestDay)
3208 return monthBegin.addDays(*id - 1); 3211 return monthBegin.addDays(*id - 1);
3209 } 3212 }
3210 break; 3213 break;
3211 } 3214 }
3212 } 3215 }
3213 return QDate(); 3216 return QDate();
3214} 3217}
3215 3218
3216/* From the recurrence monthly day number list or monthly day of week/week of 3219/* From the recurrence monthly day number list or monthly day of week/week of
3217 * month list, get the latest day in the specified month which is <= the 3220 * month list, get the latest day in the specified month which is <= the
3218 * latestDate. 3221 * latestDate.
3219 */ 3222 */
3220QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const 3223QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const
3221{ 3224{
3222 int latestDay = latestDate.day(); 3225 int latestDay = latestDate.day();
3223 int daysInMonth = latestDate.daysInMonth(); 3226 int daysInMonth = latestDate.daysInMonth();
3224 switch (recurs) { 3227 switch (recurs) {
3225 case rMonthlyDay: { 3228 case rMonthlyDay: {
3226 int maxday = -1; 3229 int maxday = -1;
3227 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { 3230 for (Q3PtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3228 int day = *it.current(); 3231 int day = *it.current();
3229 if (day < 0) 3232 if (day < 0)
3230 day = daysInMonth + day + 1; 3233 day = daysInMonth + day + 1;
3231 if (day <= latestDay && day > maxday) 3234 if (day <= latestDay && day > maxday)
3232 maxday = day; 3235 maxday = day;
3233 } 3236 }
3234 if (maxday > 0) 3237 if (maxday > 0)
3235 return QDate(latestDate.year(), latestDate.month(), maxday); 3238 return QDate(latestDate.year(), latestDate.month(), maxday);
3236 break; 3239 break;
3237 } 3240 }
3238 case rMonthlyPos: 3241 case rMonthlyPos:
3239 case rYearlyPos: { 3242 case rYearlyPos: {
3240 QDate monthBegin(latestDate.addDays(1 - latestDay)); 3243 QDate monthBegin(latestDate.addDays(1 - latestDay));
3241 QValueList<int> dayList; 3244 Q3ValueList<int> dayList;
3242 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek()); 3245 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
3243 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) { 3246 for (Q3ValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
3244 if (*id <= latestDay) 3247 if (*id <= latestDay)
3245 return monthBegin.addDays(*id - 1); 3248 return monthBegin.addDays(*id - 1);
3246 } 3249 }
3247 break; 3250 break;
3248 } 3251 }
3249 } 3252 }
3250 return QDate(); 3253 return QDate();
3251} 3254}
3252 3255
3253/* From the recurrence yearly month list or yearly day list, get the earliest 3256/* From the recurrence yearly month list or yearly day list, get the earliest
3254 * month or day in the specified year which is >= the earliestDate. 3257 * month or day in the specified year which is >= the earliestDate.
3255 * Note that rYearNums is sorted in numerical order. 3258 * Note that rYearNums is sorted in numerical order.
3256 */ 3259 */
3257QDate Recurrence::getFirstDateInYear(const QDate &earliestDate) const 3260QDate Recurrence::getFirstDateInYear(const QDate &earliestDate) const
3258{ 3261{
3259 QPtrListIterator<int> it(rYearNums); 3262 Q3PtrListIterator<int> it(rYearNums);
3260 switch (recurs) { 3263 switch (recurs) {
3261 case rYearlyMonth: { 3264 case rYearlyMonth: {
3262 int day = recurStart().date().day(); 3265 int day = recurStart().date().day();
3263 int earliestYear = earliestDate.year(); 3266 int earliestYear = earliestDate.year();
3264 int earliestMonth = earliestDate.month(); 3267 int earliestMonth = earliestDate.month();
3265 int earliestDay = earliestDate.day(); 3268 int earliestDay = earliestDate.day();
3266 if (earliestDay > day) { 3269 if (earliestDay > day) {
3267 // The earliest date is later in the month than the recurrence date, 3270 // The earliest date is later in the month than the recurrence date,
3268 // so skip to the next month before starting to check 3271 // so skip to the next month before starting to check
3269 if (++earliestMonth > 12) 3272 if (++earliestMonth > 12)
3270 return QDate(); 3273 return QDate();
3271 } 3274 }
3272 for ( ; it.current(); ++it) { 3275 for ( ; it.current(); ++it) {
3273 int month = *it.current(); 3276 int month = *it.current();
3274 if (month >= earliestMonth) { 3277 if (month >= earliestMonth) {
3275 if (day <= 28 || QDate::isValid(earliestYear, month, day)) 3278 if (day <= 28 || QDate::isValid(earliestYear, month, day))
3276 return QDate(earliestYear, month, day); 3279 return QDate(earliestYear, month, day);
3277 if (day == 29 && month == 2) { 3280 if (day == 29 && month == 2) {
3278 // It's a recurrence on February 29th, in a non-leap year 3281 // It's a recurrence on February 29th, in a non-leap year
3279 switch (mFeb29YearlyType) { 3282 switch (mFeb29YearlyType) {
3280 case rMar1: 3283 case rMar1:
3281 return QDate(earliestYear, 3, 1); 3284 return QDate(earliestYear, 3, 1);
3282 case rFeb28: 3285 case rFeb28:
3283 if (earliestDay <= 28) 3286 if (earliestDay <= 28)
3284 return QDate(earliestYear, 2, 28); 3287 return QDate(earliestYear, 2, 28);
3285 break; 3288 break;
3286 case rFeb29: 3289 case rFeb29:
3287 break; 3290 break;
3288 } 3291 }
3289 } 3292 }
3290 } 3293 }
3291 } 3294 }
3292 break; 3295 break;
3293 } 3296 }
3294 case rYearlyPos: { 3297 case rYearlyPos: {
3295 QValueList<int> dayList; 3298 Q3ValueList<int> dayList;
3296 int earliestYear = earliestDate.year(); 3299 int earliestYear = earliestDate.year();
3297 int earliestMonth = earliestDate.month(); 3300 int earliestMonth = earliestDate.month();
3298 int earliestDay = earliestDate.day(); 3301 int earliestDay = earliestDate.day();
3299 for ( ; it.current(); ++it) { 3302 for ( ; it.current(); ++it) {
3300 int month = *it.current(); 3303 int month = *it.current();
3301 if (month >= earliestMonth) { 3304 if (month >= earliestMonth) {
3302 QDate monthBegin(earliestYear, month, 1); 3305 QDate monthBegin(earliestYear, month, 1);
3303 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek()); 3306 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
3304 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) { 3307 for (Q3ValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
3305 if (*id >= earliestDay) 3308 if (*id >= earliestDay)
3306 return monthBegin.addDays(*id - 1); 3309 return monthBegin.addDays(*id - 1);
3307 } 3310 }
3308 earliestDay = 1; 3311 earliestDay = 1;
3309 } 3312 }
3310 } 3313 }
3311 break; 3314 break;
3312 } 3315 }
3313 case rYearlyDay: { 3316 case rYearlyDay: {
3314 int earliestDay = earliestDate.dayOfYear(); 3317 int earliestDay = earliestDate.dayOfYear();
3315 for ( ; it.current(); ++it) { 3318 for ( ; it.current(); ++it) {
3316 int day = *it.current(); 3319 int day = *it.current();
3317 if (day >= earliestDay && (day <= 365 || day <= earliestDate.daysInYear())) 3320 if (day >= earliestDay && (day <= 365 || day <= earliestDate.daysInYear()))
3318 return earliestDate.addDays(day - earliestDay); 3321 return earliestDate.addDays(day - earliestDay);
3319 } 3322 }
3320 break; 3323 break;
3321 } 3324 }
3322 } 3325 }
3323 return QDate(); 3326 return QDate();
3324} 3327}
3325 3328
3326/* From the recurrence yearly month list or yearly day list, get the latest 3329/* From the recurrence yearly month list or yearly day list, get the latest
3327 * month or day in the specified year which is <= the latestDate. 3330 * month or day in the specified year which is <= the latestDate.
3328 * Note that rYearNums is sorted in numerical order. 3331 * Note that rYearNums is sorted in numerical order.
3329 */ 3332 */
3330QDate Recurrence::getLastDateInYear(const QDate &latestDate) const 3333QDate Recurrence::getLastDateInYear(const QDate &latestDate) const
3331{ 3334{
3332 QPtrListIterator<int> it(rYearNums); 3335 Q3PtrListIterator<int> it(rYearNums);
3333 switch (recurs) { 3336 switch (recurs) {
3334 case rYearlyMonth: { 3337 case rYearlyMonth: {
3335 int day = recurStart().date().day(); 3338 int day = recurStart().date().day();
3336 int latestYear = latestDate.year(); 3339 int latestYear = latestDate.year();
3337 int latestMonth = latestDate.month(); 3340 int latestMonth = latestDate.month();
3338 if (latestDate.day() > day) { 3341 if (latestDate.day() > day) {
3339 // The latest date is earlier in the month than the recurrence date, 3342 // The latest date is earlier in the month than the recurrence date,
3340 // so skip to the previous month before starting to check 3343 // so skip to the previous month before starting to check
3341 if (--latestMonth <= 0) 3344 if (--latestMonth <= 0)
3342 return QDate(); 3345 return QDate();
3343 } 3346 }
3344 for (it.toLast(); it.current(); --it) { 3347 for (it.toLast(); it.current(); --it) {
3345 int month = *it.current(); 3348 int month = *it.current();
3346 if (month <= latestMonth) { 3349 if (month <= latestMonth) {
3347 if (day <= 28 || QDate::isValid(latestYear, month, day)) 3350 if (day <= 28 || QDate::isValid(latestYear, month, day))
3348 return QDate(latestYear, month, day); 3351 return QDate(latestYear, month, day);
3349 if (day == 29 && month == 2) { 3352 if (day == 29 && month == 2) {
3350 // It's a recurrence on February 29th, in a non-leap year 3353 // It's a recurrence on February 29th, in a non-leap year
3351 switch (mFeb29YearlyType) { 3354 switch (mFeb29YearlyType) {
3352 case rMar1: 3355 case rMar1:
3353 if (latestMonth >= 3) 3356 if (latestMonth >= 3)
3354 return QDate(latestYear, 3, 1); 3357 return QDate(latestYear, 3, 1);
3355 break; 3358 break;
3356 case rFeb28: 3359 case rFeb28:
3357 return QDate(latestYear, 2, 28); 3360 return QDate(latestYear, 2, 28);
3358 case rFeb29: 3361 case rFeb29:
3359 break; 3362 break;
3360 } 3363 }
3361 } 3364 }
3362 } 3365 }
3363 } 3366 }
3364 break; 3367 break;
3365 } 3368 }
3366 case rYearlyPos: { 3369 case rYearlyPos: {
3367 QValueList<int> dayList; 3370 Q3ValueList<int> dayList;
3368 int latestYear = latestDate.year(); 3371 int latestYear = latestDate.year();
3369 int latestMonth = latestDate.month(); 3372 int latestMonth = latestDate.month();
3370 int latestDay = latestDate.day(); 3373 int latestDay = latestDate.day();
3371 for (it.toLast(); it.current(); --it) { 3374 for (it.toLast(); it.current(); --it) {
3372 int month = *it.current(); 3375 int month = *it.current();
3373 if (month <= latestMonth) { 3376 if (month <= latestMonth) {
3374 QDate monthBegin(latestYear, month, 1); 3377 QDate monthBegin(latestYear, month, 1);
3375 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek()); 3378 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
3376 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) { 3379 for (Q3ValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
3377 if (*id <= latestDay) 3380 if (*id <= latestDay)
3378 return monthBegin.addDays(*id - 1); 3381 return monthBegin.addDays(*id - 1);
3379 } 3382 }
3380 latestDay = 31; 3383 latestDay = 31;
3381 } 3384 }
3382 } 3385 }
3383 break; 3386 break;
3384 } 3387 }
3385 case rYearlyDay: { 3388 case rYearlyDay: {
3386 int latestDay = latestDate.dayOfYear(); 3389 int latestDay = latestDate.dayOfYear();
3387 for (it.toLast(); it.current(); --it) { 3390 for (it.toLast(); it.current(); --it) {
3388 int day = *it.current(); 3391 int day = *it.current();
3389 if (day <= latestDay) 3392 if (day <= latestDay)
3390 return latestDate.addDays(day - latestDay); 3393 return latestDate.addDays(day - latestDay);
3391 } 3394 }
3392 break; 3395 break;
3393 } 3396 }
3394 } 3397 }
3395 return QDate(); 3398 return QDate();
3396} 3399}
3397 3400
3398void Recurrence::dump() const 3401void Recurrence::dump() const
3399{ 3402{
3400 ; 3403 ;
3401} 3404}