summaryrefslogtreecommitdiff
authorzecke <zecke>2003-05-07 16:03:03 (UTC)
committer zecke <zecke>2003-05-07 16:03:03 (UTC)
commit7c8110d568ac60517916114ac5fc4e850156d4e5 (patch) (unidiff)
treecb4ffab444f078f013de7edd3d180e2e80b23ffa
parentaccd04a63230ac46978f77deae1b0d1419618730 (diff)
downloadopie-7c8110d568ac60517916114ac5fc4e850156d4e5.zip
opie-7c8110d568ac60517916114ac5fc4e850156d4e5.tar.gz
opie-7c8110d568ac60517916114ac5fc4e850156d4e5.tar.bz2
Save recurrence
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/pim/otodoaccessxml.cpp4
-rw-r--r--libopie2/opiepim/backend/otodoaccessxml.cpp4
2 files changed, 6 insertions, 2 deletions
diff --git a/libopie/pim/otodoaccessxml.cpp b/libopie/pim/otodoaccessxml.cpp
index 55f268b..c0d8dfc 100644
--- a/libopie/pim/otodoaccessxml.cpp
+++ b/libopie/pim/otodoaccessxml.cpp
@@ -1,145 +1,146 @@
1#include <errno.h> 1#include <errno.h>
2#include <fcntl.h> 2#include <fcntl.h>
3 3
4#include <sys/mman.h> 4#include <sys/mman.h>
5#include <sys/stat.h> 5#include <sys/stat.h>
6#include <sys/types.h> 6#include <sys/types.h>
7 7
8#include <unistd.h> 8#include <unistd.h>
9 9
10 10
11#include <qfile.h> 11#include <qfile.h>
12#include <qvector.h> 12#include <qvector.h>
13 13
14#include <qpe/global.h> 14#include <qpe/global.h>
15#include <qpe/stringutil.h> 15#include <qpe/stringutil.h>
16#include <qpe/timeconversion.h> 16#include <qpe/timeconversion.h>
17 17
18#include "orecur.h"
18#include "otodoaccessxml.h" 19#include "otodoaccessxml.h"
19 20
20namespace { 21namespace {
21 // FROM TT again 22 // FROM TT again
22char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) 23char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
23{ 24{
24 char needleChar; 25 char needleChar;
25 char haystackChar; 26 char haystackChar;
26 if (!needle || !haystack || !hLen || !nLen) 27 if (!needle || !haystack || !hLen || !nLen)
27 return 0; 28 return 0;
28 29
29 const char* hsearch = haystack; 30 const char* hsearch = haystack;
30 31
31 if ((needleChar = *needle++) != 0) { 32 if ((needleChar = *needle++) != 0) {
32 nLen--; //(to make up for needle++) 33 nLen--; //(to make up for needle++)
33 do { 34 do {
34 do { 35 do {
35 if ((haystackChar = *hsearch++) == 0) 36 if ((haystackChar = *hsearch++) == 0)
36 return (0); 37 return (0);
37 if (hsearch >= haystack + hLen) 38 if (hsearch >= haystack + hLen)
38 return (0); 39 return (0);
39 } while (haystackChar != needleChar); 40 } while (haystackChar != needleChar);
40 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); 41 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
41 hsearch--; 42 hsearch--;
42 } 43 }
43 return ((char *)hsearch); 44 return ((char *)hsearch);
44} 45}
45} 46}
46 47
47 48
48OTodoAccessXML::OTodoAccessXML( const QString& appName, 49OTodoAccessXML::OTodoAccessXML( const QString& appName,
49 const QString& fileName ) 50 const QString& fileName )
50 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) 51 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false )
51{ 52{
52 if (!fileName.isEmpty() ) 53 if (!fileName.isEmpty() )
53 m_file = fileName; 54 m_file = fileName;
54 else 55 else
55 m_file = Global::applicationFileName( "todolist", "todolist.xml" ); 56 m_file = Global::applicationFileName( "todolist", "todolist.xml" );
56} 57}
57OTodoAccessXML::~OTodoAccessXML() { 58OTodoAccessXML::~OTodoAccessXML() {
58 59
59} 60}
60bool OTodoAccessXML::load() { 61bool OTodoAccessXML::load() {
61 m_opened = true; 62 m_opened = true;
62 m_changed = false; 63 m_changed = false;
63 /* initialize dict */ 64 /* initialize dict */
64 /* 65 /*
65 * UPDATE dict if you change anything!!! 66 * UPDATE dict if you change anything!!!
66 */ 67 */
67 QAsciiDict<int> dict(21); 68 QAsciiDict<int> dict(21);
68 dict.setAutoDelete( TRUE ); 69 dict.setAutoDelete( TRUE );
69 dict.insert("Categories" , new int(OTodo::Category) ); 70 dict.insert("Categories" , new int(OTodo::Category) );
70 dict.insert("Uid" , new int(OTodo::Uid) ); 71 dict.insert("Uid" , new int(OTodo::Uid) );
71 dict.insert("HasDate" , new int(OTodo::HasDate) ); 72 dict.insert("HasDate" , new int(OTodo::HasDate) );
72 dict.insert("Completed" , new int(OTodo::Completed) ); 73 dict.insert("Completed" , new int(OTodo::Completed) );
73 dict.insert("Description" , new int(OTodo::Description) ); 74 dict.insert("Description" , new int(OTodo::Description) );
74 dict.insert("Summary" , new int(OTodo::Summary) ); 75 dict.insert("Summary" , new int(OTodo::Summary) );
75 dict.insert("Priority" , new int(OTodo::Priority) ); 76 dict.insert("Priority" , new int(OTodo::Priority) );
76 dict.insert("DateDay" , new int(OTodo::DateDay) ); 77 dict.insert("DateDay" , new int(OTodo::DateDay) );
77 dict.insert("DateMonth" , new int(OTodo::DateMonth) ); 78 dict.insert("DateMonth" , new int(OTodo::DateMonth) );
78 dict.insert("DateYear" , new int(OTodo::DateYear) ); 79 dict.insert("DateYear" , new int(OTodo::DateYear) );
79 dict.insert("Progress" , new int(OTodo::Progress) ); 80 dict.insert("Progress" , new int(OTodo::Progress) );
80 dict.insert("Completed", new int(OTodo::Completed) ); 81 dict.insert("Completed", new int(OTodo::Completed) );
81 dict.insert("CrossReference", new int(OTodo::CrossReference) ); 82 dict.insert("CrossReference", new int(OTodo::CrossReference) );
82 dict.insert("State", new int(OTodo::State) ); 83 dict.insert("State", new int(OTodo::State) );
83 dict.insert("Recurrence", new int(OTodo::Recurrence) ); 84 dict.insert("Recurrence", new int(OTodo::Recurrence) );
84 dict.insert("Alarms", new int(OTodo::Alarms) ); 85 dict.insert("Alarms", new int(OTodo::Alarms) );
85 dict.insert("Reminders", new int(OTodo::Reminders) ); 86 dict.insert("Reminders", new int(OTodo::Reminders) );
86 dict.insert("Notifiers", new int(OTodo::Notifiers) ); 87 dict.insert("Notifiers", new int(OTodo::Notifiers) );
87 dict.insert("Maintainer", new int(OTodo::Maintainer) ); 88 dict.insert("Maintainer", new int(OTodo::Maintainer) );
88 89
89 // here the custom XML parser from TT it's GPL 90 // here the custom XML parser from TT it's GPL
90 // but we want to push OpiePIM... to TT..... 91 // but we want to push OpiePIM... to TT.....
91 // mmap part from zecke :) 92 // mmap part from zecke :)
92 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); 93 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY );
93 struct stat attribut; 94 struct stat attribut;
94 if ( fd < 0 ) return false; 95 if ( fd < 0 ) return false;
95 96
96 if ( fstat(fd, &attribut ) == -1 ) { 97 if ( fstat(fd, &attribut ) == -1 ) {
97 ::close( fd ); 98 ::close( fd );
98 return false; 99 return false;
99 } 100 }
100 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); 101 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 );
101 if ( map_addr == ( (caddr_t)-1) ) { 102 if ( map_addr == ( (caddr_t)-1) ) {
102 ::close(fd ); 103 ::close(fd );
103 return false; 104 return false;
104 } 105 }
105 /* advise the kernel who we want to read it */ 106 /* advise the kernel who we want to read it */
106 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); 107 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL );
107 /* we do not the file any more */ 108 /* we do not the file any more */
108 ::close( fd ); 109 ::close( fd );
109 110
110 char* dt = (char*)map_addr; 111 char* dt = (char*)map_addr;
111 int len = attribut.st_size; 112 int len = attribut.st_size;
112 int i = 0; 113 int i = 0;
113 char *point; 114 char *point;
114 const char* collectionString = "<Task "; 115 const char* collectionString = "<Task ";
115 int strLen = strlen(collectionString); 116 int strLen = strlen(collectionString);
116 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { 117 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) {
117 i = point -dt; 118 i = point -dt;
118 i+= strLen; 119 i+= strLen;
119 qWarning("Found a start at %d %d", i, (point-dt) ); 120 qWarning("Found a start at %d %d", i, (point-dt) );
120 121
121 OTodo ev; 122 OTodo ev;
122 m_year = m_month = m_day = 0; 123 m_year = m_month = m_day = 0;
123 124
124 while ( TRUE ) { 125 while ( TRUE ) {
125 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) 126 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
126 ++i; 127 ++i;
127 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) 128 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
128 break; 129 break;
129 130
130 // we have another attribute, read it. 131 // we have another attribute, read it.
131 int j = i; 132 int j = i;
132 while ( j < len && dt[j] != '=' ) 133 while ( j < len && dt[j] != '=' )
133 ++j; 134 ++j;
134 QCString attr( dt+i, j-i+1); 135 QCString attr( dt+i, j-i+1);
135 136
136 i = ++j; // skip = 137 i = ++j; // skip =
137 138
138 // find the start of quotes 139 // find the start of quotes
139 while ( i < len && dt[i] != '"' ) 140 while ( i < len && dt[i] != '"' )
140 ++i; 141 ++i;
141 j = ++i; 142 j = ++i;
142 143
143 bool haveUtf = FALSE; 144 bool haveUtf = FALSE;
144 bool haveEnt = FALSE; 145 bool haveEnt = FALSE;
145 while ( j < len && dt[j] != '"' ) { 146 while ( j < len && dt[j] != '"' ) {
@@ -309,257 +310,258 @@ QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
309 }else if ( it.data().dueDate() >= start && 310 }else if ( it.data().dueDate() >= start &&
310 it.data().dueDate() <= end ) { 311 it.data().dueDate() <= end ) {
311 ids[i] = it.key(); 312 ids[i] = it.key();
312 i++; 313 i++;
313 } 314 }
314 } 315 }
315 ids.resize( i ); 316 ids.resize( i );
316 return ids; 317 return ids;
317} 318}
318QArray<int> OTodoAccessXML::overDue() { 319QArray<int> OTodoAccessXML::overDue() {
319 QArray<int> ids( m_events.count() ); 320 QArray<int> ids( m_events.count() );
320 int i = 0; 321 int i = 0;
321 322
322 QMap<int, OTodo>::Iterator it; 323 QMap<int, OTodo>::Iterator it;
323 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 324 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
324 if ( it.data().isOverdue() ) { 325 if ( it.data().isOverdue() ) {
325 ids[i] = it.key(); 326 ids[i] = it.key();
326 i++; 327 i++;
327 } 328 }
328 } 329 }
329 ids.resize( i ); 330 ids.resize( i );
330 return ids; 331 return ids;
331} 332}
332 333
333 334
334/* private */ 335/* private */
335void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, 336void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev,
336 const QCString& attr, const QString& val) { 337 const QCString& attr, const QString& val) {
337// qWarning("parse to do from XMLElement" ); 338// qWarning("parse to do from XMLElement" );
338 339
339 int *find=0; 340 int *find=0;
340 341
341 find = (*dict)[ attr.data() ]; 342 find = (*dict)[ attr.data() ];
342 if (!find ) { 343 if (!find ) {
343// qWarning("Unknown option" + it.key() ); 344// qWarning("Unknown option" + it.key() );
344 ev.setCustomField( attr, val ); 345 ev.setCustomField( attr, val );
345 return; 346 return;
346 } 347 }
347 348
348 switch( *find ) { 349 switch( *find ) {
349 case OTodo::Uid: 350 case OTodo::Uid:
350 ev.setUid( val.toInt() ); 351 ev.setUid( val.toInt() );
351 break; 352 break;
352 case OTodo::Category: 353 case OTodo::Category:
353 ev.setCategories( ev.idsFromString( val ) ); 354 ev.setCategories( ev.idsFromString( val ) );
354 break; 355 break;
355 case OTodo::HasDate: 356 case OTodo::HasDate:
356 ev.setHasDueDate( val.toInt() ); 357 ev.setHasDueDate( val.toInt() );
357 break; 358 break;
358 case OTodo::Completed: 359 case OTodo::Completed:
359 ev.setCompleted( val.toInt() ); 360 ev.setCompleted( val.toInt() );
360 break; 361 break;
361 case OTodo::Description: 362 case OTodo::Description:
362 ev.setDescription( val ); 363 ev.setDescription( val );
363 break; 364 break;
364 case OTodo::Summary: 365 case OTodo::Summary:
365 ev.setSummary( val ); 366 ev.setSummary( val );
366 break; 367 break;
367 case OTodo::Priority: 368 case OTodo::Priority:
368 ev.setPriority( val.toInt() ); 369 ev.setPriority( val.toInt() );
369 break; 370 break;
370 case OTodo::DateDay: 371 case OTodo::DateDay:
371 m_day = val.toInt(); 372 m_day = val.toInt();
372 break; 373 break;
373 case OTodo::DateMonth: 374 case OTodo::DateMonth:
374 m_month = val.toInt(); 375 m_month = val.toInt();
375 break; 376 break;
376 case OTodo::DateYear: 377 case OTodo::DateYear:
377 m_year = val.toInt(); 378 m_year = val.toInt();
378 break; 379 break;
379 case OTodo::Progress: 380 case OTodo::Progress:
380 ev.setProgress( val.toInt() ); 381 ev.setProgress( val.toInt() );
381 break; 382 break;
382 case OTodo::CrossReference: 383 case OTodo::CrossReference:
383 { 384 {
384 /* 385 /*
385 * A cross refernce looks like 386 * A cross refernce looks like
386 * appname,id;appname,id 387 * appname,id;appname,id
387 * we need to split it up 388 * we need to split it up
388 */ 389 */
389 QStringList refs = QStringList::split(';', val ); 390 QStringList refs = QStringList::split(';', val );
390 QStringList::Iterator strIt; 391 QStringList::Iterator strIt;
391 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { 392 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) {
392 int pos = (*strIt).find(','); 393 int pos = (*strIt).find(',');
393 if ( pos > -1 ) 394 if ( pos > -1 )
394 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); 395 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() );
395 396
396 } 397 }
397 break; 398 break;
398 } 399 }
399 default: 400 default:
400 break; 401 break;
401 } 402 }
402} 403}
403QString OTodoAccessXML::toString( const OTodo& ev )const { 404QString OTodoAccessXML::toString( const OTodo& ev )const {
404 QString str; 405 QString str;
405 406
406 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; 407 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" ";
407 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; 408 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" ";
408 str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; 409 str += "Priority=\"" + QString::number( ev.priority() ) + "\" ";
409 str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; 410 str += "Progress=\"" + QString::number(ev.progress() ) + "\" ";
410 411
411 str += "Categories=\"" + toString( ev.categories() ) + "\" "; 412 str += "Categories=\"" + toString( ev.categories() ) + "\" ";
412 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; 413 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" ";
413 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; 414 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" ";
414 415
415 if ( ev.hasDueDate() ) { 416 if ( ev.hasDueDate() ) {
416 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; 417 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" ";
417 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; 418 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" ";
418 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; 419 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" ";
419 } 420 }
420// qWarning( "Uid %d", ev.uid() ); 421// qWarning( "Uid %d", ev.uid() );
421 str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; 422 str += "Uid=\"" + QString::number( ev.uid() ) + "\" ";
422 423
423// append the extra options 424// append the extra options
424 /* FIXME Qtopia::Record this is currently not 425 /* FIXME Qtopia::Record this is currently not
425 * possible you can set custom fields 426 * possible you can set custom fields
426 * but don' iterate over the list 427 * but don' iterate over the list
427 * I may do #define private protected 428 * I may do #define private protected
428 * for this case - cough --zecke 429 * for this case - cough --zecke
429 */ 430 */
430 /* 431 /*
431 QMap<QString, QString> extras = ev.extras(); 432 QMap<QString, QString> extras = ev.extras();
432 QMap<QString, QString>::Iterator extIt; 433 QMap<QString, QString>::Iterator extIt;
433 for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) 434 for (extIt = extras.begin(); extIt != extras.end(); ++extIt )
434 str += extIt.key() + "=\"" + extIt.data() + "\" "; 435 str += extIt.key() + "=\"" + extIt.data() + "\" ";
435 */ 436 */
436 // cross refernce 437 // cross refernce
437 438 if ( ev.hasRecurrence() )
439 str += ev.recurrence().toString();
438 440
439 return str; 441 return str;
440} 442}
441QString OTodoAccessXML::toString( const QArray<int>& ints ) const { 443QString OTodoAccessXML::toString( const QArray<int>& ints ) const {
442 return Qtopia::Record::idsToString( ints ); 444 return Qtopia::Record::idsToString( ints );
443} 445}
444 446
445/* internal class for sorting 447/* internal class for sorting
446 * 448 *
447 * Inspired by todoxmlio.cpp from TT 449 * Inspired by todoxmlio.cpp from TT
448 */ 450 */
449 451
450struct OTodoXMLContainer { 452struct OTodoXMLContainer {
451 OTodo todo; 453 OTodo todo;
452}; 454};
453 455
454namespace { 456namespace {
455 inline QString string( const OTodo& todo) { 457 inline QString string( const OTodo& todo) {
456 return todo.summary().isEmpty() ? 458 return todo.summary().isEmpty() ?
457 todo.description().left(20 ) : 459 todo.description().left(20 ) :
458 todo.summary(); 460 todo.summary();
459 } 461 }
460 inline int completed( const OTodo& todo1, const OTodo& todo2) { 462 inline int completed( const OTodo& todo1, const OTodo& todo2) {
461 int ret = 0; 463 int ret = 0;
462 if ( todo1.isCompleted() ) ret++; 464 if ( todo1.isCompleted() ) ret++;
463 if ( todo2.isCompleted() ) ret--; 465 if ( todo2.isCompleted() ) ret--;
464 return ret; 466 return ret;
465 } 467 }
466 inline int priority( const OTodo& t1, const OTodo& t2) { 468 inline int priority( const OTodo& t1, const OTodo& t2) {
467 return ( t1.priority() - t2.priority() ); 469 return ( t1.priority() - t2.priority() );
468 } 470 }
469 inline int description( const OTodo& t1, const OTodo& t2) { 471 inline int description( const OTodo& t1, const OTodo& t2) {
470 return QString::compare( string(t1), string(t2) ); 472 return QString::compare( string(t1), string(t2) );
471 } 473 }
472 inline int deadline( const OTodo& t1, const OTodo& t2) { 474 inline int deadline( const OTodo& t1, const OTodo& t2) {
473 int ret = 0; 475 int ret = 0;
474 if ( t1.hasDueDate() && 476 if ( t1.hasDueDate() &&
475 t2.hasDueDate() ) 477 t2.hasDueDate() )
476 ret = t2.dueDate().daysTo( t1.dueDate() ); 478 ret = t2.dueDate().daysTo( t1.dueDate() );
477 else if ( t1.hasDueDate() ) 479 else if ( t1.hasDueDate() )
478 ret = -1; 480 ret = -1;
479 else if ( t2.hasDueDate() ) 481 else if ( t2.hasDueDate() )
480 ret = 1; 482 ret = 1;
481 else 483 else
482 ret = 0; 484 ret = 0;
483 485
484 return ret; 486 return ret;
485 } 487 }
486 488
487}; 489};
488 490
489/* 491/*
490 * Returns: 492 * Returns:
491 * 0 if item1 == item2 493 * 0 if item1 == item2
492 * 494 *
493 * non-zero if item1 != item2 495 * non-zero if item1 != item2
494 * 496 *
495 * This function returns int rather than bool so that reimplementations 497 * This function returns int rather than bool so that reimplementations
496 * can return one of three values and use it to sort by: 498 * can return one of three values and use it to sort by:
497 * 499 *
498 * 0 if item1 == item2 500 * 0 if item1 == item2
499 * 501 *
500 * > 0 (positive integer) if item1 > item2 502 * > 0 (positive integer) if item1 > item2
501 * 503 *
502 * < 0 (negative integer) if item1 < item2 504 * < 0 (negative integer) if item1 < item2
503 * 505 *
504 */ 506 */
505class OTodoXMLVector : public QVector<OTodoXMLContainer> { 507class OTodoXMLVector : public QVector<OTodoXMLContainer> {
506public: 508public:
507 OTodoXMLVector(int size, bool asc, int sort) 509 OTodoXMLVector(int size, bool asc, int sort)
508 : QVector<OTodoXMLContainer>( size ) 510 : QVector<OTodoXMLContainer>( size )
509 { 511 {
510 setAutoDelete( true ); 512 setAutoDelete( true );
511 m_asc = asc; 513 m_asc = asc;
512 m_sort = sort; 514 m_sort = sort;
513 } 515 }
514 /* return the summary/description */ 516 /* return the summary/description */
515 QString string( const OTodo& todo) { 517 QString string( const OTodo& todo) {
516 return todo.summary().isEmpty() ? 518 return todo.summary().isEmpty() ?
517 todo.description().left(20 ) : 519 todo.description().left(20 ) :
518 todo.summary(); 520 todo.summary();
519 } 521 }
520 /** 522 /**
521 * we take the sortorder( switch on it ) 523 * we take the sortorder( switch on it )
522 * 524 *
523 */ 525 */
524 int compareItems( Item d1, Item d2 ) { 526 int compareItems( Item d1, Item d2 ) {
525 bool seComp, sePrio, seDesc, seDeadline; 527 bool seComp, sePrio, seDesc, seDeadline;
526 seComp = sePrio = seDeadline = seDesc = false; 528 seComp = sePrio = seDeadline = seDesc = false;
527 int ret =0; 529 int ret =0;
528 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; 530 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1;
529 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; 531 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2;
530 532
531 /* same item */ 533 /* same item */
532 if ( con1->todo.uid() == con2->todo.uid() ) 534 if ( con1->todo.uid() == con2->todo.uid() )
533 return 0; 535 return 0;
534 536
535 switch ( m_sort ) { 537 switch ( m_sort ) {
536 /* completed */ 538 /* completed */
537 case 0: { 539 case 0: {
538 ret = completed( con1->todo, con2->todo ); 540 ret = completed( con1->todo, con2->todo );
539 seComp = TRUE; 541 seComp = TRUE;
540 break; 542 break;
541 } 543 }
542 /* priority */ 544 /* priority */
543 case 1: { 545 case 1: {
544 ret = priority( con1->todo, con2->todo ); 546 ret = priority( con1->todo, con2->todo );
545 sePrio = TRUE; 547 sePrio = TRUE;
546 break; 548 break;
547 } 549 }
548 /* description */ 550 /* description */
549 case 2: { 551 case 2: {
550 ret = description( con1->todo, con2->todo ); 552 ret = description( con1->todo, con2->todo );
551 seDesc = TRUE; 553 seDesc = TRUE;
552 break; 554 break;
553 } 555 }
554 /* deadline */ 556 /* deadline */
555 case 3: { 557 case 3: {
556 ret = deadline( con1->todo, con2->todo ); 558 ret = deadline( con1->todo, con2->todo );
557 seDeadline = TRUE; 559 seDeadline = TRUE;
558 break; 560 break;
559 } 561 }
560 default: 562 default:
561 ret = 0; 563 ret = 0;
562 break; 564 break;
563 }; 565 };
564 /* 566 /*
565 * FIXME do better sorting if the first sort criteria 567 * FIXME do better sorting if the first sort criteria
diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp
index 55f268b..c0d8dfc 100644
--- a/libopie2/opiepim/backend/otodoaccessxml.cpp
+++ b/libopie2/opiepim/backend/otodoaccessxml.cpp
@@ -1,145 +1,146 @@
1#include <errno.h> 1#include <errno.h>
2#include <fcntl.h> 2#include <fcntl.h>
3 3
4#include <sys/mman.h> 4#include <sys/mman.h>
5#include <sys/stat.h> 5#include <sys/stat.h>
6#include <sys/types.h> 6#include <sys/types.h>
7 7
8#include <unistd.h> 8#include <unistd.h>
9 9
10 10
11#include <qfile.h> 11#include <qfile.h>
12#include <qvector.h> 12#include <qvector.h>
13 13
14#include <qpe/global.h> 14#include <qpe/global.h>
15#include <qpe/stringutil.h> 15#include <qpe/stringutil.h>
16#include <qpe/timeconversion.h> 16#include <qpe/timeconversion.h>
17 17
18#include "orecur.h"
18#include "otodoaccessxml.h" 19#include "otodoaccessxml.h"
19 20
20namespace { 21namespace {
21 // FROM TT again 22 // FROM TT again
22char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) 23char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
23{ 24{
24 char needleChar; 25 char needleChar;
25 char haystackChar; 26 char haystackChar;
26 if (!needle || !haystack || !hLen || !nLen) 27 if (!needle || !haystack || !hLen || !nLen)
27 return 0; 28 return 0;
28 29
29 const char* hsearch = haystack; 30 const char* hsearch = haystack;
30 31
31 if ((needleChar = *needle++) != 0) { 32 if ((needleChar = *needle++) != 0) {
32 nLen--; //(to make up for needle++) 33 nLen--; //(to make up for needle++)
33 do { 34 do {
34 do { 35 do {
35 if ((haystackChar = *hsearch++) == 0) 36 if ((haystackChar = *hsearch++) == 0)
36 return (0); 37 return (0);
37 if (hsearch >= haystack + hLen) 38 if (hsearch >= haystack + hLen)
38 return (0); 39 return (0);
39 } while (haystackChar != needleChar); 40 } while (haystackChar != needleChar);
40 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); 41 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
41 hsearch--; 42 hsearch--;
42 } 43 }
43 return ((char *)hsearch); 44 return ((char *)hsearch);
44} 45}
45} 46}
46 47
47 48
48OTodoAccessXML::OTodoAccessXML( const QString& appName, 49OTodoAccessXML::OTodoAccessXML( const QString& appName,
49 const QString& fileName ) 50 const QString& fileName )
50 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) 51 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false )
51{ 52{
52 if (!fileName.isEmpty() ) 53 if (!fileName.isEmpty() )
53 m_file = fileName; 54 m_file = fileName;
54 else 55 else
55 m_file = Global::applicationFileName( "todolist", "todolist.xml" ); 56 m_file = Global::applicationFileName( "todolist", "todolist.xml" );
56} 57}
57OTodoAccessXML::~OTodoAccessXML() { 58OTodoAccessXML::~OTodoAccessXML() {
58 59
59} 60}
60bool OTodoAccessXML::load() { 61bool OTodoAccessXML::load() {
61 m_opened = true; 62 m_opened = true;
62 m_changed = false; 63 m_changed = false;
63 /* initialize dict */ 64 /* initialize dict */
64 /* 65 /*
65 * UPDATE dict if you change anything!!! 66 * UPDATE dict if you change anything!!!
66 */ 67 */
67 QAsciiDict<int> dict(21); 68 QAsciiDict<int> dict(21);
68 dict.setAutoDelete( TRUE ); 69 dict.setAutoDelete( TRUE );
69 dict.insert("Categories" , new int(OTodo::Category) ); 70 dict.insert("Categories" , new int(OTodo::Category) );
70 dict.insert("Uid" , new int(OTodo::Uid) ); 71 dict.insert("Uid" , new int(OTodo::Uid) );
71 dict.insert("HasDate" , new int(OTodo::HasDate) ); 72 dict.insert("HasDate" , new int(OTodo::HasDate) );
72 dict.insert("Completed" , new int(OTodo::Completed) ); 73 dict.insert("Completed" , new int(OTodo::Completed) );
73 dict.insert("Description" , new int(OTodo::Description) ); 74 dict.insert("Description" , new int(OTodo::Description) );
74 dict.insert("Summary" , new int(OTodo::Summary) ); 75 dict.insert("Summary" , new int(OTodo::Summary) );
75 dict.insert("Priority" , new int(OTodo::Priority) ); 76 dict.insert("Priority" , new int(OTodo::Priority) );
76 dict.insert("DateDay" , new int(OTodo::DateDay) ); 77 dict.insert("DateDay" , new int(OTodo::DateDay) );
77 dict.insert("DateMonth" , new int(OTodo::DateMonth) ); 78 dict.insert("DateMonth" , new int(OTodo::DateMonth) );
78 dict.insert("DateYear" , new int(OTodo::DateYear) ); 79 dict.insert("DateYear" , new int(OTodo::DateYear) );
79 dict.insert("Progress" , new int(OTodo::Progress) ); 80 dict.insert("Progress" , new int(OTodo::Progress) );
80 dict.insert("Completed", new int(OTodo::Completed) ); 81 dict.insert("Completed", new int(OTodo::Completed) );
81 dict.insert("CrossReference", new int(OTodo::CrossReference) ); 82 dict.insert("CrossReference", new int(OTodo::CrossReference) );
82 dict.insert("State", new int(OTodo::State) ); 83 dict.insert("State", new int(OTodo::State) );
83 dict.insert("Recurrence", new int(OTodo::Recurrence) ); 84 dict.insert("Recurrence", new int(OTodo::Recurrence) );
84 dict.insert("Alarms", new int(OTodo::Alarms) ); 85 dict.insert("Alarms", new int(OTodo::Alarms) );
85 dict.insert("Reminders", new int(OTodo::Reminders) ); 86 dict.insert("Reminders", new int(OTodo::Reminders) );
86 dict.insert("Notifiers", new int(OTodo::Notifiers) ); 87 dict.insert("Notifiers", new int(OTodo::Notifiers) );
87 dict.insert("Maintainer", new int(OTodo::Maintainer) ); 88 dict.insert("Maintainer", new int(OTodo::Maintainer) );
88 89
89 // here the custom XML parser from TT it's GPL 90 // here the custom XML parser from TT it's GPL
90 // but we want to push OpiePIM... to TT..... 91 // but we want to push OpiePIM... to TT.....
91 // mmap part from zecke :) 92 // mmap part from zecke :)
92 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); 93 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY );
93 struct stat attribut; 94 struct stat attribut;
94 if ( fd < 0 ) return false; 95 if ( fd < 0 ) return false;
95 96
96 if ( fstat(fd, &attribut ) == -1 ) { 97 if ( fstat(fd, &attribut ) == -1 ) {
97 ::close( fd ); 98 ::close( fd );
98 return false; 99 return false;
99 } 100 }
100 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); 101 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 );
101 if ( map_addr == ( (caddr_t)-1) ) { 102 if ( map_addr == ( (caddr_t)-1) ) {
102 ::close(fd ); 103 ::close(fd );
103 return false; 104 return false;
104 } 105 }
105 /* advise the kernel who we want to read it */ 106 /* advise the kernel who we want to read it */
106 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); 107 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL );
107 /* we do not the file any more */ 108 /* we do not the file any more */
108 ::close( fd ); 109 ::close( fd );
109 110
110 char* dt = (char*)map_addr; 111 char* dt = (char*)map_addr;
111 int len = attribut.st_size; 112 int len = attribut.st_size;
112 int i = 0; 113 int i = 0;
113 char *point; 114 char *point;
114 const char* collectionString = "<Task "; 115 const char* collectionString = "<Task ";
115 int strLen = strlen(collectionString); 116 int strLen = strlen(collectionString);
116 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { 117 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) {
117 i = point -dt; 118 i = point -dt;
118 i+= strLen; 119 i+= strLen;
119 qWarning("Found a start at %d %d", i, (point-dt) ); 120 qWarning("Found a start at %d %d", i, (point-dt) );
120 121
121 OTodo ev; 122 OTodo ev;
122 m_year = m_month = m_day = 0; 123 m_year = m_month = m_day = 0;
123 124
124 while ( TRUE ) { 125 while ( TRUE ) {
125 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) 126 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
126 ++i; 127 ++i;
127 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) 128 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
128 break; 129 break;
129 130
130 // we have another attribute, read it. 131 // we have another attribute, read it.
131 int j = i; 132 int j = i;
132 while ( j < len && dt[j] != '=' ) 133 while ( j < len && dt[j] != '=' )
133 ++j; 134 ++j;
134 QCString attr( dt+i, j-i+1); 135 QCString attr( dt+i, j-i+1);
135 136
136 i = ++j; // skip = 137 i = ++j; // skip =
137 138
138 // find the start of quotes 139 // find the start of quotes
139 while ( i < len && dt[i] != '"' ) 140 while ( i < len && dt[i] != '"' )
140 ++i; 141 ++i;
141 j = ++i; 142 j = ++i;
142 143
143 bool haveUtf = FALSE; 144 bool haveUtf = FALSE;
144 bool haveEnt = FALSE; 145 bool haveEnt = FALSE;
145 while ( j < len && dt[j] != '"' ) { 146 while ( j < len && dt[j] != '"' ) {
@@ -309,257 +310,258 @@ QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
309 }else if ( it.data().dueDate() >= start && 310 }else if ( it.data().dueDate() >= start &&
310 it.data().dueDate() <= end ) { 311 it.data().dueDate() <= end ) {
311 ids[i] = it.key(); 312 ids[i] = it.key();
312 i++; 313 i++;
313 } 314 }
314 } 315 }
315 ids.resize( i ); 316 ids.resize( i );
316 return ids; 317 return ids;
317} 318}
318QArray<int> OTodoAccessXML::overDue() { 319QArray<int> OTodoAccessXML::overDue() {
319 QArray<int> ids( m_events.count() ); 320 QArray<int> ids( m_events.count() );
320 int i = 0; 321 int i = 0;
321 322
322 QMap<int, OTodo>::Iterator it; 323 QMap<int, OTodo>::Iterator it;
323 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 324 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
324 if ( it.data().isOverdue() ) { 325 if ( it.data().isOverdue() ) {
325 ids[i] = it.key(); 326 ids[i] = it.key();
326 i++; 327 i++;
327 } 328 }
328 } 329 }
329 ids.resize( i ); 330 ids.resize( i );
330 return ids; 331 return ids;
331} 332}
332 333
333 334
334/* private */ 335/* private */
335void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, 336void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev,
336 const QCString& attr, const QString& val) { 337 const QCString& attr, const QString& val) {
337// qWarning("parse to do from XMLElement" ); 338// qWarning("parse to do from XMLElement" );
338 339
339 int *find=0; 340 int *find=0;
340 341
341 find = (*dict)[ attr.data() ]; 342 find = (*dict)[ attr.data() ];
342 if (!find ) { 343 if (!find ) {
343// qWarning("Unknown option" + it.key() ); 344// qWarning("Unknown option" + it.key() );
344 ev.setCustomField( attr, val ); 345 ev.setCustomField( attr, val );
345 return; 346 return;
346 } 347 }
347 348
348 switch( *find ) { 349 switch( *find ) {
349 case OTodo::Uid: 350 case OTodo::Uid:
350 ev.setUid( val.toInt() ); 351 ev.setUid( val.toInt() );
351 break; 352 break;
352 case OTodo::Category: 353 case OTodo::Category:
353 ev.setCategories( ev.idsFromString( val ) ); 354 ev.setCategories( ev.idsFromString( val ) );
354 break; 355 break;
355 case OTodo::HasDate: 356 case OTodo::HasDate:
356 ev.setHasDueDate( val.toInt() ); 357 ev.setHasDueDate( val.toInt() );
357 break; 358 break;
358 case OTodo::Completed: 359 case OTodo::Completed:
359 ev.setCompleted( val.toInt() ); 360 ev.setCompleted( val.toInt() );
360 break; 361 break;
361 case OTodo::Description: 362 case OTodo::Description:
362 ev.setDescription( val ); 363 ev.setDescription( val );
363 break; 364 break;
364 case OTodo::Summary: 365 case OTodo::Summary:
365 ev.setSummary( val ); 366 ev.setSummary( val );
366 break; 367 break;
367 case OTodo::Priority: 368 case OTodo::Priority:
368 ev.setPriority( val.toInt() ); 369 ev.setPriority( val.toInt() );
369 break; 370 break;
370 case OTodo::DateDay: 371 case OTodo::DateDay:
371 m_day = val.toInt(); 372 m_day = val.toInt();
372 break; 373 break;
373 case OTodo::DateMonth: 374 case OTodo::DateMonth:
374 m_month = val.toInt(); 375 m_month = val.toInt();
375 break; 376 break;
376 case OTodo::DateYear: 377 case OTodo::DateYear:
377 m_year = val.toInt(); 378 m_year = val.toInt();
378 break; 379 break;
379 case OTodo::Progress: 380 case OTodo::Progress:
380 ev.setProgress( val.toInt() ); 381 ev.setProgress( val.toInt() );
381 break; 382 break;
382 case OTodo::CrossReference: 383 case OTodo::CrossReference:
383 { 384 {
384 /* 385 /*
385 * A cross refernce looks like 386 * A cross refernce looks like
386 * appname,id;appname,id 387 * appname,id;appname,id
387 * we need to split it up 388 * we need to split it up
388 */ 389 */
389 QStringList refs = QStringList::split(';', val ); 390 QStringList refs = QStringList::split(';', val );
390 QStringList::Iterator strIt; 391 QStringList::Iterator strIt;
391 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { 392 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) {
392 int pos = (*strIt).find(','); 393 int pos = (*strIt).find(',');
393 if ( pos > -1 ) 394 if ( pos > -1 )
394 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); 395 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() );
395 396
396 } 397 }
397 break; 398 break;
398 } 399 }
399 default: 400 default:
400 break; 401 break;
401 } 402 }
402} 403}
403QString OTodoAccessXML::toString( const OTodo& ev )const { 404QString OTodoAccessXML::toString( const OTodo& ev )const {
404 QString str; 405 QString str;
405 406
406 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; 407 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" ";
407 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; 408 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" ";
408 str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; 409 str += "Priority=\"" + QString::number( ev.priority() ) + "\" ";
409 str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; 410 str += "Progress=\"" + QString::number(ev.progress() ) + "\" ";
410 411
411 str += "Categories=\"" + toString( ev.categories() ) + "\" "; 412 str += "Categories=\"" + toString( ev.categories() ) + "\" ";
412 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; 413 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" ";
413 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; 414 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" ";
414 415
415 if ( ev.hasDueDate() ) { 416 if ( ev.hasDueDate() ) {
416 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; 417 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" ";
417 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; 418 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" ";
418 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; 419 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" ";
419 } 420 }
420// qWarning( "Uid %d", ev.uid() ); 421// qWarning( "Uid %d", ev.uid() );
421 str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; 422 str += "Uid=\"" + QString::number( ev.uid() ) + "\" ";
422 423
423// append the extra options 424// append the extra options
424 /* FIXME Qtopia::Record this is currently not 425 /* FIXME Qtopia::Record this is currently not
425 * possible you can set custom fields 426 * possible you can set custom fields
426 * but don' iterate over the list 427 * but don' iterate over the list
427 * I may do #define private protected 428 * I may do #define private protected
428 * for this case - cough --zecke 429 * for this case - cough --zecke
429 */ 430 */
430 /* 431 /*
431 QMap<QString, QString> extras = ev.extras(); 432 QMap<QString, QString> extras = ev.extras();
432 QMap<QString, QString>::Iterator extIt; 433 QMap<QString, QString>::Iterator extIt;
433 for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) 434 for (extIt = extras.begin(); extIt != extras.end(); ++extIt )
434 str += extIt.key() + "=\"" + extIt.data() + "\" "; 435 str += extIt.key() + "=\"" + extIt.data() + "\" ";
435 */ 436 */
436 // cross refernce 437 // cross refernce
437 438 if ( ev.hasRecurrence() )
439 str += ev.recurrence().toString();
438 440
439 return str; 441 return str;
440} 442}
441QString OTodoAccessXML::toString( const QArray<int>& ints ) const { 443QString OTodoAccessXML::toString( const QArray<int>& ints ) const {
442 return Qtopia::Record::idsToString( ints ); 444 return Qtopia::Record::idsToString( ints );
443} 445}
444 446
445/* internal class for sorting 447/* internal class for sorting
446 * 448 *
447 * Inspired by todoxmlio.cpp from TT 449 * Inspired by todoxmlio.cpp from TT
448 */ 450 */
449 451
450struct OTodoXMLContainer { 452struct OTodoXMLContainer {
451 OTodo todo; 453 OTodo todo;
452}; 454};
453 455
454namespace { 456namespace {
455 inline QString string( const OTodo& todo) { 457 inline QString string( const OTodo& todo) {
456 return todo.summary().isEmpty() ? 458 return todo.summary().isEmpty() ?
457 todo.description().left(20 ) : 459 todo.description().left(20 ) :
458 todo.summary(); 460 todo.summary();
459 } 461 }
460 inline int completed( const OTodo& todo1, const OTodo& todo2) { 462 inline int completed( const OTodo& todo1, const OTodo& todo2) {
461 int ret = 0; 463 int ret = 0;
462 if ( todo1.isCompleted() ) ret++; 464 if ( todo1.isCompleted() ) ret++;
463 if ( todo2.isCompleted() ) ret--; 465 if ( todo2.isCompleted() ) ret--;
464 return ret; 466 return ret;
465 } 467 }
466 inline int priority( const OTodo& t1, const OTodo& t2) { 468 inline int priority( const OTodo& t1, const OTodo& t2) {
467 return ( t1.priority() - t2.priority() ); 469 return ( t1.priority() - t2.priority() );
468 } 470 }
469 inline int description( const OTodo& t1, const OTodo& t2) { 471 inline int description( const OTodo& t1, const OTodo& t2) {
470 return QString::compare( string(t1), string(t2) ); 472 return QString::compare( string(t1), string(t2) );
471 } 473 }
472 inline int deadline( const OTodo& t1, const OTodo& t2) { 474 inline int deadline( const OTodo& t1, const OTodo& t2) {
473 int ret = 0; 475 int ret = 0;
474 if ( t1.hasDueDate() && 476 if ( t1.hasDueDate() &&
475 t2.hasDueDate() ) 477 t2.hasDueDate() )
476 ret = t2.dueDate().daysTo( t1.dueDate() ); 478 ret = t2.dueDate().daysTo( t1.dueDate() );
477 else if ( t1.hasDueDate() ) 479 else if ( t1.hasDueDate() )
478 ret = -1; 480 ret = -1;
479 else if ( t2.hasDueDate() ) 481 else if ( t2.hasDueDate() )
480 ret = 1; 482 ret = 1;
481 else 483 else
482 ret = 0; 484 ret = 0;
483 485
484 return ret; 486 return ret;
485 } 487 }
486 488
487}; 489};
488 490
489/* 491/*
490 * Returns: 492 * Returns:
491 * 0 if item1 == item2 493 * 0 if item1 == item2
492 * 494 *
493 * non-zero if item1 != item2 495 * non-zero if item1 != item2
494 * 496 *
495 * This function returns int rather than bool so that reimplementations 497 * This function returns int rather than bool so that reimplementations
496 * can return one of three values and use it to sort by: 498 * can return one of three values and use it to sort by:
497 * 499 *
498 * 0 if item1 == item2 500 * 0 if item1 == item2
499 * 501 *
500 * > 0 (positive integer) if item1 > item2 502 * > 0 (positive integer) if item1 > item2
501 * 503 *
502 * < 0 (negative integer) if item1 < item2 504 * < 0 (negative integer) if item1 < item2
503 * 505 *
504 */ 506 */
505class OTodoXMLVector : public QVector<OTodoXMLContainer> { 507class OTodoXMLVector : public QVector<OTodoXMLContainer> {
506public: 508public:
507 OTodoXMLVector(int size, bool asc, int sort) 509 OTodoXMLVector(int size, bool asc, int sort)
508 : QVector<OTodoXMLContainer>( size ) 510 : QVector<OTodoXMLContainer>( size )
509 { 511 {
510 setAutoDelete( true ); 512 setAutoDelete( true );
511 m_asc = asc; 513 m_asc = asc;
512 m_sort = sort; 514 m_sort = sort;
513 } 515 }
514 /* return the summary/description */ 516 /* return the summary/description */
515 QString string( const OTodo& todo) { 517 QString string( const OTodo& todo) {
516 return todo.summary().isEmpty() ? 518 return todo.summary().isEmpty() ?
517 todo.description().left(20 ) : 519 todo.description().left(20 ) :
518 todo.summary(); 520 todo.summary();
519 } 521 }
520 /** 522 /**
521 * we take the sortorder( switch on it ) 523 * we take the sortorder( switch on it )
522 * 524 *
523 */ 525 */
524 int compareItems( Item d1, Item d2 ) { 526 int compareItems( Item d1, Item d2 ) {
525 bool seComp, sePrio, seDesc, seDeadline; 527 bool seComp, sePrio, seDesc, seDeadline;
526 seComp = sePrio = seDeadline = seDesc = false; 528 seComp = sePrio = seDeadline = seDesc = false;
527 int ret =0; 529 int ret =0;
528 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; 530 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1;
529 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; 531 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2;
530 532
531 /* same item */ 533 /* same item */
532 if ( con1->todo.uid() == con2->todo.uid() ) 534 if ( con1->todo.uid() == con2->todo.uid() )
533 return 0; 535 return 0;
534 536
535 switch ( m_sort ) { 537 switch ( m_sort ) {
536 /* completed */ 538 /* completed */
537 case 0: { 539 case 0: {
538 ret = completed( con1->todo, con2->todo ); 540 ret = completed( con1->todo, con2->todo );
539 seComp = TRUE; 541 seComp = TRUE;
540 break; 542 break;
541 } 543 }
542 /* priority */ 544 /* priority */
543 case 1: { 545 case 1: {
544 ret = priority( con1->todo, con2->todo ); 546 ret = priority( con1->todo, con2->todo );
545 sePrio = TRUE; 547 sePrio = TRUE;
546 break; 548 break;
547 } 549 }
548 /* description */ 550 /* description */
549 case 2: { 551 case 2: {
550 ret = description( con1->todo, con2->todo ); 552 ret = description( con1->todo, con2->todo );
551 seDesc = TRUE; 553 seDesc = TRUE;
552 break; 554 break;
553 } 555 }
554 /* deadline */ 556 /* deadline */
555 case 3: { 557 case 3: {
556 ret = deadline( con1->todo, con2->todo ); 558 ret = deadline( con1->todo, con2->todo );
557 seDeadline = TRUE; 559 seDeadline = TRUE;
558 break; 560 break;
559 } 561 }
560 default: 562 default:
561 ret = 0; 563 ret = 0;
562 break; 564 break;
563 }; 565 };
564 /* 566 /*
565 * FIXME do better sorting if the first sort criteria 567 * FIXME do better sorting if the first sort criteria