summaryrefslogtreecommitdiff
path: root/noncore/unsupported/libopie/pim/orecur.cpp
Unidiff
Diffstat (limited to 'noncore/unsupported/libopie/pim/orecur.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/libopie/pim/orecur.cpp593
1 files changed, 593 insertions, 0 deletions
diff --git a/noncore/unsupported/libopie/pim/orecur.cpp b/noncore/unsupported/libopie/pim/orecur.cpp
new file mode 100644
index 0000000..f46f22e
--- a/dev/null
+++ b/noncore/unsupported/libopie/pim/orecur.cpp
@@ -0,0 +1,593 @@
1#include <time.h>
2
3#include <qshared.h>
4
5#include <qtopia/timeconversion.h>
6
7#include "otimezone.h"
8#include "orecur.h"
9
10struct ORecur::Data : public QShared {
11 Data() : QShared() {
12 type = ORecur::NoRepeat;
13 freq = -1;
14 days = 0;
15 pos = 0;
16 create = QDateTime::currentDateTime();
17 hasEnd = FALSE;
18 end = QDate::currentDate();
19 }
20 char days; // Q_UINT8 for 8 seven days;)
21 ORecur::RepeatType type;
22 int freq;
23 int pos;
24 bool hasEnd : 1;
25 QDate end;
26 QDateTime create;
27 int rep;
28 QString app;
29 ExceptionList list;
30 QDate start;
31};
32
33
34ORecur::ORecur() {
35 data = new Data;
36}
37
38ORecur::ORecur( const QMap<int, QString>& map )
39{
40 ORecur();
41 fromMap( map );
42}
43
44
45ORecur::ORecur( const ORecur& rec)
46 : data( rec.data )
47{
48 data->ref();
49}
50ORecur::~ORecur() {
51 if ( data->deref() ) {
52 delete data;
53 data = 0l;
54 }
55}
56void ORecur::deref() {
57 if ( data->deref() ) {
58 delete data;
59 data = 0l;
60 }
61}
62bool ORecur::operator==( const ORecur& )const {
63 return false;
64}
65ORecur &ORecur::operator=( const ORecur& re) {
66 if ( *this == re ) return *this;
67
68 re.data->ref();
69 deref();
70 data = re.data;
71
72 return *this;
73}
74bool ORecur::doesRecur()const {
75 return !( type() == NoRepeat );
76}
77/*
78 * we try to be smart here
79 *
80 */
81bool ORecur::doesRecur( const QDate& date ) {
82 /* the day before the recurrance */
83 QDate da = date.addDays(-1);
84
85 QDate recur;
86 if (!nextOcurrence( da, recur ) )
87 return false;
88
89 return (recur == date);
90}
91// FIXME unuglify!
92// GPL from Datebookdb.cpp
93// FIXME exception list!
94bool ORecur::nextOcurrence( const QDate& from, QDate& next ) {
95 bool stillLooking;
96 stillLooking = p_nextOccurrence( from, next );
97 while ( stillLooking && data->list.contains(next) )
98 stillLooking = p_nextOccurrence( next.addDays(1), next );
99
100 return stillLooking;
101}
102bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) {
103
104 // easy checks, first are we too far in the future or too far in the past?
105 QDate tmpDate;
106 int freq = frequency();
107 int diff, diff2, a;
108 int iday, imonth, iyear;
109 int dayOfWeek = 0;
110 int firstOfWeek = 0;
111 int weekOfMonth;
112
113
114 if (hasEndDate() && endDate() < from)
115 return FALSE;
116
117 if (start() >= from ) {
118 next = start();
119 return TRUE;
120 }
121
122 switch ( type() ) {
123 case Weekly:
124 /* weekly is just daily by 7 */
125 /* first convert the repeatPattern.Days() mask to the next
126 day of week valid after from */
127 dayOfWeek = from.dayOfWeek();
128 dayOfWeek--; /* we want 0-6, doco for above specs 1-7 */
129
130 /* this is done in case freq > 1 and from in week not
131 for this round */
132 // firstOfWeek = 0; this is already done at decl.
133 while(!((1 << firstOfWeek) & days() ))
134 firstOfWeek++;
135
136 /* there is at least one 'day', or there would be no event */
137 while(!((1 << (dayOfWeek % 7)) & days() ))
138 dayOfWeek++;
139
140 dayOfWeek = dayOfWeek % 7; /* the actual day of week */
141 dayOfWeek -= start().dayOfWeek() -1;
142
143 firstOfWeek = firstOfWeek % 7; /* the actual first of week */
144 firstOfWeek -= start().dayOfWeek() -1;
145
146 // dayOfWeek may be negitive now
147 // day of week is number of days to add to start day
148
149 freq *= 7;
150 // FALL-THROUGH !!!!!
151 case Daily:
152 // the add is for the possible fall through from weekly */
153 if(start().addDays(dayOfWeek) > from) {
154 /* first week exception */
155 next = QDate(start().addDays(dayOfWeek) );
156 if ((next > endDate())
157 && hasEndDate() )
158 return FALSE;
159 return TRUE;
160 }
161 /* if from is middle of a non-week */
162
163 diff = start().addDays(dayOfWeek).daysTo(from) % freq;
164 diff2 = start().addDays(firstOfWeek).daysTo(from) % freq;
165
166 if(diff != 0)
167 diff = freq - diff;
168 if(diff2 != 0)
169 diff2 = freq - diff2;
170 diff = QMIN(diff, diff2);
171
172 next = QDate(from.addDays(diff));
173 if ( (next > endDate())
174 && hasEndDate() )
175 return FALSE;
176 return TRUE;
177 case MonthlyDay:
178 iday = from.day();
179 iyear = from.year();
180 imonth = from.month();
181 /* find equivelent day of month for this month */
182 dayOfWeek = start().dayOfWeek();
183 weekOfMonth = (start().day() - 1) / 7;
184
185 /* work out when the next valid month is */
186 a = from.year() - start().year();
187 a *= 12;
188 a = a + (imonth - start().month());
189 /* a is e.start()monthsFrom(from); */
190 if(a % freq) {
191 a = freq - (a % freq);
192 imonth = from.month() + a;
193 if (imonth > 12) {
194 imonth--;
195 iyear += imonth / 12;
196 imonth = imonth % 12;
197 imonth++;
198 }
199 }
200 /* imonth is now the first month after or on
201 from that matches the frequency given */
202
203 /* find for this month */
204 tmpDate = QDate( iyear, imonth, 1 );
205
206 iday = 1;
207 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
208 iday += 7 * weekOfMonth;
209 while (iday > tmpDate.daysInMonth()) {
210 imonth += freq;
211 if (imonth > 12) {
212 imonth--;
213 iyear += imonth / 12;
214 imonth = imonth % 12;
215 imonth++;
216 }
217 tmpDate = QDate( iyear, imonth, 1 );
218 /* these loops could go for a while, check end case now */
219 if ((tmpDate > endDate()) && hasEndDate() )
220 return FALSE;
221 iday = 1;
222 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
223 iday += 7 * weekOfMonth;
224 }
225 tmpDate = QDate(iyear, imonth, iday);
226
227 if (tmpDate >= from) {
228 next = tmpDate;
229 if ((next > endDate() ) && hasEndDate() )
230 return FALSE;
231 return TRUE;
232 }
233
234 /* need to find the next iteration */
235 do {
236 imonth += freq;
237 if (imonth > 12) {
238 imonth--;
239 iyear += imonth / 12;
240 imonth = imonth % 12;
241 imonth++;
242 }
243 tmpDate = QDate( iyear, imonth, 1 );
244 /* these loops could go for a while, check end case now */
245 if ((tmpDate > endDate()) && hasEndDate() )
246 return FALSE;
247 iday = 1;
248 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
249 iday += 7 * weekOfMonth;
250 } while (iday > tmpDate.daysInMonth());
251 tmpDate = QDate(iyear, imonth, iday);
252
253 next = tmpDate;
254 if ((next > endDate()) && hasEndDate() )
255 return FALSE;
256 return TRUE;
257 case MonthlyDate:
258 iday = start().day();
259 iyear = from.year();
260 imonth = from.month();
261
262 a = from.year() - start().year();
263 a *= 12;
264 a = a + (imonth - start().month());
265 /* a is e.start()monthsFrom(from); */
266 if(a % freq) {
267 a = freq - (a % freq);
268 imonth = from.month() + a;
269 if (imonth > 12) {
270 imonth--;
271 iyear += imonth / 12;
272 imonth = imonth % 12;
273 imonth++;
274 }
275 }
276 /* imonth is now the first month after or on
277 from that matches the frequencey given */
278
279 /* this could go for a while, worse case, 4*12 iterations, probably */
280 while(!QDate::isValid(iyear, imonth, iday) ) {
281 imonth += freq;
282 if (imonth > 12) {
283 imonth--;
284 iyear += imonth / 12;
285 imonth = imonth % 12;
286 imonth++;
287 }
288 /* these loops could go for a while, check end case now */
289 if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
290 return FALSE;
291 }
292
293 if(QDate(iyear, imonth, iday) >= from) {
294 /* done */
295 next = QDate(iyear, imonth, iday);
296 if ((next > endDate()) && hasEndDate() )
297 return FALSE;
298 return TRUE;
299 }
300
301 /* ok, need to cycle */
302 imonth += freq;
303 imonth--;
304 iyear += imonth / 12;
305 imonth = imonth % 12;
306 imonth++;
307
308 while(!QDate::isValid(iyear, imonth, iday) ) {
309 imonth += freq;
310 imonth--;
311 iyear += imonth / 12;
312 imonth = imonth % 12;
313 imonth++;
314 if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
315 return FALSE;
316 }
317
318 next = QDate(iyear, imonth, iday);
319 if ((next > endDate()) && hasEndDate() )
320 return FALSE;
321 return TRUE;
322 case Yearly:
323 iday = start().day();
324 imonth = start().month();
325 iyear = from.year(); // after all, we want to start in this year
326
327 diff = 1;
328 if(imonth == 2 && iday > 28) {
329 /* leap year, and it counts, calculate actual frequency */
330 if(freq % 4)
331 if (freq % 2)
332 freq = freq * 4;
333 else
334 freq = freq * 2;
335 /* else divides by 4 already, leave freq alone */
336 diff = 4;
337 }
338
339 a = from.year() - start().year();
340 if(a % freq) {
341 a = freq - (a % freq);
342 iyear = iyear + a;
343 }
344
345 /* under the assumption we won't hit one of the special not-leap years twice */
346 if(!QDate::isValid(iyear, imonth, iday)) {
347 /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */
348 iyear += freq;
349 }
350
351 if(QDate(iyear, imonth, iday) >= from) {
352 next = QDate(iyear, imonth, iday);
353
354 if ((next > endDate()) && hasEndDate() )
355 return FALSE;
356 return TRUE;
357 }
358 /* iyear == from.year(), need to advance again */
359 iyear += freq;
360 /* under the assumption we won't hit one of the special not-leap years twice */
361 if(!QDate::isValid(iyear, imonth, iday)) {
362 /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */
363 iyear += freq;
364 }
365
366 next = QDate(iyear, imonth, iday);
367 if ((next > endDate()) && hasEndDate() )
368 return FALSE;
369 return TRUE;
370 default:
371 return FALSE;
372 }
373}
374ORecur::RepeatType ORecur::type()const{
375 return data->type;
376}
377int ORecur::frequency()const {
378 return data->freq;
379}
380int ORecur::position()const {
381 return data->pos;
382}
383char ORecur::days() const{
384 return data->days;
385}
386bool ORecur::hasEndDate()const {
387 return data->hasEnd;
388}
389QDate ORecur::endDate()const {
390 return data->end;
391}
392QDate ORecur::start()const{
393 return data->start;
394}
395QDateTime ORecur::createdDateTime()const {
396 return data->create;
397}
398int ORecur::repetition()const {
399 return data->rep;
400}
401QString ORecur::service()const {
402 return data->app;
403}
404ORecur::ExceptionList& ORecur::exceptions() {
405 return data->list;
406}
407void ORecur::setType( const RepeatType& z) {
408 checkOrModify();
409 data->type = z;
410}
411void ORecur::setFrequency( int freq ) {
412 checkOrModify();
413 data->freq = freq;
414}
415void ORecur::setPosition( int pos ) {
416 checkOrModify();
417 data->pos = pos;
418}
419void ORecur::setDays( char c ) {
420 checkOrModify();
421 data->days = c;
422}
423void ORecur::setEndDate( const QDate& dt) {
424 checkOrModify();
425 data->end = dt;
426}
427void ORecur::setCreatedDateTime( const QDateTime& t) {
428 checkOrModify();
429 data->create = t;
430}
431void ORecur::setHasEndDate( bool b) {
432 checkOrModify();
433 data->hasEnd = b;
434}
435void ORecur::setRepitition( int rep ) {
436 checkOrModify();
437 data->rep = rep;
438}
439void ORecur::setService( const QString& app ) {
440 checkOrModify();
441 data->app = app;
442}
443void ORecur::setStart( const QDate& dt ) {
444 checkOrModify();
445 data->start = dt;
446}
447void ORecur::checkOrModify() {
448 if ( data->count != 1 ) {
449 data->deref();
450 Data* d2 = new Data;
451 d2->days = data->days;
452 d2->type = data->type;
453 d2->freq = data->freq;
454 d2->pos = data->pos;
455 d2->hasEnd = data->hasEnd;
456 d2->end = data->end;
457 d2->create = data->create;
458 d2->rep = data->rep;
459 d2->app = data->app;
460 d2->list = data->list;
461 d2->start = data->start;
462 data = d2;
463 }
464}
465QString ORecur::toString()const {
466 QString buf;
467 QMap<int, QString> recMap = toMap();
468
469 buf += " rtype=\"";
470 buf += recMap[ORecur::RType];
471 buf += "\"";
472 if (data->days > 0 )
473 buf += " rweekdays=\"" + recMap[ORecur::RWeekdays] + "\"";
474 if ( data->pos != 0 )
475 buf += " rposition=\"" + recMap[ORecur::RPosition] + "\"";
476
477 buf += " rfreq=\"" + recMap[ORecur::RFreq] + "\"";
478 buf += " rhasenddate=\"" + recMap[ORecur::RHasEndDate]+ "\"";
479 if ( data->hasEnd )
480 buf += " enddt=\""
481 + recMap[ORecur::EndDate]
482 + "\"";
483 buf += " created=\"" + recMap[ORecur::Created] + "\"";
484
485 if ( data->list.isEmpty() ) return buf;
486 buf += " exceptions=\"";
487 buf += recMap[ORecur::Exceptions];
488 buf += "\" ";
489
490 return buf;
491}
492
493QString ORecur::rTypeString() const
494{
495 QString retString;
496 switch ( data->type ) {
497 case ORecur::Daily:
498 retString = "Daily";
499 break;
500 case ORecur::Weekly:
501 retString = "Weekly";
502 break;
503 case ORecur::MonthlyDay:
504 retString = "MonthlyDay";
505 break;
506 case ORecur::MonthlyDate:
507 retString = "MonthlyDate";
508 break;
509 case ORecur::Yearly:
510 retString = "Yearly";
511 break;
512 default:
513 retString = "NoRepeat";
514 break;
515
516 }
517
518 return retString;
519}
520
521QMap<QString, ORecur::RepeatType> ORecur::rTypeValueConvertMap() const
522{
523 QMap<QString, RepeatType> convertMap;
524
525 convertMap.insert( QString( "Daily" ), ORecur::Daily );
526 convertMap.insert( QString( "Weekly" ), ORecur::Weekly );
527 convertMap.insert( QString( "MonthlyDay" ), ORecur::MonthlyDay );
528 convertMap.insert( QString( "MonthlyDate" ), ORecur::MonthlyDate );
529 convertMap.insert( QString( "Yearly" ), ORecur::Yearly );
530 convertMap.insert( QString( "NoRepeat" ), ORecur::NoRepeat );
531
532 return convertMap;
533}
534
535
536QMap<int, QString> ORecur::toMap() const
537{
538 QMap<int, QString> retMap;
539
540 retMap.insert( ORecur::RType, rTypeString() );
541 retMap.insert( ORecur::RWeekdays, QString::number( static_cast<int>( data->days ) ) );
542 retMap.insert( ORecur::RPosition, QString::number(data->pos ) );
543 retMap.insert( ORecur::RFreq, QString::number( data->freq ) );
544 retMap.insert( ORecur::RHasEndDate, QString::number( static_cast<int>( data->hasEnd ) ) );
545 if( data -> hasEnd )
546 retMap.insert( ORecur::EndDate, QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) );
547 retMap.insert( ORecur::Created, QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) );
548
549 if ( data->list.isEmpty() ) return retMap;
550
551 // save exceptions list here!!
552 ExceptionList::ConstIterator it;
553 ExceptionList list = data->list;
554 QString exceptBuf;
555 QDate date;
556 for ( it = list.begin(); it != list.end(); ++it ) {
557 date = (*it);
558 if ( it != list.begin() ) exceptBuf += " ";
559
560 exceptBuf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() );
561 }
562
563 retMap.insert( ORecur::Exceptions, exceptBuf );
564
565 return retMap;
566}
567
568void ORecur::fromMap( const QMap<int, QString>& map )
569{
570 QMap<QString, RepeatType> repTypeMap = rTypeValueConvertMap();
571
572 data -> type = repTypeMap[ map [ORecur::RType] ];
573 data -> days = (char) map[ ORecur::RWeekdays ].toInt();
574 data -> pos = map[ ORecur::RPosition ].toInt();
575 data -> freq = map[ ORecur::RFreq ].toInt();
576 data -> hasEnd= map[ ORecur::RHasEndDate ].toInt() ? true : false;
577 OTimeZone utc = OTimeZone::utc();
578 if ( data -> hasEnd ){
579 data -> end = utc.fromUTCDateTime( (time_t) map[ ORecur::EndDate ].toLong() ).date();
580 }
581 data -> create = utc.fromUTCDateTime( (time_t) map[ ORecur::Created ].toLong() ).date();
582
583#if 0
584 // FIXME: Exceptions currently not supported...
585 // Convert the list of exceptions from QString into ExceptionList
586 data -> list.clear();
587 QString exceptStr = map[ ORecur::Exceptions ];
588 QStringList exceptList = QStringList::split( " ", exceptStr );
589 ...
590#endif
591
592
593}