summaryrefslogtreecommitdiffabout
path: root/libkcal/recurrence.cpp
authorzautrix <zautrix>2004-09-14 01:03:08 (UTC)
committer zautrix <zautrix>2004-09-14 01:03:08 (UTC)
commit30762fe125216362e1a6c1d5ec5d22d9525aa336 (patch) (unidiff)
tree4ff0fbf43efa921c86d64ff3f50baa9e59d207d9 /libkcal/recurrence.cpp
parent8ce7eae438dcd20f9c79fc0a36dfef0a6d3931eb (diff)
downloadkdepimpi-30762fe125216362e1a6c1d5ec5d22d9525aa336.zip
kdepimpi-30762fe125216362e1a6c1d5ec5d22d9525aa336.tar.gz
kdepimpi-30762fe125216362e1a6c1d5ec5d22d9525aa336.tar.bz2
Many bugfixes
Diffstat (limited to 'libkcal/recurrence.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libkcal/recurrence.cpp56
1 files changed, 44 insertions, 12 deletions
diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp
index dd74e10..e84f672 100644
--- a/libkcal/recurrence.cpp
+++ b/libkcal/recurrence.cpp
@@ -1,2184 +1,2216 @@
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 32
33using namespace KCal; 33using namespace KCal;
34 34
35Recurrence::Feb29Type Recurrence::mFeb29YearlyDefaultType = Recurrence::rMar1; 35Recurrence::Feb29Type Recurrence::mFeb29YearlyDefaultType = Recurrence::rMar1;
36 36
37 37
38Recurrence::Recurrence(Incidence *parent, int compatVersion) 38Recurrence::Recurrence(Incidence *parent, int compatVersion)
39: recurs(rNone), // by default, it's not a recurring event 39: recurs(rNone), // by default, it's not a recurring event
40 rWeekStart(1), // default is Monday 40 rWeekStart(1), // default is Monday
41 rDays(7), 41 rDays(7),
42 mFloats(parent ? parent->doesFloat() : false), 42 mFloats(parent ? parent->doesFloat() : false),
43 mRecurReadOnly(false), 43 mRecurReadOnly(false),
44 mRecurExDatesCount(0), 44 mRecurExDatesCount(0),
45 mFeb29YearlyType(mFeb29YearlyDefaultType), 45 mFeb29YearlyType(mFeb29YearlyDefaultType),
46 mCompatVersion(compatVersion ? compatVersion : INT_MAX), 46 mCompatVersion(compatVersion ? compatVersion : INT_MAX),
47 mCompatRecurs(rNone), 47 mCompatRecurs(rNone),
48 mCompatDuration(0), 48 mCompatDuration(0),
49 mParent(parent) 49 mParent(parent)
50{ 50{
51 rMonthDays.setAutoDelete( true ); 51 rMonthDays.setAutoDelete( true );
52 rMonthPositions.setAutoDelete( true ); 52 rMonthPositions.setAutoDelete( true );
53 rYearNums.setAutoDelete( true ); 53 rYearNums.setAutoDelete( true );
54} 54}
55 55
56Recurrence::Recurrence(const Recurrence &r, Incidence *parent) 56Recurrence::Recurrence(const Recurrence &r, Incidence *parent)
57: recurs(r.recurs), 57: recurs(r.recurs),
58 rWeekStart(r.rWeekStart), 58 rWeekStart(r.rWeekStart),
59 rDays(r.rDays.copy()), 59 rDays(r.rDays.copy()),
60 rFreq(r.rFreq), 60 rFreq(r.rFreq),
61 rDuration(r.rDuration), 61 rDuration(r.rDuration),
62 rEndDateTime(r.rEndDateTime), 62 rEndDateTime(r.rEndDateTime),
63 mRecurStart(r.mRecurStart), 63 mRecurStart(r.mRecurStart),
64 mFloats(r.mFloats), 64 mFloats(r.mFloats),
65 mRecurReadOnly(r.mRecurReadOnly), 65 mRecurReadOnly(r.mRecurReadOnly),
66 mRecurExDatesCount(r.mRecurExDatesCount), 66 mRecurExDatesCount(r.mRecurExDatesCount),
67 mFeb29YearlyType(r.mFeb29YearlyType), 67 mFeb29YearlyType(r.mFeb29YearlyType),
68 mCompatVersion(r.mCompatVersion), 68 mCompatVersion(r.mCompatVersion),
69 mCompatRecurs(r.mCompatRecurs), 69 mCompatRecurs(r.mCompatRecurs),
70 mCompatDuration(r.mCompatDuration), 70 mCompatDuration(r.mCompatDuration),
71 mParent(parent) 71 mParent(parent)
72{ 72{
73 for (QPtrListIterator<rMonthPos> mp(r.rMonthPositions); mp.current(); ++mp) { 73 for (QPtrListIterator<rMonthPos> mp(r.rMonthPositions); mp.current(); ++mp) {
74 rMonthPos *tmp = new rMonthPos; 74 rMonthPos *tmp = new rMonthPos;
75 tmp->rPos = mp.current()->rPos; 75 tmp->rPos = mp.current()->rPos;
76 tmp->negative = mp.current()->negative; 76 tmp->negative = mp.current()->negative;
77 tmp->rDays = mp.current()->rDays.copy(); 77 tmp->rDays = mp.current()->rDays.copy();
78 rMonthPositions.append(tmp); 78 rMonthPositions.append(tmp);
79 } 79 }
80 for (QPtrListIterator<int> md(r.rMonthDays); md.current(); ++md) { 80 for (QPtrListIterator<int> md(r.rMonthDays); md.current(); ++md) {
81 int *tmp = new int; 81 int *tmp = new int;
82 *tmp = *md.current(); 82 *tmp = *md.current();
83 rMonthDays.append(tmp); 83 rMonthDays.append(tmp);
84 } 84 }
85 for (QPtrListIterator<int> yn(r.rYearNums); yn.current(); ++yn) { 85 for (QPtrListIterator<int> yn(r.rYearNums); yn.current(); ++yn) {
86 int *tmp = new int; 86 int *tmp = new int;
87 *tmp = *yn.current(); 87 *tmp = *yn.current();
88 rYearNums.append(tmp); 88 rYearNums.append(tmp);
89 } 89 }
90 rMonthDays.setAutoDelete( true ); 90 rMonthDays.setAutoDelete( true );
91 rMonthPositions.setAutoDelete( true ); 91 rMonthPositions.setAutoDelete( true );
92 rYearNums.setAutoDelete( true ); 92 rYearNums.setAutoDelete( true );
93} 93}
94 94
95Recurrence::~Recurrence() 95Recurrence::~Recurrence()
96{ 96{
97} 97}
98 98
99 99
100bool Recurrence::operator==( const Recurrence& r2 ) const 100bool Recurrence::operator==( const Recurrence& r2 ) const
101{ 101{
102 102
103 // the following line is obvious 103 // the following line is obvious
104 if ( recurs == rNone && r2.recurs == rNone ) 104 if ( recurs == rNone && r2.recurs == rNone )
105 return true; 105 return true;
106 // we need the above line, because two non recurring events may 106 // we need the above line, because two non recurring events may
107 // differ in the other settings, because one (or both) 107 // differ in the other settings, because one (or both)
108 // may be not initialized properly 108 // may be not initialized properly
109
109 if ( recurs != r2.recurs 110 if ( recurs != r2.recurs
110 || rFreq != r2.rFreq 111 || rFreq != r2.rFreq
111 || rDuration != r2.rDuration 112 || rDuration != r2.rDuration
112 || !rDuration && rEndDateTime != r2.rEndDateTime 113 || !rDuration && rEndDateTime != r2.rEndDateTime
113 || mRecurStart != r2.mRecurStart 114 || mRecurStart != r2.mRecurStart
114 || mFloats != r2.mFloats 115 || mFloats != r2.mFloats
115 || mRecurReadOnly != r2.mRecurReadOnly 116 || mRecurReadOnly != r2.mRecurReadOnly
116 || mRecurExDatesCount != r2.mRecurExDatesCount ) 117 || mRecurExDatesCount != r2.mRecurExDatesCount )
117 return false; 118 return false;
118 // no need to compare mCompat* and mParent 119 // no need to compare mCompat* and mParent
119 // OK to compare the pointers 120 // OK to compare the pointers
120 switch ( recurs ) 121 switch ( recurs )
121 { 122 {
122 case rWeekly: 123 case rWeekly:
123 return rDays == r2.rDays 124 return rDays == r2.rDays
124 && rWeekStart == r2.rWeekStart; 125 && rWeekStart == r2.rWeekStart;
125 case rMonthlyPos: 126 case rMonthlyPos: {
126 return rMonthPositions.count() == r2.rMonthPositions.count(); 127 QPtrList<rMonthPos> MonthPositions = rMonthPositions;
127 case rMonthlyDay: 128 QPtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions;
128 return rMonthDays.count() == r2.rMonthDays.count(); 129 if ( !MonthPositions.count() )
129 case rYearlyPos: 130 return false;
130 return rYearNums.count() == r2.rYearNums.count() 131 if ( !MonthPositions2.count() )
131 && rMonthPositions.count() == r2.rMonthPositions.count(); 132 return false;
132 case rYearlyMonth: 133 return MonthPositions.first()->rPos == MonthPositions2.first()->rPos;
133 return rYearNums.count() == r2.rYearNums.count() 134 }
134 && mFeb29YearlyType == r2.mFeb29YearlyType; 135 case rMonthlyDay: {
135 case rYearlyDay: 136 QPtrList<int> MonthDays = rMonthDays ;
136 return rYearNums == r2.rYearNums; 137 QPtrList<int> MonthDays2 = r2.rMonthDays ;
138 if ( !MonthDays.count() )
139 return false;
140 if ( !MonthDays2.count() )
141 return false;
142 return *MonthDays.first() == *MonthDays2.first() ;
143 }
144 case rYearlyPos: {
145
146 QPtrList<int> YearNums = rYearNums;
147 QPtrList<int> YearNums2 = r2.rYearNums;
148 if ( *YearNums.first() != *YearNums2.first() )
149 return false;
150 QPtrList<rMonthPos> MonthPositions = rMonthPositions;
151 QPtrList<rMonthPos> MonthPositions2 = r2.rMonthPositions;
152 if ( !MonthPositions.count() )
153 return false;
154 if ( !MonthPositions2.count() )
155 return false;
156 return MonthPositions.first()->rPos == MonthPositions2.first()->rPos;
157
158 }
159 case rYearlyMonth: {
160 QPtrList<int> YearNums = rYearNums;
161 QPtrList<int> YearNums2 = r2.rYearNums;
162 return ( *YearNums.first() == *YearNums2.first() && mFeb29YearlyType == r2.mFeb29YearlyType);
163 }
164 case rYearlyDay: {
165 QPtrList<int> YearNums = rYearNums;
166 QPtrList<int> YearNums2 = r2.rYearNums;
167 return ( *YearNums.first() == *YearNums2.first() );
168 }
137 case rNone: 169 case rNone:
138 case rMinutely: 170 case rMinutely:
139 case rHourly: 171 case rHourly:
140 case rDaily: 172 case rDaily:
141 default: 173 default:
142 return true; 174 return true;
143 } 175 }
144} 176}
145/* 177/*
146bool Recurrence::compareLists( const QPtrList<int> &l1 ,const QPtrList<int> &l2) 178bool Recurrence::compareLists( const QPtrList<int> &l1 ,const QPtrList<int> &l2)
147{ 179{
148 if ( l1.count() != l2.count() ) 180 if ( l1.count() != l2.count() )
149 return false; 181 return false;
150 int count = l1.count(); 182 int count = l1.count();
151 int i; 183 int i;
152 for ( i = 0; i < count ; ++i ) { 184 for ( i = 0; i < count ; ++i ) {
153 // if ( l1.at(i) != l2.at(i) ) 185 // if ( l1.at(i) != l2.at(i) )
154 return false; 186 return false;
155 qDebug("compüare "); 187 qDebug("compüare ");
156 } 188 }
157 return true; 189 return true;
158} 190}
159*/ 191*/
160QString Recurrence::recurrenceText() const 192QString Recurrence::recurrenceText() const
161{ 193{
162 QString recurText = i18n("No"); 194 QString recurText = i18n("No");
163 if ( recurs == Recurrence::rMinutely ) 195 if ( recurs == Recurrence::rMinutely )
164 recurText = i18n("minutely"); 196 recurText = i18n("minutely");
165 else if ( recurs == Recurrence::rHourly ) 197 else if ( recurs == Recurrence::rHourly )
166 recurText = i18n("hourly"); 198 recurText = i18n("hourly");
167 else if ( recurs == Recurrence::rDaily ) 199 else if ( recurs == Recurrence::rDaily )
168 recurText = i18n("daily"); 200 recurText = i18n("daily");
169 else if ( recurs == Recurrence::rWeekly ) 201 else if ( recurs == Recurrence::rWeekly )
170 recurText = i18n("weekly"); 202 recurText = i18n("weekly");
171 else if ( recurs == Recurrence::rMonthlyPos ) 203 else if ( recurs == Recurrence::rMonthlyPos )
172 recurText = i18n("monthly"); 204 recurText = i18n("monthly");
173 else if ( recurs == Recurrence::rMonthlyDay ) 205 else if ( recurs == Recurrence::rMonthlyDay )
174 recurText = i18n("day-monthly"); 206 recurText = i18n("day-monthly");
175 else if ( recurs == Recurrence::rYearlyMonth ) 207 else if ( recurs == Recurrence::rYearlyMonth )
176 recurText = i18n("month-yearly"); 208 recurText = i18n("month-yearly");
177 else if ( recurs == Recurrence::rYearlyDay ) 209 else if ( recurs == Recurrence::rYearlyDay )
178 recurText = i18n("day-yearly"); 210 recurText = i18n("day-yearly");
179 else if ( recurs == Recurrence::rYearlyPos ) 211 else if ( recurs == Recurrence::rYearlyPos )
180 recurText = i18n("position-yearly"); 212 recurText = i18n("position-yearly");
181 return recurText; 213 return recurText;
182} 214}
183 215
184void Recurrence::setCompatVersion(int version) 216void Recurrence::setCompatVersion(int version)
185{ 217{
186 mCompatVersion = version ? version : INT_MAX; 218 mCompatVersion = version ? version : INT_MAX;
187} 219}
188 220
189ushort Recurrence::doesRecur() const 221ushort Recurrence::doesRecur() const
190{ 222{
191 return recurs; 223 return recurs;
192} 224}
193 225
194bool Recurrence::recursOnPure(const QDate &qd) const 226bool Recurrence::recursOnPure(const QDate &qd) const
195{ 227{
196 switch(recurs) { 228 switch(recurs) {
197 case rMinutely: 229 case rMinutely:
198 return recursSecondly(qd, rFreq*60); 230 return recursSecondly(qd, rFreq*60);
199 case rHourly: 231 case rHourly:
200 return recursSecondly(qd, rFreq*3600); 232 return recursSecondly(qd, rFreq*3600);
201 case rDaily: 233 case rDaily:
202 return recursDaily(qd); 234 return recursDaily(qd);
203 case rWeekly: 235 case rWeekly:
204 return recursWeekly(qd); 236 return recursWeekly(qd);
205 case rMonthlyPos: 237 case rMonthlyPos:
206 case rMonthlyDay: 238 case rMonthlyDay:
207 return recursMonthly(qd); 239 return recursMonthly(qd);
208 case rYearlyMonth: 240 case rYearlyMonth:
209 return recursYearlyByMonth(qd); 241 return recursYearlyByMonth(qd);
210 case rYearlyDay: 242 case rYearlyDay:
211 return recursYearlyByDay(qd); 243 return recursYearlyByDay(qd);
212 case rYearlyPos: 244 case rYearlyPos:
213 return recursYearlyByPos(qd); 245 return recursYearlyByPos(qd);
214 default: 246 default:
215 return false; 247 return false;
216 case rNone: 248 case rNone:
217 return false; 249 return false;
218 } // case 250 } // case
219 return false; 251 return false;
220} 252}
221 253
222bool Recurrence::recursAtPure(const QDateTime &dt) const 254bool Recurrence::recursAtPure(const QDateTime &dt) const
223{ 255{
224 switch(recurs) { 256 switch(recurs) {
225 case rMinutely: 257 case rMinutely:
226 return recursMinutelyAt(dt, rFreq); 258 return recursMinutelyAt(dt, rFreq);
227 case rHourly: 259 case rHourly:
228 return recursMinutelyAt(dt, rFreq*60); 260 return recursMinutelyAt(dt, rFreq*60);
229 default: 261 default:
230 if (dt.time() != mRecurStart.time()) 262 if (dt.time() != mRecurStart.time())
231 return false; 263 return false;
232 switch(recurs) { 264 switch(recurs) {
233 case rDaily: 265 case rDaily:
234 return recursDaily(dt.date()); 266 return recursDaily(dt.date());
235 case rWeekly: 267 case rWeekly:
236 return recursWeekly(dt.date()); 268 return recursWeekly(dt.date());
237 case rMonthlyPos: 269 case rMonthlyPos:
238 case rMonthlyDay: 270 case rMonthlyDay:
239 return recursMonthly(dt.date()); 271 return recursMonthly(dt.date());
240 case rYearlyMonth: 272 case rYearlyMonth:
241 return recursYearlyByMonth(dt.date()); 273 return recursYearlyByMonth(dt.date());
242 case rYearlyDay: 274 case rYearlyDay:
243 return recursYearlyByDay(dt.date()); 275 return recursYearlyByDay(dt.date());
244 case rYearlyPos: 276 case rYearlyPos:
245 return recursYearlyByPos(dt.date()); 277 return recursYearlyByPos(dt.date());
246 default: 278 default:
247 return false; 279 return false;
248 case rNone: 280 case rNone:
249 return false; 281 return false;
250 } 282 }
251 } // case 283 } // case
252 return false; 284 return false;
253} 285}
254 286
255QDate Recurrence::endDate() const 287QDate Recurrence::endDate() const
256{ 288{
257 int count = 0; 289 int count = 0;
258 QDate end; 290 QDate end;
259 if (recurs != rNone) { 291 if (recurs != rNone) {
260 if (rDuration < 0) 292 if (rDuration < 0)
261 return QDate(); // infinite recurrence 293 return QDate(); // infinite recurrence
262 if (rDuration == 0) 294 if (rDuration == 0)
263 return rEndDateTime.date(); 295 return rEndDateTime.date();
264 296
265 // The end date is determined by the recurrence count 297 // The end date is determined by the recurrence count
266 QDate dStart = mRecurStart.date(); 298 QDate dStart = mRecurStart.date();
267 switch (recurs) 299 switch (recurs)
268 { 300 {
269 case rMinutely: 301 case rMinutely:
270 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60).date(); 302 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60).date();
271 case rHourly: 303 case rHourly:
272 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600).date(); 304 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600).date();
273 case rDaily: 305 case rDaily:
274 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq); 306 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
275 307
276 case rWeekly: 308 case rWeekly:
277 count = weeklyCalc(END_DATE_AND_COUNT, end); 309 count = weeklyCalc(END_DATE_AND_COUNT, end);
278 break; 310 break;
279 case rMonthlyPos: 311 case rMonthlyPos:
280 case rMonthlyDay: 312 case rMonthlyDay:
281 count = monthlyCalc(END_DATE_AND_COUNT, end); 313 count = monthlyCalc(END_DATE_AND_COUNT, end);
282 break; 314 break;
283 case rYearlyMonth: 315 case rYearlyMonth:
284 count = yearlyMonthCalc(END_DATE_AND_COUNT, end); 316 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
285 break; 317 break;
286 case rYearlyDay: 318 case rYearlyDay:
287 count = yearlyDayCalc(END_DATE_AND_COUNT, end); 319 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
288 break; 320 break;
289 case rYearlyPos: 321 case rYearlyPos:
290 count = yearlyPosCalc(END_DATE_AND_COUNT, end); 322 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
291 break; 323 break;
292 default: 324 default:
293 // catch-all. Should never get here. 325 // catch-all. Should never get here.
294 kdDebug(5800) << "Control should never reach here in endDate()!" << endl; 326 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
295 break; 327 break;
296 } 328 }
297 } 329 }
298 if (!count) 330 if (!count)
299 return QDate(); // error - there is no recurrence 331 return QDate(); // error - there is no recurrence
300 return end; 332 return end;
301} 333}
302 334
303QDateTime Recurrence::endDateTime() const 335QDateTime Recurrence::endDateTime() const
304{ 336{
305 int count = 0; 337 int count = 0;
306 QDate end; 338 QDate end;
307 if (recurs != rNone) { 339 if (recurs != rNone) {
308 if (rDuration < 0) 340 if (rDuration < 0)
309 return QDateTime(); // infinite recurrence 341 return QDateTime(); // infinite recurrence
310 if (rDuration == 0) 342 if (rDuration == 0)
311 return rEndDateTime; 343 return rEndDateTime;
312 344
313 // The end date is determined by the recurrence count 345 // The end date is determined by the recurrence count
314 QDate dStart = mRecurStart.date(); 346 QDate dStart = mRecurStart.date();
315 switch (recurs) 347 switch (recurs)
316 { 348 {
317 case rMinutely: 349 case rMinutely:
318 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60); 350 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*60);
319 case rHourly: 351 case rHourly:
320 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600); 352 return mRecurStart.addSecs((rDuration-1+mRecurExDatesCount)*rFreq*3600);
321 case rDaily: 353 case rDaily:
322 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq); 354 return dStart.addDays((rDuration-1+mRecurExDatesCount)*rFreq);
323 355
324 case rWeekly: 356 case rWeekly:
325 count = weeklyCalc(END_DATE_AND_COUNT, end); 357 count = weeklyCalc(END_DATE_AND_COUNT, end);
326 break; 358 break;
327 case rMonthlyPos: 359 case rMonthlyPos:
328 case rMonthlyDay: 360 case rMonthlyDay:
329 count = monthlyCalc(END_DATE_AND_COUNT, end); 361 count = monthlyCalc(END_DATE_AND_COUNT, end);
330 break; 362 break;
331 case rYearlyMonth: 363 case rYearlyMonth:
332 count = yearlyMonthCalc(END_DATE_AND_COUNT, end); 364 count = yearlyMonthCalc(END_DATE_AND_COUNT, end);
333 break; 365 break;
334 case rYearlyDay: 366 case rYearlyDay:
335 count = yearlyDayCalc(END_DATE_AND_COUNT, end); 367 count = yearlyDayCalc(END_DATE_AND_COUNT, end);
336 break; 368 break;
337 case rYearlyPos: 369 case rYearlyPos:
338 count = yearlyPosCalc(END_DATE_AND_COUNT, end); 370 count = yearlyPosCalc(END_DATE_AND_COUNT, end);
339 break; 371 break;
340 default: 372 default:
341 // catch-all. Should never get here. 373 // catch-all. Should never get here.
342 kdDebug(5800) << "Control should never reach here in endDate()!" << endl; 374 kdDebug(5800) << "Control should never reach here in endDate()!" << endl;
343 break; 375 break;
344 } 376 }
345 } 377 }
346 if (!count) 378 if (!count)
347 return QDateTime(); // error - there is no recurrence 379 return QDateTime(); // error - there is no recurrence
348 return QDateTime(end, mRecurStart.time()); 380 return QDateTime(end, mRecurStart.time());
349} 381}
350 382
351int Recurrence::durationTo(const QDate &date) const 383int Recurrence::durationTo(const QDate &date) const
352{ 384{
353 QDate d = date; 385 QDate d = date;
354 return recurCalc(COUNT_TO_DATE, d); 386 return recurCalc(COUNT_TO_DATE, d);
355} 387}
356 388
357int Recurrence::durationTo(const QDateTime &datetime) const 389int Recurrence::durationTo(const QDateTime &datetime) const
358{ 390{
359 QDateTime dt = datetime; 391 QDateTime dt = datetime;
360 return recurCalc(COUNT_TO_DATE, dt); 392 return recurCalc(COUNT_TO_DATE, dt);
361} 393}
362 394
363void Recurrence::unsetRecurs() 395void Recurrence::unsetRecurs()
364{ 396{
365 if (mRecurReadOnly) return; 397 if (mRecurReadOnly) return;
366 recurs = rNone; 398 recurs = rNone;
367 rMonthPositions.clear(); 399 rMonthPositions.clear();
368 rMonthDays.clear(); 400 rMonthDays.clear();
369 rYearNums.clear(); 401 rYearNums.clear();
370} 402}
371 403
372void Recurrence::setRecurStart(const QDateTime &start) 404void Recurrence::setRecurStart(const QDateTime &start)
373{ 405{
374 mRecurStart = start; 406 mRecurStart = start;
375 mFloats = false; 407 mFloats = false;
376 switch (recurs) 408 switch (recurs)
377 { 409 {
378 case rMinutely: 410 case rMinutely:
379 case rHourly: 411 case rHourly:
380 break; 412 break;
381 case rDaily: 413 case rDaily:
382 case rWeekly: 414 case rWeekly:
383 case rMonthlyPos: 415 case rMonthlyPos:
384 case rMonthlyDay: 416 case rMonthlyDay:
385 case rYearlyMonth: 417 case rYearlyMonth:
386 case rYearlyDay: 418 case rYearlyDay:
387 case rYearlyPos: 419 case rYearlyPos:
388 default: 420 default:
389 rEndDateTime.setTime(start.time()); 421 rEndDateTime.setTime(start.time());
390 break; 422 break;
391 } 423 }
392} 424}
393 425
394void Recurrence::setRecurStart(const QDate &start) 426void Recurrence::setRecurStart(const QDate &start)
395{ 427{
396 mRecurStart.setDate(start); 428 mRecurStart.setDate(start);
397 mRecurStart.setTime(QTime(0,0,0)); 429 mRecurStart.setTime(QTime(0,0,0));
398 switch (recurs) 430 switch (recurs)
399 { 431 {
400 case rMinutely: 432 case rMinutely:
401 case rHourly: 433 case rHourly:
402 break; 434 break;
403 case rDaily: 435 case rDaily:
404 case rWeekly: 436 case rWeekly:
405 case rMonthlyPos: 437 case rMonthlyPos:
406 case rMonthlyDay: 438 case rMonthlyDay:
407 case rYearlyMonth: 439 case rYearlyMonth:
408 case rYearlyDay: 440 case rYearlyDay:
409 case rYearlyPos: 441 case rYearlyPos:
410 default: 442 default:
411 mFloats = true; 443 mFloats = true;
412 break; 444 break;
413 } 445 }
414} 446}
415 447
416void Recurrence::setFloats(bool f) 448void Recurrence::setFloats(bool f)
417{ 449{
418 switch (recurs) 450 switch (recurs)
419 { 451 {
420 case rDaily: 452 case rDaily:
421 case rWeekly: 453 case rWeekly:
422 case rMonthlyPos: 454 case rMonthlyPos:
423 case rMonthlyDay: 455 case rMonthlyDay:
424 case rYearlyMonth: 456 case rYearlyMonth:
425 case rYearlyDay: 457 case rYearlyDay:
426 case rYearlyPos: 458 case rYearlyPos:
427 break; 459 break;
428 case rMinutely: 460 case rMinutely:
429 case rHourly: 461 case rHourly:
430 default: 462 default:
431 return; // can't set sub-daily to floating 463 return; // can't set sub-daily to floating
432 } 464 }
433 mFloats = f; 465 mFloats = f;
434 if (f) { 466 if (f) {
435 mRecurStart.setTime(QTime(0,0,0)); 467 mRecurStart.setTime(QTime(0,0,0));
436 rEndDateTime.setTime(QTime(0,0,0)); 468 rEndDateTime.setTime(QTime(0,0,0));
437 } 469 }
438} 470}
439 471
440int Recurrence::frequency() const 472int Recurrence::frequency() const
441{ 473{
442 return rFreq; 474 return rFreq;
443} 475}
444 476
445int Recurrence::duration() const 477int Recurrence::duration() const
446{ 478{
447 return rDuration; 479 return rDuration;
448} 480}
449 481
450void Recurrence::setDuration(int _rDuration) 482void Recurrence::setDuration(int _rDuration)
451{ 483{
452 if (mRecurReadOnly) return; 484 if (mRecurReadOnly) return;
453 if (_rDuration > 0) { 485 if (_rDuration > 0) {
454 rDuration = _rDuration; 486 rDuration = _rDuration;
455 // Compatibility mode is only needed when reading the calendar in ICalFormatImpl, 487 // Compatibility mode is only needed when reading the calendar in ICalFormatImpl,
456 // so explicitly setting the duration means no backwards compatibility is needed. 488 // so explicitly setting the duration means no backwards compatibility is needed.
457 mCompatDuration = 0; 489 mCompatDuration = 0;
458 } 490 }
459} 491}
460 492
461QString Recurrence::endDateStr(bool shortfmt) const 493QString Recurrence::endDateStr(bool shortfmt) const
462{ 494{
463 return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt); 495 return KGlobal::locale()->formatDate(rEndDateTime.date(),shortfmt);
464} 496}
465 497
466const QBitArray &Recurrence::days() const 498const QBitArray &Recurrence::days() const
467{ 499{
468 return rDays; 500 return rDays;
469} 501}
470 502
471const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const 503const QPtrList<Recurrence::rMonthPos> &Recurrence::monthPositions() const
472{ 504{
473 return rMonthPositions; 505 return rMonthPositions;
474} 506}
475 507
476const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const 508const QPtrList<Recurrence::rMonthPos> &Recurrence::yearMonthPositions() const
477{ 509{
478 return rMonthPositions; 510 return rMonthPositions;
479} 511}
480 512
481const QPtrList<int> &Recurrence::monthDays() const 513const QPtrList<int> &Recurrence::monthDays() const
482{ 514{
483 return rMonthDays; 515 return rMonthDays;
484} 516}
485 517
486void Recurrence::setMinutely(int _rFreq, int _rDuration) 518void Recurrence::setMinutely(int _rFreq, int _rDuration)
487{ 519{
488 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 520 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
489 return; 521 return;
490 setDailySub(rMinutely, _rFreq, _rDuration); 522 setDailySub(rMinutely, _rFreq, _rDuration);
491} 523}
492 524
493void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime) 525void Recurrence::setMinutely(int _rFreq, const QDateTime &_rEndDateTime)
494{ 526{
495 if (mRecurReadOnly) return; 527 if (mRecurReadOnly) return;
496 rEndDateTime = _rEndDateTime; 528 rEndDateTime = _rEndDateTime;
497 setDailySub(rMinutely, _rFreq, 0); 529 setDailySub(rMinutely, _rFreq, 0);
498} 530}
499 531
500void Recurrence::setHourly(int _rFreq, int _rDuration) 532void Recurrence::setHourly(int _rFreq, int _rDuration)
501{ 533{
502 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 534 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
503 return; 535 return;
504 setDailySub(rHourly, _rFreq, _rDuration); 536 setDailySub(rHourly, _rFreq, _rDuration);
505} 537}
506 538
507void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime) 539void Recurrence::setHourly(int _rFreq, const QDateTime &_rEndDateTime)
508{ 540{
509 if (mRecurReadOnly) return; 541 if (mRecurReadOnly) return;
510 rEndDateTime = _rEndDateTime; 542 rEndDateTime = _rEndDateTime;
511 setDailySub(rHourly, _rFreq, 0); 543 setDailySub(rHourly, _rFreq, 0);
512} 544}
513 545
514void Recurrence::setDaily(int _rFreq, int _rDuration) 546void Recurrence::setDaily(int _rFreq, int _rDuration)
515{ 547{
516 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 548 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
517 return; 549 return;
518 setDailySub(rDaily, _rFreq, _rDuration); 550 setDailySub(rDaily, _rFreq, _rDuration);
519} 551}
520 552
521void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate) 553void Recurrence::setDaily(int _rFreq, const QDate &_rEndDate)
522{ 554{
523 if (mRecurReadOnly) return; 555 if (mRecurReadOnly) return;
524 rEndDateTime.setDate(_rEndDate); 556 rEndDateTime.setDate(_rEndDate);
525 rEndDateTime.setTime(mRecurStart.time()); 557 rEndDateTime.setTime(mRecurStart.time());
526 setDailySub(rDaily, _rFreq, 0); 558 setDailySub(rDaily, _rFreq, 0);
527} 559}
528 560
529void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays, 561void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays,
530 int _rDuration, int _rWeekStart) 562 int _rDuration, int _rWeekStart)
531{ 563{
532 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 564 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
533 return; 565 return;
534 recurs = rWeekly; 566 recurs = rWeekly;
535 567
536 rFreq = _rFreq; 568 rFreq = _rFreq;
537 rDays = _rDays; 569 rDays = _rDays;
538 rWeekStart = _rWeekStart; 570 rWeekStart = _rWeekStart;
539 rDuration = _rDuration; 571 rDuration = _rDuration;
540 if (mCompatVersion < 310 && _rDuration > 0) { 572 if (mCompatVersion < 310 && _rDuration > 0) {
541 // Backwards compatibility for KDE < 3.1. 573 // Backwards compatibility for KDE < 3.1.
542 // rDuration was set to the number of time periods to recur, 574 // rDuration was set to the number of time periods to recur,
543 // with week start always on a Monday. 575 // with week start always on a Monday.
544 // Convert this to the number of occurrences. 576 // Convert this to the number of occurrences.
545 mCompatDuration = _rDuration; 577 mCompatDuration = _rDuration;
546 int weeks = ((mCompatDuration-1+mRecurExDatesCount)*7) + (7 - mRecurStart.date().dayOfWeek()); 578 int weeks = ((mCompatDuration-1+mRecurExDatesCount)*7) + (7 - mRecurStart.date().dayOfWeek());
547 QDate end(mRecurStart.date().addDays(weeks * rFreq)); 579 QDate end(mRecurStart.date().addDays(weeks * rFreq));
548 rDuration = INT_MAX; // ensure that weeklyCalc() does its job correctly 580 rDuration = INT_MAX; // ensure that weeklyCalc() does its job correctly
549 rDuration = weeklyCalc(COUNT_TO_DATE, end); 581 rDuration = weeklyCalc(COUNT_TO_DATE, end);
550 } else { 582 } else {
551 mCompatDuration = 0; 583 mCompatDuration = 0;
552 } 584 }
553 rMonthPositions.clear(); 585 rMonthPositions.clear();
554 rMonthDays.clear(); 586 rMonthDays.clear();
555 if (mParent) mParent->updated(); 587 if (mParent) mParent->updated();
556} 588}
557 589
558void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays, 590void Recurrence::setWeekly(int _rFreq, const QBitArray &_rDays,
559 const QDate &_rEndDate, int _rWeekStart) 591 const QDate &_rEndDate, int _rWeekStart)
560{ 592{
561 if (mRecurReadOnly) return; 593 if (mRecurReadOnly) return;
562 recurs = rWeekly; 594 recurs = rWeekly;
563 595
564 rFreq = _rFreq; 596 rFreq = _rFreq;
565 rDays = _rDays; 597 rDays = _rDays;
566 rWeekStart = _rWeekStart; 598 rWeekStart = _rWeekStart;
567 rEndDateTime.setDate(_rEndDate); 599 rEndDateTime.setDate(_rEndDate);
568 rEndDateTime.setTime(mRecurStart.time()); 600 rEndDateTime.setTime(mRecurStart.time());
569 rDuration = 0; // set to 0 because there is an end date 601 rDuration = 0; // set to 0 because there is an end date
570 mCompatDuration = 0; 602 mCompatDuration = 0;
571 rMonthPositions.clear(); 603 rMonthPositions.clear();
572 rMonthDays.clear(); 604 rMonthDays.clear();
573 rYearNums.clear(); 605 rYearNums.clear();
574 if (mParent) mParent->updated(); 606 if (mParent) mParent->updated();
575} 607}
576 608
577void Recurrence::setMonthly(short type, int _rFreq, int _rDuration) 609void Recurrence::setMonthly(short type, int _rFreq, int _rDuration)
578{ 610{
579 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 611 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
580 return; 612 return;
581 recurs = type; 613 recurs = type;
582 614
583 rFreq = _rFreq; 615 rFreq = _rFreq;
584 rDuration = _rDuration; 616 rDuration = _rDuration;
585 if (mCompatVersion < 310) 617 if (mCompatVersion < 310)
586 mCompatDuration = (_rDuration > 0) ? _rDuration : 0; 618 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
587 rYearNums.clear(); 619 rYearNums.clear();
588 if (mParent) mParent->updated(); 620 if (mParent) mParent->updated();
589} 621}
590 622
591void Recurrence::setMonthly(short type, int _rFreq, 623void Recurrence::setMonthly(short type, int _rFreq,
592 const QDate &_rEndDate) 624 const QDate &_rEndDate)
593{ 625{
594 if (mRecurReadOnly) return; 626 if (mRecurReadOnly) return;
595 recurs = type; 627 recurs = type;
596 628
597 rFreq = _rFreq; 629 rFreq = _rFreq;
598 rEndDateTime.setDate(_rEndDate); 630 rEndDateTime.setDate(_rEndDate);
599 rEndDateTime.setTime(mRecurStart.time()); 631 rEndDateTime.setTime(mRecurStart.time());
600 rDuration = 0; // set to 0 because there is an end date 632 rDuration = 0; // set to 0 because there is an end date
601 mCompatDuration = 0; 633 mCompatDuration = 0;
602 rYearNums.clear(); 634 rYearNums.clear();
603 if (mParent) mParent->updated(); 635 if (mParent) mParent->updated();
604} 636}
605 637
606void Recurrence::addMonthlyPos(short _rPos, const QBitArray &_rDays) 638void Recurrence::addMonthlyPos(short _rPos, const QBitArray &_rDays)
607{ 639{
608 if (recurs == rMonthlyPos) 640 if (recurs == rMonthlyPos)
609 addMonthlyPos_(_rPos, _rDays); 641 addMonthlyPos_(_rPos, _rDays);
610} 642}
611 643
612void Recurrence::addMonthlyPos_(short _rPos, const QBitArray &_rDays) 644void Recurrence::addMonthlyPos_(short _rPos, const QBitArray &_rDays)
613{ 645{
614 if (mRecurReadOnly 646 if (mRecurReadOnly
615 || _rPos == 0 || _rPos > 5 || _rPos < -5) // invalid week number 647 || _rPos == 0 || _rPos > 5 || _rPos < -5) // invalid week number
616 return; 648 return;
617 649
618 for (rMonthPos* it = rMonthPositions.first(); it; it = rMonthPositions.next()) { 650 for (rMonthPos* it = rMonthPositions.first(); it; it = rMonthPositions.next()) {
619 int itPos = it->negative ? -it->rPos : it->rPos; 651 int itPos = it->negative ? -it->rPos : it->rPos;
620 if (_rPos == itPos) { 652 if (_rPos == itPos) {
621 // This week is already in the list. 653 // This week is already in the list.
622 // Combine the specified days with those in the list. 654 // Combine the specified days with those in the list.
623 it->rDays |= _rDays; 655 it->rDays |= _rDays;
624 if (mParent) mParent->updated(); 656 if (mParent) mParent->updated();
625 return; 657 return;
626 } 658 }
627 } 659 }
628 // Add the new position to the list 660 // Add the new position to the list
629 rMonthPos *tmpPos = new rMonthPos; 661 rMonthPos *tmpPos = new rMonthPos;
630 if (_rPos > 0) { 662 if (_rPos > 0) {
631 tmpPos->rPos = _rPos; 663 tmpPos->rPos = _rPos;
632 tmpPos->negative = false; 664 tmpPos->negative = false;
633 } else { 665 } else {
634 tmpPos->rPos = -_rPos; // take abs() 666 tmpPos->rPos = -_rPos; // take abs()
635 tmpPos->negative = true; 667 tmpPos->negative = true;
636 } 668 }
637 tmpPos->rDays = _rDays; 669 tmpPos->rDays = _rDays;
638 tmpPos->rDays.detach(); 670 tmpPos->rDays.detach();
639 rMonthPositions.append(tmpPos); 671 rMonthPositions.append(tmpPos);
640 672
641 if (mCompatVersion < 310 && mCompatDuration > 0) { 673 if (mCompatVersion < 310 && mCompatDuration > 0) {
642 // Backwards compatibility for KDE < 3.1. 674 // Backwards compatibility for KDE < 3.1.
643 // rDuration was set to the number of time periods to recur. 675 // rDuration was set to the number of time periods to recur.
644 // Convert this to the number of occurrences. 676 // Convert this to the number of occurrences.
645 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq; 677 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq;
646 int month = mRecurStart.date().month() - 1 + monthsAhead; 678 int month = mRecurStart.date().month() - 1 + monthsAhead;
647 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31); 679 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31);
648 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly 680 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly
649 rDuration = recurCalc(COUNT_TO_DATE, end); 681 rDuration = recurCalc(COUNT_TO_DATE, end);
650 } 682 }
651 683
652 if (mParent) mParent->updated(); 684 if (mParent) mParent->updated();
653} 685}
654 686
655void Recurrence::addMonthlyDay(short _rDay) 687void Recurrence::addMonthlyDay(short _rDay)
656{ 688{
657 if (mRecurReadOnly || (recurs != rMonthlyDay && recurs != rYearlyMonth) 689 if (mRecurReadOnly || (recurs != rMonthlyDay && recurs != rYearlyMonth)
658 || _rDay == 0 || _rDay > 31 || _rDay < -31) // invalid day number 690 || _rDay == 0 || _rDay > 31 || _rDay < -31) // invalid day number
659 return; 691 return;
660 for (int* it = rMonthDays.first(); it; it = rMonthDays.next()) { 692 for (int* it = rMonthDays.first(); it; it = rMonthDays.next()) {
661 if (_rDay == *it) 693 if (_rDay == *it)
662 return; // this day is already in the list - avoid duplication 694 return; // this day is already in the list - avoid duplication
663 } 695 }
664 int *tmpDay = new int; 696 int *tmpDay = new int;
665 *tmpDay = _rDay; 697 *tmpDay = _rDay;
666 rMonthDays.append(tmpDay); 698 rMonthDays.append(tmpDay);
667 699
668 if (mCompatVersion < 310 && mCompatDuration > 0) { 700 if (mCompatVersion < 310 && mCompatDuration > 0) {
669 // Backwards compatibility for KDE < 3.1. 701 // Backwards compatibility for KDE < 3.1.
670 // rDuration was set to the number of time periods to recur. 702 // rDuration was set to the number of time periods to recur.
671 // Convert this to the number of occurrences. 703 // Convert this to the number of occurrences.
672 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq; 704 int monthsAhead = (mCompatDuration-1+mRecurExDatesCount) * rFreq;
673 int month = mRecurStart.date().month() - 1 + monthsAhead; 705 int month = mRecurStart.date().month() - 1 + monthsAhead;
674 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31); 706 QDate end(mRecurStart.date().year() + month/12, month%12 + 1, 31);
675 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly 707 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly
676 rDuration = recurCalc(COUNT_TO_DATE, end); 708 rDuration = recurCalc(COUNT_TO_DATE, end);
677 } 709 }
678 710
679 if (mParent) mParent->updated(); 711 if (mParent) mParent->updated();
680} 712}
681 713
682void Recurrence::setYearly(int type, int _rFreq, int _rDuration) 714void Recurrence::setYearly(int type, int _rFreq, int _rDuration)
683{ 715{
684 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 716 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
685 return; 717 return;
686 if (mCompatVersion < 310) 718 if (mCompatVersion < 310)
687 mCompatDuration = (_rDuration > 0) ? _rDuration : 0; 719 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
688 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, _rDuration); 720 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, _rDuration);
689} 721}
690 722
691void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate) 723void Recurrence::setYearly(int type, int _rFreq, const QDate &_rEndDate)
692{ 724{
693 if (mRecurReadOnly) return; 725 if (mRecurReadOnly) return;
694 rEndDateTime.setDate(_rEndDate); 726 rEndDateTime.setDate(_rEndDate);
695 rEndDateTime.setTime(mRecurStart.time()); 727 rEndDateTime.setTime(mRecurStart.time());
696 mCompatDuration = 0; 728 mCompatDuration = 0;
697 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, 0); 729 setYearly_(type, mFeb29YearlyDefaultType, _rFreq, 0);
698} 730}
699 731
700void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, int _rDuration) 732void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, int _rDuration)
701{ 733{
702 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1) 734 if (mRecurReadOnly || _rDuration == 0 || _rDuration < -1)
703 return; 735 return;
704 if (mCompatVersion < 310) 736 if (mCompatVersion < 310)
705 mCompatDuration = (_rDuration > 0) ? _rDuration : 0; 737 mCompatDuration = (_rDuration > 0) ? _rDuration : 0;
706 setYearly_(rYearlyMonth, type, _rFreq, _rDuration); 738 setYearly_(rYearlyMonth, type, _rFreq, _rDuration);
707} 739}
708 740
709void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, const QDate &_rEndDate) 741void Recurrence::setYearlyByDate(Feb29Type type, int _rFreq, const QDate &_rEndDate)
710{ 742{
711 if (mRecurReadOnly) return; 743 if (mRecurReadOnly) return;
712 rEndDateTime.setDate(_rEndDate); 744 rEndDateTime.setDate(_rEndDate);
713 rEndDateTime.setTime(mRecurStart.time()); 745 rEndDateTime.setTime(mRecurStart.time());
714 mCompatDuration = 0; 746 mCompatDuration = 0;
715 setYearly_(rYearlyMonth, type, _rFreq, 0); 747 setYearly_(rYearlyMonth, type, _rFreq, 0);
716} 748}
717 749
718void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays) 750void Recurrence::addYearlyMonthPos(short _rPos, const QBitArray &_rDays)
719{ 751{
720 if (recurs == rYearlyPos) 752 if (recurs == rYearlyPos)
721 addMonthlyPos_(_rPos, _rDays); 753 addMonthlyPos_(_rPos, _rDays);
722} 754}
723 755
724const QPtrList<int> &Recurrence::yearNums() const 756const QPtrList<int> &Recurrence::yearNums() const
725{ 757{
726 return rYearNums; 758 return rYearNums;
727} 759}
728void Recurrence::addYearlyMonth(short _rPos ) 760void Recurrence::addYearlyMonth(short _rPos )
729{ 761{
730 if (mRecurReadOnly || recurs != rYearlyMonth) // invalid day/month number 762 if (mRecurReadOnly || recurs != rYearlyMonth) // invalid day/month number
731 return; 763 return;
732 rMonthPos *tmpPos = new rMonthPos; 764 rMonthPos *tmpPos = new rMonthPos;
733 if ( _rPos > 0) { 765 if ( _rPos > 0) {
734 tmpPos->rPos = _rPos; 766 tmpPos->rPos = _rPos;
735 tmpPos->negative = false; 767 tmpPos->negative = false;
736 } else { 768 } else {
737 tmpPos->rPos = -_rPos; // take abs() 769 tmpPos->rPos = -_rPos; // take abs()
738 tmpPos->negative = true; 770 tmpPos->negative = true;
739 } 771 }
740 rMonthPositions.append(tmpPos); 772 rMonthPositions.append(tmpPos);
741} 773}
742void Recurrence::addYearlyNum(short _rNum) 774void Recurrence::addYearlyNum(short _rNum)
743{ 775{
744 if (mRecurReadOnly 776 if (mRecurReadOnly
745 || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos) 777 || (recurs != rYearlyMonth && recurs != rYearlyDay && recurs != rYearlyPos)
746 || _rNum <= 0) // invalid day/month number 778 || _rNum <= 0) // invalid day/month number
747 return; 779 return;
748 780
749 if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) { 781 if (mCompatVersion < 310 && mCompatRecurs == rYearlyDay) {
750 // Backwards compatibility for KDE < 3.1. 782 // Backwards compatibility for KDE < 3.1.
751 // Dates were stored as day numbers, with a fiddle to take account of leap years. 783 // Dates were stored as day numbers, with a fiddle to take account of leap years.
752 // Convert the day number to a month. 784 // Convert the day number to a month.
753 if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366)) 785 if (_rNum <= 0 || _rNum > 366 || (_rNum == 366 && mRecurStart.date().daysInYear() < 366))
754 return; // invalid day number 786 return; // invalid day number
755 _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month(); 787 _rNum = QDate(mRecurStart.date().year(), 1, 1).addDays(_rNum - 1).month();
756 } else 788 } else
757 if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12 789 if ((recurs == rYearlyMonth || recurs == rYearlyPos) && _rNum > 12
758 || recurs == rYearlyDay && _rNum > 366) 790 || recurs == rYearlyDay && _rNum > 366)
759 return; // invalid day number 791 return; // invalid day number
760 792
761 uint i = 0; 793 uint i = 0;
762 for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) { 794 for (int* it = rYearNums.first(); it && _rNum >= *it; it = rYearNums.next()) {
763 if (_rNum == *it) 795 if (_rNum == *it)
764 return; // this day/month is already in the list - avoid duplication 796 return; // this day/month is already in the list - avoid duplication
765 ++i; 797 ++i;
766 } 798 }
767 799
768 int *tmpNum = new int; 800 int *tmpNum = new int;
769 *tmpNum = _rNum; 801 *tmpNum = _rNum;
770 rYearNums.insert(i, tmpNum); // insert the day/month in a sorted position 802 rYearNums.insert(i, tmpNum); // insert the day/month in a sorted position
771 803
772 if (mCompatVersion < 310 && mCompatDuration > 0) { 804 if (mCompatVersion < 310 && mCompatDuration > 0) {
773 // Backwards compatibility for KDE < 3.1. 805 // Backwards compatibility for KDE < 3.1.
774 // rDuration was set to the number of time periods to recur. 806 // rDuration was set to the number of time periods to recur.
775 // Convert this to the number of occurrences. 807 // Convert this to the number of occurrences.
776 QDate end(mRecurStart.date().year() + (mCompatDuration-1+mRecurExDatesCount)*rFreq, 12, 31); 808 QDate end(mRecurStart.date().year() + (mCompatDuration-1+mRecurExDatesCount)*rFreq, 12, 31);
777 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly 809 rDuration = INT_MAX; // ensure that recurCalc() does its job correctly
778 rDuration = recurCalc(COUNT_TO_DATE, end); 810 rDuration = recurCalc(COUNT_TO_DATE, end);
779 } 811 }
780 812
781 if (mParent) mParent->updated(); 813 if (mParent) mParent->updated();
782} 814}
783 815
784 816
785QDateTime Recurrence::getNextDateTime(const QDateTime &preDateTime, bool *last) const 817QDateTime Recurrence::getNextDateTime(const QDateTime &preDateTime, bool *last) const
786{ 818{
787 if (last) 819 if (last)
788 *last = false; 820 *last = false;
789 int freq; 821 int freq;
790 switch (recurs) 822 switch (recurs)
791 { 823 {
792 case rMinutely: 824 case rMinutely:
793 freq = rFreq * 60; 825 freq = rFreq * 60;
794 break; 826 break;
795 case rHourly: 827 case rHourly:
796 freq = rFreq * 3600; 828 freq = rFreq * 3600;
797 break; 829 break;
798 case rDaily: 830 case rDaily:
799 case rWeekly: 831 case rWeekly:
800 case rMonthlyPos: 832 case rMonthlyPos:
801 case rMonthlyDay: 833 case rMonthlyDay:
802 case rYearlyMonth: 834 case rYearlyMonth:
803 case rYearlyDay: 835 case rYearlyDay:
804 case rYearlyPos: { 836 case rYearlyPos: {
805 QDate preDate = preDateTime.date(); 837 QDate preDate = preDateTime.date();
806 if (!mFloats && mRecurStart.time() > preDateTime.time()) 838 if (!mFloats && mRecurStart.time() > preDateTime.time())
807 preDate = preDate.addDays(-1); 839 preDate = preDate.addDays(-1);
808 return QDateTime(getNextDateNoTime(preDate, last), mRecurStart.time()); 840 return QDateTime(getNextDateNoTime(preDate, last), mRecurStart.time());
809 } 841 }
810 default: 842 default:
811 return QDateTime(); 843 return QDateTime();
812 } 844 }
813 845
814 // It's a sub-daily recurrence 846 // It's a sub-daily recurrence
815 if (preDateTime < mRecurStart) 847 if (preDateTime < mRecurStart)
816 return mRecurStart; 848 return mRecurStart;
817 int count = mRecurStart.secsTo(preDateTime) / freq + 2; 849 int count = mRecurStart.secsTo(preDateTime) / freq + 2;
818 if (rDuration > 0) { 850 if (rDuration > 0) {
819 if (count > rDuration) 851 if (count > rDuration)
820 return QDateTime(); 852 return QDateTime();
821 if (last && count == rDuration) 853 if (last && count == rDuration)
822 *last = true; 854 *last = true;
823 } 855 }
824 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq); 856 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq);
825 if (rDuration == 0) { 857 if (rDuration == 0) {
826 if (endtime > rEndDateTime) 858 if (endtime > rEndDateTime)
827 return QDateTime(); 859 return QDateTime();
828 if (last && endtime == rEndDateTime) 860 if (last && endtime == rEndDateTime)
829 *last = true; 861 *last = true;
830 } 862 }
831 return endtime; 863 return endtime;
832} 864}
833 865
834QDate Recurrence::getNextDate(const QDate &preDate, bool *last) const 866QDate Recurrence::getNextDate(const QDate &preDate, bool *last) const
835{ 867{
836 if (last) 868 if (last)
837 *last = false; 869 *last = false;
838 switch (recurs) 870 switch (recurs)
839 { 871 {
840 case rMinutely: 872 case rMinutely:
841 case rHourly: 873 case rHourly:
842 return getNextDateTime(QDateTime(preDate, QTime(23,59,59)), last).date(); 874 return getNextDateTime(QDateTime(preDate, QTime(23,59,59)), last).date();
843 case rDaily: 875 case rDaily:
844 case rWeekly: 876 case rWeekly:
845 case rMonthlyPos: 877 case rMonthlyPos:
846 case rMonthlyDay: 878 case rMonthlyDay:
847 case rYearlyMonth: 879 case rYearlyMonth:
848 case rYearlyDay: 880 case rYearlyDay:
849 case rYearlyPos: 881 case rYearlyPos:
850 return getNextDateNoTime(preDate, last); 882 return getNextDateNoTime(preDate, last);
851 default: 883 default:
852 return QDate(); 884 return QDate();
853 } 885 }
854} 886}
855 887
856 888
857QDateTime Recurrence::getPreviousDateTime(const QDateTime &afterDateTime, bool *last) const 889QDateTime Recurrence::getPreviousDateTime(const QDateTime &afterDateTime, bool *last) const
858{ 890{
859 if (last) 891 if (last)
860 *last = false; 892 *last = false;
861 int freq; 893 int freq;
862 switch (recurs) 894 switch (recurs)
863 { 895 {
864 case rMinutely: 896 case rMinutely:
865 freq = rFreq * 60; 897 freq = rFreq * 60;
866 break; 898 break;
867 case rHourly: 899 case rHourly:
868 freq = rFreq * 3600; 900 freq = rFreq * 3600;
869 break; 901 break;
870 case rDaily: 902 case rDaily:
871 case rWeekly: 903 case rWeekly:
872 case rMonthlyPos: 904 case rMonthlyPos:
873 case rMonthlyDay: 905 case rMonthlyDay:
874 case rYearlyMonth: 906 case rYearlyMonth:
875 case rYearlyDay: 907 case rYearlyDay:
876 case rYearlyPos: { 908 case rYearlyPos: {
877 QDate afterDate = afterDateTime.date(); 909 QDate afterDate = afterDateTime.date();
878 if (!mFloats && mRecurStart.time() < afterDateTime.time()) 910 if (!mFloats && mRecurStart.time() < afterDateTime.time())
879 afterDate = afterDate.addDays(1); 911 afterDate = afterDate.addDays(1);
880 return QDateTime(getPreviousDateNoTime(afterDate, last), mRecurStart.time()); 912 return QDateTime(getPreviousDateNoTime(afterDate, last), mRecurStart.time());
881 } 913 }
882 default: 914 default:
883 return QDateTime(); 915 return QDateTime();
884 } 916 }
885 917
886 // It's a sub-daily recurrence 918 // It's a sub-daily recurrence
887 if (afterDateTime <= mRecurStart) 919 if (afterDateTime <= mRecurStart)
888 return QDateTime(); 920 return QDateTime();
889 int count = (mRecurStart.secsTo(afterDateTime) - 1) / freq + 1; 921 int count = (mRecurStart.secsTo(afterDateTime) - 1) / freq + 1;
890 if (rDuration > 0) { 922 if (rDuration > 0) {
891 if (count > rDuration) 923 if (count > rDuration)
892 count = rDuration; 924 count = rDuration;
893 if (last && count == rDuration) 925 if (last && count == rDuration)
894 *last = true; 926 *last = true;
895 } 927 }
896 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq); 928 QDateTime endtime = mRecurStart.addSecs((count - 1)*freq);
897 if (rDuration == 0) { 929 if (rDuration == 0) {
898 if (endtime > rEndDateTime) 930 if (endtime > rEndDateTime)
899 endtime = rEndDateTime; 931 endtime = rEndDateTime;
900 if (last && endtime == rEndDateTime) 932 if (last && endtime == rEndDateTime)
901 *last = true; 933 *last = true;
902 } 934 }
903 return endtime; 935 return endtime;
904} 936}
905 937
906QDate Recurrence::getPreviousDate(const QDate &afterDate, bool *last) const 938QDate Recurrence::getPreviousDate(const QDate &afterDate, bool *last) const
907{ 939{
908 if (last) 940 if (last)
909 *last = false; 941 *last = false;
910 switch (recurs) 942 switch (recurs)
911 { 943 {
912 case rMinutely: 944 case rMinutely:
913 case rHourly: 945 case rHourly:
914 return getPreviousDateTime(QDateTime(afterDate, QTime(0,0,0)), last).date(); 946 return getPreviousDateTime(QDateTime(afterDate, QTime(0,0,0)), last).date();
915 case rDaily: 947 case rDaily:
916 case rWeekly: 948 case rWeekly:
917 case rMonthlyPos: 949 case rMonthlyPos:
918 case rMonthlyDay: 950 case rMonthlyDay:
919 case rYearlyMonth: 951 case rYearlyMonth:
920 case rYearlyDay: 952 case rYearlyDay:
921 case rYearlyPos: 953 case rYearlyPos:
922 return getPreviousDateNoTime(afterDate, last); 954 return getPreviousDateNoTime(afterDate, last);
923 default: 955 default:
924 return QDate(); 956 return QDate();
925 } 957 }
926} 958}
927 959
928 960
929/***************************** PROTECTED FUNCTIONS ***************************/ 961/***************************** PROTECTED FUNCTIONS ***************************/
930 962
931bool Recurrence::recursSecondly(const QDate &qd, int secondFreq) const 963bool Recurrence::recursSecondly(const QDate &qd, int secondFreq) const
932{ 964{
933 if ((qd >= mRecurStart.date()) && 965 if ((qd >= mRecurStart.date()) &&
934 ((rDuration > 0) && (qd <= endDate()) || 966 ((rDuration > 0) && (qd <= endDate()) ||
935 ((rDuration == 0) && (qd <= rEndDateTime.date())) || 967 ((rDuration == 0) && (qd <= rEndDateTime.date())) ||
936 (rDuration == -1))) { 968 (rDuration == -1))) {
937 // The date queried falls within the range of the event. 969 // The date queried falls within the range of the event.
938 if (secondFreq < 24*3600) 970 if (secondFreq < 24*3600)
939 return true; // the event recurs at least once each day 971 return true; // the event recurs at least once each day
940 int after = mRecurStart.secsTo(QDateTime(qd)); 972 int after = mRecurStart.secsTo(QDateTime(qd));
941 if (after / secondFreq != (after + 24*3600) / secondFreq) 973 if (after / secondFreq != (after + 24*3600) / secondFreq)
942 return true; 974 return true;
943 } 975 }
944 return false; 976 return false;
945} 977}
946 978
947bool Recurrence::recursMinutelyAt(const QDateTime &dt, int minuteFreq) const 979bool Recurrence::recursMinutelyAt(const QDateTime &dt, int minuteFreq) const
948{ 980{
949 if ((dt >= mRecurStart) && 981 if ((dt >= mRecurStart) &&
950 ((rDuration > 0) && (dt <= endDateTime()) || 982 ((rDuration > 0) && (dt <= endDateTime()) ||
951 ((rDuration == 0) && (dt <= rEndDateTime)) || 983 ((rDuration == 0) && (dt <= rEndDateTime)) ||
952 (rDuration == -1))) { 984 (rDuration == -1))) {
953 // The time queried falls within the range of the event. 985 // The time queried falls within the range of the event.
954 if (((mRecurStart.secsTo(dt) / 60) % minuteFreq) == 0) 986 if (((mRecurStart.secsTo(dt) / 60) % minuteFreq) == 0)
955 return true; 987 return true;
956 } 988 }
957 return false; 989 return false;
958} 990}
959 991
960bool Recurrence::recursDaily(const QDate &qd) const 992bool Recurrence::recursDaily(const QDate &qd) const
961{ 993{
962 QDate dStart = mRecurStart.date(); 994 QDate dStart = mRecurStart.date();
963 if ((dStart.daysTo(qd) % rFreq) == 0) { 995 if ((dStart.daysTo(qd) % rFreq) == 0) {
964 // The date is a day which recurs 996 // The date is a day which recurs
965 if (qd >= dStart 997 if (qd >= dStart
966 && ((rDuration > 0 && qd <= endDate()) || 998 && ((rDuration > 0 && qd <= endDate()) ||
967 (rDuration == 0 && qd <= rEndDateTime.date()) || 999 (rDuration == 0 && qd <= rEndDateTime.date()) ||
968 rDuration == -1)) { 1000 rDuration == -1)) {
969 // The date queried falls within the range of the event. 1001 // The date queried falls within the range of the event.
970 return true; 1002 return true;
971 } 1003 }
972 } 1004 }
973 return false; 1005 return false;
974} 1006}
975 1007
976bool Recurrence::recursWeekly(const QDate &qd) const 1008bool Recurrence::recursWeekly(const QDate &qd) const
977{ 1009{
978 QDate dStart = mRecurStart.date(); 1010 QDate dStart = mRecurStart.date();
979 if ((dStart.daysTo(qd)/7) % rFreq == 0) { 1011 if ((dStart.daysTo(qd)/7) % rFreq == 0) {
980 // The date is in a week which recurs 1012 // The date is in a week which recurs
981 if (qd >= dStart 1013 if (qd >= dStart
982 && ((rDuration > 0 && qd <= endDate()) || 1014 && ((rDuration > 0 && qd <= endDate()) ||
983 (rDuration == 0 && qd <= rEndDateTime.date()) || 1015 (rDuration == 0 && qd <= rEndDateTime.date()) ||
984 rDuration == -1)) { 1016 rDuration == -1)) {
985 // The date queried falls within the range of the event. 1017 // The date queried falls within the range of the event.
986 // check if the bits set match today. 1018 // check if the bits set match today.
987 int i = qd.dayOfWeek()-1; 1019 int i = qd.dayOfWeek()-1;
988 if (rDays.testBit((uint) i)) 1020 if (rDays.testBit((uint) i))
989 return true; 1021 return true;
990 } 1022 }
991 } 1023 }
992 return false; 1024 return false;
993} 1025}
994 1026
995bool Recurrence::recursMonthly(const QDate &qd) const 1027bool Recurrence::recursMonthly(const QDate &qd) const
996{ 1028{
997 QDate dStart = mRecurStart.date(); 1029 QDate dStart = mRecurStart.date();
998 int year = qd.year(); 1030 int year = qd.year();
999 int month = qd.month(); 1031 int month = qd.month();
1000 int day = qd.day(); 1032 int day = qd.day();
1001 // calculate how many months ahead this date is from the original 1033 // calculate how many months ahead this date is from the original
1002 // event's date 1034 // event's date
1003 int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month()); 1035 int monthsAhead = (year - dStart.year()) * 12 + (month - dStart.month());
1004 if ((monthsAhead % rFreq) == 0) { 1036 if ((monthsAhead % rFreq) == 0) {
1005 // The date is in a month which recurs 1037 // The date is in a month which recurs
1006 if (qd >= dStart 1038 if (qd >= dStart
1007 && ((rDuration > 0 && qd <= endDate()) || 1039 && ((rDuration > 0 && qd <= endDate()) ||
1008 (rDuration == 0 && qd <= rEndDateTime.date()) || 1040 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1009 rDuration == -1)) { 1041 rDuration == -1)) {
1010 // The date queried falls within the range of the event. 1042 // The date queried falls within the range of the event.
1011 QValueList<int> days; 1043 QValueList<int> days;
1012 int daysInMonth = qd.daysInMonth(); 1044 int daysInMonth = qd.daysInMonth();
1013 if (recurs == rMonthlyDay) 1045 if (recurs == rMonthlyDay)
1014 getMonthlyDayDays(days, daysInMonth); 1046 getMonthlyDayDays(days, daysInMonth);
1015 else if (recurs == rMonthlyPos) 1047 else if (recurs == rMonthlyPos)
1016 getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek()); 1048 getMonthlyPosDays(days, daysInMonth, QDate(year, month, 1).dayOfWeek());
1017 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { 1049 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
1018 if (*it == day) 1050 if (*it == day)
1019 return true; 1051 return true;
1020 } 1052 }
1021 // no dates matched 1053 // no dates matched
1022 } 1054 }
1023 } 1055 }
1024 return false; 1056 return false;
1025} 1057}
1026 1058
1027bool Recurrence::recursYearlyByMonth(const QDate &qd) const 1059bool Recurrence::recursYearlyByMonth(const QDate &qd) const
1028{ 1060{
1029 QDate dStart = mRecurStart.date(); 1061 QDate dStart = mRecurStart.date();
1030 int startDay = dStart.day(); 1062 int startDay = dStart.day();
1031 int qday = qd.day(); 1063 int qday = qd.day();
1032 int qmonth = qd.month(); 1064 int qmonth = qd.month();
1033 int qyear = qd.year(); 1065 int qyear = qd.year();
1034 bool match = (qday == startDay); 1066 bool match = (qday == startDay);
1035 if (!match && startDay == 29 && dStart.month() == 2) { 1067 if (!match && startDay == 29 && dStart.month() == 2) {
1036 // It's a recurrence on February 29th 1068 // It's a recurrence on February 29th
1037 switch (mFeb29YearlyType) { 1069 switch (mFeb29YearlyType) {
1038 case rFeb28: 1070 case rFeb28:
1039 if (qday == 28 && qmonth == 2 && !QDate::leapYear(qyear)) 1071 if (qday == 28 && qmonth == 2 && !QDate::leapYear(qyear))
1040 match = true; 1072 match = true;
1041 break; 1073 break;
1042 case rMar1: 1074 case rMar1:
1043 if (qday == 1 && qmonth == 3 && !QDate::leapYear(qyear)) { 1075 if (qday == 1 && qmonth == 3 && !QDate::leapYear(qyear)) {
1044 qmonth = 2; 1076 qmonth = 2;
1045 match = true; 1077 match = true;
1046 } 1078 }
1047 break; 1079 break;
1048 case rFeb29: 1080 case rFeb29:
1049 break; 1081 break;
1050 } 1082 }
1051 } 1083 }
1052 1084
1053 if (match) { 1085 if (match) {
1054 // The day of the month matches. Calculate how many years ahead 1086 // The day of the month matches. Calculate how many years ahead
1055 // this date is from the original event's date. 1087 // this date is from the original event's date.
1056 int yearsAhead = (qyear - dStart.year()); 1088 int yearsAhead = (qyear - dStart.year());
1057 if (yearsAhead % rFreq == 0) { 1089 if (yearsAhead % rFreq == 0) {
1058 // The date is in a year which recurs 1090 // The date is in a year which recurs
1059 if (qd >= dStart 1091 if (qd >= dStart
1060 && ((rDuration > 0 && qd <= endDate()) || 1092 && ((rDuration > 0 && qd <= endDate()) ||
1061 (rDuration == 0 && qd <= rEndDateTime.date()) || 1093 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1062 rDuration == -1)) { 1094 rDuration == -1)) {
1063 // The date queried falls within the range of the event. 1095 // The date queried falls within the range of the event.
1064 int i = qmonth; 1096 int i = qmonth;
1065 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { 1097 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1066 if (i == *qlin.current()) 1098 if (i == *qlin.current())
1067 return true; 1099 return true;
1068 } 1100 }
1069 } 1101 }
1070 } 1102 }
1071 } 1103 }
1072 return false; 1104 return false;
1073} 1105}
1074 1106
1075bool Recurrence::recursYearlyByPos(const QDate &qd) const 1107bool Recurrence::recursYearlyByPos(const QDate &qd) const
1076{ 1108{
1077 QDate dStart = mRecurStart.date(); 1109 QDate dStart = mRecurStart.date();
1078 int year = qd.year(); 1110 int year = qd.year();
1079 int month = qd.month(); 1111 int month = qd.month();
1080 int day = qd.day(); 1112 int day = qd.day();
1081 // calculate how many years ahead this date is from the original 1113 // calculate how many years ahead this date is from the original
1082 // event's date 1114 // event's date
1083 int yearsAhead = (year - dStart.year()); 1115 int yearsAhead = (year - dStart.year());
1084 if (yearsAhead % rFreq == 0) { 1116 if (yearsAhead % rFreq == 0) {
1085 // The date is in a year which recurs 1117 // The date is in a year which recurs
1086 if (qd >= dStart 1118 if (qd >= dStart
1087 && ((rDuration > 0 && qd <= endDate()) || 1119 && ((rDuration > 0 && qd <= endDate()) ||
1088 (rDuration == 0 && qd <= rEndDateTime.date()) || 1120 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1089 rDuration == -1)) { 1121 rDuration == -1)) {
1090 // The date queried falls within the range of the event. 1122 // The date queried falls within the range of the event.
1091 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { 1123 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1092 if (month == *qlin.current()) { 1124 if (month == *qlin.current()) {
1093 // The month recurs 1125 // The month recurs
1094 QValueList<int> days; 1126 QValueList<int> days;
1095 getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek()); 1127 getMonthlyPosDays(days, qd.daysInMonth(), QDate(year, month, 1).dayOfWeek());
1096 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) { 1128 for (QValueList<int>::Iterator it = days.begin(); it != days.end(); ++it) {
1097 if (*it == day) 1129 if (*it == day)
1098 return true; 1130 return true;
1099 } 1131 }
1100 } 1132 }
1101 } 1133 }
1102 } 1134 }
1103 } 1135 }
1104 return false; 1136 return false;
1105} 1137}
1106 1138
1107bool Recurrence::recursYearlyByDay(const QDate &qd) const 1139bool Recurrence::recursYearlyByDay(const QDate &qd) const
1108{ 1140{
1109 QDate dStart = mRecurStart.date(); 1141 QDate dStart = mRecurStart.date();
1110 // calculate how many years ahead this date is from the original 1142 // calculate how many years ahead this date is from the original
1111 // event's date 1143 // event's date
1112 int yearsAhead = (qd.year() - dStart.year()); 1144 int yearsAhead = (qd.year() - dStart.year());
1113 if (yearsAhead % rFreq == 0) { 1145 if (yearsAhead % rFreq == 0) {
1114 // The date is in a year which recurs 1146 // The date is in a year which recurs
1115 if (qd >= dStart 1147 if (qd >= dStart
1116 && ((rDuration > 0 && qd <= endDate()) || 1148 && ((rDuration > 0 && qd <= endDate()) ||
1117 (rDuration == 0 && qd <= rEndDateTime.date()) || 1149 (rDuration == 0 && qd <= rEndDateTime.date()) ||
1118 rDuration == -1)) { 1150 rDuration == -1)) {
1119 // The date queried falls within the range of the event. 1151 // The date queried falls within the range of the event.
1120 int i = qd.dayOfYear(); 1152 int i = qd.dayOfYear();
1121 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) { 1153 for (QPtrListIterator<int> qlin(rYearNums); qlin.current(); ++qlin) {
1122 if (i == *qlin.current()) 1154 if (i == *qlin.current())
1123 return true; 1155 return true;
1124 } 1156 }
1125 } 1157 }
1126 } 1158 }
1127 return false; 1159 return false;
1128} 1160}
1129 1161
1130/* Get the date of the next recurrence, after the specified date. 1162/* Get the date of the next recurrence, after the specified date.
1131 * If 'last' is non-null, '*last' is set to true if the next recurrence is the 1163 * If 'last' is non-null, '*last' is set to true if the next recurrence is the
1132 * last recurrence, else false. 1164 * last recurrence, else false.
1133 * Reply = date of next recurrence, or invalid date if none. 1165 * Reply = date of next recurrence, or invalid date if none.
1134 */ 1166 */
1135QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const 1167QDate Recurrence::getNextDateNoTime(const QDate &preDate, bool *last) const
1136{ 1168{
1137 if (last) 1169 if (last)
1138 *last = false; 1170 *last = false;
1139 QDate dStart = mRecurStart.date(); 1171 QDate dStart = mRecurStart.date();
1140 if (preDate < dStart) 1172 if (preDate < dStart)
1141 return dStart; 1173 return dStart;
1142 QDate earliestDate = preDate.addDays(1); 1174 QDate earliestDate = preDate.addDays(1);
1143 QDate nextDate; 1175 QDate nextDate;
1144 1176
1145 switch (recurs) { 1177 switch (recurs) {
1146 case rDaily: 1178 case rDaily:
1147 nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq); 1179 nextDate = dStart.addDays((dStart.daysTo(preDate)/rFreq + 1) * rFreq);
1148 break; 1180 break;
1149 1181
1150 case rWeekly: { 1182 case rWeekly: {
1151 QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart 1183 QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart
1152 int earliestDayOfWeek = earliestDate.dayOfWeek(); 1184 int earliestDayOfWeek = earliestDate.dayOfWeek();
1153 int weeksAhead = start.daysTo(earliestDate) / 7; 1185 int weeksAhead = start.daysTo(earliestDate) / 7;
1154 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week 1186 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week
1155 weeksAhead -= notThisWeek; // latest week which recurred 1187 weeksAhead -= notThisWeek; // latest week which recurred
1156 int weekday = 0; 1188 int weekday = 0;
1157 // First check for any remaining day this week, if this week is a recurring week 1189 // First check for any remaining day this week, if this week is a recurring week
1158 if (!notThisWeek) 1190 if (!notThisWeek)
1159 weekday = getFirstDayInWeek(earliestDayOfWeek); 1191 weekday = getFirstDayInWeek(earliestDayOfWeek);
1160 // Check for a day in the next scheduled week 1192 // Check for a day in the next scheduled week
1161 if (!weekday && earliestDayOfWeek > 1) 1193 if (!weekday && earliestDayOfWeek > 1)
1162 weekday = getFirstDayInWeek(rWeekStart) + rFreq*7; 1194 weekday = getFirstDayInWeek(rWeekStart) + rFreq*7;
1163 if (weekday) 1195 if (weekday)
1164 nextDate = start.addDays(weeksAhead*7 + weekday - 1); 1196 nextDate = start.addDays(weeksAhead*7 + weekday - 1);
1165 break; 1197 break;
1166 } 1198 }
1167 case rMonthlyDay: 1199 case rMonthlyDay:
1168 case rMonthlyPos: { 1200 case rMonthlyPos: {
1169 int startYear = dStart.year(); 1201 int startYear = dStart.year();
1170 int startMonth = dStart.month(); // 1..12 1202 int startMonth = dStart.month(); // 1..12
1171 int earliestYear = earliestDate.year(); 1203 int earliestYear = earliestDate.year();
1172 int monthsAhead = (earliestYear - startYear)*12 + earliestDate.month() - startMonth; 1204 int monthsAhead = (earliestYear - startYear)*12 + earliestDate.month() - startMonth;
1173 int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month 1205 int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month
1174 monthsAhead -= notThisMonth; // latest month which recurred 1206 monthsAhead -= notThisMonth; // latest month which recurred
1175 // Check for the first later day in the current month 1207 // Check for the first later day in the current month
1176 if (!notThisMonth) 1208 if (!notThisMonth)
1177 nextDate = getFirstDateInMonth(earliestDate); 1209 nextDate = getFirstDateInMonth(earliestDate);
1178 if (!nextDate.isValid() && earliestDate.day() > 1) { 1210 if (!nextDate.isValid() && earliestDate.day() > 1) {
1179 // Check for a day in the next scheduled month 1211 // Check for a day in the next scheduled month
1180 int months = startMonth - 1 + monthsAhead + rFreq; 1212 int months = startMonth - 1 + monthsAhead + rFreq;
1181 nextDate = getFirstDateInMonth(QDate(startYear + months/12, months%12 + 1, 1)); 1213 nextDate = getFirstDateInMonth(QDate(startYear + months/12, months%12 + 1, 1));
1182 } 1214 }
1183 break; 1215 break;
1184 } 1216 }
1185 case rYearlyMonth: 1217 case rYearlyMonth:
1186 case rYearlyPos: 1218 case rYearlyPos:
1187 case rYearlyDay: { 1219 case rYearlyDay: {
1188 int startYear = dStart.year(); 1220 int startYear = dStart.year();
1189 int yearsAhead = earliestDate.year() - startYear; 1221 int yearsAhead = earliestDate.year() - startYear;
1190 int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year 1222 int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year
1191 yearsAhead -= notThisYear; // latest year which recurred 1223 yearsAhead -= notThisYear; // latest year which recurred
1192 // Check for the first later date in the current year 1224 // Check for the first later date in the current year
1193 if (!notThisYear) 1225 if (!notThisYear)
1194 nextDate = getFirstDateInYear(earliestDate); 1226 nextDate = getFirstDateInYear(earliestDate);
1195 // Check for a date in the next scheduled year 1227 // Check for a date in the next scheduled year
1196 if (!nextDate.isValid() && earliestDate.dayOfYear() > 1) 1228 if (!nextDate.isValid() && earliestDate.dayOfYear() > 1)
1197 nextDate = getFirstDateInYear(QDate(startYear + yearsAhead + rFreq, 1, 1)); 1229 nextDate = getFirstDateInYear(QDate(startYear + yearsAhead + rFreq, 1, 1));
1198 break; 1230 break;
1199 } 1231 }
1200 case rNone: 1232 case rNone:
1201 default: 1233 default:
1202 return QDate(); 1234 return QDate();
1203 } 1235 }
1204 1236
1205 if (rDuration >= 0 && nextDate.isValid()) { 1237 if (rDuration >= 0 && nextDate.isValid()) {
1206 // Check that the date found is within the range of the recurrence 1238 // Check that the date found is within the range of the recurrence
1207 QDate end = endDate(); 1239 QDate end = endDate();
1208 if (nextDate > end) 1240 if (nextDate > end)
1209 return QDate(); 1241 return QDate();
1210 if (last && nextDate == end) 1242 if (last && nextDate == end)
1211 *last = true; 1243 *last = true;
1212 } 1244 }
1213 return nextDate; 1245 return nextDate;
1214} 1246}
1215 1247
1216/* Get the date of the last previous recurrence, before the specified date. 1248/* Get the date of the last previous recurrence, before the specified date.
1217 * Reply = date of previous recurrence, or invalid date if none. 1249 * Reply = date of previous recurrence, or invalid date if none.
1218 */ 1250 */
1219QDate Recurrence::getPreviousDateNoTime(const QDate &afterDate, bool *last) const 1251QDate Recurrence::getPreviousDateNoTime(const QDate &afterDate, bool *last) const
1220{ 1252{
1221 if (last) 1253 if (last)
1222 *last = false; 1254 *last = false;
1223 QDate dStart = mRecurStart.date(); 1255 QDate dStart = mRecurStart.date();
1224 QDate latestDate = afterDate.addDays(-1); 1256 QDate latestDate = afterDate.addDays(-1);
1225 if (latestDate < dStart) 1257 if (latestDate < dStart)
1226 return QDate(); 1258 return QDate();
1227 QDate prevDate; 1259 QDate prevDate;
1228 1260
1229 switch (recurs) { 1261 switch (recurs) {
1230 case rDaily: 1262 case rDaily:
1231 prevDate = dStart.addDays((dStart.daysTo(latestDate) / rFreq) * rFreq); 1263 prevDate = dStart.addDays((dStart.daysTo(latestDate) / rFreq) * rFreq);
1232 break; 1264 break;
1233 1265
1234 case rWeekly: { 1266 case rWeekly: {
1235 QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart 1267 QDate start = dStart.addDays(1 - dStart.dayOfWeek()); // start of week for dStart
1236 int latestDayOfWeek = latestDate.dayOfWeek(); 1268 int latestDayOfWeek = latestDate.dayOfWeek();
1237 int weeksAhead = start.daysTo(latestDate) / 7; 1269 int weeksAhead = start.daysTo(latestDate) / 7;
1238 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week 1270 int notThisWeek = weeksAhead % rFreq; // zero if this week is a recurring week
1239 weeksAhead -= notThisWeek; // latest week which recurred 1271 weeksAhead -= notThisWeek; // latest week which recurred
1240 int weekday = 0; 1272 int weekday = 0;
1241 // First check for any previous day this week, if this week is a recurring week 1273 // First check for any previous day this week, if this week is a recurring week
1242 if (!notThisWeek) 1274 if (!notThisWeek)
1243 weekday = getLastDayInWeek(latestDayOfWeek); 1275 weekday = getLastDayInWeek(latestDayOfWeek);
1244 // Check for a day in the previous scheduled week 1276 // Check for a day in the previous scheduled week
1245 if (!weekday) { 1277 if (!weekday) {
1246 int weekEnd = (rWeekStart + 5)%7 + 1; 1278 int weekEnd = (rWeekStart + 5)%7 + 1;
1247 if (latestDayOfWeek < weekEnd) { 1279 if (latestDayOfWeek < weekEnd) {
1248 if (!notThisWeek) 1280 if (!notThisWeek)
1249 weeksAhead -= rFreq; 1281 weeksAhead -= rFreq;
1250 weekday = getLastDayInWeek(weekEnd); 1282 weekday = getLastDayInWeek(weekEnd);
1251 } 1283 }
1252 } 1284 }
1253 if (weekday) 1285 if (weekday)
1254 prevDate = start.addDays(weeksAhead*7 + weekday - 1); 1286 prevDate = start.addDays(weeksAhead*7 + weekday - 1);
1255 break; 1287 break;
1256 } 1288 }
1257 case rMonthlyDay: 1289 case rMonthlyDay:
1258 case rMonthlyPos: { 1290 case rMonthlyPos: {
1259 int startYear = dStart.year(); 1291 int startYear = dStart.year();
1260 int startMonth = dStart.month(); // 1..12 1292 int startMonth = dStart.month(); // 1..12
1261 int latestYear = latestDate.year(); 1293 int latestYear = latestDate.year();
1262 int monthsAhead = (latestYear - startYear)*12 + latestDate.month() - startMonth; 1294 int monthsAhead = (latestYear - startYear)*12 + latestDate.month() - startMonth;
1263 int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month 1295 int notThisMonth = monthsAhead % rFreq; // zero if this month is a recurring month
1264 monthsAhead -= notThisMonth; // latest month which recurred 1296 monthsAhead -= notThisMonth; // latest month which recurred
1265 // Check for the last earlier day in the current month 1297 // Check for the last earlier day in the current month
1266 if (!notThisMonth) 1298 if (!notThisMonth)
1267 prevDate = getLastDateInMonth(latestDate); 1299 prevDate = getLastDateInMonth(latestDate);
1268 if (!prevDate.isValid() && latestDate.day() < latestDate.daysInMonth()) { 1300 if (!prevDate.isValid() && latestDate.day() < latestDate.daysInMonth()) {
1269 // Check for a day in the previous scheduled month 1301 // Check for a day in the previous scheduled month
1270 if (!notThisMonth) 1302 if (!notThisMonth)
1271 monthsAhead -= rFreq; 1303 monthsAhead -= rFreq;
1272 int months = startMonth + monthsAhead; // get the month after the one that recurs 1304 int months = startMonth + monthsAhead; // get the month after the one that recurs
1273 prevDate = getLastDateInMonth(QDate(startYear + months/12, months%12 + 1, 1).addDays(-1)); 1305 prevDate = getLastDateInMonth(QDate(startYear + months/12, months%12 + 1, 1).addDays(-1));
1274 } 1306 }
1275 break; 1307 break;
1276 } 1308 }
1277 case rYearlyMonth: 1309 case rYearlyMonth:
1278 case rYearlyPos: 1310 case rYearlyPos:
1279 case rYearlyDay: { 1311 case rYearlyDay: {
1280 int startYear = dStart.year(); 1312 int startYear = dStart.year();
1281 int yearsAhead = latestDate.year() - startYear; 1313 int yearsAhead = latestDate.year() - startYear;
1282 int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year 1314 int notThisYear = yearsAhead % rFreq; // zero if this year is a recurring year
1283 yearsAhead -= notThisYear; // latest year which recurred 1315 yearsAhead -= notThisYear; // latest year which recurred
1284 // Check for the first later date in the current year 1316 // Check for the first later date in the current year
1285 if (!notThisYear) 1317 if (!notThisYear)
1286 prevDate = getLastDateInYear(latestDate); 1318 prevDate = getLastDateInYear(latestDate);
1287 if (!prevDate.isValid() && latestDate.dayOfYear() < latestDate.daysInYear()) { 1319 if (!prevDate.isValid() && latestDate.dayOfYear() < latestDate.daysInYear()) {
1288 // Check for a date in the next scheduled year 1320 // Check for a date in the next scheduled year
1289 if (!notThisYear) 1321 if (!notThisYear)
1290 yearsAhead -= rFreq; 1322 yearsAhead -= rFreq;
1291 prevDate = getLastDateInYear(QDate(startYear + yearsAhead, 12, 31)); 1323 prevDate = getLastDateInYear(QDate(startYear + yearsAhead, 12, 31));
1292 } 1324 }
1293 break; 1325 break;
1294 } 1326 }
1295 case rNone: 1327 case rNone:
1296 default: 1328 default:
1297 return QDate(); 1329 return QDate();
1298 } 1330 }
1299 1331
1300 if (prevDate.isValid()) { 1332 if (prevDate.isValid()) {
1301 // Check that the date found is within the range of the recurrence 1333 // Check that the date found is within the range of the recurrence
1302 if (prevDate < dStart) 1334 if (prevDate < dStart)
1303 return QDate(); 1335 return QDate();
1304 if (rDuration >= 0) { 1336 if (rDuration >= 0) {
1305 QDate end = endDate(); 1337 QDate end = endDate();
1306 if (prevDate >= end) { 1338 if (prevDate >= end) {
1307 if (last) 1339 if (last)
1308 *last = true; 1340 *last = true;
1309 return end; 1341 return end;
1310 } 1342 }
1311 } 1343 }
1312 } 1344 }
1313 return prevDate; 1345 return prevDate;
1314} 1346}
1315 1347
1316void Recurrence::setDailySub(short type, int freq, int duration) 1348void Recurrence::setDailySub(short type, int freq, int duration)
1317{ 1349{
1318 recurs = type; 1350 recurs = type;
1319 rFreq = freq; 1351 rFreq = freq;
1320 rDuration = duration; 1352 rDuration = duration;
1321 rMonthPositions.clear(); 1353 rMonthPositions.clear();
1322 rMonthDays.clear(); 1354 rMonthDays.clear();
1323 rYearNums.clear(); 1355 rYearNums.clear();
1324 if (type != rDaily) 1356 if (type != rDaily)
1325 mFloats = false; // sub-daily types can't be floating 1357 mFloats = false; // sub-daily types can't be floating
1326 1358
1327 if (mParent) mParent->updated(); 1359 if (mParent) mParent->updated();
1328} 1360}
1329 1361
1330void Recurrence::setYearly_(short type, Feb29Type feb29type, int freq, int duration) 1362void Recurrence::setYearly_(short type, Feb29Type feb29type, int freq, int duration)
1331{ 1363{
1332 recurs = type; 1364 recurs = type;
1333 if (mCompatVersion < 310 && type == rYearlyDay) { 1365 if (mCompatVersion < 310 && type == rYearlyDay) {
1334 mCompatRecurs = rYearlyDay; 1366 mCompatRecurs = rYearlyDay;
1335 recurs = rYearlyMonth; // convert old yearly-by-day to yearly-by-month 1367 recurs = rYearlyMonth; // convert old yearly-by-day to yearly-by-month
1336 feb29type = rMar1; // retain the same day number in the year 1368 feb29type = rMar1; // retain the same day number in the year
1337 } 1369 }
1338 1370
1339 mFeb29YearlyType = feb29type; 1371 mFeb29YearlyType = feb29type;
1340 rFreq = freq; 1372 rFreq = freq;
1341 rDuration = duration; 1373 rDuration = duration;
1342 if (type != rYearlyPos) 1374 if (type != rYearlyPos)
1343 rMonthPositions.clear(); 1375 rMonthPositions.clear();
1344 rMonthDays.clear(); 1376 rMonthDays.clear();
1345 if (mParent) mParent->updated(); 1377 if (mParent) mParent->updated();
1346} 1378}
1347 1379
1348int Recurrence::recurCalc(PeriodFunc func, QDateTime &endtime) const 1380int Recurrence::recurCalc(PeriodFunc func, QDateTime &endtime) const
1349{ 1381{
1350 QDate enddate = endtime.date(); 1382 QDate enddate = endtime.date();
1351 switch (func) { 1383 switch (func) {
1352 case END_DATE_AND_COUNT: 1384 case END_DATE_AND_COUNT:
1353 if (rDuration < 0) { 1385 if (rDuration < 0) {
1354 endtime = QDateTime(); 1386 endtime = QDateTime();
1355 return 0; // infinite recurrence 1387 return 0; // infinite recurrence
1356 } 1388 }
1357 if (rDuration == 0) { 1389 if (rDuration == 0) {
1358 endtime = rEndDateTime; 1390 endtime = rEndDateTime;
1359 func = COUNT_TO_DATE; 1391 func = COUNT_TO_DATE;
1360 } 1392 }
1361 break; 1393 break;
1362 case COUNT_TO_DATE: 1394 case COUNT_TO_DATE:
1363 // Count recurrences up to and including the specified date/time. 1395 // Count recurrences up to and including the specified date/time.
1364 if (endtime < mRecurStart) 1396 if (endtime < mRecurStart)
1365 return 0; 1397 return 0;
1366 if (rDuration == 0 && endtime > rEndDateTime) 1398 if (rDuration == 0 && endtime > rEndDateTime)
1367 enddate = rEndDateTime.date(); 1399 enddate = rEndDateTime.date();
1368 else if (!mFloats && mRecurStart.time() > endtime.time()) 1400 else if (!mFloats && mRecurStart.time() > endtime.time())
1369 enddate = enddate.addDays(-1); 1401 enddate = enddate.addDays(-1);
1370 break; 1402 break;
1371 case NEXT_AFTER_DATE: 1403 case NEXT_AFTER_DATE:
1372 // Find next recurrence AFTER endtime 1404 // Find next recurrence AFTER endtime
1373 if (endtime < mRecurStart) { 1405 if (endtime < mRecurStart) {
1374 endtime = mRecurStart; 1406 endtime = mRecurStart;
1375 return 1; 1407 return 1;
1376 } 1408 }
1377 if (rDuration == 0 && endtime >= rEndDateTime) { 1409 if (rDuration == 0 && endtime >= rEndDateTime) {
1378 endtime = QDateTime(); 1410 endtime = QDateTime();
1379 return 0; 1411 return 0;
1380 } 1412 }
1381 if (!mFloats && mRecurStart.time() > endtime.time()) 1413 if (!mFloats && mRecurStart.time() > endtime.time())
1382 enddate = enddate.addDays(-1); 1414 enddate = enddate.addDays(-1);
1383 break; 1415 break;
1384 default: 1416 default:
1385 endtime = QDateTime(); 1417 endtime = QDateTime();
1386 return 0; 1418 return 0;
1387 } 1419 }
1388 1420
1389 int count = 0; // default = error 1421 int count = 0; // default = error
1390 bool timed = false; 1422 bool timed = false;
1391 switch (recurs) { 1423 switch (recurs) {
1392 case rMinutely: 1424 case rMinutely:
1393 timed = true; 1425 timed = true;
1394 count = secondlyCalc(func, endtime, rFreq*60); 1426 count = secondlyCalc(func, endtime, rFreq*60);
1395 break; 1427 break;
1396 case rHourly: 1428 case rHourly:
1397 timed = true; 1429 timed = true;
1398 count = secondlyCalc(func, endtime, rFreq*3600); 1430 count = secondlyCalc(func, endtime, rFreq*3600);
1399 break; 1431 break;
1400 case rDaily: 1432 case rDaily:
1401 count = dailyCalc(func, enddate); 1433 count = dailyCalc(func, enddate);
1402 break; 1434 break;
1403 case rWeekly: 1435 case rWeekly:
1404 count = weeklyCalc(func, enddate); 1436 count = weeklyCalc(func, enddate);
1405 break; 1437 break;
1406 case rMonthlyPos: 1438 case rMonthlyPos:
1407 case rMonthlyDay: 1439 case rMonthlyDay:
1408 count = monthlyCalc(func, enddate); 1440 count = monthlyCalc(func, enddate);
1409 break; 1441 break;
1410 case rYearlyMonth: 1442 case rYearlyMonth:
1411 count = yearlyMonthCalc(func, enddate); 1443 count = yearlyMonthCalc(func, enddate);
1412 break; 1444 break;
1413 case rYearlyPos: 1445 case rYearlyPos:
1414 count = yearlyPosCalc(func, enddate); 1446 count = yearlyPosCalc(func, enddate);
1415 break; 1447 break;
1416 case rYearlyDay: 1448 case rYearlyDay:
1417 count = yearlyDayCalc(func, enddate); 1449 count = yearlyDayCalc(func, enddate);
1418 break; 1450 break;
1419 default: 1451 default:
1420 break; 1452 break;
1421 } 1453 }
1422 1454
1423 switch (func) { 1455 switch (func) {
1424 case END_DATE_AND_COUNT: 1456 case END_DATE_AND_COUNT:
1425 case NEXT_AFTER_DATE: 1457 case NEXT_AFTER_DATE:
1426 if (count == 0) 1458 if (count == 0)
1427 endtime = QDateTime(); 1459 endtime = QDateTime();
1428 else if (!timed) { 1460 else if (!timed) {
1429 endtime.setDate(enddate); 1461 endtime.setDate(enddate);
1430 endtime.setTime(mRecurStart.time()); 1462 endtime.setTime(mRecurStart.time());
1431 } 1463 }
1432 break; 1464 break;
1433 case COUNT_TO_DATE: 1465 case COUNT_TO_DATE:
1434 break; 1466 break;
1435 } 1467 }
1436 return count; 1468 return count;
1437} 1469}
1438 1470
1439int Recurrence::recurCalc(PeriodFunc func, QDate &enddate) const 1471int Recurrence::recurCalc(PeriodFunc func, QDate &enddate) const
1440{ 1472{
1441 QDateTime endtime(enddate, QTime(23,59,59)); 1473 QDateTime endtime(enddate, QTime(23,59,59));
1442 switch (func) { 1474 switch (func) {
1443 case END_DATE_AND_COUNT: 1475 case END_DATE_AND_COUNT:
1444 if (rDuration < 0) { 1476 if (rDuration < 0) {
1445 enddate = QDate(); 1477 enddate = QDate();
1446 return 0; // infinite recurrence 1478 return 0; // infinite recurrence
1447 } 1479 }
1448 if (rDuration == 0) { 1480 if (rDuration == 0) {
1449 enddate = rEndDateTime.date(); 1481 enddate = rEndDateTime.date();
1450 func = COUNT_TO_DATE; 1482 func = COUNT_TO_DATE;
1451 } 1483 }
1452 break; 1484 break;
1453 case COUNT_TO_DATE: 1485 case COUNT_TO_DATE:
1454 // Count recurrences up to and including the specified date. 1486 // Count recurrences up to and including the specified date.
1455 if (enddate < mRecurStart.date()) 1487 if (enddate < mRecurStart.date())
1456 return 0; 1488 return 0;
1457 if (rDuration == 0 && enddate > rEndDateTime.date()) { 1489 if (rDuration == 0 && enddate > rEndDateTime.date()) {
1458 enddate = rEndDateTime.date(); 1490 enddate = rEndDateTime.date();
1459 endtime.setDate(enddate); 1491 endtime.setDate(enddate);
1460 } 1492 }
1461 break; 1493 break;
1462 case NEXT_AFTER_DATE: 1494 case NEXT_AFTER_DATE:
1463 if (enddate < mRecurStart.date()) { 1495 if (enddate < mRecurStart.date()) {
1464 enddate = mRecurStart.date(); 1496 enddate = mRecurStart.date();
1465 return 1; 1497 return 1;
1466 } 1498 }
1467 if (rDuration == 0 && enddate >= rEndDateTime.date()) { 1499 if (rDuration == 0 && enddate >= rEndDateTime.date()) {
1468 enddate = QDate(); 1500 enddate = QDate();
1469 return 0; 1501 return 0;
1470 } 1502 }
1471 break; 1503 break;
1472 default: 1504 default:
1473 enddate = QDate(); 1505 enddate = QDate();
1474 return 0; 1506 return 0;
1475 } 1507 }
1476 1508
1477 int count = 0; // default = error 1509 int count = 0; // default = error
1478 bool timed = false; 1510 bool timed = false;
1479 switch (recurs) { 1511 switch (recurs) {
1480 case rMinutely: 1512 case rMinutely:
1481 timed = true; 1513 timed = true;
1482 count = secondlyCalc(func, endtime, rFreq*60); 1514 count = secondlyCalc(func, endtime, rFreq*60);
1483 break; 1515 break;
1484 case rHourly: 1516 case rHourly:
1485 timed = true; 1517 timed = true;
1486 count = secondlyCalc(func, endtime, rFreq*3600); 1518 count = secondlyCalc(func, endtime, rFreq*3600);
1487 break; 1519 break;
1488 case rDaily: 1520 case rDaily:
1489 count = dailyCalc(func, enddate); 1521 count = dailyCalc(func, enddate);
1490 break; 1522 break;
1491 case rWeekly: 1523 case rWeekly:
1492 count = weeklyCalc(func, enddate); 1524 count = weeklyCalc(func, enddate);
1493 break; 1525 break;
1494 case rMonthlyPos: 1526 case rMonthlyPos:
1495 case rMonthlyDay: 1527 case rMonthlyDay:
1496 count = monthlyCalc(func, enddate); 1528 count = monthlyCalc(func, enddate);
1497 break; 1529 break;
1498 case rYearlyMonth: 1530 case rYearlyMonth:
1499 count = yearlyMonthCalc(func, enddate); 1531 count = yearlyMonthCalc(func, enddate);
1500 break; 1532 break;
1501 case rYearlyPos: 1533 case rYearlyPos:
1502 count = yearlyPosCalc(func, enddate); 1534 count = yearlyPosCalc(func, enddate);
1503 break; 1535 break;
1504 case rYearlyDay: 1536 case rYearlyDay:
1505 count = yearlyDayCalc(func, enddate); 1537 count = yearlyDayCalc(func, enddate);
1506 break; 1538 break;
1507 default: 1539 default:
1508 break; 1540 break;
1509 } 1541 }
1510 1542
1511 switch (func) { 1543 switch (func) {
1512 case END_DATE_AND_COUNT: 1544 case END_DATE_AND_COUNT:
1513 case NEXT_AFTER_DATE: 1545 case NEXT_AFTER_DATE:
1514 if (count == 0) 1546 if (count == 0)
1515 endtime = QDate(); 1547 endtime = QDate();
1516 else if (timed) 1548 else if (timed)
1517 enddate = endtime.date(); 1549 enddate = endtime.date();
1518 break; 1550 break;
1519 case COUNT_TO_DATE: 1551 case COUNT_TO_DATE:
1520 break; 1552 break;
1521 } 1553 }
1522 return count; 1554 return count;
1523} 1555}
1524 1556
1525/* Find count and, depending on 'func', the end date/time of a secondly recurrence. 1557/* Find count and, depending on 'func', the end date/time of a secondly recurrence.
1526 * Reply = total number of occurrences up to 'endtime', or 0 if error. 1558 * Reply = total number of occurrences up to 'endtime', or 0 if error.
1527 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'endtime' is updated to the 1559 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'endtime' is updated to the
1528 * recurrence end date/time. 1560 * recurrence end date/time.
1529 */ 1561 */
1530int Recurrence::secondlyCalc(PeriodFunc func, QDateTime &endtime, int freq) const 1562int Recurrence::secondlyCalc(PeriodFunc func, QDateTime &endtime, int freq) const
1531{ 1563{
1532 switch (func) { 1564 switch (func) {
1533 case END_DATE_AND_COUNT: 1565 case END_DATE_AND_COUNT:
1534 endtime = mRecurStart.addSecs((rDuration + mRecurExDatesCount - 1) * freq); 1566 endtime = mRecurStart.addSecs((rDuration + mRecurExDatesCount - 1) * freq);
1535 return rDuration + mRecurExDatesCount; 1567 return rDuration + mRecurExDatesCount;
1536 case COUNT_TO_DATE: { 1568 case COUNT_TO_DATE: {
1537 int n = mRecurStart.secsTo(endtime)/freq + 1; 1569 int n = mRecurStart.secsTo(endtime)/freq + 1;
1538 if (rDuration > 0 && n > rDuration + mRecurExDatesCount) 1570 if (rDuration > 0 && n > rDuration + mRecurExDatesCount)
1539 return rDuration + mRecurExDatesCount; 1571 return rDuration + mRecurExDatesCount;
1540 return n; 1572 return n;
1541 } 1573 }
1542 case NEXT_AFTER_DATE: { 1574 case NEXT_AFTER_DATE: {
1543 int count = mRecurStart.secsTo(endtime) / freq + 2; 1575 int count = mRecurStart.secsTo(endtime) / freq + 2;
1544 if (rDuration > 0 && count > rDuration) 1576 if (rDuration > 0 && count > rDuration)
1545 return 0; 1577 return 0;
1546 endtime = mRecurStart.addSecs((count - 1)*freq); 1578 endtime = mRecurStart.addSecs((count - 1)*freq);
1547 return count; 1579 return count;
1548 } 1580 }
1549 } 1581 }
1550 return 0; 1582 return 0;
1551} 1583}
1552 1584
1553/* Find count and, depending on 'func', the end date of a daily recurrence. 1585/* Find count and, depending on 'func', the end date of a daily recurrence.
1554 * Reply = total number of occurrences up to 'enddate', or 0 if error. 1586 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1555 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 1587 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1556 * recurrence end date. 1588 * recurrence end date.
1557 */ 1589 */
1558int Recurrence::dailyCalc(PeriodFunc func, QDate &enddate) const 1590int Recurrence::dailyCalc(PeriodFunc func, QDate &enddate) const
1559{ 1591{
1560 QDate dStart = mRecurStart.date(); 1592 QDate dStart = mRecurStart.date();
1561 switch (func) { 1593 switch (func) {
1562 case END_DATE_AND_COUNT: 1594 case END_DATE_AND_COUNT:
1563 enddate = dStart.addDays((rDuration + mRecurExDatesCount - 1) * rFreq); 1595 enddate = dStart.addDays((rDuration + mRecurExDatesCount - 1) * rFreq);
1564 return rDuration + mRecurExDatesCount; 1596 return rDuration + mRecurExDatesCount;
1565 case COUNT_TO_DATE: { 1597 case COUNT_TO_DATE: {
1566 int n = dStart.daysTo(enddate)/rFreq + 1; 1598 int n = dStart.daysTo(enddate)/rFreq + 1;
1567 if (rDuration > 0 && n > rDuration + mRecurExDatesCount) 1599 if (rDuration > 0 && n > rDuration + mRecurExDatesCount)
1568 return rDuration + mRecurExDatesCount; 1600 return rDuration + mRecurExDatesCount;
1569 return n; 1601 return n;
1570 } 1602 }
1571 case NEXT_AFTER_DATE: { 1603 case NEXT_AFTER_DATE: {
1572 int count = dStart.daysTo(enddate) / rFreq + 2; 1604 int count = dStart.daysTo(enddate) / rFreq + 2;
1573 if (rDuration > 0 && count > rDuration) 1605 if (rDuration > 0 && count > rDuration)
1574 return 0; 1606 return 0;
1575 enddate = dStart.addDays((count - 1)*rFreq); 1607 enddate = dStart.addDays((count - 1)*rFreq);
1576 return count; 1608 return count;
1577 } 1609 }
1578 } 1610 }
1579 return 0; 1611 return 0;
1580} 1612}
1581 1613
1582/* Find count and, depending on 'func', the end date of a weekly recurrence. 1614/* Find count and, depending on 'func', the end date of a weekly recurrence.
1583 * Reply = total number of occurrences up to 'enddate', or 0 if error. 1615 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1584 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 1616 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1585 * recurrence end date. 1617 * recurrence end date.
1586 */ 1618 */
1587int Recurrence::weeklyCalc(PeriodFunc func, QDate &enddate) const 1619int Recurrence::weeklyCalc(PeriodFunc func, QDate &enddate) const
1588{ 1620{
1589 int daysPerWeek = 0; 1621 int daysPerWeek = 0;
1590 for (int i = 0; i < 7; ++i) { 1622 for (int i = 0; i < 7; ++i) {
1591 if (rDays.testBit((uint)i)) 1623 if (rDays.testBit((uint)i))
1592 ++daysPerWeek; 1624 ++daysPerWeek;
1593 } 1625 }
1594 if (!daysPerWeek) 1626 if (!daysPerWeek)
1595 return 0; // there are no days to recur on 1627 return 0; // there are no days to recur on
1596 1628
1597 switch (func) { 1629 switch (func) {
1598 case END_DATE_AND_COUNT: 1630 case END_DATE_AND_COUNT:
1599 return weeklyCalcEndDate(enddate, daysPerWeek); 1631 return weeklyCalcEndDate(enddate, daysPerWeek);
1600 case COUNT_TO_DATE: 1632 case COUNT_TO_DATE:
1601 return weeklyCalcToDate(enddate, daysPerWeek); 1633 return weeklyCalcToDate(enddate, daysPerWeek);
1602 case NEXT_AFTER_DATE: 1634 case NEXT_AFTER_DATE:
1603 return weeklyCalcNextAfter(enddate, daysPerWeek); 1635 return weeklyCalcNextAfter(enddate, daysPerWeek);
1604 } 1636 }
1605 return 0; 1637 return 0;
1606} 1638}
1607 1639
1608int Recurrence::weeklyCalcEndDate(QDate &enddate, int daysPerWeek) const 1640int Recurrence::weeklyCalcEndDate(QDate &enddate, int daysPerWeek) const
1609{ 1641{
1610 int startDayOfWeek = mRecurStart.date().dayOfWeek(); // 1..7 1642 int startDayOfWeek = mRecurStart.date().dayOfWeek(); // 1..7
1611 int countGone = 0; 1643 int countGone = 0;
1612 int daysGone = 0; 1644 int daysGone = 0;
1613 uint countTogo = rDuration + mRecurExDatesCount; 1645 uint countTogo = rDuration + mRecurExDatesCount;
1614 if (startDayOfWeek != rWeekStart) { 1646 if (startDayOfWeek != rWeekStart) {
1615 // Check what remains of the start week 1647 // Check what remains of the start week
1616 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) { 1648 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
1617 ++daysGone; 1649 ++daysGone;
1618 if (rDays.testBit((uint)i)) { 1650 if (rDays.testBit((uint)i)) {
1619 ++countGone; 1651 ++countGone;
1620 if (--countTogo == 0) 1652 if (--countTogo == 0)
1621 break; 1653 break;
1622 } 1654 }
1623 } 1655 }
1624 daysGone += 7 * (rFreq - 1); 1656 daysGone += 7 * (rFreq - 1);
1625 } 1657 }
1626 if (countTogo) { 1658 if (countTogo) {
1627 // Skip the remaining whole weeks 1659 // Skip the remaining whole weeks
1628 // Leave at least 1 recurrence remaining, in order to get its date 1660 // Leave at least 1 recurrence remaining, in order to get its date
1629 int wholeWeeks = (countTogo - 1) / daysPerWeek; 1661 int wholeWeeks = (countTogo - 1) / daysPerWeek;
1630 daysGone += wholeWeeks * 7 * rFreq; 1662 daysGone += wholeWeeks * 7 * rFreq;
1631 countGone += wholeWeeks * daysPerWeek; 1663 countGone += wholeWeeks * daysPerWeek;
1632 countTogo -= wholeWeeks * daysPerWeek; 1664 countTogo -= wholeWeeks * daysPerWeek;
1633 // Check the last week in the recurrence 1665 // Check the last week in the recurrence
1634 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) { 1666 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
1635 ++daysGone; 1667 ++daysGone;
1636 if (rDays.testBit((uint)i)) { 1668 if (rDays.testBit((uint)i)) {
1637 ++countGone; 1669 ++countGone;
1638 if (--countTogo == 0) 1670 if (--countTogo == 0)
1639 break; 1671 break;
1640 } 1672 }
1641 } 1673 }
1642 } 1674 }
1643 enddate = mRecurStart.date().addDays(daysGone); 1675 enddate = mRecurStart.date().addDays(daysGone);
1644 return countGone; 1676 return countGone;
1645} 1677}
1646 1678
1647int Recurrence::weeklyCalcToDate(const QDate &enddate, int daysPerWeek) const 1679int Recurrence::weeklyCalcToDate(const QDate &enddate, int daysPerWeek) const
1648{ 1680{
1649 QDate dStart = mRecurStart.date(); 1681 QDate dStart = mRecurStart.date();
1650 int startDayOfWeek = dStart.dayOfWeek(); // 1..7 1682 int startDayOfWeek = dStart.dayOfWeek(); // 1..7
1651 int countGone = 0; 1683 int countGone = 0;
1652 int daysGone = 0; 1684 int daysGone = 0;
1653 int totalDays = dStart.daysTo(enddate) + 1; 1685 int totalDays = dStart.daysTo(enddate) + 1;
1654 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 1686 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
1655 1687
1656 if (startDayOfWeek != rWeekStart) { 1688 if (startDayOfWeek != rWeekStart) {
1657 // Check what remains of the start week 1689 // Check what remains of the start week
1658 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) { 1690 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
1659 if (rDays.testBit((uint)i)) { 1691 if (rDays.testBit((uint)i)) {
1660 if (++countGone >= countMax) 1692 if (++countGone >= countMax)
1661 return countMax; 1693 return countMax;
1662 } 1694 }
1663 if (++daysGone == totalDays) 1695 if (++daysGone == totalDays)
1664 return countGone; 1696 return countGone;
1665 } 1697 }
1666 daysGone += 7 * (rFreq - 1); 1698 daysGone += 7 * (rFreq - 1);
1667 if (daysGone >= totalDays) 1699 if (daysGone >= totalDays)
1668 return countGone; 1700 return countGone;
1669 } 1701 }
1670 // Skip the remaining whole weeks 1702 // Skip the remaining whole weeks
1671 int wholeWeeks = (totalDays - daysGone) / 7; 1703 int wholeWeeks = (totalDays - daysGone) / 7;
1672 countGone += (wholeWeeks / rFreq) * daysPerWeek; 1704 countGone += (wholeWeeks / rFreq) * daysPerWeek;
1673 if (countGone >= countMax) 1705 if (countGone >= countMax)
1674 return countMax; 1706 return countMax;
1675 daysGone += wholeWeeks * 7; 1707 daysGone += wholeWeeks * 7;
1676 if (daysGone >= totalDays // have we reached the end date? 1708 if (daysGone >= totalDays // have we reached the end date?
1677 || wholeWeeks % rFreq) // is end week a recurrence week? 1709 || wholeWeeks % rFreq) // is end week a recurrence week?
1678 return countGone; 1710 return countGone;
1679 1711
1680 // Check the last week in the recurrence 1712 // Check the last week in the recurrence
1681 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) { 1713 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
1682 if (rDays.testBit((uint)i)) { 1714 if (rDays.testBit((uint)i)) {
1683 if (++countGone >= countMax) 1715 if (++countGone >= countMax)
1684 return countMax; 1716 return countMax;
1685 } 1717 }
1686 if (++daysGone == totalDays) 1718 if (++daysGone == totalDays)
1687 return countGone; 1719 return countGone;
1688 } 1720 }
1689 return countGone; 1721 return countGone;
1690} 1722}
1691 1723
1692int Recurrence::weeklyCalcNextAfter(QDate &enddate, int daysPerWeek) const 1724int Recurrence::weeklyCalcNextAfter(QDate &enddate, int daysPerWeek) const
1693{ 1725{
1694 QDate dStart = mRecurStart.date(); 1726 QDate dStart = mRecurStart.date();
1695 int startDayOfWeek = dStart.dayOfWeek(); // 1..7 1727 int startDayOfWeek = dStart.dayOfWeek(); // 1..7
1696 int totalDays = dStart.daysTo(enddate) + 1; 1728 int totalDays = dStart.daysTo(enddate) + 1;
1697 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 1729 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
1698 int countGone = 0; 1730 int countGone = 0;
1699 int daysGone = 0; 1731 int daysGone = 0;
1700 int recurWeeks; 1732 int recurWeeks;
1701 1733
1702 if (startDayOfWeek != rWeekStart) { 1734 if (startDayOfWeek != rWeekStart) {
1703 // Check what remains of the start week 1735 // Check what remains of the start week
1704 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) { 1736 for (int i = startDayOfWeek - 1; i != rWeekStart - 1; i = (i + 1) % 7) {
1705 ++daysGone; 1737 ++daysGone;
1706 if (rDays.testBit((uint)i)) { 1738 if (rDays.testBit((uint)i)) {
1707 ++countGone; 1739 ++countGone;
1708 if (daysGone > totalDays) 1740 if (daysGone > totalDays)
1709 goto ex; 1741 goto ex;
1710 if (--countTogo == 0) 1742 if (--countTogo == 0)
1711 return 0; 1743 return 0;
1712 } 1744 }
1713 } 1745 }
1714 daysGone += 7 * (rFreq - 1); 1746 daysGone += 7 * (rFreq - 1);
1715 } 1747 }
1716 1748
1717 // Skip the remaining whole weeks 1749 // Skip the remaining whole weeks
1718 recurWeeks = (totalDays - daysGone) / (7 * rFreq); 1750 recurWeeks = (totalDays - daysGone) / (7 * rFreq);
1719 if (recurWeeks) { 1751 if (recurWeeks) {
1720 int n = recurWeeks * daysPerWeek; 1752 int n = recurWeeks * daysPerWeek;
1721 if (static_cast<uint>(n) > countTogo) 1753 if (static_cast<uint>(n) > countTogo)
1722 return 0; // reached end of recurrence 1754 return 0; // reached end of recurrence
1723 countGone += n; 1755 countGone += n;
1724 countTogo -= n; 1756 countTogo -= n;
1725 daysGone += recurWeeks * 7 * rFreq; 1757 daysGone += recurWeeks * 7 * rFreq;
1726 } 1758 }
1727 1759
1728 // Check the last week or two in the recurrence 1760 // Check the last week or two in the recurrence
1729 for ( ; ; ) { 1761 for ( ; ; ) {
1730 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) { 1762 for (int i = rWeekStart - 1; ; i = (i + 1) % 7) {
1731 ++daysGone; 1763 ++daysGone;
1732 if (rDays.testBit((uint)i)) { 1764 if (rDays.testBit((uint)i)) {
1733 ++countGone; 1765 ++countGone;
1734 if (daysGone > totalDays) 1766 if (daysGone > totalDays)
1735 goto ex; 1767 goto ex;
1736 if (--countTogo == 0) 1768 if (--countTogo == 0)
1737 return 0; 1769 return 0;
1738 } 1770 }
1739 } 1771 }
1740 daysGone += 7 * (rFreq - 1); 1772 daysGone += 7 * (rFreq - 1);
1741 } 1773 }
1742ex: 1774ex:
1743 enddate = dStart.addDays(daysGone); 1775 enddate = dStart.addDays(daysGone);
1744 return countGone; 1776 return countGone;
1745} 1777}
1746 1778
1747/* Find count and, depending on 'func', the end date of a monthly recurrence. 1779/* Find count and, depending on 'func', the end date of a monthly recurrence.
1748 * Reply = total number of occurrences up to 'enddate', or 0 if error. 1780 * Reply = total number of occurrences up to 'enddate', or 0 if error.
1749 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 1781 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
1750 * recurrence end date. 1782 * recurrence end date.
1751 */ 1783 */
1752struct Recurrence::MonthlyData { 1784struct Recurrence::MonthlyData {
1753 const Recurrence *recurrence; 1785 const Recurrence *recurrence;
1754 int year; // current year 1786 int year; // current year
1755 int month; // current month 0..11 1787 int month; // current month 0..11
1756 int day; // current day of month 1..31 1788 int day; // current day of month 1..31
1757 bool varies; // true if recurring days vary between different months 1789 bool varies; // true if recurring days vary between different months
1758 private: 1790 private:
1759 QValueList<int> days28, days29, days30, days31; // recurring days in months of each length 1791 QValueList<int> days28, days29, days30, days31; // recurring days in months of each length
1760 QValueList<int> *recurDays[4]; 1792 QValueList<int> *recurDays[4];
1761 public: 1793 public:
1762 MonthlyData(const Recurrence* r, const QDate &date) 1794 MonthlyData(const Recurrence* r, const QDate &date)
1763 : recurrence(r), year(date.year()), month(date.month()-1), day(date.day()) 1795 : recurrence(r), year(date.year()), month(date.month()-1), day(date.day())
1764 { recurDays[0] = &days28; 1796 { recurDays[0] = &days28;
1765 recurDays[1] = &days29; 1797 recurDays[1] = &days29;
1766 recurDays[2] = &days30; 1798 recurDays[2] = &days30;
1767 recurDays[3] = &days31; 1799 recurDays[3] = &days31;
1768 varies = (recurrence->recurs == rMonthlyPos) 1800 varies = (recurrence->recurs == rMonthlyPos)
1769 ? true : recurrence->getMonthlyDayDays(days31, 31); 1801 ? true : recurrence->getMonthlyDayDays(days31, 31);
1770 } 1802 }
1771 const QValueList<int>* dayList() const { 1803 const QValueList<int>* dayList() const {
1772 if (!varies) 1804 if (!varies)
1773 return &days31; 1805 return &days31;
1774 QDate startOfMonth(year, month + 1, 1); 1806 QDate startOfMonth(year, month + 1, 1);
1775 int daysInMonth = startOfMonth.daysInMonth(); 1807 int daysInMonth = startOfMonth.daysInMonth();
1776 QValueList<int>* days = recurDays[daysInMonth - 28]; 1808 QValueList<int>* days = recurDays[daysInMonth - 28];
1777 if (recurrence->recurs == rMonthlyPos) 1809 if (recurrence->recurs == rMonthlyPos)
1778 recurrence->getMonthlyPosDays(*days, daysInMonth, startOfMonth.dayOfWeek()); 1810 recurrence->getMonthlyPosDays(*days, daysInMonth, startOfMonth.dayOfWeek());
1779 else if (days->isEmpty()) 1811 else if (days->isEmpty())
1780 recurrence->getMonthlyDayDays(*days, daysInMonth); 1812 recurrence->getMonthlyDayDays(*days, daysInMonth);
1781 return days; 1813 return days;
1782 } 1814 }
1783 int yearMonth() const { return year*12 + month; } 1815 int yearMonth() const { return year*12 + month; }
1784 void addMonths(int diff) { month += diff; year += month / 12; month %= 12; } 1816 void addMonths(int diff) { month += diff; year += month / 12; month %= 12; }
1785 QDate date() const { return QDate(year, month + 1, day); } 1817 QDate date() const { return QDate(year, month + 1, day); }
1786}; 1818};
1787 1819
1788int Recurrence::monthlyCalc(PeriodFunc func, QDate &enddate) const 1820int Recurrence::monthlyCalc(PeriodFunc func, QDate &enddate) const
1789{ 1821{
1790 if (recurs == rMonthlyPos && rMonthPositions.isEmpty() 1822 if (recurs == rMonthlyPos && rMonthPositions.isEmpty()
1791 || recurs == rMonthlyDay && rMonthDays.isEmpty()) 1823 || recurs == rMonthlyDay && rMonthDays.isEmpty())
1792 return 0; 1824 return 0;
1793 1825
1794 MonthlyData data(this, mRecurStart.date()); 1826 MonthlyData data(this, mRecurStart.date());
1795 switch (func) { 1827 switch (func) {
1796 case END_DATE_AND_COUNT: 1828 case END_DATE_AND_COUNT:
1797 return monthlyCalcEndDate(enddate, data); 1829 return monthlyCalcEndDate(enddate, data);
1798 case COUNT_TO_DATE: 1830 case COUNT_TO_DATE:
1799 return monthlyCalcToDate(enddate, data); 1831 return monthlyCalcToDate(enddate, data);
1800 case NEXT_AFTER_DATE: 1832 case NEXT_AFTER_DATE:
1801 return monthlyCalcNextAfter(enddate, data); 1833 return monthlyCalcNextAfter(enddate, data);
1802 } 1834 }
1803 return 0; 1835 return 0;
1804} 1836}
1805 1837
1806int Recurrence::monthlyCalcEndDate(QDate &enddate, MonthlyData &data) const 1838int Recurrence::monthlyCalcEndDate(QDate &enddate, MonthlyData &data) const
1807{ 1839{
1808 uint countTogo = rDuration + mRecurExDatesCount; 1840 uint countTogo = rDuration + mRecurExDatesCount;
1809 int countGone = 0; 1841 int countGone = 0;
1810 QValueList<int>::ConstIterator it; 1842 QValueList<int>::ConstIterator it;
1811 const QValueList<int>* days = data.dayList(); 1843 const QValueList<int>* days = data.dayList();
1812 1844
1813 if (data.day > 1) { 1845 if (data.day > 1) {
1814 // Check what remains of the start month 1846 // Check what remains of the start month
1815 for (it = days->begin(); it != days->end(); ++it) { 1847 for (it = days->begin(); it != days->end(); ++it) {
1816 if (*it >= data.day) { 1848 if (*it >= data.day) {
1817 ++countGone; 1849 ++countGone;
1818 if (--countTogo == 0) { 1850 if (--countTogo == 0) {
1819 data.day = *it; 1851 data.day = *it;
1820 break; 1852 break;
1821 } 1853 }
1822 } 1854 }
1823 } 1855 }
1824 if (countTogo) { 1856 if (countTogo) {
1825 data.day = 1; 1857 data.day = 1;
1826 data.addMonths(rFreq); 1858 data.addMonths(rFreq);
1827 } 1859 }
1828 } 1860 }
1829 if (countTogo) { 1861 if (countTogo) {
1830 if (data.varies) { 1862 if (data.varies) {
1831 // The number of recurrence days varies from month to month, 1863 // The number of recurrence days varies from month to month,
1832 // so we need to check month by month. 1864 // so we need to check month by month.
1833 for ( ; ; ) { 1865 for ( ; ; ) {
1834 days = data.dayList(); 1866 days = data.dayList();
1835 uint n = days->count(); // number of recurrence days in this month 1867 uint n = days->count(); // number of recurrence days in this month
1836 if (n >= countTogo) 1868 if (n >= countTogo)
1837 break; 1869 break;
1838 countTogo -= n; 1870 countTogo -= n;
1839 countGone += n; 1871 countGone += n;
1840 data.addMonths(rFreq); 1872 data.addMonths(rFreq);
1841 } 1873 }
1842 } else { 1874 } else {
1843 // The number of recurrences is the same every month, 1875 // The number of recurrences is the same every month,
1844 // so skip the month-by-month check. 1876 // so skip the month-by-month check.
1845 // Skip the remaining whole months, but leave at least 1877 // Skip the remaining whole months, but leave at least
1846 // 1 recurrence remaining, in order to get its date. 1878 // 1 recurrence remaining, in order to get its date.
1847 int daysPerMonth = days->count(); 1879 int daysPerMonth = days->count();
1848 int wholeMonths = (countTogo - 1) / daysPerMonth; 1880 int wholeMonths = (countTogo - 1) / daysPerMonth;
1849 data.addMonths(wholeMonths * rFreq); 1881 data.addMonths(wholeMonths * rFreq);
1850 countGone += wholeMonths * daysPerMonth; 1882 countGone += wholeMonths * daysPerMonth;
1851 countTogo -= wholeMonths * daysPerMonth; 1883 countTogo -= wholeMonths * daysPerMonth;
1852 } 1884 }
1853 if (countTogo) { 1885 if (countTogo) {
1854 // Check the last month in the recurrence 1886 // Check the last month in the recurrence
1855 for (it = days->begin(); it != days->end(); ++it) { 1887 for (it = days->begin(); it != days->end(); ++it) {
1856 ++countGone; 1888 ++countGone;
1857 if (--countTogo == 0) { 1889 if (--countTogo == 0) {
1858 data.day = *it; 1890 data.day = *it;
1859 break; 1891 break;
1860 } 1892 }
1861 } 1893 }
1862 } 1894 }
1863 } 1895 }
1864 enddate = data.date(); 1896 enddate = data.date();
1865 return countGone; 1897 return countGone;
1866} 1898}
1867 1899
1868int Recurrence::monthlyCalcToDate(const QDate &enddate, MonthlyData &data) const 1900int Recurrence::monthlyCalcToDate(const QDate &enddate, MonthlyData &data) const
1869{ 1901{
1870 int countGone = 0; 1902 int countGone = 0;
1871 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 1903 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
1872 int endYear = enddate.year(); 1904 int endYear = enddate.year();
1873 int endMonth = enddate.month() - 1; // zero-based 1905 int endMonth = enddate.month() - 1; // zero-based
1874 int endDay = enddate.day(); 1906 int endDay = enddate.day();
1875 int endYearMonth = endYear*12 + endMonth; 1907 int endYearMonth = endYear*12 + endMonth;
1876 QValueList<int>::ConstIterator it; 1908 QValueList<int>::ConstIterator it;
1877 const QValueList<int>* days = data.dayList(); 1909 const QValueList<int>* days = data.dayList();
1878 1910
1879 if (data.day > 1) { 1911 if (data.day > 1) {
1880 // Check what remains of the start month 1912 // Check what remains of the start month
1881 for (it = days->begin(); it != days->end(); ++it) { 1913 for (it = days->begin(); it != days->end(); ++it) {
1882 if (*it >= data.day) { 1914 if (*it >= data.day) {
1883 if (data.yearMonth() == endYearMonth && *it > endDay) 1915 if (data.yearMonth() == endYearMonth && *it > endDay)
1884 return countGone; 1916 return countGone;
1885 if (++countGone >= countMax) 1917 if (++countGone >= countMax)
1886 return countMax; 1918 return countMax;
1887 } 1919 }
1888 } 1920 }
1889 data.day = 1; 1921 data.day = 1;
1890 data.addMonths(rFreq); 1922 data.addMonths(rFreq);
1891 } 1923 }
1892 1924
1893 if (data.varies) { 1925 if (data.varies) {
1894 // The number of recurrence days varies from month to month, 1926 // The number of recurrence days varies from month to month,
1895 // so we need to check month by month. 1927 // so we need to check month by month.
1896 while (data.yearMonth() < endYearMonth) { 1928 while (data.yearMonth() < endYearMonth) {
1897 countGone += data.dayList()->count(); 1929 countGone += data.dayList()->count();
1898 if (countGone >= countMax) 1930 if (countGone >= countMax)
1899 return countMax; 1931 return countMax;
1900 data.addMonths(rFreq); 1932 data.addMonths(rFreq);
1901 } 1933 }
1902 days = data.dayList(); 1934 days = data.dayList();
1903 } else { 1935 } else {
1904 // The number of recurrences is the same every month, 1936 // The number of recurrences is the same every month,
1905 // so skip the month-by-month check. 1937 // so skip the month-by-month check.
1906 // Skip the remaining whole months. 1938 // Skip the remaining whole months.
1907 int daysPerMonth = days->count(); 1939 int daysPerMonth = days->count();
1908 int wholeMonths = endYearMonth - data.yearMonth(); 1940 int wholeMonths = endYearMonth - data.yearMonth();
1909 countGone += (wholeMonths / rFreq) * daysPerMonth; 1941 countGone += (wholeMonths / rFreq) * daysPerMonth;
1910 if (countGone >= countMax) 1942 if (countGone >= countMax)
1911 return countMax; 1943 return countMax;
1912 if (wholeMonths % rFreq) 1944 if (wholeMonths % rFreq)
1913 return countGone; // end year isn't a recurrence year 1945 return countGone; // end year isn't a recurrence year
1914 data.year = endYear; 1946 data.year = endYear;
1915 data.month = endMonth; 1947 data.month = endMonth;
1916 } 1948 }
1917 1949
1918 // Check the last month in the recurrence 1950 // Check the last month in the recurrence
1919 for (it = days->begin(); it != days->end(); ++it) { 1951 for (it = days->begin(); it != days->end(); ++it) {
1920 if (*it > endDay) 1952 if (*it > endDay)
1921 return countGone; 1953 return countGone;
1922 if (++countGone >= countMax) 1954 if (++countGone >= countMax)
1923 return countMax; 1955 return countMax;
1924 } 1956 }
1925 return countGone; 1957 return countGone;
1926} 1958}
1927 1959
1928int Recurrence::monthlyCalcNextAfter(QDate &enddate, MonthlyData &data) const 1960int Recurrence::monthlyCalcNextAfter(QDate &enddate, MonthlyData &data) const
1929{ 1961{
1930 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 1962 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
1931 int countGone = 0; 1963 int countGone = 0;
1932 int endYear = enddate.year(); 1964 int endYear = enddate.year();
1933 int endDay = enddate.day(); 1965 int endDay = enddate.day();
1934 int endYearMonth = endYear*12 + enddate.month() - 1; 1966 int endYearMonth = endYear*12 + enddate.month() - 1;
1935 QValueList<int>::ConstIterator it; 1967 QValueList<int>::ConstIterator it;
1936 const QValueList<int>* days = data.dayList(); 1968 const QValueList<int>* days = data.dayList();
1937 1969
1938 if (data.day > 1) { 1970 if (data.day > 1) {
1939 // Check what remains of the start month 1971 // Check what remains of the start month
1940 for (it = days->begin(); it != days->end(); ++it) { 1972 for (it = days->begin(); it != days->end(); ++it) {
1941 if (*it >= data.day) { 1973 if (*it >= data.day) {
1942 ++countGone; 1974 ++countGone;
1943 if (data.yearMonth() == endYearMonth && *it > endDay) { 1975 if (data.yearMonth() == endYearMonth && *it > endDay) {
1944 data.day = *it; 1976 data.day = *it;
1945 goto ex; 1977 goto ex;
1946 } 1978 }
1947 if (--countTogo == 0) 1979 if (--countTogo == 0)
1948 return 0; 1980 return 0;
1949 } 1981 }
1950 } 1982 }
1951 data.day = 1; 1983 data.day = 1;
1952 data.addMonths(rFreq); 1984 data.addMonths(rFreq);
1953 } 1985 }
1954 1986
1955 if (data.varies) { 1987 if (data.varies) {
1956 // The number of recurrence days varies from month to month, 1988 // The number of recurrence days varies from month to month,
1957 // so we need to check month by month. 1989 // so we need to check month by month.
1958 while (data.yearMonth() <= endYearMonth) { 1990 while (data.yearMonth() <= endYearMonth) {
1959 days = data.dayList(); 1991 days = data.dayList();
1960 uint n = days->count(); // number of recurrence days in this month 1992 uint n = days->count(); // number of recurrence days in this month
1961 if (data.yearMonth() == endYearMonth && days->last() > endDay) 1993 if (data.yearMonth() == endYearMonth && days->last() > endDay)
1962 break; 1994 break;
1963 if (n >= countTogo) 1995 if (n >= countTogo)
1964 return 0; 1996 return 0;
1965 countGone += n; 1997 countGone += n;
1966 countTogo -= n; 1998 countTogo -= n;
1967 data.addMonths(rFreq); 1999 data.addMonths(rFreq);
1968 } 2000 }
1969 days = data.dayList(); 2001 days = data.dayList();
1970 } else { 2002 } else {
1971 // The number of recurrences is the same every month, 2003 // The number of recurrences is the same every month,
1972 // so skip the month-by-month check. 2004 // so skip the month-by-month check.
1973 // Skip the remaining whole months to at least end year/month. 2005 // Skip the remaining whole months to at least end year/month.
1974 int daysPerMonth = days->count(); 2006 int daysPerMonth = days->count();
1975 int elapsed = endYearMonth - data.yearMonth(); 2007 int elapsed = endYearMonth - data.yearMonth();
1976 int recurMonths = (elapsed + rFreq - 1) / rFreq; 2008 int recurMonths = (elapsed + rFreq - 1) / rFreq;
1977 if (elapsed % rFreq == 0 && days->last() <= endDay) 2009 if (elapsed % rFreq == 0 && days->last() <= endDay)
1978 ++recurMonths; // required month is after endYearMonth 2010 ++recurMonths; // required month is after endYearMonth
1979 if (recurMonths) { 2011 if (recurMonths) {
1980 int n = recurMonths * daysPerMonth; 2012 int n = recurMonths * daysPerMonth;
1981 if (static_cast<uint>(n) > countTogo) 2013 if (static_cast<uint>(n) > countTogo)
1982 return 0; // reached end of recurrence 2014 return 0; // reached end of recurrence
1983 countTogo -= n; 2015 countTogo -= n;
1984 countGone += n; 2016 countGone += n;
1985 data.addMonths(recurMonths * rFreq); 2017 data.addMonths(recurMonths * rFreq);
1986 } 2018 }
1987 } 2019 }
1988 2020
1989 // Check the last month in the recurrence 2021 // Check the last month in the recurrence
1990 for (it = days->begin(); it != days->end(); ++it) { 2022 for (it = days->begin(); it != days->end(); ++it) {
1991 ++countGone; 2023 ++countGone;
1992 if (data.yearMonth() > endYearMonth || *it > endDay) { 2024 if (data.yearMonth() > endYearMonth || *it > endDay) {
1993 data.day = *it; 2025 data.day = *it;
1994 break; 2026 break;
1995 } 2027 }
1996 if (--countTogo == 0) 2028 if (--countTogo == 0)
1997 return 0; 2029 return 0;
1998 } 2030 }
1999ex: 2031ex:
2000 enddate = data.date(); 2032 enddate = data.date();
2001 return countGone; 2033 return countGone;
2002} 2034}
2003 2035
2004 2036
2005/* Find count and, depending on 'func', the end date of an annual recurrence by date. 2037/* Find count and, depending on 'func', the end date of an annual recurrence by date.
2006 * Reply = total number of occurrences up to 'enddate', or 0 if error. 2038 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2007 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 2039 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2008 * recurrence end date. 2040 * recurrence end date.
2009 */ 2041 */
2010struct Recurrence::YearlyMonthData { 2042struct Recurrence::YearlyMonthData {
2011 const Recurrence *recurrence; 2043 const Recurrence *recurrence;
2012 int year; // current year 2044 int year; // current year
2013 int month; // current month 1..12 2045 int month; // current month 1..12
2014 int day; // current day of month 1..31 2046 int day; // current day of month 1..31
2015 bool leapyear; // true if February 29th recurs and current year is a leap year 2047 bool leapyear; // true if February 29th recurs and current year is a leap year
2016 bool feb29; // true if February 29th recurs 2048 bool feb29; // true if February 29th recurs
2017 private: 2049 private:
2018 QValueList<int> months; // recurring months in non-leap years 1..12 2050 QValueList<int> months; // recurring months in non-leap years 1..12
2019 QValueList<int> leapMonths; // recurring months in leap years 1..12 2051 QValueList<int> leapMonths; // recurring months in leap years 1..12
2020 public: 2052 public:
2021 YearlyMonthData(const Recurrence* r, const QDate &date) 2053 YearlyMonthData(const Recurrence* r, const QDate &date)
2022 : recurrence(r), year(date.year()), month(date.month()), day(date.day()) 2054 : recurrence(r), year(date.year()), month(date.month()), day(date.day())
2023 { feb29 = recurrence->getYearlyMonthMonths(day, months, leapMonths); 2055 { feb29 = recurrence->getYearlyMonthMonths(day, months, leapMonths);
2024 leapyear = feb29 && QDate::leapYear(year); 2056 leapyear = feb29 && QDate::leapYear(year);
2025 } 2057 }
2026 const QValueList<int>* monthList() const 2058 const QValueList<int>* monthList() const
2027 { return leapyear ? &leapMonths : &months; } 2059 { return leapyear ? &leapMonths : &months; }
2028 const QValueList<int>* leapMonthList() const { return &leapMonths; } 2060 const QValueList<int>* leapMonthList() const { return &leapMonths; }
2029 QDate date() const { return QDate(year, month, day); } 2061 QDate date() const { return QDate(year, month, day); }
2030}; 2062};
2031 2063
2032int Recurrence::yearlyMonthCalc(PeriodFunc func, QDate &enddate) const 2064int Recurrence::yearlyMonthCalc(PeriodFunc func, QDate &enddate) const
2033{ 2065{
2034 if (rYearNums.isEmpty()) 2066 if (rYearNums.isEmpty())
2035 return 0; 2067 return 0;
2036 YearlyMonthData data(this, mRecurStart.date()); 2068 YearlyMonthData data(this, mRecurStart.date());
2037 switch (func) { 2069 switch (func) {
2038 case END_DATE_AND_COUNT: 2070 case END_DATE_AND_COUNT:
2039 return yearlyMonthCalcEndDate(enddate, data); 2071 return yearlyMonthCalcEndDate(enddate, data);
2040 case COUNT_TO_DATE: 2072 case COUNT_TO_DATE:
2041 return yearlyMonthCalcToDate(enddate, data); 2073 return yearlyMonthCalcToDate(enddate, data);
2042 case NEXT_AFTER_DATE: 2074 case NEXT_AFTER_DATE:
2043 return yearlyMonthCalcNextAfter(enddate, data); 2075 return yearlyMonthCalcNextAfter(enddate, data);
2044 } 2076 }
2045 return 0; 2077 return 0;
2046} 2078}
2047 2079
2048// Find total count and end date of an annual recurrence by date. 2080// Find total count and end date of an annual recurrence by date.
2049// Reply = total number of occurrences. 2081// Reply = total number of occurrences.
2050int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) const 2082int Recurrence::yearlyMonthCalcEndDate(QDate &enddate, YearlyMonthData &data) const
2051{ 2083{
2052 uint countTogo = rDuration + mRecurExDatesCount; 2084 uint countTogo = rDuration + mRecurExDatesCount;
2053 int countGone = 0; 2085 int countGone = 0;
2054 QValueList<int>::ConstIterator it; 2086 QValueList<int>::ConstIterator it;
2055 const QValueList<int>* mons = data.monthList(); // get recurring months for this year 2087 const QValueList<int>* mons = data.monthList(); // get recurring months for this year
2056 2088
2057 if (data.month > 1) { 2089 if (data.month > 1) {
2058 // Check what remains of the start year 2090 // Check what remains of the start year
2059 for (it = mons->begin(); it != mons->end(); ++it) { 2091 for (it = mons->begin(); it != mons->end(); ++it) {
2060 if (*it >= data.month) { 2092 if (*it >= data.month) {
2061 ++countGone; 2093 ++countGone;
2062 if (--countTogo == 0) { 2094 if (--countTogo == 0) {
2063 data.month = *it; 2095 data.month = *it;
2064 if (data.month == 2 && data.feb29 && !data.leapyear) { 2096 if (data.month == 2 && data.feb29 && !data.leapyear) {
2065 // The recurrence should end on February 29th, but it's a non-leap year 2097 // The recurrence should end on February 29th, but it's a non-leap year
2066 switch (mFeb29YearlyType) { 2098 switch (mFeb29YearlyType) {
2067 case rFeb28: 2099 case rFeb28:
2068 data.day = 28; 2100 data.day = 28;
2069 break; 2101 break;
2070 case rMar1: 2102 case rMar1:
2071 data.month = 3; 2103 data.month = 3;
2072 data.day = 1; 2104 data.day = 1;
2073 break; 2105 break;
2074 case rFeb29: 2106 case rFeb29:
2075 break; 2107 break;
2076 } 2108 }
2077 } 2109 }
2078 break; 2110 break;
2079 } 2111 }
2080 } 2112 }
2081 } 2113 }
2082 if (countTogo) { 2114 if (countTogo) {
2083 data.month = 1; 2115 data.month = 1;
2084 data.year += rFreq; 2116 data.year += rFreq;
2085 } 2117 }
2086 } 2118 }
2087 if (countTogo) { 2119 if (countTogo) {
2088 if (data.feb29 && mFeb29YearlyType == rFeb29) { 2120 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2089 // The number of recurrences is different on leap years, 2121 // The number of recurrences is different on leap years,
2090 // so check year-by-year. 2122 // so check year-by-year.
2091 for ( ; ; ) { 2123 for ( ; ; ) {
2092 mons = data.monthList(); 2124 mons = data.monthList();
2093 uint n = mons->count(); 2125 uint n = mons->count();
2094 if (n >= countTogo) 2126 if (n >= countTogo)
2095 break; 2127 break;
2096 countTogo -= n; 2128 countTogo -= n;
2097 countGone += n; 2129 countGone += n;
2098 data.year += rFreq; 2130 data.year += rFreq;
2099 } 2131 }
2100 } else { 2132 } else {
2101 // The number of recurrences is the same every year, 2133 // The number of recurrences is the same every year,
2102 // so skip the year-by-year check. 2134 // so skip the year-by-year check.
2103 // Skip the remaining whole years, but leave at least 2135 // Skip the remaining whole years, but leave at least
2104 // 1 recurrence remaining, in order to get its date. 2136 // 1 recurrence remaining, in order to get its date.
2105 int monthsPerYear = mons->count(); 2137 int monthsPerYear = mons->count();
2106 int wholeYears = (countTogo - 1) / monthsPerYear; 2138 int wholeYears = (countTogo - 1) / monthsPerYear;
2107 data.year += wholeYears * rFreq; 2139 data.year += wholeYears * rFreq;
2108 countGone += wholeYears * monthsPerYear; 2140 countGone += wholeYears * monthsPerYear;
2109 countTogo -= wholeYears * monthsPerYear; 2141 countTogo -= wholeYears * monthsPerYear;
2110 } 2142 }
2111 if (countTogo) { 2143 if (countTogo) {
2112 // Check the last year in the recurrence 2144 // Check the last year in the recurrence
2113 for (it = mons->begin(); it != mons->end(); ++it) { 2145 for (it = mons->begin(); it != mons->end(); ++it) {
2114 ++countGone; 2146 ++countGone;
2115 if (--countTogo == 0) { 2147 if (--countTogo == 0) {
2116 data.month = *it; 2148 data.month = *it;
2117 if (data.month == 2 && data.feb29 && !QDate::leapYear(data.year)) { 2149 if (data.month == 2 && data.feb29 && !QDate::leapYear(data.year)) {
2118 // The recurrence should end on February 29th, but it's a non-leap year 2150 // The recurrence should end on February 29th, but it's a non-leap year
2119 switch (mFeb29YearlyType) { 2151 switch (mFeb29YearlyType) {
2120 case rFeb28: 2152 case rFeb28:
2121 data.day = 28; 2153 data.day = 28;
2122 break; 2154 break;
2123 case rMar1: 2155 case rMar1:
2124 data.month = 3; 2156 data.month = 3;
2125 data.day = 1; 2157 data.day = 1;
2126 break; 2158 break;
2127 case rFeb29: 2159 case rFeb29:
2128 break; 2160 break;
2129 } 2161 }
2130 } 2162 }
2131 break; 2163 break;
2132 } 2164 }
2133 } 2165 }
2134 } 2166 }
2135 } 2167 }
2136 enddate = data.date(); 2168 enddate = data.date();
2137 return countGone; 2169 return countGone;
2138} 2170}
2139 2171
2140// Find count of an annual recurrence by date. 2172// Find count of an annual recurrence by date.
2141// Reply = total number of occurrences up to 'enddate'. 2173// Reply = total number of occurrences up to 'enddate'.
2142int Recurrence::yearlyMonthCalcToDate(const QDate &enddate, YearlyMonthData &data) const 2174int Recurrence::yearlyMonthCalcToDate(const QDate &enddate, YearlyMonthData &data) const
2143{ 2175{
2144 int countGone = 0; 2176 int countGone = 0;
2145 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 2177 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2146 int endYear = enddate.year(); 2178 int endYear = enddate.year();
2147 int endMonth = enddate.month(); 2179 int endMonth = enddate.month();
2148 int endDay = enddate.day(); 2180 int endDay = enddate.day();
2149 if (endDay < data.day) { 2181 if (endDay < data.day) {
2150 /* The end day of the month is earlier than the recurrence day of the month. 2182 /* The end day of the month is earlier than the recurrence day of the month.
2151 * If Feb 29th recurs and: 2183 * If Feb 29th recurs and:
2152 * 1) it recurs on Feb 28th in non-leap years, don't adjust the end month 2184 * 1) it recurs on Feb 28th in non-leap years, don't adjust the end month
2153 * if enddate is Feb 28th on a non-leap year. 2185 * if enddate is Feb 28th on a non-leap year.
2154 * 2) it recurs on Mar 1st in non-leap years, allow the end month to be 2186 * 2) it recurs on Mar 1st in non-leap years, allow the end month to be
2155 * adjusted to February, to simplify calculations. 2187 * adjusted to February, to simplify calculations.
2156 */ 2188 */
2157 if (data.feb29 && !QDate::leapYear(endYear) 2189 if (data.feb29 && !QDate::leapYear(endYear)
2158 && mFeb29YearlyType == rFeb28 && endDay == 28 && endMonth == 2) { 2190 && mFeb29YearlyType == rFeb28 && endDay == 28 && endMonth == 2) {
2159 } 2191 }
2160 else if (--endMonth == 0) { 2192 else if (--endMonth == 0) {
2161 endMonth = 12; 2193 endMonth = 12;
2162 --endYear; 2194 --endYear;
2163 } 2195 }
2164 } 2196 }
2165 QValueList<int>::ConstIterator it; 2197 QValueList<int>::ConstIterator it;
2166 const QValueList<int>* mons = data.monthList(); 2198 const QValueList<int>* mons = data.monthList();
2167 2199
2168 if (data.month > 1) { 2200 if (data.month > 1) {
2169 // Check what remains of the start year 2201 // Check what remains of the start year
2170 for (it = mons->begin(); it != mons->end(); ++it) { 2202 for (it = mons->begin(); it != mons->end(); ++it) {
2171 if (*it >= data.month) { 2203 if (*it >= data.month) {
2172 if (data.year == endYear && *it > endMonth) 2204 if (data.year == endYear && *it > endMonth)
2173 return countGone; 2205 return countGone;
2174 if (++countGone >= countMax) 2206 if (++countGone >= countMax)
2175 return countMax; 2207 return countMax;
2176 } 2208 }
2177 } 2209 }
2178 data.month = 1; 2210 data.month = 1;
2179 data.year += rFreq; 2211 data.year += rFreq;
2180 } 2212 }
2181 if (data.feb29 && mFeb29YearlyType == rFeb29) { 2213 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2182 // The number of recurrences is different on leap years, 2214 // The number of recurrences is different on leap years,
2183 // so check year-by-year. 2215 // so check year-by-year.
2184 while (data.year < endYear) { 2216 while (data.year < endYear) {