-rw-r--r-- | libopie/pim/orecur.cpp | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/libopie/pim/orecur.cpp b/libopie/pim/orecur.cpp index 257d4fd..daf3506 100644 --- a/libopie/pim/orecur.cpp +++ b/libopie/pim/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 | } |
61 | bool ORecur::doesRecur()const { | ||
62 | return !( type() == NoRepeat ); | ||
63 | } | ||
64 | /* | ||
65 | * we try to be smart here | ||
66 | * | ||
67 | */ | ||
68 | bool 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! | ||
81 | bool 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 | } | ||
58 | ORecur::RepeatType ORecur::type()const{ | 353 | ORecur::RepeatType ORecur::type()const{ |
59 | return data->type; | 354 | return data->type; |
60 | } | 355 | } |
@@ -73,6 +368,9 @@ bool ORecur::hasEndDate()const { | |||
73 | QDate ORecur::endDate()const { | 368 | QDate ORecur::endDate()const { |
74 | return TimeConversion::fromUTC( data->end ).date(); | 369 | return TimeConversion::fromUTC( data->end ).date(); |
75 | } | 370 | } |
371 | QDate ORecur::start()const{ | ||
372 | return data->start; | ||
373 | } | ||
76 | time_t ORecur::endDateUTC()const { | 374 | time_t ORecur::endDateUTC()const { |
77 | return data->end; | 375 | return data->end; |
78 | } | 376 | } |
@@ -82,6 +380,12 @@ time_t ORecur::createTime()const { | |||
82 | int ORecur::repetition()const { | 380 | int ORecur::repetition()const { |
83 | return data->rep; | 381 | return data->rep; |
84 | } | 382 | } |
383 | QString ORecur::service()const { | ||
384 | return data->app; | ||
385 | } | ||
386 | ORecur::ExceptionList& ORecur::exceptions() { | ||
387 | return data->list; | ||
388 | } | ||
85 | void ORecur::setType( const RepeatType& z) { | 389 | void 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 | } |
425 | void ORecur::setService( const QString& app ) { | ||
426 | checkOrModify(); | ||
427 | data->app = app; | ||
428 | } | ||
429 | void ORecur::setStart( const QDate& dt ) { | ||
430 | checkOrModify(); | ||
431 | data->start = dt; | ||
432 | } | ||
121 | void ORecur::checkOrModify() { | 433 | void 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 | } |