summaryrefslogtreecommitdiff
authoreilers <eilers>2003-03-21 10:33:09 (UTC)
committer eilers <eilers>2003-03-21 10:33:09 (UTC)
commit8136284c38384b169cd2843ee61480d45b6c1cba (patch) (unidiff)
treead798e3df8dc27a41f431a2130dbf50947fbca49
parent6f5f148ff9eac1e4d76bea4460a7984d1e3069b7 (diff)
downloadopie-8136284c38384b169cd2843ee61480d45b6c1cba.zip
opie-8136284c38384b169cd2843ee61480d45b6c1cba.tar.gz
opie-8136284c38384b169cd2843ee61480d45b6c1cba.tar.bz2
Merged speed optimized xml backend for contacts to main.
Added QDateTime to querybyexample. For instance, it is now possible to get all Birthdays/Anniversaries between two dates. This should be used to show all birthdays in the datebook.. This change is sourcecode backward compatible but you have to upgrade the binaries for today-addressbook.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/libopie.pro1
-rw-r--r--libopie/pim/ocontactaccessbackend_vcard.cpp10
-rw-r--r--libopie/pim/ocontactaccessbackend_vcard.h10
-rw-r--r--libopie/pim/ocontactaccessbackend_xml.cpp166
-rw-r--r--libopie/pim/ocontactaccessbackend_xml.h677
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.cpp2
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.h2
-rw-r--r--libopie/pim/opimaccessbackend.h6
-rw-r--r--libopie/pim/opimaccesstemplate.h6
-rw-r--r--libopie/pim/otodoaccesssql.cpp2
-rw-r--r--libopie/pim/otodoaccesssql.h2
-rw-r--r--libopie/pim/otodoaccessvcal.cpp2
-rw-r--r--libopie/pim/otodoaccessvcal.h2
-rw-r--r--libopie/pim/otodoaccessxml.cpp2
-rw-r--r--libopie/pim/otodoaccessxml.h2
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp10
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_vcard.h10
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp166
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_xml.h677
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp2
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend_xml.h2
-rw-r--r--libopie2/opiepim/backend/opimaccessbackend.h6
-rw-r--r--libopie2/opiepim/backend/otodoaccesssql.cpp2
-rw-r--r--libopie2/opiepim/backend/otodoaccesssql.h2
-rw-r--r--libopie2/opiepim/backend/otodoaccessvcal.cpp2
-rw-r--r--libopie2/opiepim/backend/otodoaccessvcal.h2
-rw-r--r--libopie2/opiepim/backend/otodoaccessxml.cpp2
-rw-r--r--libopie2/opiepim/backend/otodoaccessxml.h2
-rw-r--r--libopie2/opiepim/core/opimaccesstemplate.h6
29 files changed, 347 insertions, 1436 deletions
diff --git a/libopie/libopie.pro b/libopie/libopie.pro
index 391f30e..2bf9985 100644
--- a/libopie/libopie.pro
+++ b/libopie/libopie.pro
@@ -1,118 +1,119 @@
1TEMPLATE = lib 1TEMPLATE = lib
2CONFIG += qte warn_on release 2CONFIG += qte warn_on release
3HEADERS = ofontmenu.h \ 3HEADERS = ofontmenu.h \
4 ocolorbutton.h \ 4 ocolorbutton.h \
5 ofiledialog.h ofileselector.h \ 5 ofiledialog.h ofileselector.h \
6 ocheckitem.h \ 6 ocheckitem.h \
7 xmltree.h \ 7 xmltree.h \
8 colordialog.h colorpopupmenu.h \ 8 colordialog.h colorpopupmenu.h \
9 oclickablelabel.h oprocctrl.h \ 9 oclickablelabel.h oprocctrl.h \
10 oprocess.h odevice.h odevicebutton.h \ 10 oprocess.h odevice.h odevicebutton.h \
11 otimepicker.h otabwidget.h \ 11 otimepicker.h otabwidget.h \
12 otabbar.h otabinfo.h \ 12 otabbar.h otabinfo.h \
13 ofontselector.h \ 13 ofontselector.h \
14 pim/opimrecord.h \ 14 pim/opimrecord.h \
15 pim/otodo.h \ 15 pim/otodo.h \
16 pim/orecordlist.h \ 16 pim/orecordlist.h \
17 pim/opimaccesstemplate.h \ 17 pim/opimaccesstemplate.h \
18 pim/opimaccessbackend.h \ 18 pim/opimaccessbackend.h \
19 pim/otodoaccess.h \ 19 pim/otodoaccess.h \
20 pim/otodoaccessbackend.h \ 20 pim/otodoaccessbackend.h \
21 pim/ocontact.h \ 21 pim/ocontact.h \
22 pim/ocontactaccess.h \ 22 pim/ocontactaccess.h \
23 pim/ocontactaccessbackend.h \ 23 pim/ocontactaccessbackend.h \
24 pim/ocontactaccessbackend_xml.h \ 24 pim/ocontactaccessbackend_xml.h \
25 pim/ocontactaccessbackend_vcard.h \ 25 pim/ocontactaccessbackend_vcard.h \
26 pim/obackendfactory.h \ 26 pim/obackendfactory.h \
27 pim/opimcache.h \ 27 pim/opimcache.h \
28 pim/otodoaccessvcal.h \ 28 pim/otodoaccessvcal.h \
29 pim/orecur.h \ 29 pim/orecur.h \
30 pim/opimstate.h \ 30 pim/opimstate.h \
31 pim/opimxrefpartner.h \ 31 pim/opimxrefpartner.h \
32 pim/opimxref.h \ 32 pim/opimxref.h \
33 pim/opimxrefmanager.h \ 33 pim/opimxrefmanager.h \
34 pim/opimmaintainer.h \ 34 pim/opimmaintainer.h \
35 pim/opimnotify.h \ 35 pim/opimnotify.h \
36 pim/opimnotifymanager.h \ 36 pim/opimnotifymanager.h \
37 pim/opimmainwindow.h \ 37 pim/opimmainwindow.h \
38 pim/opimresolver.h \ 38 pim/opimresolver.h \
39 pim/oevent.h \ 39 pim/oevent.h \
40 pim/otimezone.h \ 40 pim/otimezone.h \
41 pim/odatebookaccess.h \ 41 pim/odatebookaccess.h \
42 pim/odatebookaccessbackend.h \ 42 pim/odatebookaccessbackend.h \
43 pim/odatebookaccessbackend_xml.h \ 43 pim/odatebookaccessbackend_xml.h \
44 orecurrancewidget.h \ 44 orecurrancewidget.h \
45 oticker.h 45 oticker.h
46# pim/otodoaccesssql.h \ 46# pim/otodoaccesssql.h \
47 47
48SOURCES = ofontmenu.cc \ 48SOURCES = ofontmenu.cc \
49 ocolorbutton.cpp \ 49 ocolorbutton.cpp \
50 sharp_compat.cpp \ 50 sharp_compat.cpp \
51 xmltree.cc \ 51 xmltree.cc \
52 ofiledialog.cc ofileselector.cc \ 52 ofiledialog.cc ofileselector.cc \
53 ocheckitem.cpp \ 53 ocheckitem.cpp \
54 colordialog.cpp \ 54 colordialog.cpp \
55 colorpopupmenu.cpp oclickablelabel.cpp \ 55 colorpopupmenu.cpp oclickablelabel.cpp \
56 oprocctrl.cpp oprocess.cpp \ 56 oprocctrl.cpp oprocess.cpp \
57 odevice.cpp odevicebutton.cpp otimepicker.cpp \ 57 odevice.cpp odevicebutton.cpp otimepicker.cpp \
58 otabwidget.cpp otabbar.cpp \ 58 otabwidget.cpp otabbar.cpp \
59 ofontselector.cpp \ 59 ofontselector.cpp \
60 pim/otodo.cpp \ 60 pim/otodo.cpp \
61 pim/opimrecord.cpp \ 61 pim/opimrecord.cpp \
62 pim/otodoaccess.cpp \ 62 pim/otodoaccess.cpp \
63 pim/otodoaccessbackend.cpp \ 63 pim/otodoaccessbackend.cpp \
64 pim/otodoaccessxml.cpp \ 64 pim/otodoaccessxml.cpp \
65 pim/ocontact.cpp \ 65 pim/ocontact.cpp \
66 pim/ocontactaccess.cpp \ 66 pim/ocontactaccess.cpp \
67 pim/ocontactaccessbackend_vcard.cpp \ 67 pim/ocontactaccessbackend_vcard.cpp \
68 pim/ocontactaccessbackend_xml.cpp \
68 pim/otodoaccessvcal.cpp \ 69 pim/otodoaccessvcal.cpp \
69 pim/orecur.cpp \ 70 pim/orecur.cpp \
70 pim/opimstate.cpp \ 71 pim/opimstate.cpp \
71 pim/opimxrefpartner.cpp \ 72 pim/opimxrefpartner.cpp \
72 pim/opimxref.cpp \ 73 pim/opimxref.cpp \
73 pim/opimxrefmanager.cpp \ 74 pim/opimxrefmanager.cpp \
74 pim/opimmaintainer.cpp \ 75 pim/opimmaintainer.cpp \
75 pim/opimnotify.cpp \ 76 pim/opimnotify.cpp \
76 pim/opimnotifymanager.cpp \ 77 pim/opimnotifymanager.cpp \
77 pim/opimmainwindow.cpp \ 78 pim/opimmainwindow.cpp \
78 pim/opimresolver.cpp \ 79 pim/opimresolver.cpp \
79 pim/oevent.cpp \ 80 pim/oevent.cpp \
80 pim/otimezone.cpp \ 81 pim/otimezone.cpp \
81 pim/odatebookaccess.cpp \ 82 pim/odatebookaccess.cpp \
82 pim/odatebookaccessbackend.cpp \ 83 pim/odatebookaccessbackend.cpp \
83 pim/odatebookaccessbackend_xml.cpp \ 84 pim/odatebookaccessbackend_xml.cpp \
84 orecurrancewidget.cpp \ 85 orecurrancewidget.cpp \
85 oticker.cpp 86 oticker.cpp
86# pim/otodoaccesssql.cpp \ 87# pim/otodoaccesssql.cpp \
87 88
88TARGET = opie 89TARGET = opie
89INCLUDEPATH += $(OPIEDIR)/include 90INCLUDEPATH += $(OPIEDIR)/include
90DESTDIR = $(OPIEDIR)/lib$(PROJMAK) 91DESTDIR = $(OPIEDIR)/lib$(PROJMAK)
91#VERSION = 1.0.0 92#VERSION = 1.0.0
92 93
93LIBS += -lqpe 94LIBS += -lqpe
94 95
95# LIBS += -lopiesql 96# LIBS += -lopiesql
96 97
97INTERFACES = otimepickerbase.ui orecurrancebase.ui 98INTERFACES = otimepickerbase.ui orecurrancebase.ui
98 99
99TRANSLATIONS = ../i18n/de/libopie.ts \ 100TRANSLATIONS = ../i18n/de/libopie.ts \
100 ../i18n/xx/libopie.ts \ 101 ../i18n/xx/libopie.ts \
101 ../i18n/en/libopie.ts \ 102 ../i18n/en/libopie.ts \
102 ../i18n/es/libopie.ts \ 103 ../i18n/es/libopie.ts \
103 ../i18n/fr/libopie.ts \ 104 ../i18n/fr/libopie.ts \
104 ../i18n/hu/libopie.ts \ 105 ../i18n/hu/libopie.ts \
105 ../i18n/ja/libopie.ts \ 106 ../i18n/ja/libopie.ts \
106 ../i18n/ko/libopie.ts \ 107 ../i18n/ko/libopie.ts \
107 ../i18n/no/libopie.ts \ 108 ../i18n/no/libopie.ts \
108 ../i18n/pl/libopie.ts \ 109 ../i18n/pl/libopie.ts \
109 ../i18n/pt/libopie.ts \ 110 ../i18n/pt/libopie.ts \
110 ../i18n/pt_BR/libopie.ts \ 111 ../i18n/pt_BR/libopie.ts \
111 ../i18n/sl/libopie.ts \ 112 ../i18n/sl/libopie.ts \
112 ../i18n/zh_CN/libopie.ts \ 113 ../i18n/zh_CN/libopie.ts \
113 ../i18n/zh_TW/libopie.ts \ 114 ../i18n/zh_TW/libopie.ts \
114 ../i18n/da/libopie.ts 115 ../i18n/da/libopie.ts
115 116
116 117
117 118
118include ( $(OPIEDIR)/include.pro ) 119include ( $(OPIEDIR)/include.pro )
diff --git a/libopie/pim/ocontactaccessbackend_vcard.cpp b/libopie/pim/ocontactaccessbackend_vcard.cpp
index e537269..f24523f 100644
--- a/libopie/pim/ocontactaccessbackend_vcard.cpp
+++ b/libopie/pim/ocontactaccessbackend_vcard.cpp
@@ -1,615 +1,623 @@
1/* 1/*
2 * VCard Backend for the OPIE-Contact Database. 2 * VCard Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (C) 2000 Trolltech AS. All rights reserved. 4 * Copyright (C) 2000 Trolltech AS. All rights reserved.
5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
6 * 6 *
7 * ===================================================================== 7 * =====================================================================
8 *This program is free software; you can redistribute it and/or 8 *This program is free software; you can redistribute it and/or
9 *modify it under the terms of the GNU Library General Public 9 *modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version. 11 * version 2 of the License, or (at your option) any later version.
12 * ===================================================================== 12 * =====================================================================
13 * ToDo: 13 * ToDo:
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.9 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
20 * Revision 1.8 2003/02/21 16:52:49 zecke 28 * Revision 1.8 2003/02/21 16:52:49 zecke
21 * -Remove old Todo classes they're deprecated and today I already using the 29 * -Remove old Todo classes they're deprecated and today I already using the
22 * new API 30 * new API
23 * -Guard against self assignment in OTodo 31 * -Guard against self assignment in OTodo
24 * -Add test apps for OPIM 32 * -Add test apps for OPIM
25 * -Opiefied Event classes 33 * -Opiefied Event classes
26 * -Added TimeZone handling and pinning of TimeZones to OEvent 34 * -Added TimeZone handling and pinning of TimeZones to OEvent
27 * -Adjust ORecur and the widget to better timezone behaviour 35 * -Adjust ORecur and the widget to better timezone behaviour
28 * 36 *
29 * Revision 1.7 2003/02/16 22:25:46 zecke 37 * Revision 1.7 2003/02/16 22:25:46 zecke
30 * 0000276 Fix for that bug.. or better temp workaround 38 * 0000276 Fix for that bug.. or better temp workaround
31 * A Preferred Number is HOME|VOICE 39 * A Preferred Number is HOME|VOICE
32 * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test 40 * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test
33 * triggers both 41 * triggers both
34 * and the cell phone number overrides the other entries.. 42 * and the cell phone number overrides the other entries..
35 * 43 *
36 * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the 44 * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the
37 * number 45 * number
38 * 46 *
39 * The right and final fix would be to reorder the if statement to make it 47 * The right and final fix would be to reorder the if statement to make it
40 * if else based and the less common thing put to the bottom 48 * if else based and the less common thing put to the bottom
41 * 49 *
42 * OTodoAccessVcal fix the date for beaming 50 * OTodoAccessVcal fix the date for beaming
43 * 51 *
44 * Revision 1.6 2003/01/13 15:49:31 eilers 52 * Revision 1.6 2003/01/13 15:49:31 eilers
45 * Fixing crash when businesscard.vcf is missing.. 53 * Fixing crash when businesscard.vcf is missing..
46 * 54 *
47 * Revision 1.5 2002/12/07 13:26:22 eilers 55 * Revision 1.5 2002/12/07 13:26:22 eilers
48 * Fixing bug in storing anniversary.. 56 * Fixing bug in storing anniversary..
49 * 57 *
50 * Revision 1.4 2002/11/13 14:14:51 eilers 58 * Revision 1.4 2002/11/13 14:14:51 eilers
51 * Added sorted for Contacts.. 59 * Added sorted for Contacts..
52 * 60 *
53 * Revision 1.3 2002/11/11 16:41:09 kergoth 61 * Revision 1.3 2002/11/11 16:41:09 kergoth
54 * no default arguments in implementation 62 * no default arguments in implementation
55 * 63 *
56 * Revision 1.2 2002/11/10 15:41:53 eilers 64 * Revision 1.2 2002/11/10 15:41:53 eilers
57 * Bugfixes.. 65 * Bugfixes..
58 * 66 *
59 * Revision 1.1 2002/11/09 14:34:52 eilers 67 * Revision 1.1 2002/11/09 14:34:52 eilers
60 * Added VCard Backend. 68 * Added VCard Backend.
61 * 69 *
62 */ 70 */
63#include "ocontactaccessbackend_vcard.h" 71#include "ocontactaccessbackend_vcard.h"
64#include "../../library/backend/vobject_p.h" 72#include "../../library/backend/vobject_p.h"
65#include "../../library/backend/qfiledirect_p.h" 73#include "../../library/backend/qfiledirect_p.h"
66 74
67#include <qpe/timeconversion.h> 75#include <qpe/timeconversion.h>
68 76
69#include <qfile.h> 77#include <qfile.h>
70 78
71OContactAccessBackend_VCard::OContactAccessBackend_VCard ( QString , QString filename ): 79OContactAccessBackend_VCard::OContactAccessBackend_VCard ( QString , QString filename ):
72 m_dirty( false ), 80 m_dirty( false ),
73 m_file( filename ) 81 m_file( filename )
74{ 82{
75 load(); 83 load();
76} 84}
77 85
78 86
79bool OContactAccessBackend_VCard::load () 87bool OContactAccessBackend_VCard::load ()
80{ 88{
81 m_map.clear(); 89 m_map.clear();
82 m_dirty = false; 90 m_dirty = false;
83 91
84 VObject* obj = 0l; 92 VObject* obj = 0l;
85 93
86 if ( QFile::exists(m_file) ){ 94 if ( QFile::exists(m_file) ){
87 obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); 95 obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() );
88 if ( !obj ) 96 if ( !obj )
89 return false; 97 return false;
90 }else{ 98 }else{
91 qWarning("File \"%s\" not found !", m_file.latin1() ); 99 qWarning("File \"%s\" not found !", m_file.latin1() );
92 return false; 100 return false;
93 } 101 }
94 102
95 while ( obj ) { 103 while ( obj ) {
96 OContact con = parseVObject( obj ); 104 OContact con = parseVObject( obj );
97 /* 105 /*
98 * if uid is 0 assign a new one 106 * if uid is 0 assign a new one
99 * this at least happens on 107 * this at least happens on
100 * Nokia6210 108 * Nokia6210
101 */ 109 */
102 if ( con.uid() == 0 ){ 110 if ( con.uid() == 0 ){
103 con.setUid( 1 ); 111 con.setUid( 1 );
104 qWarning("assigned new uid %d",con.uid() ); 112 qWarning("assigned new uid %d",con.uid() );
105 } 113 }
106 114
107 m_map.insert( con.uid(), con ); 115 m_map.insert( con.uid(), con );
108 116
109 VObject *t = obj; 117 VObject *t = obj;
110 obj = nextVObjectInList(obj); 118 obj = nextVObjectInList(obj);
111 cleanVObject( t ); 119 cleanVObject( t );
112 } 120 }
113 121
114 return true; 122 return true;
115 123
116} 124}
117bool OContactAccessBackend_VCard::reload() 125bool OContactAccessBackend_VCard::reload()
118{ 126{
119 return load(); 127 return load();
120} 128}
121bool OContactAccessBackend_VCard::save() 129bool OContactAccessBackend_VCard::save()
122{ 130{
123 if (!m_dirty ) 131 if (!m_dirty )
124 return true; 132 return true;
125 133
126 QFileDirect file( m_file ); 134 QFileDirect file( m_file );
127 if (!file.open(IO_WriteOnly ) ) 135 if (!file.open(IO_WriteOnly ) )
128 return false; 136 return false;
129 137
130 VObject *obj; 138 VObject *obj;
131 obj = newVObject( VCCalProp ); 139 obj = newVObject( VCCalProp );
132 addPropValue( obj, VCVersionProp, "1.0" ); 140 addPropValue( obj, VCVersionProp, "1.0" );
133 141
134 VObject *vo; 142 VObject *vo;
135 for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ 143 for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){
136 vo = createVObject( *it ); 144 vo = createVObject( *it );
137 writeVObject( file.directHandle() , vo ); 145 writeVObject( file.directHandle() , vo );
138 cleanVObject( vo ); 146 cleanVObject( vo );
139 } 147 }
140 cleanStrTbl(); 148 cleanStrTbl();
141 149
142 m_dirty = false; 150 m_dirty = false;
143 return true; 151 return true;
144 152
145 153
146} 154}
147void OContactAccessBackend_VCard::clear () 155void OContactAccessBackend_VCard::clear ()
148{ 156{
149 m_map.clear(); 157 m_map.clear();
150 m_dirty = true; // ??? sure ? (se) 158 m_dirty = true; // ??? sure ? (se)
151} 159}
152 160
153bool OContactAccessBackend_VCard::add ( const OContact& newcontact ) 161bool OContactAccessBackend_VCard::add ( const OContact& newcontact )
154{ 162{
155 m_map.insert( newcontact.uid(), newcontact ); 163 m_map.insert( newcontact.uid(), newcontact );
156 m_dirty = true; 164 m_dirty = true;
157 return true; 165 return true;
158} 166}
159 167
160bool OContactAccessBackend_VCard::remove ( int uid ) 168bool OContactAccessBackend_VCard::remove ( int uid )
161{ 169{
162 m_map.remove( uid ); 170 m_map.remove( uid );
163 m_dirty = true; 171 m_dirty = true;
164 return true; 172 return true;
165} 173}
166 174
167bool OContactAccessBackend_VCard::replace ( const OContact &contact ) 175bool OContactAccessBackend_VCard::replace ( const OContact &contact )
168{ 176{
169 m_map.replace( contact.uid(), contact ); 177 m_map.replace( contact.uid(), contact );
170 m_dirty = true; 178 m_dirty = true;
171 return true; 179 return true;
172} 180}
173 181
174OContact OContactAccessBackend_VCard::find ( int uid ) const 182OContact OContactAccessBackend_VCard::find ( int uid ) const
175{ 183{
176 return m_map[uid]; 184 return m_map[uid];
177} 185}
178 186
179QArray<int> OContactAccessBackend_VCard::allRecords() const 187QArray<int> OContactAccessBackend_VCard::allRecords() const
180{ 188{
181 QArray<int> ar( m_map.count() ); 189 QArray<int> ar( m_map.count() );
182 QMap<int, OContact>::ConstIterator it; 190 QMap<int, OContact>::ConstIterator it;
183 int i = 0; 191 int i = 0;
184 for ( it = m_map.begin(); it != m_map.end(); ++it ) { 192 for ( it = m_map.begin(); it != m_map.end(); ++it ) {
185 ar[i] = it.key(); 193 ar[i] = it.key();
186 i++; 194 i++;
187 } 195 }
188 return ar; 196 return ar;
189} 197}
190 198
191// Not implemented 199// Not implemented
192QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int ) 200QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& )
193{ 201{
194 QArray<int> ar(0); 202 QArray<int> ar(0);
195 return ar; 203 return ar;
196} 204}
197 205
198// Not implemented 206// Not implemented
199QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const 207QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const
200{ 208{
201 QArray<int> ar(0); 209 QArray<int> ar(0);
202 return ar; 210 return ar;
203} 211}
204 212
205const uint OContactAccessBackend_VCard::querySettings() 213const uint OContactAccessBackend_VCard::querySettings()
206{ 214{
207 return 0; // No search possible 215 return 0; // No search possible
208} 216}
209 217
210bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const 218bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const
211{ 219{
212 return false; // No search possible, therefore all settings invalid ;) 220 return false; // No search possible, therefore all settings invalid ;)
213} 221}
214 222
215bool OContactAccessBackend_VCard::wasChangedExternally() 223bool OContactAccessBackend_VCard::wasChangedExternally()
216{ 224{
217 return false; // Don't expect concurrent access 225 return false; // Don't expect concurrent access
218} 226}
219 227
220// Not implemented 228// Not implemented
221QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int ) 229QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int )
222{ 230{
223 QArray<int> ar(0); 231 QArray<int> ar(0);
224 return ar; 232 return ar;
225} 233}
226 234
227// *** Private stuff *** 235// *** Private stuff ***
228 236
229 237
230OContact OContactAccessBackend_VCard::parseVObject( VObject *obj ) 238OContact OContactAccessBackend_VCard::parseVObject( VObject *obj )
231{ 239{
232 OContact c; 240 OContact c;
233 241
234 VObjectIterator it; 242 VObjectIterator it;
235 initPropIterator( &it, obj ); 243 initPropIterator( &it, obj );
236 while( moreIteration( &it ) ) { 244 while( moreIteration( &it ) ) {
237 VObject *o = nextVObject( &it ); 245 VObject *o = nextVObject( &it );
238 QCString name = vObjectName( o ); 246 QCString name = vObjectName( o );
239 QCString value = vObjectStringZValue( o ); 247 QCString value = vObjectStringZValue( o );
240 if ( name == VCNameProp ) { 248 if ( name == VCNameProp ) {
241 VObjectIterator nit; 249 VObjectIterator nit;
242 initPropIterator( &nit, o ); 250 initPropIterator( &nit, o );
243 while( moreIteration( &nit ) ) { 251 while( moreIteration( &nit ) ) {
244 VObject *o = nextVObject( &nit ); 252 VObject *o = nextVObject( &nit );
245 QCString name = vObjectTypeInfo( o ); 253 QCString name = vObjectTypeInfo( o );
246 QString value = vObjectStringZValue( o ); 254 QString value = vObjectStringZValue( o );
247 if ( name == VCNamePrefixesProp ) 255 if ( name == VCNamePrefixesProp )
248 c.setTitle( value ); 256 c.setTitle( value );
249 else if ( name == VCNameSuffixesProp ) 257 else if ( name == VCNameSuffixesProp )
250 c.setSuffix( value ); 258 c.setSuffix( value );
251 else if ( name == VCFamilyNameProp ) 259 else if ( name == VCFamilyNameProp )
252 c.setLastName( value ); 260 c.setLastName( value );
253 else if ( name == VCGivenNameProp ) 261 else if ( name == VCGivenNameProp )
254 c.setFirstName( value ); 262 c.setFirstName( value );
255 else if ( name == VCAdditionalNamesProp ) 263 else if ( name == VCAdditionalNamesProp )
256 c.setMiddleName( value ); 264 c.setMiddleName( value );
257 } 265 }
258 } 266 }
259 else if ( name == VCAdrProp ) { 267 else if ( name == VCAdrProp ) {
260 bool work = TRUE; // default address is work address 268 bool work = TRUE; // default address is work address
261 QString street; 269 QString street;
262 QString city; 270 QString city;
263 QString region; 271 QString region;
264 QString postal; 272 QString postal;
265 QString country; 273 QString country;
266 274
267 VObjectIterator nit; 275 VObjectIterator nit;
268 initPropIterator( &nit, o ); 276 initPropIterator( &nit, o );
269 while( moreIteration( &nit ) ) { 277 while( moreIteration( &nit ) ) {
270 VObject *o = nextVObject( &nit ); 278 VObject *o = nextVObject( &nit );
271 QCString name = vObjectName( o ); 279 QCString name = vObjectName( o );
272 QString value = vObjectStringZValue( o ); 280 QString value = vObjectStringZValue( o );
273 if ( name == VCHomeProp ) 281 if ( name == VCHomeProp )
274 work = FALSE; 282 work = FALSE;
275 else if ( name == VCWorkProp ) 283 else if ( name == VCWorkProp )
276 work = TRUE; 284 work = TRUE;
277 else if ( name == VCStreetAddressProp ) 285 else if ( name == VCStreetAddressProp )
278 street = value; 286 street = value;
279 else if ( name == VCCityProp ) 287 else if ( name == VCCityProp )
280 city = value; 288 city = value;
281 else if ( name == VCRegionProp ) 289 else if ( name == VCRegionProp )
282 region = value; 290 region = value;
283 else if ( name == VCPostalCodeProp ) 291 else if ( name == VCPostalCodeProp )
284 postal = value; 292 postal = value;
285 else if ( name == VCCountryNameProp ) 293 else if ( name == VCCountryNameProp )
286 country = value; 294 country = value;
287 } 295 }
288 if ( work ) { 296 if ( work ) {
289 c.setBusinessStreet( street ); 297 c.setBusinessStreet( street );
290 c.setBusinessCity( city ); 298 c.setBusinessCity( city );
291 c.setBusinessCountry( country ); 299 c.setBusinessCountry( country );
292 c.setBusinessZip( postal ); 300 c.setBusinessZip( postal );
293 c.setBusinessState( region ); 301 c.setBusinessState( region );
294 } else { 302 } else {
295 c.setHomeStreet( street ); 303 c.setHomeStreet( street );
296 c.setHomeCity( city ); 304 c.setHomeCity( city );
297 c.setHomeCountry( country ); 305 c.setHomeCountry( country );
298 c.setHomeZip( postal ); 306 c.setHomeZip( postal );
299 c.setHomeState( region ); 307 c.setHomeState( region );
300 } 308 }
301 } 309 }
302 else if ( name == VCTelephoneProp ) { 310 else if ( name == VCTelephoneProp ) {
303 enum { 311 enum {
304 HOME = 0x01, 312 HOME = 0x01,
305 WORK = 0x02, 313 WORK = 0x02,
306 VOICE = 0x04, 314 VOICE = 0x04,
307 CELL = 0x08, 315 CELL = 0x08,
308 FAX = 0x10, 316 FAX = 0x10,
309 PAGER = 0x20, 317 PAGER = 0x20,
310 UNKNOWN = 0x80 318 UNKNOWN = 0x80
311 }; 319 };
312 int type = 0; 320 int type = 0;
313 321
314 VObjectIterator nit; 322 VObjectIterator nit;
315 initPropIterator( &nit, o ); 323 initPropIterator( &nit, o );
316 while( moreIteration( &nit ) ) { 324 while( moreIteration( &nit ) ) {
317 VObject *o = nextVObject( &nit ); 325 VObject *o = nextVObject( &nit );
318 QCString name = vObjectTypeInfo( o ); 326 QCString name = vObjectTypeInfo( o );
319 if ( name == VCHomeProp ) 327 if ( name == VCHomeProp )
320 type |= HOME; 328 type |= HOME;
321 else if ( name == VCWorkProp ) 329 else if ( name == VCWorkProp )
322 type |= WORK; 330 type |= WORK;
323 else if ( name == VCVoiceProp ) 331 else if ( name == VCVoiceProp )
324 type |= VOICE; 332 type |= VOICE;
325 else if ( name == VCCellularProp ) 333 else if ( name == VCCellularProp )
326 type |= CELL; 334 type |= CELL;
327 else if ( name == VCFaxProp ) 335 else if ( name == VCFaxProp )
328 type |= FAX; 336 type |= FAX;
329 else if ( name == VCPagerProp ) 337 else if ( name == VCPagerProp )
330 type |= PAGER; 338 type |= PAGER;
331 else if ( name == VCPreferredProp ) 339 else if ( name == VCPreferredProp )
332 ; 340 ;
333 else 341 else
334 type |= UNKNOWN; 342 type |= UNKNOWN;
335 } 343 }
336 if ( (type & UNKNOWN) != UNKNOWN ) { 344 if ( (type & UNKNOWN) != UNKNOWN ) {
337 if ( ( type & (HOME|WORK) ) == 0 ) // default 345 if ( ( type & (HOME|WORK) ) == 0 ) // default
338 type |= HOME; 346 type |= HOME;
339 if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default 347 if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default
340 type |= VOICE; 348 type |= VOICE;
341 349
342 qWarning("value %s %d", value.data(), type ); 350 qWarning("value %s %d", value.data(), type );
343 if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) ) 351 if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) )
344 c.setHomePhone( value ); 352 c.setHomePhone( value );
345 if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) 353 if ( ( type & (FAX|HOME) ) == (FAX|HOME) )
346 c.setHomeFax( value ); 354 c.setHomeFax( value );
347 if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) 355 if ( ( type & (CELL|HOME) ) == (CELL|HOME) )
348 c.setHomeMobile( value ); 356 c.setHomeMobile( value );
349 if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) ) 357 if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) )
350 c.setBusinessPhone( value ); 358 c.setBusinessPhone( value );
351 if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) 359 if ( ( type & (FAX|WORK) ) == (FAX|WORK) )
352 c.setBusinessFax( value ); 360 c.setBusinessFax( value );
353 if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) 361 if ( ( type & (CELL|WORK) ) == (CELL|WORK) )
354 c.setBusinessMobile( value ); 362 c.setBusinessMobile( value );
355 if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) 363 if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) )
356 c.setBusinessPager( value ); 364 c.setBusinessPager( value );
357 } 365 }
358 } 366 }
359 else if ( name == VCEmailAddressProp ) { 367 else if ( name == VCEmailAddressProp ) {
360 QString email = vObjectStringZValue( o ); 368 QString email = vObjectStringZValue( o );
361 bool valid = TRUE; 369 bool valid = TRUE;
362 VObjectIterator nit; 370 VObjectIterator nit;
363 initPropIterator( &nit, o ); 371 initPropIterator( &nit, o );
364 while( moreIteration( &nit ) ) { 372 while( moreIteration( &nit ) ) {
365 VObject *o = nextVObject( &nit ); 373 VObject *o = nextVObject( &nit );
366 QCString name = vObjectTypeInfo( o ); 374 QCString name = vObjectTypeInfo( o );
367 if ( name != VCInternetProp && name != VCHomeProp && 375 if ( name != VCInternetProp && name != VCHomeProp &&
368 name != VCWorkProp && 376 name != VCWorkProp &&
369 name != VCPreferredProp ) 377 name != VCPreferredProp )
370 // ### preffered should map to default email 378 // ### preffered should map to default email
371 valid = FALSE; 379 valid = FALSE;
372 } 380 }
373 if ( valid ) { 381 if ( valid ) {
374 c.insertEmail( email ); 382 c.insertEmail( email );
375 } 383 }
376 } 384 }
377 else if ( name == VCURLProp ) { 385 else if ( name == VCURLProp ) {
378 VObjectIterator nit; 386 VObjectIterator nit;
379 initPropIterator( &nit, o ); 387 initPropIterator( &nit, o );
380 while( moreIteration( &nit ) ) { 388 while( moreIteration( &nit ) ) {
381 VObject *o = nextVObject( &nit ); 389 VObject *o = nextVObject( &nit );
382 QCString name = vObjectTypeInfo( o ); 390 QCString name = vObjectTypeInfo( o );
383 if ( name == VCHomeProp ) 391 if ( name == VCHomeProp )
384 c.setHomeWebpage( value ); 392 c.setHomeWebpage( value );
385 else if ( name == VCWorkProp ) 393 else if ( name == VCWorkProp )
386 c.setBusinessWebpage( value ); 394 c.setBusinessWebpage( value );
387 } 395 }
388 } 396 }
389 else if ( name == VCOrgProp ) { 397 else if ( name == VCOrgProp ) {
390 VObjectIterator nit; 398 VObjectIterator nit;
391 initPropIterator( &nit, o ); 399 initPropIterator( &nit, o );
392 while( moreIteration( &nit ) ) { 400 while( moreIteration( &nit ) ) {
393 VObject *o = nextVObject( &nit ); 401 VObject *o = nextVObject( &nit );
394 QCString name = vObjectName( o ); 402 QCString name = vObjectName( o );
395 QString value = vObjectStringZValue( o ); 403 QString value = vObjectStringZValue( o );
396 if ( name == VCOrgNameProp ) 404 if ( name == VCOrgNameProp )
397 c.setCompany( value ); 405 c.setCompany( value );
398 else if ( name == VCOrgUnitProp ) 406 else if ( name == VCOrgUnitProp )
399 c.setDepartment( value ); 407 c.setDepartment( value );
400 else if ( name == VCOrgUnit2Prop ) 408 else if ( name == VCOrgUnit2Prop )
401 c.setOffice( value ); 409 c.setOffice( value );
402 } 410 }
403 } 411 }
404 else if ( name == VCTitleProp ) { 412 else if ( name == VCTitleProp ) {
405 c.setJobTitle( value ); 413 c.setJobTitle( value );
406 } 414 }
407 else if ( name == "X-Qtopia-Profession" ) { 415 else if ( name == "X-Qtopia-Profession" ) {
408 c.setProfession( value ); 416 c.setProfession( value );
409 } 417 }
410 else if ( name == "X-Qtopia-Manager" ) { 418 else if ( name == "X-Qtopia-Manager" ) {
411 c.setManager( value ); 419 c.setManager( value );
412 } 420 }
413 else if ( name == "X-Qtopia-Assistant" ) { 421 else if ( name == "X-Qtopia-Assistant" ) {
414 c.setAssistant( value ); 422 c.setAssistant( value );
415 } 423 }
416 else if ( name == "X-Qtopia-Spouse" ) { 424 else if ( name == "X-Qtopia-Spouse" ) {
417 c.setSpouse( value ); 425 c.setSpouse( value );
418 } 426 }
419 else if ( name == "X-Qtopia-Gender" ) { 427 else if ( name == "X-Qtopia-Gender" ) {
420 c.setGender( value ); 428 c.setGender( value );
421 } 429 }
422 else if ( name == "X-Qtopia-Anniversary" ) { 430 else if ( name == "X-Qtopia-Anniversary" ) {
423 c.setAnniversary( convVCardDateToDate( value ) ); 431 c.setAnniversary( convVCardDateToDate( value ) );
424 } 432 }
425 else if ( name == "X-Qtopia-Nickname" ) { 433 else if ( name == "X-Qtopia-Nickname" ) {
426 c.setNickname( value ); 434 c.setNickname( value );
427 } 435 }
428 else if ( name == "X-Qtopia-Children" ) { 436 else if ( name == "X-Qtopia-Children" ) {
429 c.setChildren( value ); 437 c.setChildren( value );
430 } 438 }
431 else if ( name == VCBirthDateProp ) { 439 else if ( name == VCBirthDateProp ) {
432 // Reading Birthdate regarding RFC 2425 (5.8.4) 440 // Reading Birthdate regarding RFC 2425 (5.8.4)
433 c.setBirthday( convVCardDateToDate( value ) ); 441 c.setBirthday( convVCardDateToDate( value ) );
434 442
435 } 443 }
436 444
437#if 0 445#if 0
438 else { 446 else {
439 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); 447 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
440 VObjectIterator nit; 448 VObjectIterator nit;
441 initPropIterator( &nit, o ); 449 initPropIterator( &nit, o );
442 while( moreIteration( &nit ) ) { 450 while( moreIteration( &nit ) ) {
443 VObject *o = nextVObject( &nit ); 451 VObject *o = nextVObject( &nit );
444 QCString name = vObjectName( o ); 452 QCString name = vObjectName( o );
445 QString value = vObjectStringZValue( o ); 453 QString value = vObjectStringZValue( o );
446 printf(" subprop: %s = %s\n", name.data(), value.latin1() ); 454 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
447 } 455 }
448 } 456 }
449#endif 457#endif
450 } 458 }
451 c.setFileAs(); 459 c.setFileAs();
452 return c; 460 return c;
453} 461}
454 462
455 463
456VObject* OContactAccessBackend_VCard::createVObject( const OContact &c ) 464VObject* OContactAccessBackend_VCard::createVObject( const OContact &c )
457{ 465{
458 VObject *vcard = newVObject( VCCardProp ); 466 VObject *vcard = newVObject( VCCardProp );
459 safeAddPropValue( vcard, VCVersionProp, "2.1" ); 467 safeAddPropValue( vcard, VCVersionProp, "2.1" );
460 safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); 468 safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) );
461 safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); 469 safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) );
462 470
463 // full name 471 // full name
464 safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); 472 safeAddPropValue( vcard, VCFullNameProp, c.fullName() );
465 473
466 // name properties 474 // name properties
467 VObject *name = safeAddProp( vcard, VCNameProp ); 475 VObject *name = safeAddProp( vcard, VCNameProp );
468 safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); 476 safeAddPropValue( name, VCFamilyNameProp, c.lastName() );
469 safeAddPropValue( name, VCGivenNameProp, c.firstName() ); 477 safeAddPropValue( name, VCGivenNameProp, c.firstName() );
470 safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); 478 safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() );
471 safeAddPropValue( name, VCNamePrefixesProp, c.title() ); 479 safeAddPropValue( name, VCNamePrefixesProp, c.title() );
472 safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); 480 safeAddPropValue( name, VCNameSuffixesProp, c.suffix() );
473 481
474 // home properties 482 // home properties
475 VObject *home_adr= safeAddProp( vcard, VCAdrProp ); 483 VObject *home_adr= safeAddProp( vcard, VCAdrProp );
476 safeAddProp( home_adr, VCHomeProp ); 484 safeAddProp( home_adr, VCHomeProp );
477 safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); 485 safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() );
478 safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); 486 safeAddPropValue( home_adr, VCCityProp, c.homeCity() );
479 safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); 487 safeAddPropValue( home_adr, VCRegionProp, c.homeState() );
480 safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); 488 safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() );
481 safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); 489 safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() );
482 490
483 VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); 491 VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() );
484 safeAddProp( home_phone, VCHomeProp ); 492 safeAddProp( home_phone, VCHomeProp );
485 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); 493 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() );
486 safeAddProp( home_phone, VCHomeProp ); 494 safeAddProp( home_phone, VCHomeProp );
487 safeAddProp( home_phone, VCCellularProp ); 495 safeAddProp( home_phone, VCCellularProp );
488 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); 496 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() );
489 safeAddProp( home_phone, VCHomeProp ); 497 safeAddProp( home_phone, VCHomeProp );
490 safeAddProp( home_phone, VCFaxProp ); 498 safeAddProp( home_phone, VCFaxProp );
491 499
492 VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); 500 VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() );
493 safeAddProp( url, VCHomeProp ); 501 safeAddProp( url, VCHomeProp );
494 502
495 // work properties 503 // work properties
496 VObject *work_adr= safeAddProp( vcard, VCAdrProp ); 504 VObject *work_adr= safeAddProp( vcard, VCAdrProp );
497 safeAddProp( work_adr, VCWorkProp ); 505 safeAddProp( work_adr, VCWorkProp );
498 safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); 506 safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() );
499 safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); 507 safeAddPropValue( work_adr, VCCityProp, c.businessCity() );
500 safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); 508 safeAddPropValue( work_adr, VCRegionProp, c.businessState() );
501 safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); 509 safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() );
502 safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); 510 safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() );
503 511
504 VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); 512 VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() );
505 safeAddProp( work_phone, VCWorkProp ); 513 safeAddProp( work_phone, VCWorkProp );
506 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); 514 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() );
507 safeAddProp( work_phone, VCWorkProp ); 515 safeAddProp( work_phone, VCWorkProp );
508 safeAddProp( work_phone, VCCellularProp ); 516 safeAddProp( work_phone, VCCellularProp );
509 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); 517 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() );
510 safeAddProp( work_phone, VCWorkProp ); 518 safeAddProp( work_phone, VCWorkProp );
511 safeAddProp( work_phone, VCFaxProp ); 519 safeAddProp( work_phone, VCFaxProp );
512 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); 520 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() );
513 safeAddProp( work_phone, VCWorkProp ); 521 safeAddProp( work_phone, VCWorkProp );
514 safeAddProp( work_phone, VCPagerProp ); 522 safeAddProp( work_phone, VCPagerProp );
515 523
516 url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); 524 url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() );
517 safeAddProp( url, VCWorkProp ); 525 safeAddProp( url, VCWorkProp );
518 526
519 VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); 527 VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() );
520 safeAddProp( title, VCWorkProp ); 528 safeAddProp( title, VCWorkProp );
521 529
522 530
523 QStringList emails = c.emailList(); 531 QStringList emails = c.emailList();
524 emails.prepend( c.defaultEmail() ); 532 emails.prepend( c.defaultEmail() );
525 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { 533 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) {
526 VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); 534 VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it );
527 safeAddProp( email, VCInternetProp ); 535 safeAddProp( email, VCInternetProp );
528 } 536 }
529 537
530 safeAddPropValue( vcard, VCNoteProp, c.notes() ); 538 safeAddPropValue( vcard, VCNoteProp, c.notes() );
531 539
532 // Exporting Birthday regarding RFC 2425 (5.8.4) 540 // Exporting Birthday regarding RFC 2425 (5.8.4)
533 if ( c.birthday().isValid() ){ 541 if ( c.birthday().isValid() ){
534 qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() ); 542 qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() );
535 safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) ); 543 safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) );
536 } 544 }
537 545
538 if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { 546 if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) {
539 VObject *org = safeAddProp( vcard, VCOrgProp ); 547 VObject *org = safeAddProp( vcard, VCOrgProp );
540 safeAddPropValue( org, VCOrgNameProp, c.company() ); 548 safeAddPropValue( org, VCOrgNameProp, c.company() );
541 safeAddPropValue( org, VCOrgUnitProp, c.department() ); 549 safeAddPropValue( org, VCOrgUnitProp, c.department() );
542 safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); 550 safeAddPropValue( org, VCOrgUnit2Prop, c.office() );
543 } 551 }
544 552
545 // some values we have to export as custom fields 553 // some values we have to export as custom fields
546 safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); 554 safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() );
547 safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); 555 safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() );
548 safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); 556 safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() );
549 557
550 safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); 558 safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() );
551 safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); 559 safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() );
552 if ( c.anniversary().isValid() ){ 560 if ( c.anniversary().isValid() ){
553 qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() ); 561 qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() );
554 safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) ); 562 safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) );
555 } 563 }
556 safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); 564 safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() );
557 safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); 565 safeAddPropValue( vcard, "X-Qtopia-Children", c.children() );
558 566
559 return vcard; 567 return vcard;
560} 568}
561 569
562QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const 570QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const
563{ 571{
564 QString str_rfc2425 = QString("%1-%2-%3") 572 QString str_rfc2425 = QString("%1-%2-%3")
565 .arg( d.year() ) 573 .arg( d.year() )
566 .arg( d.month(), 2 ) 574 .arg( d.month(), 2 )
567 .arg( d.day(), 2 ); 575 .arg( d.day(), 2 );
568 // Now replace spaces with "0"... 576 // Now replace spaces with "0"...
569 int pos = 0; 577 int pos = 0;
570 while ( ( pos = str_rfc2425.find (' ') ) > 0 ) 578 while ( ( pos = str_rfc2425.find (' ') ) > 0 )
571 str_rfc2425.replace( pos, 1, "0" ); 579 str_rfc2425.replace( pos, 1, "0" );
572 580
573 return str_rfc2425; 581 return str_rfc2425;
574} 582}
575 583
576QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr ) 584QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr )
577{ 585{
578 int monthPos = datestr.find('-'); 586 int monthPos = datestr.find('-');
579 int dayPos = datestr.find('-', monthPos+1 ); 587 int dayPos = datestr.find('-', monthPos+1 );
580 int sep_ignore = 1; 588 int sep_ignore = 1;
581 if ( monthPos == -1 || dayPos == -1 ) { 589 if ( monthPos == -1 || dayPos == -1 ) {
582 qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); 590 qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos );
583 // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD ) 591 // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD )
584 if ( datestr.length() == 8 ){ 592 if ( datestr.length() == 8 ){
585 monthPos = 4; 593 monthPos = 4;
586 dayPos = 6; 594 dayPos = 6;
587 sep_ignore = 0; 595 sep_ignore = 0;
588 qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); 596 qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos );
589 } else { 597 } else {
590 return QDate(); 598 return QDate();
591 } 599 }
592 } 600 }
593 int y = datestr.left( monthPos ).toInt(); 601 int y = datestr.left( monthPos ).toInt();
594 int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt(); 602 int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt();
595 int d = datestr.mid( dayPos + sep_ignore ).toInt(); 603 int d = datestr.mid( dayPos + sep_ignore ).toInt();
596 qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos); 604 qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos);
597 QDate date ( y,m,d ); 605 QDate date ( y,m,d );
598 return date; 606 return date;
599} 607}
600 608
601VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value ) 609VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value )
602{ 610{
603 VObject *ret = 0; 611 VObject *ret = 0;
604 if ( o && !value.isEmpty() ) 612 if ( o && !value.isEmpty() )
605 ret = addPropValue( o, prop, value.latin1() ); 613 ret = addPropValue( o, prop, value.latin1() );
606 return ret; 614 return ret;
607} 615}
608 616
609VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop) 617VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop)
610{ 618{
611 VObject *ret = 0; 619 VObject *ret = 0;
612 if ( o ) 620 if ( o )
613 ret = addProp( o, prop ); 621 ret = addProp( o, prop );
614 return ret; 622 return ret;
615} 623}
diff --git a/libopie/pim/ocontactaccessbackend_vcard.h b/libopie/pim/ocontactaccessbackend_vcard.h
index 236da00..93e2da3 100644
--- a/libopie/pim/ocontactaccessbackend_vcard.h
+++ b/libopie/pim/ocontactaccessbackend_vcard.h
@@ -1,78 +1,86 @@
1/* 1/*
2 * VCard Backend for the OPIE-Contact Database. 2 * VCard Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (C) 2000 Trolltech AS. All rights reserved. 4 * Copyright (C) 2000 Trolltech AS. All rights reserved.
5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
6 * 6 *
7 * ===================================================================== 7 * =====================================================================
8 *This program is free software; you can redistribute it and/or 8 *This program is free software; you can redistribute it and/or
9 *modify it under the terms of the GNU Library General Public 9 *modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version. 11 * version 2 of the License, or (at your option) any later version.
12 * ===================================================================== 12 * =====================================================================
13 * ToDo: 13 * ToDo:
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.5 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
20 * Revision 1.4 2002/12/07 13:26:22 eilers 28 * Revision 1.4 2002/12/07 13:26:22 eilers
21 * Fixing bug in storing anniversary.. 29 * Fixing bug in storing anniversary..
22 * 30 *
23 * Revision 1.3 2002/11/13 14:14:51 eilers 31 * Revision 1.3 2002/11/13 14:14:51 eilers
24 * Added sorted for Contacts.. 32 * Added sorted for Contacts..
25 * 33 *
26 * Revision 1.2 2002/11/10 15:41:53 eilers 34 * Revision 1.2 2002/11/10 15:41:53 eilers
27 * Bugfixes.. 35 * Bugfixes..
28 * 36 *
29 * Revision 1.1 2002/11/09 14:34:52 eilers 37 * Revision 1.1 2002/11/09 14:34:52 eilers
30 * Added VCard Backend. 38 * Added VCard Backend.
31 * 39 *
32 */ 40 */
33#ifndef __OCONTACTACCESSBACKEND_VCARD_H_ 41#ifndef __OCONTACTACCESSBACKEND_VCARD_H_
34#define __OCONTACTACCESSBACKEND_VCARD_H_ 42#define __OCONTACTACCESSBACKEND_VCARD_H_
35 43
36#include <opie/ocontact.h> 44#include <opie/ocontact.h>
37 45
38#include "ocontactaccessbackend.h" 46#include "ocontactaccessbackend.h"
39 47
40class VObject; 48class VObject;
41 49
42class OContactAccessBackend_VCard : public OContactAccessBackend { 50class OContactAccessBackend_VCard : public OContactAccessBackend {
43 public: 51 public:
44 OContactAccessBackend_VCard ( QString appname, QString filename = 0l ); 52 OContactAccessBackend_VCard ( QString appname, QString filename = 0l );
45 53
46 bool load (); 54 bool load ();
47 bool reload(); 55 bool reload();
48 bool save(); 56 bool save();
49 void clear (); 57 void clear ();
50 58
51 bool add ( const OContact& newcontact ); 59 bool add ( const OContact& newcontact );
52 bool remove ( int uid ); 60 bool remove ( int uid );
53 bool replace ( const OContact& contact ); 61 bool replace ( const OContact& contact );
54 62
55 OContact find ( int uid ) const; 63 OContact find ( int uid ) const;
56 QArray<int> allRecords() const; 64 QArray<int> allRecords() const;
57 QArray<int> queryByExample ( const OContact &query, int settings ); 65 QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() );
58 QArray<int> matchRegexp( const QRegExp &r ) const; 66 QArray<int> matchRegexp( const QRegExp &r ) const;
59 67
60 const uint querySettings(); 68 const uint querySettings();
61 bool hasQuerySettings (uint querySettings) const; 69 bool hasQuerySettings (uint querySettings) const;
62 QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); 70 QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat );
63 bool wasChangedExternally(); 71 bool wasChangedExternally();
64 72
65private: 73private:
66 OContact parseVObject( VObject* obj ); 74 OContact parseVObject( VObject* obj );
67 VObject* createVObject( const OContact& c ); 75 VObject* createVObject( const OContact& c );
68 QString convDateToVCardDate( const QDate& c ) const; 76 QString convDateToVCardDate( const QDate& c ) const;
69 QDate convVCardDateToDate( const QString& datestr ); 77 QDate convVCardDateToDate( const QString& datestr );
70 VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); 78 VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value );
71 VObject *safeAddProp( VObject* o, const char* prop); 79 VObject *safeAddProp( VObject* o, const char* prop);
72 80
73 bool m_dirty : 1; 81 bool m_dirty : 1;
74 QString m_file; 82 QString m_file;
75 QMap<int, OContact> m_map; 83 QMap<int, OContact> m_map;
76}; 84};
77 85
78#endif 86#endif
diff --git a/libopie/pim/ocontactaccessbackend_xml.cpp b/libopie/pim/ocontactaccessbackend_xml.cpp
index 2df6757..4abf4d9 100644
--- a/libopie/pim/ocontactaccessbackend_xml.cpp
+++ b/libopie/pim/ocontactaccessbackend_xml.cpp
@@ -1,739 +1,777 @@
1/* 1/*
2 * XML Backend for the OPIE-Contact Database. 2 * XML Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 * 5 *
6 * ===================================================================== 6 * =====================================================================
7 *This program is free software; you can redistribute it and/or 7 *This program is free software; you can redistribute it and/or
8 *modify it under the terms of the GNU Library General Public 8 *modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
11 * ===================================================================== 11 * =====================================================================
12 * ToDo: XML-Backend: Automatic reload if something was changed... 12 * ToDo: XML-Backend: Automatic reload if something was changed...
13 * 13 *
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.2 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
28 * Revision 1.1.2.2 2003/02/11 12:17:28 eilers
29 * Speed optimization. Removed the sequential search loops.
30 *
31 * Revision 1.1.2.1 2003/02/10 15:31:38 eilers
32 * Writing offsets to debug output..
33 *
20 * Revision 1.1 2003/02/09 15:05:01 eilers 34 * Revision 1.1 2003/02/09 15:05:01 eilers
21 * Nothing happened.. Just some cleanup before I will start.. 35 * Nothing happened.. Just some cleanup before I will start..
22 * 36 *
23 * Revision 1.12 2003/01/03 16:58:03 eilers 37 * Revision 1.12 2003/01/03 16:58:03 eilers
24 * Reenable debug output 38 * Reenable debug output
25 * 39 *
26 * Revision 1.11 2003/01/03 12:31:28 eilers 40 * Revision 1.11 2003/01/03 12:31:28 eilers
27 * Bugfix for calculating data diffs.. 41 * Bugfix for calculating data diffs..
28 * 42 *
29 * Revision 1.10 2003/01/02 14:27:12 eilers 43 * Revision 1.10 2003/01/02 14:27:12 eilers
30 * Improved query by example: Search by date is possible.. First step 44 * Improved query by example: Search by date is possible.. First step
31 * for a today plugin for birthdays.. 45 * for a today plugin for birthdays..
32 * 46 *
33 * Revision 1.9 2002/12/08 12:48:57 eilers 47 * Revision 1.9 2002/12/08 12:48:57 eilers
34 * Moved journal-enum from ocontact into i the xml-backend.. 48 * Moved journal-enum from ocontact into i the xml-backend..
35 * 49 *
36 * Revision 1.8 2002/11/14 17:04:24 eilers 50 * Revision 1.8 2002/11/14 17:04:24 eilers
37 * Sorting will now work if fullname is identical on some entries 51 * Sorting will now work if fullname is identical on some entries
38 * 52 *
39 * Revision 1.7 2002/11/13 15:02:46 eilers 53 * Revision 1.7 2002/11/13 15:02:46 eilers
40 * Small Bug in sorted fixed 54 * Small Bug in sorted fixed
41 * 55 *
42 * Revision 1.6 2002/11/13 14:14:51 eilers 56 * Revision 1.6 2002/11/13 14:14:51 eilers
43 * Added sorted for Contacts.. 57 * Added sorted for Contacts..
44 * 58 *
45 * Revision 1.5 2002/11/01 15:10:42 eilers 59 * Revision 1.5 2002/11/01 15:10:42 eilers
46 * Added regExp-search in database for all fields in a contact. 60 * Added regExp-search in database for all fields in a contact.
47 * 61 *
48 * Revision 1.4 2002/10/16 10:52:40 eilers 62 * Revision 1.4 2002/10/16 10:52:40 eilers
49 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 63 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
50 * 64 *
51 * Revision 1.3 2002/10/14 16:21:54 eilers 65 * Revision 1.3 2002/10/14 16:21:54 eilers
52 * Some minor interface updates 66 * Some minor interface updates
53 * 67 *
54 * Revision 1.2 2002/10/07 17:34:24 eilers 68 * Revision 1.2 2002/10/07 17:34:24 eilers
55 * added OBackendFactory for advanced backend access 69 * added OBackendFactory for advanced backend access
56 * 70 *
57 * Revision 1.1 2002/09/27 17:11:44 eilers 71 * Revision 1.1 2002/09/27 17:11:44 eilers
58 * Added API for accessing the Contact-Database ! It is compiling, but 72 * Added API for accessing the Contact-Database ! It is compiling, but
59 * please do not expect that anything is working ! 73 * please do not expect that anything is working !
60 * I will debug that stuff in the next time .. 74 * I will debug that stuff in the next time ..
61 * Please read README_COMPILE for compiling ! 75 * Please read README_COMPILE for compiling !
62 * 76 *
63 * 77 *
64 */ 78 */
65 79
66#include "ocontactaccessbackend_xml.h" 80#include "ocontactaccessbackend_xml.h"
67 81
68#include <qasciidict.h> 82#include <qasciidict.h>
69#include <qdatetime.h> 83#include <qdatetime.h>
70#include <qfile.h> 84#include <qfile.h>
71#include <qfileinfo.h> 85#include <qfileinfo.h>
72#include <qregexp.h> 86#include <qregexp.h>
73#include <qarray.h> 87#include <qarray.h>
74#include <qmap.h> 88#include <qmap.h>
75#include <qdatetime.h> 89#include <qdatetime.h>
76 90
77#include <qpe/global.h> 91#include <qpe/global.h>
78 92
79#include <opie/xmltree.h> 93#include <opie/xmltree.h>
80#include "ocontactaccessbackend.h" 94#include "ocontactaccessbackend.h"
81#include "ocontactaccess.h" 95#include "ocontactaccess.h"
82 96
83#include <stdlib.h> 97#include <stdlib.h>
84#include <errno.h> 98#include <errno.h>
85 99
86using namespace Opie; 100using namespace Opie;
87 101
88 102
89OContactAccessBackend_XML::OContactAccessBackend_XML ( QString appname, QString filename = 0l ): 103OContactAccessBackend_XML::OContactAccessBackend_XML ( QString appname, QString filename = 0l ):
90 m_changed( false ) 104 m_changed( false )
91{ 105{
106 // Just m_contactlist should call delete if an entry
107 // is removed.
108 m_contactList.setAutoDelete( true );
109 m_uidToContact.setAutoDelete( false );
110
92 m_appName = appname; 111 m_appName = appname;
93 112
94 /* Set journalfile name ... */ 113 /* Set journalfile name ... */
95 m_journalName = getenv("HOME"); 114 m_journalName = getenv("HOME");
96 m_journalName +="/.abjournal" + appname; 115 m_journalName +="/.abjournal" + appname;
97 116
98 /* Expecting to access the default filename if nothing else is set */ 117 /* Expecting to access the default filename if nothing else is set */
99 if ( filename.isEmpty() ){ 118 if ( filename.isEmpty() ){
100 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); 119 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
101 } else 120 } else
102 m_fileName = filename; 121 m_fileName = filename;
103 122
104 /* Load Database now */ 123 /* Load Database now */
105 load (); 124 load ();
106} 125}
107 126
108bool OContactAccessBackend_XML::save() 127bool OContactAccessBackend_XML::save()
109{ 128{
110 129
111 if ( !m_changed ) 130 if ( !m_changed )
112 return true; 131 return true;
113 132
114 QString strNewFile = m_fileName + ".new"; 133 QString strNewFile = m_fileName + ".new";
115 QFile f( strNewFile ); 134 QFile f( strNewFile );
116 if ( !f.open( IO_WriteOnly|IO_Raw ) ) 135 if ( !f.open( IO_WriteOnly|IO_Raw ) )
117 return false; 136 return false;
118 137
119 int total_written; 138 int total_written;
139 int idx_offset = 0;
120 QString out; 140 QString out;
141
142 // Write Header
121 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" 143 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
122 " <Groups>\n" 144 " <Groups>\n"
123 " </Groups>\n" 145 " </Groups>\n"
124 " <Contacts>\n"; 146 " <Contacts>\n";
125 //QValueList<Contact>::iterator it; 147 QCString cstr = out.utf8();
126 QValueListConstIterator<OContact> it; 148 f.writeBlock( cstr.data(), cstr.length() );
127 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { 149 idx_offset += cstr.length();
150 out = "";
151
152 // Write all contacts
153 QListIterator<OContact> it( m_contactList );
154 for ( ; it.current(); ++it ) {
155 qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset );
128 out += "<Contact "; 156 out += "<Contact ";
129 (*it).save( out ); 157 (*it)->save( out );
130 out += "/>\n"; 158 out += "/>\n";
131 QCString cstr = out.utf8(); 159 cstr = out.utf8();
132 total_written = f.writeBlock( cstr.data(), cstr.length() ); 160 total_written = f.writeBlock( cstr.data(), cstr.length() );
161 idx_offset += cstr.length();
133 if ( total_written != int(cstr.length()) ) { 162 if ( total_written != int(cstr.length()) ) {
134 f.close(); 163 f.close();
135 QFile::remove( strNewFile ); 164 QFile::remove( strNewFile );
136 return false; 165 return false;
137 } 166 }
138 out = ""; 167 out = "";
139 } 168 }
140 out += " </Contacts>\n</AddressBook>\n"; 169 out += " </Contacts>\n</AddressBook>\n";
141 170
142 QCString cstr = out.utf8(); 171 // Write Footer
172 cstr = out.utf8();
143 total_written = f.writeBlock( cstr.data(), cstr.length() ); 173 total_written = f.writeBlock( cstr.data(), cstr.length() );
144 if ( total_written != int( cstr.length() ) ) { 174 if ( total_written != int( cstr.length() ) ) {
145 f.close(); 175 f.close();
146 QFile::remove( strNewFile ); 176 QFile::remove( strNewFile );
147 return false; 177 return false;
148 } 178 }
149 f.close(); 179 f.close();
150 180
151 // move the file over, I'm just going to use the system call 181 // move the file over, I'm just going to use the system call
152 // because, I don't feel like using QDir. 182 // because, I don't feel like using QDir.
153 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { 183 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
154 qWarning( "problem renaming file %s to %s, errno: %d", 184 qWarning( "problem renaming file %s to %s, errno: %d",
155 strNewFile.latin1(), m_journalName.latin1(), errno ); 185 strNewFile.latin1(), m_journalName.latin1(), errno );
156 // remove the tmp file... 186 // remove the tmp file...
157 QFile::remove( strNewFile ); 187 QFile::remove( strNewFile );
158 } 188 }
159 189
160 /* The journalfile should be removed now... */ 190 /* The journalfile should be removed now... */
161 removeJournal(); 191 removeJournal();
162 192
163 m_changed = false; 193 m_changed = false;
164 return true; 194 return true;
165} 195}
166 196
167bool OContactAccessBackend_XML::load () 197bool OContactAccessBackend_XML::load ()
168{ 198{
169 m_contactList.clear(); 199 m_contactList.clear();
200 m_uidToContact.clear();
170 201
171 /* Load XML-File and journal if it exists */ 202 /* Load XML-File and journal if it exists */
172 if ( !load ( m_fileName, false ) ) 203 if ( !load ( m_fileName, false ) )
173 return false; 204 return false;
174 /* The returncode of the journalfile is ignored due to the 205 /* The returncode of the journalfile is ignored due to the
175 * fact that it does not exist when this class is instantiated ! 206 * fact that it does not exist when this class is instantiated !
176 * But there may such a file exist, if the application crashed. 207 * But there may such a file exist, if the application crashed.
177 * Therefore we try to load it to get the changes before the # 208 * Therefore we try to load it to get the changes before the #
178 * crash happened... 209 * crash happened...
179 */ 210 */
180 load (m_journalName, true); 211 load (m_journalName, true);
181 212
182 return true; 213 return true;
183} 214}
184 215
185void OContactAccessBackend_XML::clear () 216void OContactAccessBackend_XML::clear ()
186{ 217{
187 m_contactList.clear(); 218 m_contactList.clear();
219 m_uidToContact.clear();
220
188 m_changed = false; 221 m_changed = false;
189
190} 222}
191 223
192bool OContactAccessBackend_XML::wasChangedExternally() 224bool OContactAccessBackend_XML::wasChangedExternally()
193{ 225{
194 QFileInfo fi( m_fileName ); 226 QFileInfo fi( m_fileName );
195 227
196 QDateTime lastmod = fi.lastModified (); 228 QDateTime lastmod = fi.lastModified ();
197 229
198 return (lastmod != m_readtime); 230 return (lastmod != m_readtime);
199} 231}
200 232
201QArray<int> OContactAccessBackend_XML::allRecords() const 233QArray<int> OContactAccessBackend_XML::allRecords() const
202{ 234{
203 QArray<int> uid_list( m_contactList.count() ); 235 QArray<int> uid_list( m_contactList.count() );
204 236
205 uint counter = 0; 237 uint counter = 0;
206 QValueListConstIterator<OContact> it; 238 QListIterator<OContact> it( m_contactList );
207 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 239 for( ; it.current(); ++it ){
208 uid_list[counter++] = (*it).uid(); 240 uid_list[counter++] = (*it)->uid();
209 } 241 }
210 242
211 return ( uid_list ); 243 return ( uid_list );
212} 244}
213 245
214OContact OContactAccessBackend_XML::find ( int uid ) const 246OContact OContactAccessBackend_XML::find ( int uid ) const
215{ 247{
216 bool found = false;
217 OContact foundContact; //Create empty contact 248 OContact foundContact; //Create empty contact
218 249
219 QValueListConstIterator<OContact> it; 250 OContact* found = m_uidToContact.find( QString().setNum( uid ) );
220 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 251
221 if ((*it).uid() == uid){
222 found = true;
223 break;
224 }
225 }
226 if ( found ){ 252 if ( found ){
227 foundContact = *it; 253 foundContact = *found;
228 } 254 }
229 255
230 return ( foundContact ); 256 return ( foundContact );
231} 257}
232 258
233QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings ) 259QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings,
260 const QDateTime& d )
234{ 261{
235 262
236 QArray<int> m_currentQuery( m_contactList.count() ); 263 QArray<int> m_currentQuery( m_contactList.count() );
237 QValueListConstIterator<OContact> it; 264 QListIterator<OContact> it( m_contactList );
238 uint arraycounter = 0; 265 uint arraycounter = 0;
239 266
240 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 267 for( ; it.current(); ++it ){
241 /* Search all fields and compare them with query object. Store them into list 268 /* Search all fields and compare them with query object. Store them into list
242 * if all fields matches. 269 * if all fields matches.
243 */ 270 */
244 QDate* queryDate = 0l; 271 QDate* queryDate = 0l;
245 QDate* checkDate = 0l; 272 QDate* checkDate = 0l;
246 bool allcorrect = true; 273 bool allcorrect = true;
247 for ( int i = 0; i < Qtopia::Groups; i++ ) { 274 for ( int i = 0; i < Qtopia::Groups; i++ ) {
248 // Birthday and anniversary are special nonstring fields and should 275 // Birthday and anniversary are special nonstring fields and should
249 // be handled specially 276 // be handled specially
250 switch ( i ){ 277 switch ( i ){
251 case Qtopia::Birthday: 278 case Qtopia::Birthday:
252 queryDate = new QDate( query.birthday() ); 279 queryDate = new QDate( query.birthday() );
253 checkDate = new QDate( (*it).birthday() ); 280 checkDate = new QDate( (*it)->birthday() );
254 case Qtopia::Anniversary: 281 case Qtopia::Anniversary:
255 if ( queryDate == 0l ){ 282 if ( queryDate == 0l ){
256 queryDate = new QDate( query.anniversary() ); 283 queryDate = new QDate( query.anniversary() );
257 checkDate = new QDate( (*it).anniversary() ); 284 checkDate = new QDate( (*it)->anniversary() );
258 } 285 }
259 286
260 if ( queryDate->isValid() ){ 287 if ( queryDate->isValid() ){
261 if( checkDate->isValid() ){ 288 if( checkDate->isValid() ){
262 if ( settings & OContactAccess::DateYear ){ 289 if ( settings & OContactAccess::DateYear ){
263 if ( queryDate->year() != checkDate->year() ) 290 if ( queryDate->year() != checkDate->year() )
264 allcorrect = false; 291 allcorrect = false;
265 } 292 }
266 if ( settings & OContactAccess::DateMonth ){ 293 if ( settings & OContactAccess::DateMonth ){
267 if ( queryDate->month() != checkDate->month() ) 294 if ( queryDate->month() != checkDate->month() )
268 allcorrect = false; 295 allcorrect = false;
269 } 296 }
270 if ( settings & OContactAccess::DateDay ){ 297 if ( settings & OContactAccess::DateDay ){
271 if ( queryDate->day() != checkDate->day() ) 298 if ( queryDate->day() != checkDate->day() )
272 allcorrect = false; 299 allcorrect = false;
273 } 300 }
274 if ( settings & OContactAccess::DateDiff ) { 301 if ( settings & OContactAccess::DateDiff ) {
275 QDate current = QDate::currentDate(); 302 QDate current;
303 // If we get an additional date, we
304 // will take this date instead of
305 // the current one..
306 if ( !d.date().isValid() )
307 current = QDate::currentDate();
308 else
309 current = d.date();
310
276 // We have to equalize the year, otherwise 311 // We have to equalize the year, otherwise
277 // the search will fail.. 312 // the search will fail..
278 checkDate->setYMD( current.year(), 313 checkDate->setYMD( current.year(),
279 checkDate->month(), 314 checkDate->month(),
280 checkDate->day() ); 315 checkDate->day() );
281 if ( *checkDate < current ) 316 if ( *checkDate < current )
282 checkDate->setYMD( current.year()+1, 317 checkDate->setYMD( current.year()+1,
283 checkDate->month(), 318 checkDate->month(),
284 checkDate->day() ); 319 checkDate->day() );
320
321 // Check whether the birthday/anniversary date is between
322 // the current/given date and the maximum date
323 // ( maximum time range ) !
285 qWarning("Checking if %s is between %s and %s ! ", 324 qWarning("Checking if %s is between %s and %s ! ",
286 checkDate->toString().latin1(), 325 checkDate->toString().latin1(),
287 current.toString().latin1(), 326 current.toString().latin1(),
288 queryDate->toString().latin1() ); 327 queryDate->toString().latin1() );
289 if ( current.daysTo( *queryDate ) > 0 ){ 328 if ( current.daysTo( *queryDate ) > 0 ){
290 if ( !( ( *checkDate >= current ) && 329 if ( !( ( *checkDate >= current ) &&
291 ( *checkDate <= *queryDate ) ) ){ 330 ( *checkDate <= *queryDate ) ) ){
292 allcorrect = false; 331 allcorrect = false;
293 qWarning (" Nope!.."); 332 qWarning (" Nope!..");
294 } 333 }
295 } 334 }
296 } 335 }
297 } else{ 336 } else{
298 // checkDate is invalid. Therfore this entry is always rejected 337 // checkDate is invalid. Therefore this entry is always rejected
299 allcorrect = false; 338 allcorrect = false;
300 } 339 }
301 } 340 }
302 341
303 delete queryDate; 342 delete queryDate;
304 queryDate = 0l; 343 queryDate = 0l;
305 delete checkDate; 344 delete checkDate;
306 checkDate = 0l; 345 checkDate = 0l;
307 break; 346 break;
308 default: 347 default:
309 /* Just compare fields which are not empty in the query object */ 348 /* Just compare fields which are not empty in the query object */
310 if ( !query.field(i).isEmpty() ){ 349 if ( !query.field(i).isEmpty() ){
311 switch ( settings & ~( OContactAccess::IgnoreCase 350 switch ( settings & ~( OContactAccess::IgnoreCase
312 | OContactAccess::DateDiff 351 | OContactAccess::DateDiff
313 | OContactAccess::DateYear 352 | OContactAccess::DateYear
314 | OContactAccess::DateMonth 353 | OContactAccess::DateMonth
315 | OContactAccess::DateDay 354 | OContactAccess::DateDay
316 | OContactAccess::MatchOne 355 | OContactAccess::MatchOne
317 ) ){ 356 ) ){
318 357
319 case OContactAccess::RegExp:{ 358 case OContactAccess::RegExp:{
320 QRegExp expr ( query.field(i), 359 QRegExp expr ( query.field(i),
321 !(settings & OContactAccess::IgnoreCase), 360 !(settings & OContactAccess::IgnoreCase),
322 false ); 361 false );
323 if ( expr.find ( (*it).field(i), 0 ) == -1 ) 362 if ( expr.find ( (*it)->field(i), 0 ) == -1 )
324 allcorrect = false; 363 allcorrect = false;
325 } 364 }
326 break; 365 break;
327 case OContactAccess::WildCards:{ 366 case OContactAccess::WildCards:{
328 QRegExp expr ( query.field(i), 367 QRegExp expr ( query.field(i),
329 !(settings & OContactAccess::IgnoreCase), 368 !(settings & OContactAccess::IgnoreCase),
330 true ); 369 true );
331 if ( expr.find ( (*it).field(i), 0 ) == -1 ) 370 if ( expr.find ( (*it)->field(i), 0 ) == -1 )
332 allcorrect = false; 371 allcorrect = false;
333 } 372 }
334 break; 373 break;
335 case OContactAccess::ExactMatch:{ 374 case OContactAccess::ExactMatch:{
336 if (settings & OContactAccess::IgnoreCase){ 375 if (settings & OContactAccess::IgnoreCase){
337 if ( query.field(i).upper() != 376 if ( query.field(i).upper() !=
338 (*it).field(i).upper() ) 377 (*it)->field(i).upper() )
339 allcorrect = false; 378 allcorrect = false;
340 }else{ 379 }else{
341 if ( query.field(i) != (*it).field(i) ) 380 if ( query.field(i) != (*it)->field(i) )
342 allcorrect = false; 381 allcorrect = false;
343 } 382 }
344 } 383 }
345 break; 384 break;
346 } 385 }
347 } 386 }
348 } 387 }
349 } 388 }
350 if ( allcorrect ){ 389 if ( allcorrect ){
351 m_currentQuery[arraycounter++] = (*it).uid(); 390 m_currentQuery[arraycounter++] = (*it)->uid();
352 } 391 }
353 } 392 }
354 393
355 // Shrink to fit.. 394 // Shrink to fit..
356 m_currentQuery.resize(arraycounter); 395 m_currentQuery.resize(arraycounter);
357 396
358 return m_currentQuery; 397 return m_currentQuery;
359} 398}
360 399
361QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const 400QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const
362{ 401{
363 QArray<int> m_currentQuery( m_contactList.count() ); 402 QArray<int> m_currentQuery( m_contactList.count() );
364 QValueListConstIterator<OContact> it; 403 QListIterator<OContact> it( m_contactList );
365 uint arraycounter = 0; 404 uint arraycounter = 0;
366 405
367 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 406 for( ; it.current(); ++it ){
368 if ( (*it).match( r ) ){ 407 if ( (*it)->match( r ) ){
369 m_currentQuery[arraycounter++] = (*it).uid(); 408 m_currentQuery[arraycounter++] = (*it)->uid();
370 } 409 }
371 410
372 } 411 }
373 // Shrink to fit.. 412 // Shrink to fit..
374 m_currentQuery.resize(arraycounter); 413 m_currentQuery.resize(arraycounter);
375 414
376 return m_currentQuery; 415 return m_currentQuery;
377} 416}
378 417
379const uint OContactAccessBackend_XML::querySettings() 418const uint OContactAccessBackend_XML::querySettings()
380{ 419{
381 return ( OContactAccess::WildCards 420 return ( OContactAccess::WildCards
382 | OContactAccess::IgnoreCase 421 | OContactAccess::IgnoreCase
383 | OContactAccess::RegExp 422 | OContactAccess::RegExp
384 | OContactAccess::ExactMatch 423 | OContactAccess::ExactMatch
385 | OContactAccess::DateDiff 424 | OContactAccess::DateDiff
386 | OContactAccess::DateYear 425 | OContactAccess::DateYear
387 | OContactAccess::DateMonth 426 | OContactAccess::DateMonth
388 | OContactAccess::DateDay 427 | OContactAccess::DateDay
389 ); 428 );
390} 429}
391 430
392bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const 431bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const
393{ 432{
394 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay 433 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
395 * may be added with any of the other settings. IgnoreCase should never used alone. 434 * may be added with any of the other settings. IgnoreCase should never used alone.
396 * Wildcards, RegExp, ExactMatch should never used at the same time... 435 * Wildcards, RegExp, ExactMatch should never used at the same time...
397 */ 436 */
398 437
399 if ( querySettings == OContactAccess::IgnoreCase ) 438 if ( querySettings == OContactAccess::IgnoreCase )
400 return false; 439 return false;
401 440
402 switch ( querySettings & ~( OContactAccess::IgnoreCase 441 switch ( querySettings & ~( OContactAccess::IgnoreCase
403 | OContactAccess::DateDiff 442 | OContactAccess::DateDiff
404 | OContactAccess::DateYear 443 | OContactAccess::DateYear
405 | OContactAccess::DateMonth 444 | OContactAccess::DateMonth
406 | OContactAccess::DateDay 445 | OContactAccess::DateDay
407 ) 446 )
408 ){ 447 ){
409 case OContactAccess::RegExp: 448 case OContactAccess::RegExp:
410 return ( true ); 449 return ( true );
411 case OContactAccess::WildCards: 450 case OContactAccess::WildCards:
412 return ( true ); 451 return ( true );
413 case OContactAccess::ExactMatch: 452 case OContactAccess::ExactMatch:
414 return ( true ); 453 return ( true );
415 default: 454 default:
416 return ( false ); 455 return ( false );
417 } 456 }
418} 457}
419 458
420// Currently only asc implemented.. 459// Currently only asc implemented..
421QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) 460QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int )
422{ 461{
423 QMap<QString, int> nameToUid; 462 QMap<QString, int> nameToUid;
424 QStringList names; 463 QStringList names;
425 QArray<int> m_currentQuery( m_contactList.count() ); 464 QArray<int> m_currentQuery( m_contactList.count() );
426 465
427 // First fill map and StringList with all Names 466 // First fill map and StringList with all Names
428 // Afterwards sort namelist and use map to fill array to return.. 467 // Afterwards sort namelist and use map to fill array to return..
429 QValueListConstIterator<OContact> it; 468 QListIterator<OContact> it( m_contactList );
430 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 469 for( ; it.current(); ++it ){
431 names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); 470 names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) );
432 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); 471 nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() );
433 } 472 }
434 names.sort(); 473 names.sort();
435 474
436 int i = 0; 475 int i = 0;
437 if ( asc ){ 476 if ( asc ){
438 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) 477 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
439 m_currentQuery[i++] = nameToUid[ (*it) ]; 478 m_currentQuery[i++] = nameToUid[ (*it) ];
440 }else{ 479 }else{
441 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) 480 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
442 m_currentQuery[i++] = nameToUid[ (*it) ]; 481 m_currentQuery[i++] = nameToUid[ (*it) ];
443 } 482 }
444 483
445 return m_currentQuery; 484 return m_currentQuery;
446 485
447} 486}
448 487
449bool OContactAccessBackend_XML::add ( const OContact &newcontact ) 488bool OContactAccessBackend_XML::add ( const OContact &newcontact )
450{ 489{
451 //qWarning("odefaultbackend: ACTION::ADD"); 490 //qWarning("odefaultbackend: ACTION::ADD");
452 updateJournal (newcontact, ACTION_ADD); 491 updateJournal (newcontact, ACTION_ADD);
453 addContact_p( newcontact ); 492 addContact_p( newcontact );
454 493
455 m_changed = true; 494 m_changed = true;
456 495
457 return true; 496 return true;
458} 497}
459 498
460bool OContactAccessBackend_XML::replace ( const OContact &contact ) 499bool OContactAccessBackend_XML::replace ( const OContact &contact )
461{ 500{
462 m_changed = true; 501 m_changed = true;
463 502
464 bool found = false; 503 OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) );
465 504
466 QValueListIterator<OContact> it; 505 if ( found ) {
467 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 506 OContact* newCont = new OContact( contact );
468 if ( (*it).uid() == contact.uid() ){ 507
469 found = true; 508 updateJournal ( *newCont, ACTION_REPLACE);
470 break; 509 m_contactList.removeRef ( found );
471 } 510 m_contactList.append ( newCont );
472 } 511 m_uidToContact.remove( QString().setNum( contact.uid() ) );
473 if (found) { 512 m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont );
474 updateJournal (contact, ACTION_REPLACE); 513
475 m_contactList.remove (it); 514 qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid());
476 m_contactList.append (contact); 515
477 return true; 516 return true;
478 } else 517 } else
479 return false; 518 return false;
480} 519}
481 520
482bool OContactAccessBackend_XML::remove ( int uid ) 521bool OContactAccessBackend_XML::remove ( int uid )
483{ 522{
484 m_changed = true; 523 m_changed = true;
485 524
486 bool found = false; 525 OContact* found = m_uidToContact.find ( QString().setNum( uid ) );
487 QValueListIterator<OContact> it; 526
488 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 527 if ( found ) {
489 if ((*it).uid() == uid){ 528 updateJournal ( *found, ACTION_REMOVE);
490 found = true; 529 m_contactList.removeRef ( found );
491 break; 530 m_uidToContact.remove( QString().setNum( uid ) );
492 } 531
493 }
494 if (found) {
495 updateJournal ( *it, ACTION_REMOVE);
496 m_contactList.remove (it);
497 return true; 532 return true;
498 } else 533 } else
499 return false; 534 return false;
500} 535}
501 536
502bool OContactAccessBackend_XML::reload(){ 537bool OContactAccessBackend_XML::reload(){
503 /* Reload is the same as load in this implementation */ 538 /* Reload is the same as load in this implementation */
504 return ( load() ); 539 return ( load() );
505} 540}
506 541
507void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) 542void OContactAccessBackend_XML::addContact_p( const OContact &newcontact )
508{ 543{
509 m_contactList.append (newcontact); 544 OContact* contRef = new OContact( newcontact );
545
546 m_contactList.append ( contRef );
547 m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef );
510} 548}
511 549
512/* This function loads the xml-database and the journalfile */ 550/* This function loads the xml-database and the journalfile */
513bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) 551bool OContactAccessBackend_XML::load( const QString filename, bool isJournal )
514{ 552{
515 553
516 /* We use the time of the last read to check if the file was 554 /* We use the time of the last read to check if the file was
517 * changed externally. 555 * changed externally.
518 */ 556 */
519 if ( !isJournal ){ 557 if ( !isJournal ){
520 QFileInfo fi( filename ); 558 QFileInfo fi( filename );
521 m_readtime = fi.lastModified (); 559 m_readtime = fi.lastModified ();
522 } 560 }
523 561
524 const int JOURNALACTION = Qtopia::Notes + 1; 562 const int JOURNALACTION = Qtopia::Notes + 1;
525 const int JOURNALROW = JOURNALACTION + 1; 563 const int JOURNALROW = JOURNALACTION + 1;
526 564
527 bool foundAction = false; 565 bool foundAction = false;
528 journal_action action = ACTION_ADD; 566 journal_action action = ACTION_ADD;
529 int journalKey = 0; 567 int journalKey = 0;
530 QMap<int, QString> contactMap; 568 QMap<int, QString> contactMap;
531 QMap<QString, QString> customMap; 569 QMap<QString, QString> customMap;
532 QMap<QString, QString>::Iterator customIt; 570 QMap<QString, QString>::Iterator customIt;
533 QAsciiDict<int> dict( 47 ); 571 QAsciiDict<int> dict( 47 );
534 572
535 dict.setAutoDelete( TRUE ); 573 dict.setAutoDelete( TRUE );
536 dict.insert( "Uid", new int(Qtopia::AddressUid) ); 574 dict.insert( "Uid", new int(Qtopia::AddressUid) );
537 dict.insert( "Title", new int(Qtopia::Title) ); 575 dict.insert( "Title", new int(Qtopia::Title) );
538 dict.insert( "FirstName", new int(Qtopia::FirstName) ); 576 dict.insert( "FirstName", new int(Qtopia::FirstName) );
539 dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); 577 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
540 dict.insert( "LastName", new int(Qtopia::LastName) ); 578 dict.insert( "LastName", new int(Qtopia::LastName) );
541 dict.insert( "Suffix", new int(Qtopia::Suffix) ); 579 dict.insert( "Suffix", new int(Qtopia::Suffix) );
542 dict.insert( "FileAs", new int(Qtopia::FileAs) ); 580 dict.insert( "FileAs", new int(Qtopia::FileAs) );
543 dict.insert( "Categories", new int(Qtopia::AddressCategory) ); 581 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
544 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); 582 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
545 dict.insert( "Emails", new int(Qtopia::Emails) ); 583 dict.insert( "Emails", new int(Qtopia::Emails) );
546 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); 584 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
547 dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); 585 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
548 dict.insert( "HomeState", new int(Qtopia::HomeState) ); 586 dict.insert( "HomeState", new int(Qtopia::HomeState) );
549 dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); 587 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
550 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); 588 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
551 dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); 589 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
552 dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); 590 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
553 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); 591 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
554 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); 592 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
555 dict.insert( "Company", new int(Qtopia::Company) ); 593 dict.insert( "Company", new int(Qtopia::Company) );
556 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); 594 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
557 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); 595 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
558 dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); 596 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
559 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); 597 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
560 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); 598 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
561 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); 599 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
562 dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); 600 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
563 dict.insert( "Department", new int(Qtopia::Department) ); 601 dict.insert( "Department", new int(Qtopia::Department) );
564 dict.insert( "Office", new int(Qtopia::Office) ); 602 dict.insert( "Office", new int(Qtopia::Office) );
565 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); 603 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
566 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); 604 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
567 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); 605 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
568 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); 606 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
569 dict.insert( "Profession", new int(Qtopia::Profession) ); 607 dict.insert( "Profession", new int(Qtopia::Profession) );
570 dict.insert( "Assistant", new int(Qtopia::Assistant) ); 608 dict.insert( "Assistant", new int(Qtopia::Assistant) );
571 dict.insert( "Manager", new int(Qtopia::Manager) ); 609 dict.insert( "Manager", new int(Qtopia::Manager) );
572 dict.insert( "Spouse", new int(Qtopia::Spouse) ); 610 dict.insert( "Spouse", new int(Qtopia::Spouse) );
573 dict.insert( "Children", new int(Qtopia::Children) ); 611 dict.insert( "Children", new int(Qtopia::Children) );
574 dict.insert( "Gender", new int(Qtopia::Gender) ); 612 dict.insert( "Gender", new int(Qtopia::Gender) );
575 dict.insert( "Birthday", new int(Qtopia::Birthday) ); 613 dict.insert( "Birthday", new int(Qtopia::Birthday) );
576 dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); 614 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
577 dict.insert( "Nickname", new int(Qtopia::Nickname) ); 615 dict.insert( "Nickname", new int(Qtopia::Nickname) );
578 dict.insert( "Notes", new int(Qtopia::Notes) ); 616 dict.insert( "Notes", new int(Qtopia::Notes) );
579 dict.insert( "action", new int(JOURNALACTION) ); 617 dict.insert( "action", new int(JOURNALACTION) );
580 dict.insert( "actionrow", new int(JOURNALROW) ); 618 dict.insert( "actionrow", new int(JOURNALROW) );
581 619
582 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); 620 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
583 621
584 XMLElement *root = XMLElement::load( filename ); 622 XMLElement *root = XMLElement::load( filename );
585 if(root != 0l ){ // start parsing 623 if(root != 0l ){ // start parsing
586 /* Parse all XML-Elements and put the data into the 624 /* Parse all XML-Elements and put the data into the
587 * Contact-Class 625 * Contact-Class
588 */ 626 */
589 XMLElement *element = root->firstChild(); 627 XMLElement *element = root->firstChild();
590 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); 628 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
591 element = element->firstChild(); 629 element = element->firstChild();
592 630
593 /* Search Tag "Contacts" which is the parent of all Contacts */ 631 /* Search Tag "Contacts" which is the parent of all Contacts */
594 while( element && !isJournal ){ 632 while( element && !isJournal ){
595 if( element->tagName() != QString::fromLatin1("Contacts") ){ 633 if( element->tagName() != QString::fromLatin1("Contacts") ){
596 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", 634 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
597 // element->tagName().latin1()); 635 // element->tagName().latin1());
598 element = element->nextChild(); 636 element = element->nextChild();
599 } else { 637 } else {
600 element = element->firstChild(); 638 element = element->firstChild();
601 break; 639 break;
602 } 640 }
603 } 641 }
604 /* Parse all Contacts and ignore unknown tags */ 642 /* Parse all Contacts and ignore unknown tags */
605 while( element ){ 643 while( element ){
606 if( element->tagName() != QString::fromLatin1("Contact") ){ 644 if( element->tagName() != QString::fromLatin1("Contact") ){
607 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", 645 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
608 // element->tagName().latin1()); 646 // element->tagName().latin1());
609 element = element->nextChild(); 647 element = element->nextChild();
610 continue; 648 continue;
611 } 649 }
612 /* Found alement with tagname "contact", now parse and store all 650 /* Found alement with tagname "contact", now parse and store all
613 * attributes contained 651 * attributes contained
614 */ 652 */
615 //qWarning("OContactDefBack::load element tagName() : %s", 653 //qWarning("OContactDefBack::load element tagName() : %s",
616 // element->tagName().latin1() ); 654 // element->tagName().latin1() );
617 QString dummy; 655 QString dummy;
618 foundAction = false; 656 foundAction = false;
619 657
620 XMLElement::AttributeMap aMap = element->attributes(); 658 XMLElement::AttributeMap aMap = element->attributes();
621 XMLElement::AttributeMap::Iterator it; 659 XMLElement::AttributeMap::Iterator it;
622 contactMap.clear(); 660 contactMap.clear();
623 customMap.clear(); 661 customMap.clear();
624 for( it = aMap.begin(); it != aMap.end(); ++it ){ 662 for( it = aMap.begin(); it != aMap.end(); ++it ){
625 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); 663 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
626 664
627 int *find = dict[ it.key() ]; 665 int *find = dict[ it.key() ];
628 /* Unknown attributes will be stored as "Custom" elements */ 666 /* Unknown attributes will be stored as "Custom" elements */
629 if ( !find ) { 667 if ( !find ) {
630 qWarning("Attribute %s not known.", it.key().latin1()); 668 qWarning("Attribute %s not known.", it.key().latin1());
631 //contact.setCustomField(it.key(), it.data()); 669 //contact.setCustomField(it.key(), it.data());
632 customMap.insert( it.key(), it.data() ); 670 customMap.insert( it.key(), it.data() );
633 continue; 671 continue;
634 } 672 }
635 673
636 /* Check if special conversion is needed and add attribute 674 /* Check if special conversion is needed and add attribute
637 * into Contact class 675 * into Contact class
638 */ 676 */
639 switch( *find ) { 677 switch( *find ) {
640 /* 678 /*
641 case Qtopia::AddressUid: 679 case Qtopia::AddressUid:
642 contact.setUid( it.data().toInt() ); 680 contact.setUid( it.data().toInt() );
643 break; 681 break;
644 case Qtopia::AddressCategory: 682 case Qtopia::AddressCategory:
645 contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); 683 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
646 break; 684 break;
647 */ 685 */
648 case JOURNALACTION: 686 case JOURNALACTION:
649 action = journal_action(it.data().toInt()); 687 action = journal_action(it.data().toInt());
650 foundAction = true; 688 foundAction = true;
651 qWarning ("ODefBack(journal)::ACTION found: %d", action); 689 qWarning ("ODefBack(journal)::ACTION found: %d", action);
652 break; 690 break;
653 case JOURNALROW: 691 case JOURNALROW:
654 journalKey = it.data().toInt(); 692 journalKey = it.data().toInt();
655 break; 693 break;
656 default: // no conversion needed add them to the map 694 default: // no conversion needed add them to the map
657 contactMap.insert( *find, it.data() ); 695 contactMap.insert( *find, it.data() );
658 break; 696 break;
659 } 697 }
660 } 698 }
661 /* now generate the Contact contact */ 699 /* now generate the Contact contact */
662 OContact contact( contactMap ); 700 OContact contact( contactMap );
663 701
664 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { 702 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
665 contact.setCustomField( customIt.key(), customIt.data() ); 703 contact.setCustomField( customIt.key(), customIt.data() );
666 } 704 }
667 705
668 if (foundAction){ 706 if (foundAction){
669 foundAction = false; 707 foundAction = false;
670 switch ( action ) { 708 switch ( action ) {
671 case ACTION_ADD: 709 case ACTION_ADD:
672 addContact_p (contact); 710 addContact_p (contact);
673 break; 711 break;
674 case ACTION_REMOVE: 712 case ACTION_REMOVE:
675 if ( !remove (contact.uid()) ) 713 if ( !remove (contact.uid()) )
676 qWarning ("ODefBack(journal)::Unable to remove uid: %d", 714 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
677 contact.uid() ); 715 contact.uid() );
678 break; 716 break;
679 case ACTION_REPLACE: 717 case ACTION_REPLACE:
680 if ( !replace ( contact ) ) 718 if ( !replace ( contact ) )
681 qWarning ("ODefBack(journal)::Unable to replace uid: %d", 719 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
682 contact.uid() ); 720 contact.uid() );
683 break; 721 break;
684 default: 722 default:
685 qWarning ("Unknown action: ignored !"); 723 qWarning ("Unknown action: ignored !");
686 break; 724 break;
687 } 725 }
688 }else{ 726 }else{
689 /* Add contact to list */ 727 /* Add contact to list */
690 addContact_p (contact); 728 addContact_p (contact);
691 } 729 }
692 730
693 /* Move to next element */ 731 /* Move to next element */
694 element = element->nextChild(); 732 element = element->nextChild();
695 } 733 }
696 }else { 734 }else {
697 qWarning("ODefBack::could not load"); 735 qWarning("ODefBack::could not load");
698 } 736 }
699 delete root; 737 delete root;
700 qWarning("returning from loading" ); 738 qWarning("returning from loading" );
701 return true; 739 return true;
702} 740}
703 741
704 742
705void OContactAccessBackend_XML::updateJournal( const OContact& cnt, 743void OContactAccessBackend_XML::updateJournal( const OContact& cnt,
706 journal_action action ) 744 journal_action action )
707{ 745{
708 QFile f( m_journalName ); 746 QFile f( m_journalName );
709 bool created = !f.exists(); 747 bool created = !f.exists();
710 if ( !f.open(IO_WriteOnly|IO_Append) ) 748 if ( !f.open(IO_WriteOnly|IO_Append) )
711 return; 749 return;
712 750
713 QString buf; 751 QString buf;
714 QCString str; 752 QCString str;
715 753
716 // if the file was created, we have to set the Tag "<CONTACTS>" to 754 // if the file was created, we have to set the Tag "<CONTACTS>" to
717 // get a XML-File which is readable by our parser. 755 // get a XML-File which is readable by our parser.
718 // This is just a cheat, but better than rewrite the parser. 756 // This is just a cheat, but better than rewrite the parser.
719 if ( created ){ 757 if ( created ){
720 buf = "<Contacts>"; 758 buf = "<Contacts>";
721 QCString cstr = buf.utf8(); 759 QCString cstr = buf.utf8();
722 f.writeBlock( cstr.data(), cstr.length() ); 760 f.writeBlock( cstr.data(), cstr.length() );
723 } 761 }
724 762
725 buf = "<Contact "; 763 buf = "<Contact ";
726 cnt.save( buf ); 764 cnt.save( buf );
727 buf += " action=\"" + QString::number( (int)action ) + "\" "; 765 buf += " action=\"" + QString::number( (int)action ) + "\" ";
728 buf += "/>\n"; 766 buf += "/>\n";
729 QCString cstr = buf.utf8(); 767 QCString cstr = buf.utf8();
730 f.writeBlock( cstr.data(), cstr.length() ); 768 f.writeBlock( cstr.data(), cstr.length() );
731} 769}
732 770
733void OContactAccessBackend_XML::removeJournal() 771void OContactAccessBackend_XML::removeJournal()
734{ 772{
735 QFile f ( m_journalName ); 773 QFile f ( m_journalName );
736 if ( f.exists() ) 774 if ( f.exists() )
737 f.remove(); 775 f.remove();
738} 776}
739 777
diff --git a/libopie/pim/ocontactaccessbackend_xml.h b/libopie/pim/ocontactaccessbackend_xml.h
index 6477705..4d6a7ef 100644
--- a/libopie/pim/ocontactaccessbackend_xml.h
+++ b/libopie/pim/ocontactaccessbackend_xml.h
@@ -1,743 +1,144 @@
1/* 1/*
2 * XML Backend for the OPIE-Contact Database. 2 * XML Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 * 5 *
6 * ===================================================================== 6 * =====================================================================
7 *This program is free software; you can redistribute it and/or 7 *This program is free software; you can redistribute it and/or
8 *modify it under the terms of the GNU Library General Public 8 *modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
11 * ===================================================================== 11 * =====================================================================
12 * ToDo: XML-Backend: Automatic reload if something was changed... 12 * ToDo: XML-Backend: Automatic reload if something was changed...
13 * 13 *
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.13 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
28 * Revision 1.12.2.2 2003/02/11 12:17:28 eilers
29 * Speed optimization. Removed the sequential search loops.
30 *
31 * Revision 1.12.2.1 2003/02/09 15:05:01 eilers
32 * Nothing happened.. Just some cleanup before I will start..
33 *
20 * Revision 1.12 2003/01/03 16:58:03 eilers 34 * Revision 1.12 2003/01/03 16:58:03 eilers
21 * Reenable debug output 35 * Reenable debug output
22 * 36 *
23 * Revision 1.11 2003/01/03 12:31:28 eilers 37 * Revision 1.11 2003/01/03 12:31:28 eilers
24 * Bugfix for calculating data diffs.. 38 * Bugfix for calculating data diffs..
25 * 39 *
26 * Revision 1.10 2003/01/02 14:27:12 eilers 40 * Revision 1.10 2003/01/02 14:27:12 eilers
27 * Improved query by example: Search by date is possible.. First step 41 * Improved query by example: Search by date is possible.. First step
28 * for a today plugin for birthdays.. 42 * for a today plugin for birthdays..
29 * 43 *
30 * Revision 1.9 2002/12/08 12:48:57 eilers 44 * Revision 1.9 2002/12/08 12:48:57 eilers
31 * Moved journal-enum from ocontact into i the xml-backend.. 45 * Moved journal-enum from ocontact into i the xml-backend..
32 * 46 *
33 * Revision 1.8 2002/11/14 17:04:24 eilers 47 * Revision 1.8 2002/11/14 17:04:24 eilers
34 * Sorting will now work if fullname is identical on some entries 48 * Sorting will now work if fullname is identical on some entries
35 * 49 *
36 * Revision 1.7 2002/11/13 15:02:46 eilers 50 * Revision 1.7 2002/11/13 15:02:46 eilers
37 * Small Bug in sorted fixed 51 * Small Bug in sorted fixed
38 * 52 *
39 * Revision 1.6 2002/11/13 14:14:51 eilers 53 * Revision 1.6 2002/11/13 14:14:51 eilers
40 * Added sorted for Contacts.. 54 * Added sorted for Contacts..
41 * 55 *
42 * Revision 1.5 2002/11/01 15:10:42 eilers 56 * Revision 1.5 2002/11/01 15:10:42 eilers
43 * Added regExp-search in database for all fields in a contact. 57 * Added regExp-search in database for all fields in a contact.
44 * 58 *
45 * Revision 1.4 2002/10/16 10:52:40 eilers 59 * Revision 1.4 2002/10/16 10:52:40 eilers
46 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 60 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
47 * 61 *
48 * Revision 1.3 2002/10/14 16:21:54 eilers 62 * Revision 1.3 2002/10/14 16:21:54 eilers
49 * Some minor interface updates 63 * Some minor interface updates
50 * 64 *
51 * Revision 1.2 2002/10/07 17:34:24 eilers 65 * Revision 1.2 2002/10/07 17:34:24 eilers
52 * added OBackendFactory for advanced backend access 66 * added OBackendFactory for advanced backend access
53 * 67 *
54 * Revision 1.1 2002/09/27 17:11:44 eilers 68 * Revision 1.1 2002/09/27 17:11:44 eilers
55 * Added API for accessing the Contact-Database ! It is compiling, but 69 * Added API for accessing the Contact-Database ! It is compiling, but
56 * please do not expect that anything is working ! 70 * please do not expect that anything is working !
57 * I will debug that stuff in the next time .. 71 * I will debug that stuff in the next time ..
58 * Please read README_COMPILE for compiling ! 72 * Please read README_COMPILE for compiling !
59 * 73 *
60 * 74 *
61 */ 75 */
62 76
63#ifndef _OContactAccessBackend_XML_ 77#ifndef _OContactAccessBackend_XML_
64#define _OContactAccessBackend_XML_ 78#define _OContactAccessBackend_XML_
65 79
66#include <qasciidict.h>
67#include <qdatetime.h>
68#include <qfile.h>
69#include <qfileinfo.h>
70#include <qregexp.h>
71#include <qarray.h>
72#include <qmap.h>
73#include <qdatetime.h>
74
75#include <qpe/global.h>
76
77#include <opie/xmltree.h>
78#include "ocontactaccessbackend.h" 80#include "ocontactaccessbackend.h"
79#include "ocontactaccess.h" 81#include "ocontactaccess.h"
80 82
81#include <stdlib.h> 83#include <qlist.h>
82#include <errno.h> 84#include <qdict.h>
83
84using namespace Opie;
85 85
86/* the default xml implementation */ 86/* the default xml implementation */
87class OContactAccessBackend_XML : public OContactAccessBackend { 87class OContactAccessBackend_XML : public OContactAccessBackend {
88 public: 88 public:
89 OContactAccessBackend_XML ( QString appname, QString filename = 0l ): 89 OContactAccessBackend_XML ( QString appname, QString filename = 0l );
90 m_changed( false )
91 {
92 m_appName = appname;
93
94 /* Set journalfile name ... */
95 m_journalName = getenv("HOME");
96 m_journalName +="/.abjournal" + appname;
97
98 /* Expecting to access the default filename if nothing else is set */
99 if ( filename.isEmpty() ){
100 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
101 } else
102 m_fileName = filename;
103
104 /* Load Database now */
105 load ();
106 }
107 90
108 bool save() { 91 bool save();
109
110 if ( !m_changed )
111 return true;
112
113 QString strNewFile = m_fileName + ".new";
114 QFile f( strNewFile );
115 if ( !f.open( IO_WriteOnly|IO_Raw ) )
116 return false;
117
118 int total_written;
119 QString out;
120 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
121 " <Groups>\n"
122 " </Groups>\n"
123 " <Contacts>\n";
124 //QValueList<Contact>::iterator it;
125 QValueListConstIterator<OContact> it;
126 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) {
127 out += "<Contact ";
128 (*it).save( out );
129 out += "/>\n";
130 QCString cstr = out.utf8();
131 total_written = f.writeBlock( cstr.data(), cstr.length() );
132 if ( total_written != int(cstr.length()) ) {
133 f.close();
134 QFile::remove( strNewFile );
135 return false;
136 }
137 out = "";
138 }
139 out += " </Contacts>\n</AddressBook>\n";
140
141 QCString cstr = out.utf8();
142 total_written = f.writeBlock( cstr.data(), cstr.length() );
143 if ( total_written != int( cstr.length() ) ) {
144 f.close();
145 QFile::remove( strNewFile );
146 return false;
147 }
148 f.close();
149
150 // move the file over, I'm just going to use the system call
151 // because, I don't feel like using QDir.
152 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
153 qWarning( "problem renaming file %s to %s, errno: %d",
154 strNewFile.latin1(), m_journalName.latin1(), errno );
155 // remove the tmp file...
156 QFile::remove( strNewFile );
157 }
158
159 /* The journalfile should be removed now... */
160 removeJournal();
161
162 m_changed = false;
163 return true;
164 }
165 92
166 bool load () { 93 bool load ();
167 m_contactList.clear();
168
169 /* Load XML-File and journal if it exists */
170 if ( !load ( m_fileName, false ) )
171 return false;
172 /* The returncode of the journalfile is ignored due to the
173 * fact that it does not exist when this class is instantiated !
174 * But there may such a file exist, if the application crashed.
175 * Therefore we try to load it to get the changes before the #
176 * crash happened...
177 */
178 load (m_journalName, true);
179
180 return true;
181 }
182
183 void clear () {
184 m_contactList.clear();
185 m_changed = false;
186 94
187 } 95 void clear ();
188 96
189 bool wasChangedExternally() 97 bool wasChangedExternally();
190 {
191 QFileInfo fi( m_fileName );
192
193 QDateTime lastmod = fi.lastModified ();
194
195 return (lastmod != m_readtime);
196 }
197 98
198 QArray<int> allRecords() const { 99 QArray<int> allRecords() const;
199 QArray<int> uid_list( m_contactList.count() );
200
201 uint counter = 0;
202 QValueListConstIterator<OContact> it;
203 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
204 uid_list[counter++] = (*it).uid();
205 }
206
207 return ( uid_list );
208 }
209 100
210 OContact find ( int uid ) const 101 OContact find ( int uid ) const;
211 {
212 bool found = false;
213 OContact foundContact; //Create empty contact
214
215 QValueListConstIterator<OContact> it;
216 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
217 if ((*it).uid() == uid){
218 found = true;
219 break;
220 }
221 }
222 if ( found ){
223 foundContact = *it;
224 }
225
226 return ( foundContact );
227 }
228 102
229 QArray<int> queryByExample ( const OContact &query, int settings ){ 103 QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() );
230
231 QArray<int> m_currentQuery( m_contactList.count() );
232 QValueListConstIterator<OContact> it;
233 uint arraycounter = 0;
234
235 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
236 /* Search all fields and compare them with query object. Store them into list
237 * if all fields matches.
238 */
239 QDate* queryDate = 0l;
240 QDate* checkDate = 0l;
241 bool allcorrect = true;
242 for ( int i = 0; i < Qtopia::Groups; i++ ) {
243 // Birthday and anniversary are special nonstring fields and should
244 // be handled specially
245 switch ( i ){
246 case Qtopia::Birthday:
247 queryDate = new QDate( query.birthday() );
248 checkDate = new QDate( (*it).birthday() );
249 case Qtopia::Anniversary:
250 if ( queryDate == 0l ){
251 queryDate = new QDate( query.anniversary() );
252 checkDate = new QDate( (*it).anniversary() );
253 }
254
255 if ( queryDate->isValid() ){
256 if( checkDate->isValid() ){
257 if ( settings & OContactAccess::DateYear ){
258 if ( queryDate->year() != checkDate->year() )
259 allcorrect = false;
260 }
261 if ( settings & OContactAccess::DateMonth ){
262 if ( queryDate->month() != checkDate->month() )
263 allcorrect = false;
264 }
265 if ( settings & OContactAccess::DateDay ){
266 if ( queryDate->day() != checkDate->day() )
267 allcorrect = false;
268 }
269 if ( settings & OContactAccess::DateDiff ) {
270 QDate current = QDate::currentDate();
271 // We have to equalize the year, otherwise
272 // the search will fail..
273 checkDate->setYMD( current.year(),
274 checkDate->month(),
275 checkDate->day() );
276 if ( *checkDate < current )
277 checkDate->setYMD( current.year()+1,
278 checkDate->month(),
279 checkDate->day() );
280 qWarning("Checking if %s is between %s and %s ! ",
281 checkDate->toString().latin1(),
282 current.toString().latin1(),
283 queryDate->toString().latin1() );
284 if ( current.daysTo( *queryDate ) > 0 ){
285 if ( !( ( *checkDate >= current ) &&
286 ( *checkDate <= *queryDate ) ) ){
287 allcorrect = false;
288 qWarning (" Nope!..");
289 }
290 }
291 }
292 } else{
293 // checkDate is invalid. Therfore this entry is always rejected
294 allcorrect = false;
295 }
296 }
297
298 delete queryDate;
299 queryDate = 0l;
300 delete checkDate;
301 checkDate = 0l;
302 break;
303 default:
304 /* Just compare fields which are not empty in the query object */
305 if ( !query.field(i).isEmpty() ){
306 switch ( settings & ~( OContactAccess::IgnoreCase
307 | OContactAccess::DateDiff
308 | OContactAccess::DateYear
309 | OContactAccess::DateMonth
310 | OContactAccess::DateDay
311 | OContactAccess::MatchOne
312 ) ){
313 104
314 case OContactAccess::RegExp:{ 105 QArray<int> matchRegexp( const QRegExp &r ) const;
315 QRegExp expr ( query.field(i),
316 !(settings & OContactAccess::IgnoreCase),
317 false );
318 if ( expr.find ( (*it).field(i), 0 ) == -1 )
319 allcorrect = false;
320 }
321 break;
322 case OContactAccess::WildCards:{
323 QRegExp expr ( query.field(i),
324 !(settings & OContactAccess::IgnoreCase),
325 true );
326 if ( expr.find ( (*it).field(i), 0 ) == -1 )
327 allcorrect = false;
328 }
329 break;
330 case OContactAccess::ExactMatch:{
331 if (settings & OContactAccess::IgnoreCase){
332 if ( query.field(i).upper() !=
333 (*it).field(i).upper() )
334 allcorrect = false;
335 }else{
336 if ( query.field(i) != (*it).field(i) )
337 allcorrect = false;
338 }
339 }
340 break;
341 }
342 }
343 }
344 }
345 if ( allcorrect ){
346 m_currentQuery[arraycounter++] = (*it).uid();
347 }
348 }
349
350 // Shrink to fit..
351 m_currentQuery.resize(arraycounter);
352 106
353 return m_currentQuery; 107 const uint querySettings();
354 }
355
356 QArray<int> matchRegexp( const QRegExp &r ) const{
357 QArray<int> m_currentQuery( m_contactList.count() );
358 QValueListConstIterator<OContact> it;
359 uint arraycounter = 0;
360
361 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
362 if ( (*it).match( r ) ){
363 m_currentQuery[arraycounter++] = (*it).uid();
364 }
365
366 }
367 // Shrink to fit..
368 m_currentQuery.resize(arraycounter);
369
370 return m_currentQuery;
371 }
372
373 const uint querySettings()
374 {
375 return ( OContactAccess::WildCards
376 | OContactAccess::IgnoreCase
377 | OContactAccess::RegExp
378 | OContactAccess::ExactMatch
379 | OContactAccess::DateDiff
380 | OContactAccess::DateYear
381 | OContactAccess::DateMonth
382 | OContactAccess::DateDay
383 );
384 }
385 108
386 bool hasQuerySettings (uint querySettings) const 109 bool hasQuerySettings (uint querySettings) const;
387 {
388 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
389 * may be added with any of the other settings. IgnoreCase should never used alone.
390 * Wildcards, RegExp, ExactMatch should never used at the same time...
391 */
392
393 if ( querySettings == OContactAccess::IgnoreCase )
394 return false;
395
396 switch ( querySettings & ~( OContactAccess::IgnoreCase
397 | OContactAccess::DateDiff
398 | OContactAccess::DateYear
399 | OContactAccess::DateMonth
400 | OContactAccess::DateDay
401 )
402 ){
403 case OContactAccess::RegExp:
404 return ( true );
405 case OContactAccess::WildCards:
406 return ( true );
407 case OContactAccess::ExactMatch:
408 return ( true );
409 default:
410 return ( false );
411 }
412 }
413 110
414 // Currently only asc implemented.. 111 // Currently only asc implemented..
415 QArray<int> sorted( bool asc, int , int , int ) 112 QArray<int> sorted( bool asc, int , int , int );
416 { 113 bool add ( const OContact &newcontact );
417 QMap<QString, int> nameToUid;
418 QStringList names;
419 QArray<int> m_currentQuery( m_contactList.count() );
420
421 // First fill map and StringList with all Names
422 // Afterwards sort namelist and use map to fill array to return..
423 QValueListConstIterator<OContact> it;
424 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
425 names.append( (*it).fileAs() + QString::number( (*it).uid() ) );
426 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() );
427 }
428 names.sort();
429
430 int i = 0;
431 if ( asc ){
432 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
433 m_currentQuery[i++] = nameToUid[ (*it) ];
434 }else{
435 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
436 m_currentQuery[i++] = nameToUid[ (*it) ];
437 }
438
439 return m_currentQuery;
440
441 }
442 bool add ( const OContact &newcontact )
443 {
444 //qWarning("odefaultbackend: ACTION::ADD");
445 updateJournal (newcontact, ACTION_ADD);
446 addContact_p( newcontact );
447
448 m_changed = true;
449
450 return true;
451 }
452
453 bool replace ( const OContact &contact )
454 {
455 m_changed = true;
456
457 bool found = false;
458
459 QValueListIterator<OContact> it;
460 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
461 if ( (*it).uid() == contact.uid() ){
462 found = true;
463 break;
464 }
465 }
466 if (found) {
467 updateJournal (contact, ACTION_REPLACE);
468 m_contactList.remove (it);
469 m_contactList.append (contact);
470 return true;
471 } else
472 return false;
473 }
474 114
475 bool remove ( int uid ) 115 bool replace ( const OContact &contact );
476 {
477 m_changed = true;
478
479 bool found = false;
480 QValueListIterator<OContact> it;
481 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
482 if ((*it).uid() == uid){
483 found = true;
484 break;
485 }
486 }
487 if (found) {
488 updateJournal ( *it, ACTION_REMOVE);
489 m_contactList.remove (it);
490 return true;
491 } else
492 return false;
493 }
494 116
495 bool reload(){ 117 bool remove ( int uid );
496 /* Reload is the same as load in this implementation */ 118 bool reload();
497 return ( load() );
498 }
499 119
500 private: 120 private:
501 121
502 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; 122 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE };
503 123
504 void addContact_p( const OContact &newcontact ){ 124 void addContact_p( const OContact &newcontact );
505 m_contactList.append (newcontact);
506 }
507 125
508 /* This function loads the xml-database and the journalfile */ 126 /* This function loads the xml-database and the journalfile */
509 bool load( const QString filename, bool isJournal ) { 127 bool load( const QString filename, bool isJournal );
510
511 /* We use the time of the last read to check if the file was
512 * changed externally.
513 */
514 if ( !isJournal ){
515 QFileInfo fi( filename );
516 m_readtime = fi.lastModified ();
517 }
518
519 const int JOURNALACTION = Qtopia::Notes + 1;
520 const int JOURNALROW = JOURNALACTION + 1;
521
522 bool foundAction = false;
523 journal_action action = ACTION_ADD;
524 int journalKey = 0;
525 QMap<int, QString> contactMap;
526 QMap<QString, QString> customMap;
527 QMap<QString, QString>::Iterator customIt;
528 QAsciiDict<int> dict( 47 );
529
530 dict.setAutoDelete( TRUE );
531 dict.insert( "Uid", new int(Qtopia::AddressUid) );
532 dict.insert( "Title", new int(Qtopia::Title) );
533 dict.insert( "FirstName", new int(Qtopia::FirstName) );
534 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
535 dict.insert( "LastName", new int(Qtopia::LastName) );
536 dict.insert( "Suffix", new int(Qtopia::Suffix) );
537 dict.insert( "FileAs", new int(Qtopia::FileAs) );
538 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
539 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
540 dict.insert( "Emails", new int(Qtopia::Emails) );
541 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
542 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
543 dict.insert( "HomeState", new int(Qtopia::HomeState) );
544 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
545 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
546 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
547 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
548 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
549 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
550 dict.insert( "Company", new int(Qtopia::Company) );
551 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
552 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
553 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
554 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
555 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
556 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
557 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
558 dict.insert( "Department", new int(Qtopia::Department) );
559 dict.insert( "Office", new int(Qtopia::Office) );
560 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
561 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
562 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
563 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
564 dict.insert( "Profession", new int(Qtopia::Profession) );
565 dict.insert( "Assistant", new int(Qtopia::Assistant) );
566 dict.insert( "Manager", new int(Qtopia::Manager) );
567 dict.insert( "Spouse", new int(Qtopia::Spouse) );
568 dict.insert( "Children", new int(Qtopia::Children) );
569 dict.insert( "Gender", new int(Qtopia::Gender) );
570 dict.insert( "Birthday", new int(Qtopia::Birthday) );
571 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
572 dict.insert( "Nickname", new int(Qtopia::Nickname) );
573 dict.insert( "Notes", new int(Qtopia::Notes) );
574 dict.insert( "action", new int(JOURNALACTION) );
575 dict.insert( "actionrow", new int(JOURNALROW) );
576
577 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
578
579 XMLElement *root = XMLElement::load( filename );
580 if(root != 0l ){ // start parsing
581 /* Parse all XML-Elements and put the data into the
582 * Contact-Class
583 */
584 XMLElement *element = root->firstChild();
585 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
586 element = element->firstChild();
587
588 /* Search Tag "Contacts" which is the parent of all Contacts */
589 while( element && !isJournal ){
590 if( element->tagName() != QString::fromLatin1("Contacts") ){
591 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
592 // element->tagName().latin1());
593 element = element->nextChild();
594 } else {
595 element = element->firstChild();
596 break;
597 }
598 }
599 /* Parse all Contacts and ignore unknown tags */
600 while( element ){
601 if( element->tagName() != QString::fromLatin1("Contact") ){
602 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
603 // element->tagName().latin1());
604 element = element->nextChild();
605 continue;
606 }
607 /* Found alement with tagname "contact", now parse and store all
608 * attributes contained
609 */
610 //qWarning("OContactDefBack::load element tagName() : %s",
611 // element->tagName().latin1() );
612 QString dummy;
613 foundAction = false;
614
615 XMLElement::AttributeMap aMap = element->attributes();
616 XMLElement::AttributeMap::Iterator it;
617 contactMap.clear();
618 customMap.clear();
619 for( it = aMap.begin(); it != aMap.end(); ++it ){
620 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
621
622 int *find = dict[ it.key() ];
623 /* Unknown attributes will be stored as "Custom" elements */
624 if ( !find ) {
625 qWarning("Attribute %s not known.", it.key().latin1());
626 //contact.setCustomField(it.key(), it.data());
627 customMap.insert( it.key(), it.data() );
628 continue;
629 }
630
631 /* Check if special conversion is needed and add attribute
632 * into Contact class
633 */
634 switch( *find ) {
635 /*
636 case Qtopia::AddressUid:
637 contact.setUid( it.data().toInt() );
638 break;
639 case Qtopia::AddressCategory:
640 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
641 break;
642 */
643 case JOURNALACTION:
644 action = journal_action(it.data().toInt());
645 foundAction = true;
646 qWarning ("ODefBack(journal)::ACTION found: %d", action);
647 break;
648 case JOURNALROW:
649 journalKey = it.data().toInt();
650 break;
651 default: // no conversion needed add them to the map
652 contactMap.insert( *find, it.data() );
653 break;
654 }
655 }
656 /* now generate the Contact contact */
657 OContact contact( contactMap );
658
659 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
660 contact.setCustomField( customIt.key(), customIt.data() );
661 }
662
663 if (foundAction){
664 foundAction = false;
665 switch ( action ) {
666 case ACTION_ADD:
667 addContact_p (contact);
668 break;
669 case ACTION_REMOVE:
670 if ( !remove (contact.uid()) )
671 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
672 contact.uid() );
673 break;
674 case ACTION_REPLACE:
675 if ( !replace ( contact ) )
676 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
677 contact.uid() );
678 break;
679 default:
680 qWarning ("Unknown action: ignored !");
681 break;
682 }
683 }else{
684 /* Add contact to list */
685 addContact_p (contact);
686 }
687
688 /* Move to next element */
689 element = element->nextChild();
690 }
691 }else {
692 qWarning("ODefBack::could not load");
693 }
694 delete root;
695 qWarning("returning from loading" );
696 return true;
697 }
698
699 128
700 void updateJournal( const OContact& cnt,
701 journal_action action ) {
702 QFile f( m_journalName );
703 bool created = !f.exists();
704 if ( !f.open(IO_WriteOnly|IO_Append) )
705 return;
706
707 QString buf;
708 QCString str;
709
710 // if the file was created, we have to set the Tag "<CONTACTS>" to
711 // get a XML-File which is readable by our parser.
712 // This is just a cheat, but better than rewrite the parser.
713 if ( created ){
714 buf = "<Contacts>";
715 QCString cstr = buf.utf8();
716 f.writeBlock( cstr.data(), cstr.length() );
717 }
718
719 buf = "<Contact ";
720 cnt.save( buf );
721 buf += " action=\"" + QString::number( (int)action ) + "\" ";
722 buf += "/>\n";
723 QCString cstr = buf.utf8();
724 f.writeBlock( cstr.data(), cstr.length() );
725 }
726 129
727 void removeJournal() 130 void updateJournal( const OContact& cnt, journal_action action );
728 { 131 void removeJournal();
729 QFile f ( m_journalName );
730 if ( f.exists() )
731 f.remove();
732 }
733 132
734 protected: 133 protected:
735 bool m_changed; 134 bool m_changed;
736 QString m_journalName; 135 QString m_journalName;
737 QString m_fileName; 136 QString m_fileName;
738 QString m_appName; 137 QString m_appName;
739 QValueList<OContact> m_contactList; 138 QList<OContact> m_contactList;
740 QDateTime m_readtime; 139 QDateTime m_readtime;
140
141 QDict<OContact> m_uidToContact;
741}; 142};
742 143
743#endif 144#endif
diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp
index 4a6b7b8..11e19d9 100644
--- a/libopie/pim/odatebookaccessbackend_xml.cpp
+++ b/libopie/pim/odatebookaccessbackend_xml.cpp
@@ -1,587 +1,587 @@
1#include <errno.h> 1#include <errno.h>
2#include <fcntl.h> 2#include <fcntl.h>
3 3
4#include <stdio.h> 4#include <stdio.h>
5#include <stdlib.h> 5#include <stdlib.h>
6 6
7#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/mman.h> 8#include <sys/mman.h>
9#include <sys/stat.h> 9#include <sys/stat.h>
10 10
11#include <unistd.h> 11#include <unistd.h>
12 12
13#include <qasciidict.h> 13#include <qasciidict.h>
14#include <qfile.h> 14#include <qfile.h>
15 15
16#include <qtopia/global.h> 16#include <qtopia/global.h>
17#include <qtopia/stringutil.h> 17#include <qtopia/stringutil.h>
18#include <qtopia/timeconversion.h> 18#include <qtopia/timeconversion.h>
19 19
20#include "opimnotifymanager.h" 20#include "opimnotifymanager.h"
21#include "orecur.h" 21#include "orecur.h"
22#include "otimezone.h" 22#include "otimezone.h"
23#include "odatebookaccessbackend_xml.h" 23#include "odatebookaccessbackend_xml.h"
24 24
25namespace { 25namespace {
26 // FROM TT again 26 // FROM TT again
27char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) 27char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
28{ 28{
29 char needleChar; 29 char needleChar;
30 char haystackChar; 30 char haystackChar;
31 if (!needle || !haystack || !hLen || !nLen) 31 if (!needle || !haystack || !hLen || !nLen)
32 return 0; 32 return 0;
33 33
34 const char* hsearch = haystack; 34 const char* hsearch = haystack;
35 35
36 if ((needleChar = *needle++) != 0) { 36 if ((needleChar = *needle++) != 0) {
37 nLen--; //(to make up for needle++) 37 nLen--; //(to make up for needle++)
38 do { 38 do {
39 do { 39 do {
40 if ((haystackChar = *hsearch++) == 0) 40 if ((haystackChar = *hsearch++) == 0)
41 return (0); 41 return (0);
42 if (hsearch >= haystack + hLen) 42 if (hsearch >= haystack + hLen)
43 return (0); 43 return (0);
44 } while (haystackChar != needleChar); 44 } while (haystackChar != needleChar);
45 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); 45 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
46 hsearch--; 46 hsearch--;
47 } 47 }
48 return ((char *)hsearch); 48 return ((char *)hsearch);
49} 49}
50} 50}
51 51
52namespace { 52namespace {
53 time_t start, end, created, rp_end; 53 time_t start, end, created, rp_end;
54 ORecur* rec; 54 ORecur* rec;
55 ORecur* recur() { 55 ORecur* recur() {
56 if (!rec) 56 if (!rec)
57 rec = new ORecur; 57 rec = new ORecur;
58 58
59 return rec; 59 return rec;
60 } 60 }
61 int alarmTime; 61 int alarmTime;
62 int snd; 62 int snd;
63 enum Attribute{ 63 enum Attribute{
64 FDescription = 0, 64 FDescription = 0,
65 FLocation, 65 FLocation,
66 FCategories, 66 FCategories,
67 FUid, 67 FUid,
68 FType, 68 FType,
69 FAlarm, 69 FAlarm,
70 FSound, 70 FSound,
71 FRType, 71 FRType,
72 FRWeekdays, 72 FRWeekdays,
73 FRPosition, 73 FRPosition,
74 FRFreq, 74 FRFreq,
75 FRHasEndDate, 75 FRHasEndDate,
76 FREndDate, 76 FREndDate,
77 FRStart, 77 FRStart,
78 FREnd, 78 FREnd,
79 FNote, 79 FNote,
80 FCreated, 80 FCreated,
81 FTimeZone, 81 FTimeZone,
82 FRecParent, 82 FRecParent,
83 FRecChildren, 83 FRecChildren,
84 FExceptions 84 FExceptions
85 }; 85 };
86 inline void save( const OEvent& ev, QString& buf ) { 86 inline void save( const OEvent& ev, QString& buf ) {
87 qWarning("Saving %d %s", ev.uid(), ev.description().latin1() ); 87 qWarning("Saving %d %s", ev.uid(), ev.description().latin1() );
88 buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; 88 buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\"";
89 if (!ev.location().isEmpty() ) 89 if (!ev.location().isEmpty() )
90 buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; 90 buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\"";
91 91
92 buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; 92 buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\"";
93 buf += " uid=\"" + QString::number( ev.uid() ) + "\""; 93 buf += " uid=\"" + QString::number( ev.uid() ) + "\"";
94 94
95 if (ev.isAllDay() ) 95 if (ev.isAllDay() )
96 buf += " type=\"AllDay\""; 96 buf += " type=\"AllDay\"";
97 97
98 if (ev.hasNotifiers() ) { 98 if (ev.hasNotifiers() ) {
99 OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first 99 OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first
100 int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; 100 int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60;
101 buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; 101 buf += " alarm=\"" + QString::number(minutes) + "\" sound=\"";
102 if ( alarm.sound() == OPimAlarm::Loud ) 102 if ( alarm.sound() == OPimAlarm::Loud )
103 buf += "loud"; 103 buf += "loud";
104 else 104 else
105 buf += "silent"; 105 buf += "silent";
106 buf += "\""; 106 buf += "\"";
107 } 107 }
108 if ( ev.hasRecurrence() ) { 108 if ( ev.hasRecurrence() ) {
109 buf += ev.recurrence().toString(); 109 buf += ev.recurrence().toString();
110 } 110 }
111 111
112 /* 112 /*
113 * fscking timezones :) well, we'll first convert 113 * fscking timezones :) well, we'll first convert
114 * the QDateTime to a QDateTime in UTC time 114 * the QDateTime to a QDateTime in UTC time
115 * and then we'll create a nice time_t 115 * and then we'll create a nice time_t
116 */ 116 */
117 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); 117 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
118 buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; 118 buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\"";
119 buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; 119 buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\"";
120 if (!ev.note().isEmpty() ) { 120 if (!ev.note().isEmpty() ) {
121 buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; 121 buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\"";
122 } 122 }
123 123
124 buf += " timezone=\""; 124 buf += " timezone=\"";
125 if ( ev.timeZone().isEmpty() ) 125 if ( ev.timeZone().isEmpty() )
126 buf += "None"; 126 buf += "None";
127 else 127 else
128 buf += ev.timeZone(); 128 buf += ev.timeZone();
129 buf += "\""; 129 buf += "\"";
130 130
131 if (ev.parent() != 0 ) { 131 if (ev.parent() != 0 ) {
132 buf += " recparent=\""+QString::number(ev.parent() )+"\""; 132 buf += " recparent=\""+QString::number(ev.parent() )+"\"";
133 } 133 }
134 134
135 if (ev.children().count() != 0 ) { 135 if (ev.children().count() != 0 ) {
136 QArray<int> children = ev.children(); 136 QArray<int> children = ev.children();
137 buf += " recchildren=\""; 137 buf += " recchildren=\"";
138 for ( uint i = 0; i < children.count(); i++ ) { 138 for ( uint i = 0; i < children.count(); i++ ) {
139 if ( i != 0 ) buf += " "; 139 if ( i != 0 ) buf += " ";
140 buf += QString::number( children[i] ); 140 buf += QString::number( children[i] );
141 } 141 }
142 buf+= "\""; 142 buf+= "\"";
143 } 143 }
144 144
145 // skip custom writing 145 // skip custom writing
146 } 146 }
147 147
148 inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { 148 inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) {
149 QMap<int, OEvent>::ConstIterator it; 149 QMap<int, OEvent>::ConstIterator it;
150 QString buf; 150 QString buf;
151 QCString str; 151 QCString str;
152 int total_written; 152 int total_written;
153 for ( it = list.begin(); it != list.end(); ++it ) { 153 for ( it = list.begin(); it != list.end(); ++it ) {
154 buf = "<event"; 154 buf = "<event";
155 save( it.data(), buf ); 155 save( it.data(), buf );
156 buf += " />\n"; 156 buf += " />\n";
157 str = buf.utf8(); 157 str = buf.utf8();
158 158
159 total_written = file.writeBlock(str.data(), str.length() ); 159 total_written = file.writeBlock(str.data(), str.length() );
160 if ( total_written != int(str.length() ) ) 160 if ( total_written != int(str.length() ) )
161 return false; 161 return false;
162 } 162 }
163 return true; 163 return true;
164 } 164 }
165} 165}
166 166
167ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , 167ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& ,
168 const QString& fileName ) 168 const QString& fileName )
169 : ODateBookAccessBackend() { 169 : ODateBookAccessBackend() {
170 m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; 170 m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName;
171 m_changed = false; 171 m_changed = false;
172} 172}
173ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { 173ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() {
174} 174}
175bool ODateBookAccessBackend_XML::load() { 175bool ODateBookAccessBackend_XML::load() {
176 return loadFile(); 176 return loadFile();
177} 177}
178bool ODateBookAccessBackend_XML::reload() { 178bool ODateBookAccessBackend_XML::reload() {
179 clear(); 179 clear();
180 return load(); 180 return load();
181} 181}
182bool ODateBookAccessBackend_XML::save() { 182bool ODateBookAccessBackend_XML::save() {
183 if (!m_changed) return true; 183 if (!m_changed) return true;
184 184
185 int total_written; 185 int total_written;
186 QString strFileNew = m_name + ".new"; 186 QString strFileNew = m_name + ".new";
187 187
188 QFile f( strFileNew ); 188 QFile f( strFileNew );
189 if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; 189 if (!f.open( IO_WriteOnly | IO_Raw ) ) return false;
190 190
191 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); 191 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
192 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; 192 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
193 buf += "<events>\n"; 193 buf += "<events>\n";
194 QCString str = buf.utf8(); 194 QCString str = buf.utf8();
195 total_written = f.writeBlock( str.data(), str.length() ); 195 total_written = f.writeBlock( str.data(), str.length() );
196 if ( total_written != int(str.length() ) ) { 196 if ( total_written != int(str.length() ) ) {
197 f.close(); 197 f.close();
198 QFile::remove( strFileNew ); 198 QFile::remove( strFileNew );
199 return false; 199 return false;
200 } 200 }
201 201
202 if (!forAll( m_raw, f ) ) { 202 if (!forAll( m_raw, f ) ) {
203 f.close(); 203 f.close();
204 QFile::remove( strFileNew ); 204 QFile::remove( strFileNew );
205 return false; 205 return false;
206 } 206 }
207 if (!forAll( m_rep, f ) ) { 207 if (!forAll( m_rep, f ) ) {
208 f.close(); 208 f.close();
209 QFile::remove( strFileNew ); 209 QFile::remove( strFileNew );
210 return false; 210 return false;
211 } 211 }
212 212
213 buf = "</events>\n</DATEBOOK>\n"; 213 buf = "</events>\n</DATEBOOK>\n";
214 str = buf.utf8(); 214 str = buf.utf8();
215 total_written = f.writeBlock( str.data(), str.length() ); 215 total_written = f.writeBlock( str.data(), str.length() );
216 if ( total_written != int(str.length() ) ) { 216 if ( total_written != int(str.length() ) ) {
217 f.close(); 217 f.close();
218 QFile::remove( strFileNew ); 218 QFile::remove( strFileNew );
219 return false; 219 return false;
220 } 220 }
221 f.close(); 221 f.close();
222 222
223 if ( ::rename( strFileNew, m_name ) < 0 ) { 223 if ( ::rename( strFileNew, m_name ) < 0 ) {
224 QFile::remove( strFileNew ); 224 QFile::remove( strFileNew );
225 return false; 225 return false;
226 } 226 }
227 227
228 m_changed = false; 228 m_changed = false;
229 return true; 229 return true;
230} 230}
231QArray<int> ODateBookAccessBackend_XML::allRecords()const { 231QArray<int> ODateBookAccessBackend_XML::allRecords()const {
232 QArray<int> ints( m_raw.count()+ m_rep.count() ); 232 QArray<int> ints( m_raw.count()+ m_rep.count() );
233 uint i = 0; 233 uint i = 0;
234 QMap<int, OEvent>::ConstIterator it; 234 QMap<int, OEvent>::ConstIterator it;
235 235
236 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { 236 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
237 ints[i] = it.key(); 237 ints[i] = it.key();
238 i++; 238 i++;
239 } 239 }
240 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { 240 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
241 ints[i] = it.key(); 241 ints[i] = it.key();
242 i++; 242 i++;
243 } 243 }
244 244
245 return ints; 245 return ints;
246} 246}
247QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int ) { 247QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) {
248 return QArray<int>(); 248 return QArray<int>();
249} 249}
250void ODateBookAccessBackend_XML::clear() { 250void ODateBookAccessBackend_XML::clear() {
251 m_raw.clear(); 251 m_raw.clear();
252 m_rep.clear(); 252 m_rep.clear();
253} 253}
254OEvent ODateBookAccessBackend_XML::find( int uid ) const{ 254OEvent ODateBookAccessBackend_XML::find( int uid ) const{
255 if ( m_raw.contains( uid ) ) 255 if ( m_raw.contains( uid ) )
256 return m_raw[uid]; 256 return m_raw[uid];
257 else 257 else
258 return m_rep[uid]; 258 return m_rep[uid];
259} 259}
260bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { 260bool ODateBookAccessBackend_XML::add( const OEvent& ev ) {
261 m_changed = true; 261 m_changed = true;
262 if (ev.hasRecurrence() ) 262 if (ev.hasRecurrence() )
263 m_rep.insert( ev.uid(), ev ); 263 m_rep.insert( ev.uid(), ev );
264 else 264 else
265 m_raw.insert( ev.uid(), ev ); 265 m_raw.insert( ev.uid(), ev );
266 266
267 return true; 267 return true;
268} 268}
269bool ODateBookAccessBackend_XML::remove( int uid ) { 269bool ODateBookAccessBackend_XML::remove( int uid ) {
270 m_changed = true; 270 m_changed = true;
271 m_rep.remove( uid ); 271 m_rep.remove( uid );
272 m_rep.remove( uid ); 272 m_rep.remove( uid );
273 273
274 return true; 274 return true;
275} 275}
276bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) { 276bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) {
277 replace( ev.uid() ); 277 replace( ev.uid() );
278 return add( ev ); 278 return add( ev );
279} 279}
280QArray<int> ODateBookAccessBackend_XML::rawEvents()const { 280QArray<int> ODateBookAccessBackend_XML::rawEvents()const {
281 return allRecords(); 281 return allRecords();
282} 282}
283QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { 283QArray<int> ODateBookAccessBackend_XML::rawRepeats()const {
284 QArray<int> ints( m_rep.count() ); 284 QArray<int> ints( m_rep.count() );
285 uint i = 0; 285 uint i = 0;
286 QMap<int, OEvent>::ConstIterator it; 286 QMap<int, OEvent>::ConstIterator it;
287 287
288 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { 288 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
289 ints[i] = it.key(); 289 ints[i] = it.key();
290 i++; 290 i++;
291 } 291 }
292 292
293 return ints; 293 return ints;
294} 294}
295QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { 295QArray<int> ODateBookAccessBackend_XML::nonRepeats()const {
296 QArray<int> ints( m_raw.count() ); 296 QArray<int> ints( m_raw.count() );
297 uint i = 0; 297 uint i = 0;
298 QMap<int, OEvent>::ConstIterator it; 298 QMap<int, OEvent>::ConstIterator it;
299 299
300 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { 300 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
301 ints[i] = it.key(); 301 ints[i] = it.key();
302 i++; 302 i++;
303 } 303 }
304 304
305 return ints; 305 return ints;
306} 306}
307OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { 307OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() {
308 OEvent::ValueList list; 308 OEvent::ValueList list;
309 QMap<int, OEvent>::ConstIterator it; 309 QMap<int, OEvent>::ConstIterator it;
310 for (it = m_raw.begin(); it != m_raw.end(); ++it ) 310 for (it = m_raw.begin(); it != m_raw.end(); ++it )
311 list.append( it.data() ); 311 list.append( it.data() );
312 312
313 return list; 313 return list;
314} 314}
315OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { 315OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() {
316 OEvent::ValueList list; 316 OEvent::ValueList list;
317 QMap<int, OEvent>::ConstIterator it; 317 QMap<int, OEvent>::ConstIterator it;
318 for (it = m_rep.begin(); it != m_rep.end(); ++it ) 318 for (it = m_rep.begin(); it != m_rep.end(); ++it )
319 list.append( it.data() ); 319 list.append( it.data() );
320 320
321 return list; 321 return list;
322} 322}
323bool ODateBookAccessBackend_XML::loadFile() { 323bool ODateBookAccessBackend_XML::loadFile() {
324 m_changed = false; 324 m_changed = false;
325 325
326 int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); 326 int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY );
327 if ( fd < 0 ) return false; 327 if ( fd < 0 ) return false;
328 328
329 struct stat attribute; 329 struct stat attribute;
330 if ( ::fstat(fd, &attribute ) == -1 ) { 330 if ( ::fstat(fd, &attribute ) == -1 ) {
331 ::close( fd ); 331 ::close( fd );
332 return false; 332 return false;
333 } 333 }
334 void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); 334 void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 );
335 if ( map_addr == ( (caddr_t)-1) ) { 335 if ( map_addr == ( (caddr_t)-1) ) {
336 ::close( fd ); 336 ::close( fd );
337 return false; 337 return false;
338 } 338 }
339 339
340 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); 340 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL );
341 ::close( fd ); 341 ::close( fd );
342 342
343 QAsciiDict<int> dict(FExceptions+1); 343 QAsciiDict<int> dict(FExceptions+1);
344 dict.setAutoDelete( true ); 344 dict.setAutoDelete( true );
345 dict.insert( "description", new int(FDescription) ); 345 dict.insert( "description", new int(FDescription) );
346 dict.insert( "location", new int(FLocation) ); 346 dict.insert( "location", new int(FLocation) );
347 dict.insert( "categories", new int(FCategories) ); 347 dict.insert( "categories", new int(FCategories) );
348 dict.insert( "uid", new int(FUid) ); 348 dict.insert( "uid", new int(FUid) );
349 dict.insert( "type", new int(FType) ); 349 dict.insert( "type", new int(FType) );
350 dict.insert( "alarm", new int(FAlarm) ); 350 dict.insert( "alarm", new int(FAlarm) );
351 dict.insert( "sound", new int(FSound) ); 351 dict.insert( "sound", new int(FSound) );
352 dict.insert( "rtype", new int(FRType) ); 352 dict.insert( "rtype", new int(FRType) );
353 dict.insert( "rweekdays", new int(FRWeekdays) ); 353 dict.insert( "rweekdays", new int(FRWeekdays) );
354 dict.insert( "rposition", new int(FRPosition) ); 354 dict.insert( "rposition", new int(FRPosition) );
355 dict.insert( "rfreq", new int(FRFreq) ); 355 dict.insert( "rfreq", new int(FRFreq) );
356 dict.insert( "rhasenddate", new int(FRHasEndDate) ); 356 dict.insert( "rhasenddate", new int(FRHasEndDate) );
357 dict.insert( "enddt", new int(FREndDate) ); 357 dict.insert( "enddt", new int(FREndDate) );
358 dict.insert( "start", new int(FRStart) ); 358 dict.insert( "start", new int(FRStart) );
359 dict.insert( "end", new int(FREnd) ); 359 dict.insert( "end", new int(FREnd) );
360 dict.insert( "note", new int(FNote) ); 360 dict.insert( "note", new int(FNote) );
361 dict.insert( "created", new int(FCreated) ); 361 dict.insert( "created", new int(FCreated) );
362 dict.insert( "recparent", new int(FRecParent) ); 362 dict.insert( "recparent", new int(FRecParent) );
363 dict.insert( "recchildren", new int(FRecChildren) ); 363 dict.insert( "recchildren", new int(FRecChildren) );
364 dict.insert( "exceptions", new int(FExceptions) ); 364 dict.insert( "exceptions", new int(FExceptions) );
365 dict.insert( "timezone", new int(FTimeZone) ); 365 dict.insert( "timezone", new int(FTimeZone) );
366 366
367 char* dt = (char*)map_addr; 367 char* dt = (char*)map_addr;
368 int len = attribute.st_size; 368 int len = attribute.st_size;
369 int i = 0; 369 int i = 0;
370 char* point; 370 char* point;
371 const char* collectionString = "<event "; 371 const char* collectionString = "<event ";
372 int strLen = ::strlen(collectionString); 372 int strLen = ::strlen(collectionString);
373 int *find; 373 int *find;
374 while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { 374 while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) {
375 i = point -dt; 375 i = point -dt;
376 i+= strLen; 376 i+= strLen;
377 377
378 alarmTime = -1; 378 alarmTime = -1;
379 snd = 0; // silent 379 snd = 0; // silent
380 380
381 OEvent ev; 381 OEvent ev;
382 rec = 0; 382 rec = 0;
383 383
384 while ( TRUE ) { 384 while ( TRUE ) {
385 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) 385 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
386 ++i; 386 ++i;
387 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) 387 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
388 break; 388 break;
389 389
390 390
391 // we have another attribute, read it. 391 // we have another attribute, read it.
392 int j = i; 392 int j = i;
393 while ( j < len && dt[j] != '=' ) 393 while ( j < len && dt[j] != '=' )
394 ++j; 394 ++j;
395 QCString attr( dt+i, j-i+1); 395 QCString attr( dt+i, j-i+1);
396 396
397 i = ++j; // skip = 397 i = ++j; // skip =
398 398
399 // find the start of quotes 399 // find the start of quotes
400 while ( i < len && dt[i] != '"' ) 400 while ( i < len && dt[i] != '"' )
401 ++i; 401 ++i;
402 j = ++i; 402 j = ++i;
403 403
404 bool haveUtf = FALSE; 404 bool haveUtf = FALSE;
405 bool haveEnt = FALSE; 405 bool haveEnt = FALSE;
406 while ( j < len && dt[j] != '"' ) { 406 while ( j < len && dt[j] != '"' ) {
407 if ( ((unsigned char)dt[j]) > 0x7f ) 407 if ( ((unsigned char)dt[j]) > 0x7f )
408 haveUtf = TRUE; 408 haveUtf = TRUE;
409 if ( dt[j] == '&' ) 409 if ( dt[j] == '&' )
410 haveEnt = TRUE; 410 haveEnt = TRUE;
411 ++j; 411 ++j;
412 } 412 }
413 if ( i == j ) { 413 if ( i == j ) {
414 // empty value 414 // empty value
415 i = j + 1; 415 i = j + 1;
416 continue; 416 continue;
417 } 417 }
418 418
419 QCString value( dt+i, j-i+1 ); 419 QCString value( dt+i, j-i+1 );
420 i = j + 1; 420 i = j + 1;
421 421
422 QString str = (haveUtf ? QString::fromUtf8( value ) 422 QString str = (haveUtf ? QString::fromUtf8( value )
423 : QString::fromLatin1( value ) ); 423 : QString::fromLatin1( value ) );
424 if ( haveEnt ) 424 if ( haveEnt )
425 str = Qtopia::plainString( str ); 425 str = Qtopia::plainString( str );
426 426
427 /* 427 /*
428 * add key + value 428 * add key + value
429 */ 429 */
430 find = dict[attr.data()]; 430 find = dict[attr.data()];
431 if (!find) 431 if (!find)
432 ev.setCustomField( attr, value ); 432 ev.setCustomField( attr, value );
433 else { 433 else {
434 setField( ev, *find, value ); 434 setField( ev, *find, value );
435 } 435 }
436 } 436 }
437 /* time to finalize */ 437 /* time to finalize */
438 finalizeRecord( ev ); 438 finalizeRecord( ev );
439 delete rec; 439 delete rec;
440 } 440 }
441 ::munmap(map_addr, attribute.st_size ); 441 ::munmap(map_addr, attribute.st_size );
442 m_changed = false; // changed during add 442 m_changed = false; // changed during add
443 443
444 return true; 444 return true;
445} 445}
446void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { 446void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
447 /* AllDay is alway in UTC */ 447 /* AllDay is alway in UTC */
448 if ( ev.isAllDay() ) { 448 if ( ev.isAllDay() ) {
449 OTimeZone utc = OTimeZone::utc(); 449 OTimeZone utc = OTimeZone::utc();
450 ev.setStartDateTime( utc.fromUTCDateTime( start ) ); 450 ev.setStartDateTime( utc.fromUTCDateTime( start ) );
451 ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); 451 ev.setEndDateTime ( utc.fromUTCDateTime( end ) );
452 ev.setTimeZone( "UTC"); // make sure it is really utc 452 ev.setTimeZone( "UTC"); // make sure it is really utc
453 }else { 453 }else {
454 /* to current date time */ 454 /* to current date time */
455 qWarning(" Start is %d", start ); 455 qWarning(" Start is %d", start );
456 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); 456 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
457 QDateTime date = zone.toDateTime( start ); 457 QDateTime date = zone.toDateTime( start );
458 qWarning(" Start is %s", date.toString().latin1() ); 458 qWarning(" Start is %s", date.toString().latin1() );
459 ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); 459 ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
460 460
461 date = zone.toDateTime( end ); 461 date = zone.toDateTime( end );
462 ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); 462 ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
463 } 463 }
464 if ( rec && rec->doesRecur() ) { 464 if ( rec && rec->doesRecur() ) {
465 OTimeZone utc = OTimeZone::utc(); 465 OTimeZone utc = OTimeZone::utc();
466 ORecur recu( *rec ); // call copy c'tor; 466 ORecur recu( *rec ); // call copy c'tor;
467 recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); 467 recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() );
468 recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); 468 recu.setCreatedDateTime( utc.fromUTCDateTime( created ) );
469 recu.setStart( ev.startDateTime().date() ); 469 recu.setStart( ev.startDateTime().date() );
470 ev.setRecurrence( recu ); 470 ev.setRecurrence( recu );
471 } 471 }
472 472
473 if (alarmTime != -1 ) { 473 if (alarmTime != -1 ) {
474 QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); 474 QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 );
475 OPimAlarm al( snd , dt ); 475 OPimAlarm al( snd , dt );
476 ev.notifiers().add( al ); 476 ev.notifiers().add( al );
477 } 477 }
478 if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) { 478 if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) {
479 qWarning("already contains assign uid"); 479 qWarning("already contains assign uid");
480 ev.setUid( 1 ); 480 ev.setUid( 1 );
481 } 481 }
482 qWarning("addind %d %s", ev.uid(), ev.description().latin1() ); 482 qWarning("addind %d %s", ev.uid(), ev.description().latin1() );
483 if ( ev.hasRecurrence() ) 483 if ( ev.hasRecurrence() )
484 m_rep.insert( ev.uid(), ev ); 484 m_rep.insert( ev.uid(), ev );
485 else 485 else
486 m_raw.insert( ev.uid(), ev ); 486 m_raw.insert( ev.uid(), ev );
487 487
488} 488}
489void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) { 489void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) {
490// qWarning(" setting %s", value.latin1() ); 490// qWarning(" setting %s", value.latin1() );
491 switch( id ) { 491 switch( id ) {
492 case FDescription: 492 case FDescription:
493 e.setDescription( value ); 493 e.setDescription( value );
494 break; 494 break;
495 case FLocation: 495 case FLocation:
496 e.setLocation( value ); 496 e.setLocation( value );
497 break; 497 break;
498 case FCategories: 498 case FCategories:
499 e.setCategories( e.idsFromString( value ) ); 499 e.setCategories( e.idsFromString( value ) );
500 break; 500 break;
501 case FUid: 501 case FUid:
502 e.setUid( value.toInt() ); 502 e.setUid( value.toInt() );
503 break; 503 break;
504 case FType: 504 case FType:
505 if ( value == "AllDay" ) { 505 if ( value == "AllDay" ) {
506 e.setAllDay( true ); 506 e.setAllDay( true );
507 e.setTimeZone( "UTC" ); 507 e.setTimeZone( "UTC" );
508 } 508 }
509 break; 509 break;
510 case FAlarm: 510 case FAlarm:
511 alarmTime = value.toInt(); 511 alarmTime = value.toInt();
512 break; 512 break;
513 case FSound: 513 case FSound:
514 snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent; 514 snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent;
515 break; 515 break;
516 // recurrence stuff 516 // recurrence stuff
517 case FRType: 517 case FRType:
518 if ( value == "Daily" ) 518 if ( value == "Daily" )
519 recur()->setType( ORecur::Daily ); 519 recur()->setType( ORecur::Daily );
520 else if ( value == "Weekly" ) 520 else if ( value == "Weekly" )
521 recur()->setType( ORecur::Weekly); 521 recur()->setType( ORecur::Weekly);
522 else if ( value == "MonthlyDay" ) 522 else if ( value == "MonthlyDay" )
523 recur()->setType( ORecur::MonthlyDay ); 523 recur()->setType( ORecur::MonthlyDay );
524 else if ( value == "MonthlyDate" ) 524 else if ( value == "MonthlyDate" )
525 recur()->setType( ORecur::MonthlyDate ); 525 recur()->setType( ORecur::MonthlyDate );
526 else if ( value == "Yearly" ) 526 else if ( value == "Yearly" )
527 recur()->setType( ORecur::Yearly ); 527 recur()->setType( ORecur::Yearly );
528 else 528 else
529 recur()->setType( ORecur::NoRepeat ); 529 recur()->setType( ORecur::NoRepeat );
530 break; 530 break;
531 case FRWeekdays: 531 case FRWeekdays:
532 recur()->setDays( value.toInt() ); 532 recur()->setDays( value.toInt() );
533 break; 533 break;
534 case FRPosition: 534 case FRPosition:
535 recur()->setPosition( value.toInt() ); 535 recur()->setPosition( value.toInt() );
536 break; 536 break;
537 case FRFreq: 537 case FRFreq:
538 recur()->setFrequency( value.toInt() ); 538 recur()->setFrequency( value.toInt() );
539 break; 539 break;
540 case FRHasEndDate: 540 case FRHasEndDate:
541 recur()->setHasEndDate( value.toInt() ); 541 recur()->setHasEndDate( value.toInt() );
542 break; 542 break;
543 case FREndDate: { 543 case FREndDate: {
544 rp_end = (time_t) value.toLong(); 544 rp_end = (time_t) value.toLong();
545 break; 545 break;
546 } 546 }
547 case FRStart: { 547 case FRStart: {
548 start = (time_t) value.toLong(); 548 start = (time_t) value.toLong();
549 break; 549 break;
550 } 550 }
551 case FREnd: { 551 case FREnd: {
552 end = ( (time_t) value.toLong() ); 552 end = ( (time_t) value.toLong() );
553 break; 553 break;
554 } 554 }
555 case FNote: 555 case FNote:
556 e.setNote( value ); 556 e.setNote( value );
557 break; 557 break;
558 case FCreated: 558 case FCreated:
559 created = value.toInt(); 559 created = value.toInt();
560 break; 560 break;
561 case FRecParent: 561 case FRecParent:
562 e.setParent( value.toInt() ); 562 e.setParent( value.toInt() );
563 break; 563 break;
564 case FRecChildren:{ 564 case FRecChildren:{
565 QStringList list = QStringList::split(' ', value ); 565 QStringList list = QStringList::split(' ', value );
566 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { 566 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
567 e.addChild( (*it).toInt() ); 567 e.addChild( (*it).toInt() );
568 } 568 }
569 } 569 }
570 break; 570 break;
571 case FExceptions:{ 571 case FExceptions:{
572 QStringList list = QStringList::split(' ', value ); 572 QStringList list = QStringList::split(' ', value );
573 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { 573 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
574 QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); 574 QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() );
575 qWarning("adding exception %s", date.toString().latin1() ); 575 qWarning("adding exception %s", date.toString().latin1() );
576 recur()->exceptions().append( date ); 576 recur()->exceptions().append( date );
577 } 577 }
578 } 578 }
579 break; 579 break;
580 case FTimeZone: 580 case FTimeZone:
581 if ( value != "None" ) 581 if ( value != "None" )
582 e.setTimeZone( value ); 582 e.setTimeZone( value );
583 break; 583 break;
584 default: 584 default:
585 break; 585 break;
586 } 586 }
587} 587}
diff --git a/libopie/pim/odatebookaccessbackend_xml.h b/libopie/pim/odatebookaccessbackend_xml.h
index 40f69d8..563c31f 100644
--- a/libopie/pim/odatebookaccessbackend_xml.h
+++ b/libopie/pim/odatebookaccessbackend_xml.h
@@ -1,48 +1,48 @@
1#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H 1#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
2#define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H 2#define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
3 3
4#include <qmap.h> 4#include <qmap.h>
5 5
6#include "odatebookaccessbackend.h" 6#include "odatebookaccessbackend.h"
7 7
8class ODateBookAccessBackend_XML : public ODateBookAccessBackend { 8class ODateBookAccessBackend_XML : public ODateBookAccessBackend {
9public: 9public:
10 ODateBookAccessBackend_XML( const QString& appName, 10 ODateBookAccessBackend_XML( const QString& appName,
11 const QString& fileName = QString::null); 11 const QString& fileName = QString::null);
12 ~ODateBookAccessBackend_XML(); 12 ~ODateBookAccessBackend_XML();
13 13
14 bool load(); 14 bool load();
15 bool reload(); 15 bool reload();
16 bool save(); 16 bool save();
17 17
18 QArray<int> allRecords()const; 18 QArray<int> allRecords()const;
19 QArray<int> queryByExample( const OEvent&, int ); 19 QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() );
20 OEvent find( int uid )const; 20 OEvent find( int uid )const;
21 void clear(); 21 void clear();
22 bool add( const OEvent& ev ); 22 bool add( const OEvent& ev );
23 bool remove( int uid ); 23 bool remove( int uid );
24 bool replace( const OEvent& ev ); 24 bool replace( const OEvent& ev );
25 25
26 QArray<UID> rawEvents()const; 26 QArray<UID> rawEvents()const;
27 QArray<UID> rawRepeats()const; 27 QArray<UID> rawRepeats()const;
28 QArray<UID> nonRepeats()const; 28 QArray<UID> nonRepeats()const;
29 29
30 OEvent::ValueList directNonRepeats(); 30 OEvent::ValueList directNonRepeats();
31 OEvent::ValueList directRawRepeats(); 31 OEvent::ValueList directRawRepeats();
32 32
33private: 33private:
34 bool m_changed :1 ; 34 bool m_changed :1 ;
35 bool loadFile(); 35 bool loadFile();
36 inline void finalizeRecord( OEvent& ev ); 36 inline void finalizeRecord( OEvent& ev );
37 inline void setField( OEvent&, int field, const QString& val ); 37 inline void setField( OEvent&, int field, const QString& val );
38 QString m_name; 38 QString m_name;
39 QMap<int, OEvent> m_raw; 39 QMap<int, OEvent> m_raw;
40 QMap<int, OEvent> m_rep; 40 QMap<int, OEvent> m_rep;
41 41
42 struct Data; 42 struct Data;
43 Data* data; 43 Data* data;
44 class Private; 44 class Private;
45 Private *d; 45 Private *d;
46}; 46};
47 47
48#endif 48#endif
diff --git a/libopie/pim/opimaccessbackend.h b/libopie/pim/opimaccessbackend.h
index e268f4f..01a0c86 100644
--- a/libopie/pim/opimaccessbackend.h
+++ b/libopie/pim/opimaccessbackend.h
@@ -1,153 +1,153 @@
1#ifndef OPIE_PIM_ACCESS_BACKEND 1#ifndef OPIE_PIM_ACCESS_BACKEND
2#define OPIE_PIM_ACCESS_BACKEND 2#define OPIE_PIM_ACCESS_BACKEND
3 3
4#include <qarray.h> 4#include <qarray.h>
5 5
6#include <opie/otemplatebase.h> 6#include <opie/otemplatebase.h>
7#include <opie/opimrecord.h> 7#include <opie/opimrecord.h>
8 8
9 9
10/** 10/**
11 * OPimAccessBackend is the base class 11 * OPimAccessBackend is the base class
12 * for all private backends 12 * for all private backends
13 * it operates on OPimRecord as the base class 13 * it operates on OPimRecord as the base class
14 * and it's responsible for fast manipulating 14 * and it's responsible for fast manipulating
15 * the resource the implementation takes care 15 * the resource the implementation takes care
16 * of 16 * of
17 */ 17 */
18template <class T = OPimRecord> 18template <class T = OPimRecord>
19class OPimAccessBackend { 19class OPimAccessBackend {
20public: 20public:
21 typedef OTemplateBase<T> Frontend; 21 typedef OTemplateBase<T> Frontend;
22 22
23 /** The access hint from the frontend */ 23 /** The access hint from the frontend */
24 OPimAccessBackend(int access = 0); 24 OPimAccessBackend(int access = 0);
25 virtual ~OPimAccessBackend(); 25 virtual ~OPimAccessBackend();
26 26
27 /** 27 /**
28 * load the resource 28 * load the resource
29 */ 29 */
30 virtual bool load() = 0; 30 virtual bool load() = 0;
31 31
32 /** 32 /**
33 * reload the resource 33 * reload the resource
34 */ 34 */
35 virtual bool reload() = 0; 35 virtual bool reload() = 0;
36 36
37 /** 37 /**
38 * save the resource and 38 * save the resource and
39 * all it's changes 39 * all it's changes
40 */ 40 */
41 virtual bool save() = 0; 41 virtual bool save() = 0;
42 42
43 /** 43 /**
44 * return an array of 44 * return an array of
45 * all available uids 45 * all available uids
46 */ 46 */
47 virtual QArray<int> allRecords()const = 0; 47 virtual QArray<int> allRecords()const = 0;
48 48
49 /** 49 /**
50 * queryByExample for T with the SortOrder 50 * queryByExample for T with the given Settings
51 * sort 51 *
52 */ 52 */
53 virtual QArray<int> queryByExample( const T& t, int sort ) = 0; 53 virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0;
54 54
55 /** 55 /**
56 * find the OPimRecord with uid @param uid 56 * find the OPimRecord with uid @param uid
57 * returns T and T.isEmpty() if nothing was found 57 * returns T and T.isEmpty() if nothing was found
58 */ 58 */
59 virtual T find(int uid )const = 0; 59 virtual T find(int uid )const = 0;
60 60
61 virtual T find(int uid, const QArray<int>& items, 61 virtual T find(int uid, const QArray<int>& items,
62 uint current, typename Frontend::CacheDirection )const ; 62 uint current, typename Frontend::CacheDirection )const ;
63 /** 63 /**
64 * clear the back end 64 * clear the back end
65 */ 65 */
66 virtual void clear() = 0; 66 virtual void clear() = 0;
67 67
68 /** 68 /**
69 * add T 69 * add T
70 */ 70 */
71 virtual bool add( const T& t ) = 0; 71 virtual bool add( const T& t ) = 0;
72 72
73 /** 73 /**
74 * remove 74 * remove
75 */ 75 */
76 virtual bool remove( int uid ) = 0; 76 virtual bool remove( int uid ) = 0;
77 77
78 /** 78 /**
79 * replace a record with T.uid() 79 * replace a record with T.uid()
80 */ 80 */
81 virtual bool replace( const T& t ) = 0; 81 virtual bool replace( const T& t ) = 0;
82 82
83 /* 83 /*
84 * setTheFrontEnd!!! 84 * setTheFrontEnd!!!
85 */ 85 */
86 void setFrontend( Frontend* front ); 86 void setFrontend( Frontend* front );
87 87
88 /** 88 /**
89 * set the read ahead count 89 * set the read ahead count
90 */ 90 */
91 void setReadAhead( uint count ); 91 void setReadAhead( uint count );
92protected: 92protected:
93 int access()const; 93 int access()const;
94 void cache( const T& t )const; 94 void cache( const T& t )const;
95 95
96 /** 96 /**
97 * use a prime number here! 97 * use a prime number here!
98 */ 98 */
99 void setSaneCacheSize( int ); 99 void setSaneCacheSize( int );
100 100
101 uint readAhead()const; 101 uint readAhead()const;
102 102
103private: 103private:
104 class Private; 104 class Private;
105 Private* d; 105 Private* d;
106 Frontend* m_front; 106 Frontend* m_front;
107 uint m_read; 107 uint m_read;
108 int m_acc; 108 int m_acc;
109 109
110}; 110};
111 111
112template <class T> 112template <class T>
113OPimAccessBackend<T>::OPimAccessBackend(int acc) 113OPimAccessBackend<T>::OPimAccessBackend(int acc)
114 : m_acc( acc ) 114 : m_acc( acc )
115{ 115{
116 m_front = 0l; 116 m_front = 0l;
117} 117}
118template <class T> 118template <class T>
119OPimAccessBackend<T>::~OPimAccessBackend() { 119OPimAccessBackend<T>::~OPimAccessBackend() {
120 120
121} 121}
122template <class T> 122template <class T>
123void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { 123void OPimAccessBackend<T>::setFrontend( Frontend* fr ) {
124 m_front = fr; 124 m_front = fr;
125} 125}
126template <class T> 126template <class T>
127void OPimAccessBackend<T>::cache( const T& t )const { 127void OPimAccessBackend<T>::cache( const T& t )const {
128 if (m_front ) 128 if (m_front )
129 m_front->cache( t ); 129 m_front->cache( t );
130} 130}
131template <class T> 131template <class T>
132void OPimAccessBackend<T>::setSaneCacheSize( int size) { 132void OPimAccessBackend<T>::setSaneCacheSize( int size) {
133 if (m_front ) 133 if (m_front )
134 m_front->setSaneCacheSize( size ); 134 m_front->setSaneCacheSize( size );
135} 135}
136template <class T> 136template <class T>
137T OPimAccessBackend<T>::find( int uid, const QArray<int>&, 137T OPimAccessBackend<T>::find( int uid, const QArray<int>&,
138 uint, typename Frontend::CacheDirection )const { 138 uint, typename Frontend::CacheDirection )const {
139 return find( uid ); 139 return find( uid );
140} 140}
141template <class T> 141template <class T>
142void OPimAccessBackend<T>::setReadAhead( uint count ) { 142void OPimAccessBackend<T>::setReadAhead( uint count ) {
143 m_read = count; 143 m_read = count;
144} 144}
145template <class T> 145template <class T>
146uint OPimAccessBackend<T>::readAhead()const { 146uint OPimAccessBackend<T>::readAhead()const {
147 return m_read; 147 return m_read;
148} 148}
149template <class T> 149template <class T>
150int OPimAccessBackend<T>::access()const { 150int OPimAccessBackend<T>::access()const {
151 return m_acc; 151 return m_acc;
152} 152}
153#endif 153#endif
diff --git a/libopie/pim/opimaccesstemplate.h b/libopie/pim/opimaccesstemplate.h
index 259e2c1..6a3a0db 100644
--- a/libopie/pim/opimaccesstemplate.h
+++ b/libopie/pim/opimaccesstemplate.h
@@ -1,286 +1,286 @@
1#ifndef OPIE_PIM_ACCESS_TEMPLATE_H 1#ifndef OPIE_PIM_ACCESS_TEMPLATE_H
2#define OPIE_PIM_ACCESS_TEMPLATE_H 2#define OPIE_PIM_ACCESS_TEMPLATE_H
3 3
4#include <qarray.h> 4#include <qarray.h>
5 5
6#include <opie/opimrecord.h> 6#include <opie/opimrecord.h>
7#include <opie/opimaccessbackend.h> 7#include <opie/opimaccessbackend.h>
8#include <opie/orecordlist.h> 8#include <opie/orecordlist.h>
9 9
10#include "opimcache.h" 10#include "opimcache.h"
11#include "otemplatebase.h" 11#include "otemplatebase.h"
12 12
13/** 13/**
14 * Thats the frontend to our OPIE PIM 14 * Thats the frontend to our OPIE PIM
15 * Library. Either you want to use it's 15 * Library. Either you want to use it's
16 * interface or you want to implement 16 * interface or you want to implement
17 * your own Access lib 17 * your own Access lib
18 * Just create a OPimRecord and inherit from 18 * Just create a OPimRecord and inherit from
19 * the plugins 19 * the plugins
20 */ 20 */
21 21
22template <class T = OPimRecord > 22template <class T = OPimRecord >
23class OPimAccessTemplate : public OTemplateBase<T> { 23class OPimAccessTemplate : public OTemplateBase<T> {
24public: 24public:
25 enum Access { 25 enum Access {
26 Random = 0, 26 Random = 0,
27 SortedAccess 27 SortedAccess
28 }; 28 };
29 typedef ORecordList<T> List; 29 typedef ORecordList<T> List;
30 typedef OPimAccessBackend<T> BackEnd; 30 typedef OPimAccessBackend<T> BackEnd;
31 typedef OPimCache<T> Cache; 31 typedef OPimCache<T> Cache;
32 32
33 /** 33 /**
34 * c'tor BackEnd 34 * c'tor BackEnd
35 * enum Access a small hint on how to handle the backend 35 * enum Access a small hint on how to handle the backend
36 */ 36 */
37 OPimAccessTemplate( BackEnd* end); 37 OPimAccessTemplate( BackEnd* end);
38 38
39 virtual ~OPimAccessTemplate(); 39 virtual ~OPimAccessTemplate();
40 40
41 /** 41 /**
42 * load from the backend 42 * load from the backend
43 */ 43 */
44 bool load(); 44 bool load();
45 45
46 /** Reload database. 46 /** Reload database.
47 * You should execute this function if the external database 47 * You should execute this function if the external database
48 * was changed. 48 * was changed.
49 * This function will load the external database and afterwards 49 * This function will load the external database and afterwards
50 * rejoin the local changes. Therefore the local database will be set consistent. 50 * rejoin the local changes. Therefore the local database will be set consistent.
51 */ 51 */
52 virtual bool reload(); 52 virtual bool reload();
53 53
54 /** Save contacts database. 54 /** Save contacts database.
55 * Save is more a "commit". After calling this function, all changes are public available. 55 * Save is more a "commit". After calling this function, all changes are public available.
56 * @return true if successful 56 * @return true if successful
57 */ 57 */
58 bool save(); 58 bool save();
59 59
60 /** 60 /**
61 * if the resource was changed externally 61 * if the resource was changed externally
62 * You should use the signal handling instead of polling possible changes ! 62 * You should use the signal handling instead of polling possible changes !
63 * zecke: Do you implement a signal for otodoaccess ? 63 * zecke: Do you implement a signal for otodoaccess ?
64 */ 64 */
65 bool wasChangedExternally()const; 65 bool wasChangedExternally()const;
66 66
67 /** 67 /**
68 * return a List of records 68 * return a List of records
69 * you can iterate over them 69 * you can iterate over them
70 */ 70 */
71 virtual List allRecords()const; 71 virtual List allRecords()const;
72 72
73 /** 73 /**
74 * queryByExample. 74 * queryByExample.
75 * @see otodoaccess, ocontactaccess 75 * @see otodoaccess, ocontactaccess
76 */ 76 */
77 virtual List queryByExample( const T& t, int querySettings ); 77 virtual List queryByExample( const T& t, int querySettings, const QDateTime& d = QDateTime() );
78 78
79 /** 79 /**
80 * find the OPimRecord uid 80 * find the OPimRecord uid
81 */ 81 */
82 virtual T find( int uid )const; 82 virtual T find( int uid )const;
83 83
84 /** 84 /**
85 * read ahead cache find method ;) 85 * read ahead cache find method ;)
86 */ 86 */
87 virtual T find( int uid, const QArray<int>&, 87 virtual T find( int uid, const QArray<int>&,
88 uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const; 88 uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const;
89 89
90 /* invalidate cache here */ 90 /* invalidate cache here */
91 /** 91 /**
92 * clears the backend and invalidates the backend 92 * clears the backend and invalidates the backend
93 */ 93 */
94 void clear() ; 94 void clear() ;
95 95
96 /** 96 /**
97 * add T to the backend 97 * add T to the backend
98 * @param t The item to add. 98 * @param t The item to add.
99 * @return <i>true</i> if added successfully. 99 * @return <i>true</i> if added successfully.
100 */ 100 */
101 virtual bool add( const T& t ) ; 101 virtual bool add( const T& t ) ;
102 bool add( const OPimRecord& ); 102 bool add( const OPimRecord& );
103 103
104 /* only the uid matters */ 104 /* only the uid matters */
105 /** 105 /**
106 * remove T from the backend 106 * remove T from the backend
107 * @param t The item to remove 107 * @param t The item to remove
108 * @return <i>true</i> if successful. 108 * @return <i>true</i> if successful.
109 */ 109 */
110 virtual bool remove( const T& t ); 110 virtual bool remove( const T& t );
111 111
112 /** 112 /**
113 * remove the OPimRecord with uid 113 * remove the OPimRecord with uid
114 * @param uid The ID of the item to remove 114 * @param uid The ID of the item to remove
115 * @return <i>true</i> if successful. 115 * @return <i>true</i> if successful.
116 */ 116 */
117 bool remove( int uid ); 117 bool remove( int uid );
118 bool remove( const OPimRecord& ); 118 bool remove( const OPimRecord& );
119 119
120 /** 120 /**
121 * replace T from backend 121 * replace T from backend
122 * @param t The item to replace 122 * @param t The item to replace
123 * @return <i>true</i> if successful. 123 * @return <i>true</i> if successful.
124 */ 124 */
125 virtual bool replace( const T& t) ; 125 virtual bool replace( const T& t) ;
126 126
127 void setReadAhead( uint count ); 127 void setReadAhead( uint count );
128 /** 128 /**
129 * @internal 129 * @internal
130 */ 130 */
131 void cache( const T& )const; 131 void cache( const T& )const;
132 void setSaneCacheSize( int ); 132 void setSaneCacheSize( int );
133 133
134 QArray<int> records()const; 134 QArray<int> records()const;
135protected: 135protected:
136 /** 136 /**
137 * invalidate the cache 137 * invalidate the cache
138 */ 138 */
139 void invalidateCache(); 139 void invalidateCache();
140 140
141 void setBackEnd( BackEnd* end ); 141 void setBackEnd( BackEnd* end );
142 /** 142 /**
143 * returns the backend 143 * returns the backend
144 */ 144 */
145 BackEnd* backEnd(); 145 BackEnd* backEnd();
146 BackEnd* m_backEnd; 146 BackEnd* m_backEnd;
147 Cache m_cache; 147 Cache m_cache;
148 148
149}; 149};
150 150
151template <class T> 151template <class T>
152OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) 152OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end )
153 : OTemplateBase<T>(), m_backEnd( end ) 153 : OTemplateBase<T>(), m_backEnd( end )
154{ 154{
155 if (end ) 155 if (end )
156 end->setFrontend( this ); 156 end->setFrontend( this );
157} 157}
158template <class T> 158template <class T>
159OPimAccessTemplate<T>::~OPimAccessTemplate() { 159OPimAccessTemplate<T>::~OPimAccessTemplate() {
160 qWarning("~OPimAccessTemplate<T>"); 160 qWarning("~OPimAccessTemplate<T>");
161 delete m_backEnd; 161 delete m_backEnd;
162} 162}
163template <class T> 163template <class T>
164bool OPimAccessTemplate<T>::load() { 164bool OPimAccessTemplate<T>::load() {
165 invalidateCache(); 165 invalidateCache();
166 return m_backEnd->load(); 166 return m_backEnd->load();
167} 167}
168template <class T> 168template <class T>
169bool OPimAccessTemplate<T>::reload() { 169bool OPimAccessTemplate<T>::reload() {
170 invalidateCache(); // zecke: I think this should be added (se) 170 invalidateCache(); // zecke: I think this should be added (se)
171 return m_backEnd->reload(); 171 return m_backEnd->reload();
172} 172}
173template <class T> 173template <class T>
174bool OPimAccessTemplate<T>::save() { 174bool OPimAccessTemplate<T>::save() {
175 return m_backEnd->save(); 175 return m_backEnd->save();
176} 176}
177template <class T> 177template <class T>
178typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { 178typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const {
179 QArray<int> ints = m_backEnd->allRecords(); 179 QArray<int> ints = m_backEnd->allRecords();
180 List lis(ints, this ); 180 List lis(ints, this );
181 return lis; 181 return lis;
182} 182}
183template <class T> 183template <class T>
184QArray<int> OPimAccessTemplate<T>::records()const { 184QArray<int> OPimAccessTemplate<T>::records()const {
185 return m_backEnd->allRecords(); 185 return m_backEnd->allRecords();
186} 186}
187template <class T> 187template <class T>
188typename OPimAccessTemplate<T>::List 188typename OPimAccessTemplate<T>::List
189OPimAccessTemplate<T>::queryByExample( const T& t, int sortOrder ) { 189OPimAccessTemplate<T>::queryByExample( const T& t, int settings, const QDateTime& d ) {
190 QArray<int> ints = m_backEnd->queryByExample( t, sortOrder ); 190 QArray<int> ints = m_backEnd->queryByExample( t, settings, d );
191 191
192 List lis(ints, this ); 192 List lis(ints, this );
193 return lis; 193 return lis;
194} 194}
195template <class T> 195template <class T>
196T OPimAccessTemplate<T>::find( int uid ) const{ 196T OPimAccessTemplate<T>::find( int uid ) const{
197 T t = m_backEnd->find( uid ); 197 T t = m_backEnd->find( uid );
198 cache( t ); 198 cache( t );
199 return t; 199 return t;
200} 200}
201template <class T> 201template <class T>
202T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, 202T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar,
203 uint current, typename OTemplateBase<T>::CacheDirection dir )const { 203 uint current, typename OTemplateBase<T>::CacheDirection dir )const {
204 /* 204 /*
205 * better do T.isEmpty() 205 * better do T.isEmpty()
206 * after a find this way we would 206 * after a find this way we would
207 * avoid two finds in QCache... 207 * avoid two finds in QCache...
208 */ 208 */
209 // qWarning("find it now %d", uid ); 209 // qWarning("find it now %d", uid );
210 if (m_cache.contains( uid ) ) { 210 if (m_cache.contains( uid ) ) {
211 return m_cache.find( uid ); 211 return m_cache.find( uid );
212 } 212 }
213 213
214 T t = m_backEnd->find( uid, ar, current, dir ); 214 T t = m_backEnd->find( uid, ar, current, dir );
215 cache( t ); 215 cache( t );
216 return t; 216 return t;
217} 217}
218template <class T> 218template <class T>
219void OPimAccessTemplate<T>::clear() { 219void OPimAccessTemplate<T>::clear() {
220 invalidateCache(); 220 invalidateCache();
221 m_backEnd->clear(); 221 m_backEnd->clear();
222} 222}
223template <class T> 223template <class T>
224bool OPimAccessTemplate<T>::add( const T& t ) { 224bool OPimAccessTemplate<T>::add( const T& t ) {
225 cache( t ); 225 cache( t );
226 return m_backEnd->add( t ); 226 return m_backEnd->add( t );
227} 227}
228template <class T> 228template <class T>
229bool OPimAccessTemplate<T>::add( const OPimRecord& rec) { 229bool OPimAccessTemplate<T>::add( const OPimRecord& rec) {
230 /* same type */ 230 /* same type */
231 if ( rec.rtti() == T::rtti() ) { 231 if ( rec.rtti() == T::rtti() ) {
232 const T &t = static_cast<const T&>(rec); 232 const T &t = static_cast<const T&>(rec);
233 return add(t); 233 return add(t);
234 } 234 }
235 return false; 235 return false;
236} 236}
237template <class T> 237template <class T>
238bool OPimAccessTemplate<T>::remove( const T& t ) { 238bool OPimAccessTemplate<T>::remove( const T& t ) {
239 return remove( t.uid() ); 239 return remove( t.uid() );
240} 240}
241template <class T> 241template <class T>
242bool OPimAccessTemplate<T>::remove( int uid ) { 242bool OPimAccessTemplate<T>::remove( int uid ) {
243 m_cache.remove( uid ); 243 m_cache.remove( uid );
244 return m_backEnd->remove( uid ); 244 return m_backEnd->remove( uid );
245} 245}
246template <class T> 246template <class T>
247bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) { 247bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) {
248 return remove( rec.uid() ); 248 return remove( rec.uid() );
249} 249}
250template <class T> 250template <class T>
251bool OPimAccessTemplate<T>::replace( const T& t ) { 251bool OPimAccessTemplate<T>::replace( const T& t ) {
252 m_cache.replace( t ); 252 m_cache.replace( t );
253 return m_backEnd->replace( t ); 253 return m_backEnd->replace( t );
254} 254}
255template <class T> 255template <class T>
256void OPimAccessTemplate<T>::invalidateCache() { 256void OPimAccessTemplate<T>::invalidateCache() {
257 m_cache.invalidate(); 257 m_cache.invalidate();
258} 258}
259template <class T> 259template <class T>
260typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { 260typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() {
261 return m_backEnd; 261 return m_backEnd;
262} 262}
263template <class T> 263template <class T>
264bool OPimAccessTemplate<T>::wasChangedExternally()const { 264bool OPimAccessTemplate<T>::wasChangedExternally()const {
265 return false; 265 return false;
266} 266}
267template <class T> 267template <class T>
268void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { 268void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) {
269 m_backEnd = end; 269 m_backEnd = end;
270 if (m_backEnd ) 270 if (m_backEnd )
271 m_backEnd->setFrontend( this ); 271 m_backEnd->setFrontend( this );
272} 272}
273template <class T> 273template <class T>
274void OPimAccessTemplate<T>::cache( const T& t ) const{ 274void OPimAccessTemplate<T>::cache( const T& t ) const{
275 /* hacky we need to work around the const*/ 275 /* hacky we need to work around the const*/
276 ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); 276 ((OPimAccessTemplate<T>*)this)->m_cache.add( t );
277} 277}
278template <class T> 278template <class T>
279void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { 279void OPimAccessTemplate<T>::setSaneCacheSize( int size ) {
280 m_cache.setSize( size ); 280 m_cache.setSize( size );
281} 281}
282template <class T> 282template <class T>
283void OPimAccessTemplate<T>::setReadAhead( uint count ) { 283void OPimAccessTemplate<T>::setReadAhead( uint count ) {
284 m_backEnd->setReadAhead( count ); 284 m_backEnd->setReadAhead( count );
285} 285}
286#endif 286#endif
diff --git a/libopie/pim/otodoaccesssql.cpp b/libopie/pim/otodoaccesssql.cpp
index 761d7d8..ec9c14c 100644
--- a/libopie/pim/otodoaccesssql.cpp
+++ b/libopie/pim/otodoaccesssql.cpp
@@ -1,540 +1,540 @@
1 1
2#include <qdatetime.h> 2#include <qdatetime.h>
3 3
4#include <qpe/global.h> 4#include <qpe/global.h>
5 5
6#include <opie/osqldriver.h> 6#include <opie/osqldriver.h>
7#include <opie/osqlresult.h> 7#include <opie/osqlresult.h>
8#include <opie/osqlmanager.h> 8#include <opie/osqlmanager.h>
9#include <opie/osqlquery.h> 9#include <opie/osqlquery.h>
10 10
11#include "otodoaccesssql.h" 11#include "otodoaccesssql.h"
12 12
13/* 13/*
14 * first some query 14 * first some query
15 * CREATE query 15 * CREATE query
16 * LOAD query 16 * LOAD query
17 * INSERT 17 * INSERT
18 * REMOVE 18 * REMOVE
19 * CLEAR 19 * CLEAR
20 */ 20 */
21namespace { 21namespace {
22 /** 22 /**
23 * CreateQuery for the Todolist Table 23 * CreateQuery for the Todolist Table
24 */ 24 */
25 class CreateQuery : public OSQLQuery { 25 class CreateQuery : public OSQLQuery {
26 public: 26 public:
27 CreateQuery(); 27 CreateQuery();
28 ~CreateQuery(); 28 ~CreateQuery();
29 QString query()const; 29 QString query()const;
30 }; 30 };
31 31
32 /** 32 /**
33 * LoadQuery 33 * LoadQuery
34 * this one queries for all uids 34 * this one queries for all uids
35 */ 35 */
36 class LoadQuery : public OSQLQuery { 36 class LoadQuery : public OSQLQuery {
37 public: 37 public:
38 LoadQuery(); 38 LoadQuery();
39 ~LoadQuery(); 39 ~LoadQuery();
40 QString query()const; 40 QString query()const;
41 }; 41 };
42 42
43 /** 43 /**
44 * inserts/adds a OTodo to the table 44 * inserts/adds a OTodo to the table
45 */ 45 */
46 class InsertQuery : public OSQLQuery { 46 class InsertQuery : public OSQLQuery {
47 public: 47 public:
48 InsertQuery(const OTodo& ); 48 InsertQuery(const OTodo& );
49 ~InsertQuery(); 49 ~InsertQuery();
50 QString query()const; 50 QString query()const;
51 private: 51 private:
52 OTodo m_todo; 52 OTodo m_todo;
53 }; 53 };
54 54
55 /** 55 /**
56 * removes one from the table 56 * removes one from the table
57 */ 57 */
58 class RemoveQuery : public OSQLQuery { 58 class RemoveQuery : public OSQLQuery {
59 public: 59 public:
60 RemoveQuery(int uid ); 60 RemoveQuery(int uid );
61 ~RemoveQuery(); 61 ~RemoveQuery();
62 QString query()const; 62 QString query()const;
63 private: 63 private:
64 int m_uid; 64 int m_uid;
65 }; 65 };
66 66
67 /** 67 /**
68 * Clears (delete) a Table 68 * Clears (delete) a Table
69 */ 69 */
70 class ClearQuery : public OSQLQuery { 70 class ClearQuery : public OSQLQuery {
71 public: 71 public:
72 ClearQuery(); 72 ClearQuery();
73 ~ClearQuery(); 73 ~ClearQuery();
74 QString query()const; 74 QString query()const;
75 75
76 }; 76 };
77 77
78 /** 78 /**
79 * a find query 79 * a find query
80 */ 80 */
81 class FindQuery : public OSQLQuery { 81 class FindQuery : public OSQLQuery {
82 public: 82 public:
83 FindQuery(int uid); 83 FindQuery(int uid);
84 FindQuery(const QArray<int>& ); 84 FindQuery(const QArray<int>& );
85 ~FindQuery(); 85 ~FindQuery();
86 QString query()const; 86 QString query()const;
87 private: 87 private:
88 QString single()const; 88 QString single()const;
89 QString multi()const; 89 QString multi()const;
90 QArray<int> m_uids; 90 QArray<int> m_uids;
91 int m_uid; 91 int m_uid;
92 }; 92 };
93 93
94 /** 94 /**
95 * overdue query 95 * overdue query
96 */ 96 */
97 class OverDueQuery : public OSQLQuery { 97 class OverDueQuery : public OSQLQuery {
98 public: 98 public:
99 OverDueQuery(); 99 OverDueQuery();
100 ~OverDueQuery(); 100 ~OverDueQuery();
101 QString query()const; 101 QString query()const;
102 }; 102 };
103 class EffQuery : public OSQLQuery { 103 class EffQuery : public OSQLQuery {
104 public: 104 public:
105 EffQuery( const QDate&, const QDate&, bool inc ); 105 EffQuery( const QDate&, const QDate&, bool inc );
106 ~EffQuery(); 106 ~EffQuery();
107 QString query()const; 107 QString query()const;
108 private: 108 private:
109 QString with()const; 109 QString with()const;
110 QString out()const; 110 QString out()const;
111 QDate m_start; 111 QDate m_start;
112 QDate m_end; 112 QDate m_end;
113 bool m_inc :1; 113 bool m_inc :1;
114 }; 114 };
115 115
116 116
117 CreateQuery::CreateQuery() : OSQLQuery() {} 117 CreateQuery::CreateQuery() : OSQLQuery() {}
118 CreateQuery::~CreateQuery() {} 118 CreateQuery::~CreateQuery() {}
119 QString CreateQuery::query()const { 119 QString CreateQuery::query()const {
120 QString qu; 120 QString qu;
121 qu += "create table todolist( uid, categories, completed, progress, "; 121 qu += "create table todolist( uid, categories, completed, progress, ";
122 qu += "summary, DueDate, priority, description )"; 122 qu += "summary, DueDate, priority, description )";
123 return qu; 123 return qu;
124 } 124 }
125 125
126 LoadQuery::LoadQuery() : OSQLQuery() {} 126 LoadQuery::LoadQuery() : OSQLQuery() {}
127 LoadQuery::~LoadQuery() {} 127 LoadQuery::~LoadQuery() {}
128 QString LoadQuery::query()const { 128 QString LoadQuery::query()const {
129 QString qu; 129 QString qu;
130 qu += "select distinct uid from todolist"; 130 qu += "select distinct uid from todolist";
131 131
132 return qu; 132 return qu;
133 } 133 }
134 134
135 InsertQuery::InsertQuery( const OTodo& todo ) 135 InsertQuery::InsertQuery( const OTodo& todo )
136 : OSQLQuery(), m_todo( todo ) { 136 : OSQLQuery(), m_todo( todo ) {
137 } 137 }
138 InsertQuery::~InsertQuery() { 138 InsertQuery::~InsertQuery() {
139 } 139 }
140 /* 140 /*
141 * converts from a OTodo to a query 141 * converts from a OTodo to a query
142 * we leave out X-Ref + Alarms 142 * we leave out X-Ref + Alarms
143 */ 143 */
144 QString InsertQuery::query()const{ 144 QString InsertQuery::query()const{
145 145
146 int year, month, day; 146 int year, month, day;
147 year = month = day = 0; 147 year = month = day = 0;
148 if (m_todo.hasDueDate() ) { 148 if (m_todo.hasDueDate() ) {
149 QDate date = m_todo.dueDate(); 149 QDate date = m_todo.dueDate();
150 year = date.year(); 150 year = date.year();
151 month = date.month(); 151 month = date.month();
152 day = date.day(); 152 day = date.day();
153 } 153 }
154 QString qu; 154 QString qu;
155 qu = "insert into todolist VALUES(" + QString::number( m_todo.uid() ) + ",'" + m_todo.idsToString( m_todo.categories() ) + "',"; 155 qu = "insert into todolist VALUES(" + QString::number( m_todo.uid() ) + ",'" + m_todo.idsToString( m_todo.categories() ) + "',";
156 qu += QString::number( m_todo.isCompleted() ) + "," + QString::number( m_todo.progress() ) + ","; 156 qu += QString::number( m_todo.isCompleted() ) + "," + QString::number( m_todo.progress() ) + ",";
157 qu += "'"+m_todo.summary()+"','"+QString::number(year)+"-"+QString::number(month)+"-"+QString::number(day)+"',"; 157 qu += "'"+m_todo.summary()+"','"+QString::number(year)+"-"+QString::number(month)+"-"+QString::number(day)+"',";
158 qu += QString::number(m_todo.priority() ) +",'" + m_todo.description() + "')"; 158 qu += QString::number(m_todo.priority() ) +",'" + m_todo.description() + "')";
159 159
160 qWarning("add %s", qu.latin1() ); 160 qWarning("add %s", qu.latin1() );
161 return qu; 161 return qu;
162 } 162 }
163 163
164 RemoveQuery::RemoveQuery(int uid ) 164 RemoveQuery::RemoveQuery(int uid )
165 : OSQLQuery(), m_uid( uid ) {} 165 : OSQLQuery(), m_uid( uid ) {}
166 RemoveQuery::~RemoveQuery() {} 166 RemoveQuery::~RemoveQuery() {}
167 QString RemoveQuery::query()const { 167 QString RemoveQuery::query()const {
168 QString qu = "DELETE from todolist where uid = " + QString::number(m_uid); 168 QString qu = "DELETE from todolist where uid = " + QString::number(m_uid);
169 return qu; 169 return qu;
170 } 170 }
171 171
172 172
173 ClearQuery::ClearQuery() 173 ClearQuery::ClearQuery()
174 : OSQLQuery() {} 174 : OSQLQuery() {}
175 ClearQuery::~ClearQuery() {} 175 ClearQuery::~ClearQuery() {}
176 QString ClearQuery::query()const { 176 QString ClearQuery::query()const {
177 QString qu = "drop table todolist"; 177 QString qu = "drop table todolist";
178 return qu; 178 return qu;
179 } 179 }
180 FindQuery::FindQuery(int uid) 180 FindQuery::FindQuery(int uid)
181 : OSQLQuery(), m_uid(uid ) { 181 : OSQLQuery(), m_uid(uid ) {
182 } 182 }
183 FindQuery::FindQuery(const QArray<int>& ints) 183 FindQuery::FindQuery(const QArray<int>& ints)
184 : OSQLQuery(), m_uids(ints){ 184 : OSQLQuery(), m_uids(ints){
185 } 185 }
186 FindQuery::~FindQuery() { 186 FindQuery::~FindQuery() {
187 } 187 }
188 QString FindQuery::query()const{ 188 QString FindQuery::query()const{
189 if (m_uids.count() == 0 ) 189 if (m_uids.count() == 0 )
190 return single(); 190 return single();
191 else 191 else
192 return multi(); 192 return multi();
193 } 193 }
194 QString FindQuery::single()const{ 194 QString FindQuery::single()const{
195 QString qu = "select uid, categories, completed, progress, summary, "; 195 QString qu = "select uid, categories, completed, progress, summary, ";
196 qu += "DueDate, priority, description from todolist where uid = " + QString::number(m_uid); 196 qu += "DueDate, priority, description from todolist where uid = " + QString::number(m_uid);
197 return qu; 197 return qu;
198 } 198 }
199 QString FindQuery::multi()const { 199 QString FindQuery::multi()const {
200 QString qu = "select uid, categories, completed, progress, summary, "; 200 QString qu = "select uid, categories, completed, progress, summary, ";
201 qu += "DueDate, priority, description from todolist where "; 201 qu += "DueDate, priority, description from todolist where ";
202 for (uint i = 0; i < m_uids.count(); i++ ) { 202 for (uint i = 0; i < m_uids.count(); i++ ) {
203 qu += " UID = " + QString::number( m_uids[i] ) + " OR"; 203 qu += " UID = " + QString::number( m_uids[i] ) + " OR";
204 } 204 }
205 qu.remove( qu.length()-2, 2 ); 205 qu.remove( qu.length()-2, 2 );
206 return qu; 206 return qu;
207 } 207 }
208 208
209 OverDueQuery::OverDueQuery(): OSQLQuery() {} 209 OverDueQuery::OverDueQuery(): OSQLQuery() {}
210 OverDueQuery::~OverDueQuery() {} 210 OverDueQuery::~OverDueQuery() {}
211 QString OverDueQuery::query()const { 211 QString OverDueQuery::query()const {
212 QDate date = QDate::currentDate(); 212 QDate date = QDate::currentDate();
213 QString str; 213 QString str;
214 str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() ); 214 str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() );
215 215
216 return str; 216 return str;
217 } 217 }
218 218
219 219
220 EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc ) 220 EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc )
221 : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {} 221 : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {}
222 EffQuery::~EffQuery() {} 222 EffQuery::~EffQuery() {}
223 QString EffQuery::query()const { 223 QString EffQuery::query()const {
224 return m_inc ? with() : out(); 224 return m_inc ? with() : out();
225 } 225 }
226 QString EffQuery::with()const { 226 QString EffQuery::with()const {
227 QString str; 227 QString str;
228 str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") 228 str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ")
229 .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) 229 .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() )
230 .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); 230 .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() );
231 return str; 231 return str;
232 } 232 }
233 QString EffQuery::out()const { 233 QString EffQuery::out()const {
234 QString str; 234 QString str;
235 str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") 235 str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'")
236 .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) 236 .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() )
237 .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); 237 .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() );
238 238
239 return str; 239 return str;
240 } 240 }
241}; 241};
242 242
243OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) 243OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file )
244 : OTodoAccessBackend(), m_dict(15), m_dirty(true) 244 : OTodoAccessBackend(), m_dict(15), m_dirty(true)
245{ 245{
246 QString fi = file; 246 QString fi = file;
247 if ( fi.isEmpty() ) 247 if ( fi.isEmpty() )
248 fi = Global::applicationFileName( "todolist", "todolist.db" ); 248 fi = Global::applicationFileName( "todolist", "todolist.db" );
249 OSQLManager man; 249 OSQLManager man;
250 m_driver = man.standard(); 250 m_driver = man.standard();
251 m_driver->setUrl(fi); 251 m_driver->setUrl(fi);
252 fillDict(); 252 fillDict();
253} 253}
254 254
255OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ 255OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){
256} 256}
257bool OTodoAccessBackendSQL::load(){ 257bool OTodoAccessBackendSQL::load(){
258 if (!m_driver->open() ) 258 if (!m_driver->open() )
259 return false; 259 return false;
260 260
261 CreateQuery creat; 261 CreateQuery creat;
262 OSQLResult res = m_driver->query(&creat ); 262 OSQLResult res = m_driver->query(&creat );
263 263
264 m_dirty = true; 264 m_dirty = true;
265 return true; 265 return true;
266} 266}
267bool OTodoAccessBackendSQL::reload(){ 267bool OTodoAccessBackendSQL::reload(){
268 return load(); 268 return load();
269} 269}
270 270
271bool OTodoAccessBackendSQL::save(){ 271bool OTodoAccessBackendSQL::save(){
272 return m_driver->close(); 272 return m_driver->close();
273} 273}
274QArray<int> OTodoAccessBackendSQL::allRecords()const { 274QArray<int> OTodoAccessBackendSQL::allRecords()const {
275 if (m_dirty ) 275 if (m_dirty )
276 update(); 276 update();
277 277
278 return m_uids; 278 return m_uids;
279} 279}
280QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int ){ 280QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){
281 QArray<int> ints(0); 281 QArray<int> ints(0);
282 return ints; 282 return ints;
283} 283}
284OTodo OTodoAccessBackendSQL::find(int uid ) const{ 284OTodo OTodoAccessBackendSQL::find(int uid ) const{
285 FindQuery query( uid ); 285 FindQuery query( uid );
286 return todo( m_driver->query(&query) ); 286 return todo( m_driver->query(&query) );
287 287
288} 288}
289OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, 289OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints,
290 uint cur, Frontend::CacheDirection dir ) const{ 290 uint cur, Frontend::CacheDirection dir ) const{
291 int CACHE = readAhead(); 291 int CACHE = readAhead();
292 qWarning("searching for %d", uid ); 292 qWarning("searching for %d", uid );
293 QArray<int> search( CACHE ); 293 QArray<int> search( CACHE );
294 uint size =0; 294 uint size =0;
295 OTodo to; 295 OTodo to;
296 296
297 // we try to cache CACHE items 297 // we try to cache CACHE items
298 switch( dir ) { 298 switch( dir ) {
299 /* forward */ 299 /* forward */
300 case 0: 300 case 0:
301 for (uint i = cur; i < ints.count() && size < CACHE; i++ ) { 301 for (uint i = cur; i < ints.count() && size < CACHE; i++ ) {
302 qWarning("size %d %d", size, ints[i] ); 302 qWarning("size %d %d", size, ints[i] );
303 search[size] = ints[i]; 303 search[size] = ints[i];
304 size++; 304 size++;
305 } 305 }
306 break; 306 break;
307 /* reverse */ 307 /* reverse */
308 case 1: 308 case 1:
309 for (uint i = cur; i != 0 && size < CACHE; i-- ) { 309 for (uint i = cur; i != 0 && size < CACHE; i-- ) {
310 search[size] = ints[i]; 310 search[size] = ints[i];
311 size++; 311 size++;
312 } 312 }
313 break; 313 break;
314 } 314 }
315 search.resize( size ); 315 search.resize( size );
316 FindQuery query( search ); 316 FindQuery query( search );
317 OSQLResult res = m_driver->query( &query ); 317 OSQLResult res = m_driver->query( &query );
318 if ( res.state() != OSQLResult::Success ) 318 if ( res.state() != OSQLResult::Success )
319 return to; 319 return to;
320 320
321 return todo( res ); 321 return todo( res );
322} 322}
323void OTodoAccessBackendSQL::clear() { 323void OTodoAccessBackendSQL::clear() {
324 ClearQuery cle; 324 ClearQuery cle;
325 OSQLResult res = m_driver->query( &cle ); 325 OSQLResult res = m_driver->query( &cle );
326 CreateQuery qu; 326 CreateQuery qu;
327 res = m_driver->query(&qu); 327 res = m_driver->query(&qu);
328} 328}
329bool OTodoAccessBackendSQL::add( const OTodo& t) { 329bool OTodoAccessBackendSQL::add( const OTodo& t) {
330 InsertQuery ins( t ); 330 InsertQuery ins( t );
331 OSQLResult res = m_driver->query( &ins ); 331 OSQLResult res = m_driver->query( &ins );
332 332
333 if ( res.state() == OSQLResult::Failure ) 333 if ( res.state() == OSQLResult::Failure )
334 return false; 334 return false;
335 int c = m_uids.count(); 335 int c = m_uids.count();
336 m_uids.resize( c+1 ); 336 m_uids.resize( c+1 );
337 m_uids[c] = t.uid(); 337 m_uids[c] = t.uid();
338 338
339 return true; 339 return true;
340} 340}
341bool OTodoAccessBackendSQL::remove( int uid ) { 341bool OTodoAccessBackendSQL::remove( int uid ) {
342 RemoveQuery rem( uid ); 342 RemoveQuery rem( uid );
343 OSQLResult res = m_driver->query(&rem ); 343 OSQLResult res = m_driver->query(&rem );
344 344
345 if ( res.state() == OSQLResult::Failure ) 345 if ( res.state() == OSQLResult::Failure )
346 return false; 346 return false;
347 347
348 m_dirty = true; 348 m_dirty = true;
349 return true; 349 return true;
350} 350}
351/* 351/*
352 * FIXME better set query 352 * FIXME better set query
353 * but we need the cache for that 353 * but we need the cache for that
354 * now we remove 354 * now we remove
355 */ 355 */
356bool OTodoAccessBackendSQL::replace( const OTodo& t) { 356bool OTodoAccessBackendSQL::replace( const OTodo& t) {
357 remove( t.uid() ); 357 remove( t.uid() );
358 bool b= add(t); 358 bool b= add(t);
359 m_dirty = false; // we changed some stuff but the UID stayed the same 359 m_dirty = false; // we changed some stuff but the UID stayed the same
360 return b; 360 return b;
361} 361}
362QArray<int> OTodoAccessBackendSQL::overDue() { 362QArray<int> OTodoAccessBackendSQL::overDue() {
363 OverDueQuery qu; 363 OverDueQuery qu;
364 return uids( m_driver->query(&qu ) ); 364 return uids( m_driver->query(&qu ) );
365} 365}
366QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s, 366QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s,
367 const QDate& t, 367 const QDate& t,
368 bool u) { 368 bool u) {
369 EffQuery ef(s, t, u ); 369 EffQuery ef(s, t, u );
370 return uids (m_driver->query(&ef) ); 370 return uids (m_driver->query(&ef) );
371} 371}
372/* 372/*
373 * 373 *
374 */ 374 */
375QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder, 375QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder,
376 int sortFilter, int cat ) { 376 int sortFilter, int cat ) {
377 qWarning("sorted %d, %d", asc, sortOrder ); 377 qWarning("sorted %d, %d", asc, sortOrder );
378 QString query; 378 QString query;
379 query = "select uid from todolist WHERE "; 379 query = "select uid from todolist WHERE ";
380 380
381 /* 381 /*
382 * Sort Filter stuff 382 * Sort Filter stuff
383 * not that straight forward 383 * not that straight forward
384 * 384 *
385 */ 385 */
386 /* Category */ 386 /* Category */
387 if ( sortFilter & 1 ) { 387 if ( sortFilter & 1 ) {
388 QString str; 388 QString str;
389 if (cat != 0 ) str = QString::number( cat ); 389 if (cat != 0 ) str = QString::number( cat );
390 query += " categories like '%" +str+"%' AND"; 390 query += " categories like '%" +str+"%' AND";
391 } 391 }
392 /* Show only overdue */ 392 /* Show only overdue */
393 if ( sortFilter & 2 ) { 393 if ( sortFilter & 2 ) {
394 QDate date = QDate::currentDate(); 394 QDate date = QDate::currentDate();
395 QString due; 395 QString due;
396 QString base; 396 QString base;
397 base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() ); 397 base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() );
398 query += " " + base + " AND"; 398 query += " " + base + " AND";
399 } 399 }
400 /* not show completed */ 400 /* not show completed */
401 if ( sortFilter & 4 ) { 401 if ( sortFilter & 4 ) {
402 query += " completed = 0 AND"; 402 query += " completed = 0 AND";
403 }else{ 403 }else{
404 query += " ( completed = 1 OR completed = 0) AND"; 404 query += " ( completed = 1 OR completed = 0) AND";
405 } 405 }
406 /* srtip the end */ 406 /* srtip the end */
407 query = query.remove( query.length()-3, 3 ); 407 query = query.remove( query.length()-3, 3 );
408 408
409 409
410 /* 410 /*
411 * sort order stuff 411 * sort order stuff
412 * quite straight forward 412 * quite straight forward
413 */ 413 */
414 query += "ORDER BY "; 414 query += "ORDER BY ";
415 switch( sortOrder ) { 415 switch( sortOrder ) {
416 /* completed */ 416 /* completed */
417 case 0: 417 case 0:
418 query += "completed"; 418 query += "completed";
419 break; 419 break;
420 case 1: 420 case 1:
421 query += "priority"; 421 query += "priority";
422 break; 422 break;
423 case 2: 423 case 2:
424 query += "summary"; 424 query += "summary";
425 break; 425 break;
426 case 3: 426 case 3:
427 query += "DueDate"; 427 query += "DueDate";
428 break; 428 break;
429 } 429 }
430 430
431 if ( !asc ) { 431 if ( !asc ) {
432 qWarning("not ascending!"); 432 qWarning("not ascending!");
433 query += " DESC"; 433 query += " DESC";
434 } 434 }
435 435
436 qWarning( query ); 436 qWarning( query );
437 OSQLRawQuery raw(query ); 437 OSQLRawQuery raw(query );
438 return uids( m_driver->query(&raw) ); 438 return uids( m_driver->query(&raw) );
439} 439}
440bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{ 440bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{
441 if ( str == "0-0-0" ) 441 if ( str == "0-0-0" )
442 return false; 442 return false;
443 else{ 443 else{
444 int day, year, month; 444 int day, year, month;
445 QStringList list = QStringList::split("-", str ); 445 QStringList list = QStringList::split("-", str );
446 year = list[0].toInt(); 446 year = list[0].toInt();
447 month = list[1].toInt(); 447 month = list[1].toInt();
448 day = list[2].toInt(); 448 day = list[2].toInt();
449 da.setYMD( year, month, day ); 449 da.setYMD( year, month, day );
450 return true; 450 return true;
451 } 451 }
452} 452}
453OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{ 453OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{
454 if ( res.state() == OSQLResult::Failure ) { 454 if ( res.state() == OSQLResult::Failure ) {
455 OTodo to; 455 OTodo to;
456 return to; 456 return to;
457 } 457 }
458 458
459 OSQLResultItem::ValueList list = res.results(); 459 OSQLResultItem::ValueList list = res.results();
460 OSQLResultItem::ValueList::Iterator it = list.begin(); 460 OSQLResultItem::ValueList::Iterator it = list.begin();
461 qWarning("todo1"); 461 qWarning("todo1");
462 OTodo to = todo( (*it) ); 462 OTodo to = todo( (*it) );
463 cache( to ); 463 cache( to );
464 ++it; 464 ++it;
465 465
466 for ( ; it != list.end(); ++it ) { 466 for ( ; it != list.end(); ++it ) {
467 qWarning("caching"); 467 qWarning("caching");
468 cache( todo( (*it) ) ); 468 cache( todo( (*it) ) );
469 } 469 }
470 return to; 470 return to;
471} 471}
472OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const { 472OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const {
473 qWarning("todo"); 473 qWarning("todo");
474 bool has = false; QDate da = QDate::currentDate(); 474 bool has = false; QDate da = QDate::currentDate();
475 has = date( da, item.data("DueDate") ); 475 has = date( da, item.data("DueDate") );
476 QStringList cats = QStringList::split(";", item.data("categories") ); 476 QStringList cats = QStringList::split(";", item.data("categories") );
477 477
478 OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(), 478 OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(),
479 cats, item.data("summary"), item.data("description"), 479 cats, item.data("summary"), item.data("description"),
480 item.data("progress").toUShort(), has, da, 480 item.data("progress").toUShort(), has, da,
481 item.data("uid").toInt() ); 481 item.data("uid").toInt() );
482 return to; 482 return to;
483} 483}
484OTodo OTodoAccessBackendSQL::todo( int uid )const { 484OTodo OTodoAccessBackendSQL::todo( int uid )const {
485 FindQuery find( uid ); 485 FindQuery find( uid );
486 return todo( m_driver->query(&find) ); 486 return todo( m_driver->query(&find) );
487} 487}
488/* 488/*
489 * update the dict 489 * update the dict
490 */ 490 */
491void OTodoAccessBackendSQL::fillDict() { 491void OTodoAccessBackendSQL::fillDict() {
492 /* initialize dict */ 492 /* initialize dict */
493 /* 493 /*
494 * UPDATE dict if you change anything!!! 494 * UPDATE dict if you change anything!!!
495 */ 495 */
496 m_dict.setAutoDelete( TRUE ); 496 m_dict.setAutoDelete( TRUE );
497 m_dict.insert("Categories" , new int(OTodo::Category) ); 497 m_dict.insert("Categories" , new int(OTodo::Category) );
498 m_dict.insert("Uid" , new int(OTodo::Uid) ); 498 m_dict.insert("Uid" , new int(OTodo::Uid) );
499 m_dict.insert("HasDate" , new int(OTodo::HasDate) ); 499 m_dict.insert("HasDate" , new int(OTodo::HasDate) );
500 m_dict.insert("Completed" , new int(OTodo::Completed) ); 500 m_dict.insert("Completed" , new int(OTodo::Completed) );
501 m_dict.insert("Description" , new int(OTodo::Description) ); 501 m_dict.insert("Description" , new int(OTodo::Description) );
502 m_dict.insert("Summary" , new int(OTodo::Summary) ); 502 m_dict.insert("Summary" , new int(OTodo::Summary) );
503 m_dict.insert("Priority" , new int(OTodo::Priority) ); 503 m_dict.insert("Priority" , new int(OTodo::Priority) );
504 m_dict.insert("DateDay" , new int(OTodo::DateDay) ); 504 m_dict.insert("DateDay" , new int(OTodo::DateDay) );
505 m_dict.insert("DateMonth" , new int(OTodo::DateMonth) ); 505 m_dict.insert("DateMonth" , new int(OTodo::DateMonth) );
506 m_dict.insert("DateYear" , new int(OTodo::DateYear) ); 506 m_dict.insert("DateYear" , new int(OTodo::DateYear) );
507 m_dict.insert("Progress" , new int(OTodo::Progress) ); 507 m_dict.insert("Progress" , new int(OTodo::Progress) );
508 m_dict.insert("Completed", new int(OTodo::Completed) ); 508 m_dict.insert("Completed", new int(OTodo::Completed) );
509 m_dict.insert("CrossReference", new int(OTodo::CrossReference) ); 509 m_dict.insert("CrossReference", new int(OTodo::CrossReference) );
510 m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) ); 510 m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) );
511 m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) ); 511 m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) );
512} 512}
513/* 513/*
514 * need to be const so let's fool the 514 * need to be const so let's fool the
515 * compiler :( 515 * compiler :(
516 */ 516 */
517void OTodoAccessBackendSQL::update()const { 517void OTodoAccessBackendSQL::update()const {
518 ((OTodoAccessBackendSQL*)this)->m_dirty = false; 518 ((OTodoAccessBackendSQL*)this)->m_dirty = false;
519 LoadQuery lo; 519 LoadQuery lo;
520 OSQLResult res = m_driver->query(&lo); 520 OSQLResult res = m_driver->query(&lo);
521 if ( res.state() != OSQLResult::Success ) 521 if ( res.state() != OSQLResult::Success )
522 return; 522 return;
523 523
524 ((OTodoAccessBackendSQL*)this)->m_uids = uids( res ); 524 ((OTodoAccessBackendSQL*)this)->m_uids = uids( res );
525} 525}
526QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{ 526QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{
527 527
528 OSQLResultItem::ValueList list = res.results(); 528 OSQLResultItem::ValueList list = res.results();
529 OSQLResultItem::ValueList::Iterator it; 529 OSQLResultItem::ValueList::Iterator it;
530 QArray<int> ints(list.count() ); 530 QArray<int> ints(list.count() );
531 qWarning(" count = %d", list.count() ); 531 qWarning(" count = %d", list.count() );
532 532
533 int i = 0; 533 int i = 0;
534 for (it = list.begin(); it != list.end(); ++it ) { 534 for (it = list.begin(); it != list.end(); ++it ) {
535 ints[i] = (*it).data("uid").toInt(); 535 ints[i] = (*it).data("uid").toInt();
536 i++; 536 i++;
537 } 537 }
538 return ints; 538 return ints;
539} 539}
540 540
diff --git a/libopie/pim/otodoaccesssql.h b/libopie/pim/otodoaccesssql.h
index 0f6dd2c..6a4257c 100644
--- a/libopie/pim/otodoaccesssql.h
+++ b/libopie/pim/otodoaccesssql.h
@@ -1,50 +1,50 @@
1#ifndef OPIE_PIM_ACCESS_SQL_H 1#ifndef OPIE_PIM_ACCESS_SQL_H
2#define OPIE_PIM_ACCESS_SQL_H 2#define OPIE_PIM_ACCESS_SQL_H
3 3
4#include <qasciidict.h> 4#include <qasciidict.h>
5 5
6#include "otodoaccessbackend.h" 6#include "otodoaccessbackend.h"
7 7
8class OSQLDriver; 8class OSQLDriver;
9class OSQLResult; 9class OSQLResult;
10class OSQLResultItem; 10class OSQLResultItem;
11class OTodoAccessBackendSQL : public OTodoAccessBackend { 11class OTodoAccessBackendSQL : public OTodoAccessBackend {
12public: 12public:
13 OTodoAccessBackendSQL( const QString& file ); 13 OTodoAccessBackendSQL( const QString& file );
14 ~OTodoAccessBackendSQL(); 14 ~OTodoAccessBackendSQL();
15 15
16 bool load(); 16 bool load();
17 bool reload(); 17 bool reload();
18 bool save(); 18 bool save();
19 QArray<int> allRecords()const; 19 QArray<int> allRecords()const;
20 20
21 QArray<int> queryByExample( const OTodo& t, int sort ); 21 QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() );
22 OTodo find(int uid)const; 22 OTodo find(int uid)const;
23 OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; 23 OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const;
24 void clear(); 24 void clear();
25 bool add( const OTodo& t ); 25 bool add( const OTodo& t );
26 bool remove( int uid ); 26 bool remove( int uid );
27 bool replace( const OTodo& t ); 27 bool replace( const OTodo& t );
28 28
29 QArray<int> overDue(); 29 QArray<int> overDue();
30 QArray<int> effectiveToDos( const QDate& start, 30 QArray<int> effectiveToDos( const QDate& start,
31 const QDate& end, bool includeNoDates ); 31 const QDate& end, bool includeNoDates );
32 QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); 32 QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat );
33 33
34private: 34private:
35 void update()const; 35 void update()const;
36 void fillDict(); 36 void fillDict();
37 inline bool date( QDate& date, const QString& )const; 37 inline bool date( QDate& date, const QString& )const;
38 inline OTodo todo( const OSQLResult& )const; 38 inline OTodo todo( const OSQLResult& )const;
39 inline OTodo todo( OSQLResultItem& )const; 39 inline OTodo todo( OSQLResultItem& )const;
40 inline QArray<int> uids( const OSQLResult& )const; 40 inline QArray<int> uids( const OSQLResult& )const;
41 OTodo todo( int uid )const; 41 OTodo todo( int uid )const;
42 42
43 QAsciiDict<int> m_dict; 43 QAsciiDict<int> m_dict;
44 OSQLDriver* m_driver; 44 OSQLDriver* m_driver;
45 QArray<int> m_uids; 45 QArray<int> m_uids;
46 bool m_dirty : 1; 46 bool m_dirty : 1;
47}; 47};
48 48
49 49
50#endif 50#endif
diff --git a/libopie/pim/otodoaccessvcal.cpp b/libopie/pim/otodoaccessvcal.cpp
index 309f9e1..2136283 100644
--- a/libopie/pim/otodoaccessvcal.cpp
+++ b/libopie/pim/otodoaccessvcal.cpp
@@ -1,201 +1,201 @@
1#include <qfile.h> 1#include <qfile.h>
2 2
3#include <qtopia/private/vobject_p.h> 3#include <qtopia/private/vobject_p.h>
4#include <qtopia/timeconversion.h> 4#include <qtopia/timeconversion.h>
5#include <qtopia/private/qfiledirect_p.h> 5#include <qtopia/private/qfiledirect_p.h>
6 6
7#include "otodoaccessvcal.h" 7#include "otodoaccessvcal.h"
8 8
9namespace { 9namespace {
10 static OTodo eventByVObj( VObject *obj ){ 10 static OTodo eventByVObj( VObject *obj ){
11 OTodo event; 11 OTodo event;
12 VObject *ob; 12 VObject *ob;
13 QCString name; 13 QCString name;
14 // no uid, attendees, ... and no fun 14 // no uid, attendees, ... and no fun
15 // description 15 // description
16 if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){ 16 if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){
17 name = vObjectStringZValue( ob ); 17 name = vObjectStringZValue( ob );
18 event.setDescription( name ); 18 event.setDescription( name );
19 } 19 }
20 // summary 20 // summary
21 if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) { 21 if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) {
22 name = vObjectStringZValue( ob ); 22 name = vObjectStringZValue( ob );
23 event.setSummary( name ); 23 event.setSummary( name );
24 } 24 }
25 // completed 25 // completed
26 if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){ 26 if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){
27 name = vObjectStringZValue( ob ); 27 name = vObjectStringZValue( ob );
28 if( name == "COMPLETED" ){ 28 if( name == "COMPLETED" ){
29 event.setCompleted( true ); 29 event.setCompleted( true );
30 }else{ 30 }else{
31 event.setCompleted( false ); 31 event.setCompleted( false );
32 } 32 }
33 }else 33 }else
34 event.setCompleted( false ); 34 event.setCompleted( false );
35 // priority 35 // priority
36 if ((ob = isAPropertyOf(obj, VCPriorityProp))) { 36 if ((ob = isAPropertyOf(obj, VCPriorityProp))) {
37 name = vObjectStringZValue( ob ); 37 name = vObjectStringZValue( ob );
38 bool ok; 38 bool ok;
39 event.setPriority(name.toInt(&ok) ); 39 event.setPriority(name.toInt(&ok) );
40 } 40 }
41 //due date 41 //due date
42 if((ob = isAPropertyOf(obj, VCDueProp)) ){ 42 if((ob = isAPropertyOf(obj, VCDueProp)) ){
43 event.setHasDueDate( true ); 43 event.setHasDueDate( true );
44 name = vObjectStringZValue( ob ); 44 name = vObjectStringZValue( ob );
45 event.setDueDate( TimeConversion::fromISO8601( name).date() ); 45 event.setDueDate( TimeConversion::fromISO8601( name).date() );
46 } 46 }
47 // categories 47 // categories
48 if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){ 48 if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){
49 name = vObjectStringZValue( ob ); 49 name = vObjectStringZValue( ob );
50 qWarning("Categories:%s", name.data() ); 50 qWarning("Categories:%s", name.data() );
51 } 51 }
52 52
53 event.setUid( 1 ); 53 event.setUid( 1 );
54 return event; 54 return event;
55 }; 55 };
56 static VObject *vobjByEvent( const OTodo &event ) { 56 static VObject *vobjByEvent( const OTodo &event ) {
57 VObject *task = newVObject( VCTodoProp ); 57 VObject *task = newVObject( VCTodoProp );
58 if( task == 0 ) 58 if( task == 0 )
59 return 0l; 59 return 0l;
60 60
61 if( event.hasDueDate() ) { 61 if( event.hasDueDate() ) {
62 QTime time(0, 0, 0); 62 QTime time(0, 0, 0);
63 QDateTime date(event.dueDate(), time ); 63 QDateTime date(event.dueDate(), time );
64 addPropValue( task, VCDueProp, 64 addPropValue( task, VCDueProp,
65 TimeConversion::toISO8601( date ) ); 65 TimeConversion::toISO8601( date ) );
66 } 66 }
67 67
68 if( event.isCompleted() ) 68 if( event.isCompleted() )
69 addPropValue( task, VCStatusProp, "COMPLETED"); 69 addPropValue( task, VCStatusProp, "COMPLETED");
70 70
71 QString string = QString::number(event.priority() ); 71 QString string = QString::number(event.priority() );
72 addPropValue( task, VCPriorityProp, string.local8Bit() ); 72 addPropValue( task, VCPriorityProp, string.local8Bit() );
73 73
74 addPropValue( task, VCCategoriesProp, 74 addPropValue( task, VCCategoriesProp,
75 event.idsToString( event.categories() ).local8Bit() ); 75 event.idsToString( event.categories() ).local8Bit() );
76 76
77 addPropValue( task, VCDescriptionProp, 77 addPropValue( task, VCDescriptionProp,
78 event.description().local8Bit() ); 78 event.description().local8Bit() );
79 79
80 addPropValue( task, VCSummaryProp, 80 addPropValue( task, VCSummaryProp,
81 event.summary().local8Bit() ); 81 event.summary().local8Bit() );
82 return task; 82 return task;
83}; 83};
84} 84}
85 85
86OTodoAccessVCal::OTodoAccessVCal( const QString& path ) 86OTodoAccessVCal::OTodoAccessVCal( const QString& path )
87 : m_dirty(false), m_file( path ) 87 : m_dirty(false), m_file( path )
88{ 88{
89} 89}
90OTodoAccessVCal::~OTodoAccessVCal() { 90OTodoAccessVCal::~OTodoAccessVCal() {
91} 91}
92bool OTodoAccessVCal::load() { 92bool OTodoAccessVCal::load() {
93 m_map.clear(); 93 m_map.clear();
94 m_dirty = false; 94 m_dirty = false;
95 95
96 VObject* vcal = 0l; 96 VObject* vcal = 0l;
97 vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); 97 vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() );
98 if (!vcal ) 98 if (!vcal )
99 return false; 99 return false;
100 100
101 // Iterate over the list 101 // Iterate over the list
102 VObjectIterator it; 102 VObjectIterator it;
103 VObject* vobj; 103 VObject* vobj;
104 104
105 initPropIterator(&it, vcal); 105 initPropIterator(&it, vcal);
106 106
107 while( moreIteration( &it ) ) { 107 while( moreIteration( &it ) ) {
108 vobj = ::nextVObject( &it ); 108 vobj = ::nextVObject( &it );
109 QCString name = ::vObjectName( vobj ); 109 QCString name = ::vObjectName( vobj );
110 if( name == VCTodoProp ){ 110 if( name == VCTodoProp ){
111 OTodo to = eventByVObj( vobj ); 111 OTodo to = eventByVObj( vobj );
112 m_map.insert( to.uid(), to ); 112 m_map.insert( to.uid(), to );
113 } 113 }
114 } 114 }
115 115
116 // Should I do a delete vcal? 116 // Should I do a delete vcal?
117 117
118 return true; 118 return true;
119} 119}
120bool OTodoAccessVCal::reload() { 120bool OTodoAccessVCal::reload() {
121 return load(); 121 return load();
122} 122}
123bool OTodoAccessVCal::save() { 123bool OTodoAccessVCal::save() {
124 if (!m_dirty ) 124 if (!m_dirty )
125 return true; 125 return true;
126 126
127 QFileDirect file( m_file ); 127 QFileDirect file( m_file );
128 if (!file.open(IO_WriteOnly ) ) 128 if (!file.open(IO_WriteOnly ) )
129 return false; 129 return false;
130 130
131 VObject *obj; 131 VObject *obj;
132 obj = newVObject( VCCalProp ); 132 obj = newVObject( VCCalProp );
133 addPropValue( obj, VCVersionProp, "1.0" ); 133 addPropValue( obj, VCVersionProp, "1.0" );
134 VObject *vo; 134 VObject *vo;
135 for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ 135 for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){
136 vo = vobjByEvent( it.data() ); 136 vo = vobjByEvent( it.data() );
137 addVObjectProp(obj, vo ); 137 addVObjectProp(obj, vo );
138 } 138 }
139 writeVObject( file.directHandle(), obj ); 139 writeVObject( file.directHandle(), obj );
140 cleanVObject( obj ); 140 cleanVObject( obj );
141 cleanStrTbl(); 141 cleanStrTbl();
142 142
143 m_dirty = false; 143 m_dirty = false;
144 return true; 144 return true;
145} 145}
146void OTodoAccessVCal::clear() { 146void OTodoAccessVCal::clear() {
147 m_map.clear(); 147 m_map.clear();
148 m_dirty = true; 148 m_dirty = true;
149} 149}
150bool OTodoAccessVCal::add( const OTodo& to ) { 150bool OTodoAccessVCal::add( const OTodo& to ) {
151 m_map.insert( to.uid(), to ); 151 m_map.insert( to.uid(), to );
152 m_dirty = true; 152 m_dirty = true;
153 return true; 153 return true;
154} 154}
155bool OTodoAccessVCal::remove( int uid ) { 155bool OTodoAccessVCal::remove( int uid ) {
156 m_map.remove( uid ); 156 m_map.remove( uid );
157 m_dirty = true; 157 m_dirty = true;
158 return true; 158 return true;
159} 159}
160void OTodoAccessVCal::removeAllCompleted() { 160void OTodoAccessVCal::removeAllCompleted() {
161 for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) { 161 for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) {
162 if ( (*it).isCompleted() ) 162 if ( (*it).isCompleted() )
163 m_map.remove( it ); 163 m_map.remove( it );
164 } 164 }
165} 165}
166bool OTodoAccessVCal::replace( const OTodo& to ) { 166bool OTodoAccessVCal::replace( const OTodo& to ) {
167 m_map.replace( to.uid(), to ); 167 m_map.replace( to.uid(), to );
168 m_dirty = true; 168 m_dirty = true;
169 return true; 169 return true;
170} 170}
171OTodo OTodoAccessVCal::find(int uid )const { 171OTodo OTodoAccessVCal::find(int uid )const {
172 return m_map[uid]; 172 return m_map[uid];
173} 173}
174QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) { 174QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) {
175 QArray<int> ar(0); 175 QArray<int> ar(0);
176 return ar; 176 return ar;
177} 177}
178QArray<int> OTodoAccessVCal::allRecords()const { 178QArray<int> OTodoAccessVCal::allRecords()const {
179 QArray<int> ar( m_map.count() ); 179 QArray<int> ar( m_map.count() );
180 QMap<int, OTodo>::ConstIterator it; 180 QMap<int, OTodo>::ConstIterator it;
181 int i = 0; 181 int i = 0;
182 for ( it = m_map.begin(); it != m_map.end(); ++it ) { 182 for ( it = m_map.begin(); it != m_map.end(); ++it ) {
183 ar[i] = it.key(); 183 ar[i] = it.key();
184 i++; 184 i++;
185 } 185 }
186 return ar; 186 return ar;
187} 187}
188QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int ) { 188QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) {
189 QArray<int> ar(0); 189 QArray<int> ar(0);
190 return ar; 190 return ar;
191} 191}
192QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& , 192QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& ,
193 const QDate& , 193 const QDate& ,
194 bool ) { 194 bool ) {
195 QArray<int> ar(0); 195 QArray<int> ar(0);
196 return ar; 196 return ar;
197} 197}
198QArray<int> OTodoAccessVCal::overDue() { 198QArray<int> OTodoAccessVCal::overDue() {
199 QArray<int> ar(0); 199 QArray<int> ar(0);
200 return ar; 200 return ar;
201} 201}
diff --git a/libopie/pim/otodoaccessvcal.h b/libopie/pim/otodoaccessvcal.h
index 452f602..a90ee9c 100644
--- a/libopie/pim/otodoaccessvcal.h
+++ b/libopie/pim/otodoaccessvcal.h
@@ -1,37 +1,37 @@
1#ifndef OPIE_OTODO_ACCESS_VCAL_H 1#ifndef OPIE_OTODO_ACCESS_VCAL_H
2#define OPIE_OTODO_ACCESS_VCAL_H 2#define OPIE_OTODO_ACCESS_VCAL_H
3 3
4#include "otodoaccessbackend.h" 4#include "otodoaccessbackend.h"
5 5
6class OTodoAccessVCal : public OTodoAccessBackend { 6class OTodoAccessVCal : public OTodoAccessBackend {
7public: 7public:
8 OTodoAccessVCal(const QString& ); 8 OTodoAccessVCal(const QString& );
9 ~OTodoAccessVCal(); 9 ~OTodoAccessVCal();
10 10
11 bool load(); 11 bool load();
12 bool reload(); 12 bool reload();
13 bool save(); 13 bool save();
14 14
15 QArray<int> allRecords()const; 15 QArray<int> allRecords()const;
16 QArray<int> queryByExample( const OTodo& t, int sort ); 16 QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() );
17 QArray<int> effectiveToDos( const QDate& start, 17 QArray<int> effectiveToDos( const QDate& start,
18 const QDate& end, 18 const QDate& end,
19 bool includeNoDates ); 19 bool includeNoDates );
20 QArray<int> overDue(); 20 QArray<int> overDue();
21 QArray<int> sorted( bool asc, int sortOrder, int sortFilter, 21 QArray<int> sorted( bool asc, int sortOrder, int sortFilter,
22 int cat ); 22 int cat );
23 OTodo find(int uid)const; 23 OTodo find(int uid)const;
24 void clear(); 24 void clear();
25 bool add( const OTodo& ); 25 bool add( const OTodo& );
26 bool remove( int uid ); 26 bool remove( int uid );
27 bool replace( const OTodo& ); 27 bool replace( const OTodo& );
28 28
29 void removeAllCompleted(); 29 void removeAllCompleted();
30 30
31private: 31private:
32 bool m_dirty : 1; 32 bool m_dirty : 1;
33 QString m_file; 33 QString m_file;
34 QMap<int, OTodo> m_map; 34 QMap<int, OTodo> m_map;
35}; 35};
36 36
37#endif 37#endif
diff --git a/libopie/pim/otodoaccessxml.cpp b/libopie/pim/otodoaccessxml.cpp
index cda300b..71e8787 100644
--- a/libopie/pim/otodoaccessxml.cpp
+++ b/libopie/pim/otodoaccessxml.cpp
@@ -1,675 +1,675 @@
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 "otodoaccessxml.h" 18#include "otodoaccessxml.h"
19 19
20namespace { 20namespace {
21 // FROM TT again 21 // FROM TT again
22char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) 22char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
23{ 23{
24 char needleChar; 24 char needleChar;
25 char haystackChar; 25 char haystackChar;
26 if (!needle || !haystack || !hLen || !nLen) 26 if (!needle || !haystack || !hLen || !nLen)
27 return 0; 27 return 0;
28 28
29 const char* hsearch = haystack; 29 const char* hsearch = haystack;
30 30
31 if ((needleChar = *needle++) != 0) { 31 if ((needleChar = *needle++) != 0) {
32 nLen--; //(to make up for needle++) 32 nLen--; //(to make up for needle++)
33 do { 33 do {
34 do { 34 do {
35 if ((haystackChar = *hsearch++) == 0) 35 if ((haystackChar = *hsearch++) == 0)
36 return (0); 36 return (0);
37 if (hsearch >= haystack + hLen) 37 if (hsearch >= haystack + hLen)
38 return (0); 38 return (0);
39 } while (haystackChar != needleChar); 39 } while (haystackChar != needleChar);
40 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); 40 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
41 hsearch--; 41 hsearch--;
42 } 42 }
43 return ((char *)hsearch); 43 return ((char *)hsearch);
44} 44}
45} 45}
46 46
47 47
48OTodoAccessXML::OTodoAccessXML( const QString& appName, 48OTodoAccessXML::OTodoAccessXML( const QString& appName,
49 const QString& fileName ) 49 const QString& fileName )
50 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) 50 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false )
51{ 51{
52 if (!fileName.isEmpty() ) 52 if (!fileName.isEmpty() )
53 m_file = fileName; 53 m_file = fileName;
54 else 54 else
55 m_file = Global::applicationFileName( "todolist", "todolist.xml" ); 55 m_file = Global::applicationFileName( "todolist", "todolist.xml" );
56} 56}
57OTodoAccessXML::~OTodoAccessXML() { 57OTodoAccessXML::~OTodoAccessXML() {
58 58
59} 59}
60bool OTodoAccessXML::load() { 60bool OTodoAccessXML::load() {
61 m_opened = true; 61 m_opened = true;
62 m_changed = false; 62 m_changed = false;
63 /* initialize dict */ 63 /* initialize dict */
64 /* 64 /*
65 * UPDATE dict if you change anything!!! 65 * UPDATE dict if you change anything!!!
66 */ 66 */
67 QAsciiDict<int> dict(21); 67 QAsciiDict<int> dict(21);
68 dict.setAutoDelete( TRUE ); 68 dict.setAutoDelete( TRUE );
69 dict.insert("Categories" , new int(OTodo::Category) ); 69 dict.insert("Categories" , new int(OTodo::Category) );
70 dict.insert("Uid" , new int(OTodo::Uid) ); 70 dict.insert("Uid" , new int(OTodo::Uid) );
71 dict.insert("HasDate" , new int(OTodo::HasDate) ); 71 dict.insert("HasDate" , new int(OTodo::HasDate) );
72 dict.insert("Completed" , new int(OTodo::Completed) ); 72 dict.insert("Completed" , new int(OTodo::Completed) );
73 dict.insert("Description" , new int(OTodo::Description) ); 73 dict.insert("Description" , new int(OTodo::Description) );
74 dict.insert("Summary" , new int(OTodo::Summary) ); 74 dict.insert("Summary" , new int(OTodo::Summary) );
75 dict.insert("Priority" , new int(OTodo::Priority) ); 75 dict.insert("Priority" , new int(OTodo::Priority) );
76 dict.insert("DateDay" , new int(OTodo::DateDay) ); 76 dict.insert("DateDay" , new int(OTodo::DateDay) );
77 dict.insert("DateMonth" , new int(OTodo::DateMonth) ); 77 dict.insert("DateMonth" , new int(OTodo::DateMonth) );
78 dict.insert("DateYear" , new int(OTodo::DateYear) ); 78 dict.insert("DateYear" , new int(OTodo::DateYear) );
79 dict.insert("Progress" , new int(OTodo::Progress) ); 79 dict.insert("Progress" , new int(OTodo::Progress) );
80 dict.insert("Completed", new int(OTodo::Completed) ); 80 dict.insert("Completed", new int(OTodo::Completed) );
81 dict.insert("CrossReference", new int(OTodo::CrossReference) ); 81 dict.insert("CrossReference", new int(OTodo::CrossReference) );
82 dict.insert("State", new int(OTodo::State) ); 82 dict.insert("State", new int(OTodo::State) );
83 dict.insert("Recurrence", new int(OTodo::Recurrence) ); 83 dict.insert("Recurrence", new int(OTodo::Recurrence) );
84 dict.insert("Alarms", new int(OTodo::Alarms) ); 84 dict.insert("Alarms", new int(OTodo::Alarms) );
85 dict.insert("Reminders", new int(OTodo::Reminders) ); 85 dict.insert("Reminders", new int(OTodo::Reminders) );
86 dict.insert("Notifiers", new int(OTodo::Notifiers) ); 86 dict.insert("Notifiers", new int(OTodo::Notifiers) );
87 dict.insert("Maintainer", new int(OTodo::Maintainer) ); 87 dict.insert("Maintainer", new int(OTodo::Maintainer) );
88 88
89 // here the custom XML parser from TT it's GPL 89 // here the custom XML parser from TT it's GPL
90 // but we want to push OpiePIM... to TT..... 90 // but we want to push OpiePIM... to TT.....
91 // mmap part from zecke :) 91 // mmap part from zecke :)
92 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); 92 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY );
93 struct stat attribut; 93 struct stat attribut;
94 if ( fd < 0 ) return false; 94 if ( fd < 0 ) return false;
95 95
96 if ( fstat(fd, &attribut ) == -1 ) { 96 if ( fstat(fd, &attribut ) == -1 ) {
97 ::close( fd ); 97 ::close( fd );
98 return false; 98 return false;
99 } 99 }
100 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); 100 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 );
101 if ( map_addr == ( (caddr_t)-1) ) { 101 if ( map_addr == ( (caddr_t)-1) ) {
102 ::close(fd ); 102 ::close(fd );
103 return false; 103 return false;
104 } 104 }
105 /* advise the kernel who we want to read it */ 105 /* advise the kernel who we want to read it */
106 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); 106 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL );
107 /* we do not the file any more */ 107 /* we do not the file any more */
108 ::close( fd ); 108 ::close( fd );
109 109
110 char* dt = (char*)map_addr; 110 char* dt = (char*)map_addr;
111 int len = attribut.st_size; 111 int len = attribut.st_size;
112 int i = 0; 112 int i = 0;
113 char *point; 113 char *point;
114 const char* collectionString = "<Task "; 114 const char* collectionString = "<Task ";
115 int strLen = strlen(collectionString); 115 int strLen = strlen(collectionString);
116 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { 116 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) {
117 i = point -dt; 117 i = point -dt;
118 i+= strLen; 118 i+= strLen;
119 qWarning("Found a start at %d %d", i, (point-dt) ); 119 qWarning("Found a start at %d %d", i, (point-dt) );
120 120
121 OTodo ev; 121 OTodo ev;
122 m_year = m_month = m_day = 0; 122 m_year = m_month = m_day = 0;
123 123
124 while ( TRUE ) { 124 while ( TRUE ) {
125 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) 125 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
126 ++i; 126 ++i;
127 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) 127 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
128 break; 128 break;
129 129
130 // we have another attribute, read it. 130 // we have another attribute, read it.
131 int j = i; 131 int j = i;
132 while ( j < len && dt[j] != '=' ) 132 while ( j < len && dt[j] != '=' )
133 ++j; 133 ++j;
134 QCString attr( dt+i, j-i+1); 134 QCString attr( dt+i, j-i+1);
135 135
136 i = ++j; // skip = 136 i = ++j; // skip =
137 137
138 // find the start of quotes 138 // find the start of quotes
139 while ( i < len && dt[i] != '"' ) 139 while ( i < len && dt[i] != '"' )
140 ++i; 140 ++i;
141 j = ++i; 141 j = ++i;
142 142
143 bool haveUtf = FALSE; 143 bool haveUtf = FALSE;
144 bool haveEnt = FALSE; 144 bool haveEnt = FALSE;
145 while ( j < len && dt[j] != '"' ) { 145 while ( j < len && dt[j] != '"' ) {
146 if ( ((unsigned char)dt[j]) > 0x7f ) 146 if ( ((unsigned char)dt[j]) > 0x7f )
147 haveUtf = TRUE; 147 haveUtf = TRUE;
148 if ( dt[j] == '&' ) 148 if ( dt[j] == '&' )
149 haveEnt = TRUE; 149 haveEnt = TRUE;
150 ++j; 150 ++j;
151 } 151 }
152 if ( i == j ) { 152 if ( i == j ) {
153 // empty value 153 // empty value
154 i = j + 1; 154 i = j + 1;
155 continue; 155 continue;
156 } 156 }
157 157
158 QCString value( dt+i, j-i+1 ); 158 QCString value( dt+i, j-i+1 );
159 i = j + 1; 159 i = j + 1;
160 160
161 QString str = (haveUtf ? QString::fromUtf8( value ) 161 QString str = (haveUtf ? QString::fromUtf8( value )
162 : QString::fromLatin1( value ) ); 162 : QString::fromLatin1( value ) );
163 if ( haveEnt ) 163 if ( haveEnt )
164 str = Qtopia::plainString( str ); 164 str = Qtopia::plainString( str );
165 165
166 /* 166 /*
167 * add key + value 167 * add key + value
168 */ 168 */
169 todo( &dict, ev, attr, str ); 169 todo( &dict, ev, attr, str );
170 170
171 } 171 }
172 /* 172 /*
173 * now add it 173 * now add it
174 */ 174 */
175 qWarning("End at %d", i ); 175 qWarning("End at %d", i );
176 if (m_events.contains( ev.uid() ) || ev.uid() == 0) { 176 if (m_events.contains( ev.uid() ) || ev.uid() == 0) {
177 ev.setUid( 1 ); 177 ev.setUid( 1 );
178 m_changed = true; 178 m_changed = true;
179 } 179 }
180 if ( ev.hasDueDate() ) { 180 if ( ev.hasDueDate() ) {
181 ev.setDueDate( QDate(m_year, m_month, m_day) ); 181 ev.setDueDate( QDate(m_year, m_month, m_day) );
182 } 182 }
183 m_events.insert(ev.uid(), ev ); 183 m_events.insert(ev.uid(), ev );
184 m_year = m_month = m_day = -1; 184 m_year = m_month = m_day = -1;
185 } 185 }
186 186
187 munmap(map_addr, attribut.st_size ); 187 munmap(map_addr, attribut.st_size );
188 188
189 qWarning("counts %d records loaded!", m_events.count() ); 189 qWarning("counts %d records loaded!", m_events.count() );
190 return true; 190 return true;
191} 191}
192bool OTodoAccessXML::reload() { 192bool OTodoAccessXML::reload() {
193 m_events.clear(); 193 m_events.clear();
194 return load(); 194 return load();
195} 195}
196bool OTodoAccessXML::save() { 196bool OTodoAccessXML::save() {
197// qWarning("saving"); 197// qWarning("saving");
198 if (!m_opened || !m_changed ) { 198 if (!m_opened || !m_changed ) {
199// qWarning("not saving"); 199// qWarning("not saving");
200 return true; 200 return true;
201 } 201 }
202 QString strNewFile = m_file + ".new"; 202 QString strNewFile = m_file + ".new";
203 QFile f( strNewFile ); 203 QFile f( strNewFile );
204 if (!f.open( IO_WriteOnly|IO_Raw ) ) 204 if (!f.open( IO_WriteOnly|IO_Raw ) )
205 return false; 205 return false;
206 206
207 int written; 207 int written;
208 QString out; 208 QString out;
209 out = "<!DOCTYPE Tasks>\n<Tasks>\n"; 209 out = "<!DOCTYPE Tasks>\n<Tasks>\n";
210 210
211 // for all todos 211 // for all todos
212 QMap<int, OTodo>::Iterator it; 212 QMap<int, OTodo>::Iterator it;
213 for (it = m_events.begin(); it != m_events.end(); ++it ) { 213 for (it = m_events.begin(); it != m_events.end(); ++it ) {
214 out+= "<Task " + toString( (*it) ) + " />\n"; 214 out+= "<Task " + toString( (*it) ) + " />\n";
215 QCString cstr = out.utf8(); 215 QCString cstr = out.utf8();
216 written = f.writeBlock( cstr.data(), cstr.length() ); 216 written = f.writeBlock( cstr.data(), cstr.length() );
217 217
218 /* less written then we wanted */ 218 /* less written then we wanted */
219 if ( written != (int)cstr.length() ) { 219 if ( written != (int)cstr.length() ) {
220 f.close(); 220 f.close();
221 QFile::remove( strNewFile ); 221 QFile::remove( strNewFile );
222 return false; 222 return false;
223 } 223 }
224 out = QString::null; 224 out = QString::null;
225 } 225 }
226 226
227 out += "</Tasks>"; 227 out += "</Tasks>";
228 QCString cstr = out.utf8(); 228 QCString cstr = out.utf8();
229 written = f.writeBlock( cstr.data(), cstr.length() ); 229 written = f.writeBlock( cstr.data(), cstr.length() );
230 230
231 if ( written != (int)cstr.length() ) { 231 if ( written != (int)cstr.length() ) {
232 f.close(); 232 f.close();
233 QFile::remove( strNewFile ); 233 QFile::remove( strNewFile );
234 return false; 234 return false;
235 } 235 }
236 /* flush before renaming */ 236 /* flush before renaming */
237 f.close(); 237 f.close();
238 238
239 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { 239 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) {
240// qWarning("error renaming"); 240// qWarning("error renaming");
241 QFile::remove( strNewFile ); 241 QFile::remove( strNewFile );
242 } 242 }
243 243
244 m_changed = false; 244 m_changed = false;
245 return true; 245 return true;
246} 246}
247QArray<int> OTodoAccessXML::allRecords()const { 247QArray<int> OTodoAccessXML::allRecords()const {
248 QArray<int> ids( m_events.count() ); 248 QArray<int> ids( m_events.count() );
249 QMap<int, OTodo>::ConstIterator it; 249 QMap<int, OTodo>::ConstIterator it;
250 int i = 0; 250 int i = 0;
251 251
252 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 252 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
253 ids[i] = it.key(); 253 ids[i] = it.key();
254 i++; 254 i++;
255 } 255 }
256 return ids; 256 return ids;
257} 257}
258QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int ) { 258QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) {
259 QArray<int> ids(0); 259 QArray<int> ids(0);
260 return ids; 260 return ids;
261} 261}
262OTodo OTodoAccessXML::find( int uid )const { 262OTodo OTodoAccessXML::find( int uid )const {
263 OTodo todo; 263 OTodo todo;
264 todo.setUid( 0 ); // isEmpty() 264 todo.setUid( 0 ); // isEmpty()
265 QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); 265 QMap<int, OTodo>::ConstIterator it = m_events.find( uid );
266 if ( it != m_events.end() ) 266 if ( it != m_events.end() )
267 todo = it.data(); 267 todo = it.data();
268 268
269 return todo; 269 return todo;
270} 270}
271void OTodoAccessXML::clear() { 271void OTodoAccessXML::clear() {
272 if (m_opened ) 272 if (m_opened )
273 m_changed = true; 273 m_changed = true;
274 274
275 m_events.clear(); 275 m_events.clear();
276} 276}
277bool OTodoAccessXML::add( const OTodo& todo ) { 277bool OTodoAccessXML::add( const OTodo& todo ) {
278// qWarning("add"); 278// qWarning("add");
279 m_changed = true; 279 m_changed = true;
280 m_events.insert( todo.uid(), todo ); 280 m_events.insert( todo.uid(), todo );
281 281
282 return true; 282 return true;
283} 283}
284bool OTodoAccessXML::remove( int uid ) { 284bool OTodoAccessXML::remove( int uid ) {
285 m_changed = true; 285 m_changed = true;
286 m_events.remove( uid ); 286 m_events.remove( uid );
287 287
288 return true; 288 return true;
289} 289}
290bool OTodoAccessXML::replace( const OTodo& todo) { 290bool OTodoAccessXML::replace( const OTodo& todo) {
291 m_changed = true; 291 m_changed = true;
292 m_events.replace( todo.uid(), todo ); 292 m_events.replace( todo.uid(), todo );
293 293
294 return true; 294 return true;
295} 295}
296QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, 296QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
297 const QDate& end, 297 const QDate& end,
298 bool includeNoDates ) { 298 bool includeNoDates ) {
299 QArray<int> ids( m_events.count() ); 299 QArray<int> ids( m_events.count() );
300 QMap<int, OTodo>::Iterator it; 300 QMap<int, OTodo>::Iterator it;
301 301
302 int i = 0; 302 int i = 0;
303 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 303 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
304 if ( !it.data().hasDueDate() ) { 304 if ( !it.data().hasDueDate() ) {
305 if ( includeNoDates ) { 305 if ( includeNoDates ) {
306 ids[i] = it.key(); 306 ids[i] = it.key();
307 i++; 307 i++;
308 } 308 }
309 }else if ( it.data().dueDate() >= start && 309 }else if ( it.data().dueDate() >= start &&
310 it.data().dueDate() <= end ) { 310 it.data().dueDate() <= end ) {
311 ids[i] = it.key(); 311 ids[i] = it.key();
312 i++; 312 i++;
313 } 313 }
314 } 314 }
315 ids.resize( i ); 315 ids.resize( i );
316 return ids; 316 return ids;
317} 317}
318QArray<int> OTodoAccessXML::overDue() { 318QArray<int> OTodoAccessXML::overDue() {
319 QArray<int> ids( m_events.count() ); 319 QArray<int> ids( m_events.count() );
320 int i = 0; 320 int i = 0;
321 321
322 QMap<int, OTodo>::Iterator it; 322 QMap<int, OTodo>::Iterator it;
323 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 323 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
324 if ( it.data().isOverdue() ) { 324 if ( it.data().isOverdue() ) {
325 ids[i] = it.key(); 325 ids[i] = it.key();
326 i++; 326 i++;
327 } 327 }
328 } 328 }
329 ids.resize( i ); 329 ids.resize( i );
330 return ids; 330 return ids;
331} 331}
332 332
333 333
334/* private */ 334/* private */
335void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, 335void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev,
336 const QCString& attr, const QString& val) { 336 const QCString& attr, const QString& val) {
337// qWarning("parse to do from XMLElement" ); 337// qWarning("parse to do from XMLElement" );
338 338
339 int *find=0; 339 int *find=0;
340 340
341 find = (*dict)[ attr.data() ]; 341 find = (*dict)[ attr.data() ];
342 if (!find ) { 342 if (!find ) {
343// qWarning("Unknown option" + it.key() ); 343// qWarning("Unknown option" + it.key() );
344 ev.setCustomField( attr, val ); 344 ev.setCustomField( attr, val );
345 return; 345 return;
346 } 346 }
347 347
348 switch( *find ) { 348 switch( *find ) {
349 case OTodo::Uid: 349 case OTodo::Uid:
350 ev.setUid( val.toInt() ); 350 ev.setUid( val.toInt() );
351 break; 351 break;
352 case OTodo::Category: 352 case OTodo::Category:
353 ev.setCategories( ev.idsFromString( val ) ); 353 ev.setCategories( ev.idsFromString( val ) );
354 break; 354 break;
355 case OTodo::HasDate: 355 case OTodo::HasDate:
356 ev.setHasDueDate( val.toInt() ); 356 ev.setHasDueDate( val.toInt() );
357 break; 357 break;
358 case OTodo::Completed: 358 case OTodo::Completed:
359 ev.setCompleted( val.toInt() ); 359 ev.setCompleted( val.toInt() );
360 break; 360 break;
361 case OTodo::Description: 361 case OTodo::Description:
362 ev.setDescription( val ); 362 ev.setDescription( val );
363 break; 363 break;
364 case OTodo::Summary: 364 case OTodo::Summary:
365 ev.setSummary( val ); 365 ev.setSummary( val );
366 break; 366 break;
367 case OTodo::Priority: 367 case OTodo::Priority:
368 ev.setPriority( val.toInt() ); 368 ev.setPriority( val.toInt() );
369 break; 369 break;
370 case OTodo::DateDay: 370 case OTodo::DateDay:
371 m_day = val.toInt(); 371 m_day = val.toInt();
372 break; 372 break;
373 case OTodo::DateMonth: 373 case OTodo::DateMonth:
374 m_month = val.toInt(); 374 m_month = val.toInt();
375 break; 375 break;
376 case OTodo::DateYear: 376 case OTodo::DateYear:
377 m_year = val.toInt(); 377 m_year = val.toInt();
378 break; 378 break;
379 case OTodo::Progress: 379 case OTodo::Progress:
380 ev.setProgress( val.toInt() ); 380 ev.setProgress( val.toInt() );
381 break; 381 break;
382 case OTodo::CrossReference: 382 case OTodo::CrossReference:
383 { 383 {
384 /* 384 /*
385 * A cross refernce looks like 385 * A cross refernce looks like
386 * appname,id;appname,id 386 * appname,id;appname,id
387 * we need to split it up 387 * we need to split it up
388 */ 388 */
389 QStringList refs = QStringList::split(';', val ); 389 QStringList refs = QStringList::split(';', val );
390 QStringList::Iterator strIt; 390 QStringList::Iterator strIt;
391 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { 391 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) {
392 int pos = (*strIt).find(','); 392 int pos = (*strIt).find(',');
393 if ( pos > -1 ) 393 if ( pos > -1 )
394 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); 394 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() );
395 395
396 } 396 }
397 break; 397 break;
398 } 398 }
399 default: 399 default:
400 break; 400 break;
401 } 401 }
402} 402}
403QString OTodoAccessXML::toString( const OTodo& ev )const { 403QString OTodoAccessXML::toString( const OTodo& ev )const {
404 QString str; 404 QString str;
405 405
406 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; 406 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" ";
407 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; 407 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" ";
408 str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; 408 str += "Priority=\"" + QString::number( ev.priority() ) + "\" ";
409 str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; 409 str += "Progress=\"" + QString::number(ev.progress() ) + "\" ";
410 410
411 str += "Categories=\"" + toString( ev.categories() ) + "\" "; 411 str += "Categories=\"" + toString( ev.categories() ) + "\" ";
412 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; 412 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" ";
413 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; 413 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" ";
414 414
415 if ( ev.hasDueDate() ) { 415 if ( ev.hasDueDate() ) {
416 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; 416 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" ";
417 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; 417 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" ";
418 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; 418 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" ";
419 } 419 }
420// qWarning( "Uid %d", ev.uid() ); 420// qWarning( "Uid %d", ev.uid() );
421 str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; 421 str += "Uid=\"" + QString::number( ev.uid() ) + "\" ";
422 422
423// append the extra options 423// append the extra options
424 /* FIXME Qtopia::Record this is currently not 424 /* FIXME Qtopia::Record this is currently not
425 * possible you can set custom fields 425 * possible you can set custom fields
426 * but don' iterate over the list 426 * but don' iterate over the list
427 * I may do #define private protected 427 * I may do #define private protected
428 * for this case - cough --zecke 428 * for this case - cough --zecke
429 */ 429 */
430 /* 430 /*
431 QMap<QString, QString> extras = ev.extras(); 431 QMap<QString, QString> extras = ev.extras();
432 QMap<QString, QString>::Iterator extIt; 432 QMap<QString, QString>::Iterator extIt;
433 for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) 433 for (extIt = extras.begin(); extIt != extras.end(); ++extIt )
434 str += extIt.key() + "=\"" + extIt.data() + "\" "; 434 str += extIt.key() + "=\"" + extIt.data() + "\" ";
435 */ 435 */
436 // cross refernce 436 // cross refernce
437 437
438 438
439 return str; 439 return str;
440} 440}
441QString OTodoAccessXML::toString( const QArray<int>& ints ) const { 441QString OTodoAccessXML::toString( const QArray<int>& ints ) const {
442 return Qtopia::Record::idsToString( ints ); 442 return Qtopia::Record::idsToString( ints );
443} 443}
444 444
445/* internal class for sorting 445/* internal class for sorting
446 * 446 *
447 * Inspired by todoxmlio.cpp from TT 447 * Inspired by todoxmlio.cpp from TT
448 */ 448 */
449 449
450struct OTodoXMLContainer { 450struct OTodoXMLContainer {
451 OTodo todo; 451 OTodo todo;
452}; 452};
453 453
454namespace { 454namespace {
455 inline QString string( const OTodo& todo) { 455 inline QString string( const OTodo& todo) {
456 return todo.summary().isEmpty() ? 456 return todo.summary().isEmpty() ?
457 todo.description().left(20 ) : 457 todo.description().left(20 ) :
458 todo.summary(); 458 todo.summary();
459 } 459 }
460 inline int completed( const OTodo& todo1, const OTodo& todo2) { 460 inline int completed( const OTodo& todo1, const OTodo& todo2) {
461 int ret = 0; 461 int ret = 0;
462 if ( todo1.isCompleted() ) ret++; 462 if ( todo1.isCompleted() ) ret++;
463 if ( todo2.isCompleted() ) ret--; 463 if ( todo2.isCompleted() ) ret--;
464 return ret; 464 return ret;
465 } 465 }
466 inline int priority( const OTodo& t1, const OTodo& t2) { 466 inline int priority( const OTodo& t1, const OTodo& t2) {
467 return ( t1.priority() - t2.priority() ); 467 return ( t1.priority() - t2.priority() );
468 } 468 }
469 inline int description( const OTodo& t1, const OTodo& t2) { 469 inline int description( const OTodo& t1, const OTodo& t2) {
470 return QString::compare( string(t1), string(t2) ); 470 return QString::compare( string(t1), string(t2) );
471 } 471 }
472 inline int deadline( const OTodo& t1, const OTodo& t2) { 472 inline int deadline( const OTodo& t1, const OTodo& t2) {
473 int ret = 0; 473 int ret = 0;
474 if ( t1.hasDueDate() && 474 if ( t1.hasDueDate() &&
475 t2.hasDueDate() ) 475 t2.hasDueDate() )
476 ret = t2.dueDate().daysTo( t1.dueDate() ); 476 ret = t2.dueDate().daysTo( t1.dueDate() );
477 else if ( t1.hasDueDate() ) 477 else if ( t1.hasDueDate() )
478 ret = -1; 478 ret = -1;
479 else if ( t2.hasDueDate() ) 479 else if ( t2.hasDueDate() )
480 ret = 1; 480 ret = 1;
481 else 481 else
482 ret = 0; 482 ret = 0;
483 483
484 return ret; 484 return ret;
485 } 485 }
486 486
487}; 487};
488 488
489/* 489/*
490 * Returns: 490 * Returns:
491 * 0 if item1 == item2 491 * 0 if item1 == item2
492 * 492 *
493 * non-zero if item1 != item2 493 * non-zero if item1 != item2
494 * 494 *
495 * This function returns int rather than bool so that reimplementations 495 * This function returns int rather than bool so that reimplementations
496 * can return one of three values and use it to sort by: 496 * can return one of three values and use it to sort by:
497 * 497 *
498 * 0 if item1 == item2 498 * 0 if item1 == item2
499 * 499 *
500 * > 0 (positive integer) if item1 > item2 500 * > 0 (positive integer) if item1 > item2
501 * 501 *
502 * < 0 (negative integer) if item1 < item2 502 * < 0 (negative integer) if item1 < item2
503 * 503 *
504 */ 504 */
505class OTodoXMLVector : public QVector<OTodoXMLContainer> { 505class OTodoXMLVector : public QVector<OTodoXMLContainer> {
506public: 506public:
507 OTodoXMLVector(int size, bool asc, int sort) 507 OTodoXMLVector(int size, bool asc, int sort)
508 : QVector<OTodoXMLContainer>( size ) 508 : QVector<OTodoXMLContainer>( size )
509 { 509 {
510 setAutoDelete( true ); 510 setAutoDelete( true );
511 m_asc = asc; 511 m_asc = asc;
512 m_sort = sort; 512 m_sort = sort;
513 } 513 }
514 /* return the summary/description */ 514 /* return the summary/description */
515 QString string( const OTodo& todo) { 515 QString string( const OTodo& todo) {
516 return todo.summary().isEmpty() ? 516 return todo.summary().isEmpty() ?
517 todo.description().left(20 ) : 517 todo.description().left(20 ) :
518 todo.summary(); 518 todo.summary();
519 } 519 }
520 /** 520 /**
521 * we take the sortorder( switch on it ) 521 * we take the sortorder( switch on it )
522 * 522 *
523 */ 523 */
524 int compareItems( Item d1, Item d2 ) { 524 int compareItems( Item d1, Item d2 ) {
525 bool seComp, sePrio, seDesc, seDeadline; 525 bool seComp, sePrio, seDesc, seDeadline;
526 seComp = sePrio = seDeadline = seDesc = false; 526 seComp = sePrio = seDeadline = seDesc = false;
527 int ret =0; 527 int ret =0;
528 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; 528 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1;
529 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; 529 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2;
530 530
531 /* same item */ 531 /* same item */
532 if ( con1->todo.uid() == con2->todo.uid() ) 532 if ( con1->todo.uid() == con2->todo.uid() )
533 return 0; 533 return 0;
534 534
535 switch ( m_sort ) { 535 switch ( m_sort ) {
536 /* completed */ 536 /* completed */
537 case 0: { 537 case 0: {
538 ret = completed( con1->todo, con2->todo ); 538 ret = completed( con1->todo, con2->todo );
539 seComp = TRUE; 539 seComp = TRUE;
540 break; 540 break;
541 } 541 }
542 /* priority */ 542 /* priority */
543 case 1: { 543 case 1: {
544 ret = priority( con1->todo, con2->todo ); 544 ret = priority( con1->todo, con2->todo );
545 sePrio = TRUE; 545 sePrio = TRUE;
546 break; 546 break;
547 } 547 }
548 /* description */ 548 /* description */
549 case 2: { 549 case 2: {
550 ret = description( con1->todo, con2->todo ); 550 ret = description( con1->todo, con2->todo );
551 seDesc = TRUE; 551 seDesc = TRUE;
552 break; 552 break;
553 } 553 }
554 /* deadline */ 554 /* deadline */
555 case 3: { 555 case 3: {
556 ret = deadline( con1->todo, con2->todo ); 556 ret = deadline( con1->todo, con2->todo );
557 seDeadline = TRUE; 557 seDeadline = TRUE;
558 break; 558 break;
559 } 559 }
560 default: 560 default:
561 ret = 0; 561 ret = 0;
562 break; 562 break;
563 }; 563 };
564 /* 564 /*
565 * FIXME do better sorting if the first sort criteria 565 * FIXME do better sorting if the first sort criteria
566 * ret equals 0 start with complete and so on... 566 * ret equals 0 start with complete and so on...
567 */ 567 */
568 568
569 /* twist it we're not ascending*/ 569 /* twist it we're not ascending*/
570 if (!m_asc) 570 if (!m_asc)
571 ret = ret * -1; 571 ret = ret * -1;
572 572
573 if ( ret ) 573 if ( ret )
574 return ret; 574 return ret;
575 575
576 // default did not gave difference let's try it other way around 576 // default did not gave difference let's try it other way around
577 /* 577 /*
578 * General try if already checked if not test 578 * General try if already checked if not test
579 * and return 579 * and return
580 * 1.Completed 580 * 1.Completed
581 * 2.Priority 581 * 2.Priority
582 * 3.Description 582 * 3.Description
583 * 4.DueDate 583 * 4.DueDate
584 */ 584 */
585 if (!seComp ) { 585 if (!seComp ) {
586 if ( (ret = completed( con1->todo, con2->todo ) ) ) { 586 if ( (ret = completed( con1->todo, con2->todo ) ) ) {
587 if (!m_asc ) ret *= -1; 587 if (!m_asc ) ret *= -1;
588 return ret; 588 return ret;
589 } 589 }
590 } 590 }
591 if (!sePrio ) { 591 if (!sePrio ) {
592 if ( (ret = priority( con1->todo, con2->todo ) ) ) { 592 if ( (ret = priority( con1->todo, con2->todo ) ) ) {
593 if (!m_asc ) ret *= -1; 593 if (!m_asc ) ret *= -1;
594 return ret; 594 return ret;
595 } 595 }
596 } 596 }
597 if (!seDesc ) { 597 if (!seDesc ) {
598 if ( (ret = description(con1->todo, con2->todo ) ) ) { 598 if ( (ret = description(con1->todo, con2->todo ) ) ) {
599 if (!m_asc) ret *= -1; 599 if (!m_asc) ret *= -1;
600 return ret; 600 return ret;
601 } 601 }
602 } 602 }
603 if (!seDeadline) { 603 if (!seDeadline) {
604 if ( (ret = deadline( con1->todo, con2->todo ) ) ) { 604 if ( (ret = deadline( con1->todo, con2->todo ) ) ) {
605 if (!m_asc) ret *= -1; 605 if (!m_asc) ret *= -1;
606 return ret; 606 return ret;
607 } 607 }
608 } 608 }
609 609
610 return 0; 610 return 0;
611 } 611 }
612 private: 612 private:
613 bool m_asc; 613 bool m_asc;
614 int m_sort; 614 int m_sort;
615 615
616}; 616};
617 617
618QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, 618QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder,
619 int sortFilter, int cat ) { 619 int sortFilter, int cat ) {
620 qWarning("sorted! %d cat", cat); 620 qWarning("sorted! %d cat", cat);
621 OTodoXMLVector vector(m_events.count(), asc,sortOrder ); 621 OTodoXMLVector vector(m_events.count(), asc,sortOrder );
622 QMap<int, OTodo>::Iterator it; 622 QMap<int, OTodo>::Iterator it;
623 int item = 0; 623 int item = 0;
624 624
625 bool bCat = sortFilter & 1 ? true : false; 625 bool bCat = sortFilter & 1 ? true : false;
626 bool bOnly = sortFilter & 2 ? true : false; 626 bool bOnly = sortFilter & 2 ? true : false;
627 bool comp = sortFilter & 4 ? true : false; 627 bool comp = sortFilter & 4 ? true : false;
628 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 628 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
629 629
630 /* show category */ 630 /* show category */
631 if ( bCat && cat != 0) 631 if ( bCat && cat != 0)
632 if (!(*it).categories().contains( cat ) ) { 632 if (!(*it).categories().contains( cat ) ) {
633 qWarning("category mis match"); 633 qWarning("category mis match");
634 continue; 634 continue;
635 } 635 }
636 /* isOverdue but we should not show overdue - why?*/ 636 /* isOverdue but we should not show overdue - why?*/
637/* if ( (*it).isOverdue() && !bOnly ) { 637/* if ( (*it).isOverdue() && !bOnly ) {
638 qWarning("item is overdue but !bOnly"); 638 qWarning("item is overdue but !bOnly");
639 continue; 639 continue;
640 } 640 }
641*/ 641*/
642 if ( !(*it).isOverdue() && bOnly ) { 642 if ( !(*it).isOverdue() && bOnly ) {
643 qWarning("item is not overdue but bOnly checked"); 643 qWarning("item is not overdue but bOnly checked");
644 continue; 644 continue;
645 } 645 }
646 646
647 if ((*it).isCompleted() && comp ) { 647 if ((*it).isCompleted() && comp ) {
648 qWarning("completed continue!"); 648 qWarning("completed continue!");
649 continue; 649 continue;
650 } 650 }
651 651
652 652
653 OTodoXMLContainer* con = new OTodoXMLContainer(); 653 OTodoXMLContainer* con = new OTodoXMLContainer();
654 con->todo = (*it); 654 con->todo = (*it);
655 vector.insert(item, con ); 655 vector.insert(item, con );
656 item++; 656 item++;
657 } 657 }
658 qWarning("XXX %d Items added", item); 658 qWarning("XXX %d Items added", item);
659 vector.resize( item ); 659 vector.resize( item );
660 /* sort it now */ 660 /* sort it now */
661 vector.sort(); 661 vector.sort();
662 /* now get the uids */ 662 /* now get the uids */
663 QArray<int> array( vector.count() ); 663 QArray<int> array( vector.count() );
664 for (uint i= 0; i < vector.count(); i++ ) { 664 for (uint i= 0; i < vector.count(); i++ ) {
665 array[i] = ( vector.at(i) )->todo.uid(); 665 array[i] = ( vector.at(i) )->todo.uid();
666 } 666 }
667 qWarning("array count = %d %d", array.count(), vector.count() ); 667 qWarning("array count = %d %d", array.count(), vector.count() );
668 return array; 668 return array;
669}; 669};
670void OTodoAccessXML::removeAllCompleted() { 670void OTodoAccessXML::removeAllCompleted() {
671 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { 671 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) {
672 if ( (*it).isCompleted() ) 672 if ( (*it).isCompleted() )
673 m_events.remove( it ); 673 m_events.remove( it );
674 } 674 }
675} 675}
diff --git a/libopie/pim/otodoaccessxml.h b/libopie/pim/otodoaccessxml.h
index 93609fe..1032c92 100644
--- a/libopie/pim/otodoaccessxml.h
+++ b/libopie/pim/otodoaccessxml.h
@@ -1,57 +1,57 @@
1#ifndef OPIE_TODO_ACCESS_XML_H 1#ifndef OPIE_TODO_ACCESS_XML_H
2#define OPIE_TODO_ACCESS_XML_H 2#define OPIE_TODO_ACCESS_XML_H
3 3
4#include <qasciidict.h> 4#include <qasciidict.h>
5#include <qmap.h> 5#include <qmap.h>
6 6
7#include "otodoaccessbackend.h" 7#include "otodoaccessbackend.h"
8 8
9namespace Opie { 9namespace Opie {
10 class XMLElement; 10 class XMLElement;
11}; 11};
12 12
13class OTodoAccessXML : public OTodoAccessBackend { 13class OTodoAccessXML : public OTodoAccessBackend {
14public: 14public:
15 /** 15 /**
16 * fileName if Empty we will use the default path 16 * fileName if Empty we will use the default path
17 */ 17 */
18 OTodoAccessXML( const QString& appName, 18 OTodoAccessXML( const QString& appName,
19 const QString& fileName = QString::null ); 19 const QString& fileName = QString::null );
20 ~OTodoAccessXML(); 20 ~OTodoAccessXML();
21 21
22 bool load(); 22 bool load();
23 bool reload(); 23 bool reload();
24 bool save(); 24 bool save();
25 25
26 QArray<int> allRecords()const; 26 QArray<int> allRecords()const;
27 QArray<int> queryByExample( const OTodo&, int querysettings ); 27 QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() );
28 OTodo find( int uid )const; 28 OTodo find( int uid )const;
29 void clear(); 29 void clear();
30 bool add( const OTodo& ); 30 bool add( const OTodo& );
31 bool remove( int uid ); 31 bool remove( int uid );
32 void removeAllCompleted(); 32 void removeAllCompleted();
33 bool replace( const OTodo& ); 33 bool replace( const OTodo& );
34 34
35 /* our functions */ 35 /* our functions */
36 QArray<int> effectiveToDos( const QDate& start, 36 QArray<int> effectiveToDos( const QDate& start,
37 const QDate& end, 37 const QDate& end,
38 bool includeNoDates ); 38 bool includeNoDates );
39 QArray<int> overDue(); 39 QArray<int> overDue();
40 QArray<int> sorted( bool asc, int sortOrder, 40 QArray<int> sorted( bool asc, int sortOrder,
41 int sortFilter, int cat ); 41 int sortFilter, int cat );
42private: 42private:
43 void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& ); 43 void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& );
44 QString toString( const OTodo& )const; 44 QString toString( const OTodo& )const;
45 QString toString( const QArray<int>& ints ) const; 45 QString toString( const QArray<int>& ints ) const;
46 QMap<int, OTodo> m_events; 46 QMap<int, OTodo> m_events;
47 QString m_file; 47 QString m_file;
48 QString m_app; 48 QString m_app;
49 bool m_opened : 1; 49 bool m_opened : 1;
50 bool m_changed : 1; 50 bool m_changed : 1;
51 class OTodoAccessXMLPrivate; 51 class OTodoAccessXMLPrivate;
52 OTodoAccessXMLPrivate* d; 52 OTodoAccessXMLPrivate* d;
53 int m_year, m_month, m_day; 53 int m_year, m_month, m_day;
54 54
55}; 55};
56 56
57#endif 57#endif
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp
index e537269..f24523f 100644
--- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp
@@ -1,615 +1,623 @@
1/* 1/*
2 * VCard Backend for the OPIE-Contact Database. 2 * VCard Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (C) 2000 Trolltech AS. All rights reserved. 4 * Copyright (C) 2000 Trolltech AS. All rights reserved.
5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
6 * 6 *
7 * ===================================================================== 7 * =====================================================================
8 *This program is free software; you can redistribute it and/or 8 *This program is free software; you can redistribute it and/or
9 *modify it under the terms of the GNU Library General Public 9 *modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version. 11 * version 2 of the License, or (at your option) any later version.
12 * ===================================================================== 12 * =====================================================================
13 * ToDo: 13 * ToDo:
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.9 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
20 * Revision 1.8 2003/02/21 16:52:49 zecke 28 * Revision 1.8 2003/02/21 16:52:49 zecke
21 * -Remove old Todo classes they're deprecated and today I already using the 29 * -Remove old Todo classes they're deprecated and today I already using the
22 * new API 30 * new API
23 * -Guard against self assignment in OTodo 31 * -Guard against self assignment in OTodo
24 * -Add test apps for OPIM 32 * -Add test apps for OPIM
25 * -Opiefied Event classes 33 * -Opiefied Event classes
26 * -Added TimeZone handling and pinning of TimeZones to OEvent 34 * -Added TimeZone handling and pinning of TimeZones to OEvent
27 * -Adjust ORecur and the widget to better timezone behaviour 35 * -Adjust ORecur and the widget to better timezone behaviour
28 * 36 *
29 * Revision 1.7 2003/02/16 22:25:46 zecke 37 * Revision 1.7 2003/02/16 22:25:46 zecke
30 * 0000276 Fix for that bug.. or better temp workaround 38 * 0000276 Fix for that bug.. or better temp workaround
31 * A Preferred Number is HOME|VOICE 39 * A Preferred Number is HOME|VOICE
32 * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test 40 * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test
33 * triggers both 41 * triggers both
34 * and the cell phone number overrides the other entries.. 42 * and the cell phone number overrides the other entries..
35 * 43 *
36 * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the 44 * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the
37 * number 45 * number
38 * 46 *
39 * The right and final fix would be to reorder the if statement to make it 47 * The right and final fix would be to reorder the if statement to make it
40 * if else based and the less common thing put to the bottom 48 * if else based and the less common thing put to the bottom
41 * 49 *
42 * OTodoAccessVcal fix the date for beaming 50 * OTodoAccessVcal fix the date for beaming
43 * 51 *
44 * Revision 1.6 2003/01/13 15:49:31 eilers 52 * Revision 1.6 2003/01/13 15:49:31 eilers
45 * Fixing crash when businesscard.vcf is missing.. 53 * Fixing crash when businesscard.vcf is missing..
46 * 54 *
47 * Revision 1.5 2002/12/07 13:26:22 eilers 55 * Revision 1.5 2002/12/07 13:26:22 eilers
48 * Fixing bug in storing anniversary.. 56 * Fixing bug in storing anniversary..
49 * 57 *
50 * Revision 1.4 2002/11/13 14:14:51 eilers 58 * Revision 1.4 2002/11/13 14:14:51 eilers
51 * Added sorted for Contacts.. 59 * Added sorted for Contacts..
52 * 60 *
53 * Revision 1.3 2002/11/11 16:41:09 kergoth 61 * Revision 1.3 2002/11/11 16:41:09 kergoth
54 * no default arguments in implementation 62 * no default arguments in implementation
55 * 63 *
56 * Revision 1.2 2002/11/10 15:41:53 eilers 64 * Revision 1.2 2002/11/10 15:41:53 eilers
57 * Bugfixes.. 65 * Bugfixes..
58 * 66 *
59 * Revision 1.1 2002/11/09 14:34:52 eilers 67 * Revision 1.1 2002/11/09 14:34:52 eilers
60 * Added VCard Backend. 68 * Added VCard Backend.
61 * 69 *
62 */ 70 */
63#include "ocontactaccessbackend_vcard.h" 71#include "ocontactaccessbackend_vcard.h"
64#include "../../library/backend/vobject_p.h" 72#include "../../library/backend/vobject_p.h"
65#include "../../library/backend/qfiledirect_p.h" 73#include "../../library/backend/qfiledirect_p.h"
66 74
67#include <qpe/timeconversion.h> 75#include <qpe/timeconversion.h>
68 76
69#include <qfile.h> 77#include <qfile.h>
70 78
71OContactAccessBackend_VCard::OContactAccessBackend_VCard ( QString , QString filename ): 79OContactAccessBackend_VCard::OContactAccessBackend_VCard ( QString , QString filename ):
72 m_dirty( false ), 80 m_dirty( false ),
73 m_file( filename ) 81 m_file( filename )
74{ 82{
75 load(); 83 load();
76} 84}
77 85
78 86
79bool OContactAccessBackend_VCard::load () 87bool OContactAccessBackend_VCard::load ()
80{ 88{
81 m_map.clear(); 89 m_map.clear();
82 m_dirty = false; 90 m_dirty = false;
83 91
84 VObject* obj = 0l; 92 VObject* obj = 0l;
85 93
86 if ( QFile::exists(m_file) ){ 94 if ( QFile::exists(m_file) ){
87 obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); 95 obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() );
88 if ( !obj ) 96 if ( !obj )
89 return false; 97 return false;
90 }else{ 98 }else{
91 qWarning("File \"%s\" not found !", m_file.latin1() ); 99 qWarning("File \"%s\" not found !", m_file.latin1() );
92 return false; 100 return false;
93 } 101 }
94 102
95 while ( obj ) { 103 while ( obj ) {
96 OContact con = parseVObject( obj ); 104 OContact con = parseVObject( obj );
97 /* 105 /*
98 * if uid is 0 assign a new one 106 * if uid is 0 assign a new one
99 * this at least happens on 107 * this at least happens on
100 * Nokia6210 108 * Nokia6210
101 */ 109 */
102 if ( con.uid() == 0 ){ 110 if ( con.uid() == 0 ){
103 con.setUid( 1 ); 111 con.setUid( 1 );
104 qWarning("assigned new uid %d",con.uid() ); 112 qWarning("assigned new uid %d",con.uid() );
105 } 113 }
106 114
107 m_map.insert( con.uid(), con ); 115 m_map.insert( con.uid(), con );
108 116
109 VObject *t = obj; 117 VObject *t = obj;
110 obj = nextVObjectInList(obj); 118 obj = nextVObjectInList(obj);
111 cleanVObject( t ); 119 cleanVObject( t );
112 } 120 }
113 121
114 return true; 122 return true;
115 123
116} 124}
117bool OContactAccessBackend_VCard::reload() 125bool OContactAccessBackend_VCard::reload()
118{ 126{
119 return load(); 127 return load();
120} 128}
121bool OContactAccessBackend_VCard::save() 129bool OContactAccessBackend_VCard::save()
122{ 130{
123 if (!m_dirty ) 131 if (!m_dirty )
124 return true; 132 return true;
125 133
126 QFileDirect file( m_file ); 134 QFileDirect file( m_file );
127 if (!file.open(IO_WriteOnly ) ) 135 if (!file.open(IO_WriteOnly ) )
128 return false; 136 return false;
129 137
130 VObject *obj; 138 VObject *obj;
131 obj = newVObject( VCCalProp ); 139 obj = newVObject( VCCalProp );
132 addPropValue( obj, VCVersionProp, "1.0" ); 140 addPropValue( obj, VCVersionProp, "1.0" );
133 141
134 VObject *vo; 142 VObject *vo;
135 for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ 143 for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){
136 vo = createVObject( *it ); 144 vo = createVObject( *it );
137 writeVObject( file.directHandle() , vo ); 145 writeVObject( file.directHandle() , vo );
138 cleanVObject( vo ); 146 cleanVObject( vo );
139 } 147 }
140 cleanStrTbl(); 148 cleanStrTbl();
141 149
142 m_dirty = false; 150 m_dirty = false;
143 return true; 151 return true;
144 152
145 153
146} 154}
147void OContactAccessBackend_VCard::clear () 155void OContactAccessBackend_VCard::clear ()
148{ 156{
149 m_map.clear(); 157 m_map.clear();
150 m_dirty = true; // ??? sure ? (se) 158 m_dirty = true; // ??? sure ? (se)
151} 159}
152 160
153bool OContactAccessBackend_VCard::add ( const OContact& newcontact ) 161bool OContactAccessBackend_VCard::add ( const OContact& newcontact )
154{ 162{
155 m_map.insert( newcontact.uid(), newcontact ); 163 m_map.insert( newcontact.uid(), newcontact );
156 m_dirty = true; 164 m_dirty = true;
157 return true; 165 return true;
158} 166}
159 167
160bool OContactAccessBackend_VCard::remove ( int uid ) 168bool OContactAccessBackend_VCard::remove ( int uid )
161{ 169{
162 m_map.remove( uid ); 170 m_map.remove( uid );
163 m_dirty = true; 171 m_dirty = true;
164 return true; 172 return true;
165} 173}
166 174
167bool OContactAccessBackend_VCard::replace ( const OContact &contact ) 175bool OContactAccessBackend_VCard::replace ( const OContact &contact )
168{ 176{
169 m_map.replace( contact.uid(), contact ); 177 m_map.replace( contact.uid(), contact );
170 m_dirty = true; 178 m_dirty = true;
171 return true; 179 return true;
172} 180}
173 181
174OContact OContactAccessBackend_VCard::find ( int uid ) const 182OContact OContactAccessBackend_VCard::find ( int uid ) const
175{ 183{
176 return m_map[uid]; 184 return m_map[uid];
177} 185}
178 186
179QArray<int> OContactAccessBackend_VCard::allRecords() const 187QArray<int> OContactAccessBackend_VCard::allRecords() const
180{ 188{
181 QArray<int> ar( m_map.count() ); 189 QArray<int> ar( m_map.count() );
182 QMap<int, OContact>::ConstIterator it; 190 QMap<int, OContact>::ConstIterator it;
183 int i = 0; 191 int i = 0;
184 for ( it = m_map.begin(); it != m_map.end(); ++it ) { 192 for ( it = m_map.begin(); it != m_map.end(); ++it ) {
185 ar[i] = it.key(); 193 ar[i] = it.key();
186 i++; 194 i++;
187 } 195 }
188 return ar; 196 return ar;
189} 197}
190 198
191// Not implemented 199// Not implemented
192QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int ) 200QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& )
193{ 201{
194 QArray<int> ar(0); 202 QArray<int> ar(0);
195 return ar; 203 return ar;
196} 204}
197 205
198// Not implemented 206// Not implemented
199QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const 207QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const
200{ 208{
201 QArray<int> ar(0); 209 QArray<int> ar(0);
202 return ar; 210 return ar;
203} 211}
204 212
205const uint OContactAccessBackend_VCard::querySettings() 213const uint OContactAccessBackend_VCard::querySettings()
206{ 214{
207 return 0; // No search possible 215 return 0; // No search possible
208} 216}
209 217
210bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const 218bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const
211{ 219{
212 return false; // No search possible, therefore all settings invalid ;) 220 return false; // No search possible, therefore all settings invalid ;)
213} 221}
214 222
215bool OContactAccessBackend_VCard::wasChangedExternally() 223bool OContactAccessBackend_VCard::wasChangedExternally()
216{ 224{
217 return false; // Don't expect concurrent access 225 return false; // Don't expect concurrent access
218} 226}
219 227
220// Not implemented 228// Not implemented
221QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int ) 229QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int )
222{ 230{
223 QArray<int> ar(0); 231 QArray<int> ar(0);
224 return ar; 232 return ar;
225} 233}
226 234
227// *** Private stuff *** 235// *** Private stuff ***
228 236
229 237
230OContact OContactAccessBackend_VCard::parseVObject( VObject *obj ) 238OContact OContactAccessBackend_VCard::parseVObject( VObject *obj )
231{ 239{
232 OContact c; 240 OContact c;
233 241
234 VObjectIterator it; 242 VObjectIterator it;
235 initPropIterator( &it, obj ); 243 initPropIterator( &it, obj );
236 while( moreIteration( &it ) ) { 244 while( moreIteration( &it ) ) {
237 VObject *o = nextVObject( &it ); 245 VObject *o = nextVObject( &it );
238 QCString name = vObjectName( o ); 246 QCString name = vObjectName( o );
239 QCString value = vObjectStringZValue( o ); 247 QCString value = vObjectStringZValue( o );
240 if ( name == VCNameProp ) { 248 if ( name == VCNameProp ) {
241 VObjectIterator nit; 249 VObjectIterator nit;
242 initPropIterator( &nit, o ); 250 initPropIterator( &nit, o );
243 while( moreIteration( &nit ) ) { 251 while( moreIteration( &nit ) ) {
244 VObject *o = nextVObject( &nit ); 252 VObject *o = nextVObject( &nit );
245 QCString name = vObjectTypeInfo( o ); 253 QCString name = vObjectTypeInfo( o );
246 QString value = vObjectStringZValue( o ); 254 QString value = vObjectStringZValue( o );
247 if ( name == VCNamePrefixesProp ) 255 if ( name == VCNamePrefixesProp )
248 c.setTitle( value ); 256 c.setTitle( value );
249 else if ( name == VCNameSuffixesProp ) 257 else if ( name == VCNameSuffixesProp )
250 c.setSuffix( value ); 258 c.setSuffix( value );
251 else if ( name == VCFamilyNameProp ) 259 else if ( name == VCFamilyNameProp )
252 c.setLastName( value ); 260 c.setLastName( value );
253 else if ( name == VCGivenNameProp ) 261 else if ( name == VCGivenNameProp )
254 c.setFirstName( value ); 262 c.setFirstName( value );
255 else if ( name == VCAdditionalNamesProp ) 263 else if ( name == VCAdditionalNamesProp )
256 c.setMiddleName( value ); 264 c.setMiddleName( value );
257 } 265 }
258 } 266 }
259 else if ( name == VCAdrProp ) { 267 else if ( name == VCAdrProp ) {
260 bool work = TRUE; // default address is work address 268 bool work = TRUE; // default address is work address
261 QString street; 269 QString street;
262 QString city; 270 QString city;
263 QString region; 271 QString region;
264 QString postal; 272 QString postal;
265 QString country; 273 QString country;
266 274
267 VObjectIterator nit; 275 VObjectIterator nit;
268 initPropIterator( &nit, o ); 276 initPropIterator( &nit, o );
269 while( moreIteration( &nit ) ) { 277 while( moreIteration( &nit ) ) {
270 VObject *o = nextVObject( &nit ); 278 VObject *o = nextVObject( &nit );
271 QCString name = vObjectName( o ); 279 QCString name = vObjectName( o );
272 QString value = vObjectStringZValue( o ); 280 QString value = vObjectStringZValue( o );
273 if ( name == VCHomeProp ) 281 if ( name == VCHomeProp )
274 work = FALSE; 282 work = FALSE;
275 else if ( name == VCWorkProp ) 283 else if ( name == VCWorkProp )
276 work = TRUE; 284 work = TRUE;
277 else if ( name == VCStreetAddressProp ) 285 else if ( name == VCStreetAddressProp )
278 street = value; 286 street = value;
279 else if ( name == VCCityProp ) 287 else if ( name == VCCityProp )
280 city = value; 288 city = value;
281 else if ( name == VCRegionProp ) 289 else if ( name == VCRegionProp )
282 region = value; 290 region = value;
283 else if ( name == VCPostalCodeProp ) 291 else if ( name == VCPostalCodeProp )
284 postal = value; 292 postal = value;
285 else if ( name == VCCountryNameProp ) 293 else if ( name == VCCountryNameProp )
286 country = value; 294 country = value;
287 } 295 }
288 if ( work ) { 296 if ( work ) {
289 c.setBusinessStreet( street ); 297 c.setBusinessStreet( street );
290 c.setBusinessCity( city ); 298 c.setBusinessCity( city );
291 c.setBusinessCountry( country ); 299 c.setBusinessCountry( country );
292 c.setBusinessZip( postal ); 300 c.setBusinessZip( postal );
293 c.setBusinessState( region ); 301 c.setBusinessState( region );
294 } else { 302 } else {
295 c.setHomeStreet( street ); 303 c.setHomeStreet( street );
296 c.setHomeCity( city ); 304 c.setHomeCity( city );
297 c.setHomeCountry( country ); 305 c.setHomeCountry( country );
298 c.setHomeZip( postal ); 306 c.setHomeZip( postal );
299 c.setHomeState( region ); 307 c.setHomeState( region );
300 } 308 }
301 } 309 }
302 else if ( name == VCTelephoneProp ) { 310 else if ( name == VCTelephoneProp ) {
303 enum { 311 enum {
304 HOME = 0x01, 312 HOME = 0x01,
305 WORK = 0x02, 313 WORK = 0x02,
306 VOICE = 0x04, 314 VOICE = 0x04,
307 CELL = 0x08, 315 CELL = 0x08,
308 FAX = 0x10, 316 FAX = 0x10,
309 PAGER = 0x20, 317 PAGER = 0x20,
310 UNKNOWN = 0x80 318 UNKNOWN = 0x80
311 }; 319 };
312 int type = 0; 320 int type = 0;
313 321
314 VObjectIterator nit; 322 VObjectIterator nit;
315 initPropIterator( &nit, o ); 323 initPropIterator( &nit, o );
316 while( moreIteration( &nit ) ) { 324 while( moreIteration( &nit ) ) {
317 VObject *o = nextVObject( &nit ); 325 VObject *o = nextVObject( &nit );
318 QCString name = vObjectTypeInfo( o ); 326 QCString name = vObjectTypeInfo( o );
319 if ( name == VCHomeProp ) 327 if ( name == VCHomeProp )
320 type |= HOME; 328 type |= HOME;
321 else if ( name == VCWorkProp ) 329 else if ( name == VCWorkProp )
322 type |= WORK; 330 type |= WORK;
323 else if ( name == VCVoiceProp ) 331 else if ( name == VCVoiceProp )
324 type |= VOICE; 332 type |= VOICE;
325 else if ( name == VCCellularProp ) 333 else if ( name == VCCellularProp )
326 type |= CELL; 334 type |= CELL;
327 else if ( name == VCFaxProp ) 335 else if ( name == VCFaxProp )
328 type |= FAX; 336 type |= FAX;
329 else if ( name == VCPagerProp ) 337 else if ( name == VCPagerProp )
330 type |= PAGER; 338 type |= PAGER;
331 else if ( name == VCPreferredProp ) 339 else if ( name == VCPreferredProp )
332 ; 340 ;
333 else 341 else
334 type |= UNKNOWN; 342 type |= UNKNOWN;
335 } 343 }
336 if ( (type & UNKNOWN) != UNKNOWN ) { 344 if ( (type & UNKNOWN) != UNKNOWN ) {
337 if ( ( type & (HOME|WORK) ) == 0 ) // default 345 if ( ( type & (HOME|WORK) ) == 0 ) // default
338 type |= HOME; 346 type |= HOME;
339 if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default 347 if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default
340 type |= VOICE; 348 type |= VOICE;
341 349
342 qWarning("value %s %d", value.data(), type ); 350 qWarning("value %s %d", value.data(), type );
343 if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) ) 351 if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) )
344 c.setHomePhone( value ); 352 c.setHomePhone( value );
345 if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) 353 if ( ( type & (FAX|HOME) ) == (FAX|HOME) )
346 c.setHomeFax( value ); 354 c.setHomeFax( value );
347 if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) 355 if ( ( type & (CELL|HOME) ) == (CELL|HOME) )
348 c.setHomeMobile( value ); 356 c.setHomeMobile( value );
349 if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) ) 357 if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) )
350 c.setBusinessPhone( value ); 358 c.setBusinessPhone( value );
351 if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) 359 if ( ( type & (FAX|WORK) ) == (FAX|WORK) )
352 c.setBusinessFax( value ); 360 c.setBusinessFax( value );
353 if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) 361 if ( ( type & (CELL|WORK) ) == (CELL|WORK) )
354 c.setBusinessMobile( value ); 362 c.setBusinessMobile( value );
355 if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) 363 if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) )
356 c.setBusinessPager( value ); 364 c.setBusinessPager( value );
357 } 365 }
358 } 366 }
359 else if ( name == VCEmailAddressProp ) { 367 else if ( name == VCEmailAddressProp ) {
360 QString email = vObjectStringZValue( o ); 368 QString email = vObjectStringZValue( o );
361 bool valid = TRUE; 369 bool valid = TRUE;
362 VObjectIterator nit; 370 VObjectIterator nit;
363 initPropIterator( &nit, o ); 371 initPropIterator( &nit, o );
364 while( moreIteration( &nit ) ) { 372 while( moreIteration( &nit ) ) {
365 VObject *o = nextVObject( &nit ); 373 VObject *o = nextVObject( &nit );
366 QCString name = vObjectTypeInfo( o ); 374 QCString name = vObjectTypeInfo( o );
367 if ( name != VCInternetProp && name != VCHomeProp && 375 if ( name != VCInternetProp && name != VCHomeProp &&
368 name != VCWorkProp && 376 name != VCWorkProp &&
369 name != VCPreferredProp ) 377 name != VCPreferredProp )
370 // ### preffered should map to default email 378 // ### preffered should map to default email
371 valid = FALSE; 379 valid = FALSE;
372 } 380 }
373 if ( valid ) { 381 if ( valid ) {
374 c.insertEmail( email ); 382 c.insertEmail( email );
375 } 383 }
376 } 384 }
377 else if ( name == VCURLProp ) { 385 else if ( name == VCURLProp ) {
378 VObjectIterator nit; 386 VObjectIterator nit;
379 initPropIterator( &nit, o ); 387 initPropIterator( &nit, o );
380 while( moreIteration( &nit ) ) { 388 while( moreIteration( &nit ) ) {
381 VObject *o = nextVObject( &nit ); 389 VObject *o = nextVObject( &nit );
382 QCString name = vObjectTypeInfo( o ); 390 QCString name = vObjectTypeInfo( o );
383 if ( name == VCHomeProp ) 391 if ( name == VCHomeProp )
384 c.setHomeWebpage( value ); 392 c.setHomeWebpage( value );
385 else if ( name == VCWorkProp ) 393 else if ( name == VCWorkProp )
386 c.setBusinessWebpage( value ); 394 c.setBusinessWebpage( value );
387 } 395 }
388 } 396 }
389 else if ( name == VCOrgProp ) { 397 else if ( name == VCOrgProp ) {
390 VObjectIterator nit; 398 VObjectIterator nit;
391 initPropIterator( &nit, o ); 399 initPropIterator( &nit, o );
392 while( moreIteration( &nit ) ) { 400 while( moreIteration( &nit ) ) {
393 VObject *o = nextVObject( &nit ); 401 VObject *o = nextVObject( &nit );
394 QCString name = vObjectName( o ); 402 QCString name = vObjectName( o );
395 QString value = vObjectStringZValue( o ); 403 QString value = vObjectStringZValue( o );
396 if ( name == VCOrgNameProp ) 404 if ( name == VCOrgNameProp )
397 c.setCompany( value ); 405 c.setCompany( value );
398 else if ( name == VCOrgUnitProp ) 406 else if ( name == VCOrgUnitProp )
399 c.setDepartment( value ); 407 c.setDepartment( value );
400 else if ( name == VCOrgUnit2Prop ) 408 else if ( name == VCOrgUnit2Prop )
401 c.setOffice( value ); 409 c.setOffice( value );
402 } 410 }
403 } 411 }
404 else if ( name == VCTitleProp ) { 412 else if ( name == VCTitleProp ) {
405 c.setJobTitle( value ); 413 c.setJobTitle( value );
406 } 414 }
407 else if ( name == "X-Qtopia-Profession" ) { 415 else if ( name == "X-Qtopia-Profession" ) {
408 c.setProfession( value ); 416 c.setProfession( value );
409 } 417 }
410 else if ( name == "X-Qtopia-Manager" ) { 418 else if ( name == "X-Qtopia-Manager" ) {
411 c.setManager( value ); 419 c.setManager( value );
412 } 420 }
413 else if ( name == "X-Qtopia-Assistant" ) { 421 else if ( name == "X-Qtopia-Assistant" ) {
414 c.setAssistant( value ); 422 c.setAssistant( value );
415 } 423 }
416 else if ( name == "X-Qtopia-Spouse" ) { 424 else if ( name == "X-Qtopia-Spouse" ) {
417 c.setSpouse( value ); 425 c.setSpouse( value );
418 } 426 }
419 else if ( name == "X-Qtopia-Gender" ) { 427 else if ( name == "X-Qtopia-Gender" ) {
420 c.setGender( value ); 428 c.setGender( value );
421 } 429 }
422 else if ( name == "X-Qtopia-Anniversary" ) { 430 else if ( name == "X-Qtopia-Anniversary" ) {
423 c.setAnniversary( convVCardDateToDate( value ) ); 431 c.setAnniversary( convVCardDateToDate( value ) );
424 } 432 }
425 else if ( name == "X-Qtopia-Nickname" ) { 433 else if ( name == "X-Qtopia-Nickname" ) {
426 c.setNickname( value ); 434 c.setNickname( value );
427 } 435 }
428 else if ( name == "X-Qtopia-Children" ) { 436 else if ( name == "X-Qtopia-Children" ) {
429 c.setChildren( value ); 437 c.setChildren( value );
430 } 438 }
431 else if ( name == VCBirthDateProp ) { 439 else if ( name == VCBirthDateProp ) {
432 // Reading Birthdate regarding RFC 2425 (5.8.4) 440 // Reading Birthdate regarding RFC 2425 (5.8.4)
433 c.setBirthday( convVCardDateToDate( value ) ); 441 c.setBirthday( convVCardDateToDate( value ) );
434 442
435 } 443 }
436 444
437#if 0 445#if 0
438 else { 446 else {
439 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); 447 printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
440 VObjectIterator nit; 448 VObjectIterator nit;
441 initPropIterator( &nit, o ); 449 initPropIterator( &nit, o );
442 while( moreIteration( &nit ) ) { 450 while( moreIteration( &nit ) ) {
443 VObject *o = nextVObject( &nit ); 451 VObject *o = nextVObject( &nit );
444 QCString name = vObjectName( o ); 452 QCString name = vObjectName( o );
445 QString value = vObjectStringZValue( o ); 453 QString value = vObjectStringZValue( o );
446 printf(" subprop: %s = %s\n", name.data(), value.latin1() ); 454 printf(" subprop: %s = %s\n", name.data(), value.latin1() );
447 } 455 }
448 } 456 }
449#endif 457#endif
450 } 458 }
451 c.setFileAs(); 459 c.setFileAs();
452 return c; 460 return c;
453} 461}
454 462
455 463
456VObject* OContactAccessBackend_VCard::createVObject( const OContact &c ) 464VObject* OContactAccessBackend_VCard::createVObject( const OContact &c )
457{ 465{
458 VObject *vcard = newVObject( VCCardProp ); 466 VObject *vcard = newVObject( VCCardProp );
459 safeAddPropValue( vcard, VCVersionProp, "2.1" ); 467 safeAddPropValue( vcard, VCVersionProp, "2.1" );
460 safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); 468 safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) );
461 safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); 469 safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) );
462 470
463 // full name 471 // full name
464 safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); 472 safeAddPropValue( vcard, VCFullNameProp, c.fullName() );
465 473
466 // name properties 474 // name properties
467 VObject *name = safeAddProp( vcard, VCNameProp ); 475 VObject *name = safeAddProp( vcard, VCNameProp );
468 safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); 476 safeAddPropValue( name, VCFamilyNameProp, c.lastName() );
469 safeAddPropValue( name, VCGivenNameProp, c.firstName() ); 477 safeAddPropValue( name, VCGivenNameProp, c.firstName() );
470 safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); 478 safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() );
471 safeAddPropValue( name, VCNamePrefixesProp, c.title() ); 479 safeAddPropValue( name, VCNamePrefixesProp, c.title() );
472 safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); 480 safeAddPropValue( name, VCNameSuffixesProp, c.suffix() );
473 481
474 // home properties 482 // home properties
475 VObject *home_adr= safeAddProp( vcard, VCAdrProp ); 483 VObject *home_adr= safeAddProp( vcard, VCAdrProp );
476 safeAddProp( home_adr, VCHomeProp ); 484 safeAddProp( home_adr, VCHomeProp );
477 safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); 485 safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() );
478 safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); 486 safeAddPropValue( home_adr, VCCityProp, c.homeCity() );
479 safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); 487 safeAddPropValue( home_adr, VCRegionProp, c.homeState() );
480 safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); 488 safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() );
481 safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); 489 safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() );
482 490
483 VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); 491 VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() );
484 safeAddProp( home_phone, VCHomeProp ); 492 safeAddProp( home_phone, VCHomeProp );
485 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); 493 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() );
486 safeAddProp( home_phone, VCHomeProp ); 494 safeAddProp( home_phone, VCHomeProp );
487 safeAddProp( home_phone, VCCellularProp ); 495 safeAddProp( home_phone, VCCellularProp );
488 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); 496 home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() );
489 safeAddProp( home_phone, VCHomeProp ); 497 safeAddProp( home_phone, VCHomeProp );
490 safeAddProp( home_phone, VCFaxProp ); 498 safeAddProp( home_phone, VCFaxProp );
491 499
492 VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); 500 VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() );
493 safeAddProp( url, VCHomeProp ); 501 safeAddProp( url, VCHomeProp );
494 502
495 // work properties 503 // work properties
496 VObject *work_adr= safeAddProp( vcard, VCAdrProp ); 504 VObject *work_adr= safeAddProp( vcard, VCAdrProp );
497 safeAddProp( work_adr, VCWorkProp ); 505 safeAddProp( work_adr, VCWorkProp );
498 safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); 506 safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() );
499 safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); 507 safeAddPropValue( work_adr, VCCityProp, c.businessCity() );
500 safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); 508 safeAddPropValue( work_adr, VCRegionProp, c.businessState() );
501 safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); 509 safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() );
502 safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); 510 safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() );
503 511
504 VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); 512 VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() );
505 safeAddProp( work_phone, VCWorkProp ); 513 safeAddProp( work_phone, VCWorkProp );
506 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); 514 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() );
507 safeAddProp( work_phone, VCWorkProp ); 515 safeAddProp( work_phone, VCWorkProp );
508 safeAddProp( work_phone, VCCellularProp ); 516 safeAddProp( work_phone, VCCellularProp );
509 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); 517 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() );
510 safeAddProp( work_phone, VCWorkProp ); 518 safeAddProp( work_phone, VCWorkProp );
511 safeAddProp( work_phone, VCFaxProp ); 519 safeAddProp( work_phone, VCFaxProp );
512 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); 520 work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() );
513 safeAddProp( work_phone, VCWorkProp ); 521 safeAddProp( work_phone, VCWorkProp );
514 safeAddProp( work_phone, VCPagerProp ); 522 safeAddProp( work_phone, VCPagerProp );
515 523
516 url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); 524 url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() );
517 safeAddProp( url, VCWorkProp ); 525 safeAddProp( url, VCWorkProp );
518 526
519 VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); 527 VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() );
520 safeAddProp( title, VCWorkProp ); 528 safeAddProp( title, VCWorkProp );
521 529
522 530
523 QStringList emails = c.emailList(); 531 QStringList emails = c.emailList();
524 emails.prepend( c.defaultEmail() ); 532 emails.prepend( c.defaultEmail() );
525 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { 533 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) {
526 VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); 534 VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it );
527 safeAddProp( email, VCInternetProp ); 535 safeAddProp( email, VCInternetProp );
528 } 536 }
529 537
530 safeAddPropValue( vcard, VCNoteProp, c.notes() ); 538 safeAddPropValue( vcard, VCNoteProp, c.notes() );
531 539
532 // Exporting Birthday regarding RFC 2425 (5.8.4) 540 // Exporting Birthday regarding RFC 2425 (5.8.4)
533 if ( c.birthday().isValid() ){ 541 if ( c.birthday().isValid() ){
534 qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() ); 542 qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() );
535 safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) ); 543 safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) );
536 } 544 }
537 545
538 if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { 546 if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) {
539 VObject *org = safeAddProp( vcard, VCOrgProp ); 547 VObject *org = safeAddProp( vcard, VCOrgProp );
540 safeAddPropValue( org, VCOrgNameProp, c.company() ); 548 safeAddPropValue( org, VCOrgNameProp, c.company() );
541 safeAddPropValue( org, VCOrgUnitProp, c.department() ); 549 safeAddPropValue( org, VCOrgUnitProp, c.department() );
542 safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); 550 safeAddPropValue( org, VCOrgUnit2Prop, c.office() );
543 } 551 }
544 552
545 // some values we have to export as custom fields 553 // some values we have to export as custom fields
546 safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); 554 safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() );
547 safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); 555 safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() );
548 safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); 556 safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() );
549 557
550 safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); 558 safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() );
551 safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); 559 safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() );
552 if ( c.anniversary().isValid() ){ 560 if ( c.anniversary().isValid() ){
553 qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() ); 561 qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() );
554 safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) ); 562 safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) );
555 } 563 }
556 safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); 564 safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() );
557 safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); 565 safeAddPropValue( vcard, "X-Qtopia-Children", c.children() );
558 566
559 return vcard; 567 return vcard;
560} 568}
561 569
562QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const 570QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const
563{ 571{
564 QString str_rfc2425 = QString("%1-%2-%3") 572 QString str_rfc2425 = QString("%1-%2-%3")
565 .arg( d.year() ) 573 .arg( d.year() )
566 .arg( d.month(), 2 ) 574 .arg( d.month(), 2 )
567 .arg( d.day(), 2 ); 575 .arg( d.day(), 2 );
568 // Now replace spaces with "0"... 576 // Now replace spaces with "0"...
569 int pos = 0; 577 int pos = 0;
570 while ( ( pos = str_rfc2425.find (' ') ) > 0 ) 578 while ( ( pos = str_rfc2425.find (' ') ) > 0 )
571 str_rfc2425.replace( pos, 1, "0" ); 579 str_rfc2425.replace( pos, 1, "0" );
572 580
573 return str_rfc2425; 581 return str_rfc2425;
574} 582}
575 583
576QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr ) 584QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr )
577{ 585{
578 int monthPos = datestr.find('-'); 586 int monthPos = datestr.find('-');
579 int dayPos = datestr.find('-', monthPos+1 ); 587 int dayPos = datestr.find('-', monthPos+1 );
580 int sep_ignore = 1; 588 int sep_ignore = 1;
581 if ( monthPos == -1 || dayPos == -1 ) { 589 if ( monthPos == -1 || dayPos == -1 ) {
582 qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); 590 qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos );
583 // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD ) 591 // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD )
584 if ( datestr.length() == 8 ){ 592 if ( datestr.length() == 8 ){
585 monthPos = 4; 593 monthPos = 4;
586 dayPos = 6; 594 dayPos = 6;
587 sep_ignore = 0; 595 sep_ignore = 0;
588 qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); 596 qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos );
589 } else { 597 } else {
590 return QDate(); 598 return QDate();
591 } 599 }
592 } 600 }
593 int y = datestr.left( monthPos ).toInt(); 601 int y = datestr.left( monthPos ).toInt();
594 int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt(); 602 int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt();
595 int d = datestr.mid( dayPos + sep_ignore ).toInt(); 603 int d = datestr.mid( dayPos + sep_ignore ).toInt();
596 qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos); 604 qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos);
597 QDate date ( y,m,d ); 605 QDate date ( y,m,d );
598 return date; 606 return date;
599} 607}
600 608
601VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value ) 609VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value )
602{ 610{
603 VObject *ret = 0; 611 VObject *ret = 0;
604 if ( o && !value.isEmpty() ) 612 if ( o && !value.isEmpty() )
605 ret = addPropValue( o, prop, value.latin1() ); 613 ret = addPropValue( o, prop, value.latin1() );
606 return ret; 614 return ret;
607} 615}
608 616
609VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop) 617VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop)
610{ 618{
611 VObject *ret = 0; 619 VObject *ret = 0;
612 if ( o ) 620 if ( o )
613 ret = addProp( o, prop ); 621 ret = addProp( o, prop );
614 return ret; 622 return ret;
615} 623}
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h
index 236da00..93e2da3 100644
--- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h
@@ -1,78 +1,86 @@
1/* 1/*
2 * VCard Backend for the OPIE-Contact Database. 2 * VCard Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (C) 2000 Trolltech AS. All rights reserved. 4 * Copyright (C) 2000 Trolltech AS. All rights reserved.
5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 5 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
6 * 6 *
7 * ===================================================================== 7 * =====================================================================
8 *This program is free software; you can redistribute it and/or 8 *This program is free software; you can redistribute it and/or
9 *modify it under the terms of the GNU Library General Public 9 *modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version. 11 * version 2 of the License, or (at your option) any later version.
12 * ===================================================================== 12 * =====================================================================
13 * ToDo: 13 * ToDo:
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.5 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
20 * Revision 1.4 2002/12/07 13:26:22 eilers 28 * Revision 1.4 2002/12/07 13:26:22 eilers
21 * Fixing bug in storing anniversary.. 29 * Fixing bug in storing anniversary..
22 * 30 *
23 * Revision 1.3 2002/11/13 14:14:51 eilers 31 * Revision 1.3 2002/11/13 14:14:51 eilers
24 * Added sorted for Contacts.. 32 * Added sorted for Contacts..
25 * 33 *
26 * Revision 1.2 2002/11/10 15:41:53 eilers 34 * Revision 1.2 2002/11/10 15:41:53 eilers
27 * Bugfixes.. 35 * Bugfixes..
28 * 36 *
29 * Revision 1.1 2002/11/09 14:34:52 eilers 37 * Revision 1.1 2002/11/09 14:34:52 eilers
30 * Added VCard Backend. 38 * Added VCard Backend.
31 * 39 *
32 */ 40 */
33#ifndef __OCONTACTACCESSBACKEND_VCARD_H_ 41#ifndef __OCONTACTACCESSBACKEND_VCARD_H_
34#define __OCONTACTACCESSBACKEND_VCARD_H_ 42#define __OCONTACTACCESSBACKEND_VCARD_H_
35 43
36#include <opie/ocontact.h> 44#include <opie/ocontact.h>
37 45
38#include "ocontactaccessbackend.h" 46#include "ocontactaccessbackend.h"
39 47
40class VObject; 48class VObject;
41 49
42class OContactAccessBackend_VCard : public OContactAccessBackend { 50class OContactAccessBackend_VCard : public OContactAccessBackend {
43 public: 51 public:
44 OContactAccessBackend_VCard ( QString appname, QString filename = 0l ); 52 OContactAccessBackend_VCard ( QString appname, QString filename = 0l );
45 53
46 bool load (); 54 bool load ();
47 bool reload(); 55 bool reload();
48 bool save(); 56 bool save();
49 void clear (); 57 void clear ();
50 58
51 bool add ( const OContact& newcontact ); 59 bool add ( const OContact& newcontact );
52 bool remove ( int uid ); 60 bool remove ( int uid );
53 bool replace ( const OContact& contact ); 61 bool replace ( const OContact& contact );
54 62
55 OContact find ( int uid ) const; 63 OContact find ( int uid ) const;
56 QArray<int> allRecords() const; 64 QArray<int> allRecords() const;
57 QArray<int> queryByExample ( const OContact &query, int settings ); 65 QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() );
58 QArray<int> matchRegexp( const QRegExp &r ) const; 66 QArray<int> matchRegexp( const QRegExp &r ) const;
59 67
60 const uint querySettings(); 68 const uint querySettings();
61 bool hasQuerySettings (uint querySettings) const; 69 bool hasQuerySettings (uint querySettings) const;
62 QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); 70 QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat );
63 bool wasChangedExternally(); 71 bool wasChangedExternally();
64 72
65private: 73private:
66 OContact parseVObject( VObject* obj ); 74 OContact parseVObject( VObject* obj );
67 VObject* createVObject( const OContact& c ); 75 VObject* createVObject( const OContact& c );
68 QString convDateToVCardDate( const QDate& c ) const; 76 QString convDateToVCardDate( const QDate& c ) const;
69 QDate convVCardDateToDate( const QString& datestr ); 77 QDate convVCardDateToDate( const QString& datestr );
70 VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); 78 VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value );
71 VObject *safeAddProp( VObject* o, const char* prop); 79 VObject *safeAddProp( VObject* o, const char* prop);
72 80
73 bool m_dirty : 1; 81 bool m_dirty : 1;
74 QString m_file; 82 QString m_file;
75 QMap<int, OContact> m_map; 83 QMap<int, OContact> m_map;
76}; 84};
77 85
78#endif 86#endif
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp
index 2df6757..4abf4d9 100644
--- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp
@@ -1,739 +1,777 @@
1/* 1/*
2 * XML Backend for the OPIE-Contact Database. 2 * XML Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 * 5 *
6 * ===================================================================== 6 * =====================================================================
7 *This program is free software; you can redistribute it and/or 7 *This program is free software; you can redistribute it and/or
8 *modify it under the terms of the GNU Library General Public 8 *modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
11 * ===================================================================== 11 * =====================================================================
12 * ToDo: XML-Backend: Automatic reload if something was changed... 12 * ToDo: XML-Backend: Automatic reload if something was changed...
13 * 13 *
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.2 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
28 * Revision 1.1.2.2 2003/02/11 12:17:28 eilers
29 * Speed optimization. Removed the sequential search loops.
30 *
31 * Revision 1.1.2.1 2003/02/10 15:31:38 eilers
32 * Writing offsets to debug output..
33 *
20 * Revision 1.1 2003/02/09 15:05:01 eilers 34 * Revision 1.1 2003/02/09 15:05:01 eilers
21 * Nothing happened.. Just some cleanup before I will start.. 35 * Nothing happened.. Just some cleanup before I will start..
22 * 36 *
23 * Revision 1.12 2003/01/03 16:58:03 eilers 37 * Revision 1.12 2003/01/03 16:58:03 eilers
24 * Reenable debug output 38 * Reenable debug output
25 * 39 *
26 * Revision 1.11 2003/01/03 12:31:28 eilers 40 * Revision 1.11 2003/01/03 12:31:28 eilers
27 * Bugfix for calculating data diffs.. 41 * Bugfix for calculating data diffs..
28 * 42 *
29 * Revision 1.10 2003/01/02 14:27:12 eilers 43 * Revision 1.10 2003/01/02 14:27:12 eilers
30 * Improved query by example: Search by date is possible.. First step 44 * Improved query by example: Search by date is possible.. First step
31 * for a today plugin for birthdays.. 45 * for a today plugin for birthdays..
32 * 46 *
33 * Revision 1.9 2002/12/08 12:48:57 eilers 47 * Revision 1.9 2002/12/08 12:48:57 eilers
34 * Moved journal-enum from ocontact into i the xml-backend.. 48 * Moved journal-enum from ocontact into i the xml-backend..
35 * 49 *
36 * Revision 1.8 2002/11/14 17:04:24 eilers 50 * Revision 1.8 2002/11/14 17:04:24 eilers
37 * Sorting will now work if fullname is identical on some entries 51 * Sorting will now work if fullname is identical on some entries
38 * 52 *
39 * Revision 1.7 2002/11/13 15:02:46 eilers 53 * Revision 1.7 2002/11/13 15:02:46 eilers
40 * Small Bug in sorted fixed 54 * Small Bug in sorted fixed
41 * 55 *
42 * Revision 1.6 2002/11/13 14:14:51 eilers 56 * Revision 1.6 2002/11/13 14:14:51 eilers
43 * Added sorted for Contacts.. 57 * Added sorted for Contacts..
44 * 58 *
45 * Revision 1.5 2002/11/01 15:10:42 eilers 59 * Revision 1.5 2002/11/01 15:10:42 eilers
46 * Added regExp-search in database for all fields in a contact. 60 * Added regExp-search in database for all fields in a contact.
47 * 61 *
48 * Revision 1.4 2002/10/16 10:52:40 eilers 62 * Revision 1.4 2002/10/16 10:52:40 eilers
49 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 63 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
50 * 64 *
51 * Revision 1.3 2002/10/14 16:21:54 eilers 65 * Revision 1.3 2002/10/14 16:21:54 eilers
52 * Some minor interface updates 66 * Some minor interface updates
53 * 67 *
54 * Revision 1.2 2002/10/07 17:34:24 eilers 68 * Revision 1.2 2002/10/07 17:34:24 eilers
55 * added OBackendFactory for advanced backend access 69 * added OBackendFactory for advanced backend access
56 * 70 *
57 * Revision 1.1 2002/09/27 17:11:44 eilers 71 * Revision 1.1 2002/09/27 17:11:44 eilers
58 * Added API for accessing the Contact-Database ! It is compiling, but 72 * Added API for accessing the Contact-Database ! It is compiling, but
59 * please do not expect that anything is working ! 73 * please do not expect that anything is working !
60 * I will debug that stuff in the next time .. 74 * I will debug that stuff in the next time ..
61 * Please read README_COMPILE for compiling ! 75 * Please read README_COMPILE for compiling !
62 * 76 *
63 * 77 *
64 */ 78 */
65 79
66#include "ocontactaccessbackend_xml.h" 80#include "ocontactaccessbackend_xml.h"
67 81
68#include <qasciidict.h> 82#include <qasciidict.h>
69#include <qdatetime.h> 83#include <qdatetime.h>
70#include <qfile.h> 84#include <qfile.h>
71#include <qfileinfo.h> 85#include <qfileinfo.h>
72#include <qregexp.h> 86#include <qregexp.h>
73#include <qarray.h> 87#include <qarray.h>
74#include <qmap.h> 88#include <qmap.h>
75#include <qdatetime.h> 89#include <qdatetime.h>
76 90
77#include <qpe/global.h> 91#include <qpe/global.h>
78 92
79#include <opie/xmltree.h> 93#include <opie/xmltree.h>
80#include "ocontactaccessbackend.h" 94#include "ocontactaccessbackend.h"
81#include "ocontactaccess.h" 95#include "ocontactaccess.h"
82 96
83#include <stdlib.h> 97#include <stdlib.h>
84#include <errno.h> 98#include <errno.h>
85 99
86using namespace Opie; 100using namespace Opie;
87 101
88 102
89OContactAccessBackend_XML::OContactAccessBackend_XML ( QString appname, QString filename = 0l ): 103OContactAccessBackend_XML::OContactAccessBackend_XML ( QString appname, QString filename = 0l ):
90 m_changed( false ) 104 m_changed( false )
91{ 105{
106 // Just m_contactlist should call delete if an entry
107 // is removed.
108 m_contactList.setAutoDelete( true );
109 m_uidToContact.setAutoDelete( false );
110
92 m_appName = appname; 111 m_appName = appname;
93 112
94 /* Set journalfile name ... */ 113 /* Set journalfile name ... */
95 m_journalName = getenv("HOME"); 114 m_journalName = getenv("HOME");
96 m_journalName +="/.abjournal" + appname; 115 m_journalName +="/.abjournal" + appname;
97 116
98 /* Expecting to access the default filename if nothing else is set */ 117 /* Expecting to access the default filename if nothing else is set */
99 if ( filename.isEmpty() ){ 118 if ( filename.isEmpty() ){
100 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); 119 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
101 } else 120 } else
102 m_fileName = filename; 121 m_fileName = filename;
103 122
104 /* Load Database now */ 123 /* Load Database now */
105 load (); 124 load ();
106} 125}
107 126
108bool OContactAccessBackend_XML::save() 127bool OContactAccessBackend_XML::save()
109{ 128{
110 129
111 if ( !m_changed ) 130 if ( !m_changed )
112 return true; 131 return true;
113 132
114 QString strNewFile = m_fileName + ".new"; 133 QString strNewFile = m_fileName + ".new";
115 QFile f( strNewFile ); 134 QFile f( strNewFile );
116 if ( !f.open( IO_WriteOnly|IO_Raw ) ) 135 if ( !f.open( IO_WriteOnly|IO_Raw ) )
117 return false; 136 return false;
118 137
119 int total_written; 138 int total_written;
139 int idx_offset = 0;
120 QString out; 140 QString out;
141
142 // Write Header
121 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" 143 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
122 " <Groups>\n" 144 " <Groups>\n"
123 " </Groups>\n" 145 " </Groups>\n"
124 " <Contacts>\n"; 146 " <Contacts>\n";
125 //QValueList<Contact>::iterator it; 147 QCString cstr = out.utf8();
126 QValueListConstIterator<OContact> it; 148 f.writeBlock( cstr.data(), cstr.length() );
127 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { 149 idx_offset += cstr.length();
150 out = "";
151
152 // Write all contacts
153 QListIterator<OContact> it( m_contactList );
154 for ( ; it.current(); ++it ) {
155 qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset );
128 out += "<Contact "; 156 out += "<Contact ";
129 (*it).save( out ); 157 (*it)->save( out );
130 out += "/>\n"; 158 out += "/>\n";
131 QCString cstr = out.utf8(); 159 cstr = out.utf8();
132 total_written = f.writeBlock( cstr.data(), cstr.length() ); 160 total_written = f.writeBlock( cstr.data(), cstr.length() );
161 idx_offset += cstr.length();
133 if ( total_written != int(cstr.length()) ) { 162 if ( total_written != int(cstr.length()) ) {
134 f.close(); 163 f.close();
135 QFile::remove( strNewFile ); 164 QFile::remove( strNewFile );
136 return false; 165 return false;
137 } 166 }
138 out = ""; 167 out = "";
139 } 168 }
140 out += " </Contacts>\n</AddressBook>\n"; 169 out += " </Contacts>\n</AddressBook>\n";
141 170
142 QCString cstr = out.utf8(); 171 // Write Footer
172 cstr = out.utf8();
143 total_written = f.writeBlock( cstr.data(), cstr.length() ); 173 total_written = f.writeBlock( cstr.data(), cstr.length() );
144 if ( total_written != int( cstr.length() ) ) { 174 if ( total_written != int( cstr.length() ) ) {
145 f.close(); 175 f.close();
146 QFile::remove( strNewFile ); 176 QFile::remove( strNewFile );
147 return false; 177 return false;
148 } 178 }
149 f.close(); 179 f.close();
150 180
151 // move the file over, I'm just going to use the system call 181 // move the file over, I'm just going to use the system call
152 // because, I don't feel like using QDir. 182 // because, I don't feel like using QDir.
153 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { 183 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
154 qWarning( "problem renaming file %s to %s, errno: %d", 184 qWarning( "problem renaming file %s to %s, errno: %d",
155 strNewFile.latin1(), m_journalName.latin1(), errno ); 185 strNewFile.latin1(), m_journalName.latin1(), errno );
156 // remove the tmp file... 186 // remove the tmp file...
157 QFile::remove( strNewFile ); 187 QFile::remove( strNewFile );
158 } 188 }
159 189
160 /* The journalfile should be removed now... */ 190 /* The journalfile should be removed now... */
161 removeJournal(); 191 removeJournal();
162 192
163 m_changed = false; 193 m_changed = false;
164 return true; 194 return true;
165} 195}
166 196
167bool OContactAccessBackend_XML::load () 197bool OContactAccessBackend_XML::load ()
168{ 198{
169 m_contactList.clear(); 199 m_contactList.clear();
200 m_uidToContact.clear();
170 201
171 /* Load XML-File and journal if it exists */ 202 /* Load XML-File and journal if it exists */
172 if ( !load ( m_fileName, false ) ) 203 if ( !load ( m_fileName, false ) )
173 return false; 204 return false;
174 /* The returncode of the journalfile is ignored due to the 205 /* The returncode of the journalfile is ignored due to the
175 * fact that it does not exist when this class is instantiated ! 206 * fact that it does not exist when this class is instantiated !
176 * But there may such a file exist, if the application crashed. 207 * But there may such a file exist, if the application crashed.
177 * Therefore we try to load it to get the changes before the # 208 * Therefore we try to load it to get the changes before the #
178 * crash happened... 209 * crash happened...
179 */ 210 */
180 load (m_journalName, true); 211 load (m_journalName, true);
181 212
182 return true; 213 return true;
183} 214}
184 215
185void OContactAccessBackend_XML::clear () 216void OContactAccessBackend_XML::clear ()
186{ 217{
187 m_contactList.clear(); 218 m_contactList.clear();
219 m_uidToContact.clear();
220
188 m_changed = false; 221 m_changed = false;
189
190} 222}
191 223
192bool OContactAccessBackend_XML::wasChangedExternally() 224bool OContactAccessBackend_XML::wasChangedExternally()
193{ 225{
194 QFileInfo fi( m_fileName ); 226 QFileInfo fi( m_fileName );
195 227
196 QDateTime lastmod = fi.lastModified (); 228 QDateTime lastmod = fi.lastModified ();
197 229
198 return (lastmod != m_readtime); 230 return (lastmod != m_readtime);
199} 231}
200 232
201QArray<int> OContactAccessBackend_XML::allRecords() const 233QArray<int> OContactAccessBackend_XML::allRecords() const
202{ 234{
203 QArray<int> uid_list( m_contactList.count() ); 235 QArray<int> uid_list( m_contactList.count() );
204 236
205 uint counter = 0; 237 uint counter = 0;
206 QValueListConstIterator<OContact> it; 238 QListIterator<OContact> it( m_contactList );
207 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 239 for( ; it.current(); ++it ){
208 uid_list[counter++] = (*it).uid(); 240 uid_list[counter++] = (*it)->uid();
209 } 241 }
210 242
211 return ( uid_list ); 243 return ( uid_list );
212} 244}
213 245
214OContact OContactAccessBackend_XML::find ( int uid ) const 246OContact OContactAccessBackend_XML::find ( int uid ) const
215{ 247{
216 bool found = false;
217 OContact foundContact; //Create empty contact 248 OContact foundContact; //Create empty contact
218 249
219 QValueListConstIterator<OContact> it; 250 OContact* found = m_uidToContact.find( QString().setNum( uid ) );
220 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 251
221 if ((*it).uid() == uid){
222 found = true;
223 break;
224 }
225 }
226 if ( found ){ 252 if ( found ){
227 foundContact = *it; 253 foundContact = *found;
228 } 254 }
229 255
230 return ( foundContact ); 256 return ( foundContact );
231} 257}
232 258
233QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings ) 259QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings,
260 const QDateTime& d )
234{ 261{
235 262
236 QArray<int> m_currentQuery( m_contactList.count() ); 263 QArray<int> m_currentQuery( m_contactList.count() );
237 QValueListConstIterator<OContact> it; 264 QListIterator<OContact> it( m_contactList );
238 uint arraycounter = 0; 265 uint arraycounter = 0;
239 266
240 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 267 for( ; it.current(); ++it ){
241 /* Search all fields and compare them with query object. Store them into list 268 /* Search all fields and compare them with query object. Store them into list
242 * if all fields matches. 269 * if all fields matches.
243 */ 270 */
244 QDate* queryDate = 0l; 271 QDate* queryDate = 0l;
245 QDate* checkDate = 0l; 272 QDate* checkDate = 0l;
246 bool allcorrect = true; 273 bool allcorrect = true;
247 for ( int i = 0; i < Qtopia::Groups; i++ ) { 274 for ( int i = 0; i < Qtopia::Groups; i++ ) {
248 // Birthday and anniversary are special nonstring fields and should 275 // Birthday and anniversary are special nonstring fields and should
249 // be handled specially 276 // be handled specially
250 switch ( i ){ 277 switch ( i ){
251 case Qtopia::Birthday: 278 case Qtopia::Birthday:
252 queryDate = new QDate( query.birthday() ); 279 queryDate = new QDate( query.birthday() );
253 checkDate = new QDate( (*it).birthday() ); 280 checkDate = new QDate( (*it)->birthday() );
254 case Qtopia::Anniversary: 281 case Qtopia::Anniversary:
255 if ( queryDate == 0l ){ 282 if ( queryDate == 0l ){
256 queryDate = new QDate( query.anniversary() ); 283 queryDate = new QDate( query.anniversary() );
257 checkDate = new QDate( (*it).anniversary() ); 284 checkDate = new QDate( (*it)->anniversary() );
258 } 285 }
259 286
260 if ( queryDate->isValid() ){ 287 if ( queryDate->isValid() ){
261 if( checkDate->isValid() ){ 288 if( checkDate->isValid() ){
262 if ( settings & OContactAccess::DateYear ){ 289 if ( settings & OContactAccess::DateYear ){
263 if ( queryDate->year() != checkDate->year() ) 290 if ( queryDate->year() != checkDate->year() )
264 allcorrect = false; 291 allcorrect = false;
265 } 292 }
266 if ( settings & OContactAccess::DateMonth ){ 293 if ( settings & OContactAccess::DateMonth ){
267 if ( queryDate->month() != checkDate->month() ) 294 if ( queryDate->month() != checkDate->month() )
268 allcorrect = false; 295 allcorrect = false;
269 } 296 }
270 if ( settings & OContactAccess::DateDay ){ 297 if ( settings & OContactAccess::DateDay ){
271 if ( queryDate->day() != checkDate->day() ) 298 if ( queryDate->day() != checkDate->day() )
272 allcorrect = false; 299 allcorrect = false;
273 } 300 }
274 if ( settings & OContactAccess::DateDiff ) { 301 if ( settings & OContactAccess::DateDiff ) {
275 QDate current = QDate::currentDate(); 302 QDate current;
303 // If we get an additional date, we
304 // will take this date instead of
305 // the current one..
306 if ( !d.date().isValid() )
307 current = QDate::currentDate();
308 else
309 current = d.date();
310
276 // We have to equalize the year, otherwise 311 // We have to equalize the year, otherwise
277 // the search will fail.. 312 // the search will fail..
278 checkDate->setYMD( current.year(), 313 checkDate->setYMD( current.year(),
279 checkDate->month(), 314 checkDate->month(),
280 checkDate->day() ); 315 checkDate->day() );
281 if ( *checkDate < current ) 316 if ( *checkDate < current )
282 checkDate->setYMD( current.year()+1, 317 checkDate->setYMD( current.year()+1,
283 checkDate->month(), 318 checkDate->month(),
284 checkDate->day() ); 319 checkDate->day() );
320
321 // Check whether the birthday/anniversary date is between
322 // the current/given date and the maximum date
323 // ( maximum time range ) !
285 qWarning("Checking if %s is between %s and %s ! ", 324 qWarning("Checking if %s is between %s and %s ! ",
286 checkDate->toString().latin1(), 325 checkDate->toString().latin1(),
287 current.toString().latin1(), 326 current.toString().latin1(),
288 queryDate->toString().latin1() ); 327 queryDate->toString().latin1() );
289 if ( current.daysTo( *queryDate ) > 0 ){ 328 if ( current.daysTo( *queryDate ) > 0 ){
290 if ( !( ( *checkDate >= current ) && 329 if ( !( ( *checkDate >= current ) &&
291 ( *checkDate <= *queryDate ) ) ){ 330 ( *checkDate <= *queryDate ) ) ){
292 allcorrect = false; 331 allcorrect = false;
293 qWarning (" Nope!.."); 332 qWarning (" Nope!..");
294 } 333 }
295 } 334 }
296 } 335 }
297 } else{ 336 } else{
298 // checkDate is invalid. Therfore this entry is always rejected 337 // checkDate is invalid. Therefore this entry is always rejected
299 allcorrect = false; 338 allcorrect = false;
300 } 339 }
301 } 340 }
302 341
303 delete queryDate; 342 delete queryDate;
304 queryDate = 0l; 343 queryDate = 0l;
305 delete checkDate; 344 delete checkDate;
306 checkDate = 0l; 345 checkDate = 0l;
307 break; 346 break;
308 default: 347 default:
309 /* Just compare fields which are not empty in the query object */ 348 /* Just compare fields which are not empty in the query object */
310 if ( !query.field(i).isEmpty() ){ 349 if ( !query.field(i).isEmpty() ){
311 switch ( settings & ~( OContactAccess::IgnoreCase 350 switch ( settings & ~( OContactAccess::IgnoreCase
312 | OContactAccess::DateDiff 351 | OContactAccess::DateDiff
313 | OContactAccess::DateYear 352 | OContactAccess::DateYear
314 | OContactAccess::DateMonth 353 | OContactAccess::DateMonth
315 | OContactAccess::DateDay 354 | OContactAccess::DateDay
316 | OContactAccess::MatchOne 355 | OContactAccess::MatchOne
317 ) ){ 356 ) ){
318 357
319 case OContactAccess::RegExp:{ 358 case OContactAccess::RegExp:{
320 QRegExp expr ( query.field(i), 359 QRegExp expr ( query.field(i),
321 !(settings & OContactAccess::IgnoreCase), 360 !(settings & OContactAccess::IgnoreCase),
322 false ); 361 false );
323 if ( expr.find ( (*it).field(i), 0 ) == -1 ) 362 if ( expr.find ( (*it)->field(i), 0 ) == -1 )
324 allcorrect = false; 363 allcorrect = false;
325 } 364 }
326 break; 365 break;
327 case OContactAccess::WildCards:{ 366 case OContactAccess::WildCards:{
328 QRegExp expr ( query.field(i), 367 QRegExp expr ( query.field(i),
329 !(settings & OContactAccess::IgnoreCase), 368 !(settings & OContactAccess::IgnoreCase),
330 true ); 369 true );
331 if ( expr.find ( (*it).field(i), 0 ) == -1 ) 370 if ( expr.find ( (*it)->field(i), 0 ) == -1 )
332 allcorrect = false; 371 allcorrect = false;
333 } 372 }
334 break; 373 break;
335 case OContactAccess::ExactMatch:{ 374 case OContactAccess::ExactMatch:{
336 if (settings & OContactAccess::IgnoreCase){ 375 if (settings & OContactAccess::IgnoreCase){
337 if ( query.field(i).upper() != 376 if ( query.field(i).upper() !=
338 (*it).field(i).upper() ) 377 (*it)->field(i).upper() )
339 allcorrect = false; 378 allcorrect = false;
340 }else{ 379 }else{
341 if ( query.field(i) != (*it).field(i) ) 380 if ( query.field(i) != (*it)->field(i) )
342 allcorrect = false; 381 allcorrect = false;
343 } 382 }
344 } 383 }
345 break; 384 break;
346 } 385 }
347 } 386 }
348 } 387 }
349 } 388 }
350 if ( allcorrect ){ 389 if ( allcorrect ){
351 m_currentQuery[arraycounter++] = (*it).uid(); 390 m_currentQuery[arraycounter++] = (*it)->uid();
352 } 391 }
353 } 392 }
354 393
355 // Shrink to fit.. 394 // Shrink to fit..
356 m_currentQuery.resize(arraycounter); 395 m_currentQuery.resize(arraycounter);
357 396
358 return m_currentQuery; 397 return m_currentQuery;
359} 398}
360 399
361QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const 400QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const
362{ 401{
363 QArray<int> m_currentQuery( m_contactList.count() ); 402 QArray<int> m_currentQuery( m_contactList.count() );
364 QValueListConstIterator<OContact> it; 403 QListIterator<OContact> it( m_contactList );
365 uint arraycounter = 0; 404 uint arraycounter = 0;
366 405
367 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 406 for( ; it.current(); ++it ){
368 if ( (*it).match( r ) ){ 407 if ( (*it)->match( r ) ){
369 m_currentQuery[arraycounter++] = (*it).uid(); 408 m_currentQuery[arraycounter++] = (*it)->uid();
370 } 409 }
371 410
372 } 411 }
373 // Shrink to fit.. 412 // Shrink to fit..
374 m_currentQuery.resize(arraycounter); 413 m_currentQuery.resize(arraycounter);
375 414
376 return m_currentQuery; 415 return m_currentQuery;
377} 416}
378 417
379const uint OContactAccessBackend_XML::querySettings() 418const uint OContactAccessBackend_XML::querySettings()
380{ 419{
381 return ( OContactAccess::WildCards 420 return ( OContactAccess::WildCards
382 | OContactAccess::IgnoreCase 421 | OContactAccess::IgnoreCase
383 | OContactAccess::RegExp 422 | OContactAccess::RegExp
384 | OContactAccess::ExactMatch 423 | OContactAccess::ExactMatch
385 | OContactAccess::DateDiff 424 | OContactAccess::DateDiff
386 | OContactAccess::DateYear 425 | OContactAccess::DateYear
387 | OContactAccess::DateMonth 426 | OContactAccess::DateMonth
388 | OContactAccess::DateDay 427 | OContactAccess::DateDay
389 ); 428 );
390} 429}
391 430
392bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const 431bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const
393{ 432{
394 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay 433 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
395 * may be added with any of the other settings. IgnoreCase should never used alone. 434 * may be added with any of the other settings. IgnoreCase should never used alone.
396 * Wildcards, RegExp, ExactMatch should never used at the same time... 435 * Wildcards, RegExp, ExactMatch should never used at the same time...
397 */ 436 */
398 437
399 if ( querySettings == OContactAccess::IgnoreCase ) 438 if ( querySettings == OContactAccess::IgnoreCase )
400 return false; 439 return false;
401 440
402 switch ( querySettings & ~( OContactAccess::IgnoreCase 441 switch ( querySettings & ~( OContactAccess::IgnoreCase
403 | OContactAccess::DateDiff 442 | OContactAccess::DateDiff
404 | OContactAccess::DateYear 443 | OContactAccess::DateYear
405 | OContactAccess::DateMonth 444 | OContactAccess::DateMonth
406 | OContactAccess::DateDay 445 | OContactAccess::DateDay
407 ) 446 )
408 ){ 447 ){
409 case OContactAccess::RegExp: 448 case OContactAccess::RegExp:
410 return ( true ); 449 return ( true );
411 case OContactAccess::WildCards: 450 case OContactAccess::WildCards:
412 return ( true ); 451 return ( true );
413 case OContactAccess::ExactMatch: 452 case OContactAccess::ExactMatch:
414 return ( true ); 453 return ( true );
415 default: 454 default:
416 return ( false ); 455 return ( false );
417 } 456 }
418} 457}
419 458
420// Currently only asc implemented.. 459// Currently only asc implemented..
421QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) 460QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int )
422{ 461{
423 QMap<QString, int> nameToUid; 462 QMap<QString, int> nameToUid;
424 QStringList names; 463 QStringList names;
425 QArray<int> m_currentQuery( m_contactList.count() ); 464 QArray<int> m_currentQuery( m_contactList.count() );
426 465
427 // First fill map and StringList with all Names 466 // First fill map and StringList with all Names
428 // Afterwards sort namelist and use map to fill array to return.. 467 // Afterwards sort namelist and use map to fill array to return..
429 QValueListConstIterator<OContact> it; 468 QListIterator<OContact> it( m_contactList );
430 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 469 for( ; it.current(); ++it ){
431 names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); 470 names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) );
432 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); 471 nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() );
433 } 472 }
434 names.sort(); 473 names.sort();
435 474
436 int i = 0; 475 int i = 0;
437 if ( asc ){ 476 if ( asc ){
438 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) 477 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
439 m_currentQuery[i++] = nameToUid[ (*it) ]; 478 m_currentQuery[i++] = nameToUid[ (*it) ];
440 }else{ 479 }else{
441 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) 480 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
442 m_currentQuery[i++] = nameToUid[ (*it) ]; 481 m_currentQuery[i++] = nameToUid[ (*it) ];
443 } 482 }
444 483
445 return m_currentQuery; 484 return m_currentQuery;
446 485
447} 486}
448 487
449bool OContactAccessBackend_XML::add ( const OContact &newcontact ) 488bool OContactAccessBackend_XML::add ( const OContact &newcontact )
450{ 489{
451 //qWarning("odefaultbackend: ACTION::ADD"); 490 //qWarning("odefaultbackend: ACTION::ADD");
452 updateJournal (newcontact, ACTION_ADD); 491 updateJournal (newcontact, ACTION_ADD);
453 addContact_p( newcontact ); 492 addContact_p( newcontact );
454 493
455 m_changed = true; 494 m_changed = true;
456 495
457 return true; 496 return true;
458} 497}
459 498
460bool OContactAccessBackend_XML::replace ( const OContact &contact ) 499bool OContactAccessBackend_XML::replace ( const OContact &contact )
461{ 500{
462 m_changed = true; 501 m_changed = true;
463 502
464 bool found = false; 503 OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) );
465 504
466 QValueListIterator<OContact> it; 505 if ( found ) {
467 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 506 OContact* newCont = new OContact( contact );
468 if ( (*it).uid() == contact.uid() ){ 507
469 found = true; 508 updateJournal ( *newCont, ACTION_REPLACE);
470 break; 509 m_contactList.removeRef ( found );
471 } 510 m_contactList.append ( newCont );
472 } 511 m_uidToContact.remove( QString().setNum( contact.uid() ) );
473 if (found) { 512 m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont );
474 updateJournal (contact, ACTION_REPLACE); 513
475 m_contactList.remove (it); 514 qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid());
476 m_contactList.append (contact); 515
477 return true; 516 return true;
478 } else 517 } else
479 return false; 518 return false;
480} 519}
481 520
482bool OContactAccessBackend_XML::remove ( int uid ) 521bool OContactAccessBackend_XML::remove ( int uid )
483{ 522{
484 m_changed = true; 523 m_changed = true;
485 524
486 bool found = false; 525 OContact* found = m_uidToContact.find ( QString().setNum( uid ) );
487 QValueListIterator<OContact> it; 526
488 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 527 if ( found ) {
489 if ((*it).uid() == uid){ 528 updateJournal ( *found, ACTION_REMOVE);
490 found = true; 529 m_contactList.removeRef ( found );
491 break; 530 m_uidToContact.remove( QString().setNum( uid ) );
492 } 531
493 }
494 if (found) {
495 updateJournal ( *it, ACTION_REMOVE);
496 m_contactList.remove (it);
497 return true; 532 return true;
498 } else 533 } else
499 return false; 534 return false;
500} 535}
501 536
502bool OContactAccessBackend_XML::reload(){ 537bool OContactAccessBackend_XML::reload(){
503 /* Reload is the same as load in this implementation */ 538 /* Reload is the same as load in this implementation */
504 return ( load() ); 539 return ( load() );
505} 540}
506 541
507void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) 542void OContactAccessBackend_XML::addContact_p( const OContact &newcontact )
508{ 543{
509 m_contactList.append (newcontact); 544 OContact* contRef = new OContact( newcontact );
545
546 m_contactList.append ( contRef );
547 m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef );
510} 548}
511 549
512/* This function loads the xml-database and the journalfile */ 550/* This function loads the xml-database and the journalfile */
513bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) 551bool OContactAccessBackend_XML::load( const QString filename, bool isJournal )
514{ 552{
515 553
516 /* We use the time of the last read to check if the file was 554 /* We use the time of the last read to check if the file was
517 * changed externally. 555 * changed externally.
518 */ 556 */
519 if ( !isJournal ){ 557 if ( !isJournal ){
520 QFileInfo fi( filename ); 558 QFileInfo fi( filename );
521 m_readtime = fi.lastModified (); 559 m_readtime = fi.lastModified ();
522 } 560 }
523 561
524 const int JOURNALACTION = Qtopia::Notes + 1; 562 const int JOURNALACTION = Qtopia::Notes + 1;
525 const int JOURNALROW = JOURNALACTION + 1; 563 const int JOURNALROW = JOURNALACTION + 1;
526 564
527 bool foundAction = false; 565 bool foundAction = false;
528 journal_action action = ACTION_ADD; 566 journal_action action = ACTION_ADD;
529 int journalKey = 0; 567 int journalKey = 0;
530 QMap<int, QString> contactMap; 568 QMap<int, QString> contactMap;
531 QMap<QString, QString> customMap; 569 QMap<QString, QString> customMap;
532 QMap<QString, QString>::Iterator customIt; 570 QMap<QString, QString>::Iterator customIt;
533 QAsciiDict<int> dict( 47 ); 571 QAsciiDict<int> dict( 47 );
534 572
535 dict.setAutoDelete( TRUE ); 573 dict.setAutoDelete( TRUE );
536 dict.insert( "Uid", new int(Qtopia::AddressUid) ); 574 dict.insert( "Uid", new int(Qtopia::AddressUid) );
537 dict.insert( "Title", new int(Qtopia::Title) ); 575 dict.insert( "Title", new int(Qtopia::Title) );
538 dict.insert( "FirstName", new int(Qtopia::FirstName) ); 576 dict.insert( "FirstName", new int(Qtopia::FirstName) );
539 dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); 577 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
540 dict.insert( "LastName", new int(Qtopia::LastName) ); 578 dict.insert( "LastName", new int(Qtopia::LastName) );
541 dict.insert( "Suffix", new int(Qtopia::Suffix) ); 579 dict.insert( "Suffix", new int(Qtopia::Suffix) );
542 dict.insert( "FileAs", new int(Qtopia::FileAs) ); 580 dict.insert( "FileAs", new int(Qtopia::FileAs) );
543 dict.insert( "Categories", new int(Qtopia::AddressCategory) ); 581 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
544 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); 582 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
545 dict.insert( "Emails", new int(Qtopia::Emails) ); 583 dict.insert( "Emails", new int(Qtopia::Emails) );
546 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); 584 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
547 dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); 585 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
548 dict.insert( "HomeState", new int(Qtopia::HomeState) ); 586 dict.insert( "HomeState", new int(Qtopia::HomeState) );
549 dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); 587 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
550 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); 588 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
551 dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); 589 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
552 dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); 590 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
553 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); 591 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
554 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); 592 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
555 dict.insert( "Company", new int(Qtopia::Company) ); 593 dict.insert( "Company", new int(Qtopia::Company) );
556 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); 594 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
557 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); 595 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
558 dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); 596 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
559 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); 597 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
560 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); 598 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
561 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); 599 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
562 dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); 600 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
563 dict.insert( "Department", new int(Qtopia::Department) ); 601 dict.insert( "Department", new int(Qtopia::Department) );
564 dict.insert( "Office", new int(Qtopia::Office) ); 602 dict.insert( "Office", new int(Qtopia::Office) );
565 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); 603 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
566 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); 604 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
567 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); 605 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
568 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); 606 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
569 dict.insert( "Profession", new int(Qtopia::Profession) ); 607 dict.insert( "Profession", new int(Qtopia::Profession) );
570 dict.insert( "Assistant", new int(Qtopia::Assistant) ); 608 dict.insert( "Assistant", new int(Qtopia::Assistant) );
571 dict.insert( "Manager", new int(Qtopia::Manager) ); 609 dict.insert( "Manager", new int(Qtopia::Manager) );
572 dict.insert( "Spouse", new int(Qtopia::Spouse) ); 610 dict.insert( "Spouse", new int(Qtopia::Spouse) );
573 dict.insert( "Children", new int(Qtopia::Children) ); 611 dict.insert( "Children", new int(Qtopia::Children) );
574 dict.insert( "Gender", new int(Qtopia::Gender) ); 612 dict.insert( "Gender", new int(Qtopia::Gender) );
575 dict.insert( "Birthday", new int(Qtopia::Birthday) ); 613 dict.insert( "Birthday", new int(Qtopia::Birthday) );
576 dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); 614 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
577 dict.insert( "Nickname", new int(Qtopia::Nickname) ); 615 dict.insert( "Nickname", new int(Qtopia::Nickname) );
578 dict.insert( "Notes", new int(Qtopia::Notes) ); 616 dict.insert( "Notes", new int(Qtopia::Notes) );
579 dict.insert( "action", new int(JOURNALACTION) ); 617 dict.insert( "action", new int(JOURNALACTION) );
580 dict.insert( "actionrow", new int(JOURNALROW) ); 618 dict.insert( "actionrow", new int(JOURNALROW) );
581 619
582 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); 620 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
583 621
584 XMLElement *root = XMLElement::load( filename ); 622 XMLElement *root = XMLElement::load( filename );
585 if(root != 0l ){ // start parsing 623 if(root != 0l ){ // start parsing
586 /* Parse all XML-Elements and put the data into the 624 /* Parse all XML-Elements and put the data into the
587 * Contact-Class 625 * Contact-Class
588 */ 626 */
589 XMLElement *element = root->firstChild(); 627 XMLElement *element = root->firstChild();
590 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); 628 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
591 element = element->firstChild(); 629 element = element->firstChild();
592 630
593 /* Search Tag "Contacts" which is the parent of all Contacts */ 631 /* Search Tag "Contacts" which is the parent of all Contacts */
594 while( element && !isJournal ){ 632 while( element && !isJournal ){
595 if( element->tagName() != QString::fromLatin1("Contacts") ){ 633 if( element->tagName() != QString::fromLatin1("Contacts") ){
596 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", 634 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
597 // element->tagName().latin1()); 635 // element->tagName().latin1());
598 element = element->nextChild(); 636 element = element->nextChild();
599 } else { 637 } else {
600 element = element->firstChild(); 638 element = element->firstChild();
601 break; 639 break;
602 } 640 }
603 } 641 }
604 /* Parse all Contacts and ignore unknown tags */ 642 /* Parse all Contacts and ignore unknown tags */
605 while( element ){ 643 while( element ){
606 if( element->tagName() != QString::fromLatin1("Contact") ){ 644 if( element->tagName() != QString::fromLatin1("Contact") ){
607 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", 645 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
608 // element->tagName().latin1()); 646 // element->tagName().latin1());
609 element = element->nextChild(); 647 element = element->nextChild();
610 continue; 648 continue;
611 } 649 }
612 /* Found alement with tagname "contact", now parse and store all 650 /* Found alement with tagname "contact", now parse and store all
613 * attributes contained 651 * attributes contained
614 */ 652 */
615 //qWarning("OContactDefBack::load element tagName() : %s", 653 //qWarning("OContactDefBack::load element tagName() : %s",
616 // element->tagName().latin1() ); 654 // element->tagName().latin1() );
617 QString dummy; 655 QString dummy;
618 foundAction = false; 656 foundAction = false;
619 657
620 XMLElement::AttributeMap aMap = element->attributes(); 658 XMLElement::AttributeMap aMap = element->attributes();
621 XMLElement::AttributeMap::Iterator it; 659 XMLElement::AttributeMap::Iterator it;
622 contactMap.clear(); 660 contactMap.clear();
623 customMap.clear(); 661 customMap.clear();
624 for( it = aMap.begin(); it != aMap.end(); ++it ){ 662 for( it = aMap.begin(); it != aMap.end(); ++it ){
625 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); 663 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
626 664
627 int *find = dict[ it.key() ]; 665 int *find = dict[ it.key() ];
628 /* Unknown attributes will be stored as "Custom" elements */ 666 /* Unknown attributes will be stored as "Custom" elements */
629 if ( !find ) { 667 if ( !find ) {
630 qWarning("Attribute %s not known.", it.key().latin1()); 668 qWarning("Attribute %s not known.", it.key().latin1());
631 //contact.setCustomField(it.key(), it.data()); 669 //contact.setCustomField(it.key(), it.data());
632 customMap.insert( it.key(), it.data() ); 670 customMap.insert( it.key(), it.data() );
633 continue; 671 continue;
634 } 672 }
635 673
636 /* Check if special conversion is needed and add attribute 674 /* Check if special conversion is needed and add attribute
637 * into Contact class 675 * into Contact class
638 */ 676 */
639 switch( *find ) { 677 switch( *find ) {
640 /* 678 /*
641 case Qtopia::AddressUid: 679 case Qtopia::AddressUid:
642 contact.setUid( it.data().toInt() ); 680 contact.setUid( it.data().toInt() );
643 break; 681 break;
644 case Qtopia::AddressCategory: 682 case Qtopia::AddressCategory:
645 contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); 683 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
646 break; 684 break;
647 */ 685 */
648 case JOURNALACTION: 686 case JOURNALACTION:
649 action = journal_action(it.data().toInt()); 687 action = journal_action(it.data().toInt());
650 foundAction = true; 688 foundAction = true;
651 qWarning ("ODefBack(journal)::ACTION found: %d", action); 689 qWarning ("ODefBack(journal)::ACTION found: %d", action);
652 break; 690 break;
653 case JOURNALROW: 691 case JOURNALROW:
654 journalKey = it.data().toInt(); 692 journalKey = it.data().toInt();
655 break; 693 break;
656 default: // no conversion needed add them to the map 694 default: // no conversion needed add them to the map
657 contactMap.insert( *find, it.data() ); 695 contactMap.insert( *find, it.data() );
658 break; 696 break;
659 } 697 }
660 } 698 }
661 /* now generate the Contact contact */ 699 /* now generate the Contact contact */
662 OContact contact( contactMap ); 700 OContact contact( contactMap );
663 701
664 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { 702 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
665 contact.setCustomField( customIt.key(), customIt.data() ); 703 contact.setCustomField( customIt.key(), customIt.data() );
666 } 704 }
667 705
668 if (foundAction){ 706 if (foundAction){
669 foundAction = false; 707 foundAction = false;
670 switch ( action ) { 708 switch ( action ) {
671 case ACTION_ADD: 709 case ACTION_ADD:
672 addContact_p (contact); 710 addContact_p (contact);
673 break; 711 break;
674 case ACTION_REMOVE: 712 case ACTION_REMOVE:
675 if ( !remove (contact.uid()) ) 713 if ( !remove (contact.uid()) )
676 qWarning ("ODefBack(journal)::Unable to remove uid: %d", 714 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
677 contact.uid() ); 715 contact.uid() );
678 break; 716 break;
679 case ACTION_REPLACE: 717 case ACTION_REPLACE:
680 if ( !replace ( contact ) ) 718 if ( !replace ( contact ) )
681 qWarning ("ODefBack(journal)::Unable to replace uid: %d", 719 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
682 contact.uid() ); 720 contact.uid() );
683 break; 721 break;
684 default: 722 default:
685 qWarning ("Unknown action: ignored !"); 723 qWarning ("Unknown action: ignored !");
686 break; 724 break;
687 } 725 }
688 }else{ 726 }else{
689 /* Add contact to list */ 727 /* Add contact to list */
690 addContact_p (contact); 728 addContact_p (contact);
691 } 729 }
692 730
693 /* Move to next element */ 731 /* Move to next element */
694 element = element->nextChild(); 732 element = element->nextChild();
695 } 733 }
696 }else { 734 }else {
697 qWarning("ODefBack::could not load"); 735 qWarning("ODefBack::could not load");
698 } 736 }
699 delete root; 737 delete root;
700 qWarning("returning from loading" ); 738 qWarning("returning from loading" );
701 return true; 739 return true;
702} 740}
703 741
704 742
705void OContactAccessBackend_XML::updateJournal( const OContact& cnt, 743void OContactAccessBackend_XML::updateJournal( const OContact& cnt,
706 journal_action action ) 744 journal_action action )
707{ 745{
708 QFile f( m_journalName ); 746 QFile f( m_journalName );
709 bool created = !f.exists(); 747 bool created = !f.exists();
710 if ( !f.open(IO_WriteOnly|IO_Append) ) 748 if ( !f.open(IO_WriteOnly|IO_Append) )
711 return; 749 return;
712 750
713 QString buf; 751 QString buf;
714 QCString str; 752 QCString str;
715 753
716 // if the file was created, we have to set the Tag "<CONTACTS>" to 754 // if the file was created, we have to set the Tag "<CONTACTS>" to
717 // get a XML-File which is readable by our parser. 755 // get a XML-File which is readable by our parser.
718 // This is just a cheat, but better than rewrite the parser. 756 // This is just a cheat, but better than rewrite the parser.
719 if ( created ){ 757 if ( created ){
720 buf = "<Contacts>"; 758 buf = "<Contacts>";
721 QCString cstr = buf.utf8(); 759 QCString cstr = buf.utf8();
722 f.writeBlock( cstr.data(), cstr.length() ); 760 f.writeBlock( cstr.data(), cstr.length() );
723 } 761 }
724 762
725 buf = "<Contact "; 763 buf = "<Contact ";
726 cnt.save( buf ); 764 cnt.save( buf );
727 buf += " action=\"" + QString::number( (int)action ) + "\" "; 765 buf += " action=\"" + QString::number( (int)action ) + "\" ";
728 buf += "/>\n"; 766 buf += "/>\n";
729 QCString cstr = buf.utf8(); 767 QCString cstr = buf.utf8();
730 f.writeBlock( cstr.data(), cstr.length() ); 768 f.writeBlock( cstr.data(), cstr.length() );
731} 769}
732 770
733void OContactAccessBackend_XML::removeJournal() 771void OContactAccessBackend_XML::removeJournal()
734{ 772{
735 QFile f ( m_journalName ); 773 QFile f ( m_journalName );
736 if ( f.exists() ) 774 if ( f.exists() )
737 f.remove(); 775 f.remove();
738} 776}
739 777
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
index 6477705..4d6a7ef 100644
--- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
@@ -1,743 +1,144 @@
1/* 1/*
2 * XML Backend for the OPIE-Contact Database. 2 * XML Backend for the OPIE-Contact Database.
3 * 3 *
4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) 4 * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
5 * 5 *
6 * ===================================================================== 6 * =====================================================================
7 *This program is free software; you can redistribute it and/or 7 *This program is free software; you can redistribute it and/or
8 *modify it under the terms of the GNU Library General Public 8 *modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either 9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version. 10 * version 2 of the License, or (at your option) any later version.
11 * ===================================================================== 11 * =====================================================================
12 * ToDo: XML-Backend: Automatic reload if something was changed... 12 * ToDo: XML-Backend: Automatic reload if something was changed...
13 * 13 *
14 * 14 *
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.13 2003/03/21 10:33:09 eilers
21 * Merged speed optimized xml backend for contacts to main.
22 * Added QDateTime to querybyexample. For instance, it is now possible to get
23 * all Birthdays/Anniversaries between two dates. This should be used
24 * to show all birthdays in the datebook..
25 * This change is sourcecode backward compatible but you have to upgrade
26 * the binaries for today-addressbook.
27 *
28 * Revision 1.12.2.2 2003/02/11 12:17:28 eilers
29 * Speed optimization. Removed the sequential search loops.
30 *
31 * Revision 1.12.2.1 2003/02/09 15:05:01 eilers
32 * Nothing happened.. Just some cleanup before I will start..
33 *
20 * Revision 1.12 2003/01/03 16:58:03 eilers 34 * Revision 1.12 2003/01/03 16:58:03 eilers
21 * Reenable debug output 35 * Reenable debug output
22 * 36 *
23 * Revision 1.11 2003/01/03 12:31:28 eilers 37 * Revision 1.11 2003/01/03 12:31:28 eilers
24 * Bugfix for calculating data diffs.. 38 * Bugfix for calculating data diffs..
25 * 39 *
26 * Revision 1.10 2003/01/02 14:27:12 eilers 40 * Revision 1.10 2003/01/02 14:27:12 eilers
27 * Improved query by example: Search by date is possible.. First step 41 * Improved query by example: Search by date is possible.. First step
28 * for a today plugin for birthdays.. 42 * for a today plugin for birthdays..
29 * 43 *
30 * Revision 1.9 2002/12/08 12:48:57 eilers 44 * Revision 1.9 2002/12/08 12:48:57 eilers
31 * Moved journal-enum from ocontact into i the xml-backend.. 45 * Moved journal-enum from ocontact into i the xml-backend..
32 * 46 *
33 * Revision 1.8 2002/11/14 17:04:24 eilers 47 * Revision 1.8 2002/11/14 17:04:24 eilers
34 * Sorting will now work if fullname is identical on some entries 48 * Sorting will now work if fullname is identical on some entries
35 * 49 *
36 * Revision 1.7 2002/11/13 15:02:46 eilers 50 * Revision 1.7 2002/11/13 15:02:46 eilers
37 * Small Bug in sorted fixed 51 * Small Bug in sorted fixed
38 * 52 *
39 * Revision 1.6 2002/11/13 14:14:51 eilers 53 * Revision 1.6 2002/11/13 14:14:51 eilers
40 * Added sorted for Contacts.. 54 * Added sorted for Contacts..
41 * 55 *
42 * Revision 1.5 2002/11/01 15:10:42 eilers 56 * Revision 1.5 2002/11/01 15:10:42 eilers
43 * Added regExp-search in database for all fields in a contact. 57 * Added regExp-search in database for all fields in a contact.
44 * 58 *
45 * Revision 1.4 2002/10/16 10:52:40 eilers 59 * Revision 1.4 2002/10/16 10:52:40 eilers
46 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 60 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
47 * 61 *
48 * Revision 1.3 2002/10/14 16:21:54 eilers 62 * Revision 1.3 2002/10/14 16:21:54 eilers
49 * Some minor interface updates 63 * Some minor interface updates
50 * 64 *
51 * Revision 1.2 2002/10/07 17:34:24 eilers 65 * Revision 1.2 2002/10/07 17:34:24 eilers
52 * added OBackendFactory for advanced backend access 66 * added OBackendFactory for advanced backend access
53 * 67 *
54 * Revision 1.1 2002/09/27 17:11:44 eilers 68 * Revision 1.1 2002/09/27 17:11:44 eilers
55 * Added API for accessing the Contact-Database ! It is compiling, but 69 * Added API for accessing the Contact-Database ! It is compiling, but
56 * please do not expect that anything is working ! 70 * please do not expect that anything is working !
57 * I will debug that stuff in the next time .. 71 * I will debug that stuff in the next time ..
58 * Please read README_COMPILE for compiling ! 72 * Please read README_COMPILE for compiling !
59 * 73 *
60 * 74 *
61 */ 75 */
62 76
63#ifndef _OContactAccessBackend_XML_ 77#ifndef _OContactAccessBackend_XML_
64#define _OContactAccessBackend_XML_ 78#define _OContactAccessBackend_XML_
65 79
66#include <qasciidict.h>
67#include <qdatetime.h>
68#include <qfile.h>
69#include <qfileinfo.h>
70#include <qregexp.h>
71#include <qarray.h>
72#include <qmap.h>
73#include <qdatetime.h>
74
75#include <qpe/global.h>
76
77#include <opie/xmltree.h>
78#include "ocontactaccessbackend.h" 80#include "ocontactaccessbackend.h"
79#include "ocontactaccess.h" 81#include "ocontactaccess.h"
80 82
81#include <stdlib.h> 83#include <qlist.h>
82#include <errno.h> 84#include <qdict.h>
83
84using namespace Opie;
85 85
86/* the default xml implementation */ 86/* the default xml implementation */
87class OContactAccessBackend_XML : public OContactAccessBackend { 87class OContactAccessBackend_XML : public OContactAccessBackend {
88 public: 88 public:
89 OContactAccessBackend_XML ( QString appname, QString filename = 0l ): 89 OContactAccessBackend_XML ( QString appname, QString filename = 0l );
90 m_changed( false )
91 {
92 m_appName = appname;
93
94 /* Set journalfile name ... */
95 m_journalName = getenv("HOME");
96 m_journalName +="/.abjournal" + appname;
97
98 /* Expecting to access the default filename if nothing else is set */
99 if ( filename.isEmpty() ){
100 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
101 } else
102 m_fileName = filename;
103
104 /* Load Database now */
105 load ();
106 }
107 90
108 bool save() { 91 bool save();
109
110 if ( !m_changed )
111 return true;
112
113 QString strNewFile = m_fileName + ".new";
114 QFile f( strNewFile );
115 if ( !f.open( IO_WriteOnly|IO_Raw ) )
116 return false;
117
118 int total_written;
119 QString out;
120 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
121 " <Groups>\n"
122 " </Groups>\n"
123 " <Contacts>\n";
124 //QValueList<Contact>::iterator it;
125 QValueListConstIterator<OContact> it;
126 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) {
127 out += "<Contact ";
128 (*it).save( out );
129 out += "/>\n";
130 QCString cstr = out.utf8();
131 total_written = f.writeBlock( cstr.data(), cstr.length() );
132 if ( total_written != int(cstr.length()) ) {
133 f.close();
134 QFile::remove( strNewFile );
135 return false;
136 }
137 out = "";
138 }
139 out += " </Contacts>\n</AddressBook>\n";
140
141 QCString cstr = out.utf8();
142 total_written = f.writeBlock( cstr.data(), cstr.length() );
143 if ( total_written != int( cstr.length() ) ) {
144 f.close();
145 QFile::remove( strNewFile );
146 return false;
147 }
148 f.close();
149
150 // move the file over, I'm just going to use the system call
151 // because, I don't feel like using QDir.
152 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
153 qWarning( "problem renaming file %s to %s, errno: %d",
154 strNewFile.latin1(), m_journalName.latin1(), errno );
155 // remove the tmp file...
156 QFile::remove( strNewFile );
157 }
158
159 /* The journalfile should be removed now... */
160 removeJournal();
161
162 m_changed = false;
163 return true;
164 }
165 92
166 bool load () { 93 bool load ();
167 m_contactList.clear();
168
169 /* Load XML-File and journal if it exists */
170 if ( !load ( m_fileName, false ) )
171 return false;
172 /* The returncode of the journalfile is ignored due to the
173 * fact that it does not exist when this class is instantiated !
174 * But there may such a file exist, if the application crashed.
175 * Therefore we try to load it to get the changes before the #
176 * crash happened...
177 */
178 load (m_journalName, true);
179
180 return true;
181 }
182
183 void clear () {
184 m_contactList.clear();
185 m_changed = false;
186 94
187 } 95 void clear ();
188 96
189 bool wasChangedExternally() 97 bool wasChangedExternally();
190 {
191 QFileInfo fi( m_fileName );
192
193 QDateTime lastmod = fi.lastModified ();
194
195 return (lastmod != m_readtime);
196 }
197 98
198 QArray<int> allRecords() const { 99 QArray<int> allRecords() const;
199 QArray<int> uid_list( m_contactList.count() );
200
201 uint counter = 0;
202 QValueListConstIterator<OContact> it;
203 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
204 uid_list[counter++] = (*it).uid();
205 }
206
207 return ( uid_list );
208 }
209 100
210 OContact find ( int uid ) const 101 OContact find ( int uid ) const;
211 {
212 bool found = false;
213 OContact foundContact; //Create empty contact
214
215 QValueListConstIterator<OContact> it;
216 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
217 if ((*it).uid() == uid){
218 found = true;
219 break;
220 }
221 }
222 if ( found ){
223 foundContact = *it;
224 }
225
226 return ( foundContact );
227 }
228 102
229 QArray<int> queryByExample ( const OContact &query, int settings ){ 103 QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() );
230
231 QArray<int> m_currentQuery( m_contactList.count() );
232 QValueListConstIterator<OContact> it;
233 uint arraycounter = 0;
234
235 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
236 /* Search all fields and compare them with query object. Store them into list
237 * if all fields matches.
238 */
239 QDate* queryDate = 0l;
240 QDate* checkDate = 0l;
241 bool allcorrect = true;
242 for ( int i = 0; i < Qtopia::Groups; i++ ) {
243 // Birthday and anniversary are special nonstring fields and should
244 // be handled specially
245 switch ( i ){
246 case Qtopia::Birthday:
247 queryDate = new QDate( query.birthday() );
248 checkDate = new QDate( (*it).birthday() );
249 case Qtopia::Anniversary:
250 if ( queryDate == 0l ){
251 queryDate = new QDate( query.anniversary() );
252 checkDate = new QDate( (*it).anniversary() );
253 }
254
255 if ( queryDate->isValid() ){
256 if( checkDate->isValid() ){
257 if ( settings & OContactAccess::DateYear ){
258 if ( queryDate->year() != checkDate->year() )
259 allcorrect = false;
260 }
261 if ( settings & OContactAccess::DateMonth ){
262 if ( queryDate->month() != checkDate->month() )
263 allcorrect = false;
264 }
265 if ( settings & OContactAccess::DateDay ){
266 if ( queryDate->day() != checkDate->day() )
267 allcorrect = false;
268 }
269 if ( settings & OContactAccess::DateDiff ) {
270 QDate current = QDate::currentDate();
271 // We have to equalize the year, otherwise
272 // the search will fail..
273 checkDate->setYMD( current.year(),
274 checkDate->month(),
275 checkDate->day() );
276 if ( *checkDate < current )
277 checkDate->setYMD( current.year()+1,
278 checkDate->month(),
279 checkDate->day() );
280 qWarning("Checking if %s is between %s and %s ! ",
281 checkDate->toString().latin1(),
282 current.toString().latin1(),
283 queryDate->toString().latin1() );
284 if ( current.daysTo( *queryDate ) > 0 ){
285 if ( !( ( *checkDate >= current ) &&
286 ( *checkDate <= *queryDate ) ) ){
287 allcorrect = false;
288 qWarning (" Nope!..");
289 }
290 }
291 }
292 } else{
293 // checkDate is invalid. Therfore this entry is always rejected
294 allcorrect = false;
295 }
296 }
297
298 delete queryDate;
299 queryDate = 0l;
300 delete checkDate;
301 checkDate = 0l;
302 break;
303 default:
304 /* Just compare fields which are not empty in the query object */
305 if ( !query.field(i).isEmpty() ){
306 switch ( settings & ~( OContactAccess::IgnoreCase
307 | OContactAccess::DateDiff
308 | OContactAccess::DateYear
309 | OContactAccess::DateMonth
310 | OContactAccess::DateDay
311 | OContactAccess::MatchOne
312 ) ){
313 104
314 case OContactAccess::RegExp:{ 105 QArray<int> matchRegexp( const QRegExp &r ) const;
315 QRegExp expr ( query.field(i),
316 !(settings & OContactAccess::IgnoreCase),
317 false );
318 if ( expr.find ( (*it).field(i), 0 ) == -1 )
319 allcorrect = false;
320 }
321 break;
322 case OContactAccess::WildCards:{
323 QRegExp expr ( query.field(i),
324 !(settings & OContactAccess::IgnoreCase),
325 true );
326 if ( expr.find ( (*it).field(i), 0 ) == -1 )
327 allcorrect = false;
328 }
329 break;
330 case OContactAccess::ExactMatch:{
331 if (settings & OContactAccess::IgnoreCase){
332 if ( query.field(i).upper() !=
333 (*it).field(i).upper() )
334 allcorrect = false;
335 }else{
336 if ( query.field(i) != (*it).field(i) )
337 allcorrect = false;
338 }
339 }
340 break;
341 }
342 }
343 }
344 }
345 if ( allcorrect ){
346 m_currentQuery[arraycounter++] = (*it).uid();
347 }
348 }
349
350 // Shrink to fit..
351 m_currentQuery.resize(arraycounter);
352 106
353 return m_currentQuery; 107 const uint querySettings();
354 }
355
356 QArray<int> matchRegexp( const QRegExp &r ) const{
357 QArray<int> m_currentQuery( m_contactList.count() );
358 QValueListConstIterator<OContact> it;
359 uint arraycounter = 0;
360
361 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
362 if ( (*it).match( r ) ){
363 m_currentQuery[arraycounter++] = (*it).uid();
364 }
365
366 }
367 // Shrink to fit..
368 m_currentQuery.resize(arraycounter);
369
370 return m_currentQuery;
371 }
372
373 const uint querySettings()
374 {
375 return ( OContactAccess::WildCards
376 | OContactAccess::IgnoreCase
377 | OContactAccess::RegExp
378 | OContactAccess::ExactMatch
379 | OContactAccess::DateDiff
380 | OContactAccess::DateYear
381 | OContactAccess::DateMonth
382 | OContactAccess::DateDay
383 );
384 }
385 108
386 bool hasQuerySettings (uint querySettings) const 109 bool hasQuerySettings (uint querySettings) const;
387 {
388 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
389 * may be added with any of the other settings. IgnoreCase should never used alone.
390 * Wildcards, RegExp, ExactMatch should never used at the same time...
391 */
392
393 if ( querySettings == OContactAccess::IgnoreCase )
394 return false;
395
396 switch ( querySettings & ~( OContactAccess::IgnoreCase
397 | OContactAccess::DateDiff
398 | OContactAccess::DateYear
399 | OContactAccess::DateMonth
400 | OContactAccess::DateDay
401 )
402 ){
403 case OContactAccess::RegExp:
404 return ( true );
405 case OContactAccess::WildCards:
406 return ( true );
407 case OContactAccess::ExactMatch:
408 return ( true );
409 default:
410 return ( false );
411 }
412 }
413 110
414 // Currently only asc implemented.. 111 // Currently only asc implemented..
415 QArray<int> sorted( bool asc, int , int , int ) 112 QArray<int> sorted( bool asc, int , int , int );
416 { 113 bool add ( const OContact &newcontact );
417 QMap<QString, int> nameToUid;
418 QStringList names;
419 QArray<int> m_currentQuery( m_contactList.count() );
420
421 // First fill map and StringList with all Names
422 // Afterwards sort namelist and use map to fill array to return..
423 QValueListConstIterator<OContact> it;
424 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
425 names.append( (*it).fileAs() + QString::number( (*it).uid() ) );
426 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() );
427 }
428 names.sort();
429
430 int i = 0;
431 if ( asc ){
432 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
433 m_currentQuery[i++] = nameToUid[ (*it) ];
434 }else{
435 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
436 m_currentQuery[i++] = nameToUid[ (*it) ];
437 }
438
439 return m_currentQuery;
440
441 }
442 bool add ( const OContact &newcontact )
443 {
444 //qWarning("odefaultbackend: ACTION::ADD");
445 updateJournal (newcontact, ACTION_ADD);
446 addContact_p( newcontact );
447
448 m_changed = true;
449
450 return true;
451 }
452
453 bool replace ( const OContact &contact )
454 {
455 m_changed = true;
456
457 bool found = false;
458
459 QValueListIterator<OContact> it;
460 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
461 if ( (*it).uid() == contact.uid() ){
462 found = true;
463 break;
464 }
465 }
466 if (found) {
467 updateJournal (contact, ACTION_REPLACE);
468 m_contactList.remove (it);
469 m_contactList.append (contact);
470 return true;
471 } else
472 return false;
473 }
474 114
475 bool remove ( int uid ) 115 bool replace ( const OContact &contact );
476 {
477 m_changed = true;
478
479 bool found = false;
480 QValueListIterator<OContact> it;
481 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
482 if ((*it).uid() == uid){
483 found = true;
484 break;
485 }
486 }
487 if (found) {
488 updateJournal ( *it, ACTION_REMOVE);
489 m_contactList.remove (it);
490 return true;
491 } else
492 return false;
493 }
494 116
495 bool reload(){ 117 bool remove ( int uid );
496 /* Reload is the same as load in this implementation */ 118 bool reload();
497 return ( load() );
498 }
499 119
500 private: 120 private:
501 121
502 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; 122 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE };
503 123
504 void addContact_p( const OContact &newcontact ){ 124 void addContact_p( const OContact &newcontact );
505 m_contactList.append (newcontact);
506 }
507 125
508 /* This function loads the xml-database and the journalfile */ 126 /* This function loads the xml-database and the journalfile */
509 bool load( const QString filename, bool isJournal ) { 127 bool load( const QString filename, bool isJournal );
510
511 /* We use the time of the last read to check if the file was
512 * changed externally.
513 */
514 if ( !isJournal ){
515 QFileInfo fi( filename );
516 m_readtime = fi.lastModified ();
517 }
518
519 const int JOURNALACTION = Qtopia::Notes + 1;
520 const int JOURNALROW = JOURNALACTION + 1;
521
522 bool foundAction = false;
523 journal_action action = ACTION_ADD;
524 int journalKey = 0;
525 QMap<int, QString> contactMap;
526 QMap<QString, QString> customMap;
527 QMap<QString, QString>::Iterator customIt;
528 QAsciiDict<int> dict( 47 );
529
530 dict.setAutoDelete( TRUE );
531 dict.insert( "Uid", new int(Qtopia::AddressUid) );
532 dict.insert( "Title", new int(Qtopia::Title) );
533 dict.insert( "FirstName", new int(Qtopia::FirstName) );
534 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
535 dict.insert( "LastName", new int(Qtopia::LastName) );
536 dict.insert( "Suffix", new int(Qtopia::Suffix) );
537 dict.insert( "FileAs", new int(Qtopia::FileAs) );
538 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
539 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
540 dict.insert( "Emails", new int(Qtopia::Emails) );
541 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
542 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
543 dict.insert( "HomeState", new int(Qtopia::HomeState) );
544 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
545 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
546 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
547 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
548 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
549 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
550 dict.insert( "Company", new int(Qtopia::Company) );
551 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
552 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
553 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
554 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
555 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
556 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
557 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
558 dict.insert( "Department", new int(Qtopia::Department) );
559 dict.insert( "Office", new int(Qtopia::Office) );
560 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
561 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
562 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
563 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
564 dict.insert( "Profession", new int(Qtopia::Profession) );
565 dict.insert( "Assistant", new int(Qtopia::Assistant) );
566 dict.insert( "Manager", new int(Qtopia::Manager) );
567 dict.insert( "Spouse", new int(Qtopia::Spouse) );
568 dict.insert( "Children", new int(Qtopia::Children) );
569 dict.insert( "Gender", new int(Qtopia::Gender) );
570 dict.insert( "Birthday", new int(Qtopia::Birthday) );
571 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
572 dict.insert( "Nickname", new int(Qtopia::Nickname) );
573 dict.insert( "Notes", new int(Qtopia::Notes) );
574 dict.insert( "action", new int(JOURNALACTION) );
575 dict.insert( "actionrow", new int(JOURNALROW) );
576
577 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
578
579 XMLElement *root = XMLElement::load( filename );
580 if(root != 0l ){ // start parsing
581 /* Parse all XML-Elements and put the data into the
582 * Contact-Class
583 */
584 XMLElement *element = root->firstChild();
585 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
586 element = element->firstChild();
587
588 /* Search Tag "Contacts" which is the parent of all Contacts */
589 while( element && !isJournal ){
590 if( element->tagName() != QString::fromLatin1("Contacts") ){
591 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
592 // element->tagName().latin1());
593 element = element->nextChild();
594 } else {
595 element = element->firstChild();
596 break;
597 }
598 }
599 /* Parse all Contacts and ignore unknown tags */
600 while( element ){
601 if( element->tagName() != QString::fromLatin1("Contact") ){
602 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
603 // element->tagName().latin1());
604 element = element->nextChild();
605 continue;
606 }
607 /* Found alement with tagname "contact", now parse and store all
608 * attributes contained
609 */
610 //qWarning("OContactDefBack::load element tagName() : %s",
611 // element->tagName().latin1() );
612 QString dummy;
613 foundAction = false;
614
615 XMLElement::AttributeMap aMap = element->attributes();
616 XMLElement::AttributeMap::Iterator it;
617 contactMap.clear();
618 customMap.clear();
619 for( it = aMap.begin(); it != aMap.end(); ++it ){
620 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
621
622 int *find = dict[ it.key() ];
623 /* Unknown attributes will be stored as "Custom" elements */
624 if ( !find ) {
625 qWarning("Attribute %s not known.", it.key().latin1());
626 //contact.setCustomField(it.key(), it.data());
627 customMap.insert( it.key(), it.data() );
628 continue;
629 }
630
631 /* Check if special conversion is needed and add attribute
632 * into Contact class
633 */
634 switch( *find ) {
635 /*
636 case Qtopia::AddressUid:
637 contact.setUid( it.data().toInt() );
638 break;
639 case Qtopia::AddressCategory:
640 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
641 break;
642 */
643 case JOURNALACTION:
644 action = journal_action(it.data().toInt());
645 foundAction = true;
646 qWarning ("ODefBack(journal)::ACTION found: %d", action);
647 break;
648 case JOURNALROW:
649 journalKey = it.data().toInt();
650 break;
651 default: // no conversion needed add them to the map
652 contactMap.insert( *find, it.data() );
653 break;
654 }
655 }
656 /* now generate the Contact contact */
657 OContact contact( contactMap );
658
659 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
660 contact.setCustomField( customIt.key(), customIt.data() );
661 }
662
663 if (foundAction){
664 foundAction = false;
665 switch ( action ) {
666 case ACTION_ADD:
667 addContact_p (contact);
668 break;
669 case ACTION_REMOVE:
670 if ( !remove (contact.uid()) )
671 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
672 contact.uid() );
673 break;
674 case ACTION_REPLACE:
675 if ( !replace ( contact ) )
676 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
677 contact.uid() );
678 break;
679 default:
680 qWarning ("Unknown action: ignored !");
681 break;
682 }
683 }else{
684 /* Add contact to list */
685 addContact_p (contact);
686 }
687
688 /* Move to next element */
689 element = element->nextChild();
690 }
691 }else {
692 qWarning("ODefBack::could not load");
693 }
694 delete root;
695 qWarning("returning from loading" );
696 return true;
697 }
698
699 128
700 void updateJournal( const OContact& cnt,
701 journal_action action ) {
702 QFile f( m_journalName );
703 bool created = !f.exists();
704 if ( !f.open(IO_WriteOnly|IO_Append) )
705 return;
706
707 QString buf;
708 QCString str;
709
710 // if the file was created, we have to set the Tag "<CONTACTS>" to
711 // get a XML-File which is readable by our parser.
712 // This is just a cheat, but better than rewrite the parser.
713 if ( created ){
714 buf = "<Contacts>";
715 QCString cstr = buf.utf8();
716 f.writeBlock( cstr.data(), cstr.length() );
717 }
718
719 buf = "<Contact ";
720 cnt.save( buf );
721 buf += " action=\"" + QString::number( (int)action ) + "\" ";
722 buf += "/>\n";
723 QCString cstr = buf.utf8();
724 f.writeBlock( cstr.data(), cstr.length() );
725 }
726 129
727 void removeJournal() 130 void updateJournal( const OContact& cnt, journal_action action );
728 { 131 void removeJournal();
729 QFile f ( m_journalName );
730 if ( f.exists() )
731 f.remove();
732 }
733 132
734 protected: 133 protected:
735 bool m_changed; 134 bool m_changed;
736 QString m_journalName; 135 QString m_journalName;
737 QString m_fileName; 136 QString m_fileName;
738 QString m_appName; 137 QString m_appName;
739 QValueList<OContact> m_contactList; 138 QList<OContact> m_contactList;
740 QDateTime m_readtime; 139 QDateTime m_readtime;
140
141 QDict<OContact> m_uidToContact;
741}; 142};
742 143
743#endif 144#endif
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
index 4a6b7b8..11e19d9 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
+++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
@@ -1,587 +1,587 @@
1#include <errno.h> 1#include <errno.h>
2#include <fcntl.h> 2#include <fcntl.h>
3 3
4#include <stdio.h> 4#include <stdio.h>
5#include <stdlib.h> 5#include <stdlib.h>
6 6
7#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/mman.h> 8#include <sys/mman.h>
9#include <sys/stat.h> 9#include <sys/stat.h>
10 10
11#include <unistd.h> 11#include <unistd.h>
12 12
13#include <qasciidict.h> 13#include <qasciidict.h>
14#include <qfile.h> 14#include <qfile.h>
15 15
16#include <qtopia/global.h> 16#include <qtopia/global.h>
17#include <qtopia/stringutil.h> 17#include <qtopia/stringutil.h>
18#include <qtopia/timeconversion.h> 18#include <qtopia/timeconversion.h>
19 19
20#include "opimnotifymanager.h" 20#include "opimnotifymanager.h"
21#include "orecur.h" 21#include "orecur.h"
22#include "otimezone.h" 22#include "otimezone.h"
23#include "odatebookaccessbackend_xml.h" 23#include "odatebookaccessbackend_xml.h"
24 24
25namespace { 25namespace {
26 // FROM TT again 26 // FROM TT again
27char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) 27char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
28{ 28{
29 char needleChar; 29 char needleChar;
30 char haystackChar; 30 char haystackChar;
31 if (!needle || !haystack || !hLen || !nLen) 31 if (!needle || !haystack || !hLen || !nLen)
32 return 0; 32 return 0;
33 33
34 const char* hsearch = haystack; 34 const char* hsearch = haystack;
35 35
36 if ((needleChar = *needle++) != 0) { 36 if ((needleChar = *needle++) != 0) {
37 nLen--; //(to make up for needle++) 37 nLen--; //(to make up for needle++)
38 do { 38 do {
39 do { 39 do {
40 if ((haystackChar = *hsearch++) == 0) 40 if ((haystackChar = *hsearch++) == 0)
41 return (0); 41 return (0);
42 if (hsearch >= haystack + hLen) 42 if (hsearch >= haystack + hLen)
43 return (0); 43 return (0);
44 } while (haystackChar != needleChar); 44 } while (haystackChar != needleChar);
45 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); 45 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
46 hsearch--; 46 hsearch--;
47 } 47 }
48 return ((char *)hsearch); 48 return ((char *)hsearch);
49} 49}
50} 50}
51 51
52namespace { 52namespace {
53 time_t start, end, created, rp_end; 53 time_t start, end, created, rp_end;
54 ORecur* rec; 54 ORecur* rec;
55 ORecur* recur() { 55 ORecur* recur() {
56 if (!rec) 56 if (!rec)
57 rec = new ORecur; 57 rec = new ORecur;
58 58
59 return rec; 59 return rec;
60 } 60 }
61 int alarmTime; 61 int alarmTime;
62 int snd; 62 int snd;
63 enum Attribute{ 63 enum Attribute{
64 FDescription = 0, 64 FDescription = 0,
65 FLocation, 65 FLocation,
66 FCategories, 66 FCategories,
67 FUid, 67 FUid,
68 FType, 68 FType,
69 FAlarm, 69 FAlarm,
70 FSound, 70 FSound,
71 FRType, 71 FRType,
72 FRWeekdays, 72 FRWeekdays,
73 FRPosition, 73 FRPosition,
74 FRFreq, 74 FRFreq,
75 FRHasEndDate, 75 FRHasEndDate,
76 FREndDate, 76 FREndDate,
77 FRStart, 77 FRStart,
78 FREnd, 78 FREnd,
79 FNote, 79 FNote,
80 FCreated, 80 FCreated,
81 FTimeZone, 81 FTimeZone,
82 FRecParent, 82 FRecParent,
83 FRecChildren, 83 FRecChildren,
84 FExceptions 84 FExceptions
85 }; 85 };
86 inline void save( const OEvent& ev, QString& buf ) { 86 inline void save( const OEvent& ev, QString& buf ) {
87 qWarning("Saving %d %s", ev.uid(), ev.description().latin1() ); 87 qWarning("Saving %d %s", ev.uid(), ev.description().latin1() );
88 buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; 88 buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\"";
89 if (!ev.location().isEmpty() ) 89 if (!ev.location().isEmpty() )
90 buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; 90 buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\"";
91 91
92 buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; 92 buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\"";
93 buf += " uid=\"" + QString::number( ev.uid() ) + "\""; 93 buf += " uid=\"" + QString::number( ev.uid() ) + "\"";
94 94
95 if (ev.isAllDay() ) 95 if (ev.isAllDay() )
96 buf += " type=\"AllDay\""; 96 buf += " type=\"AllDay\"";
97 97
98 if (ev.hasNotifiers() ) { 98 if (ev.hasNotifiers() ) {
99 OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first 99 OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first
100 int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; 100 int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60;
101 buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; 101 buf += " alarm=\"" + QString::number(minutes) + "\" sound=\"";
102 if ( alarm.sound() == OPimAlarm::Loud ) 102 if ( alarm.sound() == OPimAlarm::Loud )
103 buf += "loud"; 103 buf += "loud";
104 else 104 else
105 buf += "silent"; 105 buf += "silent";
106 buf += "\""; 106 buf += "\"";
107 } 107 }
108 if ( ev.hasRecurrence() ) { 108 if ( ev.hasRecurrence() ) {
109 buf += ev.recurrence().toString(); 109 buf += ev.recurrence().toString();
110 } 110 }
111 111
112 /* 112 /*
113 * fscking timezones :) well, we'll first convert 113 * fscking timezones :) well, we'll first convert
114 * the QDateTime to a QDateTime in UTC time 114 * the QDateTime to a QDateTime in UTC time
115 * and then we'll create a nice time_t 115 * and then we'll create a nice time_t
116 */ 116 */
117 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); 117 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
118 buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; 118 buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\"";
119 buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; 119 buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\"";
120 if (!ev.note().isEmpty() ) { 120 if (!ev.note().isEmpty() ) {
121 buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; 121 buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\"";
122 } 122 }
123 123
124 buf += " timezone=\""; 124 buf += " timezone=\"";
125 if ( ev.timeZone().isEmpty() ) 125 if ( ev.timeZone().isEmpty() )
126 buf += "None"; 126 buf += "None";
127 else 127 else
128 buf += ev.timeZone(); 128 buf += ev.timeZone();
129 buf += "\""; 129 buf += "\"";
130 130
131 if (ev.parent() != 0 ) { 131 if (ev.parent() != 0 ) {
132 buf += " recparent=\""+QString::number(ev.parent() )+"\""; 132 buf += " recparent=\""+QString::number(ev.parent() )+"\"";
133 } 133 }
134 134
135 if (ev.children().count() != 0 ) { 135 if (ev.children().count() != 0 ) {
136 QArray<int> children = ev.children(); 136 QArray<int> children = ev.children();
137 buf += " recchildren=\""; 137 buf += " recchildren=\"";
138 for ( uint i = 0; i < children.count(); i++ ) { 138 for ( uint i = 0; i < children.count(); i++ ) {
139 if ( i != 0 ) buf += " "; 139 if ( i != 0 ) buf += " ";
140 buf += QString::number( children[i] ); 140 buf += QString::number( children[i] );
141 } 141 }
142 buf+= "\""; 142 buf+= "\"";
143 } 143 }
144 144
145 // skip custom writing 145 // skip custom writing
146 } 146 }
147 147
148 inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { 148 inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) {
149 QMap<int, OEvent>::ConstIterator it; 149 QMap<int, OEvent>::ConstIterator it;
150 QString buf; 150 QString buf;
151 QCString str; 151 QCString str;
152 int total_written; 152 int total_written;
153 for ( it = list.begin(); it != list.end(); ++it ) { 153 for ( it = list.begin(); it != list.end(); ++it ) {
154 buf = "<event"; 154 buf = "<event";
155 save( it.data(), buf ); 155 save( it.data(), buf );
156 buf += " />\n"; 156 buf += " />\n";
157 str = buf.utf8(); 157 str = buf.utf8();
158 158
159 total_written = file.writeBlock(str.data(), str.length() ); 159 total_written = file.writeBlock(str.data(), str.length() );
160 if ( total_written != int(str.length() ) ) 160 if ( total_written != int(str.length() ) )
161 return false; 161 return false;
162 } 162 }
163 return true; 163 return true;
164 } 164 }
165} 165}
166 166
167ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , 167ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& ,
168 const QString& fileName ) 168 const QString& fileName )
169 : ODateBookAccessBackend() { 169 : ODateBookAccessBackend() {
170 m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; 170 m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName;
171 m_changed = false; 171 m_changed = false;
172} 172}
173ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { 173ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() {
174} 174}
175bool ODateBookAccessBackend_XML::load() { 175bool ODateBookAccessBackend_XML::load() {
176 return loadFile(); 176 return loadFile();
177} 177}
178bool ODateBookAccessBackend_XML::reload() { 178bool ODateBookAccessBackend_XML::reload() {
179 clear(); 179 clear();
180 return load(); 180 return load();
181} 181}
182bool ODateBookAccessBackend_XML::save() { 182bool ODateBookAccessBackend_XML::save() {
183 if (!m_changed) return true; 183 if (!m_changed) return true;
184 184
185 int total_written; 185 int total_written;
186 QString strFileNew = m_name + ".new"; 186 QString strFileNew = m_name + ".new";
187 187
188 QFile f( strFileNew ); 188 QFile f( strFileNew );
189 if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; 189 if (!f.open( IO_WriteOnly | IO_Raw ) ) return false;
190 190
191 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); 191 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
192 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; 192 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
193 buf += "<events>\n"; 193 buf += "<events>\n";
194 QCString str = buf.utf8(); 194 QCString str = buf.utf8();
195 total_written = f.writeBlock( str.data(), str.length() ); 195 total_written = f.writeBlock( str.data(), str.length() );
196 if ( total_written != int(str.length() ) ) { 196 if ( total_written != int(str.length() ) ) {
197 f.close(); 197 f.close();
198 QFile::remove( strFileNew ); 198 QFile::remove( strFileNew );
199 return false; 199 return false;
200 } 200 }
201 201
202 if (!forAll( m_raw, f ) ) { 202 if (!forAll( m_raw, f ) ) {
203 f.close(); 203 f.close();
204 QFile::remove( strFileNew ); 204 QFile::remove( strFileNew );
205 return false; 205 return false;
206 } 206 }
207 if (!forAll( m_rep, f ) ) { 207 if (!forAll( m_rep, f ) ) {
208 f.close(); 208 f.close();
209 QFile::remove( strFileNew ); 209 QFile::remove( strFileNew );
210 return false; 210 return false;
211 } 211 }
212 212
213 buf = "</events>\n</DATEBOOK>\n"; 213 buf = "</events>\n</DATEBOOK>\n";
214 str = buf.utf8(); 214 str = buf.utf8();
215 total_written = f.writeBlock( str.data(), str.length() ); 215 total_written = f.writeBlock( str.data(), str.length() );
216 if ( total_written != int(str.length() ) ) { 216 if ( total_written != int(str.length() ) ) {
217 f.close(); 217 f.close();
218 QFile::remove( strFileNew ); 218 QFile::remove( strFileNew );
219 return false; 219 return false;
220 } 220 }
221 f.close(); 221 f.close();
222 222
223 if ( ::rename( strFileNew, m_name ) < 0 ) { 223 if ( ::rename( strFileNew, m_name ) < 0 ) {
224 QFile::remove( strFileNew ); 224 QFile::remove( strFileNew );
225 return false; 225 return false;
226 } 226 }
227 227
228 m_changed = false; 228 m_changed = false;
229 return true; 229 return true;
230} 230}
231QArray<int> ODateBookAccessBackend_XML::allRecords()const { 231QArray<int> ODateBookAccessBackend_XML::allRecords()const {
232 QArray<int> ints( m_raw.count()+ m_rep.count() ); 232 QArray<int> ints( m_raw.count()+ m_rep.count() );
233 uint i = 0; 233 uint i = 0;
234 QMap<int, OEvent>::ConstIterator it; 234 QMap<int, OEvent>::ConstIterator it;
235 235
236 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { 236 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
237 ints[i] = it.key(); 237 ints[i] = it.key();
238 i++; 238 i++;
239 } 239 }
240 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { 240 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
241 ints[i] = it.key(); 241 ints[i] = it.key();
242 i++; 242 i++;
243 } 243 }
244 244
245 return ints; 245 return ints;
246} 246}
247QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int ) { 247QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) {
248 return QArray<int>(); 248 return QArray<int>();
249} 249}
250void ODateBookAccessBackend_XML::clear() { 250void ODateBookAccessBackend_XML::clear() {
251 m_raw.clear(); 251 m_raw.clear();
252 m_rep.clear(); 252 m_rep.clear();
253} 253}
254OEvent ODateBookAccessBackend_XML::find( int uid ) const{ 254OEvent ODateBookAccessBackend_XML::find( int uid ) const{
255 if ( m_raw.contains( uid ) ) 255 if ( m_raw.contains( uid ) )
256 return m_raw[uid]; 256 return m_raw[uid];
257 else 257 else
258 return m_rep[uid]; 258 return m_rep[uid];
259} 259}
260bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { 260bool ODateBookAccessBackend_XML::add( const OEvent& ev ) {
261 m_changed = true; 261 m_changed = true;
262 if (ev.hasRecurrence() ) 262 if (ev.hasRecurrence() )
263 m_rep.insert( ev.uid(), ev ); 263 m_rep.insert( ev.uid(), ev );
264 else 264 else
265 m_raw.insert( ev.uid(), ev ); 265 m_raw.insert( ev.uid(), ev );
266 266
267 return true; 267 return true;
268} 268}
269bool ODateBookAccessBackend_XML::remove( int uid ) { 269bool ODateBookAccessBackend_XML::remove( int uid ) {
270 m_changed = true; 270 m_changed = true;
271 m_rep.remove( uid ); 271 m_rep.remove( uid );
272 m_rep.remove( uid ); 272 m_rep.remove( uid );
273 273
274 return true; 274 return true;
275} 275}
276bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) { 276bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) {
277 replace( ev.uid() ); 277 replace( ev.uid() );
278 return add( ev ); 278 return add( ev );
279} 279}
280QArray<int> ODateBookAccessBackend_XML::rawEvents()const { 280QArray<int> ODateBookAccessBackend_XML::rawEvents()const {
281 return allRecords(); 281 return allRecords();
282} 282}
283QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { 283QArray<int> ODateBookAccessBackend_XML::rawRepeats()const {
284 QArray<int> ints( m_rep.count() ); 284 QArray<int> ints( m_rep.count() );
285 uint i = 0; 285 uint i = 0;
286 QMap<int, OEvent>::ConstIterator it; 286 QMap<int, OEvent>::ConstIterator it;
287 287
288 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { 288 for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
289 ints[i] = it.key(); 289 ints[i] = it.key();
290 i++; 290 i++;
291 } 291 }
292 292
293 return ints; 293 return ints;
294} 294}
295QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { 295QArray<int> ODateBookAccessBackend_XML::nonRepeats()const {
296 QArray<int> ints( m_raw.count() ); 296 QArray<int> ints( m_raw.count() );
297 uint i = 0; 297 uint i = 0;
298 QMap<int, OEvent>::ConstIterator it; 298 QMap<int, OEvent>::ConstIterator it;
299 299
300 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { 300 for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
301 ints[i] = it.key(); 301 ints[i] = it.key();
302 i++; 302 i++;
303 } 303 }
304 304
305 return ints; 305 return ints;
306} 306}
307OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { 307OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() {
308 OEvent::ValueList list; 308 OEvent::ValueList list;
309 QMap<int, OEvent>::ConstIterator it; 309 QMap<int, OEvent>::ConstIterator it;
310 for (it = m_raw.begin(); it != m_raw.end(); ++it ) 310 for (it = m_raw.begin(); it != m_raw.end(); ++it )
311 list.append( it.data() ); 311 list.append( it.data() );
312 312
313 return list; 313 return list;
314} 314}
315OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { 315OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() {
316 OEvent::ValueList list; 316 OEvent::ValueList list;
317 QMap<int, OEvent>::ConstIterator it; 317 QMap<int, OEvent>::ConstIterator it;
318 for (it = m_rep.begin(); it != m_rep.end(); ++it ) 318 for (it = m_rep.begin(); it != m_rep.end(); ++it )
319 list.append( it.data() ); 319 list.append( it.data() );
320 320
321 return list; 321 return list;
322} 322}
323bool ODateBookAccessBackend_XML::loadFile() { 323bool ODateBookAccessBackend_XML::loadFile() {
324 m_changed = false; 324 m_changed = false;
325 325
326 int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); 326 int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY );
327 if ( fd < 0 ) return false; 327 if ( fd < 0 ) return false;
328 328
329 struct stat attribute; 329 struct stat attribute;
330 if ( ::fstat(fd, &attribute ) == -1 ) { 330 if ( ::fstat(fd, &attribute ) == -1 ) {
331 ::close( fd ); 331 ::close( fd );
332 return false; 332 return false;
333 } 333 }
334 void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); 334 void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 );
335 if ( map_addr == ( (caddr_t)-1) ) { 335 if ( map_addr == ( (caddr_t)-1) ) {
336 ::close( fd ); 336 ::close( fd );
337 return false; 337 return false;
338 } 338 }
339 339
340 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); 340 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL );
341 ::close( fd ); 341 ::close( fd );
342 342
343 QAsciiDict<int> dict(FExceptions+1); 343 QAsciiDict<int> dict(FExceptions+1);
344 dict.setAutoDelete( true ); 344 dict.setAutoDelete( true );
345 dict.insert( "description", new int(FDescription) ); 345 dict.insert( "description", new int(FDescription) );
346 dict.insert( "location", new int(FLocation) ); 346 dict.insert( "location", new int(FLocation) );
347 dict.insert( "categories", new int(FCategories) ); 347 dict.insert( "categories", new int(FCategories) );
348 dict.insert( "uid", new int(FUid) ); 348 dict.insert( "uid", new int(FUid) );
349 dict.insert( "type", new int(FType) ); 349 dict.insert( "type", new int(FType) );
350 dict.insert( "alarm", new int(FAlarm) ); 350 dict.insert( "alarm", new int(FAlarm) );
351 dict.insert( "sound", new int(FSound) ); 351 dict.insert( "sound", new int(FSound) );
352 dict.insert( "rtype", new int(FRType) ); 352 dict.insert( "rtype", new int(FRType) );
353 dict.insert( "rweekdays", new int(FRWeekdays) ); 353 dict.insert( "rweekdays", new int(FRWeekdays) );
354 dict.insert( "rposition", new int(FRPosition) ); 354 dict.insert( "rposition", new int(FRPosition) );
355 dict.insert( "rfreq", new int(FRFreq) ); 355 dict.insert( "rfreq", new int(FRFreq) );
356 dict.insert( "rhasenddate", new int(FRHasEndDate) ); 356 dict.insert( "rhasenddate", new int(FRHasEndDate) );
357 dict.insert( "enddt", new int(FREndDate) ); 357 dict.insert( "enddt", new int(FREndDate) );
358 dict.insert( "start", new int(FRStart) ); 358 dict.insert( "start", new int(FRStart) );
359 dict.insert( "end", new int(FREnd) ); 359 dict.insert( "end", new int(FREnd) );
360 dict.insert( "note", new int(FNote) ); 360 dict.insert( "note", new int(FNote) );
361 dict.insert( "created", new int(FCreated) ); 361 dict.insert( "created", new int(FCreated) );
362 dict.insert( "recparent", new int(FRecParent) ); 362 dict.insert( "recparent", new int(FRecParent) );
363 dict.insert( "recchildren", new int(FRecChildren) ); 363 dict.insert( "recchildren", new int(FRecChildren) );
364 dict.insert( "exceptions", new int(FExceptions) ); 364 dict.insert( "exceptions", new int(FExceptions) );
365 dict.insert( "timezone", new int(FTimeZone) ); 365 dict.insert( "timezone", new int(FTimeZone) );
366 366
367 char* dt = (char*)map_addr; 367 char* dt = (char*)map_addr;
368 int len = attribute.st_size; 368 int len = attribute.st_size;
369 int i = 0; 369 int i = 0;
370 char* point; 370 char* point;
371 const char* collectionString = "<event "; 371 const char* collectionString = "<event ";
372 int strLen = ::strlen(collectionString); 372 int strLen = ::strlen(collectionString);
373 int *find; 373 int *find;
374 while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { 374 while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) {
375 i = point -dt; 375 i = point -dt;
376 i+= strLen; 376 i+= strLen;
377 377
378 alarmTime = -1; 378 alarmTime = -1;
379 snd = 0; // silent 379 snd = 0; // silent
380 380
381 OEvent ev; 381 OEvent ev;
382 rec = 0; 382 rec = 0;
383 383
384 while ( TRUE ) { 384 while ( TRUE ) {
385 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) 385 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
386 ++i; 386 ++i;
387 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) 387 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
388 break; 388 break;
389 389
390 390
391 // we have another attribute, read it. 391 // we have another attribute, read it.
392 int j = i; 392 int j = i;
393 while ( j < len && dt[j] != '=' ) 393 while ( j < len && dt[j] != '=' )
394 ++j; 394 ++j;
395 QCString attr( dt+i, j-i+1); 395 QCString attr( dt+i, j-i+1);
396 396
397 i = ++j; // skip = 397 i = ++j; // skip =
398 398
399 // find the start of quotes 399 // find the start of quotes
400 while ( i < len && dt[i] != '"' ) 400 while ( i < len && dt[i] != '"' )
401 ++i; 401 ++i;
402 j = ++i; 402 j = ++i;
403 403
404 bool haveUtf = FALSE; 404 bool haveUtf = FALSE;
405 bool haveEnt = FALSE; 405 bool haveEnt = FALSE;
406 while ( j < len && dt[j] != '"' ) { 406 while ( j < len && dt[j] != '"' ) {
407 if ( ((unsigned char)dt[j]) > 0x7f ) 407 if ( ((unsigned char)dt[j]) > 0x7f )
408 haveUtf = TRUE; 408 haveUtf = TRUE;
409 if ( dt[j] == '&' ) 409 if ( dt[j] == '&' )
410 haveEnt = TRUE; 410 haveEnt = TRUE;
411 ++j; 411 ++j;
412 } 412 }
413 if ( i == j ) { 413 if ( i == j ) {
414 // empty value 414 // empty value
415 i = j + 1; 415 i = j + 1;
416 continue; 416 continue;
417 } 417 }
418 418
419 QCString value( dt+i, j-i+1 ); 419 QCString value( dt+i, j-i+1 );
420 i = j + 1; 420 i = j + 1;
421 421
422 QString str = (haveUtf ? QString::fromUtf8( value ) 422 QString str = (haveUtf ? QString::fromUtf8( value )
423 : QString::fromLatin1( value ) ); 423 : QString::fromLatin1( value ) );
424 if ( haveEnt ) 424 if ( haveEnt )
425 str = Qtopia::plainString( str ); 425 str = Qtopia::plainString( str );
426 426
427 /* 427 /*
428 * add key + value 428 * add key + value
429 */ 429 */
430 find = dict[attr.data()]; 430 find = dict[attr.data()];
431 if (!find) 431 if (!find)
432 ev.setCustomField( attr, value ); 432 ev.setCustomField( attr, value );
433 else { 433 else {
434 setField( ev, *find, value ); 434 setField( ev, *find, value );
435 } 435 }
436 } 436 }
437 /* time to finalize */ 437 /* time to finalize */
438 finalizeRecord( ev ); 438 finalizeRecord( ev );
439 delete rec; 439 delete rec;
440 } 440 }
441 ::munmap(map_addr, attribute.st_size ); 441 ::munmap(map_addr, attribute.st_size );
442 m_changed = false; // changed during add 442 m_changed = false; // changed during add
443 443
444 return true; 444 return true;
445} 445}
446void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { 446void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
447 /* AllDay is alway in UTC */ 447 /* AllDay is alway in UTC */
448 if ( ev.isAllDay() ) { 448 if ( ev.isAllDay() ) {
449 OTimeZone utc = OTimeZone::utc(); 449 OTimeZone utc = OTimeZone::utc();
450 ev.setStartDateTime( utc.fromUTCDateTime( start ) ); 450 ev.setStartDateTime( utc.fromUTCDateTime( start ) );
451 ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); 451 ev.setEndDateTime ( utc.fromUTCDateTime( end ) );
452 ev.setTimeZone( "UTC"); // make sure it is really utc 452 ev.setTimeZone( "UTC"); // make sure it is really utc
453 }else { 453 }else {
454 /* to current date time */ 454 /* to current date time */
455 qWarning(" Start is %d", start ); 455 qWarning(" Start is %d", start );
456 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); 456 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
457 QDateTime date = zone.toDateTime( start ); 457 QDateTime date = zone.toDateTime( start );
458 qWarning(" Start is %s", date.toString().latin1() ); 458 qWarning(" Start is %s", date.toString().latin1() );
459 ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); 459 ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
460 460
461 date = zone.toDateTime( end ); 461 date = zone.toDateTime( end );
462 ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); 462 ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
463 } 463 }
464 if ( rec && rec->doesRecur() ) { 464 if ( rec && rec->doesRecur() ) {
465 OTimeZone utc = OTimeZone::utc(); 465 OTimeZone utc = OTimeZone::utc();
466 ORecur recu( *rec ); // call copy c'tor; 466 ORecur recu( *rec ); // call copy c'tor;
467 recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); 467 recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() );
468 recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); 468 recu.setCreatedDateTime( utc.fromUTCDateTime( created ) );
469 recu.setStart( ev.startDateTime().date() ); 469 recu.setStart( ev.startDateTime().date() );
470 ev.setRecurrence( recu ); 470 ev.setRecurrence( recu );
471 } 471 }
472 472
473 if (alarmTime != -1 ) { 473 if (alarmTime != -1 ) {
474 QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); 474 QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 );
475 OPimAlarm al( snd , dt ); 475 OPimAlarm al( snd , dt );
476 ev.notifiers().add( al ); 476 ev.notifiers().add( al );
477 } 477 }
478 if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) { 478 if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) {
479 qWarning("already contains assign uid"); 479 qWarning("already contains assign uid");
480 ev.setUid( 1 ); 480 ev.setUid( 1 );
481 } 481 }
482 qWarning("addind %d %s", ev.uid(), ev.description().latin1() ); 482 qWarning("addind %d %s", ev.uid(), ev.description().latin1() );
483 if ( ev.hasRecurrence() ) 483 if ( ev.hasRecurrence() )
484 m_rep.insert( ev.uid(), ev ); 484 m_rep.insert( ev.uid(), ev );
485 else 485 else
486 m_raw.insert( ev.uid(), ev ); 486 m_raw.insert( ev.uid(), ev );
487 487
488} 488}
489void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) { 489void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) {
490// qWarning(" setting %s", value.latin1() ); 490// qWarning(" setting %s", value.latin1() );
491 switch( id ) { 491 switch( id ) {
492 case FDescription: 492 case FDescription:
493 e.setDescription( value ); 493 e.setDescription( value );
494 break; 494 break;
495 case FLocation: 495 case FLocation:
496 e.setLocation( value ); 496 e.setLocation( value );
497 break; 497 break;
498 case FCategories: 498 case FCategories:
499 e.setCategories( e.idsFromString( value ) ); 499 e.setCategories( e.idsFromString( value ) );
500 break; 500 break;
501 case FUid: 501 case FUid:
502 e.setUid( value.toInt() ); 502 e.setUid( value.toInt() );
503 break; 503 break;
504 case FType: 504 case FType:
505 if ( value == "AllDay" ) { 505 if ( value == "AllDay" ) {
506 e.setAllDay( true ); 506 e.setAllDay( true );
507 e.setTimeZone( "UTC" ); 507 e.setTimeZone( "UTC" );
508 } 508 }
509 break; 509 break;
510 case FAlarm: 510 case FAlarm:
511 alarmTime = value.toInt(); 511 alarmTime = value.toInt();
512 break; 512 break;
513 case FSound: 513 case FSound:
514 snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent; 514 snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent;
515 break; 515 break;
516 // recurrence stuff 516 // recurrence stuff
517 case FRType: 517 case FRType:
518 if ( value == "Daily" ) 518 if ( value == "Daily" )
519 recur()->setType( ORecur::Daily ); 519 recur()->setType( ORecur::Daily );
520 else if ( value == "Weekly" ) 520 else if ( value == "Weekly" )
521 recur()->setType( ORecur::Weekly); 521 recur()->setType( ORecur::Weekly);
522 else if ( value == "MonthlyDay" ) 522 else if ( value == "MonthlyDay" )
523 recur()->setType( ORecur::MonthlyDay ); 523 recur()->setType( ORecur::MonthlyDay );
524 else if ( value == "MonthlyDate" ) 524 else if ( value == "MonthlyDate" )
525 recur()->setType( ORecur::MonthlyDate ); 525 recur()->setType( ORecur::MonthlyDate );
526 else if ( value == "Yearly" ) 526 else if ( value == "Yearly" )
527 recur()->setType( ORecur::Yearly ); 527 recur()->setType( ORecur::Yearly );
528 else 528 else
529 recur()->setType( ORecur::NoRepeat ); 529 recur()->setType( ORecur::NoRepeat );
530 break; 530 break;
531 case FRWeekdays: 531 case FRWeekdays:
532 recur()->setDays( value.toInt() ); 532 recur()->setDays( value.toInt() );
533 break; 533 break;
534 case FRPosition: 534 case FRPosition:
535 recur()->setPosition( value.toInt() ); 535 recur()->setPosition( value.toInt() );
536 break; 536 break;
537 case FRFreq: 537 case FRFreq:
538 recur()->setFrequency( value.toInt() ); 538 recur()->setFrequency( value.toInt() );
539 break; 539 break;
540 case FRHasEndDate: 540 case FRHasEndDate:
541 recur()->setHasEndDate( value.toInt() ); 541 recur()->setHasEndDate( value.toInt() );
542 break; 542 break;
543 case FREndDate: { 543 case FREndDate: {
544 rp_end = (time_t) value.toLong(); 544 rp_end = (time_t) value.toLong();
545 break; 545 break;
546 } 546 }
547 case FRStart: { 547 case FRStart: {
548 start = (time_t) value.toLong(); 548 start = (time_t) value.toLong();
549 break; 549 break;
550 } 550 }
551 case FREnd: { 551 case FREnd: {
552 end = ( (time_t) value.toLong() ); 552 end = ( (time_t) value.toLong() );
553 break; 553 break;
554 } 554 }
555 case FNote: 555 case FNote:
556 e.setNote( value ); 556 e.setNote( value );
557 break; 557 break;
558 case FCreated: 558 case FCreated:
559 created = value.toInt(); 559 created = value.toInt();
560 break; 560 break;
561 case FRecParent: 561 case FRecParent:
562 e.setParent( value.toInt() ); 562 e.setParent( value.toInt() );
563 break; 563 break;
564 case FRecChildren:{ 564 case FRecChildren:{
565 QStringList list = QStringList::split(' ', value ); 565 QStringList list = QStringList::split(' ', value );
566 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { 566 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
567 e.addChild( (*it).toInt() ); 567 e.addChild( (*it).toInt() );
568 } 568 }
569 } 569 }
570 break; 570 break;
571 case FExceptions:{ 571 case FExceptions:{
572 QStringList list = QStringList::split(' ', value ); 572 QStringList list = QStringList::split(' ', value );
573 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { 573 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
574 QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); 574 QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() );
575 qWarning("adding exception %s", date.toString().latin1() ); 575 qWarning("adding exception %s", date.toString().latin1() );
576 recur()->exceptions().append( date ); 576 recur()->exceptions().append( date );
577 } 577 }
578 } 578 }
579 break; 579 break;
580 case FTimeZone: 580 case FTimeZone:
581 if ( value != "None" ) 581 if ( value != "None" )
582 e.setTimeZone( value ); 582 e.setTimeZone( value );
583 break; 583 break;
584 default: 584 default:
585 break; 585 break;
586 } 586 }
587} 587}
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h b/libopie2/opiepim/backend/odatebookaccessbackend_xml.h
index 40f69d8..563c31f 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h
+++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.h
@@ -1,48 +1,48 @@
1#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H 1#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
2#define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H 2#define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
3 3
4#include <qmap.h> 4#include <qmap.h>
5 5
6#include "odatebookaccessbackend.h" 6#include "odatebookaccessbackend.h"
7 7
8class ODateBookAccessBackend_XML : public ODateBookAccessBackend { 8class ODateBookAccessBackend_XML : public ODateBookAccessBackend {
9public: 9public:
10 ODateBookAccessBackend_XML( const QString& appName, 10 ODateBookAccessBackend_XML( const QString& appName,
11 const QString& fileName = QString::null); 11 const QString& fileName = QString::null);
12 ~ODateBookAccessBackend_XML(); 12 ~ODateBookAccessBackend_XML();
13 13
14 bool load(); 14 bool load();
15 bool reload(); 15 bool reload();
16 bool save(); 16 bool save();
17 17
18 QArray<int> allRecords()const; 18 QArray<int> allRecords()const;
19 QArray<int> queryByExample( const OEvent&, int ); 19 QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() );
20 OEvent find( int uid )const; 20 OEvent find( int uid )const;
21 void clear(); 21 void clear();
22 bool add( const OEvent& ev ); 22 bool add( const OEvent& ev );
23 bool remove( int uid ); 23 bool remove( int uid );
24 bool replace( const OEvent& ev ); 24 bool replace( const OEvent& ev );
25 25
26 QArray<UID> rawEvents()const; 26 QArray<UID> rawEvents()const;
27 QArray<UID> rawRepeats()const; 27 QArray<UID> rawRepeats()const;
28 QArray<UID> nonRepeats()const; 28 QArray<UID> nonRepeats()const;
29 29
30 OEvent::ValueList directNonRepeats(); 30 OEvent::ValueList directNonRepeats();
31 OEvent::ValueList directRawRepeats(); 31 OEvent::ValueList directRawRepeats();
32 32
33private: 33private:
34 bool m_changed :1 ; 34 bool m_changed :1 ;
35 bool loadFile(); 35 bool loadFile();
36 inline void finalizeRecord( OEvent& ev ); 36 inline void finalizeRecord( OEvent& ev );
37 inline void setField( OEvent&, int field, const QString& val ); 37 inline void setField( OEvent&, int field, const QString& val );
38 QString m_name; 38 QString m_name;
39 QMap<int, OEvent> m_raw; 39 QMap<int, OEvent> m_raw;
40 QMap<int, OEvent> m_rep; 40 QMap<int, OEvent> m_rep;
41 41
42 struct Data; 42 struct Data;
43 Data* data; 43 Data* data;
44 class Private; 44 class Private;
45 Private *d; 45 Private *d;
46}; 46};
47 47
48#endif 48#endif
diff --git a/libopie2/opiepim/backend/opimaccessbackend.h b/libopie2/opiepim/backend/opimaccessbackend.h
index e268f4f..01a0c86 100644
--- a/libopie2/opiepim/backend/opimaccessbackend.h
+++ b/libopie2/opiepim/backend/opimaccessbackend.h
@@ -1,153 +1,153 @@
1#ifndef OPIE_PIM_ACCESS_BACKEND 1#ifndef OPIE_PIM_ACCESS_BACKEND
2#define OPIE_PIM_ACCESS_BACKEND 2#define OPIE_PIM_ACCESS_BACKEND
3 3
4#include <qarray.h> 4#include <qarray.h>
5 5
6#include <opie/otemplatebase.h> 6#include <opie/otemplatebase.h>
7#include <opie/opimrecord.h> 7#include <opie/opimrecord.h>
8 8
9 9
10/** 10/**
11 * OPimAccessBackend is the base class 11 * OPimAccessBackend is the base class
12 * for all private backends 12 * for all private backends
13 * it operates on OPimRecord as the base class 13 * it operates on OPimRecord as the base class
14 * and it's responsible for fast manipulating 14 * and it's responsible for fast manipulating
15 * the resource the implementation takes care 15 * the resource the implementation takes care
16 * of 16 * of
17 */ 17 */
18template <class T = OPimRecord> 18template <class T = OPimRecord>
19class OPimAccessBackend { 19class OPimAccessBackend {
20public: 20public:
21 typedef OTemplateBase<T> Frontend; 21 typedef OTemplateBase<T> Frontend;
22 22
23 /** The access hint from the frontend */ 23 /** The access hint from the frontend */
24 OPimAccessBackend(int access = 0); 24 OPimAccessBackend(int access = 0);
25 virtual ~OPimAccessBackend(); 25 virtual ~OPimAccessBackend();
26 26
27 /** 27 /**
28 * load the resource 28 * load the resource
29 */ 29 */
30 virtual bool load() = 0; 30 virtual bool load() = 0;
31 31
32 /** 32 /**
33 * reload the resource 33 * reload the resource
34 */ 34 */
35 virtual bool reload() = 0; 35 virtual bool reload() = 0;
36 36
37 /** 37 /**
38 * save the resource and 38 * save the resource and
39 * all it's changes 39 * all it's changes
40 */ 40 */
41 virtual bool save() = 0; 41 virtual bool save() = 0;
42 42
43 /** 43 /**
44 * return an array of 44 * return an array of
45 * all available uids 45 * all available uids
46 */ 46 */
47 virtual QArray<int> allRecords()const = 0; 47 virtual QArray<int> allRecords()const = 0;
48 48
49 /** 49 /**
50 * queryByExample for T with the SortOrder 50 * queryByExample for T with the given Settings
51 * sort 51 *
52 */ 52 */
53 virtual QArray<int> queryByExample( const T& t, int sort ) = 0; 53 virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0;
54 54
55 /** 55 /**
56 * find the OPimRecord with uid @param uid 56 * find the OPimRecord with uid @param uid
57 * returns T and T.isEmpty() if nothing was found 57 * returns T and T.isEmpty() if nothing was found
58 */ 58 */
59 virtual T find(int uid )const = 0; 59 virtual T find(int uid )const = 0;
60 60
61 virtual T find(int uid, const QArray<int>& items, 61 virtual T find(int uid, const QArray<int>& items,
62 uint current, typename Frontend::CacheDirection )const ; 62 uint current, typename Frontend::CacheDirection )const ;
63 /** 63 /**
64 * clear the back end 64 * clear the back end
65 */ 65 */
66 virtual void clear() = 0; 66 virtual void clear() = 0;
67 67
68 /** 68 /**
69 * add T 69 * add T
70 */ 70 */
71 virtual bool add( const T& t ) = 0; 71 virtual bool add( const T& t ) = 0;
72 72
73 /** 73 /**
74 * remove 74 * remove
75 */ 75 */
76 virtual bool remove( int uid ) = 0; 76 virtual bool remove( int uid ) = 0;
77 77
78 /** 78 /**
79 * replace a record with T.uid() 79 * replace a record with T.uid()
80 */ 80 */
81 virtual bool replace( const T& t ) = 0; 81 virtual bool replace( const T& t ) = 0;
82 82
83 /* 83 /*
84 * setTheFrontEnd!!! 84 * setTheFrontEnd!!!
85 */ 85 */
86 void setFrontend( Frontend* front ); 86 void setFrontend( Frontend* front );
87 87
88 /** 88 /**
89 * set the read ahead count 89 * set the read ahead count
90 */ 90 */
91 void setReadAhead( uint count ); 91 void setReadAhead( uint count );
92protected: 92protected:
93 int access()const; 93 int access()const;
94 void cache( const T& t )const; 94 void cache( const T& t )const;
95 95
96 /** 96 /**
97 * use a prime number here! 97 * use a prime number here!
98 */ 98 */
99 void setSaneCacheSize( int ); 99 void setSaneCacheSize( int );
100 100
101 uint readAhead()const; 101 uint readAhead()const;
102 102
103private: 103private:
104 class Private; 104 class Private;
105 Private* d; 105 Private* d;
106 Frontend* m_front; 106 Frontend* m_front;
107 uint m_read; 107 uint m_read;
108 int m_acc; 108 int m_acc;
109 109
110}; 110};
111 111
112template <class T> 112template <class T>
113OPimAccessBackend<T>::OPimAccessBackend(int acc) 113OPimAccessBackend<T>::OPimAccessBackend(int acc)
114 : m_acc( acc ) 114 : m_acc( acc )
115{ 115{
116 m_front = 0l; 116 m_front = 0l;
117} 117}
118template <class T> 118template <class T>
119OPimAccessBackend<T>::~OPimAccessBackend() { 119OPimAccessBackend<T>::~OPimAccessBackend() {
120 120
121} 121}
122template <class T> 122template <class T>
123void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { 123void OPimAccessBackend<T>::setFrontend( Frontend* fr ) {
124 m_front = fr; 124 m_front = fr;
125} 125}
126template <class T> 126template <class T>
127void OPimAccessBackend<T>::cache( const T& t )const { 127void OPimAccessBackend<T>::cache( const T& t )const {
128 if (m_front ) 128 if (m_front )
129 m_front->cache( t ); 129 m_front->cache( t );
130} 130}
131template <class T> 131template <class T>
132void OPimAccessBackend<T>::setSaneCacheSize( int size) { 132void OPimAccessBackend<T>::setSaneCacheSize( int size) {
133 if (m_front ) 133 if (m_front )
134 m_front->setSaneCacheSize( size ); 134 m_front->setSaneCacheSize( size );
135} 135}
136template <class T> 136template <class T>
137T OPimAccessBackend<T>::find( int uid, const QArray<int>&, 137T OPimAccessBackend<T>::find( int uid, const QArray<int>&,
138 uint, typename Frontend::CacheDirection )const { 138 uint, typename Frontend::CacheDirection )const {
139 return find( uid ); 139 return find( uid );
140} 140}
141template <class T> 141template <class T>
142void OPimAccessBackend<T>::setReadAhead( uint count ) { 142void OPimAccessBackend<T>::setReadAhead( uint count ) {
143 m_read = count; 143 m_read = count;
144} 144}
145template <class T> 145template <class T>
146uint OPimAccessBackend<T>::readAhead()const { 146uint OPimAccessBackend<T>::readAhead()const {
147 return m_read; 147 return m_read;
148} 148}
149template <class T> 149template <class T>
150int OPimAccessBackend<T>::access()const { 150int OPimAccessBackend<T>::access()const {
151 return m_acc; 151 return m_acc;
152} 152}
153#endif 153#endif
diff --git a/libopie2/opiepim/backend/otodoaccesssql.cpp b/libopie2/opiepim/backend/otodoaccesssql.cpp
index 761d7d8..ec9c14c 100644
--- a/libopie2/opiepim/backend/otodoaccesssql.cpp
+++ b/libopie2/opiepim/backend/otodoaccesssql.cpp
@@ -1,540 +1,540 @@
1 1
2#include <qdatetime.h> 2#include <qdatetime.h>
3 3
4#include <qpe/global.h> 4#include <qpe/global.h>
5 5
6#include <opie/osqldriver.h> 6#include <opie/osqldriver.h>
7#include <opie/osqlresult.h> 7#include <opie/osqlresult.h>
8#include <opie/osqlmanager.h> 8#include <opie/osqlmanager.h>
9#include <opie/osqlquery.h> 9#include <opie/osqlquery.h>
10 10
11#include "otodoaccesssql.h" 11#include "otodoaccesssql.h"
12 12
13/* 13/*
14 * first some query 14 * first some query
15 * CREATE query 15 * CREATE query
16 * LOAD query 16 * LOAD query
17 * INSERT 17 * INSERT
18 * REMOVE 18 * REMOVE
19 * CLEAR 19 * CLEAR
20 */ 20 */
21namespace { 21namespace {
22 /** 22 /**
23 * CreateQuery for the Todolist Table 23 * CreateQuery for the Todolist Table
24 */ 24 */
25 class CreateQuery : public OSQLQuery { 25 class CreateQuery : public OSQLQuery {
26 public: 26 public:
27 CreateQuery(); 27 CreateQuery();
28 ~CreateQuery(); 28 ~CreateQuery();
29 QString query()const; 29 QString query()const;
30 }; 30 };
31 31
32 /** 32 /**
33 * LoadQuery 33 * LoadQuery
34 * this one queries for all uids 34 * this one queries for all uids
35 */ 35 */
36 class LoadQuery : public OSQLQuery { 36 class LoadQuery : public OSQLQuery {
37 public: 37 public:
38 LoadQuery(); 38 LoadQuery();
39 ~LoadQuery(); 39 ~LoadQuery();
40 QString query()const; 40 QString query()const;
41 }; 41 };
42 42
43 /** 43 /**
44 * inserts/adds a OTodo to the table 44 * inserts/adds a OTodo to the table
45 */ 45 */
46 class InsertQuery : public OSQLQuery { 46 class InsertQuery : public OSQLQuery {
47 public: 47 public:
48 InsertQuery(const OTodo& ); 48 InsertQuery(const OTodo& );
49 ~InsertQuery(); 49 ~InsertQuery();
50 QString query()const; 50 QString query()const;
51 private: 51 private:
52 OTodo m_todo; 52 OTodo m_todo;
53 }; 53 };
54 54
55 /** 55 /**
56 * removes one from the table 56 * removes one from the table
57 */ 57 */
58 class RemoveQuery : public OSQLQuery { 58 class RemoveQuery : public OSQLQuery {
59 public: 59 public:
60 RemoveQuery(int uid ); 60 RemoveQuery(int uid );
61 ~RemoveQuery(); 61 ~RemoveQuery();
62 QString query()const; 62 QString query()const;
63 private: 63 private:
64 int m_uid; 64 int m_uid;
65 }; 65 };
66 66
67 /** 67 /**
68 * Clears (delete) a Table 68 * Clears (delete) a Table
69 */ 69 */
70 class ClearQuery : public OSQLQuery { 70 class ClearQuery : public OSQLQuery {
71 public: 71 public:
72 ClearQuery(); 72 ClearQuery();
73 ~ClearQuery(); 73 ~ClearQuery();
74 QString query()const; 74 QString query()const;
75 75
76 }; 76 };
77 77
78 /** 78 /**
79 * a find query 79 * a find query
80 */ 80 */
81 class FindQuery : public OSQLQuery { 81 class FindQuery : public OSQLQuery {
82 public: 82 public:
83 FindQuery(int uid); 83 FindQuery(int uid);
84 FindQuery(const QArray<int>& ); 84 FindQuery(const QArray<int>& );
85 ~FindQuery(); 85 ~FindQuery();
86 QString query()const; 86 QString query()const;
87 private: 87 private:
88 QString single()const; 88 QString single()const;
89 QString multi()const; 89 QString multi()const;
90 QArray<int> m_uids; 90 QArray<int> m_uids;
91 int m_uid; 91 int m_uid;
92 }; 92 };
93 93
94 /** 94 /**
95 * overdue query 95 * overdue query
96 */ 96 */
97 class OverDueQuery : public OSQLQuery { 97 class OverDueQuery : public OSQLQuery {
98 public: 98 public:
99 OverDueQuery(); 99 OverDueQuery();
100 ~OverDueQuery(); 100 ~OverDueQuery();
101 QString query()const; 101 QString query()const;
102 }; 102 };
103 class EffQuery : public OSQLQuery { 103 class EffQuery : public OSQLQuery {
104 public: 104 public:
105 EffQuery( const QDate&, const QDate&, bool inc ); 105 EffQuery( const QDate&, const QDate&, bool inc );
106 ~EffQuery(); 106 ~EffQuery();
107 QString query()const; 107 QString query()const;
108 private: 108 private:
109 QString with()const; 109 QString with()const;
110 QString out()const; 110 QString out()const;
111 QDate m_start; 111 QDate m_start;
112 QDate m_end; 112 QDate m_end;
113 bool m_inc :1; 113 bool m_inc :1;
114 }; 114 };
115 115
116 116
117 CreateQuery::CreateQuery() : OSQLQuery() {} 117 CreateQuery::CreateQuery() : OSQLQuery() {}
118 CreateQuery::~CreateQuery() {} 118 CreateQuery::~CreateQuery() {}
119 QString CreateQuery::query()const { 119 QString CreateQuery::query()const {
120 QString qu; 120 QString qu;
121 qu += "create table todolist( uid, categories, completed, progress, "; 121 qu += "create table todolist( uid, categories, completed, progress, ";
122 qu += "summary, DueDate, priority, description )"; 122 qu += "summary, DueDate, priority, description )";
123 return qu; 123 return qu;
124 } 124 }
125 125
126 LoadQuery::LoadQuery() : OSQLQuery() {} 126 LoadQuery::LoadQuery() : OSQLQuery() {}
127 LoadQuery::~LoadQuery() {} 127 LoadQuery::~LoadQuery() {}
128 QString LoadQuery::query()const { 128 QString LoadQuery::query()const {
129 QString qu; 129 QString qu;
130 qu += "select distinct uid from todolist"; 130 qu += "select distinct uid from todolist";
131 131
132 return qu; 132 return qu;
133 } 133 }
134 134
135 InsertQuery::InsertQuery( const OTodo& todo ) 135 InsertQuery::InsertQuery( const OTodo& todo )
136 : OSQLQuery(), m_todo( todo ) { 136 : OSQLQuery(), m_todo( todo ) {
137 } 137 }
138 InsertQuery::~InsertQuery() { 138 InsertQuery::~InsertQuery() {
139 } 139 }
140 /* 140 /*
141 * converts from a OTodo to a query 141 * converts from a OTodo to a query
142 * we leave out X-Ref + Alarms 142 * we leave out X-Ref + Alarms
143 */ 143 */
144 QString InsertQuery::query()const{ 144 QString InsertQuery::query()const{
145 145
146 int year, month, day; 146 int year, month, day;
147 year = month = day = 0; 147 year = month = day = 0;
148 if (m_todo.hasDueDate() ) { 148 if (m_todo.hasDueDate() ) {
149 QDate date = m_todo.dueDate(); 149 QDate date = m_todo.dueDate();
150 year = date.year(); 150 year = date.year();
151 month = date.month(); 151 month = date.month();
152 day = date.day(); 152 day = date.day();
153 } 153 }
154 QString qu; 154 QString qu;
155 qu = "insert into todolist VALUES(" + QString::number( m_todo.uid() ) + ",'" + m_todo.idsToString( m_todo.categories() ) + "',"; 155 qu = "insert into todolist VALUES(" + QString::number( m_todo.uid() ) + ",'" + m_todo.idsToString( m_todo.categories() ) + "',";
156 qu += QString::number( m_todo.isCompleted() ) + "," + QString::number( m_todo.progress() ) + ","; 156 qu += QString::number( m_todo.isCompleted() ) + "," + QString::number( m_todo.progress() ) + ",";
157 qu += "'"+m_todo.summary()+"','"+QString::number(year)+"-"+QString::number(month)+"-"+QString::number(day)+"',"; 157 qu += "'"+m_todo.summary()+"','"+QString::number(year)+"-"+QString::number(month)+"-"+QString::number(day)+"',";
158 qu += QString::number(m_todo.priority() ) +",'" + m_todo.description() + "')"; 158 qu += QString::number(m_todo.priority() ) +",'" + m_todo.description() + "')";
159 159
160 qWarning("add %s", qu.latin1() ); 160 qWarning("add %s", qu.latin1() );
161 return qu; 161 return qu;
162 } 162 }
163 163
164 RemoveQuery::RemoveQuery(int uid ) 164 RemoveQuery::RemoveQuery(int uid )
165 : OSQLQuery(), m_uid( uid ) {} 165 : OSQLQuery(), m_uid( uid ) {}
166 RemoveQuery::~RemoveQuery() {} 166 RemoveQuery::~RemoveQuery() {}
167 QString RemoveQuery::query()const { 167 QString RemoveQuery::query()const {
168 QString qu = "DELETE from todolist where uid = " + QString::number(m_uid); 168 QString qu = "DELETE from todolist where uid = " + QString::number(m_uid);
169 return qu; 169 return qu;
170 } 170 }
171 171
172 172
173 ClearQuery::ClearQuery() 173 ClearQuery::ClearQuery()
174 : OSQLQuery() {} 174 : OSQLQuery() {}
175 ClearQuery::~ClearQuery() {} 175 ClearQuery::~ClearQuery() {}
176 QString ClearQuery::query()const { 176 QString ClearQuery::query()const {
177 QString qu = "drop table todolist"; 177 QString qu = "drop table todolist";
178 return qu; 178 return qu;
179 } 179 }
180 FindQuery::FindQuery(int uid) 180 FindQuery::FindQuery(int uid)
181 : OSQLQuery(), m_uid(uid ) { 181 : OSQLQuery(), m_uid(uid ) {
182 } 182 }
183 FindQuery::FindQuery(const QArray<int>& ints) 183 FindQuery::FindQuery(const QArray<int>& ints)
184 : OSQLQuery(), m_uids(ints){ 184 : OSQLQuery(), m_uids(ints){
185 } 185 }
186 FindQuery::~FindQuery() { 186 FindQuery::~FindQuery() {
187 } 187 }
188 QString FindQuery::query()const{ 188 QString FindQuery::query()const{
189 if (m_uids.count() == 0 ) 189 if (m_uids.count() == 0 )
190 return single(); 190 return single();
191 else 191 else
192 return multi(); 192 return multi();
193 } 193 }
194 QString FindQuery::single()const{ 194 QString FindQuery::single()const{
195 QString qu = "select uid, categories, completed, progress, summary, "; 195 QString qu = "select uid, categories, completed, progress, summary, ";
196 qu += "DueDate, priority, description from todolist where uid = " + QString::number(m_uid); 196 qu += "DueDate, priority, description from todolist where uid = " + QString::number(m_uid);
197 return qu; 197 return qu;
198 } 198 }
199 QString FindQuery::multi()const { 199 QString FindQuery::multi()const {
200 QString qu = "select uid, categories, completed, progress, summary, "; 200 QString qu = "select uid, categories, completed, progress, summary, ";
201 qu += "DueDate, priority, description from todolist where "; 201 qu += "DueDate, priority, description from todolist where ";
202 for (uint i = 0; i < m_uids.count(); i++ ) { 202 for (uint i = 0; i < m_uids.count(); i++ ) {
203 qu += " UID = " + QString::number( m_uids[i] ) + " OR"; 203 qu += " UID = " + QString::number( m_uids[i] ) + " OR";
204 } 204 }
205 qu.remove( qu.length()-2, 2 ); 205 qu.remove( qu.length()-2, 2 );
206 return qu; 206 return qu;
207 } 207 }
208 208
209 OverDueQuery::OverDueQuery(): OSQLQuery() {} 209 OverDueQuery::OverDueQuery(): OSQLQuery() {}
210 OverDueQuery::~OverDueQuery() {} 210 OverDueQuery::~OverDueQuery() {}
211 QString OverDueQuery::query()const { 211 QString OverDueQuery::query()const {
212 QDate date = QDate::currentDate(); 212 QDate date = QDate::currentDate();
213 QString str; 213 QString str;
214 str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() ); 214 str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() );
215 215
216 return str; 216 return str;
217 } 217 }
218 218
219 219
220 EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc ) 220 EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc )
221 : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {} 221 : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {}
222 EffQuery::~EffQuery() {} 222 EffQuery::~EffQuery() {}
223 QString EffQuery::query()const { 223 QString EffQuery::query()const {
224 return m_inc ? with() : out(); 224 return m_inc ? with() : out();
225 } 225 }
226 QString EffQuery::with()const { 226 QString EffQuery::with()const {
227 QString str; 227 QString str;
228 str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") 228 str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ")
229 .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) 229 .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() )
230 .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); 230 .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() );
231 return str; 231 return str;
232 } 232 }
233 QString EffQuery::out()const { 233 QString EffQuery::out()const {
234 QString str; 234 QString str;
235 str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") 235 str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'")
236 .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) 236 .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() )
237 .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); 237 .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() );
238 238
239 return str; 239 return str;
240 } 240 }
241}; 241};
242 242
243OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) 243OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file )
244 : OTodoAccessBackend(), m_dict(15), m_dirty(true) 244 : OTodoAccessBackend(), m_dict(15), m_dirty(true)
245{ 245{
246 QString fi = file; 246 QString fi = file;
247 if ( fi.isEmpty() ) 247 if ( fi.isEmpty() )
248 fi = Global::applicationFileName( "todolist", "todolist.db" ); 248 fi = Global::applicationFileName( "todolist", "todolist.db" );
249 OSQLManager man; 249 OSQLManager man;
250 m_driver = man.standard(); 250 m_driver = man.standard();
251 m_driver->setUrl(fi); 251 m_driver->setUrl(fi);
252 fillDict(); 252 fillDict();
253} 253}
254 254
255OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ 255OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){
256} 256}
257bool OTodoAccessBackendSQL::load(){ 257bool OTodoAccessBackendSQL::load(){
258 if (!m_driver->open() ) 258 if (!m_driver->open() )
259 return false; 259 return false;
260 260
261 CreateQuery creat; 261 CreateQuery creat;
262 OSQLResult res = m_driver->query(&creat ); 262 OSQLResult res = m_driver->query(&creat );
263 263
264 m_dirty = true; 264 m_dirty = true;
265 return true; 265 return true;
266} 266}
267bool OTodoAccessBackendSQL::reload(){ 267bool OTodoAccessBackendSQL::reload(){
268 return load(); 268 return load();
269} 269}
270 270
271bool OTodoAccessBackendSQL::save(){ 271bool OTodoAccessBackendSQL::save(){
272 return m_driver->close(); 272 return m_driver->close();
273} 273}
274QArray<int> OTodoAccessBackendSQL::allRecords()const { 274QArray<int> OTodoAccessBackendSQL::allRecords()const {
275 if (m_dirty ) 275 if (m_dirty )
276 update(); 276 update();
277 277
278 return m_uids; 278 return m_uids;
279} 279}
280QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int ){ 280QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){
281 QArray<int> ints(0); 281 QArray<int> ints(0);
282 return ints; 282 return ints;
283} 283}
284OTodo OTodoAccessBackendSQL::find(int uid ) const{ 284OTodo OTodoAccessBackendSQL::find(int uid ) const{
285 FindQuery query( uid ); 285 FindQuery query( uid );
286 return todo( m_driver->query(&query) ); 286 return todo( m_driver->query(&query) );
287 287
288} 288}
289OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, 289OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints,
290 uint cur, Frontend::CacheDirection dir ) const{ 290 uint cur, Frontend::CacheDirection dir ) const{
291 int CACHE = readAhead(); 291 int CACHE = readAhead();
292 qWarning("searching for %d", uid ); 292 qWarning("searching for %d", uid );
293 QArray<int> search( CACHE ); 293 QArray<int> search( CACHE );
294 uint size =0; 294 uint size =0;
295 OTodo to; 295 OTodo to;
296 296
297 // we try to cache CACHE items 297 // we try to cache CACHE items
298 switch( dir ) { 298 switch( dir ) {
299 /* forward */ 299 /* forward */
300 case 0: 300 case 0:
301 for (uint i = cur; i < ints.count() && size < CACHE; i++ ) { 301 for (uint i = cur; i < ints.count() && size < CACHE; i++ ) {
302 qWarning("size %d %d", size, ints[i] ); 302 qWarning("size %d %d", size, ints[i] );
303 search[size] = ints[i]; 303 search[size] = ints[i];
304 size++; 304 size++;
305 } 305 }
306 break; 306 break;
307 /* reverse */ 307 /* reverse */
308 case 1: 308 case 1:
309 for (uint i = cur; i != 0 && size < CACHE; i-- ) { 309 for (uint i = cur; i != 0 && size < CACHE; i-- ) {
310 search[size] = ints[i]; 310 search[size] = ints[i];
311 size++; 311 size++;
312 } 312 }
313 break; 313 break;
314 } 314 }
315 search.resize( size ); 315 search.resize( size );
316 FindQuery query( search ); 316 FindQuery query( search );
317 OSQLResult res = m_driver->query( &query ); 317 OSQLResult res = m_driver->query( &query );
318 if ( res.state() != OSQLResult::Success ) 318 if ( res.state() != OSQLResult::Success )
319 return to; 319 return to;
320 320
321 return todo( res ); 321 return todo( res );
322} 322}
323void OTodoAccessBackendSQL::clear() { 323void OTodoAccessBackendSQL::clear() {
324 ClearQuery cle; 324 ClearQuery cle;
325 OSQLResult res = m_driver->query( &cle ); 325 OSQLResult res = m_driver->query( &cle );
326 CreateQuery qu; 326 CreateQuery qu;
327 res = m_driver->query(&qu); 327 res = m_driver->query(&qu);
328} 328}
329bool OTodoAccessBackendSQL::add( const OTodo& t) { 329bool OTodoAccessBackendSQL::add( const OTodo& t) {
330 InsertQuery ins( t ); 330 InsertQuery ins( t );
331 OSQLResult res = m_driver->query( &ins ); 331 OSQLResult res = m_driver->query( &ins );
332 332
333 if ( res.state() == OSQLResult::Failure ) 333 if ( res.state() == OSQLResult::Failure )
334 return false; 334 return false;
335 int c = m_uids.count(); 335 int c = m_uids.count();
336 m_uids.resize( c+1 ); 336 m_uids.resize( c+1 );
337 m_uids[c] = t.uid(); 337 m_uids[c] = t.uid();
338 338
339 return true; 339 return true;
340} 340}
341bool OTodoAccessBackendSQL::remove( int uid ) { 341bool OTodoAccessBackendSQL::remove( int uid ) {
342 RemoveQuery rem( uid ); 342 RemoveQuery rem( uid );
343 OSQLResult res = m_driver->query(&rem ); 343 OSQLResult res = m_driver->query(&rem );
344 344
345 if ( res.state() == OSQLResult::Failure ) 345 if ( res.state() == OSQLResult::Failure )
346 return false; 346 return false;
347 347
348 m_dirty = true; 348 m_dirty = true;
349 return true; 349 return true;
350} 350}
351/* 351/*
352 * FIXME better set query 352 * FIXME better set query
353 * but we need the cache for that 353 * but we need the cache for that
354 * now we remove 354 * now we remove
355 */ 355 */
356bool OTodoAccessBackendSQL::replace( const OTodo& t) { 356bool OTodoAccessBackendSQL::replace( const OTodo& t) {
357 remove( t.uid() ); 357 remove( t.uid() );
358 bool b= add(t); 358 bool b= add(t);
359 m_dirty = false; // we changed some stuff but the UID stayed the same 359 m_dirty = false; // we changed some stuff but the UID stayed the same
360 return b; 360 return b;
361} 361}
362QArray<int> OTodoAccessBackendSQL::overDue() { 362QArray<int> OTodoAccessBackendSQL::overDue() {
363 OverDueQuery qu; 363 OverDueQuery qu;
364 return uids( m_driver->query(&qu ) ); 364 return uids( m_driver->query(&qu ) );
365} 365}
366QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s, 366QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s,
367 const QDate& t, 367 const QDate& t,
368 bool u) { 368 bool u) {
369 EffQuery ef(s, t, u ); 369 EffQuery ef(s, t, u );
370 return uids (m_driver->query(&ef) ); 370 return uids (m_driver->query(&ef) );
371} 371}
372/* 372/*
373 * 373 *
374 */ 374 */
375QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder, 375QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder,
376 int sortFilter, int cat ) { 376 int sortFilter, int cat ) {
377 qWarning("sorted %d, %d", asc, sortOrder ); 377 qWarning("sorted %d, %d", asc, sortOrder );
378 QString query; 378 QString query;
379 query = "select uid from todolist WHERE "; 379 query = "select uid from todolist WHERE ";
380 380
381 /* 381 /*
382 * Sort Filter stuff 382 * Sort Filter stuff
383 * not that straight forward 383 * not that straight forward
384 * 384 *
385 */ 385 */
386 /* Category */ 386 /* Category */
387 if ( sortFilter & 1 ) { 387 if ( sortFilter & 1 ) {
388 QString str; 388 QString str;
389 if (cat != 0 ) str = QString::number( cat ); 389 if (cat != 0 ) str = QString::number( cat );
390 query += " categories like '%" +str+"%' AND"; 390 query += " categories like '%" +str+"%' AND";
391 } 391 }
392 /* Show only overdue */ 392 /* Show only overdue */
393 if ( sortFilter & 2 ) { 393 if ( sortFilter & 2 ) {
394 QDate date = QDate::currentDate(); 394 QDate date = QDate::currentDate();
395 QString due; 395 QString due;
396 QString base; 396 QString base;
397 base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() ); 397 base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() );
398 query += " " + base + " AND"; 398 query += " " + base + " AND";
399 } 399 }
400 /* not show completed */ 400 /* not show completed */
401 if ( sortFilter & 4 ) { 401 if ( sortFilter & 4 ) {
402 query += " completed = 0 AND"; 402 query += " completed = 0 AND";
403 }else{ 403 }else{
404 query += " ( completed = 1 OR completed = 0) AND"; 404 query += " ( completed = 1 OR completed = 0) AND";
405 } 405 }
406 /* srtip the end */ 406 /* srtip the end */
407 query = query.remove( query.length()-3, 3 ); 407 query = query.remove( query.length()-3, 3 );
408 408
409 409
410 /* 410 /*
411 * sort order stuff 411 * sort order stuff
412 * quite straight forward 412 * quite straight forward
413 */ 413 */
414 query += "ORDER BY "; 414 query += "ORDER BY ";
415 switch( sortOrder ) { 415 switch( sortOrder ) {
416 /* completed */ 416 /* completed */
417 case 0: 417 case 0:
418 query += "completed"; 418 query += "completed";
419 break; 419 break;
420 case 1: 420 case 1:
421 query += "priority"; 421 query += "priority";
422 break; 422 break;
423 case 2: 423 case 2:
424 query += "summary"; 424 query += "summary";
425 break; 425 break;
426 case 3: 426 case 3:
427 query += "DueDate"; 427 query += "DueDate";
428 break; 428 break;
429 } 429 }
430 430
431 if ( !asc ) { 431 if ( !asc ) {
432 qWarning("not ascending!"); 432 qWarning("not ascending!");
433 query += " DESC"; 433 query += " DESC";
434 } 434 }
435 435
436 qWarning( query ); 436 qWarning( query );
437 OSQLRawQuery raw(query ); 437 OSQLRawQuery raw(query );
438 return uids( m_driver->query(&raw) ); 438 return uids( m_driver->query(&raw) );
439} 439}
440bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{ 440bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{
441 if ( str == "0-0-0" ) 441 if ( str == "0-0-0" )
442 return false; 442 return false;
443 else{ 443 else{
444 int day, year, month; 444 int day, year, month;
445 QStringList list = QStringList::split("-", str ); 445 QStringList list = QStringList::split("-", str );
446 year = list[0].toInt(); 446 year = list[0].toInt();
447 month = list[1].toInt(); 447 month = list[1].toInt();
448 day = list[2].toInt(); 448 day = list[2].toInt();
449 da.setYMD( year, month, day ); 449 da.setYMD( year, month, day );
450 return true; 450 return true;
451 } 451 }
452} 452}
453OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{ 453OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{
454 if ( res.state() == OSQLResult::Failure ) { 454 if ( res.state() == OSQLResult::Failure ) {
455 OTodo to; 455 OTodo to;
456 return to; 456 return to;
457 } 457 }
458 458
459 OSQLResultItem::ValueList list = res.results(); 459 OSQLResultItem::ValueList list = res.results();
460 OSQLResultItem::ValueList::Iterator it = list.begin(); 460 OSQLResultItem::ValueList::Iterator it = list.begin();
461 qWarning("todo1"); 461 qWarning("todo1");
462 OTodo to = todo( (*it) ); 462 OTodo to = todo( (*it) );
463 cache( to ); 463 cache( to );
464 ++it; 464 ++it;
465 465
466 for ( ; it != list.end(); ++it ) { 466 for ( ; it != list.end(); ++it ) {
467 qWarning("caching"); 467 qWarning("caching");
468 cache( todo( (*it) ) ); 468 cache( todo( (*it) ) );
469 } 469 }
470 return to; 470 return to;
471} 471}
472OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const { 472OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const {
473 qWarning("todo"); 473 qWarning("todo");
474 bool has = false; QDate da = QDate::currentDate(); 474 bool has = false; QDate da = QDate::currentDate();
475 has = date( da, item.data("DueDate") ); 475 has = date( da, item.data("DueDate") );
476 QStringList cats = QStringList::split(";", item.data("categories") ); 476 QStringList cats = QStringList::split(";", item.data("categories") );
477 477
478 OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(), 478 OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(),
479 cats, item.data("summary"), item.data("description"), 479 cats, item.data("summary"), item.data("description"),
480 item.data("progress").toUShort(), has, da, 480 item.data("progress").toUShort(), has, da,
481 item.data("uid").toInt() ); 481 item.data("uid").toInt() );
482 return to; 482 return to;
483} 483}
484OTodo OTodoAccessBackendSQL::todo( int uid )const { 484OTodo OTodoAccessBackendSQL::todo( int uid )const {
485 FindQuery find( uid ); 485 FindQuery find( uid );
486 return todo( m_driver->query(&find) ); 486 return todo( m_driver->query(&find) );
487} 487}
488/* 488/*
489 * update the dict 489 * update the dict
490 */ 490 */
491void OTodoAccessBackendSQL::fillDict() { 491void OTodoAccessBackendSQL::fillDict() {
492 /* initialize dict */ 492 /* initialize dict */
493 /* 493 /*
494 * UPDATE dict if you change anything!!! 494 * UPDATE dict if you change anything!!!
495 */ 495 */
496 m_dict.setAutoDelete( TRUE ); 496 m_dict.setAutoDelete( TRUE );
497 m_dict.insert("Categories" , new int(OTodo::Category) ); 497 m_dict.insert("Categories" , new int(OTodo::Category) );
498 m_dict.insert("Uid" , new int(OTodo::Uid) ); 498 m_dict.insert("Uid" , new int(OTodo::Uid) );
499 m_dict.insert("HasDate" , new int(OTodo::HasDate) ); 499 m_dict.insert("HasDate" , new int(OTodo::HasDate) );
500 m_dict.insert("Completed" , new int(OTodo::Completed) ); 500 m_dict.insert("Completed" , new int(OTodo::Completed) );
501 m_dict.insert("Description" , new int(OTodo::Description) ); 501 m_dict.insert("Description" , new int(OTodo::Description) );
502 m_dict.insert("Summary" , new int(OTodo::Summary) ); 502 m_dict.insert("Summary" , new int(OTodo::Summary) );
503 m_dict.insert("Priority" , new int(OTodo::Priority) ); 503 m_dict.insert("Priority" , new int(OTodo::Priority) );
504 m_dict.insert("DateDay" , new int(OTodo::DateDay) ); 504 m_dict.insert("DateDay" , new int(OTodo::DateDay) );
505 m_dict.insert("DateMonth" , new int(OTodo::DateMonth) ); 505 m_dict.insert("DateMonth" , new int(OTodo::DateMonth) );
506 m_dict.insert("DateYear" , new int(OTodo::DateYear) ); 506 m_dict.insert("DateYear" , new int(OTodo::DateYear) );
507 m_dict.insert("Progress" , new int(OTodo::Progress) ); 507 m_dict.insert("Progress" , new int(OTodo::Progress) );
508 m_dict.insert("Completed", new int(OTodo::Completed) ); 508 m_dict.insert("Completed", new int(OTodo::Completed) );
509 m_dict.insert("CrossReference", new int(OTodo::CrossReference) ); 509 m_dict.insert("CrossReference", new int(OTodo::CrossReference) );
510 m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) ); 510 m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) );
511 m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) ); 511 m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) );
512} 512}
513/* 513/*
514 * need to be const so let's fool the 514 * need to be const so let's fool the
515 * compiler :( 515 * compiler :(
516 */ 516 */
517void OTodoAccessBackendSQL::update()const { 517void OTodoAccessBackendSQL::update()const {
518 ((OTodoAccessBackendSQL*)this)->m_dirty = false; 518 ((OTodoAccessBackendSQL*)this)->m_dirty = false;
519 LoadQuery lo; 519 LoadQuery lo;
520 OSQLResult res = m_driver->query(&lo); 520 OSQLResult res = m_driver->query(&lo);
521 if ( res.state() != OSQLResult::Success ) 521 if ( res.state() != OSQLResult::Success )
522 return; 522 return;
523 523
524 ((OTodoAccessBackendSQL*)this)->m_uids = uids( res ); 524 ((OTodoAccessBackendSQL*)this)->m_uids = uids( res );
525} 525}
526QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{ 526QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{
527 527
528 OSQLResultItem::ValueList list = res.results(); 528 OSQLResultItem::ValueList list = res.results();
529 OSQLResultItem::ValueList::Iterator it; 529 OSQLResultItem::ValueList::Iterator it;
530 QArray<int> ints(list.count() ); 530 QArray<int> ints(list.count() );
531 qWarning(" count = %d", list.count() ); 531 qWarning(" count = %d", list.count() );
532 532
533 int i = 0; 533 int i = 0;
534 for (it = list.begin(); it != list.end(); ++it ) { 534 for (it = list.begin(); it != list.end(); ++it ) {
535 ints[i] = (*it).data("uid").toInt(); 535 ints[i] = (*it).data("uid").toInt();
536 i++; 536 i++;
537 } 537 }
538 return ints; 538 return ints;
539} 539}
540 540
diff --git a/libopie2/opiepim/backend/otodoaccesssql.h b/libopie2/opiepim/backend/otodoaccesssql.h
index 0f6dd2c..6a4257c 100644
--- a/libopie2/opiepim/backend/otodoaccesssql.h
+++ b/libopie2/opiepim/backend/otodoaccesssql.h
@@ -1,50 +1,50 @@
1#ifndef OPIE_PIM_ACCESS_SQL_H 1#ifndef OPIE_PIM_ACCESS_SQL_H
2#define OPIE_PIM_ACCESS_SQL_H 2#define OPIE_PIM_ACCESS_SQL_H
3 3
4#include <qasciidict.h> 4#include <qasciidict.h>
5 5
6#include "otodoaccessbackend.h" 6#include "otodoaccessbackend.h"
7 7
8class OSQLDriver; 8class OSQLDriver;
9class OSQLResult; 9class OSQLResult;
10class OSQLResultItem; 10class OSQLResultItem;
11class OTodoAccessBackendSQL : public OTodoAccessBackend { 11class OTodoAccessBackendSQL : public OTodoAccessBackend {
12public: 12public:
13 OTodoAccessBackendSQL( const QString& file ); 13 OTodoAccessBackendSQL( const QString& file );
14 ~OTodoAccessBackendSQL(); 14 ~OTodoAccessBackendSQL();
15 15
16 bool load(); 16 bool load();
17 bool reload(); 17 bool reload();
18 bool save(); 18 bool save();
19 QArray<int> allRecords()const; 19 QArray<int> allRecords()const;
20 20
21 QArray<int> queryByExample( const OTodo& t, int sort ); 21 QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() );
22 OTodo find(int uid)const; 22 OTodo find(int uid)const;
23 OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; 23 OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const;
24 void clear(); 24 void clear();
25 bool add( const OTodo& t ); 25 bool add( const OTodo& t );
26 bool remove( int uid ); 26 bool remove( int uid );
27 bool replace( const OTodo& t ); 27 bool replace( const OTodo& t );
28 28
29 QArray<int> overDue(); 29 QArray<int> overDue();
30 QArray<int> effectiveToDos( const QDate& start, 30 QArray<int> effectiveToDos( const QDate& start,
31 const QDate& end, bool includeNoDates ); 31 const QDate& end, bool includeNoDates );
32 QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); 32 QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat );
33 33
34private: 34private:
35 void update()const; 35 void update()const;
36 void fillDict(); 36 void fillDict();
37 inline bool date( QDate& date, const QString& )const; 37 inline bool date( QDate& date, const QString& )const;
38 inline OTodo todo( const OSQLResult& )const; 38 inline OTodo todo( const OSQLResult& )const;
39 inline OTodo todo( OSQLResultItem& )const; 39 inline OTodo todo( OSQLResultItem& )const;
40 inline QArray<int> uids( const OSQLResult& )const; 40 inline QArray<int> uids( const OSQLResult& )const;
41 OTodo todo( int uid )const; 41 OTodo todo( int uid )const;
42 42
43 QAsciiDict<int> m_dict; 43 QAsciiDict<int> m_dict;
44 OSQLDriver* m_driver; 44 OSQLDriver* m_driver;
45 QArray<int> m_uids; 45 QArray<int> m_uids;
46 bool m_dirty : 1; 46 bool m_dirty : 1;
47}; 47};
48 48
49 49
50#endif 50#endif
diff --git a/libopie2/opiepim/backend/otodoaccessvcal.cpp b/libopie2/opiepim/backend/otodoaccessvcal.cpp
index 309f9e1..2136283 100644
--- a/libopie2/opiepim/backend/otodoaccessvcal.cpp
+++ b/libopie2/opiepim/backend/otodoaccessvcal.cpp
@@ -1,201 +1,201 @@
1#include <qfile.h> 1#include <qfile.h>
2 2
3#include <qtopia/private/vobject_p.h> 3#include <qtopia/private/vobject_p.h>
4#include <qtopia/timeconversion.h> 4#include <qtopia/timeconversion.h>
5#include <qtopia/private/qfiledirect_p.h> 5#include <qtopia/private/qfiledirect_p.h>
6 6
7#include "otodoaccessvcal.h" 7#include "otodoaccessvcal.h"
8 8
9namespace { 9namespace {
10 static OTodo eventByVObj( VObject *obj ){ 10 static OTodo eventByVObj( VObject *obj ){
11 OTodo event; 11 OTodo event;
12 VObject *ob; 12 VObject *ob;
13 QCString name; 13 QCString name;
14 // no uid, attendees, ... and no fun 14 // no uid, attendees, ... and no fun
15 // description 15 // description
16 if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){ 16 if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){
17 name = vObjectStringZValue( ob ); 17 name = vObjectStringZValue( ob );
18 event.setDescription( name ); 18 event.setDescription( name );
19 } 19 }
20 // summary 20 // summary
21 if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) { 21 if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) {
22 name = vObjectStringZValue( ob ); 22 name = vObjectStringZValue( ob );
23 event.setSummary( name ); 23 event.setSummary( name );
24 } 24 }
25 // completed 25 // completed
26 if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){ 26 if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){
27 name = vObjectStringZValue( ob ); 27 name = vObjectStringZValue( ob );
28 if( name == "COMPLETED" ){ 28 if( name == "COMPLETED" ){
29 event.setCompleted( true ); 29 event.setCompleted( true );
30 }else{ 30 }else{
31 event.setCompleted( false ); 31 event.setCompleted( false );
32 } 32 }
33 }else 33 }else
34 event.setCompleted( false ); 34 event.setCompleted( false );
35 // priority 35 // priority
36 if ((ob = isAPropertyOf(obj, VCPriorityProp))) { 36 if ((ob = isAPropertyOf(obj, VCPriorityProp))) {
37 name = vObjectStringZValue( ob ); 37 name = vObjectStringZValue( ob );
38 bool ok; 38 bool ok;
39 event.setPriority(name.toInt(&ok) ); 39 event.setPriority(name.toInt(&ok) );
40 } 40 }
41 //due date 41 //due date
42 if((ob = isAPropertyOf(obj, VCDueProp)) ){ 42 if((ob = isAPropertyOf(obj, VCDueProp)) ){
43 event.setHasDueDate( true ); 43 event.setHasDueDate( true );
44 name = vObjectStringZValue( ob ); 44 name = vObjectStringZValue( ob );
45 event.setDueDate( TimeConversion::fromISO8601( name).date() ); 45 event.setDueDate( TimeConversion::fromISO8601( name).date() );
46 } 46 }
47 // categories 47 // categories
48 if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){ 48 if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){
49 name = vObjectStringZValue( ob ); 49 name = vObjectStringZValue( ob );
50 qWarning("Categories:%s", name.data() ); 50 qWarning("Categories:%s", name.data() );
51 } 51 }
52 52
53 event.setUid( 1 ); 53 event.setUid( 1 );
54 return event; 54 return event;
55 }; 55 };
56 static VObject *vobjByEvent( const OTodo &event ) { 56 static VObject *vobjByEvent( const OTodo &event ) {
57 VObject *task = newVObject( VCTodoProp ); 57 VObject *task = newVObject( VCTodoProp );
58 if( task == 0 ) 58 if( task == 0 )
59 return 0l; 59 return 0l;
60 60
61 if( event.hasDueDate() ) { 61 if( event.hasDueDate() ) {
62 QTime time(0, 0, 0); 62 QTime time(0, 0, 0);
63 QDateTime date(event.dueDate(), time ); 63 QDateTime date(event.dueDate(), time );
64 addPropValue( task, VCDueProp, 64 addPropValue( task, VCDueProp,
65 TimeConversion::toISO8601( date ) ); 65 TimeConversion::toISO8601( date ) );
66 } 66 }
67 67
68 if( event.isCompleted() ) 68 if( event.isCompleted() )
69 addPropValue( task, VCStatusProp, "COMPLETED"); 69 addPropValue( task, VCStatusProp, "COMPLETED");
70 70
71 QString string = QString::number(event.priority() ); 71 QString string = QString::number(event.priority() );
72 addPropValue( task, VCPriorityProp, string.local8Bit() ); 72 addPropValue( task, VCPriorityProp, string.local8Bit() );
73 73
74 addPropValue( task, VCCategoriesProp, 74 addPropValue( task, VCCategoriesProp,
75 event.idsToString( event.categories() ).local8Bit() ); 75 event.idsToString( event.categories() ).local8Bit() );
76 76
77 addPropValue( task, VCDescriptionProp, 77 addPropValue( task, VCDescriptionProp,
78 event.description().local8Bit() ); 78 event.description().local8Bit() );
79 79
80 addPropValue( task, VCSummaryProp, 80 addPropValue( task, VCSummaryProp,
81 event.summary().local8Bit() ); 81 event.summary().local8Bit() );
82 return task; 82 return task;
83}; 83};
84} 84}
85 85
86OTodoAccessVCal::OTodoAccessVCal( const QString& path ) 86OTodoAccessVCal::OTodoAccessVCal( const QString& path )
87 : m_dirty(false), m_file( path ) 87 : m_dirty(false), m_file( path )
88{ 88{
89} 89}
90OTodoAccessVCal::~OTodoAccessVCal() { 90OTodoAccessVCal::~OTodoAccessVCal() {
91} 91}
92bool OTodoAccessVCal::load() { 92bool OTodoAccessVCal::load() {
93 m_map.clear(); 93 m_map.clear();
94 m_dirty = false; 94 m_dirty = false;
95 95
96 VObject* vcal = 0l; 96 VObject* vcal = 0l;
97 vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); 97 vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() );
98 if (!vcal ) 98 if (!vcal )
99 return false; 99 return false;
100 100
101 // Iterate over the list 101 // Iterate over the list
102 VObjectIterator it; 102 VObjectIterator it;
103 VObject* vobj; 103 VObject* vobj;
104 104
105 initPropIterator(&it, vcal); 105 initPropIterator(&it, vcal);
106 106
107 while( moreIteration( &it ) ) { 107 while( moreIteration( &it ) ) {
108 vobj = ::nextVObject( &it ); 108 vobj = ::nextVObject( &it );
109 QCString name = ::vObjectName( vobj ); 109 QCString name = ::vObjectName( vobj );
110 if( name == VCTodoProp ){ 110 if( name == VCTodoProp ){
111 OTodo to = eventByVObj( vobj ); 111 OTodo to = eventByVObj( vobj );
112 m_map.insert( to.uid(), to ); 112 m_map.insert( to.uid(), to );
113 } 113 }
114 } 114 }
115 115
116 // Should I do a delete vcal? 116 // Should I do a delete vcal?
117 117
118 return true; 118 return true;
119} 119}
120bool OTodoAccessVCal::reload() { 120bool OTodoAccessVCal::reload() {
121 return load(); 121 return load();
122} 122}
123bool OTodoAccessVCal::save() { 123bool OTodoAccessVCal::save() {
124 if (!m_dirty ) 124 if (!m_dirty )
125 return true; 125 return true;
126 126
127 QFileDirect file( m_file ); 127 QFileDirect file( m_file );
128 if (!file.open(IO_WriteOnly ) ) 128 if (!file.open(IO_WriteOnly ) )
129 return false; 129 return false;
130 130
131 VObject *obj; 131 VObject *obj;
132 obj = newVObject( VCCalProp ); 132 obj = newVObject( VCCalProp );
133 addPropValue( obj, VCVersionProp, "1.0" ); 133 addPropValue( obj, VCVersionProp, "1.0" );
134 VObject *vo; 134 VObject *vo;
135 for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ 135 for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){
136 vo = vobjByEvent( it.data() ); 136 vo = vobjByEvent( it.data() );
137 addVObjectProp(obj, vo ); 137 addVObjectProp(obj, vo );
138 } 138 }
139 writeVObject( file.directHandle(), obj ); 139 writeVObject( file.directHandle(), obj );
140 cleanVObject( obj ); 140 cleanVObject( obj );
141 cleanStrTbl(); 141 cleanStrTbl();
142 142
143 m_dirty = false; 143 m_dirty = false;
144 return true; 144 return true;
145} 145}
146void OTodoAccessVCal::clear() { 146void OTodoAccessVCal::clear() {
147 m_map.clear(); 147 m_map.clear();
148 m_dirty = true; 148 m_dirty = true;
149} 149}
150bool OTodoAccessVCal::add( const OTodo& to ) { 150bool OTodoAccessVCal::add( const OTodo& to ) {
151 m_map.insert( to.uid(), to ); 151 m_map.insert( to.uid(), to );
152 m_dirty = true; 152 m_dirty = true;
153 return true; 153 return true;
154} 154}
155bool OTodoAccessVCal::remove( int uid ) { 155bool OTodoAccessVCal::remove( int uid ) {
156 m_map.remove( uid ); 156 m_map.remove( uid );
157 m_dirty = true; 157 m_dirty = true;
158 return true; 158 return true;
159} 159}
160void OTodoAccessVCal::removeAllCompleted() { 160void OTodoAccessVCal::removeAllCompleted() {
161 for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) { 161 for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) {
162 if ( (*it).isCompleted() ) 162 if ( (*it).isCompleted() )
163 m_map.remove( it ); 163 m_map.remove( it );
164 } 164 }
165} 165}
166bool OTodoAccessVCal::replace( const OTodo& to ) { 166bool OTodoAccessVCal::replace( const OTodo& to ) {
167 m_map.replace( to.uid(), to ); 167 m_map.replace( to.uid(), to );
168 m_dirty = true; 168 m_dirty = true;
169 return true; 169 return true;
170} 170}
171OTodo OTodoAccessVCal::find(int uid )const { 171OTodo OTodoAccessVCal::find(int uid )const {
172 return m_map[uid]; 172 return m_map[uid];
173} 173}
174QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) { 174QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) {
175 QArray<int> ar(0); 175 QArray<int> ar(0);
176 return ar; 176 return ar;
177} 177}
178QArray<int> OTodoAccessVCal::allRecords()const { 178QArray<int> OTodoAccessVCal::allRecords()const {
179 QArray<int> ar( m_map.count() ); 179 QArray<int> ar( m_map.count() );
180 QMap<int, OTodo>::ConstIterator it; 180 QMap<int, OTodo>::ConstIterator it;
181 int i = 0; 181 int i = 0;
182 for ( it = m_map.begin(); it != m_map.end(); ++it ) { 182 for ( it = m_map.begin(); it != m_map.end(); ++it ) {
183 ar[i] = it.key(); 183 ar[i] = it.key();
184 i++; 184 i++;
185 } 185 }
186 return ar; 186 return ar;
187} 187}
188QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int ) { 188QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) {
189 QArray<int> ar(0); 189 QArray<int> ar(0);
190 return ar; 190 return ar;
191} 191}
192QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& , 192QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& ,
193 const QDate& , 193 const QDate& ,
194 bool ) { 194 bool ) {
195 QArray<int> ar(0); 195 QArray<int> ar(0);
196 return ar; 196 return ar;
197} 197}
198QArray<int> OTodoAccessVCal::overDue() { 198QArray<int> OTodoAccessVCal::overDue() {
199 QArray<int> ar(0); 199 QArray<int> ar(0);
200 return ar; 200 return ar;
201} 201}
diff --git a/libopie2/opiepim/backend/otodoaccessvcal.h b/libopie2/opiepim/backend/otodoaccessvcal.h
index 452f602..a90ee9c 100644
--- a/libopie2/opiepim/backend/otodoaccessvcal.h
+++ b/libopie2/opiepim/backend/otodoaccessvcal.h
@@ -1,37 +1,37 @@
1#ifndef OPIE_OTODO_ACCESS_VCAL_H 1#ifndef OPIE_OTODO_ACCESS_VCAL_H
2#define OPIE_OTODO_ACCESS_VCAL_H 2#define OPIE_OTODO_ACCESS_VCAL_H
3 3
4#include "otodoaccessbackend.h" 4#include "otodoaccessbackend.h"
5 5
6class OTodoAccessVCal : public OTodoAccessBackend { 6class OTodoAccessVCal : public OTodoAccessBackend {
7public: 7public:
8 OTodoAccessVCal(const QString& ); 8 OTodoAccessVCal(const QString& );
9 ~OTodoAccessVCal(); 9 ~OTodoAccessVCal();
10 10
11 bool load(); 11 bool load();
12 bool reload(); 12 bool reload();
13 bool save(); 13 bool save();
14 14
15 QArray<int> allRecords()const; 15 QArray<int> allRecords()const;
16 QArray<int> queryByExample( const OTodo& t, int sort ); 16 QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() );
17 QArray<int> effectiveToDos( const QDate& start, 17 QArray<int> effectiveToDos( const QDate& start,
18 const QDate& end, 18 const QDate& end,
19 bool includeNoDates ); 19 bool includeNoDates );
20 QArray<int> overDue(); 20 QArray<int> overDue();
21 QArray<int> sorted( bool asc, int sortOrder, int sortFilter, 21 QArray<int> sorted( bool asc, int sortOrder, int sortFilter,
22 int cat ); 22 int cat );
23 OTodo find(int uid)const; 23 OTodo find(int uid)const;
24 void clear(); 24 void clear();
25 bool add( const OTodo& ); 25 bool add( const OTodo& );
26 bool remove( int uid ); 26 bool remove( int uid );
27 bool replace( const OTodo& ); 27 bool replace( const OTodo& );
28 28
29 void removeAllCompleted(); 29 void removeAllCompleted();
30 30
31private: 31private:
32 bool m_dirty : 1; 32 bool m_dirty : 1;
33 QString m_file; 33 QString m_file;
34 QMap<int, OTodo> m_map; 34 QMap<int, OTodo> m_map;
35}; 35};
36 36
37#endif 37#endif
diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp
index cda300b..71e8787 100644
--- a/libopie2/opiepim/backend/otodoaccessxml.cpp
+++ b/libopie2/opiepim/backend/otodoaccessxml.cpp
@@ -1,675 +1,675 @@
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 "otodoaccessxml.h" 18#include "otodoaccessxml.h"
19 19
20namespace { 20namespace {
21 // FROM TT again 21 // FROM TT again
22char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) 22char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
23{ 23{
24 char needleChar; 24 char needleChar;
25 char haystackChar; 25 char haystackChar;
26 if (!needle || !haystack || !hLen || !nLen) 26 if (!needle || !haystack || !hLen || !nLen)
27 return 0; 27 return 0;
28 28
29 const char* hsearch = haystack; 29 const char* hsearch = haystack;
30 30
31 if ((needleChar = *needle++) != 0) { 31 if ((needleChar = *needle++) != 0) {
32 nLen--; //(to make up for needle++) 32 nLen--; //(to make up for needle++)
33 do { 33 do {
34 do { 34 do {
35 if ((haystackChar = *hsearch++) == 0) 35 if ((haystackChar = *hsearch++) == 0)
36 return (0); 36 return (0);
37 if (hsearch >= haystack + hLen) 37 if (hsearch >= haystack + hLen)
38 return (0); 38 return (0);
39 } while (haystackChar != needleChar); 39 } while (haystackChar != needleChar);
40 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); 40 } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
41 hsearch--; 41 hsearch--;
42 } 42 }
43 return ((char *)hsearch); 43 return ((char *)hsearch);
44} 44}
45} 45}
46 46
47 47
48OTodoAccessXML::OTodoAccessXML( const QString& appName, 48OTodoAccessXML::OTodoAccessXML( const QString& appName,
49 const QString& fileName ) 49 const QString& fileName )
50 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) 50 : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false )
51{ 51{
52 if (!fileName.isEmpty() ) 52 if (!fileName.isEmpty() )
53 m_file = fileName; 53 m_file = fileName;
54 else 54 else
55 m_file = Global::applicationFileName( "todolist", "todolist.xml" ); 55 m_file = Global::applicationFileName( "todolist", "todolist.xml" );
56} 56}
57OTodoAccessXML::~OTodoAccessXML() { 57OTodoAccessXML::~OTodoAccessXML() {
58 58
59} 59}
60bool OTodoAccessXML::load() { 60bool OTodoAccessXML::load() {
61 m_opened = true; 61 m_opened = true;
62 m_changed = false; 62 m_changed = false;
63 /* initialize dict */ 63 /* initialize dict */
64 /* 64 /*
65 * UPDATE dict if you change anything!!! 65 * UPDATE dict if you change anything!!!
66 */ 66 */
67 QAsciiDict<int> dict(21); 67 QAsciiDict<int> dict(21);
68 dict.setAutoDelete( TRUE ); 68 dict.setAutoDelete( TRUE );
69 dict.insert("Categories" , new int(OTodo::Category) ); 69 dict.insert("Categories" , new int(OTodo::Category) );
70 dict.insert("Uid" , new int(OTodo::Uid) ); 70 dict.insert("Uid" , new int(OTodo::Uid) );
71 dict.insert("HasDate" , new int(OTodo::HasDate) ); 71 dict.insert("HasDate" , new int(OTodo::HasDate) );
72 dict.insert("Completed" , new int(OTodo::Completed) ); 72 dict.insert("Completed" , new int(OTodo::Completed) );
73 dict.insert("Description" , new int(OTodo::Description) ); 73 dict.insert("Description" , new int(OTodo::Description) );
74 dict.insert("Summary" , new int(OTodo::Summary) ); 74 dict.insert("Summary" , new int(OTodo::Summary) );
75 dict.insert("Priority" , new int(OTodo::Priority) ); 75 dict.insert("Priority" , new int(OTodo::Priority) );
76 dict.insert("DateDay" , new int(OTodo::DateDay) ); 76 dict.insert("DateDay" , new int(OTodo::DateDay) );
77 dict.insert("DateMonth" , new int(OTodo::DateMonth) ); 77 dict.insert("DateMonth" , new int(OTodo::DateMonth) );
78 dict.insert("DateYear" , new int(OTodo::DateYear) ); 78 dict.insert("DateYear" , new int(OTodo::DateYear) );
79 dict.insert("Progress" , new int(OTodo::Progress) ); 79 dict.insert("Progress" , new int(OTodo::Progress) );
80 dict.insert("Completed", new int(OTodo::Completed) ); 80 dict.insert("Completed", new int(OTodo::Completed) );
81 dict.insert("CrossReference", new int(OTodo::CrossReference) ); 81 dict.insert("CrossReference", new int(OTodo::CrossReference) );
82 dict.insert("State", new int(OTodo::State) ); 82 dict.insert("State", new int(OTodo::State) );
83 dict.insert("Recurrence", new int(OTodo::Recurrence) ); 83 dict.insert("Recurrence", new int(OTodo::Recurrence) );
84 dict.insert("Alarms", new int(OTodo::Alarms) ); 84 dict.insert("Alarms", new int(OTodo::Alarms) );
85 dict.insert("Reminders", new int(OTodo::Reminders) ); 85 dict.insert("Reminders", new int(OTodo::Reminders) );
86 dict.insert("Notifiers", new int(OTodo::Notifiers) ); 86 dict.insert("Notifiers", new int(OTodo::Notifiers) );
87 dict.insert("Maintainer", new int(OTodo::Maintainer) ); 87 dict.insert("Maintainer", new int(OTodo::Maintainer) );
88 88
89 // here the custom XML parser from TT it's GPL 89 // here the custom XML parser from TT it's GPL
90 // but we want to push OpiePIM... to TT..... 90 // but we want to push OpiePIM... to TT.....
91 // mmap part from zecke :) 91 // mmap part from zecke :)
92 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); 92 int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY );
93 struct stat attribut; 93 struct stat attribut;
94 if ( fd < 0 ) return false; 94 if ( fd < 0 ) return false;
95 95
96 if ( fstat(fd, &attribut ) == -1 ) { 96 if ( fstat(fd, &attribut ) == -1 ) {
97 ::close( fd ); 97 ::close( fd );
98 return false; 98 return false;
99 } 99 }
100 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); 100 void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 );
101 if ( map_addr == ( (caddr_t)-1) ) { 101 if ( map_addr == ( (caddr_t)-1) ) {
102 ::close(fd ); 102 ::close(fd );
103 return false; 103 return false;
104 } 104 }
105 /* advise the kernel who we want to read it */ 105 /* advise the kernel who we want to read it */
106 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); 106 ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL );
107 /* we do not the file any more */ 107 /* we do not the file any more */
108 ::close( fd ); 108 ::close( fd );
109 109
110 char* dt = (char*)map_addr; 110 char* dt = (char*)map_addr;
111 int len = attribut.st_size; 111 int len = attribut.st_size;
112 int i = 0; 112 int i = 0;
113 char *point; 113 char *point;
114 const char* collectionString = "<Task "; 114 const char* collectionString = "<Task ";
115 int strLen = strlen(collectionString); 115 int strLen = strlen(collectionString);
116 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { 116 while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) {
117 i = point -dt; 117 i = point -dt;
118 i+= strLen; 118 i+= strLen;
119 qWarning("Found a start at %d %d", i, (point-dt) ); 119 qWarning("Found a start at %d %d", i, (point-dt) );
120 120
121 OTodo ev; 121 OTodo ev;
122 m_year = m_month = m_day = 0; 122 m_year = m_month = m_day = 0;
123 123
124 while ( TRUE ) { 124 while ( TRUE ) {
125 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) 125 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
126 ++i; 126 ++i;
127 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) 127 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
128 break; 128 break;
129 129
130 // we have another attribute, read it. 130 // we have another attribute, read it.
131 int j = i; 131 int j = i;
132 while ( j < len && dt[j] != '=' ) 132 while ( j < len && dt[j] != '=' )
133 ++j; 133 ++j;
134 QCString attr( dt+i, j-i+1); 134 QCString attr( dt+i, j-i+1);
135 135
136 i = ++j; // skip = 136 i = ++j; // skip =
137 137
138 // find the start of quotes 138 // find the start of quotes
139 while ( i < len && dt[i] != '"' ) 139 while ( i < len && dt[i] != '"' )
140 ++i; 140 ++i;
141 j = ++i; 141 j = ++i;
142 142
143 bool haveUtf = FALSE; 143 bool haveUtf = FALSE;
144 bool haveEnt = FALSE; 144 bool haveEnt = FALSE;
145 while ( j < len && dt[j] != '"' ) { 145 while ( j < len && dt[j] != '"' ) {
146 if ( ((unsigned char)dt[j]) > 0x7f ) 146 if ( ((unsigned char)dt[j]) > 0x7f )
147 haveUtf = TRUE; 147 haveUtf = TRUE;
148 if ( dt[j] == '&' ) 148 if ( dt[j] == '&' )
149 haveEnt = TRUE; 149 haveEnt = TRUE;
150 ++j; 150 ++j;
151 } 151 }
152 if ( i == j ) { 152 if ( i == j ) {
153 // empty value 153 // empty value
154 i = j + 1; 154 i = j + 1;
155 continue; 155 continue;
156 } 156 }
157 157
158 QCString value( dt+i, j-i+1 ); 158 QCString value( dt+i, j-i+1 );
159 i = j + 1; 159 i = j + 1;
160 160
161 QString str = (haveUtf ? QString::fromUtf8( value ) 161 QString str = (haveUtf ? QString::fromUtf8( value )
162 : QString::fromLatin1( value ) ); 162 : QString::fromLatin1( value ) );
163 if ( haveEnt ) 163 if ( haveEnt )
164 str = Qtopia::plainString( str ); 164 str = Qtopia::plainString( str );
165 165
166 /* 166 /*
167 * add key + value 167 * add key + value
168 */ 168 */
169 todo( &dict, ev, attr, str ); 169 todo( &dict, ev, attr, str );
170 170
171 } 171 }
172 /* 172 /*
173 * now add it 173 * now add it
174 */ 174 */
175 qWarning("End at %d", i ); 175 qWarning("End at %d", i );
176 if (m_events.contains( ev.uid() ) || ev.uid() == 0) { 176 if (m_events.contains( ev.uid() ) || ev.uid() == 0) {
177 ev.setUid( 1 ); 177 ev.setUid( 1 );
178 m_changed = true; 178 m_changed = true;
179 } 179 }
180 if ( ev.hasDueDate() ) { 180 if ( ev.hasDueDate() ) {
181 ev.setDueDate( QDate(m_year, m_month, m_day) ); 181 ev.setDueDate( QDate(m_year, m_month, m_day) );
182 } 182 }
183 m_events.insert(ev.uid(), ev ); 183 m_events.insert(ev.uid(), ev );
184 m_year = m_month = m_day = -1; 184 m_year = m_month = m_day = -1;
185 } 185 }
186 186
187 munmap(map_addr, attribut.st_size ); 187 munmap(map_addr, attribut.st_size );
188 188
189 qWarning("counts %d records loaded!", m_events.count() ); 189 qWarning("counts %d records loaded!", m_events.count() );
190 return true; 190 return true;
191} 191}
192bool OTodoAccessXML::reload() { 192bool OTodoAccessXML::reload() {
193 m_events.clear(); 193 m_events.clear();
194 return load(); 194 return load();
195} 195}
196bool OTodoAccessXML::save() { 196bool OTodoAccessXML::save() {
197// qWarning("saving"); 197// qWarning("saving");
198 if (!m_opened || !m_changed ) { 198 if (!m_opened || !m_changed ) {
199// qWarning("not saving"); 199// qWarning("not saving");
200 return true; 200 return true;
201 } 201 }
202 QString strNewFile = m_file + ".new"; 202 QString strNewFile = m_file + ".new";
203 QFile f( strNewFile ); 203 QFile f( strNewFile );
204 if (!f.open( IO_WriteOnly|IO_Raw ) ) 204 if (!f.open( IO_WriteOnly|IO_Raw ) )
205 return false; 205 return false;
206 206
207 int written; 207 int written;
208 QString out; 208 QString out;
209 out = "<!DOCTYPE Tasks>\n<Tasks>\n"; 209 out = "<!DOCTYPE Tasks>\n<Tasks>\n";
210 210
211 // for all todos 211 // for all todos
212 QMap<int, OTodo>::Iterator it; 212 QMap<int, OTodo>::Iterator it;
213 for (it = m_events.begin(); it != m_events.end(); ++it ) { 213 for (it = m_events.begin(); it != m_events.end(); ++it ) {
214 out+= "<Task " + toString( (*it) ) + " />\n"; 214 out+= "<Task " + toString( (*it) ) + " />\n";
215 QCString cstr = out.utf8(); 215 QCString cstr = out.utf8();
216 written = f.writeBlock( cstr.data(), cstr.length() ); 216 written = f.writeBlock( cstr.data(), cstr.length() );
217 217
218 /* less written then we wanted */ 218 /* less written then we wanted */
219 if ( written != (int)cstr.length() ) { 219 if ( written != (int)cstr.length() ) {
220 f.close(); 220 f.close();
221 QFile::remove( strNewFile ); 221 QFile::remove( strNewFile );
222 return false; 222 return false;
223 } 223 }
224 out = QString::null; 224 out = QString::null;
225 } 225 }
226 226
227 out += "</Tasks>"; 227 out += "</Tasks>";
228 QCString cstr = out.utf8(); 228 QCString cstr = out.utf8();
229 written = f.writeBlock( cstr.data(), cstr.length() ); 229 written = f.writeBlock( cstr.data(), cstr.length() );
230 230
231 if ( written != (int)cstr.length() ) { 231 if ( written != (int)cstr.length() ) {
232 f.close(); 232 f.close();
233 QFile::remove( strNewFile ); 233 QFile::remove( strNewFile );
234 return false; 234 return false;
235 } 235 }
236 /* flush before renaming */ 236 /* flush before renaming */
237 f.close(); 237 f.close();
238 238
239 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { 239 if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) {
240// qWarning("error renaming"); 240// qWarning("error renaming");
241 QFile::remove( strNewFile ); 241 QFile::remove( strNewFile );
242 } 242 }
243 243
244 m_changed = false; 244 m_changed = false;
245 return true; 245 return true;
246} 246}
247QArray<int> OTodoAccessXML::allRecords()const { 247QArray<int> OTodoAccessXML::allRecords()const {
248 QArray<int> ids( m_events.count() ); 248 QArray<int> ids( m_events.count() );
249 QMap<int, OTodo>::ConstIterator it; 249 QMap<int, OTodo>::ConstIterator it;
250 int i = 0; 250 int i = 0;
251 251
252 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 252 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
253 ids[i] = it.key(); 253 ids[i] = it.key();
254 i++; 254 i++;
255 } 255 }
256 return ids; 256 return ids;
257} 257}
258QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int ) { 258QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) {
259 QArray<int> ids(0); 259 QArray<int> ids(0);
260 return ids; 260 return ids;
261} 261}
262OTodo OTodoAccessXML::find( int uid )const { 262OTodo OTodoAccessXML::find( int uid )const {
263 OTodo todo; 263 OTodo todo;
264 todo.setUid( 0 ); // isEmpty() 264 todo.setUid( 0 ); // isEmpty()
265 QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); 265 QMap<int, OTodo>::ConstIterator it = m_events.find( uid );
266 if ( it != m_events.end() ) 266 if ( it != m_events.end() )
267 todo = it.data(); 267 todo = it.data();
268 268
269 return todo; 269 return todo;
270} 270}
271void OTodoAccessXML::clear() { 271void OTodoAccessXML::clear() {
272 if (m_opened ) 272 if (m_opened )
273 m_changed = true; 273 m_changed = true;
274 274
275 m_events.clear(); 275 m_events.clear();
276} 276}
277bool OTodoAccessXML::add( const OTodo& todo ) { 277bool OTodoAccessXML::add( const OTodo& todo ) {
278// qWarning("add"); 278// qWarning("add");
279 m_changed = true; 279 m_changed = true;
280 m_events.insert( todo.uid(), todo ); 280 m_events.insert( todo.uid(), todo );
281 281
282 return true; 282 return true;
283} 283}
284bool OTodoAccessXML::remove( int uid ) { 284bool OTodoAccessXML::remove( int uid ) {
285 m_changed = true; 285 m_changed = true;
286 m_events.remove( uid ); 286 m_events.remove( uid );
287 287
288 return true; 288 return true;
289} 289}
290bool OTodoAccessXML::replace( const OTodo& todo) { 290bool OTodoAccessXML::replace( const OTodo& todo) {
291 m_changed = true; 291 m_changed = true;
292 m_events.replace( todo.uid(), todo ); 292 m_events.replace( todo.uid(), todo );
293 293
294 return true; 294 return true;
295} 295}
296QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, 296QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
297 const QDate& end, 297 const QDate& end,
298 bool includeNoDates ) { 298 bool includeNoDates ) {
299 QArray<int> ids( m_events.count() ); 299 QArray<int> ids( m_events.count() );
300 QMap<int, OTodo>::Iterator it; 300 QMap<int, OTodo>::Iterator it;
301 301
302 int i = 0; 302 int i = 0;
303 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 303 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
304 if ( !it.data().hasDueDate() ) { 304 if ( !it.data().hasDueDate() ) {
305 if ( includeNoDates ) { 305 if ( includeNoDates ) {
306 ids[i] = it.key(); 306 ids[i] = it.key();
307 i++; 307 i++;
308 } 308 }
309 }else if ( it.data().dueDate() >= start && 309 }else if ( it.data().dueDate() >= start &&
310 it.data().dueDate() <= end ) { 310 it.data().dueDate() <= end ) {
311 ids[i] = it.key(); 311 ids[i] = it.key();
312 i++; 312 i++;
313 } 313 }
314 } 314 }
315 ids.resize( i ); 315 ids.resize( i );
316 return ids; 316 return ids;
317} 317}
318QArray<int> OTodoAccessXML::overDue() { 318QArray<int> OTodoAccessXML::overDue() {
319 QArray<int> ids( m_events.count() ); 319 QArray<int> ids( m_events.count() );
320 int i = 0; 320 int i = 0;
321 321
322 QMap<int, OTodo>::Iterator it; 322 QMap<int, OTodo>::Iterator it;
323 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 323 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
324 if ( it.data().isOverdue() ) { 324 if ( it.data().isOverdue() ) {
325 ids[i] = it.key(); 325 ids[i] = it.key();
326 i++; 326 i++;
327 } 327 }
328 } 328 }
329 ids.resize( i ); 329 ids.resize( i );
330 return ids; 330 return ids;
331} 331}
332 332
333 333
334/* private */ 334/* private */
335void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, 335void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev,
336 const QCString& attr, const QString& val) { 336 const QCString& attr, const QString& val) {
337// qWarning("parse to do from XMLElement" ); 337// qWarning("parse to do from XMLElement" );
338 338
339 int *find=0; 339 int *find=0;
340 340
341 find = (*dict)[ attr.data() ]; 341 find = (*dict)[ attr.data() ];
342 if (!find ) { 342 if (!find ) {
343// qWarning("Unknown option" + it.key() ); 343// qWarning("Unknown option" + it.key() );
344 ev.setCustomField( attr, val ); 344 ev.setCustomField( attr, val );
345 return; 345 return;
346 } 346 }
347 347
348 switch( *find ) { 348 switch( *find ) {
349 case OTodo::Uid: 349 case OTodo::Uid:
350 ev.setUid( val.toInt() ); 350 ev.setUid( val.toInt() );
351 break; 351 break;
352 case OTodo::Category: 352 case OTodo::Category:
353 ev.setCategories( ev.idsFromString( val ) ); 353 ev.setCategories( ev.idsFromString( val ) );
354 break; 354 break;
355 case OTodo::HasDate: 355 case OTodo::HasDate:
356 ev.setHasDueDate( val.toInt() ); 356 ev.setHasDueDate( val.toInt() );
357 break; 357 break;
358 case OTodo::Completed: 358 case OTodo::Completed:
359 ev.setCompleted( val.toInt() ); 359 ev.setCompleted( val.toInt() );
360 break; 360 break;
361 case OTodo::Description: 361 case OTodo::Description:
362 ev.setDescription( val ); 362 ev.setDescription( val );
363 break; 363 break;
364 case OTodo::Summary: 364 case OTodo::Summary:
365 ev.setSummary( val ); 365 ev.setSummary( val );
366 break; 366 break;
367 case OTodo::Priority: 367 case OTodo::Priority:
368 ev.setPriority( val.toInt() ); 368 ev.setPriority( val.toInt() );
369 break; 369 break;
370 case OTodo::DateDay: 370 case OTodo::DateDay:
371 m_day = val.toInt(); 371 m_day = val.toInt();
372 break; 372 break;
373 case OTodo::DateMonth: 373 case OTodo::DateMonth:
374 m_month = val.toInt(); 374 m_month = val.toInt();
375 break; 375 break;
376 case OTodo::DateYear: 376 case OTodo::DateYear:
377 m_year = val.toInt(); 377 m_year = val.toInt();
378 break; 378 break;
379 case OTodo::Progress: 379 case OTodo::Progress:
380 ev.setProgress( val.toInt() ); 380 ev.setProgress( val.toInt() );
381 break; 381 break;
382 case OTodo::CrossReference: 382 case OTodo::CrossReference:
383 { 383 {
384 /* 384 /*
385 * A cross refernce looks like 385 * A cross refernce looks like
386 * appname,id;appname,id 386 * appname,id;appname,id
387 * we need to split it up 387 * we need to split it up
388 */ 388 */
389 QStringList refs = QStringList::split(';', val ); 389 QStringList refs = QStringList::split(';', val );
390 QStringList::Iterator strIt; 390 QStringList::Iterator strIt;
391 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { 391 for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) {
392 int pos = (*strIt).find(','); 392 int pos = (*strIt).find(',');
393 if ( pos > -1 ) 393 if ( pos > -1 )
394 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); 394 ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() );
395 395
396 } 396 }
397 break; 397 break;
398 } 398 }
399 default: 399 default:
400 break; 400 break;
401 } 401 }
402} 402}
403QString OTodoAccessXML::toString( const OTodo& ev )const { 403QString OTodoAccessXML::toString( const OTodo& ev )const {
404 QString str; 404 QString str;
405 405
406 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; 406 str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" ";
407 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; 407 str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" ";
408 str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; 408 str += "Priority=\"" + QString::number( ev.priority() ) + "\" ";
409 str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; 409 str += "Progress=\"" + QString::number(ev.progress() ) + "\" ";
410 410
411 str += "Categories=\"" + toString( ev.categories() ) + "\" "; 411 str += "Categories=\"" + toString( ev.categories() ) + "\" ";
412 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; 412 str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" ";
413 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; 413 str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" ";
414 414
415 if ( ev.hasDueDate() ) { 415 if ( ev.hasDueDate() ) {
416 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; 416 str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" ";
417 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; 417 str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" ";
418 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; 418 str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" ";
419 } 419 }
420// qWarning( "Uid %d", ev.uid() ); 420// qWarning( "Uid %d", ev.uid() );
421 str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; 421 str += "Uid=\"" + QString::number( ev.uid() ) + "\" ";
422 422
423// append the extra options 423// append the extra options
424 /* FIXME Qtopia::Record this is currently not 424 /* FIXME Qtopia::Record this is currently not
425 * possible you can set custom fields 425 * possible you can set custom fields
426 * but don' iterate over the list 426 * but don' iterate over the list
427 * I may do #define private protected 427 * I may do #define private protected
428 * for this case - cough --zecke 428 * for this case - cough --zecke
429 */ 429 */
430 /* 430 /*
431 QMap<QString, QString> extras = ev.extras(); 431 QMap<QString, QString> extras = ev.extras();
432 QMap<QString, QString>::Iterator extIt; 432 QMap<QString, QString>::Iterator extIt;
433 for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) 433 for (extIt = extras.begin(); extIt != extras.end(); ++extIt )
434 str += extIt.key() + "=\"" + extIt.data() + "\" "; 434 str += extIt.key() + "=\"" + extIt.data() + "\" ";
435 */ 435 */
436 // cross refernce 436 // cross refernce
437 437
438 438
439 return str; 439 return str;
440} 440}
441QString OTodoAccessXML::toString( const QArray<int>& ints ) const { 441QString OTodoAccessXML::toString( const QArray<int>& ints ) const {
442 return Qtopia::Record::idsToString( ints ); 442 return Qtopia::Record::idsToString( ints );
443} 443}
444 444
445/* internal class for sorting 445/* internal class for sorting
446 * 446 *
447 * Inspired by todoxmlio.cpp from TT 447 * Inspired by todoxmlio.cpp from TT
448 */ 448 */
449 449
450struct OTodoXMLContainer { 450struct OTodoXMLContainer {
451 OTodo todo; 451 OTodo todo;
452}; 452};
453 453
454namespace { 454namespace {
455 inline QString string( const OTodo& todo) { 455 inline QString string( const OTodo& todo) {
456 return todo.summary().isEmpty() ? 456 return todo.summary().isEmpty() ?
457 todo.description().left(20 ) : 457 todo.description().left(20 ) :
458 todo.summary(); 458 todo.summary();
459 } 459 }
460 inline int completed( const OTodo& todo1, const OTodo& todo2) { 460 inline int completed( const OTodo& todo1, const OTodo& todo2) {
461 int ret = 0; 461 int ret = 0;
462 if ( todo1.isCompleted() ) ret++; 462 if ( todo1.isCompleted() ) ret++;
463 if ( todo2.isCompleted() ) ret--; 463 if ( todo2.isCompleted() ) ret--;
464 return ret; 464 return ret;
465 } 465 }
466 inline int priority( const OTodo& t1, const OTodo& t2) { 466 inline int priority( const OTodo& t1, const OTodo& t2) {
467 return ( t1.priority() - t2.priority() ); 467 return ( t1.priority() - t2.priority() );
468 } 468 }
469 inline int description( const OTodo& t1, const OTodo& t2) { 469 inline int description( const OTodo& t1, const OTodo& t2) {
470 return QString::compare( string(t1), string(t2) ); 470 return QString::compare( string(t1), string(t2) );
471 } 471 }
472 inline int deadline( const OTodo& t1, const OTodo& t2) { 472 inline int deadline( const OTodo& t1, const OTodo& t2) {
473 int ret = 0; 473 int ret = 0;
474 if ( t1.hasDueDate() && 474 if ( t1.hasDueDate() &&
475 t2.hasDueDate() ) 475 t2.hasDueDate() )
476 ret = t2.dueDate().daysTo( t1.dueDate() ); 476 ret = t2.dueDate().daysTo( t1.dueDate() );
477 else if ( t1.hasDueDate() ) 477 else if ( t1.hasDueDate() )
478 ret = -1; 478 ret = -1;
479 else if ( t2.hasDueDate() ) 479 else if ( t2.hasDueDate() )
480 ret = 1; 480 ret = 1;
481 else 481 else
482 ret = 0; 482 ret = 0;
483 483
484 return ret; 484 return ret;
485 } 485 }
486 486
487}; 487};
488 488
489/* 489/*
490 * Returns: 490 * Returns:
491 * 0 if item1 == item2 491 * 0 if item1 == item2
492 * 492 *
493 * non-zero if item1 != item2 493 * non-zero if item1 != item2
494 * 494 *
495 * This function returns int rather than bool so that reimplementations 495 * This function returns int rather than bool so that reimplementations
496 * can return one of three values and use it to sort by: 496 * can return one of three values and use it to sort by:
497 * 497 *
498 * 0 if item1 == item2 498 * 0 if item1 == item2
499 * 499 *
500 * > 0 (positive integer) if item1 > item2 500 * > 0 (positive integer) if item1 > item2
501 * 501 *
502 * < 0 (negative integer) if item1 < item2 502 * < 0 (negative integer) if item1 < item2
503 * 503 *
504 */ 504 */
505class OTodoXMLVector : public QVector<OTodoXMLContainer> { 505class OTodoXMLVector : public QVector<OTodoXMLContainer> {
506public: 506public:
507 OTodoXMLVector(int size, bool asc, int sort) 507 OTodoXMLVector(int size, bool asc, int sort)
508 : QVector<OTodoXMLContainer>( size ) 508 : QVector<OTodoXMLContainer>( size )
509 { 509 {
510 setAutoDelete( true ); 510 setAutoDelete( true );
511 m_asc = asc; 511 m_asc = asc;
512 m_sort = sort; 512 m_sort = sort;
513 } 513 }
514 /* return the summary/description */ 514 /* return the summary/description */
515 QString string( const OTodo& todo) { 515 QString string( const OTodo& todo) {
516 return todo.summary().isEmpty() ? 516 return todo.summary().isEmpty() ?
517 todo.description().left(20 ) : 517 todo.description().left(20 ) :
518 todo.summary(); 518 todo.summary();
519 } 519 }
520 /** 520 /**
521 * we take the sortorder( switch on it ) 521 * we take the sortorder( switch on it )
522 * 522 *
523 */ 523 */
524 int compareItems( Item d1, Item d2 ) { 524 int compareItems( Item d1, Item d2 ) {
525 bool seComp, sePrio, seDesc, seDeadline; 525 bool seComp, sePrio, seDesc, seDeadline;
526 seComp = sePrio = seDeadline = seDesc = false; 526 seComp = sePrio = seDeadline = seDesc = false;
527 int ret =0; 527 int ret =0;
528 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; 528 OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1;
529 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; 529 OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2;
530 530
531 /* same item */ 531 /* same item */
532 if ( con1->todo.uid() == con2->todo.uid() ) 532 if ( con1->todo.uid() == con2->todo.uid() )
533 return 0; 533 return 0;
534 534
535 switch ( m_sort ) { 535 switch ( m_sort ) {
536 /* completed */ 536 /* completed */
537 case 0: { 537 case 0: {
538 ret = completed( con1->todo, con2->todo ); 538 ret = completed( con1->todo, con2->todo );
539 seComp = TRUE; 539 seComp = TRUE;
540 break; 540 break;
541 } 541 }
542 /* priority */ 542 /* priority */
543 case 1: { 543 case 1: {
544 ret = priority( con1->todo, con2->todo ); 544 ret = priority( con1->todo, con2->todo );
545 sePrio = TRUE; 545 sePrio = TRUE;
546 break; 546 break;
547 } 547 }
548 /* description */ 548 /* description */
549 case 2: { 549 case 2: {
550 ret = description( con1->todo, con2->todo ); 550 ret = description( con1->todo, con2->todo );
551 seDesc = TRUE; 551 seDesc = TRUE;
552 break; 552 break;
553 } 553 }
554 /* deadline */ 554 /* deadline */
555 case 3: { 555 case 3: {
556 ret = deadline( con1->todo, con2->todo ); 556 ret = deadline( con1->todo, con2->todo );
557 seDeadline = TRUE; 557 seDeadline = TRUE;
558 break; 558 break;
559 } 559 }
560 default: 560 default:
561 ret = 0; 561 ret = 0;
562 break; 562 break;
563 }; 563 };
564 /* 564 /*
565 * FIXME do better sorting if the first sort criteria 565 * FIXME do better sorting if the first sort criteria
566 * ret equals 0 start with complete and so on... 566 * ret equals 0 start with complete and so on...
567 */ 567 */
568 568
569 /* twist it we're not ascending*/ 569 /* twist it we're not ascending*/
570 if (!m_asc) 570 if (!m_asc)
571 ret = ret * -1; 571 ret = ret * -1;
572 572
573 if ( ret ) 573 if ( ret )
574 return ret; 574 return ret;
575 575
576 // default did not gave difference let's try it other way around 576 // default did not gave difference let's try it other way around
577 /* 577 /*
578 * General try if already checked if not test 578 * General try if already checked if not test
579 * and return 579 * and return
580 * 1.Completed 580 * 1.Completed
581 * 2.Priority 581 * 2.Priority
582 * 3.Description 582 * 3.Description
583 * 4.DueDate 583 * 4.DueDate
584 */ 584 */
585 if (!seComp ) { 585 if (!seComp ) {
586 if ( (ret = completed( con1->todo, con2->todo ) ) ) { 586 if ( (ret = completed( con1->todo, con2->todo ) ) ) {
587 if (!m_asc ) ret *= -1; 587 if (!m_asc ) ret *= -1;
588 return ret; 588 return ret;
589 } 589 }
590 } 590 }
591 if (!sePrio ) { 591 if (!sePrio ) {
592 if ( (ret = priority( con1->todo, con2->todo ) ) ) { 592 if ( (ret = priority( con1->todo, con2->todo ) ) ) {
593 if (!m_asc ) ret *= -1; 593 if (!m_asc ) ret *= -1;
594 return ret; 594 return ret;
595 } 595 }
596 } 596 }
597 if (!seDesc ) { 597 if (!seDesc ) {
598 if ( (ret = description(con1->todo, con2->todo ) ) ) { 598 if ( (ret = description(con1->todo, con2->todo ) ) ) {
599 if (!m_asc) ret *= -1; 599 if (!m_asc) ret *= -1;
600 return ret; 600 return ret;
601 } 601 }
602 } 602 }
603 if (!seDeadline) { 603 if (!seDeadline) {
604 if ( (ret = deadline( con1->todo, con2->todo ) ) ) { 604 if ( (ret = deadline( con1->todo, con2->todo ) ) ) {
605 if (!m_asc) ret *= -1; 605 if (!m_asc) ret *= -1;
606 return ret; 606 return ret;
607 } 607 }
608 } 608 }
609 609
610 return 0; 610 return 0;
611 } 611 }
612 private: 612 private:
613 bool m_asc; 613 bool m_asc;
614 int m_sort; 614 int m_sort;
615 615
616}; 616};
617 617
618QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, 618QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder,
619 int sortFilter, int cat ) { 619 int sortFilter, int cat ) {
620 qWarning("sorted! %d cat", cat); 620 qWarning("sorted! %d cat", cat);
621 OTodoXMLVector vector(m_events.count(), asc,sortOrder ); 621 OTodoXMLVector vector(m_events.count(), asc,sortOrder );
622 QMap<int, OTodo>::Iterator it; 622 QMap<int, OTodo>::Iterator it;
623 int item = 0; 623 int item = 0;
624 624
625 bool bCat = sortFilter & 1 ? true : false; 625 bool bCat = sortFilter & 1 ? true : false;
626 bool bOnly = sortFilter & 2 ? true : false; 626 bool bOnly = sortFilter & 2 ? true : false;
627 bool comp = sortFilter & 4 ? true : false; 627 bool comp = sortFilter & 4 ? true : false;
628 for ( it = m_events.begin(); it != m_events.end(); ++it ) { 628 for ( it = m_events.begin(); it != m_events.end(); ++it ) {
629 629
630 /* show category */ 630 /* show category */
631 if ( bCat && cat != 0) 631 if ( bCat && cat != 0)
632 if (!(*it).categories().contains( cat ) ) { 632 if (!(*it).categories().contains( cat ) ) {
633 qWarning("category mis match"); 633 qWarning("category mis match");
634 continue; 634 continue;
635 } 635 }
636 /* isOverdue but we should not show overdue - why?*/ 636 /* isOverdue but we should not show overdue - why?*/
637/* if ( (*it).isOverdue() && !bOnly ) { 637/* if ( (*it).isOverdue() && !bOnly ) {
638 qWarning("item is overdue but !bOnly"); 638 qWarning("item is overdue but !bOnly");
639 continue; 639 continue;
640 } 640 }
641*/ 641*/
642 if ( !(*it).isOverdue() && bOnly ) { 642 if ( !(*it).isOverdue() && bOnly ) {
643 qWarning("item is not overdue but bOnly checked"); 643 qWarning("item is not overdue but bOnly checked");
644 continue; 644 continue;
645 } 645 }
646 646
647 if ((*it).isCompleted() && comp ) { 647 if ((*it).isCompleted() && comp ) {
648 qWarning("completed continue!"); 648 qWarning("completed continue!");
649 continue; 649 continue;
650 } 650 }
651 651
652 652
653 OTodoXMLContainer* con = new OTodoXMLContainer(); 653 OTodoXMLContainer* con = new OTodoXMLContainer();
654 con->todo = (*it); 654 con->todo = (*it);
655 vector.insert(item, con ); 655 vector.insert(item, con );
656 item++; 656 item++;
657 } 657 }
658 qWarning("XXX %d Items added", item); 658 qWarning("XXX %d Items added", item);
659 vector.resize( item ); 659 vector.resize( item );
660 /* sort it now */ 660 /* sort it now */
661 vector.sort(); 661 vector.sort();
662 /* now get the uids */ 662 /* now get the uids */
663 QArray<int> array( vector.count() ); 663 QArray<int> array( vector.count() );
664 for (uint i= 0; i < vector.count(); i++ ) { 664 for (uint i= 0; i < vector.count(); i++ ) {
665 array[i] = ( vector.at(i) )->todo.uid(); 665 array[i] = ( vector.at(i) )->todo.uid();
666 } 666 }
667 qWarning("array count = %d %d", array.count(), vector.count() ); 667 qWarning("array count = %d %d", array.count(), vector.count() );
668 return array; 668 return array;
669}; 669};
670void OTodoAccessXML::removeAllCompleted() { 670void OTodoAccessXML::removeAllCompleted() {
671 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { 671 for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) {
672 if ( (*it).isCompleted() ) 672 if ( (*it).isCompleted() )
673 m_events.remove( it ); 673 m_events.remove( it );
674 } 674 }
675} 675}
diff --git a/libopie2/opiepim/backend/otodoaccessxml.h b/libopie2/opiepim/backend/otodoaccessxml.h
index 93609fe..1032c92 100644
--- a/libopie2/opiepim/backend/otodoaccessxml.h
+++ b/libopie2/opiepim/backend/otodoaccessxml.h
@@ -1,57 +1,57 @@
1#ifndef OPIE_TODO_ACCESS_XML_H 1#ifndef OPIE_TODO_ACCESS_XML_H
2#define OPIE_TODO_ACCESS_XML_H 2#define OPIE_TODO_ACCESS_XML_H
3 3
4#include <qasciidict.h> 4#include <qasciidict.h>
5#include <qmap.h> 5#include <qmap.h>
6 6
7#include "otodoaccessbackend.h" 7#include "otodoaccessbackend.h"
8 8
9namespace Opie { 9namespace Opie {
10 class XMLElement; 10 class XMLElement;
11}; 11};
12 12
13class OTodoAccessXML : public OTodoAccessBackend { 13class OTodoAccessXML : public OTodoAccessBackend {
14public: 14public:
15 /** 15 /**
16 * fileName if Empty we will use the default path 16 * fileName if Empty we will use the default path
17 */ 17 */
18 OTodoAccessXML( const QString& appName, 18 OTodoAccessXML( const QString& appName,
19 const QString& fileName = QString::null ); 19 const QString& fileName = QString::null );
20 ~OTodoAccessXML(); 20 ~OTodoAccessXML();
21 21
22 bool load(); 22 bool load();
23 bool reload(); 23 bool reload();
24 bool save(); 24 bool save();
25 25
26 QArray<int> allRecords()const; 26 QArray<int> allRecords()const;
27 QArray<int> queryByExample( const OTodo&, int querysettings ); 27 QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() );
28 OTodo find( int uid )const; 28 OTodo find( int uid )const;
29 void clear(); 29 void clear();
30 bool add( const OTodo& ); 30 bool add( const OTodo& );
31 bool remove( int uid ); 31 bool remove( int uid );
32 void removeAllCompleted(); 32 void removeAllCompleted();
33 bool replace( const OTodo& ); 33 bool replace( const OTodo& );
34 34
35 /* our functions */ 35 /* our functions */
36 QArray<int> effectiveToDos( const QDate& start, 36 QArray<int> effectiveToDos( const QDate& start,
37 const QDate& end, 37 const QDate& end,
38 bool includeNoDates ); 38 bool includeNoDates );
39 QArray<int> overDue(); 39 QArray<int> overDue();
40 QArray<int> sorted( bool asc, int sortOrder, 40 QArray<int> sorted( bool asc, int sortOrder,
41 int sortFilter, int cat ); 41 int sortFilter, int cat );
42private: 42private:
43 void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& ); 43 void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& );
44 QString toString( const OTodo& )const; 44 QString toString( const OTodo& )const;
45 QString toString( const QArray<int>& ints ) const; 45 QString toString( const QArray<int>& ints ) const;
46 QMap<int, OTodo> m_events; 46 QMap<int, OTodo> m_events;
47 QString m_file; 47 QString m_file;
48 QString m_app; 48 QString m_app;
49 bool m_opened : 1; 49 bool m_opened : 1;
50 bool m_changed : 1; 50 bool m_changed : 1;
51 class OTodoAccessXMLPrivate; 51 class OTodoAccessXMLPrivate;
52 OTodoAccessXMLPrivate* d; 52 OTodoAccessXMLPrivate* d;
53 int m_year, m_month, m_day; 53 int m_year, m_month, m_day;
54 54
55}; 55};
56 56
57#endif 57#endif
diff --git a/libopie2/opiepim/core/opimaccesstemplate.h b/libopie2/opiepim/core/opimaccesstemplate.h
index 259e2c1..6a3a0db 100644
--- a/libopie2/opiepim/core/opimaccesstemplate.h
+++ b/libopie2/opiepim/core/opimaccesstemplate.h
@@ -1,286 +1,286 @@
1#ifndef OPIE_PIM_ACCESS_TEMPLATE_H 1#ifndef OPIE_PIM_ACCESS_TEMPLATE_H
2#define OPIE_PIM_ACCESS_TEMPLATE_H 2#define OPIE_PIM_ACCESS_TEMPLATE_H
3 3
4#include <qarray.h> 4#include <qarray.h>
5 5
6#include <opie/opimrecord.h> 6#include <opie/opimrecord.h>
7#include <opie/opimaccessbackend.h> 7#include <opie/opimaccessbackend.h>
8#include <opie/orecordlist.h> 8#include <opie/orecordlist.h>
9 9
10#include "opimcache.h" 10#include "opimcache.h"
11#include "otemplatebase.h" 11#include "otemplatebase.h"
12 12
13/** 13/**
14 * Thats the frontend to our OPIE PIM 14 * Thats the frontend to our OPIE PIM
15 * Library. Either you want to use it's 15 * Library. Either you want to use it's
16 * interface or you want to implement 16 * interface or you want to implement
17 * your own Access lib 17 * your own Access lib
18 * Just create a OPimRecord and inherit from 18 * Just create a OPimRecord and inherit from
19 * the plugins 19 * the plugins
20 */ 20 */
21 21
22template <class T = OPimRecord > 22template <class T = OPimRecord >
23class OPimAccessTemplate : public OTemplateBase<T> { 23class OPimAccessTemplate : public OTemplateBase<T> {
24public: 24public:
25 enum Access { 25 enum Access {
26 Random = 0, 26 Random = 0,
27 SortedAccess 27 SortedAccess
28 }; 28 };
29 typedef ORecordList<T> List; 29 typedef ORecordList<T> List;
30 typedef OPimAccessBackend<T> BackEnd; 30 typedef OPimAccessBackend<T> BackEnd;
31 typedef OPimCache<T> Cache; 31 typedef OPimCache<T> Cache;
32 32
33 /** 33 /**
34 * c'tor BackEnd 34 * c'tor BackEnd
35 * enum Access a small hint on how to handle the backend 35 * enum Access a small hint on how to handle the backend
36 */ 36 */
37 OPimAccessTemplate( BackEnd* end); 37 OPimAccessTemplate( BackEnd* end);
38 38
39 virtual ~OPimAccessTemplate(); 39 virtual ~OPimAccessTemplate();
40 40
41 /** 41 /**
42 * load from the backend 42 * load from the backend
43 */ 43 */
44 bool load(); 44 bool load();
45 45
46 /** Reload database. 46 /** Reload database.
47 * You should execute this function if the external database 47 * You should execute this function if the external database
48 * was changed. 48 * was changed.
49 * This function will load the external database and afterwards 49 * This function will load the external database and afterwards
50 * rejoin the local changes. Therefore the local database will be set consistent. 50 * rejoin the local changes. Therefore the local database will be set consistent.
51 */ 51 */
52 virtual bool reload(); 52 virtual bool reload();
53 53
54 /** Save contacts database. 54 /** Save contacts database.
55 * Save is more a "commit". After calling this function, all changes are public available. 55 * Save is more a "commit". After calling this function, all changes are public available.
56 * @return true if successful 56 * @return true if successful
57 */ 57 */
58 bool save(); 58 bool save();
59 59
60 /** 60 /**
61 * if the resource was changed externally 61 * if the resource was changed externally
62 * You should use the signal handling instead of polling possible changes ! 62 * You should use the signal handling instead of polling possible changes !
63 * zecke: Do you implement a signal for otodoaccess ? 63 * zecke: Do you implement a signal for otodoaccess ?
64 */ 64 */
65 bool wasChangedExternally()const; 65 bool wasChangedExternally()const;
66 66
67 /** 67 /**
68 * return a List of records 68 * return a List of records
69 * you can iterate over them 69 * you can iterate over them
70 */ 70 */
71 virtual List allRecords()const; 71 virtual List allRecords()const;
72 72
73 /** 73 /**
74 * queryByExample. 74 * queryByExample.
75 * @see otodoaccess, ocontactaccess 75 * @see otodoaccess, ocontactaccess
76 */ 76 */
77 virtual List queryByExample( const T& t, int querySettings ); 77 virtual List queryByExample( const T& t, int querySettings, const QDateTime& d = QDateTime() );
78 78
79 /** 79 /**
80 * find the OPimRecord uid 80 * find the OPimRecord uid
81 */ 81 */
82 virtual T find( int uid )const; 82 virtual T find( int uid )const;
83 83
84 /** 84 /**
85 * read ahead cache find method ;) 85 * read ahead cache find method ;)
86 */ 86 */
87 virtual T find( int uid, const QArray<int>&, 87 virtual T find( int uid, const QArray<int>&,
88 uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const; 88 uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const;
89 89
90 /* invalidate cache here */ 90 /* invalidate cache here */
91 /** 91 /**
92 * clears the backend and invalidates the backend 92 * clears the backend and invalidates the backend
93 */ 93 */
94 void clear() ; 94 void clear() ;
95 95
96 /** 96 /**
97 * add T to the backend 97 * add T to the backend
98 * @param t The item to add. 98 * @param t The item to add.
99 * @return <i>true</i> if added successfully. 99 * @return <i>true</i> if added successfully.
100 */ 100 */
101 virtual bool add( const T& t ) ; 101 virtual bool add( const T& t ) ;
102 bool add( const OPimRecord& ); 102 bool add( const OPimRecord& );
103 103
104 /* only the uid matters */ 104 /* only the uid matters */
105 /** 105 /**
106 * remove T from the backend 106 * remove T from the backend
107 * @param t The item to remove 107 * @param t The item to remove
108 * @return <i>true</i> if successful. 108 * @return <i>true</i> if successful.
109 */ 109 */
110 virtual bool remove( const T& t ); 110 virtual bool remove( const T& t );
111 111
112 /** 112 /**
113 * remove the OPimRecord with uid 113 * remove the OPimRecord with uid
114 * @param uid The ID of the item to remove 114 * @param uid The ID of the item to remove
115 * @return <i>true</i> if successful. 115 * @return <i>true</i> if successful.
116 */ 116 */
117 bool remove( int uid ); 117 bool remove( int uid );
118 bool remove( const OPimRecord& ); 118 bool remove( const OPimRecord& );
119 119
120 /** 120 /**
121 * replace T from backend 121 * replace T from backend
122 * @param t The item to replace 122 * @param t The item to replace
123 * @return <i>true</i> if successful. 123 * @return <i>true</i> if successful.
124 */ 124 */
125 virtual bool replace( const T& t) ; 125 virtual bool replace( const T& t) ;
126 126
127 void setReadAhead( uint count ); 127 void setReadAhead( uint count );
128 /** 128 /**
129 * @internal 129 * @internal
130 */ 130 */
131 void cache( const T& )const; 131 void cache( const T& )const;
132 void setSaneCacheSize( int ); 132 void setSaneCacheSize( int );
133 133
134 QArray<int> records()const; 134 QArray<int> records()const;
135protected: 135protected:
136 /** 136 /**
137 * invalidate the cache 137 * invalidate the cache
138 */ 138 */
139 void invalidateCache(); 139 void invalidateCache();
140 140
141 void setBackEnd( BackEnd* end ); 141 void setBackEnd( BackEnd* end );
142 /** 142 /**
143 * returns the backend 143 * returns the backend
144 */ 144 */
145 BackEnd* backEnd(); 145 BackEnd* backEnd();
146 BackEnd* m_backEnd; 146 BackEnd* m_backEnd;
147 Cache m_cache; 147 Cache m_cache;
148 148
149}; 149};
150 150
151template <class T> 151template <class T>
152OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) 152OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end )
153 : OTemplateBase<T>(), m_backEnd( end ) 153 : OTemplateBase<T>(), m_backEnd( end )
154{ 154{
155 if (end ) 155 if (end )
156 end->setFrontend( this ); 156 end->setFrontend( this );
157} 157}
158template <class T> 158template <class T>
159OPimAccessTemplate<T>::~OPimAccessTemplate() { 159OPimAccessTemplate<T>::~OPimAccessTemplate() {
160 qWarning("~OPimAccessTemplate<T>"); 160 qWarning("~OPimAccessTemplate<T>");
161 delete m_backEnd; 161 delete m_backEnd;
162} 162}
163template <class T> 163template <class T>
164bool OPimAccessTemplate<T>::load() { 164bool OPimAccessTemplate<T>::load() {
165 invalidateCache(); 165 invalidateCache();
166 return m_backEnd->load(); 166 return m_backEnd->load();
167} 167}
168template <class T> 168template <class T>
169bool OPimAccessTemplate<T>::reload() { 169bool OPimAccessTemplate<T>::reload() {
170 invalidateCache(); // zecke: I think this should be added (se) 170 invalidateCache(); // zecke: I think this should be added (se)
171 return m_backEnd->reload(); 171 return m_backEnd->reload();
172} 172}
173template <class T> 173template <class T>
174bool OPimAccessTemplate<T>::save() { 174bool OPimAccessTemplate<T>::save() {
175 return m_backEnd->save(); 175 return m_backEnd->save();
176} 176}
177template <class T> 177template <class T>
178typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { 178typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const {
179 QArray<int> ints = m_backEnd->allRecords(); 179 QArray<int> ints = m_backEnd->allRecords();
180 List lis(ints, this ); 180 List lis(ints, this );
181 return lis; 181 return lis;
182} 182}
183template <class T> 183template <class T>
184QArray<int> OPimAccessTemplate<T>::records()const { 184QArray<int> OPimAccessTemplate<T>::records()const {
185 return m_backEnd->allRecords(); 185 return m_backEnd->allRecords();
186} 186}
187template <class T> 187template <class T>
188typename OPimAccessTemplate<T>::List 188typename OPimAccessTemplate<T>::List
189OPimAccessTemplate<T>::queryByExample( const T& t, int sortOrder ) { 189OPimAccessTemplate<T>::queryByExample( const T& t, int settings, const QDateTime& d ) {
190 QArray<int> ints = m_backEnd->queryByExample( t, sortOrder ); 190 QArray<int> ints = m_backEnd->queryByExample( t, settings, d );
191 191
192 List lis(ints, this ); 192 List lis(ints, this );
193 return lis; 193 return lis;
194} 194}
195template <class T> 195template <class T>
196T OPimAccessTemplate<T>::find( int uid ) const{ 196T OPimAccessTemplate<T>::find( int uid ) const{
197 T t = m_backEnd->find( uid ); 197 T t = m_backEnd->find( uid );
198 cache( t ); 198 cache( t );
199 return t; 199 return t;
200} 200}
201template <class T> 201template <class T>
202T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, 202T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar,
203 uint current, typename OTemplateBase<T>::CacheDirection dir )const { 203 uint current, typename OTemplateBase<T>::CacheDirection dir )const {
204 /* 204 /*
205 * better do T.isEmpty() 205 * better do T.isEmpty()
206 * after a find this way we would 206 * after a find this way we would
207 * avoid two finds in QCache... 207 * avoid two finds in QCache...
208 */ 208 */
209 // qWarning("find it now %d", uid ); 209 // qWarning("find it now %d", uid );
210 if (m_cache.contains( uid ) ) { 210 if (m_cache.contains( uid ) ) {
211 return m_cache.find( uid ); 211 return m_cache.find( uid );
212 } 212 }
213 213
214 T t = m_backEnd->find( uid, ar, current, dir ); 214 T t = m_backEnd->find( uid, ar, current, dir );
215 cache( t ); 215 cache( t );
216 return t; 216 return t;
217} 217}
218template <class T> 218template <class T>
219void OPimAccessTemplate<T>::clear() { 219void OPimAccessTemplate<T>::clear() {
220 invalidateCache(); 220 invalidateCache();
221 m_backEnd->clear(); 221 m_backEnd->clear();
222} 222}
223template <class T> 223template <class T>
224bool OPimAccessTemplate<T>::add( const T& t ) { 224bool OPimAccessTemplate<T>::add( const T& t ) {
225 cache( t ); 225 cache( t );
226 return m_backEnd->add( t ); 226 return m_backEnd->add( t );
227} 227}
228template <class T> 228template <class T>
229bool OPimAccessTemplate<T>::add( const OPimRecord& rec) { 229bool OPimAccessTemplate<T>::add( const OPimRecord& rec) {
230 /* same type */ 230 /* same type */
231 if ( rec.rtti() == T::rtti() ) { 231 if ( rec.rtti() == T::rtti() ) {
232 const T &t = static_cast<const T&>(rec); 232 const T &t = static_cast<const T&>(rec);
233 return add(t); 233 return add(t);
234 } 234 }
235 return false; 235 return false;
236} 236}
237template <class T> 237template <class T>
238bool OPimAccessTemplate<T>::remove( const T& t ) { 238bool OPimAccessTemplate<T>::remove( const T& t ) {
239 return remove( t.uid() ); 239 return remove( t.uid() );
240} 240}
241template <class T> 241template <class T>
242bool OPimAccessTemplate<T>::remove( int uid ) { 242bool OPimAccessTemplate<T>::remove( int uid ) {
243 m_cache.remove( uid ); 243 m_cache.remove( uid );
244 return m_backEnd->remove( uid ); 244 return m_backEnd->remove( uid );
245} 245}
246template <class T> 246template <class T>
247bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) { 247bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) {
248 return remove( rec.uid() ); 248 return remove( rec.uid() );
249} 249}
250template <class T> 250template <class T>
251bool OPimAccessTemplate<T>::replace( const T& t ) { 251bool OPimAccessTemplate<T>::replace( const T& t ) {
252 m_cache.replace( t ); 252 m_cache.replace( t );
253 return m_backEnd->replace( t ); 253 return m_backEnd->replace( t );
254} 254}
255template <class T> 255template <class T>
256void OPimAccessTemplate<T>::invalidateCache() { 256void OPimAccessTemplate<T>::invalidateCache() {
257 m_cache.invalidate(); 257 m_cache.invalidate();
258} 258}
259template <class T> 259template <class T>
260typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { 260typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() {
261 return m_backEnd; 261 return m_backEnd;
262} 262}
263template <class T> 263template <class T>
264bool OPimAccessTemplate<T>::wasChangedExternally()const { 264bool OPimAccessTemplate<T>::wasChangedExternally()const {
265 return false; 265 return false;
266} 266}
267template <class T> 267template <class T>
268void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { 268void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) {
269 m_backEnd = end; 269 m_backEnd = end;
270 if (m_backEnd ) 270 if (m_backEnd )
271 m_backEnd->setFrontend( this ); 271 m_backEnd->setFrontend( this );
272} 272}
273template <class T> 273template <class T>
274void OPimAccessTemplate<T>::cache( const T& t ) const{ 274void OPimAccessTemplate<T>::cache( const T& t ) const{
275 /* hacky we need to work around the const*/ 275 /* hacky we need to work around the const*/
276 ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); 276 ((OPimAccessTemplate<T>*)this)->m_cache.add( t );
277} 277}
278template <class T> 278template <class T>
279void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { 279void OPimAccessTemplate<T>::setSaneCacheSize( int size ) {
280 m_cache.setSize( size ); 280 m_cache.setSize( size );
281} 281}
282template <class T> 282template <class T>
283void OPimAccessTemplate<T>::setReadAhead( uint count ) { 283void OPimAccessTemplate<T>::setReadAhead( uint count ) {
284 m_backEnd->setReadAhead( count ); 284 m_backEnd->setReadAhead( count );
285} 285}
286#endif 286#endif