author | mickeyl <mickeyl> | 2004-11-16 19:14:18 (UTC) |
---|---|---|
committer | mickeyl <mickeyl> | 2004-11-16 19:14:18 (UTC) |
commit | ea3945a9bd8f9830f70b1efa133f9df13b19362f (patch) (unidiff) | |
tree | f2ea22cc50e9aa8aa73ee7dea148f41c563c9666 /noncore/unsupported/libopie/pim/otodoaccessxml.cpp | |
parent | 1c6f490e8541626f68422e0a3a7c7281d7f5b7d3 (diff) | |
download | opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.zip opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.tar.gz opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.tar.bz2 |
libopie1 goes into unsupported
Diffstat (limited to 'noncore/unsupported/libopie/pim/otodoaccessxml.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/unsupported/libopie/pim/otodoaccessxml.cpp | 876 |
1 files changed, 876 insertions, 0 deletions
diff --git a/noncore/unsupported/libopie/pim/otodoaccessxml.cpp b/noncore/unsupported/libopie/pim/otodoaccessxml.cpp new file mode 100644 index 0000000..4a5cb33 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessxml.cpp | |||
@@ -0,0 +1,876 @@ | |||
1 | #include <errno.h> | ||
2 | #include <fcntl.h> | ||
3 | |||
4 | #include <sys/mman.h> | ||
5 | #include <sys/stat.h> | ||
6 | #include <sys/types.h> | ||
7 | |||
8 | #include <unistd.h> | ||
9 | |||
10 | |||
11 | #include <qfile.h> | ||
12 | #include <qvector.h> | ||
13 | |||
14 | #include <qpe/global.h> | ||
15 | #include <qpe/stringutil.h> | ||
16 | #include <qpe/timeconversion.h> | ||
17 | |||
18 | #include "oconversion.h" | ||
19 | #include "opimstate.h" | ||
20 | #include "otimezone.h" | ||
21 | #include "opimnotifymanager.h" | ||
22 | #include "orecur.h" | ||
23 | #include "otodoaccessxml.h" | ||
24 | |||
25 | namespace { | ||
26 | time_t rp_end; | ||
27 | ORecur* rec; | ||
28 | ORecur *recur() { | ||
29 | if (!rec ) rec = new ORecur; | ||
30 | return rec; | ||
31 | } | ||
32 | int snd; | ||
33 | enum MoreAttributes { | ||
34 | FRType = OTodo::CompletedDate + 2, | ||
35 | FRWeekdays, | ||
36 | FRPosition, | ||
37 | FRFreq, | ||
38 | FRHasEndDate, | ||
39 | FREndDate, | ||
40 | FRStart, | ||
41 | FREnd | ||
42 | }; | ||
43 | // FROM TT again | ||
44 | char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) | ||
45 | { | ||
46 | char needleChar; | ||
47 | char haystackChar; | ||
48 | if (!needle || !haystack || !hLen || !nLen) | ||
49 | return 0; | ||
50 | |||
51 | const char* hsearch = haystack; | ||
52 | |||
53 | if ((needleChar = *needle++) != 0) { | ||
54 | nLen--; //(to make up for needle++) | ||
55 | do { | ||
56 | do { | ||
57 | if ((haystackChar = *hsearch++) == 0) | ||
58 | return (0); | ||
59 | if (hsearch >= haystack + hLen) | ||
60 | return (0); | ||
61 | } while (haystackChar != needleChar); | ||
62 | } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); | ||
63 | hsearch--; | ||
64 | } | ||
65 | return ((char *)hsearch); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | |||
70 | OTodoAccessXML::OTodoAccessXML( const QString& appName, | ||
71 | const QString& fileName ) | ||
72 | : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) | ||
73 | { | ||
74 | if (!fileName.isEmpty() ) | ||
75 | m_file = fileName; | ||
76 | else | ||
77 | m_file = Global::applicationFileName( "todolist", "todolist.xml" ); | ||
78 | } | ||
79 | OTodoAccessXML::~OTodoAccessXML() { | ||
80 | |||
81 | } | ||
82 | bool OTodoAccessXML::load() { | ||
83 | rec = 0; | ||
84 | m_opened = true; | ||
85 | m_changed = false; | ||
86 | /* initialize dict */ | ||
87 | /* | ||
88 | * UPDATE dict if you change anything!!! | ||
89 | */ | ||
90 | QAsciiDict<int> dict(26); | ||
91 | dict.setAutoDelete( TRUE ); | ||
92 | dict.insert("Categories" , new int(OTodo::Category) ); | ||
93 | dict.insert("Uid" , new int(OTodo::Uid) ); | ||
94 | dict.insert("HasDate" , new int(OTodo::HasDate) ); | ||
95 | dict.insert("Completed" , new int(OTodo::Completed) ); | ||
96 | dict.insert("Description" , new int(OTodo::Description) ); | ||
97 | dict.insert("Summary" , new int(OTodo::Summary) ); | ||
98 | dict.insert("Priority" , new int(OTodo::Priority) ); | ||
99 | dict.insert("DateDay" , new int(OTodo::DateDay) ); | ||
100 | dict.insert("DateMonth" , new int(OTodo::DateMonth) ); | ||
101 | dict.insert("DateYear" , new int(OTodo::DateYear) ); | ||
102 | dict.insert("Progress" , new int(OTodo::Progress) ); | ||
103 | dict.insert("CompletedDate", new int(OTodo::CompletedDate) ); | ||
104 | dict.insert("StartDate", new int(OTodo::StartDate) ); | ||
105 | dict.insert("CrossReference", new int(OTodo::CrossReference) ); | ||
106 | dict.insert("State", new int(OTodo::State) ); | ||
107 | dict.insert("Alarms", new int(OTodo::Alarms) ); | ||
108 | dict.insert("Reminders", new int(OTodo::Reminders) ); | ||
109 | dict.insert("Notifiers", new int(OTodo::Notifiers) ); | ||
110 | dict.insert("Maintainer", new int(OTodo::Maintainer) ); | ||
111 | dict.insert("rtype", new int(FRType) ); | ||
112 | dict.insert("rweekdays", new int(FRWeekdays) ); | ||
113 | dict.insert("rposition", new int(FRPosition) ); | ||
114 | dict.insert("rfreq", new int(FRFreq) ); | ||
115 | dict.insert("start", new int(FRStart) ); | ||
116 | dict.insert("rhasenddate", new int(FRHasEndDate) ); | ||
117 | dict.insert("enddt", new int(FREndDate) ); | ||
118 | |||
119 | // here the custom XML parser from TT it's GPL | ||
120 | // but we want to push OpiePIM... to TT..... | ||
121 | // mmap part from zecke :) | ||
122 | int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); | ||
123 | struct stat attribut; | ||
124 | if ( fd < 0 ) return false; | ||
125 | |||
126 | if ( fstat(fd, &attribut ) == -1 ) { | ||
127 | ::close( fd ); | ||
128 | return false; | ||
129 | } | ||
130 | void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); | ||
131 | if ( map_addr == ( (caddr_t)-1) ) { | ||
132 | ::close(fd ); | ||
133 | return false; | ||
134 | } | ||
135 | /* advise the kernel who we want to read it */ | ||
136 | ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); | ||
137 | /* we do not the file any more */ | ||
138 | ::close( fd ); | ||
139 | |||
140 | char* dt = (char*)map_addr; | ||
141 | int len = attribut.st_size; | ||
142 | int i = 0; | ||
143 | char *point; | ||
144 | const char* collectionString = "<Task "; | ||
145 | int strLen = strlen(collectionString); | ||
146 | while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { | ||
147 | i = point -dt; | ||
148 | i+= strLen; | ||
149 | qWarning("Found a start at %d %d", i, (point-dt) ); | ||
150 | |||
151 | OTodo ev; | ||
152 | m_year = m_month = m_day = 0; | ||
153 | |||
154 | while ( TRUE ) { | ||
155 | while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) | ||
156 | ++i; | ||
157 | if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) | ||
158 | break; | ||
159 | |||
160 | // we have another attribute, read it. | ||
161 | int j = i; | ||
162 | while ( j < len && dt[j] != '=' ) | ||
163 | ++j; | ||
164 | QCString attr( dt+i, j-i+1); | ||
165 | |||
166 | i = ++j; // skip = | ||
167 | |||
168 | // find the start of quotes | ||
169 | while ( i < len && dt[i] != '"' ) | ||
170 | ++i; | ||
171 | j = ++i; | ||
172 | |||
173 | bool haveUtf = FALSE; | ||
174 | bool haveEnt = FALSE; | ||
175 | while ( j < len && dt[j] != '"' ) { | ||
176 | if ( ((unsigned char)dt[j]) > 0x7f ) | ||
177 | haveUtf = TRUE; | ||
178 | if ( dt[j] == '&' ) | ||
179 | haveEnt = TRUE; | ||
180 | ++j; | ||
181 | } | ||
182 | if ( i == j ) { | ||
183 | // empty value | ||
184 | i = j + 1; | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | QCString value( dt+i, j-i+1 ); | ||
189 | i = j + 1; | ||
190 | |||
191 | QString str = (haveUtf ? QString::fromUtf8( value ) | ||
192 | : QString::fromLatin1( value ) ); | ||
193 | if ( haveEnt ) | ||
194 | str = Qtopia::plainString( str ); | ||
195 | |||
196 | /* | ||
197 | * add key + value | ||
198 | */ | ||
199 | todo( &dict, ev, attr, str ); | ||
200 | |||
201 | } | ||
202 | /* | ||
203 | * now add it | ||
204 | */ | ||
205 | qWarning("End at %d", i ); | ||
206 | if (m_events.contains( ev.uid() ) || ev.uid() == 0) { | ||
207 | ev.setUid( 1 ); | ||
208 | m_changed = true; | ||
209 | } | ||
210 | if ( ev.hasDueDate() ) { | ||
211 | ev.setDueDate( QDate(m_year, m_month, m_day) ); | ||
212 | } | ||
213 | if ( rec && rec->doesRecur() ) { | ||
214 | OTimeZone utc = OTimeZone::utc(); | ||
215 | ORecur recu( *rec ); // call copy c'tor | ||
216 | recu.setEndDate( utc.fromUTCDateTime( rp_end ).date() ); | ||
217 | recu.setStart( ev.dueDate() ); | ||
218 | ev.setRecurrence( recu ); | ||
219 | } | ||
220 | m_events.insert(ev.uid(), ev ); | ||
221 | m_year = m_month = m_day = -1; | ||
222 | delete rec; | ||
223 | rec = 0; | ||
224 | } | ||
225 | |||
226 | munmap(map_addr, attribut.st_size ); | ||
227 | |||
228 | qWarning("counts %d records loaded!", m_events.count() ); | ||
229 | return true; | ||
230 | } | ||
231 | bool OTodoAccessXML::reload() { | ||
232 | m_events.clear(); | ||
233 | return load(); | ||
234 | } | ||
235 | bool OTodoAccessXML::save() { | ||
236 | // qWarning("saving"); | ||
237 | if (!m_opened || !m_changed ) { | ||
238 | // qWarning("not saving"); | ||
239 | return true; | ||
240 | } | ||
241 | QString strNewFile = m_file + ".new"; | ||
242 | QFile f( strNewFile ); | ||
243 | if (!f.open( IO_WriteOnly|IO_Raw ) ) | ||
244 | return false; | ||
245 | |||
246 | int written; | ||
247 | QString out; | ||
248 | out = "<!DOCTYPE Tasks>\n<Tasks>\n"; | ||
249 | |||
250 | // for all todos | ||
251 | QMap<int, OTodo>::Iterator it; | ||
252 | for (it = m_events.begin(); it != m_events.end(); ++it ) { | ||
253 | out+= "<Task " + toString( (*it) ) + " />\n"; | ||
254 | QCString cstr = out.utf8(); | ||
255 | written = f.writeBlock( cstr.data(), cstr.length() ); | ||
256 | |||
257 | /* less written then we wanted */ | ||
258 | if ( written != (int)cstr.length() ) { | ||
259 | f.close(); | ||
260 | QFile::remove( strNewFile ); | ||
261 | return false; | ||
262 | } | ||
263 | out = QString::null; | ||
264 | } | ||
265 | |||
266 | out += "</Tasks>"; | ||
267 | QCString cstr = out.utf8(); | ||
268 | written = f.writeBlock( cstr.data(), cstr.length() ); | ||
269 | |||
270 | if ( written != (int)cstr.length() ) { | ||
271 | f.close(); | ||
272 | QFile::remove( strNewFile ); | ||
273 | return false; | ||
274 | } | ||
275 | /* flush before renaming */ | ||
276 | f.close(); | ||
277 | |||
278 | if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { | ||
279 | // qWarning("error renaming"); | ||
280 | QFile::remove( strNewFile ); | ||
281 | } | ||
282 | |||
283 | m_changed = false; | ||
284 | return true; | ||
285 | } | ||
286 | QArray<int> OTodoAccessXML::allRecords()const { | ||
287 | QArray<int> ids( m_events.count() ); | ||
288 | QMap<int, OTodo>::ConstIterator it; | ||
289 | int i = 0; | ||
290 | |||
291 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
292 | ids[i] = it.key(); | ||
293 | i++; | ||
294 | } | ||
295 | return ids; | ||
296 | } | ||
297 | QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { | ||
298 | QArray<int> ids(0); | ||
299 | return ids; | ||
300 | } | ||
301 | OTodo OTodoAccessXML::find( int uid )const { | ||
302 | OTodo todo; | ||
303 | todo.setUid( 0 ); // isEmpty() | ||
304 | QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); | ||
305 | if ( it != m_events.end() ) | ||
306 | todo = it.data(); | ||
307 | |||
308 | return todo; | ||
309 | } | ||
310 | void OTodoAccessXML::clear() { | ||
311 | if (m_opened ) | ||
312 | m_changed = true; | ||
313 | |||
314 | m_events.clear(); | ||
315 | } | ||
316 | bool OTodoAccessXML::add( const OTodo& todo ) { | ||
317 | // qWarning("add"); | ||
318 | m_changed = true; | ||
319 | m_events.insert( todo.uid(), todo ); | ||
320 | |||
321 | return true; | ||
322 | } | ||
323 | bool OTodoAccessXML::remove( int uid ) { | ||
324 | m_changed = true; | ||
325 | m_events.remove( uid ); | ||
326 | |||
327 | return true; | ||
328 | } | ||
329 | bool OTodoAccessXML::replace( const OTodo& todo) { | ||
330 | m_changed = true; | ||
331 | m_events.replace( todo.uid(), todo ); | ||
332 | |||
333 | return true; | ||
334 | } | ||
335 | QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, | ||
336 | const QDate& end, | ||
337 | bool includeNoDates ) { | ||
338 | QArray<int> ids( m_events.count() ); | ||
339 | QMap<int, OTodo>::Iterator it; | ||
340 | |||
341 | int i = 0; | ||
342 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
343 | if ( !it.data().hasDueDate() ) { | ||
344 | if ( includeNoDates ) { | ||
345 | ids[i] = it.key(); | ||
346 | i++; | ||
347 | } | ||
348 | }else if ( it.data().dueDate() >= start && | ||
349 | it.data().dueDate() <= end ) { | ||
350 | ids[i] = it.key(); | ||
351 | i++; | ||
352 | } | ||
353 | } | ||
354 | ids.resize( i ); | ||
355 | return ids; | ||
356 | } | ||
357 | QArray<int> OTodoAccessXML::overDue() { | ||
358 | QArray<int> ids( m_events.count() ); | ||
359 | int i = 0; | ||
360 | |||
361 | QMap<int, OTodo>::Iterator it; | ||
362 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
363 | if ( it.data().isOverdue() ) { | ||
364 | ids[i] = it.key(); | ||
365 | i++; | ||
366 | } | ||
367 | } | ||
368 | ids.resize( i ); | ||
369 | return ids; | ||
370 | } | ||
371 | |||
372 | |||
373 | /* private */ | ||
374 | void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, | ||
375 | const QCString& attr, const QString& val) { | ||
376 | // qWarning("parse to do from XMLElement" ); | ||
377 | |||
378 | int *find=0; | ||
379 | |||
380 | find = (*dict)[ attr.data() ]; | ||
381 | if (!find ) { | ||
382 | // qWarning("Unknown option" + it.key() ); | ||
383 | ev.setCustomField( attr, val ); | ||
384 | return; | ||
385 | } | ||
386 | |||
387 | switch( *find ) { | ||
388 | case OTodo::Uid: | ||
389 | ev.setUid( val.toInt() ); | ||
390 | break; | ||
391 | case OTodo::Category: | ||
392 | ev.setCategories( ev.idsFromString( val ) ); | ||
393 | break; | ||
394 | case OTodo::HasDate: | ||
395 | ev.setHasDueDate( val.toInt() ); | ||
396 | break; | ||
397 | case OTodo::Completed: | ||
398 | ev.setCompleted( val.toInt() ); | ||
399 | break; | ||
400 | case OTodo::Description: | ||
401 | ev.setDescription( val ); | ||
402 | break; | ||
403 | case OTodo::Summary: | ||
404 | ev.setSummary( val ); | ||
405 | break; | ||
406 | case OTodo::Priority: | ||
407 | ev.setPriority( val.toInt() ); | ||
408 | break; | ||
409 | case OTodo::DateDay: | ||
410 | m_day = val.toInt(); | ||
411 | break; | ||
412 | case OTodo::DateMonth: | ||
413 | m_month = val.toInt(); | ||
414 | break; | ||
415 | case OTodo::DateYear: | ||
416 | m_year = val.toInt(); | ||
417 | break; | ||
418 | case OTodo::Progress: | ||
419 | ev.setProgress( val.toInt() ); | ||
420 | break; | ||
421 | case OTodo::CompletedDate: | ||
422 | ev.setCompletedDate( OConversion::dateFromString( val ) ); | ||
423 | break; | ||
424 | case OTodo::StartDate: | ||
425 | ev.setStartDate( OConversion::dateFromString( val ) ); | ||
426 | break; | ||
427 | case OTodo::State: | ||
428 | ev.setState( val.toInt() ); | ||
429 | break; | ||
430 | case OTodo::Alarms:{ | ||
431 | OPimNotifyManager &manager = ev.notifiers(); | ||
432 | QStringList als = QStringList::split(";", val ); | ||
433 | for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) { | ||
434 | QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty | ||
435 | qWarning("alarm: %s", alarm.join("___").latin1() ); | ||
436 | qWarning("alarm[0]: %s %s", alarm[0].latin1(), OConversion::dateTimeFromString( alarm[0] ).toString().latin1() ); | ||
437 | OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), alarm[1].toInt() ); | ||
438 | manager.add( al ); | ||
439 | } | ||
440 | } | ||
441 | break; | ||
442 | case OTodo::Reminders:{ | ||
443 | OPimNotifyManager &manager = ev.notifiers(); | ||
444 | QStringList rems = QStringList::split(";", val ); | ||
445 | for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) { | ||
446 | OPimReminder rem( (*it).toInt() ); | ||
447 | manager.add( rem ); | ||
448 | } | ||
449 | } | ||
450 | break; | ||
451 | case OTodo::CrossReference: | ||
452 | { | ||
453 | /* | ||
454 | * A cross refernce looks like | ||
455 | * appname,id;appname,id | ||
456 | * we need to split it up | ||
457 | */ | ||
458 | QStringList refs = QStringList::split(';', val ); | ||
459 | QStringList::Iterator strIt; | ||
460 | for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { | ||
461 | int pos = (*strIt).find(','); | ||
462 | if ( pos > -1 ) | ||
463 | ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); | ||
464 | |||
465 | } | ||
466 | break; | ||
467 | } | ||
468 | /* Recurrence stuff below + post processing later */ | ||
469 | case FRType: | ||
470 | if ( val == "Daily" ) | ||
471 | recur()->setType( ORecur::Daily ); | ||
472 | else if ( val == "Weekly" ) | ||
473 | recur()->setType( ORecur::Weekly); | ||
474 | else if ( val == "MonthlyDay" ) | ||
475 | recur()->setType( ORecur::MonthlyDay ); | ||
476 | else if ( val == "MonthlyDate" ) | ||
477 | recur()->setType( ORecur::MonthlyDate ); | ||
478 | else if ( val == "Yearly" ) | ||
479 | recur()->setType( ORecur::Yearly ); | ||
480 | else | ||
481 | recur()->setType( ORecur::NoRepeat ); | ||
482 | break; | ||
483 | case FRWeekdays: | ||
484 | recur()->setDays( val.toInt() ); | ||
485 | break; | ||
486 | case FRPosition: | ||
487 | recur()->setPosition( val.toInt() ); | ||
488 | break; | ||
489 | case FRFreq: | ||
490 | recur()->setFrequency( val.toInt() ); | ||
491 | break; | ||
492 | case FRHasEndDate: | ||
493 | recur()->setHasEndDate( val.toInt() ); | ||
494 | break; | ||
495 | case FREndDate: { | ||
496 | rp_end = (time_t) val.toLong(); | ||
497 | break; | ||
498 | } | ||
499 | default: | ||
500 | ev.setCustomField( attr, val ); | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | // from PalmtopRecord... GPL ### FIXME | ||
506 | namespace { | ||
507 | QString customToXml(const QMap<QString, QString>& customMap ) | ||
508 | { | ||
509 | //qWarning(QString("writing custom %1").arg(customMap.count())); | ||
510 | QString buf(" "); | ||
511 | for ( QMap<QString, QString>::ConstIterator cit = customMap.begin(); | ||
512 | cit != customMap.end(); ++cit) { | ||
513 | // qWarning(".ITEM."); | ||
514 | buf += cit.key(); | ||
515 | buf += "=\""; | ||
516 | buf += Qtopia::escapeString(cit.data()); | ||
517 | buf += "\" "; | ||
518 | } | ||
519 | return buf; | ||
520 | } | ||
521 | |||
522 | |||
523 | } | ||
524 | |||
525 | QString OTodoAccessXML::toString( const OTodo& ev )const { | ||
526 | QString str; | ||
527 | |||
528 | str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; | ||
529 | str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; | ||
530 | str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; | ||
531 | str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; | ||
532 | |||
533 | str += "Categories=\"" + toString( ev.categories() ) + "\" "; | ||
534 | str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; | ||
535 | str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; | ||
536 | |||
537 | if ( ev.hasDueDate() ) { | ||
538 | str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; | ||
539 | str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; | ||
540 | str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; | ||
541 | } | ||
542 | // qWarning( "Uid %d", ev.uid() ); | ||
543 | str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; | ||
544 | |||
545 | // append the extra options | ||
546 | /* FIXME Qtopia::Record this is currently not | ||
547 | * possible you can set custom fields | ||
548 | * but don' iterate over the list | ||
549 | * I may do #define private protected | ||
550 | * for this case - cough --zecke | ||
551 | */ | ||
552 | /* | ||
553 | QMap<QString, QString> extras = ev.extras(); | ||
554 | QMap<QString, QString>::Iterator extIt; | ||
555 | for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) | ||
556 | str += extIt.key() + "=\"" + extIt.data() + "\" "; | ||
557 | */ | ||
558 | // cross refernce | ||
559 | if ( ev.hasRecurrence() ) { | ||
560 | str += ev.recurrence().toString(); | ||
561 | } | ||
562 | if ( ev.hasStartDate() ) | ||
563 | str += "StartDate=\""+ OConversion::dateToString( ev.startDate() ) +"\" "; | ||
564 | if ( ev.hasCompletedDate() ) | ||
565 | str += "CompletedDate=\""+ OConversion::dateToString( ev.completedDate() ) +"\" "; | ||
566 | if ( ev.hasState() ) | ||
567 | str += "State=\""+QString::number( ev.state().state() )+"\" "; | ||
568 | |||
569 | /* | ||
570 | * save reminders and notifiers! | ||
571 | * DATE_TIME:DURATION:SOUND:NOT_USED_YET;OTHER_DATE_TIME:OTHER_DURATION:SOUND:.... | ||
572 | */ | ||
573 | if ( ev.hasNotifiers() ) { | ||
574 | OPimNotifyManager manager = ev.notifiers(); | ||
575 | OPimNotifyManager::Alarms alarms = manager.alarms(); | ||
576 | if (!alarms.isEmpty() ) { | ||
577 | QStringList als; | ||
578 | OPimNotifyManager::Alarms::Iterator it = alarms.begin(); | ||
579 | for ( ; it != alarms.end(); ++it ) { | ||
580 | /* only if time is valid */ | ||
581 | if ( (*it).dateTime().isValid() ) { | ||
582 | als << OConversion::dateTimeToString( (*it).dateTime() ) | ||
583 | + ":" + QString::number( (*it).duration() ) | ||
584 | + ":" + QString::number( (*it).sound() ) | ||
585 | + ":"; | ||
586 | } | ||
587 | } | ||
588 | // now write the list | ||
589 | qWarning("als: %s", als.join("____________").latin1() ); | ||
590 | str += "Alarms=\""+als.join(";") +"\" "; | ||
591 | } | ||
592 | |||
593 | /* | ||
594 | * now the same for reminders but more easy. We just save the uid of the OEvent. | ||
595 | */ | ||
596 | OPimNotifyManager::Reminders reminders = manager.reminders(); | ||
597 | if (!reminders.isEmpty() ) { | ||
598 | OPimNotifyManager::Reminders::Iterator it = reminders.begin(); | ||
599 | QStringList records; | ||
600 | for ( ; it != reminders.end(); ++it ) { | ||
601 | records << QString::number( (*it).recordUid() ); | ||
602 | } | ||
603 | str += "Reminders=\""+ records.join(";") +"\" "; | ||
604 | } | ||
605 | } | ||
606 | str += customToXml( ev.toExtraMap() ); | ||
607 | |||
608 | |||
609 | return str; | ||
610 | } | ||
611 | QString OTodoAccessXML::toString( const QArray<int>& ints ) const { | ||
612 | return Qtopia::Record::idsToString( ints ); | ||
613 | } | ||
614 | |||
615 | /* internal class for sorting | ||
616 | * | ||
617 | * Inspired by todoxmlio.cpp from TT | ||
618 | */ | ||
619 | |||
620 | struct OTodoXMLContainer { | ||
621 | OTodo todo; | ||
622 | }; | ||
623 | |||
624 | namespace { | ||
625 | inline QString string( const OTodo& todo) { | ||
626 | return todo.summary().isEmpty() ? | ||
627 | todo.description().left(20 ) : | ||
628 | todo.summary(); | ||
629 | } | ||
630 | inline int completed( const OTodo& todo1, const OTodo& todo2) { | ||
631 | int ret = 0; | ||
632 | if ( todo1.isCompleted() ) ret++; | ||
633 | if ( todo2.isCompleted() ) ret--; | ||
634 | return ret; | ||
635 | } | ||
636 | inline int priority( const OTodo& t1, const OTodo& t2) { | ||
637 | return ( t1.priority() - t2.priority() ); | ||
638 | } | ||
639 | inline int description( const OTodo& t1, const OTodo& t2) { | ||
640 | return QString::compare( string(t1), string(t2) ); | ||
641 | } | ||
642 | inline int deadline( const OTodo& t1, const OTodo& t2) { | ||
643 | int ret = 0; | ||
644 | if ( t1.hasDueDate() && | ||
645 | t2.hasDueDate() ) | ||
646 | ret = t2.dueDate().daysTo( t1.dueDate() ); | ||
647 | else if ( t1.hasDueDate() ) | ||
648 | ret = -1; | ||
649 | else if ( t2.hasDueDate() ) | ||
650 | ret = 1; | ||
651 | else | ||
652 | ret = 0; | ||
653 | |||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | }; | ||
658 | |||
659 | /* | ||
660 | * Returns: | ||
661 | * 0 if item1 == item2 | ||
662 | * | ||
663 | * non-zero if item1 != item2 | ||
664 | * | ||
665 | * This function returns int rather than bool so that reimplementations | ||
666 | * can return one of three values and use it to sort by: | ||
667 | * | ||
668 | * 0 if item1 == item2 | ||
669 | * | ||
670 | * > 0 (positive integer) if item1 > item2 | ||
671 | * | ||
672 | * < 0 (negative integer) if item1 < item2 | ||
673 | * | ||
674 | */ | ||
675 | class OTodoXMLVector : public QVector<OTodoXMLContainer> { | ||
676 | public: | ||
677 | OTodoXMLVector(int size, bool asc, int sort) | ||
678 | : QVector<OTodoXMLContainer>( size ) | ||
679 | { | ||
680 | setAutoDelete( true ); | ||
681 | m_asc = asc; | ||
682 | m_sort = sort; | ||
683 | } | ||
684 | /* return the summary/description */ | ||
685 | QString string( const OTodo& todo) { | ||
686 | return todo.summary().isEmpty() ? | ||
687 | todo.description().left(20 ) : | ||
688 | todo.summary(); | ||
689 | } | ||
690 | /** | ||
691 | * we take the sortorder( switch on it ) | ||
692 | * | ||
693 | */ | ||
694 | int compareItems( Item d1, Item d2 ) { | ||
695 | bool seComp, sePrio, seDesc, seDeadline; | ||
696 | seComp = sePrio = seDeadline = seDesc = false; | ||
697 | int ret =0; | ||
698 | OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; | ||
699 | OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; | ||
700 | |||
701 | /* same item */ | ||
702 | if ( con1->todo.uid() == con2->todo.uid() ) | ||
703 | return 0; | ||
704 | |||
705 | switch ( m_sort ) { | ||
706 | /* completed */ | ||
707 | case 0: { | ||
708 | ret = completed( con1->todo, con2->todo ); | ||
709 | seComp = TRUE; | ||
710 | break; | ||
711 | } | ||
712 | /* priority */ | ||
713 | case 1: { | ||
714 | ret = priority( con1->todo, con2->todo ); | ||
715 | sePrio = TRUE; | ||
716 | break; | ||
717 | } | ||
718 | /* description */ | ||
719 | case 2: { | ||
720 | ret = description( con1->todo, con2->todo ); | ||
721 | seDesc = TRUE; | ||
722 | break; | ||
723 | } | ||
724 | /* deadline */ | ||
725 | case 3: { | ||
726 | ret = deadline( con1->todo, con2->todo ); | ||
727 | seDeadline = TRUE; | ||
728 | break; | ||
729 | } | ||
730 | default: | ||
731 | ret = 0; | ||
732 | break; | ||
733 | }; | ||
734 | /* | ||
735 | * FIXME do better sorting if the first sort criteria | ||
736 | * ret equals 0 start with complete and so on... | ||
737 | */ | ||
738 | |||
739 | /* twist it we're not ascending*/ | ||
740 | if (!m_asc) | ||
741 | ret = ret * -1; | ||
742 | |||
743 | if ( ret ) | ||
744 | return ret; | ||
745 | |||
746 | // default did not gave difference let's try it other way around | ||
747 | /* | ||
748 | * General try if already checked if not test | ||
749 | * and return | ||
750 | * 1.Completed | ||
751 | * 2.Priority | ||
752 | * 3.Description | ||
753 | * 4.DueDate | ||
754 | */ | ||
755 | if (!seComp ) { | ||
756 | if ( (ret = completed( con1->todo, con2->todo ) ) ) { | ||
757 | if (!m_asc ) ret *= -1; | ||
758 | return ret; | ||
759 | } | ||
760 | } | ||
761 | if (!sePrio ) { | ||
762 | if ( (ret = priority( con1->todo, con2->todo ) ) ) { | ||
763 | if (!m_asc ) ret *= -1; | ||
764 | return ret; | ||
765 | } | ||
766 | } | ||
767 | if (!seDesc ) { | ||
768 | if ( (ret = description(con1->todo, con2->todo ) ) ) { | ||
769 | if (!m_asc) ret *= -1; | ||
770 | return ret; | ||
771 | } | ||
772 | } | ||
773 | if (!seDeadline) { | ||
774 | if ( (ret = deadline( con1->todo, con2->todo ) ) ) { | ||
775 | if (!m_asc) ret *= -1; | ||
776 | return ret; | ||
777 | } | ||
778 | } | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | private: | ||
783 | bool m_asc; | ||
784 | int m_sort; | ||
785 | |||
786 | }; | ||
787 | |||
788 | QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, | ||
789 | int sortFilter, int cat ) { | ||
790 | OTodoXMLVector vector(m_events.count(), asc,sortOrder ); | ||
791 | QMap<int, OTodo>::Iterator it; | ||
792 | int item = 0; | ||
793 | |||
794 | bool bCat = sortFilter & 1 ? true : false; | ||
795 | bool bOnly = sortFilter & 2 ? true : false; | ||
796 | bool comp = sortFilter & 4 ? true : false; | ||
797 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
798 | |||
799 | /* show category */ | ||
800 | /* -1 == unfiled */ | ||
801 | if ( bCat && cat == -1 ) { | ||
802 | if(!(*it).categories().isEmpty() ) | ||
803 | continue; | ||
804 | }else if ( bCat && cat != 0) | ||
805 | if (!(*it).categories().contains( cat ) ) { | ||
806 | continue; | ||
807 | } | ||
808 | /* isOverdue but we should not show overdue - why?*/ | ||
809 | /* if ( (*it).isOverdue() && !bOnly ) { | ||
810 | qWarning("item is overdue but !bOnly"); | ||
811 | continue; | ||
812 | } | ||
813 | */ | ||
814 | if ( !(*it).isOverdue() && bOnly ) { | ||
815 | continue; | ||
816 | } | ||
817 | |||
818 | if ((*it).isCompleted() && comp ) { | ||
819 | continue; | ||
820 | } | ||
821 | |||
822 | |||
823 | OTodoXMLContainer* con = new OTodoXMLContainer(); | ||
824 | con->todo = (*it); | ||
825 | vector.insert(item, con ); | ||
826 | item++; | ||
827 | } | ||
828 | vector.resize( item ); | ||
829 | /* sort it now */ | ||
830 | vector.sort(); | ||
831 | /* now get the uids */ | ||
832 | QArray<int> array( vector.count() ); | ||
833 | for (uint i= 0; i < vector.count(); i++ ) { | ||
834 | array[i] = ( vector.at(i) )->todo.uid(); | ||
835 | } | ||
836 | return array; | ||
837 | }; | ||
838 | void OTodoAccessXML::removeAllCompleted() { | ||
839 | QMap<int, OTodo> events = m_events; | ||
840 | for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { | ||
841 | if ( (*it).isCompleted() ) | ||
842 | events.remove( it.key() ); | ||
843 | } | ||
844 | m_events = events; | ||
845 | } | ||
846 | QBitArray OTodoAccessXML::supports()const { | ||
847 | static QBitArray ar = sup(); | ||
848 | return ar; | ||
849 | } | ||
850 | QBitArray OTodoAccessXML::sup() { | ||
851 | QBitArray ar( OTodo::CompletedDate +1 ); | ||
852 | ar.fill( true ); | ||
853 | ar[OTodo::CrossReference] = false; | ||
854 | ar[OTodo::State ] = false; | ||
855 | ar[OTodo::Reminders] = false; | ||
856 | ar[OTodo::Notifiers] = false; | ||
857 | ar[OTodo::Maintainer] = false; | ||
858 | |||
859 | return ar; | ||
860 | } | ||
861 | QArray<int> OTodoAccessXML::matchRegexp( const QRegExp &r ) const | ||
862 | { | ||
863 | QArray<int> m_currentQuery( m_events.count() ); | ||
864 | uint arraycounter = 0; | ||
865 | |||
866 | QMap<int, OTodo>::ConstIterator it; | ||
867 | for (it = m_events.begin(); it != m_events.end(); ++it ) { | ||
868 | if ( it.data().match( r ) ) | ||
869 | m_currentQuery[arraycounter++] = it.data().uid(); | ||
870 | |||
871 | } | ||
872 | // Shrink to fit.. | ||
873 | m_currentQuery.resize(arraycounter); | ||
874 | |||
875 | return m_currentQuery; | ||
876 | } | ||