summaryrefslogtreecommitdiff
path: root/libopie2/opiepim/core/orecur.cpp
Unidiff
Diffstat (limited to 'libopie2/opiepim/core/orecur.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--libopie2/opiepim/core/orecur.cpp315
1 files changed, 315 insertions, 0 deletions
diff --git a/libopie2/opiepim/core/orecur.cpp b/libopie2/opiepim/core/orecur.cpp
index 257d4fd..daf3506 100644
--- a/libopie2/opiepim/core/orecur.cpp
+++ b/libopie2/opiepim/core/orecur.cpp
@@ -22,6 +22,9 @@ struct ORecur::Data : public QShared {
22 time_t end; 22 time_t end;
23 time_t create; 23 time_t create;
24 int rep; 24 int rep;
25 QString app;
26 ExceptionList list;
27 QDate start;
25}; 28};
26 29
27 30
@@ -55,6 +58,298 @@ ORecur &ORecur::operator=( const ORecur& re) {
55 58
56 return *this; 59 return *this;
57} 60}
61bool ORecur::doesRecur()const {
62 return !( type() == NoRepeat );
63}
64/*
65 * we try to be smart here
66 *
67 */
68bool ORecur::doesRecur( const QDate& date ) {
69 /* the day before the recurrance */
70 QDate da = date.addDays(-1);
71
72 QDate recur;
73 if (!nextOcurrence( da, recur ) )
74 return false;
75
76 return (recur == date);
77}
78// FIXME unuglify!
79// GPL from Datebookdb.cpp
80// FIXME exception list!
81bool ORecur::nextOcurrence( const QDate& from, QDate& next ) {
82
83 // easy checks, first are we too far in the future or too far in the past?
84 QDate tmpDate;
85 int freq = frequency();
86 int diff, diff2, a;
87 int iday, imonth, iyear;
88 int dayOfWeek = 0;
89 int firstOfWeek = 0;
90 int weekOfMonth;
91
92
93 if (hasEndDate() && endDate() < from)
94 return FALSE;
95
96 if (start() >= from) {
97 next = start();
98 return TRUE;
99 }
100
101 switch ( type() ) {
102 case Weekly:
103 /* weekly is just daily by 7 */
104 /* first convert the repeatPattern.Days() mask to the next
105 day of week valid after from */
106 dayOfWeek = from.dayOfWeek();
107 dayOfWeek--; /* we want 0-6, doco for above specs 1-7 */
108
109 /* this is done in case freq > 1 and from in week not
110 for this round */
111 // firstOfWeek = 0; this is already done at decl.
112 while(!((1 << firstOfWeek) & days() ))
113 firstOfWeek++;
114
115 /* there is at least one 'day', or there would be no event */
116 while(!((1 << (dayOfWeek % 7)) & days() ))
117 dayOfWeek++;
118
119 dayOfWeek = dayOfWeek % 7; /* the actual day of week */
120 dayOfWeek -= start().dayOfWeek() -1;
121
122 firstOfWeek = firstOfWeek % 7; /* the actual first of week */
123 firstOfWeek -= start().dayOfWeek() -1;
124
125 // dayOfWeek may be negitive now
126 // day of week is number of days to add to start day
127
128 freq *= 7;
129 // FALL-THROUGH !!!!!
130 case Daily:
131 // the add is for the possible fall through from weekly */
132 if(start().addDays(dayOfWeek) > from) {
133 /* first week exception */
134 next = QDate(start().addDays(dayOfWeek) );
135 if ((next > endDate())
136 && hasEndDate() )
137 return FALSE;
138 return TRUE;
139 }
140 /* if from is middle of a non-week */
141
142 diff = start().addDays(dayOfWeek).daysTo(from) % freq;
143 diff2 = start().addDays(firstOfWeek).daysTo(from) % freq;
144
145 if(diff != 0)
146 diff = freq - diff;
147 if(diff2 != 0)
148 diff2 = freq - diff2;
149 diff = QMIN(diff, diff2);
150
151 next = QDate(from.addDays(diff));
152 if ( (next > endDate())
153 && hasEndDate() )
154 return FALSE;
155 return TRUE;
156 case MonthlyDay:
157 iday = from.day();
158 iyear = from.year();
159 imonth = from.month();
160 /* find equivelent day of month for this month */
161 dayOfWeek = start().dayOfWeek();
162 weekOfMonth = (start().day() - 1) / 7;
163
164 /* work out when the next valid month is */
165 a = from.year() - start().year();
166 a *= 12;
167 a = a + (imonth - start().month());
168 /* a is e.start()monthsFrom(from); */
169 if(a % freq) {
170 a = freq - (a % freq);
171 imonth = from.month() + a;
172 if (imonth > 12) {
173 imonth--;
174 iyear += imonth / 12;
175 imonth = imonth % 12;
176 imonth++;
177 }
178 }
179 /* imonth is now the first month after or on
180 from that matches the frequency given */
181
182 /* find for this month */
183 tmpDate = QDate( iyear, imonth, 1 );
184
185 iday = 1;
186 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
187 iday += 7 * weekOfMonth;
188 while (iday > tmpDate.daysInMonth()) {
189 imonth += freq;
190 if (imonth > 12) {
191 imonth--;
192 iyear += imonth / 12;
193 imonth = imonth % 12;
194 imonth++;
195 }
196 tmpDate = QDate( iyear, imonth, 1 );
197 /* these loops could go for a while, check end case now */
198 if ((tmpDate > endDate()) && hasEndDate() )
199 return FALSE;
200 iday = 1;
201 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
202 iday += 7 * weekOfMonth;
203 }
204 tmpDate = QDate(iyear, imonth, iday);
205
206 if (tmpDate >= from) {
207 next = tmpDate;
208 if ((next > endDate() ) && hasEndDate() )
209 return FALSE;
210 return TRUE;
211 }
212
213 /* need to find the next iteration */
214 do {
215 imonth += freq;
216 if (imonth > 12) {
217 imonth--;
218 iyear += imonth / 12;
219 imonth = imonth % 12;
220 imonth++;
221 }
222 tmpDate = QDate( iyear, imonth, 1 );
223 /* these loops could go for a while, check end case now */
224 if ((tmpDate > endDate()) && hasEndDate() )
225 return FALSE;
226 iday = 1;
227 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
228 iday += 7 * weekOfMonth;
229 } while (iday > tmpDate.daysInMonth());
230 tmpDate = QDate(iyear, imonth, iday);
231
232 next = tmpDate;
233 if ((next > endDate()) && hasEndDate() )
234 return FALSE;
235 return TRUE;
236 case MonthlyDate:
237 iday = start().day();
238 iyear = from.year();
239 imonth = from.month();
240
241 a = from.year() - start().year();
242 a *= 12;
243 a = a + (imonth - start().month());
244 /* a is e.start()monthsFrom(from); */
245 if(a % freq) {
246 a = freq - (a % freq);
247 imonth = from.month() + a;
248 if (imonth > 12) {
249 imonth--;
250 iyear += imonth / 12;
251 imonth = imonth % 12;
252 imonth++;
253 }
254 }
255 /* imonth is now the first month after or on
256 from that matches the frequencey given */
257
258 /* this could go for a while, worse case, 4*12 iterations, probably */
259 while(!QDate::isValid(iyear, imonth, iday) ) {
260 imonth += freq;
261 if (imonth > 12) {
262 imonth--;
263 iyear += imonth / 12;
264 imonth = imonth % 12;
265 imonth++;
266 }
267 /* these loops could go for a while, check end case now */
268 if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
269 return FALSE;
270 }
271
272 if(QDate(iyear, imonth, iday) >= from) {
273 /* done */
274 next = QDate(iyear, imonth, iday);
275 if ((next > endDate()) && hasEndDate() )
276 return FALSE;
277 return TRUE;
278 }
279
280 /* ok, need to cycle */
281 imonth += freq;
282 imonth--;
283 iyear += imonth / 12;
284 imonth = imonth % 12;
285 imonth++;
286
287 while(!QDate::isValid(iyear, imonth, iday) ) {
288 imonth += freq;
289 imonth--;
290 iyear += imonth / 12;
291 imonth = imonth % 12;
292 imonth++;
293 if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
294 return FALSE;
295 }
296
297 next = QDate(iyear, imonth, iday);
298 if ((next > endDate()) && hasEndDate() )
299 return FALSE;
300 return TRUE;
301 case Yearly:
302 iday = start().day();
303 imonth = start().month();
304 iyear = from.year(); // after all, we want to start in this year
305
306 diff = 1;
307 if(imonth == 2 && iday > 28) {
308 /* leap year, and it counts, calculate actual frequency */
309 if(freq % 4)
310 if (freq % 2)
311 freq = freq * 4;
312 else
313 freq = freq * 2;
314 /* else divides by 4 already, leave freq alone */
315 diff = 4;
316 }
317
318 a = from.year() - start().year();
319 if(a % freq) {
320 a = freq - (a % freq);
321 iyear = iyear + a;
322 }
323
324 /* under the assumption we won't hit one of the special not-leap years twice */
325 if(!QDate::isValid(iyear, imonth, iday)) {
326 /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */
327 iyear += freq;
328 }
329
330 if(QDate(iyear, imonth, iday) >= from) {
331 next = QDate(iyear, imonth, iday);
332
333 if ((next > endDate()) && hasEndDate() )
334 return FALSE;
335 return TRUE;
336 }
337 /* iyear == from.year(), need to advance again */
338 iyear += freq;
339 /* under the assumption we won't hit one of the special not-leap years twice */
340 if(!QDate::isValid(iyear, imonth, iday)) {
341 /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */
342 iyear += freq;
343 }
344
345 next = QDate(iyear, imonth, iday);
346 if ((next > endDate()) && hasEndDate() )
347 return FALSE;
348 return TRUE;
349 default:
350 return FALSE;
351 }
352}
58ORecur::RepeatType ORecur::type()const{ 353ORecur::RepeatType ORecur::type()const{
59 return data->type; 354 return data->type;
60} 355}
@@ -73,6 +368,9 @@ bool ORecur::hasEndDate()const {
73QDate ORecur::endDate()const { 368QDate ORecur::endDate()const {
74 return TimeConversion::fromUTC( data->end ).date(); 369 return TimeConversion::fromUTC( data->end ).date();
75} 370}
371QDate ORecur::start()const{
372 return data->start;
373}
76time_t ORecur::endDateUTC()const { 374time_t ORecur::endDateUTC()const {
77 return data->end; 375 return data->end;
78} 376}
@@ -82,6 +380,12 @@ time_t ORecur::createTime()const {
82int ORecur::repetition()const { 380int ORecur::repetition()const {
83 return data->rep; 381 return data->rep;
84} 382}
383QString ORecur::service()const {
384 return data->app;
385}
386ORecur::ExceptionList& ORecur::exceptions() {
387 return data->list;
388}
85void ORecur::setType( const RepeatType& z) { 389void ORecur::setType( const RepeatType& z) {
86 checkOrModify(); 390 checkOrModify();
87 data->type = z; 391 data->type = z;
@@ -118,6 +422,14 @@ void ORecur::setRepitition( int rep ) {
118 checkOrModify(); 422 checkOrModify();
119 data->rep = rep; 423 data->rep = rep;
120} 424}
425void ORecur::setService( const QString& app ) {
426 checkOrModify();
427 data->app = app;
428}
429void ORecur::setStart( const QDate& dt ) {
430 checkOrModify();
431 data->start = dt;
432}
121void ORecur::checkOrModify() { 433void ORecur::checkOrModify() {
122 if ( data->count != 1 ) { 434 if ( data->count != 1 ) {
123 data->deref(); 435 data->deref();
@@ -130,6 +442,9 @@ void ORecur::checkOrModify() {
130 d2->end = data->end; 442 d2->end = data->end;
131 d2->create = data->create; 443 d2->create = data->create;
132 d2->rep = data->rep; 444 d2->rep = data->rep;
445 d2->app = data->app;
446 d2->list = data->list;
447 d2->start = data->start;
133 data = d2; 448 data = d2;
134 } 449 }
135} 450}