Diffstat (limited to 'noncore/unsupported/libopie/pim') (more/less context) (ignore whitespace changes)
70 files changed, 15010 insertions, 0 deletions
diff --git a/noncore/unsupported/libopie/pim/.cvsignore b/noncore/unsupported/libopie/pim/.cvsignore new file mode 100644 index 0000000..aef62c4 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/.cvsignore | |||
@@ -0,0 +1,2 @@ | |||
1 | config.in | ||
2 | moc* | ||
diff --git a/noncore/unsupported/libopie/pim/config.in b/noncore/unsupported/libopie/pim/config.in new file mode 100644 index 0000000..95d3737 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/config.in | |||
@@ -0,0 +1,2 @@ | |||
1 | menu "Pim" | ||
2 | endmenu | ||
diff --git a/noncore/unsupported/libopie/pim/libopie.pro b/noncore/unsupported/libopie/pim/libopie.pro new file mode 100644 index 0000000..62f235d --- a/dev/null +++ b/noncore/unsupported/libopie/pim/libopie.pro | |||
@@ -0,0 +1,64 @@ | |||
1 | TEMPLATE = lib | ||
2 | CONFIG += qte warn_on release | ||
3 | HEADERS = ofontmenu.h \ | ||
4 | tododb.h \ | ||
5 | todoevent.h todoresource.h \ | ||
6 | todovcalresource.h xmltree.h \ | ||
7 | colordialog.h colorpopupmenu.h \ | ||
8 | oclickablelabel.h oprocctrl.h \ | ||
9 | oprocess.h odevice.h \ | ||
10 | otimepicker.h otabwidget.h \ | ||
11 | otabbar.h otabinfo.h \ | ||
12 | ofileselector/ofiledialog.h \ | ||
13 | ofileselector/ofilelistview.h \ | ||
14 | ofileselector/ofileselector.h \ | ||
15 | ofileselector/ofileselectoritem.h \ | ||
16 | ofileselector/ofileview.h \ | ||
17 | ofileselector/olister.h \ | ||
18 | ofileselector/olocallister.h \ | ||
19 | ofileselector/ofileselectormain.h \ | ||
20 | pim/opimrecord.h \ | ||
21 | pim/otodo.h \ | ||
22 | pim/orecordlist.h \ | ||
23 | pim/opimaccesstemplate.h \ | ||
24 | pim/opimaccessbackend.h \ | ||
25 | pim/otodoaccess.h \ | ||
26 | pim/otodacessbackend.h \ | ||
27 | pim/ocontact.h \ | ||
28 | pim/ocontactaccess.h \ | ||
29 | pim/ocontactaccessbackend.h \ | ||
30 | pim/ocontactaccessbackend_xml.h \ | ||
31 | pim/orecord.h | ||
32 | |||
33 | SOURCES = ofontmenu.cc \ | ||
34 | xmltree.cc \ | ||
35 | tododb.cpp todoevent.cpp \ | ||
36 | todovcalresource.cpp colordialog.cpp \ | ||
37 | colorpopupmenu.cpp oclickablelabel.cpp \ | ||
38 | oprocctrl.cpp oprocess.cpp \ | ||
39 | odevice.cpp otimepicker.cpp \ | ||
40 | otabwidget.cpp otabbar.cpp \ | ||
41 | ofileselector/ofiledialog.cpp \ | ||
42 | ofileselector/ofilelistview.cpp \ | ||
43 | ofileselector/ofileselector.cpp \ | ||
44 | ofileselector/ofileselectoritem.cpp \ | ||
45 | ofileselector/ofileview.cpp \ | ||
46 | ofileselector/olister.cpp \ | ||
47 | ofileselector/olocallister.cpp \ | ||
48 | ofileselector/ofileselectormain.cpp \ | ||
49 | pim/otodo.cpp \ | ||
50 | pim/opimrecord.cpp \ | ||
51 | pim/otodoaccess.cpp \ | ||
52 | pim/otodoaccessbackend.cpp \ | ||
53 | pim/ocontact.cpp \ | ||
54 | pim/ocontactaccess.cpp \ | ||
55 | pim/orecord.cpp | ||
56 | |||
57 | TARGET = opie | ||
58 | INCLUDEPATH += $(OPIEDIR)/include | ||
59 | DESTDIR = $(OPIEDIR)/lib$(PROJMAK) | ||
60 | #VERSION = 1.0.0 | ||
61 | |||
62 | INTERFACES = otimepickerbase.ui | ||
63 | |||
64 | include ( $(OPIEDIR)/include.pro ) | ||
diff --git a/noncore/unsupported/libopie/pim/obackendfactory.h b/noncore/unsupported/libopie/pim/obackendfactory.h new file mode 100644 index 0000000..4cdef8b --- a/dev/null +++ b/noncore/unsupported/libopie/pim/obackendfactory.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Class to manage Backends. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; | ||
10 | * either version 2 of the License, or (at your option) any later | ||
11 | * version. | ||
12 | * ===================================================================== | ||
13 | * ToDo: Use plugins | ||
14 | * ===================================================================== | ||
15 | * Version: $Id$ | ||
16 | * ===================================================================== | ||
17 | * History: | ||
18 | * $Log$ | ||
19 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
20 | * libopie1 goes into unsupported | ||
21 | * | ||
22 | * Revision 1.9 2003/12/22 10:19:26 eilers | ||
23 | * Finishing implementation of sql-backend for datebook. But I have to | ||
24 | * port the PIM datebook application to use it, before I could debug the | ||
25 | * whole stuff. | ||
26 | * Thus, PIM-Database backend is finished, but highly experimental. And some | ||
27 | * parts are still generic. For instance, the "queryByExample()" methods are | ||
28 | * not (or not fully) implemented. Todo: custom-entries not stored. | ||
29 | * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular | ||
30 | * expression search in the database, which is not supported by sqlite ! | ||
31 | * Therefore we need either an extended sqlite or a workaround which would | ||
32 | * be very slow and memory consuming.. | ||
33 | * | ||
34 | * Revision 1.8 2003/09/22 14:31:16 eilers | ||
35 | * Added first experimental incarnation of sql-backend for addressbook. | ||
36 | * Some modifications to be able to compile the todo sql-backend. | ||
37 | * A lot of changes fill follow... | ||
38 | * | ||
39 | * Revision 1.7 2003/08/01 12:30:16 eilers | ||
40 | * Merging changes from BRANCH_1_0 to HEAD | ||
41 | * | ||
42 | * Revision 1.6.4.1 2003/06/30 14:34:19 eilers | ||
43 | * Patches from Zecke: | ||
44 | * Fixing and cleaning up extraMap handling | ||
45 | * Adding d_ptr for binary compatibility in the future | ||
46 | * | ||
47 | * Revision 1.6 2003/04/13 18:07:10 zecke | ||
48 | * More API doc | ||
49 | * QString -> const QString& | ||
50 | * QString = 0l -> QString::null | ||
51 | * | ||
52 | * Revision 1.5 2003/02/21 23:31:52 zecke | ||
53 | * Add XML datebookresource | ||
54 | * -clean up todoaccessxml header | ||
55 | * -implement some more stuff in the oeven tester | ||
56 | * -extend DefaultFactory to not crash and to use datebook | ||
57 | * | ||
58 | * -reading of OEvents is working nicely.. saving will be added | ||
59 | * tomorrow | ||
60 | * -fix spelling in ODateBookAcces | ||
61 | * | ||
62 | * Revision 1.4 2002/10/14 15:55:18 eilers | ||
63 | * Redeactivate SQL.. ;) | ||
64 | * | ||
65 | * Revision 1.3 2002/10/10 17:08:58 zecke | ||
66 | * The Cache is finally in place | ||
67 | * I tested it with my todolist and it 'works' for 10.000 todos the hits are awesome ;) | ||
68 | * The read ahead functionality does not make sense for XMLs backends because most of the stuff is already in memory. While using readahead on SQL makes things a lot faster.... | ||
69 | * I still have to fully implement read ahead | ||
70 | * This change is bic but sc | ||
71 | * | ||
72 | * Revision 1.2 2002/10/08 09:27:36 eilers | ||
73 | * Fixed libopie.pro to include the new pim-API. | ||
74 | * The SQL-Stuff is currently deactivated. Otherwise everyone who wants to | ||
75 | * compile itself would need to install libsqlite, libopiesql... | ||
76 | * Therefore, the backend currently uses XML only.. | ||
77 | * | ||
78 | * Revision 1.1 2002/10/07 17:35:01 eilers | ||
79 | * added OBackendFactory for advanced backend access | ||
80 | * | ||
81 | * | ||
82 | * ===================================================================== | ||
83 | */ | ||
84 | #ifndef OPIE_BACKENDFACTORY_H_ | ||
85 | #define OPIE_BACKENDFACTORY_H_ | ||
86 | |||
87 | #include <qstring.h> | ||
88 | #include <qasciidict.h> | ||
89 | #include <qpe/config.h> | ||
90 | |||
91 | #include "otodoaccessxml.h" | ||
92 | #include "ocontactaccessbackend_xml.h" | ||
93 | #include "odatebookaccessbackend_xml.h" | ||
94 | |||
95 | #ifdef __USE_SQL | ||
96 | #include "otodoaccesssql.h" | ||
97 | #include "ocontactaccessbackend_sql.h" | ||
98 | #include "odatebookaccessbackend_sql.h" | ||
99 | #endif | ||
100 | |||
101 | class OBackendPrivate; | ||
102 | |||
103 | /** | ||
104 | * This class is our factory. It will give us the default implementations | ||
105 | * of at least Todolist, Contacts and Datebook. In the future this class will | ||
106 | * allow users to switch the backend with ( XML->SQLite ) without the need | ||
107 | * to recompile.# | ||
108 | * This class as the whole PIM Api is making use of templates | ||
109 | * | ||
110 | * <pre> | ||
111 | * OTodoAccessBackend* backend = OBackEndFactory<OTodoAccessBackend>::Default("todo", QString::null ); | ||
112 | * backend->load(); | ||
113 | * </pre> | ||
114 | * | ||
115 | * @author Stefan Eilers | ||
116 | * @version 0.1 | ||
117 | */ | ||
118 | template<class T> | ||
119 | class OBackendFactory | ||
120 | { | ||
121 | public: | ||
122 | OBackendFactory() {}; | ||
123 | |||
124 | enum BACKENDS { | ||
125 | TODO, | ||
126 | CONTACT, | ||
127 | DATE | ||
128 | }; | ||
129 | |||
130 | /** | ||
131 | * Returns a backend implementation for backendName | ||
132 | * @param backendName the type of the backend | ||
133 | * @param appName will be passed on to the backend | ||
134 | */ | ||
135 | static T* Default( const QString backendName, const QString& appName ){ | ||
136 | |||
137 | // __asm__("int3"); | ||
138 | |||
139 | Config config( "pimaccess" ); | ||
140 | config.setGroup ( backendName ); | ||
141 | QString backend = config.readEntry( "usebackend" ); | ||
142 | |||
143 | qWarning("Selected backend for %s is: %s", backendName.latin1(), backend.latin1() ); | ||
144 | |||
145 | QAsciiDict<int> dict ( 3 ); | ||
146 | dict.setAutoDelete ( TRUE ); | ||
147 | |||
148 | dict.insert( "todo", new int (TODO) ); | ||
149 | dict.insert( "contact", new int (CONTACT) ); | ||
150 | dict.insert( "datebook", new int(DATE) ); | ||
151 | |||
152 | int *find = dict[ backendName ]; | ||
153 | if (!find ) return 0; | ||
154 | |||
155 | switch ( *find ){ | ||
156 | case TODO: | ||
157 | #ifdef __USE_SQL | ||
158 | if ( backend == "sql" ) | ||
159 | return (T*) new OTodoAccessBackendSQL(""); | ||
160 | #else | ||
161 | if ( backend == "sql" ) | ||
162 | qWarning ("OBackendFactory:: sql Backend for TODO not implemented! Using XML instead!"); | ||
163 | #endif | ||
164 | |||
165 | return (T*) new OTodoAccessXML( appName ); | ||
166 | case CONTACT: | ||
167 | #ifdef __USE_SQL | ||
168 | if ( backend == "sql" ) | ||
169 | return (T*) new OContactAccessBackend_SQL(""); | ||
170 | #else | ||
171 | if ( backend == "sql" ) | ||
172 | qWarning ("OBackendFactory:: sql Backend for CONTACT not implemented! Using XML instead!"); | ||
173 | #endif | ||
174 | |||
175 | return (T*) new OContactAccessBackend_XML( appName ); | ||
176 | case DATE: | ||
177 | #ifdef __USE_SQL | ||
178 | if ( backend == "sql" ) | ||
179 | return (T*) new ODateBookAccessBackend_SQL(""); | ||
180 | #else | ||
181 | if ( backend == "sql" ) | ||
182 | qWarning("OBackendFactory:: sql Backend for DATEBOOK not implemented! Using XML instead!"); | ||
183 | #endif | ||
184 | |||
185 | return (T*) new ODateBookAccessBackend_XML( appName ); | ||
186 | default: | ||
187 | return NULL; | ||
188 | } | ||
189 | |||
190 | |||
191 | } | ||
192 | private: | ||
193 | OBackendPrivate* d; | ||
194 | }; | ||
195 | |||
196 | |||
197 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/ocontact.cpp b/noncore/unsupported/libopie/pim/ocontact.cpp new file mode 100644 index 0000000..fcf3b26 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontact.cpp | |||
@@ -0,0 +1,1207 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de) | ||
4 | ** | ||
5 | ** This file may be distributed and/or modified under the terms of the | ||
6 | ** GNU General Public License version 2 as published by the Free Software | ||
7 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
8 | ** packaging of this file. | ||
9 | ** | ||
10 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
11 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
12 | ** | ||
13 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
14 | ** | ||
15 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
16 | ** not clear to you. | ||
17 | ** | ||
18 | **********************************************************************/ | ||
19 | |||
20 | #define QTOPIA_INTERNAL_CONTACT_MRE | ||
21 | |||
22 | #include "ocontact.h" | ||
23 | #include "opimresolver.h" | ||
24 | #include "oconversion.h" | ||
25 | |||
26 | #include <qpe/stringutil.h> | ||
27 | #include <qpe/timestring.h> | ||
28 | #include <qpe/config.h> | ||
29 | |||
30 | #include <qobject.h> | ||
31 | #include <qregexp.h> | ||
32 | #include <qstylesheet.h> | ||
33 | #include <qfileinfo.h> | ||
34 | #include <qmap.h> | ||
35 | |||
36 | #include <stdio.h> | ||
37 | |||
38 | /*! | ||
39 | \class Contact contact.h | ||
40 | \brief The Contact class holds the data of an address book entry. | ||
41 | |||
42 | This data includes information the name of the person, contact | ||
43 | information, and business information such as deparment and job title. | ||
44 | |||
45 | \ingroup qtopiaemb | ||
46 | \ingroup qtopiadesktop | ||
47 | */ | ||
48 | |||
49 | |||
50 | /*! | ||
51 | Creates a new, empty contact. | ||
52 | */ | ||
53 | OContact::OContact() | ||
54 | : OPimRecord(), mMap(), d( 0 ) | ||
55 | { | ||
56 | } | ||
57 | |||
58 | /*! | ||
59 | \internal | ||
60 | Creates a new contact. The properties of the contact are | ||
61 | set from \a fromMap. | ||
62 | */ | ||
63 | OContact::OContact( const QMap<int, QString> &fromMap ) : | ||
64 | OPimRecord(), mMap( fromMap ), d( 0 ) | ||
65 | { | ||
66 | QString cats = mMap[ Qtopia::AddressCategory ]; | ||
67 | if ( !cats.isEmpty() ) | ||
68 | setCategories( idsFromString( cats ) ); | ||
69 | |||
70 | QString uidStr = find( Qtopia::AddressUid ); | ||
71 | |||
72 | if ( uidStr.isEmpty() || (uidStr.toInt() == 0) ){ | ||
73 | qWarning( "Invalid UID found. Generate new one.." ); | ||
74 | setUid( uidGen().generate() ); | ||
75 | }else | ||
76 | setUid( uidStr.toInt() ); | ||
77 | |||
78 | // if ( !uidStr.isEmpty() ) | ||
79 | // setUid( uidStr.toInt() ); | ||
80 | } | ||
81 | |||
82 | /*! | ||
83 | Destroys a contact. | ||
84 | */ | ||
85 | OContact::~OContact() | ||
86 | { | ||
87 | } | ||
88 | |||
89 | /*! \fn void OContact::setTitle( const QString &str ) | ||
90 | Sets the title of the contact to \a str. | ||
91 | */ | ||
92 | |||
93 | /*! \fn void OContact::setFirstName( const QString &str ) | ||
94 | Sets the first name of the contact to \a str. | ||
95 | */ | ||
96 | |||
97 | /*! \fn void OContact::setMiddleName( const QString &str ) | ||
98 | Sets the middle name of the contact to \a str. | ||
99 | */ | ||
100 | |||
101 | /*! \fn void OContact::setLastName( const QString &str ) | ||
102 | Sets the last name of the contact to \a str. | ||
103 | */ | ||
104 | |||
105 | /*! \fn void OContact::setSuffix( const QString &str ) | ||
106 | Sets the suffix of the contact to \a str. | ||
107 | */ | ||
108 | |||
109 | /*! \fn void OContact::setFileAs( const QString &str ) | ||
110 | Sets the contact to filed as \a str. | ||
111 | */ | ||
112 | |||
113 | /*! \fn void OContact::setDefaultEmail( const QString &str ) | ||
114 | Sets the default email of the contact to \a str. | ||
115 | */ | ||
116 | |||
117 | /*! \fn void OContact::setHomeStreet( const QString &str ) | ||
118 | Sets the home street address of the contact to \a str. | ||
119 | */ | ||
120 | |||
121 | /*! \fn void OContact::setHomeCity( const QString &str ) | ||
122 | Sets the home city of the contact to \a str. | ||
123 | */ | ||
124 | |||
125 | /*! \fn void OContact::setHomeState( const QString &str ) | ||
126 | Sets the home state of the contact to \a str. | ||
127 | */ | ||
128 | |||
129 | /*! \fn void OContact::setHomeZip( const QString &str ) | ||
130 | Sets the home zip code of the contact to \a str. | ||
131 | */ | ||
132 | |||
133 | /*! \fn void OContact::setHomeCountry( const QString &str ) | ||
134 | Sets the home country of the contact to \a str. | ||
135 | */ | ||
136 | |||
137 | /*! \fn void OContact::setHomePhone( const QString &str ) | ||
138 | Sets the home phone number of the contact to \a str. | ||
139 | */ | ||
140 | |||
141 | /*! \fn void OContact::setHomeFax( const QString &str ) | ||
142 | Sets the home fax number of the contact to \a str. | ||
143 | */ | ||
144 | |||
145 | /*! \fn void OContact::setHomeMobile( const QString &str ) | ||
146 | Sets the home mobile phone number of the contact to \a str. | ||
147 | */ | ||
148 | |||
149 | /*! \fn void OContact::setHomeWebpage( const QString &str ) | ||
150 | Sets the home webpage of the contact to \a str. | ||
151 | */ | ||
152 | |||
153 | /*! \fn void OContact::setCompany( const QString &str ) | ||
154 | Sets the company for contact to \a str. | ||
155 | */ | ||
156 | |||
157 | /*! \fn void OContact::setJobTitle( const QString &str ) | ||
158 | Sets the job title of the contact to \a str. | ||
159 | */ | ||
160 | |||
161 | /*! \fn void OContact::setDepartment( const QString &str ) | ||
162 | Sets the department for contact to \a str. | ||
163 | */ | ||
164 | |||
165 | /*! \fn void OContact::setOffice( const QString &str ) | ||
166 | Sets the office for contact to \a str. | ||
167 | */ | ||
168 | |||
169 | /*! \fn void OContact::setBusinessStreet( const QString &str ) | ||
170 | Sets the business street address of the contact to \a str. | ||
171 | */ | ||
172 | |||
173 | /*! \fn void OContact::setBusinessCity( const QString &str ) | ||
174 | Sets the business city of the contact to \a str. | ||
175 | */ | ||
176 | |||
177 | /*! \fn void OContact::setBusinessState( const QString &str ) | ||
178 | Sets the business state of the contact to \a str. | ||
179 | */ | ||
180 | |||
181 | /*! \fn void OContact::setBusinessZip( const QString &str ) | ||
182 | Sets the business zip code of the contact to \a str. | ||
183 | */ | ||
184 | |||
185 | /*! \fn void OContact::setBusinessCountry( const QString &str ) | ||
186 | Sets the business country of the contact to \a str. | ||
187 | */ | ||
188 | |||
189 | /*! \fn void OContact::setBusinessPhone( const QString &str ) | ||
190 | Sets the business phone number of the contact to \a str. | ||
191 | */ | ||
192 | |||
193 | /*! \fn void OContact::setBusinessFax( const QString &str ) | ||
194 | Sets the business fax number of the contact to \a str. | ||
195 | */ | ||
196 | |||
197 | /*! \fn void OContact::setBusinessMobile( const QString &str ) | ||
198 | Sets the business mobile phone number of the contact to \a str. | ||
199 | */ | ||
200 | |||
201 | /*! \fn void OContact::setBusinessPager( const QString &str ) | ||
202 | Sets the business pager number of the contact to \a str. | ||
203 | */ | ||
204 | |||
205 | /*! \fn void OContact::setBusinessWebpage( const QString &str ) | ||
206 | Sets the business webpage of the contact to \a str. | ||
207 | */ | ||
208 | |||
209 | /*! \fn void OContact::setProfession( const QString &str ) | ||
210 | Sets the profession of the contact to \a str. | ||
211 | */ | ||
212 | |||
213 | /*! \fn void OContact::setAssistant( const QString &str ) | ||
214 | Sets the assistant of the contact to \a str. | ||
215 | */ | ||
216 | |||
217 | /*! \fn void OContact::setManager( const QString &str ) | ||
218 | Sets the manager of the contact to \a str. | ||
219 | */ | ||
220 | |||
221 | /*! \fn void OContact::setSpouse( const QString &str ) | ||
222 | Sets the spouse of the contact to \a str. | ||
223 | */ | ||
224 | |||
225 | /*! \fn void OContact::setGender( const QString &str ) | ||
226 | Sets the gender of the contact to \a str. | ||
227 | */ | ||
228 | |||
229 | /*! \fn void OContact::setNickname( const QString &str ) | ||
230 | Sets the nickname of the contact to \a str. | ||
231 | */ | ||
232 | |||
233 | /*! \fn void OContact::setNotes( const QString &str ) | ||
234 | Sets the notes about the contact to \a str. | ||
235 | */ | ||
236 | |||
237 | /*! \fn QString OContact::title() const | ||
238 | Returns the title of the contact. | ||
239 | */ | ||
240 | |||
241 | /*! \fn QString OContact::firstName() const | ||
242 | Returns the first name of the contact. | ||
243 | */ | ||
244 | |||
245 | /*! \fn QString OContact::middleName() const | ||
246 | Returns the middle name of the contact. | ||
247 | */ | ||
248 | |||
249 | /*! \fn QString OContact::lastName() const | ||
250 | Returns the last name of the contact. | ||
251 | */ | ||
252 | |||
253 | /*! \fn QString OContact::suffix() const | ||
254 | Returns the suffix of the contact. | ||
255 | */ | ||
256 | |||
257 | /*! \fn QString OContact::fileAs() const | ||
258 | Returns the string the contact is filed as. | ||
259 | */ | ||
260 | |||
261 | /*! \fn QString OContact::defaultEmail() const | ||
262 | Returns the default email address of the contact. | ||
263 | */ | ||
264 | |||
265 | /*! \fn QString OContact::emails() const | ||
266 | Returns the list of email address for a contact separated by ';'s in a single | ||
267 | string. | ||
268 | */ | ||
269 | |||
270 | /*! \fn QString OContact::homeStreet() const | ||
271 | Returns the home street address of the contact. | ||
272 | */ | ||
273 | |||
274 | /*! \fn QString OContact::homeCity() const | ||
275 | Returns the home city of the contact. | ||
276 | */ | ||
277 | |||
278 | /*! \fn QString OContact::homeState() const | ||
279 | Returns the home state of the contact. | ||
280 | */ | ||
281 | |||
282 | /*! \fn QString OContact::homeZip() const | ||
283 | Returns the home zip of the contact. | ||
284 | */ | ||
285 | |||
286 | /*! \fn QString OContact::homeCountry() const | ||
287 | Returns the home country of the contact. | ||
288 | */ | ||
289 | |||
290 | /*! \fn QString OContact::homePhone() const | ||
291 | Returns the home phone number of the contact. | ||
292 | */ | ||
293 | |||
294 | /*! \fn QString OContact::homeFax() const | ||
295 | Returns the home fax number of the contact. | ||
296 | */ | ||
297 | |||
298 | /*! \fn QString OContact::homeMobile() const | ||
299 | Returns the home mobile number of the contact. | ||
300 | */ | ||
301 | |||
302 | /*! \fn QString OContact::homeWebpage() const | ||
303 | Returns the home webpage of the contact. | ||
304 | */ | ||
305 | |||
306 | /*! \fn QString OContact::company() const | ||
307 | Returns the company for the contact. | ||
308 | */ | ||
309 | |||
310 | /*! \fn QString OContact::department() const | ||
311 | Returns the department for the contact. | ||
312 | */ | ||
313 | |||
314 | /*! \fn QString OContact::office() const | ||
315 | Returns the office for the contact. | ||
316 | */ | ||
317 | |||
318 | /*! \fn QString OContact::jobTitle() const | ||
319 | Returns the job title of the contact. | ||
320 | */ | ||
321 | |||
322 | /*! \fn QString OContact::profession() const | ||
323 | Returns the profession of the contact. | ||
324 | */ | ||
325 | |||
326 | /*! \fn QString OContact::assistant() const | ||
327 | Returns the assistant of the contact. | ||
328 | */ | ||
329 | |||
330 | /*! \fn QString OContact::manager() const | ||
331 | Returns the manager of the contact. | ||
332 | */ | ||
333 | |||
334 | /*! \fn QString OContact::businessStreet() const | ||
335 | Returns the business street address of the contact. | ||
336 | */ | ||
337 | |||
338 | /*! \fn QString OContact::businessCity() const | ||
339 | Returns the business city of the contact. | ||
340 | */ | ||
341 | |||
342 | /*! \fn QString OContact::businessState() const | ||
343 | Returns the business state of the contact. | ||
344 | */ | ||
345 | |||
346 | /*! \fn QString OContact::businessZip() const | ||
347 | Returns the business zip of the contact. | ||
348 | */ | ||
349 | |||
350 | /*! \fn QString OContact::businessCountry() const | ||
351 | Returns the business country of the contact. | ||
352 | */ | ||
353 | |||
354 | /*! \fn QString OContact::businessPhone() const | ||
355 | Returns the business phone number of the contact. | ||
356 | */ | ||
357 | |||
358 | /*! \fn QString OContact::businessFax() const | ||
359 | Returns the business fax number of the contact. | ||
360 | */ | ||
361 | |||
362 | /*! \fn QString OContact::businessMobile() const | ||
363 | Returns the business mobile number of the contact. | ||
364 | */ | ||
365 | |||
366 | /*! \fn QString OContact::businessPager() const | ||
367 | Returns the business pager number of the contact. | ||
368 | */ | ||
369 | |||
370 | /*! \fn QString OContact::businessWebpage() const | ||
371 | Returns the business webpage of the contact. | ||
372 | */ | ||
373 | |||
374 | /*! \fn QString OContact::spouse() const | ||
375 | Returns the spouse of the contact. | ||
376 | */ | ||
377 | |||
378 | /*! \fn QString OContact::gender() const | ||
379 | Returns the gender of the contact. | ||
380 | */ | ||
381 | |||
382 | /*! \fn QString OContact::nickname() const | ||
383 | Returns the nickname of the contact. | ||
384 | */ | ||
385 | |||
386 | /*! \fn QString OContact::children() const | ||
387 | Returns the children of the contact. | ||
388 | */ | ||
389 | |||
390 | /*! \fn QString OContact::notes() const | ||
391 | Returns the notes relating to the the contact. | ||
392 | */ | ||
393 | |||
394 | /*! \fn QString OContact::groups() const | ||
395 | \internal | ||
396 | Returns the groups for the contact. | ||
397 | */ | ||
398 | |||
399 | /*! \fn QStringList OContact::groupList() const | ||
400 | \internal | ||
401 | */ | ||
402 | |||
403 | /*! \fn QString OContact::field(int) const | ||
404 | \internal | ||
405 | */ | ||
406 | |||
407 | /*! \fn void OContact::saveJournal( journal_action, const QString & = QString::null ) | ||
408 | \internal | ||
409 | */ | ||
410 | |||
411 | /*! \fn void OContact::setUid( int id ) | ||
412 | \internal | ||
413 | Sets the uid for this record to \a id. | ||
414 | */ | ||
415 | |||
416 | /*! \enum OContact::journal_action | ||
417 | \internal | ||
418 | */ | ||
419 | |||
420 | /*! | ||
421 | \internal | ||
422 | */ | ||
423 | QMap<int, QString> OContact::toMap() const | ||
424 | { | ||
425 | QMap<int, QString> map = mMap; | ||
426 | QString cats = idsToString( categories() ); | ||
427 | if ( !cats.isEmpty() ) | ||
428 | map.insert( Qtopia::AddressCategory, cats ); | ||
429 | return map; | ||
430 | } | ||
431 | |||
432 | /*! | ||
433 | Returns a rich text formatted QString representing the contents the contact. | ||
434 | */ | ||
435 | QString OContact::toRichText() const | ||
436 | { | ||
437 | QString text; | ||
438 | QString value, comp, state; | ||
439 | QString str; | ||
440 | bool marker = false; | ||
441 | |||
442 | Config cfg("qpe"); | ||
443 | cfg.setGroup("Appearance"); | ||
444 | int addressformat = cfg.readNumEntry( "AddressFormat", Zip_City_State ); | ||
445 | |||
446 | // name, jobtitle and company | ||
447 | if ( !(value = fullName()).isEmpty() ) | ||
448 | text += "<b><h3><img src=\"addressbook/AddressBook\"> " + Qtopia::escapeString(value) + "</h3></b>"; | ||
449 | |||
450 | if ( !(value = jobTitle()).isEmpty() ) | ||
451 | text += Qtopia::escapeString(value) + " "; | ||
452 | |||
453 | comp = company(); | ||
454 | if ( !(value = department()).isEmpty() ) { | ||
455 | text += Qtopia::escapeString(value); | ||
456 | if ( comp ) | ||
457 | text += ", " + Qtopia::escapeString(comp); | ||
458 | }else if ( comp ) | ||
459 | text += "<br>" + Qtopia::escapeString(comp); | ||
460 | text += "<br><hr>"; | ||
461 | |||
462 | // defailt email | ||
463 | QString defEmail = defaultEmail(); | ||
464 | if ( !defEmail.isEmpty() ){ | ||
465 | text += "<b><img src=\"addressbook/email\"> " + QObject::tr("Default Email: ") + "</b>" | ||
466 | + Qtopia::escapeString(defEmail); | ||
467 | marker = true; | ||
468 | } | ||
469 | |||
470 | // business address | ||
471 | if ( !businessStreet().isEmpty() || !businessCity().isEmpty() || | ||
472 | !businessZip().isEmpty() || !businessCountry().isEmpty() ) { | ||
473 | text += QObject::tr( "<br><b>Work Address:</b>" ); | ||
474 | marker = true; | ||
475 | } | ||
476 | |||
477 | if ( !(value = businessStreet()).isEmpty() ){ | ||
478 | text += "<br>" + Qtopia::escapeString(value); | ||
479 | marker = true; | ||
480 | } | ||
481 | |||
482 | switch( addressformat ){ | ||
483 | case Zip_City_State:{ // Zip_Code City, State | ||
484 | state = businessState(); | ||
485 | if ( !(value = businessZip()).isEmpty() ){ | ||
486 | text += "<br>" + Qtopia::escapeString(value) + " "; | ||
487 | marker = true; | ||
488 | |||
489 | } | ||
490 | if ( !(value = businessCity()).isEmpty() ) { | ||
491 | marker = true; | ||
492 | if ( businessZip().isEmpty() && !businessStreet().isEmpty() ) | ||
493 | text += "<br>"; | ||
494 | text += Qtopia::escapeString(value); | ||
495 | if ( state ) | ||
496 | text += ", " + Qtopia::escapeString(state); | ||
497 | } else if ( !state.isEmpty() ){ | ||
498 | text += "<br>" + Qtopia::escapeString(state); | ||
499 | marker = true; | ||
500 | } | ||
501 | break; | ||
502 | } | ||
503 | case City_State_Zip:{ // City, State Zip_Code | ||
504 | state = businessState(); | ||
505 | if ( !(value = businessCity()).isEmpty() ) { | ||
506 | marker = true; | ||
507 | text += "<br>" + Qtopia::escapeString(value); | ||
508 | if ( state ) | ||
509 | text += ", " + Qtopia::escapeString(state); | ||
510 | } else if ( !state.isEmpty() ){ | ||
511 | text += "<br>" + Qtopia::escapeString(state); | ||
512 | marker = true; | ||
513 | } | ||
514 | if ( !(value = businessZip()).isEmpty() ){ | ||
515 | text += " " + Qtopia::escapeString(value); | ||
516 | marker = true; | ||
517 | } | ||
518 | break; | ||
519 | } | ||
520 | } | ||
521 | |||
522 | if ( !(value = businessCountry()).isEmpty() ){ | ||
523 | text += "<br>" + Qtopia::escapeString(value); | ||
524 | marker = true; | ||
525 | } | ||
526 | |||
527 | // rest of Business data | ||
528 | str = office(); | ||
529 | if ( !str.isEmpty() ){ | ||
530 | text += "<br><b>" + QObject::tr("Office: ") + "</b>" | ||
531 | + Qtopia::escapeString(str); | ||
532 | marker = true; | ||
533 | } | ||
534 | str = businessWebpage(); | ||
535 | if ( !str.isEmpty() ){ | ||
536 | text += "<br><b><img src=\"addressbook/webpagework\"> " + QObject::tr("Business Web Page: ") + "</b>" | ||
537 | + Qtopia::escapeString(str); | ||
538 | marker = true; | ||
539 | } | ||
540 | str = businessPhone(); | ||
541 | if ( !str.isEmpty() ){ | ||
542 | text += "<br><b><img src=\"addressbook/phonework\"> " + QObject::tr("Business Phone: ") + "</b>" | ||
543 | + Qtopia::escapeString(str); | ||
544 | marker = true; | ||
545 | } | ||
546 | str = businessFax(); | ||
547 | if ( !str.isEmpty() ){ | ||
548 | text += "<br><b><img src=\"addressbook/faxwork\"> " + QObject::tr("Business Fax: ") + "</b>" | ||
549 | + Qtopia::escapeString(str); | ||
550 | marker = true; | ||
551 | } | ||
552 | str = businessMobile(); | ||
553 | if ( !str.isEmpty() ){ | ||
554 | text += "<br><b><img src=\"addressbook/mobilework\"> " + QObject::tr("Business Mobile: ") + "</b>" | ||
555 | + Qtopia::escapeString(str); | ||
556 | marker = true; | ||
557 | } | ||
558 | str = businessPager(); | ||
559 | if ( !str.isEmpty() ){ | ||
560 | text += "<br><b>" + QObject::tr("Business Pager: ") + "</b>" | ||
561 | + Qtopia::escapeString(str); | ||
562 | marker = true; | ||
563 | } | ||
564 | |||
565 | // text += "<br>"; | ||
566 | |||
567 | // home address | ||
568 | if ( !homeStreet().isEmpty() || !homeCity().isEmpty() || | ||
569 | !homeZip().isEmpty() || !homeCountry().isEmpty() ) { | ||
570 | text += QObject::tr( "<br><b>Home Address:</b>" ); | ||
571 | marker = true; | ||
572 | } | ||
573 | |||
574 | if ( !(value = homeStreet()).isEmpty() ){ | ||
575 | text += "<br>" + Qtopia::escapeString(value); | ||
576 | marker = true; | ||
577 | } | ||
578 | |||
579 | switch( addressformat ){ | ||
580 | case Zip_City_State:{ // Zip_Code City, State | ||
581 | state = homeState(); | ||
582 | if ( !(value = homeZip()).isEmpty() ){ | ||
583 | text += "<br>" + Qtopia::escapeString(value) + " "; | ||
584 | marker = true; | ||
585 | } | ||
586 | if ( !(value = homeCity()).isEmpty() ) { | ||
587 | marker = true; | ||
588 | if ( homeZip().isEmpty() && !homeStreet().isEmpty() ) | ||
589 | text += "<br>"; | ||
590 | text += Qtopia::escapeString(value); | ||
591 | if ( !state.isEmpty() ) | ||
592 | text += ", " + Qtopia::escapeString(state); | ||
593 | } else if (!state.isEmpty()) { | ||
594 | text += "<br>" + Qtopia::escapeString(state); | ||
595 | marker = true; | ||
596 | } | ||
597 | break; | ||
598 | } | ||
599 | case City_State_Zip:{ // City, State Zip_Code | ||
600 | state = homeState(); | ||
601 | if ( !(value = homeCity()).isEmpty() ) { | ||
602 | marker = true; | ||
603 | text += "<br>" + Qtopia::escapeString(value); | ||
604 | if ( state ) | ||
605 | text += ", " + Qtopia::escapeString(state); | ||
606 | } else if ( !state.isEmpty() ){ | ||
607 | text += "<br>" + Qtopia::escapeString(state); | ||
608 | marker = true; | ||
609 | } | ||
610 | if ( !(value = homeZip()).isEmpty() ){ | ||
611 | text += " " + Qtopia::escapeString(value); | ||
612 | marker = true; | ||
613 | } | ||
614 | break; | ||
615 | } | ||
616 | } | ||
617 | |||
618 | if ( !(value = homeCountry()).isEmpty() ){ | ||
619 | text += "<br>" + Qtopia::escapeString(value); | ||
620 | marker = true; | ||
621 | } | ||
622 | |||
623 | // rest of Home data | ||
624 | str = homeWebpage(); | ||
625 | if ( !str.isEmpty() ){ | ||
626 | text += "<br><b><img src=\"addressbook/webpagehome\"> " + QObject::tr("Home Web Page: ") + "</b>" | ||
627 | + Qtopia::escapeString(str); | ||
628 | marker = true; | ||
629 | } | ||
630 | str = homePhone(); | ||
631 | if ( !str.isEmpty() ){ | ||
632 | text += "<br><b><img src=\"addressbook/phonehome\"> " + QObject::tr("Home Phone: ") + "</b>" | ||
633 | + Qtopia::escapeString(str); | ||
634 | marker = true; | ||
635 | } | ||
636 | str = homeFax(); | ||
637 | if ( !str.isEmpty() ){ | ||
638 | text += "<br><b><img src=\"addressbook/faxhome\"> " + QObject::tr("Home Fax: ") + "</b>" | ||
639 | + Qtopia::escapeString(str); | ||
640 | marker = true; | ||
641 | } | ||
642 | str = homeMobile(); | ||
643 | if ( !str.isEmpty() ){ | ||
644 | text += "<br><b><img src=\"addressbook/mobilehome\"> " + QObject::tr("Home Mobile: ") + "</b>" | ||
645 | + Qtopia::escapeString(str); | ||
646 | marker = true; | ||
647 | } | ||
648 | |||
649 | if ( marker ) | ||
650 | text += "<br><hr>"; | ||
651 | |||
652 | // the rest... | ||
653 | str = emails(); | ||
654 | if ( !str.isEmpty() && ( str != defEmail ) ) | ||
655 | text += "<br><b>" + QObject::tr("All Emails: ") + "</b>" | ||
656 | + Qtopia::escapeString(str); | ||
657 | str = profession(); | ||
658 | if ( !str.isEmpty() ) | ||
659 | text += "<br><b>" + QObject::tr("Profession: ") + "</b>" | ||
660 | + Qtopia::escapeString(str); | ||
661 | str = assistant(); | ||
662 | if ( !str.isEmpty() ) | ||
663 | text += "<br><b>" + QObject::tr("Assistant: ") + "</b>" | ||
664 | + Qtopia::escapeString(str); | ||
665 | str = manager(); | ||
666 | if ( !str.isEmpty() ) | ||
667 | text += "<br><b>" + QObject::tr("Manager: ") + "</b>" | ||
668 | + Qtopia::escapeString(str); | ||
669 | str = gender(); | ||
670 | if ( !str.isEmpty() && str.toInt() != 0 ) { | ||
671 | text += "<br>"; | ||
672 | if ( str.toInt() == 1 ) | ||
673 | str = QObject::tr( "Male" ); | ||
674 | else if ( str.toInt() == 2 ) | ||
675 | str = QObject::tr( "Female" ); | ||
676 | text += "<b>" + QObject::tr("Gender: ") + "</b>" + str; | ||
677 | } | ||
678 | str = spouse(); | ||
679 | if ( !str.isEmpty() ) | ||
680 | text += "<br><b>" + QObject::tr("Spouse: ") + "</b>" | ||
681 | + Qtopia::escapeString(str); | ||
682 | if ( birthday().isValid() ){ | ||
683 | str = TimeString::numberDateString( birthday() ); | ||
684 | text += "<br><b>" + QObject::tr("Birthday: ") + "</b>" | ||
685 | + Qtopia::escapeString(str); | ||
686 | } | ||
687 | if ( anniversary().isValid() ){ | ||
688 | str = TimeString::numberDateString( anniversary() ); | ||
689 | text += "<br><b>" + QObject::tr("Anniversary: ") + "</b>" | ||
690 | + Qtopia::escapeString(str); | ||
691 | } | ||
692 | str = children(); | ||
693 | if ( !str.isEmpty() ) | ||
694 | text += "<br><b>" + QObject::tr("Children: ") + "</b>" | ||
695 | + Qtopia::escapeString(str); | ||
696 | |||
697 | str = nickname(); | ||
698 | if ( !str.isEmpty() ) | ||
699 | text += "<br><b>" + QObject::tr("Nickname: ") + "</b>" | ||
700 | + Qtopia::escapeString(str); | ||
701 | |||
702 | // categories | ||
703 | if ( categoryNames("Contacts").count() ){ | ||
704 | text += "<br><b>" + QObject::tr( "Category:") + "</b> "; | ||
705 | text += categoryNames("Contacts").join(", "); | ||
706 | } | ||
707 | |||
708 | // notes last | ||
709 | if ( !(value = notes()).isEmpty() ) { | ||
710 | text += "<br><hr><b>" + QObject::tr( "Notes:") + "</b> "; | ||
711 | QRegExp reg("\n"); | ||
712 | |||
713 | //QString tmp = Qtopia::escapeString(value); | ||
714 | QString tmp = QStyleSheet::convertFromPlainText(value); | ||
715 | //tmp.replace( reg, "<br>" ); | ||
716 | text += "<br>" + tmp + "<br>"; | ||
717 | } | ||
718 | return text; | ||
719 | } | ||
720 | |||
721 | /*! | ||
722 | \internal | ||
723 | */ | ||
724 | void OContact::insert( int key, const QString &v ) | ||
725 | { | ||
726 | QString value = v.stripWhiteSpace(); | ||
727 | if ( value.isEmpty() ) | ||
728 | mMap.remove( key ); | ||
729 | else | ||
730 | mMap.insert( key, value ); | ||
731 | } | ||
732 | |||
733 | /*! | ||
734 | \internal | ||
735 | */ | ||
736 | void OContact::replace( int key, const QString & v ) | ||
737 | { | ||
738 | QString value = v.stripWhiteSpace(); | ||
739 | if ( value.isEmpty() ) | ||
740 | mMap.remove( key ); | ||
741 | else | ||
742 | mMap.replace( key, value ); | ||
743 | } | ||
744 | |||
745 | /*! | ||
746 | \internal | ||
747 | */ | ||
748 | QString OContact::find( int key ) const | ||
749 | { | ||
750 | return mMap[key]; | ||
751 | } | ||
752 | |||
753 | /*! | ||
754 | \internal | ||
755 | */ | ||
756 | QString OContact::displayAddress( const QString &street, | ||
757 | const QString &city, | ||
758 | const QString &state, | ||
759 | const QString &zip, | ||
760 | const QString &country ) const | ||
761 | { | ||
762 | QString s = street; | ||
763 | if ( !street.isEmpty() ) | ||
764 | s+= "\n"; | ||
765 | s += city; | ||
766 | if ( !city.isEmpty() && !state.isEmpty() ) | ||
767 | s += ", "; | ||
768 | s += state; | ||
769 | if ( !state.isEmpty() && !zip.isEmpty() ) | ||
770 | s += " "; | ||
771 | s += zip; | ||
772 | if ( !country.isEmpty() && !s.isEmpty() ) | ||
773 | s += "\n"; | ||
774 | s += country; | ||
775 | return s; | ||
776 | } | ||
777 | |||
778 | /*! | ||
779 | \internal | ||
780 | */ | ||
781 | QString OContact::displayBusinessAddress() const | ||
782 | { | ||
783 | return displayAddress( businessStreet(), businessCity(), | ||
784 | businessState(), businessZip(), | ||
785 | businessCountry() ); | ||
786 | } | ||
787 | |||
788 | /*! | ||
789 | \internal | ||
790 | */ | ||
791 | QString OContact::displayHomeAddress() const | ||
792 | { | ||
793 | return displayAddress( homeStreet(), homeCity(), | ||
794 | homeState(), homeZip(), | ||
795 | homeCountry() ); | ||
796 | } | ||
797 | |||
798 | /*! | ||
799 | Returns the full name of the contact | ||
800 | */ | ||
801 | QString OContact::fullName() const | ||
802 | { | ||
803 | QString title = find( Qtopia::Title ); | ||
804 | QString firstName = find( Qtopia::FirstName ); | ||
805 | QString middleName = find( Qtopia::MiddleName ); | ||
806 | QString lastName = find( Qtopia::LastName ); | ||
807 | QString suffix = find( Qtopia::Suffix ); | ||
808 | |||
809 | QString name = title; | ||
810 | if ( !firstName.isEmpty() ) { | ||
811 | if ( !name.isEmpty() ) | ||
812 | name += " "; | ||
813 | name += firstName; | ||
814 | } | ||
815 | if ( !middleName.isEmpty() ) { | ||
816 | if ( !name.isEmpty() ) | ||
817 | name += " "; | ||
818 | name += middleName; | ||
819 | } | ||
820 | if ( !lastName.isEmpty() ) { | ||
821 | if ( !name.isEmpty() ) | ||
822 | name += " "; | ||
823 | name += lastName; | ||
824 | } | ||
825 | if ( !suffix.isEmpty() ) { | ||
826 | if ( !name.isEmpty() ) | ||
827 | name += " "; | ||
828 | name += suffix; | ||
829 | } | ||
830 | return name.simplifyWhiteSpace(); | ||
831 | } | ||
832 | |||
833 | /*! | ||
834 | Returns a list of the names of the children of the contact. | ||
835 | */ | ||
836 | QStringList OContact::childrenList() const | ||
837 | { | ||
838 | return QStringList::split( " ", find( Qtopia::Children ) ); | ||
839 | } | ||
840 | |||
841 | /*! \fn void OContact::insertEmail( const QString &email ) | ||
842 | |||
843 | Insert \a email into the email list. Ensures \a email can only be added | ||
844 | once. If there is no default email address set, it sets it to the \a email. | ||
845 | */ | ||
846 | |||
847 | /*! \fn void OContact::removeEmail( const QString &email ) | ||
848 | |||
849 | Removes the \a email from the email list. If the default email was \a email, | ||
850 | then the default email address is assigned to the first email in the | ||
851 | email list | ||
852 | */ | ||
853 | |||
854 | /*! \fn void OContact::clearEmails() | ||
855 | |||
856 | Clears the email list. | ||
857 | */ | ||
858 | |||
859 | /*! \fn void OContact::insertEmails( const QStringList &emailList ) | ||
860 | |||
861 | Appends the \a emailList to the exiting email list | ||
862 | */ | ||
863 | |||
864 | /*! | ||
865 | Returns a list of email addresses belonging to the contact, including | ||
866 | the default email address. | ||
867 | */ | ||
868 | QStringList OContact::emailList() const | ||
869 | { | ||
870 | QString emailStr = emails(); | ||
871 | |||
872 | QStringList r; | ||
873 | if ( !emailStr.isEmpty() ) { | ||
874 | qDebug(" emailstr "); | ||
875 | QStringList l = QStringList::split( emailSeparator(), emailStr ); | ||
876 | for ( QStringList::ConstIterator it = l.begin();it != l.end();++it ) | ||
877 | r += (*it).simplifyWhiteSpace(); | ||
878 | } | ||
879 | |||
880 | return r; | ||
881 | } | ||
882 | |||
883 | /*! | ||
884 | \overload | ||
885 | |||
886 | Generates the string for the contact to be filed as from the first, | ||
887 | middle and last name of the contact. | ||
888 | */ | ||
889 | void OContact::setFileAs() | ||
890 | { | ||
891 | QString lastName, firstName, middleName, fileas; | ||
892 | |||
893 | lastName = find( Qtopia::LastName ); | ||
894 | firstName = find( Qtopia::FirstName ); | ||
895 | middleName = find( Qtopia::MiddleName ); | ||
896 | if ( !lastName.isEmpty() && !firstName.isEmpty() | ||
897 | && !middleName.isEmpty() ) | ||
898 | fileas = lastName + ", " + firstName + " " + middleName; | ||
899 | else if ( !lastName.isEmpty() && !firstName.isEmpty() ) | ||
900 | fileas = lastName + ", " + firstName; | ||
901 | else if ( !lastName.isEmpty() || !firstName.isEmpty() || | ||
902 | !middleName.isEmpty() ) | ||
903 | fileas = firstName + ( firstName.isEmpty() ? "" : " " ) | ||
904 | + middleName + ( middleName.isEmpty() ? "" : " " ) | ||
905 | + lastName; | ||
906 | |||
907 | replace( Qtopia::FileAs, fileas ); | ||
908 | } | ||
909 | |||
910 | /*! | ||
911 | \internal | ||
912 | Appends the contact information to \a buf. | ||
913 | */ | ||
914 | void OContact::save( QString &buf ) const | ||
915 | { | ||
916 | static const QStringList SLFIELDS = fields(); | ||
917 | // I'm expecting "<Contact " in front of this... | ||
918 | for ( QMap<int, QString>::ConstIterator it = mMap.begin(); | ||
919 | it != mMap.end(); ++it ) { | ||
920 | const QString &value = it.data(); | ||
921 | int key = it.key(); | ||
922 | if ( !value.isEmpty() ) { | ||
923 | if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid) | ||
924 | continue; | ||
925 | |||
926 | key -= Qtopia::AddressCategory+1; | ||
927 | buf += SLFIELDS[key]; | ||
928 | buf += "=\"" + Qtopia::escapeString(value) + "\" "; | ||
929 | } | ||
930 | } | ||
931 | buf += customToXml(); | ||
932 | if ( categories().count() > 0 ) | ||
933 | buf += "Categories=\"" + idsToString( categories() ) + "\" "; | ||
934 | buf += "Uid=\"" + QString::number( uid() ) + "\" "; | ||
935 | // You need to close this yourself | ||
936 | } | ||
937 | |||
938 | |||
939 | /*! | ||
940 | \internal | ||
941 | Returns the list of fields belonging to a contact | ||
942 | Never change order of this list ! It has to be regarding | ||
943 | enum AddressBookFields !! | ||
944 | */ | ||
945 | QStringList OContact::fields() | ||
946 | { | ||
947 | QStringList list; | ||
948 | |||
949 | list.append( "Title" ); // Not Used! | ||
950 | list.append( "FirstName" ); | ||
951 | list.append( "MiddleName" ); | ||
952 | list.append( "LastName" ); | ||
953 | list.append( "Suffix" ); | ||
954 | list.append( "FileAs" ); | ||
955 | |||
956 | list.append( "JobTitle" ); | ||
957 | list.append( "Department" ); | ||
958 | list.append( "Company" ); | ||
959 | list.append( "BusinessPhone" ); | ||
960 | list.append( "BusinessFax" ); | ||
961 | list.append( "BusinessMobile" ); | ||
962 | |||
963 | list.append( "DefaultEmail" ); | ||
964 | list.append( "Emails" ); | ||
965 | |||
966 | list.append( "HomePhone" ); | ||
967 | list.append( "HomeFax" ); | ||
968 | list.append( "HomeMobile" ); | ||
969 | |||
970 | list.append( "BusinessStreet" ); | ||
971 | list.append( "BusinessCity" ); | ||
972 | list.append( "BusinessState" ); | ||
973 | list.append( "BusinessZip" ); | ||
974 | list.append( "BusinessCountry" ); | ||
975 | list.append( "BusinessPager" ); | ||
976 | list.append( "BusinessWebPage" ); | ||
977 | |||
978 | list.append( "Office" ); | ||
979 | list.append( "Profession" ); | ||
980 | list.append( "Assistant" ); | ||
981 | list.append( "Manager" ); | ||
982 | |||
983 | list.append( "HomeStreet" ); | ||
984 | list.append( "HomeCity" ); | ||
985 | list.append( "HomeState" ); | ||
986 | list.append( "HomeZip" ); | ||
987 | list.append( "HomeCountry" ); | ||
988 | list.append( "HomeWebPage" ); | ||
989 | |||
990 | list.append( "Spouse" ); | ||
991 | list.append( "Gender" ); | ||
992 | list.append( "Birthday" ); | ||
993 | list.append( "Anniversary" ); | ||
994 | list.append( "Nickname" ); | ||
995 | list.append( "Children" ); | ||
996 | |||
997 | list.append( "Notes" ); | ||
998 | list.append( "Groups" ); | ||
999 | |||
1000 | return list; | ||
1001 | } | ||
1002 | |||
1003 | |||
1004 | /*! | ||
1005 | Sets the list of email address for contact to those contained in \a str. | ||
1006 | Email address should be separated by ';'s. | ||
1007 | */ | ||
1008 | void OContact::setEmails( const QString &str ) | ||
1009 | { | ||
1010 | replace( Qtopia::Emails, str ); | ||
1011 | if ( str.isEmpty() ) | ||
1012 | setDefaultEmail( QString::null ); | ||
1013 | } | ||
1014 | |||
1015 | /*! | ||
1016 | Sets the list of children for the contact to those contained in \a str. | ||
1017 | */ | ||
1018 | void OContact::setChildren( const QString &str ) | ||
1019 | { | ||
1020 | replace( Qtopia::Children, str ); | ||
1021 | } | ||
1022 | |||
1023 | /*! | ||
1024 | \overload | ||
1025 | Returns TRUE if the contact matches the regular expression \a regexp. | ||
1026 | Otherwise returns FALSE. | ||
1027 | */ | ||
1028 | bool OContact::match( const QRegExp &r ) const | ||
1029 | { | ||
1030 | setLastHitField( -1 ); | ||
1031 | bool match; | ||
1032 | match = false; | ||
1033 | QMap<int, QString>::ConstIterator it; | ||
1034 | for ( it = mMap.begin(); it != mMap.end(); ++it ) { | ||
1035 | if ( (*it).find( r ) > -1 ) { | ||
1036 | setLastHitField( it.key() ); | ||
1037 | match = true; | ||
1038 | break; | ||
1039 | } | ||
1040 | } | ||
1041 | return match; | ||
1042 | } | ||
1043 | |||
1044 | |||
1045 | QString OContact::toShortText() const | ||
1046 | { | ||
1047 | return ( fullName() ); | ||
1048 | } | ||
1049 | QString OContact::type() const | ||
1050 | { | ||
1051 | return QString::fromLatin1( "OContact" ); | ||
1052 | } | ||
1053 | |||
1054 | |||
1055 | |||
1056 | class QString OContact::recordField( int pos ) const | ||
1057 | { | ||
1058 | QStringList SLFIELDS = fields(); // ?? why this ? (se) | ||
1059 | return SLFIELDS[pos]; | ||
1060 | } | ||
1061 | |||
1062 | // In future releases, we should store birthday and anniversary | ||
1063 | // internally as QDate instead of QString ! | ||
1064 | // QString is always too complicate to interprete (DD.MM.YY, DD/MM/YY, MM/DD/YY, etc..)(se) | ||
1065 | |||
1066 | /*! \fn void OContact::setBirthday( const QDate& date ) | ||
1067 | Sets the birthday for the contact to \a date. If date is null | ||
1068 | the current stored date will be removed. | ||
1069 | */ | ||
1070 | void OContact::setBirthday( const QDate &v ) | ||
1071 | { | ||
1072 | if ( v.isNull() ){ | ||
1073 | qWarning( "Remove Birthday"); | ||
1074 | replace( Qtopia::Birthday, QString::null ); | ||
1075 | return; | ||
1076 | } | ||
1077 | |||
1078 | if ( v.isValid() ) | ||
1079 | replace( Qtopia::Birthday, OConversion::dateToString( v ) ); | ||
1080 | |||
1081 | } | ||
1082 | |||
1083 | |||
1084 | /*! \fn void OContact::setAnniversary( const QDate &date ) | ||
1085 | Sets the anniversary of the contact to \a date. If date is | ||
1086 | null, the current stored date will be removed. | ||
1087 | */ | ||
1088 | void OContact::setAnniversary( const QDate &v ) | ||
1089 | { | ||
1090 | if ( v.isNull() ){ | ||
1091 | qWarning( "Remove Anniversary"); | ||
1092 | replace( Qtopia::Anniversary, QString::null ); | ||
1093 | return; | ||
1094 | } | ||
1095 | |||
1096 | if ( v.isValid() ) | ||
1097 | replace( Qtopia::Anniversary, OConversion::dateToString( v ) ); | ||
1098 | } | ||
1099 | |||
1100 | /*! \fn QDate OContact::birthday() const | ||
1101 | Returns the birthday of the contact. | ||
1102 | */ | ||
1103 | QDate OContact::birthday() const | ||
1104 | { | ||
1105 | QString str = find( Qtopia::Birthday ); | ||
1106 | // qWarning ("Birthday %s", str.latin1() ); | ||
1107 | if ( !str.isEmpty() ) | ||
1108 | return OConversion::dateFromString ( str ); | ||
1109 | else | ||
1110 | return QDate(); | ||
1111 | } | ||
1112 | |||
1113 | |||
1114 | /*! \fn QDate OContact::anniversary() const | ||
1115 | Returns the anniversary of the contact. | ||
1116 | */ | ||
1117 | QDate OContact::anniversary() const | ||
1118 | { | ||
1119 | QDate empty; | ||
1120 | QString str = find( Qtopia::Anniversary ); | ||
1121 | // qWarning ("Anniversary %s", str.latin1() ); | ||
1122 | if ( !str.isEmpty() ) | ||
1123 | return OConversion::dateFromString ( str ); | ||
1124 | else | ||
1125 | return empty; | ||
1126 | } | ||
1127 | |||
1128 | |||
1129 | void OContact::insertEmail( const QString &v ) | ||
1130 | { | ||
1131 | //qDebug("insertEmail %s", v.latin1()); | ||
1132 | QString e = v.simplifyWhiteSpace(); | ||
1133 | QString def = defaultEmail(); | ||
1134 | |||
1135 | // if no default, set it as the default email and don't insert | ||
1136 | if ( def.isEmpty() ) { | ||
1137 | setDefaultEmail( e ); // will insert into the list for us | ||
1138 | return; | ||
1139 | } | ||
1140 | |||
1141 | // otherwise, insert assuming doesn't already exist | ||
1142 | QString emailsStr = find( Qtopia::Emails ); | ||
1143 | if ( emailsStr.contains( e )) | ||
1144 | return; | ||
1145 | if ( !emailsStr.isEmpty() ) | ||
1146 | emailsStr += emailSeparator(); | ||
1147 | emailsStr += e; | ||
1148 | replace( Qtopia::Emails, emailsStr ); | ||
1149 | } | ||
1150 | |||
1151 | void OContact::removeEmail( const QString &v ) | ||
1152 | { | ||
1153 | QString e = v.simplifyWhiteSpace(); | ||
1154 | QString def = defaultEmail(); | ||
1155 | QString emailsStr = find( Qtopia::Emails ); | ||
1156 | QStringList emails = emailList(); | ||
1157 | |||
1158 | // otherwise, must first contain it | ||
1159 | if ( !emailsStr.contains( e ) ) | ||
1160 | return; | ||
1161 | |||
1162 | // remove it | ||
1163 | //qDebug(" removing email from list %s", e.latin1()); | ||
1164 | emails.remove( e ); | ||
1165 | // reset the string | ||
1166 | emailsStr = emails.join(emailSeparator()); // Sharp's brain dead separator | ||
1167 | replace( Qtopia::Emails, emailsStr ); | ||
1168 | |||
1169 | // if default, then replace the default email with the first one | ||
1170 | if ( def == e ) { | ||
1171 | //qDebug("removeEmail is default; setting new default"); | ||
1172 | if ( !emails.count() ) | ||
1173 | clearEmails(); | ||
1174 | else // setDefaultEmail will remove e from the list | ||
1175 | setDefaultEmail( emails.first() ); | ||
1176 | } | ||
1177 | } | ||
1178 | void OContact::clearEmails() | ||
1179 | { | ||
1180 | mMap.remove( Qtopia::DefaultEmail ); | ||
1181 | mMap.remove( Qtopia::Emails ); | ||
1182 | } | ||
1183 | void OContact::setDefaultEmail( const QString &v ) | ||
1184 | { | ||
1185 | QString e = v.simplifyWhiteSpace(); | ||
1186 | |||
1187 | //qDebug("OContact::setDefaultEmail %s", e.latin1()); | ||
1188 | replace( Qtopia::DefaultEmail, e ); | ||
1189 | |||
1190 | if ( !e.isEmpty() ) | ||
1191 | insertEmail( e ); | ||
1192 | |||
1193 | } | ||
1194 | |||
1195 | void OContact::insertEmails( const QStringList &v ) | ||
1196 | { | ||
1197 | for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it ) | ||
1198 | insertEmail( *it ); | ||
1199 | } | ||
1200 | int OContact::rtti() { | ||
1201 | return OPimResolver::AddressBook; | ||
1202 | } | ||
1203 | void OContact::setUid( int i ) | ||
1204 | { | ||
1205 | OPimRecord::setUid(i); | ||
1206 | replace( Qtopia::AddressUid , QString::number(i)); | ||
1207 | } | ||
diff --git a/noncore/unsupported/libopie/pim/ocontact.h b/noncore/unsupported/libopie/pim/ocontact.h new file mode 100644 index 0000000..1d46b81 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontact.h | |||
@@ -0,0 +1,240 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de) | ||
4 | ** | ||
5 | ** This file may be distributed and/or modified under the terms of the | ||
6 | ** GNU General Public License version 2 as published by the Free Software | ||
7 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
8 | ** packaging of this file. | ||
9 | ** | ||
10 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
11 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
12 | ** | ||
13 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
14 | ** | ||
15 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
16 | ** not clear to you. | ||
17 | ** | ||
18 | **********************************************************************/ | ||
19 | |||
20 | #ifndef __OCONTACT_H__ | ||
21 | #define __OCONTACT_H__ | ||
22 | |||
23 | #include <opie/opimrecord.h> | ||
24 | #include <qpe/recordfields.h> | ||
25 | |||
26 | #include <qdatetime.h> | ||
27 | #include <qstringlist.h> | ||
28 | |||
29 | #if defined(QPC_TEMPLATEDLL) | ||
30 | // MOC_SKIP_BEGIN | ||
31 | QPC_TEMPLATEEXTERN template class QPC_EXPORT QMap<int, QString>; | ||
32 | // MOC_SKIP_END | ||
33 | #endif | ||
34 | |||
35 | class OContactPrivate; | ||
36 | |||
37 | /** | ||
38 | * OContact class represents a specialised PIM Record for contacts. | ||
39 | * It does store all kind of persopn related information. | ||
40 | * | ||
41 | * @short Contact Container | ||
42 | * @author TT, Stefan Eiler, Holger Freyther | ||
43 | */ | ||
44 | class QPC_EXPORT OContact : public OPimRecord | ||
45 | { | ||
46 | friend class DataSet; | ||
47 | public: | ||
48 | OContact(); | ||
49 | OContact( const QMap<int, QString> &fromMap ); | ||
50 | virtual ~OContact(); | ||
51 | |||
52 | enum DateFormat{ | ||
53 | Zip_City_State = 0, | ||
54 | City_State_Zip | ||
55 | }; | ||
56 | |||
57 | /* | ||
58 | * do we need to inline them | ||
59 | * if yes do we need to inline them this way? | ||
60 | * -zecke | ||
61 | */ | ||
62 | void setTitle( const QString &v ) { replace( Qtopia::Title, v ); } | ||
63 | void setFirstName( const QString &v ) { replace( Qtopia::FirstName, v ); } | ||
64 | void setMiddleName( const QString &v ) { replace( Qtopia::MiddleName, v ); } | ||
65 | void setLastName( const QString &v ) { replace( Qtopia::LastName, v ); } | ||
66 | void setSuffix( const QString &v ) { replace( Qtopia::Suffix, v ); } | ||
67 | void setFileAs( const QString &v ) { replace( Qtopia::FileAs, v ); } | ||
68 | void setFileAs(); | ||
69 | |||
70 | // default email address | ||
71 | void setDefaultEmail( const QString &v ); | ||
72 | // inserts email to list and ensure's doesn't already exist | ||
73 | void insertEmail( const QString &v ); | ||
74 | void removeEmail( const QString &v ); | ||
75 | void clearEmails(); | ||
76 | void insertEmails( const QStringList &v ); | ||
77 | |||
78 | // home | ||
79 | void setHomeStreet( const QString &v ) { replace( Qtopia::HomeStreet, v ); } | ||
80 | void setHomeCity( const QString &v ) { replace( Qtopia::HomeCity, v ); } | ||
81 | void setHomeState( const QString &v ) { replace( Qtopia::HomeState, v ); } | ||
82 | void setHomeZip( const QString &v ) { replace( Qtopia::HomeZip, v ); } | ||
83 | void setHomeCountry( const QString &v ) { replace( Qtopia::HomeCountry, v ); } | ||
84 | void setHomePhone( const QString &v ) { replace( Qtopia::HomePhone, v ); } | ||
85 | void setHomeFax( const QString &v ) { replace( Qtopia::HomeFax, v ); } | ||
86 | void setHomeMobile( const QString &v ) { replace( Qtopia::HomeMobile, v ); } | ||
87 | void setHomeWebpage( const QString &v ) { replace( Qtopia::HomeWebPage, v ); } | ||
88 | |||
89 | // business | ||
90 | void setCompany( const QString &v ) { replace( Qtopia::Company, v ); } | ||
91 | void setBusinessStreet( const QString &v ) { replace( Qtopia::BusinessStreet, v ); } | ||
92 | void setBusinessCity( const QString &v ) { replace( Qtopia::BusinessCity, v ); } | ||
93 | void setBusinessState( const QString &v ) { replace( Qtopia::BusinessState, v ); } | ||
94 | void setBusinessZip( const QString &v ) { replace( Qtopia::BusinessZip, v ); } | ||
95 | void setBusinessCountry( const QString &v ) { replace( Qtopia::BusinessCountry, v ); } | ||
96 | void setBusinessWebpage( const QString &v ) { replace( Qtopia::BusinessWebPage, v ); } | ||
97 | void setJobTitle( const QString &v ) { replace( Qtopia::JobTitle, v ); } | ||
98 | void setDepartment( const QString &v ) { replace( Qtopia::Department, v ); } | ||
99 | void setOffice( const QString &v ) { replace( Qtopia::Office, v ); } | ||
100 | void setBusinessPhone( const QString &v ) { replace( Qtopia::BusinessPhone, v ); } | ||
101 | void setBusinessFax( const QString &v ) { replace( Qtopia::BusinessFax, v ); } | ||
102 | void setBusinessMobile( const QString &v ) { replace( Qtopia::BusinessMobile, v ); } | ||
103 | void setBusinessPager( const QString &v ) { replace( Qtopia::BusinessPager, v ); } | ||
104 | void setProfession( const QString &v ) { replace( Qtopia::Profession, v ); } | ||
105 | void setAssistant( const QString &v ) { replace( Qtopia::Assistant, v ); } | ||
106 | void setManager( const QString &v ) { replace( Qtopia::Manager, v ); } | ||
107 | |||
108 | // personal | ||
109 | void setSpouse( const QString &v ) { replace( Qtopia::Spouse, v ); } | ||
110 | void setGender( const QString &v ) { replace( Qtopia::Gender, v ); } | ||
111 | void setBirthday( const QDate &v ); | ||
112 | void setAnniversary( const QDate &v ); | ||
113 | void setNickname( const QString &v ) { replace( Qtopia::Nickname, v ); } | ||
114 | void setChildren( const QString &v ); | ||
115 | |||
116 | // other | ||
117 | void setNotes( const QString &v ) { replace( Qtopia::Notes, v); } | ||
118 | |||
119 | virtual bool match( const QRegExp ®exp ) const; | ||
120 | |||
121 | // // custom | ||
122 | // void setCustomField( const QString &key, const QString &v ) | ||
123 | // { replace(Custom- + key, v ); } | ||
124 | |||
125 | // name | ||
126 | QString fullName() const; | ||
127 | QString title() const { return find( Qtopia::Title ); } | ||
128 | QString firstName() const { return find( Qtopia::FirstName ); } | ||
129 | QString middleName() const { return find( Qtopia::MiddleName ); } | ||
130 | QString lastName() const { return find( Qtopia::LastName ); } | ||
131 | QString suffix() const { return find( Qtopia::Suffix ); } | ||
132 | QString fileAs() const { return find( Qtopia::FileAs ); } | ||
133 | |||
134 | |||
135 | QString defaultEmail() const { return find( Qtopia::DefaultEmail ); } | ||
136 | QStringList emailList() const; | ||
137 | |||
138 | // home | ||
139 | /* | ||
140 | * OPimAddress address(enum Location)const; | ||
141 | * would be some how nicer... | ||
142 | * -zecke | ||
143 | */ | ||
144 | QString homeStreet() const { return find( Qtopia::HomeStreet ); } | ||
145 | QString homeCity() const { return find( Qtopia::HomeCity ); } | ||
146 | QString homeState() const { return find( Qtopia::HomeState ); } | ||
147 | QString homeZip() const { return find( Qtopia::HomeZip ); } | ||
148 | QString homeCountry() const { return find( Qtopia::HomeCountry ); } | ||
149 | QString homePhone() const { return find( Qtopia::HomePhone ); } | ||
150 | QString homeFax() const { return find( Qtopia::HomeFax ); } | ||
151 | QString homeMobile() const { return find( Qtopia::HomeMobile ); } | ||
152 | QString homeWebpage() const { return find( Qtopia::HomeWebPage ); } | ||
153 | /** Multi line string containing all non-empty address info in the form | ||
154 | * Street | ||
155 | * City, State Zip | ||
156 | * Country | ||
157 | */ | ||
158 | QString displayHomeAddress() const; | ||
159 | |||
160 | // business | ||
161 | QString company() const { return find( Qtopia::Company ); } | ||
162 | QString businessStreet() const { return find( Qtopia::BusinessStreet ); } | ||
163 | QString businessCity() const { return find( Qtopia::BusinessCity ); } | ||
164 | QString businessState() const { return find( Qtopia::BusinessState ); } | ||
165 | QString businessZip() const { return find( Qtopia::BusinessZip ); } | ||
166 | QString businessCountry() const { return find( Qtopia::BusinessCountry ); } | ||
167 | QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); } | ||
168 | QString jobTitle() const { return find( Qtopia::JobTitle ); } | ||
169 | QString department() const { return find( Qtopia::Department ); } | ||
170 | QString office() const { return find( Qtopia::Office ); } | ||
171 | QString businessPhone() const { return find( Qtopia::BusinessPhone ); } | ||
172 | QString businessFax() const { return find( Qtopia::BusinessFax ); } | ||
173 | QString businessMobile() const { return find( Qtopia::BusinessMobile ); } | ||
174 | QString businessPager() const { return find( Qtopia::BusinessPager ); } | ||
175 | QString profession() const { return find( Qtopia::Profession ); } | ||
176 | QString assistant() const { return find( Qtopia::Assistant ); } | ||
177 | QString manager() const { return find( Qtopia::Manager ); } | ||
178 | /** Multi line string containing all non-empty address info in the form | ||
179 | * Street | ||
180 | * City, State Zip | ||
181 | * Country | ||
182 | */ | ||
183 | QString displayBusinessAddress() const; | ||
184 | |||
185 | //personal | ||
186 | QString spouse() const { return find( Qtopia::Spouse ); } | ||
187 | QString gender() const { return find( Qtopia::Gender ); } | ||
188 | QDate birthday() const; | ||
189 | QDate anniversary() const; | ||
190 | QString nickname() const { return find( Qtopia::Nickname ); } | ||
191 | QString children() const { return find( Qtopia::Children ); } | ||
192 | QStringList childrenList() const; | ||
193 | |||
194 | // other | ||
195 | QString notes() const { return find( Qtopia::Notes ); } | ||
196 | QString groups() const { return find( Qtopia::Groups ); } | ||
197 | QStringList groupList() const; | ||
198 | |||
199 | QString toRichText() const; | ||
200 | QMap<int, QString> toMap() const; | ||
201 | QString field( int key ) const { return find( key ); } | ||
202 | |||
203 | |||
204 | void setUid( int i ); | ||
205 | |||
206 | QString toShortText()const; | ||
207 | QString type()const; | ||
208 | class QString recordField(int) const; | ||
209 | |||
210 | // Why private ? (eilers,se) | ||
211 | QString emailSeparator() const { return " "; } | ||
212 | |||
213 | // the emails should be seperated by a comma | ||
214 | void setEmails( const QString &v ); | ||
215 | QString emails() const { return find( Qtopia::Emails ); } | ||
216 | static int rtti(); | ||
217 | |||
218 | private: | ||
219 | // The XML Backend needs some access to the private functions | ||
220 | friend class OContactAccessBackend_XML; | ||
221 | |||
222 | void insert( int key, const QString &value ); | ||
223 | void replace( int key, const QString &value ); | ||
224 | QString find( int key ) const; | ||
225 | static QStringList fields(); | ||
226 | |||
227 | void save( QString &buf ) const; | ||
228 | |||
229 | QString displayAddress( const QString &street, | ||
230 | const QString &city, | ||
231 | const QString &state, | ||
232 | const QString &zip, | ||
233 | const QString &country ) const; | ||
234 | |||
235 | QMap<int, QString> mMap; | ||
236 | OContactPrivate *d; | ||
237 | }; | ||
238 | |||
239 | |||
240 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccess.cpp b/noncore/unsupported/libopie/pim/ocontactaccess.cpp new file mode 100644 index 0000000..63b93ee --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccess.cpp | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Class to manage the Contacts. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * Info: This class could just work with a change in the header-file | ||
13 | * of the Contact class ! Therefore our libopie only compiles | ||
14 | * with our version of libqpe | ||
15 | * ===================================================================== | ||
16 | * ToDo: XML-Backend: Automatic reload if something was changed... | ||
17 | * | ||
18 | * | ||
19 | * ===================================================================== | ||
20 | * Version: $Id$ | ||
21 | * ===================================================================== | ||
22 | * History: | ||
23 | * $Log$ | ||
24 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
25 | * libopie1 goes into unsupported | ||
26 | * | ||
27 | * Revision 1.9 2004/03/02 12:14:22 alwin | ||
28 | * run the optimize_connect script | ||
29 | * the whole cvs is tagged with "before_optimize_connect" if there are problems you | ||
30 | * can check the diff (but it had compiled and run here) | ||
31 | * | ||
32 | * Revision 1.8 2003/05/08 13:55:09 tille | ||
33 | * search stuff | ||
34 | * and match, toRichText & toShortText in oevent | ||
35 | * | ||
36 | * Revision 1.7 2002/11/13 14:14:51 eilers | ||
37 | * Added sorted for Contacts.. | ||
38 | * | ||
39 | * Revision 1.6 2002/11/01 15:10:42 eilers | ||
40 | * Added regExp-search in database for all fields in a contact. | ||
41 | * | ||
42 | * Revision 1.5 2002/10/16 10:52:40 eilers | ||
43 | * Added some docu to the interface and now using the cache infrastucture by zecke.. :) | ||
44 | * | ||
45 | * Revision 1.4 2002/10/14 16:21:54 eilers | ||
46 | * Some minor interface updates | ||
47 | * | ||
48 | * Revision 1.3 2002/10/07 17:34:24 eilers | ||
49 | * added OBackendFactory for advanced backend access | ||
50 | * | ||
51 | * Revision 1.2 2002/10/02 16:18:11 eilers | ||
52 | * debugged and seems to work almost perfectly .. | ||
53 | * | ||
54 | * Revision 1.1 2002/09/27 17:11:44 eilers | ||
55 | * Added API for accessing the Contact-Database ! It is compiling, but | ||
56 | * please do not expect that anything is working ! | ||
57 | * I will debug that stuff in the next time .. | ||
58 | * Please read README_COMPILE for compiling ! | ||
59 | * | ||
60 | * | ||
61 | */ | ||
62 | |||
63 | #include "ocontactaccess.h" | ||
64 | #include "obackendfactory.h" | ||
65 | |||
66 | #include <qasciidict.h> | ||
67 | #include <qdatetime.h> | ||
68 | #include <qfile.h> | ||
69 | #include <qregexp.h> | ||
70 | #include <qlist.h> | ||
71 | #include <qcopchannel_qws.h> | ||
72 | |||
73 | //#include <qpe/qcopenvelope_qws.h> | ||
74 | #include <qpe/global.h> | ||
75 | |||
76 | #include <errno.h> | ||
77 | #include <fcntl.h> | ||
78 | #include <unistd.h> | ||
79 | #include <stdlib.h> | ||
80 | |||
81 | #include "ocontactaccessbackend_xml.h" | ||
82 | |||
83 | |||
84 | OContactAccess::OContactAccess ( const QString appname, const QString , | ||
85 | OContactAccessBackend* end, bool autosync ): | ||
86 | OPimAccessTemplate<OContact>( end ) | ||
87 | { | ||
88 | /* take care of the backend. If there is no one defined, we | ||
89 | * will use the XML-Backend as default (until we have a cute SQL-Backend..). | ||
90 | */ | ||
91 | if( end == 0 ) { | ||
92 | qWarning ("Using BackendFactory !"); | ||
93 | end = OBackendFactory<OContactAccessBackend>::Default( "contact", appname ); | ||
94 | } | ||
95 | // Set backend locally and in template | ||
96 | m_backEnd = end; | ||
97 | OPimAccessTemplate<OContact>::setBackEnd (end); | ||
98 | |||
99 | |||
100 | /* Connect signal of external db change to function */ | ||
101 | QCopChannel *dbchannel = new QCopChannel( "QPE/PIM", this ); | ||
102 | connect( dbchannel, SIGNAL(received(const QCString&,const QByteArray&)), | ||
103 | this, SLOT(copMessage(const QCString&,const QByteArray&)) ); | ||
104 | if ( autosync ){ | ||
105 | QCopChannel *syncchannel = new QCopChannel( "QPE/Sync", this ); | ||
106 | connect( syncchannel, SIGNAL(received(const QCString&,const QByteArray&)), | ||
107 | this, SLOT(copMessage(const QCString&,const QByteArray&)) ); | ||
108 | } | ||
109 | |||
110 | |||
111 | } | ||
112 | OContactAccess::~OContactAccess () | ||
113 | { | ||
114 | /* The user may forget to save the changed database, therefore try to | ||
115 | * do it for him.. | ||
116 | */ | ||
117 | save(); | ||
118 | // delete m_backEnd; is done by template.. | ||
119 | } | ||
120 | |||
121 | |||
122 | bool OContactAccess::save () | ||
123 | { | ||
124 | /* If the database was changed externally, we could not save the | ||
125 | * Data. This will remove added items which is unacceptable ! | ||
126 | * Therefore: Reload database and merge the data... | ||
127 | */ | ||
128 | if ( OPimAccessTemplate<OContact>::wasChangedExternally() ) | ||
129 | reload(); | ||
130 | |||
131 | bool status = OPimAccessTemplate<OContact>::save(); | ||
132 | if ( !status ) return false; | ||
133 | |||
134 | /* Now tell everyone that new data is available. | ||
135 | */ | ||
136 | QCopEnvelope e( "QPE/PIM", "addressbookUpdated()" ); | ||
137 | |||
138 | return true; | ||
139 | } | ||
140 | |||
141 | const uint OContactAccess::querySettings() | ||
142 | { | ||
143 | return ( m_backEnd->querySettings() ); | ||
144 | } | ||
145 | |||
146 | bool OContactAccess::hasQuerySettings ( int querySettings ) const | ||
147 | { | ||
148 | return ( m_backEnd->hasQuerySettings ( querySettings ) ); | ||
149 | } | ||
150 | ORecordList<OContact> OContactAccess::sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const | ||
151 | { | ||
152 | QArray<int> matchingContacts = m_backEnd -> sorted( ascending, sortOrder, sortFilter, cat ); | ||
153 | return ( ORecordList<OContact>(matchingContacts, this) ); | ||
154 | } | ||
155 | |||
156 | |||
157 | bool OContactAccess::wasChangedExternally()const | ||
158 | { | ||
159 | return ( m_backEnd->wasChangedExternally() ); | ||
160 | } | ||
161 | |||
162 | |||
163 | void OContactAccess::copMessage( const QCString &msg, const QByteArray & ) | ||
164 | { | ||
165 | if ( msg == "addressbookUpdated()" ){ | ||
166 | qWarning ("OContactAccess: Received addressbokUpdated()"); | ||
167 | emit signalChanged ( this ); | ||
168 | } else if ( msg == "flush()" ) { | ||
169 | qWarning ("OContactAccess: Received flush()"); | ||
170 | save (); | ||
171 | } else if ( msg == "reload()" ) { | ||
172 | qWarning ("OContactAccess: Received reload()"); | ||
173 | reload (); | ||
174 | emit signalChanged ( this ); | ||
175 | } | ||
176 | } | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccess.h b/noncore/unsupported/libopie/pim/ocontactaccess.h new file mode 100644 index 0000000..a7a099f --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccess.h | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Class to manage the Contacts. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) | ||
6 | * | ||
7 | * ===================================================================== | ||
8 | *This program is free software; you can redistribute it and/or | ||
9 | *modify it under the terms of the GNU Library General Public | ||
10 | * License as published by the Free Software Foundation; | ||
11 | * either version 2 of the License, or (at your option) any later | ||
12 | * version. | ||
13 | * ===================================================================== | ||
14 | * ToDo: Define enum for query settings | ||
15 | * ===================================================================== | ||
16 | * Version: $Id$ | ||
17 | * ===================================================================== | ||
18 | * History: | ||
19 | * $Log$ | ||
20 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
21 | * libopie1 goes into unsupported | ||
22 | * | ||
23 | * Revision 1.10 2003/12/22 10:19:26 eilers | ||
24 | * Finishing implementation of sql-backend for datebook. But I have to | ||
25 | * port the PIM datebook application to use it, before I could debug the | ||
26 | * whole stuff. | ||
27 | * Thus, PIM-Database backend is finished, but highly experimental. And some | ||
28 | * parts are still generic. For instance, the "queryByExample()" methods are | ||
29 | * not (or not fully) implemented. Todo: custom-entries not stored. | ||
30 | * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular | ||
31 | * expression search in the database, which is not supported by sqlite ! | ||
32 | * Therefore we need either an extended sqlite or a workaround which would | ||
33 | * be very slow and memory consuming.. | ||
34 | * | ||
35 | * Revision 1.9 2003/08/01 12:30:16 eilers | ||
36 | * Merging changes from BRANCH_1_0 to HEAD | ||
37 | * | ||
38 | * Revision 1.8.2.1 2003/06/30 14:34:19 eilers | ||
39 | * Patches from Zecke: | ||
40 | * Fixing and cleaning up extraMap handling | ||
41 | * Adding d_ptr for binary compatibility in the future | ||
42 | * | ||
43 | * Revision 1.8 2003/05/08 13:55:09 tille | ||
44 | * search stuff | ||
45 | * and match, toRichText & toShortText in oevent | ||
46 | * | ||
47 | * Revision 1.7 2003/04/13 18:07:10 zecke | ||
48 | * More API doc | ||
49 | * QString -> const QString& | ||
50 | * QString = 0l -> QString::null | ||
51 | * | ||
52 | * Revision 1.6 2003/01/02 14:27:12 eilers | ||
53 | * Improved query by example: Search by date is possible.. First step | ||
54 | * for a today plugin for birthdays.. | ||
55 | * | ||
56 | * Revision 1.5 2002/11/13 14:14:51 eilers | ||
57 | * Added sorted for Contacts.. | ||
58 | * | ||
59 | * Revision 1.4 2002/11/01 15:10:42 eilers | ||
60 | * Added regExp-search in database for all fields in a contact. | ||
61 | * | ||
62 | * Revision 1.3 2002/10/16 10:52:40 eilers | ||
63 | * Added some docu to the interface and now using the cache infrastucture by zecke.. :) | ||
64 | * | ||
65 | * Revision 1.2 2002/10/14 16:21:54 eilers | ||
66 | * Some minor interface updates | ||
67 | * | ||
68 | * Revision 1.1 2002/09/27 17:11:44 eilers | ||
69 | * Added API for accessing the Contact-Database ! It is compiling, but | ||
70 | * please do not expect that anything is working ! | ||
71 | * I will debug that stuff in the next time .. | ||
72 | * Please read README_COMPILE for compiling ! | ||
73 | * | ||
74 | * ===================================================================== | ||
75 | */ | ||
76 | #ifndef _OCONTACTACCESS_H | ||
77 | #define _OCONTACTACCESS_H | ||
78 | |||
79 | #include <qobject.h> | ||
80 | |||
81 | #include <qpe/qcopenvelope_qws.h> | ||
82 | |||
83 | #include <qvaluelist.h> | ||
84 | #include <qfileinfo.h> | ||
85 | |||
86 | #include "ocontact.h" | ||
87 | #include "ocontactaccessbackend.h" | ||
88 | #include "opimaccesstemplate.h" | ||
89 | |||
90 | /** | ||
91 | * Class to access the contacts database. | ||
92 | * This is just a frontend for the real database handling which is | ||
93 | * done by the backend. | ||
94 | * This class is used to access the Contacts on a system. This class as any OPIE PIM | ||
95 | * class is backend independent. | ||
96 | * @author Stefan Eilers, Holger Freyther | ||
97 | * @see OPimAccessTemplate | ||
98 | */ | ||
99 | class OContactAccess: public QObject, public OPimAccessTemplate<OContact> | ||
100 | { | ||
101 | Q_OBJECT | ||
102 | |||
103 | public: | ||
104 | /** | ||
105 | * Create Database with contacts (addressbook). | ||
106 | * @param appname Name of application which wants access to the database | ||
107 | * (i.e. "todolist") | ||
108 | * @param filename The name of the database file. If not set, the default one | ||
109 | * is used. | ||
110 | * @param backend Pointer to an alternative Backend. If not set, we will use | ||
111 | * the default backend. | ||
112 | * @param handlesync If <b>true</b> the database stores the current state | ||
113 | * automatically if it receives the signals <i>flush()</i> and <i>reload()</i> | ||
114 | * which are used before and after synchronisation. If the application wants | ||
115 | * to react itself, it should be disabled by setting it to <b>false</b> | ||
116 | * @see OContactAccessBackend | ||
117 | */ | ||
118 | OContactAccess (const QString appname, const QString filename = 0l, | ||
119 | OContactAccessBackend* backend = 0l, bool handlesync = true); | ||
120 | ~OContactAccess (); | ||
121 | |||
122 | /** Constants for query. | ||
123 | * Use this constants to set the query parameters. | ||
124 | * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes ! | ||
125 | * @see queryByExample() | ||
126 | */ | ||
127 | enum QuerySettings { | ||
128 | WildCards = 0x0001, | ||
129 | IgnoreCase = 0x0002, | ||
130 | RegExp = 0x0004, | ||
131 | ExactMatch = 0x0008, | ||
132 | MatchOne = 0x0010, // Only one Entry must match | ||
133 | DateDiff = 0x0020, // Find all entries from today until given date | ||
134 | DateYear = 0x0040, // The year matches | ||
135 | DateMonth = 0x0080, // The month matches | ||
136 | DateDay = 0x0100, // The day matches | ||
137 | }; | ||
138 | |||
139 | |||
140 | /** Return all Contacts in a sorted manner. | ||
141 | * @param ascending true: Sorted in acending order. | ||
142 | * @param sortOrder Currently not implemented. Just defined to stay compatible to otodoaccess | ||
143 | * @param sortFilter Currently not implemented. Just defined to stay compatible to otodoaccess | ||
144 | * @param cat Currently not implemented. Just defined to stay compatible to otodoaccess | ||
145 | */ | ||
146 | List sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const; | ||
147 | |||
148 | /** Return all possible settings. | ||
149 | * @return All settings provided by the current backend | ||
150 | * (i.e.: query_WildCards & query_IgnoreCase) | ||
151 | */ | ||
152 | const uint querySettings(); | ||
153 | |||
154 | /** Check whether settings are correct. | ||
155 | * @return <i>true</i> if the given settings are correct and possible. | ||
156 | */ | ||
157 | bool hasQuerySettings ( int querySettings ) const; | ||
158 | |||
159 | /** | ||
160 | * if the resource was changed externally. | ||
161 | * You should use the signal instead of polling possible changes ! | ||
162 | */ | ||
163 | bool wasChangedExternally()const; | ||
164 | |||
165 | |||
166 | /** Save contacts database. | ||
167 | * Save is more a "commit". After calling this function, all changes are public available. | ||
168 | * @return true if successful | ||
169 | */ | ||
170 | bool save(); | ||
171 | |||
172 | signals: | ||
173 | /* Signal is emitted if the database was changed. Therefore | ||
174 | * we may need to reload to stay consistent. | ||
175 | * @param which Pointer to the database who created this event. This pointer | ||
176 | * is useful if an application has to handle multiple databases at the same time. | ||
177 | * @see reload() | ||
178 | */ | ||
179 | void signalChanged ( const OContactAccess *which ); | ||
180 | |||
181 | |||
182 | private: | ||
183 | // class OContactAccessPrivate; | ||
184 | // OContactAccessPrivate* d; | ||
185 | OContactAccessBackend *m_backEnd; | ||
186 | bool m_loading:1; | ||
187 | |||
188 | private slots: | ||
189 | void copMessage( const QCString &msg, const QByteArray &data ); | ||
190 | |||
191 | private: | ||
192 | class Private; | ||
193 | Private *d; | ||
194 | |||
195 | }; | ||
196 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend.h new file mode 100644 index 0000000..cfeeff2 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend.h | |||
@@ -0,0 +1,131 @@ | |||
1 | /** | ||
2 | * The class responsible for managing a backend. | ||
3 | * The implementation of this abstract class contains | ||
4 | * the complete database handling. | ||
5 | * | ||
6 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
7 | * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) | ||
8 | * | ||
9 | * ===================================================================== | ||
10 | *This program is free software; you can redistribute it and/or | ||
11 | *modify it under the terms of the GNU Library General Public | ||
12 | * License as published by the Free Software Foundation; | ||
13 | * either version 2 of the License, or (at your option) any later | ||
14 | * version. | ||
15 | * ===================================================================== | ||
16 | * ToDo: Define enum for query settings | ||
17 | * ===================================================================== | ||
18 | * Version: $Id$ | ||
19 | * ===================================================================== | ||
20 | * History: | ||
21 | * $Log$ | ||
22 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
23 | * libopie1 goes into unsupported | ||
24 | * | ||
25 | * Revision 1.7 2004/02/19 02:05:37 zecke | ||
26 | * Add notes for API fixes and BC stuff | ||
27 | * | ||
28 | * Revision 1.6 2003/08/01 12:30:16 eilers | ||
29 | * Merging changes from BRANCH_1_0 to HEAD | ||
30 | * | ||
31 | * Revision 1.5.4.1 2003/06/30 14:34:19 eilers | ||
32 | * Patches from Zecke: | ||
33 | * Fixing and cleaning up extraMap handling | ||
34 | * Adding d_ptr for binary compatibility in the future | ||
35 | * | ||
36 | * Revision 1.5 2003/04/13 18:07:10 zecke | ||
37 | * More API doc | ||
38 | * QString -> const QString& | ||
39 | * QString = 0l -> QString::null | ||
40 | * | ||
41 | * Revision 1.4 2002/11/13 14:14:51 eilers | ||
42 | * Added sorted for Contacts.. | ||
43 | * | ||
44 | * Revision 1.3 2002/11/01 15:10:42 eilers | ||
45 | * Added regExp-search in database for all fields in a contact. | ||
46 | * | ||
47 | * Revision 1.2 2002/10/07 17:34:24 eilers | ||
48 | * added OBackendFactory for advanced backend access | ||
49 | * | ||
50 | * Revision 1.1 2002/09/27 17:11:44 eilers | ||
51 | * Added API for accessing the Contact-Database ! It is compiling, but | ||
52 | * please do not expect that anything is working ! | ||
53 | * I will debug that stuff in the next time .. | ||
54 | * Please read README_COMPILE for compiling ! | ||
55 | * | ||
56 | * ===================================================================== | ||
57 | * | ||
58 | */ | ||
59 | |||
60 | #ifndef _OCONTACTACCESSBACKEND_H_ | ||
61 | #define _OCONTACTACCESSBACKEND_H_ | ||
62 | |||
63 | #include "ocontact.h" | ||
64 | #include "opimaccessbackend.h" | ||
65 | |||
66 | #include <qregexp.h> | ||
67 | |||
68 | /** | ||
69 | * This class represents the interface of all Contact Backends. | ||
70 | * Derivates of this class will be used to access the contacts. | ||
71 | * As implementation currently XML and vCard exist. This class needs to be implemented | ||
72 | * if you want to provide your own storage. | ||
73 | * In all queries a list of uids is passed on instead of loading the actual record! | ||
74 | * | ||
75 | * @see OContactAccessBackend_VCard | ||
76 | * @see OContactAccessBackend_XML | ||
77 | */ | ||
78 | class OContactAccessBackend: public OPimAccessBackend<OContact> { | ||
79 | public: | ||
80 | /** | ||
81 | * @todo make non line in regard to BC guide of KDE | ||
82 | */ | ||
83 | OContactAccessBackend() {} | ||
84 | /** | ||
85 | * @todo make non inline in regard to the BC guide of KDE | ||
86 | */ | ||
87 | virtual ~OContactAccessBackend() {} | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Return if database was changed externally. | ||
92 | * This may just make sense on file based databases like a XML-File. | ||
93 | * It is used to prevent to overwrite the current database content | ||
94 | * if the file was already changed by something else ! | ||
95 | * If this happens, we have to reload before save our data. | ||
96 | * If we use real databases, this should be handled by the database | ||
97 | * management system themselve, therefore this function should always return false in | ||
98 | * this case. It is not our problem to handle this conflict ... | ||
99 | * @return <i>true</i> if the database was changed and if save without reload will | ||
100 | * be dangerous. <i>false</i> if the database was not changed or it is save to write | ||
101 | * in this situation. | ||
102 | */ | ||
103 | virtual bool wasChangedExternally() = 0; | ||
104 | |||
105 | virtual QArray<int> matchRegexp( const QRegExp &r ) const = 0; | ||
106 | |||
107 | /** | ||
108 | * Return all possible settings. | ||
109 | * @return All settings provided by the current backend | ||
110 | * (i.e.: query_WildCards & query_IgnoreCase) | ||
111 | */ | ||
112 | virtual const uint querySettings() = 0; | ||
113 | |||
114 | /** | ||
115 | * Check whether settings are correct. | ||
116 | * @return <i>true</i> if the given settings are correct and possible. | ||
117 | */ | ||
118 | virtual bool hasQuerySettings (uint querySettings) const = 0; | ||
119 | |||
120 | /** | ||
121 | * FIXME!!! | ||
122 | * Returns a sorted list of records either ascendinf or descending for a giving criteria and category | ||
123 | */ | ||
124 | virtual QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ) = 0; | ||
125 | |||
126 | |||
127 | private: | ||
128 | class Private; | ||
129 | Private *d; | ||
130 | }; | ||
131 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.cpp b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.cpp new file mode 100644 index 0000000..669483d --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.cpp | |||
@@ -0,0 +1,948 @@ | |||
1 | /* | ||
2 | * SQL Backend for the OPIE-Contact Database. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * ===================================================================== | ||
13 | * Version: $Id$ | ||
14 | * ===================================================================== | ||
15 | * History: | ||
16 | * $Log$ | ||
17 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
18 | * libopie1 goes into unsupported | ||
19 | * | ||
20 | * Revision 1.5 2004/03/14 13:50:35 alwin | ||
21 | * namespace correction | ||
22 | * | ||
23 | * Revision 1.4 2003/12/22 10:19:26 eilers | ||
24 | * Finishing implementation of sql-backend for datebook. But I have to | ||
25 | * port the PIM datebook application to use it, before I could debug the | ||
26 | * whole stuff. | ||
27 | * Thus, PIM-Database backend is finished, but highly experimental. And some | ||
28 | * parts are still generic. For instance, the "queryByExample()" methods are | ||
29 | * not (or not fully) implemented. Todo: custom-entries not stored. | ||
30 | * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular | ||
31 | * expression search in the database, which is not supported by sqlite ! | ||
32 | * Therefore we need either an extended sqlite or a workaround which would | ||
33 | * be very slow and memory consuming.. | ||
34 | * | ||
35 | * Revision 1.3 2003/12/08 15:18:10 eilers | ||
36 | * Committing unfinished sql implementation before merging to libopie2 starts.. | ||
37 | * | ||
38 | * Revision 1.2 2003/09/29 07:44:26 eilers | ||
39 | * Improvement of PIM-SQL Databases, but search queries are still limited. | ||
40 | * Addressbook: Changed table layout. Now, we just need 1/3 of disk-space. | ||
41 | * Todo: Started to add new attributes. Some type conversions missing. | ||
42 | * | ||
43 | * Revision 1.1 2003/09/22 14:31:16 eilers | ||
44 | * Added first experimental incarnation of sql-backend for addressbook. | ||
45 | * Some modifications to be able to compile the todo sql-backend. | ||
46 | * A lot of changes fill follow... | ||
47 | * | ||
48 | */ | ||
49 | |||
50 | #include "ocontactaccessbackend_sql.h" | ||
51 | |||
52 | #include <qarray.h> | ||
53 | #include <qdatetime.h> | ||
54 | #include <qstringlist.h> | ||
55 | |||
56 | #include <qpe/global.h> | ||
57 | #include <qpe/recordfields.h> | ||
58 | |||
59 | #include <opie/ocontactfields.h> | ||
60 | #include <opie/oconversion.h> | ||
61 | #include <opie2/osqldriver.h> | ||
62 | #include <opie2/osqlresult.h> | ||
63 | #include <opie2/osqlmanager.h> | ||
64 | #include <opie2/osqlquery.h> | ||
65 | |||
66 | using namespace Opie::DB; | ||
67 | |||
68 | |||
69 | // If defined, we use a horizontal table ( uid, attr1, attr2, attr3, ..., attrn ) instead | ||
70 | // vertical like "uid, type, value". | ||
71 | // DON'T DEACTIVATE THIS DEFINE IN PRODUCTIVE ENVIRONMENTS !! | ||
72 | #define __STORE_HORIZONTAL_ | ||
73 | |||
74 | // Distinct loading is not very fast. If I expect that every person has just | ||
75 | // one (and always one) 'Last Name', I can request all uid's for existing lastnames, | ||
76 | // which is faster.. | ||
77 | // But this may not be true for all entries, like company contacts.. | ||
78 | // The current AddressBook application handles this problem, but other may not.. (eilers) | ||
79 | #define __USE_SUPERFAST_LOADQUERY | ||
80 | |||
81 | |||
82 | /* | ||
83 | * Implementation of used query types | ||
84 | * CREATE query | ||
85 | * LOAD query | ||
86 | * INSERT | ||
87 | * REMOVE | ||
88 | * CLEAR | ||
89 | */ | ||
90 | namespace { | ||
91 | /** | ||
92 | * CreateQuery for the Todolist Table | ||
93 | */ | ||
94 | class CreateQuery : public OSQLQuery { | ||
95 | public: | ||
96 | CreateQuery(); | ||
97 | ~CreateQuery(); | ||
98 | QString query()const; | ||
99 | }; | ||
100 | |||
101 | /** | ||
102 | * Clears (delete) a Table | ||
103 | */ | ||
104 | class ClearQuery : public OSQLQuery { | ||
105 | public: | ||
106 | ClearQuery(); | ||
107 | ~ClearQuery(); | ||
108 | QString query()const; | ||
109 | |||
110 | }; | ||
111 | |||
112 | |||
113 | /** | ||
114 | * LoadQuery | ||
115 | * this one queries for all uids | ||
116 | */ | ||
117 | class LoadQuery : public OSQLQuery { | ||
118 | public: | ||
119 | LoadQuery(); | ||
120 | ~LoadQuery(); | ||
121 | QString query()const; | ||
122 | }; | ||
123 | |||
124 | /** | ||
125 | * inserts/adds a OContact to the table | ||
126 | */ | ||
127 | class InsertQuery : public OSQLQuery { | ||
128 | public: | ||
129 | InsertQuery(const OContact& ); | ||
130 | ~InsertQuery(); | ||
131 | QString query()const; | ||
132 | private: | ||
133 | OContact m_contact; | ||
134 | }; | ||
135 | |||
136 | |||
137 | /** | ||
138 | * removes one from the table | ||
139 | */ | ||
140 | class RemoveQuery : public OSQLQuery { | ||
141 | public: | ||
142 | RemoveQuery(int uid ); | ||
143 | ~RemoveQuery(); | ||
144 | QString query()const; | ||
145 | private: | ||
146 | int m_uid; | ||
147 | }; | ||
148 | |||
149 | /** | ||
150 | * a find query for noncustom elements | ||
151 | */ | ||
152 | class FindQuery : public OSQLQuery { | ||
153 | public: | ||
154 | FindQuery(int uid); | ||
155 | FindQuery(const QArray<int>& ); | ||
156 | ~FindQuery(); | ||
157 | QString query()const; | ||
158 | private: | ||
159 | QString single()const; | ||
160 | QString multi()const; | ||
161 | QArray<int> m_uids; | ||
162 | int m_uid; | ||
163 | }; | ||
164 | |||
165 | /** | ||
166 | * a find query for custom elements | ||
167 | */ | ||
168 | class FindCustomQuery : public OSQLQuery { | ||
169 | public: | ||
170 | FindCustomQuery(int uid); | ||
171 | FindCustomQuery(const QArray<int>& ); | ||
172 | ~FindCustomQuery(); | ||
173 | QString query()const; | ||
174 | private: | ||
175 | QString single()const; | ||
176 | QString multi()const; | ||
177 | QArray<int> m_uids; | ||
178 | int m_uid; | ||
179 | }; | ||
180 | |||
181 | |||
182 | |||
183 | // We using three tables to store the information: | ||
184 | // 1. addressbook : It contains General information about the contact (non custom) | ||
185 | // 2. custom_data : Not official supported entries | ||
186 | // All tables are connected by the uid of the contact. | ||
187 | // Maybe I should add a table for meta-information ? | ||
188 | CreateQuery::CreateQuery() : OSQLQuery() {} | ||
189 | CreateQuery::~CreateQuery() {} | ||
190 | QString CreateQuery::query()const { | ||
191 | QString qu; | ||
192 | #ifdef __STORE_HORIZONTAL_ | ||
193 | |||
194 | qu += "create table addressbook( uid PRIMARY KEY "; | ||
195 | |||
196 | QStringList fieldList = OContactFields::untrfields( false ); | ||
197 | for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ | ||
198 | qu += QString( ",\"%1\" VARCHAR(10)" ).arg( *it ); | ||
199 | } | ||
200 | qu += " );"; | ||
201 | |||
202 | qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; | ||
203 | |||
204 | #else | ||
205 | |||
206 | qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));"; | ||
207 | qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; | ||
208 | // qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );"; | ||
209 | |||
210 | #endif // __STORE_HORIZONTAL_ | ||
211 | return qu; | ||
212 | } | ||
213 | |||
214 | ClearQuery::ClearQuery() | ||
215 | : OSQLQuery() {} | ||
216 | ClearQuery::~ClearQuery() {} | ||
217 | QString ClearQuery::query()const { | ||
218 | QString qu = "drop table addressbook;"; | ||
219 | qu += "drop table custom_data;"; | ||
220 | // qu += "drop table dates;"; | ||
221 | return qu; | ||
222 | } | ||
223 | |||
224 | |||
225 | LoadQuery::LoadQuery() : OSQLQuery() {} | ||
226 | LoadQuery::~LoadQuery() {} | ||
227 | QString LoadQuery::query()const { | ||
228 | QString qu; | ||
229 | #ifdef __STORE_HORIZONTAL_ | ||
230 | qu += "select uid from addressbook"; | ||
231 | #else | ||
232 | # ifndef __USE_SUPERFAST_LOADQUERY | ||
233 | qu += "select distinct uid from addressbook"; | ||
234 | # else | ||
235 | qu += "select uid from addressbook where type = 'Last Name'"; | ||
236 | # endif // __USE_SUPERFAST_LOADQUERY | ||
237 | #endif // __STORE_HORIZONTAL_ | ||
238 | |||
239 | return qu; | ||
240 | } | ||
241 | |||
242 | |||
243 | InsertQuery::InsertQuery( const OContact& contact ) | ||
244 | : OSQLQuery(), m_contact( contact ) { | ||
245 | } | ||
246 | |||
247 | InsertQuery::~InsertQuery() { | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * converts from a OContact to a query | ||
252 | */ | ||
253 | QString InsertQuery::query()const{ | ||
254 | |||
255 | #ifdef __STORE_HORIZONTAL_ | ||
256 | QString qu; | ||
257 | qu += "insert into addressbook VALUES( " + | ||
258 | QString::number( m_contact.uid() ); | ||
259 | |||
260 | // Get all information out of the contact-class | ||
261 | // Remember: The category is stored in contactMap, too ! | ||
262 | QMap<int, QString> contactMap = m_contact.toMap(); | ||
263 | |||
264 | QStringList fieldList = OContactFields::untrfields( false ); | ||
265 | QMap<QString, int> translate = OContactFields::untrFieldsToId(); | ||
266 | for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ | ||
267 | // Convert Column-String to Id and get value for this id.. | ||
268 | // Hmmm.. Maybe not very cute solution.. | ||
269 | int id = translate[*it]; | ||
270 | switch ( id ){ | ||
271 | case Qtopia::Birthday:{ | ||
272 | // These entries should stored in a special format | ||
273 | // year-month-day | ||
274 | QDate day = m_contact.birthday(); | ||
275 | if ( day.isValid() ){ | ||
276 | qu += QString(",\"%1-%2-%3\"") | ||
277 | .arg( day.year() ) | ||
278 | .arg( day.month() ) | ||
279 | .arg( day.day() ); | ||
280 | } else { | ||
281 | qu += ",\"\""; | ||
282 | } | ||
283 | } | ||
284 | break; | ||
285 | case Qtopia::Anniversary:{ | ||
286 | // These entries should stored in a special format | ||
287 | // year-month-day | ||
288 | QDate day = m_contact.anniversary(); | ||
289 | if ( day.isValid() ){ | ||
290 | qu += QString(",\"%1-%2-%3\"") | ||
291 | .arg( day.year() ) | ||
292 | .arg( day.month() ) | ||
293 | .arg( day.day() ); | ||
294 | } else { | ||
295 | qu += ",\"\""; | ||
296 | } | ||
297 | } | ||
298 | break; | ||
299 | |||
300 | default: | ||
301 | qu += QString( ",\"%1\"" ).arg( contactMap[id] ); | ||
302 | } | ||
303 | } | ||
304 | qu += " );"; | ||
305 | |||
306 | |||
307 | #else | ||
308 | // Get all information out of the contact-class | ||
309 | // Remember: The category is stored in contactMap, too ! | ||
310 | QMap<int, QString> contactMap = m_contact.toMap(); | ||
311 | |||
312 | QMap<QString, QString> addressbook_db; | ||
313 | |||
314 | // Get the translation from the ID to the String | ||
315 | QMap<int, QString> transMap = OContactFields::idToUntrFields(); | ||
316 | |||
317 | for( QMap<int, QString>::Iterator it = contactMap.begin(); | ||
318 | it != contactMap.end(); ++it ){ | ||
319 | switch ( it.key() ){ | ||
320 | case Qtopia::Birthday:{ | ||
321 | // These entries should stored in a special format | ||
322 | // year-month-day | ||
323 | QDate day = m_contact.birthday(); | ||
324 | addressbook_db.insert( transMap[it.key()], | ||
325 | QString("%1-%2-%3") | ||
326 | .arg( day.year() ) | ||
327 | .arg( day.month() ) | ||
328 | .arg( day.day() ) ); | ||
329 | } | ||
330 | break; | ||
331 | case Qtopia::Anniversary:{ | ||
332 | // These entries should stored in a special format | ||
333 | // year-month-day | ||
334 | QDate day = m_contact.anniversary(); | ||
335 | addressbook_db.insert( transMap[it.key()], | ||
336 | QString("%1-%2-%3") | ||
337 | .arg( day.year() ) | ||
338 | .arg( day.month() ) | ||
339 | .arg( day.day() ) ); | ||
340 | } | ||
341 | break; | ||
342 | case Qtopia::AddressUid: // Ignore UID | ||
343 | break; | ||
344 | default: // Translate id to String | ||
345 | addressbook_db.insert( transMap[it.key()], it.data() ); | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | } | ||
350 | |||
351 | // Now convert this whole stuff into a SQL String, beginning with | ||
352 | // the addressbook table.. | ||
353 | QString qu; | ||
354 | // qu += "begin transaction;"; | ||
355 | int id = 0; | ||
356 | for( QMap<QString, QString>::Iterator it = addressbook_db.begin(); | ||
357 | it != addressbook_db.end(); ++it ){ | ||
358 | qu += "insert into addressbook VALUES(" | ||
359 | + QString::number( m_contact.uid() ) | ||
360 | + "," | ||
361 | + QString::number( id++ ) | ||
362 | + ",'" | ||
363 | + it.key() //.latin1() | ||
364 | + "'," | ||
365 | + "0" // Priority for future enhancements | ||
366 | + ",'" | ||
367 | + it.data() //.latin1() | ||
368 | + "');"; | ||
369 | } | ||
370 | |||
371 | #endif //__STORE_HORIZONTAL_ | ||
372 | // Now add custom data.. | ||
373 | #ifdef __STORE_HORIZONTAL_ | ||
374 | int id = 0; | ||
375 | #endif | ||
376 | id = 0; | ||
377 | QMap<QString, QString> customMap = m_contact.toExtraMap(); | ||
378 | for( QMap<QString, QString>::Iterator it = customMap.begin(); | ||
379 | it != customMap.end(); ++it ){ | ||
380 | qu += "insert into custom_data VALUES(" | ||
381 | + QString::number( m_contact.uid() ) | ||
382 | + "," | ||
383 | + QString::number( id++ ) | ||
384 | + ",'" | ||
385 | + it.key() //.latin1() | ||
386 | + "'," | ||
387 | + "0" // Priority for future enhancements | ||
388 | + ",'" | ||
389 | + it.data() //.latin1() | ||
390 | + "');"; | ||
391 | } | ||
392 | // qu += "commit;"; | ||
393 | qWarning("add %s", qu.latin1() ); | ||
394 | return qu; | ||
395 | } | ||
396 | |||
397 | |||
398 | RemoveQuery::RemoveQuery(int uid ) | ||
399 | : OSQLQuery(), m_uid( uid ) {} | ||
400 | RemoveQuery::~RemoveQuery() {} | ||
401 | QString RemoveQuery::query()const { | ||
402 | QString qu = "DELETE from addressbook where uid = " | ||
403 | + QString::number(m_uid) + ";"; | ||
404 | qu += "DELETE from custom_data where uid = " | ||
405 | + QString::number(m_uid) + ";"; | ||
406 | return qu; | ||
407 | } | ||
408 | |||
409 | |||
410 | |||
411 | |||
412 | FindQuery::FindQuery(int uid) | ||
413 | : OSQLQuery(), m_uid( uid ) { | ||
414 | } | ||
415 | FindQuery::FindQuery(const QArray<int>& ints) | ||
416 | : OSQLQuery(), m_uids( ints ){ | ||
417 | } | ||
418 | FindQuery::~FindQuery() { | ||
419 | } | ||
420 | QString FindQuery::query()const{ | ||
421 | // if ( m_uids.count() == 0 ) | ||
422 | return single(); | ||
423 | } | ||
424 | /* | ||
425 | else | ||
426 | return multi(); | ||
427 | } | ||
428 | QString FindQuery::multi()const { | ||
429 | QString qu = "select uid, type, value from addressbook where"; | ||
430 | for (uint i = 0; i < m_uids.count(); i++ ) { | ||
431 | qu += " UID = " + QString::number( m_uids[i] ) + " OR"; | ||
432 | } | ||
433 | qu.remove( qu.length()-2, 2 ); // Hmmmm.. | ||
434 | return qu; | ||
435 | } | ||
436 | */ | ||
437 | #ifdef __STORE_HORIZONTAL_ | ||
438 | QString FindQuery::single()const{ | ||
439 | QString qu = "select *"; | ||
440 | qu += " from addressbook where uid = " + QString::number(m_uid); | ||
441 | |||
442 | // qWarning("find query: %s", qu.latin1() ); | ||
443 | return qu; | ||
444 | } | ||
445 | #else | ||
446 | QString FindQuery::single()const{ | ||
447 | QString qu = "select uid, type, value from addressbook where uid = "; | ||
448 | qu += QString::number(m_uid); | ||
449 | return qu; | ||
450 | } | ||
451 | #endif | ||
452 | |||
453 | |||
454 | FindCustomQuery::FindCustomQuery(int uid) | ||
455 | : OSQLQuery(), m_uid( uid ) { | ||
456 | } | ||
457 | FindCustomQuery::FindCustomQuery(const QArray<int>& ints) | ||
458 | : OSQLQuery(), m_uids( ints ){ | ||
459 | } | ||
460 | FindCustomQuery::~FindCustomQuery() { | ||
461 | } | ||
462 | QString FindCustomQuery::query()const{ | ||
463 | // if ( m_uids.count() == 0 ) | ||
464 | return single(); | ||
465 | } | ||
466 | QString FindCustomQuery::single()const{ | ||
467 | QString qu = "select uid, type, value from custom_data where uid = "; | ||
468 | qu += QString::number(m_uid); | ||
469 | return qu; | ||
470 | } | ||
471 | |||
472 | }; | ||
473 | |||
474 | |||
475 | /* --------------------------------------------------------------------------- */ | ||
476 | |||
477 | OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, | ||
478 | const QString& filename ): | ||
479 | OContactAccessBackend(), m_changed(false), m_driver( NULL ) | ||
480 | { | ||
481 | qWarning("C'tor OContactAccessBackend_SQL starts"); | ||
482 | QTime t; | ||
483 | t.start(); | ||
484 | |||
485 | /* Expecting to access the default filename if nothing else is set */ | ||
486 | if ( filename.isEmpty() ){ | ||
487 | m_fileName = Global::applicationFileName( "addressbook","addressbook.db" ); | ||
488 | } else | ||
489 | m_fileName = filename; | ||
490 | |||
491 | // Get the standart sql-driver from the OSQLManager.. | ||
492 | OSQLManager man; | ||
493 | m_driver = man.standard(); | ||
494 | m_driver->setUrl( m_fileName ); | ||
495 | |||
496 | load(); | ||
497 | |||
498 | qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() ); | ||
499 | } | ||
500 | |||
501 | OContactAccessBackend_SQL::~OContactAccessBackend_SQL () | ||
502 | { | ||
503 | if( m_driver ) | ||
504 | delete m_driver; | ||
505 | } | ||
506 | |||
507 | bool OContactAccessBackend_SQL::load () | ||
508 | { | ||
509 | if (!m_driver->open() ) | ||
510 | return false; | ||
511 | |||
512 | // Don't expect that the database exists. | ||
513 | // It is save here to create the table, even if it | ||
514 | // do exist. ( Is that correct for all databases ?? ) | ||
515 | CreateQuery creat; | ||
516 | OSQLResult res = m_driver->query( &creat ); | ||
517 | |||
518 | update(); | ||
519 | |||
520 | return true; | ||
521 | |||
522 | } | ||
523 | |||
524 | bool OContactAccessBackend_SQL::reload() | ||
525 | { | ||
526 | return load(); | ||
527 | } | ||
528 | |||
529 | bool OContactAccessBackend_SQL::save() | ||
530 | { | ||
531 | return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) | ||
532 | } | ||
533 | |||
534 | |||
535 | void OContactAccessBackend_SQL::clear () | ||
536 | { | ||
537 | ClearQuery cle; | ||
538 | OSQLResult res = m_driver->query( &cle ); | ||
539 | |||
540 | reload(); | ||
541 | } | ||
542 | |||
543 | bool OContactAccessBackend_SQL::wasChangedExternally() | ||
544 | { | ||
545 | return false; | ||
546 | } | ||
547 | |||
548 | QArray<int> OContactAccessBackend_SQL::allRecords() const | ||
549 | { | ||
550 | |||
551 | // FIXME: Think about cute handling of changed tables.. | ||
552 | // Thus, we don't have to call update here... | ||
553 | if ( m_changed ) | ||
554 | ((OContactAccessBackend_SQL*)this)->update(); | ||
555 | |||
556 | return m_uids; | ||
557 | } | ||
558 | |||
559 | bool OContactAccessBackend_SQL::add ( const OContact &newcontact ) | ||
560 | { | ||
561 | InsertQuery ins( newcontact ); | ||
562 | OSQLResult res = m_driver->query( &ins ); | ||
563 | |||
564 | if ( res.state() == OSQLResult::Failure ) | ||
565 | return false; | ||
566 | |||
567 | int c = m_uids.count(); | ||
568 | m_uids.resize( c+1 ); | ||
569 | m_uids[c] = newcontact.uid(); | ||
570 | |||
571 | return true; | ||
572 | } | ||
573 | |||
574 | |||
575 | bool OContactAccessBackend_SQL::remove ( int uid ) | ||
576 | { | ||
577 | RemoveQuery rem( uid ); | ||
578 | OSQLResult res = m_driver->query(&rem ); | ||
579 | |||
580 | if ( res.state() == OSQLResult::Failure ) | ||
581 | return false; | ||
582 | |||
583 | m_changed = true; | ||
584 | |||
585 | return true; | ||
586 | } | ||
587 | |||
588 | bool OContactAccessBackend_SQL::replace ( const OContact &contact ) | ||
589 | { | ||
590 | if ( !remove( contact.uid() ) ) | ||
591 | return false; | ||
592 | |||
593 | return add( contact ); | ||
594 | } | ||
595 | |||
596 | |||
597 | OContact OContactAccessBackend_SQL::find ( int uid ) const | ||
598 | { | ||
599 | qWarning("OContactAccessBackend_SQL::find()"); | ||
600 | QTime t; | ||
601 | t.start(); | ||
602 | |||
603 | OContact retContact( requestNonCustom( uid ) ); | ||
604 | retContact.setExtraMap( requestCustom( uid ) ); | ||
605 | |||
606 | qWarning("OContactAccessBackend_SQL::find() needed: %d ms", t.elapsed() ); | ||
607 | return retContact; | ||
608 | } | ||
609 | |||
610 | |||
611 | |||
612 | QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ) | ||
613 | { | ||
614 | QString qu = "SELECT uid FROM addressbook WHERE"; | ||
615 | |||
616 | QMap<int, QString> queryFields = query.toMap(); | ||
617 | QStringList fieldList = OContactFields::untrfields( false ); | ||
618 | QMap<QString, int> translate = OContactFields::untrFieldsToId(); | ||
619 | |||
620 | // Convert every filled field to a SQL-Query | ||
621 | bool isAnyFieldSelected = false; | ||
622 | for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ | ||
623 | int id = translate[*it]; | ||
624 | QString queryStr = queryFields[id]; | ||
625 | if ( !queryStr.isEmpty() ){ | ||
626 | isAnyFieldSelected = true; | ||
627 | switch( id ){ | ||
628 | default: | ||
629 | // Switching between case sensitive and insensitive... | ||
630 | // LIKE is not case sensitive, GLOB is case sensitive | ||
631 | // Do exist a better solution to switch this ? | ||
632 | if ( settings & OContactAccess::IgnoreCase ) | ||
633 | qu += "(\"" + *it + "\"" + " LIKE " + "'" | ||
634 | + queryStr.replace(QRegExp("\\*"),"%") + "'" + ") AND "; | ||
635 | else | ||
636 | qu += "(\"" + *it + "\"" + " GLOB " + "'" | ||
637 | + queryStr + "'" + ") AND "; | ||
638 | |||
639 | } | ||
640 | } | ||
641 | } | ||
642 | // Skip trailing "AND" | ||
643 | if ( isAnyFieldSelected ) | ||
644 | qu = qu.left( qu.length() - 4 ); | ||
645 | |||
646 | qWarning( "queryByExample query: %s", qu.latin1() ); | ||
647 | |||
648 | // Execute query and return the received uid's | ||
649 | OSQLRawQuery raw( qu ); | ||
650 | OSQLResult res = m_driver->query( &raw ); | ||
651 | if ( res.state() != OSQLResult::Success ){ | ||
652 | QArray<int> empty; | ||
653 | return empty; | ||
654 | } | ||
655 | |||
656 | QArray<int> list = extractUids( res ); | ||
657 | |||
658 | return list; | ||
659 | } | ||
660 | |||
661 | QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const | ||
662 | { | ||
663 | QArray<int> nix(0); | ||
664 | return nix; | ||
665 | } | ||
666 | |||
667 | const uint OContactAccessBackend_SQL::querySettings() | ||
668 | { | ||
669 | return OContactAccess::IgnoreCase | ||
670 | || OContactAccess::WildCards; | ||
671 | } | ||
672 | |||
673 | bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const | ||
674 | { | ||
675 | /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay | ||
676 | * may be added with any of the other settings. IgnoreCase should never used alone. | ||
677 | * Wildcards, RegExp, ExactMatch should never used at the same time... | ||
678 | */ | ||
679 | |||
680 | // Step 1: Check whether the given settings are supported by this backend | ||
681 | if ( ( querySettings & ( | ||
682 | OContactAccess::IgnoreCase | ||
683 | | OContactAccess::WildCards | ||
684 | // | OContactAccess::DateDiff | ||
685 | // | OContactAccess::DateYear | ||
686 | // | OContactAccess::DateMonth | ||
687 | // | OContactAccess::DateDay | ||
688 | // | OContactAccess::RegExp | ||
689 | // | OContactAccess::ExactMatch | ||
690 | ) ) != querySettings ) | ||
691 | return false; | ||
692 | |||
693 | // Step 2: Check whether the given combinations are ok.. | ||
694 | |||
695 | // IngoreCase alone is invalid | ||
696 | if ( querySettings == OContactAccess::IgnoreCase ) | ||
697 | return false; | ||
698 | |||
699 | // WildCards, RegExp and ExactMatch should never used at the same time | ||
700 | switch ( querySettings & ~( OContactAccess::IgnoreCase | ||
701 | | OContactAccess::DateDiff | ||
702 | | OContactAccess::DateYear | ||
703 | | OContactAccess::DateMonth | ||
704 | | OContactAccess::DateDay | ||
705 | ) | ||
706 | ){ | ||
707 | case OContactAccess::RegExp: | ||
708 | return ( true ); | ||
709 | case OContactAccess::WildCards: | ||
710 | return ( true ); | ||
711 | case OContactAccess::ExactMatch: | ||
712 | return ( true ); | ||
713 | case 0: // one of the upper removed bits were set.. | ||
714 | return ( true ); | ||
715 | default: | ||
716 | return ( false ); | ||
717 | } | ||
718 | |||
719 | } | ||
720 | |||
721 | QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int ) | ||
722 | { | ||
723 | QTime t; | ||
724 | t.start(); | ||
725 | |||
726 | #ifdef __STORE_HORIZONTAL_ | ||
727 | QString query = "SELECT uid FROM addressbook "; | ||
728 | query += "ORDER BY \"Last Name\" "; | ||
729 | #else | ||
730 | QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' "; | ||
731 | query += "ORDER BY upper( value )"; | ||
732 | #endif | ||
733 | |||
734 | if ( !asc ) | ||
735 | query += "DESC"; | ||
736 | |||
737 | // qWarning("sorted query is: %s", query.latin1() ); | ||
738 | |||
739 | OSQLRawQuery raw( query ); | ||
740 | OSQLResult res = m_driver->query( &raw ); | ||
741 | if ( res.state() != OSQLResult::Success ){ | ||
742 | QArray<int> empty; | ||
743 | return empty; | ||
744 | } | ||
745 | |||
746 | QArray<int> list = extractUids( res ); | ||
747 | |||
748 | qWarning("sorted needed %d ms!", t.elapsed() ); | ||
749 | return list; | ||
750 | } | ||
751 | |||
752 | |||
753 | void OContactAccessBackend_SQL::update() | ||
754 | { | ||
755 | qWarning("Update starts"); | ||
756 | QTime t; | ||
757 | t.start(); | ||
758 | |||
759 | // Now load the database set and extract the uid's | ||
760 | // which will be held locally | ||
761 | |||
762 | LoadQuery lo; | ||
763 | OSQLResult res = m_driver->query(&lo); | ||
764 | if ( res.state() != OSQLResult::Success ) | ||
765 | return; | ||
766 | |||
767 | m_uids = extractUids( res ); | ||
768 | |||
769 | m_changed = false; | ||
770 | |||
771 | qWarning("Update ends %d ms", t.elapsed() ); | ||
772 | } | ||
773 | |||
774 | QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const | ||
775 | { | ||
776 | qWarning("extractUids"); | ||
777 | QTime t; | ||
778 | t.start(); | ||
779 | OSQLResultItem::ValueList list = res.results(); | ||
780 | OSQLResultItem::ValueList::Iterator it; | ||
781 | QArray<int> ints(list.count() ); | ||
782 | qWarning(" count = %d", list.count() ); | ||
783 | |||
784 | int i = 0; | ||
785 | for (it = list.begin(); it != list.end(); ++it ) { | ||
786 | ints[i] = (*it).data("uid").toInt(); | ||
787 | i++; | ||
788 | } | ||
789 | qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); | ||
790 | |||
791 | return ints; | ||
792 | |||
793 | } | ||
794 | |||
795 | #ifdef __STORE_HORIZONTAL_ | ||
796 | QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const | ||
797 | { | ||
798 | QTime t; | ||
799 | t.start(); | ||
800 | |||
801 | QMap<int, QString> nonCustomMap; | ||
802 | |||
803 | int t2needed = 0; | ||
804 | int t3needed = 0; | ||
805 | QTime t2; | ||
806 | t2.start(); | ||
807 | FindQuery query( uid ); | ||
808 | OSQLResult res_noncustom = m_driver->query( &query ); | ||
809 | t2needed = t2.elapsed(); | ||
810 | |||
811 | OSQLResultItem resItem = res_noncustom.first(); | ||
812 | |||
813 | QTime t3; | ||
814 | t3.start(); | ||
815 | // Now loop through all columns | ||
816 | QStringList fieldList = OContactFields::untrfields( false ); | ||
817 | QMap<QString, int> translate = OContactFields::untrFieldsToId(); | ||
818 | for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ | ||
819 | // Get data for the selected column and store it with the | ||
820 | // corresponding id into the map.. | ||
821 | |||
822 | int id = translate[*it]; | ||
823 | QString value = resItem.data( (*it) ); | ||
824 | |||
825 | // qWarning("Reading %s... found: %s", (*it).latin1(), value.latin1() ); | ||
826 | |||
827 | switch( id ){ | ||
828 | case Qtopia::Birthday: | ||
829 | case Qtopia::Anniversary:{ | ||
830 | // Birthday and Anniversary are encoded special ( yyyy-mm-dd ) | ||
831 | QStringList list = QStringList::split( '-', value ); | ||
832 | QStringList::Iterator lit = list.begin(); | ||
833 | int year = (*lit).toInt(); | ||
834 | int month = (*(++lit)).toInt(); | ||
835 | int day = (*(++lit)).toInt(); | ||
836 | if ( ( day != 0 ) && ( month != 0 ) && ( year != 0 ) ){ | ||
837 | QDate date( year, month, day ); | ||
838 | nonCustomMap.insert( id, OConversion::dateToString( date ) ); | ||
839 | } | ||
840 | } | ||
841 | break; | ||
842 | case Qtopia::AddressCategory: | ||
843 | qWarning("Category is: %s", value.latin1() ); | ||
844 | default: | ||
845 | nonCustomMap.insert( id, value ); | ||
846 | } | ||
847 | } | ||
848 | |||
849 | // First insert uid | ||
850 | nonCustomMap.insert( Qtopia::AddressUid, resItem.data( "uid" ) ); | ||
851 | t3needed = t3.elapsed(); | ||
852 | |||
853 | // qWarning("Adding UID: %s", resItem.data( "uid" ).latin1() ); | ||
854 | qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", | ||
855 | t.elapsed(), t2needed, t3needed ); | ||
856 | |||
857 | return nonCustomMap; | ||
858 | } | ||
859 | #else | ||
860 | |||
861 | QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const | ||
862 | { | ||
863 | QTime t; | ||
864 | t.start(); | ||
865 | |||
866 | QMap<int, QString> nonCustomMap; | ||
867 | |||
868 | int t2needed = 0; | ||
869 | QTime t2; | ||
870 | t2.start(); | ||
871 | FindQuery query( uid ); | ||
872 | OSQLResult res_noncustom = m_driver->query( &query ); | ||
873 | t2needed = t2.elapsed(); | ||
874 | |||
875 | if ( res_noncustom.state() == OSQLResult::Failure ) { | ||
876 | qWarning("OSQLResult::Failure in find query !!"); | ||
877 | QMap<int, QString> empty; | ||
878 | return empty; | ||
879 | } | ||
880 | |||
881 | int t3needed = 0; | ||
882 | QTime t3; | ||
883 | t3.start(); | ||
884 | QMap<QString, int> translateMap = OContactFields::untrFieldsToId(); | ||
885 | |||
886 | OSQLResultItem::ValueList list = res_noncustom.results(); | ||
887 | OSQLResultItem::ValueList::Iterator it = list.begin(); | ||
888 | for ( ; it != list.end(); ++it ) { | ||
889 | if ( (*it).data("type") != "" ){ | ||
890 | int typeId = translateMap[(*it).data( "type" )]; | ||
891 | switch( typeId ){ | ||
892 | case Qtopia::Birthday: | ||
893 | case Qtopia::Anniversary:{ | ||
894 | // Birthday and Anniversary are encoded special ( yyyy-mm-dd ) | ||
895 | QStringList list = QStringList::split( '-', (*it).data( "value" ) ); | ||
896 | QStringList::Iterator lit = list.begin(); | ||
897 | int year = (*lit).toInt(); | ||
898 | qWarning("1. %s", (*lit).latin1()); | ||
899 | int month = (*(++lit)).toInt(); | ||
900 | qWarning("2. %s", (*lit).latin1()); | ||
901 | int day = (*(++lit)).toInt(); | ||
902 | qWarning("3. %s", (*lit).latin1()); | ||
903 | qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day ); | ||
904 | QDate date( year, month, day ); | ||
905 | nonCustomMap.insert( typeId, OConversion::dateToString( date ) ); | ||
906 | } | ||
907 | break; | ||
908 | default: | ||
909 | nonCustomMap.insert( typeId, | ||
910 | (*it).data( "value" ) ); | ||
911 | } | ||
912 | } | ||
913 | } | ||
914 | // Add UID to Map.. | ||
915 | nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) ); | ||
916 | t3needed = t3.elapsed(); | ||
917 | |||
918 | qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", t.elapsed(), t2needed, t3needed ); | ||
919 | return nonCustomMap; | ||
920 | } | ||
921 | |||
922 | #endif // __STORE_HORIZONTAL_ | ||
923 | |||
924 | QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const | ||
925 | { | ||
926 | QTime t; | ||
927 | t.start(); | ||
928 | |||
929 | QMap<QString, QString> customMap; | ||
930 | |||
931 | FindCustomQuery query( uid ); | ||
932 | OSQLResult res_custom = m_driver->query( &query ); | ||
933 | |||
934 | if ( res_custom.state() == OSQLResult::Failure ) { | ||
935 | qWarning("OSQLResult::Failure in find query !!"); | ||
936 | QMap<QString, QString> empty; | ||
937 | return empty; | ||
938 | } | ||
939 | |||
940 | OSQLResultItem::ValueList list = res_custom.results(); | ||
941 | OSQLResultItem::ValueList::Iterator it = list.begin(); | ||
942 | for ( ; it != list.end(); ++it ) { | ||
943 | customMap.insert( (*it).data( "type" ), (*it).data( "value" ) ); | ||
944 | } | ||
945 | |||
946 | qWarning("RequestCustom needed: %d ms", t.elapsed() ); | ||
947 | return customMap; | ||
948 | } | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.h new file mode 100644 index 0000000..8cd92e8 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.h | |||
@@ -0,0 +1,110 @@ | |||
1 | /* | ||
2 | * SQL Backend for the OPIE-Contact Database. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * | ||
13 | * | ||
14 | * ===================================================================== | ||
15 | * Version: $Id$ | ||
16 | * ===================================================================== | ||
17 | * History: | ||
18 | * $Log$ | ||
19 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
20 | * libopie1 goes into unsupported | ||
21 | * | ||
22 | * Revision 1.3 2004/03/14 13:50:35 alwin | ||
23 | * namespace correction | ||
24 | * | ||
25 | * Revision 1.2 2003/12/08 15:18:11 eilers | ||
26 | * Committing unfinished sql implementation before merging to libopie2 starts.. | ||
27 | * | ||
28 | * Revision 1.1 2003/09/22 14:31:16 eilers | ||
29 | * Added first experimental incarnation of sql-backend for addressbook. | ||
30 | * Some modifications to be able to compile the todo sql-backend. | ||
31 | * A lot of changes fill follow... | ||
32 | * | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #ifndef _OContactAccessBackend_SQL_ | ||
37 | #define _OContactAccessBackend_SQL_ | ||
38 | |||
39 | #include "ocontactaccessbackend.h" | ||
40 | #include "ocontactaccess.h" | ||
41 | |||
42 | #include <qlist.h> | ||
43 | #include <qdict.h> | ||
44 | |||
45 | namespace Opie { namespace DB { | ||
46 | class OSQLDriver; | ||
47 | class OSQLResult; | ||
48 | class OSQLResultItem; | ||
49 | |||
50 | }} | ||
51 | |||
52 | /* the default xml implementation */ | ||
53 | /** | ||
54 | * This class is the SQL implementation of a Contact backend | ||
55 | * it does implement everything available for OContact. | ||
56 | * @see OPimAccessBackend for more information of available methods | ||
57 | */ | ||
58 | class OContactAccessBackend_SQL : public OContactAccessBackend { | ||
59 | public: | ||
60 | OContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null ); | ||
61 | |||
62 | ~OContactAccessBackend_SQL (); | ||
63 | |||
64 | bool save(); | ||
65 | |||
66 | bool load (); | ||
67 | |||
68 | void clear (); | ||
69 | |||
70 | bool wasChangedExternally(); | ||
71 | |||
72 | QArray<int> allRecords() const; | ||
73 | |||
74 | OContact find ( int uid ) const; | ||
75 | // FIXME: Add lookahead-cache support ! | ||
76 | //OContact find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; | ||
77 | |||
78 | QArray<int> queryByExample ( const OContact &query, int settings, | ||
79 | const QDateTime& d ); | ||
80 | |||
81 | QArray<int> matchRegexp( const QRegExp &r ) const; | ||
82 | |||
83 | const uint querySettings(); | ||
84 | |||
85 | bool hasQuerySettings (uint querySettings) const; | ||
86 | |||
87 | // Currently only asc implemented.. | ||
88 | QArray<int> sorted( bool asc, int , int , int ); | ||
89 | bool add ( const OContact &newcontact ); | ||
90 | |||
91 | bool replace ( const OContact &contact ); | ||
92 | |||
93 | bool remove ( int uid ); | ||
94 | bool reload(); | ||
95 | |||
96 | private: | ||
97 | QArray<int> extractUids( Opie::DB::OSQLResult& res ) const; | ||
98 | QMap<int, QString> requestNonCustom( int uid ) const; | ||
99 | QMap<QString, QString> requestCustom( int uid ) const; | ||
100 | void update(); | ||
101 | |||
102 | protected: | ||
103 | bool m_changed; | ||
104 | QString m_fileName; | ||
105 | QArray<int> m_uids; | ||
106 | |||
107 | Opie::DB::OSQLDriver* m_driver; | ||
108 | }; | ||
109 | |||
110 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.cpp b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.cpp new file mode 100644 index 0000000..a795b56 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.cpp | |||
@@ -0,0 +1,649 @@ | |||
1 | /* | ||
2 | * VCard Backend for the OPIE-Contact Database. | ||
3 | * | ||
4 | * Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
5 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
6 | * | ||
7 | * ===================================================================== | ||
8 | *This program is free software; you can redistribute it and/or | ||
9 | *modify it under the terms of the GNU Library General Public | ||
10 | * License as published by the Free Software Foundation; either | ||
11 | * version 2 of the License, or (at your option) any later version. | ||
12 | * ===================================================================== | ||
13 | * ToDo: | ||
14 | * | ||
15 | * ===================================================================== | ||
16 | * Version: $Id$ | ||
17 | * ===================================================================== | ||
18 | * History: | ||
19 | * $Log$ | ||
20 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
21 | * libopie1 goes into unsupported | ||
22 | * | ||
23 | * Revision 1.11 2003/08/01 12:30:16 eilers | ||
24 | * Merging changes from BRANCH_1_0 to HEAD | ||
25 | * | ||
26 | * Revision 1.10.4.3 2003/07/23 08:54:37 eilers | ||
27 | * Default email was added to the list of all emails, which already contains | ||
28 | * the default email.. | ||
29 | * This closes bug #1045 | ||
30 | * | ||
31 | * Revision 1.10.4.2 2003/07/23 08:44:45 eilers | ||
32 | * Importing of Notes in vcard files wasn't implemented. | ||
33 | * Closes bug #1044 | ||
34 | * | ||
35 | * Revision 1.10.4.1 2003/06/02 13:37:49 eilers | ||
36 | * Fixing memory leak | ||
37 | * | ||
38 | * Revision 1.10 2003/04/13 18:07:10 zecke | ||
39 | * More API doc | ||
40 | * QString -> const QString& | ||
41 | * QString = 0l -> QString::null | ||
42 | * | ||
43 | * Revision 1.9 2003/03/21 10:33:09 eilers | ||
44 | * Merged speed optimized xml backend for contacts to main. | ||
45 | * Added QDateTime to querybyexample. For instance, it is now possible to get | ||
46 | * all Birthdays/Anniversaries between two dates. This should be used | ||
47 | * to show all birthdays in the datebook.. | ||
48 | * This change is sourcecode backward compatible but you have to upgrade | ||
49 | * the binaries for today-addressbook. | ||
50 | * | ||
51 | * Revision 1.8 2003/02/21 16:52:49 zecke | ||
52 | * -Remove old Todo classes they're deprecated and today I already using the | ||
53 | * new API | ||
54 | * -Guard against self assignment in OTodo | ||
55 | * -Add test apps for OPIM | ||
56 | * -Opiefied Event classes | ||
57 | * -Added TimeZone handling and pinning of TimeZones to OEvent | ||
58 | * -Adjust ORecur and the widget to better timezone behaviour | ||
59 | * | ||
60 | * Revision 1.7 2003/02/16 22:25:46 zecke | ||
61 | * 0000276 Fix for that bug.. or better temp workaround | ||
62 | * A Preferred Number is HOME|VOICE | ||
63 | * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test | ||
64 | * triggers both | ||
65 | * and the cell phone number overrides the other entries.. | ||
66 | * | ||
67 | * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the | ||
68 | * number | ||
69 | * | ||
70 | * The right and final fix would be to reorder the if statement to make it | ||
71 | * if else based and the less common thing put to the bottom | ||
72 | * | ||
73 | * OTodoAccessVcal fix the date for beaming | ||
74 | * | ||
75 | * Revision 1.6 2003/01/13 15:49:31 eilers | ||
76 | * Fixing crash when businesscard.vcf is missing.. | ||
77 | * | ||
78 | * Revision 1.5 2002/12/07 13:26:22 eilers | ||
79 | * Fixing bug in storing anniversary.. | ||
80 | * | ||
81 | * Revision 1.4 2002/11/13 14:14:51 eilers | ||
82 | * Added sorted for Contacts.. | ||
83 | * | ||
84 | * Revision 1.3 2002/11/11 16:41:09 kergoth | ||
85 | * no default arguments in implementation | ||
86 | * | ||
87 | * Revision 1.2 2002/11/10 15:41:53 eilers | ||
88 | * Bugfixes.. | ||
89 | * | ||
90 | * Revision 1.1 2002/11/09 14:34:52 eilers | ||
91 | * Added VCard Backend. | ||
92 | * | ||
93 | */ | ||
94 | #include "ocontactaccessbackend_vcard.h" | ||
95 | #include "../../library/backend/vobject_p.h" | ||
96 | #include "../../library/backend/qfiledirect_p.h" | ||
97 | |||
98 | #include <qpe/timeconversion.h> | ||
99 | |||
100 | #include <qfile.h> | ||
101 | |||
102 | OContactAccessBackend_VCard::OContactAccessBackend_VCard ( const QString& , const QString& filename ): | ||
103 | m_dirty( false ), | ||
104 | m_file( filename ) | ||
105 | { | ||
106 | load(); | ||
107 | } | ||
108 | |||
109 | |||
110 | bool OContactAccessBackend_VCard::load () | ||
111 | { | ||
112 | m_map.clear(); | ||
113 | m_dirty = false; | ||
114 | |||
115 | VObject* obj = 0l; | ||
116 | |||
117 | if ( QFile::exists(m_file) ){ | ||
118 | obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); | ||
119 | if ( !obj ) | ||
120 | return false; | ||
121 | }else{ | ||
122 | qWarning("File \"%s\" not found !", m_file.latin1() ); | ||
123 | return false; | ||
124 | } | ||
125 | |||
126 | while ( obj ) { | ||
127 | OContact con = parseVObject( obj ); | ||
128 | /* | ||
129 | * if uid is 0 assign a new one | ||
130 | * this at least happens on | ||
131 | * Nokia6210 | ||
132 | */ | ||
133 | if ( con.uid() == 0 ){ | ||
134 | con.setUid( 1 ); | ||
135 | qWarning("assigned new uid %d",con.uid() ); | ||
136 | } | ||
137 | |||
138 | m_map.insert( con.uid(), con ); | ||
139 | |||
140 | VObject *t = obj; | ||
141 | obj = nextVObjectInList(obj); | ||
142 | cleanVObject( t ); | ||
143 | } | ||
144 | |||
145 | return true; | ||
146 | |||
147 | } | ||
148 | bool OContactAccessBackend_VCard::reload() | ||
149 | { | ||
150 | return load(); | ||
151 | } | ||
152 | bool OContactAccessBackend_VCard::save() | ||
153 | { | ||
154 | if (!m_dirty ) | ||
155 | return true; | ||
156 | |||
157 | QFileDirect file( m_file ); | ||
158 | if (!file.open(IO_WriteOnly ) ) | ||
159 | return false; | ||
160 | |||
161 | VObject *obj; | ||
162 | obj = newVObject( VCCalProp ); | ||
163 | addPropValue( obj, VCVersionProp, "1.0" ); | ||
164 | |||
165 | VObject *vo; | ||
166 | for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ | ||
167 | vo = createVObject( *it ); | ||
168 | writeVObject( file.directHandle() , vo ); | ||
169 | cleanVObject( vo ); | ||
170 | } | ||
171 | cleanStrTbl(); | ||
172 | deleteVObject( obj ); | ||
173 | |||
174 | m_dirty = false; | ||
175 | return true; | ||
176 | |||
177 | |||
178 | } | ||
179 | void OContactAccessBackend_VCard::clear () | ||
180 | { | ||
181 | m_map.clear(); | ||
182 | m_dirty = true; // ??? sure ? (se) | ||
183 | } | ||
184 | |||
185 | bool OContactAccessBackend_VCard::add ( const OContact& newcontact ) | ||
186 | { | ||
187 | m_map.insert( newcontact.uid(), newcontact ); | ||
188 | m_dirty = true; | ||
189 | return true; | ||
190 | } | ||
191 | |||
192 | bool OContactAccessBackend_VCard::remove ( int uid ) | ||
193 | { | ||
194 | m_map.remove( uid ); | ||
195 | m_dirty = true; | ||
196 | return true; | ||
197 | } | ||
198 | |||
199 | bool OContactAccessBackend_VCard::replace ( const OContact &contact ) | ||
200 | { | ||
201 | m_map.replace( contact.uid(), contact ); | ||
202 | m_dirty = true; | ||
203 | return true; | ||
204 | } | ||
205 | |||
206 | OContact OContactAccessBackend_VCard::find ( int uid ) const | ||
207 | { | ||
208 | return m_map[uid]; | ||
209 | } | ||
210 | |||
211 | QArray<int> OContactAccessBackend_VCard::allRecords() const | ||
212 | { | ||
213 | QArray<int> ar( m_map.count() ); | ||
214 | QMap<int, OContact>::ConstIterator it; | ||
215 | int i = 0; | ||
216 | for ( it = m_map.begin(); it != m_map.end(); ++it ) { | ||
217 | ar[i] = it.key(); | ||
218 | i++; | ||
219 | } | ||
220 | return ar; | ||
221 | } | ||
222 | |||
223 | // Not implemented | ||
224 | QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& ) | ||
225 | { | ||
226 | QArray<int> ar(0); | ||
227 | return ar; | ||
228 | } | ||
229 | |||
230 | // Not implemented | ||
231 | QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const | ||
232 | { | ||
233 | QArray<int> ar(0); | ||
234 | return ar; | ||
235 | } | ||
236 | |||
237 | const uint OContactAccessBackend_VCard::querySettings() | ||
238 | { | ||
239 | return 0; // No search possible | ||
240 | } | ||
241 | |||
242 | bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const | ||
243 | { | ||
244 | return false; // No search possible, therefore all settings invalid ;) | ||
245 | } | ||
246 | |||
247 | bool OContactAccessBackend_VCard::wasChangedExternally() | ||
248 | { | ||
249 | return false; // Don't expect concurrent access | ||
250 | } | ||
251 | |||
252 | // Not implemented | ||
253 | QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int ) | ||
254 | { | ||
255 | QArray<int> ar(0); | ||
256 | return ar; | ||
257 | } | ||
258 | |||
259 | // *** Private stuff *** | ||
260 | |||
261 | |||
262 | OContact OContactAccessBackend_VCard::parseVObject( VObject *obj ) | ||
263 | { | ||
264 | OContact c; | ||
265 | |||
266 | VObjectIterator it; | ||
267 | initPropIterator( &it, obj ); | ||
268 | while( moreIteration( &it ) ) { | ||
269 | VObject *o = nextVObject( &it ); | ||
270 | QCString name = vObjectName( o ); | ||
271 | QCString value = vObjectStringZValue( o ); | ||
272 | if ( name == VCNameProp ) { | ||
273 | VObjectIterator nit; | ||
274 | initPropIterator( &nit, o ); | ||
275 | while( moreIteration( &nit ) ) { | ||
276 | VObject *o = nextVObject( &nit ); | ||
277 | QCString name = vObjectTypeInfo( o ); | ||
278 | QString value = vObjectStringZValue( o ); | ||
279 | if ( name == VCNamePrefixesProp ) | ||
280 | c.setTitle( value ); | ||
281 | else if ( name == VCNameSuffixesProp ) | ||
282 | c.setSuffix( value ); | ||
283 | else if ( name == VCFamilyNameProp ) | ||
284 | c.setLastName( value ); | ||
285 | else if ( name == VCGivenNameProp ) | ||
286 | c.setFirstName( value ); | ||
287 | else if ( name == VCAdditionalNamesProp ) | ||
288 | c.setMiddleName( value ); | ||
289 | } | ||
290 | } | ||
291 | else if ( name == VCAdrProp ) { | ||
292 | bool work = TRUE; // default address is work address | ||
293 | QString street; | ||
294 | QString city; | ||
295 | QString region; | ||
296 | QString postal; | ||
297 | QString country; | ||
298 | |||
299 | VObjectIterator nit; | ||
300 | initPropIterator( &nit, o ); | ||
301 | while( moreIteration( &nit ) ) { | ||
302 | VObject *o = nextVObject( &nit ); | ||
303 | QCString name = vObjectName( o ); | ||
304 | QString value = vObjectStringZValue( o ); | ||
305 | if ( name == VCHomeProp ) | ||
306 | work = FALSE; | ||
307 | else if ( name == VCWorkProp ) | ||
308 | work = TRUE; | ||
309 | else if ( name == VCStreetAddressProp ) | ||
310 | street = value; | ||
311 | else if ( name == VCCityProp ) | ||
312 | city = value; | ||
313 | else if ( name == VCRegionProp ) | ||
314 | region = value; | ||
315 | else if ( name == VCPostalCodeProp ) | ||
316 | postal = value; | ||
317 | else if ( name == VCCountryNameProp ) | ||
318 | country = value; | ||
319 | } | ||
320 | if ( work ) { | ||
321 | c.setBusinessStreet( street ); | ||
322 | c.setBusinessCity( city ); | ||
323 | c.setBusinessCountry( country ); | ||
324 | c.setBusinessZip( postal ); | ||
325 | c.setBusinessState( region ); | ||
326 | } else { | ||
327 | c.setHomeStreet( street ); | ||
328 | c.setHomeCity( city ); | ||
329 | c.setHomeCountry( country ); | ||
330 | c.setHomeZip( postal ); | ||
331 | c.setHomeState( region ); | ||
332 | } | ||
333 | } | ||
334 | else if ( name == VCTelephoneProp ) { | ||
335 | enum { | ||
336 | HOME = 0x01, | ||
337 | WORK = 0x02, | ||
338 | VOICE = 0x04, | ||
339 | CELL = 0x08, | ||
340 | FAX = 0x10, | ||
341 | PAGER = 0x20, | ||
342 | UNKNOWN = 0x80 | ||
343 | }; | ||
344 | int type = 0; | ||
345 | |||
346 | VObjectIterator nit; | ||
347 | initPropIterator( &nit, o ); | ||
348 | while( moreIteration( &nit ) ) { | ||
349 | VObject *o = nextVObject( &nit ); | ||
350 | QCString name = vObjectTypeInfo( o ); | ||
351 | if ( name == VCHomeProp ) | ||
352 | type |= HOME; | ||
353 | else if ( name == VCWorkProp ) | ||
354 | type |= WORK; | ||
355 | else if ( name == VCVoiceProp ) | ||
356 | type |= VOICE; | ||
357 | else if ( name == VCCellularProp ) | ||
358 | type |= CELL; | ||
359 | else if ( name == VCFaxProp ) | ||
360 | type |= FAX; | ||
361 | else if ( name == VCPagerProp ) | ||
362 | type |= PAGER; | ||
363 | else if ( name == VCPreferredProp ) | ||
364 | ; | ||
365 | else | ||
366 | type |= UNKNOWN; | ||
367 | } | ||
368 | if ( (type & UNKNOWN) != UNKNOWN ) { | ||
369 | if ( ( type & (HOME|WORK) ) == 0 ) // default | ||
370 | type |= HOME; | ||
371 | if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default | ||
372 | type |= VOICE; | ||
373 | |||
374 | qWarning("value %s %d", value.data(), type ); | ||
375 | if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) ) | ||
376 | c.setHomePhone( value ); | ||
377 | if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) | ||
378 | c.setHomeFax( value ); | ||
379 | if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) | ||
380 | c.setHomeMobile( value ); | ||
381 | if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) ) | ||
382 | c.setBusinessPhone( value ); | ||
383 | if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) | ||
384 | c.setBusinessFax( value ); | ||
385 | if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) | ||
386 | c.setBusinessMobile( value ); | ||
387 | if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) | ||
388 | c.setBusinessPager( value ); | ||
389 | } | ||
390 | } | ||
391 | else if ( name == VCEmailAddressProp ) { | ||
392 | QString email = vObjectStringZValue( o ); | ||
393 | bool valid = TRUE; | ||
394 | VObjectIterator nit; | ||
395 | initPropIterator( &nit, o ); | ||
396 | while( moreIteration( &nit ) ) { | ||
397 | VObject *o = nextVObject( &nit ); | ||
398 | QCString name = vObjectTypeInfo( o ); | ||
399 | if ( name != VCInternetProp && name != VCHomeProp && | ||
400 | name != VCWorkProp && | ||
401 | name != VCPreferredProp ) | ||
402 | // ### preffered should map to default email | ||
403 | valid = FALSE; | ||
404 | } | ||
405 | if ( valid ) { | ||
406 | c.insertEmail( email ); | ||
407 | } | ||
408 | } | ||
409 | else if ( name == VCURLProp ) { | ||
410 | VObjectIterator nit; | ||
411 | initPropIterator( &nit, o ); | ||
412 | while( moreIteration( &nit ) ) { | ||
413 | VObject *o = nextVObject( &nit ); | ||
414 | QCString name = vObjectTypeInfo( o ); | ||
415 | if ( name == VCHomeProp ) | ||
416 | c.setHomeWebpage( value ); | ||
417 | else if ( name == VCWorkProp ) | ||
418 | c.setBusinessWebpage( value ); | ||
419 | } | ||
420 | } | ||
421 | else if ( name == VCOrgProp ) { | ||
422 | VObjectIterator nit; | ||
423 | initPropIterator( &nit, o ); | ||
424 | while( moreIteration( &nit ) ) { | ||
425 | VObject *o = nextVObject( &nit ); | ||
426 | QCString name = vObjectName( o ); | ||
427 | QString value = vObjectStringZValue( o ); | ||
428 | if ( name == VCOrgNameProp ) | ||
429 | c.setCompany( value ); | ||
430 | else if ( name == VCOrgUnitProp ) | ||
431 | c.setDepartment( value ); | ||
432 | else if ( name == VCOrgUnit2Prop ) | ||
433 | c.setOffice( value ); | ||
434 | } | ||
435 | } | ||
436 | else if ( name == VCTitleProp ) { | ||
437 | c.setJobTitle( value ); | ||
438 | } | ||
439 | else if ( name == "X-Qtopia-Profession" ) { | ||
440 | c.setProfession( value ); | ||
441 | } | ||
442 | else if ( name == "X-Qtopia-Manager" ) { | ||
443 | c.setManager( value ); | ||
444 | } | ||
445 | else if ( name == "X-Qtopia-Assistant" ) { | ||
446 | c.setAssistant( value ); | ||
447 | } | ||
448 | else if ( name == "X-Qtopia-Spouse" ) { | ||
449 | c.setSpouse( value ); | ||
450 | } | ||
451 | else if ( name == "X-Qtopia-Gender" ) { | ||
452 | c.setGender( value ); | ||
453 | } | ||
454 | else if ( name == "X-Qtopia-Anniversary" ) { | ||
455 | c.setAnniversary( convVCardDateToDate( value ) ); | ||
456 | } | ||
457 | else if ( name == "X-Qtopia-Nickname" ) { | ||
458 | c.setNickname( value ); | ||
459 | } | ||
460 | else if ( name == "X-Qtopia-Children" ) { | ||
461 | c.setChildren( value ); | ||
462 | } | ||
463 | else if ( name == VCBirthDateProp ) { | ||
464 | // Reading Birthdate regarding RFC 2425 (5.8.4) | ||
465 | c.setBirthday( convVCardDateToDate( value ) ); | ||
466 | |||
467 | } | ||
468 | else if ( name == VCCommentProp ) { | ||
469 | c.setNotes( value ); | ||
470 | } | ||
471 | #if 0 | ||
472 | else { | ||
473 | printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); | ||
474 | VObjectIterator nit; | ||
475 | initPropIterator( &nit, o ); | ||
476 | while( moreIteration( &nit ) ) { | ||
477 | VObject *o = nextVObject( &nit ); | ||
478 | QCString name = vObjectName( o ); | ||
479 | QString value = vObjectStringZValue( o ); | ||
480 | printf(" subprop: %s = %s\n", name.data(), value.latin1() ); | ||
481 | } | ||
482 | } | ||
483 | #endif | ||
484 | } | ||
485 | c.setFileAs(); | ||
486 | return c; | ||
487 | } | ||
488 | |||
489 | |||
490 | VObject* OContactAccessBackend_VCard::createVObject( const OContact &c ) | ||
491 | { | ||
492 | VObject *vcard = newVObject( VCCardProp ); | ||
493 | safeAddPropValue( vcard, VCVersionProp, "2.1" ); | ||
494 | safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); | ||
495 | safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); | ||
496 | |||
497 | // full name | ||
498 | safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); | ||
499 | |||
500 | // name properties | ||
501 | VObject *name = safeAddProp( vcard, VCNameProp ); | ||
502 | safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); | ||
503 | safeAddPropValue( name, VCGivenNameProp, c.firstName() ); | ||
504 | safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); | ||
505 | safeAddPropValue( name, VCNamePrefixesProp, c.title() ); | ||
506 | safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); | ||
507 | |||
508 | // home properties | ||
509 | VObject *home_adr= safeAddProp( vcard, VCAdrProp ); | ||
510 | safeAddProp( home_adr, VCHomeProp ); | ||
511 | safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); | ||
512 | safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); | ||
513 | safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); | ||
514 | safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); | ||
515 | safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); | ||
516 | |||
517 | VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); | ||
518 | safeAddProp( home_phone, VCHomeProp ); | ||
519 | home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); | ||
520 | safeAddProp( home_phone, VCHomeProp ); | ||
521 | safeAddProp( home_phone, VCCellularProp ); | ||
522 | home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); | ||
523 | safeAddProp( home_phone, VCHomeProp ); | ||
524 | safeAddProp( home_phone, VCFaxProp ); | ||
525 | |||
526 | VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); | ||
527 | safeAddProp( url, VCHomeProp ); | ||
528 | |||
529 | // work properties | ||
530 | VObject *work_adr= safeAddProp( vcard, VCAdrProp ); | ||
531 | safeAddProp( work_adr, VCWorkProp ); | ||
532 | safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); | ||
533 | safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); | ||
534 | safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); | ||
535 | safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); | ||
536 | safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); | ||
537 | |||
538 | VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); | ||
539 | safeAddProp( work_phone, VCWorkProp ); | ||
540 | work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); | ||
541 | safeAddProp( work_phone, VCWorkProp ); | ||
542 | safeAddProp( work_phone, VCCellularProp ); | ||
543 | work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); | ||
544 | safeAddProp( work_phone, VCWorkProp ); | ||
545 | safeAddProp( work_phone, VCFaxProp ); | ||
546 | work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); | ||
547 | safeAddProp( work_phone, VCWorkProp ); | ||
548 | safeAddProp( work_phone, VCPagerProp ); | ||
549 | |||
550 | url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); | ||
551 | safeAddProp( url, VCWorkProp ); | ||
552 | |||
553 | VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); | ||
554 | safeAddProp( title, VCWorkProp ); | ||
555 | |||
556 | |||
557 | QStringList emails = c.emailList(); | ||
558 | // emails.prepend( c.defaultEmail() ); Fix for bugreport #1045 | ||
559 | for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { | ||
560 | VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); | ||
561 | safeAddProp( email, VCInternetProp ); | ||
562 | } | ||
563 | |||
564 | safeAddPropValue( vcard, VCNoteProp, c.notes() ); | ||
565 | |||
566 | // Exporting Birthday regarding RFC 2425 (5.8.4) | ||
567 | if ( c.birthday().isValid() ){ | ||
568 | qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() ); | ||
569 | safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) ); | ||
570 | } | ||
571 | |||
572 | if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { | ||
573 | VObject *org = safeAddProp( vcard, VCOrgProp ); | ||
574 | safeAddPropValue( org, VCOrgNameProp, c.company() ); | ||
575 | safeAddPropValue( org, VCOrgUnitProp, c.department() ); | ||
576 | safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); | ||
577 | } | ||
578 | |||
579 | // some values we have to export as custom fields | ||
580 | safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); | ||
581 | safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); | ||
582 | safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); | ||
583 | |||
584 | safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); | ||
585 | safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); | ||
586 | if ( c.anniversary().isValid() ){ | ||
587 | qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() ); | ||
588 | safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) ); | ||
589 | } | ||
590 | safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); | ||
591 | safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); | ||
592 | |||
593 | return vcard; | ||
594 | } | ||
595 | |||
596 | QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const | ||
597 | { | ||
598 | QString str_rfc2425 = QString("%1-%2-%3") | ||
599 | .arg( d.year() ) | ||
600 | .arg( d.month(), 2 ) | ||
601 | .arg( d.day(), 2 ); | ||
602 | // Now replace spaces with "0"... | ||
603 | int pos = 0; | ||
604 | while ( ( pos = str_rfc2425.find (' ') ) > 0 ) | ||
605 | str_rfc2425.replace( pos, 1, "0" ); | ||
606 | |||
607 | return str_rfc2425; | ||
608 | } | ||
609 | |||
610 | QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr ) | ||
611 | { | ||
612 | int monthPos = datestr.find('-'); | ||
613 | int dayPos = datestr.find('-', monthPos+1 ); | ||
614 | int sep_ignore = 1; | ||
615 | if ( monthPos == -1 || dayPos == -1 ) { | ||
616 | qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); | ||
617 | // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD ) | ||
618 | if ( datestr.length() == 8 ){ | ||
619 | monthPos = 4; | ||
620 | dayPos = 6; | ||
621 | sep_ignore = 0; | ||
622 | qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); | ||
623 | } else { | ||
624 | return QDate(); | ||
625 | } | ||
626 | } | ||
627 | int y = datestr.left( monthPos ).toInt(); | ||
628 | int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt(); | ||
629 | int d = datestr.mid( dayPos + sep_ignore ).toInt(); | ||
630 | qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos); | ||
631 | QDate date ( y,m,d ); | ||
632 | return date; | ||
633 | } | ||
634 | |||
635 | VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value ) | ||
636 | { | ||
637 | VObject *ret = 0; | ||
638 | if ( o && !value.isEmpty() ) | ||
639 | ret = addPropValue( o, prop, value.latin1() ); | ||
640 | return ret; | ||
641 | } | ||
642 | |||
643 | VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop) | ||
644 | { | ||
645 | VObject *ret = 0; | ||
646 | if ( o ) | ||
647 | ret = addProp( o, prop ); | ||
648 | return ret; | ||
649 | } | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.h new file mode 100644 index 0000000..6dbc718 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * VCard Backend for the OPIE-Contact Database. | ||
3 | * | ||
4 | * Copyright (C) 2000 Trolltech AS. All rights reserved. | ||
5 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
6 | * | ||
7 | * ===================================================================== | ||
8 | *This program is free software; you can redistribute it and/or | ||
9 | *modify it under the terms of the GNU Library General Public | ||
10 | * License as published by the Free Software Foundation; either | ||
11 | * version 2 of the License, or (at your option) any later version. | ||
12 | * ===================================================================== | ||
13 | * ToDo: | ||
14 | * | ||
15 | * ===================================================================== | ||
16 | * Version: $Id$ | ||
17 | * ===================================================================== | ||
18 | * History: | ||
19 | * $Log$ | ||
20 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
21 | * libopie1 goes into unsupported | ||
22 | * | ||
23 | * Revision 1.6 2003/04/13 18:07:10 zecke | ||
24 | * More API doc | ||
25 | * QString -> const QString& | ||
26 | * QString = 0l -> QString::null | ||
27 | * | ||
28 | * Revision 1.5 2003/03/21 10:33:09 eilers | ||
29 | * Merged speed optimized xml backend for contacts to main. | ||
30 | * Added QDateTime to querybyexample. For instance, it is now possible to get | ||
31 | * all Birthdays/Anniversaries between two dates. This should be used | ||
32 | * to show all birthdays in the datebook.. | ||
33 | * This change is sourcecode backward compatible but you have to upgrade | ||
34 | * the binaries for today-addressbook. | ||
35 | * | ||
36 | * Revision 1.4 2002/12/07 13:26:22 eilers | ||
37 | * Fixing bug in storing anniversary.. | ||
38 | * | ||
39 | * Revision 1.3 2002/11/13 14:14:51 eilers | ||
40 | * Added sorted for Contacts.. | ||
41 | * | ||
42 | * Revision 1.2 2002/11/10 15:41:53 eilers | ||
43 | * Bugfixes.. | ||
44 | * | ||
45 | * Revision 1.1 2002/11/09 14:34:52 eilers | ||
46 | * Added VCard Backend. | ||
47 | * | ||
48 | */ | ||
49 | #ifndef __OCONTACTACCESSBACKEND_VCARD_H_ | ||
50 | #define __OCONTACTACCESSBACKEND_VCARD_H_ | ||
51 | |||
52 | #include <opie/ocontact.h> | ||
53 | |||
54 | #include "ocontactaccessbackend.h" | ||
55 | |||
56 | class VObject; | ||
57 | |||
58 | /** | ||
59 | * This is the vCard 2.1 implementation of the Contact Storage | ||
60 | * @see OContactAccessBackend_XML | ||
61 | * @see OPimAccessBackend | ||
62 | */ | ||
63 | class OContactAccessBackend_VCard : public OContactAccessBackend { | ||
64 | public: | ||
65 | OContactAccessBackend_VCard ( const QString& appname, const QString& filename = QString::null ); | ||
66 | |||
67 | bool load (); | ||
68 | bool reload(); | ||
69 | bool save(); | ||
70 | void clear (); | ||
71 | |||
72 | bool add ( const OContact& newcontact ); | ||
73 | bool remove ( int uid ); | ||
74 | bool replace ( const OContact& contact ); | ||
75 | |||
76 | OContact find ( int uid ) const; | ||
77 | QArray<int> allRecords() const; | ||
78 | QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); | ||
79 | QArray<int> matchRegexp( const QRegExp &r ) const; | ||
80 | |||
81 | const uint querySettings(); | ||
82 | bool hasQuerySettings (uint querySettings) const; | ||
83 | QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); | ||
84 | bool wasChangedExternally(); | ||
85 | |||
86 | private: | ||
87 | OContact parseVObject( VObject* obj ); | ||
88 | VObject* createVObject( const OContact& c ); | ||
89 | QString convDateToVCardDate( const QDate& c ) const; | ||
90 | QDate convVCardDateToDate( const QString& datestr ); | ||
91 | VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); | ||
92 | VObject *safeAddProp( VObject* o, const char* prop); | ||
93 | |||
94 | bool m_dirty : 1; | ||
95 | QString m_file; | ||
96 | QMap<int, OContact> m_map; | ||
97 | }; | ||
98 | |||
99 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp new file mode 100644 index 0000000..7ceaf5b --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp | |||
@@ -0,0 +1,824 @@ | |||
1 | /* | ||
2 | * XML Backend for the OPIE-Contact Database. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * | ||
13 | * ===================================================================== | ||
14 | * Version: $Id$ | ||
15 | * ===================================================================== | ||
16 | * History: | ||
17 | * $Log$ | ||
18 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
19 | * libopie1 goes into unsupported | ||
20 | * | ||
21 | * Revision 1.10 2004/03/01 15:44:36 chicken | ||
22 | * fix includes | ||
23 | * | ||
24 | * Revision 1.9 2003/09/22 14:31:16 eilers | ||
25 | * Added first experimental incarnation of sql-backend for addressbook. | ||
26 | * Some modifications to be able to compile the todo sql-backend. | ||
27 | * A lot of changes fill follow... | ||
28 | * | ||
29 | * Revision 1.8 2003/08/30 15:28:26 eilers | ||
30 | * Removed some unimportant debug output which causes slow down.. | ||
31 | * | ||
32 | * Revision 1.7 2003/08/01 12:30:16 eilers | ||
33 | * Merging changes from BRANCH_1_0 to HEAD | ||
34 | * | ||
35 | * Revision 1.6 2003/07/07 16:19:47 eilers | ||
36 | * Fixing serious bug in hasQuerySettings() | ||
37 | * | ||
38 | * Revision 1.5 2003/04/13 18:07:10 zecke | ||
39 | * More API doc | ||
40 | * QString -> const QString& | ||
41 | * QString = 0l -> QString::null | ||
42 | * | ||
43 | * Revision 1.4 2003/03/21 14:32:54 mickeyl | ||
44 | * g++ compliance fix: default arguments belong into the declaration, but not the definition | ||
45 | * | ||
46 | * Revision 1.3 2003/03/21 12:26:28 eilers | ||
47 | * Fixing small bug: If we search a birthday from today to today, it returned | ||
48 | * every contact .. | ||
49 | * | ||
50 | * Revision 1.2 2003/03/21 10:33:09 eilers | ||
51 | * Merged speed optimized xml backend for contacts to main. | ||
52 | * Added QDateTime to querybyexample. For instance, it is now possible to get | ||
53 | * all Birthdays/Anniversaries between two dates. This should be used | ||
54 | * to show all birthdays in the datebook.. | ||
55 | * This change is sourcecode backward compatible but you have to upgrade | ||
56 | * the binaries for today-addressbook. | ||
57 | * | ||
58 | * Revision 1.1.2.2 2003/02/11 12:17:28 eilers | ||
59 | * Speed optimization. Removed the sequential search loops. | ||
60 | * | ||
61 | * Revision 1.1.2.1 2003/02/10 15:31:38 eilers | ||
62 | * Writing offsets to debug output.. | ||
63 | * | ||
64 | * Revision 1.1 2003/02/09 15:05:01 eilers | ||
65 | * Nothing happened.. Just some cleanup before I will start.. | ||
66 | * | ||
67 | * Revision 1.12 2003/01/03 16:58:03 eilers | ||
68 | * Reenable debug output | ||
69 | * | ||
70 | * Revision 1.11 2003/01/03 12:31:28 eilers | ||
71 | * Bugfix for calculating data diffs.. | ||
72 | * | ||
73 | * Revision 1.10 2003/01/02 14:27:12 eilers | ||
74 | * Improved query by example: Search by date is possible.. First step | ||
75 | * for a today plugin for birthdays.. | ||
76 | * | ||
77 | * Revision 1.9 2002/12/08 12:48:57 eilers | ||
78 | * Moved journal-enum from ocontact into i the xml-backend.. | ||
79 | * | ||
80 | * Revision 1.8 2002/11/14 17:04:24 eilers | ||
81 | * Sorting will now work if fullname is identical on some entries | ||
82 | * | ||
83 | * Revision 1.7 2002/11/13 15:02:46 eilers | ||
84 | * Small Bug in sorted fixed | ||
85 | * | ||
86 | * Revision 1.6 2002/11/13 14:14:51 eilers | ||
87 | * Added sorted for Contacts.. | ||
88 | * | ||
89 | * Revision 1.5 2002/11/01 15:10:42 eilers | ||
90 | * Added regExp-search in database for all fields in a contact. | ||
91 | * | ||
92 | * Revision 1.4 2002/10/16 10:52:40 eilers | ||
93 | * Added some docu to the interface and now using the cache infrastucture by zecke.. :) | ||
94 | * | ||
95 | * Revision 1.3 2002/10/14 16:21:54 eilers | ||
96 | * Some minor interface updates | ||
97 | * | ||
98 | * Revision 1.2 2002/10/07 17:34:24 eilers | ||
99 | * added OBackendFactory for advanced backend access | ||
100 | * | ||
101 | * Revision 1.1 2002/09/27 17:11:44 eilers | ||
102 | * Added API for accessing the Contact-Database ! It is compiling, but | ||
103 | * please do not expect that anything is working ! | ||
104 | * I will debug that stuff in the next time .. | ||
105 | * Please read README_COMPILE for compiling ! | ||
106 | * | ||
107 | * | ||
108 | */ | ||
109 | |||
110 | #include "ocontactaccessbackend_xml.h" | ||
111 | |||
112 | #include <qasciidict.h> | ||
113 | #include <qfile.h> | ||
114 | #include <qfileinfo.h> | ||
115 | #include <qregexp.h> | ||
116 | #include <qarray.h> | ||
117 | #include <qmap.h> | ||
118 | |||
119 | #include <qpe/global.h> | ||
120 | |||
121 | #include <opie/xmltree.h> | ||
122 | #include "ocontactaccessbackend.h" | ||
123 | #include "ocontactaccess.h" | ||
124 | |||
125 | #include <stdlib.h> | ||
126 | #include <errno.h> | ||
127 | |||
128 | using namespace Opie; | ||
129 | |||
130 | |||
131 | OContactAccessBackend_XML::OContactAccessBackend_XML ( const QString& appname, const QString& filename ): | ||
132 | m_changed( false ) | ||
133 | { | ||
134 | // Just m_contactlist should call delete if an entry | ||
135 | // is removed. | ||
136 | m_contactList.setAutoDelete( true ); | ||
137 | m_uidToContact.setAutoDelete( false ); | ||
138 | |||
139 | m_appName = appname; | ||
140 | |||
141 | /* Set journalfile name ... */ | ||
142 | m_journalName = getenv("HOME"); | ||
143 | m_journalName +="/.abjournal" + appname; | ||
144 | |||
145 | /* Expecting to access the default filename if nothing else is set */ | ||
146 | if ( filename.isEmpty() ){ | ||
147 | m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); | ||
148 | } else | ||
149 | m_fileName = filename; | ||
150 | |||
151 | /* Load Database now */ | ||
152 | load (); | ||
153 | } | ||
154 | |||
155 | bool OContactAccessBackend_XML::save() | ||
156 | { | ||
157 | |||
158 | if ( !m_changed ) | ||
159 | return true; | ||
160 | |||
161 | QString strNewFile = m_fileName + ".new"; | ||
162 | QFile f( strNewFile ); | ||
163 | if ( !f.open( IO_WriteOnly|IO_Raw ) ) | ||
164 | return false; | ||
165 | |||
166 | int total_written; | ||
167 | int idx_offset = 0; | ||
168 | QString out; | ||
169 | |||
170 | // Write Header | ||
171 | out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" | ||
172 | " <Groups>\n" | ||
173 | " </Groups>\n" | ||
174 | " <Contacts>\n"; | ||
175 | QCString cstr = out.utf8(); | ||
176 | f.writeBlock( cstr.data(), cstr.length() ); | ||
177 | idx_offset += cstr.length(); | ||
178 | out = ""; | ||
179 | |||
180 | // Write all contacts | ||
181 | QListIterator<OContact> it( m_contactList ); | ||
182 | for ( ; it.current(); ++it ) { | ||
183 | // qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset ); | ||
184 | out += "<Contact "; | ||
185 | (*it)->save( out ); | ||
186 | out += "/>\n"; | ||
187 | cstr = out.utf8(); | ||
188 | total_written = f.writeBlock( cstr.data(), cstr.length() ); | ||
189 | idx_offset += cstr.length(); | ||
190 | if ( total_written != int(cstr.length()) ) { | ||
191 | f.close(); | ||
192 | QFile::remove( strNewFile ); | ||
193 | return false; | ||
194 | } | ||
195 | out = ""; | ||
196 | } | ||
197 | out += " </Contacts>\n</AddressBook>\n"; | ||
198 | |||
199 | // Write Footer | ||
200 | cstr = out.utf8(); | ||
201 | total_written = f.writeBlock( cstr.data(), cstr.length() ); | ||
202 | if ( total_written != int( cstr.length() ) ) { | ||
203 | f.close(); | ||
204 | QFile::remove( strNewFile ); | ||
205 | return false; | ||
206 | } | ||
207 | f.close(); | ||
208 | |||
209 | // move the file over, I'm just going to use the system call | ||
210 | // because, I don't feel like using QDir. | ||
211 | if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { | ||
212 | qWarning( "problem renaming file %s to %s, errno: %d", | ||
213 | strNewFile.latin1(), m_journalName.latin1(), errno ); | ||
214 | // remove the tmp file... | ||
215 | QFile::remove( strNewFile ); | ||
216 | } | ||
217 | |||
218 | /* The journalfile should be removed now... */ | ||
219 | removeJournal(); | ||
220 | |||
221 | m_changed = false; | ||
222 | return true; | ||
223 | } | ||
224 | |||
225 | bool OContactAccessBackend_XML::load () | ||
226 | { | ||
227 | m_contactList.clear(); | ||
228 | m_uidToContact.clear(); | ||
229 | |||
230 | /* Load XML-File and journal if it exists */ | ||
231 | if ( !load ( m_fileName, false ) ) | ||
232 | return false; | ||
233 | /* The returncode of the journalfile is ignored due to the | ||
234 | * fact that it does not exist when this class is instantiated ! | ||
235 | * But there may such a file exist, if the application crashed. | ||
236 | * Therefore we try to load it to get the changes before the # | ||
237 | * crash happened... | ||
238 | */ | ||
239 | load (m_journalName, true); | ||
240 | |||
241 | return true; | ||
242 | } | ||
243 | |||
244 | void OContactAccessBackend_XML::clear () | ||
245 | { | ||
246 | m_contactList.clear(); | ||
247 | m_uidToContact.clear(); | ||
248 | |||
249 | m_changed = false; | ||
250 | } | ||
251 | |||
252 | bool OContactAccessBackend_XML::wasChangedExternally() | ||
253 | { | ||
254 | QFileInfo fi( m_fileName ); | ||
255 | |||
256 | QDateTime lastmod = fi.lastModified (); | ||
257 | |||
258 | return (lastmod != m_readtime); | ||
259 | } | ||
260 | |||
261 | QArray<int> OContactAccessBackend_XML::allRecords() const | ||
262 | { | ||
263 | QArray<int> uid_list( m_contactList.count() ); | ||
264 | |||
265 | uint counter = 0; | ||
266 | QListIterator<OContact> it( m_contactList ); | ||
267 | for( ; it.current(); ++it ){ | ||
268 | uid_list[counter++] = (*it)->uid(); | ||
269 | } | ||
270 | |||
271 | return ( uid_list ); | ||
272 | } | ||
273 | |||
274 | OContact OContactAccessBackend_XML::find ( int uid ) const | ||
275 | { | ||
276 | OContact foundContact; //Create empty contact | ||
277 | |||
278 | OContact* found = m_uidToContact.find( QString().setNum( uid ) ); | ||
279 | |||
280 | if ( found ){ | ||
281 | foundContact = *found; | ||
282 | } | ||
283 | |||
284 | return ( foundContact ); | ||
285 | } | ||
286 | |||
287 | QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings, | ||
288 | const QDateTime& d ) | ||
289 | { | ||
290 | |||
291 | QArray<int> m_currentQuery( m_contactList.count() ); | ||
292 | QListIterator<OContact> it( m_contactList ); | ||
293 | uint arraycounter = 0; | ||
294 | |||
295 | for( ; it.current(); ++it ){ | ||
296 | /* Search all fields and compare them with query object. Store them into list | ||
297 | * if all fields matches. | ||
298 | */ | ||
299 | QDate* queryDate = 0l; | ||
300 | QDate* checkDate = 0l; | ||
301 | bool allcorrect = true; | ||
302 | for ( int i = 0; i < Qtopia::Groups; i++ ) { | ||
303 | // Birthday and anniversary are special nonstring fields and should | ||
304 | // be handled specially | ||
305 | switch ( i ){ | ||
306 | case Qtopia::Birthday: | ||
307 | queryDate = new QDate( query.birthday() ); | ||
308 | checkDate = new QDate( (*it)->birthday() ); | ||
309 | case Qtopia::Anniversary: | ||
310 | if ( queryDate == 0l ){ | ||
311 | queryDate = new QDate( query.anniversary() ); | ||
312 | checkDate = new QDate( (*it)->anniversary() ); | ||
313 | } | ||
314 | |||
315 | if ( queryDate->isValid() ){ | ||
316 | if( checkDate->isValid() ){ | ||
317 | if ( settings & OContactAccess::DateYear ){ | ||
318 | if ( queryDate->year() != checkDate->year() ) | ||
319 | allcorrect = false; | ||
320 | } | ||
321 | if ( settings & OContactAccess::DateMonth ){ | ||
322 | if ( queryDate->month() != checkDate->month() ) | ||
323 | allcorrect = false; | ||
324 | } | ||
325 | if ( settings & OContactAccess::DateDay ){ | ||
326 | if ( queryDate->day() != checkDate->day() ) | ||
327 | allcorrect = false; | ||
328 | } | ||
329 | if ( settings & OContactAccess::DateDiff ) { | ||
330 | QDate current; | ||
331 | // If we get an additional date, we | ||
332 | // will take this date instead of | ||
333 | // the current one.. | ||
334 | if ( !d.date().isValid() ) | ||
335 | current = QDate::currentDate(); | ||
336 | else | ||
337 | current = d.date(); | ||
338 | |||
339 | // We have to equalize the year, otherwise | ||
340 | // the search will fail.. | ||
341 | checkDate->setYMD( current.year(), | ||
342 | checkDate->month(), | ||
343 | checkDate->day() ); | ||
344 | if ( *checkDate < current ) | ||
345 | checkDate->setYMD( current.year()+1, | ||
346 | checkDate->month(), | ||
347 | checkDate->day() ); | ||
348 | |||
349 | // Check whether the birthday/anniversary date is between | ||
350 | // the current/given date and the maximum date | ||
351 | // ( maximum time range ) ! | ||
352 | qWarning("Checking if %s is between %s and %s ! ", | ||
353 | checkDate->toString().latin1(), | ||
354 | current.toString().latin1(), | ||
355 | queryDate->toString().latin1() ); | ||
356 | if ( current.daysTo( *queryDate ) >= 0 ){ | ||
357 | if ( !( ( *checkDate >= current ) && | ||
358 | ( *checkDate <= *queryDate ) ) ){ | ||
359 | allcorrect = false; | ||
360 | qWarning (" Nope!.."); | ||
361 | } | ||
362 | } | ||
363 | } | ||
364 | } else{ | ||
365 | // checkDate is invalid. Therefore this entry is always rejected | ||
366 | allcorrect = false; | ||
367 | } | ||
368 | } | ||
369 | |||
370 | delete queryDate; | ||
371 | queryDate = 0l; | ||
372 | delete checkDate; | ||
373 | checkDate = 0l; | ||
374 | break; | ||
375 | default: | ||
376 | /* Just compare fields which are not empty in the query object */ | ||
377 | if ( !query.field(i).isEmpty() ){ | ||
378 | switch ( settings & ~( OContactAccess::IgnoreCase | ||
379 | | OContactAccess::DateDiff | ||
380 | | OContactAccess::DateYear | ||
381 | | OContactAccess::DateMonth | ||
382 | | OContactAccess::DateDay | ||
383 | | OContactAccess::MatchOne | ||
384 | ) ){ | ||
385 | |||
386 | case OContactAccess::RegExp:{ | ||
387 | QRegExp expr ( query.field(i), | ||
388 | !(settings & OContactAccess::IgnoreCase), | ||
389 | false ); | ||
390 | if ( expr.find ( (*it)->field(i), 0 ) == -1 ) | ||
391 | allcorrect = false; | ||
392 | } | ||
393 | break; | ||
394 | case OContactAccess::WildCards:{ | ||
395 | QRegExp expr ( query.field(i), | ||
396 | !(settings & OContactAccess::IgnoreCase), | ||
397 | true ); | ||
398 | if ( expr.find ( (*it)->field(i), 0 ) == -1 ) | ||
399 | allcorrect = false; | ||
400 | } | ||
401 | break; | ||
402 | case OContactAccess::ExactMatch:{ | ||
403 | if (settings & OContactAccess::IgnoreCase){ | ||
404 | if ( query.field(i).upper() != | ||
405 | (*it)->field(i).upper() ) | ||
406 | allcorrect = false; | ||
407 | }else{ | ||
408 | if ( query.field(i) != (*it)->field(i) ) | ||
409 | allcorrect = false; | ||
410 | } | ||
411 | } | ||
412 | break; | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | } | ||
417 | if ( allcorrect ){ | ||
418 | m_currentQuery[arraycounter++] = (*it)->uid(); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | // Shrink to fit.. | ||
423 | m_currentQuery.resize(arraycounter); | ||
424 | |||
425 | return m_currentQuery; | ||
426 | } | ||
427 | |||
428 | QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const | ||
429 | { | ||
430 | QArray<int> m_currentQuery( m_contactList.count() ); | ||
431 | QListIterator<OContact> it( m_contactList ); | ||
432 | uint arraycounter = 0; | ||
433 | |||
434 | for( ; it.current(); ++it ){ | ||
435 | if ( (*it)->match( r ) ){ | ||
436 | m_currentQuery[arraycounter++] = (*it)->uid(); | ||
437 | } | ||
438 | |||
439 | } | ||
440 | // Shrink to fit.. | ||
441 | m_currentQuery.resize(arraycounter); | ||
442 | |||
443 | return m_currentQuery; | ||
444 | } | ||
445 | |||
446 | const uint OContactAccessBackend_XML::querySettings() | ||
447 | { | ||
448 | return ( OContactAccess::WildCards | ||
449 | | OContactAccess::IgnoreCase | ||
450 | | OContactAccess::RegExp | ||
451 | | OContactAccess::ExactMatch | ||
452 | | OContactAccess::DateDiff | ||
453 | | OContactAccess::DateYear | ||
454 | | OContactAccess::DateMonth | ||
455 | | OContactAccess::DateDay | ||
456 | ); | ||
457 | } | ||
458 | |||
459 | bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const | ||
460 | { | ||
461 | /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay | ||
462 | * may be added with any of the other settings. IgnoreCase should never used alone. | ||
463 | * Wildcards, RegExp, ExactMatch should never used at the same time... | ||
464 | */ | ||
465 | |||
466 | // Step 1: Check whether the given settings are supported by this backend | ||
467 | if ( ( querySettings & ( | ||
468 | OContactAccess::IgnoreCase | ||
469 | | OContactAccess::WildCards | ||
470 | | OContactAccess::DateDiff | ||
471 | | OContactAccess::DateYear | ||
472 | | OContactAccess::DateMonth | ||
473 | | OContactAccess::DateDay | ||
474 | | OContactAccess::RegExp | ||
475 | | OContactAccess::ExactMatch | ||
476 | ) ) != querySettings ) | ||
477 | return false; | ||
478 | |||
479 | // Step 2: Check whether the given combinations are ok.. | ||
480 | |||
481 | // IngoreCase alone is invalid | ||
482 | if ( querySettings == OContactAccess::IgnoreCase ) | ||
483 | return false; | ||
484 | |||
485 | // WildCards, RegExp and ExactMatch should never used at the same time | ||
486 | switch ( querySettings & ~( OContactAccess::IgnoreCase | ||
487 | | OContactAccess::DateDiff | ||
488 | | OContactAccess::DateYear | ||
489 | | OContactAccess::DateMonth | ||
490 | | OContactAccess::DateDay | ||
491 | ) | ||
492 | ){ | ||
493 | case OContactAccess::RegExp: | ||
494 | return ( true ); | ||
495 | case OContactAccess::WildCards: | ||
496 | return ( true ); | ||
497 | case OContactAccess::ExactMatch: | ||
498 | return ( true ); | ||
499 | case 0: // one of the upper removed bits were set.. | ||
500 | return ( true ); | ||
501 | default: | ||
502 | return ( false ); | ||
503 | } | ||
504 | } | ||
505 | |||
506 | // Currently only asc implemented.. | ||
507 | QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) | ||
508 | { | ||
509 | QMap<QString, int> nameToUid; | ||
510 | QStringList names; | ||
511 | QArray<int> m_currentQuery( m_contactList.count() ); | ||
512 | |||
513 | // First fill map and StringList with all Names | ||
514 | // Afterwards sort namelist and use map to fill array to return.. | ||
515 | QListIterator<OContact> it( m_contactList ); | ||
516 | for( ; it.current(); ++it ){ | ||
517 | names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) ); | ||
518 | nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() ); | ||
519 | } | ||
520 | names.sort(); | ||
521 | |||
522 | int i = 0; | ||
523 | if ( asc ){ | ||
524 | for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) | ||
525 | m_currentQuery[i++] = nameToUid[ (*it) ]; | ||
526 | }else{ | ||
527 | for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) | ||
528 | m_currentQuery[i++] = nameToUid[ (*it) ]; | ||
529 | } | ||
530 | |||
531 | return m_currentQuery; | ||
532 | |||
533 | } | ||
534 | |||
535 | bool OContactAccessBackend_XML::add ( const OContact &newcontact ) | ||
536 | { | ||
537 | //qWarning("odefaultbackend: ACTION::ADD"); | ||
538 | updateJournal (newcontact, ACTION_ADD); | ||
539 | addContact_p( newcontact ); | ||
540 | |||
541 | m_changed = true; | ||
542 | |||
543 | return true; | ||
544 | } | ||
545 | |||
546 | bool OContactAccessBackend_XML::replace ( const OContact &contact ) | ||
547 | { | ||
548 | m_changed = true; | ||
549 | |||
550 | OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) ); | ||
551 | |||
552 | if ( found ) { | ||
553 | OContact* newCont = new OContact( contact ); | ||
554 | |||
555 | updateJournal ( *newCont, ACTION_REPLACE); | ||
556 | m_contactList.removeRef ( found ); | ||
557 | m_contactList.append ( newCont ); | ||
558 | m_uidToContact.remove( QString().setNum( contact.uid() ) ); | ||
559 | m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont ); | ||
560 | |||
561 | qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid()); | ||
562 | |||
563 | return true; | ||
564 | } else | ||
565 | return false; | ||
566 | } | ||
567 | |||
568 | bool OContactAccessBackend_XML::remove ( int uid ) | ||
569 | { | ||
570 | m_changed = true; | ||
571 | |||
572 | OContact* found = m_uidToContact.find ( QString().setNum( uid ) ); | ||
573 | |||
574 | if ( found ) { | ||
575 | updateJournal ( *found, ACTION_REMOVE); | ||
576 | m_contactList.removeRef ( found ); | ||
577 | m_uidToContact.remove( QString().setNum( uid ) ); | ||
578 | |||
579 | return true; | ||
580 | } else | ||
581 | return false; | ||
582 | } | ||
583 | |||
584 | bool OContactAccessBackend_XML::reload(){ | ||
585 | /* Reload is the same as load in this implementation */ | ||
586 | return ( load() ); | ||
587 | } | ||
588 | |||
589 | void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) | ||
590 | { | ||
591 | OContact* contRef = new OContact( newcontact ); | ||
592 | |||
593 | m_contactList.append ( contRef ); | ||
594 | m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef ); | ||
595 | } | ||
596 | |||
597 | /* This function loads the xml-database and the journalfile */ | ||
598 | bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) | ||
599 | { | ||
600 | |||
601 | /* We use the time of the last read to check if the file was | ||
602 | * changed externally. | ||
603 | */ | ||
604 | if ( !isJournal ){ | ||
605 | QFileInfo fi( filename ); | ||
606 | m_readtime = fi.lastModified (); | ||
607 | } | ||
608 | |||
609 | const int JOURNALACTION = Qtopia::Notes + 1; | ||
610 | const int JOURNALROW = JOURNALACTION + 1; | ||
611 | |||
612 | bool foundAction = false; | ||
613 | journal_action action = ACTION_ADD; | ||
614 | int journalKey = 0; | ||
615 | QMap<int, QString> contactMap; | ||
616 | QMap<QString, QString> customMap; | ||
617 | QMap<QString, QString>::Iterator customIt; | ||
618 | QAsciiDict<int> dict( 47 ); | ||
619 | |||
620 | dict.setAutoDelete( TRUE ); | ||
621 | dict.insert( "Uid", new int(Qtopia::AddressUid) ); | ||
622 | dict.insert( "Title", new int(Qtopia::Title) ); | ||
623 | dict.insert( "FirstName", new int(Qtopia::FirstName) ); | ||
624 | dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); | ||
625 | dict.insert( "LastName", new int(Qtopia::LastName) ); | ||
626 | dict.insert( "Suffix", new int(Qtopia::Suffix) ); | ||
627 | dict.insert( "FileAs", new int(Qtopia::FileAs) ); | ||
628 | dict.insert( "Categories", new int(Qtopia::AddressCategory) ); | ||
629 | dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); | ||
630 | dict.insert( "Emails", new int(Qtopia::Emails) ); | ||
631 | dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); | ||
632 | dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); | ||
633 | dict.insert( "HomeState", new int(Qtopia::HomeState) ); | ||
634 | dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); | ||
635 | dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); | ||
636 | dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); | ||
637 | dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); | ||
638 | dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); | ||
639 | dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); | ||
640 | dict.insert( "Company", new int(Qtopia::Company) ); | ||
641 | dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); | ||
642 | dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); | ||
643 | dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); | ||
644 | dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); | ||
645 | dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); | ||
646 | dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); | ||
647 | dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); | ||
648 | dict.insert( "Department", new int(Qtopia::Department) ); | ||
649 | dict.insert( "Office", new int(Qtopia::Office) ); | ||
650 | dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); | ||
651 | dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); | ||
652 | dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); | ||
653 | dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); | ||
654 | dict.insert( "Profession", new int(Qtopia::Profession) ); | ||
655 | dict.insert( "Assistant", new int(Qtopia::Assistant) ); | ||
656 | dict.insert( "Manager", new int(Qtopia::Manager) ); | ||
657 | dict.insert( "Spouse", new int(Qtopia::Spouse) ); | ||
658 | dict.insert( "Children", new int(Qtopia::Children) ); | ||
659 | dict.insert( "Gender", new int(Qtopia::Gender) ); | ||
660 | dict.insert( "Birthday", new int(Qtopia::Birthday) ); | ||
661 | dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); | ||
662 | dict.insert( "Nickname", new int(Qtopia::Nickname) ); | ||
663 | dict.insert( "Notes", new int(Qtopia::Notes) ); | ||
664 | dict.insert( "action", new int(JOURNALACTION) ); | ||
665 | dict.insert( "actionrow", new int(JOURNALROW) ); | ||
666 | |||
667 | //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); | ||
668 | |||
669 | XMLElement *root = XMLElement::load( filename ); | ||
670 | if(root != 0l ){ // start parsing | ||
671 | /* Parse all XML-Elements and put the data into the | ||
672 | * Contact-Class | ||
673 | */ | ||
674 | XMLElement *element = root->firstChild(); | ||
675 | //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); | ||
676 | element = element->firstChild(); | ||
677 | |||
678 | /* Search Tag "Contacts" which is the parent of all Contacts */ | ||
679 | while( element && !isJournal ){ | ||
680 | if( element->tagName() != QString::fromLatin1("Contacts") ){ | ||
681 | //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", | ||
682 | // element->tagName().latin1()); | ||
683 | element = element->nextChild(); | ||
684 | } else { | ||
685 | element = element->firstChild(); | ||
686 | break; | ||
687 | } | ||
688 | } | ||
689 | /* Parse all Contacts and ignore unknown tags */ | ||
690 | while( element ){ | ||
691 | if( element->tagName() != QString::fromLatin1("Contact") ){ | ||
692 | //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", | ||
693 | // element->tagName().latin1()); | ||
694 | element = element->nextChild(); | ||
695 | continue; | ||
696 | } | ||
697 | /* Found alement with tagname "contact", now parse and store all | ||
698 | * attributes contained | ||
699 | */ | ||
700 | //qWarning("OContactDefBack::load element tagName() : %s", | ||
701 | // element->tagName().latin1() ); | ||
702 | QString dummy; | ||
703 | foundAction = false; | ||
704 | |||
705 | XMLElement::AttributeMap aMap = element->attributes(); | ||
706 | XMLElement::AttributeMap::Iterator it; | ||
707 | contactMap.clear(); | ||
708 | customMap.clear(); | ||
709 | for( it = aMap.begin(); it != aMap.end(); ++it ){ | ||
710 | // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); | ||
711 | |||
712 | int *find = dict[ it.key() ]; | ||
713 | /* Unknown attributes will be stored as "Custom" elements */ | ||
714 | if ( !find ) { | ||
715 | // qWarning("Attribute %s not known.", it.key().latin1()); | ||
716 | //contact.setCustomField(it.key(), it.data()); | ||
717 | customMap.insert( it.key(), it.data() ); | ||
718 | continue; | ||
719 | } | ||
720 | |||
721 | /* Check if special conversion is needed and add attribute | ||
722 | * into Contact class | ||
723 | */ | ||
724 | switch( *find ) { | ||
725 | /* | ||
726 | case Qtopia::AddressUid: | ||
727 | contact.setUid( it.data().toInt() ); | ||
728 | break; | ||
729 | case Qtopia::AddressCategory: | ||
730 | contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); | ||
731 | break; | ||
732 | */ | ||
733 | case JOURNALACTION: | ||
734 | action = journal_action(it.data().toInt()); | ||
735 | foundAction = true; | ||
736 | qWarning ("ODefBack(journal)::ACTION found: %d", action); | ||
737 | break; | ||
738 | case JOURNALROW: | ||
739 | journalKey = it.data().toInt(); | ||
740 | break; | ||
741 | default: // no conversion needed add them to the map | ||
742 | contactMap.insert( *find, it.data() ); | ||
743 | break; | ||
744 | } | ||
745 | } | ||
746 | /* now generate the Contact contact */ | ||
747 | OContact contact( contactMap ); | ||
748 | |||
749 | for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { | ||
750 | contact.setCustomField( customIt.key(), customIt.data() ); | ||
751 | } | ||
752 | |||
753 | if (foundAction){ | ||
754 | foundAction = false; | ||
755 | switch ( action ) { | ||
756 | case ACTION_ADD: | ||
757 | addContact_p (contact); | ||
758 | break; | ||
759 | case ACTION_REMOVE: | ||
760 | if ( !remove (contact.uid()) ) | ||
761 | qWarning ("ODefBack(journal)::Unable to remove uid: %d", | ||
762 | contact.uid() ); | ||
763 | break; | ||
764 | case ACTION_REPLACE: | ||
765 | if ( !replace ( contact ) ) | ||
766 | qWarning ("ODefBack(journal)::Unable to replace uid: %d", | ||
767 | contact.uid() ); | ||
768 | break; | ||
769 | default: | ||
770 | qWarning ("Unknown action: ignored !"); | ||
771 | break; | ||
772 | } | ||
773 | }else{ | ||
774 | /* Add contact to list */ | ||
775 | addContact_p (contact); | ||
776 | } | ||
777 | |||
778 | /* Move to next element */ | ||
779 | element = element->nextChild(); | ||
780 | } | ||
781 | }else { | ||
782 | qWarning("ODefBack::could not load"); | ||
783 | } | ||
784 | delete root; | ||
785 | qWarning("returning from loading" ); | ||
786 | return true; | ||
787 | } | ||
788 | |||
789 | |||
790 | void OContactAccessBackend_XML::updateJournal( const OContact& cnt, | ||
791 | journal_action action ) | ||
792 | { | ||
793 | QFile f( m_journalName ); | ||
794 | bool created = !f.exists(); | ||
795 | if ( !f.open(IO_WriteOnly|IO_Append) ) | ||
796 | return; | ||
797 | |||
798 | QString buf; | ||
799 | QCString str; | ||
800 | |||
801 | // if the file was created, we have to set the Tag "<CONTACTS>" to | ||
802 | // get a XML-File which is readable by our parser. | ||
803 | // This is just a cheat, but better than rewrite the parser. | ||
804 | if ( created ){ | ||
805 | buf = "<Contacts>"; | ||
806 | QCString cstr = buf.utf8(); | ||
807 | f.writeBlock( cstr.data(), cstr.length() ); | ||
808 | } | ||
809 | |||
810 | buf = "<Contact "; | ||
811 | cnt.save( buf ); | ||
812 | buf += " action=\"" + QString::number( (int)action ) + "\" "; | ||
813 | buf += "/>\n"; | ||
814 | QCString cstr = buf.utf8(); | ||
815 | f.writeBlock( cstr.data(), cstr.length() ); | ||
816 | } | ||
817 | |||
818 | void OContactAccessBackend_XML::removeJournal() | ||
819 | { | ||
820 | QFile f ( m_journalName ); | ||
821 | if ( f.exists() ) | ||
822 | f.remove(); | ||
823 | } | ||
824 | |||
diff --git a/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.h b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.h new file mode 100644 index 0000000..6857844 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.h | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * XML Backend for the OPIE-Contact Database. | ||
3 | * | ||
4 | * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * ToDo: XML-Backend: Automatic reload if something was changed... | ||
13 | * File Locking to protect against concurrent access | ||
14 | * | ||
15 | * | ||
16 | * ===================================================================== | ||
17 | * Version: $Id$ | ||
18 | * ===================================================================== | ||
19 | * History: | ||
20 | * $Log$ | ||
21 | * Revision 1.1 2004/11/16 21:46:07 mickeyl | ||
22 | * libopie1 goes into unsupported | ||
23 | * | ||
24 | * Revision 1.15 2003/09/22 14:31:16 eilers | ||
25 | * Added first experimental incarnation of sql-backend for addressbook. | ||
26 | * Some modifications to be able to compile the todo sql-backend. | ||
27 | * A lot of changes fill follow... | ||
28 | * | ||
29 | * Revision 1.14 2003/04/13 18:07:10 zecke | ||
30 | * More API doc | ||
31 | * QString -> const QString& | ||
32 | * QString = 0l -> QString::null | ||
33 | * | ||
34 | * Revision 1.13 2003/03/21 10:33:09 eilers | ||
35 | * Merged speed optimized xml backend for contacts to main. | ||
36 | * Added QDateTime to querybyexample. For instance, it is now possible to get | ||
37 | * all Birthdays/Anniversaries between two dates. This should be used | ||
38 | * to show all birthdays in the datebook.. | ||
39 | * This change is sourcecode backward compatible but you have to upgrade | ||
40 | * the binaries for today-addressbook. | ||
41 | * | ||
42 | * Revision 1.12.2.2 2003/02/11 12:17:28 eilers | ||
43 | * Speed optimization. Removed the sequential search loops. | ||
44 | * | ||
45 | * Revision 1.12.2.1 2003/02/09 15:05:01 eilers | ||
46 | * Nothing happened.. Just some cleanup before I will start.. | ||
47 | * | ||
48 | * Revision 1.12 2003/01/03 16:58:03 eilers | ||
49 | * Reenable debug output | ||
50 | * | ||
51 | * Revision 1.11 2003/01/03 12:31:28 eilers | ||
52 | * Bugfix for calculating data diffs.. | ||
53 | * | ||
54 | * Revision 1.10 2003/01/02 14:27:12 eilers | ||
55 | * Improved query by example: Search by date is possible.. First step | ||
56 | * for a today plugin for birthdays.. | ||
57 | * | ||
58 | * Revision 1.9 2002/12/08 12:48:57 eilers | ||
59 | * Moved journal-enum from ocontact into i the xml-backend.. | ||
60 | * | ||
61 | * Revision 1.8 2002/11/14 17:04:24 eilers | ||
62 | * Sorting will now work if fullname is identical on some entries | ||
63 | * | ||
64 | * Revision 1.7 2002/11/13 15:02:46 eilers | ||
65 | * Small Bug in sorted fixed | ||
66 | * | ||
67 | * Revision 1.6 2002/11/13 14:14:51 eilers | ||
68 | * Added sorted for Contacts.. | ||
69 | * | ||
70 | * Revision 1.5 2002/11/01 15:10:42 eilers | ||
71 | * Added regExp-search in database for all fields in a contact. | ||
72 | * | ||
73 | * Revision 1.4 2002/10/16 10:52:40 eilers | ||
74 | * Added some docu to the interface and now using the cache infrastucture by zecke.. :) | ||
75 | * | ||
76 | * Revision 1.3 2002/10/14 16:21:54 eilers | ||
77 | * Some minor interface updates | ||
78 | * | ||
79 | * Revision 1.2 2002/10/07 17:34:24 eilers | ||
80 | * added OBackendFactory for advanced backend access | ||
81 | * | ||
82 | * Revision 1.1 2002/09/27 17:11:44 eilers | ||
83 | * Added API for accessing the Contact-Database ! It is compiling, but | ||
84 | * please do not expect that anything is working ! | ||
85 | * I will debug that stuff in the next time .. | ||
86 | * Please read README_COMPILE for compiling ! | ||
87 | * | ||
88 | * | ||
89 | */ | ||
90 | |||
91 | #ifndef _OContactAccessBackend_XML_ | ||
92 | #define _OContactAccessBackend_XML_ | ||
93 | |||
94 | #include "ocontactaccessbackend.h" | ||
95 | #include "ocontactaccess.h" | ||
96 | |||
97 | #include <qlist.h> | ||
98 | #include <qdict.h> | ||
99 | |||
100 | /* the default xml implementation */ | ||
101 | /** | ||
102 | * This class is the XML implementation of a Contact backend | ||
103 | * it does implement everything available for OContact. | ||
104 | * @see OPimAccessBackend for more information of available methods | ||
105 | */ | ||
106 | class OContactAccessBackend_XML : public OContactAccessBackend { | ||
107 | public: | ||
108 | OContactAccessBackend_XML ( const QString& appname, const QString& filename = QString::null ); | ||
109 | |||
110 | bool save(); | ||
111 | |||
112 | bool load (); | ||
113 | |||
114 | void clear (); | ||
115 | |||
116 | bool wasChangedExternally(); | ||
117 | |||
118 | QArray<int> allRecords() const; | ||
119 | |||
120 | OContact find ( int uid ) const; | ||
121 | |||
122 | QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); | ||
123 | |||
124 | QArray<int> matchRegexp( const QRegExp &r ) const; | ||
125 | |||
126 | const uint querySettings(); | ||
127 | |||
128 | bool hasQuerySettings (uint querySettings) const; | ||
129 | |||
130 | // Currently only asc implemented.. | ||
131 | QArray<int> sorted( bool asc, int , int , int ); | ||
132 | bool add ( const OContact &newcontact ); | ||
133 | |||
134 | bool replace ( const OContact &contact ); | ||
135 | |||
136 | bool remove ( int uid ); | ||
137 | bool reload(); | ||
138 | |||
139 | private: | ||
140 | |||
141 | enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; | ||
142 | |||
143 | void addContact_p( const OContact &newcontact ); | ||
144 | |||
145 | /* This function loads the xml-database and the journalfile */ | ||
146 | bool load( const QString filename, bool isJournal ); | ||
147 | |||
148 | |||
149 | void updateJournal( const OContact& cnt, journal_action action ); | ||
150 | void removeJournal(); | ||
151 | |||
152 | protected: | ||
153 | bool m_changed; | ||
154 | QString m_journalName; | ||
155 | QString m_fileName; | ||
156 | QString m_appName; | ||
157 | QList<OContact> m_contactList; | ||
158 | QDateTime m_readtime; | ||
159 | |||
160 | QDict<OContact> m_uidToContact; | ||
161 | }; | ||
162 | |||
163 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactfields.cpp b/noncore/unsupported/libopie/pim/ocontactfields.cpp new file mode 100644 index 0000000..0f08a5a --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactfields.cpp | |||
@@ -0,0 +1,477 @@ | |||
1 | |||
2 | #include "ocontactfields.h" | ||
3 | |||
4 | #include <qstringlist.h> | ||
5 | #include <qobject.h> | ||
6 | |||
7 | // We should use our own enum in the future .. | ||
8 | #include <qpe/recordfields.h> | ||
9 | #include <qpe/config.h> | ||
10 | #include <opie/ocontact.h> | ||
11 | |||
12 | /*! | ||
13 | \internal | ||
14 | Returns a list of personal field names for a contact. | ||
15 | */ | ||
16 | QStringList OContactFields::personalfields( bool sorted, bool translated ) | ||
17 | { | ||
18 | QStringList list; | ||
19 | QMap<int, QString> mapIdToStr; | ||
20 | if ( translated ) | ||
21 | mapIdToStr = idToTrFields(); | ||
22 | else | ||
23 | mapIdToStr = idToUntrFields(); | ||
24 | |||
25 | list.append( mapIdToStr[ Qtopia::AddressUid ] ); | ||
26 | list.append( mapIdToStr[ Qtopia::AddressCategory ] ); | ||
27 | |||
28 | list.append( mapIdToStr[ Qtopia::Title ] ); | ||
29 | list.append( mapIdToStr[ Qtopia::FirstName ] ); | ||
30 | list.append( mapIdToStr[ Qtopia::MiddleName ] ); | ||
31 | list.append( mapIdToStr[ Qtopia::LastName ] ); | ||
32 | list.append( mapIdToStr[ Qtopia::Suffix ] ); | ||
33 | list.append( mapIdToStr[ Qtopia::FileAs ] ); | ||
34 | |||
35 | list.append( mapIdToStr[ Qtopia::JobTitle ] ); | ||
36 | list.append( mapIdToStr[ Qtopia::Department ] ); | ||
37 | list.append( mapIdToStr[ Qtopia::Company ] ); | ||
38 | |||
39 | list.append( mapIdToStr[ Qtopia::Notes ] ); | ||
40 | list.append( mapIdToStr[ Qtopia::Groups ] ); | ||
41 | |||
42 | if (sorted) list.sort(); | ||
43 | return list; | ||
44 | } | ||
45 | |||
46 | /*! | ||
47 | \internal | ||
48 | Returns a list of details field names for a contact. | ||
49 | */ | ||
50 | QStringList OContactFields::detailsfields( bool sorted, bool translated ) | ||
51 | { | ||
52 | QStringList list; | ||
53 | QMap<int, QString> mapIdToStr; | ||
54 | if ( translated ) | ||
55 | mapIdToStr = idToTrFields(); | ||
56 | else | ||
57 | mapIdToStr = idToUntrFields(); | ||
58 | |||
59 | list.append( mapIdToStr[ Qtopia::Office ] ); | ||
60 | list.append( mapIdToStr[ Qtopia::Profession ] ); | ||
61 | list.append( mapIdToStr[ Qtopia::Assistant ] ); | ||
62 | list.append( mapIdToStr[ Qtopia::Manager ] ); | ||
63 | |||
64 | list.append( mapIdToStr[ Qtopia::Spouse ] ); | ||
65 | list.append( mapIdToStr[ Qtopia::Gender ] ); | ||
66 | list.append( mapIdToStr[ Qtopia::Birthday ] ); | ||
67 | list.append( mapIdToStr[ Qtopia::Anniversary ] ); | ||
68 | list.append( mapIdToStr[ Qtopia::Nickname ] ); | ||
69 | list.append( mapIdToStr[ Qtopia::Children ] ); | ||
70 | |||
71 | if (sorted) list.sort(); | ||
72 | return list; | ||
73 | } | ||
74 | |||
75 | /*! | ||
76 | \internal | ||
77 | Returns a list of phone field names for a contact. | ||
78 | */ | ||
79 | QStringList OContactFields::phonefields( bool sorted, bool translated ) | ||
80 | { | ||
81 | QStringList list; | ||
82 | QMap<int, QString> mapIdToStr; | ||
83 | if ( translated ) | ||
84 | mapIdToStr = idToTrFields(); | ||
85 | else | ||
86 | mapIdToStr = idToUntrFields(); | ||
87 | |||
88 | list.append( mapIdToStr[Qtopia::BusinessPhone] ); | ||
89 | list.append( mapIdToStr[Qtopia::BusinessFax] ); | ||
90 | list.append( mapIdToStr[Qtopia::BusinessMobile] ); | ||
91 | list.append( mapIdToStr[Qtopia::BusinessPager] ); | ||
92 | list.append( mapIdToStr[Qtopia::BusinessWebPage] ); | ||
93 | |||
94 | list.append( mapIdToStr[Qtopia::DefaultEmail] ); | ||
95 | list.append( mapIdToStr[Qtopia::Emails] ); | ||
96 | |||
97 | list.append( mapIdToStr[Qtopia::HomePhone] ); | ||
98 | list.append( mapIdToStr[Qtopia::HomeFax] ); | ||
99 | list.append( mapIdToStr[Qtopia::HomeMobile] ); | ||
100 | // list.append( mapIdToStr[Qtopia::HomePager] ); | ||
101 | list.append( mapIdToStr[Qtopia::HomeWebPage] ); | ||
102 | |||
103 | if (sorted) list.sort(); | ||
104 | |||
105 | return list; | ||
106 | } | ||
107 | |||
108 | /*! | ||
109 | \internal | ||
110 | Returns a list of field names for a contact. | ||
111 | */ | ||
112 | QStringList OContactFields::fields( bool sorted, bool translated ) | ||
113 | { | ||
114 | QStringList list; | ||
115 | QMap<int, QString> mapIdToStr; | ||
116 | if ( translated ) | ||
117 | mapIdToStr = idToTrFields(); | ||
118 | else | ||
119 | mapIdToStr = idToUntrFields(); | ||
120 | |||
121 | list += personalfields( sorted, translated ); | ||
122 | |||
123 | list += phonefields( sorted, translated ); | ||
124 | |||
125 | list.append( mapIdToStr[Qtopia::BusinessStreet] ); | ||
126 | list.append( mapIdToStr[Qtopia::BusinessCity] ); | ||
127 | list.append( mapIdToStr[Qtopia::BusinessState] ); | ||
128 | list.append( mapIdToStr[Qtopia::BusinessZip] ); | ||
129 | list.append( mapIdToStr[Qtopia::BusinessCountry] ); | ||
130 | |||
131 | list.append( mapIdToStr[Qtopia::HomeStreet] ); | ||
132 | list.append( mapIdToStr[Qtopia::HomeCity] ); | ||
133 | list.append( mapIdToStr[Qtopia::HomeState] ); | ||
134 | list.append( mapIdToStr[Qtopia::HomeZip] ); | ||
135 | list.append( mapIdToStr[Qtopia::HomeCountry] ); | ||
136 | |||
137 | list += detailsfields( sorted, translated ); | ||
138 | |||
139 | if (sorted) list.sort(); | ||
140 | |||
141 | return list; | ||
142 | } | ||
143 | |||
144 | |||
145 | /*! | ||
146 | \internal | ||
147 | Returns an untranslated list of personal field names for a contact. | ||
148 | */ | ||
149 | QStringList OContactFields::untrpersonalfields( bool sorted ) | ||
150 | { | ||
151 | return personalfields( sorted, false ); | ||
152 | } | ||
153 | |||
154 | |||
155 | /*! | ||
156 | \internal | ||
157 | Returns a translated list of personal field names for a contact. | ||
158 | */ | ||
159 | QStringList OContactFields::trpersonalfields( bool sorted ) | ||
160 | { | ||
161 | return personalfields( sorted, true ); | ||
162 | } | ||
163 | |||
164 | |||
165 | /*! | ||
166 | \internal | ||
167 | Returns an untranslated list of details field names for a contact. | ||
168 | */ | ||
169 | QStringList OContactFields::untrdetailsfields( bool sorted ) | ||
170 | { | ||
171 | return detailsfields( sorted, false ); | ||
172 | } | ||
173 | |||
174 | |||
175 | /*! | ||
176 | \internal | ||
177 | Returns a translated list of details field names for a contact. | ||
178 | */ | ||
179 | QStringList OContactFields::trdetailsfields( bool sorted ) | ||
180 | { | ||
181 | return detailsfields( sorted, true ); | ||
182 | } | ||
183 | |||
184 | |||
185 | /*! | ||
186 | \internal | ||
187 | Returns a translated list of phone field names for a contact. | ||
188 | */ | ||
189 | QStringList OContactFields::trphonefields( bool sorted ) | ||
190 | { | ||
191 | return phonefields( sorted, true ); | ||
192 | } | ||
193 | |||
194 | /*! | ||
195 | \internal | ||
196 | Returns an untranslated list of phone field names for a contact. | ||
197 | */ | ||
198 | QStringList OContactFields::untrphonefields( bool sorted ) | ||
199 | { | ||
200 | return phonefields( sorted, false ); | ||
201 | } | ||
202 | |||
203 | |||
204 | /*! | ||
205 | \internal | ||
206 | Returns a translated list of field names for a contact. | ||
207 | */ | ||
208 | QStringList OContactFields::trfields( bool sorted ) | ||
209 | { | ||
210 | return fields( sorted, true ); | ||
211 | } | ||
212 | |||
213 | /*! | ||
214 | \internal | ||
215 | Returns an untranslated list of field names for a contact. | ||
216 | */ | ||
217 | QStringList OContactFields::untrfields( bool sorted ) | ||
218 | { | ||
219 | return fields( sorted, false ); | ||
220 | } | ||
221 | |||
222 | QMap<int, QString> OContactFields::idToTrFields() | ||
223 | { | ||
224 | QMap<int, QString> ret_map; | ||
225 | |||
226 | ret_map.insert( Qtopia::AddressUid, QObject::tr( "User Id" ) ); | ||
227 | ret_map.insert( Qtopia::AddressCategory, QObject::tr( "Categories" ) ); | ||
228 | |||
229 | ret_map.insert( Qtopia::Title, QObject::tr( "Name Title") ); | ||
230 | ret_map.insert( Qtopia::FirstName, QObject::tr( "First Name" ) ); | ||
231 | ret_map.insert( Qtopia::MiddleName, QObject::tr( "Middle Name" ) ); | ||
232 | ret_map.insert( Qtopia::LastName, QObject::tr( "Last Name" ) ); | ||
233 | ret_map.insert( Qtopia::Suffix, QObject::tr( "Suffix" )); | ||
234 | ret_map.insert( Qtopia::FileAs, QObject::tr( "File As" ) ); | ||
235 | |||
236 | ret_map.insert( Qtopia::JobTitle, QObject::tr( "Job Title" ) ); | ||
237 | ret_map.insert( Qtopia::Department, QObject::tr( "Department" ) ); | ||
238 | ret_map.insert( Qtopia::Company, QObject::tr( "Company" ) ); | ||
239 | ret_map.insert( Qtopia::BusinessPhone, QObject::tr( "Business Phone" ) ); | ||
240 | ret_map.insert( Qtopia::BusinessFax, QObject::tr( "Business Fax" ) ); | ||
241 | ret_map.insert( Qtopia::BusinessMobile, QObject::tr( "Business Mobile" )); | ||
242 | |||
243 | |||
244 | ret_map.insert( Qtopia::DefaultEmail, QObject::tr( "Default Email" ) ); | ||
245 | ret_map.insert( Qtopia::Emails, QObject::tr( "Emails" ) ); | ||
246 | |||
247 | ret_map.insert( Qtopia::HomePhone, QObject::tr( "Home Phone" ) ); | ||
248 | ret_map.insert( Qtopia::HomeFax, QObject::tr( "Home Fax" ) ); | ||
249 | ret_map.insert( Qtopia::HomeMobile, QObject::tr( "Home Mobile" ) ); | ||
250 | |||
251 | // business | ||
252 | ret_map.insert( Qtopia::BusinessStreet, QObject::tr( "Business Street" ) ); | ||
253 | ret_map.insert( Qtopia::BusinessCity, QObject::tr( "Business City" ) ); | ||
254 | ret_map.insert( Qtopia::BusinessState, QObject::tr( "Business State" ) ); | ||
255 | ret_map.insert( Qtopia::BusinessZip, QObject::tr( "Business Zip" ) ); | ||
256 | ret_map.insert( Qtopia::BusinessCountry, QObject::tr( "Business Country" ) ); | ||
257 | ret_map.insert( Qtopia::BusinessPager, QObject::tr( "Business Pager" ) ); | ||
258 | ret_map.insert( Qtopia::BusinessWebPage, QObject::tr( "Business WebPage" ) ); | ||
259 | |||
260 | ret_map.insert( Qtopia::Office, QObject::tr( "Office" ) ); | ||
261 | ret_map.insert( Qtopia::Profession, QObject::tr( "Profession" ) ); | ||
262 | ret_map.insert( Qtopia::Assistant, QObject::tr( "Assistant" ) ); | ||
263 | ret_map.insert( Qtopia::Manager, QObject::tr( "Manager" ) ); | ||
264 | |||
265 | // home | ||
266 | ret_map.insert( Qtopia::HomeStreet, QObject::tr( "Home Street" ) ); | ||
267 | ret_map.insert( Qtopia::HomeCity, QObject::tr( "Home City" ) ); | ||
268 | ret_map.insert( Qtopia::HomeState, QObject::tr( "Home State" ) ); | ||
269 | ret_map.insert( Qtopia::HomeZip, QObject::tr( "Home Zip" ) ); | ||
270 | ret_map.insert( Qtopia::HomeCountry, QObject::tr( "Home Country" ) ); | ||
271 | ret_map.insert( Qtopia::HomeWebPage, QObject::tr( "Home Web Page" ) ); | ||
272 | |||
273 | //personal | ||
274 | ret_map.insert( Qtopia::Spouse, QObject::tr( "Spouse" ) ); | ||
275 | ret_map.insert( Qtopia::Gender, QObject::tr( "Gender" ) ); | ||
276 | ret_map.insert( Qtopia::Birthday, QObject::tr( "Birthday" ) ); | ||
277 | ret_map.insert( Qtopia::Anniversary, QObject::tr( "Anniversary" ) ); | ||
278 | ret_map.insert( Qtopia::Nickname, QObject::tr( "Nickname" ) ); | ||
279 | ret_map.insert( Qtopia::Children, QObject::tr( "Children" ) ); | ||
280 | |||
281 | // other | ||
282 | ret_map.insert( Qtopia::Notes, QObject::tr( "Notes" ) ); | ||
283 | |||
284 | |||
285 | return ret_map; | ||
286 | } | ||
287 | |||
288 | QMap<int, QString> OContactFields::idToUntrFields() | ||
289 | { | ||
290 | QMap<int, QString> ret_map; | ||
291 | |||
292 | ret_map.insert( Qtopia::AddressUid, "User Id" ); | ||
293 | ret_map.insert( Qtopia::AddressCategory, "Categories" ); | ||
294 | |||
295 | ret_map.insert( Qtopia::Title, "Name Title" ); | ||
296 | ret_map.insert( Qtopia::FirstName, "First Name" ); | ||
297 | ret_map.insert( Qtopia::MiddleName, "Middle Name" ); | ||
298 | ret_map.insert( Qtopia::LastName, "Last Name" ); | ||
299 | ret_map.insert( Qtopia::Suffix, "Suffix" ); | ||
300 | ret_map.insert( Qtopia::FileAs, "File As" ); | ||
301 | |||
302 | ret_map.insert( Qtopia::JobTitle, "Job Title" ); | ||
303 | ret_map.insert( Qtopia::Department, "Department" ); | ||
304 | ret_map.insert( Qtopia::Company, "Company" ); | ||
305 | ret_map.insert( Qtopia::BusinessPhone, "Business Phone" ); | ||
306 | ret_map.insert( Qtopia::BusinessFax, "Business Fax" ); | ||
307 | ret_map.insert( Qtopia::BusinessMobile, "Business Mobile" ); | ||
308 | |||
309 | |||
310 | ret_map.insert( Qtopia::DefaultEmail, "Default Email" ); | ||
311 | ret_map.insert( Qtopia::Emails, "Emails" ); | ||
312 | |||
313 | ret_map.insert( Qtopia::HomePhone, "Home Phone" ); | ||
314 | ret_map.insert( Qtopia::HomeFax, "Home Fax" ); | ||
315 | ret_map.insert( Qtopia::HomeMobile, "Home Mobile" ); | ||
316 | |||
317 | // business | ||
318 | ret_map.insert( Qtopia::BusinessStreet, "Business Street" ); | ||
319 | ret_map.insert( Qtopia::BusinessCity, "Business City" ); | ||
320 | ret_map.insert( Qtopia::BusinessState, "Business State" ); | ||
321 | ret_map.insert( Qtopia::BusinessZip, "Business Zip" ); | ||
322 | ret_map.insert( Qtopia::BusinessCountry, "Business Country" ); | ||
323 | ret_map.insert( Qtopia::BusinessPager, "Business Pager" ); | ||
324 | ret_map.insert( Qtopia::BusinessWebPage, "Business WebPage" ); | ||
325 | |||
326 | ret_map.insert( Qtopia::Office, "Office" ); | ||
327 | ret_map.insert( Qtopia::Profession, "Profession" ); | ||
328 | ret_map.insert( Qtopia::Assistant, "Assistant" ); | ||
329 | ret_map.insert( Qtopia::Manager, "Manager" ); | ||
330 | |||
331 | // home | ||
332 | ret_map.insert( Qtopia::HomeStreet, "Home Street" ); | ||
333 | ret_map.insert( Qtopia::HomeCity, "Home City" ); | ||
334 | ret_map.insert( Qtopia::HomeState, "Home State" ); | ||
335 | ret_map.insert( Qtopia::HomeZip, "Home Zip" ); | ||
336 | ret_map.insert( Qtopia::HomeCountry, "Home Country" ); | ||
337 | ret_map.insert( Qtopia::HomeWebPage, "Home Web Page" ); | ||
338 | |||
339 | //personal | ||
340 | ret_map.insert( Qtopia::Spouse, "Spouse" ); | ||
341 | ret_map.insert( Qtopia::Gender, "Gender" ); | ||
342 | ret_map.insert( Qtopia::Birthday, "Birthday" ); | ||
343 | ret_map.insert( Qtopia::Anniversary, "Anniversary" ); | ||
344 | ret_map.insert( Qtopia::Nickname, "Nickname" ); | ||
345 | ret_map.insert( Qtopia::Children, "Children" ); | ||
346 | |||
347 | // other | ||
348 | ret_map.insert( Qtopia::Notes, "Notes" ); | ||
349 | ret_map.insert( Qtopia::Groups, "Groups" ); | ||
350 | |||
351 | |||
352 | return ret_map; | ||
353 | } | ||
354 | |||
355 | QMap<QString, int> OContactFields::trFieldsToId() | ||
356 | { | ||
357 | QMap<int, QString> idtostr = idToTrFields(); | ||
358 | QMap<QString, int> ret_map; | ||
359 | |||
360 | |||
361 | QMap<int, QString>::Iterator it; | ||
362 | for( it = idtostr.begin(); it != idtostr.end(); ++it ) | ||
363 | ret_map.insert( *it, it.key() ); | ||
364 | |||
365 | |||
366 | return ret_map; | ||
367 | } | ||
368 | |||
369 | /* ======================================================================= */ | ||
370 | |||
371 | QMap<QString, int> OContactFields::untrFieldsToId() | ||
372 | { | ||
373 | QMap<int, QString> idtostr = idToUntrFields(); | ||
374 | QMap<QString, int> ret_map; | ||
375 | |||
376 | |||
377 | QMap<int, QString>::Iterator it; | ||
378 | for( it = idtostr.begin(); it != idtostr.end(); ++it ) | ||
379 | ret_map.insert( *it, it.key() ); | ||
380 | |||
381 | |||
382 | return ret_map; | ||
383 | } | ||
384 | |||
385 | |||
386 | OContactFields::OContactFields(): | ||
387 | fieldOrder( DEFAULT_FIELD_ORDER ), | ||
388 | changedFieldOrder( false ) | ||
389 | { | ||
390 | // Get the global field order from the config file and | ||
391 | // use it as a start pattern | ||
392 | Config cfg ( "AddressBook" ); | ||
393 | cfg.setGroup( "ContactFieldOrder" ); | ||
394 | globalFieldOrder = cfg.readEntry( "General", DEFAULT_FIELD_ORDER ); | ||
395 | } | ||
396 | |||
397 | OContactFields::~OContactFields(){ | ||
398 | |||
399 | // We will store the fieldorder into the config file | ||
400 | // to reuse it for the future.. | ||
401 | if ( changedFieldOrder ){ | ||
402 | Config cfg ( "AddressBook" ); | ||
403 | cfg.setGroup( "ContactFieldOrder" ); | ||
404 | cfg.writeEntry( "General", globalFieldOrder ); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | |||
409 | |||
410 | void OContactFields::saveToRecord( OContact &cnt ){ | ||
411 | |||
412 | qDebug("ocontactfields saveToRecord: >%s<",fieldOrder.latin1()); | ||
413 | |||
414 | // Store fieldorder into this contact. | ||
415 | cnt.setCustomField( CONTACT_FIELD_ORDER_NAME, fieldOrder ); | ||
416 | |||
417 | globalFieldOrder = fieldOrder; | ||
418 | changedFieldOrder = true; | ||
419 | |||
420 | } | ||
421 | |||
422 | void OContactFields::loadFromRecord( const OContact &cnt ){ | ||
423 | qDebug("ocontactfields loadFromRecord"); | ||
424 | qDebug("loading >%s<",cnt.fullName().latin1()); | ||
425 | |||
426 | // Get fieldorder for this contact. If none is defined, | ||
427 | // we will use the global one from the config file.. | ||
428 | |||
429 | fieldOrder = cnt.customField( CONTACT_FIELD_ORDER_NAME ); | ||
430 | |||
431 | qDebug("fieldOrder from contact>%s<",fieldOrder.latin1()); | ||
432 | |||
433 | if (fieldOrder.isEmpty()){ | ||
434 | fieldOrder = globalFieldOrder; | ||
435 | } | ||
436 | |||
437 | |||
438 | qDebug("effective fieldOrder in loadFromRecord >%s<",fieldOrder.latin1()); | ||
439 | } | ||
440 | |||
441 | void OContactFields::setFieldOrder( int num, int index ){ | ||
442 | qDebug("qcontactfields setfieldorder pos %i -> %i",num,index); | ||
443 | |||
444 | fieldOrder[num] = QString::number( index, 16 )[0]; | ||
445 | |||
446 | // We will store this new fieldorder globally to | ||
447 | // remember it for contacts which have none | ||
448 | globalFieldOrder = fieldOrder; | ||
449 | changedFieldOrder = true; | ||
450 | |||
451 | qDebug("fieldOrder >%s<",fieldOrder.latin1()); | ||
452 | } | ||
453 | |||
454 | int OContactFields::getFieldOrder( int num, int defIndex ){ | ||
455 | qDebug("ocontactfields getFieldOrder"); | ||
456 | qDebug("fieldOrder >%s<",fieldOrder.latin1()); | ||
457 | |||
458 | // Get index of combo as char.. | ||
459 | QChar poschar = fieldOrder[num]; | ||
460 | |||
461 | bool ok; | ||
462 | int ret = 0; | ||
463 | // Convert char to number.. | ||
464 | if ( !( poschar == QChar::null ) ) | ||
465 | ret = QString( poschar ).toInt(&ok, 16); | ||
466 | else | ||
467 | ok = false; | ||
468 | |||
469 | // Return default value if index for | ||
470 | // num was not set or if anything else happened.. | ||
471 | if ( !ok ) ret = defIndex; | ||
472 | |||
473 | qDebug("returning >%i<",ret); | ||
474 | |||
475 | return ret; | ||
476 | |||
477 | } | ||
diff --git a/noncore/unsupported/libopie/pim/ocontactfields.h b/noncore/unsupported/libopie/pim/ocontactfields.h new file mode 100644 index 0000000..f105de7 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/ocontactfields.h | |||
@@ -0,0 +1,67 @@ | |||
1 | #ifndef OPIE_CONTACTS_FIELDS | ||
2 | #define OPIE_CONTACTS_FIELDS | ||
3 | |||
4 | class QStringList; | ||
5 | |||
6 | #include <qmap.h> | ||
7 | #include <qstring.h> | ||
8 | #include <opie/ocontact.h> | ||
9 | |||
10 | #define CONTACT_FIELD_ORDER_NAME "opie-contactfield-order" | ||
11 | #define DEFAULT_FIELD_ORDER "__________" | ||
12 | |||
13 | class OContactFields{ | ||
14 | |||
15 | public: | ||
16 | OContactFields(); | ||
17 | ~OContactFields(); | ||
18 | /** Set the index for combo boxes. | ||
19 | * Sets the <b>index</b> of combo <b>num</b>. | ||
20 | * @param num selects the number of the combo | ||
21 | * @param index sets the index in the combo | ||
22 | */ | ||
23 | void setFieldOrder( int num, int index ); | ||
24 | |||
25 | /** Get the index for combo boxes. | ||
26 | * Returns the index of combo <b>num</b> or defindex | ||
27 | * if none was defined.. | ||
28 | * @param num Selects the number of the combo | ||
29 | * @param defIndex will be returned if none was defined (either | ||
30 | * globally in the config file, nor by the contact which was used | ||
31 | * by loadFromRecord() ) | ||
32 | */ | ||
33 | int getFieldOrder( int num, int defIndex); | ||
34 | |||
35 | /** Store fieldorder to contact. */ | ||
36 | void saveToRecord( OContact& ); | ||
37 | /** Get Fieldorder from contact. */ | ||
38 | void loadFromRecord( const OContact& ); | ||
39 | |||
40 | private: | ||
41 | QString fieldOrder; | ||
42 | QString globalFieldOrder; | ||
43 | bool changedFieldOrder; | ||
44 | |||
45 | public: | ||
46 | static QStringList personalfields( bool sorted = true, bool translated = false ); | ||
47 | static QStringList phonefields( bool sorted = true, bool translated = false ); | ||
48 | static QStringList detailsfields( bool sorted = true, bool translated = false ); | ||
49 | static QStringList fields( bool sorted = true, bool translated = false ); | ||
50 | |||
51 | static QStringList trpersonalfields( bool sorted = true ); | ||
52 | static QStringList untrpersonalfields( bool sorted = true ); | ||
53 | static QStringList trphonefields( bool sorted = true ); | ||
54 | static QStringList untrphonefields( bool sorted = true ); | ||
55 | static QStringList trdetailsfields( bool sorted = true ); | ||
56 | static QStringList untrdetailsfields( bool sorted = true ); | ||
57 | static QStringList trfields( bool sorted = true ); | ||
58 | static QStringList untrfields( bool sorted = true ); | ||
59 | |||
60 | static QMap<int, QString> idToTrFields(); | ||
61 | static QMap<QString, int> trFieldsToId(); | ||
62 | static QMap<int, QString> idToUntrFields(); | ||
63 | static QMap<QString, int> untrFieldsToId(); | ||
64 | |||
65 | }; | ||
66 | |||
67 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/oconversion.cpp b/noncore/unsupported/libopie/pim/oconversion.cpp new file mode 100644 index 0000000..0d15414 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oconversion.cpp | |||
@@ -0,0 +1,113 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2003 by Stefan Eilers (eilers.stefan@epost.de) | ||
3 | ** | ||
4 | ** This file may be distributed and/or modified under the terms of the | ||
5 | ** GNU Lesser General Public License version 2 as published by the Free Software | ||
6 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
7 | ** packaging of this file. | ||
8 | ** | ||
9 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
10 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
11 | ** | ||
12 | **********************************************************************/ | ||
13 | |||
14 | #include "oconversion.h" | ||
15 | #include <qpe/timeconversion.h> | ||
16 | |||
17 | |||
18 | QString OConversion::dateToString( const QDate &d ) | ||
19 | { | ||
20 | if ( d.isNull() || !d.isValid() ) | ||
21 | return QString::null; | ||
22 | |||
23 | // ISO format in year, month, day (YYYYMMDD); e.g. 20021231 | ||
24 | QString year = QString::number( d.year() ); | ||
25 | QString month = QString::number( d.month() ); | ||
26 | month = month.rightJustify( 2, '0' ); | ||
27 | QString day = QString::number( d.day() ); | ||
28 | day = day.rightJustify( 2, '0' ); | ||
29 | |||
30 | QString str = year + month + day; | ||
31 | //qDebug( "\tPimContact dateToStr = %s", str.latin1() ); | ||
32 | |||
33 | return str; | ||
34 | } | ||
35 | |||
36 | QDate OConversion::dateFromString( const QString& s ) | ||
37 | { | ||
38 | QDate date; | ||
39 | |||
40 | if ( s.isEmpty() ) | ||
41 | return date; | ||
42 | |||
43 | // Be backward compatible to old Opie format: | ||
44 | // Try to load old format. If it fails, try new ISO-Format! | ||
45 | date = TimeConversion::fromString ( s ); | ||
46 | if ( date.isValid() ) | ||
47 | return date; | ||
48 | |||
49 | // Read ISO-Format (YYYYMMDD) | ||
50 | int year = s.mid(0, 4).toInt(); | ||
51 | int month = s.mid(4,2).toInt(); | ||
52 | int day = s.mid(6,2).toInt(); | ||
53 | |||
54 | // do some quick sanity checking -eilers | ||
55 | // but we isValid() again? -zecke | ||
56 | if ( year < 1900 || year > 3000 ) { | ||
57 | qWarning( "PimContact year is not in range"); | ||
58 | return date; | ||
59 | } | ||
60 | if ( month < 0 || month > 12 ) { | ||
61 | qWarning( "PimContact month is not in range"); | ||
62 | return date; | ||
63 | } | ||
64 | if ( day < 0 || day > 31 ) { | ||
65 | qWarning( "PimContact day is not in range"); | ||
66 | return date; | ||
67 | } | ||
68 | |||
69 | date.setYMD( year, month, day ); | ||
70 | if ( !date.isValid() ) { | ||
71 | qWarning( "PimContact date is not valid"); | ||
72 | return date; | ||
73 | } | ||
74 | |||
75 | return date; | ||
76 | } | ||
77 | QString OConversion::dateTimeToString( const QDateTime& dt ) { | ||
78 | if (!dt.isValid() || dt.isNull() ) return QString::null; | ||
79 | |||
80 | QString year = QString::number( dt.date().year() ); | ||
81 | QString month = QString::number( dt.date().month() ); | ||
82 | QString day = QString::number( dt.date().day() ); | ||
83 | |||
84 | QString hour = QString::number( dt.time().hour() ); | ||
85 | QString min = QString::number( dt.time().minute() ); | ||
86 | QString sec = QString::number( dt.time().second() ); | ||
87 | |||
88 | month = month.rightJustify( 2, '0' ); | ||
89 | day = day. rightJustify( 2, '0' ); | ||
90 | hour = hour. rightJustify( 2, '0' ); | ||
91 | min = min. rightJustify( 2, '0' ); | ||
92 | sec = sec. rightJustify( 2, '0' ); | ||
93 | |||
94 | QString str = day + month + year + hour + min + sec; | ||
95 | |||
96 | return str; | ||
97 | } | ||
98 | QDateTime OConversion::dateTimeFromString( const QString& str) { | ||
99 | |||
100 | if ( str.isEmpty() ) return QDateTime(); | ||
101 | int day = str.mid(0, 2).toInt(); | ||
102 | int month = str.mid(2, 2).toInt(); | ||
103 | int year = str.mid(4, 4).toInt(); | ||
104 | int hour = str.mid(8, 2).toInt(); | ||
105 | int min = str.mid(10, 2).toInt(); | ||
106 | int sec = str.mid(12, 2).toInt(); | ||
107 | |||
108 | QDate date( year, month, day ); | ||
109 | QTime time( hour, min, sec ); | ||
110 | QDateTime dt( date, time ); | ||
111 | return dt; | ||
112 | } | ||
113 | |||
diff --git a/noncore/unsupported/libopie/pim/oconversion.h b/noncore/unsupported/libopie/pim/oconversion.h new file mode 100644 index 0000000..4c0a497 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oconversion.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /********************************************************************** | ||
2 | ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. | ||
3 | ** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de) | ||
4 | ** | ||
5 | ** This file may be distributed and/or modified under the terms of the | ||
6 | ** GNU General Public License version 2 as published by the Free Software | ||
7 | ** Foundation and appearing in the file LICENSE.GPL included in the | ||
8 | ** packaging of this file. | ||
9 | ** | ||
10 | ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | ||
11 | ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | ||
12 | ** | ||
13 | ** See http://www.trolltech.com/gpl/ for GPL licensing information. | ||
14 | ** | ||
15 | ** Contact info@trolltech.com if any conditions of this licensing are | ||
16 | ** not clear to you. | ||
17 | **********************************************************************/ | ||
18 | |||
19 | #ifndef __oconversion_h__ | ||
20 | #define __oconversion_h__ | ||
21 | |||
22 | /* #include <time.h> */ | ||
23 | /* #include <sys/types.h> */ | ||
24 | #include <qdatetime.h> | ||
25 | |||
26 | /* FIXME namespace? -zecke */ | ||
27 | class OConversion | ||
28 | { | ||
29 | public: | ||
30 | static QString dateToString( const QDate &d ); | ||
31 | static QDate dateFromString( const QString &datestr ); | ||
32 | |||
33 | /** | ||
34 | * simple function to store DateTime as string and read from string | ||
35 | * no timezone changing is done | ||
36 | * DDMMYYYYHHMMSS is the simple format | ||
37 | */ | ||
38 | static QString dateTimeToString( const QDateTime& ); | ||
39 | static QDateTime dateTimeFromString( const QString& ); | ||
40 | |||
41 | private: | ||
42 | class Private; | ||
43 | Private* d; | ||
44 | |||
45 | }; | ||
46 | |||
47 | #endif // __oconversion_h__ | ||
48 | |||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccess.cpp b/noncore/unsupported/libopie/pim/odatebookaccess.cpp new file mode 100644 index 0000000..d95fed6 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccess.cpp | |||
@@ -0,0 +1,81 @@ | |||
1 | #include "obackendfactory.h" | ||
2 | #include "odatebookaccess.h" | ||
3 | |||
4 | /** | ||
5 | * Simple constructor | ||
6 | * It takes a ODateBookAccessBackend as parent. If it is 0 the default implementation | ||
7 | * will be used! | ||
8 | * @param back The backend to be used or 0 for the default backend | ||
9 | * @param ac What kind of access is intended | ||
10 | */ | ||
11 | ODateBookAccess::ODateBookAccess( ODateBookAccessBackend* back, enum Access ac ) | ||
12 | : OPimAccessTemplate<OEvent>( back ) | ||
13 | { | ||
14 | if (!back ) | ||
15 | back = OBackendFactory<ODateBookAccessBackend>::Default("datebook", QString::null ); | ||
16 | |||
17 | m_backEnd = back; | ||
18 | setBackEnd( m_backEnd ); | ||
19 | } | ||
20 | ODateBookAccess::~ODateBookAccess() { | ||
21 | } | ||
22 | |||
23 | /** | ||
24 | * @return all events available | ||
25 | */ | ||
26 | ODateBookAccess::List ODateBookAccess::rawEvents()const { | ||
27 | QArray<int> ints = m_backEnd->rawEvents(); | ||
28 | |||
29 | List lis( ints, this ); | ||
30 | return lis; | ||
31 | } | ||
32 | |||
33 | /** | ||
34 | * @return all repeating events | ||
35 | */ | ||
36 | ODateBookAccess::List ODateBookAccess::rawRepeats()const { | ||
37 | QArray<int> ints = m_backEnd->rawRepeats(); | ||
38 | |||
39 | List lis( ints, this ); | ||
40 | return lis; | ||
41 | } | ||
42 | |||
43 | /** | ||
44 | * @return all non repeating events | ||
45 | */ | ||
46 | ODateBookAccess::List ODateBookAccess::nonRepeats()const { | ||
47 | QArray<int> ints = m_backEnd->nonRepeats(); | ||
48 | |||
49 | List lis( ints, this ); | ||
50 | return lis; | ||
51 | } | ||
52 | |||
53 | /** | ||
54 | * @return dates in the time span between from and to | ||
55 | * @param from Include all events from... | ||
56 | * @param to Include all events to... | ||
57 | */ | ||
58 | OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDate& from, const QDate& to ) const { | ||
59 | return m_backEnd->effectiveEvents( from, to ); | ||
60 | } | ||
61 | /** | ||
62 | * @return all events at a given datetime | ||
63 | */ | ||
64 | OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDateTime& start ) const { | ||
65 | return m_backEnd->effectiveEvents( start ); | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * @return non repeating dates in the time span between from and to | ||
70 | * @param from Include all events from... | ||
71 | * @param to Include all events to... | ||
72 | */ | ||
73 | OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) const { | ||
74 | return m_backEnd->effectiveNonRepeatingEvents( from, to ); | ||
75 | } | ||
76 | /** | ||
77 | * @return all non repeating events at a given datetime | ||
78 | */ | ||
79 | OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDateTime& start ) const { | ||
80 | return m_backEnd->effectiveNonRepeatingEvents( start ); | ||
81 | } | ||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccess.h b/noncore/unsupported/libopie/pim/odatebookaccess.h new file mode 100644 index 0000000..62196da --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccess.h | |||
@@ -0,0 +1,44 @@ | |||
1 | #ifndef OPIE_DATE_BOOK_ACCESS_H | ||
2 | #define OPIE_DATE_BOOK_ACCESS_H | ||
3 | |||
4 | #include "odatebookaccessbackend.h" | ||
5 | #include "opimaccesstemplate.h" | ||
6 | |||
7 | #include "oevent.h" | ||
8 | |||
9 | /** | ||
10 | * This is the object orientated datebook database. It'll use OBackendFactory | ||
11 | * to query for a backend. | ||
12 | * All access to the datebook should be done via this class. | ||
13 | * Make sure to load and save the datebook this is not part of | ||
14 | * destructing and creating the object | ||
15 | * | ||
16 | * @author Holger Freyther, Stefan Eilers | ||
17 | */ | ||
18 | class ODateBookAccess : public OPimAccessTemplate<OEvent> { | ||
19 | public: | ||
20 | ODateBookAccess( ODateBookAccessBackend* = 0l, enum Access acc = Random ); | ||
21 | ~ODateBookAccess(); | ||
22 | |||
23 | /* return all events */ | ||
24 | List rawEvents()const; | ||
25 | |||
26 | /* return repeating events */ | ||
27 | List rawRepeats()const; | ||
28 | |||
29 | /* return non repeating events */ | ||
30 | List nonRepeats()const; | ||
31 | |||
32 | /* return non repeating events (from,to) */ | ||
33 | OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to ) const; | ||
34 | OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start ) const; | ||
35 | OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) const; | ||
36 | OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start ) const; | ||
37 | |||
38 | private: | ||
39 | ODateBookAccessBackend* m_backEnd; | ||
40 | class Private; | ||
41 | Private* d; | ||
42 | }; | ||
43 | |||
44 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend.cpp b/noncore/unsupported/libopie/pim/odatebookaccessbackend.cpp new file mode 100644 index 0000000..f0c5d65 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend.cpp | |||
@@ -0,0 +1,182 @@ | |||
1 | #include <qtl.h> | ||
2 | |||
3 | #include "orecur.h" | ||
4 | |||
5 | #include "odatebookaccessbackend.h" | ||
6 | |||
7 | namespace { | ||
8 | /* a small helper to get all NonRepeating events for a range of time */ | ||
9 | void events( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& events, | ||
10 | const QDate& from, const QDate& to ) { | ||
11 | QDateTime dtStart, dtEnd; | ||
12 | |||
13 | for ( OEvent::ValueList::ConstIterator it = events.begin(); it != events.end(); ++it ) { | ||
14 | dtStart = (*it).startDateTime(); | ||
15 | dtEnd = (*it).endDateTime(); | ||
16 | |||
17 | /* | ||
18 | * If in range | ||
19 | */ | ||
20 | if (dtStart.date() >= from && dtEnd.date() <= to ) { | ||
21 | OEffectiveEvent eff; | ||
22 | eff.setEvent( (*it) ); | ||
23 | eff.setDate( dtStart.date() ); | ||
24 | eff.setStartTime( dtStart.time() ); | ||
25 | |||
26 | /* if not on the same day */ | ||
27 | if ( dtStart.date() != dtEnd.date() ) | ||
28 | eff.setEndTime( QTime(23, 59, 0 ) ); | ||
29 | else | ||
30 | eff.setEndTime( dtEnd.time() ); | ||
31 | |||
32 | tmpList.append( eff ); | ||
33 | } | ||
34 | |||
35 | /* we must also check for end date information... */ | ||
36 | if ( dtEnd.date() != dtStart.date() && dtEnd.date() >= from ) { | ||
37 | QDateTime dt = dtStart.addDays( 1 ); | ||
38 | dt.setTime( QTime(0, 0, 0 ) ); | ||
39 | QDateTime dtStop; | ||
40 | if ( dtEnd > to ) | ||
41 | dtStop = to; | ||
42 | else | ||
43 | dtStop = dtEnd; | ||
44 | |||
45 | while ( dt <= dtStop ) { | ||
46 | OEffectiveEvent eff; | ||
47 | eff.setEvent( (*it) ); | ||
48 | eff.setDate( dt.date() ); | ||
49 | |||
50 | if ( dt >= from ) { | ||
51 | eff.setStartTime( QTime(0, 0, 0 ) ); | ||
52 | if ( dt.date() == dtEnd.date() ) | ||
53 | eff.setEndTime( dtEnd.time() ); | ||
54 | else | ||
55 | eff.setEndTime( QTime(23, 59, 0 ) ); | ||
56 | tmpList.append( eff ); | ||
57 | } | ||
58 | dt = dt.addDays( 1 ); | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | void repeat( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& list, | ||
65 | const QDate& from, const QDate& to ) { | ||
66 | QDate repeat; | ||
67 | for ( OEvent::ValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) { | ||
68 | int dur = (*it).startDateTime().date().daysTo( (*it).endDateTime().date() ); | ||
69 | QDate itDate = from.addDays(-dur ); | ||
70 | ORecur rec = (*it).recurrence(); | ||
71 | if ( !rec.hasEndDate() || rec.endDate() > to ) { | ||
72 | rec.setEndDate( to ); | ||
73 | rec.setHasEndDate( true ); | ||
74 | } | ||
75 | while (rec.nextOcurrence(itDate, repeat ) ) { | ||
76 | if (repeat > to ) break; | ||
77 | OEffectiveEvent eff; | ||
78 | eff.setDate( repeat ); | ||
79 | if ( (*it).isAllDay() ) { | ||
80 | eff.setStartTime( QTime(0, 0, 0 ) ); | ||
81 | eff.setEndTime( QTime(23, 59, 59 ) ); | ||
82 | }else { | ||
83 | /* we only occur by days, not hours/minutes/seconds. Hence | ||
84 | * the actual end and start times will be the same for | ||
85 | * every repeated event. For multi day events this is | ||
86 | * fixed up later if on wronge day span | ||
87 | */ | ||
88 | eff.setStartTime( (*it).startDateTime().time() ); | ||
89 | eff.setEndTime( (*it).endDateTime().time() ); | ||
90 | } | ||
91 | if ( dur != 0 ) { | ||
92 | // multi-day repeating events | ||
93 | QDate sub_it = QMAX( repeat, from ); | ||
94 | QDate startDate = repeat; | ||
95 | QDate endDate = startDate.addDays( dur ); | ||
96 | |||
97 | while ( sub_it <= endDate && sub_it <= to ) { | ||
98 | OEffectiveEvent tmpEff = eff; | ||
99 | tmpEff.setEvent( (*it) ); | ||
100 | if ( sub_it != startDate ) | ||
101 | tmpEff.setStartTime( QTime(0, 0, 0 ) ); | ||
102 | if ( sub_it != endDate ) | ||
103 | tmpEff.setEndTime( QTime( 23, 59, 59 ) ); | ||
104 | |||
105 | tmpEff.setDate( sub_it ); | ||
106 | tmpEff.setEffectiveDates( startDate, endDate ); | ||
107 | tmpList.append( tmpEff ); | ||
108 | |||
109 | sub_it = sub_it.addDays( 1 ); | ||
110 | } | ||
111 | itDate = endDate; | ||
112 | }else { | ||
113 | eff.setEvent( (*it) ); | ||
114 | tmpList.append( eff ); | ||
115 | itDate = repeat.addDays( 1 ); | ||
116 | } | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | ODateBookAccessBackend::ODateBookAccessBackend() | ||
123 | : OPimAccessBackend<OEvent>() | ||
124 | { | ||
125 | |||
126 | } | ||
127 | ODateBookAccessBackend::~ODateBookAccessBackend() { | ||
128 | |||
129 | } | ||
130 | OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDate& from, | ||
131 | const QDate& to ) { | ||
132 | OEffectiveEvent::ValueList tmpList; | ||
133 | OEvent::ValueList list = directNonRepeats(); | ||
134 | |||
135 | events( tmpList, list, from, to ); | ||
136 | repeat( tmpList, directRawRepeats(),from,to ); | ||
137 | |||
138 | list = directRawRepeats(); // Useless, isn't it ? (eilers) | ||
139 | |||
140 | qHeapSort( tmpList ); | ||
141 | return tmpList; | ||
142 | } | ||
143 | OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDateTime& dt ) { | ||
144 | OEffectiveEvent::ValueList day = effectiveEvents( dt.date(), dt.date() ); | ||
145 | OEffectiveEvent::ValueList::Iterator it; | ||
146 | |||
147 | OEffectiveEvent::ValueList tmpList; | ||
148 | QDateTime dtTmp; | ||
149 | for ( it = day.begin(); it != day.end(); ++it ) { | ||
150 | dtTmp = QDateTime( (*it).date(), (*it).startTime() ); | ||
151 | if ( QABS(dt.secsTo(dtTmp) ) < 60 ) | ||
152 | tmpList.append( (*it) ); | ||
153 | } | ||
154 | |||
155 | return tmpList; | ||
156 | } | ||
157 | |||
158 | OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDate& from, | ||
159 | const QDate& to ) { | ||
160 | OEffectiveEvent::ValueList tmpList; | ||
161 | OEvent::ValueList list = directNonRepeats(); | ||
162 | |||
163 | events( tmpList, list, from, to ); | ||
164 | |||
165 | qHeapSort( tmpList ); | ||
166 | return tmpList; | ||
167 | } | ||
168 | |||
169 | OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt ) { | ||
170 | OEffectiveEvent::ValueList day = effectiveNonRepeatingEvents( dt.date(), dt.date() ); | ||
171 | OEffectiveEvent::ValueList::Iterator it; | ||
172 | |||
173 | OEffectiveEvent::ValueList tmpList; | ||
174 | QDateTime dtTmp; | ||
175 | for ( it = day.begin(); it != day.end(); ++it ) { | ||
176 | dtTmp = QDateTime( (*it).date(), (*it).startTime() ); | ||
177 | if ( QABS(dt.secsTo(dtTmp) ) < 60 ) | ||
178 | tmpList.append( (*it) ); | ||
179 | } | ||
180 | |||
181 | return tmpList; | ||
182 | } | ||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend.h b/noncore/unsupported/libopie/pim/odatebookaccessbackend.h new file mode 100644 index 0000000..3472ab3 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend.h | |||
@@ -0,0 +1,90 @@ | |||
1 | #ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_H | ||
2 | #define OPIE_DATE_BOOK_ACCESS_BACKEND_H | ||
3 | |||
4 | #include <qarray.h> | ||
5 | |||
6 | #include "opimaccessbackend.h" | ||
7 | #include "oevent.h" | ||
8 | |||
9 | /** | ||
10 | * This class is the interface to the storage of Events. | ||
11 | * @see OPimAccessBackend | ||
12 | * | ||
13 | */ | ||
14 | class ODateBookAccessBackend : public OPimAccessBackend<OEvent> { | ||
15 | public: | ||
16 | typedef int UID; | ||
17 | |||
18 | /** | ||
19 | * c'tor without parameter | ||
20 | */ | ||
21 | ODateBookAccessBackend(); | ||
22 | ~ODateBookAccessBackend(); | ||
23 | |||
24 | /** | ||
25 | * This method should return a list of UIDs containing | ||
26 | * all events. No filter should be applied | ||
27 | * @return list of events | ||
28 | */ | ||
29 | virtual QArray<UID> rawEvents()const = 0; | ||
30 | |||
31 | /** | ||
32 | * This method should return a list of UIDs containing | ||
33 | * all repeating events. No filter should be applied | ||
34 | * @return list of repeating events | ||
35 | */ | ||
36 | virtual QArray<UID> rawRepeats()const = 0; | ||
37 | |||
38 | /** | ||
39 | * This mthod should return a list of UIDs containing all non | ||
40 | * repeating events. No filter should be applied | ||
41 | * @return list of nonrepeating events | ||
42 | */ | ||
43 | virtual QArray<UID> nonRepeats() const = 0; | ||
44 | |||
45 | /** | ||
46 | * If you do not want to implement the effectiveEvents methods below | ||
47 | * you need to supply it with directNonRepeats. | ||
48 | * This method can return empty lists if effectiveEvents is implememted | ||
49 | */ | ||
50 | virtual OEvent::ValueList directNonRepeats() = 0; | ||
51 | |||
52 | /** | ||
53 | * Same as above but return raw repeats! | ||
54 | */ | ||
55 | virtual OEvent::ValueList directRawRepeats() = 0; | ||
56 | |||
57 | /* is implemented by default but you can reimplement it*/ | ||
58 | /** | ||
59 | * Effective Events are special event occuring during a time frame. This method does calcualte | ||
60 | * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method | ||
61 | * yourself | ||
62 | */ | ||
63 | virtual OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to ); | ||
64 | |||
65 | /** | ||
66 | * this is an overloaded member function | ||
67 | * @see effectiveEvents( const QDate& from, const QDate& to ) | ||
68 | */ | ||
69 | virtual OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start ); | ||
70 | |||
71 | /** | ||
72 | * Effective Events are special event occuring during a time frame. This method does calcualte | ||
73 | * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method | ||
74 | * yourself | ||
75 | */ | ||
76 | virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to ); | ||
77 | |||
78 | /** | ||
79 | * this is an overloaded member function | ||
80 | * @see effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) | ||
81 | */ | ||
82 | virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start ); | ||
83 | |||
84 | private: | ||
85 | class Private; | ||
86 | Private *d; | ||
87 | |||
88 | }; | ||
89 | |||
90 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.cpp b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.cpp new file mode 100644 index 0000000..5f87afe --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.cpp | |||
@@ -0,0 +1,374 @@ | |||
1 | /* | ||
2 | * SQL Backend for the OPIE-Calender Database. | ||
3 | * | ||
4 | * Copyright (c) 2003 by Stefan Eilers (Eilers.Stefan@epost.de) | ||
5 | * | ||
6 | * ===================================================================== | ||
7 | *This program is free software; you can redistribute it and/or | ||
8 | *modify it under the terms of the GNU Library General Public | ||
9 | * License as published by the Free Software Foundation; either | ||
10 | * version 2 of the License, or (at your option) any later version. | ||
11 | * ===================================================================== | ||
12 | * ===================================================================== | ||
13 | * Version: $Id$ | ||
14 | * ===================================================================== | ||
15 | * History: | ||
16 | * $Log$ | ||
17 | * Revision 1.1 2004/11/16 21:46:08 mickeyl | ||
18 | * libopie1 goes into unsupported | ||
19 | * | ||
20 | * Revision 1.4 2004/03/14 13:50:35 alwin | ||
21 | * namespace correction | ||
22 | * | ||
23 | * Revision 1.3 2003/12/22 11:41:39 eilers | ||
24 | * Fixing stupid bug, found by sourcode review.. | ||
25 | * | ||
26 | * Revision 1.2 2003/12/22 10:19:26 eilers | ||
27 | * Finishing implementation of sql-backend for datebook. But I have to | ||
28 | * port the PIM datebook application to use it, before I could debug the | ||
29 | * whole stuff. | ||
30 | * Thus, PIM-Database backend is finished, but highly experimental. And some | ||
31 | * parts are still generic. For instance, the "queryByExample()" methods are | ||
32 | * not (or not fully) implemented. Todo: custom-entries not stored. | ||
33 | * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular | ||
34 | * expression search in the database, which is not supported by sqlite ! | ||
35 | * Therefore we need either an extended sqlite or a workaround which would | ||
36 | * be very slow and memory consuming.. | ||
37 | * | ||
38 | * Revision 1.1 2003/12/08 15:18:12 eilers | ||
39 | * Committing unfinished sql implementation before merging to libopie2 starts.. | ||
40 | * | ||
41 | * | ||
42 | */ | ||
43 | |||
44 | #include <stdio.h> | ||
45 | #include <stdlib.h> | ||
46 | |||
47 | #include <qarray.h> | ||
48 | #include <qstringlist.h> | ||
49 | |||
50 | #include <qpe/global.h> | ||
51 | |||
52 | #include <opie2/osqldriver.h> | ||
53 | #include <opie2/osqlmanager.h> | ||
54 | #include <opie2/osqlquery.h> | ||
55 | |||
56 | #include "orecur.h" | ||
57 | #include "odatebookaccessbackend_sql.h" | ||
58 | |||
59 | using namespace Opie::DB; | ||
60 | |||
61 | |||
62 | ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& , | ||
63 | const QString& fileName ) | ||
64 | : ODateBookAccessBackend(), m_driver( NULL ) | ||
65 | { | ||
66 | m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName; | ||
67 | |||
68 | // Get the standart sql-driver from the OSQLManager.. | ||
69 | OSQLManager man; | ||
70 | m_driver = man.standard(); | ||
71 | m_driver->setUrl( m_fileName ); | ||
72 | |||
73 | initFields(); | ||
74 | |||
75 | load(); | ||
76 | } | ||
77 | |||
78 | ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() { | ||
79 | if( m_driver ) | ||
80 | delete m_driver; | ||
81 | } | ||
82 | |||
83 | void ODateBookAccessBackend_SQL::initFields() | ||
84 | { | ||
85 | |||
86 | // This map contains the translation of the fieldtype id's to | ||
87 | // the names of the table columns | ||
88 | m_fieldMap.insert( OEvent::FUid, "uid" ); | ||
89 | m_fieldMap.insert( OEvent::FCategories, "Categories" ); | ||
90 | m_fieldMap.insert( OEvent::FDescription, "Description" ); | ||
91 | m_fieldMap.insert( OEvent::FLocation, "Location" ); | ||
92 | m_fieldMap.insert( OEvent::FType, "Type" ); | ||
93 | m_fieldMap.insert( OEvent::FAlarm, "Alarm" ); | ||
94 | m_fieldMap.insert( OEvent::FSound, "Sound" ); | ||
95 | m_fieldMap.insert( OEvent::FRType, "RType" ); | ||
96 | m_fieldMap.insert( OEvent::FRWeekdays, "RWeekdays" ); | ||
97 | m_fieldMap.insert( OEvent::FRPosition, "RPosition" ); | ||
98 | m_fieldMap.insert( OEvent::FRFreq, "RFreq" ); | ||
99 | m_fieldMap.insert( OEvent::FRHasEndDate, "RHasEndDate" ); | ||
100 | m_fieldMap.insert( OEvent::FREndDate, "REndDate" ); | ||
101 | m_fieldMap.insert( OEvent::FRCreated, "RCreated" ); | ||
102 | m_fieldMap.insert( OEvent::FRExceptions, "RExceptions" ); | ||
103 | m_fieldMap.insert( OEvent::FStart, "Start" ); | ||
104 | m_fieldMap.insert( OEvent::FEnd, "End" ); | ||
105 | m_fieldMap.insert( OEvent::FNote, "Note" ); | ||
106 | m_fieldMap.insert( OEvent::FTimeZone, "TimeZone" ); | ||
107 | m_fieldMap.insert( OEvent::FRecParent, "RecParent" ); | ||
108 | m_fieldMap.insert( OEvent::FRecChildren, "Recchildren" ); | ||
109 | |||
110 | // Create a map that maps the column name to the id | ||
111 | QMapConstIterator<int, QString> it; | ||
112 | for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ | ||
113 | m_reverseFieldMap.insert( it.data(), it.key() ); | ||
114 | } | ||
115 | |||
116 | } | ||
117 | |||
118 | bool ODateBookAccessBackend_SQL::load() | ||
119 | { | ||
120 | if (!m_driver->open() ) | ||
121 | return false; | ||
122 | |||
123 | // Don't expect that the database exists. | ||
124 | // It is save here to create the table, even if it | ||
125 | // do exist. ( Is that correct for all databases ?? ) | ||
126 | QStringqu = "create table datebook( uid INTEGER PRIMARY KEY "; | ||
127 | |||
128 | QMap<int, QString>::Iterator it; | ||
129 | for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ | ||
130 | qu += QString( ",%1 VARCHAR(10)" ).arg( it.data() ); | ||
131 | } | ||
132 | qu += " );"; | ||
133 | |||
134 | qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; | ||
135 | |||
136 | qWarning( "command: %s", qu.latin1() ); | ||
137 | |||
138 | OSQLRawQuery raw( qu ); | ||
139 | OSQLResult res = m_driver->query( &raw ); | ||
140 | if ( res.state() != OSQLResult::Success ) | ||
141 | return false; | ||
142 | |||
143 | update(); | ||
144 | |||
145 | return true; | ||
146 | } | ||
147 | |||
148 | void ODateBookAccessBackend_SQL::update() | ||
149 | { | ||
150 | |||
151 | QString qu = "select uid from datebook"; | ||
152 | OSQLRawQuery raw( qu ); | ||
153 | OSQLResult res = m_driver->query( &raw ); | ||
154 | if ( res.state() != OSQLResult::Success ){ | ||
155 | // m_uids.clear(); | ||
156 | return; | ||
157 | } | ||
158 | |||
159 | m_uids = extractUids( res ); | ||
160 | |||
161 | } | ||
162 | |||
163 | bool ODateBookAccessBackend_SQL::reload() | ||
164 | { | ||
165 | return load(); | ||
166 | } | ||
167 | |||
168 | bool ODateBookAccessBackend_SQL::save() | ||
169 | { | ||
170 | return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) | ||
171 | } | ||
172 | |||
173 | QArray<int> ODateBookAccessBackend_SQL::allRecords()const | ||
174 | { | ||
175 | return m_uids; | ||
176 | } | ||
177 | |||
178 | QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) { | ||
179 | return QArray<int>(); | ||
180 | } | ||
181 | |||
182 | void ODateBookAccessBackend_SQL::clear() | ||
183 | { | ||
184 | QString qu = "drop table datebook;"; | ||
185 | qu += "drop table custom_data;"; | ||
186 | |||
187 | OSQLRawQuery raw( qu ); | ||
188 | OSQLResult res = m_driver->query( &raw ); | ||
189 | |||
190 | reload(); | ||
191 | } | ||
192 | |||
193 | |||
194 | OEvent ODateBookAccessBackend_SQL::find( int uid ) const{ | ||
195 | QString qu = "select *"; | ||
196 | qu += "from datebook where uid = " + QString::number(uid); | ||
197 | |||
198 | OSQLRawQuery raw( qu ); | ||
199 | OSQLResult res = m_driver->query( &raw ); | ||
200 | |||
201 | OSQLResultItem resItem = res.first(); | ||
202 | |||
203 | // Create Map for date event and insert UID | ||
204 | QMap<int,QString> dateEventMap; | ||
205 | dateEventMap.insert( OEvent::FUid, QString::number( uid ) ); | ||
206 | |||
207 | // Now insert the data out of the columns into the map. | ||
208 | QMapConstIterator<int, QString> it; | ||
209 | for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ | ||
210 | dateEventMap.insert( m_reverseFieldMap[*it], resItem.data( *it ) ); | ||
211 | } | ||
212 | |||
213 | // Last step: Put map into date event and return it | ||
214 | OEvent retDate( dateEventMap ); | ||
215 | |||
216 | return retDate; | ||
217 | } | ||
218 | |||
219 | // FIXME: Speed up update of uid's.. | ||
220 | bool ODateBookAccessBackend_SQL::add( const OEvent& ev ) | ||
221 | { | ||
222 | QMap<int,QString> eventMap = ev.toMap(); | ||
223 | |||
224 | QString qu = "insert into datebook VALUES( " + QString::number( ev.uid() ); | ||
225 | QMap<int, QString>::Iterator it; | ||
226 | for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ | ||
227 | if ( !eventMap[it.key()].isEmpty() ) | ||
228 | qu += QString( ",\"%1\"" ).arg( eventMap[it.key()] ); | ||
229 | else | ||
230 | qu += QString( ",\"\"" ); | ||
231 | } | ||
232 | qu += " );"; | ||
233 | |||
234 | // Add custom entries | ||
235 | int id = 0; | ||
236 | QMap<QString, QString> customMap = ev.toExtraMap(); | ||
237 | for( QMap<QString, QString>::Iterator it = customMap.begin(); | ||
238 | it != customMap.end(); ++it ){ | ||
239 | qu += "insert into custom_data VALUES(" | ||
240 | + QString::number( ev.uid() ) | ||
241 | + "," | ||
242 | + QString::number( id++ ) | ||
243 | + ",'" | ||
244 | + it.key() //.latin1() | ||
245 | + "'," | ||
246 | + "0" // Priority for future enhancements | ||
247 | + ",'" | ||
248 | + it.data() //.latin1() | ||
249 | + "');"; | ||
250 | } | ||
251 | qWarning("add %s", qu.latin1() ); | ||
252 | |||
253 | OSQLRawQuery raw( qu ); | ||
254 | OSQLResult res = m_driver->query( &raw ); | ||
255 | if ( res.state() != OSQLResult::Success ){ | ||
256 | return false; | ||
257 | } | ||
258 | |||
259 | // Update list of uid's | ||
260 | update(); | ||
261 | |||
262 | return true; | ||
263 | } | ||
264 | |||
265 | // FIXME: Speed up update of uid's.. | ||
266 | bool ODateBookAccessBackend_SQL::remove( int uid ) | ||
267 | { | ||
268 | QString qu = "DELETE from datebook where uid = " | ||
269 | + QString::number( uid ) + ";"; | ||
270 | qu += "DELETE from custom_data where uid = " | ||
271 | + QString::number( uid ) + ";"; | ||
272 | |||
273 | OSQLRawQuery raw( qu ); | ||
274 | OSQLResult res = m_driver->query( &raw ); | ||
275 | if ( res.state() != OSQLResult::Success ){ | ||
276 | return false; | ||
277 | } | ||
278 | |||
279 | // Update list of uid's | ||
280 | update(); | ||
281 | |||
282 | return true; | ||
283 | } | ||
284 | |||
285 | bool ODateBookAccessBackend_SQL::replace( const OEvent& ev ) | ||
286 | { | ||
287 | remove( ev.uid() ); | ||
288 | return add( ev ); | ||
289 | } | ||
290 | |||
291 | QArray<int> ODateBookAccessBackend_SQL::rawEvents()const | ||
292 | { | ||
293 | return allRecords(); | ||
294 | } | ||
295 | |||
296 | QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const | ||
297 | { | ||
298 | QString qu = "select uid from datebook where RType!=\"\" AND RType!=\"NoRepeat\""; | ||
299 | OSQLRawQuery raw( qu ); | ||
300 | OSQLResult res = m_driver->query( &raw ); | ||
301 | if ( res.state() != OSQLResult::Success ){ | ||
302 | QArray<int> nix; | ||
303 | return nix; | ||
304 | } | ||
305 | |||
306 | return extractUids( res ); | ||
307 | } | ||
308 | |||
309 | QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const | ||
310 | { | ||
311 | QString qu = "select uid from datebook where RType=\"\" or RType=\"NoRepeat\""; | ||
312 | OSQLRawQuery raw( qu ); | ||
313 | OSQLResult res = m_driver->query( &raw ); | ||
314 | if ( res.state() != OSQLResult::Success ){ | ||
315 | QArray<int> nix; | ||
316 | return nix; | ||
317 | } | ||
318 | |||
319 | return extractUids( res ); | ||
320 | } | ||
321 | |||
322 | OEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats() | ||
323 | { | ||
324 | QArray<int> nonRepUids = nonRepeats(); | ||
325 | OEvent::ValueList list; | ||
326 | |||
327 | for (uint i = 0; i < nonRepUids.count(); ++i ){ | ||
328 | list.append( find( nonRepUids[i] ) ); | ||
329 | } | ||
330 | |||
331 | return list; | ||
332 | |||
333 | } | ||
334 | OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats() | ||
335 | { | ||
336 | QArray<int> rawRepUids = rawRepeats(); | ||
337 | OEvent::ValueList list; | ||
338 | |||
339 | for (uint i = 0; i < rawRepUids.count(); ++i ){ | ||
340 | list.append( find( rawRepUids[i] ) ); | ||
341 | } | ||
342 | |||
343 | return list; | ||
344 | } | ||
345 | |||
346 | |||
347 | QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const | ||
348 | { | ||
349 | QArray<int> null; | ||
350 | return null; | ||
351 | } | ||
352 | |||
353 | /* ===== Private Functions ========================================== */ | ||
354 | |||
355 | QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const | ||
356 | { | ||
357 | qWarning("extractUids"); | ||
358 | QTime t; | ||
359 | t.start(); | ||
360 | OSQLResultItem::ValueList list = res.results(); | ||
361 | OSQLResultItem::ValueList::Iterator it; | ||
362 | QArray<int> ints(list.count() ); | ||
363 | qWarning(" count = %d", list.count() ); | ||
364 | |||
365 | int i = 0; | ||
366 | for (it = list.begin(); it != list.end(); ++it ) { | ||
367 | ints[i] = (*it).data("uid").toInt(); | ||
368 | i++; | ||
369 | } | ||
370 | qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); | ||
371 | |||
372 | return ints; | ||
373 | |||
374 | } | ||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.h b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.h new file mode 100644 index 0000000..ba514bc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.h | |||
@@ -0,0 +1,65 @@ | |||
1 | #ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H | ||
2 | #define OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H | ||
3 | |||
4 | #include <qmap.h> | ||
5 | #include <opie2/osqlresult.h> | ||
6 | |||
7 | #include "odatebookaccessbackend.h" | ||
8 | |||
9 | namespace Opie { namespace DB { | ||
10 | class OSQLDriver; | ||
11 | |||
12 | }} | ||
13 | |||
14 | /** | ||
15 | * This is the default SQL implementation for DateBoook SQL storage | ||
16 | * It fully implements the interface | ||
17 | * @see ODateBookAccessBackend | ||
18 | * @see OPimAccessBackend | ||
19 | */ | ||
20 | class ODateBookAccessBackend_SQL : public ODateBookAccessBackend { | ||
21 | public: | ||
22 | ODateBookAccessBackend_SQL( const QString& appName, | ||
23 | const QString& fileName = QString::null); | ||
24 | ~ODateBookAccessBackend_SQL(); | ||
25 | |||
26 | bool load(); | ||
27 | bool reload(); | ||
28 | bool save(); | ||
29 | |||
30 | QArray<int> allRecords()const; | ||
31 | QArray<int> matchRegexp(const QRegExp &r) const; | ||
32 | QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); | ||
33 | OEvent find( int uid )const; | ||
34 | void clear(); | ||
35 | bool add( const OEvent& ev ); | ||
36 | bool remove( int uid ); | ||
37 | bool replace( const OEvent& ev ); | ||
38 | |||
39 | QArray<UID> rawEvents()const; | ||
40 | QArray<UID> rawRepeats()const; | ||
41 | QArray<UID> nonRepeats()const; | ||
42 | |||
43 | OEvent::ValueList directNonRepeats(); | ||
44 | OEvent::ValueList directRawRepeats(); | ||
45 | |||
46 | private: | ||
47 | bool loadFile(); | ||
48 | QString m_fileName; | ||
49 | QArray<int> m_uids; | ||
50 | |||
51 | QMap<int, QString> m_fieldMap; | ||
52 | QMap<QString, int> m_reverseFieldMap; | ||
53 | |||
54 | Opie::DB::OSQLDriver* m_driver; | ||
55 | |||
56 | class Private; | ||
57 | Private *d; | ||
58 | |||
59 | void initFields(); | ||
60 | void update(); | ||
61 | QArray<int> extractUids( Opie::DB::OSQLResult& res ) const; | ||
62 | |||
63 | }; | ||
64 | |||
65 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp new file mode 100644 index 0000000..929d004 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp | |||
@@ -0,0 +1,612 @@ | |||
1 | #include <errno.h> | ||
2 | #include <fcntl.h> | ||
3 | |||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | |||
7 | #include <sys/types.h> | ||
8 | #include <sys/mman.h> | ||
9 | #include <sys/stat.h> | ||
10 | |||
11 | #include <unistd.h> | ||
12 | |||
13 | #include <qasciidict.h> | ||
14 | #include <qfile.h> | ||
15 | |||
16 | #include <qtopia/global.h> | ||
17 | #include <qtopia/stringutil.h> | ||
18 | #include <qtopia/timeconversion.h> | ||
19 | |||
20 | #include "opimnotifymanager.h" | ||
21 | #include "orecur.h" | ||
22 | #include "otimezone.h" | ||
23 | #include "odatebookaccessbackend_xml.h" | ||
24 | |||
25 | namespace { | ||
26 | // FROM TT again | ||
27 | char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) | ||
28 | { | ||
29 | char needleChar; | ||
30 | char haystackChar; | ||
31 | if (!needle || !haystack || !hLen || !nLen) | ||
32 | return 0; | ||
33 | |||
34 | const char* hsearch = haystack; | ||
35 | |||
36 | if ((needleChar = *needle++) != 0) { | ||
37 | nLen--; //(to make up for needle++) | ||
38 | do { | ||
39 | do { | ||
40 | if ((haystackChar = *hsearch++) == 0) | ||
41 | return (0); | ||
42 | if (hsearch >= haystack + hLen) | ||
43 | return (0); | ||
44 | } while (haystackChar != needleChar); | ||
45 | } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); | ||
46 | hsearch--; | ||
47 | } | ||
48 | return ((char *)hsearch); | ||
49 | } | ||
50 | } | ||
51 | |||
52 | namespace { | ||
53 | time_t start, end, created, rp_end; | ||
54 | ORecur* rec; | ||
55 | ORecur* recur() { | ||
56 | if (!rec) | ||
57 | rec = new ORecur; | ||
58 | |||
59 | return rec; | ||
60 | } | ||
61 | int alarmTime; | ||
62 | int snd; | ||
63 | enum Attribute{ | ||
64 | FDescription = 0, | ||
65 | FLocation, | ||
66 | FCategories, | ||
67 | FUid, | ||
68 | FType, | ||
69 | FAlarm, | ||
70 | FSound, | ||
71 | FRType, | ||
72 | FRWeekdays, | ||
73 | FRPosition, | ||
74 | FRFreq, | ||
75 | FRHasEndDate, | ||
76 | FREndDate, | ||
77 | FRStart, | ||
78 | FREnd, | ||
79 | FNote, | ||
80 | FCreated, // Should't this be called FRCreated ? | ||
81 | FTimeZone, | ||
82 | FRecParent, | ||
83 | FRecChildren, | ||
84 | FExceptions | ||
85 | }; | ||
86 | |||
87 | // FIXME: Use OEvent::toMap() here !! (eilers) | ||
88 | inline void save( const OEvent& ev, QString& buf ) { | ||
89 | qWarning("Saving %d %s", ev.uid(), ev.description().latin1() ); | ||
90 | buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; | ||
91 | if (!ev.location().isEmpty() ) | ||
92 | buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; | ||
93 | |||
94 | buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; | ||
95 | buf += " uid=\"" + QString::number( ev.uid() ) + "\""; | ||
96 | |||
97 | if (ev.isAllDay() ) | ||
98 | buf += " type=\"AllDay\""; // is that all ?? (eilers) | ||
99 | |||
100 | if (ev.hasNotifiers() ) { | ||
101 | OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first | ||
102 | int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; | ||
103 | buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; | ||
104 | if ( alarm.sound() == OPimAlarm::Loud ) | ||
105 | buf += "loud"; | ||
106 | else | ||
107 | buf += "silent"; | ||
108 | buf += "\""; | ||
109 | } | ||
110 | if ( ev.hasRecurrence() ) { | ||
111 | buf += ev.recurrence().toString(); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * fscking timezones :) well, we'll first convert | ||
116 | * the QDateTime to a QDateTime in UTC time | ||
117 | * and then we'll create a nice time_t | ||
118 | */ | ||
119 | OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); | ||
120 | buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; | ||
121 | buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; | ||
122 | if (!ev.note().isEmpty() ) { | ||
123 | buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; | ||
124 | } | ||
125 | |||
126 | buf += " timezone=\""; | ||
127 | if ( ev.timeZone().isEmpty() ) | ||
128 | buf += "None"; | ||
129 | else | ||
130 | buf += ev.timeZone(); | ||
131 | buf += "\""; | ||
132 | |||
133 | if (ev.parent() != 0 ) { | ||
134 | buf += " recparent=\""+QString::number(ev.parent() )+"\""; | ||
135 | } | ||
136 | |||
137 | if (ev.children().count() != 0 ) { | ||
138 | QArray<int> children = ev.children(); | ||
139 | buf += " recchildren=\""; | ||
140 | for ( uint i = 0; i < children.count(); i++ ) { | ||
141 | if ( i != 0 ) buf += " "; | ||
142 | buf += QString::number( children[i] ); | ||
143 | } | ||
144 | buf+= "\""; | ||
145 | } | ||
146 | |||
147 | // skip custom writing | ||
148 | } | ||
149 | |||
150 | inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { | ||
151 | QMap<int, OEvent>::ConstIterator it; | ||
152 | QString buf; | ||
153 | QCString str; | ||
154 | int total_written; | ||
155 | for ( it = list.begin(); it != list.end(); ++it ) { | ||
156 | buf = "<event"; | ||
157 | save( it.data(), buf ); | ||
158 | buf += " />\n"; | ||
159 | str = buf.utf8(); | ||
160 | |||
161 | total_written = file.writeBlock(str.data(), str.length() ); | ||
162 | if ( total_written != int(str.length() ) ) | ||
163 | return false; | ||
164 | } | ||
165 | return true; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , | ||
170 | const QString& fileName ) | ||
171 | : ODateBookAccessBackend() { | ||
172 | m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; | ||
173 | m_changed = false; | ||
174 | } | ||
175 | ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { | ||
176 | } | ||
177 | bool ODateBookAccessBackend_XML::load() { | ||
178 | return loadFile(); | ||
179 | } | ||
180 | bool ODateBookAccessBackend_XML::reload() { | ||
181 | clear(); | ||
182 | return load(); | ||
183 | } | ||
184 | bool ODateBookAccessBackend_XML::save() { | ||
185 | if (!m_changed) return true; | ||
186 | |||
187 | int total_written; | ||
188 | QString strFileNew = m_name + ".new"; | ||
189 | |||
190 | QFile f( strFileNew ); | ||
191 | if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; | ||
192 | |||
193 | QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); | ||
194 | buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; | ||
195 | buf += "<events>\n"; | ||
196 | QCString str = buf.utf8(); | ||
197 | total_written = f.writeBlock( str.data(), str.length() ); | ||
198 | if ( total_written != int(str.length() ) ) { | ||
199 | f.close(); | ||
200 | QFile::remove( strFileNew ); | ||
201 | return false; | ||
202 | } | ||
203 | |||
204 | if (!forAll( m_raw, f ) ) { | ||
205 | f.close(); | ||
206 | QFile::remove( strFileNew ); | ||
207 | return false; | ||
208 | } | ||
209 | if (!forAll( m_rep, f ) ) { | ||
210 | f.close(); | ||
211 | QFile::remove( strFileNew ); | ||
212 | return false; | ||
213 | } | ||
214 | |||
215 | buf = "</events>\n</DATEBOOK>\n"; | ||
216 | str = buf.utf8(); | ||
217 | total_written = f.writeBlock( str.data(), str.length() ); | ||
218 | if ( total_written != int(str.length() ) ) { | ||
219 | f.close(); | ||
220 | QFile::remove( strFileNew ); | ||
221 | return false; | ||
222 | } | ||
223 | f.close(); | ||
224 | |||
225 | if ( ::rename( strFileNew, m_name ) < 0 ) { | ||
226 | QFile::remove( strFileNew ); | ||
227 | return false; | ||
228 | } | ||
229 | |||
230 | m_changed = false; | ||
231 | return true; | ||
232 | } | ||
233 | QArray<int> ODateBookAccessBackend_XML::allRecords()const { | ||
234 | QArray<int> ints( m_raw.count()+ m_rep.count() ); | ||
235 | uint i = 0; | ||
236 | QMap<int, OEvent>::ConstIterator it; | ||
237 | |||
238 | for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { | ||
239 | ints[i] = it.key(); | ||
240 | i++; | ||
241 | } | ||
242 | for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { | ||
243 | ints[i] = it.key(); | ||
244 | i++; | ||
245 | } | ||
246 | |||
247 | return ints; | ||
248 | } | ||
249 | QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) { | ||
250 | return QArray<int>(); | ||
251 | } | ||
252 | void ODateBookAccessBackend_XML::clear() { | ||
253 | m_changed = true; | ||
254 | m_raw.clear(); | ||
255 | m_rep.clear(); | ||
256 | } | ||
257 | OEvent ODateBookAccessBackend_XML::find( int uid ) const{ | ||
258 | if ( m_raw.contains( uid ) ) | ||
259 | return m_raw[uid]; | ||
260 | else | ||
261 | return m_rep[uid]; | ||
262 | } | ||
263 | bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { | ||
264 | m_changed = true; | ||
265 | if (ev.hasRecurrence() ) | ||
266 | m_rep.insert( ev.uid(), ev ); | ||
267 | else | ||
268 | m_raw.insert( ev.uid(), ev ); | ||
269 | |||
270 | return true; | ||
271 | } | ||
272 | bool ODateBookAccessBackend_XML::remove( int uid ) { | ||
273 | m_changed = true; | ||
274 | m_rep.remove( uid ); | ||
275 | m_rep.remove( uid ); | ||
276 | |||
277 | return true; | ||
278 | } | ||
279 | bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) { | ||
280 | replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers) | ||
281 | return add( ev ); | ||
282 | } | ||
283 | QArray<int> ODateBookAccessBackend_XML::rawEvents()const { | ||
284 | return allRecords(); | ||
285 | } | ||
286 | QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { | ||
287 | QArray<int> ints( m_rep.count() ); | ||
288 | uint i = 0; | ||
289 | QMap<int, OEvent>::ConstIterator it; | ||
290 | |||
291 | for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { | ||
292 | ints[i] = it.key(); | ||
293 | i++; | ||
294 | } | ||
295 | |||
296 | return ints; | ||
297 | } | ||
298 | QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { | ||
299 | QArray<int> ints( m_raw.count() ); | ||
300 | uint i = 0; | ||
301 | QMap<int, OEvent>::ConstIterator it; | ||
302 | |||
303 | for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { | ||
304 | ints[i] = it.key(); | ||
305 | i++; | ||
306 | } | ||
307 | |||
308 | return ints; | ||
309 | } | ||
310 | OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { | ||
311 | OEvent::ValueList list; | ||
312 | QMap<int, OEvent>::ConstIterator it; | ||
313 | for (it = m_raw.begin(); it != m_raw.end(); ++it ) | ||
314 | list.append( it.data() ); | ||
315 | |||
316 | return list; | ||
317 | } | ||
318 | OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { | ||
319 | OEvent::ValueList list; | ||
320 | QMap<int, OEvent>::ConstIterator it; | ||
321 | for (it = m_rep.begin(); it != m_rep.end(); ++it ) | ||
322 | list.append( it.data() ); | ||
323 | |||
324 | return list; | ||
325 | } | ||
326 | |||
327 | // FIXME: Use OEvent::fromMap() (eilers) | ||
328 | bool ODateBookAccessBackend_XML::loadFile() { | ||
329 | m_changed = false; | ||
330 | |||
331 | int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); | ||
332 | if ( fd < 0 ) return false; | ||
333 | |||
334 | struct stat attribute; | ||
335 | if ( ::fstat(fd, &attribute ) == -1 ) { | ||
336 | ::close( fd ); | ||
337 | return false; | ||
338 | } | ||
339 | void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); | ||
340 | if ( map_addr == ( (caddr_t)-1) ) { | ||
341 | ::close( fd ); | ||
342 | return false; | ||
343 | } | ||
344 | |||
345 | ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); | ||
346 | ::close( fd ); | ||
347 | |||
348 | QAsciiDict<int> dict(FExceptions+1); | ||
349 | dict.setAutoDelete( true ); | ||
350 | dict.insert( "description", new int(FDescription) ); | ||
351 | dict.insert( "location", new int(FLocation) ); | ||
352 | dict.insert( "categories", new int(FCategories) ); | ||
353 | dict.insert( "uid", new int(FUid) ); | ||
354 | dict.insert( "type", new int(FType) ); | ||
355 | dict.insert( "alarm", new int(FAlarm) ); | ||
356 | dict.insert( "sound", new int(FSound) ); | ||
357 | dict.insert( "rtype", new int(FRType) ); | ||
358 | dict.insert( "rweekdays", new int(FRWeekdays) ); | ||
359 | dict.insert( "rposition", new int(FRPosition) ); | ||
360 | dict.insert( "rfreq", new int(FRFreq) ); | ||
361 | dict.insert( "rhasenddate", new int(FRHasEndDate) ); | ||
362 | dict.insert( "enddt", new int(FREndDate) ); | ||
363 | dict.insert( "start", new int(FRStart) ); | ||
364 | dict.insert( "end", new int(FREnd) ); | ||
365 | dict.insert( "note", new int(FNote) ); | ||
366 | dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ?? | ||
367 | dict.insert( "recparent", new int(FRecParent) ); | ||
368 | dict.insert( "recchildren", new int(FRecChildren) ); | ||
369 | dict.insert( "exceptions", new int(FExceptions) ); | ||
370 | dict.insert( "timezone", new int(FTimeZone) ); | ||
371 | |||
372 | char* dt = (char*)map_addr; | ||
373 | int len = attribute.st_size; | ||
374 | int i = 0; | ||
375 | char* point; | ||
376 | const char* collectionString = "<event "; | ||
377 | int strLen = ::strlen(collectionString); | ||
378 | int *find; | ||
379 | while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { | ||
380 | i = point -dt; | ||
381 | i+= strLen; | ||
382 | |||
383 | alarmTime = -1; | ||
384 | snd = 0; // silent | ||
385 | |||
386 | OEvent ev; | ||
387 | rec = 0; | ||
388 | |||
389 | while ( TRUE ) { | ||
390 | while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) | ||
391 | ++i; | ||
392 | if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) | ||
393 | break; | ||
394 | |||
395 | |||
396 | // we have another attribute, read it. | ||
397 | int j = i; | ||
398 | while ( j < len && dt[j] != '=' ) | ||
399 | ++j; | ||
400 | QCString attr( dt+i, j-i+1); | ||
401 | |||
402 | i = ++j; // skip = | ||
403 | |||
404 | // find the start of quotes | ||
405 | while ( i < len && dt[i] != '"' ) | ||
406 | ++i; | ||
407 | j = ++i; | ||
408 | |||
409 | bool haveUtf = FALSE; | ||
410 | bool haveEnt = FALSE; | ||
411 | while ( j < len && dt[j] != '"' ) { | ||
412 | if ( ((unsigned char)dt[j]) > 0x7f ) | ||
413 | haveUtf = TRUE; | ||
414 | if ( dt[j] == '&' ) | ||
415 | haveEnt = TRUE; | ||
416 | ++j; | ||
417 | } | ||
418 | if ( i == j ) { | ||
419 | // empty value | ||
420 | i = j + 1; | ||
421 | continue; | ||
422 | } | ||
423 | |||
424 | QCString value( dt+i, j-i+1 ); | ||
425 | i = j + 1; | ||
426 | |||
427 | QString str = (haveUtf ? QString::fromUtf8( value ) | ||
428 | : QString::fromLatin1( value ) ); | ||
429 | if ( haveEnt ) | ||
430 | str = Qtopia::plainString( str ); | ||
431 | |||
432 | /* | ||
433 | * add key + value | ||
434 | */ | ||
435 | find = dict[attr.data()]; | ||
436 | if (!find) | ||
437 | ev.setCustomField( attr, str ); | ||
438 | else { | ||
439 | setField( ev, *find, str ); | ||
440 | } | ||
441 | } | ||
442 | /* time to finalize */ | ||
443 | finalizeRecord( ev ); | ||
444 | delete rec; | ||
445 | } | ||
446 | ::munmap(map_addr, attribute.st_size ); | ||
447 | m_changed = false; // changed during add | ||
448 | |||
449 | return true; | ||
450 | } | ||
451 | |||
452 | // FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers) | ||
453 | void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { | ||
454 | /* AllDay is alway in UTC */ | ||
455 | if ( ev.isAllDay() ) { | ||
456 | OTimeZone utc = OTimeZone::utc(); | ||
457 | ev.setStartDateTime( utc.fromUTCDateTime( start ) ); | ||
458 | ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); | ||
459 | ev.setTimeZone( "UTC"); // make sure it is really utc | ||
460 | }else { | ||
461 | /* to current date time */ | ||
462 | // qWarning(" Start is %d", start ); | ||
463 | OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); | ||
464 | QDateTime date = zone.toDateTime( start ); | ||
465 | qWarning(" Start is %s", date.toString().latin1() ); | ||
466 | ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); | ||
467 | |||
468 | date = zone.toDateTime( end ); | ||
469 | ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); | ||
470 | } | ||
471 | if ( rec && rec->doesRecur() ) { | ||
472 | OTimeZone utc = OTimeZone::utc(); | ||
473 | ORecur recu( *rec ); // call copy c'tor; | ||
474 | recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); | ||
475 | recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); | ||
476 | recu.setStart( ev.startDateTime().date() ); | ||
477 | ev.setRecurrence( recu ); | ||
478 | } | ||
479 | |||
480 | if (alarmTime != -1 ) { | ||
481 | QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); | ||
482 | OPimAlarm al( snd , dt ); | ||
483 | ev.notifiers().add( al ); | ||
484 | } | ||
485 | if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) { | ||
486 | qWarning("already contains assign uid"); | ||
487 | ev.setUid( 1 ); | ||
488 | } | ||
489 | qWarning("addind %d %s", ev.uid(), ev.description().latin1() ); | ||
490 | if ( ev.hasRecurrence() ) | ||
491 | m_rep.insert( ev.uid(), ev ); | ||
492 | else | ||
493 | m_raw.insert( ev.uid(), ev ); | ||
494 | |||
495 | } | ||
496 | void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) { | ||
497 | // qWarning(" setting %s", value.latin1() ); | ||
498 | switch( id ) { | ||
499 | case FDescription: | ||
500 | e.setDescription( value ); | ||
501 | break; | ||
502 | case FLocation: | ||
503 | e.setLocation( value ); | ||
504 | break; | ||
505 | case FCategories: | ||
506 | e.setCategories( e.idsFromString( value ) ); | ||
507 | break; | ||
508 | case FUid: | ||
509 | e.setUid( value.toInt() ); | ||
510 | break; | ||
511 | case FType: | ||
512 | if ( value == "AllDay" ) { | ||
513 | e.setAllDay( true ); | ||
514 | e.setTimeZone( "UTC" ); | ||
515 | } | ||
516 | break; | ||
517 | case FAlarm: | ||
518 | alarmTime = value.toInt(); | ||
519 | break; | ||
520 | case FSound: | ||
521 | snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent; | ||
522 | break; | ||
523 | // recurrence stuff | ||
524 | case FRType: | ||
525 | if ( value == "Daily" ) | ||
526 | recur()->setType( ORecur::Daily ); | ||
527 | else if ( value == "Weekly" ) | ||
528 | recur()->setType( ORecur::Weekly); | ||
529 | else if ( value == "MonthlyDay" ) | ||
530 | recur()->setType( ORecur::MonthlyDay ); | ||
531 | else if ( value == "MonthlyDate" ) | ||
532 | recur()->setType( ORecur::MonthlyDate ); | ||
533 | else if ( value == "Yearly" ) | ||
534 | recur()->setType( ORecur::Yearly ); | ||
535 | else | ||
536 | recur()->setType( ORecur::NoRepeat ); | ||
537 | break; | ||
538 | case FRWeekdays: | ||
539 | recur()->setDays( value.toInt() ); | ||
540 | break; | ||
541 | case FRPosition: | ||
542 | recur()->setPosition( value.toInt() ); | ||
543 | break; | ||
544 | case FRFreq: | ||
545 | recur()->setFrequency( value.toInt() ); | ||
546 | break; | ||
547 | case FRHasEndDate: | ||
548 | recur()->setHasEndDate( value.toInt() ); | ||
549 | break; | ||
550 | case FREndDate: { | ||
551 | rp_end = (time_t) value.toLong(); | ||
552 | break; | ||
553 | } | ||
554 | case FRStart: { | ||
555 | start = (time_t) value.toLong(); | ||
556 | break; | ||
557 | } | ||
558 | case FREnd: { | ||
559 | end = ( (time_t) value.toLong() ); | ||
560 | break; | ||
561 | } | ||
562 | case FNote: | ||
563 | e.setNote( value ); | ||
564 | break; | ||
565 | case FCreated: | ||
566 | created = value.toInt(); | ||
567 | break; | ||
568 | case FRecParent: | ||
569 | e.setParent( value.toInt() ); | ||
570 | break; | ||
571 | case FRecChildren:{ | ||
572 | QStringList list = QStringList::split(' ', value ); | ||
573 | for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { | ||
574 | e.addChild( (*it).toInt() ); | ||
575 | } | ||
576 | } | ||
577 | break; | ||
578 | case FExceptions:{ | ||
579 | QStringList list = QStringList::split(' ', value ); | ||
580 | for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { | ||
581 | QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); | ||
582 | qWarning("adding exception %s", date.toString().latin1() ); | ||
583 | recur()->exceptions().append( date ); | ||
584 | } | ||
585 | } | ||
586 | break; | ||
587 | case FTimeZone: | ||
588 | if ( value != "None" ) | ||
589 | e.setTimeZone( value ); | ||
590 | break; | ||
591 | default: | ||
592 | break; | ||
593 | } | ||
594 | } | ||
595 | QArray<int> ODateBookAccessBackend_XML::matchRegexp( const QRegExp &r ) const | ||
596 | { | ||
597 | QArray<int> m_currentQuery( m_raw.count()+ m_rep.count() ); | ||
598 | uint arraycounter = 0; | ||
599 | QMap<int, OEvent>::ConstIterator it; | ||
600 | |||
601 | for ( it = m_raw.begin(); it != m_raw.end(); ++it ) | ||
602 | if ( it.data().match( r ) ) | ||
603 | m_currentQuery[arraycounter++] = it.data().uid(); | ||
604 | for ( it = m_rep.begin(); it != m_rep.end(); ++it ) | ||
605 | if ( it.data().match( r ) ) | ||
606 | m_currentQuery[arraycounter++] = it.data().uid(); | ||
607 | |||
608 | // Shrink to fit.. | ||
609 | m_currentQuery.resize(arraycounter); | ||
610 | |||
611 | return m_currentQuery; | ||
612 | } | ||
diff --git a/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.h b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.h new file mode 100644 index 0000000..a5cc0fc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.h | |||
@@ -0,0 +1,55 @@ | |||
1 | #ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H | ||
2 | #define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H | ||
3 | |||
4 | #include <qmap.h> | ||
5 | |||
6 | #include "odatebookaccessbackend.h" | ||
7 | |||
8 | /** | ||
9 | * This is the default XML implementation for DateBoook XML storage | ||
10 | * It fully implements the interface | ||
11 | * @see ODateBookAccessBackend | ||
12 | * @see OPimAccessBackend | ||
13 | */ | ||
14 | class ODateBookAccessBackend_XML : public ODateBookAccessBackend { | ||
15 | public: | ||
16 | ODateBookAccessBackend_XML( const QString& appName, | ||
17 | const QString& fileName = QString::null); | ||
18 | ~ODateBookAccessBackend_XML(); | ||
19 | |||
20 | bool load(); | ||
21 | bool reload(); | ||
22 | bool save(); | ||
23 | |||
24 | QArray<int> allRecords()const; | ||
25 | QArray<int> matchRegexp(const QRegExp &r) const; | ||
26 | QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); | ||
27 | OEvent find( int uid )const; | ||
28 | void clear(); | ||
29 | bool add( const OEvent& ev ); | ||
30 | bool remove( int uid ); | ||
31 | bool replace( const OEvent& ev ); | ||
32 | |||
33 | QArray<UID> rawEvents()const; | ||
34 | QArray<UID> rawRepeats()const; | ||
35 | QArray<UID> nonRepeats()const; | ||
36 | |||
37 | OEvent::ValueList directNonRepeats(); | ||
38 | OEvent::ValueList directRawRepeats(); | ||
39 | |||
40 | private: | ||
41 | bool m_changed :1 ; | ||
42 | bool loadFile(); | ||
43 | inline void finalizeRecord( OEvent& ev ); | ||
44 | inline void setField( OEvent&, int field, const QString& val ); | ||
45 | QString m_name; | ||
46 | QMap<int, OEvent> m_raw; | ||
47 | QMap<int, OEvent> m_rep; | ||
48 | |||
49 | struct Data; | ||
50 | Data* data; | ||
51 | class Private; | ||
52 | Private *d; | ||
53 | }; | ||
54 | |||
55 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/oevent.cpp b/noncore/unsupported/libopie/pim/oevent.cpp new file mode 100644 index 0000000..9b31957 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oevent.cpp | |||
@@ -0,0 +1,717 @@ | |||
1 | #include <qshared.h> | ||
2 | #include <qarray.h> | ||
3 | |||
4 | #include <qpe/palmtopuidgen.h> | ||
5 | #include <qpe/categories.h> | ||
6 | #include <qpe/stringutil.h> | ||
7 | |||
8 | #include "orecur.h" | ||
9 | #include "opimresolver.h" | ||
10 | #include "opimnotifymanager.h" | ||
11 | |||
12 | #include "oevent.h" | ||
13 | |||
14 | int OCalendarHelper::week( const QDate& date) { | ||
15 | // Calculates the week this date is in within that | ||
16 | // month. Equals the "row" is is in in the month view | ||
17 | int week = 1; | ||
18 | QDate tmp( date.year(), date.month(), 1 ); | ||
19 | if ( date.dayOfWeek() < tmp.dayOfWeek() ) | ||
20 | ++week; | ||
21 | |||
22 | week += ( date.day() - 1 ) / 7; | ||
23 | |||
24 | return week; | ||
25 | } | ||
26 | int OCalendarHelper::ocurrence( const QDate& date) { | ||
27 | // calculates the number of occurrances of this day of the | ||
28 | // week till the given date (e.g 3rd Wednesday of the month) | ||
29 | return ( date.day() - 1 ) / 7 + 1; | ||
30 | } | ||
31 | int OCalendarHelper::dayOfWeek( char day ) { | ||
32 | int dayOfWeek = 1; | ||
33 | char i = ORecur::MON; | ||
34 | while ( !( i & day ) && i <= ORecur::SUN ) { | ||
35 | i <<= 1; | ||
36 | ++dayOfWeek; | ||
37 | } | ||
38 | return dayOfWeek; | ||
39 | } | ||
40 | int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) { | ||
41 | return ( second.year() - first.year() ) * 12 + | ||
42 | second.month() - first.month(); | ||
43 | } | ||
44 | |||
45 | struct OEvent::Data : public QShared { | ||
46 | Data() : QShared() { | ||
47 | child = 0; | ||
48 | recur = 0; | ||
49 | manager = 0; | ||
50 | isAllDay = false; | ||
51 | parent = 0; | ||
52 | } | ||
53 | ~Data() { | ||
54 | delete manager; | ||
55 | delete recur; | ||
56 | } | ||
57 | QString description; | ||
58 | QString location; | ||
59 | OPimNotifyManager* manager; | ||
60 | ORecur* recur; | ||
61 | QString note; | ||
62 | QDateTime created; | ||
63 | QDateTime start; | ||
64 | QDateTime end; | ||
65 | bool isAllDay : 1; | ||
66 | QString timezone; | ||
67 | QArray<int>* child; | ||
68 | int parent; | ||
69 | }; | ||
70 | |||
71 | OEvent::OEvent( int uid ) | ||
72 | : OPimRecord( uid ) { | ||
73 | data = new Data; | ||
74 | } | ||
75 | OEvent::OEvent( const OEvent& ev) | ||
76 | : OPimRecord( ev ), data( ev.data ) | ||
77 | { | ||
78 | data->ref(); | ||
79 | } | ||
80 | |||
81 | OEvent::OEvent( const QMap<int, QString> map ) | ||
82 | : OPimRecord( 0 ) | ||
83 | { | ||
84 | data = new Data; | ||
85 | |||
86 | fromMap( map ); | ||
87 | } | ||
88 | |||
89 | OEvent::~OEvent() { | ||
90 | if ( data->deref() ) { | ||
91 | delete data; | ||
92 | data = 0; | ||
93 | } | ||
94 | } | ||
95 | OEvent& OEvent::operator=( const OEvent& ev) { | ||
96 | if ( this == &ev ) return *this; | ||
97 | |||
98 | OPimRecord::operator=( ev ); | ||
99 | ev.data->ref(); | ||
100 | deref(); | ||
101 | data = ev.data; | ||
102 | |||
103 | |||
104 | return *this; | ||
105 | } | ||
106 | QString OEvent::description()const { | ||
107 | return data->description; | ||
108 | } | ||
109 | void OEvent::setDescription( const QString& description ) { | ||
110 | changeOrModify(); | ||
111 | data->description = description; | ||
112 | } | ||
113 | void OEvent::setLocation( const QString& loc ) { | ||
114 | changeOrModify(); | ||
115 | data->location = loc; | ||
116 | } | ||
117 | QString OEvent::location()const { | ||
118 | return data->location; | ||
119 | } | ||
120 | OPimNotifyManager &OEvent::notifiers()const { | ||
121 | // I hope we can skip the changeOrModify here | ||
122 | // the notifier should take care of it | ||
123 | // and OPimNotify is shared too | ||
124 | if (!data->manager ) | ||
125 | data->manager = new OPimNotifyManager; | ||
126 | |||
127 | return *data->manager; | ||
128 | } | ||
129 | bool OEvent::hasNotifiers()const { | ||
130 | if (!data->manager ) | ||
131 | return false; | ||
132 | if (data->manager->reminders().isEmpty() && | ||
133 | data->manager->alarms().isEmpty() ) | ||
134 | return false; | ||
135 | |||
136 | return true; | ||
137 | } | ||
138 | ORecur OEvent::recurrence()const { | ||
139 | if (!data->recur) | ||
140 | data->recur = new ORecur; | ||
141 | |||
142 | return *data->recur; | ||
143 | } | ||
144 | void OEvent::setRecurrence( const ORecur& rec) { | ||
145 | changeOrModify(); | ||
146 | if (data->recur ) | ||
147 | (*data->recur) = rec; | ||
148 | else | ||
149 | data->recur = new ORecur( rec ); | ||
150 | } | ||
151 | bool OEvent::hasRecurrence()const { | ||
152 | if (!data->recur ) return false; | ||
153 | return data->recur->doesRecur(); | ||
154 | } | ||
155 | QString OEvent::note()const { | ||
156 | return data->note; | ||
157 | } | ||
158 | void OEvent::setNote( const QString& note ) { | ||
159 | changeOrModify(); | ||
160 | data->note = note; | ||
161 | } | ||
162 | QDateTime OEvent::createdDateTime()const { | ||
163 | return data->created; | ||
164 | } | ||
165 | void OEvent::setCreatedDateTime( const QDateTime& time ) { | ||
166 | changeOrModify(); | ||
167 | data->created = time; | ||
168 | } | ||
169 | QDateTime OEvent::startDateTime()const { | ||
170 | if ( data->isAllDay ) | ||
171 | return QDateTime( data->start.date(), QTime(0, 0, 0 ) ); | ||
172 | return data->start; | ||
173 | } | ||
174 | QDateTime OEvent::startDateTimeInZone()const { | ||
175 | /* if no timezone, or all day event or if the current and this timeZone match... */ | ||
176 | if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return startDateTime(); | ||
177 | |||
178 | OTimeZone zone(data->timezone ); | ||
179 | return zone.toDateTime( data->start, OTimeZone::current() ); | ||
180 | } | ||
181 | void OEvent::setStartDateTime( const QDateTime& dt ) { | ||
182 | changeOrModify(); | ||
183 | data->start = dt; | ||
184 | } | ||
185 | QDateTime OEvent::endDateTime()const { | ||
186 | /* | ||
187 | * if all Day event the end time needs | ||
188 | * to be on the same day as the start | ||
189 | */ | ||
190 | if ( data->isAllDay ) | ||
191 | return QDateTime( data->start.date(), QTime(23, 59, 59 ) ); | ||
192 | return data->end; | ||
193 | } | ||
194 | QDateTime OEvent::endDateTimeInZone()const { | ||
195 | /* if no timezone, or all day event or if the current and this timeZone match... */ | ||
196 | if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return endDateTime(); | ||
197 | |||
198 | OTimeZone zone(data->timezone ); | ||
199 | return zone.toDateTime( data->end, OTimeZone::current() ); | ||
200 | } | ||
201 | void OEvent::setEndDateTime( const QDateTime& dt ) { | ||
202 | changeOrModify(); | ||
203 | data->end = dt; | ||
204 | } | ||
205 | bool OEvent::isMultipleDay()const { | ||
206 | return data->end.date().day() - data->start.date().day(); | ||
207 | } | ||
208 | bool OEvent::isAllDay()const { | ||
209 | return data->isAllDay; | ||
210 | } | ||
211 | void OEvent::setAllDay( bool allDay ) { | ||
212 | changeOrModify(); | ||
213 | data->isAllDay = allDay; | ||
214 | if (allDay ) data->timezone = "UTC"; | ||
215 | } | ||
216 | void OEvent::setTimeZone( const QString& tz ) { | ||
217 | changeOrModify(); | ||
218 | data->timezone = tz; | ||
219 | } | ||
220 | QString OEvent::timeZone()const { | ||
221 | if (data->isAllDay ) return QString::fromLatin1("UTC"); | ||
222 | return data->timezone; | ||
223 | } | ||
224 | bool OEvent::match( const QRegExp& re )const { | ||
225 | if ( re.match( data->description ) != -1 ){ | ||
226 | setLastHitField( Qtopia::DatebookDescription ); | ||
227 | return true; | ||
228 | } | ||
229 | if ( re.match( data->note ) != -1 ){ | ||
230 | setLastHitField( Qtopia::Note ); | ||
231 | return true; | ||
232 | } | ||
233 | if ( re.match( data->location ) != -1 ){ | ||
234 | setLastHitField( Qtopia::Location ); | ||
235 | return true; | ||
236 | } | ||
237 | if ( re.match( data->start.toString() ) != -1 ){ | ||
238 | setLastHitField( Qtopia::StartDateTime ); | ||
239 | return true; | ||
240 | } | ||
241 | if ( re.match( data->end.toString() ) != -1 ){ | ||
242 | setLastHitField( Qtopia::EndDateTime ); | ||
243 | return true; | ||
244 | } | ||
245 | return false; | ||
246 | } | ||
247 | QString OEvent::toRichText()const { | ||
248 | QString text, value; | ||
249 | |||
250 | // description | ||
251 | text += "<b><h3><img src=\"datebook/DateBook\">"; | ||
252 | if ( !description().isEmpty() ) { | ||
253 | text += Qtopia::escapeString(description() ).replace(QRegExp( "[\n]"), "" ); | ||
254 | } | ||
255 | text += "</h3></b><br><hr><br>"; | ||
256 | |||
257 | // location | ||
258 | if ( !(value = location()).isEmpty() ) { | ||
259 | text += "<b>" + QObject::tr( "Location:" ) + "</b> "; | ||
260 | text += Qtopia::escapeString(value) + "<br>"; | ||
261 | } | ||
262 | |||
263 | // all day event | ||
264 | if ( isAllDay() ) { | ||
265 | text += "<b><i>" + QObject::tr( "This is an all day event" ) + "</i></b><br>"; | ||
266 | } | ||
267 | // multiple day event | ||
268 | else if ( isMultipleDay () ) { | ||
269 | text += "<b><i>" + QObject::tr( "This is a multiple day event" ) + "</i></b><br>"; | ||
270 | } | ||
271 | // start & end times | ||
272 | else { | ||
273 | // start time | ||
274 | if ( startDateTime().isValid() ) { | ||
275 | text += "<b>" + QObject::tr( "Start:") + "</b> "; | ||
276 | text += Qtopia::escapeString(startDateTime().toString() ). | ||
277 | replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; | ||
278 | } | ||
279 | |||
280 | // end time | ||
281 | if ( endDateTime().isValid() ) { | ||
282 | text += "<b>" + QObject::tr( "End:") + "</b> "; | ||
283 | text += Qtopia::escapeString(endDateTime().toString() ). | ||
284 | replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | // categories | ||
289 | if ( categoryNames("Calendar").count() ){ | ||
290 | text += "<b>" + QObject::tr( "Category:") + "</b> "; | ||
291 | text += categoryNames("Calendar").join(", "); | ||
292 | text += "<br>"; | ||
293 | } | ||
294 | |||
295 | //notes | ||
296 | if ( !note().isEmpty() ) { | ||
297 | text += "<b>" + QObject::tr( "Note:") + "</b><br>"; | ||
298 | text += note(); | ||
299 | // text += Qtopia::escapeString(note() ). | ||
300 | // replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; | ||
301 | } | ||
302 | return text; | ||
303 | } | ||
304 | QString OEvent::toShortText()const { | ||
305 | QString text; | ||
306 | text += QString::number( startDateTime().date().day() ); | ||
307 | text += "."; | ||
308 | text += QString::number( startDateTime().date().month() ); | ||
309 | text += "."; | ||
310 | text += QString::number( startDateTime().date().year() ); | ||
311 | text += " "; | ||
312 | text += QString::number( startDateTime().time().hour() ); | ||
313 | text += ":"; | ||
314 | text += QString::number( startDateTime().time().minute() ); | ||
315 | text += " - "; | ||
316 | text += description(); | ||
317 | return text; | ||
318 | } | ||
319 | QString OEvent::type()const { | ||
320 | return QString::fromLatin1("OEvent"); | ||
321 | } | ||
322 | QString OEvent::recordField( int /*id */ )const { | ||
323 | return QString::null; | ||
324 | } | ||
325 | int OEvent::rtti() { | ||
326 | return OPimResolver::DateBook; | ||
327 | } | ||
328 | bool OEvent::loadFromStream( QDataStream& ) { | ||
329 | return true; | ||
330 | } | ||
331 | bool OEvent::saveToStream( QDataStream& )const { | ||
332 | return true; | ||
333 | } | ||
334 | void OEvent::changeOrModify() { | ||
335 | if ( data->count != 1 ) { | ||
336 | data->deref(); | ||
337 | Data* d2 = new Data; | ||
338 | d2->description = data->description; | ||
339 | d2->location = data->location; | ||
340 | |||
341 | if (data->manager ) | ||
342 | d2->manager = new OPimNotifyManager( *data->manager ); | ||
343 | |||
344 | if ( data->recur ) | ||
345 | d2->recur = new ORecur( *data->recur ); | ||
346 | |||
347 | d2->note = data->note; | ||
348 | d2->created = data->created; | ||
349 | d2->start = data->start; | ||
350 | d2->end = data->end; | ||
351 | d2->isAllDay = data->isAllDay; | ||
352 | d2->timezone = data->timezone; | ||
353 | d2->parent = data->parent; | ||
354 | |||
355 | if ( data->child ) { | ||
356 | d2->child = new QArray<int>( *data->child ); | ||
357 | d2->child->detach(); | ||
358 | } | ||
359 | |||
360 | data = d2; | ||
361 | } | ||
362 | } | ||
363 | void OEvent::deref() { | ||
364 | if ( data->deref() ) { | ||
365 | delete data; | ||
366 | data = 0; | ||
367 | } | ||
368 | } | ||
369 | // Exporting Event data to map. Using the same | ||
370 | // encoding as ODateBookAccessBackend_xml does.. | ||
371 | // Thus, we could remove the stuff there and use this | ||
372 | // for it and for all other places.. | ||
373 | // Encoding should happen at one place, only ! (eilers) | ||
374 | QMap<int, QString> OEvent::toMap()const { | ||
375 | QMap<int, QString> retMap; | ||
376 | |||
377 | retMap.insert( OEvent::FUid, QString::number( uid() ) ); | ||
378 | retMap.insert( OEvent::FCategories, Qtopia::escapeString( Qtopia::Record::idsToString( categories() ) )); | ||
379 | retMap.insert( OEvent::FDescription, Qtopia::escapeString( description() ) ); | ||
380 | retMap.insert( OEvent::FLocation, Qtopia::escapeString( location() ) ); | ||
381 | retMap.insert( OEvent::FType, isAllDay() ? "AllDay" : "" ); | ||
382 | OPimAlarm alarm = notifiers().alarms()[0]; | ||
383 | retMap.insert( OEvent::FAlarm, QString::number( alarm.dateTime().secsTo( startDateTime() ) / 60 ) ); | ||
384 | retMap.insert( OEvent::FSound, (alarm.sound() == OPimAlarm::Loud) ? "loud" : "silent" ); | ||
385 | |||
386 | OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); | ||
387 | retMap.insert( OEvent::FStart, QString::number( zone.fromUTCDateTime( zone.toDateTime( startDateTime(), OTimeZone::utc() ) ) ) ); | ||
388 | retMap.insert( OEvent::FEnd, QString::number( zone.fromUTCDateTime( zone.toDateTime( endDateTime(), OTimeZone::utc() ) ) ) ); | ||
389 | retMap.insert( OEvent::FNote, Qtopia::escapeString( note() ) ); | ||
390 | retMap.insert( OEvent::FTimeZone, timeZone().isEmpty() ? QString( "None" ) : timeZone() ); | ||
391 | if( parent() ) | ||
392 | retMap.insert( OEvent::FRecParent, QString::number( parent() ) ); | ||
393 | if( children().count() ){ | ||
394 | QArray<int> childr = children(); | ||
395 | QString buf; | ||
396 | for ( uint i = 0; i < childr.count(); i++ ) { | ||
397 | if ( i != 0 ) buf += " "; | ||
398 | buf += QString::number( childr[i] ); | ||
399 | } | ||
400 | retMap.insert( OEvent::FRecChildren, buf ); | ||
401 | } | ||
402 | |||
403 | // Add recurrence stuff | ||
404 | if( hasRecurrence() ){ | ||
405 | ORecur recur = recurrence(); | ||
406 | QMap<int, QString> recFields = recur.toMap(); | ||
407 | retMap.insert( OEvent::FRType, recFields[ORecur::RType] ); | ||
408 | retMap.insert( OEvent::FRWeekdays, recFields[ORecur::RWeekdays] ); | ||
409 | retMap.insert( OEvent::FRPosition, recFields[ORecur::RPosition] ); | ||
410 | retMap.insert( OEvent::FRFreq, recFields[ORecur::RFreq] ); | ||
411 | retMap.insert( OEvent::FRHasEndDate, recFields[ORecur::RHasEndDate] ); | ||
412 | retMap.insert( OEvent::FREndDate, recFields[ORecur::EndDate] ); | ||
413 | retMap.insert( OEvent::FRCreated, recFields[ORecur::Created] ); | ||
414 | retMap.insert( OEvent::FRExceptions, recFields[ORecur::Exceptions] ); | ||
415 | } else { | ||
416 | ORecur recur = recurrence(); | ||
417 | QMap<int, QString> recFields = recur.toMap(); | ||
418 | retMap.insert( OEvent::FRType, recFields[ORecur::RType] ); | ||
419 | } | ||
420 | |||
421 | return retMap; | ||
422 | } | ||
423 | |||
424 | void OEvent::fromMap( const QMap<int, QString>& map ) | ||
425 | { | ||
426 | |||
427 | // We just want to set the UID if it is really stored. | ||
428 | if ( !map[OEvent::FUid].isEmpty() ) | ||
429 | setUid( map[OEvent::FUid].toInt() ); | ||
430 | |||
431 | setCategories( idsFromString( map[OEvent::FCategories] ) ); | ||
432 | setDescription( map[OEvent::FDescription] ); | ||
433 | setLocation( map[OEvent::FLocation] ); | ||
434 | |||
435 | if ( map[OEvent::FType] == "AllDay" ) | ||
436 | setAllDay( true ); | ||
437 | else | ||
438 | setAllDay( false ); | ||
439 | |||
440 | int alarmTime = -1; | ||
441 | if( !map[OEvent::FAlarm].isEmpty() ) | ||
442 | alarmTime = map[OEvent::FAlarm].toInt(); | ||
443 | |||
444 | int sound = ( ( map[OEvent::FSound] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent ); | ||
445 | if ( ( alarmTime != -1 ) ){ | ||
446 | QDateTime dt = startDateTime().addSecs( -1*alarmTime*60 ); | ||
447 | OPimAlarm al( sound , dt ); | ||
448 | notifiers().add( al ); | ||
449 | } | ||
450 | if ( !map[OEvent::FTimeZone].isEmpty() && ( map[OEvent::FTimeZone] != "None" ) ){ | ||
451 | setTimeZone( map[OEvent::FTimeZone] ); | ||
452 | } | ||
453 | |||
454 | time_t start = (time_t) map[OEvent::FStart].toLong(); | ||
455 | time_t end = (time_t) map[OEvent::FEnd].toLong(); | ||
456 | |||
457 | /* AllDay is always in UTC */ | ||
458 | if ( isAllDay() ) { | ||
459 | OTimeZone utc = OTimeZone::utc(); | ||
460 | setStartDateTime( utc.fromUTCDateTime( start ) ); | ||
461 | setEndDateTime ( utc.fromUTCDateTime( end ) ); | ||
462 | setTimeZone( "UTC"); // make sure it is really utc | ||
463 | }else { | ||
464 | /* to current date time */ | ||
465 | // qWarning(" Start is %d", start ); | ||
466 | OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); | ||
467 | QDateTime date = zone.toDateTime( start ); | ||
468 | qWarning(" Start is %s", date.toString().latin1() ); | ||
469 | setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); | ||
470 | |||
471 | date = zone.toDateTime( end ); | ||
472 | setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); | ||
473 | } | ||
474 | |||
475 | if ( !map[OEvent::FRecParent].isEmpty() ) | ||
476 | setParent( map[OEvent::FRecParent].toInt() ); | ||
477 | |||
478 | if ( !map[OEvent::FRecChildren].isEmpty() ){ | ||
479 | QStringList list = QStringList::split(' ', map[OEvent::FRecChildren] ); | ||
480 | for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { | ||
481 | addChild( (*it).toInt() ); | ||
482 | } | ||
483 | } | ||
484 | |||
485 | // Fill recurrence stuff and put it directly into the ORecur-Object using fromMap.. | ||
486 | if( !map[OEvent::FRType].isEmpty() ){ | ||
487 | QMap<int, QString> recFields; | ||
488 | recFields.insert( ORecur::RType, map[OEvent::FRType] ); | ||
489 | recFields.insert( ORecur::RWeekdays, map[OEvent::FRWeekdays] ); | ||
490 | recFields.insert( ORecur::RPosition, map[OEvent::FRPosition] ); | ||
491 | recFields.insert( ORecur::RFreq, map[OEvent::FRFreq] ); | ||
492 | recFields.insert( ORecur::RHasEndDate, map[OEvent::FRHasEndDate] ); | ||
493 | recFields.insert( ORecur::EndDate, map[OEvent::FREndDate] ); | ||
494 | recFields.insert( ORecur::Created, map[OEvent::FRCreated] ); | ||
495 | recFields.insert( ORecur::Exceptions, map[OEvent::FRExceptions] ); | ||
496 | ORecur recur( recFields ); | ||
497 | setRecurrence( recur ); | ||
498 | } | ||
499 | |||
500 | } | ||
501 | |||
502 | |||
503 | int OEvent::parent()const { | ||
504 | return data->parent; | ||
505 | } | ||
506 | void OEvent::setParent( int uid ) { | ||
507 | changeOrModify(); | ||
508 | data->parent = uid; | ||
509 | } | ||
510 | QArray<int> OEvent::children() const{ | ||
511 | if (!data->child) return QArray<int>(); | ||
512 | else | ||
513 | return data->child->copy(); | ||
514 | } | ||
515 | void OEvent::setChildren( const QArray<int>& arr ) { | ||
516 | changeOrModify(); | ||
517 | if (data->child) delete data->child; | ||
518 | |||
519 | data->child = new QArray<int>( arr ); | ||
520 | data->child->detach(); | ||
521 | } | ||
522 | void OEvent::addChild( int uid ) { | ||
523 | changeOrModify(); | ||
524 | if (!data->child ) { | ||
525 | data->child = new QArray<int>(1); | ||
526 | (*data->child)[0] = uid; | ||
527 | }else{ | ||
528 | int count = data->child->count(); | ||
529 | data->child->resize( count + 1 ); | ||
530 | (*data->child)[count] = uid; | ||
531 | } | ||
532 | } | ||
533 | void OEvent::removeChild( int uid ) { | ||
534 | if (!data->child || !data->child->contains( uid ) ) return; | ||
535 | changeOrModify(); | ||
536 | QArray<int> newAr( data->child->count() - 1 ); | ||
537 | int j = 0; | ||
538 | uint count = data->child->count(); | ||
539 | for ( uint i = 0; i < count; i++ ) { | ||
540 | if ( (*data->child)[i] != uid ) { | ||
541 | newAr[j] = (*data->child)[i]; | ||
542 | j++; | ||
543 | } | ||
544 | } | ||
545 | (*data->child) = newAr; | ||
546 | } | ||
547 | struct OEffectiveEvent::Data : public QShared { | ||
548 | Data() : QShared() { | ||
549 | } | ||
550 | OEvent event; | ||
551 | QDate date; | ||
552 | QTime start, end; | ||
553 | QDate startDate, endDate; | ||
554 | bool dates : 1; | ||
555 | }; | ||
556 | |||
557 | OEffectiveEvent::OEffectiveEvent() { | ||
558 | data = new Data; | ||
559 | data->date = QDate::currentDate(); | ||
560 | data->start = data->end = QTime::currentTime(); | ||
561 | data->dates = false; | ||
562 | } | ||
563 | OEffectiveEvent::OEffectiveEvent( const OEvent& ev, const QDate& startDate, | ||
564 | Position pos ) { | ||
565 | data = new Data; | ||
566 | data->event = ev; | ||
567 | data->date = startDate; | ||
568 | if ( pos & Start ) | ||
569 | data->start = ev.startDateTime().time(); | ||
570 | else | ||
571 | data->start = QTime( 0, 0, 0 ); | ||
572 | |||
573 | if ( pos & End ) | ||
574 | data->end = ev.endDateTime().time(); | ||
575 | else | ||
576 | data->end = QTime( 23, 59, 59 ); | ||
577 | |||
578 | data->dates = false; | ||
579 | } | ||
580 | OEffectiveEvent::OEffectiveEvent( const OEffectiveEvent& ev) { | ||
581 | data = ev.data; | ||
582 | data->ref(); | ||
583 | } | ||
584 | OEffectiveEvent::~OEffectiveEvent() { | ||
585 | if ( data->deref() ) { | ||
586 | delete data; | ||
587 | data = 0; | ||
588 | } | ||
589 | } | ||
590 | OEffectiveEvent& OEffectiveEvent::operator=( const OEffectiveEvent& ev ) { | ||
591 | if ( *this == ev ) return *this; | ||
592 | |||
593 | ev.data->ref(); | ||
594 | deref(); | ||
595 | data = ev.data; | ||
596 | |||
597 | return *this; | ||
598 | } | ||
599 | |||
600 | void OEffectiveEvent::setStartTime( const QTime& ti) { | ||
601 | changeOrModify(); | ||
602 | data->start = ti; | ||
603 | } | ||
604 | void OEffectiveEvent::setEndTime( const QTime& en) { | ||
605 | changeOrModify(); | ||
606 | data->end = en; | ||
607 | } | ||
608 | void OEffectiveEvent::setEvent( const OEvent& ev) { | ||
609 | changeOrModify(); | ||
610 | data->event = ev; | ||
611 | } | ||
612 | void OEffectiveEvent::setDate( const QDate& da) { | ||
613 | changeOrModify(); | ||
614 | data->date = da; | ||
615 | } | ||
616 | void OEffectiveEvent::setEffectiveDates( const QDate& from, | ||
617 | const QDate& to ) { | ||
618 | if (!from.isValid() ) { | ||
619 | data->dates = false; | ||
620 | return; | ||
621 | } | ||
622 | |||
623 | data->startDate = from; | ||
624 | data->endDate = to; | ||
625 | } | ||
626 | QString OEffectiveEvent::description()const { | ||
627 | return data->event.description(); | ||
628 | } | ||
629 | QString OEffectiveEvent::location()const { | ||
630 | return data->event.location(); | ||
631 | } | ||
632 | QString OEffectiveEvent::note()const { | ||
633 | return data->event.note(); | ||
634 | } | ||
635 | OEvent OEffectiveEvent::event()const { | ||
636 | return data->event; | ||
637 | } | ||
638 | QTime OEffectiveEvent::startTime()const { | ||
639 | return data->start; | ||
640 | } | ||
641 | QTime OEffectiveEvent::endTime()const { | ||
642 | return data->end; | ||
643 | } | ||
644 | QDate OEffectiveEvent::date()const { | ||
645 | return data->date; | ||
646 | } | ||
647 | int OEffectiveEvent::length()const { | ||
648 | return (data->end.hour() * 60 - data->start.hour() * 60) | ||
649 | + QABS(data->start.minute() - data->end.minute() ); | ||
650 | } | ||
651 | int OEffectiveEvent::size()const { | ||
652 | return ( data->end.hour() - data->start.hour() ) * 3600 | ||
653 | + (data->end.minute() - data->start.minute() * 60 | ||
654 | + data->end.second() - data->start.second() ); | ||
655 | } | ||
656 | QDate OEffectiveEvent::startDate()const { | ||
657 | if ( data->dates ) | ||
658 | return data->startDate; | ||
659 | else if ( data->event.hasRecurrence() ) // single day, since multi-day should have a d pointer | ||
660 | return data->date; | ||
661 | else | ||
662 | return data->event.startDateTime().date(); | ||
663 | } | ||
664 | QDate OEffectiveEvent::endDate()const { | ||
665 | if ( data->dates ) | ||
666 | return data->endDate; | ||
667 | else if ( data->event.hasRecurrence() ) | ||
668 | return data->date; | ||
669 | else | ||
670 | return data->event.endDateTime().date(); | ||
671 | } | ||
672 | void OEffectiveEvent::deref() { | ||
673 | if ( data->deref() ) { | ||
674 | delete data; | ||
675 | data = 0; | ||
676 | } | ||
677 | } | ||
678 | void OEffectiveEvent::changeOrModify() { | ||
679 | if ( data->count != 1 ) { | ||
680 | data->deref(); | ||
681 | Data* d2 = new Data; | ||
682 | d2->event = data->event; | ||
683 | d2->date = data->date; | ||
684 | d2->start = data->start; | ||
685 | d2->end = data->end; | ||
686 | d2->startDate = data->startDate; | ||
687 | d2->endDate = data->endDate; | ||
688 | d2->dates = data->dates; | ||
689 | data = d2; | ||
690 | } | ||
691 | } | ||
692 | bool OEffectiveEvent::operator<( const OEffectiveEvent &e ) const{ | ||
693 | if ( data->date < e.date() ) | ||
694 | return TRUE; | ||
695 | if ( data->date == e.date() ) | ||
696 | return ( startTime() < e.startTime() ); | ||
697 | else | ||
698 | return FALSE; | ||
699 | } | ||
700 | bool OEffectiveEvent::operator<=( const OEffectiveEvent &e ) const{ | ||
701 | return (data->date <= e.date() ); | ||
702 | } | ||
703 | bool OEffectiveEvent::operator==( const OEffectiveEvent &e ) const { | ||
704 | return ( date() == e.date() | ||
705 | && startTime() == e.startTime() | ||
706 | && endTime()== e.endTime() | ||
707 | && event() == e.event() ); | ||
708 | } | ||
709 | bool OEffectiveEvent::operator!=( const OEffectiveEvent &e ) const { | ||
710 | return !(*this == e ); | ||
711 | } | ||
712 | bool OEffectiveEvent::operator>( const OEffectiveEvent &e ) const { | ||
713 | return !(*this <= e ); | ||
714 | } | ||
715 | bool OEffectiveEvent::operator>= ( const OEffectiveEvent &e ) const { | ||
716 | return !(*this < e); | ||
717 | } | ||
diff --git a/noncore/unsupported/libopie/pim/oevent.h b/noncore/unsupported/libopie/pim/oevent.h new file mode 100644 index 0000000..9eb948f --- a/dev/null +++ b/noncore/unsupported/libopie/pim/oevent.h | |||
@@ -0,0 +1,236 @@ | |||
1 | // CONTAINS GPLed code of TT | ||
2 | |||
3 | #ifndef OPIE_PIM_EVENT_H | ||
4 | #define OPIE_PIM_EVENT_H | ||
5 | |||
6 | #include <qstring.h> | ||
7 | #include <qdatetime.h> | ||
8 | #include <qvaluelist.h> | ||
9 | |||
10 | #include <qpe/recordfields.h> | ||
11 | #include <qpe/palmtopuidgen.h> | ||
12 | |||
13 | #include "otimezone.h" | ||
14 | #include "opimrecord.h" | ||
15 | |||
16 | struct OCalendarHelper { | ||
17 | /** calculate the week number of the date */ | ||
18 | static int week( const QDate& ); | ||
19 | /** calculate the occurence of week days since the start of the month */ | ||
20 | static int ocurrence( const QDate& ); | ||
21 | |||
22 | // returns the dayOfWeek for the *first* day it finds (ignores | ||
23 | // any further days!). Returns 1 (Monday) if there isn't any day found | ||
24 | static int dayOfWeek( char day ); | ||
25 | |||
26 | /** returns the diff of month */ | ||
27 | static int monthDiff( const QDate& first, const QDate& second ); | ||
28 | |||
29 | }; | ||
30 | |||
31 | class OPimNotifyManager; | ||
32 | class ORecur; | ||
33 | |||
34 | /** | ||
35 | * This is the container for all Events. It encapsules all | ||
36 | * available information for a single Event | ||
37 | * @short container for events. | ||
38 | */ | ||
39 | class OEvent : public OPimRecord { | ||
40 | public: | ||
41 | typedef QValueList<OEvent> ValueList; | ||
42 | /** | ||
43 | * RecordFields contain possible attributes | ||
44 | * used in the Results of toMap().. | ||
45 | */ | ||
46 | enum RecordFields { | ||
47 | FUid = Qtopia::UID_ID, | ||
48 | FCategories = Qtopia::CATEGORY_ID, | ||
49 | FDescription = 0, | ||
50 | FLocation, | ||
51 | FType, | ||
52 | FAlarm, | ||
53 | FSound, | ||
54 | FRType, | ||
55 | FRWeekdays, | ||
56 | FRPosition, | ||
57 | FRFreq, | ||
58 | FRHasEndDate, | ||
59 | FREndDate, | ||
60 | FRCreated, | ||
61 | FRExceptions, | ||
62 | FStart, | ||
63 | FEnd, | ||
64 | FNote, | ||
65 | FTimeZone, | ||
66 | FRecParent, | ||
67 | FRecChildren, | ||
68 | }; | ||
69 | |||
70 | /** | ||
71 | * Start with an Empty OEvent. UID == 0 means that it is empty | ||
72 | */ | ||
73 | OEvent(int uid = 0); | ||
74 | |||
75 | /** | ||
76 | * copy c'tor | ||
77 | */ | ||
78 | OEvent( const OEvent& ); | ||
79 | |||
80 | /** | ||
81 | * Create OEvent, initialized by map | ||
82 | * @see enum RecordFields | ||
83 | */ | ||
84 | OEvent( const QMap<int, QString> map ); | ||
85 | ~OEvent(); | ||
86 | OEvent &operator=( const OEvent& ); | ||
87 | |||
88 | QString description()const; | ||
89 | void setDescription( const QString& description ); | ||
90 | |||
91 | QString location()const; | ||
92 | void setLocation( const QString& loc ); | ||
93 | |||
94 | bool hasNotifiers()const; | ||
95 | OPimNotifyManager ¬ifiers()const; | ||
96 | |||
97 | ORecur recurrence()const; | ||
98 | void setRecurrence( const ORecur& ); | ||
99 | bool hasRecurrence()const; | ||
100 | |||
101 | QString note()const; | ||
102 | void setNote( const QString& note ); | ||
103 | |||
104 | |||
105 | QDateTime createdDateTime()const; | ||
106 | void setCreatedDateTime( const QDateTime& dt); | ||
107 | |||
108 | /** set the date to dt. dt is the QDateTime in localtime */ | ||
109 | void setStartDateTime( const QDateTime& ); | ||
110 | /** returns the datetime in the local timeZone */ | ||
111 | QDateTime startDateTime()const; | ||
112 | |||
113 | /** returns the start datetime in the current zone */ | ||
114 | QDateTime startDateTimeInZone()const; | ||
115 | |||
116 | /** in current timezone */ | ||
117 | void setEndDateTime( const QDateTime& ); | ||
118 | /** in current timezone */ | ||
119 | QDateTime endDateTime()const; | ||
120 | QDateTime endDateTimeInZone()const; | ||
121 | |||
122 | bool isMultipleDay()const; | ||
123 | bool isAllDay()const; | ||
124 | void setAllDay( bool isAllDay ); | ||
125 | |||
126 | /* pin this event to a timezone! FIXME */ | ||
127 | void setTimeZone( const QString& timeZone ); | ||
128 | QString timeZone()const; | ||
129 | |||
130 | |||
131 | virtual bool match( const QRegExp& )const; | ||
132 | |||
133 | /** For exception to recurrence here is a list of children... */ | ||
134 | QArray<int> children()const; | ||
135 | void setChildren( const QArray<int>& ); | ||
136 | void addChild( int uid ); | ||
137 | void removeChild( int uid ); | ||
138 | |||
139 | /** return the parent OEvent */ | ||
140 | int parent()const; | ||
141 | void setParent( int uid ); | ||
142 | |||
143 | |||
144 | /* needed reimp */ | ||
145 | QString toRichText()const; | ||
146 | QString toShortText()const; | ||
147 | QString type()const; | ||
148 | |||
149 | QMap<int, QString> toMap()const; | ||
150 | void fromMap( const QMap<int, QString>& map ); | ||
151 | QString recordField(int )const; | ||
152 | |||
153 | static int rtti(); | ||
154 | |||
155 | bool loadFromStream( QDataStream& ); | ||
156 | bool saveToStream( QDataStream& )const; | ||
157 | |||
158 | /* bool operator==( const OEvent& ); | ||
159 | bool operator!=( const OEvent& ); | ||
160 | bool operator<( const OEvent& ); | ||
161 | bool operator<=( const OEvent& ); | ||
162 | bool operator>( const OEvent& ); | ||
163 | bool operator>=(const OEvent& ); | ||
164 | */ | ||
165 | private: | ||
166 | inline void changeOrModify(); | ||
167 | void deref(); | ||
168 | struct Data; | ||
169 | Data* data; | ||
170 | class Private; | ||
171 | Private* priv; | ||
172 | |||
173 | }; | ||
174 | |||
175 | /** | ||
176 | * AN Event can span through multiple days. We split up a multiday eve | ||
177 | */ | ||
178 | class OEffectiveEvent { | ||
179 | public: | ||
180 | typedef QValueList<OEffectiveEvent> ValueList; | ||
181 | enum Position { MidWay, Start, End, StartEnd }; | ||
182 | // If we calculate the effective event of a multi-day event | ||
183 | // we have to figure out whether we are at the first day, | ||
184 | // at the end, or anywhere else ("middle"). This is important | ||
185 | // for the start/end times (00:00/23:59) | ||
186 | // MidWay: 00:00 -> 23:59, as we are "in the middle" of a multi- | ||
187 | // day event | ||
188 | // Start: start time -> 23:59 | ||
189 | // End: 00:00 -> end time | ||
190 | // Start | End == StartEnd: for single-day events (default) | ||
191 | // here we draw start time -> end time | ||
192 | OEffectiveEvent(); | ||
193 | OEffectiveEvent( const OEvent& event, const QDate& startDate, Position pos = StartEnd ); | ||
194 | OEffectiveEvent( const OEffectiveEvent& ); | ||
195 | OEffectiveEvent &operator=(const OEffectiveEvent& ); | ||
196 | ~OEffectiveEvent(); | ||
197 | |||
198 | void setStartTime( const QTime& ); | ||
199 | void setEndTime( const QTime& ); | ||
200 | void setEvent( const OEvent& ); | ||
201 | void setDate( const QDate& ); | ||
202 | |||
203 | void setEffectiveDates( const QDate& from, const QDate& to ); | ||
204 | |||
205 | QString description()const; | ||
206 | QString location()const; | ||
207 | QString note()const; | ||
208 | OEvent event()const; | ||
209 | QTime startTime()const; | ||
210 | QTime endTime()const; | ||
211 | QDate date()const; | ||
212 | |||
213 | /* return the length in hours */ | ||
214 | int length()const; | ||
215 | int size()const; | ||
216 | |||
217 | QDate startDate()const; | ||
218 | QDate endDate()const; | ||
219 | |||
220 | bool operator<( const OEffectiveEvent &e ) const; | ||
221 | bool operator<=( const OEffectiveEvent &e ) const; | ||
222 | bool operator==( const OEffectiveEvent &e ) const; | ||
223 | bool operator!=( const OEffectiveEvent &e ) const; | ||
224 | bool operator>( const OEffectiveEvent &e ) const; | ||
225 | bool operator>= ( const OEffectiveEvent &e ) const; | ||
226 | |||
227 | private: | ||
228 | void deref(); | ||
229 | inline void changeOrModify(); | ||
230 | class Private; | ||
231 | Private* priv; | ||
232 | struct Data; | ||
233 | Data* data; | ||
234 | |||
235 | }; | ||
236 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimaccessbackend.h b/noncore/unsupported/libopie/pim/opimaccessbackend.h new file mode 100644 index 0000000..fd264fc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimaccessbackend.h | |||
@@ -0,0 +1,160 @@ | |||
1 | #ifndef OPIE_PIM_ACCESS_BACKEND | ||
2 | #define OPIE_PIM_ACCESS_BACKEND | ||
3 | |||
4 | #include <qarray.h> | ||
5 | #include <qdatetime.h> | ||
6 | |||
7 | #include <opie/otemplatebase.h> | ||
8 | #include <opie/opimrecord.h> | ||
9 | |||
10 | |||
11 | class OPimAccessBackendPrivate; | ||
12 | /** | ||
13 | * OPimAccessBackend is the base class | ||
14 | * for all private backends | ||
15 | * it operates on OPimRecord as the base class | ||
16 | * and it's responsible for fast manipulating | ||
17 | * the resource the implementation takes care | ||
18 | * of | ||
19 | */ | ||
20 | template <class T = OPimRecord> | ||
21 | class OPimAccessBackend { | ||
22 | public: | ||
23 | typedef OTemplateBase<T> Frontend; | ||
24 | |||
25 | /** The access hint from the frontend */ | ||
26 | OPimAccessBackend(int access = 0); | ||
27 | virtual ~OPimAccessBackend(); | ||
28 | |||
29 | /** | ||
30 | * load the resource | ||
31 | */ | ||
32 | virtual bool load() = 0; | ||
33 | |||
34 | /** | ||
35 | * reload the resource | ||
36 | */ | ||
37 | virtual bool reload() = 0; | ||
38 | |||
39 | /** | ||
40 | * save the resource and | ||
41 | * all it's changes | ||
42 | */ | ||
43 | virtual bool save() = 0; | ||
44 | |||
45 | /** | ||
46 | * return an array of | ||
47 | * all available uids | ||
48 | */ | ||
49 | virtual QArray<int> allRecords()const = 0; | ||
50 | |||
51 | /** | ||
52 | * return a List of records | ||
53 | * that match the regex | ||
54 | */ | ||
55 | virtual QArray<int> matchRegexp(const QRegExp &r) const = 0; | ||
56 | |||
57 | /** | ||
58 | * queryByExample for T with the given Settings | ||
59 | * | ||
60 | */ | ||
61 | virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0; | ||
62 | |||
63 | /** | ||
64 | * find the OPimRecord with uid @param uid | ||
65 | * returns T and T.isEmpty() if nothing was found | ||
66 | */ | ||
67 | virtual T find(int uid )const = 0; | ||
68 | |||
69 | virtual T find(int uid, const QArray<int>& items, | ||
70 | uint current, typename Frontend::CacheDirection )const ; | ||
71 | /** | ||
72 | * clear the back end | ||
73 | */ | ||
74 | virtual void clear() = 0; | ||
75 | |||
76 | /** | ||
77 | * add T | ||
78 | */ | ||
79 | virtual bool add( const T& t ) = 0; | ||
80 | |||
81 | /** | ||
82 | * remove | ||
83 | */ | ||
84 | virtual bool remove( int uid ) = 0; | ||
85 | |||
86 | /** | ||
87 | * replace a record with T.uid() | ||
88 | */ | ||
89 | virtual bool replace( const T& t ) = 0; | ||
90 | |||
91 | /* | ||
92 | * setTheFrontEnd!!! | ||
93 | */ | ||
94 | void setFrontend( Frontend* front ); | ||
95 | |||
96 | /** | ||
97 | * set the read ahead count | ||
98 | */ | ||
99 | void setReadAhead( uint count ); | ||
100 | protected: | ||
101 | int access()const; | ||
102 | void cache( const T& t )const; | ||
103 | |||
104 | /** | ||
105 | * use a prime number here! | ||
106 | */ | ||
107 | void setSaneCacheSize( int ); | ||
108 | |||
109 | uint readAhead()const; | ||
110 | |||
111 | private: | ||
112 | OPimAccessBackendPrivate *d; | ||
113 | Frontend* m_front; | ||
114 | uint m_read; | ||
115 | int m_acc; | ||
116 | |||
117 | }; | ||
118 | |||
119 | template <class T> | ||
120 | OPimAccessBackend<T>::OPimAccessBackend(int acc) | ||
121 | : m_acc( acc ) | ||
122 | { | ||
123 | m_front = 0l; | ||
124 | } | ||
125 | template <class T> | ||
126 | OPimAccessBackend<T>::~OPimAccessBackend() { | ||
127 | |||
128 | } | ||
129 | template <class T> | ||
130 | void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { | ||
131 | m_front = fr; | ||
132 | } | ||
133 | template <class T> | ||
134 | void OPimAccessBackend<T>::cache( const T& t )const { | ||
135 | if (m_front ) | ||
136 | m_front->cache( t ); | ||
137 | } | ||
138 | template <class T> | ||
139 | void OPimAccessBackend<T>::setSaneCacheSize( int size) { | ||
140 | if (m_front ) | ||
141 | m_front->setSaneCacheSize( size ); | ||
142 | } | ||
143 | template <class T> | ||
144 | T OPimAccessBackend<T>::find( int uid, const QArray<int>&, | ||
145 | uint, typename Frontend::CacheDirection )const { | ||
146 | return find( uid ); | ||
147 | } | ||
148 | template <class T> | ||
149 | void OPimAccessBackend<T>::setReadAhead( uint count ) { | ||
150 | m_read = count; | ||
151 | } | ||
152 | template <class T> | ||
153 | uint OPimAccessBackend<T>::readAhead()const { | ||
154 | return m_read; | ||
155 | } | ||
156 | template <class T> | ||
157 | int OPimAccessBackend<T>::access()const { | ||
158 | return m_acc; | ||
159 | } | ||
160 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimaccesstemplate.h b/noncore/unsupported/libopie/pim/opimaccesstemplate.h new file mode 100644 index 0000000..ecbeb68 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimaccesstemplate.h | |||
@@ -0,0 +1,302 @@ | |||
1 | #ifndef OPIE_PIM_ACCESS_TEMPLATE_H | ||
2 | #define OPIE_PIM_ACCESS_TEMPLATE_H | ||
3 | |||
4 | #include <qarray.h> | ||
5 | |||
6 | #include <opie/opimrecord.h> | ||
7 | #include <opie/opimaccessbackend.h> | ||
8 | #include <opie/orecordlist.h> | ||
9 | |||
10 | #include "opimcache.h" | ||
11 | #include "otemplatebase.h" | ||
12 | |||
13 | class OPimAccessTemplatePrivate; | ||
14 | /** | ||
15 | * Thats the frontend to our OPIE PIM | ||
16 | * Library. Either you want to use it's | ||
17 | * interface or you want to implement | ||
18 | * your own Access lib | ||
19 | * Just create a OPimRecord and inherit from | ||
20 | * the plugins | ||
21 | */ | ||
22 | |||
23 | template <class T = OPimRecord > | ||
24 | class OPimAccessTemplate : public OTemplateBase<T> { | ||
25 | public: | ||
26 | enum Access { | ||
27 | Random = 0, | ||
28 | SortedAccess | ||
29 | }; | ||
30 | typedef ORecordList<T> List; | ||
31 | typedef OPimAccessBackend<T> BackEnd; | ||
32 | typedef OPimCache<T> Cache; | ||
33 | |||
34 | /** | ||
35 | * c'tor BackEnd | ||
36 | * enum Access a small hint on how to handle the backend | ||
37 | */ | ||
38 | OPimAccessTemplate( BackEnd* end); | ||
39 | |||
40 | virtual ~OPimAccessTemplate(); | ||
41 | |||
42 | /** | ||
43 | * load from the backend | ||
44 | */ | ||
45 | bool load(); | ||
46 | |||
47 | /** Reload database. | ||
48 | * You should execute this function if the external database | ||
49 | * was changed. | ||
50 | * This function will load the external database and afterwards | ||
51 | * rejoin the local changes. Therefore the local database will be set consistent. | ||
52 | */ | ||
53 | virtual bool reload(); | ||
54 | |||
55 | /** Save contacts database. | ||
56 | * Save is more a "commit". After calling this function, all changes are public available. | ||
57 | * @return true if successful | ||
58 | */ | ||
59 | bool save(); | ||
60 | |||
61 | /** | ||
62 | * if the resource was changed externally | ||
63 | * You should use the signal handling instead of polling possible changes ! | ||
64 | * zecke: Do you implement a signal for otodoaccess ? | ||
65 | */ | ||
66 | bool wasChangedExternally()const; | ||
67 | |||
68 | /** | ||
69 | * return a List of records | ||
70 | * you can iterate over them | ||
71 | */ | ||
72 | virtual List allRecords()const; | ||
73 | |||
74 | /** | ||
75 | * return a List of records | ||
76 | * that match the regex | ||
77 | */ | ||
78 | virtual List matchRegexp( const QRegExp &r ) const; | ||
79 | |||
80 | /** | ||
81 | * queryByExample. | ||
82 | * @see otodoaccess, ocontactaccess | ||
83 | */ | ||
84 | virtual List queryByExample( const T& t, int querySettings, const QDateTime& d = QDateTime() ); | ||
85 | |||
86 | /** | ||
87 | * find the OPimRecord uid | ||
88 | */ | ||
89 | virtual T find( int uid )const; | ||
90 | |||
91 | /** | ||
92 | * read ahead cache find method ;) | ||
93 | */ | ||
94 | virtual T find( int uid, const QArray<int>&, | ||
95 | uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const; | ||
96 | |||
97 | /* invalidate cache here */ | ||
98 | /** | ||
99 | * clears the backend and invalidates the backend | ||
100 | */ | ||
101 | void clear() ; | ||
102 | |||
103 | /** | ||
104 | * add T to the backend | ||
105 | * @param t The item to add. | ||
106 | * @return <i>true</i> if added successfully. | ||
107 | */ | ||
108 | virtual bool add( const T& t ) ; | ||
109 | bool add( const OPimRecord& ); | ||
110 | |||
111 | /* only the uid matters */ | ||
112 | /** | ||
113 | * remove T from the backend | ||
114 | * @param t The item to remove | ||
115 | * @return <i>true</i> if successful. | ||
116 | */ | ||
117 | virtual bool remove( const T& t ); | ||
118 | |||
119 | /** | ||
120 | * remove the OPimRecord with uid | ||
121 | * @param uid The ID of the item to remove | ||
122 | * @return <i>true</i> if successful. | ||
123 | */ | ||
124 | bool remove( int uid ); | ||
125 | bool remove( const OPimRecord& ); | ||
126 | |||
127 | /** | ||
128 | * replace T from backend | ||
129 | * @param t The item to replace | ||
130 | * @return <i>true</i> if successful. | ||
131 | */ | ||
132 | virtual bool replace( const T& t) ; | ||
133 | |||
134 | void setReadAhead( uint count ); | ||
135 | /** | ||
136 | * @internal | ||
137 | */ | ||
138 | void cache( const T& )const; | ||
139 | void setSaneCacheSize( int ); | ||
140 | |||
141 | QArray<int> records()const; | ||
142 | protected: | ||
143 | /** | ||
144 | * invalidate the cache | ||
145 | */ | ||
146 | void invalidateCache(); | ||
147 | |||
148 | void setBackEnd( BackEnd* end ); | ||
149 | /** | ||
150 | * returns the backend | ||
151 | */ | ||
152 | BackEnd* backEnd(); | ||
153 | BackEnd* m_backEnd; | ||
154 | Cache m_cache; | ||
155 | |||
156 | private: | ||
157 | OPimAccessTemplatePrivate *d; | ||
158 | |||
159 | }; | ||
160 | |||
161 | template <class T> | ||
162 | OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) | ||
163 | : OTemplateBase<T>(), m_backEnd( end ) | ||
164 | { | ||
165 | if (end ) | ||
166 | end->setFrontend( this ); | ||
167 | } | ||
168 | template <class T> | ||
169 | OPimAccessTemplate<T>::~OPimAccessTemplate() { | ||
170 | qWarning("~OPimAccessTemplate<T>"); | ||
171 | delete m_backEnd; | ||
172 | } | ||
173 | template <class T> | ||
174 | bool OPimAccessTemplate<T>::load() { | ||
175 | invalidateCache(); | ||
176 | return m_backEnd->load(); | ||
177 | } | ||
178 | template <class T> | ||
179 | bool OPimAccessTemplate<T>::reload() { | ||
180 | invalidateCache(); // zecke: I think this should be added (se) | ||
181 | return m_backEnd->reload(); | ||
182 | } | ||
183 | template <class T> | ||
184 | bool OPimAccessTemplate<T>::save() { | ||
185 | return m_backEnd->save(); | ||
186 | } | ||
187 | template <class T> | ||
188 | typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { | ||
189 | QArray<int> ints = m_backEnd->allRecords(); | ||
190 | List lis(ints, this ); | ||
191 | return lis; | ||
192 | } | ||
193 | template <class T> | ||
194 | typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::matchRegexp( const QRegExp &r )const { | ||
195 | QArray<int> ints = m_backEnd->matchRegexp( r ); | ||
196 | List lis(ints, this ); | ||
197 | return lis; | ||
198 | } | ||
199 | template <class T> | ||
200 | QArray<int> OPimAccessTemplate<T>::records()const { | ||
201 | return m_backEnd->allRecords(); | ||
202 | } | ||
203 | template <class T> | ||
204 | typename OPimAccessTemplate<T>::List | ||
205 | OPimAccessTemplate<T>::queryByExample( const T& t, int settings, const QDateTime& d ) { | ||
206 | QArray<int> ints = m_backEnd->queryByExample( t, settings, d ); | ||
207 | |||
208 | List lis(ints, this ); | ||
209 | return lis; | ||
210 | } | ||
211 | template <class T> | ||
212 | T OPimAccessTemplate<T>::find( int uid ) const{ | ||
213 | T t = m_backEnd->find( uid ); | ||
214 | cache( t ); | ||
215 | return t; | ||
216 | } | ||
217 | template <class T> | ||
218 | T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, | ||
219 | uint current, typename OTemplateBase<T>::CacheDirection dir )const { | ||
220 | /* | ||
221 | * better do T.isEmpty() | ||
222 | * after a find this way we would | ||
223 | * avoid two finds in QCache... | ||
224 | */ | ||
225 | // qWarning("find it now %d", uid ); | ||
226 | if (m_cache.contains( uid ) ) { | ||
227 | return m_cache.find( uid ); | ||
228 | } | ||
229 | |||
230 | T t = m_backEnd->find( uid, ar, current, dir ); | ||
231 | cache( t ); | ||
232 | return t; | ||
233 | } | ||
234 | template <class T> | ||
235 | void OPimAccessTemplate<T>::clear() { | ||
236 | invalidateCache(); | ||
237 | m_backEnd->clear(); | ||
238 | } | ||
239 | template <class T> | ||
240 | bool OPimAccessTemplate<T>::add( const T& t ) { | ||
241 | cache( t ); | ||
242 | return m_backEnd->add( t ); | ||
243 | } | ||
244 | template <class T> | ||
245 | bool OPimAccessTemplate<T>::add( const OPimRecord& rec) { | ||
246 | /* same type */ | ||
247 | if ( rec.rtti() == T::rtti() ) { | ||
248 | const T &t = static_cast<const T&>(rec); | ||
249 | return add(t); | ||
250 | } | ||
251 | return false; | ||
252 | } | ||
253 | template <class T> | ||
254 | bool OPimAccessTemplate<T>::remove( const T& t ) { | ||
255 | return remove( t.uid() ); | ||
256 | } | ||
257 | template <class T> | ||
258 | bool OPimAccessTemplate<T>::remove( int uid ) { | ||
259 | m_cache.remove( uid ); | ||
260 | return m_backEnd->remove( uid ); | ||
261 | } | ||
262 | template <class T> | ||
263 | bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) { | ||
264 | return remove( rec.uid() ); | ||
265 | } | ||
266 | template <class T> | ||
267 | bool OPimAccessTemplate<T>::replace( const T& t ) { | ||
268 | m_cache.replace( t ); | ||
269 | return m_backEnd->replace( t ); | ||
270 | } | ||
271 | template <class T> | ||
272 | void OPimAccessTemplate<T>::invalidateCache() { | ||
273 | m_cache.invalidate(); | ||
274 | } | ||
275 | template <class T> | ||
276 | typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { | ||
277 | return m_backEnd; | ||
278 | } | ||
279 | template <class T> | ||
280 | bool OPimAccessTemplate<T>::wasChangedExternally()const { | ||
281 | return false; | ||
282 | } | ||
283 | template <class T> | ||
284 | void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { | ||
285 | m_backEnd = end; | ||
286 | if (m_backEnd ) | ||
287 | m_backEnd->setFrontend( this ); | ||
288 | } | ||
289 | template <class T> | ||
290 | void OPimAccessTemplate<T>::cache( const T& t ) const{ | ||
291 | /* hacky we need to work around the const*/ | ||
292 | ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); | ||
293 | } | ||
294 | template <class T> | ||
295 | void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { | ||
296 | m_cache.setSize( size ); | ||
297 | } | ||
298 | template <class T> | ||
299 | void OPimAccessTemplate<T>::setReadAhead( uint count ) { | ||
300 | m_backEnd->setReadAhead( count ); | ||
301 | } | ||
302 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimcache.h b/noncore/unsupported/libopie/pim/opimcache.h new file mode 100644 index 0000000..7f7cff5 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimcache.h | |||
@@ -0,0 +1,131 @@ | |||
1 | #ifndef OPIE_PIM_CACHE_H | ||
2 | #define OPIE_PIM_CACHE_H | ||
3 | |||
4 | #include <qintcache.h> | ||
5 | |||
6 | #include "opimrecord.h" | ||
7 | |||
8 | class OPimCacheItemPrivate; | ||
9 | |||
10 | template <class T = OPimRecord> | ||
11 | class OPimCacheItem { | ||
12 | public: | ||
13 | OPimCacheItem( const T& t = T() ); | ||
14 | OPimCacheItem( const OPimCacheItem& ); | ||
15 | ~OPimCacheItem(); | ||
16 | |||
17 | OPimCacheItem &operator=( const OPimCacheItem& ); | ||
18 | |||
19 | T record()const; | ||
20 | void setRecord( const T& ); | ||
21 | private: | ||
22 | T m_t; | ||
23 | OPimCacheItemPrivate *d; | ||
24 | }; | ||
25 | |||
26 | |||
27 | class OPimCachePrivate; | ||
28 | /** | ||
29 | * OPimCache for caching the items | ||
30 | * We support adding, removing | ||
31 | * and finding | ||
32 | */ | ||
33 | template <class T = OPimRecord> | ||
34 | class OPimCache { | ||
35 | public: | ||
36 | typedef OPimCacheItem<T> Item; | ||
37 | OPimCache(); | ||
38 | OPimCache( const OPimCache& ); | ||
39 | ~OPimCache(); | ||
40 | |||
41 | OPimCache &operator=( const OPimCache& ); | ||
42 | |||
43 | bool contains(int uid)const; | ||
44 | void invalidate(); | ||
45 | void setSize( int size ); | ||
46 | |||
47 | T find(int uid )const; | ||
48 | void add( const T& ); | ||
49 | void remove( int uid ); | ||
50 | void replace( const T& ); | ||
51 | |||
52 | private: | ||
53 | QIntCache<Item> m_cache; | ||
54 | OPimCachePrivate* d; | ||
55 | }; | ||
56 | |||
57 | // Implementation | ||
58 | template <class T> | ||
59 | OPimCacheItem<T>::OPimCacheItem( const T& t ) | ||
60 | : m_t(t) { | ||
61 | } | ||
62 | template <class T> | ||
63 | OPimCacheItem<T>::~OPimCacheItem() { | ||
64 | |||
65 | } | ||
66 | template <class T> | ||
67 | T OPimCacheItem<T>::record()const { | ||
68 | return m_t; | ||
69 | } | ||
70 | template <class T> | ||
71 | void OPimCacheItem<T>::setRecord( const T& t ) { | ||
72 | m_t = t; | ||
73 | } | ||
74 | // Cache | ||
75 | template <class T> | ||
76 | OPimCache<T>::OPimCache() | ||
77 | : m_cache(100, 53 ) | ||
78 | { | ||
79 | m_cache.setAutoDelete( TRUE ); | ||
80 | } | ||
81 | template <class T> | ||
82 | OPimCache<T>::~OPimCache() { | ||
83 | |||
84 | } | ||
85 | template <class T> | ||
86 | bool OPimCache<T>::contains(int uid )const { | ||
87 | Item* it = m_cache.find( uid, FALSE ); | ||
88 | if (!it) | ||
89 | return false; | ||
90 | return true; | ||
91 | } | ||
92 | template <class T> | ||
93 | void OPimCache<T>::invalidate() { | ||
94 | m_cache.clear(); | ||
95 | } | ||
96 | template <class T> | ||
97 | void OPimCache<T>::setSize( int size ) { | ||
98 | m_cache.setMaxCost( size ); | ||
99 | } | ||
100 | template <class T> | ||
101 | T OPimCache<T>::find(int uid )const { | ||
102 | Item *it = m_cache.find( uid ); | ||
103 | if (it) | ||
104 | return it->record(); | ||
105 | return T(); | ||
106 | } | ||
107 | template <class T> | ||
108 | void OPimCache<T>::add( const T& t ) { | ||
109 | Item* it = 0l; | ||
110 | it = m_cache.find(t.uid(), FALSE ); | ||
111 | |||
112 | if (it ) | ||
113 | it->setRecord( t ); | ||
114 | |||
115 | it = new Item( t ); | ||
116 | if (!m_cache.insert( t.uid(), it ) ) | ||
117 | delete it; | ||
118 | } | ||
119 | template <class T> | ||
120 | void OPimCache<T>::remove( int uid ) { | ||
121 | m_cache.remove( uid ); | ||
122 | } | ||
123 | template <class T> | ||
124 | void OPimCache<T>::replace( const T& t) { | ||
125 | Item *it = m_cache.find( t.uid() ); | ||
126 | if ( it ) { | ||
127 | it->setRecord( t ); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimmaintainer.cpp b/noncore/unsupported/libopie/pim/opimmaintainer.cpp new file mode 100644 index 0000000..92cb25a --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmaintainer.cpp | |||
@@ -0,0 +1,37 @@ | |||
1 | #include "opimmaintainer.h" | ||
2 | |||
3 | OPimMaintainer::OPimMaintainer( int mode, int uid ) | ||
4 | : m_mode(mode), m_uid(uid ) | ||
5 | {} | ||
6 | OPimMaintainer::~OPimMaintainer() { | ||
7 | } | ||
8 | OPimMaintainer::OPimMaintainer( const OPimMaintainer& main ) { | ||
9 | *this = main; | ||
10 | } | ||
11 | OPimMaintainer &OPimMaintainer::operator=( const OPimMaintainer& main ) { | ||
12 | m_mode = main.m_mode; | ||
13 | m_uid = main.m_uid; | ||
14 | |||
15 | return *this; | ||
16 | } | ||
17 | bool OPimMaintainer::operator==( const OPimMaintainer& main ) { | ||
18 | if (m_mode != main.m_mode ) return false; | ||
19 | if (m_uid != main.m_uid ) return false; | ||
20 | |||
21 | return true; | ||
22 | } | ||
23 | bool OPimMaintainer::operator!=( const OPimMaintainer& main ) { | ||
24 | return !(*this == main ); | ||
25 | } | ||
26 | int OPimMaintainer::mode()const { | ||
27 | return m_mode; | ||
28 | } | ||
29 | int OPimMaintainer::uid()const { | ||
30 | return m_uid; | ||
31 | } | ||
32 | void OPimMaintainer::setMode( int mo) { | ||
33 | m_mode = mo; | ||
34 | } | ||
35 | void OPimMaintainer::setUid( int uid ) { | ||
36 | m_uid = uid; | ||
37 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimmaintainer.h b/noncore/unsupported/libopie/pim/opimmaintainer.h new file mode 100644 index 0000000..793d066 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmaintainer.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifndef OPIE_PIM_MAINTAINER_H | ||
2 | #define OPIE_PIM_MAINTAINER_H | ||
3 | |||
4 | #include <qstring.h> | ||
5 | |||
6 | /** | ||
7 | * Who maintains what? | ||
8 | */ | ||
9 | class OPimMaintainer { | ||
10 | public: | ||
11 | enum Mode { Undefined = -1, | ||
12 | Nothing = 0, | ||
13 | Responsible, | ||
14 | DoneBy, | ||
15 | Coordinating, | ||
16 | }; | ||
17 | OPimMaintainer( int mode = Undefined, int uid = 0); | ||
18 | OPimMaintainer( const OPimMaintainer& ); | ||
19 | ~OPimMaintainer(); | ||
20 | |||
21 | OPimMaintainer &operator=( const OPimMaintainer& ); | ||
22 | bool operator==( const OPimMaintainer& ); | ||
23 | bool operator!=( const OPimMaintainer& ); | ||
24 | |||
25 | |||
26 | int mode()const; | ||
27 | int uid()const; | ||
28 | |||
29 | void setMode( int mode ); | ||
30 | void setUid( int uid ); | ||
31 | |||
32 | private: | ||
33 | int m_mode; | ||
34 | int m_uid; | ||
35 | class Private; | ||
36 | Private *d; | ||
37 | |||
38 | }; | ||
39 | |||
40 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimmainwindow.cpp b/noncore/unsupported/libopie/pim/opimmainwindow.cpp new file mode 100644 index 0000000..99a0333 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmainwindow.cpp | |||
@@ -0,0 +1,150 @@ | |||
1 | #include <qapplication.h> | ||
2 | #include <qdatetime.h> | ||
3 | #include <qcopchannel_qws.h> | ||
4 | |||
5 | #include <qpe/sound.h> | ||
6 | #include <qpe/qcopenvelope_qws.h> | ||
7 | #include <qpe/qpeapplication.h> | ||
8 | |||
9 | #include "opimresolver.h" | ||
10 | #include "opimmainwindow.h" | ||
11 | |||
12 | OPimMainWindow::OPimMainWindow( const QString& service, QWidget* parent, | ||
13 | const char* name, WFlags flag ) | ||
14 | : QMainWindow( parent, name, flag ), m_rtti(-1), m_service( service ), m_fallBack(0l) { | ||
15 | |||
16 | /* | ||
17 | * let's generate our QCopChannel | ||
18 | */ | ||
19 | m_str = QString("QPE/"+m_service).local8Bit(); | ||
20 | m_channel= new QCopChannel(m_str, this ); | ||
21 | connect(m_channel, SIGNAL(received(const QCString&,const QByteArray&) ), | ||
22 | this, SLOT( appMessage(const QCString&,const QByteArray&) ) ); | ||
23 | connect(qApp, SIGNAL(appMessage(const QCString&,const QByteArray&) ), | ||
24 | this, SLOT( appMessage(const QCString&,const QByteArray&) ) ); | ||
25 | |||
26 | /* connect flush and reload */ | ||
27 | connect(qApp, SIGNAL(flush() ), | ||
28 | this, SLOT(flush() ) ); | ||
29 | connect(qApp, SIGNAL(reload() ), | ||
30 | this, SLOT(reload() ) ); | ||
31 | } | ||
32 | OPimMainWindow::~OPimMainWindow() { | ||
33 | delete m_channel; | ||
34 | } | ||
35 | QCopChannel* OPimMainWindow::channel() { | ||
36 | return m_channel; | ||
37 | } | ||
38 | void OPimMainWindow::doSetDocument( const QString& ) { | ||
39 | |||
40 | } | ||
41 | void OPimMainWindow::appMessage( const QCString& cmd, const QByteArray& array ) { | ||
42 | bool needShow = false; | ||
43 | /* | ||
44 | * create demands to create | ||
45 | * a new record... | ||
46 | */ | ||
47 | QDataStream stream(array, IO_ReadOnly); | ||
48 | if ( cmd == "create()" ) { | ||
49 | raise(); | ||
50 | int uid = create(); | ||
51 | QCopEnvelope e(m_str, "created(int)" ); | ||
52 | e << uid; | ||
53 | needShow = true; | ||
54 | }else if ( cmd == "remove(int)" ) { | ||
55 | int uid; | ||
56 | stream >> uid; | ||
57 | bool rem = remove( uid ); | ||
58 | QCopEnvelope e(m_str, "removed(bool)" ); | ||
59 | e << rem; | ||
60 | needShow = true; | ||
61 | }else if ( cmd == "beam(int)" ) { | ||
62 | int uid; | ||
63 | stream >> uid; | ||
64 | beam( uid); | ||
65 | }else if ( cmd == "show(int)" ) { | ||
66 | raise(); | ||
67 | int uid; | ||
68 | stream >> uid; | ||
69 | show( uid ); | ||
70 | needShow = true; | ||
71 | }else if ( cmd == "edit(int)" ) { | ||
72 | raise(); | ||
73 | int uid; | ||
74 | stream >> uid; | ||
75 | edit( uid ); | ||
76 | }else if ( cmd == "add(int,QByteArray)" ) { | ||
77 | int rtti; | ||
78 | QByteArray array; | ||
79 | stream >> rtti; | ||
80 | stream >> array; | ||
81 | m_fallBack = record(rtti, array ); | ||
82 | if (!m_fallBack) return; | ||
83 | add( *m_fallBack ); | ||
84 | delete m_fallBack; | ||
85 | }else if ( cmd == "alarm(QDateTime,int)" ) { | ||
86 | raise(); | ||
87 | QDateTime dt; int uid; | ||
88 | stream >> dt; | ||
89 | stream >> uid; | ||
90 | qWarning(" Date: %s Uid: %d", dt.toString().latin1(), uid ); | ||
91 | QDateTime current = QDateTime::currentDateTime(); | ||
92 | if ( current.time().hour() != dt.time().hour() && current.time().minute() != dt.time().minute() ) | ||
93 | return; | ||
94 | doAlarm( dt, uid ); | ||
95 | needShow = true; | ||
96 | } | ||
97 | |||
98 | if (needShow ) | ||
99 | QPEApplication::setKeepRunning(); | ||
100 | } | ||
101 | /* implement the url scripting here */ | ||
102 | void OPimMainWindow::setDocument( const QString& str) { | ||
103 | doSetDocument( str ); | ||
104 | } | ||
105 | /* | ||
106 | * we now try to get the array demarshalled | ||
107 | * check if the rtti matches this one | ||
108 | */ | ||
109 | OPimRecord* OPimMainWindow::record( int rtti, const QByteArray& array ) { | ||
110 | if ( service() != rtti ) | ||
111 | return 0l; | ||
112 | |||
113 | OPimRecord* record = OPimResolver::self()->record( rtti ); | ||
114 | QDataStream str(array, IO_ReadOnly ); | ||
115 | if ( !record || !record->loadFromStream(str) ) { | ||
116 | delete record; | ||
117 | record = 0l; | ||
118 | } | ||
119 | |||
120 | return record; | ||
121 | } | ||
122 | /* | ||
123 | * get the rtti for the service | ||
124 | */ | ||
125 | int OPimMainWindow::service() { | ||
126 | if ( m_rtti == -1 ) | ||
127 | m_rtti = OPimResolver::self()->serviceId( m_service ); | ||
128 | |||
129 | return m_rtti; | ||
130 | } | ||
131 | void OPimMainWindow::doAlarm( const QDateTime&, int ) { | ||
132 | |||
133 | } | ||
134 | void OPimMainWindow::startAlarm(int count ) { | ||
135 | m_alarmCount = count; | ||
136 | m_playedCount = 0; | ||
137 | Sound::soundAlarm(); | ||
138 | m_timerId = startTimer( 5000 ); | ||
139 | } | ||
140 | void OPimMainWindow::killAlarm() { | ||
141 | killTimer( m_timerId ); | ||
142 | } | ||
143 | void OPimMainWindow::timerEvent( QTimerEvent* e) { | ||
144 | if ( m_playedCount <m_alarmCount ) { | ||
145 | m_playedCount++; | ||
146 | Sound::soundAlarm(); | ||
147 | }else { | ||
148 | killTimer( e->timerId() ); | ||
149 | } | ||
150 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimmainwindow.h b/noncore/unsupported/libopie/pim/opimmainwindow.h new file mode 100644 index 0000000..855d364 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimmainwindow.h | |||
@@ -0,0 +1,99 @@ | |||
1 | #ifndef OPIE_PIM_MAINWINDOW_H | ||
2 | #define OPIE_PIM_MAINWINDOW_H | ||
3 | |||
4 | #include <qmainwindow.h> | ||
5 | |||
6 | #include <opie/opimrecord.h> | ||
7 | |||
8 | /** | ||
9 | * This is a common Opie PIM MainWindow | ||
10 | * it takes care of the QCOP internals | ||
11 | * and implements some functions | ||
12 | * for the URL scripting schema | ||
13 | */ | ||
14 | /* | ||
15 | * due Qt and Templates with signal and slots | ||
16 | * do not work that good :( | ||
17 | * (Ok how to moc a template ;) ) | ||
18 | * We will have the mainwindow which calls a struct which | ||
19 | * is normally reimplemented as a template ;) | ||
20 | */ | ||
21 | |||
22 | class QCopChannel; | ||
23 | class QDateTime; | ||
24 | class OPimMainWindow : public QMainWindow { | ||
25 | Q_OBJECT | ||
26 | public: | ||
27 | enum TransPort { BlueTooth=0, | ||
28 | IrDa }; | ||
29 | |||
30 | OPimMainWindow( const QString& service, QWidget *parent = 0, const char* name = 0, | ||
31 | WFlags f = WType_TopLevel); | ||
32 | virtual ~OPimMainWindow(); | ||
33 | |||
34 | |||
35 | protected slots: | ||
36 | /* | ||
37 | * called when a setDocument | ||
38 | * couldn't be handled by this window | ||
39 | */ | ||
40 | virtual void doSetDocument( const QString& ); | ||
41 | /* for syncing */ | ||
42 | virtual void flush() = 0; | ||
43 | virtual void reload() = 0; | ||
44 | |||
45 | /** create a new Records and return the uid */ | ||
46 | virtual int create() = 0; | ||
47 | /** remove a record with UID == uid */ | ||
48 | virtual bool remove( int uid ) = 0; | ||
49 | /** beam the record with UID = uid */ | ||
50 | virtual void beam( int uid ) = 0; | ||
51 | |||
52 | /** show the record with UID == uid */ | ||
53 | virtual void show( int uid ) = 0; | ||
54 | /** edit the record */ | ||
55 | virtual void edit( int uid ) = 0; | ||
56 | |||
57 | /** make a copy of it! */ | ||
58 | virtual void add( const OPimRecord& ) = 0; | ||
59 | |||
60 | virtual void doAlarm( const QDateTime&, int uid ); | ||
61 | |||
62 | QCopChannel* channel(); | ||
63 | |||
64 | protected: | ||
65 | /** | ||
66 | * start to play soundAlarm() | ||
67 | * @param count How many times the alarm is played | ||
68 | */ | ||
69 | void startAlarm(int count = 10); | ||
70 | void killAlarm(); | ||
71 | void timerEvent( QTimerEvent* ); | ||
72 | |||
73 | private slots: | ||
74 | void appMessage( const QCString&, const QByteArray& ); | ||
75 | void setDocument( const QString& ); | ||
76 | |||
77 | |||
78 | private: | ||
79 | class Private; | ||
80 | Private* d; | ||
81 | |||
82 | int m_rtti; | ||
83 | QCopChannel* m_channel; | ||
84 | QString m_service; | ||
85 | QCString m_str; | ||
86 | OPimRecord* m_fallBack; | ||
87 | int m_alarmCount; | ||
88 | int m_playedCount; | ||
89 | int m_timerId; | ||
90 | /* I would love to do this as a template | ||
91 | * but can't think of a right way | ||
92 | * because I need signal and slots -zecke | ||
93 | */ | ||
94 | virtual OPimRecord* record( int rtti, const QByteArray& ) ; | ||
95 | int service(); | ||
96 | }; | ||
97 | |||
98 | |||
99 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimnotify.cpp b/noncore/unsupported/libopie/pim/opimnotify.cpp new file mode 100644 index 0000000..af5514b --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotify.cpp | |||
@@ -0,0 +1,227 @@ | |||
1 | #include <qshared.h> | ||
2 | |||
3 | #include "opimnotify.h" | ||
4 | |||
5 | struct OPimNotify::Data : public QShared { | ||
6 | Data() : QShared(),dur(-1),parent(0) { | ||
7 | |||
8 | } | ||
9 | QDateTime start; | ||
10 | int dur; | ||
11 | QString application; | ||
12 | int parent; | ||
13 | }; | ||
14 | |||
15 | OPimNotify::OPimNotify( const QDateTime& start, int duration, int parent ) { | ||
16 | data = new Data; | ||
17 | data->start = start; | ||
18 | data->dur = duration; | ||
19 | data->parent = parent; | ||
20 | } | ||
21 | OPimNotify::OPimNotify( const OPimNotify& noti) | ||
22 | : data( noti.data ) | ||
23 | { | ||
24 | data->ref(); | ||
25 | } | ||
26 | OPimNotify::~OPimNotify() { | ||
27 | if ( data->deref() ) { | ||
28 | delete data; | ||
29 | data = 0l; | ||
30 | } | ||
31 | } | ||
32 | |||
33 | OPimNotify &OPimNotify::operator=( const OPimNotify& noti) { | ||
34 | noti.data->ref(); | ||
35 | deref(); | ||
36 | data = noti.data; | ||
37 | |||
38 | return *this; | ||
39 | } | ||
40 | bool OPimNotify::operator==( const OPimNotify& noti ) { | ||
41 | if ( data == noti.data ) return true; | ||
42 | if ( data->dur != noti.data->dur ) return false; | ||
43 | if ( data->parent != noti.data->parent ) return false; | ||
44 | if ( data->application != noti.data->application ) return false; | ||
45 | if ( data->start != noti.data->start ) return false; | ||
46 | |||
47 | return true; | ||
48 | } | ||
49 | QDateTime OPimNotify::dateTime()const { | ||
50 | return data->start; | ||
51 | } | ||
52 | QString OPimNotify::service()const { | ||
53 | return data->application; | ||
54 | } | ||
55 | int OPimNotify::parent()const { | ||
56 | return data->parent; | ||
57 | } | ||
58 | int OPimNotify::duration()const { | ||
59 | return data->dur; | ||
60 | } | ||
61 | QDateTime OPimNotify::endTime()const { | ||
62 | return QDateTime( data->start.date(), data->start.time().addSecs( data->dur) ); | ||
63 | } | ||
64 | void OPimNotify::setDateTime( const QDateTime& time ) { | ||
65 | copyIntern(); | ||
66 | data->start = time; | ||
67 | } | ||
68 | void OPimNotify::setDuration( int dur ) { | ||
69 | copyIntern(); | ||
70 | data->dur = dur; | ||
71 | } | ||
72 | void OPimNotify::setParent( int uid ) { | ||
73 | copyIntern(); | ||
74 | data->parent = uid; | ||
75 | } | ||
76 | void OPimNotify::setService( const QString& str ) { | ||
77 | copyIntern(); | ||
78 | data->application = str; | ||
79 | } | ||
80 | void OPimNotify::copyIntern() { | ||
81 | if ( data->count != 1 ) { | ||
82 | data->deref(); | ||
83 | Data* dat = new Data; | ||
84 | dat->start = data->start; | ||
85 | dat->dur = data->dur; | ||
86 | dat->application = data->application; | ||
87 | dat->parent = data->parent; | ||
88 | data = dat; | ||
89 | } | ||
90 | } | ||
91 | void OPimNotify::deref() { | ||
92 | if ( data->deref() ) { | ||
93 | delete data; | ||
94 | data = 0; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /***********************************************************/ | ||
99 | struct OPimAlarm::Data : public QShared { | ||
100 | Data() : QShared() { | ||
101 | sound = 1; | ||
102 | } | ||
103 | int sound; | ||
104 | QString file; | ||
105 | }; | ||
106 | OPimAlarm::OPimAlarm( int sound, const QDateTime& start, int duration, int parent ) | ||
107 | : OPimNotify( start, duration, parent ) | ||
108 | { | ||
109 | data = new Data; | ||
110 | data->sound = sound; | ||
111 | } | ||
112 | OPimAlarm::OPimAlarm( const OPimAlarm& al) | ||
113 | : OPimNotify(al), data( al.data ) | ||
114 | { | ||
115 | data->ref(); | ||
116 | } | ||
117 | OPimAlarm::~OPimAlarm() { | ||
118 | if ( data->deref() ) { | ||
119 | delete data; | ||
120 | data = 0l; | ||
121 | } | ||
122 | } | ||
123 | OPimAlarm &OPimAlarm::operator=( const OPimAlarm& al) | ||
124 | { | ||
125 | OPimNotify::operator=( al ); | ||
126 | deref(); | ||
127 | al.data->ref(); | ||
128 | |||
129 | data = al.data; | ||
130 | |||
131 | |||
132 | return *this; | ||
133 | } | ||
134 | bool OPimAlarm::operator==( const OPimAlarm& al) { | ||
135 | if ( data->sound != al.data->sound ) return false; | ||
136 | else if ( data->sound == Custom && data->file != al.data->file ) | ||
137 | return false; | ||
138 | |||
139 | return OPimNotify::operator==( al ); | ||
140 | } | ||
141 | QString OPimAlarm::type()const { | ||
142 | return QString::fromLatin1("OPimAlarm"); | ||
143 | } | ||
144 | int OPimAlarm::sound()const { | ||
145 | return data->sound; | ||
146 | } | ||
147 | QString OPimAlarm::file()const { | ||
148 | return data->file; | ||
149 | } | ||
150 | void OPimAlarm::setSound( int snd) { | ||
151 | copyIntern(); | ||
152 | data->sound = snd; | ||
153 | } | ||
154 | void OPimAlarm::setFile( const QString& sound ) { | ||
155 | copyIntern(); | ||
156 | data->file = sound; | ||
157 | } | ||
158 | void OPimAlarm::deref() { | ||
159 | if ( data->deref() ) { | ||
160 | delete data; | ||
161 | data = 0l; | ||
162 | } | ||
163 | } | ||
164 | void OPimAlarm::copyIntern() { | ||
165 | if ( data->count != 1 ) { | ||
166 | data->deref(); | ||
167 | Data *newDat = new Data; | ||
168 | newDat->sound = data->sound; | ||
169 | newDat->file = data->file; | ||
170 | data = newDat; | ||
171 | } | ||
172 | } | ||
173 | /************************/ | ||
174 | struct OPimReminder::Data : public QShared { | ||
175 | Data() : QShared(), record( 0) { | ||
176 | } | ||
177 | int record; | ||
178 | |||
179 | }; | ||
180 | OPimReminder::OPimReminder( int uid, const QDateTime& start, int dur, int parent ) | ||
181 | : OPimNotify( start, dur, parent ) | ||
182 | { | ||
183 | data = new Data; | ||
184 | data->record = uid; | ||
185 | } | ||
186 | OPimReminder::OPimReminder( const OPimReminder& rem ) | ||
187 | : OPimNotify( rem ), data( rem.data ) | ||
188 | { | ||
189 | data->ref(); | ||
190 | } | ||
191 | OPimReminder& OPimReminder::operator=( const OPimReminder& rem) { | ||
192 | OPimNotify::operator=(rem ); | ||
193 | |||
194 | deref(); | ||
195 | rem.data->ref(); | ||
196 | data = rem.data; | ||
197 | |||
198 | return *this; | ||
199 | } | ||
200 | bool OPimReminder::operator==( const OPimReminder& rem) { | ||
201 | if ( data->record != rem.data->record ) return false; | ||
202 | |||
203 | return OPimNotify::operator==( rem ); | ||
204 | } | ||
205 | QString OPimReminder::type()const { | ||
206 | return QString::fromLatin1("OPimReminder"); | ||
207 | } | ||
208 | int OPimReminder::recordUid()const { | ||
209 | return data->record; | ||
210 | } | ||
211 | void OPimReminder::setRecordUid( int uid ) { | ||
212 | copyIntern(); | ||
213 | data->record = uid; | ||
214 | } | ||
215 | void OPimReminder::deref() { | ||
216 | if ( data->deref() ) { | ||
217 | delete data; | ||
218 | data = 0l; | ||
219 | } | ||
220 | } | ||
221 | void OPimReminder::copyIntern() { | ||
222 | if ( data->count != 1 ) { | ||
223 | Data* da = new Data; | ||
224 | da->record = data->record; | ||
225 | data = da; | ||
226 | } | ||
227 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimnotify.h b/noncore/unsupported/libopie/pim/opimnotify.h new file mode 100644 index 0000000..58417db --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotify.h | |||
@@ -0,0 +1,144 @@ | |||
1 | #ifndef OPIE_PIM_NOTIFY_H | ||
2 | #define OPIE_PIM_NOTIFY_H | ||
3 | |||
4 | #include <qdatetime.h> | ||
5 | #include <qvaluelist.h> | ||
6 | |||
7 | /** | ||
8 | * This is the base class of Notifiers. Possible | ||
9 | * notifiers would be Alarms, Reminders | ||
10 | * What they share is that they have | ||
11 | * A DateTime, Type, Duration | ||
12 | * This is what this base class takes care of | ||
13 | * on top of that it's shared | ||
14 | */ | ||
15 | /* | ||
16 | * TALK to eilers: have a class OPimDuration which sets the Duration | ||
17 | * given on the Due/Start Date? -zecke | ||
18 | * discuss: do we need a uid for the notify? -zecke | ||
19 | */ | ||
20 | class OPimNotify { | ||
21 | public: | ||
22 | typedef QValueList<OPimNotify> ValueList; | ||
23 | OPimNotify( const QDateTime& start = QDateTime(), int duration = 0, int parent = 0 ); | ||
24 | OPimNotify( const OPimNotify& ); | ||
25 | virtual ~OPimNotify(); | ||
26 | |||
27 | OPimNotify &operator=(const OPimNotify& ); | ||
28 | bool operator==( const OPimNotify& ); | ||
29 | |||
30 | virtual QString type()const = 0; | ||
31 | |||
32 | /** start date */ | ||
33 | QDateTime dateTime()const; | ||
34 | QString service()const; | ||
35 | |||
36 | /** | ||
37 | * RETURN the parent uid | ||
38 | */ | ||
39 | int parent()const; | ||
40 | |||
41 | /** | ||
42 | * in Seconds | ||
43 | */ | ||
44 | int duration()const; | ||
45 | |||
46 | /** | ||
47 | * Start Time + Duration | ||
48 | */ | ||
49 | QDateTime endTime()const; | ||
50 | |||
51 | void setDateTime( const QDateTime& ); | ||
52 | void setDuration( int dur ); | ||
53 | void setParent(int uid ); | ||
54 | void setService( const QString& ); | ||
55 | |||
56 | |||
57 | private: | ||
58 | inline void copyIntern(); | ||
59 | void deref(); | ||
60 | struct Data; | ||
61 | Data* data; | ||
62 | |||
63 | /* d-pointer */ | ||
64 | class NotifyPrivate; | ||
65 | NotifyPrivate* d; | ||
66 | |||
67 | }; | ||
68 | /** | ||
69 | * An alarm is a sound/mail/buzzer played/send | ||
70 | * at a given time to inform about | ||
71 | * an Event | ||
72 | */ | ||
73 | class OPimAlarm : public OPimNotify { | ||
74 | public: | ||
75 | enum Sound{Loud=1, Silent=0, Custom=2 }; | ||
76 | OPimAlarm( int sound = Silent, const QDateTime& start = QDateTime(), int duration = 0, int parent = 0 ); | ||
77 | OPimAlarm( const OPimAlarm& ); | ||
78 | ~OPimAlarm(); | ||
79 | |||
80 | OPimAlarm &operator=( const OPimAlarm& ); | ||
81 | bool operator==( const OPimAlarm& ); | ||
82 | QString type()const; | ||
83 | |||
84 | int sound()const; | ||
85 | QString file()const; | ||
86 | |||
87 | void setSound( int ); | ||
88 | /* only when sound is custom... */ | ||
89 | void setFile( const QString& sound ); | ||
90 | |||
91 | private: | ||
92 | void deref(); | ||
93 | void copyIntern(); | ||
94 | struct Data; | ||
95 | Data * data; | ||
96 | |||
97 | class Private; | ||
98 | Private* d; | ||
99 | |||
100 | }; | ||
101 | |||
102 | /** | ||
103 | * A Reminder will be put into the | ||
104 | * datebook | ||
105 | * Note that the returned dateTime() may be not valid. | ||
106 | * In these cases one must resolve the uid and get the OEvent | ||
107 | */ | ||
108 | class OPimReminder : public OPimNotify { | ||
109 | public: | ||
110 | |||
111 | /** | ||
112 | * c'tor of a reminder | ||
113 | * @param uid The uid of the Record inside the Datebook | ||
114 | * @param start the StartDate invalid for all day... | ||
115 | * @param duration The duration of the event ( -1 for all day ) | ||
116 | * @param parent The 'parent' record of this reminder | ||
117 | */ | ||
118 | OPimReminder( int uid = 0, const QDateTime& start = QDateTime(), | ||
119 | int duration = 0, int parent = 0 ); | ||
120 | OPimReminder( const OPimReminder& ); | ||
121 | OPimReminder &operator=(const OPimReminder& ); | ||
122 | |||
123 | QString type()const; | ||
124 | |||
125 | bool operator==( const OPimReminder& ); | ||
126 | |||
127 | /** | ||
128 | * the uid of the alarm | ||
129 | * inside the 'datebook' application | ||
130 | */ | ||
131 | int recordUid()const; | ||
132 | void setRecordUid( int uid ); | ||
133 | |||
134 | private: | ||
135 | void deref(); | ||
136 | void copyIntern(); | ||
137 | |||
138 | struct Data; | ||
139 | Data* data; | ||
140 | class Private; | ||
141 | Private *d; | ||
142 | }; | ||
143 | |||
144 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimnotifymanager.cpp b/noncore/unsupported/libopie/pim/opimnotifymanager.cpp new file mode 100644 index 0000000..d6f0ead --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotifymanager.cpp | |||
@@ -0,0 +1,162 @@ | |||
1 | #include "opimnotifymanager.h" | ||
2 | |||
3 | #include "oconversion.h" | ||
4 | |||
5 | #include <qstringlist.h> | ||
6 | |||
7 | OPimNotifyManager::OPimNotifyManager( const Reminders& rem, const Alarms& al) | ||
8 | : m_rem( rem ), m_al( al ) | ||
9 | {} | ||
10 | OPimNotifyManager::~OPimNotifyManager() { | ||
11 | } | ||
12 | /* use static_cast and type instead of dynamic... */ | ||
13 | void OPimNotifyManager::add( const OPimNotify& noti) { | ||
14 | if ( noti.type() == QString::fromLatin1("OPimReminder") ) { | ||
15 | const OPimReminder& rem = static_cast<const OPimReminder&>(noti); | ||
16 | m_rem.append( rem ); | ||
17 | }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) { | ||
18 | const OPimAlarm& al = static_cast<const OPimAlarm&>(noti); | ||
19 | m_al.append( al ); | ||
20 | } | ||
21 | } | ||
22 | void OPimNotifyManager::remove( const OPimNotify& noti) { | ||
23 | if ( noti.type() == QString::fromLatin1("OPimReminder") ) { | ||
24 | const OPimReminder& rem = static_cast<const OPimReminder&>(noti); | ||
25 | m_rem.remove( rem ); | ||
26 | }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) { | ||
27 | const OPimAlarm& al = static_cast<const OPimAlarm&>(noti); | ||
28 | m_al.remove( al ); | ||
29 | } | ||
30 | } | ||
31 | void OPimNotifyManager::replace( const OPimNotify& noti) { | ||
32 | if ( noti.type() == QString::fromLatin1("OPimReminder") ) { | ||
33 | const OPimReminder& rem = static_cast<const OPimReminder&>(noti); | ||
34 | m_rem.remove( rem ); | ||
35 | m_rem.append( rem ); | ||
36 | }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) { | ||
37 | const OPimAlarm& al = static_cast<const OPimAlarm&>(noti); | ||
38 | m_al.remove( al ); | ||
39 | m_al.append( al ); | ||
40 | } | ||
41 | } | ||
42 | OPimNotifyManager::Reminders OPimNotifyManager::reminders()const { | ||
43 | return m_rem; | ||
44 | } | ||
45 | OPimNotifyManager::Alarms OPimNotifyManager::alarms()const { | ||
46 | return m_al; | ||
47 | } | ||
48 | OPimAlarm OPimNotifyManager::alarmAtDateTime( const QDateTime& when, bool& found ) const { | ||
49 | Alarms::ConstIterator it; | ||
50 | found = true; | ||
51 | |||
52 | for ( it = m_al.begin(); it != m_al.end(); ++it ){ | ||
53 | if ( (*it).dateTime() == when ) | ||
54 | return (*it); | ||
55 | } | ||
56 | |||
57 | // Fall through if nothing could be found | ||
58 | found = false; | ||
59 | OPimAlarm empty; | ||
60 | return empty; | ||
61 | } | ||
62 | |||
63 | |||
64 | void OPimNotifyManager::setAlarms( const Alarms& al) { | ||
65 | m_al = al; | ||
66 | } | ||
67 | void OPimNotifyManager::setReminders( const Reminders& rem) { | ||
68 | m_rem = rem; | ||
69 | } | ||
70 | /* FIXME!!! */ | ||
71 | /** | ||
72 | * The idea is to check if the provider for our service | ||
73 | * is online | ||
74 | * if it is we will use QCOP | ||
75 | * if not the Factory to get the backend... | ||
76 | * Qtopia1.6 services would be kewl to have here.... | ||
77 | */ | ||
78 | void OPimNotifyManager::registerNotify( const OPimNotify& ) { | ||
79 | |||
80 | } | ||
81 | /* FIXME!!! */ | ||
82 | /** | ||
83 | * same as above... | ||
84 | * Also implement Url model | ||
85 | * have a MainWindow.... | ||
86 | */ | ||
87 | void OPimNotifyManager::deregister( const OPimNotify& ) { | ||
88 | |||
89 | } | ||
90 | |||
91 | bool OPimNotifyManager::isEmpty()const { | ||
92 | qWarning("is Empty called on OPimNotifyManager %d %d", m_rem.count(), m_al.count() ); | ||
93 | if ( m_rem.isEmpty() && m_al.isEmpty() ) return true; | ||
94 | else return false; | ||
95 | } | ||
96 | |||
97 | // Taken from otodoaccessxml.. | ||
98 | QString OPimNotifyManager::alarmsToString() const | ||
99 | { | ||
100 | QString str; | ||
101 | |||
102 | OPimNotifyManager::Alarms alarms = m_al; | ||
103 | if ( !alarms.isEmpty() ) { | ||
104 | QStringList als; | ||
105 | OPimNotifyManager::Alarms::Iterator it = alarms.begin(); | ||
106 | for ( ; it != alarms.end(); ++it ) { | ||
107 | /* only if time is valid */ | ||
108 | if ( (*it).dateTime().isValid() ) { | ||
109 | als << OConversion::dateTimeToString( (*it).dateTime() ) | ||
110 | + ":" + QString::number( (*it).duration() ) | ||
111 | + ":" + QString::number( (*it).sound() ) | ||
112 | + ":"; | ||
113 | } | ||
114 | } | ||
115 | // now write the list | ||
116 | qWarning("als: %s", als.join("____________").latin1() ); | ||
117 | str = als.join(";"); | ||
118 | } | ||
119 | |||
120 | return str; | ||
121 | } | ||
122 | QString OPimNotifyManager::remindersToString() const | ||
123 | { | ||
124 | QString str; | ||
125 | |||
126 | OPimNotifyManager::Reminders reminders = m_rem; | ||
127 | if (!reminders.isEmpty() ) { | ||
128 | OPimNotifyManager::Reminders::Iterator it = reminders.begin(); | ||
129 | QStringList records; | ||
130 | for ( ; it != reminders.end(); ++it ) { | ||
131 | records << QString::number( (*it).recordUid() ); | ||
132 | } | ||
133 | str = records.join(";"); | ||
134 | } | ||
135 | |||
136 | return str; | ||
137 | } | ||
138 | |||
139 | void OPimNotifyManager::alarmsFromString( const QString& str ) | ||
140 | { | ||
141 | QStringList als = QStringList::split(";", str ); | ||
142 | for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) { | ||
143 | QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty | ||
144 | qWarning("alarm: %s", alarm.join("___").latin1() ); | ||
145 | qWarning("alarm[0]: %s %s", alarm[0].latin1(), | ||
146 | OConversion::dateTimeFromString( alarm[0] ).toString().latin1() ); | ||
147 | OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), | ||
148 | alarm[1].toInt() ); | ||
149 | add( al ); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | void OPimNotifyManager::remindersFromString( const QString& str ) | ||
154 | { | ||
155 | |||
156 | QStringList rems = QStringList::split(";", str ); | ||
157 | for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) { | ||
158 | OPimReminder rem( (*it).toInt() ); | ||
159 | add( rem ); | ||
160 | } | ||
161 | |||
162 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimnotifymanager.h b/noncore/unsupported/libopie/pim/opimnotifymanager.h new file mode 100644 index 0000000..f3c22f9 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimnotifymanager.h | |||
@@ -0,0 +1,91 @@ | |||
1 | #ifndef OPIE_PIM_NOTIFY_MANAGER_H | ||
2 | #define OPIE_PIM_NOTIFY_MANAGER_H | ||
3 | |||
4 | #include <qvaluelist.h> | ||
5 | |||
6 | #include <opie/opimnotify.h> | ||
7 | |||
8 | /** | ||
9 | * The notify manager keeps track of the Notifiers.... | ||
10 | */ | ||
11 | class OPimNotifyManager { | ||
12 | public: | ||
13 | typedef QValueList<OPimReminder> Reminders; | ||
14 | typedef QValueList<OPimAlarm> Alarms; | ||
15 | OPimNotifyManager( const Reminders& rems = Reminders(), const Alarms& alarms = Alarms() ); | ||
16 | ~OPimNotifyManager(); | ||
17 | |||
18 | /* we will cast it for you ;) */ | ||
19 | void add( const OPimNotify& ); | ||
20 | void remove( const OPimNotify& ); | ||
21 | /* replaces all with this one! */ | ||
22 | void replace( const OPimNotify& ); | ||
23 | |||
24 | Reminders reminders()const; | ||
25 | |||
26 | /** | ||
27 | * Return | ||
28 | */ | ||
29 | Alarms alarms()const; | ||
30 | |||
31 | /** | ||
32 | * Return alarm at DateTime "when". If more than one is registered at this | ||
33 | * DateTime, the first one is returned. | ||
34 | * If none was found, an empty Alarm is returned. | ||
35 | * @param when The date and time of the returned alarm | ||
36 | * @param found Returns true if anything was found. | ||
37 | * @return Returns the found alarm at given DateTime. It is empty if found is false | ||
38 | * (nothing could be found at given date and time) | ||
39 | */ | ||
40 | OPimAlarm alarmAtDateTime( const QDateTime& when, bool& found ) const; | ||
41 | |||
42 | void setAlarms( const Alarms& ); | ||
43 | void setReminders( const Reminders& ); | ||
44 | |||
45 | /* register is a Ansi C keyword... */ | ||
46 | /** | ||
47 | * This function will register the Notify to the Alarm Server | ||
48 | * or datebook depending on the type of the notify | ||
49 | */ | ||
50 | void registerNotify( const OPimNotify& ); | ||
51 | |||
52 | /** | ||
53 | * this will do the opposite.. | ||
54 | */ | ||
55 | void deregister( const OPimNotify& ); | ||
56 | |||
57 | bool isEmpty()const; | ||
58 | |||
59 | /** | ||
60 | * Return all alarms as string | ||
61 | */ | ||
62 | QString alarmsToString() const; | ||
63 | /** | ||
64 | * Return all notifiers as string | ||
65 | */ | ||
66 | QString remindersToString() const; | ||
67 | |||
68 | /** | ||
69 | * Convert string to alarms | ||
70 | * @param str String created by alarmsToString() | ||
71 | */ | ||
72 | void alarmsFromString( const QString& str ); | ||
73 | |||
74 | /** | ||
75 | * Convert string to reminders | ||
76 | * @param str String created by remindersToString() | ||
77 | */ | ||
78 | void remindersFromString( const QString& str ); | ||
79 | |||
80 | |||
81 | |||
82 | private: | ||
83 | Reminders m_rem; | ||
84 | Alarms m_al; | ||
85 | |||
86 | class Private; | ||
87 | Private *d; | ||
88 | |||
89 | }; | ||
90 | |||
91 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimrecord.cpp b/noncore/unsupported/libopie/pim/opimrecord.cpp new file mode 100644 index 0000000..2365748 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimrecord.cpp | |||
@@ -0,0 +1,182 @@ | |||
1 | #include <qarray.h> | ||
2 | |||
3 | #include <qpe/categories.h> | ||
4 | #include <qpe/categoryselect.h> | ||
5 | |||
6 | #include "opimrecord.h" | ||
7 | |||
8 | Qtopia::UidGen OPimRecord::m_uidGen( Qtopia::UidGen::Qtopia ); | ||
9 | |||
10 | |||
11 | OPimRecord::OPimRecord( int uid ) | ||
12 | : Qtopia::Record() { | ||
13 | |||
14 | m_lastHit = -1; | ||
15 | setUid( uid ); | ||
16 | } | ||
17 | OPimRecord::~OPimRecord() { | ||
18 | } | ||
19 | OPimRecord::OPimRecord( const OPimRecord& rec ) | ||
20 | : Qtopia::Record( rec ) | ||
21 | { | ||
22 | (*this) = rec; | ||
23 | } | ||
24 | |||
25 | OPimRecord &OPimRecord::operator=( const OPimRecord& rec) { | ||
26 | if ( this == &rec ) return *this; | ||
27 | |||
28 | Qtopia::Record::operator=( rec ); | ||
29 | m_xrefman = rec.m_xrefman; | ||
30 | m_lastHit = rec.m_lastHit; | ||
31 | |||
32 | return *this; | ||
33 | } | ||
34 | /* | ||
35 | * category names | ||
36 | */ | ||
37 | QStringList OPimRecord::categoryNames( const QString& appname ) const { | ||
38 | QStringList list; | ||
39 | QArray<int> cats = categories(); | ||
40 | Categories catDB; | ||
41 | catDB.load( categoryFileName() ); | ||
42 | |||
43 | for (uint i = 0; i < cats.count(); i++ ) { | ||
44 | list << catDB.label( appname, cats[i] ); | ||
45 | } | ||
46 | |||
47 | return list; | ||
48 | } | ||
49 | void OPimRecord::setCategoryNames( const QStringList& ) { | ||
50 | |||
51 | } | ||
52 | void OPimRecord::addCategoryName( const QString& ) { | ||
53 | Categories catDB; | ||
54 | catDB.load( categoryFileName() ); | ||
55 | |||
56 | |||
57 | } | ||
58 | bool OPimRecord::isEmpty()const { | ||
59 | return ( uid() == 0 ); | ||
60 | } | ||
61 | /*QString OPimRecord::crossToString()const { | ||
62 | QString str; | ||
63 | QMap<QString, QArray<int> >::ConstIterator it; | ||
64 | for (it = m_relations.begin(); it != m_relations.end(); ++it ) { | ||
65 | QArray<int> id = it.data(); | ||
66 | for ( uint i = 0; i < id.size(); ++i ) { | ||
67 | str += it.key() + "," + QString::number( i ) + ";"; | ||
68 | } | ||
69 | } | ||
70 | str = str.remove( str.length()-1, 1); // strip the ; | ||
71 | //qWarning("IDS " + str ); | ||
72 | |||
73 | return str; | ||
74 | }*/ | ||
75 | /* if uid = 1 assign a new one */ | ||
76 | void OPimRecord::setUid( int uid ) { | ||
77 | if ( uid == 1) | ||
78 | uid = uidGen().generate(); | ||
79 | |||
80 | Qtopia::Record::setUid( uid ); | ||
81 | }; | ||
82 | Qtopia::UidGen &OPimRecord::uidGen() { | ||
83 | return m_uidGen; | ||
84 | } | ||
85 | OPimXRefManager &OPimRecord::xrefmanager() { | ||
86 | return m_xrefman; | ||
87 | } | ||
88 | int OPimRecord::rtti(){ | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | /** | ||
93 | * now let's put our data into the stream | ||
94 | */ | ||
95 | /* | ||
96 | * First read UID | ||
97 | * Categories | ||
98 | * XRef | ||
99 | */ | ||
100 | bool OPimRecord::loadFromStream( QDataStream& stream ) { | ||
101 | int Int; | ||
102 | uint UInt; | ||
103 | stream >> Int; | ||
104 | setUid(Int); | ||
105 | |||
106 | /** Categories */ | ||
107 | stream >> UInt; | ||
108 | QArray<int> array(UInt); | ||
109 | for (uint i = 0; i < UInt; i++ ) { | ||
110 | stream >> array[i]; | ||
111 | } | ||
112 | setCategories( array ); | ||
113 | |||
114 | /* | ||
115 | * now we do the X-Ref stuff | ||
116 | */ | ||
117 | OPimXRef xref; | ||
118 | stream >> UInt; | ||
119 | for ( uint i = 0; i < UInt; i++ ) { | ||
120 | xref.setPartner( OPimXRef::One, partner( stream ) ); | ||
121 | xref.setPartner( OPimXRef::Two, partner( stream ) ); | ||
122 | m_xrefman.add( xref ); | ||
123 | } | ||
124 | |||
125 | return true; | ||
126 | } | ||
127 | bool OPimRecord::saveToStream( QDataStream& stream )const { | ||
128 | /** UIDs */ | ||
129 | |||
130 | stream << uid(); | ||
131 | |||
132 | /** Categories */ | ||
133 | stream << categories().count(); | ||
134 | for ( uint i = 0; i < categories().count(); i++ ) { | ||
135 | stream << categories()[i]; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * first the XRef count | ||
140 | * then the xrefs | ||
141 | */ | ||
142 | stream << m_xrefman.list().count(); | ||
143 | for ( OPimXRef::ValueList::ConstIterator it = m_xrefman.list().begin(); | ||
144 | it != m_xrefman.list().end(); ++it ) { | ||
145 | flush( (*it).partner( OPimXRef::One), stream ); | ||
146 | flush( (*it).partner( OPimXRef::Two), stream ); | ||
147 | } | ||
148 | return true; | ||
149 | } | ||
150 | void OPimRecord::flush( const OPimXRefPartner& par, QDataStream& str ) const{ | ||
151 | str << par.service(); | ||
152 | str << par.uid(); | ||
153 | str << par.field(); | ||
154 | } | ||
155 | OPimXRefPartner OPimRecord::partner( QDataStream& stream ) { | ||
156 | OPimXRefPartner par; | ||
157 | QString str; | ||
158 | int i; | ||
159 | |||
160 | stream >> str; | ||
161 | par.setService( str ); | ||
162 | |||
163 | stream >> i; | ||
164 | par.setUid( i ); | ||
165 | |||
166 | stream >> i ; | ||
167 | par.setField( i ); | ||
168 | |||
169 | return par; | ||
170 | } | ||
171 | void OPimRecord::setLastHitField( int lastHit )const { | ||
172 | m_lastHit = lastHit; | ||
173 | } | ||
174 | int OPimRecord::lastHitField()const{ | ||
175 | return m_lastHit; | ||
176 | } | ||
177 | QMap<QString, QString> OPimRecord::toExtraMap()const { | ||
178 | return customMap; | ||
179 | } | ||
180 | void OPimRecord::setExtraMap( const QMap<QString, QString>& map) { | ||
181 | customMap = map; | ||
182 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimrecord.h b/noncore/unsupported/libopie/pim/opimrecord.h new file mode 100644 index 0000000..3d774e2 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimrecord.h | |||
@@ -0,0 +1,158 @@ | |||
1 | #ifndef OPIE_PIM_RECORD_H | ||
2 | #define OPIE_PIM_RECORD_H | ||
3 | |||
4 | #include <qdatastream.h> | ||
5 | #include <qmap.h> | ||
6 | #include <qstring.h> | ||
7 | #include <qstringlist.h> | ||
8 | |||
9 | /* | ||
10 | * we need to get customMap which is private... | ||
11 | */ | ||
12 | #define private protected | ||
13 | #include <qpe/palmtoprecord.h> | ||
14 | #undef private | ||
15 | |||
16 | #include <opie/opimxrefmanager.h> | ||
17 | |||
18 | /** | ||
19 | * This is the base class for | ||
20 | * all PIM Records | ||
21 | * | ||
22 | */ | ||
23 | class OPimRecord : public Qtopia::Record { | ||
24 | public: | ||
25 | /** | ||
26 | * c'tor | ||
27 | * uid of 0 isEmpty | ||
28 | * uid of 1 will be assigned a new one | ||
29 | */ | ||
30 | OPimRecord(int uid = 0); | ||
31 | ~OPimRecord(); | ||
32 | |||
33 | /** | ||
34 | * copy c'tor | ||
35 | */ | ||
36 | OPimRecord( const OPimRecord& rec ); | ||
37 | |||
38 | /** | ||
39 | * copy operator | ||
40 | */ | ||
41 | OPimRecord &operator=( const OPimRecord& ); | ||
42 | |||
43 | /** | ||
44 | * category names resolved | ||
45 | */ | ||
46 | QStringList categoryNames( const QString& appname )const; | ||
47 | |||
48 | /** | ||
49 | * set category names they will be resolved | ||
50 | */ | ||
51 | void setCategoryNames( const QStringList& ); | ||
52 | |||
53 | /** | ||
54 | * addCategoryName adds a name | ||
55 | * to the internal category list | ||
56 | */ | ||
57 | void addCategoryName( const QString& ); | ||
58 | |||
59 | /** | ||
60 | * if a Record isEmpty | ||
61 | * it's empty if it's 0 | ||
62 | */ | ||
63 | virtual bool isEmpty()const; | ||
64 | |||
65 | /** | ||
66 | * toRichText summary | ||
67 | */ | ||
68 | virtual QString toRichText()const = 0; | ||
69 | |||
70 | /** | ||
71 | * a small one line summary | ||
72 | */ | ||
73 | virtual QString toShortText()const = 0; | ||
74 | |||
75 | /** | ||
76 | * the name of the Record | ||
77 | */ | ||
78 | virtual QString type()const = 0; | ||
79 | |||
80 | /** | ||
81 | * matches the Records the regular expression? | ||
82 | */ | ||
83 | virtual bool match( const QString ®exp ) const | ||
84 | {setLastHitField( -1 ); | ||
85 | return Qtopia::Record::match(QRegExp(regexp));}; | ||
86 | |||
87 | /** | ||
88 | * if implemented this function returns which item has been | ||
89 | * last hit by the match() function. | ||
90 | * or -1 if not implemented or no hit has occured | ||
91 | */ | ||
92 | int lastHitField()const; | ||
93 | |||
94 | /** | ||
95 | * converts the internal structure to a map | ||
96 | */ | ||
97 | virtual QMap<int, QString> toMap()const = 0; | ||
98 | // virtual fromMap( const <int, QString>& map ) = 0; // Should be added in the future (eilers) | ||
99 | |||
100 | /** | ||
101 | * key value representation of extra items | ||
102 | */ | ||
103 | QMap<QString, QString> toExtraMap()const; | ||
104 | void setExtraMap( const QMap<QString, QString>& ); | ||
105 | |||
106 | /** | ||
107 | * the name for a recordField | ||
108 | */ | ||
109 | virtual QString recordField(int)const = 0; | ||
110 | |||
111 | /** | ||
112 | * returns a reference of the | ||
113 | * Cross Reference Manager | ||
114 | * Partner 'One' is THIS PIM RECORD! | ||
115 | * 'Two' is the Partner where we link to | ||
116 | */ | ||
117 | OPimXRefManager& xrefmanager(); | ||
118 | |||
119 | /** | ||
120 | * set the uid | ||
121 | */ | ||
122 | virtual void setUid( int uid ); | ||
123 | |||
124 | /* | ||
125 | * used inside the Templates for casting | ||
126 | * REIMPLEMENT in your .... | ||
127 | */ | ||
128 | static int rtti(); | ||
129 | |||
130 | /** | ||
131 | * some marshalling and de marshalling code | ||
132 | * saves the OPimRecord | ||
133 | * to and from a DataStream | ||
134 | */ | ||
135 | virtual bool loadFromStream(QDataStream& ); | ||
136 | virtual bool saveToStream( QDataStream& stream )const; | ||
137 | |||
138 | protected: | ||
139 | // need to be const cause it is called from const methods | ||
140 | mutable int m_lastHit; | ||
141 | void setLastHitField( int lastHit )const; | ||
142 | Qtopia::UidGen &uidGen(); | ||
143 | // QString crossToString()const; | ||
144 | |||
145 | private: | ||
146 | class OPimRecordPrivate; | ||
147 | OPimRecordPrivate *d; | ||
148 | OPimXRefManager m_xrefman; | ||
149 | static Qtopia::UidGen m_uidGen; | ||
150 | |||
151 | private: | ||
152 | void flush( const OPimXRefPartner&, QDataStream& stream )const; | ||
153 | OPimXRefPartner partner( QDataStream& ); | ||
154 | }; | ||
155 | |||
156 | |||
157 | |||
158 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimresolver.cpp b/noncore/unsupported/libopie/pim/opimresolver.cpp new file mode 100644 index 0000000..4ebbd6e --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimresolver.cpp | |||
@@ -0,0 +1,198 @@ | |||
1 | #include <qcopchannel_qws.h> | ||
2 | |||
3 | #include <qpe/qcopenvelope_qws.h> | ||
4 | |||
5 | #include "otodoaccess.h" | ||
6 | #include "ocontactaccess.h" | ||
7 | |||
8 | //#include "opimfactory.h" | ||
9 | #include "opimresolver.h" | ||
10 | |||
11 | OPimResolver* OPimResolver::m_self = 0l; | ||
12 | |||
13 | OPimResolver::OPimResolver() { | ||
14 | /* the built in channels */ | ||
15 | m_builtIns << "Todolist" << "Addressbook" << "Datebook"; | ||
16 | } | ||
17 | OPimResolver* OPimResolver::self() { | ||
18 | if (!m_self) | ||
19 | m_self = new OPimResolver(); | ||
20 | |||
21 | return m_self; | ||
22 | } | ||
23 | |||
24 | /* | ||
25 | * FIXME use a cache here too | ||
26 | */ | ||
27 | OPimRecord* OPimResolver::record( const QString& service, int uid ) { | ||
28 | OPimRecord* rec = 0l; | ||
29 | OPimBase* base = backend( service ); | ||
30 | |||
31 | if ( base ) | ||
32 | rec = base->record( uid ); | ||
33 | delete base; | ||
34 | |||
35 | return rec; | ||
36 | } | ||
37 | OPimRecord* OPimResolver::record( const QString& service ) { | ||
38 | return record( serviceId( service ) ); | ||
39 | } | ||
40 | OPimRecord* OPimResolver::record( int rtti ) { | ||
41 | OPimRecord* rec = 0l; | ||
42 | switch( rtti ) { | ||
43 | case 1: /* todolist */ | ||
44 | rec = new OTodo(); | ||
45 | case 2: /* contact */ | ||
46 | rec = new OContact(); | ||
47 | default: | ||
48 | break; | ||
49 | } | ||
50 | /* | ||
51 | * FIXME resolve externally | ||
52 | */ | ||
53 | if (!rec ) { | ||
54 | ; | ||
55 | } | ||
56 | return 0l; | ||
57 | } | ||
58 | bool OPimResolver::isBuiltIn( const QString& str) const{ | ||
59 | return m_builtIns.contains( str ); | ||
60 | } | ||
61 | QCString OPimResolver::qcopChannel( enum BuiltIn& built)const { | ||
62 | QCString str("QPE/"); | ||
63 | switch( built ) { | ||
64 | case TodoList: | ||
65 | str += "Todolist"; | ||
66 | break; | ||
67 | case DateBook: | ||
68 | str += "Datebook"; | ||
69 | break; | ||
70 | case AddressBook: | ||
71 | str += "Addressbook"; | ||
72 | break; | ||
73 | default: | ||
74 | break; | ||
75 | } | ||
76 | |||
77 | return str; | ||
78 | } | ||
79 | QCString OPimResolver::qcopChannel( const QString& service )const { | ||
80 | QCString str("QPE/"); | ||
81 | str += service.latin1(); | ||
82 | return str; | ||
83 | } | ||
84 | /* | ||
85 | * Implement services!! | ||
86 | * FIXME | ||
87 | */ | ||
88 | QCString OPimResolver::applicationChannel( enum BuiltIn& built)const { | ||
89 | QCString str("QPE/Application/"); | ||
90 | switch( built ) { | ||
91 | case TodoList: | ||
92 | str += "todolist"; | ||
93 | break; | ||
94 | case DateBook: | ||
95 | str += "datebook"; | ||
96 | break; | ||
97 | case AddressBook: | ||
98 | str += "addressbook"; | ||
99 | break; | ||
100 | } | ||
101 | |||
102 | return str; | ||
103 | } | ||
104 | QCString OPimResolver::applicationChannel( const QString& service )const { | ||
105 | QCString str("QPE/Application/"); | ||
106 | |||
107 | if ( isBuiltIn( service ) ) { | ||
108 | if ( service == "Todolist" ) | ||
109 | str += "todolist"; | ||
110 | else if ( service == "Datebook" ) | ||
111 | str += "datebook"; | ||
112 | else if ( service == "Addressbook" ) | ||
113 | str += "addressbook"; | ||
114 | }else | ||
115 | ; // FIXME for additional stuff | ||
116 | |||
117 | return str; | ||
118 | } | ||
119 | QStringList OPimResolver::services()const { | ||
120 | return m_builtIns; | ||
121 | } | ||
122 | QString OPimResolver::serviceName( int rtti ) const{ | ||
123 | QString str; | ||
124 | switch ( rtti ) { | ||
125 | case TodoList: | ||
126 | str = "Todolist"; | ||
127 | break; | ||
128 | case DateBook: | ||
129 | str = "Datebook"; | ||
130 | break; | ||
131 | case AddressBook: | ||
132 | str = "Addressbook"; | ||
133 | break; | ||
134 | default: | ||
135 | break; | ||
136 | } | ||
137 | return str; | ||
138 | // FIXME me for 3rd party | ||
139 | } | ||
140 | int OPimResolver::serviceId( const QString& service ) { | ||
141 | int rtti = 0; | ||
142 | if ( service == "Todolist" ) | ||
143 | rtti = TodoList; | ||
144 | else if ( service == "Datebook" ) | ||
145 | rtti = DateBook; | ||
146 | else if ( service == "Addressbook" ) | ||
147 | rtti = AddressBook; | ||
148 | |||
149 | return rtti; | ||
150 | } | ||
151 | /** | ||
152 | * check if the 'service' is registered and if so we'll | ||
153 | */ | ||
154 | bool OPimResolver::add( const QString& service, const OPimRecord& rec) { | ||
155 | if ( QCopChannel::isRegistered( applicationChannel( service ) ) ) { | ||
156 | QByteArray data; | ||
157 | QDataStream arg(data, IO_WriteOnly ); | ||
158 | if ( rec.saveToStream( arg ) ) { | ||
159 | QCopEnvelope env( applicationChannel( service ), "add(int,QByteArray)" ); | ||
160 | env << rec.rtti(); | ||
161 | env << data; | ||
162 | }else | ||
163 | return false; | ||
164 | }else{ | ||
165 | OPimBase* base = backend( service ); | ||
166 | if (!base ) return false; | ||
167 | |||
168 | base->load(); | ||
169 | base->add( rec ); | ||
170 | base->save(); | ||
171 | delete base; | ||
172 | } | ||
173 | |||
174 | return true; | ||
175 | } | ||
176 | OPimBase* OPimResolver::backend( const QString& service ) { | ||
177 | return backend( serviceId( service ) ); | ||
178 | } | ||
179 | OPimBase* OPimResolver::backend( int rtti ) { | ||
180 | OPimBase* base = 0l; | ||
181 | switch( rtti ) { | ||
182 | case TodoList: | ||
183 | base = new OTodoAccess(); | ||
184 | break; | ||
185 | case DateBook: | ||
186 | break; | ||
187 | case AddressBook: | ||
188 | base = new OContactAccess("Resolver"); | ||
189 | break; | ||
190 | default: | ||
191 | break; | ||
192 | } | ||
193 | // FIXME for 3rd party | ||
194 | if (!base ) | ||
195 | ; | ||
196 | |||
197 | return base; | ||
198 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimresolver.h b/noncore/unsupported/libopie/pim/opimresolver.h new file mode 100644 index 0000000..1ce1619 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimresolver.h | |||
@@ -0,0 +1,90 @@ | |||
1 | #ifndef OPIE_PIM_RESOLVER | ||
2 | #define OPIE_PIM_RESOLVER | ||
3 | |||
4 | #include <qstring.h> | ||
5 | #include <qvaluelist.h> | ||
6 | |||
7 | #include <opie/otemplatebase.h> | ||
8 | |||
9 | /** | ||
10 | * OPimResolver is a MetaClass to access | ||
11 | * available backends read only. | ||
12 | * It will be used to resolve uids + app names | ||
13 | * to full informations | ||
14 | * to traverse through a list of alarms, reminders | ||
15 | * to get access to built in PIM functionality | ||
16 | * and to more stuff | ||
17 | * THE PERFORMANCE will depend on THE BACKEND | ||
18 | * USING XML is a waste of memory!!!!! | ||
19 | */ | ||
20 | class OPimResolver { | ||
21 | public: | ||
22 | enum BuiltIn { TodoList = 0, | ||
23 | DateBook, | ||
24 | AddressBook | ||
25 | }; | ||
26 | static OPimResolver* self(); | ||
27 | |||
28 | |||
29 | /** | ||
30 | * return a record for a uid | ||
31 | * and an service | ||
32 | * You've THE OWNERSHIP NOW! | ||
33 | */ | ||
34 | OPimRecord *record( const QString& service, int uid ); | ||
35 | |||
36 | /** | ||
37 | * return the QCopChannel for service | ||
38 | * When we will use Qtopia Services it will be used here | ||
39 | */ | ||
40 | QCString qcopChannel( enum BuiltIn& )const; | ||
41 | QCString qcopChannel( const QString& service )const; | ||
42 | |||
43 | /** | ||
44 | * The Application channel (QPE/Application/name) | ||
45 | */ | ||
46 | QCString applicationChannel( enum BuiltIn& )const; | ||
47 | QCString applicationChannel( const QString& service )const; | ||
48 | |||
49 | /** | ||
50 | * return a list of available services | ||
51 | */ | ||
52 | QStringList services()const; | ||
53 | inline QString serviceName(int rrti )const; | ||
54 | int serviceId( const QString& Service); | ||
55 | /** | ||
56 | * add a record to a service... ;) | ||
57 | */ | ||
58 | bool add( const QString& service, const OPimRecord& ); | ||
59 | |||
60 | |||
61 | /** | ||
62 | * record returns an empty record for a given service. | ||
63 | * Be sure to delete it!!! | ||
64 | * | ||
65 | */ | ||
66 | OPimRecord* record( const QString& service ); | ||
67 | OPimRecord* record( int rtti ); | ||
68 | |||
69 | /** | ||
70 | * you can cast to your | ||
71 | */ | ||
72 | OPimBase* backend( const QString& service ); | ||
73 | OPimBase* backend( int rtti ); | ||
74 | private: | ||
75 | OPimResolver(); | ||
76 | void loadData(); | ||
77 | inline bool isBuiltIn( const QString& )const; | ||
78 | OPimRecord* recordExtern( const QString&, int ); | ||
79 | OPimRecord* recordExtern( const QString& ); | ||
80 | |||
81 | static OPimResolver* m_self; | ||
82 | struct Data; | ||
83 | class Private; | ||
84 | |||
85 | Data* data; | ||
86 | Private* d; | ||
87 | QStringList m_builtIns; | ||
88 | }; | ||
89 | |||
90 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimstate.cpp b/noncore/unsupported/libopie/pim/opimstate.cpp new file mode 100644 index 0000000..6fb2feb --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimstate.cpp | |||
@@ -0,0 +1,64 @@ | |||
1 | #include <qshared.h> | ||
2 | |||
3 | #include "opimstate.h" | ||
4 | |||
5 | /* | ||
6 | * for one int this does not make | ||
7 | * much sense but never the less | ||
8 | * we will do it for the future | ||
9 | */ | ||
10 | struct OPimState::Data : public QShared { | ||
11 | Data() : QShared(),state(Undefined) { | ||
12 | } | ||
13 | int state; | ||
14 | }; | ||
15 | |||
16 | OPimState::OPimState( int state ) { | ||
17 | data = new Data; | ||
18 | data->state = state; | ||
19 | } | ||
20 | OPimState::OPimState( const OPimState& st) : | ||
21 | data( st.data ) { | ||
22 | /* ref up */ | ||
23 | data->ref(); | ||
24 | } | ||
25 | OPimState::~OPimState() { | ||
26 | if ( data->deref() ) { | ||
27 | delete data ; | ||
28 | data = 0; | ||
29 | } | ||
30 | } | ||
31 | bool OPimState::operator==( const OPimState& st) { | ||
32 | if ( data->state == st.data->state ) return true; | ||
33 | |||
34 | return false; | ||
35 | } | ||
36 | OPimState &OPimState::operator=( const OPimState& st) { | ||
37 | st.data->ref(); | ||
38 | deref(); | ||
39 | data = st.data; | ||
40 | |||
41 | return *this; | ||
42 | } | ||
43 | void OPimState::setState( int st) { | ||
44 | copyInternally(); | ||
45 | data->state = st; | ||
46 | } | ||
47 | int OPimState::state()const { | ||
48 | return data->state; | ||
49 | } | ||
50 | void OPimState::deref() { | ||
51 | if ( data->deref() ) { | ||
52 | delete data; | ||
53 | data = 0l; | ||
54 | } | ||
55 | } | ||
56 | void OPimState::copyInternally() { | ||
57 | /* we need to change it */ | ||
58 | if ( data->count != 1 ) { | ||
59 | data->deref(); | ||
60 | Data* d2 = new Data; | ||
61 | d2->state = data->state; | ||
62 | data = d2; | ||
63 | } | ||
64 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimstate.h b/noncore/unsupported/libopie/pim/opimstate.h new file mode 100644 index 0000000..cf6af46 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimstate.h | |||
@@ -0,0 +1,46 @@ | |||
1 | #ifndef OPIE_PIM_STATE_H | ||
2 | #define OPIE_PIM_STATE_H | ||
3 | |||
4 | #include <qstring.h> | ||
5 | |||
6 | /** | ||
7 | * The State of a Task | ||
8 | * This class encapsules the state of a todo | ||
9 | * and it's shared too | ||
10 | */ | ||
11 | /* | ||
12 | * in c a simple struct would be enough ;) | ||
13 | * g_new_state(); | ||
14 | * g_do_some_thing( state_t* ); | ||
15 | * ;) | ||
16 | */ | ||
17 | class OPimState { | ||
18 | public: | ||
19 | enum State { | ||
20 | Started = 0, | ||
21 | Postponed, | ||
22 | Finished, | ||
23 | NotStarted, | ||
24 | Undefined | ||
25 | }; | ||
26 | OPimState( int state = Undefined ); | ||
27 | OPimState( const OPimState& ); | ||
28 | ~OPimState(); | ||
29 | |||
30 | bool operator==( const OPimState& ); | ||
31 | OPimState &operator=( const OPimState& ); | ||
32 | void setState( int state); | ||
33 | int state()const; | ||
34 | private: | ||
35 | void deref(); | ||
36 | inline void copyInternally(); | ||
37 | |||
38 | struct Data; | ||
39 | Data* data; | ||
40 | |||
41 | class Private; | ||
42 | Private *d; | ||
43 | }; | ||
44 | |||
45 | |||
46 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimxref.cpp b/noncore/unsupported/libopie/pim/opimxref.cpp new file mode 100644 index 0000000..8eefbd8 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxref.cpp | |||
@@ -0,0 +1,47 @@ | |||
1 | #include "opimxref.h" | ||
2 | |||
3 | OPimXRef::OPimXRef( const OPimXRefPartner& one, const OPimXRefPartner& two ) | ||
4 | : m_partners(2) | ||
5 | { | ||
6 | m_partners[0] = one; | ||
7 | m_partners[1] = two; | ||
8 | } | ||
9 | OPimXRef::OPimXRef() | ||
10 | : m_partners(2) | ||
11 | { | ||
12 | |||
13 | } | ||
14 | OPimXRef::OPimXRef( const OPimXRef& ref) { | ||
15 | *this = ref; | ||
16 | } | ||
17 | OPimXRef::~OPimXRef() { | ||
18 | } | ||
19 | OPimXRef &OPimXRef::operator=( const OPimXRef& ref) { | ||
20 | m_partners = ref.m_partners; | ||
21 | m_partners.detach(); | ||
22 | |||
23 | return* this; | ||
24 | } | ||
25 | bool OPimXRef::operator==( const OPimXRef& oper ) { | ||
26 | if ( m_partners == oper.m_partners ) return true; | ||
27 | |||
28 | return false; | ||
29 | } | ||
30 | OPimXRefPartner OPimXRef::partner( enum Partners par) const{ | ||
31 | return m_partners[par]; | ||
32 | } | ||
33 | void OPimXRef::setPartner( enum Partners par, const OPimXRefPartner& part) { | ||
34 | m_partners[par] = part; | ||
35 | } | ||
36 | bool OPimXRef::containsString( const QString& string ) const{ | ||
37 | if ( m_partners[One].service() == string || | ||
38 | m_partners[Two].service() == string ) return true; | ||
39 | |||
40 | return false; | ||
41 | } | ||
42 | bool OPimXRef::containsUid( int uid ) const{ | ||
43 | if ( m_partners[One].uid() == uid || | ||
44 | m_partners[Two].uid() == uid ) return true; | ||
45 | |||
46 | return false; | ||
47 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimxref.h b/noncore/unsupported/libopie/pim/opimxref.h new file mode 100644 index 0000000..6852651 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxref.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef OPIM_XREF_H | ||
2 | #define OPIM_XREF_H | ||
3 | |||
4 | #include <qarray.h> | ||
5 | #include <qvaluelist.h> | ||
6 | |||
7 | #include <opie/opimxrefpartner.h> | ||
8 | |||
9 | /** | ||
10 | * this is a Cross Referecne between | ||
11 | * two Cross Reference Partners | ||
12 | */ | ||
13 | class OPimXRef { | ||
14 | public: | ||
15 | typedef QValueList<OPimXRef> ValueList; | ||
16 | enum Partners { One, Two }; | ||
17 | OPimXRef( const OPimXRefPartner& ONE, const OPimXRefPartner& ); | ||
18 | OPimXRef(); | ||
19 | OPimXRef( const OPimXRef& ); | ||
20 | ~OPimXRef(); | ||
21 | |||
22 | OPimXRef &operator=( const OPimXRef& ); | ||
23 | bool operator==( const OPimXRef& ); | ||
24 | |||
25 | OPimXRefPartner partner( enum Partners )const; | ||
26 | |||
27 | void setPartner( enum Partners, const OPimXRefPartner& ); | ||
28 | |||
29 | bool containsString( const QString& service)const; | ||
30 | bool containsUid( int uid )const; | ||
31 | |||
32 | private: | ||
33 | QArray<OPimXRefPartner> m_partners; | ||
34 | |||
35 | class Private; | ||
36 | Private *d; | ||
37 | }; | ||
38 | |||
39 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimxrefmanager.cpp b/noncore/unsupported/libopie/pim/opimxrefmanager.cpp new file mode 100644 index 0000000..58bfd24 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefmanager.cpp | |||
@@ -0,0 +1,71 @@ | |||
1 | #include "opimxrefmanager.h" | ||
2 | |||
3 | |||
4 | OPimXRefManager::OPimXRefManager() { | ||
5 | } | ||
6 | OPimXRefManager::OPimXRefManager( const OPimXRefManager& ref) { | ||
7 | m_list = ref.m_list; | ||
8 | } | ||
9 | OPimXRefManager::~OPimXRefManager() { | ||
10 | } | ||
11 | OPimXRefManager &OPimXRefManager::operator=( const OPimXRefManager& ref) { | ||
12 | m_list = ref.m_list; | ||
13 | return *this; | ||
14 | } | ||
15 | bool OPimXRefManager::operator==( const OPimXRefManager& /*ref*/) { | ||
16 | // if ( m_list == ref.m_list ) return true; | ||
17 | |||
18 | return false; | ||
19 | } | ||
20 | void OPimXRefManager::add( const OPimXRef& ref) { | ||
21 | m_list.append( ref ); | ||
22 | } | ||
23 | void OPimXRefManager::remove( const OPimXRef& ref) { | ||
24 | m_list.remove( ref ); | ||
25 | } | ||
26 | void OPimXRefManager::replace( const OPimXRef& ref) { | ||
27 | m_list.remove( ref ); | ||
28 | m_list.append( ref ); | ||
29 | } | ||
30 | void OPimXRefManager::clear() { | ||
31 | m_list.clear(); | ||
32 | } | ||
33 | QStringList OPimXRefManager::apps()const { | ||
34 | OPimXRef::ValueList::ConstIterator it; | ||
35 | QStringList list; | ||
36 | |||
37 | QString str; | ||
38 | for ( it = m_list.begin(); it != m_list.end(); ++it ) { | ||
39 | str = (*it).partner( OPimXRef::One ).service(); | ||
40 | if ( !list.contains( str ) ) list << str; | ||
41 | |||
42 | str = (*it).partner( OPimXRef::Two ).service(); | ||
43 | if ( !list.contains( str ) ) list << str; | ||
44 | } | ||
45 | return list; | ||
46 | } | ||
47 | OPimXRef::ValueList OPimXRefManager::list()const { | ||
48 | return m_list; | ||
49 | } | ||
50 | OPimXRef::ValueList OPimXRefManager::list( const QString& appName )const{ | ||
51 | OPimXRef::ValueList list; | ||
52 | OPimXRef::ValueList::ConstIterator it; | ||
53 | |||
54 | for ( it = m_list.begin(); it != m_list.end(); ++it ) { | ||
55 | if ( (*it).containsString( appName ) ) | ||
56 | list.append( (*it) ); | ||
57 | } | ||
58 | |||
59 | return list; | ||
60 | } | ||
61 | OPimXRef::ValueList OPimXRefManager::list( int uid )const { | ||
62 | OPimXRef::ValueList list; | ||
63 | OPimXRef::ValueList::ConstIterator it; | ||
64 | |||
65 | for ( it = m_list.begin(); it != m_list.end(); ++it ) { | ||
66 | if ( (*it).containsUid( uid ) ) | ||
67 | list.append( (*it) ); | ||
68 | } | ||
69 | |||
70 | return list; | ||
71 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimxrefmanager.h b/noncore/unsupported/libopie/pim/opimxrefmanager.h new file mode 100644 index 0000000..c485e98 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefmanager.h | |||
@@ -0,0 +1,43 @@ | |||
1 | #ifndef OPIM_XREF_MANAGER_H | ||
2 | #define OPIM_XREF_MANAGER_H | ||
3 | |||
4 | #include <qstringlist.h> | ||
5 | |||
6 | #include <opie/opimxref.h> | ||
7 | |||
8 | /** | ||
9 | * This is a simple manager for | ||
10 | * OPimXRefs. | ||
11 | * It allows addition, removing, replacing | ||
12 | * clearing and 'querying' the XRef... | ||
13 | */ | ||
14 | class OPimXRefManager { | ||
15 | public: | ||
16 | OPimXRefManager(); | ||
17 | OPimXRefManager( const OPimXRefManager& ); | ||
18 | ~OPimXRefManager(); | ||
19 | |||
20 | OPimXRefManager& operator=( const OPimXRefManager& ); | ||
21 | bool operator==( const OPimXRefManager& ); | ||
22 | |||
23 | void add( const OPimXRef& ); | ||
24 | void remove( const OPimXRef& ); | ||
25 | void replace( const OPimXRef& ); | ||
26 | |||
27 | void clear(); | ||
28 | |||
29 | /** | ||
30 | * apps participating | ||
31 | */ | ||
32 | QStringList apps()const; | ||
33 | OPimXRef::ValueList list()const; | ||
34 | OPimXRef::ValueList list( const QString& service )const; | ||
35 | OPimXRef::ValueList list( int uid )const; | ||
36 | |||
37 | private: | ||
38 | OPimXRef::ValueList m_list; | ||
39 | class Private; | ||
40 | Private *d; | ||
41 | }; | ||
42 | |||
43 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/opimxrefpartner.cpp b/noncore/unsupported/libopie/pim/opimxrefpartner.cpp new file mode 100644 index 0000000..6ef3efb --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefpartner.cpp | |||
@@ -0,0 +1,43 @@ | |||
1 | #include "opimxrefpartner.h" | ||
2 | |||
3 | OPimXRefPartner::OPimXRefPartner( const QString& appName, | ||
4 | int uid, int field ) | ||
5 | : m_app(appName), m_uid(uid), m_field( field ) { | ||
6 | } | ||
7 | OPimXRefPartner::OPimXRefPartner( const OPimXRefPartner& ref ) { | ||
8 | *this = ref; | ||
9 | } | ||
10 | OPimXRefPartner::~OPimXRefPartner() { | ||
11 | } | ||
12 | OPimXRefPartner &OPimXRefPartner::operator=( const OPimXRefPartner& par ) { | ||
13 | m_app = par.m_app; | ||
14 | m_uid = par.m_uid; | ||
15 | m_field = par.m_field; | ||
16 | |||
17 | return *this; | ||
18 | } | ||
19 | bool OPimXRefPartner::operator==( const OPimXRefPartner& par ) { | ||
20 | if ( m_app != par.m_app ) return false; | ||
21 | if ( m_uid != par.m_uid ) return false; | ||
22 | if ( m_field != par.m_field ) return false; | ||
23 | |||
24 | return true; | ||
25 | } | ||
26 | QString OPimXRefPartner::service()const { | ||
27 | return m_app; | ||
28 | } | ||
29 | int OPimXRefPartner::uid()const { | ||
30 | return m_uid; | ||
31 | } | ||
32 | int OPimXRefPartner::field()const { | ||
33 | return m_field; | ||
34 | } | ||
35 | void OPimXRefPartner::setService( const QString& appName ) { | ||
36 | m_app = appName; | ||
37 | } | ||
38 | void OPimXRefPartner::setUid( int uid ) { | ||
39 | m_uid = uid; | ||
40 | } | ||
41 | void OPimXRefPartner::setField( int field ) { | ||
42 | m_field = field; | ||
43 | } | ||
diff --git a/noncore/unsupported/libopie/pim/opimxrefpartner.h b/noncore/unsupported/libopie/pim/opimxrefpartner.h new file mode 100644 index 0000000..d76e384 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/opimxrefpartner.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifndef OPIM_XREF_PARTNER_H | ||
2 | #define OPIM_XREF_PARTNER_H | ||
3 | |||
4 | #include <qstring.h> | ||
5 | |||
6 | /** | ||
7 | * This class represents one partner | ||
8 | * of a Cross Reference. | ||
9 | * In Opie one application | ||
10 | * can link one uid | ||
11 | * with one tableId( fieldId ) to another. | ||
12 | */ | ||
13 | class OPimXRefPartner { | ||
14 | public: | ||
15 | OPimXRefPartner( const QString& service = QString::null, | ||
16 | int uid = 0, int field = -1 ); | ||
17 | OPimXRefPartner( const OPimXRefPartner& ); | ||
18 | OPimXRefPartner& operator=( const OPimXRefPartner& ); | ||
19 | ~OPimXRefPartner(); | ||
20 | |||
21 | bool operator==(const OPimXRefPartner& ); | ||
22 | |||
23 | QString service()const; | ||
24 | int uid()const; | ||
25 | int field()const; | ||
26 | |||
27 | void setService( const QString& service ); | ||
28 | void setUid( int uid ); | ||
29 | void setField( int field ); | ||
30 | private: | ||
31 | QString m_app; | ||
32 | int m_uid; | ||
33 | int m_field; | ||
34 | |||
35 | class Private; | ||
36 | Private* d; | ||
37 | }; | ||
38 | |||
39 | |||
40 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/orecordlist.h b/noncore/unsupported/libopie/pim/orecordlist.h new file mode 100644 index 0000000..5211f57 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/orecordlist.h | |||
@@ -0,0 +1,306 @@ | |||
1 | |||
2 | #ifndef OPIE_RECORD_LIST_H | ||
3 | #define OPIE_RECORD_LIST_H | ||
4 | |||
5 | #include <qarray.h> | ||
6 | |||
7 | #include "otemplatebase.h" | ||
8 | #include "opimrecord.h" | ||
9 | |||
10 | class ORecordListIteratorPrivate; | ||
11 | /** | ||
12 | * Our List Iterator | ||
13 | * it behaves like STL or Qt | ||
14 | * | ||
15 | * for(it = list.begin(); it != list.end(); ++it ) | ||
16 | * doSomeCoolStuff( (*it) ); | ||
17 | */ | ||
18 | template <class T> class ORecordList; | ||
19 | template <class T = OPimRecord> | ||
20 | class ORecordListIterator { | ||
21 | friend class ORecordList<T>; | ||
22 | public: | ||
23 | typedef OTemplateBase<T> Base; | ||
24 | |||
25 | /** | ||
26 | * The c'tor used internally from | ||
27 | * ORecordList | ||
28 | */ | ||
29 | ORecordListIterator( const QArray<int>, const Base* ); | ||
30 | |||
31 | /** | ||
32 | * The standard c'tor | ||
33 | */ | ||
34 | ORecordListIterator(); | ||
35 | ~ORecordListIterator(); | ||
36 | |||
37 | ORecordListIterator( const ORecordListIterator& ); | ||
38 | ORecordListIterator &operator=(const ORecordListIterator& ); | ||
39 | |||
40 | /** | ||
41 | * a * operator ;) | ||
42 | * use it like this T = (*it); | ||
43 | */ | ||
44 | T operator*(); | ||
45 | ORecordListIterator &operator++(); | ||
46 | ORecordListIterator &operator--(); | ||
47 | |||
48 | bool operator==( const ORecordListIterator& it ); | ||
49 | bool operator!=( const ORecordListIterator& it ); | ||
50 | |||
51 | /** | ||
52 | * the current item | ||
53 | */ | ||
54 | uint current()const; | ||
55 | |||
56 | /** | ||
57 | * the number of items | ||
58 | */ | ||
59 | uint count()const; | ||
60 | |||
61 | /** | ||
62 | * sets the current item | ||
63 | */ | ||
64 | void setCurrent( uint cur ); | ||
65 | |||
66 | private: | ||
67 | QArray<int> m_uids; | ||
68 | uint m_current; | ||
69 | const Base* m_temp; | ||
70 | bool m_end : 1; | ||
71 | T m_record; | ||
72 | bool m_direction :1; | ||
73 | |||
74 | /* d pointer for future versions */ | ||
75 | ORecordListIteratorPrivate *d; | ||
76 | }; | ||
77 | |||
78 | class ORecordListPrivate; | ||
79 | /** | ||
80 | * The recordlist used as a return type | ||
81 | * from OPimAccessTemplate | ||
82 | */ | ||
83 | template <class T = OPimRecord > | ||
84 | class ORecordList { | ||
85 | public: | ||
86 | typedef OTemplateBase<T> Base; | ||
87 | typedef ORecordListIterator<T> Iterator; | ||
88 | |||
89 | /** | ||
90 | * c'tor | ||
91 | */ | ||
92 | ORecordList () { | ||
93 | } | ||
94 | ORecordList( const QArray<int>& ids, | ||
95 | const Base* ); | ||
96 | ~ORecordList(); | ||
97 | |||
98 | /** | ||
99 | * the first iterator | ||
100 | */ | ||
101 | Iterator begin(); | ||
102 | |||
103 | /** | ||
104 | * the end | ||
105 | */ | ||
106 | Iterator end(); | ||
107 | |||
108 | /** | ||
109 | * the number of items in the list | ||
110 | */ | ||
111 | uint count()const; | ||
112 | |||
113 | T operator[]( uint i ); | ||
114 | int uidAt(uint i ); | ||
115 | |||
116 | /** | ||
117 | * Remove the contact with given uid | ||
118 | */ | ||
119 | bool remove( int uid ); | ||
120 | |||
121 | /* | ||
122 | ConstIterator begin()const; | ||
123 | ConstIterator end()const; | ||
124 | */ | ||
125 | private: | ||
126 | QArray<int> m_ids; | ||
127 | const Base* m_acc; | ||
128 | ORecordListPrivate *d; | ||
129 | }; | ||
130 | |||
131 | /* ok now implement it */ | ||
132 | template <class T> | ||
133 | ORecordListIterator<T>::ORecordListIterator() { | ||
134 | m_current = 0; | ||
135 | m_temp = 0l; | ||
136 | m_end = true; | ||
137 | m_record = T(); | ||
138 | /* forward */ | ||
139 | m_direction = TRUE; | ||
140 | } | ||
141 | template <class T> | ||
142 | ORecordListIterator<T>::~ORecordListIterator() { | ||
143 | /* nothing to delete */ | ||
144 | } | ||
145 | |||
146 | template <class T> | ||
147 | ORecordListIterator<T>::ORecordListIterator( const ORecordListIterator<T>& it) { | ||
148 | // qWarning("ORecordListIterator copy c'tor"); | ||
149 | m_uids = it.m_uids; | ||
150 | m_current = it.m_current; | ||
151 | m_temp = it.m_temp; | ||
152 | m_end = it.m_end; | ||
153 | m_record = it.m_record; | ||
154 | m_direction = it.m_direction; | ||
155 | } | ||
156 | |||
157 | template <class T> | ||
158 | ORecordListIterator<T> &ORecordListIterator<T>::operator=( const ORecordListIterator<T>& it) { | ||
159 | m_uids = it.m_uids; | ||
160 | m_current = it.m_current; | ||
161 | m_temp = it.m_temp; | ||
162 | m_end = it.m_end; | ||
163 | m_record = it.m_record; | ||
164 | |||
165 | return *this; | ||
166 | } | ||
167 | |||
168 | template <class T> | ||
169 | T ORecordListIterator<T>::operator*() { | ||
170 | //qWarning("operator* %d %d", m_current, m_uids[m_current] ); | ||
171 | if (!m_end ) | ||
172 | m_record = m_temp->find( m_uids[m_current], m_uids, m_current, | ||
173 | m_direction ? Base::Forward : | ||
174 | Base::Reverse ); | ||
175 | else | ||
176 | m_record = T(); | ||
177 | |||
178 | return m_record; | ||
179 | } | ||
180 | |||
181 | template <class T> | ||
182 | ORecordListIterator<T> &ORecordListIterator<T>::operator++() { | ||
183 | m_direction = true; | ||
184 | if (m_current < m_uids.count() ) { | ||
185 | m_end = false; | ||
186 | ++m_current; | ||
187 | }else | ||
188 | m_end = true; | ||
189 | |||
190 | return *this; | ||
191 | } | ||
192 | template <class T> | ||
193 | ORecordListIterator<T> &ORecordListIterator<T>::operator--() { | ||
194 | m_direction = false; | ||
195 | if ( m_current > 0 ) { | ||
196 | --m_current; | ||
197 | m_end = false; | ||
198 | } else | ||
199 | m_end = true; | ||
200 | |||
201 | return *this; | ||
202 | } | ||
203 | |||
204 | template <class T> | ||
205 | bool ORecordListIterator<T>::operator==( const ORecordListIterator<T>& it ) { | ||
206 | |||
207 | /* if both are at we're the same.... */ | ||
208 | if ( m_end == it.m_end ) return true; | ||
209 | |||
210 | if ( m_uids != it.m_uids ) return false; | ||
211 | if ( m_current != it.m_current ) return false; | ||
212 | if ( m_temp != it.m_temp ) return false; | ||
213 | |||
214 | return true; | ||
215 | } | ||
216 | template <class T> | ||
217 | bool ORecordListIterator<T>::operator!=( const ORecordListIterator<T>& it ) { | ||
218 | return !(*this == it ); | ||
219 | } | ||
220 | template <class T> | ||
221 | ORecordListIterator<T>::ORecordListIterator( const QArray<int> uids, | ||
222 | const Base* t ) | ||
223 | : m_uids( uids ), m_current( 0 ), m_temp( t ), m_end( false ), | ||
224 | m_direction( false ) | ||
225 | { | ||
226 | /* if the list is empty we're already at the end of the list */ | ||
227 | if (uids.count() == 0 ) | ||
228 | m_end = true; | ||
229 | } | ||
230 | template <class T> | ||
231 | uint ORecordListIterator<T>::current()const { | ||
232 | return m_current; | ||
233 | } | ||
234 | template <class T> | ||
235 | void ORecordListIterator<T>::setCurrent( uint cur ) { | ||
236 | if( cur < m_uids.count() ) { | ||
237 | m_end = false; | ||
238 | m_current= cur; | ||
239 | } | ||
240 | } | ||
241 | template <class T> | ||
242 | uint ORecordListIterator<T>::count()const { | ||
243 | return m_uids.count(); | ||
244 | } | ||
245 | template <class T> | ||
246 | ORecordList<T>::ORecordList( const QArray<int>& ids, | ||
247 | const Base* acc ) | ||
248 | : m_ids( ids ), m_acc( acc ) | ||
249 | { | ||
250 | } | ||
251 | template <class T> | ||
252 | ORecordList<T>::~ORecordList() { | ||
253 | /* nothing to do here */ | ||
254 | } | ||
255 | template <class T> | ||
256 | typename ORecordList<T>::Iterator ORecordList<T>::begin() { | ||
257 | Iterator it( m_ids, m_acc ); | ||
258 | return it; | ||
259 | } | ||
260 | template <class T> | ||
261 | typename ORecordList<T>::Iterator ORecordList<T>::end() { | ||
262 | Iterator it( m_ids, m_acc ); | ||
263 | it.m_end = true; | ||
264 | it.m_current = m_ids.count(); | ||
265 | |||
266 | return it; | ||
267 | } | ||
268 | template <class T> | ||
269 | uint ORecordList<T>::count()const { | ||
270 | return m_ids.count(); | ||
271 | } | ||
272 | template <class T> | ||
273 | T ORecordList<T>::operator[]( uint i ) { | ||
274 | if ( i >= m_ids.count() ) | ||
275 | return T(); | ||
276 | /* forward */ | ||
277 | return m_acc->find( m_ids[i], m_ids, i ); | ||
278 | } | ||
279 | template <class T> | ||
280 | int ORecordList<T>::uidAt( uint i ) { | ||
281 | return m_ids[i]; | ||
282 | } | ||
283 | |||
284 | template <class T> | ||
285 | bool ORecordList<T>::remove( int uid ) { | ||
286 | QArray<int> copy( m_ids.count() ); | ||
287 | int counter = 0; | ||
288 | bool ret_val = false; | ||
289 | |||
290 | for (uint i = 0; i < m_ids.count(); i++){ | ||
291 | if ( m_ids[i] != uid ){ | ||
292 | copy[counter++] = m_ids[i]; | ||
293 | |||
294 | }else | ||
295 | ret_val = true; | ||
296 | } | ||
297 | |||
298 | copy.resize( counter ); | ||
299 | m_ids = copy; | ||
300 | |||
301 | |||
302 | return ret_val; | ||
303 | } | ||
304 | |||
305 | |||
306 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/orecur.cpp b/noncore/unsupported/libopie/pim/orecur.cpp new file mode 100644 index 0000000..f46f22e --- a/dev/null +++ b/noncore/unsupported/libopie/pim/orecur.cpp | |||
@@ -0,0 +1,593 @@ | |||
1 | #include <time.h> | ||
2 | |||
3 | #include <qshared.h> | ||
4 | |||
5 | #include <qtopia/timeconversion.h> | ||
6 | |||
7 | #include "otimezone.h" | ||
8 | #include "orecur.h" | ||
9 | |||
10 | struct ORecur::Data : public QShared { | ||
11 | Data() : QShared() { | ||
12 | type = ORecur::NoRepeat; | ||
13 | freq = -1; | ||
14 | days = 0; | ||
15 | pos = 0; | ||
16 | create = QDateTime::currentDateTime(); | ||
17 | hasEnd = FALSE; | ||
18 | end = QDate::currentDate(); | ||
19 | } | ||
20 | char days; // Q_UINT8 for 8 seven days;) | ||
21 | ORecur::RepeatType type; | ||
22 | int freq; | ||
23 | int pos; | ||
24 | bool hasEnd : 1; | ||
25 | QDate end; | ||
26 | QDateTime create; | ||
27 | int rep; | ||
28 | QString app; | ||
29 | ExceptionList list; | ||
30 | QDate start; | ||
31 | }; | ||
32 | |||
33 | |||
34 | ORecur::ORecur() { | ||
35 | data = new Data; | ||
36 | } | ||
37 | |||
38 | ORecur::ORecur( const QMap<int, QString>& map ) | ||
39 | { | ||
40 | ORecur(); | ||
41 | fromMap( map ); | ||
42 | } | ||
43 | |||
44 | |||
45 | ORecur::ORecur( const ORecur& rec) | ||
46 | : data( rec.data ) | ||
47 | { | ||
48 | data->ref(); | ||
49 | } | ||
50 | ORecur::~ORecur() { | ||
51 | if ( data->deref() ) { | ||
52 | delete data; | ||
53 | data = 0l; | ||
54 | } | ||
55 | } | ||
56 | void ORecur::deref() { | ||
57 | if ( data->deref() ) { | ||
58 | delete data; | ||
59 | data = 0l; | ||
60 | } | ||
61 | } | ||
62 | bool ORecur::operator==( const ORecur& )const { | ||
63 | return false; | ||
64 | } | ||
65 | ORecur &ORecur::operator=( const ORecur& re) { | ||
66 | if ( *this == re ) return *this; | ||
67 | |||
68 | re.data->ref(); | ||
69 | deref(); | ||
70 | data = re.data; | ||
71 | |||
72 | return *this; | ||
73 | } | ||
74 | bool ORecur::doesRecur()const { | ||
75 | return !( type() == NoRepeat ); | ||
76 | } | ||
77 | /* | ||
78 | * we try to be smart here | ||
79 | * | ||
80 | */ | ||
81 | bool ORecur::doesRecur( const QDate& date ) { | ||
82 | /* the day before the recurrance */ | ||
83 | QDate da = date.addDays(-1); | ||
84 | |||
85 | QDate recur; | ||
86 | if (!nextOcurrence( da, recur ) ) | ||
87 | return false; | ||
88 | |||
89 | return (recur == date); | ||
90 | } | ||
91 | // FIXME unuglify! | ||
92 | // GPL from Datebookdb.cpp | ||
93 | // FIXME exception list! | ||
94 | bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { | ||
95 | bool stillLooking; | ||
96 | stillLooking = p_nextOccurrence( from, next ); | ||
97 | while ( stillLooking && data->list.contains(next) ) | ||
98 | stillLooking = p_nextOccurrence( next.addDays(1), next ); | ||
99 | |||
100 | return stillLooking; | ||
101 | } | ||
102 | bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) { | ||
103 | |||
104 | // easy checks, first are we too far in the future or too far in the past? | ||
105 | QDate tmpDate; | ||
106 | int freq = frequency(); | ||
107 | int diff, diff2, a; | ||
108 | int iday, imonth, iyear; | ||
109 | int dayOfWeek = 0; | ||
110 | int firstOfWeek = 0; | ||
111 | int weekOfMonth; | ||
112 | |||
113 | |||
114 | if (hasEndDate() && endDate() < from) | ||
115 | return FALSE; | ||
116 | |||
117 | if (start() >= from ) { | ||
118 | next = start(); | ||
119 | return TRUE; | ||
120 | } | ||
121 | |||
122 | switch ( type() ) { | ||
123 | case Weekly: | ||
124 | /* weekly is just daily by 7 */ | ||
125 | /* first convert the repeatPattern.Days() mask to the next | ||
126 | day of week valid after from */ | ||
127 | dayOfWeek = from.dayOfWeek(); | ||
128 | dayOfWeek--; /* we want 0-6, doco for above specs 1-7 */ | ||
129 | |||
130 | /* this is done in case freq > 1 and from in week not | ||
131 | for this round */ | ||
132 | // firstOfWeek = 0; this is already done at decl. | ||
133 | while(!((1 << firstOfWeek) & days() )) | ||
134 | firstOfWeek++; | ||
135 | |||
136 | /* there is at least one 'day', or there would be no event */ | ||
137 | while(!((1 << (dayOfWeek % 7)) & days() )) | ||
138 | dayOfWeek++; | ||
139 | |||
140 | dayOfWeek = dayOfWeek % 7; /* the actual day of week */ | ||
141 | dayOfWeek -= start().dayOfWeek() -1; | ||
142 | |||
143 | firstOfWeek = firstOfWeek % 7; /* the actual first of week */ | ||
144 | firstOfWeek -= start().dayOfWeek() -1; | ||
145 | |||
146 | // dayOfWeek may be negitive now | ||
147 | // day of week is number of days to add to start day | ||
148 | |||
149 | freq *= 7; | ||
150 | // FALL-THROUGH !!!!! | ||
151 | case Daily: | ||
152 | // the add is for the possible fall through from weekly */ | ||
153 | if(start().addDays(dayOfWeek) > from) { | ||
154 | /* first week exception */ | ||
155 | next = QDate(start().addDays(dayOfWeek) ); | ||
156 | if ((next > endDate()) | ||
157 | && hasEndDate() ) | ||
158 | return FALSE; | ||
159 | return TRUE; | ||
160 | } | ||
161 | /* if from is middle of a non-week */ | ||
162 | |||
163 | diff = start().addDays(dayOfWeek).daysTo(from) % freq; | ||
164 | diff2 = start().addDays(firstOfWeek).daysTo(from) % freq; | ||
165 | |||
166 | if(diff != 0) | ||
167 | diff = freq - diff; | ||
168 | if(diff2 != 0) | ||
169 | diff2 = freq - diff2; | ||
170 | diff = QMIN(diff, diff2); | ||
171 | |||
172 | next = QDate(from.addDays(diff)); | ||
173 | if ( (next > endDate()) | ||
174 | && hasEndDate() ) | ||
175 | return FALSE; | ||
176 | return TRUE; | ||
177 | case MonthlyDay: | ||
178 | iday = from.day(); | ||
179 | iyear = from.year(); | ||
180 | imonth = from.month(); | ||
181 | /* find equivelent day of month for this month */ | ||
182 | dayOfWeek = start().dayOfWeek(); | ||
183 | weekOfMonth = (start().day() - 1) / 7; | ||
184 | |||
185 | /* work out when the next valid month is */ | ||
186 | a = from.year() - start().year(); | ||
187 | a *= 12; | ||
188 | a = a + (imonth - start().month()); | ||
189 | /* a is e.start()monthsFrom(from); */ | ||
190 | if(a % freq) { | ||
191 | a = freq - (a % freq); | ||
192 | imonth = from.month() + a; | ||
193 | if (imonth > 12) { | ||
194 | imonth--; | ||
195 | iyear += imonth / 12; | ||
196 | imonth = imonth % 12; | ||
197 | imonth++; | ||
198 | } | ||
199 | } | ||
200 | /* imonth is now the first month after or on | ||
201 | from that matches the frequency given */ | ||
202 | |||
203 | /* find for this month */ | ||
204 | tmpDate = QDate( iyear, imonth, 1 ); | ||
205 | |||
206 | iday = 1; | ||
207 | iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; | ||
208 | iday += 7 * weekOfMonth; | ||
209 | while (iday > tmpDate.daysInMonth()) { | ||
210 | imonth += freq; | ||
211 | if (imonth > 12) { | ||
212 | imonth--; | ||
213 | iyear += imonth / 12; | ||
214 | imonth = imonth % 12; | ||
215 | imonth++; | ||
216 | } | ||
217 | tmpDate = QDate( iyear, imonth, 1 ); | ||
218 | /* these loops could go for a while, check end case now */ | ||
219 | if ((tmpDate > endDate()) && hasEndDate() ) | ||
220 | return FALSE; | ||
221 | iday = 1; | ||
222 | iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; | ||
223 | iday += 7 * weekOfMonth; | ||
224 | } | ||
225 | tmpDate = QDate(iyear, imonth, iday); | ||
226 | |||
227 | if (tmpDate >= from) { | ||
228 | next = tmpDate; | ||
229 | if ((next > endDate() ) && hasEndDate() ) | ||
230 | return FALSE; | ||
231 | return TRUE; | ||
232 | } | ||
233 | |||
234 | /* need to find the next iteration */ | ||
235 | do { | ||
236 | imonth += freq; | ||
237 | if (imonth > 12) { | ||
238 | imonth--; | ||
239 | iyear += imonth / 12; | ||
240 | imonth = imonth % 12; | ||
241 | imonth++; | ||
242 | } | ||
243 | tmpDate = QDate( iyear, imonth, 1 ); | ||
244 | /* these loops could go for a while, check end case now */ | ||
245 | if ((tmpDate > endDate()) && hasEndDate() ) | ||
246 | return FALSE; | ||
247 | iday = 1; | ||
248 | iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; | ||
249 | iday += 7 * weekOfMonth; | ||
250 | } while (iday > tmpDate.daysInMonth()); | ||
251 | tmpDate = QDate(iyear, imonth, iday); | ||
252 | |||
253 | next = tmpDate; | ||
254 | if ((next > endDate()) && hasEndDate() ) | ||
255 | return FALSE; | ||
256 | return TRUE; | ||
257 | case MonthlyDate: | ||
258 | iday = start().day(); | ||
259 | iyear = from.year(); | ||
260 | imonth = from.month(); | ||
261 | |||
262 | a = from.year() - start().year(); | ||
263 | a *= 12; | ||
264 | a = a + (imonth - start().month()); | ||
265 | /* a is e.start()monthsFrom(from); */ | ||
266 | if(a % freq) { | ||
267 | a = freq - (a % freq); | ||
268 | imonth = from.month() + a; | ||
269 | if (imonth > 12) { | ||
270 | imonth--; | ||
271 | iyear += imonth / 12; | ||
272 | imonth = imonth % 12; | ||
273 | imonth++; | ||
274 | } | ||
275 | } | ||
276 | /* imonth is now the first month after or on | ||
277 | from that matches the frequencey given */ | ||
278 | |||
279 | /* this could go for a while, worse case, 4*12 iterations, probably */ | ||
280 | while(!QDate::isValid(iyear, imonth, iday) ) { | ||
281 | imonth += freq; | ||
282 | if (imonth > 12) { | ||
283 | imonth--; | ||
284 | iyear += imonth / 12; | ||
285 | imonth = imonth % 12; | ||
286 | imonth++; | ||
287 | } | ||
288 | /* these loops could go for a while, check end case now */ | ||
289 | if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) | ||
290 | return FALSE; | ||
291 | } | ||
292 | |||
293 | if(QDate(iyear, imonth, iday) >= from) { | ||
294 | /* done */ | ||
295 | next = QDate(iyear, imonth, iday); | ||
296 | if ((next > endDate()) && hasEndDate() ) | ||
297 | return FALSE; | ||
298 | return TRUE; | ||
299 | } | ||
300 | |||
301 | /* ok, need to cycle */ | ||
302 | imonth += freq; | ||
303 | imonth--; | ||
304 | iyear += imonth / 12; | ||
305 | imonth = imonth % 12; | ||
306 | imonth++; | ||
307 | |||
308 | while(!QDate::isValid(iyear, imonth, iday) ) { | ||
309 | imonth += freq; | ||
310 | imonth--; | ||
311 | iyear += imonth / 12; | ||
312 | imonth = imonth % 12; | ||
313 | imonth++; | ||
314 | if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) | ||
315 | return FALSE; | ||
316 | } | ||
317 | |||
318 | next = QDate(iyear, imonth, iday); | ||
319 | if ((next > endDate()) && hasEndDate() ) | ||
320 | return FALSE; | ||
321 | return TRUE; | ||
322 | case Yearly: | ||
323 | iday = start().day(); | ||
324 | imonth = start().month(); | ||
325 | iyear = from.year(); // after all, we want to start in this year | ||
326 | |||
327 | diff = 1; | ||
328 | if(imonth == 2 && iday > 28) { | ||
329 | /* leap year, and it counts, calculate actual frequency */ | ||
330 | if(freq % 4) | ||
331 | if (freq % 2) | ||
332 | freq = freq * 4; | ||
333 | else | ||
334 | freq = freq * 2; | ||
335 | /* else divides by 4 already, leave freq alone */ | ||
336 | diff = 4; | ||
337 | } | ||
338 | |||
339 | a = from.year() - start().year(); | ||
340 | if(a % freq) { | ||
341 | a = freq - (a % freq); | ||
342 | iyear = iyear + a; | ||
343 | } | ||
344 | |||
345 | /* under the assumption we won't hit one of the special not-leap years twice */ | ||
346 | if(!QDate::isValid(iyear, imonth, iday)) { | ||
347 | /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ | ||
348 | iyear += freq; | ||
349 | } | ||
350 | |||
351 | if(QDate(iyear, imonth, iday) >= from) { | ||
352 | next = QDate(iyear, imonth, iday); | ||
353 | |||
354 | if ((next > endDate()) && hasEndDate() ) | ||
355 | return FALSE; | ||
356 | return TRUE; | ||
357 | } | ||
358 | /* iyear == from.year(), need to advance again */ | ||
359 | iyear += freq; | ||
360 | /* under the assumption we won't hit one of the special not-leap years twice */ | ||
361 | if(!QDate::isValid(iyear, imonth, iday)) { | ||
362 | /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ | ||
363 | iyear += freq; | ||
364 | } | ||
365 | |||
366 | next = QDate(iyear, imonth, iday); | ||
367 | if ((next > endDate()) && hasEndDate() ) | ||
368 | return FALSE; | ||
369 | return TRUE; | ||
370 | default: | ||
371 | return FALSE; | ||
372 | } | ||
373 | } | ||
374 | ORecur::RepeatType ORecur::type()const{ | ||
375 | return data->type; | ||
376 | } | ||
377 | int ORecur::frequency()const { | ||
378 | return data->freq; | ||
379 | } | ||
380 | int ORecur::position()const { | ||
381 | return data->pos; | ||
382 | } | ||
383 | char ORecur::days() const{ | ||
384 | return data->days; | ||
385 | } | ||
386 | bool ORecur::hasEndDate()const { | ||
387 | return data->hasEnd; | ||
388 | } | ||
389 | QDate ORecur::endDate()const { | ||
390 | return data->end; | ||
391 | } | ||
392 | QDate ORecur::start()const{ | ||
393 | return data->start; | ||
394 | } | ||
395 | QDateTime ORecur::createdDateTime()const { | ||
396 | return data->create; | ||
397 | } | ||
398 | int ORecur::repetition()const { | ||
399 | return data->rep; | ||
400 | } | ||
401 | QString ORecur::service()const { | ||
402 | return data->app; | ||
403 | } | ||
404 | ORecur::ExceptionList& ORecur::exceptions() { | ||
405 | return data->list; | ||
406 | } | ||
407 | void ORecur::setType( const RepeatType& z) { | ||
408 | checkOrModify(); | ||
409 | data->type = z; | ||
410 | } | ||
411 | void ORecur::setFrequency( int freq ) { | ||
412 | checkOrModify(); | ||
413 | data->freq = freq; | ||
414 | } | ||
415 | void ORecur::setPosition( int pos ) { | ||
416 | checkOrModify(); | ||
417 | data->pos = pos; | ||
418 | } | ||
419 | void ORecur::setDays( char c ) { | ||
420 | checkOrModify(); | ||
421 | data->days = c; | ||
422 | } | ||
423 | void ORecur::setEndDate( const QDate& dt) { | ||
424 | checkOrModify(); | ||
425 | data->end = dt; | ||
426 | } | ||
427 | void ORecur::setCreatedDateTime( const QDateTime& t) { | ||
428 | checkOrModify(); | ||
429 | data->create = t; | ||
430 | } | ||
431 | void ORecur::setHasEndDate( bool b) { | ||
432 | checkOrModify(); | ||
433 | data->hasEnd = b; | ||
434 | } | ||
435 | void ORecur::setRepitition( int rep ) { | ||
436 | checkOrModify(); | ||
437 | data->rep = rep; | ||
438 | } | ||
439 | void ORecur::setService( const QString& app ) { | ||
440 | checkOrModify(); | ||
441 | data->app = app; | ||
442 | } | ||
443 | void ORecur::setStart( const QDate& dt ) { | ||
444 | checkOrModify(); | ||
445 | data->start = dt; | ||
446 | } | ||
447 | void ORecur::checkOrModify() { | ||
448 | if ( data->count != 1 ) { | ||
449 | data->deref(); | ||
450 | Data* d2 = new Data; | ||
451 | d2->days = data->days; | ||
452 | d2->type = data->type; | ||
453 | d2->freq = data->freq; | ||
454 | d2->pos = data->pos; | ||
455 | d2->hasEnd = data->hasEnd; | ||
456 | d2->end = data->end; | ||
457 | d2->create = data->create; | ||
458 | d2->rep = data->rep; | ||
459 | d2->app = data->app; | ||
460 | d2->list = data->list; | ||
461 | d2->start = data->start; | ||
462 | data = d2; | ||
463 | } | ||
464 | } | ||
465 | QString ORecur::toString()const { | ||
466 | QString buf; | ||
467 | QMap<int, QString> recMap = toMap(); | ||
468 | |||
469 | buf += " rtype=\""; | ||
470 | buf += recMap[ORecur::RType]; | ||
471 | buf += "\""; | ||
472 | if (data->days > 0 ) | ||
473 | buf += " rweekdays=\"" + recMap[ORecur::RWeekdays] + "\""; | ||
474 | if ( data->pos != 0 ) | ||
475 | buf += " rposition=\"" + recMap[ORecur::RPosition] + "\""; | ||
476 | |||
477 | buf += " rfreq=\"" + recMap[ORecur::RFreq] + "\""; | ||
478 | buf += " rhasenddate=\"" + recMap[ORecur::RHasEndDate]+ "\""; | ||
479 | if ( data->hasEnd ) | ||
480 | buf += " enddt=\"" | ||
481 | + recMap[ORecur::EndDate] | ||
482 | + "\""; | ||
483 | buf += " created=\"" + recMap[ORecur::Created] + "\""; | ||
484 | |||
485 | if ( data->list.isEmpty() ) return buf; | ||
486 | buf += " exceptions=\""; | ||
487 | buf += recMap[ORecur::Exceptions]; | ||
488 | buf += "\" "; | ||
489 | |||
490 | return buf; | ||
491 | } | ||
492 | |||
493 | QString ORecur::rTypeString() const | ||
494 | { | ||
495 | QString retString; | ||
496 | switch ( data->type ) { | ||
497 | case ORecur::Daily: | ||
498 | retString = "Daily"; | ||
499 | break; | ||
500 | case ORecur::Weekly: | ||
501 | retString = "Weekly"; | ||
502 | break; | ||
503 | case ORecur::MonthlyDay: | ||
504 | retString = "MonthlyDay"; | ||
505 | break; | ||
506 | case ORecur::MonthlyDate: | ||
507 | retString = "MonthlyDate"; | ||
508 | break; | ||
509 | case ORecur::Yearly: | ||
510 | retString = "Yearly"; | ||
511 | break; | ||
512 | default: | ||
513 | retString = "NoRepeat"; | ||
514 | break; | ||
515 | |||
516 | } | ||
517 | |||
518 | return retString; | ||
519 | } | ||
520 | |||
521 | QMap<QString, ORecur::RepeatType> ORecur::rTypeValueConvertMap() const | ||
522 | { | ||
523 | QMap<QString, RepeatType> convertMap; | ||
524 | |||
525 | convertMap.insert( QString( "Daily" ), ORecur::Daily ); | ||
526 | convertMap.insert( QString( "Weekly" ), ORecur::Weekly ); | ||
527 | convertMap.insert( QString( "MonthlyDay" ), ORecur::MonthlyDay ); | ||
528 | convertMap.insert( QString( "MonthlyDate" ), ORecur::MonthlyDate ); | ||
529 | convertMap.insert( QString( "Yearly" ), ORecur::Yearly ); | ||
530 | convertMap.insert( QString( "NoRepeat" ), ORecur::NoRepeat ); | ||
531 | |||
532 | return convertMap; | ||
533 | } | ||
534 | |||
535 | |||
536 | QMap<int, QString> ORecur::toMap() const | ||
537 | { | ||
538 | QMap<int, QString> retMap; | ||
539 | |||
540 | retMap.insert( ORecur::RType, rTypeString() ); | ||
541 | retMap.insert( ORecur::RWeekdays, QString::number( static_cast<int>( data->days ) ) ); | ||
542 | retMap.insert( ORecur::RPosition, QString::number(data->pos ) ); | ||
543 | retMap.insert( ORecur::RFreq, QString::number( data->freq ) ); | ||
544 | retMap.insert( ORecur::RHasEndDate, QString::number( static_cast<int>( data->hasEnd ) ) ); | ||
545 | if( data -> hasEnd ) | ||
546 | retMap.insert( ORecur::EndDate, QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) ); | ||
547 | retMap.insert( ORecur::Created, QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) ); | ||
548 | |||
549 | if ( data->list.isEmpty() ) return retMap; | ||
550 | |||
551 | // save exceptions list here!! | ||
552 | ExceptionList::ConstIterator it; | ||
553 | ExceptionList list = data->list; | ||
554 | QString exceptBuf; | ||
555 | QDate date; | ||
556 | for ( it = list.begin(); it != list.end(); ++it ) { | ||
557 | date = (*it); | ||
558 | if ( it != list.begin() ) exceptBuf += " "; | ||
559 | |||
560 | exceptBuf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() ); | ||
561 | } | ||
562 | |||
563 | retMap.insert( ORecur::Exceptions, exceptBuf ); | ||
564 | |||
565 | return retMap; | ||
566 | } | ||
567 | |||
568 | void ORecur::fromMap( const QMap<int, QString>& map ) | ||
569 | { | ||
570 | QMap<QString, RepeatType> repTypeMap = rTypeValueConvertMap(); | ||
571 | |||
572 | data -> type = repTypeMap[ map [ORecur::RType] ]; | ||
573 | data -> days = (char) map[ ORecur::RWeekdays ].toInt(); | ||
574 | data -> pos = map[ ORecur::RPosition ].toInt(); | ||
575 | data -> freq = map[ ORecur::RFreq ].toInt(); | ||
576 | data -> hasEnd= map[ ORecur::RHasEndDate ].toInt() ? true : false; | ||
577 | OTimeZone utc = OTimeZone::utc(); | ||
578 | if ( data -> hasEnd ){ | ||
579 | data -> end = utc.fromUTCDateTime( (time_t) map[ ORecur::EndDate ].toLong() ).date(); | ||
580 | } | ||
581 | data -> create = utc.fromUTCDateTime( (time_t) map[ ORecur::Created ].toLong() ).date(); | ||
582 | |||
583 | #if 0 | ||
584 | // FIXME: Exceptions currently not supported... | ||
585 | // Convert the list of exceptions from QString into ExceptionList | ||
586 | data -> list.clear(); | ||
587 | QString exceptStr = map[ ORecur::Exceptions ]; | ||
588 | QStringList exceptList = QStringList::split( " ", exceptStr ); | ||
589 | ... | ||
590 | #endif | ||
591 | |||
592 | |||
593 | } | ||
diff --git a/noncore/unsupported/libopie/pim/orecur.h b/noncore/unsupported/libopie/pim/orecur.h new file mode 100644 index 0000000..d7ecd90 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/orecur.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * GPL from TT | ||
3 | */ | ||
4 | |||
5 | #ifndef OPIE_RECUR_H | ||
6 | #define OPIE_RECUR_H | ||
7 | |||
8 | #include <sys/types.h> | ||
9 | |||
10 | #include <qdatetime.h> | ||
11 | #include <qvaluelist.h> | ||
12 | #include <qmap.h> | ||
13 | |||
14 | |||
15 | /** | ||
16 | * Class to handle Recurrencies.. | ||
17 | */ | ||
18 | |||
19 | class ORecur { | ||
20 | public: | ||
21 | typedef QValueList<QDate> ExceptionList; | ||
22 | enum RepeatType{ NoRepeat = -1, Daily, Weekly, MonthlyDay, | ||
23 | MonthlyDate, Yearly }; | ||
24 | enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08, | ||
25 | FRI = 0x10, SAT = 0x20, SUN = 0x40 }; | ||
26 | enum Fields{ RType = 0, RWeekdays, RPosition, RFreq, RHasEndDate, | ||
27 | EndDate, Created, Exceptions }; | ||
28 | |||
29 | ORecur(); | ||
30 | ORecur( const QMap<int, QString>& map ); | ||
31 | ORecur( const ORecur& ); | ||
32 | ~ORecur(); | ||
33 | |||
34 | ORecur &operator=( const ORecur& ); | ||
35 | bool operator==(const ORecur& )const; | ||
36 | |||
37 | bool doesRecur()const; | ||
38 | /* if it recurrs on that day */ | ||
39 | bool doesRecur( const QDate& ); | ||
40 | RepeatType type()const; | ||
41 | int frequency()const; | ||
42 | int position()const; | ||
43 | char days()const; | ||
44 | bool hasEndDate()const; | ||
45 | QDate start()const; | ||
46 | QDate endDate()const; | ||
47 | QDateTime createdDateTime()const; | ||
48 | /** | ||
49 | * starting on monday=0, sunday=6 | ||
50 | * for convience | ||
51 | */ | ||
52 | bool repeatOnWeekDay( int day )const; | ||
53 | |||
54 | /** | ||
55 | * FromWhereToStart is not included!!! | ||
56 | */ | ||
57 | bool nextOcurrence( const QDate& FromWhereToStart, QDate &recurDate ); | ||
58 | |||
59 | /** | ||
60 | * The module this ORecur belongs to | ||
61 | */ | ||
62 | QString service()const; | ||
63 | |||
64 | /* | ||
65 | * reference to the exception list | ||
66 | */ | ||
67 | ExceptionList &exceptions(); | ||
68 | |||
69 | /** | ||
70 | * the current repetition | ||
71 | */ | ||
72 | int repetition()const; | ||
73 | |||
74 | void setType( const RepeatType& ); | ||
75 | void setFrequency( int freq ); | ||
76 | void setPosition( int pos ); | ||
77 | void setDays( char c); | ||
78 | void setEndDate( const QDate& dt ); | ||
79 | void setStart( const QDate& dt ); | ||
80 | void setCreatedDateTime( const QDateTime& ); | ||
81 | void setHasEndDate( bool b ); | ||
82 | void setRepitition(int ); | ||
83 | |||
84 | void setService( const QString& ser ); | ||
85 | |||
86 | QMap<int, QString> toMap() const; | ||
87 | void fromMap( const QMap<int, QString>& map ); | ||
88 | |||
89 | /* almost internal */ | ||
90 | QString toString()const; | ||
91 | private: | ||
92 | bool p_nextOccurrence( const QDate& from, QDate& next ); | ||
93 | void deref(); | ||
94 | inline void checkOrModify(); | ||
95 | |||
96 | /* Converts rType to String */ | ||
97 | QString rTypeString() const; | ||
98 | /* Returns a map to convert Stringname for RType to RepeatType */ | ||
99 | QMap<QString, RepeatType> rTypeValueConvertMap() const; | ||
100 | |||
101 | class Data; | ||
102 | Data* data; | ||
103 | class ORecurPrivate; | ||
104 | ORecurPrivate *d; | ||
105 | }; | ||
106 | |||
107 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otemplatebase.h b/noncore/unsupported/libopie/pim/otemplatebase.h new file mode 100644 index 0000000..cadac74 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otemplatebase.h | |||
@@ -0,0 +1,98 @@ | |||
1 | #ifndef OPIE_TEMPLATE_BASE_H | ||
2 | #define OPIE_TEMPLATE_BASE_H | ||
3 | |||
4 | #include <qarray.h> | ||
5 | |||
6 | #include <opie/opimrecord.h> | ||
7 | |||
8 | |||
9 | /** | ||
10 | * Templates do not have a base class, This is why | ||
11 | * we've this class | ||
12 | * this is here to give us the possibility | ||
13 | * to have a common base class | ||
14 | * You may not want to use that interface internaly | ||
15 | * POOR mans interface | ||
16 | */ | ||
17 | class OPimBasePrivate; | ||
18 | struct OPimBase { | ||
19 | /** | ||
20 | * return the rtti | ||
21 | */ | ||
22 | virtual int rtti()= 0; | ||
23 | virtual OPimRecord* record()const = 0; | ||
24 | virtual OPimRecord* record(int uid)const = 0; | ||
25 | virtual bool add( const OPimRecord& ) = 0; | ||
26 | virtual bool remove( int uid ) = 0; | ||
27 | virtual bool remove( const OPimRecord& ) = 0; | ||
28 | virtual void clear() = 0; | ||
29 | virtual bool load() = 0; | ||
30 | virtual bool save() = 0; | ||
31 | virtual QArray<int> records()const = 0; | ||
32 | /* | ||
33 | * ADD editing here? | ||
34 | * -zecke | ||
35 | */ | ||
36 | private: | ||
37 | OPimBasePrivate* d; | ||
38 | |||
39 | }; | ||
40 | /** | ||
41 | * internal template base | ||
42 | * T needs to implement the copy c'tor!!! | ||
43 | */ | ||
44 | class OTemplateBasePrivate; | ||
45 | template <class T = OPimRecord> | ||
46 | class OTemplateBase : public OPimBase { | ||
47 | public: | ||
48 | enum CacheDirection { Forward=0, Reverse }; | ||
49 | OTemplateBase() { | ||
50 | }; | ||
51 | virtual ~OTemplateBase() { | ||
52 | } | ||
53 | virtual T find( int uid )const = 0; | ||
54 | |||
55 | /** | ||
56 | * read ahead find | ||
57 | */ | ||
58 | virtual T find( int uid, const QArray<int>& items, | ||
59 | uint current, CacheDirection dir = Forward )const = 0; | ||
60 | virtual void cache( const T& )const = 0; | ||
61 | virtual void setSaneCacheSize( int ) = 0; | ||
62 | |||
63 | /* reimplement of OPimBase */ | ||
64 | int rtti(); | ||
65 | OPimRecord* record()const; | ||
66 | OPimRecord* record(int uid )const; | ||
67 | static T* rec(); | ||
68 | |||
69 | private: | ||
70 | OTemplateBasePrivate *d; | ||
71 | }; | ||
72 | |||
73 | /* | ||
74 | * implementation | ||
75 | */ | ||
76 | template <class T> | ||
77 | int | ||
78 | OTemplateBase<T>::rtti() { | ||
79 | return T::rtti(); | ||
80 | } | ||
81 | template <class T> | ||
82 | OPimRecord* OTemplateBase<T>::record()const { | ||
83 | T* t = new T; | ||
84 | return t; | ||
85 | } | ||
86 | template <class T> | ||
87 | OPimRecord* OTemplateBase<T>::record(int uid )const { | ||
88 | T t2 = find(uid ); | ||
89 | T* t1 = new T(t2); | ||
90 | |||
91 | return t1; | ||
92 | }; | ||
93 | template <class T> | ||
94 | T* OTemplateBase<T>::rec() { | ||
95 | return new T; | ||
96 | } | ||
97 | |||
98 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otimezone.cpp b/noncore/unsupported/libopie/pim/otimezone.cpp new file mode 100644 index 0000000..34659c3 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otimezone.cpp | |||
@@ -0,0 +1,113 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | #include <sys/types.h> | ||
5 | |||
6 | #include "otimezone.h" | ||
7 | |||
8 | namespace { | ||
9 | |||
10 | QDateTime utcTime( time_t t) { | ||
11 | tm* broken = ::gmtime( &t ); | ||
12 | QDateTime ret; | ||
13 | ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) ); | ||
14 | ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) ); | ||
15 | return ret; | ||
16 | } | ||
17 | QDateTime utcTime( time_t t, const QString& zone) { | ||
18 | QCString org = ::getenv( "TZ" ); | ||
19 | #ifndef Q_OS_MACX // Following line causes bus errors on Mac | ||
20 | ::setenv( "TZ", zone.latin1(), true ); | ||
21 | ::tzset(); | ||
22 | |||
23 | tm* broken = ::localtime( &t ); | ||
24 | ::setenv( "TZ", org, true ); | ||
25 | #else | ||
26 | #warning "Need a replacement for MacOSX!!" | ||
27 | tm* broken = ::localtime( &t ); | ||
28 | #endif | ||
29 | |||
30 | QDateTime ret; | ||
31 | ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) ); | ||
32 | ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) ); | ||
33 | |||
34 | return ret; | ||
35 | } | ||
36 | time_t to_Time_t( const QDateTime& utc, const QString& str ) { | ||
37 | QDate d = utc.date(); | ||
38 | QTime t = utc.time(); | ||
39 | |||
40 | tm broken; | ||
41 | broken.tm_year = d.year() - 1900; | ||
42 | broken.tm_mon = d.month() - 1; | ||
43 | broken.tm_mday = d.day(); | ||
44 | broken.tm_hour = t.hour(); | ||
45 | broken.tm_min = t.minute(); | ||
46 | broken.tm_sec = t.second(); | ||
47 | |||
48 | QCString org = ::getenv( "TZ" ); | ||
49 | #ifndef Q_OS_MACX // Following line causes bus errors on Mac | ||
50 | ::setenv( "TZ", str.latin1(), true ); | ||
51 | ::tzset(); | ||
52 | |||
53 | time_t ti = ::mktime( &broken ); | ||
54 | ::setenv( "TZ", org, true ); | ||
55 | #else | ||
56 | #warning "Need a replacement for MacOSX!!" | ||
57 | time_t ti = ::mktime( &broken ); | ||
58 | #endif | ||
59 | return ti; | ||
60 | } | ||
61 | } | ||
62 | OTimeZone::OTimeZone( const ZoneName& zone ) | ||
63 | : m_name(zone) { | ||
64 | } | ||
65 | OTimeZone::~OTimeZone() { | ||
66 | } | ||
67 | |||
68 | bool OTimeZone::isValid()const { | ||
69 | return !m_name.isEmpty(); | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * we will get the current timezone | ||
74 | * and ask it to convert to the timezone date | ||
75 | */ | ||
76 | QDateTime OTimeZone::toLocalDateTime( const QDateTime& dt) { | ||
77 | return OTimeZone::current().toDateTime( dt, *this ); | ||
78 | } | ||
79 | QDateTime OTimeZone::toUTCDateTime( const QDateTime& dt ) { | ||
80 | return OTimeZone::utc().toDateTime( dt, *this ); | ||
81 | } | ||
82 | QDateTime OTimeZone::fromUTCDateTime( time_t t) { | ||
83 | return utcTime( t ); | ||
84 | } | ||
85 | QDateTime OTimeZone::toDateTime( time_t t) { | ||
86 | return utcTime( t, m_name ); | ||
87 | } | ||
88 | /* | ||
89 | * convert dt to utc using zone.m_name | ||
90 | * convert utc -> timeZoneDT using this->m_name | ||
91 | */ | ||
92 | QDateTime OTimeZone::toDateTime( const QDateTime& dt, const OTimeZone& zone ) { | ||
93 | time_t utc = to_Time_t( dt, zone.m_name ); | ||
94 | qWarning("%d %s", utc, zone.m_name.latin1() ); | ||
95 | return utcTime( utc, m_name ); | ||
96 | } | ||
97 | time_t OTimeZone::fromDateTime( const QDateTime& time ) { | ||
98 | return to_Time_t( time, m_name ); | ||
99 | } | ||
100 | time_t OTimeZone::fromUTCDateTime( const QDateTime& time ) { | ||
101 | return to_Time_t( time, "UTC" ); | ||
102 | } | ||
103 | OTimeZone OTimeZone::current() { | ||
104 | QCString str = ::getenv("TZ"); | ||
105 | OTimeZone zone( str ); | ||
106 | return zone; | ||
107 | } | ||
108 | OTimeZone OTimeZone::utc() { | ||
109 | return OTimeZone("UTC"); | ||
110 | } | ||
111 | QString OTimeZone::timeZone()const { | ||
112 | return m_name; | ||
113 | } | ||
diff --git a/noncore/unsupported/libopie/pim/otimezone.h b/noncore/unsupported/libopie/pim/otimezone.h new file mode 100644 index 0000000..bb08349 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otimezone.h | |||
@@ -0,0 +1,71 @@ | |||
1 | #ifndef OPIE_TIME_ZONE_H | ||
2 | #define OPIE_TIME_ZONE_H | ||
3 | |||
4 | #include <time.h> | ||
5 | #include <qdatetime.h> | ||
6 | |||
7 | /** | ||
8 | * A very primitive class to convert time | ||
9 | * from one timezone to another | ||
10 | * and to localtime | ||
11 | * and time_t | ||
12 | */ | ||
13 | class OTimeZone { | ||
14 | public: | ||
15 | typedef QString ZoneName; | ||
16 | OTimeZone( const ZoneName& = ZoneName::null ); | ||
17 | virtual ~OTimeZone(); // just in case. | ||
18 | |||
19 | bool isValid()const; | ||
20 | |||
21 | /** | ||
22 | * converts the QDateTime to a DateTime | ||
23 | * in the local timezone | ||
24 | * if QDateTime is 25th Jan and takes place in Europe/Berlin at 12h | ||
25 | * and the current timezone is Europe/London the returned | ||
26 | * time will be 11h. | ||
27 | */ | ||
28 | QDateTime toLocalDateTime( const QDateTime& dt ); | ||
29 | |||
30 | /** | ||
31 | * converts the QDateTime to UTC time | ||
32 | */ | ||
33 | QDateTime toUTCDateTime( const QDateTime& dt ); | ||
34 | |||
35 | /** | ||
36 | * reads the time_t into a QDateTime using UTC as timezone! | ||
37 | */ | ||
38 | QDateTime fromUTCDateTime( time_t ); | ||
39 | |||
40 | /** | ||
41 | * converts the time_t to the time in the timezone | ||
42 | */ | ||
43 | QDateTime toDateTime( time_t ); | ||
44 | |||
45 | /** | ||
46 | * converts the QDateTime from one timezone to this timeZone | ||
47 | */ | ||
48 | QDateTime toDateTime( const QDateTime&, const OTimeZone& timeZone ); | ||
49 | |||
50 | /** | ||
51 | * converts the date time into a time_t. It takes the timezone into account | ||
52 | */ | ||
53 | time_t fromDateTime( const QDateTime& ); | ||
54 | |||
55 | /** | ||
56 | * converts the datetime with timezone UTC | ||
57 | */ | ||
58 | time_t fromUTCDateTime( const QDateTime& ); | ||
59 | |||
60 | static OTimeZone current(); | ||
61 | static OTimeZone utc(); | ||
62 | |||
63 | QString timeZone()const; | ||
64 | private: | ||
65 | ZoneName m_name; | ||
66 | class Private; | ||
67 | Private* d; | ||
68 | }; | ||
69 | |||
70 | |||
71 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otodo.cpp b/noncore/unsupported/libopie/pim/otodo.cpp new file mode 100644 index 0000000..b2c76f8 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodo.cpp | |||
@@ -0,0 +1,519 @@ | |||
1 | |||
2 | #include <qobject.h> | ||
3 | #include <qshared.h> | ||
4 | |||
5 | |||
6 | |||
7 | #include <qpe/palmtopuidgen.h> | ||
8 | #include <qpe/palmtoprecord.h> | ||
9 | #include <qpe/categories.h> | ||
10 | #include <qpe/categoryselect.h> | ||
11 | #include <qpe/stringutil.h> | ||
12 | |||
13 | |||
14 | #include "opimstate.h" | ||
15 | #include "orecur.h" | ||
16 | #include "opimmaintainer.h" | ||
17 | #include "opimnotifymanager.h" | ||
18 | #include "opimresolver.h" | ||
19 | |||
20 | #include "otodo.h" | ||
21 | |||
22 | |||
23 | struct OTodo::OTodoData : public QShared { | ||
24 | OTodoData() : QShared() { | ||
25 | recur = 0; | ||
26 | state = 0; | ||
27 | maintainer = 0; | ||
28 | notifiers = 0; | ||
29 | }; | ||
30 | ~OTodoData() { | ||
31 | delete recur; | ||
32 | delete maintainer; | ||
33 | delete notifiers; | ||
34 | } | ||
35 | |||
36 | QDate date; | ||
37 | bool isCompleted:1; | ||
38 | bool hasDate:1; | ||
39 | int priority; | ||
40 | QString desc; | ||
41 | QString sum; | ||
42 | QMap<QString, QString> extra; | ||
43 | ushort prog; | ||
44 | OPimState *state; | ||
45 | ORecur *recur; | ||
46 | OPimMaintainer *maintainer; | ||
47 | QDate start; | ||
48 | QDate completed; | ||
49 | OPimNotifyManager *notifiers; | ||
50 | }; | ||
51 | |||
52 | OTodo::OTodo(const OTodo &event ) | ||
53 | : OPimRecord( event ), data( event.data ) | ||
54 | { | ||
55 | data->ref(); | ||
56 | // qWarning("ref up"); | ||
57 | } | ||
58 | OTodo::~OTodo() { | ||
59 | |||
60 | // qWarning("~OTodo " ); | ||
61 | if ( data->deref() ) { | ||
62 | // qWarning("OTodo::dereffing"); | ||
63 | delete data; | ||
64 | data = 0l; | ||
65 | } | ||
66 | } | ||
67 | OTodo::OTodo(bool completed, int priority, | ||
68 | const QArray<int> &category, | ||
69 | const QString& summary, | ||
70 | const QString &description, | ||
71 | ushort progress, | ||
72 | bool hasDate, QDate date, int uid ) | ||
73 | : OPimRecord( uid ) | ||
74 | { | ||
75 | // qWarning("OTodoData " + summary); | ||
76 | setCategories( category ); | ||
77 | |||
78 | data = new OTodoData; | ||
79 | |||
80 | data->date = date; | ||
81 | data->isCompleted = completed; | ||
82 | data->hasDate = hasDate; | ||
83 | data->priority = priority; | ||
84 | data->sum = summary; | ||
85 | data->prog = progress; | ||
86 | data->desc = Qtopia::simplifyMultiLineSpace(description ); | ||
87 | } | ||
88 | OTodo::OTodo(bool completed, int priority, | ||
89 | const QStringList &category, | ||
90 | const QString& summary, | ||
91 | const QString &description, | ||
92 | ushort progress, | ||
93 | bool hasDate, QDate date, int uid ) | ||
94 | : OPimRecord( uid ) | ||
95 | { | ||
96 | // qWarning("OTodoData" + summary); | ||
97 | setCategories( idsFromString( category.join(";") ) ); | ||
98 | |||
99 | data = new OTodoData; | ||
100 | |||
101 | data->date = date; | ||
102 | data->isCompleted = completed; | ||
103 | data->hasDate = hasDate; | ||
104 | data->priority = priority; | ||
105 | data->sum = summary; | ||
106 | data->prog = progress; | ||
107 | data->desc = Qtopia::simplifyMultiLineSpace(description ); | ||
108 | } | ||
109 | bool OTodo::match( const QRegExp ®Exp )const | ||
110 | { | ||
111 | if( QString::number( data->priority ).find( regExp ) != -1 ){ | ||
112 | setLastHitField( Priority ); | ||
113 | return true; | ||
114 | }else if( data->hasDate && data->date.toString().find( regExp) != -1 ){ | ||
115 | setLastHitField( HasDate ); | ||
116 | return true; | ||
117 | }else if(data->desc.find( regExp ) != -1 ){ | ||
118 | setLastHitField( Description ); | ||
119 | return true; | ||
120 | }else if(data->sum.find( regExp ) != -1 ) { | ||
121 | setLastHitField( Summary ); | ||
122 | return true; | ||
123 | } | ||
124 | return false; | ||
125 | } | ||
126 | bool OTodo::isCompleted() const | ||
127 | { | ||
128 | return data->isCompleted; | ||
129 | } | ||
130 | bool OTodo::hasDueDate() const | ||
131 | { | ||
132 | return data->hasDate; | ||
133 | } | ||
134 | bool OTodo::hasStartDate()const { | ||
135 | return data->start.isValid(); | ||
136 | } | ||
137 | bool OTodo::hasCompletedDate()const { | ||
138 | return data->completed.isValid(); | ||
139 | } | ||
140 | int OTodo::priority()const | ||
141 | { | ||
142 | return data->priority; | ||
143 | } | ||
144 | QString OTodo::summary() const | ||
145 | { | ||
146 | return data->sum; | ||
147 | } | ||
148 | ushort OTodo::progress() const | ||
149 | { | ||
150 | return data->prog; | ||
151 | } | ||
152 | QDate OTodo::dueDate()const | ||
153 | { | ||
154 | return data->date; | ||
155 | } | ||
156 | QDate OTodo::startDate()const { | ||
157 | return data->start; | ||
158 | } | ||
159 | QDate OTodo::completedDate()const { | ||
160 | return data->completed; | ||
161 | } | ||
162 | QString OTodo::description()const | ||
163 | { | ||
164 | return data->desc; | ||
165 | } | ||
166 | bool OTodo::hasState() const{ | ||
167 | if (!data->state ) return false; | ||
168 | return ( data->state->state() != OPimState::Undefined ); | ||
169 | } | ||
170 | OPimState OTodo::state()const { | ||
171 | if (!data->state ) { | ||
172 | OPimState state; | ||
173 | return state; | ||
174 | } | ||
175 | |||
176 | return (*data->state); | ||
177 | } | ||
178 | bool OTodo::hasRecurrence()const { | ||
179 | if (!data->recur) return false; | ||
180 | return data->recur->doesRecur(); | ||
181 | } | ||
182 | ORecur OTodo::recurrence()const { | ||
183 | if (!data->recur) return ORecur(); | ||
184 | |||
185 | return (*data->recur); | ||
186 | } | ||
187 | bool OTodo::hasMaintainer()const { | ||
188 | if (!data->maintainer) return false; | ||
189 | |||
190 | return (data->maintainer->mode() != OPimMaintainer::Undefined ); | ||
191 | } | ||
192 | OPimMaintainer OTodo::maintainer()const { | ||
193 | if (!data->maintainer) return OPimMaintainer(); | ||
194 | |||
195 | return (*data->maintainer); | ||
196 | } | ||
197 | void OTodo::setCompleted( bool completed ) | ||
198 | { | ||
199 | changeOrModify(); | ||
200 | data->isCompleted = completed; | ||
201 | } | ||
202 | void OTodo::setHasDueDate( bool hasDate ) | ||
203 | { | ||
204 | changeOrModify(); | ||
205 | data->hasDate = hasDate; | ||
206 | } | ||
207 | void OTodo::setDescription(const QString &desc ) | ||
208 | { | ||
209 | // qWarning( "desc " + desc ); | ||
210 | changeOrModify(); | ||
211 | data->desc = Qtopia::simplifyMultiLineSpace(desc ); | ||
212 | } | ||
213 | void OTodo::setSummary( const QString& sum ) | ||
214 | { | ||
215 | changeOrModify(); | ||
216 | data->sum = sum; | ||
217 | } | ||
218 | void OTodo::setPriority(int prio ) | ||
219 | { | ||
220 | changeOrModify(); | ||
221 | data->priority = prio; | ||
222 | } | ||
223 | void OTodo::setDueDate( const QDate& date ) | ||
224 | { | ||
225 | changeOrModify(); | ||
226 | data->date = date; | ||
227 | } | ||
228 | void OTodo::setStartDate( const QDate& date ) { | ||
229 | changeOrModify(); | ||
230 | data->start = date; | ||
231 | } | ||
232 | void OTodo::setCompletedDate( const QDate& date ) { | ||
233 | changeOrModify(); | ||
234 | data->completed = date; | ||
235 | } | ||
236 | void OTodo::setState( const OPimState& state ) { | ||
237 | changeOrModify(); | ||
238 | if (data->state ) | ||
239 | (*data->state) = state; | ||
240 | else | ||
241 | data->state = new OPimState( state ); | ||
242 | } | ||
243 | void OTodo::setRecurrence( const ORecur& rec) { | ||
244 | changeOrModify(); | ||
245 | if (data->recur ) | ||
246 | (*data->recur) = rec; | ||
247 | else | ||
248 | data->recur = new ORecur( rec ); | ||
249 | } | ||
250 | void OTodo::setMaintainer( const OPimMaintainer& pim ) { | ||
251 | changeOrModify(); | ||
252 | |||
253 | if (data->maintainer ) | ||
254 | (*data->maintainer) = pim; | ||
255 | else | ||
256 | data->maintainer = new OPimMaintainer( pim ); | ||
257 | } | ||
258 | bool OTodo::isOverdue( ) | ||
259 | { | ||
260 | if( data->hasDate && !data->isCompleted) | ||
261 | return QDate::currentDate() > data->date; | ||
262 | return false; | ||
263 | } | ||
264 | void OTodo::setProgress(ushort progress ) | ||
265 | { | ||
266 | changeOrModify(); | ||
267 | data->prog = progress; | ||
268 | } | ||
269 | QString OTodo::toShortText() const { | ||
270 | return summary(); | ||
271 | } | ||
272 | /*! | ||
273 | Returns a richt text string | ||
274 | */ | ||
275 | QString OTodo::toRichText() const | ||
276 | { | ||
277 | QString text; | ||
278 | QStringList catlist; | ||
279 | |||
280 | // summary | ||
281 | text += "<b><h3><img src=\"todo/TodoList\"> "; | ||
282 | if ( !summary().isEmpty() ) { | ||
283 | text += Qtopia::escapeString(summary() ).replace(QRegExp( "[\n]"), "" ); | ||
284 | } | ||
285 | text += "</h3></b><br><hr><br>"; | ||
286 | |||
287 | // description | ||
288 | if( !description().isEmpty() ){ | ||
289 | text += "<b>" + QObject::tr( "Description:" ) + "</b><br>"; | ||
290 | text += Qtopia::escapeString(description() ).replace(QRegExp( "[\n]"), "<br>" ) + "<br>"; | ||
291 | } | ||
292 | |||
293 | // priority | ||
294 | int priorityval = priority(); | ||
295 | text += "<b>" + QObject::tr( "Priority:") +" </b><img src=\"todo/priority" + | ||
296 | QString::number( priorityval ) + "\"> "; | ||
297 | |||
298 | switch ( priorityval ) | ||
299 | { | ||
300 | case 1 : text += QObject::tr( "Very high" ); | ||
301 | break; | ||
302 | case 2 : text += QObject::tr( "High" ); | ||
303 | break; | ||
304 | case 3 : text += QObject::tr( "Normal" ); | ||
305 | break; | ||
306 | case 4 : text += QObject::tr( "Low" ); | ||
307 | break; | ||
308 | case 5 : text += QObject::tr( "Very low" ); | ||
309 | break; | ||
310 | }; | ||
311 | text += "<br>"; | ||
312 | |||
313 | // progress | ||
314 | text += "<b>" + QObject::tr( "Progress:") + " </b>" | ||
315 | + QString::number( progress() ) + " %<br>"; | ||
316 | |||
317 | // due date | ||
318 | if (hasDueDate() ){ | ||
319 | QDate dd = dueDate(); | ||
320 | int off = QDate::currentDate().daysTo( dd ); | ||
321 | |||
322 | text += "<b>" + QObject::tr( "Deadline:" ) + " </b><font color=\""; | ||
323 | if ( off < 0 ) | ||
324 | text += "#FF0000"; | ||
325 | else if ( off == 0 ) | ||
326 | text += "#FFFF00"; | ||
327 | else if ( off > 0 ) | ||
328 | text += "#00FF00"; | ||
329 | |||
330 | text += "\">" + dd.toString() + "</font><br>"; | ||
331 | } | ||
332 | |||
333 | // categories | ||
334 | text += "<b>" + QObject::tr( "Category:") + "</b> "; | ||
335 | text += categoryNames( "Todo List" ).join(", "); | ||
336 | text += "<br>"; | ||
337 | |||
338 | return text; | ||
339 | } | ||
340 | bool OTodo::hasNotifiers()const { | ||
341 | if (!data->notifiers) return false; | ||
342 | return !data->notifiers->isEmpty(); | ||
343 | } | ||
344 | OPimNotifyManager& OTodo::notifiers() { | ||
345 | if (!data->notifiers ) | ||
346 | data->notifiers = new OPimNotifyManager; | ||
347 | return (*data->notifiers); | ||
348 | } | ||
349 | const OPimNotifyManager& OTodo::notifiers()const{ | ||
350 | if (!data->notifiers ) | ||
351 | data->notifiers = new OPimNotifyManager; | ||
352 | |||
353 | return (*data->notifiers); | ||
354 | } | ||
355 | |||
356 | bool OTodo::operator<( const OTodo &toDoEvent )const{ | ||
357 | if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; | ||
358 | if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; | ||
359 | if( hasDueDate() && toDoEvent.hasDueDate() ){ | ||
360 | if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide | ||
361 | return priority() < toDoEvent.priority(); | ||
362 | }else{ | ||
363 | return dueDate() < toDoEvent.dueDate(); | ||
364 | } | ||
365 | } | ||
366 | return false; | ||
367 | } | ||
368 | bool OTodo::operator<=(const OTodo &toDoEvent )const | ||
369 | { | ||
370 | if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; | ||
371 | if( !hasDueDate() && toDoEvent.hasDueDate() ) return true; | ||
372 | if( hasDueDate() && toDoEvent.hasDueDate() ){ | ||
373 | if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide | ||
374 | return priority() <= toDoEvent.priority(); | ||
375 | }else{ | ||
376 | return dueDate() <= toDoEvent.dueDate(); | ||
377 | } | ||
378 | } | ||
379 | return true; | ||
380 | } | ||
381 | bool OTodo::operator>(const OTodo &toDoEvent )const | ||
382 | { | ||
383 | if( !hasDueDate() && !toDoEvent.hasDueDate() ) return false; | ||
384 | if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; | ||
385 | if( hasDueDate() && toDoEvent.hasDueDate() ){ | ||
386 | if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide | ||
387 | return priority() > toDoEvent.priority(); | ||
388 | }else{ | ||
389 | return dueDate() > toDoEvent.dueDate(); | ||
390 | } | ||
391 | } | ||
392 | return false; | ||
393 | } | ||
394 | bool OTodo::operator>=(const OTodo &toDoEvent )const | ||
395 | { | ||
396 | if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true; | ||
397 | if( !hasDueDate() && toDoEvent.hasDueDate() ) return false; | ||
398 | if( hasDueDate() && toDoEvent.hasDueDate() ){ | ||
399 | if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide | ||
400 | return priority() > toDoEvent.priority(); | ||
401 | }else{ | ||
402 | return dueDate() > toDoEvent.dueDate(); | ||
403 | } | ||
404 | } | ||
405 | return true; | ||
406 | } | ||
407 | bool OTodo::operator==(const OTodo &toDoEvent )const | ||
408 | { | ||
409 | if ( data->priority != toDoEvent.data->priority ) return false; | ||
410 | if ( data->priority != toDoEvent.data->prog ) return false; | ||
411 | if ( data->isCompleted != toDoEvent.data->isCompleted ) return false; | ||
412 | if ( data->hasDate != toDoEvent.data->hasDate ) return false; | ||
413 | if ( data->date != toDoEvent.data->date ) return false; | ||
414 | if ( data->sum != toDoEvent.data->sum ) return false; | ||
415 | if ( data->desc != toDoEvent.data->desc ) return false; | ||
416 | if ( data->maintainer != toDoEvent.data->maintainer ) | ||
417 | return false; | ||
418 | |||
419 | return OPimRecord::operator==( toDoEvent ); | ||
420 | } | ||
421 | void OTodo::deref() { | ||
422 | |||
423 | // qWarning("deref in ToDoEvent"); | ||
424 | if ( data->deref() ) { | ||
425 | // qWarning("deleting"); | ||
426 | delete data; | ||
427 | data= 0; | ||
428 | } | ||
429 | } | ||
430 | OTodo &OTodo::operator=(const OTodo &item ) | ||
431 | { | ||
432 | if ( this == &item ) return *this; | ||
433 | |||
434 | OPimRecord::operator=( item ); | ||
435 | //qWarning("operator= ref "); | ||
436 | item.data->ref(); | ||
437 | deref(); | ||
438 | data = item.data; | ||
439 | |||
440 | return *this; | ||
441 | } | ||
442 | |||
443 | QMap<int, QString> OTodo::toMap() const { | ||
444 | QMap<int, QString> map; | ||
445 | |||
446 | map.insert( Uid, QString::number( uid() ) ); | ||
447 | map.insert( Category, idsToString( categories() ) ); | ||
448 | map.insert( HasDate, QString::number( data->hasDate ) ); | ||
449 | map.insert( Completed, QString::number( data->isCompleted ) ); | ||
450 | map.insert( Description, data->desc ); | ||
451 | map.insert( Summary, data->sum ); | ||
452 | map.insert( Priority, QString::number( data->priority ) ); | ||
453 | map.insert( DateDay, QString::number( data->date.day() ) ); | ||
454 | map.insert( DateMonth, QString::number( data->date.month() ) ); | ||
455 | map.insert( DateYear, QString::number( data->date.year() ) ); | ||
456 | map.insert( Progress, QString::number( data->prog ) ); | ||
457 | // map.insert( CrossReference, crossToString() ); | ||
458 | /* FIXME!!! map.insert( State, ); | ||
459 | map.insert( Recurrence, ); | ||
460 | map.insert( Reminders, ); | ||
461 | map. | ||
462 | */ | ||
463 | return map; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * change or modify looks at the ref count and either | ||
468 | * creates a new QShared Object or it can modify it | ||
469 | * right in place | ||
470 | */ | ||
471 | void OTodo::changeOrModify() { | ||
472 | if ( data->count != 1 ) { | ||
473 | qWarning("changeOrModify"); | ||
474 | data->deref(); | ||
475 | OTodoData* d2 = new OTodoData(); | ||
476 | copy(data, d2 ); | ||
477 | data = d2; | ||
478 | } | ||
479 | } | ||
480 | // WATCHOUT | ||
481 | /* | ||
482 | * if you add something to the Data struct | ||
483 | * be sure to copy it here | ||
484 | */ | ||
485 | void OTodo::copy( OTodoData* src, OTodoData* dest ) { | ||
486 | dest->date = src->date; | ||
487 | dest->isCompleted = src->isCompleted; | ||
488 | dest->hasDate = src->hasDate; | ||
489 | dest->priority = src->priority; | ||
490 | dest->desc = src->desc; | ||
491 | dest->sum = src->sum; | ||
492 | dest->extra = src->extra; | ||
493 | dest->prog = src->prog; | ||
494 | |||
495 | if (src->state ) | ||
496 | dest->state = new OPimState( *src->state ); | ||
497 | |||
498 | if (src->recur ) | ||
499 | dest->recur = new ORecur( *src->recur ); | ||
500 | |||
501 | if (src->maintainer ) | ||
502 | dest->maintainer = new OPimMaintainer( *src->maintainer ) | ||
503 | ; | ||
504 | dest->start = src->start; | ||
505 | dest->completed = src->completed; | ||
506 | |||
507 | if (src->notifiers ) | ||
508 | dest->notifiers = new OPimNotifyManager( *src->notifiers ); | ||
509 | } | ||
510 | QString OTodo::type() const { | ||
511 | return QString::fromLatin1("OTodo"); | ||
512 | } | ||
513 | QString OTodo::recordField(int /*id*/ )const { | ||
514 | return QString::null; | ||
515 | } | ||
516 | |||
517 | int OTodo::rtti(){ | ||
518 | return OPimResolver::TodoList; | ||
519 | } | ||
diff --git a/noncore/unsupported/libopie/pim/otodo.h b/noncore/unsupported/libopie/pim/otodo.h new file mode 100644 index 0000000..6df98b9 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodo.h | |||
@@ -0,0 +1,285 @@ | |||
1 | |||
2 | #ifndef OPIE_TODO_EVENT_H | ||
3 | #define OPIE_TODO_EVENT_H | ||
4 | |||
5 | |||
6 | #include <qarray.h> | ||
7 | #include <qmap.h> | ||
8 | #include <qregexp.h> | ||
9 | #include <qstringlist.h> | ||
10 | #include <qdatetime.h> | ||
11 | #include <qvaluelist.h> | ||
12 | |||
13 | #include <qpe/recordfields.h> | ||
14 | #include <qpe/palmtopuidgen.h> | ||
15 | |||
16 | #include <opie/opimrecord.h> | ||
17 | |||
18 | |||
19 | class OPimState; | ||
20 | class ORecur; | ||
21 | class OPimMaintainer; | ||
22 | class OPimNotifyManager; | ||
23 | class OTodo : public OPimRecord { | ||
24 | public: | ||
25 | typedef QValueList<OTodo> ValueList; | ||
26 | enum RecordFields { | ||
27 | Uid = Qtopia::UID_ID, | ||
28 | Category = Qtopia::CATEGORY_ID, | ||
29 | HasDate, | ||
30 | Completed, | ||
31 | Description, | ||
32 | Summary, | ||
33 | Priority, | ||
34 | DateDay, | ||
35 | DateMonth, | ||
36 | DateYear, | ||
37 | Progress, | ||
38 | CrossReference, | ||
39 | State, | ||
40 | Recurrence, | ||
41 | Alarms, | ||
42 | Reminders, | ||
43 | Notifiers, | ||
44 | Maintainer, | ||
45 | StartDate, | ||
46 | CompletedDate | ||
47 | }; | ||
48 | public: | ||
49 | // priorities from Very low to very high | ||
50 | enum TaskPriority { VeryHigh=1, High, Normal, Low, VeryLow }; | ||
51 | |||
52 | /* Constructs a new ToDoEvent | ||
53 | @param completed Is the TodoEvent completed | ||
54 | @param priority What is the priority of this ToDoEvent | ||
55 | @param category Which category does it belong( uid ) | ||
56 | @param summary A small summary of the todo | ||
57 | @param description What is this ToDoEvent about | ||
58 | @param hasDate Does this Event got a deadline | ||
59 | @param date what is the deadline? | ||
60 | @param uid what is the UUID of this Event | ||
61 | **/ | ||
62 | OTodo( bool completed = false, int priority = Normal, | ||
63 | const QStringList &category = QStringList(), | ||
64 | const QString &summary = QString::null , | ||
65 | const QString &description = QString::null, | ||
66 | ushort progress = 0, | ||
67 | bool hasDate = false, QDate date = QDate::currentDate(), | ||
68 | int uid = 0 /*empty*/ ); | ||
69 | |||
70 | OTodo( bool completed, int priority, | ||
71 | const QArray<int>& category, | ||
72 | const QString& summary = QString::null, | ||
73 | const QString& description = QString::null, | ||
74 | ushort progress = 0, | ||
75 | bool hasDate = false, QDate date = QDate::currentDate(), | ||
76 | int uid = 0 /* empty */ ); | ||
77 | |||
78 | /** Copy c'tor | ||
79 | * | ||
80 | */ | ||
81 | OTodo(const OTodo & ); | ||
82 | |||
83 | /** | ||
84 | *destructor | ||
85 | */ | ||
86 | ~OTodo(); | ||
87 | |||
88 | /** | ||
89 | * Is this event completed? | ||
90 | */ | ||
91 | bool isCompleted() const; | ||
92 | |||
93 | /** | ||
94 | * Does this Event have a deadline | ||
95 | */ | ||
96 | bool hasDueDate() const; | ||
97 | bool hasStartDate()const; | ||
98 | bool hasCompletedDate()const; | ||
99 | |||
100 | /** | ||
101 | * What is the priority? | ||
102 | */ | ||
103 | int priority()const ; | ||
104 | |||
105 | /** | ||
106 | * progress as ushort 0, 20, 40, 60, 80 or 100% | ||
107 | */ | ||
108 | ushort progress() const; | ||
109 | |||
110 | /** | ||
111 | * The due Date | ||
112 | */ | ||
113 | QDate dueDate()const; | ||
114 | |||
115 | /** | ||
116 | * When did it start? | ||
117 | */ | ||
118 | QDate startDate()const; | ||
119 | |||
120 | /** | ||
121 | * When was it completed? | ||
122 | */ | ||
123 | QDate completedDate()const; | ||
124 | |||
125 | /** | ||
126 | * does it have a state? | ||
127 | */ | ||
128 | bool hasState()const; | ||
129 | |||
130 | /** | ||
131 | * What is the state of this OTodo? | ||
132 | */ | ||
133 | OPimState state()const; | ||
134 | |||
135 | /** | ||
136 | * has recurrence? | ||
137 | */ | ||
138 | bool hasRecurrence()const; | ||
139 | |||
140 | /** | ||
141 | * the recurrance of this | ||
142 | */ | ||
143 | ORecur recurrence()const; | ||
144 | |||
145 | /** | ||
146 | * does this OTodo have a maintainer? | ||
147 | */ | ||
148 | bool hasMaintainer()const; | ||
149 | |||
150 | /** | ||
151 | * the Maintainer of this OTodo | ||
152 | */ | ||
153 | OPimMaintainer maintainer()const; | ||
154 | |||
155 | /** | ||
156 | * The description of the todo | ||
157 | */ | ||
158 | QString description()const; | ||
159 | |||
160 | /** | ||
161 | * A small summary of the todo | ||
162 | */ | ||
163 | QString summary() const; | ||
164 | |||
165 | /** | ||
166 | * @reimplemented | ||
167 | * Return this todoevent in a RichText formatted QString | ||
168 | */ | ||
169 | QString toRichText() const; | ||
170 | |||
171 | bool hasNotifiers()const; | ||
172 | /* | ||
173 | * FIXME check if the sharing is still fine!! -zecke | ||
174 | * ### CHECK If API is fine | ||
175 | */ | ||
176 | /** | ||
177 | * return a reference to our notifiers... | ||
178 | */ | ||
179 | OPimNotifyManager ¬ifiers(); | ||
180 | |||
181 | /** | ||
182 | * | ||
183 | */ | ||
184 | const OPimNotifyManager ¬ifiers()const; | ||
185 | |||
186 | /** | ||
187 | * reimplementations | ||
188 | */ | ||
189 | QString type()const; | ||
190 | QString toShortText()const; | ||
191 | QString recordField(int id )const; | ||
192 | |||
193 | /** | ||
194 | * toMap puts all data into the map. int relates | ||
195 | * to ToDoEvent RecordFields enum | ||
196 | */ | ||
197 | QMap<int, QString> toMap()const; | ||
198 | |||
199 | /** | ||
200 | * Set if this Todo is completed | ||
201 | */ | ||
202 | void setCompleted(bool completed ); | ||
203 | |||
204 | /** | ||
205 | * set if this todo got an end data | ||
206 | */ | ||
207 | void setHasDueDate( bool hasDate ); | ||
208 | // FIXME we do not have these for start, completed | ||
209 | // cause we'll use the isNull() of QDate for figuring | ||
210 | // out if it's has a date... | ||
211 | // decide what to do here? -zecke | ||
212 | |||
213 | /** | ||
214 | * Set the priority of the Todo | ||
215 | */ | ||
216 | void setPriority(int priority ); | ||
217 | |||
218 | /** | ||
219 | * Set the progress. | ||
220 | */ | ||
221 | void setProgress( ushort progress ); | ||
222 | |||
223 | /** | ||
224 | * set the end date | ||
225 | */ | ||
226 | void setDueDate( const QDate& date ); | ||
227 | |||
228 | /** | ||
229 | * set the start date | ||
230 | */ | ||
231 | void setStartDate( const QDate& date ); | ||
232 | |||
233 | /** | ||
234 | * set the completed date | ||
235 | */ | ||
236 | void setCompletedDate( const QDate& date ); | ||
237 | |||
238 | void setRecurrence( const ORecur& ); | ||
239 | |||
240 | void setDescription(const QString& ); | ||
241 | void setSummary(const QString& ); | ||
242 | |||
243 | /** | ||
244 | * set the state of a Todo | ||
245 | * @param state State what the todo should take | ||
246 | */ | ||
247 | void setState( const OPimState& state); | ||
248 | |||
249 | /** | ||
250 | * set the Maintainer Mode | ||
251 | */ | ||
252 | void setMaintainer( const OPimMaintainer& ); | ||
253 | |||
254 | bool isOverdue(); | ||
255 | |||
256 | |||
257 | virtual bool match( const QRegExp &r )const; | ||
258 | |||
259 | bool operator<(const OTodo &toDoEvent )const; | ||
260 | bool operator<=(const OTodo &toDoEvent )const; | ||
261 | bool operator!=(const OTodo &toDoEvent )const; | ||
262 | bool operator>(const OTodo &toDoEvent )const; | ||
263 | bool operator>=(const OTodo &toDoEvent)const; | ||
264 | bool operator==(const OTodo &toDoEvent )const; | ||
265 | OTodo &operator=(const OTodo &toDoEvent ); | ||
266 | |||
267 | static int rtti(); | ||
268 | |||
269 | private: | ||
270 | class OTodoPrivate; | ||
271 | struct OTodoData; | ||
272 | |||
273 | void deref(); | ||
274 | inline void changeOrModify(); | ||
275 | void copy( OTodoData* src, OTodoData* dest ); | ||
276 | OTodoPrivate *d; | ||
277 | OTodoData *data; | ||
278 | |||
279 | }; | ||
280 | inline bool OTodo::operator!=(const OTodo &toDoEvent )const { | ||
281 | return !(*this == toDoEvent); | ||
282 | } | ||
283 | |||
284 | |||
285 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccess.cpp b/noncore/unsupported/libopie/pim/otodoaccess.cpp new file mode 100644 index 0000000..37f6fbc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccess.cpp | |||
@@ -0,0 +1,62 @@ | |||
1 | #include <qdatetime.h> | ||
2 | |||
3 | #include <qpe/alarmserver.h> | ||
4 | |||
5 | // #include "otodoaccesssql.h" | ||
6 | #include "otodoaccess.h" | ||
7 | #include "obackendfactory.h" | ||
8 | |||
9 | OTodoAccess::OTodoAccess( OTodoAccessBackend* end, enum Access ) | ||
10 | : QObject(), OPimAccessTemplate<OTodo>( end ), m_todoBackEnd( end ) | ||
11 | { | ||
12 | // if (end == 0l ) | ||
13 | // m_todoBackEnd = new OTodoAccessBackendSQL( QString::null); | ||
14 | |||
15 | // Zecke: Du musst hier noch für das XML-Backend einen Appnamen übergeben ! | ||
16 | if (end == 0l ) | ||
17 | m_todoBackEnd = OBackendFactory<OTodoAccessBackend>::Default ("todo", QString::null); | ||
18 | |||
19 | setBackEnd( m_todoBackEnd ); | ||
20 | } | ||
21 | OTodoAccess::~OTodoAccess() { | ||
22 | // qWarning("~OTodoAccess"); | ||
23 | } | ||
24 | void OTodoAccess::mergeWith( const QValueList<OTodo>& list ) { | ||
25 | QValueList<OTodo>::ConstIterator it; | ||
26 | for ( it = list.begin(); it != list.end(); ++it ) { | ||
27 | replace( (*it) ); | ||
28 | } | ||
29 | } | ||
30 | OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, | ||
31 | const QDate& end, | ||
32 | bool includeNoDates ) { | ||
33 | QArray<int> ints = m_todoBackEnd->effectiveToDos( start, end, includeNoDates ); | ||
34 | |||
35 | List lis( ints, this ); | ||
36 | return lis; | ||
37 | } | ||
38 | OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, | ||
39 | bool includeNoDates ) { | ||
40 | return effectiveToDos( start, QDate::currentDate(), | ||
41 | includeNoDates ); | ||
42 | } | ||
43 | OTodoAccess::List OTodoAccess::overDue() { | ||
44 | List lis( m_todoBackEnd->overDue(), this ); | ||
45 | return lis; | ||
46 | } | ||
47 | /* sort order */ | ||
48 | OTodoAccess::List OTodoAccess::sorted( bool ascending, int sort,int filter, int cat ) { | ||
49 | QArray<int> ints = m_todoBackEnd->sorted( ascending, sort, | ||
50 | filter, cat ); | ||
51 | OTodoAccess::List list( ints, this ); | ||
52 | return list; | ||
53 | } | ||
54 | void OTodoAccess::removeAllCompleted() { | ||
55 | m_todoBackEnd->removeAllCompleted(); | ||
56 | } | ||
57 | QBitArray OTodoAccess::backendSupport( const QString& ) const{ | ||
58 | return m_todoBackEnd->supports(); | ||
59 | } | ||
60 | bool OTodoAccess::backendSupports( int attr, const QString& ar) const{ | ||
61 | return backendSupport(ar).testBit( attr ); | ||
62 | } | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccess.h b/noncore/unsupported/libopie/pim/otodoaccess.h new file mode 100644 index 0000000..916923f --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccess.h | |||
@@ -0,0 +1,105 @@ | |||
1 | #ifndef OPIE_TODO_ACCESS_H | ||
2 | #define OPIE_TODO_ACCESS_H | ||
3 | |||
4 | #include <qobject.h> | ||
5 | #include <qvaluelist.h> | ||
6 | |||
7 | #include "otodo.h" | ||
8 | #include "otodoaccessbackend.h" | ||
9 | #include "opimaccesstemplate.h" | ||
10 | |||
11 | |||
12 | /** | ||
13 | * OTodoAccess | ||
14 | * the class to get access to | ||
15 | * the todolist | ||
16 | */ | ||
17 | class OTodoAccess : public QObject, public OPimAccessTemplate<OTodo> { | ||
18 | Q_OBJECT | ||
19 | public: | ||
20 | enum SortOrder { Completed = 0, | ||
21 | Priority, | ||
22 | Description, | ||
23 | Deadline }; | ||
24 | enum SortFilter{ Category =1, | ||
25 | OnlyOverDue= 2, | ||
26 | DoNotShowCompleted =4 }; | ||
27 | /** | ||
28 | * if you use 0l | ||
29 | * the default resource will be | ||
30 | * picked up | ||
31 | */ | ||
32 | OTodoAccess( OTodoAccessBackend* = 0l, enum Access acc = Random ); | ||
33 | ~OTodoAccess(); | ||
34 | |||
35 | |||
36 | /* our functions here */ | ||
37 | /** | ||
38 | * include todos from start to end | ||
39 | * includeNoDates whether or not to include | ||
40 | * events with no dates | ||
41 | */ | ||
42 | List effectiveToDos( const QDate& start, | ||
43 | const QDate& end, | ||
44 | bool includeNoDates = true ); | ||
45 | |||
46 | /** | ||
47 | * start | ||
48 | * end date taken from the currentDate() | ||
49 | */ | ||
50 | List effectiveToDos( const QDate& start, | ||
51 | bool includeNoDates = true ); | ||
52 | |||
53 | |||
54 | /** | ||
55 | * return overdue OTodos | ||
56 | */ | ||
57 | List overDue(); | ||
58 | |||
59 | /** | ||
60 | * | ||
61 | */ | ||
62 | List sorted( bool ascending, int sortOrder, int sortFilter, int cat ); | ||
63 | |||
64 | /** | ||
65 | * merge a list of OTodos into | ||
66 | * the resource | ||
67 | */ | ||
68 | void mergeWith( const QValueList<OTodo>& ); | ||
69 | |||
70 | /** | ||
71 | * delete all already completed items | ||
72 | */ | ||
73 | void removeAllCompleted(); | ||
74 | |||
75 | /** | ||
76 | * request information about what a backend supports. | ||
77 | * Supports in the sense of beeing able to store. | ||
78 | * This is related to the enum in OTodo | ||
79 | * | ||
80 | * @param backend Will be used in the future when we support multiple backend | ||
81 | */ | ||
82 | QBitArray backendSupport( const QString& backend = QString::null )const; | ||
83 | |||
84 | /** | ||
85 | * see above but for a specefic attribute. This method was added for convience | ||
86 | * @param attr The attribute to be queried for | ||
87 | * @param backend Will be used in the future when we support multiple backends | ||
88 | */ | ||
89 | bool backendSupports( int attr, const QString& backend = QString::null )const; | ||
90 | signals: | ||
91 | /** | ||
92 | * if the OTodoAccess was changed | ||
93 | */ | ||
94 | void changed( const OTodoAccess* ); | ||
95 | void changed( const OTodoAccess*, int uid ); | ||
96 | void added( const OTodoAccess*, int uid ); | ||
97 | void removed( const OTodoAccess*, int uid ); | ||
98 | private: | ||
99 | int m_cat; | ||
100 | OTodoAccessBackend* m_todoBackEnd; | ||
101 | class OTodoAccessPrivate; | ||
102 | OTodoAccessPrivate* d; | ||
103 | }; | ||
104 | |||
105 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccessbackend.cpp b/noncore/unsupported/libopie/pim/otodoaccessbackend.cpp new file mode 100644 index 0000000..baaeecc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessbackend.cpp | |||
@@ -0,0 +1,10 @@ | |||
1 | |||
2 | #include "otodoaccessbackend.h" | ||
3 | |||
4 | OTodoAccessBackend::OTodoAccessBackend() | ||
5 | : OPimAccessBackend<OTodo>() | ||
6 | { | ||
7 | } | ||
8 | OTodoAccessBackend::~OTodoAccessBackend() { | ||
9 | |||
10 | } | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccessbackend.h b/noncore/unsupported/libopie/pim/otodoaccessbackend.h new file mode 100644 index 0000000..6be95bc --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessbackend.h | |||
@@ -0,0 +1,28 @@ | |||
1 | #ifndef OPIE_TODO_ACCESS_BACKEND_H | ||
2 | #define OPIE_TODO_ACCESS_BACKEND_H | ||
3 | |||
4 | #include <qbitarray.h> | ||
5 | |||
6 | #include "otodo.h" | ||
7 | #include "opimaccessbackend.h" | ||
8 | |||
9 | class OTodoAccessBackend : public OPimAccessBackend<OTodo> { | ||
10 | public: | ||
11 | OTodoAccessBackend(); | ||
12 | ~OTodoAccessBackend(); | ||
13 | virtual QArray<int> effectiveToDos( const QDate& start, | ||
14 | const QDate& end, | ||
15 | bool includeNoDates ) = 0; | ||
16 | virtual QArray<int> overDue() = 0; | ||
17 | virtual QArray<int> sorted( bool asc, int sortOrder, int sortFilter, | ||
18 | int cat ) = 0; | ||
19 | virtual void removeAllCompleted() = 0; | ||
20 | virtual QBitArray supports()const = 0; | ||
21 | |||
22 | private: | ||
23 | class Private; | ||
24 | Private *d; | ||
25 | |||
26 | }; | ||
27 | |||
28 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccesssql.cpp b/noncore/unsupported/libopie/pim/otodoaccesssql.cpp new file mode 100644 index 0000000..fd01a42 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccesssql.cpp | |||
@@ -0,0 +1,694 @@ | |||
1 | |||
2 | #include <qdatetime.h> | ||
3 | |||
4 | #include <qpe/global.h> | ||
5 | |||
6 | #include <opie2/osqldriver.h> | ||
7 | #include <opie2/osqlresult.h> | ||
8 | #include <opie2/osqlmanager.h> | ||
9 | #include <opie2/osqlquery.h> | ||
10 | |||
11 | #include "otodoaccesssql.h" | ||
12 | #include "opimstate.h" | ||
13 | #include "opimnotifymanager.h" | ||
14 | #include "orecur.h" | ||
15 | |||
16 | using namespace Opie::DB; | ||
17 | /* | ||
18 | * first some query | ||
19 | * CREATE query | ||
20 | * LOAD query | ||
21 | * INSERT | ||
22 | * REMOVE | ||
23 | * CLEAR | ||
24 | */ | ||
25 | namespace { | ||
26 | /** | ||
27 | * CreateQuery for the Todolist Table | ||
28 | */ | ||
29 | class CreateQuery : public OSQLQuery { | ||
30 | public: | ||
31 | CreateQuery(); | ||
32 | ~CreateQuery(); | ||
33 | QString query()const; | ||
34 | }; | ||
35 | |||
36 | /** | ||
37 | * LoadQuery | ||
38 | * this one queries for all uids | ||
39 | */ | ||
40 | class LoadQuery : public OSQLQuery { | ||
41 | public: | ||
42 | LoadQuery(); | ||
43 | ~LoadQuery(); | ||
44 | QString query()const; | ||
45 | }; | ||
46 | |||
47 | /** | ||
48 | * inserts/adds a OTodo to the table | ||
49 | */ | ||
50 | class InsertQuery : public OSQLQuery { | ||
51 | public: | ||
52 | InsertQuery(const OTodo& ); | ||
53 | ~InsertQuery(); | ||
54 | QString query()const; | ||
55 | private: | ||
56 | OTodo m_todo; | ||
57 | }; | ||
58 | |||
59 | /** | ||
60 | * removes one from the table | ||
61 | */ | ||
62 | class RemoveQuery : public OSQLQuery { | ||
63 | public: | ||
64 | RemoveQuery(int uid ); | ||
65 | ~RemoveQuery(); | ||
66 | QString query()const; | ||
67 | private: | ||
68 | int m_uid; | ||
69 | }; | ||
70 | |||
71 | /** | ||
72 | * Clears (delete) a Table | ||
73 | */ | ||
74 | class ClearQuery : public OSQLQuery { | ||
75 | public: | ||
76 | ClearQuery(); | ||
77 | ~ClearQuery(); | ||
78 | QString query()const; | ||
79 | |||
80 | }; | ||
81 | |||
82 | /** | ||
83 | * a find query | ||
84 | */ | ||
85 | class FindQuery : public OSQLQuery { | ||
86 | public: | ||
87 | FindQuery(int uid); | ||
88 | FindQuery(const QArray<int>& ); | ||
89 | ~FindQuery(); | ||
90 | QString query()const; | ||
91 | private: | ||
92 | QString single()const; | ||
93 | QString multi()const; | ||
94 | QArray<int> m_uids; | ||
95 | int m_uid; | ||
96 | }; | ||
97 | |||
98 | /** | ||
99 | * overdue query | ||
100 | */ | ||
101 | class OverDueQuery : public OSQLQuery { | ||
102 | public: | ||
103 | OverDueQuery(); | ||
104 | ~OverDueQuery(); | ||
105 | QString query()const; | ||
106 | }; | ||
107 | class EffQuery : public OSQLQuery { | ||
108 | public: | ||
109 | EffQuery( const QDate&, const QDate&, bool inc ); | ||
110 | ~EffQuery(); | ||
111 | QString query()const; | ||
112 | private: | ||
113 | QString with()const; | ||
114 | QString out()const; | ||
115 | QDate m_start; | ||
116 | QDate m_end; | ||
117 | bool m_inc :1; | ||
118 | }; | ||
119 | |||
120 | |||
121 | CreateQuery::CreateQuery() : OSQLQuery() {} | ||
122 | CreateQuery::~CreateQuery() {} | ||
123 | QString CreateQuery::query()const { | ||
124 | QString qu; | ||
125 | qu += "create table todolist( uid PRIMARY KEY, categories, completed, "; | ||
126 | qu += "description, summary, priority, DueDate, progress , state, "; | ||
127 | // This is the recurrance-stuff .. Exceptions are currently not supported (see ORecur.cpp) ! (eilers) | ||
128 | qu += "RType, RWeekdays, RPosition, RFreq, RHasEndDate, EndDate, Created, Exceptions, "; | ||
129 | qu += "reminders, alarms, maintainer, startdate, completeddate);"; | ||
130 | qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );"; | ||
131 | return qu; | ||
132 | } | ||
133 | |||
134 | LoadQuery::LoadQuery() : OSQLQuery() {} | ||
135 | LoadQuery::~LoadQuery() {} | ||
136 | QString LoadQuery::query()const { | ||
137 | QString qu; | ||
138 | // We do not need "distinct" here. The primary key is always unique.. | ||
139 | //qu += "select distinct uid from todolist"; | ||
140 | qu += "select uid from todolist"; | ||
141 | |||
142 | return qu; | ||
143 | } | ||
144 | |||
145 | InsertQuery::InsertQuery( const OTodo& todo ) | ||
146 | : OSQLQuery(), m_todo( todo ) { | ||
147 | } | ||
148 | InsertQuery::~InsertQuery() { | ||
149 | } | ||
150 | /* | ||
151 | * converts from a OTodo to a query | ||
152 | * we leave out X-Ref + Alarms | ||
153 | */ | ||
154 | QString InsertQuery::query()const{ | ||
155 | |||
156 | int year, month, day; | ||
157 | year = month = day = 0; | ||
158 | if (m_todo.hasDueDate() ) { | ||
159 | QDate date = m_todo.dueDate(); | ||
160 | year = date.year(); | ||
161 | month = date.month(); | ||
162 | day = date.day(); | ||
163 | } | ||
164 | int sYear = 0, sMonth = 0, sDay = 0; | ||
165 | if( m_todo.hasStartDate() ){ | ||
166 | QDate sDate = m_todo.startDate(); | ||
167 | sYear = sDate.year(); | ||
168 | sMonth= sDate.month(); | ||
169 | sDay = sDate.day(); | ||
170 | } | ||
171 | |||
172 | int eYear = 0, eMonth = 0, eDay = 0; | ||
173 | if( m_todo.hasCompletedDate() ){ | ||
174 | QDate eDate = m_todo.completedDate(); | ||
175 | eYear = eDate.year(); | ||
176 | eMonth= eDate.month(); | ||
177 | eDay = eDate.day(); | ||
178 | } | ||
179 | QString qu; | ||
180 | QMap<int, QString> recMap = m_todo.recurrence().toMap(); | ||
181 | qu = "insert into todolist VALUES(" | ||
182 | + QString::number( m_todo.uid() ) + "," | ||
183 | + "'" + m_todo.idsToString( m_todo.categories() ) + "'" + "," | ||
184 | + QString::number( m_todo.isCompleted() ) + "," | ||
185 | + "'" + m_todo.description() + "'" + "," | ||
186 | + "'" + m_todo.summary() + "'" + "," | ||
187 | + QString::number(m_todo.priority() ) + "," | ||
188 | + "'" + QString::number(year) + "-" | ||
189 | + QString::number(month) | ||
190 | + "-" + QString::number( day ) + "'" + "," | ||
191 | + QString::number( m_todo.progress() ) + "," | ||
192 | + QString::number( m_todo.state().state() ) + "," | ||
193 | + "'" + recMap[ ORecur::RType ] + "'" + "," | ||
194 | + "'" + recMap[ ORecur::RWeekdays ] + "'" + "," | ||
195 | + "'" + recMap[ ORecur::RPosition ] + "'" + "," | ||
196 | + "'" + recMap[ ORecur::RFreq ] + "'" + "," | ||
197 | + "'" + recMap[ ORecur::RHasEndDate ] + "'" + "," | ||
198 | + "'" + recMap[ ORecur::EndDate ] + "'" + "," | ||
199 | + "'" + recMap[ ORecur::Created ] + "'" + "," | ||
200 | + "'" + recMap[ ORecur::Exceptions ] + "'" + ","; | ||
201 | |||
202 | if ( m_todo.hasNotifiers() ) { | ||
203 | OPimNotifyManager manager = m_todo.notifiers(); | ||
204 | qu += "'" + manager.remindersToString() + "'" + "," | ||
205 | + "'" + manager.alarmsToString() + "'" + ","; | ||
206 | } | ||
207 | else{ | ||
208 | qu += QString( "''" ) + "," | ||
209 | + "''" + ","; | ||
210 | } | ||
211 | |||
212 | qu += QString( "''" ) + QString( "," ) // Maintainers (cur. not supported !) | ||
213 | + "'" + QString::number(sYear) + "-" | ||
214 | + QString::number(sMonth) | ||
215 | + "-" + QString::number(sDay) + "'" + "," | ||
216 | + "'" + QString::number(eYear) + "-" | ||
217 | + QString::number(eMonth) | ||
218 | + "-"+QString::number(eDay) + "'" | ||
219 | + ")"; | ||
220 | |||
221 | qWarning("add %s", qu.latin1() ); | ||
222 | return qu; | ||
223 | } | ||
224 | |||
225 | RemoveQuery::RemoveQuery(int uid ) | ||
226 | : OSQLQuery(), m_uid( uid ) {} | ||
227 | RemoveQuery::~RemoveQuery() {} | ||
228 | QString RemoveQuery::query()const { | ||
229 | QString qu = "DELETE from todolist where uid = " + QString::number(m_uid); | ||
230 | return qu; | ||
231 | } | ||
232 | |||
233 | |||
234 | ClearQuery::ClearQuery() | ||
235 | : OSQLQuery() {} | ||
236 | ClearQuery::~ClearQuery() {} | ||
237 | QString ClearQuery::query()const { | ||
238 | QString qu = "drop table todolist"; | ||
239 | return qu; | ||
240 | } | ||
241 | FindQuery::FindQuery(int uid) | ||
242 | : OSQLQuery(), m_uid(uid ) { | ||
243 | } | ||
244 | FindQuery::FindQuery(const QArray<int>& ints) | ||
245 | : OSQLQuery(), m_uids(ints){ | ||
246 | } | ||
247 | FindQuery::~FindQuery() { | ||
248 | } | ||
249 | QString FindQuery::query()const{ | ||
250 | if (m_uids.count() == 0 ) | ||
251 | return single(); | ||
252 | else | ||
253 | return multi(); | ||
254 | } | ||
255 | QString FindQuery::single()const{ | ||
256 | QString qu = "select * from todolist where uid = " + QString::number(m_uid); | ||
257 | return qu; | ||
258 | } | ||
259 | QString FindQuery::multi()const { | ||
260 | QString qu = "select * from todolist where "; | ||
261 | for (uint i = 0; i < m_uids.count(); i++ ) { | ||
262 | qu += " UID = " + QString::number( m_uids[i] ) + " OR"; | ||
263 | } | ||
264 | qu.remove( qu.length()-2, 2 ); | ||
265 | return qu; | ||
266 | } | ||
267 | |||
268 | OverDueQuery::OverDueQuery(): OSQLQuery() {} | ||
269 | OverDueQuery::~OverDueQuery() {} | ||
270 | QString OverDueQuery::query()const { | ||
271 | QDate date = QDate::currentDate(); | ||
272 | QString str; | ||
273 | str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() ); | ||
274 | |||
275 | return str; | ||
276 | } | ||
277 | |||
278 | |||
279 | EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc ) | ||
280 | : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {} | ||
281 | EffQuery::~EffQuery() {} | ||
282 | QString EffQuery::query()const { | ||
283 | return m_inc ? with() : out(); | ||
284 | } | ||
285 | QString EffQuery::with()const { | ||
286 | QString str; | ||
287 | str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") | ||
288 | .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) | ||
289 | .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); | ||
290 | return str; | ||
291 | } | ||
292 | QString EffQuery::out()const { | ||
293 | QString str; | ||
294 | str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") | ||
295 | .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) | ||
296 | .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); | ||
297 | |||
298 | return str; | ||
299 | } | ||
300 | }; | ||
301 | |||
302 | OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) | ||
303 | : OTodoAccessBackend(), m_dict(15), m_driver(NULL), m_dirty(true) | ||
304 | { | ||
305 | QString fi = file; | ||
306 | if ( fi.isEmpty() ) | ||
307 | fi = Global::applicationFileName( "todolist", "todolist.db" ); | ||
308 | OSQLManager man; | ||
309 | m_driver = man.standard(); | ||
310 | m_driver->setUrl(fi); | ||
311 | // fillDict(); | ||
312 | } | ||
313 | |||
314 | OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ | ||
315 | if( m_driver ) | ||
316 | delete m_driver; | ||
317 | } | ||
318 | |||
319 | bool OTodoAccessBackendSQL::load(){ | ||
320 | if (!m_driver->open() ) | ||
321 | return false; | ||
322 | |||
323 | CreateQuery creat; | ||
324 | OSQLResult res = m_driver->query(&creat ); | ||
325 | |||
326 | m_dirty = true; | ||
327 | return true; | ||
328 | } | ||
329 | bool OTodoAccessBackendSQL::reload(){ | ||
330 | return load(); | ||
331 | } | ||
332 | |||
333 | bool OTodoAccessBackendSQL::save(){ | ||
334 | return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) | ||
335 | } | ||
336 | QArray<int> OTodoAccessBackendSQL::allRecords()const { | ||
337 | if (m_dirty ) | ||
338 | update(); | ||
339 | |||
340 | return m_uids; | ||
341 | } | ||
342 | QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){ | ||
343 | QArray<int> ints(0); | ||
344 | return ints; | ||
345 | } | ||
346 | OTodo OTodoAccessBackendSQL::find(int uid ) const{ | ||
347 | FindQuery query( uid ); | ||
348 | return todo( m_driver->query(&query) ); | ||
349 | |||
350 | } | ||
351 | OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, | ||
352 | uint cur, Frontend::CacheDirection dir ) const{ | ||
353 | uint CACHE = readAhead(); | ||
354 | qWarning("searching for %d", uid ); | ||
355 | QArray<int> search( CACHE ); | ||
356 | uint size =0; | ||
357 | OTodo to; | ||
358 | |||
359 | // we try to cache CACHE items | ||
360 | switch( dir ) { | ||
361 | /* forward */ | ||
362 | case 0: // FIXME: Not a good style to use magic numbers here (eilers) | ||
363 | for (uint i = cur; i < ints.count() && size < CACHE; i++ ) { | ||
364 | qWarning("size %d %d", size, ints[i] ); | ||
365 | search[size] = ints[i]; | ||
366 | size++; | ||
367 | } | ||
368 | break; | ||
369 | /* reverse */ | ||
370 | case 1: // FIXME: Not a good style to use magic numbers here (eilers) | ||
371 | for (uint i = cur; i != 0 && size < CACHE; i-- ) { | ||
372 | search[size] = ints[i]; | ||
373 | size++; | ||
374 | } | ||
375 | break; | ||
376 | } | ||
377 | search.resize( size ); | ||
378 | FindQuery query( search ); | ||
379 | OSQLResult res = m_driver->query( &query ); | ||
380 | if ( res.state() != OSQLResult::Success ) | ||
381 | return to; | ||
382 | |||
383 | return todo( res ); | ||
384 | } | ||
385 | void OTodoAccessBackendSQL::clear() { | ||
386 | ClearQuery cle; | ||
387 | OSQLResult res = m_driver->query( &cle ); | ||
388 | CreateQuery qu; | ||
389 | res = m_driver->query(&qu); | ||
390 | } | ||
391 | bool OTodoAccessBackendSQL::add( const OTodo& t) { | ||
392 | InsertQuery ins( t ); | ||
393 | OSQLResult res = m_driver->query( &ins ); | ||
394 | |||
395 | if ( res.state() == OSQLResult::Failure ) | ||
396 | return false; | ||
397 | int c = m_uids.count(); | ||
398 | m_uids.resize( c+1 ); | ||
399 | m_uids[c] = t.uid(); | ||
400 | |||
401 | return true; | ||
402 | } | ||
403 | bool OTodoAccessBackendSQL::remove( int uid ) { | ||
404 | RemoveQuery rem( uid ); | ||
405 | OSQLResult res = m_driver->query(&rem ); | ||
406 | |||
407 | if ( res.state() == OSQLResult::Failure ) | ||
408 | return false; | ||
409 | |||
410 | m_dirty = true; | ||
411 | return true; | ||
412 | } | ||
413 | /* | ||
414 | * FIXME better set query | ||
415 | * but we need the cache for that | ||
416 | * now we remove | ||
417 | */ | ||
418 | bool OTodoAccessBackendSQL::replace( const OTodo& t) { | ||
419 | remove( t.uid() ); | ||
420 | bool b= add(t); | ||
421 | m_dirty = false; // we changed some stuff but the UID stayed the same | ||
422 | return b; | ||
423 | } | ||
424 | QArray<int> OTodoAccessBackendSQL::overDue() { | ||
425 | OverDueQuery qu; | ||
426 | return uids( m_driver->query(&qu ) ); | ||
427 | } | ||
428 | QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s, | ||
429 | const QDate& t, | ||
430 | bool u) { | ||
431 | EffQuery ef(s, t, u ); | ||
432 | return uids (m_driver->query(&ef) ); | ||
433 | } | ||
434 | /* | ||
435 | * | ||
436 | */ | ||
437 | QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder, | ||
438 | int sortFilter, int cat ) { | ||
439 | qWarning("sorted %d, %d", asc, sortOrder ); | ||
440 | QString query; | ||
441 | query = "select uid from todolist WHERE "; | ||
442 | |||
443 | /* | ||
444 | * Sort Filter stuff | ||
445 | * not that straight forward | ||
446 | * FIXME: Replace magic numbers | ||
447 | * | ||
448 | */ | ||
449 | /* Category */ | ||
450 | if ( sortFilter & 1 ) { | ||
451 | QString str; | ||
452 | if (cat != 0 ) str = QString::number( cat ); | ||
453 | query += " categories like '%" +str+"%' AND"; | ||
454 | } | ||
455 | /* Show only overdue */ | ||
456 | if ( sortFilter & 2 ) { | ||
457 | QDate date = QDate::currentDate(); | ||
458 | QString due; | ||
459 | QString base; | ||
460 | base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() ); | ||
461 | query += " " + base + " AND"; | ||
462 | } | ||
463 | /* not show completed */ | ||
464 | if ( sortFilter & 4 ) { | ||
465 | query += " completed = 0 AND"; | ||
466 | }else{ | ||
467 | query += " ( completed = 1 OR completed = 0) AND"; | ||
468 | } | ||
469 | /* srtip the end */ | ||
470 | query = query.remove( query.length()-3, 3 ); | ||
471 | |||
472 | |||
473 | /* | ||
474 | * sort order stuff | ||
475 | * quite straight forward | ||
476 | */ | ||
477 | query += "ORDER BY "; | ||
478 | switch( sortOrder ) { | ||
479 | /* completed */ | ||
480 | case 0: | ||
481 | query += "completed"; | ||
482 | break; | ||
483 | case 1: | ||
484 | query += "priority"; | ||
485 | break; | ||
486 | case 2: | ||
487 | query += "summary"; | ||
488 | break; | ||
489 | case 3: | ||
490 | query += "DueDate"; | ||
491 | break; | ||
492 | } | ||
493 | |||
494 | if ( !asc ) { | ||
495 | qWarning("not ascending!"); | ||
496 | query += " DESC"; | ||
497 | } | ||
498 | |||
499 | qWarning( query ); | ||
500 | OSQLRawQuery raw(query ); | ||
501 | return uids( m_driver->query(&raw) ); | ||
502 | } | ||
503 | bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{ | ||
504 | if ( str == "0-0-0" ) | ||
505 | return false; | ||
506 | else{ | ||
507 | int day, year, month; | ||
508 | QStringList list = QStringList::split("-", str ); | ||
509 | year = list[0].toInt(); | ||
510 | month = list[1].toInt(); | ||
511 | day = list[2].toInt(); | ||
512 | da.setYMD( year, month, day ); | ||
513 | return true; | ||
514 | } | ||
515 | } | ||
516 | OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{ | ||
517 | if ( res.state() == OSQLResult::Failure ) { | ||
518 | OTodo to; | ||
519 | return to; | ||
520 | } | ||
521 | |||
522 | OSQLResultItem::ValueList list = res.results(); | ||
523 | OSQLResultItem::ValueList::Iterator it = list.begin(); | ||
524 | qWarning("todo1"); | ||
525 | OTodo to = todo( (*it) ); | ||
526 | cache( to ); | ||
527 | ++it; | ||
528 | |||
529 | for ( ; it != list.end(); ++it ) { | ||
530 | qWarning("caching"); | ||
531 | cache( todo( (*it) ) ); | ||
532 | } | ||
533 | return to; | ||
534 | } | ||
535 | OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const { | ||
536 | qWarning("todo"); | ||
537 | bool hasDueDate = false; QDate dueDate = QDate::currentDate(); | ||
538 | hasDueDate = date( dueDate, item.data("DueDate") ); | ||
539 | QStringList cats = QStringList::split(";", item.data("categories") ); | ||
540 | |||
541 | qWarning("Item is completed: %d", item.data("completed").toInt() ); | ||
542 | |||
543 | OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(), | ||
544 | cats, item.data("summary"), item.data("description"), | ||
545 | item.data("progress").toUShort(), hasDueDate, dueDate, | ||
546 | item.data("uid").toInt() ); | ||
547 | |||
548 | bool isOk; | ||
549 | int prioInt = QString( item.data("priority") ).toInt( &isOk ); | ||
550 | if ( isOk ) | ||
551 | to.setPriority( prioInt ); | ||
552 | |||
553 | bool hasStartDate = false; QDate startDate = QDate::currentDate(); | ||
554 | hasStartDate = date( startDate, item.data("startdate") ); | ||
555 | bool hasCompletedDate = false; QDate completedDate = QDate::currentDate(); | ||
556 | hasCompletedDate = date( completedDate, item.data("completeddate") ); | ||
557 | |||
558 | if ( hasStartDate ) | ||
559 | to.setStartDate( startDate ); | ||
560 | if ( hasCompletedDate ) | ||
561 | to.setCompletedDate( completedDate ); | ||
562 | |||
563 | OPimNotifyManager& manager = to.notifiers(); | ||
564 | manager.alarmsFromString( item.data("alarms") ); | ||
565 | manager.remindersFromString( item.data("reminders") ); | ||
566 | |||
567 | OPimState pimState; | ||
568 | pimState.setState( QString( item.data("state") ).toInt() ); | ||
569 | to.setState( pimState ); | ||
570 | |||
571 | QMap<int, QString> recMap; | ||
572 | recMap.insert( ORecur::RType , item.data("RType") ); | ||
573 | recMap.insert( ORecur::RWeekdays , item.data("RWeekdays") ); | ||
574 | recMap.insert( ORecur::RPosition , item.data("RPosition") ); | ||
575 | recMap.insert( ORecur::RFreq , item.data("RFreq") ); | ||
576 | recMap.insert( ORecur::RHasEndDate, item.data("RHasEndDate") ); | ||
577 | recMap.insert( ORecur::EndDate , item.data("EndDate") ); | ||
578 | recMap.insert( ORecur::Created , item.data("Created") ); | ||
579 | recMap.insert( ORecur::Exceptions , item.data("Exceptions") ); | ||
580 | |||
581 | ORecur recur; | ||
582 | recur.fromMap( recMap ); | ||
583 | to.setRecurrence( recur ); | ||
584 | |||
585 | return to; | ||
586 | } | ||
587 | OTodo OTodoAccessBackendSQL::todo( int uid )const { | ||
588 | FindQuery find( uid ); | ||
589 | return todo( m_driver->query(&find) ); | ||
590 | } | ||
591 | /* | ||
592 | * update the dict | ||
593 | */ | ||
594 | void OTodoAccessBackendSQL::fillDict() { | ||
595 | /* initialize dict */ | ||
596 | /* | ||
597 | * UPDATE dict if you change anything!!! | ||
598 | * FIXME: Isn't this dict obsolete ? (eilers) | ||
599 | */ | ||
600 | m_dict.setAutoDelete( TRUE ); | ||
601 | m_dict.insert("Categories" , new int(OTodo::Category) ); | ||
602 | m_dict.insert("Uid" , new int(OTodo::Uid) ); | ||
603 | m_dict.insert("HasDate" , new int(OTodo::HasDate) ); | ||
604 | m_dict.insert("Completed" , new int(OTodo::Completed) ); | ||
605 | m_dict.insert("Description" , new int(OTodo::Description) ); | ||
606 | m_dict.insert("Summary" , new int(OTodo::Summary) ); | ||
607 | m_dict.insert("Priority" , new int(OTodo::Priority) ); | ||
608 | m_dict.insert("DateDay" , new int(OTodo::DateDay) ); | ||
609 | m_dict.insert("DateMonth" , new int(OTodo::DateMonth) ); | ||
610 | m_dict.insert("DateYear" , new int(OTodo::DateYear) ); | ||
611 | m_dict.insert("Progress" , new int(OTodo::Progress) ); | ||
612 | m_dict.insert("Completed", new int(OTodo::Completed) ); // Why twice ? (eilers) | ||
613 | m_dict.insert("CrossReference", new int(OTodo::CrossReference) ); | ||
614 | // m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) ); // old stuff (eilers) | ||
615 | // m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) ); // old stuff (eilers) | ||
616 | } | ||
617 | /* | ||
618 | * need to be const so let's fool the | ||
619 | * compiler :( | ||
620 | */ | ||
621 | void OTodoAccessBackendSQL::update()const { | ||
622 | ((OTodoAccessBackendSQL*)this)->m_dirty = false; | ||
623 | LoadQuery lo; | ||
624 | OSQLResult res = m_driver->query(&lo); | ||
625 | if ( res.state() != OSQLResult::Success ) | ||
626 | return; | ||
627 | |||
628 | ((OTodoAccessBackendSQL*)this)->m_uids = uids( res ); | ||
629 | } | ||
630 | QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{ | ||
631 | |||
632 | OSQLResultItem::ValueList list = res.results(); | ||
633 | OSQLResultItem::ValueList::Iterator it; | ||
634 | QArray<int> ints(list.count() ); | ||
635 | qWarning(" count = %d", list.count() ); | ||
636 | |||
637 | int i = 0; | ||
638 | for (it = list.begin(); it != list.end(); ++it ) { | ||
639 | ints[i] = (*it).data("uid").toInt(); | ||
640 | i++; | ||
641 | } | ||
642 | return ints; | ||
643 | } | ||
644 | |||
645 | QArray<int> OTodoAccessBackendSQL::matchRegexp( const QRegExp &r ) const | ||
646 | { | ||
647 | |||
648 | #warning OTodoAccessBackendSQL::matchRegexp() not implemented !! | ||
649 | |||
650 | #if 0 | ||
651 | |||
652 | Copied from xml-backend by not adapted to sql (eilers) | ||
653 | |||
654 | QArray<int> m_currentQuery( m_events.count() ); | ||
655 | uint arraycounter = 0; | ||
656 | |||
657 | |||
658 | |||
659 | QMap<int, OTodo>::ConstIterator it; | ||
660 | for (it = m_events.begin(); it != m_events.end(); ++it ) { | ||
661 | if ( it.data().match( r ) ) | ||
662 | m_currentQuery[arraycounter++] = it.data().uid(); | ||
663 | |||
664 | } | ||
665 | // Shrink to fit.. | ||
666 | m_currentQuery.resize(arraycounter); | ||
667 | |||
668 | return m_currentQuery; | ||
669 | #endif | ||
670 | QArray<int> empty; | ||
671 | return empty; | ||
672 | } | ||
673 | QBitArray OTodoAccessBackendSQL::supports()const { | ||
674 | |||
675 | return sup(); | ||
676 | } | ||
677 | |||
678 | QBitArray OTodoAccessBackendSQL::sup() const{ | ||
679 | |||
680 | QBitArray ar( OTodo::CompletedDate + 1 ); | ||
681 | ar.fill( true ); | ||
682 | ar[OTodo::CrossReference] = false; | ||
683 | ar[OTodo::State ] = false; | ||
684 | ar[OTodo::Reminders] = false; | ||
685 | ar[OTodo::Notifiers] = false; | ||
686 | ar[OTodo::Maintainer] = false; | ||
687 | |||
688 | return ar; | ||
689 | } | ||
690 | |||
691 | void OTodoAccessBackendSQL::removeAllCompleted(){ | ||
692 | #warning OTodoAccessBackendSQL::removeAllCompleted() not implemented !! | ||
693 | |||
694 | } | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccesssql.h b/noncore/unsupported/libopie/pim/otodoaccesssql.h new file mode 100644 index 0000000..72214de --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccesssql.h | |||
@@ -0,0 +1,61 @@ | |||
1 | #ifndef OPIE_PIM_ACCESS_SQL_H | ||
2 | #define OPIE_PIM_ACCESS_SQL_H | ||
3 | |||
4 | #include <qasciidict.h> | ||
5 | |||
6 | #include "otodoaccessbackend.h" | ||
7 | |||
8 | namespace Opie{ | ||
9 | namespace DB { | ||
10 | class OSQLDriver; | ||
11 | class OSQLResult; | ||
12 | class OSQLResultItem; | ||
13 | } | ||
14 | } | ||
15 | |||
16 | class OTodoAccessBackendSQL : public OTodoAccessBackend { | ||
17 | public: | ||
18 | OTodoAccessBackendSQL( const QString& file ); | ||
19 | ~OTodoAccessBackendSQL(); | ||
20 | |||
21 | bool load(); | ||
22 | bool reload(); | ||
23 | bool save(); | ||
24 | QArray<int> allRecords()const; | ||
25 | |||
26 | QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() ); | ||
27 | OTodo find(int uid)const; | ||
28 | OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; | ||
29 | void clear(); | ||
30 | bool add( const OTodo& t ); | ||
31 | bool remove( int uid ); | ||
32 | bool replace( const OTodo& t ); | ||
33 | |||
34 | QArray<int> overDue(); | ||
35 | QArray<int> effectiveToDos( const QDate& start, | ||
36 | const QDate& end, bool includeNoDates ); | ||
37 | QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); | ||
38 | |||
39 | QBitArray supports()const; | ||
40 | QArray<int> matchRegexp( const QRegExp &r ) const; | ||
41 | void removeAllCompleted(); | ||
42 | |||
43 | |||
44 | private: | ||
45 | void update()const; | ||
46 | void fillDict(); | ||
47 | inline bool date( QDate& date, const QString& )const; | ||
48 | inline OTodo todo( const Opie::DB::OSQLResult& )const; | ||
49 | inline OTodo todo( Opie::DB::OSQLResultItem& )const; | ||
50 | inline QArray<int> uids( const Opie::DB::OSQLResult& )const; | ||
51 | OTodo todo( int uid )const; | ||
52 | QBitArray sup() const; | ||
53 | |||
54 | QAsciiDict<int> m_dict; | ||
55 | Opie::DB::OSQLDriver* m_driver; | ||
56 | QArray<int> m_uids; | ||
57 | bool m_dirty : 1; | ||
58 | }; | ||
59 | |||
60 | |||
61 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccessvcal.cpp b/noncore/unsupported/libopie/pim/otodoaccessvcal.cpp new file mode 100644 index 0000000..6415952 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessvcal.cpp | |||
@@ -0,0 +1,249 @@ | |||
1 | #include <qfile.h> | ||
2 | |||
3 | #include <qtopia/private/vobject_p.h> | ||
4 | #include <qtopia/timeconversion.h> | ||
5 | #include <qtopia/private/qfiledirect_p.h> | ||
6 | |||
7 | #include "otodoaccessvcal.h" | ||
8 | |||
9 | namespace { | ||
10 | static OTodo eventByVObj( VObject *obj ){ | ||
11 | OTodo event; | ||
12 | VObject *ob; | ||
13 | QCString name; | ||
14 | // no uid, attendees, ... and no fun | ||
15 | // description | ||
16 | if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){ | ||
17 | name = vObjectStringZValue( ob ); | ||
18 | #if 0 | ||
19 | event.setDescription( name ); | ||
20 | #else | ||
21 | event.setSummary( name ); | ||
22 | #endif | ||
23 | } | ||
24 | // summary | ||
25 | if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) { | ||
26 | name = vObjectStringZValue( ob ); | ||
27 | #if 0 | ||
28 | event.setSummary( name ); | ||
29 | #else | ||
30 | event.setDescription( name ); | ||
31 | #endif | ||
32 | } | ||
33 | // completed | ||
34 | if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){ | ||
35 | name = vObjectStringZValue( ob ); | ||
36 | if( name == "COMPLETED" ){ | ||
37 | event.setCompleted( true ); | ||
38 | }else{ | ||
39 | event.setCompleted( false ); | ||
40 | } | ||
41 | }else | ||
42 | event.setCompleted( false ); | ||
43 | // priority | ||
44 | if ((ob = isAPropertyOf(obj, VCPriorityProp))) { | ||
45 | name = vObjectStringZValue( ob ); | ||
46 | bool ok; | ||
47 | event.setPriority(name.toInt(&ok) ); | ||
48 | } | ||
49 | //due date | ||
50 | if((ob = isAPropertyOf(obj, VCDueProp)) ){ | ||
51 | event.setHasDueDate( true ); | ||
52 | name = vObjectStringZValue( ob ); | ||
53 | event.setDueDate( TimeConversion::fromISO8601( name).date() ); | ||
54 | } | ||
55 | // categories | ||
56 | if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){ | ||
57 | name = vObjectStringZValue( ob ); | ||
58 | qWarning("Categories:%s", name.data() ); | ||
59 | } | ||
60 | |||
61 | event.setUid( 1 ); | ||
62 | return event; | ||
63 | }; | ||
64 | static VObject *vobjByEvent( const OTodo &event ) { | ||
65 | VObject *task = newVObject( VCTodoProp ); | ||
66 | if( task == 0 ) | ||
67 | return 0l; | ||
68 | |||
69 | if( event.hasDueDate() ) { | ||
70 | QTime time(0, 0, 0); | ||
71 | QDateTime date(event.dueDate(), time ); | ||
72 | addPropValue( task, VCDueProp, | ||
73 | TimeConversion::toISO8601( date ) ); | ||
74 | } | ||
75 | |||
76 | if( event.isCompleted() ) | ||
77 | addPropValue( task, VCStatusProp, "COMPLETED"); | ||
78 | |||
79 | QString string = QString::number(event.priority() ); | ||
80 | addPropValue( task, VCPriorityProp, string.local8Bit() ); | ||
81 | |||
82 | addPropValue( task, VCCategoriesProp, | ||
83 | event.idsToString( event.categories() ).local8Bit() ); | ||
84 | |||
85 | #if 0 | ||
86 | |||
87 | // There seems a misrepresentation between summary in otodoevent | ||
88 | // and summary in vcard. | ||
89 | // The same with description.. | ||
90 | // Description is summary and vice versa.. Argh.. (eilers) | ||
91 | |||
92 | |||
93 | addPropValue( task, VCDescriptionProp, | ||
94 | event.description().local8Bit() ); | ||
95 | |||
96 | addPropValue( task, VCSummaryProp, | ||
97 | event.summary().local8Bit() ); | ||
98 | |||
99 | #else | ||
100 | addPropValue( task, VCDescriptionProp, | ||
101 | event.summary().local8Bit() ); | ||
102 | |||
103 | addPropValue( task, VCSummaryProp, | ||
104 | event.description().local8Bit() ); | ||
105 | #endif | ||
106 | return task; | ||
107 | }; | ||
108 | } | ||
109 | |||
110 | OTodoAccessVCal::OTodoAccessVCal( const QString& path ) | ||
111 | : m_dirty(false), m_file( path ) | ||
112 | { | ||
113 | } | ||
114 | OTodoAccessVCal::~OTodoAccessVCal() { | ||
115 | } | ||
116 | bool OTodoAccessVCal::load() { | ||
117 | m_map.clear(); | ||
118 | m_dirty = false; | ||
119 | |||
120 | VObject* vcal = 0l; | ||
121 | vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); | ||
122 | if (!vcal ) | ||
123 | return false; | ||
124 | |||
125 | // Iterate over the list | ||
126 | VObjectIterator it; | ||
127 | VObject* vobj; | ||
128 | |||
129 | initPropIterator(&it, vcal); | ||
130 | |||
131 | while( moreIteration( &it ) ) { | ||
132 | vobj = ::nextVObject( &it ); | ||
133 | QCString name = ::vObjectName( vobj ); | ||
134 | if( name == VCTodoProp ){ | ||
135 | OTodo to = eventByVObj( vobj ); | ||
136 | m_map.insert( to.uid(), to ); | ||
137 | } | ||
138 | } | ||
139 | |||
140 | // Should I do a delete vcal? | ||
141 | |||
142 | return true; | ||
143 | } | ||
144 | bool OTodoAccessVCal::reload() { | ||
145 | return load(); | ||
146 | } | ||
147 | bool OTodoAccessVCal::save() { | ||
148 | if (!m_dirty ) | ||
149 | return true; | ||
150 | |||
151 | QFileDirect file( m_file ); | ||
152 | if (!file.open(IO_WriteOnly ) ) | ||
153 | return false; | ||
154 | |||
155 | VObject *obj; | ||
156 | obj = newVObject( VCCalProp ); | ||
157 | addPropValue( obj, VCVersionProp, "1.0" ); | ||
158 | VObject *vo; | ||
159 | for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ | ||
160 | vo = vobjByEvent( it.data() ); | ||
161 | addVObjectProp(obj, vo ); | ||
162 | } | ||
163 | writeVObject( file.directHandle(), obj ); | ||
164 | cleanVObject( obj ); | ||
165 | cleanStrTbl(); | ||
166 | |||
167 | m_dirty = false; | ||
168 | return true; | ||
169 | } | ||
170 | void OTodoAccessVCal::clear() { | ||
171 | m_map.clear(); | ||
172 | m_dirty = true; | ||
173 | } | ||
174 | bool OTodoAccessVCal::add( const OTodo& to ) { | ||
175 | m_map.insert( to.uid(), to ); | ||
176 | m_dirty = true; | ||
177 | return true; | ||
178 | } | ||
179 | bool OTodoAccessVCal::remove( int uid ) { | ||
180 | m_map.remove( uid ); | ||
181 | m_dirty = true; | ||
182 | return true; | ||
183 | } | ||
184 | void OTodoAccessVCal::removeAllCompleted() { | ||
185 | for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) { | ||
186 | if ( (*it).isCompleted() ) | ||
187 | m_map.remove( it ); | ||
188 | } | ||
189 | } | ||
190 | bool OTodoAccessVCal::replace( const OTodo& to ) { | ||
191 | m_map.replace( to.uid(), to ); | ||
192 | m_dirty = true; | ||
193 | return true; | ||
194 | } | ||
195 | OTodo OTodoAccessVCal::find(int uid )const { | ||
196 | return m_map[uid]; | ||
197 | } | ||
198 | QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) { | ||
199 | QArray<int> ar(0); | ||
200 | return ar; | ||
201 | } | ||
202 | QArray<int> OTodoAccessVCal::allRecords()const { | ||
203 | QArray<int> ar( m_map.count() ); | ||
204 | QMap<int, OTodo>::ConstIterator it; | ||
205 | int i = 0; | ||
206 | for ( it = m_map.begin(); it != m_map.end(); ++it ) { | ||
207 | ar[i] = it.key(); | ||
208 | i++; | ||
209 | } | ||
210 | return ar; | ||
211 | } | ||
212 | QArray<int> OTodoAccessVCal::matchRegexp(const QRegExp& /* r */)const { | ||
213 | QArray<int> ar(0); | ||
214 | return ar; | ||
215 | } | ||
216 | QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) { | ||
217 | QArray<int> ar(0); | ||
218 | return ar; | ||
219 | } | ||
220 | QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& , | ||
221 | const QDate& , | ||
222 | bool ) { | ||
223 | QArray<int> ar(0); | ||
224 | return ar; | ||
225 | } | ||
226 | QArray<int> OTodoAccessVCal::overDue() { | ||
227 | QArray<int> ar(0); | ||
228 | return ar; | ||
229 | } | ||
230 | QBitArray OTodoAccessVCal::supports()const { | ||
231 | static QBitArray ar = sup(); | ||
232 | |||
233 | return ar; | ||
234 | } | ||
235 | QBitArray OTodoAccessVCal::sup() { | ||
236 | QBitArray ar ( OTodo::CompletedDate +1 ); | ||
237 | ar.fill( true ); | ||
238 | |||
239 | ar[OTodo::CrossReference] = false; | ||
240 | ar[OTodo::State ] = false; | ||
241 | ar[OTodo::Reminders] = false; | ||
242 | ar[OTodo::Notifiers] = false; | ||
243 | ar[OTodo::Maintainer] = false; | ||
244 | ar[OTodo::Progress] = false; | ||
245 | ar[OTodo::Alarms ] = false; | ||
246 | ar[OTodo::Recurrence] = false; | ||
247 | |||
248 | return ar; | ||
249 | } | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccessvcal.h b/noncore/unsupported/libopie/pim/otodoaccessvcal.h new file mode 100644 index 0000000..2b17147 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessvcal.h | |||
@@ -0,0 +1,40 @@ | |||
1 | #ifndef OPIE_OTODO_ACCESS_VCAL_H | ||
2 | #define OPIE_OTODO_ACCESS_VCAL_H | ||
3 | |||
4 | #include "otodoaccessbackend.h" | ||
5 | |||
6 | class OTodoAccessVCal : public OTodoAccessBackend { | ||
7 | public: | ||
8 | OTodoAccessVCal(const QString& ); | ||
9 | ~OTodoAccessVCal(); | ||
10 | |||
11 | bool load(); | ||
12 | bool reload(); | ||
13 | bool save(); | ||
14 | |||
15 | QArray<int> allRecords()const; | ||
16 | QArray<int> matchRegexp(const QRegExp &r) const; | ||
17 | QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() ); | ||
18 | QArray<int> effectiveToDos( const QDate& start, | ||
19 | const QDate& end, | ||
20 | bool includeNoDates ); | ||
21 | QArray<int> overDue(); | ||
22 | QArray<int> sorted( bool asc, int sortOrder, int sortFilter, | ||
23 | int cat ); | ||
24 | OTodo find(int uid)const; | ||
25 | void clear(); | ||
26 | bool add( const OTodo& ); | ||
27 | bool remove( int uid ); | ||
28 | bool replace( const OTodo& ); | ||
29 | |||
30 | void removeAllCompleted(); | ||
31 | virtual QBitArray supports()const; | ||
32 | |||
33 | private: | ||
34 | static QBitArray sup(); | ||
35 | bool m_dirty : 1; | ||
36 | QString m_file; | ||
37 | QMap<int, OTodo> m_map; | ||
38 | }; | ||
39 | |||
40 | #endif | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccessxml.cpp b/noncore/unsupported/libopie/pim/otodoaccessxml.cpp new file mode 100644 index 0000000..4a5cb33 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessxml.cpp | |||
@@ -0,0 +1,876 @@ | |||
1 | #include <errno.h> | ||
2 | #include <fcntl.h> | ||
3 | |||
4 | #include <sys/mman.h> | ||
5 | #include <sys/stat.h> | ||
6 | #include <sys/types.h> | ||
7 | |||
8 | #include <unistd.h> | ||
9 | |||
10 | |||
11 | #include <qfile.h> | ||
12 | #include <qvector.h> | ||
13 | |||
14 | #include <qpe/global.h> | ||
15 | #include <qpe/stringutil.h> | ||
16 | #include <qpe/timeconversion.h> | ||
17 | |||
18 | #include "oconversion.h" | ||
19 | #include "opimstate.h" | ||
20 | #include "otimezone.h" | ||
21 | #include "opimnotifymanager.h" | ||
22 | #include "orecur.h" | ||
23 | #include "otodoaccessxml.h" | ||
24 | |||
25 | namespace { | ||
26 | time_t rp_end; | ||
27 | ORecur* rec; | ||
28 | ORecur *recur() { | ||
29 | if (!rec ) rec = new ORecur; | ||
30 | return rec; | ||
31 | } | ||
32 | int snd; | ||
33 | enum MoreAttributes { | ||
34 | FRType = OTodo::CompletedDate + 2, | ||
35 | FRWeekdays, | ||
36 | FRPosition, | ||
37 | FRFreq, | ||
38 | FRHasEndDate, | ||
39 | FREndDate, | ||
40 | FRStart, | ||
41 | FREnd | ||
42 | }; | ||
43 | // FROM TT again | ||
44 | char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) | ||
45 | { | ||
46 | char needleChar; | ||
47 | char haystackChar; | ||
48 | if (!needle || !haystack || !hLen || !nLen) | ||
49 | return 0; | ||
50 | |||
51 | const char* hsearch = haystack; | ||
52 | |||
53 | if ((needleChar = *needle++) != 0) { | ||
54 | nLen--; //(to make up for needle++) | ||
55 | do { | ||
56 | do { | ||
57 | if ((haystackChar = *hsearch++) == 0) | ||
58 | return (0); | ||
59 | if (hsearch >= haystack + hLen) | ||
60 | return (0); | ||
61 | } while (haystackChar != needleChar); | ||
62 | } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); | ||
63 | hsearch--; | ||
64 | } | ||
65 | return ((char *)hsearch); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | |||
70 | OTodoAccessXML::OTodoAccessXML( const QString& appName, | ||
71 | const QString& fileName ) | ||
72 | : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) | ||
73 | { | ||
74 | if (!fileName.isEmpty() ) | ||
75 | m_file = fileName; | ||
76 | else | ||
77 | m_file = Global::applicationFileName( "todolist", "todolist.xml" ); | ||
78 | } | ||
79 | OTodoAccessXML::~OTodoAccessXML() { | ||
80 | |||
81 | } | ||
82 | bool OTodoAccessXML::load() { | ||
83 | rec = 0; | ||
84 | m_opened = true; | ||
85 | m_changed = false; | ||
86 | /* initialize dict */ | ||
87 | /* | ||
88 | * UPDATE dict if you change anything!!! | ||
89 | */ | ||
90 | QAsciiDict<int> dict(26); | ||
91 | dict.setAutoDelete( TRUE ); | ||
92 | dict.insert("Categories" , new int(OTodo::Category) ); | ||
93 | dict.insert("Uid" , new int(OTodo::Uid) ); | ||
94 | dict.insert("HasDate" , new int(OTodo::HasDate) ); | ||
95 | dict.insert("Completed" , new int(OTodo::Completed) ); | ||
96 | dict.insert("Description" , new int(OTodo::Description) ); | ||
97 | dict.insert("Summary" , new int(OTodo::Summary) ); | ||
98 | dict.insert("Priority" , new int(OTodo::Priority) ); | ||
99 | dict.insert("DateDay" , new int(OTodo::DateDay) ); | ||
100 | dict.insert("DateMonth" , new int(OTodo::DateMonth) ); | ||
101 | dict.insert("DateYear" , new int(OTodo::DateYear) ); | ||
102 | dict.insert("Progress" , new int(OTodo::Progress) ); | ||
103 | dict.insert("CompletedDate", new int(OTodo::CompletedDate) ); | ||
104 | dict.insert("StartDate", new int(OTodo::StartDate) ); | ||
105 | dict.insert("CrossReference", new int(OTodo::CrossReference) ); | ||
106 | dict.insert("State", new int(OTodo::State) ); | ||
107 | dict.insert("Alarms", new int(OTodo::Alarms) ); | ||
108 | dict.insert("Reminders", new int(OTodo::Reminders) ); | ||
109 | dict.insert("Notifiers", new int(OTodo::Notifiers) ); | ||
110 | dict.insert("Maintainer", new int(OTodo::Maintainer) ); | ||
111 | dict.insert("rtype", new int(FRType) ); | ||
112 | dict.insert("rweekdays", new int(FRWeekdays) ); | ||
113 | dict.insert("rposition", new int(FRPosition) ); | ||
114 | dict.insert("rfreq", new int(FRFreq) ); | ||
115 | dict.insert("start", new int(FRStart) ); | ||
116 | dict.insert("rhasenddate", new int(FRHasEndDate) ); | ||
117 | dict.insert("enddt", new int(FREndDate) ); | ||
118 | |||
119 | // here the custom XML parser from TT it's GPL | ||
120 | // but we want to push OpiePIM... to TT..... | ||
121 | // mmap part from zecke :) | ||
122 | int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); | ||
123 | struct stat attribut; | ||
124 | if ( fd < 0 ) return false; | ||
125 | |||
126 | if ( fstat(fd, &attribut ) == -1 ) { | ||
127 | ::close( fd ); | ||
128 | return false; | ||
129 | } | ||
130 | void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); | ||
131 | if ( map_addr == ( (caddr_t)-1) ) { | ||
132 | ::close(fd ); | ||
133 | return false; | ||
134 | } | ||
135 | /* advise the kernel who we want to read it */ | ||
136 | ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); | ||
137 | /* we do not the file any more */ | ||
138 | ::close( fd ); | ||
139 | |||
140 | char* dt = (char*)map_addr; | ||
141 | int len = attribut.st_size; | ||
142 | int i = 0; | ||
143 | char *point; | ||
144 | const char* collectionString = "<Task "; | ||
145 | int strLen = strlen(collectionString); | ||
146 | while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { | ||
147 | i = point -dt; | ||
148 | i+= strLen; | ||
149 | qWarning("Found a start at %d %d", i, (point-dt) ); | ||
150 | |||
151 | OTodo ev; | ||
152 | m_year = m_month = m_day = 0; | ||
153 | |||
154 | while ( TRUE ) { | ||
155 | while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) | ||
156 | ++i; | ||
157 | if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) | ||
158 | break; | ||
159 | |||
160 | // we have another attribute, read it. | ||
161 | int j = i; | ||
162 | while ( j < len && dt[j] != '=' ) | ||
163 | ++j; | ||
164 | QCString attr( dt+i, j-i+1); | ||
165 | |||
166 | i = ++j; // skip = | ||
167 | |||
168 | // find the start of quotes | ||
169 | while ( i < len && dt[i] != '"' ) | ||
170 | ++i; | ||
171 | j = ++i; | ||
172 | |||
173 | bool haveUtf = FALSE; | ||
174 | bool haveEnt = FALSE; | ||
175 | while ( j < len && dt[j] != '"' ) { | ||
176 | if ( ((unsigned char)dt[j]) > 0x7f ) | ||
177 | haveUtf = TRUE; | ||
178 | if ( dt[j] == '&' ) | ||
179 | haveEnt = TRUE; | ||
180 | ++j; | ||
181 | } | ||
182 | if ( i == j ) { | ||
183 | // empty value | ||
184 | i = j + 1; | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | QCString value( dt+i, j-i+1 ); | ||
189 | i = j + 1; | ||
190 | |||
191 | QString str = (haveUtf ? QString::fromUtf8( value ) | ||
192 | : QString::fromLatin1( value ) ); | ||
193 | if ( haveEnt ) | ||
194 | str = Qtopia::plainString( str ); | ||
195 | |||
196 | /* | ||
197 | * add key + value | ||
198 | */ | ||
199 | todo( &dict, ev, attr, str ); | ||
200 | |||
201 | } | ||
202 | /* | ||
203 | * now add it | ||
204 | */ | ||
205 | qWarning("End at %d", i ); | ||
206 | if (m_events.contains( ev.uid() ) || ev.uid() == 0) { | ||
207 | ev.setUid( 1 ); | ||
208 | m_changed = true; | ||
209 | } | ||
210 | if ( ev.hasDueDate() ) { | ||
211 | ev.setDueDate( QDate(m_year, m_month, m_day) ); | ||
212 | } | ||
213 | if ( rec && rec->doesRecur() ) { | ||
214 | OTimeZone utc = OTimeZone::utc(); | ||
215 | ORecur recu( *rec ); // call copy c'tor | ||
216 | recu.setEndDate( utc.fromUTCDateTime( rp_end ).date() ); | ||
217 | recu.setStart( ev.dueDate() ); | ||
218 | ev.setRecurrence( recu ); | ||
219 | } | ||
220 | m_events.insert(ev.uid(), ev ); | ||
221 | m_year = m_month = m_day = -1; | ||
222 | delete rec; | ||
223 | rec = 0; | ||
224 | } | ||
225 | |||
226 | munmap(map_addr, attribut.st_size ); | ||
227 | |||
228 | qWarning("counts %d records loaded!", m_events.count() ); | ||
229 | return true; | ||
230 | } | ||
231 | bool OTodoAccessXML::reload() { | ||
232 | m_events.clear(); | ||
233 | return load(); | ||
234 | } | ||
235 | bool OTodoAccessXML::save() { | ||
236 | // qWarning("saving"); | ||
237 | if (!m_opened || !m_changed ) { | ||
238 | // qWarning("not saving"); | ||
239 | return true; | ||
240 | } | ||
241 | QString strNewFile = m_file + ".new"; | ||
242 | QFile f( strNewFile ); | ||
243 | if (!f.open( IO_WriteOnly|IO_Raw ) ) | ||
244 | return false; | ||
245 | |||
246 | int written; | ||
247 | QString out; | ||
248 | out = "<!DOCTYPE Tasks>\n<Tasks>\n"; | ||
249 | |||
250 | // for all todos | ||
251 | QMap<int, OTodo>::Iterator it; | ||
252 | for (it = m_events.begin(); it != m_events.end(); ++it ) { | ||
253 | out+= "<Task " + toString( (*it) ) + " />\n"; | ||
254 | QCString cstr = out.utf8(); | ||
255 | written = f.writeBlock( cstr.data(), cstr.length() ); | ||
256 | |||
257 | /* less written then we wanted */ | ||
258 | if ( written != (int)cstr.length() ) { | ||
259 | f.close(); | ||
260 | QFile::remove( strNewFile ); | ||
261 | return false; | ||
262 | } | ||
263 | out = QString::null; | ||
264 | } | ||
265 | |||
266 | out += "</Tasks>"; | ||
267 | QCString cstr = out.utf8(); | ||
268 | written = f.writeBlock( cstr.data(), cstr.length() ); | ||
269 | |||
270 | if ( written != (int)cstr.length() ) { | ||
271 | f.close(); | ||
272 | QFile::remove( strNewFile ); | ||
273 | return false; | ||
274 | } | ||
275 | /* flush before renaming */ | ||
276 | f.close(); | ||
277 | |||
278 | if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { | ||
279 | // qWarning("error renaming"); | ||
280 | QFile::remove( strNewFile ); | ||
281 | } | ||
282 | |||
283 | m_changed = false; | ||
284 | return true; | ||
285 | } | ||
286 | QArray<int> OTodoAccessXML::allRecords()const { | ||
287 | QArray<int> ids( m_events.count() ); | ||
288 | QMap<int, OTodo>::ConstIterator it; | ||
289 | int i = 0; | ||
290 | |||
291 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
292 | ids[i] = it.key(); | ||
293 | i++; | ||
294 | } | ||
295 | return ids; | ||
296 | } | ||
297 | QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { | ||
298 | QArray<int> ids(0); | ||
299 | return ids; | ||
300 | } | ||
301 | OTodo OTodoAccessXML::find( int uid )const { | ||
302 | OTodo todo; | ||
303 | todo.setUid( 0 ); // isEmpty() | ||
304 | QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); | ||
305 | if ( it != m_events.end() ) | ||
306 | todo = it.data(); | ||
307 | |||
308 | return todo; | ||
309 | } | ||
310 | void OTodoAccessXML::clear() { | ||
311 | if (m_opened ) | ||
312 | m_changed = true; | ||
313 | |||
314 | m_events.clear(); | ||
315 | } | ||
316 | bool OTodoAccessXML::add( const OTodo& todo ) { | ||
317 | // qWarning("add"); | ||
318 | m_changed = true; | ||
319 | m_events.insert( todo.uid(), todo ); | ||
320 | |||
321 | return true; | ||
322 | } | ||
323 | bool OTodoAccessXML::remove( int uid ) { | ||
324 | m_changed = true; | ||
325 | m_events.remove( uid ); | ||
326 | |||
327 | return true; | ||
328 | } | ||
329 | bool OTodoAccessXML::replace( const OTodo& todo) { | ||
330 | m_changed = true; | ||
331 | m_events.replace( todo.uid(), todo ); | ||
332 | |||
333 | return true; | ||
334 | } | ||
335 | QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, | ||
336 | const QDate& end, | ||
337 | bool includeNoDates ) { | ||
338 | QArray<int> ids( m_events.count() ); | ||
339 | QMap<int, OTodo>::Iterator it; | ||
340 | |||
341 | int i = 0; | ||
342 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
343 | if ( !it.data().hasDueDate() ) { | ||
344 | if ( includeNoDates ) { | ||
345 | ids[i] = it.key(); | ||
346 | i++; | ||
347 | } | ||
348 | }else if ( it.data().dueDate() >= start && | ||
349 | it.data().dueDate() <= end ) { | ||
350 | ids[i] = it.key(); | ||
351 | i++; | ||
352 | } | ||
353 | } | ||
354 | ids.resize( i ); | ||
355 | return ids; | ||
356 | } | ||
357 | QArray<int> OTodoAccessXML::overDue() { | ||
358 | QArray<int> ids( m_events.count() ); | ||
359 | int i = 0; | ||
360 | |||
361 | QMap<int, OTodo>::Iterator it; | ||
362 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
363 | if ( it.data().isOverdue() ) { | ||
364 | ids[i] = it.key(); | ||
365 | i++; | ||
366 | } | ||
367 | } | ||
368 | ids.resize( i ); | ||
369 | return ids; | ||
370 | } | ||
371 | |||
372 | |||
373 | /* private */ | ||
374 | void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, | ||
375 | const QCString& attr, const QString& val) { | ||
376 | // qWarning("parse to do from XMLElement" ); | ||
377 | |||
378 | int *find=0; | ||
379 | |||
380 | find = (*dict)[ attr.data() ]; | ||
381 | if (!find ) { | ||
382 | // qWarning("Unknown option" + it.key() ); | ||
383 | ev.setCustomField( attr, val ); | ||
384 | return; | ||
385 | } | ||
386 | |||
387 | switch( *find ) { | ||
388 | case OTodo::Uid: | ||
389 | ev.setUid( val.toInt() ); | ||
390 | break; | ||
391 | case OTodo::Category: | ||
392 | ev.setCategories( ev.idsFromString( val ) ); | ||
393 | break; | ||
394 | case OTodo::HasDate: | ||
395 | ev.setHasDueDate( val.toInt() ); | ||
396 | break; | ||
397 | case OTodo::Completed: | ||
398 | ev.setCompleted( val.toInt() ); | ||
399 | break; | ||
400 | case OTodo::Description: | ||
401 | ev.setDescription( val ); | ||
402 | break; | ||
403 | case OTodo::Summary: | ||
404 | ev.setSummary( val ); | ||
405 | break; | ||
406 | case OTodo::Priority: | ||
407 | ev.setPriority( val.toInt() ); | ||
408 | break; | ||
409 | case OTodo::DateDay: | ||
410 | m_day = val.toInt(); | ||
411 | break; | ||
412 | case OTodo::DateMonth: | ||
413 | m_month = val.toInt(); | ||
414 | break; | ||
415 | case OTodo::DateYear: | ||
416 | m_year = val.toInt(); | ||
417 | break; | ||
418 | case OTodo::Progress: | ||
419 | ev.setProgress( val.toInt() ); | ||
420 | break; | ||
421 | case OTodo::CompletedDate: | ||
422 | ev.setCompletedDate( OConversion::dateFromString( val ) ); | ||
423 | break; | ||
424 | case OTodo::StartDate: | ||
425 | ev.setStartDate( OConversion::dateFromString( val ) ); | ||
426 | break; | ||
427 | case OTodo::State: | ||
428 | ev.setState( val.toInt() ); | ||
429 | break; | ||
430 | case OTodo::Alarms:{ | ||
431 | OPimNotifyManager &manager = ev.notifiers(); | ||
432 | QStringList als = QStringList::split(";", val ); | ||
433 | for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) { | ||
434 | QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty | ||
435 | qWarning("alarm: %s", alarm.join("___").latin1() ); | ||
436 | qWarning("alarm[0]: %s %s", alarm[0].latin1(), OConversion::dateTimeFromString( alarm[0] ).toString().latin1() ); | ||
437 | OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), alarm[1].toInt() ); | ||
438 | manager.add( al ); | ||
439 | } | ||
440 | } | ||
441 | break; | ||
442 | case OTodo::Reminders:{ | ||
443 | OPimNotifyManager &manager = ev.notifiers(); | ||
444 | QStringList rems = QStringList::split(";", val ); | ||
445 | for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) { | ||
446 | OPimReminder rem( (*it).toInt() ); | ||
447 | manager.add( rem ); | ||
448 | } | ||
449 | } | ||
450 | break; | ||
451 | case OTodo::CrossReference: | ||
452 | { | ||
453 | /* | ||
454 | * A cross refernce looks like | ||
455 | * appname,id;appname,id | ||
456 | * we need to split it up | ||
457 | */ | ||
458 | QStringList refs = QStringList::split(';', val ); | ||
459 | QStringList::Iterator strIt; | ||
460 | for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { | ||
461 | int pos = (*strIt).find(','); | ||
462 | if ( pos > -1 ) | ||
463 | ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); | ||
464 | |||
465 | } | ||
466 | break; | ||
467 | } | ||
468 | /* Recurrence stuff below + post processing later */ | ||
469 | case FRType: | ||
470 | if ( val == "Daily" ) | ||
471 | recur()->setType( ORecur::Daily ); | ||
472 | else if ( val == "Weekly" ) | ||
473 | recur()->setType( ORecur::Weekly); | ||
474 | else if ( val == "MonthlyDay" ) | ||
475 | recur()->setType( ORecur::MonthlyDay ); | ||
476 | else if ( val == "MonthlyDate" ) | ||
477 | recur()->setType( ORecur::MonthlyDate ); | ||
478 | else if ( val == "Yearly" ) | ||
479 | recur()->setType( ORecur::Yearly ); | ||
480 | else | ||
481 | recur()->setType( ORecur::NoRepeat ); | ||
482 | break; | ||
483 | case FRWeekdays: | ||
484 | recur()->setDays( val.toInt() ); | ||
485 | break; | ||
486 | case FRPosition: | ||
487 | recur()->setPosition( val.toInt() ); | ||
488 | break; | ||
489 | case FRFreq: | ||
490 | recur()->setFrequency( val.toInt() ); | ||
491 | break; | ||
492 | case FRHasEndDate: | ||
493 | recur()->setHasEndDate( val.toInt() ); | ||
494 | break; | ||
495 | case FREndDate: { | ||
496 | rp_end = (time_t) val.toLong(); | ||
497 | break; | ||
498 | } | ||
499 | default: | ||
500 | ev.setCustomField( attr, val ); | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | // from PalmtopRecord... GPL ### FIXME | ||
506 | namespace { | ||
507 | QString customToXml(const QMap<QString, QString>& customMap ) | ||
508 | { | ||
509 | //qWarning(QString("writing custom %1").arg(customMap.count())); | ||
510 | QString buf(" "); | ||
511 | for ( QMap<QString, QString>::ConstIterator cit = customMap.begin(); | ||
512 | cit != customMap.end(); ++cit) { | ||
513 | // qWarning(".ITEM."); | ||
514 | buf += cit.key(); | ||
515 | buf += "=\""; | ||
516 | buf += Qtopia::escapeString(cit.data()); | ||
517 | buf += "\" "; | ||
518 | } | ||
519 | return buf; | ||
520 | } | ||
521 | |||
522 | |||
523 | } | ||
524 | |||
525 | QString OTodoAccessXML::toString( const OTodo& ev )const { | ||
526 | QString str; | ||
527 | |||
528 | str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; | ||
529 | str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; | ||
530 | str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; | ||
531 | str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; | ||
532 | |||
533 | str += "Categories=\"" + toString( ev.categories() ) + "\" "; | ||
534 | str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; | ||
535 | str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; | ||
536 | |||
537 | if ( ev.hasDueDate() ) { | ||
538 | str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; | ||
539 | str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; | ||
540 | str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; | ||
541 | } | ||
542 | // qWarning( "Uid %d", ev.uid() ); | ||
543 | str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; | ||
544 | |||
545 | // append the extra options | ||
546 | /* FIXME Qtopia::Record this is currently not | ||
547 | * possible you can set custom fields | ||
548 | * but don' iterate over the list | ||
549 | * I may do #define private protected | ||
550 | * for this case - cough --zecke | ||
551 | */ | ||
552 | /* | ||
553 | QMap<QString, QString> extras = ev.extras(); | ||
554 | QMap<QString, QString>::Iterator extIt; | ||
555 | for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) | ||
556 | str += extIt.key() + "=\"" + extIt.data() + "\" "; | ||
557 | */ | ||
558 | // cross refernce | ||
559 | if ( ev.hasRecurrence() ) { | ||
560 | str += ev.recurrence().toString(); | ||
561 | } | ||
562 | if ( ev.hasStartDate() ) | ||
563 | str += "StartDate=\""+ OConversion::dateToString( ev.startDate() ) +"\" "; | ||
564 | if ( ev.hasCompletedDate() ) | ||
565 | str += "CompletedDate=\""+ OConversion::dateToString( ev.completedDate() ) +"\" "; | ||
566 | if ( ev.hasState() ) | ||
567 | str += "State=\""+QString::number( ev.state().state() )+"\" "; | ||
568 | |||
569 | /* | ||
570 | * save reminders and notifiers! | ||
571 | * DATE_TIME:DURATION:SOUND:NOT_USED_YET;OTHER_DATE_TIME:OTHER_DURATION:SOUND:.... | ||
572 | */ | ||
573 | if ( ev.hasNotifiers() ) { | ||
574 | OPimNotifyManager manager = ev.notifiers(); | ||
575 | OPimNotifyManager::Alarms alarms = manager.alarms(); | ||
576 | if (!alarms.isEmpty() ) { | ||
577 | QStringList als; | ||
578 | OPimNotifyManager::Alarms::Iterator it = alarms.begin(); | ||
579 | for ( ; it != alarms.end(); ++it ) { | ||
580 | /* only if time is valid */ | ||
581 | if ( (*it).dateTime().isValid() ) { | ||
582 | als << OConversion::dateTimeToString( (*it).dateTime() ) | ||
583 | + ":" + QString::number( (*it).duration() ) | ||
584 | + ":" + QString::number( (*it).sound() ) | ||
585 | + ":"; | ||
586 | } | ||
587 | } | ||
588 | // now write the list | ||
589 | qWarning("als: %s", als.join("____________").latin1() ); | ||
590 | str += "Alarms=\""+als.join(";") +"\" "; | ||
591 | } | ||
592 | |||
593 | /* | ||
594 | * now the same for reminders but more easy. We just save the uid of the OEvent. | ||
595 | */ | ||
596 | OPimNotifyManager::Reminders reminders = manager.reminders(); | ||
597 | if (!reminders.isEmpty() ) { | ||
598 | OPimNotifyManager::Reminders::Iterator it = reminders.begin(); | ||
599 | QStringList records; | ||
600 | for ( ; it != reminders.end(); ++it ) { | ||
601 | records << QString::number( (*it).recordUid() ); | ||
602 | } | ||
603 | str += "Reminders=\""+ records.join(";") +"\" "; | ||
604 | } | ||
605 | } | ||
606 | str += customToXml( ev.toExtraMap() ); | ||
607 | |||
608 | |||
609 | return str; | ||
610 | } | ||
611 | QString OTodoAccessXML::toString( const QArray<int>& ints ) const { | ||
612 | return Qtopia::Record::idsToString( ints ); | ||
613 | } | ||
614 | |||
615 | /* internal class for sorting | ||
616 | * | ||
617 | * Inspired by todoxmlio.cpp from TT | ||
618 | */ | ||
619 | |||
620 | struct OTodoXMLContainer { | ||
621 | OTodo todo; | ||
622 | }; | ||
623 | |||
624 | namespace { | ||
625 | inline QString string( const OTodo& todo) { | ||
626 | return todo.summary().isEmpty() ? | ||
627 | todo.description().left(20 ) : | ||
628 | todo.summary(); | ||
629 | } | ||
630 | inline int completed( const OTodo& todo1, const OTodo& todo2) { | ||
631 | int ret = 0; | ||
632 | if ( todo1.isCompleted() ) ret++; | ||
633 | if ( todo2.isCompleted() ) ret--; | ||
634 | return ret; | ||
635 | } | ||
636 | inline int priority( const OTodo& t1, const OTodo& t2) { | ||
637 | return ( t1.priority() - t2.priority() ); | ||
638 | } | ||
639 | inline int description( const OTodo& t1, const OTodo& t2) { | ||
640 | return QString::compare( string(t1), string(t2) ); | ||
641 | } | ||
642 | inline int deadline( const OTodo& t1, const OTodo& t2) { | ||
643 | int ret = 0; | ||
644 | if ( t1.hasDueDate() && | ||
645 | t2.hasDueDate() ) | ||
646 | ret = t2.dueDate().daysTo( t1.dueDate() ); | ||
647 | else if ( t1.hasDueDate() ) | ||
648 | ret = -1; | ||
649 | else if ( t2.hasDueDate() ) | ||
650 | ret = 1; | ||
651 | else | ||
652 | ret = 0; | ||
653 | |||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | }; | ||
658 | |||
659 | /* | ||
660 | * Returns: | ||
661 | * 0 if item1 == item2 | ||
662 | * | ||
663 | * non-zero if item1 != item2 | ||
664 | * | ||
665 | * This function returns int rather than bool so that reimplementations | ||
666 | * can return one of three values and use it to sort by: | ||
667 | * | ||
668 | * 0 if item1 == item2 | ||
669 | * | ||
670 | * > 0 (positive integer) if item1 > item2 | ||
671 | * | ||
672 | * < 0 (negative integer) if item1 < item2 | ||
673 | * | ||
674 | */ | ||
675 | class OTodoXMLVector : public QVector<OTodoXMLContainer> { | ||
676 | public: | ||
677 | OTodoXMLVector(int size, bool asc, int sort) | ||
678 | : QVector<OTodoXMLContainer>( size ) | ||
679 | { | ||
680 | setAutoDelete( true ); | ||
681 | m_asc = asc; | ||
682 | m_sort = sort; | ||
683 | } | ||
684 | /* return the summary/description */ | ||
685 | QString string( const OTodo& todo) { | ||
686 | return todo.summary().isEmpty() ? | ||
687 | todo.description().left(20 ) : | ||
688 | todo.summary(); | ||
689 | } | ||
690 | /** | ||
691 | * we take the sortorder( switch on it ) | ||
692 | * | ||
693 | */ | ||
694 | int compareItems( Item d1, Item d2 ) { | ||
695 | bool seComp, sePrio, seDesc, seDeadline; | ||
696 | seComp = sePrio = seDeadline = seDesc = false; | ||
697 | int ret =0; | ||
698 | OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; | ||
699 | OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; | ||
700 | |||
701 | /* same item */ | ||
702 | if ( con1->todo.uid() == con2->todo.uid() ) | ||
703 | return 0; | ||
704 | |||
705 | switch ( m_sort ) { | ||
706 | /* completed */ | ||
707 | case 0: { | ||
708 | ret = completed( con1->todo, con2->todo ); | ||
709 | seComp = TRUE; | ||
710 | break; | ||
711 | } | ||
712 | /* priority */ | ||
713 | case 1: { | ||
714 | ret = priority( con1->todo, con2->todo ); | ||
715 | sePrio = TRUE; | ||
716 | break; | ||
717 | } | ||
718 | /* description */ | ||
719 | case 2: { | ||
720 | ret = description( con1->todo, con2->todo ); | ||
721 | seDesc = TRUE; | ||
722 | break; | ||
723 | } | ||
724 | /* deadline */ | ||
725 | case 3: { | ||
726 | ret = deadline( con1->todo, con2->todo ); | ||
727 | seDeadline = TRUE; | ||
728 | break; | ||
729 | } | ||
730 | default: | ||
731 | ret = 0; | ||
732 | break; | ||
733 | }; | ||
734 | /* | ||
735 | * FIXME do better sorting if the first sort criteria | ||
736 | * ret equals 0 start with complete and so on... | ||
737 | */ | ||
738 | |||
739 | /* twist it we're not ascending*/ | ||
740 | if (!m_asc) | ||
741 | ret = ret * -1; | ||
742 | |||
743 | if ( ret ) | ||
744 | return ret; | ||
745 | |||
746 | // default did not gave difference let's try it other way around | ||
747 | /* | ||
748 | * General try if already checked if not test | ||
749 | * and return | ||
750 | * 1.Completed | ||
751 | * 2.Priority | ||
752 | * 3.Description | ||
753 | * 4.DueDate | ||
754 | */ | ||
755 | if (!seComp ) { | ||
756 | if ( (ret = completed( con1->todo, con2->todo ) ) ) { | ||
757 | if (!m_asc ) ret *= -1; | ||
758 | return ret; | ||
759 | } | ||
760 | } | ||
761 | if (!sePrio ) { | ||
762 | if ( (ret = priority( con1->todo, con2->todo ) ) ) { | ||
763 | if (!m_asc ) ret *= -1; | ||
764 | return ret; | ||
765 | } | ||
766 | } | ||
767 | if (!seDesc ) { | ||
768 | if ( (ret = description(con1->todo, con2->todo ) ) ) { | ||
769 | if (!m_asc) ret *= -1; | ||
770 | return ret; | ||
771 | } | ||
772 | } | ||
773 | if (!seDeadline) { | ||
774 | if ( (ret = deadline( con1->todo, con2->todo ) ) ) { | ||
775 | if (!m_asc) ret *= -1; | ||
776 | return ret; | ||
777 | } | ||
778 | } | ||
779 | |||
780 | return 0; | ||
781 | } | ||
782 | private: | ||
783 | bool m_asc; | ||
784 | int m_sort; | ||
785 | |||
786 | }; | ||
787 | |||
788 | QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, | ||
789 | int sortFilter, int cat ) { | ||
790 | OTodoXMLVector vector(m_events.count(), asc,sortOrder ); | ||
791 | QMap<int, OTodo>::Iterator it; | ||
792 | int item = 0; | ||
793 | |||
794 | bool bCat = sortFilter & 1 ? true : false; | ||
795 | bool bOnly = sortFilter & 2 ? true : false; | ||
796 | bool comp = sortFilter & 4 ? true : false; | ||
797 | for ( it = m_events.begin(); it != m_events.end(); ++it ) { | ||
798 | |||
799 | /* show category */ | ||
800 | /* -1 == unfiled */ | ||
801 | if ( bCat && cat == -1 ) { | ||
802 | if(!(*it).categories().isEmpty() ) | ||
803 | continue; | ||
804 | }else if ( bCat && cat != 0) | ||
805 | if (!(*it).categories().contains( cat ) ) { | ||
806 | continue; | ||
807 | } | ||
808 | /* isOverdue but we should not show overdue - why?*/ | ||
809 | /* if ( (*it).isOverdue() && !bOnly ) { | ||
810 | qWarning("item is overdue but !bOnly"); | ||
811 | continue; | ||
812 | } | ||
813 | */ | ||
814 | if ( !(*it).isOverdue() && bOnly ) { | ||
815 | continue; | ||
816 | } | ||
817 | |||
818 | if ((*it).isCompleted() && comp ) { | ||
819 | continue; | ||
820 | } | ||
821 | |||
822 | |||
823 | OTodoXMLContainer* con = new OTodoXMLContainer(); | ||
824 | con->todo = (*it); | ||
825 | vector.insert(item, con ); | ||
826 | item++; | ||
827 | } | ||
828 | vector.resize( item ); | ||
829 | /* sort it now */ | ||
830 | vector.sort(); | ||
831 | /* now get the uids */ | ||
832 | QArray<int> array( vector.count() ); | ||
833 | for (uint i= 0; i < vector.count(); i++ ) { | ||
834 | array[i] = ( vector.at(i) )->todo.uid(); | ||
835 | } | ||
836 | return array; | ||
837 | }; | ||
838 | void OTodoAccessXML::removeAllCompleted() { | ||
839 | QMap<int, OTodo> events = m_events; | ||
840 | for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { | ||
841 | if ( (*it).isCompleted() ) | ||
842 | events.remove( it.key() ); | ||
843 | } | ||
844 | m_events = events; | ||
845 | } | ||
846 | QBitArray OTodoAccessXML::supports()const { | ||
847 | static QBitArray ar = sup(); | ||
848 | return ar; | ||
849 | } | ||
850 | QBitArray OTodoAccessXML::sup() { | ||
851 | QBitArray ar( OTodo::CompletedDate +1 ); | ||
852 | ar.fill( true ); | ||
853 | ar[OTodo::CrossReference] = false; | ||
854 | ar[OTodo::State ] = false; | ||
855 | ar[OTodo::Reminders] = false; | ||
856 | ar[OTodo::Notifiers] = false; | ||
857 | ar[OTodo::Maintainer] = false; | ||
858 | |||
859 | return ar; | ||
860 | } | ||
861 | QArray<int> OTodoAccessXML::matchRegexp( const QRegExp &r ) const | ||
862 | { | ||
863 | QArray<int> m_currentQuery( m_events.count() ); | ||
864 | uint arraycounter = 0; | ||
865 | |||
866 | QMap<int, OTodo>::ConstIterator it; | ||
867 | for (it = m_events.begin(); it != m_events.end(); ++it ) { | ||
868 | if ( it.data().match( r ) ) | ||
869 | m_currentQuery[arraycounter++] = it.data().uid(); | ||
870 | |||
871 | } | ||
872 | // Shrink to fit.. | ||
873 | m_currentQuery.resize(arraycounter); | ||
874 | |||
875 | return m_currentQuery; | ||
876 | } | ||
diff --git a/noncore/unsupported/libopie/pim/otodoaccessxml.h b/noncore/unsupported/libopie/pim/otodoaccessxml.h new file mode 100644 index 0000000..e4850a1 --- a/dev/null +++ b/noncore/unsupported/libopie/pim/otodoaccessxml.h | |||
@@ -0,0 +1,60 @@ | |||
1 | #ifndef OPIE_TODO_ACCESS_XML_H | ||
2 | #define OPIE_TODO_ACCESS_XML_H | ||
3 | |||
4 | #include <qasciidict.h> | ||
5 | #include <qmap.h> | ||
6 | |||
7 | #include "otodoaccessbackend.h" | ||
8 | |||
9 | namespace Opie { | ||
10 | class XMLElement; | ||
11 | }; | ||
12 | |||
13 | class OTodoAccessXML : public OTodoAccessBackend { | ||
14 | public: | ||
15 | /** | ||
16 | * fileName if Empty we will use the default path | ||
17 | */ | ||
18 | OTodoAccessXML( const QString& appName, | ||
19 | const QString& fileName = QString::null ); | ||
20 | ~OTodoAccessXML(); | ||
21 | |||
22 | bool load(); | ||
23 | bool reload(); | ||
24 | bool save(); | ||
25 | |||
26 | QArray<int> allRecords()const; | ||
27 | QArray<int> matchRegexp(const QRegExp &r) const; | ||
28 | QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() ); | ||
29 | OTodo find( int uid )const; | ||
30 | void clear(); | ||
31 | bool add( const OTodo& ); | ||
32 | bool remove( int uid ); | ||
33 | void removeAllCompleted(); | ||
34 | bool replace( const OTodo& ); | ||
35 | |||
36 | /* our functions */ | ||
37 | QArray<int> effectiveToDos( const QDate& start, | ||
38 | const QDate& end, | ||
39 | bool includeNoDates ); | ||
40 | QArray<int> overDue(); | ||
41 | QArray<int> sorted( bool asc, int sortOrder, | ||
42 | int sortFilter, int cat ); | ||
43 | QBitArray supports()const; | ||
44 | private: | ||
45 | static QBitArray sup(); | ||
46 | void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& ); | ||
47 | QString toString( const OTodo& )const; | ||
48 | QString toString( const QArray<int>& ints ) const; | ||
49 | QMap<int, OTodo> m_events; | ||
50 | QString m_file; | ||
51 | QString m_app; | ||
52 | bool m_opened : 1; | ||
53 | bool m_changed : 1; | ||
54 | class OTodoAccessXMLPrivate; | ||
55 | OTodoAccessXMLPrivate* d; | ||
56 | int m_year, m_month, m_day; | ||
57 | |||
58 | }; | ||
59 | |||
60 | #endif | ||