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