summaryrefslogtreecommitdiff
path: root/noncore/unsupported/libopie/pim
Unidiff
Diffstat (limited to 'noncore/unsupported/libopie/pim') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/libopie/pim/.cvsignore2
-rw-r--r--noncore/unsupported/libopie/pim/config.in2
-rw-r--r--noncore/unsupported/libopie/pim/libopie.pro64
-rw-r--r--noncore/unsupported/libopie/pim/obackendfactory.h197
-rw-r--r--noncore/unsupported/libopie/pim/ocontact.cpp1207
-rw-r--r--noncore/unsupported/libopie/pim/ocontact.h240
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccess.cpp176
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccess.h196
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend.h131
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.cpp948
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend_sql.h110
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.cpp649
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend_vcard.h99
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.cpp824
-rw-r--r--noncore/unsupported/libopie/pim/ocontactaccessbackend_xml.h163
-rw-r--r--noncore/unsupported/libopie/pim/ocontactfields.cpp477
-rw-r--r--noncore/unsupported/libopie/pim/ocontactfields.h67
-rw-r--r--noncore/unsupported/libopie/pim/oconversion.cpp113
-rw-r--r--noncore/unsupported/libopie/pim/oconversion.h48
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccess.cpp81
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccess.h44
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccessbackend.cpp182
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccessbackend.h90
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.cpp374
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccessbackend_sql.h65
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.cpp612
-rw-r--r--noncore/unsupported/libopie/pim/odatebookaccessbackend_xml.h55
-rw-r--r--noncore/unsupported/libopie/pim/oevent.cpp717
-rw-r--r--noncore/unsupported/libopie/pim/oevent.h236
-rw-r--r--noncore/unsupported/libopie/pim/opimaccessbackend.h160
-rw-r--r--noncore/unsupported/libopie/pim/opimaccesstemplate.h302
-rw-r--r--noncore/unsupported/libopie/pim/opimcache.h131
-rw-r--r--noncore/unsupported/libopie/pim/opimmaintainer.cpp37
-rw-r--r--noncore/unsupported/libopie/pim/opimmaintainer.h40
-rw-r--r--noncore/unsupported/libopie/pim/opimmainwindow.cpp150
-rw-r--r--noncore/unsupported/libopie/pim/opimmainwindow.h99
-rw-r--r--noncore/unsupported/libopie/pim/opimnotify.cpp227
-rw-r--r--noncore/unsupported/libopie/pim/opimnotify.h144
-rw-r--r--noncore/unsupported/libopie/pim/opimnotifymanager.cpp162
-rw-r--r--noncore/unsupported/libopie/pim/opimnotifymanager.h91
-rw-r--r--noncore/unsupported/libopie/pim/opimrecord.cpp182
-rw-r--r--noncore/unsupported/libopie/pim/opimrecord.h158
-rw-r--r--noncore/unsupported/libopie/pim/opimresolver.cpp198
-rw-r--r--noncore/unsupported/libopie/pim/opimresolver.h90
-rw-r--r--noncore/unsupported/libopie/pim/opimstate.cpp64
-rw-r--r--noncore/unsupported/libopie/pim/opimstate.h46
-rw-r--r--noncore/unsupported/libopie/pim/opimxref.cpp47
-rw-r--r--noncore/unsupported/libopie/pim/opimxref.h39
-rw-r--r--noncore/unsupported/libopie/pim/opimxrefmanager.cpp71
-rw-r--r--noncore/unsupported/libopie/pim/opimxrefmanager.h43
-rw-r--r--noncore/unsupported/libopie/pim/opimxrefpartner.cpp43
-rw-r--r--noncore/unsupported/libopie/pim/opimxrefpartner.h40
-rw-r--r--noncore/unsupported/libopie/pim/orecordlist.h306
-rw-r--r--noncore/unsupported/libopie/pim/orecur.cpp593
-rw-r--r--noncore/unsupported/libopie/pim/orecur.h107
-rw-r--r--noncore/unsupported/libopie/pim/otemplatebase.h98
-rw-r--r--noncore/unsupported/libopie/pim/otimezone.cpp113
-rw-r--r--noncore/unsupported/libopie/pim/otimezone.h71
-rw-r--r--noncore/unsupported/libopie/pim/otodo.cpp519
-rw-r--r--noncore/unsupported/libopie/pim/otodo.h285
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccess.cpp62
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccess.h105
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccessbackend.cpp10
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccessbackend.h28
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccesssql.cpp694
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccesssql.h61
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccessvcal.cpp249
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccessvcal.h40
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccessxml.cpp876
-rw-r--r--noncore/unsupported/libopie/pim/otodoaccessxml.h60
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 @@
1config.in
2moc*
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 @@
1menu "Pim"
2endmenu
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 @@
1TEMPLATE = lib
2CONFIG += qte warn_on release
3HEADERS = 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
33SOURCES = 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
57TARGET = opie
58INCLUDEPATH += $(OPIEDIR)/include
59DESTDIR = $(OPIEDIR)/lib$(PROJMAK)
60#VERSION = 1.0.0
61
62INTERFACES = otimepickerbase.ui
63
64include ( $(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
101class 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 */
118template<class T>
119class 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*/
53OContact::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*/
63OContact::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*/
85OContact::~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*/
423QMap<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*/
435QString 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*/
724void 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*/
736void 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*/
748QString OContact::find( int key ) const
749{
750 return mMap[key];
751}
752
753/*!
754 \internal
755*/
756QString 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*/
781QString OContact::displayBusinessAddress() const
782{
783 return displayAddress( businessStreet(), businessCity(),
784 businessState(), businessZip(),
785 businessCountry() );
786}
787
788/*!
789 \internal
790*/
791QString 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*/
801QString 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*/
836QStringList 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*/
868QStringList 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*/
889void 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*/
914void 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*/
945QStringList 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*/
1008void 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*/
1018void 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*/
1028bool 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
1045QString OContact::toShortText() const
1046{
1047 return ( fullName() );
1048}
1049QString OContact::type() const
1050{
1051 return QString::fromLatin1( "OContact" );
1052}
1053
1054
1055
1056class 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*/
1070void 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*/
1088void 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*/
1103QDate 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*/
1117QDate 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
1129void 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
1151void 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}
1178void OContact::clearEmails()
1179{
1180 mMap.remove( Qtopia::DefaultEmail );
1181 mMap.remove( Qtopia::Emails );
1182}
1183void 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
1195void OContact::insertEmails( const QStringList &v )
1196{
1197 for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it )
1198 insertEmail( *it );
1199}
1200int OContact::rtti() {
1201 return OPimResolver::AddressBook;
1202}
1203void 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
31QPC_TEMPLATEEXTERN template class QPC_EXPORT QMap<int, QString>;
32// MOC_SKIP_END
33#endif
34
35class 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 */
44class QPC_EXPORT OContact : public OPimRecord
45{
46 friend class DataSet;
47public:
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 &regexp ) 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 // email
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
218private:
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
84OContactAccess::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}
112OContactAccess::~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
122bool 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
141const uint OContactAccess::querySettings()
142{
143 return ( m_backEnd->querySettings() );
144}
145
146bool OContactAccess::hasQuerySettings ( int querySettings ) const
147{
148 return ( m_backEnd->hasQuerySettings ( querySettings ) );
149}
150ORecordList<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
157bool OContactAccess::wasChangedExternally()const
158{
159 return ( m_backEnd->wasChangedExternally() );
160}
161
162
163void 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 */
99class 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 */
78class 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
127private:
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
66using 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 */
90namespace {
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
477OContactAccessBackend_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
501OContactAccessBackend_SQL::~OContactAccessBackend_SQL ()
502{
503 if( m_driver )
504 delete m_driver;
505}
506
507bool 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
524bool OContactAccessBackend_SQL::reload()
525{
526 return load();
527}
528
529bool OContactAccessBackend_SQL::save()
530{
531 return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
532}
533
534
535void OContactAccessBackend_SQL::clear ()
536{
537 ClearQuery cle;
538 OSQLResult res = m_driver->query( &cle );
539
540 reload();
541}
542
543bool OContactAccessBackend_SQL::wasChangedExternally()
544{
545 return false;
546}
547
548QArray<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
559bool 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
575bool 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
588bool OContactAccessBackend_SQL::replace ( const OContact &contact )
589{
590 if ( !remove( contact.uid() ) )
591 return false;
592
593 return add( contact );
594}
595
596
597OContact 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
612QArray<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
661QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
662{
663 QArray<int> nix(0);
664 return nix;
665}
666
667const uint OContactAccessBackend_SQL::querySettings()
668{
669 return OContactAccess::IgnoreCase
670 || OContactAccess::WildCards;
671}
672
673bool 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
721QArray<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
753void 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
774QArray<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_
796QMap<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
861QMap<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
924QMap<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
45namespace Opie { namespace DB {
46class OSQLDriver;
47class OSQLResult;
48class 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 */
58class 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
102OContactAccessBackend_VCard::OContactAccessBackend_VCard ( const QString& , const QString& filename ):
103 m_dirty( false ),
104 m_file( filename )
105{
106 load();
107}
108
109
110bool 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}
148bool OContactAccessBackend_VCard::reload()
149{
150 return load();
151}
152bool 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}
179void OContactAccessBackend_VCard::clear ()
180{
181 m_map.clear();
182 m_dirty = true; // ??? sure ? (se)
183}
184
185bool OContactAccessBackend_VCard::add ( const OContact& newcontact )
186{
187 m_map.insert( newcontact.uid(), newcontact );
188 m_dirty = true;
189 return true;
190}
191
192bool OContactAccessBackend_VCard::remove ( int uid )
193{
194 m_map.remove( uid );
195 m_dirty = true;
196 return true;
197}
198
199bool OContactAccessBackend_VCard::replace ( const OContact &contact )
200{
201 m_map.replace( contact.uid(), contact );
202 m_dirty = true;
203 return true;
204}
205
206OContact OContactAccessBackend_VCard::find ( int uid ) const
207{
208 return m_map[uid];
209}
210
211QArray<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
224QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& )
225{
226 QArray<int> ar(0);
227 return ar;
228}
229
230// Not implemented
231QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const
232{
233 QArray<int> ar(0);
234 return ar;
235}
236
237const uint OContactAccessBackend_VCard::querySettings()
238{
239 return 0; // No search possible
240}
241
242bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const
243{
244 return false; // No search possible, therefore all settings invalid ;)
245}
246
247bool OContactAccessBackend_VCard::wasChangedExternally()
248{
249 return false; // Don't expect concurrent access
250}
251
252// Not implemented
253QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int )
254{
255 QArray<int> ar(0);
256 return ar;
257}
258
259// *** Private stuff ***
260
261
262OContact 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
490VObject* 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
596QString 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
610QDate 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
635VObject* 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
643VObject* 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
56class VObject;
57
58/**
59 * This is the vCard 2.1 implementation of the Contact Storage
60 * @see OContactAccessBackend_XML
61 * @see OPimAccessBackend
62 */
63class 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
86private:
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
128using namespace Opie;
129
130
131OContactAccessBackend_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
155bool 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
225bool 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
244void OContactAccessBackend_XML::clear ()
245{
246 m_contactList.clear();
247 m_uidToContact.clear();
248
249 m_changed = false;
250}
251
252bool OContactAccessBackend_XML::wasChangedExternally()
253{
254 QFileInfo fi( m_fileName );
255
256 QDateTime lastmod = fi.lastModified ();
257
258 return (lastmod != m_readtime);
259}
260
261QArray<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
274OContact 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
287QArray<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
428QArray<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
446const 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
459bool 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..
507QArray<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
535bool 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
546bool 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
568bool 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
584bool OContactAccessBackend_XML::reload(){
585 /* Reload is the same as load in this implementation */
586 return ( load() );
587}
588
589void 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 */
598bool 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
790void 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
818void 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 */
106class 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*/
16QStringList 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*/
50QStringList 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*/
79QStringList 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*/
112QStringList 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*/
149QStringList 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*/
159QStringList 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*/
169QStringList 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*/
179QStringList 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*/
189QStringList 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*/
198QStringList 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*/
208QStringList 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*/
217QStringList OContactFields::untrfields( bool sorted )
218{
219 return fields( sorted, false );
220}
221
222QMap<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 // email
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
288QMap<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 // email
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
355QMap<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
371QMap<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
386OContactFields::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
397OContactFields::~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
410void 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
422void 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
441void 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
454int 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
4class 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
13class 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
18QString 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
36QDate 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}
77QString 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}
98QDateTime 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 */
27class OConversion
28{
29public:
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
41private:
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 */
11ODateBookAccess::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}
20ODateBookAccess::~ODateBookAccess() {
21}
22
23/**
24 * @return all events available
25 */
26ODateBookAccess::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 */
36ODateBookAccess::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 */
46ODateBookAccess::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 */
58OEffectiveEvent::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 */
64OEffectiveEvent::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 */
73OEffectiveEvent::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 */
79OEffectiveEvent::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 */
18class ODateBookAccess : public OPimAccessTemplate<OEvent> {
19public:
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
38private:
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
7namespace {
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
122ODateBookAccessBackend::ODateBookAccessBackend()
123 : OPimAccessBackend<OEvent>()
124{
125
126}
127ODateBookAccessBackend::~ODateBookAccessBackend() {
128
129}
130OEffectiveEvent::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}
143OEffectiveEvent::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
158OEffectiveEvent::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
169OEffectiveEvent::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 */
14class ODateBookAccessBackend : public OPimAccessBackend<OEvent> {
15public:
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
84private:
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
59using namespace Opie::DB;
60
61
62ODateBookAccessBackend_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
78ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() {
79 if( m_driver )
80 delete m_driver;
81}
82
83void 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
118bool 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
148void 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
163bool ODateBookAccessBackend_SQL::reload()
164{
165 return load();
166}
167
168bool ODateBookAccessBackend_SQL::save()
169{
170 return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
171}
172
173QArray<int> ODateBookAccessBackend_SQL::allRecords()const
174{
175 return m_uids;
176}
177
178QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) {
179 return QArray<int>();
180}
181
182void 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
194OEvent 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..
220bool 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..
266bool 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
285bool ODateBookAccessBackend_SQL::replace( const OEvent& ev )
286{
287 remove( ev.uid() );
288 return add( ev );
289}
290
291QArray<int> ODateBookAccessBackend_SQL::rawEvents()const
292{
293 return allRecords();
294}
295
296QArray<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
309QArray<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
322OEvent::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}
334OEvent::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
347QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
348{
349 QArray<int> null;
350 return null;
351}
352
353/* ===== Private Functions ========================================== */
354
355QArray<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
9namespace Opie { namespace DB {
10class 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 */
20class ODateBookAccessBackend_SQL : public ODateBookAccessBackend {
21public:
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
46private:
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
25namespace {
26 // FROM TT again
27char *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
52namespace {
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
169ODateBookAccessBackend_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}
175ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() {
176}
177bool ODateBookAccessBackend_XML::load() {
178 return loadFile();
179}
180bool ODateBookAccessBackend_XML::reload() {
181 clear();
182 return load();
183}
184bool 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}
233QArray<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}
249QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) {
250 return QArray<int>();
251}
252void ODateBookAccessBackend_XML::clear() {
253 m_changed = true;
254 m_raw.clear();
255 m_rep.clear();
256}
257OEvent 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}
263bool 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}
272bool ODateBookAccessBackend_XML::remove( int uid ) {
273 m_changed = true;
274 m_rep.remove( uid );
275 m_rep.remove( uid );
276
277 return true;
278}
279bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) {
280 replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers)
281 return add( ev );
282}
283QArray<int> ODateBookAccessBackend_XML::rawEvents()const {
284 return allRecords();
285}
286QArray<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}
298QArray<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}
310OEvent::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}
318OEvent::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)
328bool 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)
453void 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}
496void 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}
595QArray<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 */
14class ODateBookAccessBackend_XML : public ODateBookAccessBackend {
15public:
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
40private:
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
14int 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}
26int 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}
31int 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}
40int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) {
41 return ( second.year() - first.year() ) * 12 +
42 second.month() - first.month();
43}
44
45struct 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
71OEvent::OEvent( int uid )
72 : OPimRecord( uid ) {
73 data = new Data;
74}
75OEvent::OEvent( const OEvent& ev)
76 : OPimRecord( ev ), data( ev.data )
77{
78 data->ref();
79}
80
81OEvent::OEvent( const QMap<int, QString> map )
82 : OPimRecord( 0 )
83{
84 data = new Data;
85
86 fromMap( map );
87}
88
89OEvent::~OEvent() {
90 if ( data->deref() ) {
91 delete data;
92 data = 0;
93 }
94}
95OEvent& 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}
106QString OEvent::description()const {
107 return data->description;
108}
109void OEvent::setDescription( const QString& description ) {
110 changeOrModify();
111 data->description = description;
112}
113void OEvent::setLocation( const QString& loc ) {
114 changeOrModify();
115 data->location = loc;
116}
117QString OEvent::location()const {
118 return data->location;
119}
120OPimNotifyManager &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}
129bool 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}
138ORecur OEvent::recurrence()const {
139 if (!data->recur)
140 data->recur = new ORecur;
141
142 return *data->recur;
143}
144void OEvent::setRecurrence( const ORecur& rec) {
145 changeOrModify();
146 if (data->recur )
147 (*data->recur) = rec;
148 else
149 data->recur = new ORecur( rec );
150}
151bool OEvent::hasRecurrence()const {
152 if (!data->recur ) return false;
153 return data->recur->doesRecur();
154}
155QString OEvent::note()const {
156 return data->note;
157}
158void OEvent::setNote( const QString& note ) {
159 changeOrModify();
160 data->note = note;
161}
162QDateTime OEvent::createdDateTime()const {
163 return data->created;
164}
165void OEvent::setCreatedDateTime( const QDateTime& time ) {
166 changeOrModify();
167 data->created = time;
168}
169QDateTime OEvent::startDateTime()const {
170 if ( data->isAllDay )
171 return QDateTime( data->start.date(), QTime(0, 0, 0 ) );
172 return data->start;
173}
174QDateTime 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}
181void OEvent::setStartDateTime( const QDateTime& dt ) {
182 changeOrModify();
183 data->start = dt;
184}
185QDateTime 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}
194QDateTime 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}
201void OEvent::setEndDateTime( const QDateTime& dt ) {
202 changeOrModify();
203 data->end = dt;
204}
205bool OEvent::isMultipleDay()const {
206 return data->end.date().day() - data->start.date().day();
207}
208bool OEvent::isAllDay()const {
209 return data->isAllDay;
210}
211void OEvent::setAllDay( bool allDay ) {
212 changeOrModify();
213 data->isAllDay = allDay;
214 if (allDay ) data->timezone = "UTC";
215}
216void OEvent::setTimeZone( const QString& tz ) {
217 changeOrModify();
218 data->timezone = tz;
219}
220QString OEvent::timeZone()const {
221 if (data->isAllDay ) return QString::fromLatin1("UTC");
222 return data->timezone;
223}
224bool 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}
247QString 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}
304QString 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}
319QString OEvent::type()const {
320 return QString::fromLatin1("OEvent");
321}
322QString OEvent::recordField( int /*id */ )const {
323 return QString::null;
324}
325int OEvent::rtti() {
326 return OPimResolver::DateBook;
327}
328bool OEvent::loadFromStream( QDataStream& ) {
329 return true;
330}
331bool OEvent::saveToStream( QDataStream& )const {
332 return true;
333}
334void 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}
363void 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)
374QMap<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
424void 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
503int OEvent::parent()const {
504 return data->parent;
505}
506void OEvent::setParent( int uid ) {
507 changeOrModify();
508 data->parent = uid;
509}
510QArray<int> OEvent::children() const{
511 if (!data->child) return QArray<int>();
512 else
513 return data->child->copy();
514}
515void 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}
522void 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}
533void 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}
547struct 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
557OEffectiveEvent::OEffectiveEvent() {
558 data = new Data;
559 data->date = QDate::currentDate();
560 data->start = data->end = QTime::currentTime();
561 data->dates = false;
562}
563OEffectiveEvent::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}
580OEffectiveEvent::OEffectiveEvent( const OEffectiveEvent& ev) {
581 data = ev.data;
582 data->ref();
583}
584OEffectiveEvent::~OEffectiveEvent() {
585 if ( data->deref() ) {
586 delete data;
587 data = 0;
588 }
589}
590OEffectiveEvent& 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
600void OEffectiveEvent::setStartTime( const QTime& ti) {
601 changeOrModify();
602 data->start = ti;
603}
604void OEffectiveEvent::setEndTime( const QTime& en) {
605 changeOrModify();
606 data->end = en;
607}
608void OEffectiveEvent::setEvent( const OEvent& ev) {
609 changeOrModify();
610 data->event = ev;
611}
612void OEffectiveEvent::setDate( const QDate& da) {
613 changeOrModify();
614 data->date = da;
615}
616void 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}
626QString OEffectiveEvent::description()const {
627 return data->event.description();
628}
629QString OEffectiveEvent::location()const {
630 return data->event.location();
631}
632QString OEffectiveEvent::note()const {
633 return data->event.note();
634}
635OEvent OEffectiveEvent::event()const {
636 return data->event;
637}
638QTime OEffectiveEvent::startTime()const {
639 return data->start;
640}
641QTime OEffectiveEvent::endTime()const {
642 return data->end;
643}
644QDate OEffectiveEvent::date()const {
645 return data->date;
646}
647int OEffectiveEvent::length()const {
648 return (data->end.hour() * 60 - data->start.hour() * 60)
649 + QABS(data->start.minute() - data->end.minute() );
650}
651int 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}
656QDate 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}
664QDate 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}
672void OEffectiveEvent::deref() {
673 if ( data->deref() ) {
674 delete data;
675 data = 0;
676 }
677}
678void 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}
692bool 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}
700bool OEffectiveEvent::operator<=( const OEffectiveEvent &e ) const{
701 return (data->date <= e.date() );
702}
703bool OEffectiveEvent::operator==( const OEffectiveEvent &e ) const {
704 return ( date() == e.date()
705 && startTime() == e.startTime()
706 && endTime()== e.endTime()
707 && event() == e.event() );
708}
709bool OEffectiveEvent::operator!=( const OEffectiveEvent &e ) const {
710 return !(*this == e );
711}
712bool OEffectiveEvent::operator>( const OEffectiveEvent &e ) const {
713 return !(*this <= e );
714}
715bool 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
16struct 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
31class OPimNotifyManager;
32class 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 */
39class OEvent : public OPimRecord {
40public:
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 &notifiers()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*/
165private:
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 */
178class OEffectiveEvent {
179public:
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
227private:
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
11class 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 */
20template <class T = OPimRecord>
21class OPimAccessBackend {
22public:
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 );
100protected:
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
111private:
112 OPimAccessBackendPrivate *d;
113 Frontend* m_front;
114 uint m_read;
115 int m_acc;
116
117};
118
119template <class T>
120OPimAccessBackend<T>::OPimAccessBackend(int acc)
121 : m_acc( acc )
122{
123 m_front = 0l;
124}
125template <class T>
126OPimAccessBackend<T>::~OPimAccessBackend() {
127
128}
129template <class T>
130void OPimAccessBackend<T>::setFrontend( Frontend* fr ) {
131 m_front = fr;
132}
133template <class T>
134void OPimAccessBackend<T>::cache( const T& t )const {
135 if (m_front )
136 m_front->cache( t );
137}
138template <class T>
139void OPimAccessBackend<T>::setSaneCacheSize( int size) {
140 if (m_front )
141 m_front->setSaneCacheSize( size );
142}
143template <class T>
144T OPimAccessBackend<T>::find( int uid, const QArray<int>&,
145 uint, typename Frontend::CacheDirection )const {
146 return find( uid );
147}
148template <class T>
149void OPimAccessBackend<T>::setReadAhead( uint count ) {
150 m_read = count;
151}
152template <class T>
153uint OPimAccessBackend<T>::readAhead()const {
154 return m_read;
155}
156template <class T>
157int 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
13class 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
23template <class T = OPimRecord >
24class OPimAccessTemplate : public OTemplateBase<T> {
25public:
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;
142protected:
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
156private:
157 OPimAccessTemplatePrivate *d;
158
159};
160
161template <class T>
162OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end )
163 : OTemplateBase<T>(), m_backEnd( end )
164{
165 if (end )
166 end->setFrontend( this );
167}
168template <class T>
169OPimAccessTemplate<T>::~OPimAccessTemplate() {
170 qWarning("~OPimAccessTemplate<T>");
171 delete m_backEnd;
172}
173template <class T>
174bool OPimAccessTemplate<T>::load() {
175 invalidateCache();
176 return m_backEnd->load();
177}
178template <class T>
179bool OPimAccessTemplate<T>::reload() {
180 invalidateCache(); // zecke: I think this should be added (se)
181 return m_backEnd->reload();
182}
183template <class T>
184bool OPimAccessTemplate<T>::save() {
185 return m_backEnd->save();
186}
187template <class T>
188typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const {
189 QArray<int> ints = m_backEnd->allRecords();
190 List lis(ints, this );
191 return lis;
192}
193template <class T>
194typename 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}
199template <class T>
200QArray<int> OPimAccessTemplate<T>::records()const {
201 return m_backEnd->allRecords();
202}
203template <class T>
204typename OPimAccessTemplate<T>::List
205OPimAccessTemplate<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}
211template <class T>
212T OPimAccessTemplate<T>::find( int uid ) const{
213 T t = m_backEnd->find( uid );
214 cache( t );
215 return t;
216}
217template <class T>
218T 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}
234template <class T>
235void OPimAccessTemplate<T>::clear() {
236 invalidateCache();
237 m_backEnd->clear();
238}
239template <class T>
240bool OPimAccessTemplate<T>::add( const T& t ) {
241 cache( t );
242 return m_backEnd->add( t );
243}
244template <class T>
245bool 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}
253template <class T>
254bool OPimAccessTemplate<T>::remove( const T& t ) {
255 return remove( t.uid() );
256}
257template <class T>
258bool OPimAccessTemplate<T>::remove( int uid ) {
259 m_cache.remove( uid );
260 return m_backEnd->remove( uid );
261}
262template <class T>
263bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) {
264 return remove( rec.uid() );
265}
266template <class T>
267bool OPimAccessTemplate<T>::replace( const T& t ) {
268 m_cache.replace( t );
269 return m_backEnd->replace( t );
270}
271template <class T>
272void OPimAccessTemplate<T>::invalidateCache() {
273 m_cache.invalidate();
274}
275template <class T>
276typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() {
277 return m_backEnd;
278}
279template <class T>
280bool OPimAccessTemplate<T>::wasChangedExternally()const {
281 return false;
282}
283template <class T>
284void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) {
285 m_backEnd = end;
286 if (m_backEnd )
287 m_backEnd->setFrontend( this );
288}
289template <class T>
290void 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}
294template <class T>
295void OPimAccessTemplate<T>::setSaneCacheSize( int size ) {
296 m_cache.setSize( size );
297}
298template <class T>
299void 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
8class OPimCacheItemPrivate;
9
10template <class T = OPimRecord>
11class OPimCacheItem {
12public:
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& );
21private:
22 T m_t;
23 OPimCacheItemPrivate *d;
24};
25
26
27class OPimCachePrivate;
28/**
29 * OPimCache for caching the items
30 * We support adding, removing
31 * and finding
32 */
33template <class T = OPimRecord>
34class OPimCache {
35public:
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
52private:
53 QIntCache<Item> m_cache;
54 OPimCachePrivate* d;
55};
56
57// Implementation
58template <class T>
59OPimCacheItem<T>::OPimCacheItem( const T& t )
60 : m_t(t) {
61}
62template <class T>
63OPimCacheItem<T>::~OPimCacheItem() {
64
65}
66template <class T>
67T OPimCacheItem<T>::record()const {
68 return m_t;
69}
70template <class T>
71void OPimCacheItem<T>::setRecord( const T& t ) {
72 m_t = t;
73}
74// Cache
75template <class T>
76OPimCache<T>::OPimCache()
77 : m_cache(100, 53 )
78{
79 m_cache.setAutoDelete( TRUE );
80}
81template <class T>
82OPimCache<T>::~OPimCache() {
83
84}
85template <class T>
86bool OPimCache<T>::contains(int uid )const {
87 Item* it = m_cache.find( uid, FALSE );
88 if (!it)
89 return false;
90 return true;
91}
92template <class T>
93void OPimCache<T>::invalidate() {
94 m_cache.clear();
95}
96template <class T>
97void OPimCache<T>::setSize( int size ) {
98 m_cache.setMaxCost( size );
99}
100template <class T>
101T OPimCache<T>::find(int uid )const {
102 Item *it = m_cache.find( uid );
103 if (it)
104 return it->record();
105 return T();
106}
107template <class T>
108void 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}
119template <class T>
120void OPimCache<T>::remove( int uid ) {
121 m_cache.remove( uid );
122}
123template <class T>
124void 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
3OPimMaintainer::OPimMaintainer( int mode, int uid )
4 : m_mode(mode), m_uid(uid )
5{}
6OPimMaintainer::~OPimMaintainer() {
7}
8OPimMaintainer::OPimMaintainer( const OPimMaintainer& main ) {
9 *this = main;
10}
11OPimMaintainer &OPimMaintainer::operator=( const OPimMaintainer& main ) {
12 m_mode = main.m_mode;
13 m_uid = main.m_uid;
14
15 return *this;
16}
17bool 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}
23bool OPimMaintainer::operator!=( const OPimMaintainer& main ) {
24 return !(*this == main );
25}
26int OPimMaintainer::mode()const {
27 return m_mode;
28}
29int OPimMaintainer::uid()const {
30 return m_uid;
31}
32void OPimMaintainer::setMode( int mo) {
33 m_mode = mo;
34}
35void 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 */
9class OPimMaintainer {
10public:
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
32private:
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
12OPimMainWindow::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}
32OPimMainWindow::~OPimMainWindow() {
33 delete m_channel;
34}
35QCopChannel* OPimMainWindow::channel() {
36 return m_channel;
37}
38void OPimMainWindow::doSetDocument( const QString& ) {
39
40}
41void 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 */
102void 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 */
109OPimRecord* 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 */
125int OPimMainWindow::service() {
126 if ( m_rtti == -1 )
127 m_rtti = OPimResolver::self()->serviceId( m_service );
128
129 return m_rtti;
130}
131void OPimMainWindow::doAlarm( const QDateTime&, int ) {
132
133}
134void OPimMainWindow::startAlarm(int count ) {
135 m_alarmCount = count;
136 m_playedCount = 0;
137 Sound::soundAlarm();
138 m_timerId = startTimer( 5000 );
139}
140void OPimMainWindow::killAlarm() {
141 killTimer( m_timerId );
142}
143void 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
22class QCopChannel;
23class QDateTime;
24class OPimMainWindow : public QMainWindow {
25 Q_OBJECT
26public:
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
35protected 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
64protected:
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
73private slots:
74 void appMessage( const QCString&, const QByteArray& );
75 void setDocument( const QString& );
76
77
78private:
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
5struct 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
15OPimNotify::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}
21OPimNotify::OPimNotify( const OPimNotify& noti)
22 : data( noti.data )
23{
24 data->ref();
25}
26OPimNotify::~OPimNotify() {
27 if ( data->deref() ) {
28 delete data;
29 data = 0l;
30 }
31}
32
33OPimNotify &OPimNotify::operator=( const OPimNotify& noti) {
34 noti.data->ref();
35 deref();
36 data = noti.data;
37
38 return *this;
39}
40bool 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}
49QDateTime OPimNotify::dateTime()const {
50 return data->start;
51}
52QString OPimNotify::service()const {
53 return data->application;
54}
55int OPimNotify::parent()const {
56 return data->parent;
57}
58int OPimNotify::duration()const {
59 return data->dur;
60}
61QDateTime OPimNotify::endTime()const {
62 return QDateTime( data->start.date(), data->start.time().addSecs( data->dur) );
63}
64void OPimNotify::setDateTime( const QDateTime& time ) {
65 copyIntern();
66 data->start = time;
67}
68void OPimNotify::setDuration( int dur ) {
69 copyIntern();
70 data->dur = dur;
71}
72void OPimNotify::setParent( int uid ) {
73 copyIntern();
74 data->parent = uid;
75}
76void OPimNotify::setService( const QString& str ) {
77 copyIntern();
78 data->application = str;
79}
80void 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}
91void OPimNotify::deref() {
92 if ( data->deref() ) {
93 delete data;
94 data = 0;
95 }
96}
97
98/***********************************************************/
99struct OPimAlarm::Data : public QShared {
100 Data() : QShared() {
101 sound = 1;
102 }
103 int sound;
104 QString file;
105};
106OPimAlarm::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}
112OPimAlarm::OPimAlarm( const OPimAlarm& al)
113 : OPimNotify(al), data( al.data )
114{
115 data->ref();
116}
117OPimAlarm::~OPimAlarm() {
118 if ( data->deref() ) {
119 delete data;
120 data = 0l;
121 }
122}
123OPimAlarm &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}
134bool 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}
141QString OPimAlarm::type()const {
142 return QString::fromLatin1("OPimAlarm");
143}
144int OPimAlarm::sound()const {
145 return data->sound;
146}
147QString OPimAlarm::file()const {
148 return data->file;
149}
150void OPimAlarm::setSound( int snd) {
151 copyIntern();
152 data->sound = snd;
153}
154void OPimAlarm::setFile( const QString& sound ) {
155 copyIntern();
156 data->file = sound;
157}
158void OPimAlarm::deref() {
159 if ( data->deref() ) {
160 delete data;
161 data = 0l;
162 }
163}
164void 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/************************/
174struct OPimReminder::Data : public QShared {
175 Data() : QShared(), record( 0) {
176 }
177 int record;
178
179};
180OPimReminder::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}
186OPimReminder::OPimReminder( const OPimReminder& rem )
187 : OPimNotify( rem ), data( rem.data )
188{
189 data->ref();
190}
191OPimReminder& 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}
200bool OPimReminder::operator==( const OPimReminder& rem) {
201 if ( data->record != rem.data->record ) return false;
202
203 return OPimNotify::operator==( rem );
204}
205QString OPimReminder::type()const {
206 return QString::fromLatin1("OPimReminder");
207}
208int OPimReminder::recordUid()const {
209 return data->record;
210}
211void OPimReminder::setRecordUid( int uid ) {
212 copyIntern();
213 data->record = uid;
214}
215void OPimReminder::deref() {
216 if ( data->deref() ) {
217 delete data;
218 data = 0l;
219 }
220}
221void 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 */
20class OPimNotify {
21public:
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
57private:
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 */
73class OPimAlarm : public OPimNotify {
74public:
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
91private:
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 */
108class OPimReminder : public OPimNotify {
109public:
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
134private:
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
7OPimNotifyManager::OPimNotifyManager( const Reminders& rem, const Alarms& al)
8 : m_rem( rem ), m_al( al )
9{}
10OPimNotifyManager::~OPimNotifyManager() {
11}
12/* use static_cast and type instead of dynamic... */
13void 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}
22void 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}
31void 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}
42OPimNotifyManager::Reminders OPimNotifyManager::reminders()const {
43 return m_rem;
44}
45OPimNotifyManager::Alarms OPimNotifyManager::alarms()const {
46 return m_al;
47}
48OPimAlarm 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
64void OPimNotifyManager::setAlarms( const Alarms& al) {
65 m_al = al;
66}
67void 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 */
78void OPimNotifyManager::registerNotify( const OPimNotify& ) {
79
80}
81/* FIXME!!! */
82/**
83 * same as above...
84 * Also implement Url model
85 * have a MainWindow....
86 */
87void OPimNotifyManager::deregister( const OPimNotify& ) {
88
89}
90
91bool 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..
98QString 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}
122QString 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
139void 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
153void 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 */
11class OPimNotifyManager {
12public:
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
82private:
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
8Qtopia::UidGen OPimRecord::m_uidGen( Qtopia::UidGen::Qtopia );
9
10
11OPimRecord::OPimRecord( int uid )
12 : Qtopia::Record() {
13
14 m_lastHit = -1;
15 setUid( uid );
16}
17OPimRecord::~OPimRecord() {
18}
19OPimRecord::OPimRecord( const OPimRecord& rec )
20 : Qtopia::Record( rec )
21{
22 (*this) = rec;
23}
24
25OPimRecord &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 */
37QStringList 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}
49void OPimRecord::setCategoryNames( const QStringList& ) {
50
51}
52void OPimRecord::addCategoryName( const QString& ) {
53 Categories catDB;
54 catDB.load( categoryFileName() );
55
56
57}
58bool 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 */
76void OPimRecord::setUid( int uid ) {
77 if ( uid == 1)
78 uid = uidGen().generate();
79
80 Qtopia::Record::setUid( uid );
81};
82Qtopia::UidGen &OPimRecord::uidGen() {
83 return m_uidGen;
84}
85OPimXRefManager &OPimRecord::xrefmanager() {
86 return m_xrefman;
87}
88int 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 */
100bool 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}
127bool 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}
150void OPimRecord::flush( const OPimXRefPartner& par, QDataStream& str ) const{
151 str << par.service();
152 str << par.uid();
153 str << par.field();
154}
155OPimXRefPartner 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}
171void OPimRecord::setLastHitField( int lastHit )const {
172 m_lastHit = lastHit;
173}
174int OPimRecord::lastHitField()const{
175 return m_lastHit;
176}
177QMap<QString, QString> OPimRecord::toExtraMap()const {
178 return customMap;
179}
180void 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 */
23class OPimRecord : public Qtopia::Record {
24public:
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 &regexp ) 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
138protected:
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
145private:
146 class OPimRecordPrivate;
147 OPimRecordPrivate *d;
148 OPimXRefManager m_xrefman;
149 static Qtopia::UidGen m_uidGen;
150
151private:
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
11OPimResolver* OPimResolver::m_self = 0l;
12
13OPimResolver::OPimResolver() {
14 /* the built in channels */
15 m_builtIns << "Todolist" << "Addressbook" << "Datebook";
16}
17OPimResolver* 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 */
27OPimRecord* 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}
37OPimRecord* OPimResolver::record( const QString& service ) {
38 return record( serviceId( service ) );
39}
40OPimRecord* 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}
58bool OPimResolver::isBuiltIn( const QString& str) const{
59 return m_builtIns.contains( str );
60}
61QCString 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}
79QCString 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 */
88QCString 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}
104QCString 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}
119QStringList OPimResolver::services()const {
120 return m_builtIns;
121}
122QString 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}
140int 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 */
154bool 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}
176OPimBase* OPimResolver::backend( const QString& service ) {
177 return backend( serviceId( service ) );
178}
179OPimBase* 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 */
20class OPimResolver {
21public:
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 );
74private:
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 */
10struct OPimState::Data : public QShared {
11 Data() : QShared(),state(Undefined) {
12 }
13 int state;
14};
15
16OPimState::OPimState( int state ) {
17 data = new Data;
18 data->state = state;
19}
20OPimState::OPimState( const OPimState& st) :
21 data( st.data ) {
22 /* ref up */
23 data->ref();
24}
25OPimState::~OPimState() {
26 if ( data->deref() ) {
27 delete data ;
28 data = 0;
29 }
30}
31bool OPimState::operator==( const OPimState& st) {
32 if ( data->state == st.data->state ) return true;
33
34 return false;
35}
36OPimState &OPimState::operator=( const OPimState& st) {
37 st.data->ref();
38 deref();
39 data = st.data;
40
41 return *this;
42}
43void OPimState::setState( int st) {
44 copyInternally();
45 data->state = st;
46}
47int OPimState::state()const {
48 return data->state;
49}
50void OPimState::deref() {
51 if ( data->deref() ) {
52 delete data;
53 data = 0l;
54 }
55}
56void 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 */
17class OPimState {
18public:
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;
34private:
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
3OPimXRef::OPimXRef( const OPimXRefPartner& one, const OPimXRefPartner& two )
4 : m_partners(2)
5{
6 m_partners[0] = one;
7 m_partners[1] = two;
8}
9OPimXRef::OPimXRef()
10 : m_partners(2)
11{
12
13}
14OPimXRef::OPimXRef( const OPimXRef& ref) {
15 *this = ref;
16}
17OPimXRef::~OPimXRef() {
18}
19OPimXRef &OPimXRef::operator=( const OPimXRef& ref) {
20 m_partners = ref.m_partners;
21 m_partners.detach();
22
23 return* this;
24}
25bool OPimXRef::operator==( const OPimXRef& oper ) {
26 if ( m_partners == oper.m_partners ) return true;
27
28 return false;
29}
30OPimXRefPartner OPimXRef::partner( enum Partners par) const{
31 return m_partners[par];
32}
33void OPimXRef::setPartner( enum Partners par, const OPimXRefPartner& part) {
34 m_partners[par] = part;
35}
36bool 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}
42bool 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 */
13class OPimXRef {
14public:
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
32private:
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
4OPimXRefManager::OPimXRefManager() {
5}
6OPimXRefManager::OPimXRefManager( const OPimXRefManager& ref) {
7 m_list = ref.m_list;
8}
9OPimXRefManager::~OPimXRefManager() {
10}
11OPimXRefManager &OPimXRefManager::operator=( const OPimXRefManager& ref) {
12 m_list = ref.m_list;
13 return *this;
14}
15bool OPimXRefManager::operator==( const OPimXRefManager& /*ref*/) {
16 // if ( m_list == ref.m_list ) return true;
17
18 return false;
19}
20void OPimXRefManager::add( const OPimXRef& ref) {
21 m_list.append( ref );
22}
23void OPimXRefManager::remove( const OPimXRef& ref) {
24 m_list.remove( ref );
25}
26void OPimXRefManager::replace( const OPimXRef& ref) {
27 m_list.remove( ref );
28 m_list.append( ref );
29}
30void OPimXRefManager::clear() {
31 m_list.clear();
32}
33QStringList 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}
47OPimXRef::ValueList OPimXRefManager::list()const {
48 return m_list;
49}
50OPimXRef::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}
61OPimXRef::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 */
14class OPimXRefManager {
15public:
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
37private:
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
3OPimXRefPartner::OPimXRefPartner( const QString& appName,
4 int uid, int field )
5 : m_app(appName), m_uid(uid), m_field( field ) {
6}
7OPimXRefPartner::OPimXRefPartner( const OPimXRefPartner& ref ) {
8 *this = ref;
9}
10OPimXRefPartner::~OPimXRefPartner() {
11}
12OPimXRefPartner &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}
19bool 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}
26QString OPimXRefPartner::service()const {
27 return m_app;
28}
29int OPimXRefPartner::uid()const {
30 return m_uid;
31}
32int OPimXRefPartner::field()const {
33 return m_field;
34}
35void OPimXRefPartner::setService( const QString& appName ) {
36 m_app = appName;
37}
38void OPimXRefPartner::setUid( int uid ) {
39 m_uid = uid;
40}
41void 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 */
13class OPimXRefPartner {
14public:
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 );
30private:
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
10class 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 */
18template <class T> class ORecordList;
19template <class T = OPimRecord>
20class ORecordListIterator {
21 friend class ORecordList<T>;
22public:
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
66private:
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
78class ORecordListPrivate;
79/**
80 * The recordlist used as a return type
81 * from OPimAccessTemplate
82 */
83template <class T = OPimRecord >
84class ORecordList {
85public:
86 typedef OTemplateBase<T> Base;
87 typedef ORecordListIterator<T> Iterator;
88
89 /**
90 * c'tor
91 */
92 ORecordList () {
93 }
94ORecordList( 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 */
125private:
126 QArray<int> m_ids;
127 const Base* m_acc;
128 ORecordListPrivate *d;
129};
130
131/* ok now implement it */
132template <class T>
133ORecordListIterator<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}
141template <class T>
142ORecordListIterator<T>::~ORecordListIterator() {
143/* nothing to delete */
144}
145
146template <class T>
147ORecordListIterator<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
157template <class T>
158ORecordListIterator<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
168template <class T>
169T 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
181template <class T>
182ORecordListIterator<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}
192template <class T>
193ORecordListIterator<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
204template <class T>
205bool 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}
216template <class T>
217bool ORecordListIterator<T>::operator!=( const ORecordListIterator<T>& it ) {
218 return !(*this == it );
219}
220template <class T>
221ORecordListIterator<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}
230template <class T>
231uint ORecordListIterator<T>::current()const {
232 return m_current;
233}
234template <class T>
235void ORecordListIterator<T>::setCurrent( uint cur ) {
236 if( cur < m_uids.count() ) {
237 m_end = false;
238 m_current= cur;
239 }
240}
241template <class T>
242uint ORecordListIterator<T>::count()const {
243 return m_uids.count();
244}
245template <class T>
246ORecordList<T>::ORecordList( const QArray<int>& ids,
247 const Base* acc )
248 : m_ids( ids ), m_acc( acc )
249{
250}
251template <class T>
252ORecordList<T>::~ORecordList() {
253/* nothing to do here */
254}
255template <class T>
256typename ORecordList<T>::Iterator ORecordList<T>::begin() {
257 Iterator it( m_ids, m_acc );
258 return it;
259}
260template <class T>
261typename 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}
268template <class T>
269uint ORecordList<T>::count()const {
270return m_ids.count();
271}
272template <class T>
273T 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}
279template <class T>
280int ORecordList<T>::uidAt( uint i ) {
281 return m_ids[i];
282}
283
284template <class T>
285bool 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
10struct 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
34ORecur::ORecur() {
35 data = new Data;
36}
37
38ORecur::ORecur( const QMap<int, QString>& map )
39{
40 ORecur();
41 fromMap( map );
42}
43
44
45ORecur::ORecur( const ORecur& rec)
46 : data( rec.data )
47{
48 data->ref();
49}
50ORecur::~ORecur() {
51 if ( data->deref() ) {
52 delete data;
53 data = 0l;
54 }
55}
56void ORecur::deref() {
57 if ( data->deref() ) {
58 delete data;
59 data = 0l;
60 }
61}
62bool ORecur::operator==( const ORecur& )const {
63 return false;
64}
65ORecur &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}
74bool ORecur::doesRecur()const {
75 return !( type() == NoRepeat );
76}
77/*
78 * we try to be smart here
79 *
80 */
81bool 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!
94bool 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}
102bool 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}
374ORecur::RepeatType ORecur::type()const{
375 return data->type;
376}
377int ORecur::frequency()const {
378 return data->freq;
379}
380int ORecur::position()const {
381 return data->pos;
382}
383char ORecur::days() const{
384 return data->days;
385}
386bool ORecur::hasEndDate()const {
387 return data->hasEnd;
388}
389QDate ORecur::endDate()const {
390 return data->end;
391}
392QDate ORecur::start()const{
393 return data->start;
394}
395QDateTime ORecur::createdDateTime()const {
396 return data->create;
397}
398int ORecur::repetition()const {
399 return data->rep;
400}
401QString ORecur::service()const {
402 return data->app;
403}
404ORecur::ExceptionList& ORecur::exceptions() {
405 return data->list;
406}
407void ORecur::setType( const RepeatType& z) {
408 checkOrModify();
409 data->type = z;
410}
411void ORecur::setFrequency( int freq ) {
412 checkOrModify();
413 data->freq = freq;
414}
415void ORecur::setPosition( int pos ) {
416 checkOrModify();
417 data->pos = pos;
418}
419void ORecur::setDays( char c ) {
420 checkOrModify();
421 data->days = c;
422}
423void ORecur::setEndDate( const QDate& dt) {
424 checkOrModify();
425 data->end = dt;
426}
427void ORecur::setCreatedDateTime( const QDateTime& t) {
428 checkOrModify();
429 data->create = t;
430}
431void ORecur::setHasEndDate( bool b) {
432 checkOrModify();
433 data->hasEnd = b;
434}
435void ORecur::setRepitition( int rep ) {
436 checkOrModify();
437 data->rep = rep;
438}
439void ORecur::setService( const QString& app ) {
440 checkOrModify();
441 data->app = app;
442}
443void ORecur::setStart( const QDate& dt ) {
444 checkOrModify();
445 data->start = dt;
446}
447void 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}
465QString 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
493QString 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
521QMap<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
536QMap<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
568void 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
19class ORecur {
20public:
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;
91private:
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 */
17class OPimBasePrivate;
18struct 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 */
36private:
37 OPimBasePrivate* d;
38
39};
40/**
41 * internal template base
42 * T needs to implement the copy c'tor!!!
43 */
44class OTemplateBasePrivate;
45template <class T = OPimRecord>
46class OTemplateBase : public OPimBase {
47public:
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
69private:
70 OTemplateBasePrivate *d;
71};
72
73/*
74 * implementation
75 */
76template <class T>
77int
78OTemplateBase<T>::rtti() {
79 return T::rtti();
80}
81template <class T>
82OPimRecord* OTemplateBase<T>::record()const {
83 T* t = new T;
84 return t;
85}
86template <class T>
87OPimRecord* OTemplateBase<T>::record(int uid )const {
88 T t2 = find(uid );
89 T* t1 = new T(t2);
90
91 return t1;
92};
93template <class T>
94T* 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
8namespace {
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}
62OTimeZone::OTimeZone( const ZoneName& zone )
63 : m_name(zone) {
64}
65OTimeZone::~OTimeZone() {
66}
67
68bool 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 */
76QDateTime OTimeZone::toLocalDateTime( const QDateTime& dt) {
77 return OTimeZone::current().toDateTime( dt, *this );
78}
79QDateTime OTimeZone::toUTCDateTime( const QDateTime& dt ) {
80 return OTimeZone::utc().toDateTime( dt, *this );
81}
82QDateTime OTimeZone::fromUTCDateTime( time_t t) {
83 return utcTime( t );
84}
85QDateTime 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 */
92QDateTime 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}
97time_t OTimeZone::fromDateTime( const QDateTime& time ) {
98 return to_Time_t( time, m_name );
99}
100time_t OTimeZone::fromUTCDateTime( const QDateTime& time ) {
101 return to_Time_t( time, "UTC" );
102}
103OTimeZone OTimeZone::current() {
104 QCString str = ::getenv("TZ");
105 OTimeZone zone( str );
106 return zone;
107}
108OTimeZone OTimeZone::utc() {
109 return OTimeZone("UTC");
110}
111QString 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 */
13class 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
23struct 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
52OTodo::OTodo(const OTodo &event )
53 : OPimRecord( event ), data( event.data )
54{
55 data->ref();
56// qWarning("ref up");
57}
58OTodo::~OTodo() {
59
60// qWarning("~OTodo " );
61 if ( data->deref() ) {
62// qWarning("OTodo::dereffing");
63 delete data;
64 data = 0l;
65 }
66}
67OTodo::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}
88OTodo::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}
109bool OTodo::match( const QRegExp &regExp )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}
126bool OTodo::isCompleted() const
127{
128 return data->isCompleted;
129}
130bool OTodo::hasDueDate() const
131{
132 return data->hasDate;
133}
134bool OTodo::hasStartDate()const {
135 return data->start.isValid();
136}
137bool OTodo::hasCompletedDate()const {
138 return data->completed.isValid();
139}
140int OTodo::priority()const
141{
142 return data->priority;
143}
144QString OTodo::summary() const
145{
146 return data->sum;
147}
148ushort OTodo::progress() const
149{
150 return data->prog;
151}
152QDate OTodo::dueDate()const
153{
154 return data->date;
155}
156QDate OTodo::startDate()const {
157 return data->start;
158}
159QDate OTodo::completedDate()const {
160 return data->completed;
161}
162QString OTodo::description()const
163{
164 return data->desc;
165}
166bool OTodo::hasState() const{
167 if (!data->state ) return false;
168 return ( data->state->state() != OPimState::Undefined );
169}
170OPimState OTodo::state()const {
171 if (!data->state ) {
172 OPimState state;
173 return state;
174 }
175
176 return (*data->state);
177}
178bool OTodo::hasRecurrence()const {
179 if (!data->recur) return false;
180 return data->recur->doesRecur();
181}
182ORecur OTodo::recurrence()const {
183 if (!data->recur) return ORecur();
184
185 return (*data->recur);
186}
187bool OTodo::hasMaintainer()const {
188 if (!data->maintainer) return false;
189
190 return (data->maintainer->mode() != OPimMaintainer::Undefined );
191}
192OPimMaintainer OTodo::maintainer()const {
193 if (!data->maintainer) return OPimMaintainer();
194
195 return (*data->maintainer);
196}
197void OTodo::setCompleted( bool completed )
198{
199 changeOrModify();
200 data->isCompleted = completed;
201}
202void OTodo::setHasDueDate( bool hasDate )
203{
204 changeOrModify();
205 data->hasDate = hasDate;
206}
207void OTodo::setDescription(const QString &desc )
208{
209// qWarning( "desc " + desc );
210 changeOrModify();
211 data->desc = Qtopia::simplifyMultiLineSpace(desc );
212}
213void OTodo::setSummary( const QString& sum )
214{
215 changeOrModify();
216 data->sum = sum;
217}
218void OTodo::setPriority(int prio )
219{
220 changeOrModify();
221 data->priority = prio;
222}
223void OTodo::setDueDate( const QDate& date )
224{
225 changeOrModify();
226 data->date = date;
227}
228void OTodo::setStartDate( const QDate& date ) {
229 changeOrModify();
230 data->start = date;
231}
232void OTodo::setCompletedDate( const QDate& date ) {
233 changeOrModify();
234 data->completed = date;
235}
236void OTodo::setState( const OPimState& state ) {
237 changeOrModify();
238 if (data->state )
239 (*data->state) = state;
240 else
241 data->state = new OPimState( state );
242}
243void OTodo::setRecurrence( const ORecur& rec) {
244 changeOrModify();
245 if (data->recur )
246 (*data->recur) = rec;
247 else
248 data->recur = new ORecur( rec );
249}
250void 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}
258bool OTodo::isOverdue( )
259{
260 if( data->hasDate && !data->isCompleted)
261 return QDate::currentDate() > data->date;
262 return false;
263}
264void OTodo::setProgress(ushort progress )
265{
266 changeOrModify();
267 data->prog = progress;
268}
269QString OTodo::toShortText() const {
270 return summary();
271}
272/*!
273 Returns a richt text string
274*/
275QString 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}
340bool OTodo::hasNotifiers()const {
341 if (!data->notifiers) return false;
342 return !data->notifiers->isEmpty();
343}
344OPimNotifyManager& OTodo::notifiers() {
345 if (!data->notifiers )
346 data->notifiers = new OPimNotifyManager;
347 return (*data->notifiers);
348}
349const OPimNotifyManager& OTodo::notifiers()const{
350 if (!data->notifiers )
351 data->notifiers = new OPimNotifyManager;
352
353 return (*data->notifiers);
354}
355
356bool 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}
368bool 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}
381bool 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}
394bool 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}
407bool 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}
421void OTodo::deref() {
422
423// qWarning("deref in ToDoEvent");
424 if ( data->deref() ) {
425// qWarning("deleting");
426 delete data;
427 data= 0;
428 }
429}
430OTodo &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
443QMap<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 */
471void 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 */
485void 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}
510QString OTodo::type() const {
511 return QString::fromLatin1("OTodo");
512}
513QString OTodo::recordField(int /*id*/ )const {
514 return QString::null;
515}
516
517int 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
19class OPimState;
20class ORecur;
21class OPimMaintainer;
22class OPimNotifyManager;
23class OTodo : public OPimRecord {
24public:
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 &notifiers();
180
181 /**
182 *
183 */
184 const OPimNotifyManager &notifiers()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};
280inline 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
9OTodoAccess::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}
21OTodoAccess::~OTodoAccess() {
22// qWarning("~OTodoAccess");
23}
24void 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}
30OTodoAccess::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}
38OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start,
39 bool includeNoDates ) {
40 return effectiveToDos( start, QDate::currentDate(),
41 includeNoDates );
42}
43OTodoAccess::List OTodoAccess::overDue() {
44 List lis( m_todoBackEnd->overDue(), this );
45 return lis;
46}
47/* sort order */
48OTodoAccess::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}
54void OTodoAccess::removeAllCompleted() {
55 m_todoBackEnd->removeAllCompleted();
56}
57QBitArray OTodoAccess::backendSupport( const QString& ) const{
58 return m_todoBackEnd->supports();
59}
60bool 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 */
17class OTodoAccess : public QObject, public OPimAccessTemplate<OTodo> {
18 Q_OBJECT
19public:
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;
90signals:
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 );
98private:
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
4OTodoAccessBackend::OTodoAccessBackend()
5 : OPimAccessBackend<OTodo>()
6{
7}
8OTodoAccessBackend::~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
9class OTodoAccessBackend : public OPimAccessBackend<OTodo> {
10public:
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
22private:
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
16using namespace Opie::DB;
17/*
18 * first some query
19 * CREATE query
20 * LOAD query
21 * INSERT
22 * REMOVE
23 * CLEAR
24 */
25namespace {
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
302OTodoAccessBackendSQL::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
314OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){
315 if( m_driver )
316 delete m_driver;
317}
318
319bool 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}
329bool OTodoAccessBackendSQL::reload(){
330 return load();
331}
332
333bool OTodoAccessBackendSQL::save(){
334 return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
335}
336QArray<int> OTodoAccessBackendSQL::allRecords()const {
337 if (m_dirty )
338 update();
339
340 return m_uids;
341}
342QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){
343 QArray<int> ints(0);
344 return ints;
345}
346OTodo OTodoAccessBackendSQL::find(int uid ) const{
347 FindQuery query( uid );
348 return todo( m_driver->query(&query) );
349
350}
351OTodo 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}
385void OTodoAccessBackendSQL::clear() {
386 ClearQuery cle;
387 OSQLResult res = m_driver->query( &cle );
388 CreateQuery qu;
389 res = m_driver->query(&qu);
390}
391bool 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}
403bool 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 */
418bool 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}
424QArray<int> OTodoAccessBackendSQL::overDue() {
425 OverDueQuery qu;
426 return uids( m_driver->query(&qu ) );
427}
428QArray<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 */
437QArray<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}
503bool 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}
516OTodo 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}
535OTodo 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}
587OTodo OTodoAccessBackendSQL::todo( int uid )const {
588 FindQuery find( uid );
589 return todo( m_driver->query(&find) );
590}
591/*
592 * update the dict
593 */
594void 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 */
621void 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}
630QArray<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
645QArray<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}
673QBitArray OTodoAccessBackendSQL::supports()const {
674
675 return sup();
676}
677
678QBitArray 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
691void 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
8namespace Opie{
9namespace DB {
10class OSQLDriver;
11class OSQLResult;
12class OSQLResultItem;
13}
14}
15
16class OTodoAccessBackendSQL : public OTodoAccessBackend {
17public:
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
44private:
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
9namespace {
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
110OTodoAccessVCal::OTodoAccessVCal( const QString& path )
111 : m_dirty(false), m_file( path )
112{
113}
114OTodoAccessVCal::~OTodoAccessVCal() {
115}
116bool 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}
144bool OTodoAccessVCal::reload() {
145 return load();
146}
147bool 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}
170void OTodoAccessVCal::clear() {
171 m_map.clear();
172 m_dirty = true;
173}
174bool OTodoAccessVCal::add( const OTodo& to ) {
175 m_map.insert( to.uid(), to );
176 m_dirty = true;
177 return true;
178}
179bool OTodoAccessVCal::remove( int uid ) {
180 m_map.remove( uid );
181 m_dirty = true;
182 return true;
183}
184void 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}
190bool OTodoAccessVCal::replace( const OTodo& to ) {
191 m_map.replace( to.uid(), to );
192 m_dirty = true;
193 return true;
194}
195OTodo OTodoAccessVCal::find(int uid )const {
196 return m_map[uid];
197}
198QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) {
199 QArray<int> ar(0);
200 return ar;
201}
202QArray<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}
212QArray<int> OTodoAccessVCal::matchRegexp(const QRegExp& /* r */)const {
213 QArray<int> ar(0);
214 return ar;
215}
216QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) {
217 QArray<int> ar(0);
218 return ar;
219}
220QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& ,
221 const QDate& ,
222 bool ) {
223 QArray<int> ar(0);
224 return ar;
225}
226QArray<int> OTodoAccessVCal::overDue() {
227 QArray<int> ar(0);
228 return ar;
229}
230QBitArray OTodoAccessVCal::supports()const {
231 static QBitArray ar = sup();
232
233 return ar;
234}
235QBitArray 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
6class OTodoAccessVCal : public OTodoAccessBackend {
7public:
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
33private:
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
25namespace {
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
44char *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
70OTodoAccessXML::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}
79OTodoAccessXML::~OTodoAccessXML() {
80
81}
82bool 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}
231bool OTodoAccessXML::reload() {
232 m_events.clear();
233 return load();
234}
235bool 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}
286QArray<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}
297QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) {
298 QArray<int> ids(0);
299 return ids;
300}
301OTodo 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}
310void OTodoAccessXML::clear() {
311 if (m_opened )
312 m_changed = true;
313
314 m_events.clear();
315}
316bool OTodoAccessXML::add( const OTodo& todo ) {
317// qWarning("add");
318 m_changed = true;
319 m_events.insert( todo.uid(), todo );
320
321 return true;
322}
323bool OTodoAccessXML::remove( int uid ) {
324 m_changed = true;
325 m_events.remove( uid );
326
327 return true;
328}
329bool OTodoAccessXML::replace( const OTodo& todo) {
330 m_changed = true;
331 m_events.replace( todo.uid(), todo );
332
333 return true;
334}
335QArray<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}
357QArray<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 */
374void 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
506namespace {
507QString 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
525QString 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}
611QString 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
620struct OTodoXMLContainer {
621 OTodo todo;
622};
623
624namespace {
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 */
675class OTodoXMLVector : public QVector<OTodoXMLContainer> {
676public:
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
788QArray<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};
838void 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}
846QBitArray OTodoAccessXML::supports()const {
847 static QBitArray ar = sup();
848 return ar;
849}
850QBitArray 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}
861QArray<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
9namespace Opie {
10 class XMLElement;
11};
12
13class OTodoAccessXML : public OTodoAccessBackend {
14public:
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;
44private:
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