summaryrefslogtreecommitdiff
Unidiff
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,689 +1,691 @@
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] != '"' ) {
146 if ( ((unsigned char)dt[j]) > 0x7f ) 147 if ( ((unsigned char)dt[j]) > 0x7f )
147 haveUtf = TRUE; 148 haveUtf = TRUE;
148 if ( dt[j] == '&' ) 149 if ( dt[j] == '&' )
149 haveEnt = TRUE; 150 haveEnt = TRUE;
150 ++j; 151 ++j;
151 } 152 }
152 if ( i == j ) { 153 if ( i == j ) {
153 // empty value 154 // empty value
154 i = j + 1; 155 i = j + 1;
155 continue; 156 continue;
156 } 157 }
157 158
158 QCString value( dt+i, j-i+1 ); 159 QCString value( dt+i, j-i+1 );
159 i = j + 1; 160 i = j + 1;
160 161
161 QString str = (haveUtf ? QString::fromUtf8( value ) 162 QString str = (haveUtf ? QString::fromUtf8( value )
162 : QString::fromLatin1( value ) ); 163 : QString::fromLatin1( value ) );
163 if ( haveEnt ) 164 if ( haveEnt )
164 str = Qtopia::plainString( str ); 165 str = Qtopia::plainString( str );
165 166
166 /* 167 /*
167 * add key + value 168 * add key + value
168 */ 169 */
169 todo( &dict, ev, attr, str ); 170 todo( &dict, ev, attr, str );
170 171
171 } 172 }
172 /* 173 /*
173 * now add it 174 * now add it
174 */ 175 */
175 qWarning("End at %d", i ); 176 qWarning("End at %d", i );
176 if (m_events.contains( ev.uid() ) || ev.uid() == 0) { 177 if (m_events.contains( ev.uid() ) || ev.uid() == 0) {
177 ev.setUid( 1 ); 178 ev.setUid( 1 );
178 m_changed = true; 179 m_changed = true;
179 } 180 }
180 if ( ev.hasDueDate() ) { 181 if ( ev.hasDueDate() ) {
181 ev.setDueDate( QDate(m_year, m_month, m_day) ); 182 ev.setDueDate( QDate(m_year, m_month, m_day) );
182 } 183 }
183 m_events.insert(ev.uid(), ev ); 184 m_events.insert(ev.uid(), ev );
184 m_year = m_month = m_day = -1; 185 m_year = m_month = m_day = -1;
185 } 186 }
186 187
187 munmap(map_addr, attribut.st_size ); 188 munmap(map_addr, attribut.st_size );
188 189
189 qWarning("counts %d records loaded!", m_events.count() ); 190 qWarning("counts %d records loaded!", m_events.count() );
190 return true; 191 return true;
191} 192}
192bool OTodoAccessXML::reload() { 193bool OTodoAccessXML::reload() {
193 m_events.clear(); 194 m_events.clear();
194 return load(); 195 return load();
195} 196}
196bool OTodoAccessXML::save() { 197bool OTodoAccessXML::save() {
197// qWarning("saving"); 198// qWarning("saving");
198 if (!m_opened || !m_changed ) { 199 if (!m_opened || !m_changed ) {
199// qWarning("not saving"); 200// qWarning("not saving");
200 return true; 201 return true;
201 } 202 }
202 QString strNewFile = m_file + ".new"; 203 QString strNewFile = m_file + ".new";
203 QFile f( strNewFile ); 204 QFile f( strNewFile );
204 if (!f.open( IO_WriteOnly|IO_Raw ) ) 205 if (!f.open( IO_WriteOnly|IO_Raw ) )
205 return false; 206 return false;
206 207
207 int written; 208 int written;
208 QString out; 209 QString out;
209 out = "<!DOCTYPE Tasks>\n<Tasks>\n"; 210 out = "<!DOCTYPE Tasks>\n<Tasks>\n";
210 211
211 // for all todos 212 // for all todos
212 QMap<int, OTodo>::Iterator it; 213 QMap<int, OTodo>::Iterator it;
213 for (it = m_events.begin(); it != m_events.end(); ++it ) { 214 for (it = m_events.begin(); it != m_events.end(); ++it ) {
214 out+= "<Task " + toString( (*it) ) + " />\n"; 215 out+= "<Task " + toString( (*it) ) + " />\n";
215 QCString cstr = out.utf8(); 216 QCString cstr = out.utf8();
216 written = f.writeBlock( cstr.data(), cstr.length() ); 217 written = f.writeBlock( cstr.data(), cstr.length() );
217 218
218 /* less written then we wanted */ 219 /* less written then we wanted */
219 if ( written != (int)cstr.length() ) { 220 if ( written != (int)cstr.length() ) {
220 f.close(); 221 f.close();
221 QFile::remove( strNewFile ); 222 QFile::remove( strNewFile );
222 return false; 223 return false;
223 } 224 }
224 out = QString::null; 225 out = QString::null;
225 } 226 }
226 227
227 out += "</Tasks>"; 228 out += "</Tasks>";
228 QCString cstr = out.utf8(); 229 QCString cstr = out.utf8();
229 written = f.writeBlock( cstr.data(), cstr.length() ); 230 written = f.writeBlock( cstr.data(), cstr.length() );
230 231
231 if ( written != (int)cstr.length() ) { 232 if ( written != (int)cstr.length() ) {
232 f.close(); 233 f.close();
233 QFile::remove( strNewFile ); 234 QFile::remove( strNewFile );
234 return false; 235 return false;
235 } 236 }
236 /* flush before renaming */ 237 /* flush before renaming */
237 f.close(); 238 f.close();
238 239
239 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { 240 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) {
240// qWarning("error renaming"); 241// qWarning("error renaming");
241 QFile::remove( strNewFile ); 242 QFile::remove( strNewFile );
242 } 243 }
243 244
244 m_changed = false; 245 m_changed = false;
245 return true; 246 return true;
246} 247}
247QArray<int> OTodoAccessXML::allRecords()const { 248QArray<int> OTodoAccessXML::allRecords()const {
248 QArray<int> ids( m_events.count() ); 249 QArray<int> ids( m_events.count() );
249 QMap<int, OTodo>::ConstIterator it; 250 QMap<int, OTodo>::ConstIterator it;
250 int i = 0; 251 int i = 0;
251 252
252 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 253 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
253 ids[i] = it.key(); 254 ids[i] = it.key();
254 i++; 255 i++;
255 } 256 }
256 return ids; 257 return ids;
257} 258}
258QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { 259QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) {
259 QArray<int> ids(0); 260 QArray<int> ids(0);
260 return ids; 261 return ids;
261} 262}
262OTodo OTodoAccessXML::find( int uid )const { 263OTodo OTodoAccessXML::find( int uid )const {
263 OTodo todo; 264 OTodo todo;
264 todo.setUid( 0 ); // isEmpty() 265 todo.setUid( 0 ); // isEmpty()
265 QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); 266 QMap<int, OTodo>::ConstIterator it = m_events.find( uid );
266 if ( it != m_events.end() ) 267 if ( it != m_events.end() )
267 todo = it.data(); 268 todo = it.data();
268 269
269 return todo; 270 return todo;
270} 271}
271void OTodoAccessXML::clear() { 272void OTodoAccessXML::clear() {
272 if (m_opened ) 273 if (m_opened )
273 m_changed = true; 274 m_changed = true;
274 275
275 m_events.clear(); 276 m_events.clear();
276} 277}
277bool OTodoAccessXML::add( const OTodo& todo ) { 278bool OTodoAccessXML::add( const OTodo& todo ) {
278// qWarning("add"); 279// qWarning("add");
279 m_changed = true; 280 m_changed = true;
280 m_events.insert( todo.uid(), todo ); 281 m_events.insert( todo.uid(), todo );
281 282
282 return true; 283 return true;
283} 284}
284bool OTodoAccessXML::remove( int uid ) { 285bool OTodoAccessXML::remove( int uid ) {
285 m_changed = true; 286 m_changed = true;
286 m_events.remove( uid ); 287 m_events.remove( uid );
287 288
288 return true; 289 return true;
289} 290}
290bool OTodoAccessXML::replace( const OTodo& todo) { 291bool OTodoAccessXML::replace( const OTodo& todo) {
291 m_changed = true; 292 m_changed = true;
292 m_events.replace( todo.uid(), todo ); 293 m_events.replace( todo.uid(), todo );
293 294
294 return true; 295 return true;
295} 296}
296QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, 297QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
297 const QDate& end, 298 const QDate& end,
298 bool includeNoDates ) { 299 bool includeNoDates ) {
299 QArray<int> ids( m_events.count() ); 300 QArray<int> ids( m_events.count() );
300 QMap<int, OTodo>::Iterator it; 301 QMap<int, OTodo>::Iterator it;
301 302
302 int i = 0; 303 int i = 0;
303 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 304 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
304 if ( !it.data().hasDueDate() ) { 305 if ( !it.data().hasDueDate() ) {
305 if ( includeNoDates ) { 306 if ( includeNoDates ) {
306 ids[i] = it.key(); 307 ids[i] = it.key();
307 i++; 308 i++;
308 } 309 }
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
566 * ret equals 0 start with complete and so on... 568 * ret equals 0 start with complete and so on...
567 */ 569 */
568 570
569 /* twist it we're not ascending*/ 571 /* twist it we're not ascending*/
570 if (!m_asc) 572 if (!m_asc)
571 ret = ret * -1; 573 ret = ret * -1;
572 574
573 if ( ret ) 575 if ( ret )
574 return ret; 576 return ret;
575 577
576 // default did not gave difference let's try it other way around 578 // default did not gave difference let's try it other way around
577 /* 579 /*
578 * General try if already checked if not test 580 * General try if already checked if not test
579 * and return 581 * and return
580 * 1.Completed 582 * 1.Completed
581 * 2.Priority 583 * 2.Priority
582 * 3.Description 584 * 3.Description
583 * 4.DueDate 585 * 4.DueDate
584 */ 586 */
585 if (!seComp ) { 587 if (!seComp ) {
586 if ( (ret = completed( con1->todo, con2->todo ) ) ) { 588 if ( (ret = completed( con1->todo, con2->todo ) ) ) {
587 if (!m_asc ) ret *= -1; 589 if (!m_asc ) ret *= -1;
588 return ret; 590 return ret;
589 } 591 }
590 } 592 }
591 if (!sePrio ) { 593 if (!sePrio ) {
592 if ( (ret = priority( con1->todo, con2->todo ) ) ) { 594 if ( (ret = priority( con1->todo, con2->todo ) ) ) {
593 if (!m_asc ) ret *= -1; 595 if (!m_asc ) ret *= -1;
594 return ret; 596 return ret;
595 } 597 }
596 } 598 }
597 if (!seDesc ) { 599 if (!seDesc ) {
598 if ( (ret = description(con1->todo, con2->todo ) ) ) { 600 if ( (ret = description(con1->todo, con2->todo ) ) ) {
599 if (!m_asc) ret *= -1; 601 if (!m_asc) ret *= -1;
600 return ret; 602 return ret;
601 } 603 }
602 } 604 }
603 if (!seDeadline) { 605 if (!seDeadline) {
604 if ( (ret = deadline( con1->todo, con2->todo ) ) ) { 606 if ( (ret = deadline( con1->todo, con2->todo ) ) ) {
605 if (!m_asc) ret *= -1; 607 if (!m_asc) ret *= -1;
606 return ret; 608 return ret;
607 } 609 }
608 } 610 }
609 611
610 return 0; 612 return 0;
611 } 613 }
612 private: 614 private:
613 bool m_asc; 615 bool m_asc;
614 int m_sort; 616 int m_sort;
615 617
616}; 618};
617 619
618QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, 620QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder,
619 int sortFilter, int cat ) { 621 int sortFilter, int cat ) {
620 qWarning("sorted! %d cat", cat); 622 qWarning("sorted! %d cat", cat);
621 OTodoXMLVector vector(m_events.count(), asc,sortOrder ); 623 OTodoXMLVector vector(m_events.count(), asc,sortOrder );
622 QMap<int, OTodo>::Iterator it; 624 QMap<int, OTodo>::Iterator it;
623 int item = 0; 625 int item = 0;
624 626
625 bool bCat = sortFilter & 1 ? true : false; 627 bool bCat = sortFilter & 1 ? true : false;
626 bool bOnly = sortFilter & 2 ? true : false; 628 bool bOnly = sortFilter & 2 ? true : false;
627 bool comp = sortFilter & 4 ? true : false; 629 bool comp = sortFilter & 4 ? true : false;
628 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 630 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
629 631
630 /* show category */ 632 /* show category */
631 if ( bCat && cat != 0) 633 if ( bCat && cat != 0)
632 if (!(*it).categories().contains( cat ) ) { 634 if (!(*it).categories().contains( cat ) ) {
633 qWarning("category mis match"); 635 qWarning("category mis match");
634 continue; 636 continue;
635 } 637 }
636 /* isOverdue but we should not show overdue - why?*/ 638 /* isOverdue but we should not show overdue - why?*/
637/* if ( (*it).isOverdue() && !bOnly ) { 639/* if ( (*it).isOverdue() && !bOnly ) {
638 qWarning("item is overdue but !bOnly"); 640 qWarning("item is overdue but !bOnly");
639 continue; 641 continue;
640 } 642 }
641*/ 643*/
642 if ( !(*it).isOverdue() && bOnly ) { 644 if ( !(*it).isOverdue() && bOnly ) {
643 qWarning("item is not overdue but bOnly checked"); 645 qWarning("item is not overdue but bOnly checked");
644 continue; 646 continue;
645 } 647 }
646 648
647 if ((*it).isCompleted() && comp ) { 649 if ((*it).isCompleted() && comp ) {
648 qWarning("completed continue!"); 650 qWarning("completed continue!");
649 continue; 651 continue;
650 } 652 }
651 653
652 654
653 OTodoXMLContainer* con = new OTodoXMLContainer(); 655 OTodoXMLContainer* con = new OTodoXMLContainer();
654 con->todo = (*it); 656 con->todo = (*it);
655 vector.insert(item, con ); 657 vector.insert(item, con );
656 item++; 658 item++;
657 } 659 }
658 qWarning("XXX %d Items added", item); 660 qWarning("XXX %d Items added", item);
659 vector.resize( item ); 661 vector.resize( item );
660 /* sort it now */ 662 /* sort it now */
661 vector.sort(); 663 vector.sort();
662 /* now get the uids */ 664 /* now get the uids */
663 QArray<int> array( vector.count() ); 665 QArray<int> array( vector.count() );
664 for (uint i= 0; i < vector.count(); i++ ) { 666 for (uint i= 0; i < vector.count(); i++ ) {
665 array[i] = ( vector.at(i) )->todo.uid(); 667 array[i] = ( vector.at(i) )->todo.uid();
666 } 668 }
667 return array; 669 return array;
668}; 670};
669void OTodoAccessXML::removeAllCompleted() { 671void OTodoAccessXML::removeAllCompleted() {
670 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { 672 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) {
671 if ( (*it).isCompleted() ) 673 if ( (*it).isCompleted() )
672 m_events.remove( it ); 674 m_events.remove( it );
673 } 675 }
674} 676}
675QBitArray OTodoAccessXML::supports()const { 677QBitArray OTodoAccessXML::supports()const {
676 static QBitArray ar = sup(); 678 static QBitArray ar = sup();
677 return ar; 679 return ar;
678} 680}
679QBitArray OTodoAccessXML::sup() { 681QBitArray OTodoAccessXML::sup() {
680 QBitArray ar( OTodo::CompletedDate +1 ); 682 QBitArray ar( OTodo::CompletedDate +1 );
681 ar.fill( true ); 683 ar.fill( true );
682 ar[OTodo::CrossReference] = false; 684 ar[OTodo::CrossReference] = false;
683 ar[OTodo::State ] = false; 685 ar[OTodo::State ] = false;
684 ar[OTodo::Reminders] = false; 686 ar[OTodo::Reminders] = false;
685 ar[OTodo::Notifiers] = false; 687 ar[OTodo::Notifiers] = false;
686 ar[OTodo::Maintainer] = false; 688 ar[OTodo::Maintainer] = false;
687 689
688 return ar; 690 return ar;
689} 691}
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,689 +1,691 @@
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] != '"' ) {
146 if ( ((unsigned char)dt[j]) > 0x7f ) 147 if ( ((unsigned char)dt[j]) > 0x7f )
147 haveUtf = TRUE; 148 haveUtf = TRUE;
148 if ( dt[j] == '&' ) 149 if ( dt[j] == '&' )
149 haveEnt = TRUE; 150 haveEnt = TRUE;
150 ++j; 151 ++j;
151 } 152 }
152 if ( i == j ) { 153 if ( i == j ) {
153 // empty value 154 // empty value
154 i = j + 1; 155 i = j + 1;
155 continue; 156 continue;
156 } 157 }
157 158
158 QCString value( dt+i, j-i+1 ); 159 QCString value( dt+i, j-i+1 );
159 i = j + 1; 160 i = j + 1;
160 161
161 QString str = (haveUtf ? QString::fromUtf8( value ) 162 QString str = (haveUtf ? QString::fromUtf8( value )
162 : QString::fromLatin1( value ) ); 163 : QString::fromLatin1( value ) );
163 if ( haveEnt ) 164 if ( haveEnt )
164 str = Qtopia::plainString( str ); 165 str = Qtopia::plainString( str );
165 166
166 /* 167 /*
167 * add key + value 168 * add key + value
168 */ 169 */
169 todo( &dict, ev, attr, str ); 170 todo( &dict, ev, attr, str );
170 171
171 } 172 }
172 /* 173 /*
173 * now add it 174 * now add it
174 */ 175 */
175 qWarning("End at %d", i ); 176 qWarning("End at %d", i );
176 if (m_events.contains( ev.uid() ) || ev.uid() == 0) { 177 if (m_events.contains( ev.uid() ) || ev.uid() == 0) {
177 ev.setUid( 1 ); 178 ev.setUid( 1 );
178 m_changed = true; 179 m_changed = true;
179 } 180 }
180 if ( ev.hasDueDate() ) { 181 if ( ev.hasDueDate() ) {
181 ev.setDueDate( QDate(m_year, m_month, m_day) ); 182 ev.setDueDate( QDate(m_year, m_month, m_day) );
182 } 183 }
183 m_events.insert(ev.uid(), ev ); 184 m_events.insert(ev.uid(), ev );
184 m_year = m_month = m_day = -1; 185 m_year = m_month = m_day = -1;
185 } 186 }
186 187
187 munmap(map_addr, attribut.st_size ); 188 munmap(map_addr, attribut.st_size );
188 189
189 qWarning("counts %d records loaded!", m_events.count() ); 190 qWarning("counts %d records loaded!", m_events.count() );
190 return true; 191 return true;
191} 192}
192bool OTodoAccessXML::reload() { 193bool OTodoAccessXML::reload() {
193 m_events.clear(); 194 m_events.clear();
194 return load(); 195 return load();
195} 196}
196bool OTodoAccessXML::save() { 197bool OTodoAccessXML::save() {
197// qWarning("saving"); 198// qWarning("saving");
198 if (!m_opened || !m_changed ) { 199 if (!m_opened || !m_changed ) {
199// qWarning("not saving"); 200// qWarning("not saving");
200 return true; 201 return true;
201 } 202 }
202 QString strNewFile = m_file + ".new"; 203 QString strNewFile = m_file + ".new";
203 QFile f( strNewFile ); 204 QFile f( strNewFile );
204 if (!f.open( IO_WriteOnly|IO_Raw ) ) 205 if (!f.open( IO_WriteOnly|IO_Raw ) )
205 return false; 206 return false;
206 207
207 int written; 208 int written;
208 QString out; 209 QString out;
209 out = "<!DOCTYPE Tasks>\n<Tasks>\n"; 210 out = "<!DOCTYPE Tasks>\n<Tasks>\n";
210 211
211 // for all todos 212 // for all todos
212 QMap<int, OTodo>::Iterator it; 213 QMap<int, OTodo>::Iterator it;
213 for (it = m_events.begin(); it != m_events.end(); ++it ) { 214 for (it = m_events.begin(); it != m_events.end(); ++it ) {
214 out+= "<Task " + toString( (*it) ) + " />\n"; 215 out+= "<Task " + toString( (*it) ) + " />\n";
215 QCString cstr = out.utf8(); 216 QCString cstr = out.utf8();
216 written = f.writeBlock( cstr.data(), cstr.length() ); 217 written = f.writeBlock( cstr.data(), cstr.length() );
217 218
218 /* less written then we wanted */ 219 /* less written then we wanted */
219 if ( written != (int)cstr.length() ) { 220 if ( written != (int)cstr.length() ) {
220 f.close(); 221 f.close();
221 QFile::remove( strNewFile ); 222 QFile::remove( strNewFile );
222 return false; 223 return false;
223 } 224 }
224 out = QString::null; 225 out = QString::null;
225 } 226 }
226 227
227 out += "</Tasks>"; 228 out += "</Tasks>";
228 QCString cstr = out.utf8(); 229 QCString cstr = out.utf8();
229 written = f.writeBlock( cstr.data(), cstr.length() ); 230 written = f.writeBlock( cstr.data(), cstr.length() );
230 231
231 if ( written != (int)cstr.length() ) { 232 if ( written != (int)cstr.length() ) {
232 f.close(); 233 f.close();
233 QFile::remove( strNewFile ); 234 QFile::remove( strNewFile );
234 return false; 235 return false;
235 } 236 }
236 /* flush before renaming */ 237 /* flush before renaming */
237 f.close(); 238 f.close();
238 239
239 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { 240 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) {
240// qWarning("error renaming"); 241// qWarning("error renaming");
241 QFile::remove( strNewFile ); 242 QFile::remove( strNewFile );
242 } 243 }
243 244
244 m_changed = false; 245 m_changed = false;
245 return true; 246 return true;
246} 247}
247QArray<int> OTodoAccessXML::allRecords()const { 248QArray<int> OTodoAccessXML::allRecords()const {
248 QArray<int> ids( m_events.count() ); 249 QArray<int> ids( m_events.count() );
249 QMap<int, OTodo>::ConstIterator it; 250 QMap<int, OTodo>::ConstIterator it;
250 int i = 0; 251 int i = 0;
251 252
252 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 253 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
253 ids[i] = it.key(); 254 ids[i] = it.key();
254 i++; 255 i++;
255 } 256 }
256 return ids; 257 return ids;
257} 258}
258QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { 259QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) {
259 QArray<int> ids(0); 260 QArray<int> ids(0);
260 return ids; 261 return ids;
261} 262}
262OTodo OTodoAccessXML::find( int uid )const { 263OTodo OTodoAccessXML::find( int uid )const {
263 OTodo todo; 264 OTodo todo;
264 todo.setUid( 0 ); // isEmpty() 265 todo.setUid( 0 ); // isEmpty()
265 QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); 266 QMap<int, OTodo>::ConstIterator it = m_events.find( uid );
266 if ( it != m_events.end() ) 267 if ( it != m_events.end() )
267 todo = it.data(); 268 todo = it.data();
268 269
269 return todo; 270 return todo;
270} 271}
271void OTodoAccessXML::clear() { 272void OTodoAccessXML::clear() {
272 if (m_opened ) 273 if (m_opened )
273 m_changed = true; 274 m_changed = true;
274 275
275 m_events.clear(); 276 m_events.clear();
276} 277}
277bool OTodoAccessXML::add( const OTodo& todo ) { 278bool OTodoAccessXML::add( const OTodo& todo ) {
278// qWarning("add"); 279// qWarning("add");
279 m_changed = true; 280 m_changed = true;
280 m_events.insert( todo.uid(), todo ); 281 m_events.insert( todo.uid(), todo );
281 282
282 return true; 283 return true;
283} 284}
284bool OTodoAccessXML::remove( int uid ) { 285bool OTodoAccessXML::remove( int uid ) {
285 m_changed = true; 286 m_changed = true;
286 m_events.remove( uid ); 287 m_events.remove( uid );
287 288
288 return true; 289 return true;
289} 290}
290bool OTodoAccessXML::replace( const OTodo& todo) { 291bool OTodoAccessXML::replace( const OTodo& todo) {
291 m_changed = true; 292 m_changed = true;
292 m_events.replace( todo.uid(), todo ); 293 m_events.replace( todo.uid(), todo );
293 294
294 return true; 295 return true;
295} 296}
296QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, 297QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
297 const QDate& end, 298 const QDate& end,
298 bool includeNoDates ) { 299 bool includeNoDates ) {
299 QArray<int> ids( m_events.count() ); 300 QArray<int> ids( m_events.count() );
300 QMap<int, OTodo>::Iterator it; 301 QMap<int, OTodo>::Iterator it;
301 302
302 int i = 0; 303 int i = 0;
303 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 304 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
304 if ( !it.data().hasDueDate() ) { 305 if ( !it.data().hasDueDate() ) {
305 if ( includeNoDates ) { 306 if ( includeNoDates ) {
306 ids[i] = it.key(); 307 ids[i] = it.key();
307 i++; 308 i++;
308 } 309 }
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
566 * ret equals 0 start with complete and so on... 568 * ret equals 0 start with complete and so on...
567 */ 569 */
568 570
569 /* twist it we're not ascending*/ 571 /* twist it we're not ascending*/
570 if (!m_asc) 572 if (!m_asc)
571 ret = ret * -1; 573 ret = ret * -1;
572 574
573 if ( ret ) 575 if ( ret )
574 return ret; 576 return ret;
575 577
576 // default did not gave difference let's try it other way around 578 // default did not gave difference let's try it other way around
577 /* 579 /*
578 * General try if already checked if not test 580 * General try if already checked if not test
579 * and return 581 * and return
580 * 1.Completed 582 * 1.Completed
581 * 2.Priority 583 * 2.Priority
582 * 3.Description 584 * 3.Description
583 * 4.DueDate 585 * 4.DueDate
584 */ 586 */
585 if (!seComp ) { 587 if (!seComp ) {
586 if ( (ret = completed( con1->todo, con2->todo ) ) ) { 588 if ( (ret = completed( con1->todo, con2->todo ) ) ) {
587 if (!m_asc ) ret *= -1; 589 if (!m_asc ) ret *= -1;
588 return ret; 590 return ret;
589 } 591 }
590 } 592 }
591 if (!sePrio ) { 593 if (!sePrio ) {
592 if ( (ret = priority( con1->todo, con2->todo ) ) ) { 594 if ( (ret = priority( con1->todo, con2->todo ) ) ) {
593 if (!m_asc ) ret *= -1; 595 if (!m_asc ) ret *= -1;
594 return ret; 596 return ret;
595 } 597 }
596 } 598 }
597 if (!seDesc ) { 599 if (!seDesc ) {
598 if ( (ret = description(con1->todo, con2->todo ) ) ) { 600 if ( (ret = description(con1->todo, con2->todo ) ) ) {
599 if (!m_asc) ret *= -1; 601 if (!m_asc) ret *= -1;
600 return ret; 602 return ret;
601 } 603 }
602 } 604 }
603 if (!seDeadline) { 605 if (!seDeadline) {
604 if ( (ret = deadline( con1->todo, con2->todo ) ) ) { 606 if ( (ret = deadline( con1->todo, con2->todo ) ) ) {
605 if (!m_asc) ret *= -1; 607 if (!m_asc) ret *= -1;
606 return ret; 608 return ret;
607 } 609 }
608 } 610 }
609 611
610 return 0; 612 return 0;
611 } 613 }
612 private: 614 private:
613 bool m_asc; 615 bool m_asc;
614 int m_sort; 616 int m_sort;
615 617
616}; 618};
617 619
618QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, 620QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder,
619 int sortFilter, int cat ) { 621 int sortFilter, int cat ) {
620 qWarning("sorted! %d cat", cat); 622 qWarning("sorted! %d cat", cat);
621 OTodoXMLVector vector(m_events.count(), asc,sortOrder ); 623 OTodoXMLVector vector(m_events.count(), asc,sortOrder );
622 QMap<int, OTodo>::Iterator it; 624 QMap<int, OTodo>::Iterator it;
623 int item = 0; 625 int item = 0;
624 626
625 bool bCat = sortFilter & 1 ? true : false; 627 bool bCat = sortFilter & 1 ? true : false;
626 bool bOnly = sortFilter & 2 ? true : false; 628 bool bOnly = sortFilter & 2 ? true : false;
627 bool comp = sortFilter & 4 ? true : false; 629 bool comp = sortFilter & 4 ? true : false;
628 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 630 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
629 631
630 /* show category */ 632 /* show category */
631 if ( bCat && cat != 0) 633 if ( bCat && cat != 0)
632 if (!(*it).categories().contains( cat ) ) { 634 if (!(*it).categories().contains( cat ) ) {
633 qWarning("category mis match"); 635 qWarning("category mis match");
634 continue; 636 continue;
635 } 637 }
636 /* isOverdue but we should not show overdue - why?*/ 638 /* isOverdue but we should not show overdue - why?*/
637/* if ( (*it).isOverdue() && !bOnly ) { 639/* if ( (*it).isOverdue() && !bOnly ) {
638 qWarning("item is overdue but !bOnly"); 640 qWarning("item is overdue but !bOnly");
639 continue; 641 continue;
640 } 642 }
641*/ 643*/
642 if ( !(*it).isOverdue() && bOnly ) { 644 if ( !(*it).isOverdue() && bOnly ) {
643 qWarning("item is not overdue but bOnly checked"); 645 qWarning("item is not overdue but bOnly checked");
644 continue; 646 continue;
645 } 647 }
646 648
647 if ((*it).isCompleted() && comp ) { 649 if ((*it).isCompleted() && comp ) {
648 qWarning("completed continue!"); 650 qWarning("completed continue!");
649 continue; 651 continue;
650 } 652 }
651 653
652 654
653 OTodoXMLContainer* con = new OTodoXMLContainer(); 655 OTodoXMLContainer* con = new OTodoXMLContainer();
654 con->todo = (*it); 656 con->todo = (*it);
655 vector.insert(item, con ); 657 vector.insert(item, con );
656 item++; 658 item++;
657 } 659 }
658 qWarning("XXX %d Items added", item); 660 qWarning("XXX %d Items added", item);
659 vector.resize( item ); 661 vector.resize( item );
660 /* sort it now */ 662 /* sort it now */
661 vector.sort(); 663 vector.sort();
662 /* now get the uids */ 664 /* now get the uids */
663 QArray<int> array( vector.count() ); 665 QArray<int> array( vector.count() );
664 for (uint i= 0; i < vector.count(); i++ ) { 666 for (uint i= 0; i < vector.count(); i++ ) {
665 array[i] = ( vector.at(i) )->todo.uid(); 667 array[i] = ( vector.at(i) )->todo.uid();
666 } 668 }
667 return array; 669 return array;
668}; 670};
669void OTodoAccessXML::removeAllCompleted() { 671void OTodoAccessXML::removeAllCompleted() {
670 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { 672 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) {
671 if ( (*it).isCompleted() ) 673 if ( (*it).isCompleted() )
672 m_events.remove( it ); 674 m_events.remove( it );
673 } 675 }
674} 676}
675QBitArray OTodoAccessXML::supports()const { 677QBitArray OTodoAccessXML::supports()const {
676 static QBitArray ar = sup(); 678 static QBitArray ar = sup();
677 return ar; 679 return ar;
678} 680}
679QBitArray OTodoAccessXML::sup() { 681QBitArray OTodoAccessXML::sup() {
680 QBitArray ar( OTodo::CompletedDate +1 ); 682 QBitArray ar( OTodo::CompletedDate +1 );
681 ar.fill( true ); 683 ar.fill( true );
682 ar[OTodo::CrossReference] = false; 684 ar[OTodo::CrossReference] = false;
683 ar[OTodo::State ] = false; 685 ar[OTodo::State ] = false;
684 ar[OTodo::Reminders] = false; 686 ar[OTodo::Reminders] = false;
685 ar[OTodo::Notifiers] = false; 687 ar[OTodo::Notifiers] = false;
686 ar[OTodo::Maintainer] = false; 688 ar[OTodo::Maintainer] = false;
687 689
688 return ar; 690 return ar;
689} 691}