summaryrefslogtreecommitdiffabout
path: root/libkcal
authorzautrix <zautrix>2004-09-14 01:03:08 (UTC)
committer zautrix <zautrix>2004-09-14 01:03:08 (UTC)
commit30762fe125216362e1a6c1d5ec5d22d9525aa336 (patch) (unidiff)
tree4ff0fbf43efa921c86d64ff3f50baa9e59d207d9 /libkcal
parent8ce7eae438dcd20f9c79fc0a36dfef0a6d3931eb (diff)
downloadkdepimpi-30762fe125216362e1a6c1d5ec5d22d9525aa336.zip
kdepimpi-30762fe125216362e1a6c1d5ec5d22d9525aa336.tar.gz
kdepimpi-30762fe125216362e1a6c1d5ec5d22d9525aa336.tar.bz2
Many bugfixes
Diffstat (limited to 'libkcal') (more/less context) (ignore whitespace changes)
-rw-r--r--libkcal/alarm.cpp36
-rw-r--r--libkcal/recurrence.cpp56
-rw-r--r--libkcal/sharpformat.cpp7
3 files changed, 83 insertions, 16 deletions
diff --git a/libkcal/alarm.cpp b/libkcal/alarm.cpp
index 29e6205..1fc7169 100644
--- a/libkcal/alarm.cpp
+++ b/libkcal/alarm.cpp
@@ -1,423 +1,457 @@
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 5
6 This library is free software; you can redistribute it and/or 6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public 7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either 8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version. 9 version 2 of the License, or (at your option) any later version.
10 10
11 This library is distributed in the hope that it will be useful, 11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details. 14 Library General Public License for more details.
15 15
16 You should have received a copy of the GNU Library General Public License 16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to 17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. 19 Boston, MA 02111-1307, USA.
20*/ 20*/
21 21
22#include <kdebug.h> 22#include <kdebug.h>
23 23
24#include "incidence.h" 24#include "incidence.h"
25#include "todo.h" 25#include "todo.h"
26 26
27#include "alarm.h" 27#include "alarm.h"
28 28
29using namespace KCal; 29using namespace KCal;
30#include <qwidget.h> 30#include <qwidget.h>
31Alarm::Alarm(Incidence *parent) 31Alarm::Alarm(Incidence *parent)
32 : mParent(parent), 32 : mParent(parent),
33 mType(Audio), 33 mType(Audio),
34 mDescription(""), // to make operator==() not fail 34 mDescription(""), // to make operator==() not fail
35 mFile(""), // to make operator==() not fail 35 mFile(""), // to make operator==() not fail
36 mMailSubject(""), // to make operator==() not fail 36 mMailSubject(""), // to make operator==() not fail
37 mAlarmSnoozeTime(5), 37 mAlarmSnoozeTime(5),
38 mAlarmRepeatCount(0), 38 mAlarmRepeatCount(0),
39 mEndOffset(false), 39 mEndOffset(false),
40 mHasTime(false), 40 mHasTime(false),
41 mAlarmEnabled(false) 41 mAlarmEnabled(false)
42{ 42{
43 43
44} 44}
45 45
46Alarm::~Alarm() 46Alarm::~Alarm()
47{ 47{
48} 48}
49 49
50bool Alarm::operator==( const Alarm& rhs ) const 50bool Alarm::operator==( const Alarm& rhs ) const
51{ 51{
52
52 if ( mType != rhs.mType || 53 if ( mType != rhs.mType ||
53 mAlarmSnoozeTime != rhs.mAlarmSnoozeTime || 54 mAlarmSnoozeTime != rhs.mAlarmSnoozeTime ||
54 mAlarmRepeatCount != rhs.mAlarmRepeatCount || 55 mAlarmRepeatCount != rhs.mAlarmRepeatCount ||
55 mAlarmEnabled != rhs.mAlarmEnabled || 56 mAlarmEnabled != rhs.mAlarmEnabled ||
56 mHasTime != rhs.mHasTime) 57 mHasTime != rhs.mHasTime)
57 return false; 58 return false;
58 59
60#if 0
61 if ( mType != rhs.mType ) {
62
63 qDebug("aaa1 ");
64 return false;
65 }
66
67 if ( mAlarmSnoozeTime != rhs.mAlarmSnoozeTime ) {
68
69 qDebug("aaa2 ");
70 return false;
71 }
72
73
74 if ( mAlarmRepeatCount != rhs.mAlarmRepeatCount ) {
75
76 qDebug("aaa3 ");
77 return false;
78 }
79
80 if ( mAlarmEnabled != rhs.mAlarmEnabled ) {
81
82 qDebug("aaa4 ");
83 return false;
84 }
85
86 if ( mHasTime != rhs.mHasTime ) {
87
88 qDebug("aaa5 ");
89 return false;
90 }
91#endif
92
93
59 if (mHasTime) { 94 if (mHasTime) {
60 if (mAlarmTime != rhs.mAlarmTime) 95 if (mAlarmTime != rhs.mAlarmTime)
61 return false; 96 return false;
62 } else { 97 } else {
63 if (mOffset != rhs.mOffset || 98 if (mOffset != rhs.mOffset ||
64 mEndOffset != rhs.mEndOffset) 99 mEndOffset != rhs.mEndOffset)
65 return false; 100 return false;
66 } 101 }
67
68 switch (mType) { 102 switch (mType) {
69 case Display: 103 case Display:
70 return mDescription == rhs.mDescription; 104 return mDescription == rhs.mDescription;
71 105
72 case Email: 106 case Email:
73 return mDescription == rhs.mDescription && 107 return mDescription == rhs.mDescription &&
74 mMailAttachFiles == rhs.mMailAttachFiles && 108 mMailAttachFiles == rhs.mMailAttachFiles &&
75 mMailAddresses == rhs.mMailAddresses && 109 mMailAddresses == rhs.mMailAddresses &&
76 mMailSubject == rhs.mMailSubject; 110 mMailSubject == rhs.mMailSubject;
77 111
78 case Procedure: 112 case Procedure:
79 return mFile == rhs.mFile && 113 return mFile == rhs.mFile &&
80 mDescription == rhs.mDescription; 114 mDescription == rhs.mDescription;
81 115
82 case Audio: 116 case Audio:
83 return mFile == rhs.mFile; 117 return mFile == rhs.mFile;
84 118
85 case Invalid: 119 case Invalid:
86 break; 120 break;
87 } 121 }
88 return false; 122 return false;
89} 123}
90 124
91void Alarm::setType(Alarm::Type type) 125void Alarm::setType(Alarm::Type type)
92{ 126{
93 if (type == mType) 127 if (type == mType)
94 return; 128 return;
95 129
96 switch (type) { 130 switch (type) {
97 case Display: 131 case Display:
98 mDescription = ""; 132 mDescription = "";
99 break; 133 break;
100 case Procedure: 134 case Procedure:
101 mFile = mDescription = ""; 135 mFile = mDescription = "";
102 break; 136 break;
103 case Audio: 137 case Audio:
104 mFile = ""; 138 mFile = "";
105 break; 139 break;
106 case Email: 140 case Email:
107 mMailSubject = mDescription = ""; 141 mMailSubject = mDescription = "";
108 mMailAddresses.clear(); 142 mMailAddresses.clear();
109 mMailAttachFiles.clear(); 143 mMailAttachFiles.clear();
110 break; 144 break;
111 case Invalid: 145 case Invalid:
112 break; 146 break;
113 default: 147 default:
114 return; 148 return;
115 } 149 }
116 mType = type; 150 mType = type;
117 mParent->updated(); 151 mParent->updated();
118} 152}
119 153
120Alarm::Type Alarm::type() const 154Alarm::Type Alarm::type() const
121{ 155{
122 return mType; 156 return mType;
123} 157}
124 158
125void Alarm::setAudioAlarm(const QString &audioFile) 159void Alarm::setAudioAlarm(const QString &audioFile)
126{ 160{
127 mType = Audio; 161 mType = Audio;
128 mFile = audioFile; 162 mFile = audioFile;
129 mParent->updated(); 163 mParent->updated();
130} 164}
131 165
132void Alarm::setAudioFile(const QString &audioFile) 166void Alarm::setAudioFile(const QString &audioFile)
133{ 167{
134 if (mType == Audio) { 168 if (mType == Audio) {
135 mFile = audioFile; 169 mFile = audioFile;
136 mParent->updated(); 170 mParent->updated();
137 } 171 }
138} 172}
139 173
140QString Alarm::audioFile() const 174QString Alarm::audioFile() const
141{ 175{
142 return (mType == Audio) ? mFile : QString::null; 176 return (mType == Audio) ? mFile : QString::null;
143} 177}
144 178
145void Alarm::setProcedureAlarm(const QString &programFile, const QString &arguments) 179void Alarm::setProcedureAlarm(const QString &programFile, const QString &arguments)
146{ 180{
147 mType = Procedure; 181 mType = Procedure;
148 mFile = programFile; 182 mFile = programFile;
149 mDescription = arguments; 183 mDescription = arguments;
150 mParent->updated(); 184 mParent->updated();
151} 185}
152 186
153void Alarm::setProgramFile(const QString &programFile) 187void Alarm::setProgramFile(const QString &programFile)
154{ 188{
155 if (mType == Procedure) { 189 if (mType == Procedure) {
156 mFile = programFile; 190 mFile = programFile;
157 mParent->updated(); 191 mParent->updated();
158 } 192 }
159} 193}
160 194
161QString Alarm::programFile() const 195QString Alarm::programFile() const
162{ 196{
163 return (mType == Procedure) ? mFile : QString::null; 197 return (mType == Procedure) ? mFile : QString::null;
164} 198}
165 199
166void Alarm::setProgramArguments(const QString &arguments) 200void Alarm::setProgramArguments(const QString &arguments)
167{ 201{
168 if (mType == Procedure) { 202 if (mType == Procedure) {
169 mDescription = arguments; 203 mDescription = arguments;
170 mParent->updated(); 204 mParent->updated();
171 } 205 }
172} 206}
173 207
174QString Alarm::programArguments() const 208QString Alarm::programArguments() const
175{ 209{
176 return (mType == Procedure) ? mDescription : QString::null; 210 return (mType == Procedure) ? mDescription : QString::null;
177} 211}
178 212
179void Alarm::setEmailAlarm(const QString &subject, const QString &text, 213void Alarm::setEmailAlarm(const QString &subject, const QString &text,
180 const QValueList<Person> &addressees, const QStringList &attachments) 214 const QValueList<Person> &addressees, const QStringList &attachments)
181{ 215{
182 mType = Email; 216 mType = Email;
183 mMailSubject = subject; 217 mMailSubject = subject;
184 mDescription = text; 218 mDescription = text;
185 mMailAddresses = addressees; 219 mMailAddresses = addressees;
186 mMailAttachFiles = attachments; 220 mMailAttachFiles = attachments;
187 mParent->updated(); 221 mParent->updated();
188} 222}
189 223
190void Alarm::setMailAddress(const Person &mailAddress) 224void Alarm::setMailAddress(const Person &mailAddress)
191{ 225{
192 if (mType == Email) { 226 if (mType == Email) {
193 mMailAddresses.clear(); 227 mMailAddresses.clear();
194 mMailAddresses += mailAddress; 228 mMailAddresses += mailAddress;
195 mParent->updated(); 229 mParent->updated();
196 } 230 }
197} 231}
198 232
199void Alarm::setMailAddresses(const QValueList<Person> &mailAddresses) 233void Alarm::setMailAddresses(const QValueList<Person> &mailAddresses)
200{ 234{
201 if (mType == Email) { 235 if (mType == Email) {
202 mMailAddresses = mailAddresses; 236 mMailAddresses = mailAddresses;
203 mParent->updated(); 237 mParent->updated();
204 } 238 }
205} 239}
206 240
207void Alarm::addMailAddress(const Person &mailAddress) 241void Alarm::addMailAddress(const Person &mailAddress)
208{ 242{
209 if (mType == Email) { 243 if (mType == Email) {
210 mMailAddresses += mailAddress; 244 mMailAddresses += mailAddress;
211 mParent->updated(); 245 mParent->updated();
212 } 246 }
213} 247}
214 248
215QValueList<Person> Alarm::mailAddresses() const 249QValueList<Person> Alarm::mailAddresses() const
216{ 250{
217 return (mType == Email) ? mMailAddresses : QValueList<Person>(); 251 return (mType == Email) ? mMailAddresses : QValueList<Person>();
218} 252}
219 253
220void Alarm::setMailSubject(const QString &mailAlarmSubject) 254void Alarm::setMailSubject(const QString &mailAlarmSubject)
221{ 255{
222 if (mType == Email) { 256 if (mType == Email) {
223 mMailSubject = mailAlarmSubject; 257 mMailSubject = mailAlarmSubject;
224 mParent->updated(); 258 mParent->updated();
225 } 259 }
226} 260}
227 261
228QString Alarm::mailSubject() const 262QString Alarm::mailSubject() const
229{ 263{
230 return (mType == Email) ? mMailSubject : QString::null; 264 return (mType == Email) ? mMailSubject : QString::null;
231} 265}
232 266
233void Alarm::setMailAttachment(const QString &mailAttachFile) 267void Alarm::setMailAttachment(const QString &mailAttachFile)
234{ 268{
235 if (mType == Email) { 269 if (mType == Email) {
236 mMailAttachFiles.clear(); 270 mMailAttachFiles.clear();
237 mMailAttachFiles += mailAttachFile; 271 mMailAttachFiles += mailAttachFile;
238 mParent->updated(); 272 mParent->updated();
239 } 273 }
240} 274}
241 275
242void Alarm::setMailAttachments(const QStringList &mailAttachFiles) 276void Alarm::setMailAttachments(const QStringList &mailAttachFiles)
243{ 277{
244 if (mType == Email) { 278 if (mType == Email) {
245 mMailAttachFiles = mailAttachFiles; 279 mMailAttachFiles = mailAttachFiles;
246 mParent->updated(); 280 mParent->updated();
247 } 281 }
248} 282}
249 283
250void Alarm::addMailAttachment(const QString &mailAttachFile) 284void Alarm::addMailAttachment(const QString &mailAttachFile)
251{ 285{
252 if (mType == Email) { 286 if (mType == Email) {
253 mMailAttachFiles += mailAttachFile; 287 mMailAttachFiles += mailAttachFile;
254 mParent->updated(); 288 mParent->updated();
255 } 289 }
256} 290}
257 291
258QStringList Alarm::mailAttachments() const 292QStringList Alarm::mailAttachments() const
259{ 293{
260 return (mType == Email) ? mMailAttachFiles : QStringList(); 294 return (mType == Email) ? mMailAttachFiles : QStringList();
261} 295}
262 296
263void Alarm::setMailText(const QString &text) 297void Alarm::setMailText(const QString &text)
264{ 298{
265 if (mType == Email) { 299 if (mType == Email) {
266 mDescription = text; 300 mDescription = text;
267 mParent->updated(); 301 mParent->updated();
268 } 302 }
269} 303}
270 304
271QString Alarm::mailText() const 305QString Alarm::mailText() const
272{ 306{
273 return (mType == Email) ? mDescription : QString::null; 307 return (mType == Email) ? mDescription : QString::null;
274} 308}
275 309
276void Alarm::setDisplayAlarm(const QString &text) 310void Alarm::setDisplayAlarm(const QString &text)
277{ 311{
278 mType = Display; 312 mType = Display;
279 mDescription = text; 313 mDescription = text;
280 mParent->updated(); 314 mParent->updated();
281} 315}
282 316
283void Alarm::setText(const QString &text) 317void Alarm::setText(const QString &text)
284{ 318{
285 if (mType == Display) { 319 if (mType == Display) {
286 mDescription = text; 320 mDescription = text;
287 mParent->updated(); 321 mParent->updated();
288 } 322 }
289} 323}
290 324
291QString Alarm::text() const 325QString Alarm::text() const
292{ 326{
293 return (mType == Display) ? mDescription : QString::null; 327 return (mType == Display) ? mDescription : QString::null;
294} 328}
295 329
296void Alarm::setTime(const QDateTime &alarmTime) 330void Alarm::setTime(const QDateTime &alarmTime)
297{ 331{
298 mAlarmTime = alarmTime; 332 mAlarmTime = alarmTime;
299 mHasTime = true; 333 mHasTime = true;
300 334
301 mParent->updated(); 335 mParent->updated();
302} 336}
303int Alarm::offset() 337int Alarm::offset()
304{ 338{
305 if ( hasTime() ) { 339 if ( hasTime() ) {
306 if (mParent->type()=="Todo") { 340 if (mParent->type()=="Todo") {
307 Todo *t = static_cast<Todo*>(mParent); 341 Todo *t = static_cast<Todo*>(mParent);
308 return t->dtDue().secsTo( mAlarmTime ) ; 342 return t->dtDue().secsTo( mAlarmTime ) ;
309 } else 343 } else
310 return mParent->dtStart().secsTo( mAlarmTime ) ; 344 return mParent->dtStart().secsTo( mAlarmTime ) ;
311 } 345 }
312 else 346 else
313 { 347 {
314 return mOffset.asSeconds(); 348 return mOffset.asSeconds();
315 } 349 }
316 350
317} 351}
318 352
319 353
320QDateTime Alarm::time() const 354QDateTime Alarm::time() const
321{ 355{
322 if ( hasTime() ) 356 if ( hasTime() )
323 return mAlarmTime; 357 return mAlarmTime;
324 else 358 else
325 { 359 {
326 if (mParent->type()=="Todo") { 360 if (mParent->type()=="Todo") {
327 Todo *t = static_cast<Todo*>(mParent); 361 Todo *t = static_cast<Todo*>(mParent);
328 return mOffset.end( t->dtDue() ); 362 return mOffset.end( t->dtDue() );
329 } else if (mEndOffset) { 363 } else if (mEndOffset) {
330 return mOffset.end( mParent->dtEnd() ); 364 return mOffset.end( mParent->dtEnd() );
331 } else { 365 } else {
332 return mOffset.end( mParent->dtStart() ); 366 return mOffset.end( mParent->dtStart() );
333 } 367 }
334 } 368 }
335} 369}
336 370
337bool Alarm::hasTime() const 371bool Alarm::hasTime() const
338{ 372{
339 return mHasTime; 373 return mHasTime;
340} 374}
341 375
342void Alarm::setSnoozeTime(int alarmSnoozeTime) 376void Alarm::setSnoozeTime(int alarmSnoozeTime)
343{ 377{
344 mAlarmSnoozeTime = alarmSnoozeTime; 378 mAlarmSnoozeTime = alarmSnoozeTime;
345 mParent->updated(); 379 mParent->updated();
346} 380}
347 381
348int Alarm::snoozeTime() const 382int Alarm::snoozeTime() const
349{ 383{
350 return mAlarmSnoozeTime; 384 return mAlarmSnoozeTime;
351} 385}
352 386
353void Alarm::setRepeatCount(int alarmRepeatCount) 387void Alarm::setRepeatCount(int alarmRepeatCount)
354{ 388{
355 kdDebug(5800) << "Alarm::setRepeatCount(): " << alarmRepeatCount << endl; 389 kdDebug(5800) << "Alarm::setRepeatCount(): " << alarmRepeatCount << endl;
356 390
357 mAlarmRepeatCount = alarmRepeatCount; 391 mAlarmRepeatCount = alarmRepeatCount;
358 mParent->updated(); 392 mParent->updated();
359} 393}
360 394
361int Alarm::repeatCount() const 395int Alarm::repeatCount() const
362{ 396{
363 kdDebug(5800) << "Alarm::repeatCount(): " << mAlarmRepeatCount << endl; 397 kdDebug(5800) << "Alarm::repeatCount(): " << mAlarmRepeatCount << endl;
364 return mAlarmRepeatCount; 398 return mAlarmRepeatCount;
365} 399}
366 400
367void Alarm::toggleAlarm() 401void Alarm::toggleAlarm()
368{ 402{
369 mAlarmEnabled = !mAlarmEnabled; 403 mAlarmEnabled = !mAlarmEnabled;
370 mParent->updated(); 404 mParent->updated();
371} 405}
372 406
373void Alarm::setEnabled(bool enable) 407void Alarm::setEnabled(bool enable)
374{ 408{
375 mAlarmEnabled = enable; 409 mAlarmEnabled = enable;
376 mParent->updated(); 410 mParent->updated();
377} 411}
378 412
379bool Alarm::enabled() const 413bool Alarm::enabled() const
380{ 414{
381 return mAlarmEnabled; 415 return mAlarmEnabled;
382} 416}
383 417
384void Alarm::setStartOffset( const Duration &offset ) 418void Alarm::setStartOffset( const Duration &offset )
385{ 419{
386 mOffset = offset; 420 mOffset = offset;
387 mEndOffset = false; 421 mEndOffset = false;
388 mHasTime = false; 422 mHasTime = false;
389 mParent->updated(); 423 mParent->updated();
390} 424}
391 425
392Duration Alarm::startOffset() const 426Duration Alarm::startOffset() const
393{ 427{
394 return (mHasTime || mEndOffset) ? 0 : mOffset; 428 return (mHasTime || mEndOffset) ? 0 : mOffset;
395} 429}
396 430
397bool Alarm::hasStartOffset() const 431bool Alarm::hasStartOffset() const
398{ 432{
399 return !mHasTime && !mEndOffset; 433 return !mHasTime && !mEndOffset;
400} 434}
401 435
402bool Alarm::hasEndOffset() const 436bool Alarm::hasEndOffset() const
403{ 437{
404 return !mHasTime && mEndOffset; 438 return !mHasTime && mEndOffset;
405} 439}
406 440
407void Alarm::setEndOffset( const Duration &offset ) 441void Alarm::setEndOffset( const Duration &offset )
408{ 442{
409 mOffset = offset; 443 mOffset = offset;
410 mEndOffset = true; 444 mEndOffset = true;
411 mHasTime = false; 445 mHasTime = false;
412 mParent->updated(); 446 mParent->updated();
413} 447}
414 448
415Duration Alarm::endOffset() const 449Duration Alarm::endOffset() const
416{ 450{
417 return (mHasTime || !mEndOffset) ? 0 : mOffset; 451 return (mHasTime || !mEndOffset) ? 0 : mOffset;
418} 452}
419 453
420void Alarm::setParent( Incidence *parent ) 454void Alarm::setParent( Incidence *parent )
421{ 455{
422 mParent = parent; 456 mParent = parent;
423} 457}
diff --git a/libkcal/recurrence.cpp b/libkcal/recurrence.cpp
index dd74e10..e84f672 100644
--- a/libkcal/recurrence.cpp
+++ b/libkcal/recurrence.cpp
@@ -1,3373 +1,3405 @@
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) {
2185 countGone += data.monthList()->count(); 2217 countGone += data.monthList()->count();
2186 if (countGone >= countMax) 2218 if (countGone >= countMax)
2187 return countMax; 2219 return countMax;
2188 data.year += rFreq; 2220 data.year += rFreq;
2189 } 2221 }
2190 mons = data.monthList(); 2222 mons = data.monthList();
2191 } else { 2223 } else {
2192 // The number of recurrences is the same every year, 2224 // The number of recurrences is the same every year,
2193 // so skip the year-by-year check. 2225 // so skip the year-by-year check.
2194 // Skip the remaining whole years. 2226 // Skip the remaining whole years.
2195 int monthsPerYear = mons->count(); 2227 int monthsPerYear = mons->count();
2196 int wholeYears = endYear - data.year; 2228 int wholeYears = endYear - data.year;
2197 countGone += (wholeYears / rFreq) * monthsPerYear; 2229 countGone += (wholeYears / rFreq) * monthsPerYear;
2198 if (countGone >= countMax) 2230 if (countGone >= countMax)
2199 return countMax; 2231 return countMax;
2200 if (wholeYears % rFreq) 2232 if (wholeYears % rFreq)
2201 return countGone; // end year isn't a recurrence year 2233 return countGone; // end year isn't a recurrence year
2202 data.year = endYear; 2234 data.year = endYear;
2203 } 2235 }
2204 2236
2205 // Check the last year in the recurrence 2237 // Check the last year in the recurrence
2206 for (it = mons->begin(); it != mons->end(); ++it) { 2238 for (it = mons->begin(); it != mons->end(); ++it) {
2207 if (*it > endMonth) 2239 if (*it > endMonth)
2208 return countGone; 2240 return countGone;
2209 if (++countGone >= countMax) 2241 if (++countGone >= countMax)
2210 return countMax; 2242 return countMax;
2211 } 2243 }
2212 return countGone; 2244 return countGone;
2213} 2245}
2214 2246
2215// Find count and date of first recurrence after 'enddate' of an annual recurrence by date. 2247// Find count and date of first recurrence after 'enddate' of an annual recurrence by date.
2216// Reply = total number of occurrences up to 'enddate'. 2248// Reply = total number of occurrences up to 'enddate'.
2217int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data) const 2249int Recurrence::yearlyMonthCalcNextAfter(QDate &enddate, YearlyMonthData &data) const
2218{ 2250{
2219 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 2251 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2220 int countGone = 0; 2252 int countGone = 0;
2221 int endYear = enddate.year(); 2253 int endYear = enddate.year();
2222 int endMonth = enddate.month(); 2254 int endMonth = enddate.month();
2223 int endDay = enddate.day(); 2255 int endDay = enddate.day();
2224 bool mar1TooEarly = false; 2256 bool mar1TooEarly = false;
2225 bool feb28ok = false; 2257 bool feb28ok = false;
2226 if (endDay < data.day) { 2258 if (endDay < data.day) {
2227 if (data.feb29 && mFeb29YearlyType == rMar1 && endMonth == 3) 2259 if (data.feb29 && mFeb29YearlyType == rMar1 && endMonth == 3)
2228 mar1TooEarly = true; 2260 mar1TooEarly = true;
2229 if (data.feb29 && mFeb29YearlyType == rFeb28 && endMonth == 2 && endDay == 28) 2261 if (data.feb29 && mFeb29YearlyType == rFeb28 && endMonth == 2 && endDay == 28)
2230 feb28ok = true; 2262 feb28ok = true;
2231 else if (--endMonth == 0) { 2263 else if (--endMonth == 0) {
2232 endMonth = 12; 2264 endMonth = 12;
2233 --endYear; 2265 --endYear;
2234 } 2266 }
2235 } 2267 }
2236 QValueList<int>::ConstIterator it; 2268 QValueList<int>::ConstIterator it;
2237 const QValueList<int>* mons = data.monthList(); 2269 const QValueList<int>* mons = data.monthList();
2238 2270
2239 if (data.month > 1) { 2271 if (data.month > 1) {
2240 // Check what remains of the start year 2272 // Check what remains of the start year
2241 for (it = mons->begin(); it != mons->end(); ++it) { 2273 for (it = mons->begin(); it != mons->end(); ++it) {
2242 if (*it >= data.month) { 2274 if (*it >= data.month) {
2243 ++countGone; 2275 ++countGone;
2244 if (data.year == endYear 2276 if (data.year == endYear
2245 && ( *it > endMonth && (*it > 3 || !mar1TooEarly) 2277 && ( *it > endMonth && (*it > 3 || !mar1TooEarly)
2246 || *it == 2 && feb28ok && data.leapyear)) { 2278 || *it == 2 && feb28ok && data.leapyear)) {
2247 if (*it == 2 && data.feb29 && !data.leapyear) { 2279 if (*it == 2 && data.feb29 && !data.leapyear) {
2248 // The next recurrence should be on February 29th, but it's a non-leap year 2280 // The next recurrence should be on February 29th, but it's a non-leap year
2249 switch (mFeb29YearlyType) { 2281 switch (mFeb29YearlyType) {
2250 case rFeb28: 2282 case rFeb28:
2251 data.month = 2; 2283 data.month = 2;
2252 data.day = 28; 2284 data.day = 28;
2253 break; 2285 break;
2254 case rMar1: 2286 case rMar1:
2255 data.month = 3; 2287 data.month = 3;
2256 data.day = 1; 2288 data.day = 1;
2257 break; 2289 break;
2258 case rFeb29: // impossible in this context! 2290 case rFeb29: // impossible in this context!
2259 break; 2291 break;
2260 } 2292 }
2261 } 2293 }
2262 else 2294 else
2263 data.month = *it; 2295 data.month = *it;
2264 goto ex; 2296 goto ex;
2265 } 2297 }
2266 if (--countTogo == 0) 2298 if (--countTogo == 0)
2267 return 0; 2299 return 0;
2268 } 2300 }
2269 } 2301 }
2270 data.month = 1; 2302 data.month = 1;
2271 data.year += rFreq; 2303 data.year += rFreq;
2272 } 2304 }
2273 2305
2274 if (data.feb29 && mFeb29YearlyType == rFeb29) { 2306 if (data.feb29 && mFeb29YearlyType == rFeb29) {
2275 // The number of recurrences is different on leap years, 2307 // The number of recurrences is different on leap years,
2276 // so check year-by-year. 2308 // so check year-by-year.
2277 while (data.year <= endYear) { 2309 while (data.year <= endYear) {
2278 mons = data.monthList(); 2310 mons = data.monthList();
2279 if (data.year == endYear && mons->last() > endMonth) 2311 if (data.year == endYear && mons->last() > endMonth)
2280 break; 2312 break;
2281 uint n = mons->count(); 2313 uint n = mons->count();
2282 if (n >= countTogo) 2314 if (n >= countTogo)
2283 break; 2315 break;
2284 countTogo -= n; 2316 countTogo -= n;
2285 countGone += n; 2317 countGone += n;
2286 data.year += rFreq; 2318 data.year += rFreq;
2287 } 2319 }
2288 mons = data.monthList(); 2320 mons = data.monthList();
2289 } else { 2321 } else {
2290 // The number of recurrences is the same every year, 2322 // The number of recurrences is the same every year,
2291 // so skip the year-by-year check. 2323 // so skip the year-by-year check.
2292 // Skip the remaining whole years to at least endYear. 2324 // Skip the remaining whole years to at least endYear.
2293 int monthsPerYear = mons->count(); 2325 int monthsPerYear = mons->count();
2294 int recurYears = (endYear - data.year + rFreq - 1) / rFreq; 2326 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2295 if ((endYear - data.year)%rFreq == 0 2327 if ((endYear - data.year)%rFreq == 0
2296 && mons->last() <= endMonth) 2328 && mons->last() <= endMonth)
2297 ++recurYears; // required year is after endYear 2329 ++recurYears; // required year is after endYear
2298 if (recurYears) { 2330 if (recurYears) {
2299 int n = recurYears * monthsPerYear; 2331 int n = recurYears * monthsPerYear;
2300 if (static_cast<uint>(n) > countTogo) 2332 if (static_cast<uint>(n) > countTogo)
2301 return 0; // reached end of recurrence 2333 return 0; // reached end of recurrence
2302 countTogo -= n; 2334 countTogo -= n;
2303 countGone += n; 2335 countGone += n;
2304 data.year += recurYears * rFreq; 2336 data.year += recurYears * rFreq;
2305 } 2337 }
2306 } 2338 }
2307 2339
2308 // Check the last year in the recurrence 2340 // Check the last year in the recurrence
2309 for (it = mons->begin(); it != mons->end(); ++it) { 2341 for (it = mons->begin(); it != mons->end(); ++it) {
2310 ++countGone; 2342 ++countGone;
2311 if (data.year > endYear 2343 if (data.year > endYear
2312 || ( *it > endMonth && (*it > 3 || !mar1TooEarly) 2344 || ( *it > endMonth && (*it > 3 || !mar1TooEarly)
2313 || *it == 2 && feb28ok && QDate::leapYear(data.year))) { 2345 || *it == 2 && feb28ok && QDate::leapYear(data.year))) {
2314 if (*it == 2 && data.feb29 && !QDate::leapYear(data.year)) { 2346 if (*it == 2 && data.feb29 && !QDate::leapYear(data.year)) {
2315 // The next recurrence should be on February 29th, but it's a non-leap year 2347 // The next recurrence should be on February 29th, but it's a non-leap year
2316 switch (mFeb29YearlyType) { 2348 switch (mFeb29YearlyType) {
2317 case rFeb28: 2349 case rFeb28:
2318 data.month = 2; 2350 data.month = 2;
2319 data.day = 28; 2351 data.day = 28;
2320 break; 2352 break;
2321 case rMar1: 2353 case rMar1:
2322 data.month = 3; 2354 data.month = 3;
2323 data.day = 1; 2355 data.day = 1;
2324 break; 2356 break;
2325 case rFeb29: // impossible in this context! 2357 case rFeb29: // impossible in this context!
2326 break; 2358 break;
2327 } 2359 }
2328 } 2360 }
2329 else 2361 else
2330 data.month = *it; 2362 data.month = *it;
2331 break; 2363 break;
2332 } 2364 }
2333 if (--countTogo == 0) 2365 if (--countTogo == 0)
2334 return 0; 2366 return 0;
2335 } 2367 }
2336ex: 2368ex:
2337 enddate = data.date(); 2369 enddate = data.date();
2338 return countGone; 2370 return countGone;
2339} 2371}
2340 2372
2341 2373
2342/* Find count and, depending on 'func', the end date of an annual recurrence by date. 2374/* Find count and, depending on 'func', the end date of an annual recurrence by date.
2343 * Reply = total number of occurrences up to 'enddate', or 0 if error. 2375 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2344 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 2376 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2345 * recurrence end date. 2377 * recurrence end date.
2346 */ 2378 */
2347struct Recurrence::YearlyPosData { 2379struct Recurrence::YearlyPosData {
2348 const Recurrence *recurrence; 2380 const Recurrence *recurrence;
2349 int year; // current year 2381 int year; // current year
2350 int month; // current month 1..12 2382 int month; // current month 1..12
2351 int day; // current day of month 1..31 2383 int day; // current day of month 1..31
2352 int daysPerMonth; // number of days which recur each month, or -1 if variable 2384 int daysPerMonth; // number of days which recur each month, or -1 if variable
2353 int count; // number of days which recur each year, or -1 if variable 2385 int count; // number of days which recur each year, or -1 if variable
2354 bool varies; // true if number of days varies from year to year 2386 bool varies; // true if number of days varies from year to year
2355 private: 2387 private:
2356 mutable QValueList<int> days; 2388 mutable QValueList<int> days;
2357 public: 2389 public:
2358 YearlyPosData(const Recurrence* r, const QDate &date) 2390 YearlyPosData(const Recurrence* r, const QDate &date)
2359 : recurrence(r), year(date.year()), month(date.month()), day(date.day()), count(-1) 2391 : recurrence(r), year(date.year()), month(date.month()), day(date.day()), count(-1)
2360 { if ((daysPerMonth = r->countMonthlyPosDays()) > 0) 2392 { if ((daysPerMonth = r->countMonthlyPosDays()) > 0)
2361 count = daysPerMonth * r->rYearNums.count(); 2393 count = daysPerMonth * r->rYearNums.count();
2362 varies = (daysPerMonth < 0); 2394 varies = (daysPerMonth < 0);
2363 } 2395 }
2364 const QValueList<int>* dayList() const { 2396 const QValueList<int>* dayList() const {
2365 QDate startOfMonth(year, month, 1); 2397 QDate startOfMonth(year, month, 1);
2366 recurrence->getMonthlyPosDays(days, startOfMonth.daysInMonth(), startOfMonth.dayOfWeek()); 2398 recurrence->getMonthlyPosDays(days, startOfMonth.daysInMonth(), startOfMonth.dayOfWeek());
2367 return &days; 2399 return &days;
2368 } 2400 }
2369 int yearMonth() const { return year*12 + month - 1; } 2401 int yearMonth() const { return year*12 + month - 1; }
2370 void addMonths(int diff) { month += diff - 1; year += month / 12; month = month % 12 + 1; } 2402 void addMonths(int diff) { month += diff - 1; year += month / 12; month = month % 12 + 1; }
2371 QDate date() const { return QDate(year, month, day); } 2403 QDate date() const { return QDate(year, month, day); }
2372}; 2404};
2373 2405
2374int Recurrence::yearlyPosCalc(PeriodFunc func, QDate &enddate) const 2406int Recurrence::yearlyPosCalc(PeriodFunc func, QDate &enddate) const
2375{ 2407{
2376 if (rYearNums.isEmpty() || rMonthPositions.isEmpty()) 2408 if (rYearNums.isEmpty() || rMonthPositions.isEmpty())
2377 return 0; 2409 return 0;
2378 YearlyPosData data(this, mRecurStart.date()); 2410 YearlyPosData data(this, mRecurStart.date());
2379 switch (func) { 2411 switch (func) {
2380 case END_DATE_AND_COUNT: 2412 case END_DATE_AND_COUNT:
2381 return yearlyPosCalcEndDate(enddate, data); 2413 return yearlyPosCalcEndDate(enddate, data);
2382 case COUNT_TO_DATE: 2414 case COUNT_TO_DATE:
2383 return yearlyPosCalcToDate(enddate, data); 2415 return yearlyPosCalcToDate(enddate, data);
2384 case NEXT_AFTER_DATE: 2416 case NEXT_AFTER_DATE:
2385 return yearlyPosCalcNextAfter(enddate, data); 2417 return yearlyPosCalcNextAfter(enddate, data);
2386 } 2418 }
2387 return 0; 2419 return 0;
2388} 2420}
2389 2421
2390int Recurrence::yearlyPosCalcEndDate(QDate &enddate, YearlyPosData &data) const 2422int Recurrence::yearlyPosCalcEndDate(QDate &enddate, YearlyPosData &data) const
2391{ 2423{
2392 uint countTogo = rDuration + mRecurExDatesCount; 2424 uint countTogo = rDuration + mRecurExDatesCount;
2393 int countGone = 0; 2425 int countGone = 0;
2394 QValueList<int>::ConstIterator id; 2426 QValueList<int>::ConstIterator id;
2395 const QValueList<int>* days; 2427 const QValueList<int>* days;
2396 2428
2397 if (data.month > 1 || data.day > 1) { 2429 if (data.month > 1 || data.day > 1) {
2398 // Check what remains of the start year 2430 // Check what remains of the start year
2399 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2431 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2400 if (*im.current() >= data.month) { 2432 if (*im.current() >= data.month) {
2401 // Check what remains of the start month 2433 // Check what remains of the start month
2402 if (data.day > 1 || data.varies 2434 if (data.day > 1 || data.varies
2403 || static_cast<uint>(data.daysPerMonth) >= countTogo) { 2435 || static_cast<uint>(data.daysPerMonth) >= countTogo) {
2404 data.month = *im.current(); 2436 data.month = *im.current();
2405 days = data.dayList(); 2437 days = data.dayList();
2406 for (id = days->begin(); id != days->end(); ++id) { 2438 for (id = days->begin(); id != days->end(); ++id) {
2407 if (*id >= data.day) { 2439 if (*id >= data.day) {
2408 ++countGone; 2440 ++countGone;
2409 if (--countTogo == 0) { 2441 if (--countTogo == 0) {
2410 data.month = *im.current(); 2442 data.month = *im.current();
2411 data.day = *id; 2443 data.day = *id;
2412 goto ex; 2444 goto ex;
2413 } 2445 }
2414 } 2446 }
2415 } 2447 }
2416 data.day = 1; 2448 data.day = 1;
2417 } else { 2449 } else {
2418 // The number of days per month is constant, so skip 2450 // The number of days per month is constant, so skip
2419 // the whole month. 2451 // the whole month.
2420 countTogo -= data.daysPerMonth; 2452 countTogo -= data.daysPerMonth;
2421 countGone += data.daysPerMonth; 2453 countGone += data.daysPerMonth;
2422 } 2454 }
2423 } 2455 }
2424 } 2456 }
2425 data.month = 1; 2457 data.month = 1;
2426 data.year += rFreq; 2458 data.year += rFreq;
2427 } 2459 }
2428 2460
2429 if (data.varies) { 2461 if (data.varies) {
2430 // The number of recurrences varies from year to year. 2462 // The number of recurrences varies from year to year.
2431 for ( ; ; ) { 2463 for ( ; ; ) {
2432 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2464 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2433 data.month = *im.current(); 2465 data.month = *im.current();
2434 days = data.dayList(); 2466 days = data.dayList();
2435 int n = days->count(); 2467 int n = days->count();
2436 if (static_cast<uint>(n) >= countTogo) { 2468 if (static_cast<uint>(n) >= countTogo) {
2437 // Check the last month in the recurrence 2469 // Check the last month in the recurrence
2438 for (id = days->begin(); id != days->end(); ++id) { 2470 for (id = days->begin(); id != days->end(); ++id) {
2439 ++countGone; 2471 ++countGone;
2440 if (--countTogo == 0) { 2472 if (--countTogo == 0) {
2441 data.day = *id; 2473 data.day = *id;
2442 goto ex; 2474 goto ex;
2443 } 2475 }
2444 } 2476 }
2445 } 2477 }
2446 countTogo -= n; 2478 countTogo -= n;
2447 countGone += n; 2479 countGone += n;
2448 } 2480 }
2449 data.year += rFreq; 2481 data.year += rFreq;
2450 } 2482 }
2451 } else { 2483 } else {
2452 // The number of recurrences is the same every year, 2484 // The number of recurrences is the same every year,
2453 // so skip the year-by-year check. 2485 // so skip the year-by-year check.
2454 // Skip the remaining whole years, but leave at least 2486 // Skip the remaining whole years, but leave at least
2455 // 1 recurrence remaining, in order to get its date. 2487 // 1 recurrence remaining, in order to get its date.
2456 int wholeYears = (countTogo - 1) / data.count; 2488 int wholeYears = (countTogo - 1) / data.count;
2457 data.year += wholeYears * rFreq; 2489 data.year += wholeYears * rFreq;
2458 countGone += wholeYears * data.count; 2490 countGone += wholeYears * data.count;
2459 countTogo -= wholeYears * data.count; 2491 countTogo -= wholeYears * data.count;
2460 2492
2461 // Check the last year in the recurrence. 2493 // Check the last year in the recurrence.
2462 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2494 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2463 if (static_cast<uint>(data.daysPerMonth) >= countTogo) { 2495 if (static_cast<uint>(data.daysPerMonth) >= countTogo) {
2464 // Check the last month in the recurrence 2496 // Check the last month in the recurrence
2465 data.month = *im.current(); 2497 data.month = *im.current();
2466 days = data.dayList(); 2498 days = data.dayList();
2467 for (id = days->begin(); id != days->end(); ++id) { 2499 for (id = days->begin(); id != days->end(); ++id) {
2468 ++countGone; 2500 ++countGone;
2469 if (--countTogo == 0) { 2501 if (--countTogo == 0) {
2470 data.day = *id; 2502 data.day = *id;
2471 goto ex; 2503 goto ex;
2472 } 2504 }
2473 } 2505 }
2474 } 2506 }
2475 countTogo -= data.daysPerMonth; 2507 countTogo -= data.daysPerMonth;
2476 countGone += data.daysPerMonth; 2508 countGone += data.daysPerMonth;
2477 } 2509 }
2478 data.year += rFreq; 2510 data.year += rFreq;
2479 } 2511 }
2480ex: 2512ex:
2481 enddate = data.date(); 2513 enddate = data.date();
2482 return countGone; 2514 return countGone;
2483} 2515}
2484 2516
2485int Recurrence::yearlyPosCalcToDate(const QDate &enddate, YearlyPosData &data) const 2517int Recurrence::yearlyPosCalcToDate(const QDate &enddate, YearlyPosData &data) const
2486{ 2518{
2487 int countGone = 0; 2519 int countGone = 0;
2488 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 2520 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2489 int endYear = enddate.year(); 2521 int endYear = enddate.year();
2490 int endMonth = enddate.month(); 2522 int endMonth = enddate.month();
2491 int endDay = enddate.day(); 2523 int endDay = enddate.day();
2492 if (endDay < data.day && --endMonth == 0) { 2524 if (endDay < data.day && --endMonth == 0) {
2493 endMonth = 12; 2525 endMonth = 12;
2494 --endYear; 2526 --endYear;
2495 } 2527 }
2496 int endYearMonth = endYear*12 + endMonth; 2528 int endYearMonth = endYear*12 + endMonth;
2497 QValueList<int>::ConstIterator id; 2529 QValueList<int>::ConstIterator id;
2498 const QValueList<int>* days; 2530 const QValueList<int>* days;
2499 2531
2500 if (data.month > 1 || data.day > 1) { 2532 if (data.month > 1 || data.day > 1) {
2501 // Check what remains of the start year 2533 // Check what remains of the start year
2502 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2534 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2503 if (*im.current() >= data.month) { 2535 if (*im.current() >= data.month) {
2504 data.month = *im.current(); 2536 data.month = *im.current();
2505 if (data.yearMonth() > endYearMonth) 2537 if (data.yearMonth() > endYearMonth)
2506 return countGone; 2538 return countGone;
2507 // Check what remains of the start month 2539 // Check what remains of the start month
2508 bool lastMonth = (data.yearMonth() == endYearMonth); 2540 bool lastMonth = (data.yearMonth() == endYearMonth);
2509 if (lastMonth || data.day > 1 || data.varies) { 2541 if (lastMonth || data.day > 1 || data.varies) {
2510 days = data.dayList(); 2542 days = data.dayList();
2511 if (lastMonth || data.day > 1) { 2543 if (lastMonth || data.day > 1) {
2512 for (id = days->begin(); id != days->end(); ++id) { 2544 for (id = days->begin(); id != days->end(); ++id) {
2513 if (*id >= data.day) { 2545 if (*id >= data.day) {
2514 if (lastMonth && *id > endDay) 2546 if (lastMonth && *id > endDay)
2515 return countGone; 2547 return countGone;
2516 if (++countGone >= countMax) 2548 if (++countGone >= countMax)
2517 return countMax; 2549 return countMax;
2518 } 2550 }
2519 } 2551 }
2520 } else { 2552 } else {
2521 countGone += days->count(); 2553 countGone += days->count();
2522 if (countGone >= countMax) 2554 if (countGone >= countMax)
2523 return countMax; 2555 return countMax;
2524 } 2556 }
2525 data.day = 1; 2557 data.day = 1;
2526 } else { 2558 } else {
2527 // The number of days per month is constant, so skip 2559 // The number of days per month is constant, so skip
2528 // the whole month. 2560 // the whole month.
2529 countGone += data.daysPerMonth; 2561 countGone += data.daysPerMonth;
2530 if (countGone >= countMax) 2562 if (countGone >= countMax)
2531 return countMax; 2563 return countMax;
2532 } 2564 }
2533 } 2565 }
2534 } 2566 }
2535 data.month = 1; 2567 data.month = 1;
2536 data.year += rFreq; 2568 data.year += rFreq;
2537 } 2569 }
2538 2570
2539 if (data.varies) { 2571 if (data.varies) {
2540 // The number of recurrences varies from year to year. 2572 // The number of recurrences varies from year to year.
2541 for ( ; ; ) { 2573 for ( ; ; ) {
2542 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2574 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2543 data.month = *im.current(); 2575 data.month = *im.current();
2544 days = data.dayList(); 2576 days = data.dayList();
2545 if (data.yearMonth() >= endYearMonth) { 2577 if (data.yearMonth() >= endYearMonth) {
2546 if (data.yearMonth() > endYearMonth) 2578 if (data.yearMonth() > endYearMonth)
2547 return countGone; 2579 return countGone;
2548 // Check the last month in the recurrence 2580 // Check the last month in the recurrence
2549 for (id = days->begin(); id != days->end(); ++id) { 2581 for (id = days->begin(); id != days->end(); ++id) {
2550 if (*id > endDay) 2582 if (*id > endDay)
2551 return countGone; 2583 return countGone;
2552 if (++countGone >= countMax) 2584 if (++countGone >= countMax)
2553 return countMax; 2585 return countMax;
2554 } 2586 }
2555 } else { 2587 } else {
2556 countGone += days->count(); 2588 countGone += days->count();
2557 if (countGone >= countMax) 2589 if (countGone >= countMax)
2558 return countMax; 2590 return countMax;
2559 } 2591 }
2560 } 2592 }
2561 data.year += rFreq; 2593 data.year += rFreq;
2562 } 2594 }
2563 } else { 2595 } else {
2564 // The number of recurrences is the same every year, 2596 // The number of recurrences is the same every year,
2565 // so skip the year-by-year check. 2597 // so skip the year-by-year check.
2566 // Skip the remaining whole years, but leave at least 2598 // Skip the remaining whole years, but leave at least
2567 // 1 recurrence remaining, in order to get its date. 2599 // 1 recurrence remaining, in order to get its date.
2568 int wholeYears = endYear - data.year; 2600 int wholeYears = endYear - data.year;
2569 countGone += (wholeYears / rFreq) * data.count; 2601 countGone += (wholeYears / rFreq) * data.count;
2570 if (countGone >= countMax) 2602 if (countGone >= countMax)
2571 return countMax; 2603 return countMax;
2572 if (wholeYears % rFreq) 2604 if (wholeYears % rFreq)
2573 return countGone; // end year isn't a recurrence year 2605 return countGone; // end year isn't a recurrence year
2574 data.year = endYear; 2606 data.year = endYear;
2575 2607
2576 // Check the last year in the recurrence. 2608 // Check the last year in the recurrence.
2577 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2609 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2578 data.month = *im.current(); 2610 data.month = *im.current();
2579 if (data.month >= endMonth) { 2611 if (data.month >= endMonth) {
2580 if (data.month > endMonth) 2612 if (data.month > endMonth)
2581 return countGone; 2613 return countGone;
2582 // Check the last month in the recurrence 2614 // Check the last month in the recurrence
2583 days = data.dayList(); 2615 days = data.dayList();
2584 for (id = days->begin(); id != days->end(); ++id) { 2616 for (id = days->begin(); id != days->end(); ++id) {
2585 if (*id > endDay) 2617 if (*id > endDay)
2586 return countGone; 2618 return countGone;
2587 if (++countGone >= countMax) 2619 if (++countGone >= countMax)
2588 return countMax; 2620 return countMax;
2589 } 2621 }
2590 } else { 2622 } else {
2591 countGone += data.daysPerMonth; 2623 countGone += data.daysPerMonth;
2592 if (countGone >= countMax) 2624 if (countGone >= countMax)
2593 return countMax; 2625 return countMax;
2594 } 2626 }
2595 } 2627 }
2596 } 2628 }
2597 return countGone; 2629 return countGone;
2598} 2630}
2599 2631
2600int Recurrence::yearlyPosCalcNextAfter(QDate &enddate, YearlyPosData &data) const 2632int Recurrence::yearlyPosCalcNextAfter(QDate &enddate, YearlyPosData &data) const
2601{ 2633{
2602 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 2634 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2603 int countGone = 0; 2635 int countGone = 0;
2604 int endYear = enddate.year(); 2636 int endYear = enddate.year();
2605 int endMonth = enddate.month(); 2637 int endMonth = enddate.month();
2606 int endDay = enddate.day(); 2638 int endDay = enddate.day();
2607 if (endDay < data.day && --endMonth == 0) { 2639 if (endDay < data.day && --endMonth == 0) {
2608 endMonth = 12; 2640 endMonth = 12;
2609 --endYear; 2641 --endYear;
2610 } 2642 }
2611 int endYearMonth = endYear*12 + endMonth; 2643 int endYearMonth = endYear*12 + endMonth;
2612 QValueList<int>::ConstIterator id; 2644 QValueList<int>::ConstIterator id;
2613 const QValueList<int>* days; 2645 const QValueList<int>* days;
2614 2646
2615 if (data.varies) { 2647 if (data.varies) {
2616 // The number of recurrences varies from year to year. 2648 // The number of recurrences varies from year to year.
2617 for ( ; ; ) { 2649 for ( ; ; ) {
2618 // Check the next year 2650 // Check the next year
2619 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2651 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2620 if (*im.current() >= data.month) { 2652 if (*im.current() >= data.month) {
2621 // Check the next month 2653 // Check the next month
2622 data.month = *im.current(); 2654 data.month = *im.current();
2623 int ended = data.yearMonth() - endYearMonth; 2655 int ended = data.yearMonth() - endYearMonth;
2624 days = data.dayList(); 2656 days = data.dayList();
2625 if (ended >= 0 || data.day > 1) { 2657 if (ended >= 0 || data.day > 1) {
2626 // This is the start or end month, so check each day 2658 // This is the start or end month, so check each day
2627 for (id = days->begin(); id != days->end(); ++id) { 2659 for (id = days->begin(); id != days->end(); ++id) {
2628 if (*id >= data.day) { 2660 if (*id >= data.day) {
2629 ++countGone; 2661 ++countGone;
2630 if (ended > 0 || (ended == 0 && *id > endDay)) { 2662 if (ended > 0 || (ended == 0 && *id > endDay)) {
2631 data.day = *id; 2663 data.day = *id;
2632 goto ex; 2664 goto ex;
2633 } 2665 }
2634 if (--countTogo == 0) 2666 if (--countTogo == 0)
2635 return 0; 2667 return 0;
2636 } 2668 }
2637 } 2669 }
2638 } else { 2670 } else {
2639 // Skip the whole month 2671 // Skip the whole month
2640 uint n = days->count(); 2672 uint n = days->count();
2641 if (n >= countTogo) 2673 if (n >= countTogo)
2642 return 0; 2674 return 0;
2643 countGone += n; 2675 countGone += n;
2644 } 2676 }
2645 data.day = 1; // we've checked the start month now 2677 data.day = 1; // we've checked the start month now
2646 } 2678 }
2647 } 2679 }
2648 data.month = 1; // we've checked the start year now 2680 data.month = 1; // we've checked the start year now
2649 data.year += rFreq; 2681 data.year += rFreq;
2650 } 2682 }
2651 } else { 2683 } else {
2652 // The number of recurrences is the same every year. 2684 // The number of recurrences is the same every year.
2653 if (data.month > 1 || data.day > 1) { 2685 if (data.month > 1 || data.day > 1) {
2654 // Check what remains of the start year 2686 // Check what remains of the start year
2655 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2687 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2656 if (*im.current() >= data.month) { 2688 if (*im.current() >= data.month) {
2657 // Check what remains of the start month 2689 // Check what remains of the start month
2658 data.month = *im.current(); 2690 data.month = *im.current();
2659 int ended = data.yearMonth() - endYearMonth; 2691 int ended = data.yearMonth() - endYearMonth;
2660 if (ended >= 0 || data.day > 1) { 2692 if (ended >= 0 || data.day > 1) {
2661 // This is the start or end month, so check each day 2693 // This is the start or end month, so check each day
2662 days = data.dayList(); 2694 days = data.dayList();
2663 for (id = days->begin(); id != days->end(); ++id) { 2695 for (id = days->begin(); id != days->end(); ++id) {
2664 if (*id >= data.day) { 2696 if (*id >= data.day) {
2665 ++countGone; 2697 ++countGone;
2666 if (ended > 0 || (ended == 0 && *id > endDay)) { 2698 if (ended > 0 || (ended == 0 && *id > endDay)) {
2667 data.day = *id; 2699 data.day = *id;
2668 goto ex; 2700 goto ex;
2669 } 2701 }
2670 if (--countTogo == 0) 2702 if (--countTogo == 0)
2671 return 0; 2703 return 0;
2672 } 2704 }
2673 } 2705 }
2674 data.day = 1; // we've checked the start month now 2706 data.day = 1; // we've checked the start month now
2675 } else { 2707 } else {
2676 // Skip the whole month. 2708 // Skip the whole month.
2677 if (static_cast<uint>(data.daysPerMonth) >= countTogo) 2709 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
2678 return 0; 2710 return 0;
2679 countGone += data.daysPerMonth; 2711 countGone += data.daysPerMonth;
2680 } 2712 }
2681 } 2713 }
2682 } 2714 }
2683 data.year += rFreq; 2715 data.year += rFreq;
2684 } 2716 }
2685 // Skip the remaining whole years to at least endYear. 2717 // Skip the remaining whole years to at least endYear.
2686 int recurYears = (endYear - data.year + rFreq - 1) / rFreq; 2718 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2687 if ((endYear - data.year)%rFreq == 0 2719 if ((endYear - data.year)%rFreq == 0
2688 && *rYearNums.getLast() <= endMonth) 2720 && *rYearNums.getLast() <= endMonth)
2689 ++recurYears; // required year is after endYear 2721 ++recurYears; // required year is after endYear
2690 if (recurYears) { 2722 if (recurYears) {
2691 int n = recurYears * data.count; 2723 int n = recurYears * data.count;
2692 if (static_cast<uint>(n) > countTogo) 2724 if (static_cast<uint>(n) > countTogo)
2693 return 0; // reached end of recurrence 2725 return 0; // reached end of recurrence
2694 countTogo -= n; 2726 countTogo -= n;
2695 countGone += n; 2727 countGone += n;
2696 data.year += recurYears * rFreq; 2728 data.year += recurYears * rFreq;
2697 } 2729 }
2698 2730
2699 // Check the last year in the recurrence 2731 // Check the last year in the recurrence
2700 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) { 2732 for (QPtrListIterator<int> im(rYearNums); im.current(); ++im) {
2701 data.month = *im.current(); 2733 data.month = *im.current();
2702 int ended = data.yearMonth() - endYearMonth; 2734 int ended = data.yearMonth() - endYearMonth;
2703 if (ended >= 0) { 2735 if (ended >= 0) {
2704 // This is the end month, so check each day 2736 // This is the end month, so check each day
2705 days = data.dayList(); 2737 days = data.dayList();
2706 for (id = days->begin(); id != days->end(); ++id) { 2738 for (id = days->begin(); id != days->end(); ++id) {
2707 ++countGone; 2739 ++countGone;
2708 if (ended > 0 || (ended == 0 && *id > endDay)) { 2740 if (ended > 0 || (ended == 0 && *id > endDay)) {
2709 data.day = *id; 2741 data.day = *id;
2710 goto ex; 2742 goto ex;
2711 } 2743 }
2712 if (--countTogo == 0) 2744 if (--countTogo == 0)
2713 return 0; 2745 return 0;
2714 } 2746 }
2715 } else { 2747 } else {
2716 // Skip the whole month. 2748 // Skip the whole month.
2717 if (static_cast<uint>(data.daysPerMonth) >= countTogo) 2749 if (static_cast<uint>(data.daysPerMonth) >= countTogo)
2718 return 0; 2750 return 0;
2719 countGone += data.daysPerMonth; 2751 countGone += data.daysPerMonth;
2720 } 2752 }
2721 } 2753 }
2722 } 2754 }
2723ex: 2755ex:
2724 enddate = data.date(); 2756 enddate = data.date();
2725 return countGone; 2757 return countGone;
2726} 2758}
2727 2759
2728 2760
2729/* Find count and, depending on 'func', the end date of an annual recurrence by day. 2761/* Find count and, depending on 'func', the end date of an annual recurrence by day.
2730 * Reply = total number of occurrences up to 'enddate', or 0 if error. 2762 * Reply = total number of occurrences up to 'enddate', or 0 if error.
2731 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the 2763 * If 'func' = END_DATE_AND_COUNT or NEXT_AFTER_DATE, 'enddate' is updated to the
2732 * recurrence end date. 2764 * recurrence end date.
2733 */ 2765 */
2734struct Recurrence::YearlyDayData { 2766struct Recurrence::YearlyDayData {
2735 int year; // current year 2767 int year; // current year
2736 int day; // current day of year 1..366 2768 int day; // current day of year 1..366
2737 bool varies; // true if day 366 recurs 2769 bool varies; // true if day 366 recurs
2738 private: 2770 private:
2739 int daycount; 2771 int daycount;
2740 public: 2772 public:
2741 YearlyDayData(const Recurrence* r, const QDate &date) 2773 YearlyDayData(const Recurrence* r, const QDate &date)
2742 : year(date.year()), day(date.dayOfYear()), varies(*r->rYearNums.getLast() == 366), 2774 : year(date.year()), day(date.dayOfYear()), varies(*r->rYearNums.getLast() == 366),
2743 daycount(r->rYearNums.count()) { } 2775 daycount(r->rYearNums.count()) { }
2744 bool leapYear() const { return QDate::leapYear(year); } 2776 bool leapYear() const { return QDate::leapYear(year); }
2745 int dayCount() const { return daycount - (varies && !QDate::leapYear(year) ? 1 : 0); } 2777 int dayCount() const { return daycount - (varies && !QDate::leapYear(year) ? 1 : 0); }
2746 bool isMaxDayCount() const { return !varies || QDate::leapYear(year); } 2778 bool isMaxDayCount() const { return !varies || QDate::leapYear(year); }
2747 QDate date() const { return QDate(year, 1, 1).addDays(day - 1); } 2779 QDate date() const { return QDate(year, 1, 1).addDays(day - 1); }
2748}; 2780};
2749 2781
2750int Recurrence::yearlyDayCalc(PeriodFunc func, QDate &enddate) const 2782int Recurrence::yearlyDayCalc(PeriodFunc func, QDate &enddate) const
2751{ 2783{
2752 if (rYearNums.isEmpty()) 2784 if (rYearNums.isEmpty())
2753 return 0; 2785 return 0;
2754 YearlyDayData data(this, mRecurStart.date()); 2786 YearlyDayData data(this, mRecurStart.date());
2755 switch (func) { 2787 switch (func) {
2756 case END_DATE_AND_COUNT: 2788 case END_DATE_AND_COUNT:
2757 return yearlyDayCalcEndDate(enddate, data); 2789 return yearlyDayCalcEndDate(enddate, data);
2758 case COUNT_TO_DATE: 2790 case COUNT_TO_DATE:
2759 return yearlyDayCalcToDate(enddate, data); 2791 return yearlyDayCalcToDate(enddate, data);
2760 case NEXT_AFTER_DATE: 2792 case NEXT_AFTER_DATE:
2761 return yearlyDayCalcNextAfter(enddate, data); 2793 return yearlyDayCalcNextAfter(enddate, data);
2762 } 2794 }
2763 return 0; 2795 return 0;
2764} 2796}
2765 2797
2766int Recurrence::yearlyDayCalcEndDate(QDate &enddate, YearlyDayData &data) const 2798int Recurrence::yearlyDayCalcEndDate(QDate &enddate, YearlyDayData &data) const
2767{ 2799{
2768 uint countTogo = rDuration + mRecurExDatesCount; 2800 uint countTogo = rDuration + mRecurExDatesCount;
2769 int countGone = 0; 2801 int countGone = 0;
2770 2802
2771 if (data.day > 1) { 2803 if (data.day > 1) {
2772 // Check what remains of the start year 2804 // Check what remains of the start year
2773 bool leapOK = data.isMaxDayCount(); 2805 bool leapOK = data.isMaxDayCount();
2774 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2806 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2775 int d = *it.current(); 2807 int d = *it.current();
2776 if (d >= data.day && (leapOK || d < 366)) { 2808 if (d >= data.day && (leapOK || d < 366)) {
2777 ++countGone; 2809 ++countGone;
2778 if (--countTogo == 0) { 2810 if (--countTogo == 0) {
2779 data.day = d; 2811 data.day = d;
2780 goto ex; 2812 goto ex;
2781 } 2813 }
2782 } 2814 }
2783 } 2815 }
2784 data.day = 1; 2816 data.day = 1;
2785 data.year += rFreq; 2817 data.year += rFreq;
2786 } 2818 }
2787 2819
2788 if (data.varies) { 2820 if (data.varies) {
2789 // The number of recurrences is different in leap years, 2821 // The number of recurrences is different in leap years,
2790 // so check year-by-year. 2822 // so check year-by-year.
2791 for ( ; ; ) { 2823 for ( ; ; ) {
2792 uint n = data.dayCount(); 2824 uint n = data.dayCount();
2793 if (n >= countTogo) 2825 if (n >= countTogo)
2794 break; 2826 break;
2795 countTogo -= n; 2827 countTogo -= n;
2796 countGone += n; 2828 countGone += n;
2797 data.year += rFreq; 2829 data.year += rFreq;
2798 } 2830 }
2799 } else { 2831 } else {
2800 // The number of recurrences is the same every year, 2832 // The number of recurrences is the same every year,
2801 // so skip the year-by-year check. 2833 // so skip the year-by-year check.
2802 // Skip the remaining whole years, but leave at least 2834 // Skip the remaining whole years, but leave at least
2803 // 1 recurrence remaining, in order to get its date. 2835 // 1 recurrence remaining, in order to get its date.
2804 int daysPerYear = rYearNums.count(); 2836 int daysPerYear = rYearNums.count();
2805 int wholeYears = (countTogo - 1) / daysPerYear; 2837 int wholeYears = (countTogo - 1) / daysPerYear;
2806 data.year += wholeYears * rFreq; 2838 data.year += wholeYears * rFreq;
2807 countGone += wholeYears * daysPerYear; 2839 countGone += wholeYears * daysPerYear;
2808 countTogo -= wholeYears * daysPerYear; 2840 countTogo -= wholeYears * daysPerYear;
2809 } 2841 }
2810 if (countTogo) { 2842 if (countTogo) {
2811 // Check the last year in the recurrence 2843 // Check the last year in the recurrence
2812 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2844 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2813 ++countGone; 2845 ++countGone;
2814 if (--countTogo == 0) { 2846 if (--countTogo == 0) {
2815 data.day = *it.current(); 2847 data.day = *it.current();
2816 break; 2848 break;
2817 } 2849 }
2818 } 2850 }
2819 } 2851 }
2820ex: 2852ex:
2821 enddate = data.date(); 2853 enddate = data.date();
2822 return countGone; 2854 return countGone;
2823} 2855}
2824 2856
2825int Recurrence::yearlyDayCalcToDate(const QDate &enddate, YearlyDayData &data) const 2857int Recurrence::yearlyDayCalcToDate(const QDate &enddate, YearlyDayData &data) const
2826{ 2858{
2827 int countGone = 0; 2859 int countGone = 0;
2828 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX; 2860 int countMax = (rDuration > 0) ? rDuration + mRecurExDatesCount : INT_MAX;
2829 int endYear = enddate.year(); 2861 int endYear = enddate.year();
2830 int endDay = enddate.dayOfYear(); 2862 int endDay = enddate.dayOfYear();
2831 2863
2832 if (data.day > 1) { 2864 if (data.day > 1) {
2833 // Check what remains of the start year 2865 // Check what remains of the start year
2834 bool leapOK = data.isMaxDayCount(); 2866 bool leapOK = data.isMaxDayCount();
2835 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2867 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2836 int d = *it.current(); 2868 int d = *it.current();
2837 if (d >= data.day && (leapOK || d < 366)) { 2869 if (d >= data.day && (leapOK || d < 366)) {
2838 if (data.year == endYear && d > endDay) 2870 if (data.year == endYear && d > endDay)
2839 return countGone; 2871 return countGone;
2840 if (++countGone >= countMax) 2872 if (++countGone >= countMax)
2841 return countMax; 2873 return countMax;
2842 } 2874 }
2843 } 2875 }
2844 data.day = 1; 2876 data.day = 1;
2845 data.year += rFreq; 2877 data.year += rFreq;
2846 } 2878 }
2847 2879
2848 if (data.varies) { 2880 if (data.varies) {
2849 // The number of recurrences is different in leap years, 2881 // The number of recurrences is different in leap years,
2850 // so check year-by-year. 2882 // so check year-by-year.
2851 while (data.year < endYear) { 2883 while (data.year < endYear) {
2852 uint n = data.dayCount(); 2884 uint n = data.dayCount();
2853 countGone += n; 2885 countGone += n;
2854 if (countGone >= countMax) 2886 if (countGone >= countMax)
2855 return countMax; 2887 return countMax;
2856 data.year += rFreq; 2888 data.year += rFreq;
2857 } 2889 }
2858 if (data.year > endYear) 2890 if (data.year > endYear)
2859 return countGone; 2891 return countGone;
2860 } else { 2892 } else {
2861 // The number of recurrences is the same every year. 2893 // The number of recurrences is the same every year.
2862 // Skip the remaining whole years. 2894 // Skip the remaining whole years.
2863 int wholeYears = endYear - data.year; 2895 int wholeYears = endYear - data.year;
2864 countGone += (wholeYears / rFreq) * rYearNums.count(); 2896 countGone += (wholeYears / rFreq) * rYearNums.count();
2865 if (countGone >= countMax) 2897 if (countGone >= countMax)
2866 return countMax; 2898 return countMax;
2867 if (wholeYears % rFreq) 2899 if (wholeYears % rFreq)
2868 return countGone; // end year isn't a recurrence year 2900 return countGone; // end year isn't a recurrence year
2869 data.year = endYear; 2901 data.year = endYear;
2870 } 2902 }
2871 2903
2872 if (data.year <= endYear) { 2904 if (data.year <= endYear) {
2873 // Check the last year in the recurrence 2905 // Check the last year in the recurrence
2874 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2906 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2875 if (*it.current() > endDay) 2907 if (*it.current() > endDay)
2876 return countGone; 2908 return countGone;
2877 if (++countGone >= countMax) 2909 if (++countGone >= countMax)
2878 return countMax; 2910 return countMax;
2879 } 2911 }
2880 } 2912 }
2881 return countGone; 2913 return countGone;
2882} 2914}
2883 2915
2884int Recurrence::yearlyDayCalcNextAfter(QDate &enddate, YearlyDayData &data) const 2916int Recurrence::yearlyDayCalcNextAfter(QDate &enddate, YearlyDayData &data) const
2885{ 2917{
2886 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX; 2918 uint countTogo = (rDuration > 0) ? rDuration + mRecurExDatesCount : UINT_MAX;
2887 int countGone = 0; 2919 int countGone = 0;
2888 int endYear = enddate.year(); 2920 int endYear = enddate.year();
2889 int endDay = enddate.dayOfYear(); 2921 int endDay = enddate.dayOfYear();
2890 2922
2891 if (data.day > 1) { 2923 if (data.day > 1) {
2892 // Check what remains of the start year 2924 // Check what remains of the start year
2893 bool leapOK = data.isMaxDayCount(); 2925 bool leapOK = data.isMaxDayCount();
2894 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2926 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2895 int d = *it.current(); 2927 int d = *it.current();
2896 if (d >= data.day && (leapOK || d < 366)) { 2928 if (d >= data.day && (leapOK || d < 366)) {
2897 ++countGone; 2929 ++countGone;
2898 if (data.year == endYear && d > endDay) { 2930 if (data.year == endYear && d > endDay) {
2899 data.day = d; 2931 data.day = d;
2900 goto ex; 2932 goto ex;
2901 } 2933 }
2902 if (--countTogo == 0) 2934 if (--countTogo == 0)
2903 return 0; 2935 return 0;
2904 } 2936 }
2905 } 2937 }
2906 data.day = 1; 2938 data.day = 1;
2907 data.year += rFreq; 2939 data.year += rFreq;
2908 } 2940 }
2909 2941
2910 if (data.varies) { 2942 if (data.varies) {
2911 // The number of recurrences is different in leap years, 2943 // The number of recurrences is different in leap years,
2912 // so check year-by-year. 2944 // so check year-by-year.
2913 while (data.year <= endYear) { 2945 while (data.year <= endYear) {
2914 uint n = data.dayCount(); 2946 uint n = data.dayCount();
2915 if (data.year == endYear && *rYearNums.getLast() > endDay) 2947 if (data.year == endYear && *rYearNums.getLast() > endDay)
2916 break; 2948 break;
2917 if (n >= countTogo) 2949 if (n >= countTogo)
2918 break; 2950 break;
2919 countTogo -= n; 2951 countTogo -= n;
2920 countGone += n; 2952 countGone += n;
2921 data.year += rFreq; 2953 data.year += rFreq;
2922 } 2954 }
2923 } else { 2955 } else {
2924 // The number of recurrences is the same every year, 2956 // The number of recurrences is the same every year,
2925 // so skip the year-by-year check. 2957 // so skip the year-by-year check.
2926 // Skip the remaining whole years to at least endYear. 2958 // Skip the remaining whole years to at least endYear.
2927 int daysPerYear = rYearNums.count(); 2959 int daysPerYear = rYearNums.count();
2928 int recurYears = (endYear - data.year + rFreq - 1) / rFreq; 2960 int recurYears = (endYear - data.year + rFreq - 1) / rFreq;
2929 if ((endYear - data.year)%rFreq == 0 2961 if ((endYear - data.year)%rFreq == 0
2930 && *rYearNums.getLast() <= endDay) 2962 && *rYearNums.getLast() <= endDay)
2931 ++recurYears; // required year is after endYear 2963 ++recurYears; // required year is after endYear
2932 if (recurYears) { 2964 if (recurYears) {
2933 int n = recurYears * daysPerYear; 2965 int n = recurYears * daysPerYear;
2934 if (static_cast<uint>(n) > countTogo) 2966 if (static_cast<uint>(n) > countTogo)
2935 return 0; // reached end of recurrence 2967 return 0; // reached end of recurrence
2936 countTogo -= n; 2968 countTogo -= n;
2937 countGone += n; 2969 countGone += n;
2938 data.year += recurYears * rFreq; 2970 data.year += recurYears * rFreq;
2939 } 2971 }
2940 } 2972 }
2941 2973
2942 // Check the last year in the recurrence 2974 // Check the last year in the recurrence
2943 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 2975 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
2944 ++countGone; 2976 ++countGone;
2945 int d = *it.current(); 2977 int d = *it.current();
2946 if (data.year > endYear || d > endDay) { 2978 if (data.year > endYear || d > endDay) {
2947 data.day = d; 2979 data.day = d;
2948 break; 2980 break;
2949 } 2981 }
2950 if (--countTogo == 0) 2982 if (--countTogo == 0)
2951 return 0; 2983 return 0;
2952 } 2984 }
2953ex: 2985ex:
2954 enddate = data.date(); 2986 enddate = data.date();
2955 return countGone; 2987 return countGone;
2956} 2988}
2957 2989
2958// Get the days in this month which recur, in numerical order. 2990// Get the days in this month which recur, in numerical order.
2959// Parameters: daysInMonth = number of days in this month 2991// Parameters: daysInMonth = number of days in this month
2960// startDayOfWeek = day of week for first day of month. 2992// startDayOfWeek = day of week for first day of month.
2961void Recurrence::getMonthlyPosDays(QValueList<int> &list, int daysInMonth, int startDayOfWeek) const 2993void Recurrence::getMonthlyPosDays(QValueList<int> &list, int daysInMonth, int startDayOfWeek) const
2962{ 2994{
2963 list.clear(); 2995 list.clear();
2964 int endDayOfWeek = (startDayOfWeek + daysInMonth - 2) % 7 + 1; 2996 int endDayOfWeek = (startDayOfWeek + daysInMonth - 2) % 7 + 1;
2965 // Go through the list, compiling a bit list of actual day numbers 2997 // Go through the list, compiling a bit list of actual day numbers
2966 Q_UINT32 days = 0; 2998 Q_UINT32 days = 0;
2967 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) { 2999 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
2968 int weeknum = pos.current()->rPos - 1; // get 0-based week number 3000 int weeknum = pos.current()->rPos - 1; // get 0-based week number
2969 QBitArray &rdays = pos.current()->rDays; 3001 QBitArray &rdays = pos.current()->rDays;
2970 if (pos.current()->negative) { 3002 if (pos.current()->negative) {
2971 // nth days before the end of the month 3003 // nth days before the end of the month
2972 for (uint i = 1; i <= 7; ++i) { 3004 for (uint i = 1; i <= 7; ++i) {
2973 if (rdays.testBit(i - 1)) { 3005 if (rdays.testBit(i - 1)) {
2974 int day = daysInMonth - weeknum*7 - (endDayOfWeek - i + 7) % 7; 3006 int day = daysInMonth - weeknum*7 - (endDayOfWeek - i + 7) % 7;
2975 if (day > 0) 3007 if (day > 0)
2976 days |= 1 << (day - 1); 3008 days |= 1 << (day - 1);
2977 } 3009 }
2978 } 3010 }
2979 } else { 3011 } else {
2980 // nth days after the start of the month 3012 // nth days after the start of the month
2981 for (uint i = 1; i <= 7; ++i) { 3013 for (uint i = 1; i <= 7; ++i) {
2982 if (rdays.testBit(i - 1)) { 3014 if (rdays.testBit(i - 1)) {
2983 int day = 1 + weeknum*7 + (i - startDayOfWeek + 7) % 7; 3015 int day = 1 + weeknum*7 + (i - startDayOfWeek + 7) % 7;
2984 if (day <= daysInMonth) 3016 if (day <= daysInMonth)
2985 days |= 1 << (day - 1); 3017 days |= 1 << (day - 1);
2986 } 3018 }
2987 } 3019 }
2988 } 3020 }
2989 } 3021 }
2990 // Compile the ordered list 3022 // Compile the ordered list
2991 Q_UINT32 mask = 1; 3023 Q_UINT32 mask = 1;
2992 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) { 3024 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
2993 if (days & mask) 3025 if (days & mask)
2994 list.append(i + 1); 3026 list.append(i + 1);
2995 } 3027 }
2996} 3028}
2997 3029
2998// Get the number of days in the month which recur. 3030// Get the number of days in the month which recur.
2999// Reply = -1 if the number varies from month to month. 3031// Reply = -1 if the number varies from month to month.
3000int Recurrence::countMonthlyPosDays() const 3032int Recurrence::countMonthlyPosDays() const
3001{ 3033{
3002 int count = 0; 3034 int count = 0;
3003 Q_UINT8 positive[5] = { 0, 0, 0, 0, 0 }; 3035 Q_UINT8 positive[5] = { 0, 0, 0, 0, 0 };
3004 Q_UINT8 negative[4] = { 0, 0, 0, 0 }; 3036 Q_UINT8 negative[4] = { 0, 0, 0, 0 };
3005 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) { 3037 for (QPtrListIterator<rMonthPos> pos(rMonthPositions); pos.current(); ++pos) {
3006 int weeknum = pos.current()->rPos; 3038 int weeknum = pos.current()->rPos;
3007 Q_UINT8* wk; 3039 Q_UINT8* wk;
3008 if (pos.current()->negative) { 3040 if (pos.current()->negative) {
3009 // nth days before the end of the month 3041 // nth days before the end of the month
3010 if (weeknum > 4) 3042 if (weeknum > 4)
3011 return -1; // days in 5th week are often missing 3043 return -1; // days in 5th week are often missing
3012 wk = &negative[4 - weeknum]; 3044 wk = &negative[4 - weeknum];
3013 } else { 3045 } else {
3014 // nth days after the start of the month 3046 // nth days after the start of the month
3015 if (weeknum > 4) 3047 if (weeknum > 4)
3016 return -1; // days in 5th week are often missing 3048 return -1; // days in 5th week are often missing
3017 wk = &positive[weeknum - 1]; 3049 wk = &positive[weeknum - 1];
3018 } 3050 }
3019 QBitArray &rdays = pos.current()->rDays; 3051 QBitArray &rdays = pos.current()->rDays;
3020 for (uint i = 0; i < 7; ++i) { 3052 for (uint i = 0; i < 7; ++i) {
3021 if (rdays.testBit(i)) { 3053 if (rdays.testBit(i)) {
3022 ++count; 3054 ++count;
3023 *wk |= (1 << i); 3055 *wk |= (1 << i);
3024 } 3056 }
3025 } 3057 }
3026 } 3058 }
3027 // Check for any possible days which could be duplicated by 3059 // Check for any possible days which could be duplicated by
3028 // a positive and a negative position. 3060 // a positive and a negative position.
3029 for (int i = 0; i < 4; ++i) { 3061 for (int i = 0; i < 4; ++i) {
3030 if (negative[i] & (positive[i] | positive[i+1])) 3062 if (negative[i] & (positive[i] | positive[i+1]))
3031 return -1; 3063 return -1;
3032 } 3064 }
3033 return count; 3065 return count;
3034} 3066}
3035 3067
3036// Get the days in this month which recur, in numerical order. 3068// Get the days in this month which recur, in numerical order.
3037// Reply = true if day numbers varies from month to month. 3069// Reply = true if day numbers varies from month to month.
3038bool Recurrence::getMonthlyDayDays(QValueList<int> &list, int daysInMonth) const 3070bool Recurrence::getMonthlyDayDays(QValueList<int> &list, int daysInMonth) const
3039{ 3071{
3040 list.clear(); 3072 list.clear();
3041 bool variable = false; 3073 bool variable = false;
3042 Q_UINT32 days = 0; 3074 Q_UINT32 days = 0;
3043 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { 3075 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3044 int day = *it.current(); 3076 int day = *it.current();
3045 if (day > 0) { 3077 if (day > 0) {
3046 // date in the month 3078 // date in the month
3047 if (day <= daysInMonth) 3079 if (day <= daysInMonth)
3048 days |= 1 << (day - 1); 3080 days |= 1 << (day - 1);
3049 if (day > 28 && day <= 31) 3081 if (day > 28 && day <= 31)
3050 variable = true; // this date does not appear in some months 3082 variable = true; // this date does not appear in some months
3051 } else if (day < 0) { 3083 } else if (day < 0) {
3052 // days before the end of the month 3084 // days before the end of the month
3053 variable = true; // this date varies depending on the month length 3085 variable = true; // this date varies depending on the month length
3054 day = daysInMonth + day; // zero-based day of month 3086 day = daysInMonth + day; // zero-based day of month
3055 if (day >= 0) 3087 if (day >= 0)
3056 days |= 1 << day; 3088 days |= 1 << day;
3057 } 3089 }
3058 } 3090 }
3059 // Compile the ordered list 3091 // Compile the ordered list
3060 Q_UINT32 mask = 1; 3092 Q_UINT32 mask = 1;
3061 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) { 3093 for (int i = 0; i < daysInMonth; mask <<= 1, ++i) {
3062 if (days & mask) 3094 if (days & mask)
3063 list.append(i + 1); 3095 list.append(i + 1);
3064 } 3096 }
3065 return variable; 3097 return variable;
3066} 3098}
3067 3099
3068// Get the months which recur, in numerical order, for both leap years and non-leap years. 3100// Get the months which recur, in numerical order, for both leap years and non-leap years.
3069// N.B. If February 29th recurs on March 1st in non-leap years, February (not March) is 3101// N.B. If February 29th recurs on March 1st in non-leap years, February (not March) is
3070// included in the non-leap year month list. 3102// included in the non-leap year month list.
3071// Reply = true if February 29th also recurs. 3103// Reply = true if February 29th also recurs.
3072bool Recurrence::getYearlyMonthMonths(int day, QValueList<int> &list, QValueList<int> &leaplist) const 3104bool Recurrence::getYearlyMonthMonths(int day, QValueList<int> &list, QValueList<int> &leaplist) const
3073{ 3105{
3074 list.clear(); 3106 list.clear();
3075 leaplist.clear(); 3107 leaplist.clear();
3076 bool feb29 = false; 3108 bool feb29 = false;
3077 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) { 3109 for (QPtrListIterator<int> it(rYearNums); it.current(); ++it) {
3078 int month = *it.current(); 3110 int month = *it.current();
3079 if (month == 2) { 3111 if (month == 2) {
3080 if (day <= 28) { 3112 if (day <= 28) {
3081 list.append(month); // date appears in February 3113 list.append(month); // date appears in February
3082 leaplist.append(month); 3114 leaplist.append(month);
3083 } 3115 }
3084 else if (day == 29) { 3116 else if (day == 29) {
3085 // February 29th 3117 // February 29th
3086 leaplist.append(month); 3118 leaplist.append(month);
3087 switch (mFeb29YearlyType) { 3119 switch (mFeb29YearlyType) {
3088 case rFeb28: 3120 case rFeb28:
3089 case rMar1: 3121 case rMar1:
3090 list.append(2); 3122 list.append(2);
3091 break; 3123 break;
3092 case rFeb29: 3124 case rFeb29:
3093 break; 3125 break;
3094 } 3126 }
3095 feb29 = true; 3127 feb29 = true;
3096 } 3128 }
3097 } 3129 }
3098 else if (day <= 30 || QDate(2000, month, 1).daysInMonth() == 31) { 3130 else if (day <= 30 || QDate(2000, month, 1).daysInMonth() == 31) {
3099 list.append(month); // date appears in every month 3131 list.append(month); // date appears in every month
3100 leaplist.append(month); 3132 leaplist.append(month);
3101 } 3133 }
3102 } 3134 }
3103 return feb29; 3135 return feb29;
3104} 3136}
3105 3137
3106/* From the recurrence day of the week list, get the earliest day in the 3138/* From the recurrence day of the week list, get the earliest day in the
3107 * specified week which is >= the startDay. 3139 * specified week which is >= the startDay.
3108 * Parameters: startDay = 1..7 (Monday..Sunday) 3140 * Parameters: startDay = 1..7 (Monday..Sunday)
3109 * useWeekStart = true to end search at day before next rWeekStart 3141 * useWeekStart = true to end search at day before next rWeekStart
3110 * = false to search for a full 7 days 3142 * = false to search for a full 7 days
3111 * Reply = day of the week (1..7), or 0 if none found. 3143 * Reply = day of the week (1..7), or 0 if none found.
3112 */ 3144 */
3113int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const 3145int Recurrence::getFirstDayInWeek(int startDay, bool useWeekStart) const
3114{ 3146{
3115 int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7; 3147 int last = ((useWeekStart ? rWeekStart : startDay) + 5)%7;
3116 for (int i = startDay - 1; ; i = (i + 1)%7) { 3148 for (int i = startDay - 1; ; i = (i + 1)%7) {
3117 if (rDays.testBit(i)) 3149 if (rDays.testBit(i))
3118 return i + 1; 3150 return i + 1;
3119 if (i == last) 3151 if (i == last)
3120 return 0; 3152 return 0;
3121 } 3153 }
3122} 3154}
3123 3155
3124/* From the recurrence day of the week list, get the latest day in the 3156/* From the recurrence day of the week list, get the latest day in the
3125 * specified week which is <= the endDay. 3157 * specified week which is <= the endDay.
3126 * Parameters: endDay = 1..7 (Monday..Sunday) 3158 * Parameters: endDay = 1..7 (Monday..Sunday)
3127 * useWeekStart = true to end search at rWeekStart 3159 * useWeekStart = true to end search at rWeekStart
3128 * = false to search for a full 7 days 3160 * = false to search for a full 7 days
3129 * Reply = day of the week (1..7), or 0 if none found. 3161 * Reply = day of the week (1..7), or 0 if none found.
3130 */ 3162 */
3131int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const 3163int Recurrence::getLastDayInWeek(int endDay, bool useWeekStart) const
3132{ 3164{
3133 int last = useWeekStart ? rWeekStart - 1 : endDay%7; 3165 int last = useWeekStart ? rWeekStart - 1 : endDay%7;
3134 for (int i = endDay - 1; ; i = (i + 6)%7) { 3166 for (int i = endDay - 1; ; i = (i + 6)%7) {
3135 if (rDays.testBit(i)) 3167 if (rDays.testBit(i))
3136 return i + 1; 3168 return i + 1;
3137 if (i == last) 3169 if (i == last)
3138 return 0; 3170 return 0;
3139 } 3171 }
3140} 3172}
3141 3173
3142/* From the recurrence monthly day number list or monthly day of week/week of 3174/* From the recurrence monthly day number list or monthly day of week/week of
3143 * month list, get the earliest day in the specified month which is >= the 3175 * month list, get the earliest day in the specified month which is >= the
3144 * earliestDate. 3176 * earliestDate.
3145 */ 3177 */
3146QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const 3178QDate Recurrence::getFirstDateInMonth(const QDate &earliestDate) const
3147{ 3179{
3148 int earliestDay = earliestDate.day(); 3180 int earliestDay = earliestDate.day();
3149 int daysInMonth = earliestDate.daysInMonth(); 3181 int daysInMonth = earliestDate.daysInMonth();
3150 switch (recurs) { 3182 switch (recurs) {
3151 case rMonthlyDay: { 3183 case rMonthlyDay: {
3152 int minday = daysInMonth + 1; 3184 int minday = daysInMonth + 1;
3153 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { 3185 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3154 int day = *it.current(); 3186 int day = *it.current();
3155 if (day < 0) 3187 if (day < 0)
3156 day = daysInMonth + day + 1; 3188 day = daysInMonth + day + 1;
3157 if (day >= earliestDay && day < minday) 3189 if (day >= earliestDay && day < minday)
3158 minday = day; 3190 minday = day;
3159 } 3191 }
3160 if (minday <= daysInMonth) 3192 if (minday <= daysInMonth)
3161 return earliestDate.addDays(minday - earliestDay); 3193 return earliestDate.addDays(minday - earliestDay);
3162 break; 3194 break;
3163 } 3195 }
3164 case rMonthlyPos: 3196 case rMonthlyPos:
3165 case rYearlyPos: { 3197 case rYearlyPos: {
3166 QDate monthBegin(earliestDate.addDays(1 - earliestDay)); 3198 QDate monthBegin(earliestDate.addDays(1 - earliestDay));
3167 QValueList<int> dayList; 3199 QValueList<int> dayList;
3168 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek()); 3200 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
3169 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) { 3201 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
3170 if (*id >= earliestDay) 3202 if (*id >= earliestDay)
3171 return monthBegin.addDays(*id - 1); 3203 return monthBegin.addDays(*id - 1);
3172 } 3204 }
3173 break; 3205 break;
3174 } 3206 }
3175 } 3207 }
3176 return QDate(); 3208 return QDate();
3177} 3209}
3178 3210
3179/* From the recurrence monthly day number list or monthly day of week/week of 3211/* From the recurrence monthly day number list or monthly day of week/week of
3180 * month list, get the latest day in the specified month which is <= the 3212 * month list, get the latest day in the specified month which is <= the
3181 * latestDate. 3213 * latestDate.
3182 */ 3214 */
3183QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const 3215QDate Recurrence::getLastDateInMonth(const QDate &latestDate) const
3184{ 3216{
3185 int latestDay = latestDate.day(); 3217 int latestDay = latestDate.day();
3186 int daysInMonth = latestDate.daysInMonth(); 3218 int daysInMonth = latestDate.daysInMonth();
3187 switch (recurs) { 3219 switch (recurs) {
3188 case rMonthlyDay: { 3220 case rMonthlyDay: {
3189 int maxday = -1; 3221 int maxday = -1;
3190 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) { 3222 for (QPtrListIterator<int> it(rMonthDays); it.current(); ++it) {
3191 int day = *it.current(); 3223 int day = *it.current();
3192 if (day < 0) 3224 if (day < 0)
3193 day = daysInMonth + day + 1; 3225 day = daysInMonth + day + 1;
3194 if (day <= latestDay && day > maxday) 3226 if (day <= latestDay && day > maxday)
3195 maxday = day; 3227 maxday = day;
3196 } 3228 }
3197 if (maxday > 0) 3229 if (maxday > 0)
3198 return QDate(latestDate.year(), latestDate.month(), maxday); 3230 return QDate(latestDate.year(), latestDate.month(), maxday);
3199 break; 3231 break;
3200 } 3232 }
3201 case rMonthlyPos: 3233 case rMonthlyPos:
3202 case rYearlyPos: { 3234 case rYearlyPos: {
3203 QDate monthBegin(latestDate.addDays(1 - latestDay)); 3235 QDate monthBegin(latestDate.addDays(1 - latestDay));
3204 QValueList<int> dayList; 3236 QValueList<int> dayList;
3205 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek()); 3237 getMonthlyPosDays(dayList, daysInMonth, monthBegin.dayOfWeek());
3206 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) { 3238 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
3207 if (*id <= latestDay) 3239 if (*id <= latestDay)
3208 return monthBegin.addDays(*id - 1); 3240 return monthBegin.addDays(*id - 1);
3209 } 3241 }
3210 break; 3242 break;
3211 } 3243 }
3212 } 3244 }
3213 return QDate(); 3245 return QDate();
3214} 3246}
3215 3247
3216/* From the recurrence yearly month list or yearly day list, get the earliest 3248/* From the recurrence yearly month list or yearly day list, get the earliest
3217 * month or day in the specified year which is >= the earliestDate. 3249 * month or day in the specified year which is >= the earliestDate.
3218 * Note that rYearNums is sorted in numerical order. 3250 * Note that rYearNums is sorted in numerical order.
3219 */ 3251 */
3220QDate Recurrence::getFirstDateInYear(const QDate &earliestDate) const 3252QDate Recurrence::getFirstDateInYear(const QDate &earliestDate) const
3221{ 3253{
3222 QPtrListIterator<int> it(rYearNums); 3254 QPtrListIterator<int> it(rYearNums);
3223 switch (recurs) { 3255 switch (recurs) {
3224 case rYearlyMonth: { 3256 case rYearlyMonth: {
3225 int day = recurStart().date().day(); 3257 int day = recurStart().date().day();
3226 int earliestYear = earliestDate.year(); 3258 int earliestYear = earliestDate.year();
3227 int earliestMonth = earliestDate.month(); 3259 int earliestMonth = earliestDate.month();
3228 int earliestDay = earliestDate.day(); 3260 int earliestDay = earliestDate.day();
3229 if (earliestDay > day) { 3261 if (earliestDay > day) {
3230 // The earliest date is later in the month than the recurrence date, 3262 // The earliest date is later in the month than the recurrence date,
3231 // so skip to the next month before starting to check 3263 // so skip to the next month before starting to check
3232 if (++earliestMonth > 12) 3264 if (++earliestMonth > 12)
3233 return QDate(); 3265 return QDate();
3234 } 3266 }
3235 for ( ; it.current(); ++it) { 3267 for ( ; it.current(); ++it) {
3236 int month = *it.current(); 3268 int month = *it.current();
3237 if (month >= earliestMonth) { 3269 if (month >= earliestMonth) {
3238 if (day <= 28 || QDate::isValid(earliestYear, month, day)) 3270 if (day <= 28 || QDate::isValid(earliestYear, month, day))
3239 return QDate(earliestYear, month, day); 3271 return QDate(earliestYear, month, day);
3240 if (day == 29 && month == 2) { 3272 if (day == 29 && month == 2) {
3241 // It's a recurrence on February 29th, in a non-leap year 3273 // It's a recurrence on February 29th, in a non-leap year
3242 switch (mFeb29YearlyType) { 3274 switch (mFeb29YearlyType) {
3243 case rMar1: 3275 case rMar1:
3244 return QDate(earliestYear, 3, 1); 3276 return QDate(earliestYear, 3, 1);
3245 case rFeb28: 3277 case rFeb28:
3246 if (earliestDay <= 28) 3278 if (earliestDay <= 28)
3247 return QDate(earliestYear, 2, 28); 3279 return QDate(earliestYear, 2, 28);
3248 break; 3280 break;
3249 case rFeb29: 3281 case rFeb29:
3250 break; 3282 break;
3251 } 3283 }
3252 } 3284 }
3253 } 3285 }
3254 } 3286 }
3255 break; 3287 break;
3256 } 3288 }
3257 case rYearlyPos: { 3289 case rYearlyPos: {
3258 QValueList<int> dayList; 3290 QValueList<int> dayList;
3259 int earliestYear = earliestDate.year(); 3291 int earliestYear = earliestDate.year();
3260 int earliestMonth = earliestDate.month(); 3292 int earliestMonth = earliestDate.month();
3261 int earliestDay = earliestDate.day(); 3293 int earliestDay = earliestDate.day();
3262 for ( ; it.current(); ++it) { 3294 for ( ; it.current(); ++it) {
3263 int month = *it.current(); 3295 int month = *it.current();
3264 if (month >= earliestMonth) { 3296 if (month >= earliestMonth) {
3265 QDate monthBegin(earliestYear, month, 1); 3297 QDate monthBegin(earliestYear, month, 1);
3266 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek()); 3298 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
3267 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) { 3299 for (QValueList<int>::ConstIterator id = dayList.begin(); id != dayList.end(); ++id) {
3268 if (*id >= earliestDay) 3300 if (*id >= earliestDay)
3269 return monthBegin.addDays(*id - 1); 3301 return monthBegin.addDays(*id - 1);
3270 } 3302 }
3271 earliestDay = 1; 3303 earliestDay = 1;
3272 } 3304 }
3273 } 3305 }
3274 break; 3306 break;
3275 } 3307 }
3276 case rYearlyDay: { 3308 case rYearlyDay: {
3277 int earliestDay = earliestDate.dayOfYear(); 3309 int earliestDay = earliestDate.dayOfYear();
3278 for ( ; it.current(); ++it) { 3310 for ( ; it.current(); ++it) {
3279 int day = *it.current(); 3311 int day = *it.current();
3280 if (day >= earliestDay && (day <= 365 || day <= earliestDate.daysInYear())) 3312 if (day >= earliestDay && (day <= 365 || day <= earliestDate.daysInYear()))
3281 return earliestDate.addDays(day - earliestDay); 3313 return earliestDate.addDays(day - earliestDay);
3282 } 3314 }
3283 break; 3315 break;
3284 } 3316 }
3285 } 3317 }
3286 return QDate(); 3318 return QDate();
3287} 3319}
3288 3320
3289/* From the recurrence yearly month list or yearly day list, get the latest 3321/* From the recurrence yearly month list or yearly day list, get the latest
3290 * month or day in the specified year which is <= the latestDate. 3322 * month or day in the specified year which is <= the latestDate.
3291 * Note that rYearNums is sorted in numerical order. 3323 * Note that rYearNums is sorted in numerical order.
3292 */ 3324 */
3293QDate Recurrence::getLastDateInYear(const QDate &latestDate) const 3325QDate Recurrence::getLastDateInYear(const QDate &latestDate) const
3294{ 3326{
3295 QPtrListIterator<int> it(rYearNums); 3327 QPtrListIterator<int> it(rYearNums);
3296 switch (recurs) { 3328 switch (recurs) {
3297 case rYearlyMonth: { 3329 case rYearlyMonth: {
3298 int day = recurStart().date().day(); 3330 int day = recurStart().date().day();
3299 int latestYear = latestDate.year(); 3331 int latestYear = latestDate.year();
3300 int latestMonth = latestDate.month(); 3332 int latestMonth = latestDate.month();
3301 if (latestDate.day() > day) { 3333 if (latestDate.day() > day) {
3302 // The latest date is earlier in the month than the recurrence date, 3334 // The latest date is earlier in the month than the recurrence date,
3303 // so skip to the previous month before starting to check 3335 // so skip to the previous month before starting to check
3304 if (--latestMonth <= 0) 3336 if (--latestMonth <= 0)
3305 return QDate(); 3337 return QDate();
3306 } 3338 }
3307 for (it.toLast(); it.current(); --it) { 3339 for (it.toLast(); it.current(); --it) {
3308 int month = *it.current(); 3340 int month = *it.current();
3309 if (month <= latestMonth) { 3341 if (month <= latestMonth) {
3310 if (day <= 28 || QDate::isValid(latestYear, month, day)) 3342 if (day <= 28 || QDate::isValid(latestYear, month, day))
3311 return QDate(latestYear, month, day); 3343 return QDate(latestYear, month, day);
3312 if (day == 29 && month == 2) { 3344 if (day == 29 && month == 2) {
3313 // It's a recurrence on February 29th, in a non-leap year 3345 // It's a recurrence on February 29th, in a non-leap year
3314 switch (mFeb29YearlyType) { 3346 switch (mFeb29YearlyType) {
3315 case rMar1: 3347 case rMar1:
3316 if (latestMonth >= 3) 3348 if (latestMonth >= 3)
3317 return QDate(latestYear, 3, 1); 3349 return QDate(latestYear, 3, 1);
3318 break; 3350 break;
3319 case rFeb28: 3351 case rFeb28:
3320 return QDate(latestYear, 2, 28); 3352 return QDate(latestYear, 2, 28);
3321 case rFeb29: 3353 case rFeb29:
3322 break; 3354 break;
3323 } 3355 }
3324 } 3356 }
3325 } 3357 }
3326 } 3358 }
3327 break; 3359 break;
3328 } 3360 }
3329 case rYearlyPos: { 3361 case rYearlyPos: {
3330 QValueList<int> dayList; 3362 QValueList<int> dayList;
3331 int latestYear = latestDate.year(); 3363 int latestYear = latestDate.year();
3332 int latestMonth = latestDate.month(); 3364 int latestMonth = latestDate.month();
3333 int latestDay = latestDate.day(); 3365 int latestDay = latestDate.day();
3334 for (it.toLast(); it.current(); --it) { 3366 for (it.toLast(); it.current(); --it) {
3335 int month = *it.current(); 3367 int month = *it.current();
3336 if (month <= latestMonth) { 3368 if (month <= latestMonth) {
3337 QDate monthBegin(latestYear, month, 1); 3369 QDate monthBegin(latestYear, month, 1);
3338 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek()); 3370 getMonthlyPosDays(dayList, monthBegin.daysInMonth(), monthBegin.dayOfWeek());
3339 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) { 3371 for (QValueList<int>::ConstIterator id = dayList.fromLast(); id != dayList.end(); --id) {
3340 if (*id <= latestDay) 3372 if (*id <= latestDay)
3341 return monthBegin.addDays(*id - 1); 3373 return monthBegin.addDays(*id - 1);
3342 } 3374 }
3343 latestDay = 31; 3375 latestDay = 31;
3344 } 3376 }
3345 } 3377 }
3346 break; 3378 break;
3347 } 3379 }
3348 case rYearlyDay: { 3380 case rYearlyDay: {
3349 int latestDay = latestDate.dayOfYear(); 3381 int latestDay = latestDate.dayOfYear();
3350 for (it.toLast(); it.current(); --it) { 3382 for (it.toLast(); it.current(); --it) {
3351 int day = *it.current(); 3383 int day = *it.current();
3352 if (day <= latestDay) 3384 if (day <= latestDay)
3353 return latestDate.addDays(day - latestDay); 3385 return latestDate.addDays(day - latestDay);
3354 } 3386 }
3355 break; 3387 break;
3356 } 3388 }
3357 } 3389 }
3358 return QDate(); 3390 return QDate();
3359} 3391}
3360 3392
3361void Recurrence::dump() const 3393void Recurrence::dump() const
3362{ 3394{
3363 kdDebug() << "Recurrence::dump():" << endl; 3395 kdDebug() << "Recurrence::dump():" << endl;
3364 3396
3365 kdDebug() << " type: " << recurs << endl; 3397 kdDebug() << " type: " << recurs << endl;
3366 3398
3367 kdDebug() << " rDays: " << endl; 3399 kdDebug() << " rDays: " << endl;
3368 int i; 3400 int i;
3369 for( i = 0; i < 7; ++i ) { 3401 for( i = 0; i < 7; ++i ) {
3370 kdDebug() << " " << i << ": " 3402 kdDebug() << " " << i << ": "
3371 << ( rDays.testBit( i ) ? "true" : "false" ) << endl; 3403 << ( rDays.testBit( i ) ? "true" : "false" ) << endl;
3372 } 3404 }
3373} 3405}
diff --git a/libkcal/sharpformat.cpp b/libkcal/sharpformat.cpp
index defdb09..89eb72f 100644
--- a/libkcal/sharpformat.cpp
+++ b/libkcal/sharpformat.cpp
@@ -1,1018 +1,1019 @@
1/* 1/*
2 This file is part of libkcal. 2 This file is part of libkcal.
3 3
4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> 4 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
5 5
6 This library is free software; you can redistribute it and/or 6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public 7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either 8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version. 9 version 2 of the License, or (at your option) any later version.
10 10
11 This library is distributed in the hope that it will be useful, 11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details. 14 Library General Public License for more details.
15 15
16 You should have received a copy of the GNU Library General Public License 16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to 17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. 19 Boston, MA 02111-1307, USA.
20*/ 20*/
21 21
22#include <qdatetime.h> 22#include <qdatetime.h>
23#include <qstring.h> 23#include <qstring.h>
24#include <qapplication.h> 24#include <qapplication.h>
25#include <qptrlist.h> 25#include <qptrlist.h>
26#include <qregexp.h> 26#include <qregexp.h>
27#include <qmessagebox.h> 27#include <qmessagebox.h>
28#include <qclipboard.h> 28#include <qclipboard.h>
29#include <qfile.h> 29#include <qfile.h>
30#include <qtextstream.h> 30#include <qtextstream.h>
31#include <qtextcodec.h> 31#include <qtextcodec.h>
32#include <qxml.h> 32#include <qxml.h>
33#include <qlabel.h> 33#include <qlabel.h>
34 34
35#include <kdebug.h> 35#include <kdebug.h>
36#include <klocale.h> 36#include <klocale.h>
37#include <kglobal.h> 37#include <kglobal.h>
38 38
39#include "calendar.h" 39#include "calendar.h"
40#include "alarm.h" 40#include "alarm.h"
41#include "recurrence.h" 41#include "recurrence.h"
42#include "calendarlocal.h" 42#include "calendarlocal.h"
43 43
44#include "sharpformat.h" 44#include "sharpformat.h"
45#include "syncdefines.h" 45#include "syncdefines.h"
46 46
47using namespace KCal; 47using namespace KCal;
48 48
49//CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY 49//CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY
50// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 50// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
51 51
52//ARSD silentalarm = 0 52//ARSD silentalarm = 0
53// 11 RTYP 225 no /0 dialy/ 1 weekly/ 3 month by date/ 2 month by day(pos)/ yearly 53// 11 RTYP 225 no /0 dialy/ 1 weekly/ 3 month by date/ 2 month by day(pos)/ yearly
54// 12 RFRQ 54// 12 RFRQ
55// 13 RPOS pos = 4. monday in month 55// 13 RPOS pos = 4. monday in month
56// 14 RDYS days: 1 mon/ 2 tue .. 64 sun 56// 14 RDYS days: 1 mon/ 2 tue .. 64 sun
57// 15 REND 0 = no end/ 1 = end 57// 15 REND 0 = no end/ 1 = end
58// 16 REDT rec end dt 58// 16 REDT rec end dt
59//ALSD 59//ALSD
60//ALED 60//ALED
61//MDAY 61//MDAY
62 62
63class SharpParser : public QObject 63class SharpParser : public QObject
64{ 64{
65 public: 65 public:
66 SharpParser( Calendar *calendar ) : mCalendar( calendar ) { 66 SharpParser( Calendar *calendar ) : mCalendar( calendar ) {
67 oldCategories = 0; 67 oldCategories = 0;
68 } 68 }
69 69
70 bool startElement( Calendar *existingCalendar, const QStringList & attList, QString qName ) 70 bool startElement( Calendar *existingCalendar, const QStringList & attList, QString qName )
71 { 71 {
72 int i = 1; 72 int i = 1;
73 bool skip = true; 73 bool skip = true;
74 int max = attList.count() -2; 74 int max = attList.count() -2;
75 while ( i < max ) { 75 while ( i < max ) {
76 if ( !attList[i].isEmpty() ) { 76 if ( !attList[i].isEmpty() ) {
77 skip = false; 77 skip = false;
78 break; 78 break;
79 } 79 }
80 ++i ; 80 ++i ;
81 } 81 }
82 if ( skip ) 82 if ( skip )
83 return false; 83 return false;
84 ulong cSum = SharpFormat::getCsum(attList ); 84 ulong cSum = SharpFormat::getCsum(attList );
85 85
86 if ( qName == "Event" ) { 86 if ( qName == "Event" ) {
87 Event *event; 87 Event *event;
88 event = existingCalendar->event( "Sharp_DTM",attList[0] ); 88 event = existingCalendar->event( "Sharp_DTM",attList[0] );
89 if ( event ) 89 if ( event )
90 event = (Event*)event->clone(); 90 event = (Event*)event->clone();
91 else 91 else
92 event = new Event; 92 event = new Event;
93 event->setID("Sharp_DTM", attList[0] ); 93 event->setID("Sharp_DTM", attList[0] );
94 event->setCsum( "Sharp_DTM", QString::number( cSum )); 94 event->setCsum( "Sharp_DTM", QString::number( cSum ));
95 event->setTempSyncStat(SYNC_TEMPSTATE_NEW_EXTERNAL ); 95 event->setTempSyncStat(SYNC_TEMPSTATE_NEW_EXTERNAL );
96 96
97 event->setSummary( attList[2] ); 97 event->setSummary( attList[2] );
98 event->setLocation( attList[3] ); 98 event->setLocation( attList[3] );
99 event->setDescription( attList[4] ); 99 event->setDescription( attList[4] );
100 if ( attList[7] == "1" ) { 100 if ( attList[7] == "1" ) {
101 event->setDtStart( QDateTime(fromString( attList[17]+"T000000", false ).date(),QTime(0,0,0 ) )); 101 event->setDtStart( QDateTime(fromString( attList[17]+"T000000", false ).date(),QTime(0,0,0 ) ));
102 event->setDtEnd( QDateTime(fromString( attList[18]+"T000000", false ).date(),QTime(0,0,0 ))); 102 event->setDtEnd( QDateTime(fromString( attList[18]+"T000000", false ).date(),QTime(0,0,0 )));
103 event->setFloats( true ); 103 event->setFloats( true );
104 } else { 104 } else {
105 event->setFloats( false ); 105 event->setFloats( false );
106 event->setDtStart( fromString( attList[5] ) ); 106 event->setDtStart( fromString( attList[5] ) );
107 event->setDtEnd( fromString( attList[6] )); 107 event->setDtEnd( fromString( attList[6] ));
108 } 108 }
109 109
110 QString rtype = attList[11]; 110 QString rtype = attList[11];
111 if ( rtype != "255" ) { 111 if ( rtype != "255" ) {
112 // qDebug("recurs "); 112 // qDebug("recurs ");
113 QDate startDate = event->dtStart().date(); 113 QDate startDate = event->dtStart().date();
114 114
115 QString freqStr = attList[12]; 115 QString freqStr = attList[12];
116 int freq = freqStr.toInt(); 116 int freq = freqStr.toInt();
117 117
118 QString hasEndDateStr = attList[15] ; 118 QString hasEndDateStr = attList[15] ;
119 bool hasEndDate = hasEndDateStr == "1"; 119 bool hasEndDate = hasEndDateStr == "1";
120 120
121 QString endDateStr = attList[16]; 121 QString endDateStr = attList[16];
122 QDate endDate = fromString( endDateStr ).date(); 122 QDate endDate = fromString( endDateStr ).date();
123 123
124 QString weekDaysStr = attList[14]; 124 QString weekDaysStr = attList[14];
125 uint weekDaysNum = weekDaysStr.toInt(); 125 uint weekDaysNum = weekDaysStr.toInt();
126 126
127 QBitArray weekDays( 7 ); 127 QBitArray weekDays( 7 );
128 int i; 128 int i;
129 int bb = 1; 129 int bb = 1;
130 for( i = 1; i <= 7; ++i ) { 130 for( i = 1; i <= 7; ++i ) {
131 weekDays.setBit( i - 1, ( bb & weekDaysNum )); 131 weekDays.setBit( i - 1, ( bb & weekDaysNum ));
132 bb = 2 << (i-1); 132 bb = 2 << (i-1);
133 //qDebug(" %d bit %d ",i-1,weekDays.at(i-1) ); 133 //qDebug(" %d bit %d ",i-1,weekDays.at(i-1) );
134 } 134 }
135 // qDebug("next "); 135 // qDebug("next ");
136 QString posStr = attList[13]; 136 QString posStr = attList[13];
137 int pos = posStr.toInt(); 137 int pos = posStr.toInt();
138 Recurrence *r = event->recurrence(); 138 Recurrence *r = event->recurrence();
139 139
140 if ( rtype == "0" ) { 140 if ( rtype == "0" ) {
141 if ( hasEndDate ) r->setDaily( freq, endDate ); 141 if ( hasEndDate ) r->setDaily( freq, endDate );
142 else r->setDaily( freq, -1 ); 142 else r->setDaily( freq, -1 );
143 } else if ( rtype == "1" ) { 143 } else if ( rtype == "1" ) {
144 if ( hasEndDate ) r->setWeekly( freq, weekDays, endDate ); 144 if ( hasEndDate ) r->setWeekly( freq, weekDays, endDate );
145 else r->setWeekly( freq, weekDays, -1 ); 145 else r->setWeekly( freq, weekDays, -1 );
146 } else if ( rtype == "3" ) { 146 } else if ( rtype == "3" ) {
147 if ( hasEndDate ) 147 if ( hasEndDate )
148 r->setMonthly( Recurrence::rMonthlyDay, freq, endDate ); 148 r->setMonthly( Recurrence::rMonthlyDay, freq, endDate );
149 else 149 else
150 r->setMonthly( Recurrence::rMonthlyDay, freq, -1 ); 150 r->setMonthly( Recurrence::rMonthlyDay, freq, -1 );
151 r->addMonthlyDay( startDate.day() ); 151 r->addMonthlyDay( startDate.day() );
152 } else if ( rtype == "2" ) { 152 } else if ( rtype == "2" ) {
153 if ( hasEndDate ) 153 if ( hasEndDate )
154 r->setMonthly( Recurrence::rMonthlyPos, freq, endDate ); 154 r->setMonthly( Recurrence::rMonthlyPos, freq, endDate );
155 else 155 else
156 r->setMonthly( Recurrence::rMonthlyPos, freq, -1 ); 156 r->setMonthly( Recurrence::rMonthlyPos, freq, -1 );
157 QBitArray days( 7 ); 157 QBitArray days( 7 );
158 days.fill( false ); 158 days.fill( false );
159 days.setBit( startDate.dayOfWeek() - 1 ); 159 days.setBit( startDate.dayOfWeek() - 1 );
160 r->addMonthlyPos( pos, days ); 160 r->addMonthlyPos( pos, days );
161 } else if ( rtype == "4" ) { 161 } else if ( rtype == "4" ) {
162 if ( hasEndDate ) 162 if ( hasEndDate )
163 r->setYearly( Recurrence::rYearlyMonth, freq, endDate ); 163 r->setYearly( Recurrence::rYearlyMonth, freq, endDate );
164 else 164 else
165 r->setYearly( Recurrence::rYearlyMonth, freq, -1 ); 165 r->setYearly( Recurrence::rYearlyMonth, freq, -1 );
166 r->addYearlyNum( startDate.month() ); 166 r->addYearlyNum( startDate.month() );
167 } 167 }
168 } else { 168 } else {
169 event->recurrence()->unsetRecurs(); 169 event->recurrence()->unsetRecurs();
170 } 170 }
171 171
172 QString categoryList = attList[1] ; 172 QString categoryList = attList[1] ;
173 event->setCategories( lookupCategories( categoryList ) ); 173 event->setCategories( lookupCategories( categoryList ) );
174 174
175 // strange 0 semms to mean: alarm enabled 175 // strange 0 semms to mean: alarm enabled
176 if ( attList[8] == "0" ) { 176 if ( attList[8] == "0" ) {
177 Alarm *alarm; 177 Alarm *alarm;
178 if ( event->alarms().count() > 0 ) 178 if ( event->alarms().count() > 0 )
179 alarm = event->alarms().first(); 179 alarm = event->alarms().first();
180 else { 180 else {
181 alarm = new Alarm( event ); 181 alarm = new Alarm( event );
182 event->addAlarm( alarm ); 182 event->addAlarm( alarm );
183 alarm->setType( Alarm::Audio );
183 } 184 }
184 alarm->setType( Alarm::Audio ); 185 //alarm->setType( Alarm::Audio );
185 alarm->setEnabled( true ); 186 alarm->setEnabled( true );
186 int alarmOffset = attList[9].toInt(); 187 int alarmOffset = attList[9].toInt();
187 alarm->setStartOffset( alarmOffset * -60 ); 188 alarm->setStartOffset( alarmOffset * -60 );
188 } else { 189 } else {
189 Alarm *alarm; 190 Alarm *alarm;
190 if ( event->alarms().count() > 0 ) { 191 if ( event->alarms().count() > 0 ) {
191 alarm = event->alarms().first(); 192 alarm = event->alarms().first();
192 alarm->setType( Alarm::Audio ); 193 alarm->setType( Alarm::Audio );
193 alarm->setStartOffset( -60*15 ); 194 alarm->setStartOffset( -60*15 );
194 alarm->setEnabled( false ); 195 alarm->setEnabled( false );
195 } 196 }
196 } 197 }
197 198
198 mCalendar->addEvent( event); 199 mCalendar->addEvent( event);
199 } else if ( qName == "Todo" ) { 200 } else if ( qName == "Todo" ) {
200 Todo *todo; 201 Todo *todo;
201 202
202 todo = existingCalendar->todo( "Sharp_DTM", attList[0] ); 203 todo = existingCalendar->todo( "Sharp_DTM", attList[0] );
203 if (todo ) 204 if (todo )
204 todo = (Todo*)todo->clone(); 205 todo = (Todo*)todo->clone();
205 else 206 else
206 todo = new Todo; 207 todo = new Todo;
207 208
208//CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1 209//CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1
209// 0 1 2 3 4 5 6 7 8 210// 0 1 2 3 4 5 6 7 8
210//1,,,,,1,4,Loch zumachen,"" 211//1,,,,,1,4,Loch zumachen,""
211//3,Privat,20040317T000000,20040318T000000,20040319T000000,0,5,Call bbb,"notes123 bbb gggg ""bb "" " 212//3,Privat,20040317T000000,20040318T000000,20040319T000000,0,5,Call bbb,"notes123 bbb gggg ""bb "" "
212//2,"Familie,Freunde,Holiday",20040318T000000,20040324T000000,20040317T000000,1,2,tod2,notes 213//2,"Familie,Freunde,Holiday",20040318T000000,20040324T000000,20040317T000000,1,2,tod2,notes
213 214
214 todo->setID( "Sharp_DTM", attList[0]); 215 todo->setID( "Sharp_DTM", attList[0]);
215 todo->setCsum( "Sharp_DTM", QString::number( cSum )); 216 todo->setCsum( "Sharp_DTM", QString::number( cSum ));
216 todo->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL ); 217 todo->setTempSyncStat( SYNC_TEMPSTATE_NEW_EXTERNAL );
217 218
218 todo->setSummary( attList[7] ); 219 todo->setSummary( attList[7] );
219 todo->setDescription( attList[8]); 220 todo->setDescription( attList[8]);
220 221
221 int priority = attList[6].toInt(); 222 int priority = attList[6].toInt();
222 if ( priority == 0 ) priority = 3; 223 if ( priority == 0 ) priority = 3;
223 todo->setPriority( priority ); 224 todo->setPriority( priority );
224 225
225 QString categoryList = attList[1]; 226 QString categoryList = attList[1];
226 todo->setCategories( lookupCategories( categoryList ) ); 227 todo->setCategories( lookupCategories( categoryList ) );
227 228
228 229
229 230
230 QString hasDateStr = attList[3]; // due 231 QString hasDateStr = attList[3]; // due
231 if ( !hasDateStr.isEmpty() ) { 232 if ( !hasDateStr.isEmpty() ) {
232 if ( hasDateStr.right(6) == "000000" ) { 233 if ( hasDateStr.right(6) == "000000" ) {
233 todo->setDtDue( QDateTime(fromString( hasDateStr, false ).date(), QTime(0,0,0 )) ); 234 todo->setDtDue( QDateTime(fromString( hasDateStr, false ).date(), QTime(0,0,0 )) );
234 todo->setFloats( true ); 235 todo->setFloats( true );
235 } 236 }
236 else { 237 else {
237 todo->setDtDue( fromString( hasDateStr ) ); 238 todo->setDtDue( fromString( hasDateStr ) );
238 todo->setFloats( false ); 239 todo->setFloats( false );
239 } 240 }
240 241
241 todo->setHasDueDate( true ); 242 todo->setHasDueDate( true );
242 } 243 }
243 hasDateStr = attList[2];//start 244 hasDateStr = attList[2];//start
244 if ( !hasDateStr.isEmpty() ) { 245 if ( !hasDateStr.isEmpty() ) {
245 246
246 todo->setDtStart( fromString( hasDateStr ) ); 247 todo->setDtStart( fromString( hasDateStr ) );
247 todo->setHasStartDate( true); 248 todo->setHasStartDate( true);
248 } else 249 } else
249 todo->setHasStartDate( false ); 250 todo->setHasStartDate( false );
250 hasDateStr = attList[4];//completed 251 hasDateStr = attList[4];//completed
251 if ( !hasDateStr.isEmpty() ) { 252 if ( !hasDateStr.isEmpty() ) {
252 todo->setCompleted(fromString( hasDateStr ) ); 253 todo->setCompleted(fromString( hasDateStr ) );
253 } 254 }
254 QString completedStr = attList[5]; 255 QString completedStr = attList[5];
255 if ( completedStr == "0" ) 256 if ( completedStr == "0" )
256 todo->setCompleted( true ); 257 todo->setCompleted( true );
257 else 258 else
258 todo->setCompleted( false ); 259 todo->setCompleted( false );
259 mCalendar->addTodo( todo ); 260 mCalendar->addTodo( todo );
260 261
261 } else if ( qName == "Category" ) { 262 } else if ( qName == "Category" ) {
262 /* 263 /*
263 QString id = attributes.value( "id" ); 264 QString id = attributes.value( "id" );
264 QString name = attributes.value( "name" ); 265 QString name = attributes.value( "name" );
265 setCategory( id, name ); 266 setCategory( id, name );
266 */ 267 */
267 } 268 }
268 //qDebug("end "); 269 //qDebug("end ");
269 return true; 270 return true;
270 } 271 }
271 272
272 273
273 void setCategoriesList ( QStringList * c ) 274 void setCategoriesList ( QStringList * c )
274 { 275 {
275 oldCategories = c; 276 oldCategories = c;
276 } 277 }
277 278
278 QDateTime fromString ( QString s, bool useTz = true ) { 279 QDateTime fromString ( QString s, bool useTz = true ) {
279 QDateTime dt; 280 QDateTime dt;
280 int y,m,t,h,min,sec; 281 int y,m,t,h,min,sec;
281 y = s.mid(0,4).toInt(); 282 y = s.mid(0,4).toInt();
282 m = s.mid(4,2).toInt(); 283 m = s.mid(4,2).toInt();
283 t = s.mid(6,2).toInt(); 284 t = s.mid(6,2).toInt();
284 h = s.mid(9,2).toInt(); 285 h = s.mid(9,2).toInt();
285 min = s.mid(11,2).toInt(); 286 min = s.mid(11,2).toInt();
286 sec = s.mid(13,2).toInt(); 287 sec = s.mid(13,2).toInt();
287 dt = QDateTime(QDate(y,m,t), QTime(h,min,sec)); 288 dt = QDateTime(QDate(y,m,t), QTime(h,min,sec));
288 int offset = KGlobal::locale()->localTimeOffset( dt ); 289 int offset = KGlobal::locale()->localTimeOffset( dt );
289 if ( useTz ) 290 if ( useTz )
290 dt = dt.addSecs ( offset*60); 291 dt = dt.addSecs ( offset*60);
291 return dt; 292 return dt;
292 293
293 } 294 }
294 protected: 295 protected:
295 QDateTime toDateTime( const QString &value ) 296 QDateTime toDateTime( const QString &value )
296 { 297 {
297 QDateTime dt; 298 QDateTime dt;
298 dt.setTime_t( value.toUInt() ); 299 dt.setTime_t( value.toUInt() );
299 300
300 return dt; 301 return dt;
301 } 302 }
302 303
303 QStringList lookupCategories( const QString &categoryList ) 304 QStringList lookupCategories( const QString &categoryList )
304 { 305 {
305 QStringList categoryIds = QStringList::split( ";", categoryList ); 306 QStringList categoryIds = QStringList::split( ";", categoryList );
306 QStringList categories; 307 QStringList categories;
307 QStringList::ConstIterator it; 308 QStringList::ConstIterator it;
308 for( it = categoryIds.begin(); it != categoryIds.end(); ++it ) { 309 for( it = categoryIds.begin(); it != categoryIds.end(); ++it ) {
309 QString cate = category( *it ); 310 QString cate = category( *it );
310 if ( oldCategories ) { 311 if ( oldCategories ) {
311 if ( ! oldCategories->contains( cate ) ) 312 if ( ! oldCategories->contains( cate ) )
312 oldCategories->append( cate ); 313 oldCategories->append( cate );
313 } 314 }
314 categories.append(cate ); 315 categories.append(cate );
315 } 316 }
316 return categories; 317 return categories;
317 } 318 }
318 319
319 private: 320 private:
320 Calendar *mCalendar; 321 Calendar *mCalendar;
321 QStringList * oldCategories; 322 QStringList * oldCategories;
322 static QString category( const QString &id ) 323 static QString category( const QString &id )
323 { 324 {
324 QMap<QString,QString>::ConstIterator it = mCategoriesMap.find( id ); 325 QMap<QString,QString>::ConstIterator it = mCategoriesMap.find( id );
325 if ( it == mCategoriesMap.end() ) return id; 326 if ( it == mCategoriesMap.end() ) return id;
326 else return *it; 327 else return *it;
327 } 328 }
328 329
329 static void setCategory( const QString &id, const QString &name ) 330 static void setCategory( const QString &id, const QString &name )
330 { 331 {
331 mCategoriesMap.insert( id, name ); 332 mCategoriesMap.insert( id, name );
332 } 333 }
333 334
334 static QMap<QString,QString> mCategoriesMap; 335 static QMap<QString,QString> mCategoriesMap;
335}; 336};
336 337
337QMap<QString,QString> SharpParser::mCategoriesMap; 338QMap<QString,QString> SharpParser::mCategoriesMap;
338 339
339SharpFormat::SharpFormat() 340SharpFormat::SharpFormat()
340{ 341{
341 mCategories = 0; 342 mCategories = 0;
342} 343}
343 344
344SharpFormat::~SharpFormat() 345SharpFormat::~SharpFormat()
345{ 346{
346} 347}
347ulong SharpFormat::getCsum( const QStringList & attList) 348ulong SharpFormat::getCsum( const QStringList & attList)
348{ 349{
349 int max = attList.count() -1; 350 int max = attList.count() -1;
350 ulong cSum = 0; 351 ulong cSum = 0;
351 int j,k,i; 352 int j,k,i;
352 int add; 353 int add;
353 for ( i = 1; i < max ; ++i ) { 354 for ( i = 1; i < max ; ++i ) {
354 QString s = attList[i]; 355 QString s = attList[i];
355 if ( ! s.isEmpty() ){ 356 if ( ! s.isEmpty() ){
356 j = s.length(); 357 j = s.length();
357 for ( k = 0; k < j; ++k ) { 358 for ( k = 0; k < j; ++k ) {
358 int mul = k +1; 359 int mul = k +1;
359 add = s[k].unicode (); 360 add = s[k].unicode ();
360 if ( k < 16 ) 361 if ( k < 16 )
361 mul = mul * mul; 362 mul = mul * mul;
362 add = add * mul *i*i*i; 363 add = add * mul *i*i*i;
363 cSum += add; 364 cSum += add;
364 } 365 }
365 } 366 }
366 } 367 }
367 return cSum; 368 return cSum;
368 369
369} 370}
370#include <stdlib.h> 371#include <stdlib.h>
371#define DEBUGMODE false 372//#define DEBUGMODE false
373#define DEBUGMODE true
372bool SharpFormat::load( Calendar *calendar, Calendar *existngCal ) 374bool SharpFormat::load( Calendar *calendar, Calendar *existngCal )
373{ 375{
374 376
375 377
376 bool debug = DEBUGMODE; 378 bool debug = DEBUGMODE;
377 //debug = true;
378 QString text; 379 QString text;
379 QString codec = "utf8"; 380 QString codec = "utf8";
380 QLabel status ( i18n("Reading events ..."), 0 ); 381 QLabel status ( i18n("Reading events ..."), 0 );
381 382
382 int w = status.sizeHint().width()+20 ; 383 int w = status.sizeHint().width()+20 ;
383 if ( w < 200 ) w = 200; 384 if ( w < 200 ) w = 200;
384 int h = status.sizeHint().height()+20 ; 385 int h = status.sizeHint().height()+20 ;
385 int dw = QApplication::desktop()->width(); 386 int dw = QApplication::desktop()->width();
386 int dh = QApplication::desktop()->height(); 387 int dh = QApplication::desktop()->height();
387 status.setCaption(i18n("Reading DTM Data") ); 388 status.setCaption(i18n("Reading DTM Data") );
388 status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); 389 status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
389 status.show(); 390 status.show();
390 status.raise(); 391 status.raise();
391 qApp->processEvents(); 392 qApp->processEvents();
392 QString fileName; 393 QString fileName;
393 if ( ! debug ) { 394 if ( ! debug ) {
394 fileName = "/tmp/kopitempout"; 395 fileName = "/tmp/kopitempout";
395 QString command ="db2file datebook -r -c "+ codec + " > " + fileName; 396 QString command ="db2file datebook -r -c "+ codec + " > " + fileName;
396 system ( command.latin1() ); 397 system ( command.latin1() );
397 } else { 398 } else {
398 fileName = "/tmp/events.txt"; 399 fileName = "/tmp/events.txt";
399 400
400 } 401 }
401 QFile file( fileName ); 402 QFile file( fileName );
402 if (!file.open( IO_ReadOnly ) ) { 403 if (!file.open( IO_ReadOnly ) ) {
403 return false; 404 return false;
404 405
405 } 406 }
406 QTextStream ts( &file ); 407 QTextStream ts( &file );
407 ts.setCodec( QTextCodec::codecForName("utf8") ); 408 ts.setCodec( QTextCodec::codecForName("utf8") );
408 text = ts.read(); 409 text = ts.read();
409 file.close(); 410 file.close();
410 status.setText( i18n("Processing events ...") ); 411 status.setText( i18n("Processing events ...") );
411 status.raise(); 412 status.raise();
412 qApp->processEvents(); 413 qApp->processEvents();
413 fromString2Cal( calendar, existngCal, text, "Event" ); 414 fromString2Cal( calendar, existngCal, text, "Event" );
414 status.setText( i18n("Reading todos ...") ); 415 status.setText( i18n("Reading todos ...") );
415 qApp->processEvents(); 416 qApp->processEvents();
416 if ( ! debug ) { 417 if ( ! debug ) {
417 fileName = "/tmp/kopitempout"; 418 fileName = "/tmp/kopitempout";
418 QString command = "db2file todo -r -c " + codec+ " > " + fileName; 419 QString command = "db2file todo -r -c " + codec+ " > " + fileName;
419 system ( command.latin1() ); 420 system ( command.latin1() );
420 } else { 421 } else {
421 fileName = "/tmp/todo.txt"; 422 fileName = "/tmp/todo.txt";
422 } 423 }
423 file.setName( fileName ); 424 file.setName( fileName );
424 if (!file.open( IO_ReadOnly ) ) { 425 if (!file.open( IO_ReadOnly ) ) {
425 return false; 426 return false;
426 427
427 } 428 }
428 ts.setDevice( &file ); 429 ts.setDevice( &file );
429 text = ts.read(); 430 text = ts.read();
430 file.close(); 431 file.close();
431 432
432 status.setText( i18n("Processing todos ...") ); 433 status.setText( i18n("Processing todos ...") );
433 status.raise(); 434 status.raise();
434 qApp->processEvents(); 435 qApp->processEvents();
435 fromString2Cal( calendar, existngCal, text, "Todo" ); 436 fromString2Cal( calendar, existngCal, text, "Todo" );
436 return true; 437 return true;
437} 438}
438int SharpFormat::getNumFromRecord( QString answer, Incidence* inc ) 439int SharpFormat::getNumFromRecord( QString answer, Incidence* inc )
439{ 440{
440 int retval = -1; 441 int retval = -1;
441 QStringList templist; 442 QStringList templist;
442 QString tempString; 443 QString tempString;
443 int start = 0; 444 int start = 0;
444 int len = answer.length(); 445 int len = answer.length();
445 int end = answer.find ("\n",start)+1; 446 int end = answer.find ("\n",start)+1;
446 bool ok = true; 447 bool ok = true;
447 start = end; 448 start = end;
448 int ccc = 0; 449 int ccc = 0;
449 while ( start > 0 ) { 450 while ( start > 0 ) {
450 templist.clear(); 451 templist.clear();
451 ok = true; 452 ok = true;
452 int loopCount = 0; 453 int loopCount = 0;
453 while ( ok ) { 454 while ( ok ) {
454 ++loopCount; 455 ++loopCount;
455 if ( loopCount > 25 ) { 456 if ( loopCount > 25 ) {
456 qDebug("KO: Error in while loop"); 457 qDebug("KO: Error in while loop");
457 ok = false; 458 ok = false;
458 start = 0; 459 start = 0;
459 break; 460 break;
460 } 461 }
461 if ( ok ) 462 if ( ok )
462 tempString = getPart( answer, ok, start ); 463 tempString = getPart( answer, ok, start );
463 if ( start >= len || start == 0 ) { 464 if ( start >= len || start == 0 ) {
464 start = 0; 465 start = 0;
465 ok = false; 466 ok = false;
466 } 467 }
467 if ( tempString.right(1) =="\n" ) 468 if ( tempString.right(1) =="\n" )
468 tempString = tempString.left( tempString.length()-1); 469 tempString = tempString.left( tempString.length()-1);
469 470
470 templist.append( tempString ); 471 templist.append( tempString );
471 } 472 }
472 ++ccc; 473 ++ccc;
473 if ( ccc == 2 && loopCount < 25 ) { 474 if ( ccc == 2 && loopCount < 25 ) {
474 start = 0; 475 start = 0;
475 bool ok; 476 bool ok;
476 int newnum = templist[0].toInt( &ok ); 477 int newnum = templist[0].toInt( &ok );
477 if ( ok && newnum > 0) { 478 if ( ok && newnum > 0) {
478 retval = newnum; 479 retval = newnum;
479 inc->setID( "Sharp_DTM",templist[0] ); 480 inc->setID( "Sharp_DTM",templist[0] );
480 inc->setCsum( "Sharp_DTM", QString::number( getCsum( templist ) )); 481 inc->setCsum( "Sharp_DTM", QString::number( getCsum( templist ) ));
481 inc->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID ); 482 inc->setTempSyncStat( SYNC_TEMPSTATE_NEW_ID );
482 } 483 }
483 } 484 }
484 } 485 }
485 //qDebug("getNumFromRecord returning : %d ", retval); 486 //qDebug("getNumFromRecord returning : %d ", retval);
486 return retval; 487 return retval;
487} 488}
488bool SharpFormat::save( Calendar *calendar) 489bool SharpFormat::save( Calendar *calendar)
489{ 490{
490 491
491 QLabel status ( i18n("Processing/adding events ..."), 0 ); 492 QLabel status ( i18n("Processing/adding events ..."), 0 );
492 int w = status.sizeHint().width()+20 ; 493 int w = status.sizeHint().width()+20 ;
493 if ( w < 200 ) w = 200; 494 if ( w < 200 ) w = 200;
494 int h = status.sizeHint().height()+20 ; 495 int h = status.sizeHint().height()+20 ;
495 int dw = QApplication::desktop()->width(); 496 int dw = QApplication::desktop()->width();
496 int dh = QApplication::desktop()->height(); 497 int dh = QApplication::desktop()->height();
497 status.setCaption(i18n("Writing DTM Data") ); 498 status.setCaption(i18n("Writing DTM Data") );
498 status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); 499 status.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
499 status.show(); 500 status.show();
500 status.raise(); 501 status.raise();
501 qApp->processEvents(); 502 qApp->processEvents();
502 bool debug = DEBUGMODE; 503 bool debug = DEBUGMODE;
503 QString codec = "utf8"; 504 QString codec = "utf8";
504 QString answer; 505 QString answer;
505 QString ePrefix = "CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY\n"; 506 QString ePrefix = "CARDID,CATEGORY,DSRP,PLCE,MEM1,TIM1,TIM2,ADAY,ARON,ARMN,ARSD,RTYP,RFRQ,RPOS,RDYS,REND,REDT,ALSD,ALED,MDAY\n";
506 QString tPrefix = "CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1\n"; 507 QString tPrefix = "CARDID,CATEGORY,ETDY,LTDY,FNDY,MARK,PRTY,TITL,MEM1\n";
507 QString command; 508 QString command;
508 QPtrList<Event> er = calendar->rawEvents(); 509 QPtrList<Event> er = calendar->rawEvents();
509 Event* ev = er.first(); 510 Event* ev = er.first();
510 QString fileName = "/tmp/kopitempout"; 511 QString fileName = "/tmp/kopitempout";
511 int i = 0; 512 int i = 0;
512 QString changeString = ePrefix; 513 QString changeString = ePrefix;
513 QString deleteString = ePrefix; 514 QString deleteString = ePrefix;
514 bool deleteEnt = false; 515 bool deleteEnt = false;
515 bool changeEnt = false; 516 bool changeEnt = false;
516 QString message = i18n("Processing event # "); 517 QString message = i18n("Processing event # ");
517 int procCount = 0; 518 int procCount = 0;
518 while ( ev ) { 519 while ( ev ) {
519 //qDebug("i %d ", ++i); 520 //qDebug("i %d ", ++i);
520 if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { 521 if ( ev->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) {
521 status.setText ( message + QString::number ( ++procCount ) ); 522 status.setText ( message + QString::number ( ++procCount ) );
522 qApp->processEvents(); 523 qApp->processEvents();
523 QString eString = getEventString( ev ); 524 QString eString = getEventString( ev );
524 if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete 525 if ( ev->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete
525 // deleting empty strings does not work. 526 // deleting empty strings does not work.
526 // we write first and x and then delete the record with the x 527 // we write first and x and then delete the record with the x
527 eString = eString.replace( QRegExp(",\"\""),",\"x\"" ); 528 eString = eString.replace( QRegExp(",\"\""),",\"x\"" );
528 changeString += eString + "\n"; 529 changeString += eString + "\n";
529 deleteString += eString + "\n"; 530 deleteString += eString + "\n";
530 deleteEnt = true; 531 deleteEnt = true;
531 changeEnt = true; 532 changeEnt = true;
532 } 533 }
533 else if ( ev->getID("Sharp_DTM").isEmpty() ) { // add new 534 else if ( ev->getID("Sharp_DTM").isEmpty() ) { // add new
534 command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName; 535 command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
535 system ( command.utf8() ); 536 system ( command.utf8() );
536 QFile file( fileName ); 537 QFile file( fileName );
537 if (!file.open( IO_ReadOnly ) ) { 538 if (!file.open( IO_ReadOnly ) ) {
538 return false; 539 return false;
539 540
540 } 541 }
541 QTextStream ts( &file ); 542 QTextStream ts( &file );
542 ts.setCodec( QTextCodec::codecForName("utf8") ); 543 ts.setCodec( QTextCodec::codecForName("utf8") );
543 answer = ts.read(); 544 answer = ts.read();
544 file.close(); 545 file.close();
545 //qDebug("answer \n%s ", answer.latin1()); 546 //qDebug("answer \n%s ", answer.latin1());
546 getNumFromRecord( answer, ev ) ; 547 getNumFromRecord( answer, ev ) ;
547 548
548 } 549 }
549 else { // change existing 550 else { // change existing
550 //qDebug("canging %d %d",ev->zaurusStat() ,ev->zaurusId() ); 551 //qDebug("canging %d %d",ev->zaurusStat() ,ev->zaurusId() );
551 //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName; 552 //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
552 changeString += eString + "\n"; 553 changeString += eString + "\n";
553 changeEnt = true; 554 changeEnt = true;
554 555
555 } 556 }
556 } 557 }
557 ev = er.next(); 558 ev = er.next();
558 } 559 }
559 status.setText ( i18n("Changing events ...") ); 560 status.setText ( i18n("Changing events ...") );
560 qApp->processEvents(); 561 qApp->processEvents();
561 //qDebug("changing... "); 562 //qDebug("changing... ");
562 if ( changeEnt ) { 563 if ( changeEnt ) {
563 QFile file( fileName ); 564 QFile file( fileName );
564 if (!file.open( IO_WriteOnly ) ) { 565 if (!file.open( IO_WriteOnly ) ) {
565 return false; 566 return false;
566 567
567 } 568 }
568 QTextStream ts( &file ); 569 QTextStream ts( &file );
569 ts.setCodec( QTextCodec::codecForName("utf8") ); 570 ts.setCodec( QTextCodec::codecForName("utf8") );
570 ts << changeString ; 571 ts << changeString ;
571 file.close(); 572 file.close();
572 command = "db2file datebook -w -g -c " + codec+ " < "+ fileName; 573 command = "db2file datebook -w -g -c " + codec+ " < "+ fileName;
573 system ( command.latin1() ); 574 system ( command.latin1() );
574 //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1()); 575 //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1());
575 576
576 } 577 }
577 status.setText ( i18n("Deleting events ...") ); 578 status.setText ( i18n("Deleting events ...") );
578 qApp->processEvents(); 579 qApp->processEvents();
579 //qDebug("deleting... "); 580 //qDebug("deleting... ");
580 if ( deleteEnt ) { 581 if ( deleteEnt ) {
581 QFile file( fileName ); 582 QFile file( fileName );
582 if (!file.open( IO_WriteOnly ) ) { 583 if (!file.open( IO_WriteOnly ) ) {
583 return false; 584 return false;
584 585
585 } 586 }
586 QTextStream ts( &file ); 587 QTextStream ts( &file );
587 ts.setCodec( QTextCodec::codecForName("utf8") ); 588 ts.setCodec( QTextCodec::codecForName("utf8") );
588 ts << deleteString; 589 ts << deleteString;
589 file.close(); 590 file.close();
590 command = "db2file datebook -d -c " + codec+ " < "+ fileName; 591 command = "db2file datebook -d -c " + codec+ " < "+ fileName;
591 system ( command.latin1() ); 592 system ( command.latin1() );
592 // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1()); 593 // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1());
593 } 594 }
594 595
595 596
596 changeString = tPrefix; 597 changeString = tPrefix;
597 deleteString = tPrefix; 598 deleteString = tPrefix;
598 status.setText ( i18n("Processing todos ...") ); 599 status.setText ( i18n("Processing todos ...") );
599 qApp->processEvents(); 600 qApp->processEvents();
600 QPtrList<Todo> tl = calendar->rawTodos(); 601 QPtrList<Todo> tl = calendar->rawTodos();
601 Todo* to = tl.first(); 602 Todo* to = tl.first();
602 i = 0; 603 i = 0;
603 message = i18n("Processing todo # "); 604 message = i18n("Processing todo # ");
604 procCount = 0; 605 procCount = 0;
605 while ( to ) { 606 while ( to ) {
606 if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) { 607 if ( to->tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) {
607 status.setText ( message + QString::number ( ++procCount ) ); 608 status.setText ( message + QString::number ( ++procCount ) );
608 qApp->processEvents(); 609 qApp->processEvents();
609 QString eString = getTodoString( to ); 610 QString eString = getTodoString( to );
610 if ( to->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete 611 if ( to->tempSyncStat() == SYNC_TEMPSTATE_DELETE ) { // delete
611 // deleting empty strings does not work. 612 // deleting empty strings does not work.
612 // we write first and x and then delete the record with the x 613 // we write first and x and then delete the record with the x
613 eString = eString.replace( QRegExp(",\"\""),",\"x\"" ); 614 eString = eString.replace( QRegExp(",\"\""),",\"x\"" );
614 changeString += eString + "\n"; 615 changeString += eString + "\n";
615 deleteString += eString + "\n"; 616 deleteString += eString + "\n";
616 deleteEnt = true; 617 deleteEnt = true;
617 changeEnt = true; 618 changeEnt = true;
618 } 619 }
619 else if ( to->getID("Sharp_DTM").isEmpty() ) { // add new 620 else if ( to->getID("Sharp_DTM").isEmpty() ) { // add new
620 command = "(echo \"" + tPrefix + eString + "\" ) | db2file todo -w -g -c " + codec+ " > "+ fileName; 621 command = "(echo \"" + tPrefix + eString + "\" ) | db2file todo -w -g -c " + codec+ " > "+ fileName;
621 system ( command.utf8() ); 622 system ( command.utf8() );
622 QFile file( fileName ); 623 QFile file( fileName );
623 if (!file.open( IO_ReadOnly ) ) { 624 if (!file.open( IO_ReadOnly ) ) {
624 return false; 625 return false;
625 626
626 } 627 }
627 QTextStream ts( &file ); 628 QTextStream ts( &file );
628 ts.setCodec( QTextCodec::codecForName("utf8") ); 629 ts.setCodec( QTextCodec::codecForName("utf8") );
629 answer = ts.read(); 630 answer = ts.read();
630 file.close(); 631 file.close();
631 //qDebug("answer \n%s ", answer.latin1()); 632 //qDebug("answer \n%s ", answer.latin1());
632 getNumFromRecord( answer, to ) ; 633 getNumFromRecord( answer, to ) ;
633 634
634 } 635 }
635 else { // change existing 636 else { // change existing
636 //qDebug("canging %d %d",to->zaurusStat() ,to->zaurusId() ); 637 //qDebug("canging %d %d",to->zaurusStat() ,to->zaurusId() );
637 //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName; 638 //command = "(echo \"" + ePrefix + eString + "\" ) | db2file datebook -w -g -c " + codec+ " > "+ fileName;
638 changeString += eString + "\n"; 639 changeString += eString + "\n";
639 changeEnt = true; 640 changeEnt = true;
640 641
641 } 642 }
642 } 643 }
643 644
644 to = tl.next(); 645 to = tl.next();
645 } 646 }
646 status.setText ( i18n("Changing todos ...") ); 647 status.setText ( i18n("Changing todos ...") );
647 qApp->processEvents(); 648 qApp->processEvents();
648 //qDebug("changing... "); 649 //qDebug("changing... ");
649 if ( changeEnt ) { 650 if ( changeEnt ) {
650 QFile file( fileName ); 651 QFile file( fileName );
651 if (!file.open( IO_WriteOnly ) ) { 652 if (!file.open( IO_WriteOnly ) ) {
652 return false; 653 return false;
653 654
654 } 655 }
655 QTextStream ts( &file ); 656 QTextStream ts( &file );
656 ts.setCodec( QTextCodec::codecForName("utf8") ); 657 ts.setCodec( QTextCodec::codecForName("utf8") );
657 ts << changeString ; 658 ts << changeString ;
658 file.close(); 659 file.close();
659 command = "db2file todo -w -g -c " + codec+ " < "+ fileName; 660 command = "db2file todo -w -g -c " + codec+ " < "+ fileName;
660 system ( command.latin1() ); 661 system ( command.latin1() );
661 //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1()); 662 //qDebug("command %s file :\n%s ", command.latin1(), changeString.latin1());
662 663
663 } 664 }
664 status.setText ( i18n("Deleting todos ...") ); 665 status.setText ( i18n("Deleting todos ...") );
665 qApp->processEvents(); 666 qApp->processEvents();
666 //qDebug("deleting... "); 667 //qDebug("deleting... ");
667 if ( deleteEnt ) { 668 if ( deleteEnt ) {
668 QFile file( fileName ); 669 QFile file( fileName );
669 if (!file.open( IO_WriteOnly ) ) { 670 if (!file.open( IO_WriteOnly ) ) {
670 return false; 671 return false;
671 672
672 } 673 }
673 QTextStream ts( &file ); 674 QTextStream ts( &file );
674 ts.setCodec( QTextCodec::codecForName("utf8") ); 675 ts.setCodec( QTextCodec::codecForName("utf8") );
675 ts << deleteString; 676 ts << deleteString;
676 file.close(); 677 file.close();
677 command = "db2file todo -d -c " + codec+ " < "+ fileName; 678 command = "db2file todo -d -c " + codec+ " < "+ fileName;
678 system ( command.latin1() ); 679 system ( command.latin1() );
679 // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1()); 680 // qDebug("command %s file :\n%s ", command.latin1(), deleteString.latin1());
680 } 681 }
681 682
682 return true; 683 return true;
683} 684}
684QString SharpFormat::dtToString( const QDateTime& dti, bool useTZ ) 685QString SharpFormat::dtToString( const QDateTime& dti, bool useTZ )
685{ 686{
686 QString datestr; 687 QString datestr;
687 QString timestr; 688 QString timestr;
688 int offset = KGlobal::locale()->localTimeOffset( dti ); 689 int offset = KGlobal::locale()->localTimeOffset( dti );
689 QDateTime dt; 690 QDateTime dt;
690 if (useTZ) 691 if (useTZ)
691 dt = dti.addSecs ( -(offset*60)); 692 dt = dti.addSecs ( -(offset*60));
692 else 693 else
693 dt = dti; 694 dt = dti;
694 if(dt.date().isValid()){ 695 if(dt.date().isValid()){
695 const QDate& date = dt.date(); 696 const QDate& date = dt.date();
696 datestr.sprintf("%04d%02d%02d", 697 datestr.sprintf("%04d%02d%02d",
697 date.year(), date.month(), date.day()); 698 date.year(), date.month(), date.day());
698 } 699 }
699 if(dt.time().isValid()){ 700 if(dt.time().isValid()){
700 const QTime& time = dt.time(); 701 const QTime& time = dt.time();
701 timestr.sprintf("T%02d%02d%02d", 702 timestr.sprintf("T%02d%02d%02d",
702 time.hour(), time.minute(), time.second()); 703 time.hour(), time.minute(), time.second());
703 } 704 }
704 return datestr + timestr; 705 return datestr + timestr;
705} 706}
706QString SharpFormat::getEventString( Event* event ) 707QString SharpFormat::getEventString( Event* event )
707{ 708{
708 QStringList list; 709 QStringList list;
709 list.append( event->getID("Sharp_DTM") ); 710 list.append( event->getID("Sharp_DTM") );
710 list.append( event->categories().join(",") ); 711 list.append( event->categories().join(",") );
711 if ( !event->summary().isEmpty() ) 712 if ( !event->summary().isEmpty() )
712 list.append( event->summary() ); 713 list.append( event->summary() );
713 else 714 else
714 list.append("" ); 715 list.append("" );
715 if ( !event->location().isEmpty() ) 716 if ( !event->location().isEmpty() )
716 list.append( event->location() ); 717 list.append( event->location() );
717 else 718 else
718 list.append("" ); 719 list.append("" );
719 if ( !event->description().isEmpty() ) 720 if ( !event->description().isEmpty() )
720 list.append( event->description() ); 721 list.append( event->description() );
721 else 722 else
722 list.append( "" ); 723 list.append( "" );
723 if ( event->doesFloat () ) { 724 if ( event->doesFloat () ) {
724 list.append( dtToString( QDateTime(event->dtStart().date(), QTime(0,0,0)), false )); 725 list.append( dtToString( QDateTime(event->dtStart().date(), QTime(0,0,0)), false ));
725 list.append( dtToString( QDateTime(event->dtEnd().date(),QTime(23,59,59)), false )); //6 726 list.append( dtToString( QDateTime(event->dtEnd().date(),QTime(23,59,59)), false )); //6
726 list.append( "1" ); 727 list.append( "1" );
727 728
728 } 729 }
729 else { 730 else {
730 list.append( dtToString( event->dtStart()) ); 731 list.append( dtToString( event->dtStart()) );
731 list.append( dtToString( event->dtEnd()) ); //6 732 list.append( dtToString( event->dtEnd()) ); //6
732 list.append( "0" ); 733 list.append( "0" );
733 } 734 }
734 bool noAlarm = true; 735 bool noAlarm = true;
735 if ( event->alarms().count() > 0 ) { 736 if ( event->alarms().count() > 0 ) {
736 Alarm * al = event->alarms().first(); 737 Alarm * al = event->alarms().first();
737 if ( al->enabled() ) { 738 if ( al->enabled() ) {
738 noAlarm = false; 739 noAlarm = false;
739 list.append( "0" ); // yes, 0 == alarm 740 list.append( "0" ); // yes, 0 == alarm
740 list.append( QString::number( al->startOffset().asSeconds()/(-60) ) ); 741 list.append( QString::number( al->startOffset().asSeconds()/(-60) ) );
741 if ( al->type() == Alarm::Audio ) 742 if ( al->type() == Alarm::Audio )
742 list.append( "1" ); // type audio 743 list.append( "1" ); // type audio
743 else 744 else
744 list.append( "0" ); // type silent 745 list.append( "0" ); // type silent
745 } 746 }
746 } 747 }
747 if ( noAlarm ) { 748 if ( noAlarm ) {
748 list.append( "1" ); // yes, 1 == no alarm 749 list.append( "1" ); // yes, 1 == no alarm
749 list.append( "0" ); // no alarm offset 750 list.append( "0" ); // no alarm offset
750 list.append( "1" ); // type 751 list.append( "1" ); // type
751 } 752 }
752 // next is: 11 753 // next is: 11
753 // next is: 11-16 are recurrence 754 // next is: 11-16 are recurrence
754 Recurrence* rec = event->recurrence(); 755 Recurrence* rec = event->recurrence();
755 756
756 bool writeEndDate = false; 757 bool writeEndDate = false;
757 switch ( rec->doesRecur() ) 758 switch ( rec->doesRecur() )
758 { 759 {
759 case Recurrence::rDaily: // 0 760 case Recurrence::rDaily: // 0
760 list.append( "0" ); 761 list.append( "0" );
761 list.append( QString::number( rec->frequency() ));//12 762 list.append( QString::number( rec->frequency() ));//12
762 list.append( "0" ); 763 list.append( "0" );
763 list.append( "0" ); 764 list.append( "0" );
764 writeEndDate = true; 765 writeEndDate = true;
765 break; 766 break;
766 case Recurrence::rWeekly:// 1 767 case Recurrence::rWeekly:// 1
767 list.append( "1" ); 768 list.append( "1" );
768 list.append( QString::number( rec->frequency()) );//12 769 list.append( QString::number( rec->frequency()) );//12
769 list.append( "0" ); 770 list.append( "0" );
770 { 771 {
771 int days = 0; 772 int days = 0;
772 QBitArray weekDays = rec->days(); 773 QBitArray weekDays = rec->days();
773 int i; 774 int i;
774 for( i = 1; i <= 7; ++i ) { 775 for( i = 1; i <= 7; ++i ) {
775 if ( weekDays[i-1] ) { 776 if ( weekDays[i-1] ) {
776 days += 1 << (i-1); 777 days += 1 << (i-1);
777 } 778 }
778 } 779 }
779 list.append( QString::number( days ) ); 780 list.append( QString::number( days ) );
780 } 781 }
781 //pending weekdays 782 //pending weekdays
782 writeEndDate = true; 783 writeEndDate = true;
783 784
784 break; 785 break;
785 case Recurrence::rMonthlyPos:// 2 786 case Recurrence::rMonthlyPos:// 2
786 list.append( "2" ); 787 list.append( "2" );
787 list.append( QString::number( rec->frequency()) );//12 788 list.append( QString::number( rec->frequency()) );//12
788 789
789 writeEndDate = true; 790 writeEndDate = true;
790 { 791 {
791 int count = 1; 792 int count = 1;
792 QPtrList<Recurrence::rMonthPos> rmp; 793 QPtrList<Recurrence::rMonthPos> rmp;
793 rmp = rec->monthPositions(); 794 rmp = rec->monthPositions();
794 if ( rmp.first()->negative ) 795 if ( rmp.first()->negative )
795 count = 5 - rmp.first()->rPos - 1; 796 count = 5 - rmp.first()->rPos - 1;
796 else 797 else
797 count = rmp.first()->rPos - 1; 798 count = rmp.first()->rPos - 1;
798 list.append( QString::number( count ) ); 799 list.append( QString::number( count ) );
799 800
800 } 801 }
801 802
802 list.append( "0" ); 803 list.append( "0" );
803 break; 804 break;
804 case Recurrence::rMonthlyDay:// 3 805 case Recurrence::rMonthlyDay:// 3
805 list.append( "3" ); 806 list.append( "3" );
806 list.append( QString::number( rec->frequency()) );//12 807 list.append( QString::number( rec->frequency()) );//12
807 list.append( "0" ); 808 list.append( "0" );
808 list.append( "0" ); 809 list.append( "0" );
809 writeEndDate = true; 810 writeEndDate = true;
810 break; 811 break;
811 case Recurrence::rYearlyMonth://4 812 case Recurrence::rYearlyMonth://4
812 list.append( "4" ); 813 list.append( "4" );
813 list.append( QString::number( rec->frequency()) );//12 814 list.append( QString::number( rec->frequency()) );//12
814 list.append( "0" ); 815 list.append( "0" );
815 list.append( "0" ); 816 list.append( "0" );
816 writeEndDate = true; 817 writeEndDate = true;
817 break; 818 break;
818 819
819 default: 820 default:
820 list.append( "255" ); 821 list.append( "255" );
821 list.append( QString() ); 822 list.append( QString() );
822 list.append( "0" ); 823 list.append( "0" );
823 list.append( QString() ); 824 list.append( QString() );
824 list.append( "0" ); 825 list.append( "0" );
825 list.append( "20991231T000000" ); 826 list.append( "20991231T000000" );
826 break; 827 break;
827 } 828 }
828 if ( writeEndDate ) { 829 if ( writeEndDate ) {
829 830
830 if ( rec->endDate().isValid() ) { // 15 + 16 831 if ( rec->endDate().isValid() ) { // 15 + 16
831 list.append( "1" ); 832 list.append( "1" );
832 list.append( dtToString( rec->endDate()) ); 833 list.append( dtToString( rec->endDate()) );
833 } else { 834 } else {
834 list.append( "0" ); 835 list.append( "0" );
835 list.append( "20991231T000000" ); 836 list.append( "20991231T000000" );
836 } 837 }
837 838
838 } 839 }
839 if ( event->doesFloat () ) { 840 if ( event->doesFloat () ) {
840 list.append( dtToString( event->dtStart(), false ).left( 8 )); 841 list.append( dtToString( event->dtStart(), false ).left( 8 ));
841 list.append( dtToString( event->dtEnd(), false ).left( 8 )); //6 842 list.append( dtToString( event->dtEnd(), false ).left( 8 )); //6
842 843
843 } 844 }
844 else { 845 else {
845 list.append( QString() ); 846 list.append( QString() );
846 list.append( QString() ); 847 list.append( QString() );
847 848
848 } 849 }
849 if (event->dtStart().date() == event->dtEnd().date() ) 850 if (event->dtStart().date() == event->dtEnd().date() )
850 list.append( "0" ); 851 list.append( "0" );
851 else 852 else
852 list.append( "1" ); 853 list.append( "1" );
853 854
854 855
855 for(QStringList::Iterator it=list.begin(); 856 for(QStringList::Iterator it=list.begin();
856 it!=list.end(); ++it){ 857 it!=list.end(); ++it){
857 QString& s = (*it); 858 QString& s = (*it);
858 s.replace(QRegExp("\""), "\"\""); 859 s.replace(QRegExp("\""), "\"\"");
859 if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){ 860 if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){
860 s.prepend('\"'); 861 s.prepend('\"');
861 s.append('\"'); 862 s.append('\"');
862 } else if(s.isEmpty() && !s.isNull()){ 863 } else if(s.isEmpty() && !s.isNull()){
863 s = "\"\""; 864 s = "\"\"";
864 } 865 }
865 } 866 }
866 return list.join(","); 867 return list.join(",");
867 868
868 869
869} 870}
870QString SharpFormat::getTodoString( Todo* todo ) 871QString SharpFormat::getTodoString( Todo* todo )
871{ 872{
872 QStringList list; 873 QStringList list;
873 list.append( todo->getID("Sharp_DTM") ); 874 list.append( todo->getID("Sharp_DTM") );
874 list.append( todo->categories().join(",") ); 875 list.append( todo->categories().join(",") );
875 876
876 if ( todo->hasStartDate() ) { 877 if ( todo->hasStartDate() ) {
877 list.append( dtToString( todo->dtStart()) ); 878 list.append( dtToString( todo->dtStart()) );
878 } else 879 } else
879 list.append( QString() ); 880 list.append( QString() );
880 881
881 if ( todo->hasDueDate() ) { 882 if ( todo->hasDueDate() ) {
882 QTime tim; 883 QTime tim;
883 if ( todo->doesFloat()) { 884 if ( todo->doesFloat()) {
884 list.append( dtToString( QDateTime(todo->dtDue().date(),QTime( 0,0,0 )), false)) ; 885 list.append( dtToString( QDateTime(todo->dtDue().date(),QTime( 0,0,0 )), false)) ;
885 } else { 886 } else {
886 list.append( dtToString(todo->dtDue() ) ); 887 list.append( dtToString(todo->dtDue() ) );
887 } 888 }
888 } else 889 } else
889 list.append( QString() ); 890 list.append( QString() );
890 891
891 if ( todo->isCompleted() ) { 892 if ( todo->isCompleted() ) {
892 list.append( dtToString( todo->completed()) ); 893 list.append( dtToString( todo->completed()) );
893 list.append( "0" ); // yes 0 == completed 894 list.append( "0" ); // yes 0 == completed
894 } else { 895 } else {
895 list.append( dtToString( todo->completed()) ); 896 list.append( dtToString( todo->completed()) );
896 list.append( "1" ); 897 list.append( "1" );
897 } 898 }
898 list.append( QString::number( todo->priority() )); 899 list.append( QString::number( todo->priority() ));
899 if( ! todo->summary().isEmpty() ) 900 if( ! todo->summary().isEmpty() )
900 list.append( todo->summary() ); 901 list.append( todo->summary() );
901 else 902 else
902 list.append( "" ); 903 list.append( "" );
903 if (! todo->description().isEmpty() ) 904 if (! todo->description().isEmpty() )
904 list.append( todo->description() ); 905 list.append( todo->description() );
905 else 906 else
906 list.append( "" ); 907 list.append( "" );
907 for(QStringList::Iterator it=list.begin(); 908 for(QStringList::Iterator it=list.begin();
908 it!=list.end(); ++it){ 909 it!=list.end(); ++it){
909 QString& s = (*it); 910 QString& s = (*it);
910 s.replace(QRegExp("\""), "\"\""); 911 s.replace(QRegExp("\""), "\"\"");
911 if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){ 912 if(s.contains(QRegExp("[,\"\r\n]")) || s.stripWhiteSpace() != s){
912 s.prepend('\"'); 913 s.prepend('\"');
913 s.append('\"'); 914 s.append('\"');
914 } else if(s.isEmpty() && !s.isNull()){ 915 } else if(s.isEmpty() && !s.isNull()){
915 s = "\"\""; 916 s = "\"\"";
916 } 917 }
917 } 918 }
918 return list.join(","); 919 return list.join(",");
919} 920}
920QString SharpFormat::getPart( const QString & text, bool &ok, int &start ) 921QString SharpFormat::getPart( const QString & text, bool &ok, int &start )
921{ 922{
922 //qDebug("start %d ", start); 923 //qDebug("start %d ", start);
923 924
924 QString retval =""; 925 QString retval ="";
925 if ( text.at(start) == '"' ) { 926 if ( text.at(start) == '"' ) {
926 if ( text.mid( start,2) == "\"\"" && !( text.mid( start+2,1) == "\"")) { 927 if ( text.mid( start,2) == "\"\"" && !( text.mid( start+2,1) == "\"")) {
927 start = start +2; 928 start = start +2;
928 if ( text.mid( start,1) == "," ) { 929 if ( text.mid( start,1) == "," ) {
929 start += 1; 930 start += 1;
930 } 931 }
931 retval = ""; 932 retval = "";
932 if ( text.mid( start,1) == "\n" ) { 933 if ( text.mid( start,1) == "\n" ) {
933 start += 1; 934 start += 1;
934 ok = false; 935 ok = false;
935 } 936 }
936 return retval; 937 return retval;
937 } 938 }
938 int hk = start+1; 939 int hk = start+1;
939 hk = text.find ('"',hk); 940 hk = text.find ('"',hk);
940 while ( text.at(hk+1) == '"' ) 941 while ( text.at(hk+1) == '"' )
941 hk = text.find ('"',hk+2); 942 hk = text.find ('"',hk+2);
942 retval = text.mid( start+1, hk-start-1); 943 retval = text.mid( start+1, hk-start-1);
943 start = hk+1; 944 start = hk+1;
944 retval.replace( QRegExp("\"\""), "\""); 945 retval.replace( QRegExp("\"\""), "\"");
945 if ( text.mid( start,1) == "," ) { 946 if ( text.mid( start,1) == "," ) {
946 start += 1; 947 start += 1;
947 } 948 }
948 if ( text.mid( start,1) == "\n" ) { 949 if ( text.mid( start,1) == "\n" ) {
949 start += 1; 950 start += 1;
950 ok = false; 951 ok = false;
951 } 952 }
952 //qDebug("retval***%s*** ",retval.latin1() ); 953 //qDebug("retval***%s*** ",retval.latin1() );
953 return retval; 954 return retval;
954 955
955 } else { 956 } else {
956 int nl = text.find ("\n",start); 957 int nl = text.find ("\n",start);
957 int kom = text.find (',',start); 958 int kom = text.find (',',start);
958 if ( kom < nl ) { 959 if ( kom < nl ) {
959 // qDebug("kom < nl %d ", kom); 960 // qDebug("kom < nl %d ", kom);
960 retval = text.mid(start, kom-start); 961 retval = text.mid(start, kom-start);
961 start = kom+1; 962 start = kom+1;
962 return retval; 963 return retval;
963 } else { 964 } else {
964 if ( nl == kom ) { 965 if ( nl == kom ) {
965 // qDebug(" nl == kom "); 966 // qDebug(" nl == kom ");
966 start = 0; 967 start = 0;
967 ok = false; 968 ok = false;
968 return "0"; 969 return "0";
969 } 970 }
970 // qDebug(" nl < kom ", nl); 971 // qDebug(" nl < kom ", nl);
971 retval = text.mid( start, nl-start); 972 retval = text.mid( start, nl-start);
972 ok = false; 973 ok = false;
973 start = nl+1; 974 start = nl+1;
974 return retval; 975 return retval;
975 } 976 }
976 } 977 }
977} 978}
978bool SharpFormat::fromString( Calendar *calendar, const QString & text) 979bool SharpFormat::fromString( Calendar *calendar, const QString & text)
979{ 980{
980 return false; 981 return false;
981} 982}
982bool SharpFormat::fromString2Cal( Calendar *calendar,Calendar *existingCalendar, const QString & text, const QString & type) 983bool SharpFormat::fromString2Cal( Calendar *calendar,Calendar *existingCalendar, const QString & text, const QString & type)
983{ 984{
984 // qDebug("test %s ", text.latin1()); 985 // qDebug("test %s ", text.latin1());
985 QStringList templist; 986 QStringList templist;
986 QString tempString; 987 QString tempString;
987 int start = 0; 988 int start = 0;
988 int len = text.length(); 989 int len = text.length();
989 int end = text.find ("\n",start)+1; 990 int end = text.find ("\n",start)+1;
990 bool ok = true; 991 bool ok = true;
991 start = end; 992 start = end;
992 SharpParser handler( calendar ); 993 SharpParser handler( calendar );
993 handler.setCategoriesList( mCategories ); 994 handler.setCategoriesList( mCategories );
994 while ( start > 0 ) { 995 while ( start > 0 ) {
995 templist.clear(); 996 templist.clear();
996 ok = true; 997 ok = true;
997 while ( ok ) { 998 while ( ok ) {
998 tempString = getPart( text, ok, start ); 999 tempString = getPart( text, ok, start );
999 if ( start >= len || start == 0 ) { 1000 if ( start >= len || start == 0 ) {
1000 start = 0; 1001 start = 0;
1001 ok = false; 1002 ok = false;
1002 } 1003 }
1003 if ( tempString.right(1) =="\n" ) 1004 if ( tempString.right(1) =="\n" )
1004 tempString = tempString.left( tempString.length()-1); 1005 tempString = tempString.left( tempString.length()-1);
1005 //if ( ok ) 1006 //if ( ok )
1006 templist.append( tempString ); 1007 templist.append( tempString );
1007 //qDebug("%d ---%s---", templist.count(),tempString.latin1() ); 1008 //qDebug("%d ---%s---", templist.count(),tempString.latin1() );
1008 } 1009 }
1009 handler.startElement( existingCalendar, templist, type ); 1010 handler.startElement( existingCalendar, templist, type );
1010 } 1011 }
1011 1012
1012 return false; 1013 return false;
1013} 1014}
1014 1015
1015QString SharpFormat::toString( Calendar * ) 1016QString SharpFormat::toString( Calendar * )
1016{ 1017{
1017 return QString::null; 1018 return QString::null;
1018} 1019}