summaryrefslogtreecommitdiff
authoreilers <eilers>2003-01-02 14:27:12 (UTC)
committer eilers <eilers>2003-01-02 14:27:12 (UTC)
commit8a9fc13259d7c2797068752687a011f57f613251 (patch) (unidiff)
tree26019057f2974c71881d9d7759732326cd0ede25
parent12e9ed4ac80ac7fa042059b48d7447db0e59a86c (diff)
downloadopie-8a9fc13259d7c2797068752687a011f57f613251.zip
opie-8a9fc13259d7c2797068752687a011f57f613251.tar.gz
opie-8a9fc13259d7c2797068752687a011f57f613251.tar.bz2
Improved query by example: Search by date is possible.. First step
for a today plugin for birthdays..
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/pim/ocontactaccess.h10
-rw-r--r--libopie/pim/ocontactaccessbackend_xml.h137
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_xml.h137
-rw-r--r--libopie2/opiepim/core/ocontactaccess.h10
4 files changed, 226 insertions, 68 deletions
diff --git a/libopie/pim/ocontactaccess.h b/libopie/pim/ocontactaccess.h
index 961968f..32b2dcb 100644
--- a/libopie/pim/ocontactaccess.h
+++ b/libopie/pim/ocontactaccess.h
@@ -1,150 +1,158 @@
1/* 1/*
2 * Class to manage the Contacts. 2 * Class to manage the Contacts.
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 * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) 5 * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org)
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; 10 * License as published by the Free Software Foundation;
11 * either version 2 of the License, or (at your option) any later 11 * either version 2 of the License, or (at your option) any later
12 * version. 12 * version.
13 * ===================================================================== 13 * =====================================================================
14 * ToDo: Define enum for query settings 14 * ToDo: Define enum for query settings
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.6 2003/01/02 14:27:12 eilers
21 * Improved query by example: Search by date is possible.. First step
22 * for a today plugin for birthdays..
23 *
20 * Revision 1.5 2002/11/13 14:14:51 eilers 24 * Revision 1.5 2002/11/13 14:14:51 eilers
21 * Added sorted for Contacts.. 25 * Added sorted for Contacts..
22 * 26 *
23 * Revision 1.4 2002/11/01 15:10:42 eilers 27 * Revision 1.4 2002/11/01 15:10:42 eilers
24 * Added regExp-search in database for all fields in a contact. 28 * Added regExp-search in database for all fields in a contact.
25 * 29 *
26 * Revision 1.3 2002/10/16 10:52:40 eilers 30 * Revision 1.3 2002/10/16 10:52:40 eilers
27 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 31 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
28 * 32 *
29 * Revision 1.2 2002/10/14 16:21:54 eilers 33 * Revision 1.2 2002/10/14 16:21:54 eilers
30 * Some minor interface updates 34 * Some minor interface updates
31 * 35 *
32 * Revision 1.1 2002/09/27 17:11:44 eilers 36 * Revision 1.1 2002/09/27 17:11:44 eilers
33 * Added API for accessing the Contact-Database ! It is compiling, but 37 * Added API for accessing the Contact-Database ! It is compiling, but
34 * please do not expect that anything is working ! 38 * please do not expect that anything is working !
35 * I will debug that stuff in the next time .. 39 * I will debug that stuff in the next time ..
36 * Please read README_COMPILE for compiling ! 40 * Please read README_COMPILE for compiling !
37 * 41 *
38 * ===================================================================== 42 * =====================================================================
39 */ 43 */
40#ifndef _OCONTACTACCESS_H 44#ifndef _OCONTACTACCESS_H
41#define _OCONTACTACCESS_H 45#define _OCONTACTACCESS_H
42 46
43#include <qobject.h> 47#include <qobject.h>
44 48
45#include <qpe/qcopenvelope_qws.h> 49#include <qpe/qcopenvelope_qws.h>
46 50
47#include <qvaluelist.h> 51#include <qvaluelist.h>
48#include <qfileinfo.h> 52#include <qfileinfo.h>
49 53
50#include "ocontact.h" 54#include "ocontact.h"
51#include "ocontactaccessbackend.h" 55#include "ocontactaccessbackend.h"
52#include "opimaccesstemplate.h" 56#include "opimaccesstemplate.h"
53 57
54/** Class to access the contacts database. 58/** Class to access the contacts database.
55 * This is just a frontend for the real database handling which is 59 * This is just a frontend for the real database handling which is
56 * done by the backend. 60 * done by the backend.
57 * @see OPimAccessTemplate 61 * @see OPimAccessTemplate
58 */ 62 */
59class OContactAccess: public QObject, public OPimAccessTemplate<OContact> 63class OContactAccess: public QObject, public OPimAccessTemplate<OContact>
60{ 64{
61 Q_OBJECT 65 Q_OBJECT
62 66
63 public: 67 public:
64 /** Create Database with contacts (addressbook). 68 /** Create Database with contacts (addressbook).
65 * @param appname Name of application which wants access to the database 69 * @param appname Name of application which wants access to the database
66 * (i.e. "todolist") 70 * (i.e. "todolist")
67 * @param filename The name of the database file. If not set, the default one 71 * @param filename The name of the database file. If not set, the default one
68 * is used. 72 * is used.
69 * @param backend Pointer to an alternative Backend. If not set, we will use 73 * @param backend Pointer to an alternative Backend. If not set, we will use
70 * the default backend. 74 * the default backend.
71 * @param handlesync If <b>true</b> the database stores the current state 75 * @param handlesync If <b>true</b> the database stores the current state
72 * automatically if it receives the signals <i>flush()</i> and <i>reload()</i> 76 * automatically if it receives the signals <i>flush()</i> and <i>reload()</i>
73 * which are used before and after synchronisation. If the application wants 77 * which are used before and after synchronisation. If the application wants
74 * to react itself, it should be disabled by setting it to <b>false</b> 78 * to react itself, it should be disabled by setting it to <b>false</b>
75 * @see OContactAccessBackend 79 * @see OContactAccessBackend
76 */ 80 */
77 OContactAccess (const QString appname, const QString filename = 0l, 81 OContactAccess (const QString appname, const QString filename = 0l,
78 OContactAccessBackend* backend = 0l, bool handlesync = true); 82 OContactAccessBackend* backend = 0l, bool handlesync = true);
79 ~OContactAccess (); 83 ~OContactAccess ();
80 84
81 /** Constants for query. 85 /** Constants for query.
82 * Use this constants to set the query parameters. 86 * Use this constants to set the query parameters.
83 * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes ! 87 * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes !
84 * @see queryByExample() 88 * @see queryByExample()
85 */ 89 */
86 enum QuerySettings { 90 enum QuerySettings {
87 WildCards = 0x0001, 91 WildCards = 0x0001,
88 IgnoreCase = 0x0002, 92 IgnoreCase = 0x0002,
89 RegExp = 0x0004, 93 RegExp = 0x0004,
90 ExactMatch = 0x0008, 94 ExactMatch = 0x0008,
91 MatchOne = 0x0010 // Only one Entry must match 95 MatchOne = 0x0010, // Only one Entry must match
96 DateDiff = 0x0020, // Find all entries from today until given date
97 DateYear = 0x0040, // The year matches
98 DateMonth = 0x0080, // The month matches
99 DateDay = 0x0100, // The day matches
92 }; 100 };
93 101
94 102
95 ORecordList<OContact> matchRegexp( const QRegExp &r )const; 103 ORecordList<OContact> matchRegexp( const QRegExp &r )const;
96 104
97 /** Return all Contacts in a sorted manner. 105 /** Return all Contacts in a sorted manner.
98 * @param ascending true: Sorted in acending order. 106 * @param ascending true: Sorted in acending order.
99 * @param sortOrder Currently not implemented. Just defined to stay compatible to otodoaccess 107 * @param sortOrder Currently not implemented. Just defined to stay compatible to otodoaccess
100 * @param sortFilter Currently not implemented. Just defined to stay compatible to otodoaccess 108 * @param sortFilter Currently not implemented. Just defined to stay compatible to otodoaccess
101 * @param cat Currently not implemented. Just defined to stay compatible to otodoaccess 109 * @param cat Currently not implemented. Just defined to stay compatible to otodoaccess
102 */ 110 */
103 List sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const; 111 List sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const;
104 112
105 /** Return all possible settings. 113 /** Return all possible settings.
106 * @return All settings provided by the current backend 114 * @return All settings provided by the current backend
107 * (i.e.: query_WildCards & query_IgnoreCase) 115 * (i.e.: query_WildCards & query_IgnoreCase)
108 */ 116 */
109 const uint querySettings(); 117 const uint querySettings();
110 118
111 /** Check whether settings are correct. 119 /** Check whether settings are correct.
112 * @return <i>true</i> if the given settings are correct and possible. 120 * @return <i>true</i> if the given settings are correct and possible.
113 */ 121 */
114 bool hasQuerySettings ( int querySettings ) const; 122 bool hasQuerySettings ( int querySettings ) const;
115 123
116 /** 124 /**
117 * if the resource was changed externally. 125 * if the resource was changed externally.
118 * You should use the signal instead of polling possible changes ! 126 * You should use the signal instead of polling possible changes !
119 */ 127 */
120 bool wasChangedExternally()const; 128 bool wasChangedExternally()const;
121 129
122 130
123 /** Save contacts database. 131 /** Save contacts database.
124 * Save is more a "commit". After calling this function, all changes are public available. 132 * Save is more a "commit". After calling this function, all changes are public available.
125 * @return true if successful 133 * @return true if successful
126 */ 134 */
127 bool save(); 135 bool save();
128 136
129 signals: 137 signals:
130 /* Signal is emitted if the database was changed. Therefore 138 /* Signal is emitted if the database was changed. Therefore
131 * we may need to reload to stay consistent. 139 * we may need to reload to stay consistent.
132 * @param which Pointer to the database who created this event. This pointer 140 * @param which Pointer to the database who created this event. This pointer
133 * is useful if an application has to handle multiple databases at the same time. 141 * is useful if an application has to handle multiple databases at the same time.
134 * @see reload() 142 * @see reload()
135 */ 143 */
136 void signalChanged ( const OContactAccess *which ); 144 void signalChanged ( const OContactAccess *which );
137 145
138 146
139 private: 147 private:
140 // class OContactAccessPrivate; 148 // class OContactAccessPrivate;
141 // OContactAccessPrivate* d; 149 // OContactAccessPrivate* d;
142 OContactAccessBackend *m_backEnd; 150 OContactAccessBackend *m_backEnd;
143 bool m_loading:1; 151 bool m_loading:1;
144 152
145 private slots: 153 private slots:
146 void copMessage( const QCString &msg, const QByteArray &data ); 154 void copMessage( const QCString &msg, const QByteArray &data );
147 155
148 156
149}; 157};
150#endif 158#endif
diff --git a/libopie/pim/ocontactaccessbackend_xml.h b/libopie/pim/ocontactaccessbackend_xml.h
index c765ff5..c6e6cbc 100644
--- a/libopie/pim/ocontactaccessbackend_xml.h
+++ b/libopie/pim/ocontactaccessbackend_xml.h
@@ -1,646 +1,717 @@
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.10 2003/01/02 14:27:12 eilers
21 * Improved query by example: Search by date is possible.. First step
22 * for a today plugin for birthdays..
23 *
20 * Revision 1.9 2002/12/08 12:48:57 eilers 24 * Revision 1.9 2002/12/08 12:48:57 eilers
21 * Moved journal-enum from ocontact into i the xml-backend.. 25 * Moved journal-enum from ocontact into i the xml-backend..
22 * 26 *
23 * Revision 1.8 2002/11/14 17:04:24 eilers 27 * Revision 1.8 2002/11/14 17:04:24 eilers
24 * Sorting will now work if fullname is identical on some entries 28 * Sorting will now work if fullname is identical on some entries
25 * 29 *
26 * Revision 1.7 2002/11/13 15:02:46 eilers 30 * Revision 1.7 2002/11/13 15:02:46 eilers
27 * Small Bug in sorted fixed 31 * Small Bug in sorted fixed
28 * 32 *
29 * Revision 1.6 2002/11/13 14:14:51 eilers 33 * Revision 1.6 2002/11/13 14:14:51 eilers
30 * Added sorted for Contacts.. 34 * Added sorted for Contacts..
31 * 35 *
32 * Revision 1.5 2002/11/01 15:10:42 eilers 36 * Revision 1.5 2002/11/01 15:10:42 eilers
33 * Added regExp-search in database for all fields in a contact. 37 * Added regExp-search in database for all fields in a contact.
34 * 38 *
35 * Revision 1.4 2002/10/16 10:52:40 eilers 39 * Revision 1.4 2002/10/16 10:52:40 eilers
36 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 40 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
37 * 41 *
38 * Revision 1.3 2002/10/14 16:21:54 eilers 42 * Revision 1.3 2002/10/14 16:21:54 eilers
39 * Some minor interface updates 43 * Some minor interface updates
40 * 44 *
41 * Revision 1.2 2002/10/07 17:34:24 eilers 45 * Revision 1.2 2002/10/07 17:34:24 eilers
42 * added OBackendFactory for advanced backend access 46 * added OBackendFactory for advanced backend access
43 * 47 *
44 * Revision 1.1 2002/09/27 17:11:44 eilers 48 * Revision 1.1 2002/09/27 17:11:44 eilers
45 * Added API for accessing the Contact-Database ! It is compiling, but 49 * Added API for accessing the Contact-Database ! It is compiling, but
46 * please do not expect that anything is working ! 50 * please do not expect that anything is working !
47 * I will debug that stuff in the next time .. 51 * I will debug that stuff in the next time ..
48 * Please read README_COMPILE for compiling ! 52 * Please read README_COMPILE for compiling !
49 * 53 *
50 * 54 *
51 */ 55 */
52 56
53#ifndef _OContactAccessBackend_XML_ 57#ifndef _OContactAccessBackend_XML_
54#define _OContactAccessBackend_XML_ 58#define _OContactAccessBackend_XML_
55 59
56#include <qasciidict.h> 60#include <qasciidict.h>
57#include <qdatetime.h> 61#include <qdatetime.h>
58#include <qfile.h> 62#include <qfile.h>
59#include <qfileinfo.h> 63#include <qfileinfo.h>
60#include <qregexp.h> 64#include <qregexp.h>
61#include <qarray.h> 65#include <qarray.h>
62#include <qmap.h> 66#include <qmap.h>
67#include <qdatetime.h>
63 68
64#include <qpe/global.h> 69#include <qpe/global.h>
65 70
66#include <opie/xmltree.h> 71#include <opie/xmltree.h>
67#include "ocontactaccessbackend.h" 72#include "ocontactaccessbackend.h"
68#include "ocontactaccess.h" 73#include "ocontactaccess.h"
69 74
70#include <stdlib.h> 75#include <stdlib.h>
71#include <errno.h> 76#include <errno.h>
72 77
73using namespace Opie; 78using namespace Opie;
74 79
75/* the default xml implementation */ 80/* the default xml implementation */
76class OContactAccessBackend_XML : public OContactAccessBackend { 81class OContactAccessBackend_XML : public OContactAccessBackend {
77 public: 82 public:
78 OContactAccessBackend_XML ( QString appname, QString filename = 0l ): 83 OContactAccessBackend_XML ( QString appname, QString filename = 0l ):
79 m_changed( false ) 84 m_changed( false )
80 { 85 {
81 m_appName = appname; 86 m_appName = appname;
82 87
83 /* Set journalfile name ... */ 88 /* Set journalfile name ... */
84 m_journalName = getenv("HOME"); 89 m_journalName = getenv("HOME");
85 m_journalName +="/.abjournal" + appname; 90 m_journalName +="/.abjournal" + appname;
86 91
87 /* Expecting to access the default filename if nothing else is set */ 92 /* Expecting to access the default filename if nothing else is set */
88 if ( filename.isEmpty() ){ 93 if ( filename.isEmpty() ){
89 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); 94 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
90 } else 95 } else
91 m_fileName = filename; 96 m_fileName = filename;
92 97
93 /* Load Database now */ 98 /* Load Database now */
94 load (); 99 load ();
95 } 100 }
96 101
97 bool save() { 102 bool save() {
98 103
99 if ( !m_changed ) 104 if ( !m_changed )
100 return true; 105 return true;
101 106
102 QString strNewFile = m_fileName + ".new"; 107 QString strNewFile = m_fileName + ".new";
103 QFile f( strNewFile ); 108 QFile f( strNewFile );
104 if ( !f.open( IO_WriteOnly|IO_Raw ) ) 109 if ( !f.open( IO_WriteOnly|IO_Raw ) )
105 return false; 110 return false;
106 111
107 int total_written; 112 int total_written;
108 QString out; 113 QString out;
109 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" 114 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
110 " <Groups>\n" 115 " <Groups>\n"
111 " </Groups>\n" 116 " </Groups>\n"
112 " <Contacts>\n"; 117 " <Contacts>\n";
113 //QValueList<Contact>::iterator it; 118 //QValueList<Contact>::iterator it;
114 QValueListConstIterator<OContact> it; 119 QValueListConstIterator<OContact> it;
115 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { 120 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) {
116 out += "<Contact "; 121 out += "<Contact ";
117 (*it).save( out ); 122 (*it).save( out );
118 out += "/>\n"; 123 out += "/>\n";
119 QCString cstr = out.utf8(); 124 QCString cstr = out.utf8();
120 total_written = f.writeBlock( cstr.data(), cstr.length() ); 125 total_written = f.writeBlock( cstr.data(), cstr.length() );
121 if ( total_written != int(cstr.length()) ) { 126 if ( total_written != int(cstr.length()) ) {
122 f.close(); 127 f.close();
123 QFile::remove( strNewFile ); 128 QFile::remove( strNewFile );
124 return false; 129 return false;
125 } 130 }
126 out = ""; 131 out = "";
127 } 132 }
128 out += " </Contacts>\n</AddressBook>\n"; 133 out += " </Contacts>\n</AddressBook>\n";
129 134
130 QCString cstr = out.utf8(); 135 QCString cstr = out.utf8();
131 total_written = f.writeBlock( cstr.data(), cstr.length() ); 136 total_written = f.writeBlock( cstr.data(), cstr.length() );
132 if ( total_written != int( cstr.length() ) ) { 137 if ( total_written != int( cstr.length() ) ) {
133 f.close(); 138 f.close();
134 QFile::remove( strNewFile ); 139 QFile::remove( strNewFile );
135 return false; 140 return false;
136 } 141 }
137 f.close(); 142 f.close();
138 143
139 // move the file over, I'm just going to use the system call 144 // move the file over, I'm just going to use the system call
140 // because, I don't feel like using QDir. 145 // because, I don't feel like using QDir.
141 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { 146 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
142 qWarning( "problem renaming file %s to %s, errno: %d", 147 qWarning( "problem renaming file %s to %s, errno: %d",
143 strNewFile.latin1(), m_journalName.latin1(), errno ); 148 strNewFile.latin1(), m_journalName.latin1(), errno );
144 // remove the tmp file... 149 // remove the tmp file...
145 QFile::remove( strNewFile ); 150 QFile::remove( strNewFile );
146 } 151 }
147 152
148 /* The journalfile should be removed now... */ 153 /* The journalfile should be removed now... */
149 removeJournal(); 154 removeJournal();
150 155
151 m_changed = false; 156 m_changed = false;
152 return true; 157 return true;
153 } 158 }
154 159
155 bool load () { 160 bool load () {
156 m_contactList.clear(); 161 m_contactList.clear();
157 162
158 /* Load XML-File and journal if it exists */ 163 /* Load XML-File and journal if it exists */
159 if ( !load ( m_fileName, false ) ) 164 if ( !load ( m_fileName, false ) )
160 return false; 165 return false;
161 /* The returncode of the journalfile is ignored due to the 166 /* The returncode of the journalfile is ignored due to the
162 * fact that it does not exist when this class is instantiated ! 167 * fact that it does not exist when this class is instantiated !
163 * But there may such a file exist, if the application crashed. 168 * But there may such a file exist, if the application crashed.
164 * Therefore we try to load it to get the changes before the # 169 * Therefore we try to load it to get the changes before the #
165 * crash happened... 170 * crash happened...
166 */ 171 */
167 load (m_journalName, true); 172 load (m_journalName, true);
168 173
169 return true; 174 return true;
170 } 175 }
171 176
172 void clear () { 177 void clear () {
173 m_contactList.clear(); 178 m_contactList.clear();
174 m_changed = false; 179 m_changed = false;
175 180
176 } 181 }
177 182
178 bool wasChangedExternally() 183 bool wasChangedExternally()
179 { 184 {
180 QFileInfo fi( m_fileName ); 185 QFileInfo fi( m_fileName );
181 186
182 QDateTime lastmod = fi.lastModified (); 187 QDateTime lastmod = fi.lastModified ();
183 188
184 return (lastmod != m_readtime); 189 return (lastmod != m_readtime);
185 } 190 }
186 191
187 QArray<int> allRecords() const { 192 QArray<int> allRecords() const {
188 QArray<int> uid_list( m_contactList.count() ); 193 QArray<int> uid_list( m_contactList.count() );
189 194
190 uint counter = 0; 195 uint counter = 0;
191 QValueListConstIterator<OContact> it; 196 QValueListConstIterator<OContact> it;
192 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 197 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
193 uid_list[counter++] = (*it).uid(); 198 uid_list[counter++] = (*it).uid();
194 } 199 }
195 200
196 return ( uid_list ); 201 return ( uid_list );
197 } 202 }
198 203
199 OContact find ( int uid ) const 204 OContact find ( int uid ) const
200 { 205 {
201 bool found = false; 206 bool found = false;
202 OContact foundContact; //Create empty contact 207 OContact foundContact; //Create empty contact
203 208
204 QValueListConstIterator<OContact> it; 209 QValueListConstIterator<OContact> it;
205 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 210 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
206 if ((*it).uid() == uid){ 211 if ((*it).uid() == uid){
207 found = true; 212 found = true;
208 break; 213 break;
209 } 214 }
210 } 215 }
211 if ( found ){ 216 if ( found ){
212 foundContact = *it; 217 foundContact = *it;
213 } 218 }
214 219
215 return ( foundContact ); 220 return ( foundContact );
216 } 221 }
217 222
218 QArray<int> queryByExample ( const OContact &query, int settings ){ 223 QArray<int> queryByExample ( const OContact &query, int settings ){
219 224
220 QArray<int> m_currentQuery( m_contactList.count() ); 225 QArray<int> m_currentQuery( m_contactList.count() );
221 QValueListConstIterator<OContact> it; 226 QValueListConstIterator<OContact> it;
222 uint arraycounter = 0; 227 uint arraycounter = 0;
223 228
224 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 229 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
225 /* Search all fields and compare them with query object. Store them into list 230 /* Search all fields and compare them with query object. Store them into list
226 * if all fields matches. 231 * if all fields matches.
227 */ 232 */
233 QDate* queryDate = 0l;
234 QDate* checkDate = 0l;
228 bool allcorrect = true; 235 bool allcorrect = true;
229 for ( int i = 0; i < Qtopia::rid; i++ ) { 236 for ( int i = 0; i < Qtopia::Groups; i++ ) {
230 /* Just compare fields which are not empty in the query object */ 237 // Birthday and anniversary are special nonstring fields and should
231 if ( !query.field(i).isEmpty() ){ 238 // be handled especially
232 switch ( settings & ~OContactAccess::IgnoreCase ){ 239 switch ( i ){
233 case OContactAccess::RegExp:{ 240 case Qtopia::Birthday:
234 QRegExp expr ( query.field(i), 241 queryDate = new QDate( query.birthday() );
235 !(settings & OContactAccess::IgnoreCase), 242 checkDate = new QDate( (*it).birthday() );
236 false ); 243 case Qtopia::Anniversary:
237 if ( expr.find ( (*it).field(i), 0 ) == -1 ) 244 if ( queryDate == 0l ){
238 allcorrect = false; 245 queryDate = new QDate( query.anniversary() );
239 } 246 checkDate = new QDate( (*it).anniversary() );
240 break;
241 case OContactAccess::WildCards:{
242 QRegExp expr ( query.field(i),
243 !(settings & OContactAccess::IgnoreCase),
244 true );
245 if ( expr.find ( (*it).field(i), 0 ) == -1 )
246 allcorrect = false;
247 } 247 }
248 break; 248
249 case OContactAccess::ExactMatch:{ 249 if ( queryDate->isValid() ){
250 if (settings & OContactAccess::IgnoreCase){ 250 if ( settings & OContactAccess::DateYear ){
251 if ( query.field(i).upper() != 251 if ( queryDate->year() != checkDate->year() )
252 (*it).field(i).upper() )
253 allcorrect = false; 252 allcorrect = false;
254 }else{ 253 }
255 if ( query.field(i) != (*it).field(i) ) 254 if ( settings & OContactAccess::DateMonth ){
255 if ( queryDate->month() != checkDate->month() )
256 allcorrect = false; 256 allcorrect = false;
257 }
258 if ( settings & OContactAccess::DateDay ){
259 if ( queryDate->day() != checkDate->day() )
260 allcorrect = false;
261 }
262 if ( settings & OContactAccess::DateDiff ) {
263 QDate current = QDate::currentDate();
264 if ( current.daysTo( *queryDate ) > 0 ){
265 if ( !( ( *checkDate >= current ) &&
266 ( *checkDate <= *queryDate ) ) )
267 allcorrect = false;
268 }
257 } 269 }
258 } 270 }
259 break; 271
272 delete queryDate;
273 queryDate = 0l;
274 delete checkDate;
275 checkDate = 0l;
276 break;
277 default:
278 /* Just compare fields which are not empty in the query object */
279 if ( !query.field(i).isEmpty() ){
280 switch ( settings & ~( OContactAccess::IgnoreCase
281 | OContactAccess::DateDiff
282 | OContactAccess::DateYear
283 | OContactAccess::DateMonth
284 | OContactAccess::DateDay
285 | OContactAccess::MatchOne
286 ) ){
287
288 case OContactAccess::RegExp:{
289 QRegExp expr ( query.field(i),
290 !(settings & OContactAccess::IgnoreCase),
291 false );
292 if ( expr.find ( (*it).field(i), 0 ) == -1 )
293 allcorrect = false;
294 }
295 break;
296 case OContactAccess::WildCards:{
297 QRegExp expr ( query.field(i),
298 !(settings & OContactAccess::IgnoreCase),
299 true );
300 if ( expr.find ( (*it).field(i), 0 ) == -1 )
301 allcorrect = false;
302 }
303 break;
304 case OContactAccess::ExactMatch:{
305 if (settings & OContactAccess::IgnoreCase){
306 if ( query.field(i).upper() !=
307 (*it).field(i).upper() )
308 allcorrect = false;
309 }else{
310 if ( query.field(i) != (*it).field(i) )
311 allcorrect = false;
312 }
313 }
314 break;
315 }
260 } 316 }
261 } 317 }
262 } 318 }
263 if ( allcorrect ){ 319 if ( allcorrect ){
264 m_currentQuery[arraycounter++] = (*it).uid(); 320 m_currentQuery[arraycounter++] = (*it).uid();
265 } 321 }
266 } 322 }
267 323
268 // Shrink to fit.. 324 // Shrink to fit..
269 m_currentQuery.resize(arraycounter); 325 m_currentQuery.resize(arraycounter);
270 326
271 return m_currentQuery; 327 return m_currentQuery;
272 } 328 }
273 329
274 QArray<int> matchRegexp( const QRegExp &r ) const{ 330 QArray<int> matchRegexp( const QRegExp &r ) const{
275 QArray<int> m_currentQuery( m_contactList.count() ); 331 QArray<int> m_currentQuery( m_contactList.count() );
276 QValueListConstIterator<OContact> it; 332 QValueListConstIterator<OContact> it;
277 uint arraycounter = 0; 333 uint arraycounter = 0;
278 334
279 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 335 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
280 if ( (*it).match( r ) ){ 336 if ( (*it).match( r ) ){
281 m_currentQuery[arraycounter++] = (*it).uid(); 337 m_currentQuery[arraycounter++] = (*it).uid();
282 } 338 }
283 339
284 } 340 }
285 // Shrink to fit.. 341 // Shrink to fit..
286 m_currentQuery.resize(arraycounter); 342 m_currentQuery.resize(arraycounter);
287 343
288 return m_currentQuery; 344 return m_currentQuery;
289 } 345 }
290 346
291 const uint querySettings() 347 const uint querySettings()
292 { 348 {
293 return ( OContactAccess::WildCards 349 return ( OContactAccess::WildCards
294 & OContactAccess::IgnoreCase 350 | OContactAccess::IgnoreCase
295 & OContactAccess::RegExp 351 | OContactAccess::RegExp
296 & OContactAccess::ExactMatch ); 352 | OContactAccess::ExactMatch
353 | OContactAccess::DateDiff
354 | OContactAccess::DateYear
355 | OContactAccess::DateMonth
356 | OContactAccess::DateDay
357 );
297 } 358 }
298 359
299 bool hasQuerySettings (uint querySettings) const 360 bool hasQuerySettings (uint querySettings) const
300 { 361 {
301 /* OContactAccess::IgnoreCase may be added with one 362 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
302 * of the other settings, but never used alone. 363 * may be added with any of the other settings. IgnoreCase should never used alone.
303 * The other settings are just valid alone... 364 * Wildcards, RegExp, ExactMatch should never used at the same time...
304 */ 365 */
305 switch ( querySettings & ~OContactAccess::IgnoreCase ){ 366
367 if ( querySettings == OContactAccess::IgnoreCase )
368 return false;
369
370 switch ( querySettings & ~( OContactAccess::IgnoreCase
371 | OContactAccess::DateDiff
372 | OContactAccess::DateYear
373 | OContactAccess::DateMonth
374 | OContactAccess::DateDay
375 )
376 ){
306 case OContactAccess::RegExp: 377 case OContactAccess::RegExp:
307 return ( true ); 378 return ( true );
308 case OContactAccess::WildCards: 379 case OContactAccess::WildCards:
309 return ( true ); 380 return ( true );
310 case OContactAccess::ExactMatch: 381 case OContactAccess::ExactMatch:
311 return ( true ); 382 return ( true );
312 default: 383 default:
313 return ( false ); 384 return ( false );
314 } 385 }
315 } 386 }
316 387
317 // Currently only asc implemented.. 388 // Currently only asc implemented..
318 QArray<int> sorted( bool asc, int , int , int ) 389 QArray<int> sorted( bool asc, int , int , int )
319 { 390 {
320 QMap<QString, int> nameToUid; 391 QMap<QString, int> nameToUid;
321 QStringList names; 392 QStringList names;
322 QArray<int> m_currentQuery( m_contactList.count() ); 393 QArray<int> m_currentQuery( m_contactList.count() );
323 394
324 // First fill map and StringList with all Names 395 // First fill map and StringList with all Names
325 // Afterwards sort namelist and use map to fill array to return.. 396 // Afterwards sort namelist and use map to fill array to return..
326 QValueListConstIterator<OContact> it; 397 QValueListConstIterator<OContact> it;
327 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 398 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
328 names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); 399 names.append( (*it).fileAs() + QString::number( (*it).uid() ) );
329 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); 400 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() );
330 } 401 }
331 names.sort(); 402 names.sort();
332 403
333 int i = 0; 404 int i = 0;
334 if ( asc ){ 405 if ( asc ){
335 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) 406 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
336 m_currentQuery[i++] = nameToUid[ (*it) ]; 407 m_currentQuery[i++] = nameToUid[ (*it) ];
337 }else{ 408 }else{
338 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) 409 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
339 m_currentQuery[i++] = nameToUid[ (*it) ]; 410 m_currentQuery[i++] = nameToUid[ (*it) ];
340 } 411 }
341 412
342 return m_currentQuery; 413 return m_currentQuery;
343 414
344 } 415 }
345 bool add ( const OContact &newcontact ) 416 bool add ( const OContact &newcontact )
346 { 417 {
347 //qWarning("odefaultbackend: ACTION::ADD"); 418 //qWarning("odefaultbackend: ACTION::ADD");
348 updateJournal (newcontact, ACTION_ADD); 419 updateJournal (newcontact, ACTION_ADD);
349 addContact_p( newcontact ); 420 addContact_p( newcontact );
350 421
351 m_changed = true; 422 m_changed = true;
352 423
353 return true; 424 return true;
354 } 425 }
355 426
356 bool replace ( const OContact &contact ) 427 bool replace ( const OContact &contact )
357 { 428 {
358 m_changed = true; 429 m_changed = true;
359 430
360 bool found = false; 431 bool found = false;
361 432
362 QValueListIterator<OContact> it; 433 QValueListIterator<OContact> it;
363 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 434 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
364 if ( (*it).uid() == contact.uid() ){ 435 if ( (*it).uid() == contact.uid() ){
365 found = true; 436 found = true;
366 break; 437 break;
367 } 438 }
368 } 439 }
369 if (found) { 440 if (found) {
370 updateJournal (contact, ACTION_REPLACE); 441 updateJournal (contact, ACTION_REPLACE);
371 m_contactList.remove (it); 442 m_contactList.remove (it);
372 m_contactList.append (contact); 443 m_contactList.append (contact);
373 return true; 444 return true;
374 } else 445 } else
375 return false; 446 return false;
376 } 447 }
377 448
378 bool remove ( int uid ) 449 bool remove ( int uid )
379 { 450 {
380 m_changed = true; 451 m_changed = true;
381 452
382 bool found = false; 453 bool found = false;
383 QValueListIterator<OContact> it; 454 QValueListIterator<OContact> it;
384 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 455 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
385 if ((*it).uid() == uid){ 456 if ((*it).uid() == uid){
386 found = true; 457 found = true;
387 break; 458 break;
388 } 459 }
389 } 460 }
390 if (found) { 461 if (found) {
391 updateJournal ( *it, ACTION_REMOVE); 462 updateJournal ( *it, ACTION_REMOVE);
392 m_contactList.remove (it); 463 m_contactList.remove (it);
393 return true; 464 return true;
394 } else 465 } else
395 return false; 466 return false;
396 } 467 }
397 468
398 bool reload(){ 469 bool reload(){
399 /* Reload is the same as load in this implementation */ 470 /* Reload is the same as load in this implementation */
400 return ( load() ); 471 return ( load() );
401 } 472 }
402 473
403 private: 474 private:
404 475
405 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; 476 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE };
406 477
407 void addContact_p( const OContact &newcontact ){ 478 void addContact_p( const OContact &newcontact ){
408 m_contactList.append (newcontact); 479 m_contactList.append (newcontact);
409 } 480 }
410 481
411 /* This function loads the xml-database and the journalfile */ 482 /* This function loads the xml-database and the journalfile */
412 bool load( const QString filename, bool isJournal ) { 483 bool load( const QString filename, bool isJournal ) {
413 484
414 /* We use the time of the last read to check if the file was 485 /* We use the time of the last read to check if the file was
415 * changed externally. 486 * changed externally.
416 */ 487 */
417 if ( !isJournal ){ 488 if ( !isJournal ){
418 QFileInfo fi( filename ); 489 QFileInfo fi( filename );
419 m_readtime = fi.lastModified (); 490 m_readtime = fi.lastModified ();
420 } 491 }
421 492
422 const int JOURNALACTION = Qtopia::Notes + 1; 493 const int JOURNALACTION = Qtopia::Notes + 1;
423 const int JOURNALROW = JOURNALACTION + 1; 494 const int JOURNALROW = JOURNALACTION + 1;
424 495
425 bool foundAction = false; 496 bool foundAction = false;
426 journal_action action = ACTION_ADD; 497 journal_action action = ACTION_ADD;
427 int journalKey = 0; 498 int journalKey = 0;
428 QMap<int, QString> contactMap; 499 QMap<int, QString> contactMap;
429 QMap<QString, QString> customMap; 500 QMap<QString, QString> customMap;
430 QMap<QString, QString>::Iterator customIt; 501 QMap<QString, QString>::Iterator customIt;
431 QAsciiDict<int> dict( 47 ); 502 QAsciiDict<int> dict( 47 );
432 503
433 dict.setAutoDelete( TRUE ); 504 dict.setAutoDelete( TRUE );
434 dict.insert( "Uid", new int(Qtopia::AddressUid) ); 505 dict.insert( "Uid", new int(Qtopia::AddressUid) );
435 dict.insert( "Title", new int(Qtopia::Title) ); 506 dict.insert( "Title", new int(Qtopia::Title) );
436 dict.insert( "FirstName", new int(Qtopia::FirstName) ); 507 dict.insert( "FirstName", new int(Qtopia::FirstName) );
437 dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); 508 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
438 dict.insert( "LastName", new int(Qtopia::LastName) ); 509 dict.insert( "LastName", new int(Qtopia::LastName) );
439 dict.insert( "Suffix", new int(Qtopia::Suffix) ); 510 dict.insert( "Suffix", new int(Qtopia::Suffix) );
440 dict.insert( "FileAs", new int(Qtopia::FileAs) ); 511 dict.insert( "FileAs", new int(Qtopia::FileAs) );
441 dict.insert( "Categories", new int(Qtopia::AddressCategory) ); 512 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
442 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); 513 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
443 dict.insert( "Emails", new int(Qtopia::Emails) ); 514 dict.insert( "Emails", new int(Qtopia::Emails) );
444 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); 515 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
445 dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); 516 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
446 dict.insert( "HomeState", new int(Qtopia::HomeState) ); 517 dict.insert( "HomeState", new int(Qtopia::HomeState) );
447 dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); 518 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
448 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); 519 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
449 dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); 520 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
450 dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); 521 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
451 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); 522 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
452 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); 523 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
453 dict.insert( "Company", new int(Qtopia::Company) ); 524 dict.insert( "Company", new int(Qtopia::Company) );
454 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); 525 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
455 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); 526 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
456 dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); 527 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
457 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); 528 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
458 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); 529 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
459 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); 530 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
460 dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); 531 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
461 dict.insert( "Department", new int(Qtopia::Department) ); 532 dict.insert( "Department", new int(Qtopia::Department) );
462 dict.insert( "Office", new int(Qtopia::Office) ); 533 dict.insert( "Office", new int(Qtopia::Office) );
463 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); 534 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
464 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); 535 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
465 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); 536 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
466 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); 537 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
467 dict.insert( "Profession", new int(Qtopia::Profession) ); 538 dict.insert( "Profession", new int(Qtopia::Profession) );
468 dict.insert( "Assistant", new int(Qtopia::Assistant) ); 539 dict.insert( "Assistant", new int(Qtopia::Assistant) );
469 dict.insert( "Manager", new int(Qtopia::Manager) ); 540 dict.insert( "Manager", new int(Qtopia::Manager) );
470 dict.insert( "Spouse", new int(Qtopia::Spouse) ); 541 dict.insert( "Spouse", new int(Qtopia::Spouse) );
471 dict.insert( "Children", new int(Qtopia::Children) ); 542 dict.insert( "Children", new int(Qtopia::Children) );
472 dict.insert( "Gender", new int(Qtopia::Gender) ); 543 dict.insert( "Gender", new int(Qtopia::Gender) );
473 dict.insert( "Birthday", new int(Qtopia::Birthday) ); 544 dict.insert( "Birthday", new int(Qtopia::Birthday) );
474 dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); 545 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
475 dict.insert( "Nickname", new int(Qtopia::Nickname) ); 546 dict.insert( "Nickname", new int(Qtopia::Nickname) );
476 dict.insert( "Notes", new int(Qtopia::Notes) ); 547 dict.insert( "Notes", new int(Qtopia::Notes) );
477 dict.insert( "action", new int(JOURNALACTION) ); 548 dict.insert( "action", new int(JOURNALACTION) );
478 dict.insert( "actionrow", new int(JOURNALROW) ); 549 dict.insert( "actionrow", new int(JOURNALROW) );
479 550
480 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); 551 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
481 552
482 XMLElement *root = XMLElement::load( filename ); 553 XMLElement *root = XMLElement::load( filename );
483 if(root != 0l ){ // start parsing 554 if(root != 0l ){ // start parsing
484 /* Parse all XML-Elements and put the data into the 555 /* Parse all XML-Elements and put the data into the
485 * Contact-Class 556 * Contact-Class
486 */ 557 */
487 XMLElement *element = root->firstChild(); 558 XMLElement *element = root->firstChild();
488 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); 559 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
489 element = element->firstChild(); 560 element = element->firstChild();
490 561
491 /* Search Tag "Contacts" which is the parent of all Contacts */ 562 /* Search Tag "Contacts" which is the parent of all Contacts */
492 while( element && !isJournal ){ 563 while( element && !isJournal ){
493 if( element->tagName() != QString::fromLatin1("Contacts") ){ 564 if( element->tagName() != QString::fromLatin1("Contacts") ){
494 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", 565 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
495 // element->tagName().latin1()); 566 // element->tagName().latin1());
496 element = element->nextChild(); 567 element = element->nextChild();
497 } else { 568 } else {
498 element = element->firstChild(); 569 element = element->firstChild();
499 break; 570 break;
500 } 571 }
501 } 572 }
502 /* Parse all Contacts and ignore unknown tags */ 573 /* Parse all Contacts and ignore unknown tags */
503 while( element ){ 574 while( element ){
504 if( element->tagName() != QString::fromLatin1("Contact") ){ 575 if( element->tagName() != QString::fromLatin1("Contact") ){
505 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", 576 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
506 // element->tagName().latin1()); 577 // element->tagName().latin1());
507 element = element->nextChild(); 578 element = element->nextChild();
508 continue; 579 continue;
509 } 580 }
510 /* Found alement with tagname "contact", now parse and store all 581 /* Found alement with tagname "contact", now parse and store all
511 * attributes contained 582 * attributes contained
512 */ 583 */
513 //qWarning("OContactDefBack::load element tagName() : %s", 584 //qWarning("OContactDefBack::load element tagName() : %s",
514 // element->tagName().latin1() ); 585 // element->tagName().latin1() );
515 QString dummy; 586 QString dummy;
516 foundAction = false; 587 foundAction = false;
517 588
518 XMLElement::AttributeMap aMap = element->attributes(); 589 XMLElement::AttributeMap aMap = element->attributes();
519 XMLElement::AttributeMap::Iterator it; 590 XMLElement::AttributeMap::Iterator it;
520 contactMap.clear(); 591 contactMap.clear();
521 customMap.clear(); 592 customMap.clear();
522 for( it = aMap.begin(); it != aMap.end(); ++it ){ 593 for( it = aMap.begin(); it != aMap.end(); ++it ){
523 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); 594 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
524 595
525 int *find = dict[ it.key() ]; 596 int *find = dict[ it.key() ];
526 /* Unknown attributes will be stored as "Custom" elements */ 597 /* Unknown attributes will be stored as "Custom" elements */
527 if ( !find ) { 598 if ( !find ) {
528 qWarning("Attribute %s not known.", it.key().latin1()); 599 qWarning("Attribute %s not known.", it.key().latin1());
529 //contact.setCustomField(it.key(), it.data()); 600 //contact.setCustomField(it.key(), it.data());
530 customMap.insert( it.key(), it.data() ); 601 customMap.insert( it.key(), it.data() );
531 continue; 602 continue;
532 } 603 }
533 604
534 /* Check if special conversion is needed and add attribute 605 /* Check if special conversion is needed and add attribute
535 * into Contact class 606 * into Contact class
536 */ 607 */
537 switch( *find ) { 608 switch( *find ) {
538 /* 609 /*
539 case Qtopia::AddressUid: 610 case Qtopia::AddressUid:
540 contact.setUid( it.data().toInt() ); 611 contact.setUid( it.data().toInt() );
541 break; 612 break;
542 case Qtopia::AddressCategory: 613 case Qtopia::AddressCategory:
543 contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); 614 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
544 break; 615 break;
545 */ 616 */
546 case JOURNALACTION: 617 case JOURNALACTION:
547 action = journal_action(it.data().toInt()); 618 action = journal_action(it.data().toInt());
548 foundAction = true; 619 foundAction = true;
549 qWarning ("ODefBack(journal)::ACTION found: %d", action); 620 qWarning ("ODefBack(journal)::ACTION found: %d", action);
550 break; 621 break;
551 case JOURNALROW: 622 case JOURNALROW:
552 journalKey = it.data().toInt(); 623 journalKey = it.data().toInt();
553 break; 624 break;
554 default: // no conversion needed add them to the map 625 default: // no conversion needed add them to the map
555 contactMap.insert( *find, it.data() ); 626 contactMap.insert( *find, it.data() );
556 break; 627 break;
557 } 628 }
558 } 629 }
559 /* now generate the Contact contact */ 630 /* now generate the Contact contact */
560 OContact contact( contactMap ); 631 OContact contact( contactMap );
561 632
562 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { 633 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
563 contact.setCustomField( customIt.key(), customIt.data() ); 634 contact.setCustomField( customIt.key(), customIt.data() );
564 } 635 }
565 636
566 if (foundAction){ 637 if (foundAction){
567 foundAction = false; 638 foundAction = false;
568 switch ( action ) { 639 switch ( action ) {
569 case ACTION_ADD: 640 case ACTION_ADD:
570 addContact_p (contact); 641 addContact_p (contact);
571 break; 642 break;
572 case ACTION_REMOVE: 643 case ACTION_REMOVE:
573 if ( !remove (contact.uid()) ) 644 if ( !remove (contact.uid()) )
574 qWarning ("ODefBack(journal)::Unable to remove uid: %d", 645 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
575 contact.uid() ); 646 contact.uid() );
576 break; 647 break;
577 case ACTION_REPLACE: 648 case ACTION_REPLACE:
578 if ( !replace ( contact ) ) 649 if ( !replace ( contact ) )
579 qWarning ("ODefBack(journal)::Unable to replace uid: %d", 650 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
580 contact.uid() ); 651 contact.uid() );
581 break; 652 break;
582 default: 653 default:
583 qWarning ("Unknown action: ignored !"); 654 qWarning ("Unknown action: ignored !");
584 break; 655 break;
585 } 656 }
586 }else{ 657 }else{
587 /* Add contact to list */ 658 /* Add contact to list */
588 addContact_p (contact); 659 addContact_p (contact);
589 } 660 }
590 661
591 /* Move to next element */ 662 /* Move to next element */
592 element = element->nextChild(); 663 element = element->nextChild();
593 } 664 }
594 }else { 665 }else {
595 qWarning("ODefBack::could not load"); 666 qWarning("ODefBack::could not load");
596 } 667 }
597 delete root; 668 delete root;
598 qWarning("returning from loading" ); 669 qWarning("returning from loading" );
599 return true; 670 return true;
600 } 671 }
601 672
602 673
603 void updateJournal( const OContact& cnt, 674 void updateJournal( const OContact& cnt,
604 journal_action action ) { 675 journal_action action ) {
605 QFile f( m_journalName ); 676 QFile f( m_journalName );
606 bool created = !f.exists(); 677 bool created = !f.exists();
607 if ( !f.open(IO_WriteOnly|IO_Append) ) 678 if ( !f.open(IO_WriteOnly|IO_Append) )
608 return; 679 return;
609 680
610 QString buf; 681 QString buf;
611 QCString str; 682 QCString str;
612 683
613 // if the file was created, we have to set the Tag "<CONTACTS>" to 684 // if the file was created, we have to set the Tag "<CONTACTS>" to
614 // get a XML-File which is readable by our parser. 685 // get a XML-File which is readable by our parser.
615 // This is just a cheat, but better than rewrite the parser. 686 // This is just a cheat, but better than rewrite the parser.
616 if ( created ){ 687 if ( created ){
617 buf = "<Contacts>"; 688 buf = "<Contacts>";
618 QCString cstr = buf.utf8(); 689 QCString cstr = buf.utf8();
619 f.writeBlock( cstr.data(), cstr.length() ); 690 f.writeBlock( cstr.data(), cstr.length() );
620 } 691 }
621 692
622 buf = "<Contact "; 693 buf = "<Contact ";
623 cnt.save( buf ); 694 cnt.save( buf );
624 buf += " action=\"" + QString::number( (int)action ) + "\" "; 695 buf += " action=\"" + QString::number( (int)action ) + "\" ";
625 buf += "/>\n"; 696 buf += "/>\n";
626 QCString cstr = buf.utf8(); 697 QCString cstr = buf.utf8();
627 f.writeBlock( cstr.data(), cstr.length() ); 698 f.writeBlock( cstr.data(), cstr.length() );
628 } 699 }
629 700
630 void removeJournal() 701 void removeJournal()
631 { 702 {
632 QFile f ( m_journalName ); 703 QFile f ( m_journalName );
633 if ( f.exists() ) 704 if ( f.exists() )
634 f.remove(); 705 f.remove();
635 } 706 }
636 707
637 protected: 708 protected:
638 bool m_changed; 709 bool m_changed;
639 QString m_journalName; 710 QString m_journalName;
640 QString m_fileName; 711 QString m_fileName;
641 QString m_appName; 712 QString m_appName;
642 QValueList<OContact> m_contactList; 713 QValueList<OContact> m_contactList;
643 QDateTime m_readtime; 714 QDateTime m_readtime;
644}; 715};
645 716
646#endif 717#endif
diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
index c765ff5..c6e6cbc 100644
--- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h
@@ -1,646 +1,717 @@
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.10 2003/01/02 14:27:12 eilers
21 * Improved query by example: Search by date is possible.. First step
22 * for a today plugin for birthdays..
23 *
20 * Revision 1.9 2002/12/08 12:48:57 eilers 24 * Revision 1.9 2002/12/08 12:48:57 eilers
21 * Moved journal-enum from ocontact into i the xml-backend.. 25 * Moved journal-enum from ocontact into i the xml-backend..
22 * 26 *
23 * Revision 1.8 2002/11/14 17:04:24 eilers 27 * Revision 1.8 2002/11/14 17:04:24 eilers
24 * Sorting will now work if fullname is identical on some entries 28 * Sorting will now work if fullname is identical on some entries
25 * 29 *
26 * Revision 1.7 2002/11/13 15:02:46 eilers 30 * Revision 1.7 2002/11/13 15:02:46 eilers
27 * Small Bug in sorted fixed 31 * Small Bug in sorted fixed
28 * 32 *
29 * Revision 1.6 2002/11/13 14:14:51 eilers 33 * Revision 1.6 2002/11/13 14:14:51 eilers
30 * Added sorted for Contacts.. 34 * Added sorted for Contacts..
31 * 35 *
32 * Revision 1.5 2002/11/01 15:10:42 eilers 36 * Revision 1.5 2002/11/01 15:10:42 eilers
33 * Added regExp-search in database for all fields in a contact. 37 * Added regExp-search in database for all fields in a contact.
34 * 38 *
35 * Revision 1.4 2002/10/16 10:52:40 eilers 39 * Revision 1.4 2002/10/16 10:52:40 eilers
36 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 40 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
37 * 41 *
38 * Revision 1.3 2002/10/14 16:21:54 eilers 42 * Revision 1.3 2002/10/14 16:21:54 eilers
39 * Some minor interface updates 43 * Some minor interface updates
40 * 44 *
41 * Revision 1.2 2002/10/07 17:34:24 eilers 45 * Revision 1.2 2002/10/07 17:34:24 eilers
42 * added OBackendFactory for advanced backend access 46 * added OBackendFactory for advanced backend access
43 * 47 *
44 * Revision 1.1 2002/09/27 17:11:44 eilers 48 * Revision 1.1 2002/09/27 17:11:44 eilers
45 * Added API for accessing the Contact-Database ! It is compiling, but 49 * Added API for accessing the Contact-Database ! It is compiling, but
46 * please do not expect that anything is working ! 50 * please do not expect that anything is working !
47 * I will debug that stuff in the next time .. 51 * I will debug that stuff in the next time ..
48 * Please read README_COMPILE for compiling ! 52 * Please read README_COMPILE for compiling !
49 * 53 *
50 * 54 *
51 */ 55 */
52 56
53#ifndef _OContactAccessBackend_XML_ 57#ifndef _OContactAccessBackend_XML_
54#define _OContactAccessBackend_XML_ 58#define _OContactAccessBackend_XML_
55 59
56#include <qasciidict.h> 60#include <qasciidict.h>
57#include <qdatetime.h> 61#include <qdatetime.h>
58#include <qfile.h> 62#include <qfile.h>
59#include <qfileinfo.h> 63#include <qfileinfo.h>
60#include <qregexp.h> 64#include <qregexp.h>
61#include <qarray.h> 65#include <qarray.h>
62#include <qmap.h> 66#include <qmap.h>
67#include <qdatetime.h>
63 68
64#include <qpe/global.h> 69#include <qpe/global.h>
65 70
66#include <opie/xmltree.h> 71#include <opie/xmltree.h>
67#include "ocontactaccessbackend.h" 72#include "ocontactaccessbackend.h"
68#include "ocontactaccess.h" 73#include "ocontactaccess.h"
69 74
70#include <stdlib.h> 75#include <stdlib.h>
71#include <errno.h> 76#include <errno.h>
72 77
73using namespace Opie; 78using namespace Opie;
74 79
75/* the default xml implementation */ 80/* the default xml implementation */
76class OContactAccessBackend_XML : public OContactAccessBackend { 81class OContactAccessBackend_XML : public OContactAccessBackend {
77 public: 82 public:
78 OContactAccessBackend_XML ( QString appname, QString filename = 0l ): 83 OContactAccessBackend_XML ( QString appname, QString filename = 0l ):
79 m_changed( false ) 84 m_changed( false )
80 { 85 {
81 m_appName = appname; 86 m_appName = appname;
82 87
83 /* Set journalfile name ... */ 88 /* Set journalfile name ... */
84 m_journalName = getenv("HOME"); 89 m_journalName = getenv("HOME");
85 m_journalName +="/.abjournal" + appname; 90 m_journalName +="/.abjournal" + appname;
86 91
87 /* Expecting to access the default filename if nothing else is set */ 92 /* Expecting to access the default filename if nothing else is set */
88 if ( filename.isEmpty() ){ 93 if ( filename.isEmpty() ){
89 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); 94 m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
90 } else 95 } else
91 m_fileName = filename; 96 m_fileName = filename;
92 97
93 /* Load Database now */ 98 /* Load Database now */
94 load (); 99 load ();
95 } 100 }
96 101
97 bool save() { 102 bool save() {
98 103
99 if ( !m_changed ) 104 if ( !m_changed )
100 return true; 105 return true;
101 106
102 QString strNewFile = m_fileName + ".new"; 107 QString strNewFile = m_fileName + ".new";
103 QFile f( strNewFile ); 108 QFile f( strNewFile );
104 if ( !f.open( IO_WriteOnly|IO_Raw ) ) 109 if ( !f.open( IO_WriteOnly|IO_Raw ) )
105 return false; 110 return false;
106 111
107 int total_written; 112 int total_written;
108 QString out; 113 QString out;
109 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" 114 out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
110 " <Groups>\n" 115 " <Groups>\n"
111 " </Groups>\n" 116 " </Groups>\n"
112 " <Contacts>\n"; 117 " <Contacts>\n";
113 //QValueList<Contact>::iterator it; 118 //QValueList<Contact>::iterator it;
114 QValueListConstIterator<OContact> it; 119 QValueListConstIterator<OContact> it;
115 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { 120 for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) {
116 out += "<Contact "; 121 out += "<Contact ";
117 (*it).save( out ); 122 (*it).save( out );
118 out += "/>\n"; 123 out += "/>\n";
119 QCString cstr = out.utf8(); 124 QCString cstr = out.utf8();
120 total_written = f.writeBlock( cstr.data(), cstr.length() ); 125 total_written = f.writeBlock( cstr.data(), cstr.length() );
121 if ( total_written != int(cstr.length()) ) { 126 if ( total_written != int(cstr.length()) ) {
122 f.close(); 127 f.close();
123 QFile::remove( strNewFile ); 128 QFile::remove( strNewFile );
124 return false; 129 return false;
125 } 130 }
126 out = ""; 131 out = "";
127 } 132 }
128 out += " </Contacts>\n</AddressBook>\n"; 133 out += " </Contacts>\n</AddressBook>\n";
129 134
130 QCString cstr = out.utf8(); 135 QCString cstr = out.utf8();
131 total_written = f.writeBlock( cstr.data(), cstr.length() ); 136 total_written = f.writeBlock( cstr.data(), cstr.length() );
132 if ( total_written != int( cstr.length() ) ) { 137 if ( total_written != int( cstr.length() ) ) {
133 f.close(); 138 f.close();
134 QFile::remove( strNewFile ); 139 QFile::remove( strNewFile );
135 return false; 140 return false;
136 } 141 }
137 f.close(); 142 f.close();
138 143
139 // move the file over, I'm just going to use the system call 144 // move the file over, I'm just going to use the system call
140 // because, I don't feel like using QDir. 145 // because, I don't feel like using QDir.
141 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { 146 if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
142 qWarning( "problem renaming file %s to %s, errno: %d", 147 qWarning( "problem renaming file %s to %s, errno: %d",
143 strNewFile.latin1(), m_journalName.latin1(), errno ); 148 strNewFile.latin1(), m_journalName.latin1(), errno );
144 // remove the tmp file... 149 // remove the tmp file...
145 QFile::remove( strNewFile ); 150 QFile::remove( strNewFile );
146 } 151 }
147 152
148 /* The journalfile should be removed now... */ 153 /* The journalfile should be removed now... */
149 removeJournal(); 154 removeJournal();
150 155
151 m_changed = false; 156 m_changed = false;
152 return true; 157 return true;
153 } 158 }
154 159
155 bool load () { 160 bool load () {
156 m_contactList.clear(); 161 m_contactList.clear();
157 162
158 /* Load XML-File and journal if it exists */ 163 /* Load XML-File and journal if it exists */
159 if ( !load ( m_fileName, false ) ) 164 if ( !load ( m_fileName, false ) )
160 return false; 165 return false;
161 /* The returncode of the journalfile is ignored due to the 166 /* The returncode of the journalfile is ignored due to the
162 * fact that it does not exist when this class is instantiated ! 167 * fact that it does not exist when this class is instantiated !
163 * But there may such a file exist, if the application crashed. 168 * But there may such a file exist, if the application crashed.
164 * Therefore we try to load it to get the changes before the # 169 * Therefore we try to load it to get the changes before the #
165 * crash happened... 170 * crash happened...
166 */ 171 */
167 load (m_journalName, true); 172 load (m_journalName, true);
168 173
169 return true; 174 return true;
170 } 175 }
171 176
172 void clear () { 177 void clear () {
173 m_contactList.clear(); 178 m_contactList.clear();
174 m_changed = false; 179 m_changed = false;
175 180
176 } 181 }
177 182
178 bool wasChangedExternally() 183 bool wasChangedExternally()
179 { 184 {
180 QFileInfo fi( m_fileName ); 185 QFileInfo fi( m_fileName );
181 186
182 QDateTime lastmod = fi.lastModified (); 187 QDateTime lastmod = fi.lastModified ();
183 188
184 return (lastmod != m_readtime); 189 return (lastmod != m_readtime);
185 } 190 }
186 191
187 QArray<int> allRecords() const { 192 QArray<int> allRecords() const {
188 QArray<int> uid_list( m_contactList.count() ); 193 QArray<int> uid_list( m_contactList.count() );
189 194
190 uint counter = 0; 195 uint counter = 0;
191 QValueListConstIterator<OContact> it; 196 QValueListConstIterator<OContact> it;
192 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 197 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
193 uid_list[counter++] = (*it).uid(); 198 uid_list[counter++] = (*it).uid();
194 } 199 }
195 200
196 return ( uid_list ); 201 return ( uid_list );
197 } 202 }
198 203
199 OContact find ( int uid ) const 204 OContact find ( int uid ) const
200 { 205 {
201 bool found = false; 206 bool found = false;
202 OContact foundContact; //Create empty contact 207 OContact foundContact; //Create empty contact
203 208
204 QValueListConstIterator<OContact> it; 209 QValueListConstIterator<OContact> it;
205 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 210 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
206 if ((*it).uid() == uid){ 211 if ((*it).uid() == uid){
207 found = true; 212 found = true;
208 break; 213 break;
209 } 214 }
210 } 215 }
211 if ( found ){ 216 if ( found ){
212 foundContact = *it; 217 foundContact = *it;
213 } 218 }
214 219
215 return ( foundContact ); 220 return ( foundContact );
216 } 221 }
217 222
218 QArray<int> queryByExample ( const OContact &query, int settings ){ 223 QArray<int> queryByExample ( const OContact &query, int settings ){
219 224
220 QArray<int> m_currentQuery( m_contactList.count() ); 225 QArray<int> m_currentQuery( m_contactList.count() );
221 QValueListConstIterator<OContact> it; 226 QValueListConstIterator<OContact> it;
222 uint arraycounter = 0; 227 uint arraycounter = 0;
223 228
224 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 229 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
225 /* Search all fields and compare them with query object. Store them into list 230 /* Search all fields and compare them with query object. Store them into list
226 * if all fields matches. 231 * if all fields matches.
227 */ 232 */
233 QDate* queryDate = 0l;
234 QDate* checkDate = 0l;
228 bool allcorrect = true; 235 bool allcorrect = true;
229 for ( int i = 0; i < Qtopia::rid; i++ ) { 236 for ( int i = 0; i < Qtopia::Groups; i++ ) {
230 /* Just compare fields which are not empty in the query object */ 237 // Birthday and anniversary are special nonstring fields and should
231 if ( !query.field(i).isEmpty() ){ 238 // be handled especially
232 switch ( settings & ~OContactAccess::IgnoreCase ){ 239 switch ( i ){
233 case OContactAccess::RegExp:{ 240 case Qtopia::Birthday:
234 QRegExp expr ( query.field(i), 241 queryDate = new QDate( query.birthday() );
235 !(settings & OContactAccess::IgnoreCase), 242 checkDate = new QDate( (*it).birthday() );
236 false ); 243 case Qtopia::Anniversary:
237 if ( expr.find ( (*it).field(i), 0 ) == -1 ) 244 if ( queryDate == 0l ){
238 allcorrect = false; 245 queryDate = new QDate( query.anniversary() );
239 } 246 checkDate = new QDate( (*it).anniversary() );
240 break;
241 case OContactAccess::WildCards:{
242 QRegExp expr ( query.field(i),
243 !(settings & OContactAccess::IgnoreCase),
244 true );
245 if ( expr.find ( (*it).field(i), 0 ) == -1 )
246 allcorrect = false;
247 } 247 }
248 break; 248
249 case OContactAccess::ExactMatch:{ 249 if ( queryDate->isValid() ){
250 if (settings & OContactAccess::IgnoreCase){ 250 if ( settings & OContactAccess::DateYear ){
251 if ( query.field(i).upper() != 251 if ( queryDate->year() != checkDate->year() )
252 (*it).field(i).upper() )
253 allcorrect = false; 252 allcorrect = false;
254 }else{ 253 }
255 if ( query.field(i) != (*it).field(i) ) 254 if ( settings & OContactAccess::DateMonth ){
255 if ( queryDate->month() != checkDate->month() )
256 allcorrect = false; 256 allcorrect = false;
257 }
258 if ( settings & OContactAccess::DateDay ){
259 if ( queryDate->day() != checkDate->day() )
260 allcorrect = false;
261 }
262 if ( settings & OContactAccess::DateDiff ) {
263 QDate current = QDate::currentDate();
264 if ( current.daysTo( *queryDate ) > 0 ){
265 if ( !( ( *checkDate >= current ) &&
266 ( *checkDate <= *queryDate ) ) )
267 allcorrect = false;
268 }
257 } 269 }
258 } 270 }
259 break; 271
272 delete queryDate;
273 queryDate = 0l;
274 delete checkDate;
275 checkDate = 0l;
276 break;
277 default:
278 /* Just compare fields which are not empty in the query object */
279 if ( !query.field(i).isEmpty() ){
280 switch ( settings & ~( OContactAccess::IgnoreCase
281 | OContactAccess::DateDiff
282 | OContactAccess::DateYear
283 | OContactAccess::DateMonth
284 | OContactAccess::DateDay
285 | OContactAccess::MatchOne
286 ) ){
287
288 case OContactAccess::RegExp:{
289 QRegExp expr ( query.field(i),
290 !(settings & OContactAccess::IgnoreCase),
291 false );
292 if ( expr.find ( (*it).field(i), 0 ) == -1 )
293 allcorrect = false;
294 }
295 break;
296 case OContactAccess::WildCards:{
297 QRegExp expr ( query.field(i),
298 !(settings & OContactAccess::IgnoreCase),
299 true );
300 if ( expr.find ( (*it).field(i), 0 ) == -1 )
301 allcorrect = false;
302 }
303 break;
304 case OContactAccess::ExactMatch:{
305 if (settings & OContactAccess::IgnoreCase){
306 if ( query.field(i).upper() !=
307 (*it).field(i).upper() )
308 allcorrect = false;
309 }else{
310 if ( query.field(i) != (*it).field(i) )
311 allcorrect = false;
312 }
313 }
314 break;
315 }
260 } 316 }
261 } 317 }
262 } 318 }
263 if ( allcorrect ){ 319 if ( allcorrect ){
264 m_currentQuery[arraycounter++] = (*it).uid(); 320 m_currentQuery[arraycounter++] = (*it).uid();
265 } 321 }
266 } 322 }
267 323
268 // Shrink to fit.. 324 // Shrink to fit..
269 m_currentQuery.resize(arraycounter); 325 m_currentQuery.resize(arraycounter);
270 326
271 return m_currentQuery; 327 return m_currentQuery;
272 } 328 }
273 329
274 QArray<int> matchRegexp( const QRegExp &r ) const{ 330 QArray<int> matchRegexp( const QRegExp &r ) const{
275 QArray<int> m_currentQuery( m_contactList.count() ); 331 QArray<int> m_currentQuery( m_contactList.count() );
276 QValueListConstIterator<OContact> it; 332 QValueListConstIterator<OContact> it;
277 uint arraycounter = 0; 333 uint arraycounter = 0;
278 334
279 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 335 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
280 if ( (*it).match( r ) ){ 336 if ( (*it).match( r ) ){
281 m_currentQuery[arraycounter++] = (*it).uid(); 337 m_currentQuery[arraycounter++] = (*it).uid();
282 } 338 }
283 339
284 } 340 }
285 // Shrink to fit.. 341 // Shrink to fit..
286 m_currentQuery.resize(arraycounter); 342 m_currentQuery.resize(arraycounter);
287 343
288 return m_currentQuery; 344 return m_currentQuery;
289 } 345 }
290 346
291 const uint querySettings() 347 const uint querySettings()
292 { 348 {
293 return ( OContactAccess::WildCards 349 return ( OContactAccess::WildCards
294 & OContactAccess::IgnoreCase 350 | OContactAccess::IgnoreCase
295 & OContactAccess::RegExp 351 | OContactAccess::RegExp
296 & OContactAccess::ExactMatch ); 352 | OContactAccess::ExactMatch
353 | OContactAccess::DateDiff
354 | OContactAccess::DateYear
355 | OContactAccess::DateMonth
356 | OContactAccess::DateDay
357 );
297 } 358 }
298 359
299 bool hasQuerySettings (uint querySettings) const 360 bool hasQuerySettings (uint querySettings) const
300 { 361 {
301 /* OContactAccess::IgnoreCase may be added with one 362 /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
302 * of the other settings, but never used alone. 363 * may be added with any of the other settings. IgnoreCase should never used alone.
303 * The other settings are just valid alone... 364 * Wildcards, RegExp, ExactMatch should never used at the same time...
304 */ 365 */
305 switch ( querySettings & ~OContactAccess::IgnoreCase ){ 366
367 if ( querySettings == OContactAccess::IgnoreCase )
368 return false;
369
370 switch ( querySettings & ~( OContactAccess::IgnoreCase
371 | OContactAccess::DateDiff
372 | OContactAccess::DateYear
373 | OContactAccess::DateMonth
374 | OContactAccess::DateDay
375 )
376 ){
306 case OContactAccess::RegExp: 377 case OContactAccess::RegExp:
307 return ( true ); 378 return ( true );
308 case OContactAccess::WildCards: 379 case OContactAccess::WildCards:
309 return ( true ); 380 return ( true );
310 case OContactAccess::ExactMatch: 381 case OContactAccess::ExactMatch:
311 return ( true ); 382 return ( true );
312 default: 383 default:
313 return ( false ); 384 return ( false );
314 } 385 }
315 } 386 }
316 387
317 // Currently only asc implemented.. 388 // Currently only asc implemented..
318 QArray<int> sorted( bool asc, int , int , int ) 389 QArray<int> sorted( bool asc, int , int , int )
319 { 390 {
320 QMap<QString, int> nameToUid; 391 QMap<QString, int> nameToUid;
321 QStringList names; 392 QStringList names;
322 QArray<int> m_currentQuery( m_contactList.count() ); 393 QArray<int> m_currentQuery( m_contactList.count() );
323 394
324 // First fill map and StringList with all Names 395 // First fill map and StringList with all Names
325 // Afterwards sort namelist and use map to fill array to return.. 396 // Afterwards sort namelist and use map to fill array to return..
326 QValueListConstIterator<OContact> it; 397 QValueListConstIterator<OContact> it;
327 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 398 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
328 names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); 399 names.append( (*it).fileAs() + QString::number( (*it).uid() ) );
329 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); 400 nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() );
330 } 401 }
331 names.sort(); 402 names.sort();
332 403
333 int i = 0; 404 int i = 0;
334 if ( asc ){ 405 if ( asc ){
335 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) 406 for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
336 m_currentQuery[i++] = nameToUid[ (*it) ]; 407 m_currentQuery[i++] = nameToUid[ (*it) ];
337 }else{ 408 }else{
338 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) 409 for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
339 m_currentQuery[i++] = nameToUid[ (*it) ]; 410 m_currentQuery[i++] = nameToUid[ (*it) ];
340 } 411 }
341 412
342 return m_currentQuery; 413 return m_currentQuery;
343 414
344 } 415 }
345 bool add ( const OContact &newcontact ) 416 bool add ( const OContact &newcontact )
346 { 417 {
347 //qWarning("odefaultbackend: ACTION::ADD"); 418 //qWarning("odefaultbackend: ACTION::ADD");
348 updateJournal (newcontact, ACTION_ADD); 419 updateJournal (newcontact, ACTION_ADD);
349 addContact_p( newcontact ); 420 addContact_p( newcontact );
350 421
351 m_changed = true; 422 m_changed = true;
352 423
353 return true; 424 return true;
354 } 425 }
355 426
356 bool replace ( const OContact &contact ) 427 bool replace ( const OContact &contact )
357 { 428 {
358 m_changed = true; 429 m_changed = true;
359 430
360 bool found = false; 431 bool found = false;
361 432
362 QValueListIterator<OContact> it; 433 QValueListIterator<OContact> it;
363 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 434 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
364 if ( (*it).uid() == contact.uid() ){ 435 if ( (*it).uid() == contact.uid() ){
365 found = true; 436 found = true;
366 break; 437 break;
367 } 438 }
368 } 439 }
369 if (found) { 440 if (found) {
370 updateJournal (contact, ACTION_REPLACE); 441 updateJournal (contact, ACTION_REPLACE);
371 m_contactList.remove (it); 442 m_contactList.remove (it);
372 m_contactList.append (contact); 443 m_contactList.append (contact);
373 return true; 444 return true;
374 } else 445 } else
375 return false; 446 return false;
376 } 447 }
377 448
378 bool remove ( int uid ) 449 bool remove ( int uid )
379 { 450 {
380 m_changed = true; 451 m_changed = true;
381 452
382 bool found = false; 453 bool found = false;
383 QValueListIterator<OContact> it; 454 QValueListIterator<OContact> it;
384 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ 455 for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){
385 if ((*it).uid() == uid){ 456 if ((*it).uid() == uid){
386 found = true; 457 found = true;
387 break; 458 break;
388 } 459 }
389 } 460 }
390 if (found) { 461 if (found) {
391 updateJournal ( *it, ACTION_REMOVE); 462 updateJournal ( *it, ACTION_REMOVE);
392 m_contactList.remove (it); 463 m_contactList.remove (it);
393 return true; 464 return true;
394 } else 465 } else
395 return false; 466 return false;
396 } 467 }
397 468
398 bool reload(){ 469 bool reload(){
399 /* Reload is the same as load in this implementation */ 470 /* Reload is the same as load in this implementation */
400 return ( load() ); 471 return ( load() );
401 } 472 }
402 473
403 private: 474 private:
404 475
405 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; 476 enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE };
406 477
407 void addContact_p( const OContact &newcontact ){ 478 void addContact_p( const OContact &newcontact ){
408 m_contactList.append (newcontact); 479 m_contactList.append (newcontact);
409 } 480 }
410 481
411 /* This function loads the xml-database and the journalfile */ 482 /* This function loads the xml-database and the journalfile */
412 bool load( const QString filename, bool isJournal ) { 483 bool load( const QString filename, bool isJournal ) {
413 484
414 /* We use the time of the last read to check if the file was 485 /* We use the time of the last read to check if the file was
415 * changed externally. 486 * changed externally.
416 */ 487 */
417 if ( !isJournal ){ 488 if ( !isJournal ){
418 QFileInfo fi( filename ); 489 QFileInfo fi( filename );
419 m_readtime = fi.lastModified (); 490 m_readtime = fi.lastModified ();
420 } 491 }
421 492
422 const int JOURNALACTION = Qtopia::Notes + 1; 493 const int JOURNALACTION = Qtopia::Notes + 1;
423 const int JOURNALROW = JOURNALACTION + 1; 494 const int JOURNALROW = JOURNALACTION + 1;
424 495
425 bool foundAction = false; 496 bool foundAction = false;
426 journal_action action = ACTION_ADD; 497 journal_action action = ACTION_ADD;
427 int journalKey = 0; 498 int journalKey = 0;
428 QMap<int, QString> contactMap; 499 QMap<int, QString> contactMap;
429 QMap<QString, QString> customMap; 500 QMap<QString, QString> customMap;
430 QMap<QString, QString>::Iterator customIt; 501 QMap<QString, QString>::Iterator customIt;
431 QAsciiDict<int> dict( 47 ); 502 QAsciiDict<int> dict( 47 );
432 503
433 dict.setAutoDelete( TRUE ); 504 dict.setAutoDelete( TRUE );
434 dict.insert( "Uid", new int(Qtopia::AddressUid) ); 505 dict.insert( "Uid", new int(Qtopia::AddressUid) );
435 dict.insert( "Title", new int(Qtopia::Title) ); 506 dict.insert( "Title", new int(Qtopia::Title) );
436 dict.insert( "FirstName", new int(Qtopia::FirstName) ); 507 dict.insert( "FirstName", new int(Qtopia::FirstName) );
437 dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); 508 dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
438 dict.insert( "LastName", new int(Qtopia::LastName) ); 509 dict.insert( "LastName", new int(Qtopia::LastName) );
439 dict.insert( "Suffix", new int(Qtopia::Suffix) ); 510 dict.insert( "Suffix", new int(Qtopia::Suffix) );
440 dict.insert( "FileAs", new int(Qtopia::FileAs) ); 511 dict.insert( "FileAs", new int(Qtopia::FileAs) );
441 dict.insert( "Categories", new int(Qtopia::AddressCategory) ); 512 dict.insert( "Categories", new int(Qtopia::AddressCategory) );
442 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); 513 dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
443 dict.insert( "Emails", new int(Qtopia::Emails) ); 514 dict.insert( "Emails", new int(Qtopia::Emails) );
444 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); 515 dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
445 dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); 516 dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
446 dict.insert( "HomeState", new int(Qtopia::HomeState) ); 517 dict.insert( "HomeState", new int(Qtopia::HomeState) );
447 dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); 518 dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
448 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); 519 dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
449 dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); 520 dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
450 dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); 521 dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
451 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); 522 dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
452 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); 523 dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
453 dict.insert( "Company", new int(Qtopia::Company) ); 524 dict.insert( "Company", new int(Qtopia::Company) );
454 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); 525 dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
455 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); 526 dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
456 dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); 527 dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
457 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); 528 dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
458 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); 529 dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
459 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); 530 dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
460 dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); 531 dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
461 dict.insert( "Department", new int(Qtopia::Department) ); 532 dict.insert( "Department", new int(Qtopia::Department) );
462 dict.insert( "Office", new int(Qtopia::Office) ); 533 dict.insert( "Office", new int(Qtopia::Office) );
463 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); 534 dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
464 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); 535 dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
465 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); 536 dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
466 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); 537 dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
467 dict.insert( "Profession", new int(Qtopia::Profession) ); 538 dict.insert( "Profession", new int(Qtopia::Profession) );
468 dict.insert( "Assistant", new int(Qtopia::Assistant) ); 539 dict.insert( "Assistant", new int(Qtopia::Assistant) );
469 dict.insert( "Manager", new int(Qtopia::Manager) ); 540 dict.insert( "Manager", new int(Qtopia::Manager) );
470 dict.insert( "Spouse", new int(Qtopia::Spouse) ); 541 dict.insert( "Spouse", new int(Qtopia::Spouse) );
471 dict.insert( "Children", new int(Qtopia::Children) ); 542 dict.insert( "Children", new int(Qtopia::Children) );
472 dict.insert( "Gender", new int(Qtopia::Gender) ); 543 dict.insert( "Gender", new int(Qtopia::Gender) );
473 dict.insert( "Birthday", new int(Qtopia::Birthday) ); 544 dict.insert( "Birthday", new int(Qtopia::Birthday) );
474 dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); 545 dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
475 dict.insert( "Nickname", new int(Qtopia::Nickname) ); 546 dict.insert( "Nickname", new int(Qtopia::Nickname) );
476 dict.insert( "Notes", new int(Qtopia::Notes) ); 547 dict.insert( "Notes", new int(Qtopia::Notes) );
477 dict.insert( "action", new int(JOURNALACTION) ); 548 dict.insert( "action", new int(JOURNALACTION) );
478 dict.insert( "actionrow", new int(JOURNALROW) ); 549 dict.insert( "actionrow", new int(JOURNALROW) );
479 550
480 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); 551 //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
481 552
482 XMLElement *root = XMLElement::load( filename ); 553 XMLElement *root = XMLElement::load( filename );
483 if(root != 0l ){ // start parsing 554 if(root != 0l ){ // start parsing
484 /* Parse all XML-Elements and put the data into the 555 /* Parse all XML-Elements and put the data into the
485 * Contact-Class 556 * Contact-Class
486 */ 557 */
487 XMLElement *element = root->firstChild(); 558 XMLElement *element = root->firstChild();
488 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); 559 //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
489 element = element->firstChild(); 560 element = element->firstChild();
490 561
491 /* Search Tag "Contacts" which is the parent of all Contacts */ 562 /* Search Tag "Contacts" which is the parent of all Contacts */
492 while( element && !isJournal ){ 563 while( element && !isJournal ){
493 if( element->tagName() != QString::fromLatin1("Contacts") ){ 564 if( element->tagName() != QString::fromLatin1("Contacts") ){
494 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", 565 //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
495 // element->tagName().latin1()); 566 // element->tagName().latin1());
496 element = element->nextChild(); 567 element = element->nextChild();
497 } else { 568 } else {
498 element = element->firstChild(); 569 element = element->firstChild();
499 break; 570 break;
500 } 571 }
501 } 572 }
502 /* Parse all Contacts and ignore unknown tags */ 573 /* Parse all Contacts and ignore unknown tags */
503 while( element ){ 574 while( element ){
504 if( element->tagName() != QString::fromLatin1("Contact") ){ 575 if( element->tagName() != QString::fromLatin1("Contact") ){
505 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", 576 //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
506 // element->tagName().latin1()); 577 // element->tagName().latin1());
507 element = element->nextChild(); 578 element = element->nextChild();
508 continue; 579 continue;
509 } 580 }
510 /* Found alement with tagname "contact", now parse and store all 581 /* Found alement with tagname "contact", now parse and store all
511 * attributes contained 582 * attributes contained
512 */ 583 */
513 //qWarning("OContactDefBack::load element tagName() : %s", 584 //qWarning("OContactDefBack::load element tagName() : %s",
514 // element->tagName().latin1() ); 585 // element->tagName().latin1() );
515 QString dummy; 586 QString dummy;
516 foundAction = false; 587 foundAction = false;
517 588
518 XMLElement::AttributeMap aMap = element->attributes(); 589 XMLElement::AttributeMap aMap = element->attributes();
519 XMLElement::AttributeMap::Iterator it; 590 XMLElement::AttributeMap::Iterator it;
520 contactMap.clear(); 591 contactMap.clear();
521 customMap.clear(); 592 customMap.clear();
522 for( it = aMap.begin(); it != aMap.end(); ++it ){ 593 for( it = aMap.begin(); it != aMap.end(); ++it ){
523 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); 594 // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
524 595
525 int *find = dict[ it.key() ]; 596 int *find = dict[ it.key() ];
526 /* Unknown attributes will be stored as "Custom" elements */ 597 /* Unknown attributes will be stored as "Custom" elements */
527 if ( !find ) { 598 if ( !find ) {
528 qWarning("Attribute %s not known.", it.key().latin1()); 599 qWarning("Attribute %s not known.", it.key().latin1());
529 //contact.setCustomField(it.key(), it.data()); 600 //contact.setCustomField(it.key(), it.data());
530 customMap.insert( it.key(), it.data() ); 601 customMap.insert( it.key(), it.data() );
531 continue; 602 continue;
532 } 603 }
533 604
534 /* Check if special conversion is needed and add attribute 605 /* Check if special conversion is needed and add attribute
535 * into Contact class 606 * into Contact class
536 */ 607 */
537 switch( *find ) { 608 switch( *find ) {
538 /* 609 /*
539 case Qtopia::AddressUid: 610 case Qtopia::AddressUid:
540 contact.setUid( it.data().toInt() ); 611 contact.setUid( it.data().toInt() );
541 break; 612 break;
542 case Qtopia::AddressCategory: 613 case Qtopia::AddressCategory:
543 contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); 614 contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
544 break; 615 break;
545 */ 616 */
546 case JOURNALACTION: 617 case JOURNALACTION:
547 action = journal_action(it.data().toInt()); 618 action = journal_action(it.data().toInt());
548 foundAction = true; 619 foundAction = true;
549 qWarning ("ODefBack(journal)::ACTION found: %d", action); 620 qWarning ("ODefBack(journal)::ACTION found: %d", action);
550 break; 621 break;
551 case JOURNALROW: 622 case JOURNALROW:
552 journalKey = it.data().toInt(); 623 journalKey = it.data().toInt();
553 break; 624 break;
554 default: // no conversion needed add them to the map 625 default: // no conversion needed add them to the map
555 contactMap.insert( *find, it.data() ); 626 contactMap.insert( *find, it.data() );
556 break; 627 break;
557 } 628 }
558 } 629 }
559 /* now generate the Contact contact */ 630 /* now generate the Contact contact */
560 OContact contact( contactMap ); 631 OContact contact( contactMap );
561 632
562 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { 633 for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
563 contact.setCustomField( customIt.key(), customIt.data() ); 634 contact.setCustomField( customIt.key(), customIt.data() );
564 } 635 }
565 636
566 if (foundAction){ 637 if (foundAction){
567 foundAction = false; 638 foundAction = false;
568 switch ( action ) { 639 switch ( action ) {
569 case ACTION_ADD: 640 case ACTION_ADD:
570 addContact_p (contact); 641 addContact_p (contact);
571 break; 642 break;
572 case ACTION_REMOVE: 643 case ACTION_REMOVE:
573 if ( !remove (contact.uid()) ) 644 if ( !remove (contact.uid()) )
574 qWarning ("ODefBack(journal)::Unable to remove uid: %d", 645 qWarning ("ODefBack(journal)::Unable to remove uid: %d",
575 contact.uid() ); 646 contact.uid() );
576 break; 647 break;
577 case ACTION_REPLACE: 648 case ACTION_REPLACE:
578 if ( !replace ( contact ) ) 649 if ( !replace ( contact ) )
579 qWarning ("ODefBack(journal)::Unable to replace uid: %d", 650 qWarning ("ODefBack(journal)::Unable to replace uid: %d",
580 contact.uid() ); 651 contact.uid() );
581 break; 652 break;
582 default: 653 default:
583 qWarning ("Unknown action: ignored !"); 654 qWarning ("Unknown action: ignored !");
584 break; 655 break;
585 } 656 }
586 }else{ 657 }else{
587 /* Add contact to list */ 658 /* Add contact to list */
588 addContact_p (contact); 659 addContact_p (contact);
589 } 660 }
590 661
591 /* Move to next element */ 662 /* Move to next element */
592 element = element->nextChild(); 663 element = element->nextChild();
593 } 664 }
594 }else { 665 }else {
595 qWarning("ODefBack::could not load"); 666 qWarning("ODefBack::could not load");
596 } 667 }
597 delete root; 668 delete root;
598 qWarning("returning from loading" ); 669 qWarning("returning from loading" );
599 return true; 670 return true;
600 } 671 }
601 672
602 673
603 void updateJournal( const OContact& cnt, 674 void updateJournal( const OContact& cnt,
604 journal_action action ) { 675 journal_action action ) {
605 QFile f( m_journalName ); 676 QFile f( m_journalName );
606 bool created = !f.exists(); 677 bool created = !f.exists();
607 if ( !f.open(IO_WriteOnly|IO_Append) ) 678 if ( !f.open(IO_WriteOnly|IO_Append) )
608 return; 679 return;
609 680
610 QString buf; 681 QString buf;
611 QCString str; 682 QCString str;
612 683
613 // if the file was created, we have to set the Tag "<CONTACTS>" to 684 // if the file was created, we have to set the Tag "<CONTACTS>" to
614 // get a XML-File which is readable by our parser. 685 // get a XML-File which is readable by our parser.
615 // This is just a cheat, but better than rewrite the parser. 686 // This is just a cheat, but better than rewrite the parser.
616 if ( created ){ 687 if ( created ){
617 buf = "<Contacts>"; 688 buf = "<Contacts>";
618 QCString cstr = buf.utf8(); 689 QCString cstr = buf.utf8();
619 f.writeBlock( cstr.data(), cstr.length() ); 690 f.writeBlock( cstr.data(), cstr.length() );
620 } 691 }
621 692
622 buf = "<Contact "; 693 buf = "<Contact ";
623 cnt.save( buf ); 694 cnt.save( buf );
624 buf += " action=\"" + QString::number( (int)action ) + "\" "; 695 buf += " action=\"" + QString::number( (int)action ) + "\" ";
625 buf += "/>\n"; 696 buf += "/>\n";
626 QCString cstr = buf.utf8(); 697 QCString cstr = buf.utf8();
627 f.writeBlock( cstr.data(), cstr.length() ); 698 f.writeBlock( cstr.data(), cstr.length() );
628 } 699 }
629 700
630 void removeJournal() 701 void removeJournal()
631 { 702 {
632 QFile f ( m_journalName ); 703 QFile f ( m_journalName );
633 if ( f.exists() ) 704 if ( f.exists() )
634 f.remove(); 705 f.remove();
635 } 706 }
636 707
637 protected: 708 protected:
638 bool m_changed; 709 bool m_changed;
639 QString m_journalName; 710 QString m_journalName;
640 QString m_fileName; 711 QString m_fileName;
641 QString m_appName; 712 QString m_appName;
642 QValueList<OContact> m_contactList; 713 QValueList<OContact> m_contactList;
643 QDateTime m_readtime; 714 QDateTime m_readtime;
644}; 715};
645 716
646#endif 717#endif
diff --git a/libopie2/opiepim/core/ocontactaccess.h b/libopie2/opiepim/core/ocontactaccess.h
index 961968f..32b2dcb 100644
--- a/libopie2/opiepim/core/ocontactaccess.h
+++ b/libopie2/opiepim/core/ocontactaccess.h
@@ -1,150 +1,158 @@
1/* 1/*
2 * Class to manage the Contacts. 2 * Class to manage the Contacts.
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 * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) 5 * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org)
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; 10 * License as published by the Free Software Foundation;
11 * either version 2 of the License, or (at your option) any later 11 * either version 2 of the License, or (at your option) any later
12 * version. 12 * version.
13 * ===================================================================== 13 * =====================================================================
14 * ToDo: Define enum for query settings 14 * ToDo: Define enum for query settings
15 * ===================================================================== 15 * =====================================================================
16 * Version: $Id$ 16 * Version: $Id$
17 * ===================================================================== 17 * =====================================================================
18 * History: 18 * History:
19 * $Log$ 19 * $Log$
20 * Revision 1.6 2003/01/02 14:27:12 eilers
21 * Improved query by example: Search by date is possible.. First step
22 * for a today plugin for birthdays..
23 *
20 * Revision 1.5 2002/11/13 14:14:51 eilers 24 * Revision 1.5 2002/11/13 14:14:51 eilers
21 * Added sorted for Contacts.. 25 * Added sorted for Contacts..
22 * 26 *
23 * Revision 1.4 2002/11/01 15:10:42 eilers 27 * Revision 1.4 2002/11/01 15:10:42 eilers
24 * Added regExp-search in database for all fields in a contact. 28 * Added regExp-search in database for all fields in a contact.
25 * 29 *
26 * Revision 1.3 2002/10/16 10:52:40 eilers 30 * Revision 1.3 2002/10/16 10:52:40 eilers
27 * Added some docu to the interface and now using the cache infrastucture by zecke.. :) 31 * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
28 * 32 *
29 * Revision 1.2 2002/10/14 16:21:54 eilers 33 * Revision 1.2 2002/10/14 16:21:54 eilers
30 * Some minor interface updates 34 * Some minor interface updates
31 * 35 *
32 * Revision 1.1 2002/09/27 17:11:44 eilers 36 * Revision 1.1 2002/09/27 17:11:44 eilers
33 * Added API for accessing the Contact-Database ! It is compiling, but 37 * Added API for accessing the Contact-Database ! It is compiling, but
34 * please do not expect that anything is working ! 38 * please do not expect that anything is working !
35 * I will debug that stuff in the next time .. 39 * I will debug that stuff in the next time ..
36 * Please read README_COMPILE for compiling ! 40 * Please read README_COMPILE for compiling !
37 * 41 *
38 * ===================================================================== 42 * =====================================================================
39 */ 43 */
40#ifndef _OCONTACTACCESS_H 44#ifndef _OCONTACTACCESS_H
41#define _OCONTACTACCESS_H 45#define _OCONTACTACCESS_H
42 46
43#include <qobject.h> 47#include <qobject.h>
44 48
45#include <qpe/qcopenvelope_qws.h> 49#include <qpe/qcopenvelope_qws.h>
46 50
47#include <qvaluelist.h> 51#include <qvaluelist.h>
48#include <qfileinfo.h> 52#include <qfileinfo.h>
49 53
50#include "ocontact.h" 54#include "ocontact.h"
51#include "ocontactaccessbackend.h" 55#include "ocontactaccessbackend.h"
52#include "opimaccesstemplate.h" 56#include "opimaccesstemplate.h"
53 57
54/** Class to access the contacts database. 58/** Class to access the contacts database.
55 * This is just a frontend for the real database handling which is 59 * This is just a frontend for the real database handling which is
56 * done by the backend. 60 * done by the backend.
57 * @see OPimAccessTemplate 61 * @see OPimAccessTemplate
58 */ 62 */
59class OContactAccess: public QObject, public OPimAccessTemplate<OContact> 63class OContactAccess: public QObject, public OPimAccessTemplate<OContact>
60{ 64{
61 Q_OBJECT 65 Q_OBJECT
62 66
63 public: 67 public:
64 /** Create Database with contacts (addressbook). 68 /** Create Database with contacts (addressbook).
65 * @param appname Name of application which wants access to the database 69 * @param appname Name of application which wants access to the database
66 * (i.e. "todolist") 70 * (i.e. "todolist")
67 * @param filename The name of the database file. If not set, the default one 71 * @param filename The name of the database file. If not set, the default one
68 * is used. 72 * is used.
69 * @param backend Pointer to an alternative Backend. If not set, we will use 73 * @param backend Pointer to an alternative Backend. If not set, we will use
70 * the default backend. 74 * the default backend.
71 * @param handlesync If <b>true</b> the database stores the current state 75 * @param handlesync If <b>true</b> the database stores the current state
72 * automatically if it receives the signals <i>flush()</i> and <i>reload()</i> 76 * automatically if it receives the signals <i>flush()</i> and <i>reload()</i>
73 * which are used before and after synchronisation. If the application wants 77 * which are used before and after synchronisation. If the application wants
74 * to react itself, it should be disabled by setting it to <b>false</b> 78 * to react itself, it should be disabled by setting it to <b>false</b>
75 * @see OContactAccessBackend 79 * @see OContactAccessBackend
76 */ 80 */
77 OContactAccess (const QString appname, const QString filename = 0l, 81 OContactAccess (const QString appname, const QString filename = 0l,
78 OContactAccessBackend* backend = 0l, bool handlesync = true); 82 OContactAccessBackend* backend = 0l, bool handlesync = true);
79 ~OContactAccess (); 83 ~OContactAccess ();
80 84
81 /** Constants for query. 85 /** Constants for query.
82 * Use this constants to set the query parameters. 86 * Use this constants to set the query parameters.
83 * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes ! 87 * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes !
84 * @see queryByExample() 88 * @see queryByExample()
85 */ 89 */
86 enum QuerySettings { 90 enum QuerySettings {
87 WildCards = 0x0001, 91 WildCards = 0x0001,
88 IgnoreCase = 0x0002, 92 IgnoreCase = 0x0002,
89 RegExp = 0x0004, 93 RegExp = 0x0004,
90 ExactMatch = 0x0008, 94 ExactMatch = 0x0008,
91 MatchOne = 0x0010 // Only one Entry must match 95 MatchOne = 0x0010, // Only one Entry must match
96 DateDiff = 0x0020, // Find all entries from today until given date
97 DateYear = 0x0040, // The year matches
98 DateMonth = 0x0080, // The month matches
99 DateDay = 0x0100, // The day matches
92 }; 100 };
93 101
94 102
95 ORecordList<OContact> matchRegexp( const QRegExp &r )const; 103 ORecordList<OContact> matchRegexp( const QRegExp &r )const;
96 104
97 /** Return all Contacts in a sorted manner. 105 /** Return all Contacts in a sorted manner.
98 * @param ascending true: Sorted in acending order. 106 * @param ascending true: Sorted in acending order.
99 * @param sortOrder Currently not implemented. Just defined to stay compatible to otodoaccess 107 * @param sortOrder Currently not implemented. Just defined to stay compatible to otodoaccess
100 * @param sortFilter Currently not implemented. Just defined to stay compatible to otodoaccess 108 * @param sortFilter Currently not implemented. Just defined to stay compatible to otodoaccess
101 * @param cat Currently not implemented. Just defined to stay compatible to otodoaccess 109 * @param cat Currently not implemented. Just defined to stay compatible to otodoaccess
102 */ 110 */
103 List sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const; 111 List sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const;
104 112
105 /** Return all possible settings. 113 /** Return all possible settings.
106 * @return All settings provided by the current backend 114 * @return All settings provided by the current backend
107 * (i.e.: query_WildCards & query_IgnoreCase) 115 * (i.e.: query_WildCards & query_IgnoreCase)
108 */ 116 */
109 const uint querySettings(); 117 const uint querySettings();
110 118
111 /** Check whether settings are correct. 119 /** Check whether settings are correct.
112 * @return <i>true</i> if the given settings are correct and possible. 120 * @return <i>true</i> if the given settings are correct and possible.
113 */ 121 */
114 bool hasQuerySettings ( int querySettings ) const; 122 bool hasQuerySettings ( int querySettings ) const;
115 123
116 /** 124 /**
117 * if the resource was changed externally. 125 * if the resource was changed externally.
118 * You should use the signal instead of polling possible changes ! 126 * You should use the signal instead of polling possible changes !
119 */ 127 */
120 bool wasChangedExternally()const; 128 bool wasChangedExternally()const;
121 129
122 130
123 /** Save contacts database. 131 /** Save contacts database.
124 * Save is more a "commit". After calling this function, all changes are public available. 132 * Save is more a "commit". After calling this function, all changes are public available.
125 * @return true if successful 133 * @return true if successful
126 */ 134 */
127 bool save(); 135 bool save();
128 136
129 signals: 137 signals:
130 /* Signal is emitted if the database was changed. Therefore 138 /* Signal is emitted if the database was changed. Therefore
131 * we may need to reload to stay consistent. 139 * we may need to reload to stay consistent.
132 * @param which Pointer to the database who created this event. This pointer 140 * @param which Pointer to the database who created this event. This pointer
133 * is useful if an application has to handle multiple databases at the same time. 141 * is useful if an application has to handle multiple databases at the same time.
134 * @see reload() 142 * @see reload()
135 */ 143 */
136 void signalChanged ( const OContactAccess *which ); 144 void signalChanged ( const OContactAccess *which );
137 145
138 146
139 private: 147 private:
140 // class OContactAccessPrivate; 148 // class OContactAccessPrivate;
141 // OContactAccessPrivate* d; 149 // OContactAccessPrivate* d;
142 OContactAccessBackend *m_backEnd; 150 OContactAccessBackend *m_backEnd;
143 bool m_loading:1; 151 bool m_loading:1;
144 152
145 private slots: 153 private slots:
146 void copMessage( const QCString &msg, const QByteArray &data ); 154 void copMessage( const QCString &msg, const QByteArray &data );
147 155
148 156
149}; 157};
150#endif 158#endif