author | mickeyl <mickeyl> | 2004-11-16 19:14:18 (UTC) |
---|---|---|
committer | mickeyl <mickeyl> | 2004-11-16 19:14:18 (UTC) |
commit | ea3945a9bd8f9830f70b1efa133f9df13b19362f (patch) (unidiff) | |
tree | f2ea22cc50e9aa8aa73ee7dea148f41c563c9666 /libopie/pim/ocontactaccessbackend_xml.cpp | |
parent | 1c6f490e8541626f68422e0a3a7c7281d7f5b7d3 (diff) | |
download | opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.zip opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.tar.gz opie-ea3945a9bd8f9830f70b1efa133f9df13b19362f.tar.bz2 |
libopie1 goes into unsupported
Diffstat (limited to 'libopie/pim/ocontactaccessbackend_xml.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libopie/pim/ocontactaccessbackend_xml.cpp | 821 |
1 files changed, 0 insertions, 821 deletions
diff --git a/libopie/pim/ocontactaccessbackend_xml.cpp b/libopie/pim/ocontactaccessbackend_xml.cpp deleted file mode 100644 index 2373ad6..0000000 --- a/libopie/pim/ocontactaccessbackend_xml.cpp +++ b/dev/null | |||
@@ -1,821 +0,0 @@ | |||
1 | /* | ||
2 | * XML Backend for the OPIE-Contact Database. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * | ||
13 | * ===================================================================== | ||
14 | * Version: $Id$ | ||
15 | * ===================================================================== | ||
16 | * History: | ||
17 | * $Log$ | ||
18 | * Revision 1.10 2004/03/01 15:44:36 chicken | ||
19 | * fix includes | ||
20 | * | ||
21 | * Revision 1.9 2003/09/22 14:31:16 eilers | ||
22 | * Added first experimental incarnation of sql-backend for addressbook. | ||
23 | * Some modifications to be able to compile the todo sql-backend. | ||
24 | * A lot of changes fill follow... | ||
25 | * | ||
26 | * Revision 1.8 2003/08/30 15:28:26 eilers | ||
27 | * Removed some unimportant debug output which causes slow down.. | ||
28 | * | ||
29 | * Revision 1.7 2003/08/01 12:30:16 eilers | ||
30 | * Merging changes from BRANCH_1_0 to HEAD | ||
31 | * | ||
32 | * Revision 1.6 2003/07/07 16:19:47 eilers | ||
33 | * Fixing serious bug in hasQuerySettings() | ||
34 | * | ||
35 | * Revision 1.5 2003/04/13 18:07:10 zecke | ||
36 | * More API doc | ||
37 | * QString -> const QString& | ||
38 | * QString = 0l -> QString::null | ||
39 | * | ||
40 | * Revision 1.4 2003/03/21 14:32:54 mickeyl | ||
41 | * g++ compliance fix: default arguments belong into the declaration, but not the definition | ||
42 | * | ||
43 | * Revision 1.3 2003/03/21 12:26:28 eilers | ||
44 | * Fixing small bug: If we search a birthday from today to today, it returned | ||
45 | * every contact .. | ||
46 | * | ||
47 | * Revision 1.2 2003/03/21 10:33:09 eilers | ||
48 | * Merged speed optimized xml backend for contacts to main. | ||
49 | * Added QDateTime to querybyexample. For instance, it is now possible to get | ||
50 | * all Birthdays/Anniversaries between two dates. This should be used | ||
51 | * to show all birthdays in the datebook.. | ||
52 | * This change is sourcecode backward compatible but you have to upgrade | ||
53 | * the binaries for today-addressbook. | ||
54 | * | ||
55 | * Revision 1.1.2.2 2003/02/11 12:17:28 eilers | ||
56 | * Speed optimization. Removed the sequential search loops. | ||
57 | * | ||
58 | * Revision 1.1.2.1 2003/02/10 15:31:38 eilers | ||
59 | * Writing offsets to debug output.. | ||
60 | * | ||
61 | * Revision 1.1 2003/02/09 15:05:01 eilers | ||
62 | * Nothing happened.. Just some cleanup before I will start.. | ||
63 | * | ||
64 | * Revision 1.12 2003/01/03 16:58:03 eilers | ||
65 | * Reenable debug output | ||
66 | * | ||
67 | * Revision 1.11 2003/01/03 12:31:28 eilers | ||
68 | * Bugfix for calculating data diffs.. | ||
69 | * | ||
70 | * Revision 1.10 2003/01/02 14:27:12 eilers | ||
71 | * Improved query by example: Search by date is possible.. First step | ||
72 | * for a today plugin for birthdays.. | ||
73 | * | ||
74 | * Revision 1.9 2002/12/08 12:48:57 eilers | ||
75 | * Moved journal-enum from ocontact into i the xml-backend.. | ||
76 | * | ||
77 | * Revision 1.8 2002/11/14 17:04:24 eilers | ||
78 | * Sorting will now work if fullname is identical on some entries | ||
79 | * | ||
80 | * Revision 1.7 2002/11/13 15:02:46 eilers | ||
81 | * Small Bug in sorted fixed | ||
82 | * | ||
83 | * Revision 1.6 2002/11/13 14:14:51 eilers | ||
84 | * Added sorted for Contacts.. | ||
85 | * | ||
86 | * Revision 1.5 2002/11/01 15:10:42 eilers | ||
87 | * Added regExp-search in database for all fields in a contact. | ||
88 | * | ||
89 | * Revision 1.4 2002/10/16 10:52:40 eilers | ||
90 | * Added some docu to the interface and now using the cache infrastucture by zecke.. :) | ||
91 | * | ||
92 | * Revision 1.3 2002/10/14 16:21:54 eilers | ||
93 | * Some minor interface updates | ||
94 | * | ||
95 | * Revision 1.2 2002/10/07 17:34:24 eilers | ||
96 | * added OBackendFactory for advanced backend access | ||
97 | * | ||
98 | * Revision 1.1 2002/09/27 17:11:44 eilers | ||
99 | * Added API for accessing the Contact-Database ! It is compiling, but | ||
100 | * please do not expect that anything is working ! | ||
101 | * I will debug that stuff in the next time .. | ||
102 | * Please read README_COMPILE for compiling ! | ||
103 | * | ||
104 | * | ||
105 | */ | ||
106 | |||
107 | #include "ocontactaccessbackend_xml.h" | ||
108 | |||
109 | #include <qasciidict.h> | ||
110 | #include <qfile.h> | ||
111 | #include <qfileinfo.h> | ||
112 | #include <qregexp.h> | ||
113 | #include <qarray.h> | ||
114 | #include <qmap.h> | ||
115 | |||
116 | #include <qpe/global.h> | ||
117 | |||
118 | #include <opie/xmltree.h> | ||
119 | #include "ocontactaccessbackend.h" | ||
120 | #include "ocontactaccess.h" | ||
121 | |||
122 | #include <stdlib.h> | ||
123 | #include <errno.h> | ||
124 | |||
125 | using namespace Opie; | ||
126 | |||
127 | |||
128 | OContactAccessBackend_XML::OContactAccessBackend_XML ( const QString& appname, const QString& filename ): | ||
129 | m_changed( false ) | ||
130 | { | ||
131 | // Just m_contactlist should call delete if an entry | ||
132 | // is removed. | ||
133 | m_contactList.setAutoDelete( true ); | ||
134 | m_uidToContact.setAutoDelete( false ); | ||
135 | |||
136 | m_appName = appname; | ||
137 | |||
138 | /* Set journalfile name ... */ | ||
139 | m_journalName = getenv("HOME"); | ||
140 | m_journalName +="/.abjournal" + appname; | ||
141 | |||
142 | /* Expecting to access the default filename if nothing else is set */ | ||
143 | if ( filename.isEmpty() ){ | ||
144 | m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); | ||
145 | } else | ||
146 | m_fileName = filename; | ||
147 | |||
148 | /* Load Database now */ | ||
149 | load (); | ||
150 | } | ||
151 | |||
152 | bool OContactAccessBackend_XML::save() | ||
153 | { | ||
154 | |||
155 | if ( !m_changed ) | ||
156 | return true; | ||
157 | |||
158 | QString strNewFile = m_fileName + ".new"; | ||
159 | QFile f( strNewFile ); | ||
160 | if ( !f.open( IO_WriteOnly|IO_Raw ) ) | ||
161 | return false; | ||
162 | |||
163 | int total_written; | ||
164 | int idx_offset = 0; | ||
165 | QString out; | ||
166 | |||
167 | // Write Header | ||
168 | out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" | ||
169 | " <Groups>\n" | ||
170 | " </Groups>\n" | ||
171 | " <Contacts>\n"; | ||
172 | QCString cstr = out.utf8(); | ||
173 | f.writeBlock( cstr.data(), cstr.length() ); | ||
174 | idx_offset += cstr.length(); | ||
175 | out = ""; | ||
176 | |||
177 | // Write all contacts | ||
178 | QListIterator<OContact> it( m_contactList ); | ||
179 | for ( ; it.current(); ++it ) { | ||
180 | // qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset ); | ||
181 | out += "<Contact "; | ||
182 | (*it)->save( out ); | ||
183 | out += "/>\n"; | ||
184 | cstr = out.utf8(); | ||
185 | total_written = f.writeBlock( cstr.data(), cstr.length() ); | ||
186 | idx_offset += cstr.length(); | ||
187 | if ( total_written != int(cstr.length()) ) { | ||
188 | f.close(); | ||
189 | QFile::remove( strNewFile ); | ||
190 | return false; | ||
191 | } | ||
192 | out = ""; | ||
193 | } | ||
194 | out += " </Contacts>\n</AddressBook>\n"; | ||
195 | |||
196 | // Write Footer | ||
197 | cstr = out.utf8(); | ||
198 | total_written = f.writeBlock( cstr.data(), cstr.length() ); | ||
199 | if ( total_written != int( cstr.length() ) ) { | ||
200 | f.close(); | ||
201 | QFile::remove( strNewFile ); | ||
202 | return false; | ||
203 | } | ||
204 | f.close(); | ||
205 | |||
206 | // move the file over, I'm just going to use the system call | ||
207 | // because, I don't feel like using QDir. | ||
208 | if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { | ||
209 | qWarning( "problem renaming file %s to %s, errno: %d", | ||
210 | strNewFile.latin1(), m_journalName.latin1(), errno ); | ||
211 | // remove the tmp file... | ||
212 | QFile::remove( strNewFile ); | ||
213 | } | ||
214 | |||
215 | /* The journalfile should be removed now... */ | ||
216 | removeJournal(); | ||
217 | |||
218 | m_changed = false; | ||
219 | return true; | ||
220 | } | ||
221 | |||
222 | bool OContactAccessBackend_XML::load () | ||
223 | { | ||
224 | m_contactList.clear(); | ||
225 | m_uidToContact.clear(); | ||
226 | |||
227 | /* Load XML-File and journal if it exists */ | ||
228 | if ( !load ( m_fileName, false ) ) | ||
229 | return false; | ||
230 | /* The returncode of the journalfile is ignored due to the | ||
231 | * fact that it does not exist when this class is instantiated ! | ||
232 | * But there may such a file exist, if the application crashed. | ||
233 | * Therefore we try to load it to get the changes before the # | ||
234 | * crash happened... | ||
235 | */ | ||
236 | load (m_journalName, true); | ||
237 | |||
238 | return true; | ||
239 | } | ||
240 | |||
241 | void OContactAccessBackend_XML::clear () | ||
242 | { | ||
243 | m_contactList.clear(); | ||
244 | m_uidToContact.clear(); | ||
245 | |||
246 | m_changed = false; | ||
247 | } | ||
248 | |||
249 | bool OContactAccessBackend_XML::wasChangedExternally() | ||
250 | { | ||
251 | QFileInfo fi( m_fileName ); | ||
252 | |||
253 | QDateTime lastmod = fi.lastModified (); | ||
254 | |||
255 | return (lastmod != m_readtime); | ||
256 | } | ||
257 | |||
258 | QArray<int> OContactAccessBackend_XML::allRecords() const | ||
259 | { | ||
260 | QArray<int> uid_list( m_contactList.count() ); | ||
261 | |||
262 | uint counter = 0; | ||
263 | QListIterator<OContact> it( m_contactList ); | ||
264 | for( ; it.current(); ++it ){ | ||
265 | uid_list[counter++] = (*it)->uid(); | ||
266 | } | ||
267 | |||
268 | return ( uid_list ); | ||
269 | } | ||
270 | |||
271 | OContact OContactAccessBackend_XML::find ( int uid ) const | ||
272 | { | ||
273 | OContact foundContact; //Create empty contact | ||
274 | |||
275 | OContact* found = m_uidToContact.find( QString().setNum( uid ) ); | ||
276 | |||
277 | if ( found ){ | ||
278 | foundContact = *found; | ||
279 | } | ||
280 | |||
281 | return ( foundContact ); | ||
282 | } | ||
283 | |||
284 | QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings, | ||
285 | const QDateTime& d ) | ||
286 | { | ||
287 | |||
288 | QArray<int> m_currentQuery( m_contactList.count() ); | ||
289 | QListIterator<OContact> it( m_contactList ); | ||
290 | uint arraycounter = 0; | ||
291 | |||
292 | for( ; it.current(); ++it ){ | ||
293 | /* Search all fields and compare them with query object. Store them into list | ||
294 | * if all fields matches. | ||
295 | */ | ||
296 | QDate* queryDate = 0l; | ||
297 | QDate* checkDate = 0l; | ||
298 | bool allcorrect = true; | ||
299 | for ( int i = 0; i < Qtopia::Groups; i++ ) { | ||
300 | // Birthday and anniversary are special nonstring fields and should | ||
301 | // be handled specially | ||
302 | switch ( i ){ | ||
303 | case Qtopia::Birthday: | ||
304 | queryDate = new QDate( query.birthday() ); | ||
305 | checkDate = new QDate( (*it)->birthday() ); | ||
306 | case Qtopia::Anniversary: | ||
307 | if ( queryDate == 0l ){ | ||
308 | queryDate = new QDate( query.anniversary() ); | ||
309 | checkDate = new QDate( (*it)->anniversary() ); | ||
310 | } | ||
311 | |||
312 | if ( queryDate->isValid() ){ | ||
313 | if( checkDate->isValid() ){ | ||
314 | if ( settings & OContactAccess::DateYear ){ | ||
315 | if ( queryDate->year() != checkDate->year() ) | ||
316 | allcorrect = false; | ||
317 | } | ||
318 | if ( settings & OContactAccess::DateMonth ){ | ||
319 | if ( queryDate->month() != checkDate->month() ) | ||
320 | allcorrect = false; | ||
321 | } | ||
322 | if ( settings & OContactAccess::DateDay ){ | ||
323 | if ( queryDate->day() != checkDate->day() ) | ||
324 | allcorrect = false; | ||
325 | } | ||
326 | if ( settings & OContactAccess::DateDiff ) { | ||
327 | QDate current; | ||
328 | // If we get an additional date, we | ||
329 | // will take this date instead of | ||
330 | // the current one.. | ||
331 | if ( !d.date().isValid() ) | ||
332 | current = QDate::currentDate(); | ||
333 | else | ||
334 | current = d.date(); | ||
335 | |||
336 | // We have to equalize the year, otherwise | ||
337 | // the search will fail.. | ||
338 | checkDate->setYMD( current.year(), | ||
339 | checkDate->month(), | ||
340 | checkDate->day() ); | ||
341 | if ( *checkDate < current ) | ||
342 | checkDate->setYMD( current.year()+1, | ||
343 | checkDate->month(), | ||
344 | checkDate->day() ); | ||
345 | |||
346 | // Check whether the birthday/anniversary date is between | ||
347 | // the current/given date and the maximum date | ||
348 | // ( maximum time range ) ! | ||
349 | qWarning("Checking if %s is between %s and %s ! ", | ||
350 | checkDate->toString().latin1(), | ||
351 | current.toString().latin1(), | ||
352 | queryDate->toString().latin1() ); | ||
353 | if ( current.daysTo( *queryDate ) >= 0 ){ | ||
354 | if ( !( ( *checkDate >= current ) && | ||
355 | ( *checkDate <= *queryDate ) ) ){ | ||
356 | allcorrect = false; | ||
357 | qWarning (" Nope!.."); | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | } else{ | ||
362 | // checkDate is invalid. Therefore this entry is always rejected | ||
363 | allcorrect = false; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | delete queryDate; | ||
368 | queryDate = 0l; | ||
369 | delete checkDate; | ||
370 | checkDate = 0l; | ||
371 | break; | ||
372 | default: | ||
373 | /* Just compare fields which are not empty in the query object */ | ||
374 | if ( !query.field(i).isEmpty() ){ | ||
375 | switch ( settings & ~( OContactAccess::IgnoreCase | ||
376 | | OContactAccess::DateDiff | ||
377 | | OContactAccess::DateYear | ||
378 | | OContactAccess::DateMonth | ||
379 | | OContactAccess::DateDay | ||
380 | | OContactAccess::MatchOne | ||
381 | ) ){ | ||
382 | |||
383 | case OContactAccess::RegExp:{ | ||
384 | QRegExp expr ( query.field(i), | ||
385 | !(settings & OContactAccess::IgnoreCase), | ||
386 | false ); | ||
387 | if ( expr.find ( (*it)->field(i), 0 ) == -1 ) | ||
388 | allcorrect = false; | ||
389 | } | ||
390 | break; | ||
391 | case OContactAccess::WildCards:{ | ||
392 | QRegExp expr ( query.field(i), | ||
393 | !(settings & OContactAccess::IgnoreCase), | ||
394 | true ); | ||
395 | if ( expr.find ( (*it)->field(i), 0 ) == -1 ) | ||
396 | allcorrect = false; | ||
397 | } | ||
398 | break; | ||
399 | case OContactAccess::ExactMatch:{ | ||
400 | if (settings & OContactAccess::IgnoreCase){ | ||
401 | if ( query.field(i).upper() != | ||
402 | (*it)->field(i).upper() ) | ||
403 | allcorrect = false; | ||
404 | }else{ | ||
405 | if ( query.field(i) != (*it)->field(i) ) | ||
406 | allcorrect = false; | ||
407 | } | ||
408 | } | ||
409 | break; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | } | ||
414 | if ( allcorrect ){ | ||
415 | m_currentQuery[arraycounter++] = (*it)->uid(); | ||
416 | } | ||
417 | } | ||
418 | |||
419 | // Shrink to fit.. | ||
420 | m_currentQuery.resize(arraycounter); | ||
421 | |||
422 | return m_currentQuery; | ||
423 | } | ||
424 | |||
425 | QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const | ||
426 | { | ||
427 | QArray<int> m_currentQuery( m_contactList.count() ); | ||
428 | QListIterator<OContact> it( m_contactList ); | ||
429 | uint arraycounter = 0; | ||
430 | |||
431 | for( ; it.current(); ++it ){ | ||
432 | if ( (*it)->match( r ) ){ | ||
433 | m_currentQuery[arraycounter++] = (*it)->uid(); | ||
434 | } | ||
435 | |||
436 | } | ||
437 | // Shrink to fit.. | ||
438 | m_currentQuery.resize(arraycounter); | ||
439 | |||
440 | return m_currentQuery; | ||
441 | } | ||
442 | |||
443 | const uint OContactAccessBackend_XML::querySettings() | ||
444 | { | ||
445 | return ( OContactAccess::WildCards | ||
446 | | OContactAccess::IgnoreCase | ||
447 | | OContactAccess::RegExp | ||
448 | | OContactAccess::ExactMatch | ||
449 | | OContactAccess::DateDiff | ||
450 | | OContactAccess::DateYear | ||
451 | | OContactAccess::DateMonth | ||
452 | | OContactAccess::DateDay | ||
453 | ); | ||
454 | } | ||
455 | |||
456 | bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const | ||
457 | { | ||
458 | /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay | ||
459 | * may be added with any of the other settings. IgnoreCase should never used alone. | ||
460 | * Wildcards, RegExp, ExactMatch should never used at the same time... | ||
461 | */ | ||
462 | |||
463 | // Step 1: Check whether the given settings are supported by this backend | ||
464 | if ( ( querySettings & ( | ||
465 | OContactAccess::IgnoreCase | ||
466 | | OContactAccess::WildCards | ||
467 | | OContactAccess::DateDiff | ||
468 | | OContactAccess::DateYear | ||
469 | | OContactAccess::DateMonth | ||
470 | | OContactAccess::DateDay | ||
471 | | OContactAccess::RegExp | ||
472 | | OContactAccess::ExactMatch | ||
473 | ) ) != querySettings ) | ||
474 | return false; | ||
475 | |||
476 | // Step 2: Check whether the given combinations are ok.. | ||
477 | |||
478 | // IngoreCase alone is invalid | ||
479 | if ( querySettings == OContactAccess::IgnoreCase ) | ||
480 | return false; | ||
481 | |||
482 | // WildCards, RegExp and ExactMatch should never used at the same time | ||
483 | switch ( querySettings & ~( OContactAccess::IgnoreCase | ||
484 | | OContactAccess::DateDiff | ||
485 | | OContactAccess::DateYear | ||
486 | | OContactAccess::DateMonth | ||
487 | | OContactAccess::DateDay | ||
488 | ) | ||
489 | ){ | ||
490 | case OContactAccess::RegExp: | ||
491 | return ( true ); | ||
492 | case OContactAccess::WildCards: | ||
493 | return ( true ); | ||
494 | case OContactAccess::ExactMatch: | ||
495 | return ( true ); | ||
496 | case 0: // one of the upper removed bits were set.. | ||
497 | return ( true ); | ||
498 | default: | ||
499 | return ( false ); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | // Currently only asc implemented.. | ||
504 | QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) | ||
505 | { | ||
506 | QMap<QString, int> nameToUid; | ||
507 | QStringList names; | ||
508 | QArray<int> m_currentQuery( m_contactList.count() ); | ||
509 | |||
510 | // First fill map and StringList with all Names | ||
511 | // Afterwards sort namelist and use map to fill array to return.. | ||
512 | QListIterator<OContact> it( m_contactList ); | ||
513 | for( ; it.current(); ++it ){ | ||
514 | names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) ); | ||
515 | nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() ); | ||
516 | } | ||
517 | names.sort(); | ||
518 | |||
519 | int i = 0; | ||
520 | if ( asc ){ | ||
521 | for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) | ||
522 | m_currentQuery[i++] = nameToUid[ (*it) ]; | ||
523 | }else{ | ||
524 | for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) | ||
525 | m_currentQuery[i++] = nameToUid[ (*it) ]; | ||
526 | } | ||
527 | |||
528 | return m_currentQuery; | ||
529 | |||
530 | } | ||
531 | |||
532 | bool OContactAccessBackend_XML::add ( const OContact &newcontact ) | ||
533 | { | ||
534 | //qWarning("odefaultbackend: ACTION::ADD"); | ||
535 | updateJournal (newcontact, ACTION_ADD); | ||
536 | addContact_p( newcontact ); | ||
537 | |||
538 | m_changed = true; | ||
539 | |||
540 | return true; | ||
541 | } | ||
542 | |||
543 | bool OContactAccessBackend_XML::replace ( const OContact &contact ) | ||
544 | { | ||
545 | m_changed = true; | ||
546 | |||
547 | OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) ); | ||
548 | |||
549 | if ( found ) { | ||
550 | OContact* newCont = new OContact( contact ); | ||
551 | |||
552 | updateJournal ( *newCont, ACTION_REPLACE); | ||
553 | m_contactList.removeRef ( found ); | ||
554 | m_contactList.append ( newCont ); | ||
555 | m_uidToContact.remove( QString().setNum( contact.uid() ) ); | ||
556 | m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont ); | ||
557 | |||
558 | qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid()); | ||
559 | |||
560 | return true; | ||
561 | } else | ||
562 | return false; | ||
563 | } | ||
564 | |||
565 | bool OContactAccessBackend_XML::remove ( int uid ) | ||
566 | { | ||
567 | m_changed = true; | ||
568 | |||
569 | OContact* found = m_uidToContact.find ( QString().setNum( uid ) ); | ||
570 | |||
571 | if ( found ) { | ||
572 | updateJournal ( *found, ACTION_REMOVE); | ||
573 | m_contactList.removeRef ( found ); | ||
574 | m_uidToContact.remove( QString().setNum( uid ) ); | ||
575 | |||
576 | return true; | ||
577 | } else | ||
578 | return false; | ||
579 | } | ||
580 | |||
581 | bool OContactAccessBackend_XML::reload(){ | ||
582 | /* Reload is the same as load in this implementation */ | ||
583 | return ( load() ); | ||
584 | } | ||
585 | |||
586 | void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) | ||
587 | { | ||
588 | OContact* contRef = new OContact( newcontact ); | ||
589 | |||
590 | m_contactList.append ( contRef ); | ||
591 | m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef ); | ||
592 | } | ||
593 | |||
594 | /* This function loads the xml-database and the journalfile */ | ||
595 | bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) | ||
596 | { | ||
597 | |||
598 | /* We use the time of the last read to check if the file was | ||
599 | * changed externally. | ||
600 | */ | ||
601 | if ( !isJournal ){ | ||
602 | QFileInfo fi( filename ); | ||
603 | m_readtime = fi.lastModified (); | ||
604 | } | ||
605 | |||
606 | const int JOURNALACTION = Qtopia::Notes + 1; | ||
607 | const int JOURNALROW = JOURNALACTION + 1; | ||
608 | |||
609 | bool foundAction = false; | ||
610 | journal_action action = ACTION_ADD; | ||
611 | int journalKey = 0; | ||
612 | QMap<int, QString> contactMap; | ||
613 | QMap<QString, QString> customMap; | ||
614 | QMap<QString, QString>::Iterator customIt; | ||
615 | QAsciiDict<int> dict( 47 ); | ||
616 | |||
617 | dict.setAutoDelete( TRUE ); | ||
618 | dict.insert( "Uid", new int(Qtopia::AddressUid) ); | ||
619 | dict.insert( "Title", new int(Qtopia::Title) ); | ||
620 | dict.insert( "FirstName", new int(Qtopia::FirstName) ); | ||
621 | dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); | ||
622 | dict.insert( "LastName", new int(Qtopia::LastName) ); | ||
623 | dict.insert( "Suffix", new int(Qtopia::Suffix) ); | ||
624 | dict.insert( "FileAs", new int(Qtopia::FileAs) ); | ||
625 | dict.insert( "Categories", new int(Qtopia::AddressCategory) ); | ||
626 | dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); | ||
627 | dict.insert( "Emails", new int(Qtopia::Emails) ); | ||
628 | dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); | ||
629 | dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); | ||
630 | dict.insert( "HomeState", new int(Qtopia::HomeState) ); | ||
631 | dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); | ||
632 | dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); | ||
633 | dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); | ||
634 | dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); | ||
635 | dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); | ||
636 | dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); | ||
637 | dict.insert( "Company", new int(Qtopia::Company) ); | ||
638 | dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); | ||
639 | dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); | ||
640 | dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); | ||
641 | dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); | ||
642 | dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); | ||
643 | dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); | ||
644 | dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); | ||
645 | dict.insert( "Department", new int(Qtopia::Department) ); | ||
646 | dict.insert( "Office", new int(Qtopia::Office) ); | ||
647 | dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); | ||
648 | dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); | ||
649 | dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); | ||
650 | dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); | ||
651 | dict.insert( "Profession", new int(Qtopia::Profession) ); | ||
652 | dict.insert( "Assistant", new int(Qtopia::Assistant) ); | ||
653 | dict.insert( "Manager", new int(Qtopia::Manager) ); | ||
654 | dict.insert( "Spouse", new int(Qtopia::Spouse) ); | ||
655 | dict.insert( "Children", new int(Qtopia::Children) ); | ||
656 | dict.insert( "Gender", new int(Qtopia::Gender) ); | ||
657 | dict.insert( "Birthday", new int(Qtopia::Birthday) ); | ||
658 | dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); | ||
659 | dict.insert( "Nickname", new int(Qtopia::Nickname) ); | ||
660 | dict.insert( "Notes", new int(Qtopia::Notes) ); | ||
661 | dict.insert( "action", new int(JOURNALACTION) ); | ||
662 | dict.insert( "actionrow", new int(JOURNALROW) ); | ||
663 | |||
664 | //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); | ||
665 | |||
666 | XMLElement *root = XMLElement::load( filename ); | ||
667 | if(root != 0l ){ // start parsing | ||
668 | /* Parse all XML-Elements and put the data into the | ||
669 | * Contact-Class | ||
670 | */ | ||
671 | XMLElement *element = root->firstChild(); | ||
672 | //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); | ||
673 | element = element->firstChild(); | ||
674 | |||
675 | /* Search Tag "Contacts" which is the parent of all Contacts */ | ||
676 | while( element && !isJournal ){ | ||
677 | if( element->tagName() != QString::fromLatin1("Contacts") ){ | ||
678 | //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", | ||
679 | // element->tagName().latin1()); | ||
680 | element = element->nextChild(); | ||
681 | } else { | ||
682 | element = element->firstChild(); | ||
683 | break; | ||
684 | } | ||
685 | } | ||
686 | /* Parse all Contacts and ignore unknown tags */ | ||
687 | while( element ){ | ||
688 | if( element->tagName() != QString::fromLatin1("Contact") ){ | ||
689 | //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", | ||
690 | // element->tagName().latin1()); | ||
691 | element = element->nextChild(); | ||
692 | continue; | ||
693 | } | ||
694 | /* Found alement with tagname "contact", now parse and store all | ||
695 | * attributes contained | ||
696 | */ | ||
697 | //qWarning("OContactDefBack::load element tagName() : %s", | ||
698 | // element->tagName().latin1() ); | ||
699 | QString dummy; | ||
700 | foundAction = false; | ||
701 | |||
702 | XMLElement::AttributeMap aMap = element->attributes(); | ||
703 | XMLElement::AttributeMap::Iterator it; | ||
704 | contactMap.clear(); | ||
705 | customMap.clear(); | ||
706 | for( it = aMap.begin(); it != aMap.end(); ++it ){ | ||
707 | // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); | ||
708 | |||
709 | int *find = dict[ it.key() ]; | ||
710 | /* Unknown attributes will be stored as "Custom" elements */ | ||
711 | if ( !find ) { | ||
712 | // qWarning("Attribute %s not known.", it.key().latin1()); | ||
713 | //contact.setCustomField(it.key(), it.data()); | ||
714 | customMap.insert( it.key(), it.data() ); | ||
715 | continue; | ||
716 | } | ||
717 | |||
718 | /* Check if special conversion is needed and add attribute | ||
719 | * into Contact class | ||
720 | */ | ||
721 | switch( *find ) { | ||
722 | /* | ||
723 | case Qtopia::AddressUid: | ||
724 | contact.setUid( it.data().toInt() ); | ||
725 | break; | ||
726 | case Qtopia::AddressCategory: | ||
727 | contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); | ||
728 | break; | ||
729 | */ | ||
730 | case JOURNALACTION: | ||
731 | action = journal_action(it.data().toInt()); | ||
732 | foundAction = true; | ||
733 | qWarning ("ODefBack(journal)::ACTION found: %d", action); | ||
734 | break; | ||
735 | case JOURNALROW: | ||
736 | journalKey = it.data().toInt(); | ||
737 | break; | ||
738 | default: // no conversion needed add them to the map | ||
739 | contactMap.insert( *find, it.data() ); | ||
740 | break; | ||
741 | } | ||
742 | } | ||
743 | /* now generate the Contact contact */ | ||
744 | OContact contact( contactMap ); | ||
745 | |||
746 | for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { | ||
747 | contact.setCustomField( customIt.key(), customIt.data() ); | ||
748 | } | ||
749 | |||
750 | if (foundAction){ | ||
751 | foundAction = false; | ||
752 | switch ( action ) { | ||
753 | case ACTION_ADD: | ||
754 | addContact_p (contact); | ||
755 | break; | ||
756 | case ACTION_REMOVE: | ||
757 | if ( !remove (contact.uid()) ) | ||
758 | qWarning ("ODefBack(journal)::Unable to remove uid: %d", | ||
759 | contact.uid() ); | ||
760 | break; | ||
761 | case ACTION_REPLACE: | ||
762 | if ( !replace ( contact ) ) | ||
763 | qWarning ("ODefBack(journal)::Unable to replace uid: %d", | ||
764 | contact.uid() ); | ||
765 | break; | ||
766 | default: | ||
767 | qWarning ("Unknown action: ignored !"); | ||
768 | break; | ||
769 | } | ||
770 | }else{ | ||
771 | /* Add contact to list */ | ||
772 | addContact_p (contact); | ||
773 | } | ||
774 | |||
775 | /* Move to next element */ | ||
776 | element = element->nextChild(); | ||
777 | } | ||
778 | }else { | ||
779 | qWarning("ODefBack::could not load"); | ||
780 | } | ||
781 | delete root; | ||
782 | qWarning("returning from loading" ); | ||
783 | return true; | ||
784 | } | ||
785 | |||
786 | |||
787 | void OContactAccessBackend_XML::updateJournal( const OContact& cnt, | ||
788 | journal_action action ) | ||
789 | { | ||
790 | QFile f( m_journalName ); | ||
791 | bool created = !f.exists(); | ||
792 | if ( !f.open(IO_WriteOnly|IO_Append) ) | ||
793 | return; | ||
794 | |||
795 | QString buf; | ||
796 | QCString str; | ||
797 | |||
798 | // if the file was created, we have to set the Tag "<CONTACTS>" to | ||
799 | // get a XML-File which is readable by our parser. | ||
800 | // This is just a cheat, but better than rewrite the parser. | ||
801 | if ( created ){ | ||
802 | buf = "<Contacts>"; | ||
803 | QCString cstr = buf.utf8(); | ||
804 | f.writeBlock( cstr.data(), cstr.length() ); | ||
805 | } | ||
806 | |||
807 | buf = "<Contact "; | ||
808 | cnt.save( buf ); | ||
809 | buf += " action=\"" + QString::number( (int)action ) + "\" "; | ||
810 | buf += "/>\n"; | ||
811 | QCString cstr = buf.utf8(); | ||
812 | f.writeBlock( cstr.data(), cstr.length() ); | ||
813 | } | ||
814 | |||
815 | void OContactAccessBackend_XML::removeJournal() | ||
816 | { | ||
817 | QFile f ( m_journalName ); | ||
818 | if ( f.exists() ) | ||
819 | f.remove(); | ||
820 | } | ||
821 | |||