summaryrefslogtreecommitdiff
path: root/noncore/unsupported/libopie/pim
Side-by-side diff
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 @@
+config.in
+moc*
diff --git a/noncore/unsupported/libopie/pim/config.in b/noncore/unsupported/libopie/pim/config.in
new file mode 100644
index 0000000..95d3737
--- a/dev/null
+++ b/noncore/unsupported/libopie/pim/config.in
@@ -0,0 +1,2 @@
+menu "Pim"
+endmenu
diff --git a/noncore/unsupported/libopie/pim/libopie.pro b/noncore/unsupported/libopie/pim/libopie.pro
new file mode 100644
index 0000000..62f235d
--- a/dev/null
+++ b/noncore/unsupported/libopie/pim/libopie.pro
@@ -0,0 +1,64 @@
+TEMPLATE = lib
+CONFIG += qte warn_on release
+HEADERS = ofontmenu.h \
+ tododb.h \
+ todoevent.h todoresource.h \
+ todovcalresource.h xmltree.h \
+ colordialog.h colorpopupmenu.h \
+ oclickablelabel.h oprocctrl.h \
+ oprocess.h odevice.h \
+ otimepicker.h otabwidget.h \
+ otabbar.h otabinfo.h \
+ ofileselector/ofiledialog.h \
+ ofileselector/ofilelistview.h \
+ ofileselector/ofileselector.h \
+ ofileselector/ofileselectoritem.h \
+ ofileselector/ofileview.h \
+ ofileselector/olister.h \
+ ofileselector/olocallister.h \
+ ofileselector/ofileselectormain.h \
+ pim/opimrecord.h \
+ pim/otodo.h \
+ pim/orecordlist.h \
+ pim/opimaccesstemplate.h \
+ pim/opimaccessbackend.h \
+ pim/otodoaccess.h \
+ pim/otodacessbackend.h \
+ pim/ocontact.h \
+ pim/ocontactaccess.h \
+ pim/ocontactaccessbackend.h \
+ pim/ocontactaccessbackend_xml.h \
+ pim/orecord.h
+
+SOURCES = ofontmenu.cc \
+ xmltree.cc \
+ tododb.cpp todoevent.cpp \
+ todovcalresource.cpp colordialog.cpp \
+ colorpopupmenu.cpp oclickablelabel.cpp \
+ oprocctrl.cpp oprocess.cpp \
+ odevice.cpp otimepicker.cpp \
+ otabwidget.cpp otabbar.cpp \
+ ofileselector/ofiledialog.cpp \
+ ofileselector/ofilelistview.cpp \
+ ofileselector/ofileselector.cpp \
+ ofileselector/ofileselectoritem.cpp \
+ ofileselector/ofileview.cpp \
+ ofileselector/olister.cpp \
+ ofileselector/olocallister.cpp \
+ ofileselector/ofileselectormain.cpp \
+ pim/otodo.cpp \
+ pim/opimrecord.cpp \
+ pim/otodoaccess.cpp \
+ pim/otodoaccessbackend.cpp \
+ pim/ocontact.cpp \
+ pim/ocontactaccess.cpp \
+ pim/orecord.cpp
+
+TARGET = opie
+INCLUDEPATH += $(OPIEDIR)/include
+DESTDIR = $(OPIEDIR)/lib$(PROJMAK)
+#VERSION = 1.0.0
+
+INTERFACES = otimepickerbase.ui
+
+include ( $(OPIEDIR)/include.pro )
diff --git a/noncore/unsupported/libopie/pim/obackendfactory.h b/noncore/unsupported/libopie/pim/obackendfactory.h
new file mode 100644
index 0000000..4cdef8b
--- a/dev/null
+++ b/noncore/unsupported/libopie/pim/obackendfactory.h
@@ -0,0 +1,197 @@
+/*
+ * Class to manage Backends.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later
+ * version.
+ * =====================================================================
+ * ToDo: Use plugins
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.9 2003/12/22 10:19:26 eilers
+ * Finishing implementation of sql-backend for datebook. But I have to
+ * port the PIM datebook application to use it, before I could debug the
+ * whole stuff.
+ * Thus, PIM-Database backend is finished, but highly experimental. And some
+ * parts are still generic. For instance, the "queryByExample()" methods are
+ * not (or not fully) implemented. Todo: custom-entries not stored.
+ * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular
+ * expression search in the database, which is not supported by sqlite !
+ * Therefore we need either an extended sqlite or a workaround which would
+ * be very slow and memory consuming..
+ *
+ * Revision 1.8 2003/09/22 14:31:16 eilers
+ * Added first experimental incarnation of sql-backend for addressbook.
+ * Some modifications to be able to compile the todo sql-backend.
+ * A lot of changes fill follow...
+ *
+ * Revision 1.7 2003/08/01 12:30:16 eilers
+ * Merging changes from BRANCH_1_0 to HEAD
+ *
+ * Revision 1.6.4.1 2003/06/30 14:34:19 eilers
+ * Patches from Zecke:
+ * Fixing and cleaning up extraMap handling
+ * Adding d_ptr for binary compatibility in the future
+ *
+ * Revision 1.6 2003/04/13 18:07:10 zecke
+ * More API doc
+ * QString -> const QString&
+ * QString = 0l -> QString::null
+ *
+ * Revision 1.5 2003/02/21 23:31:52 zecke
+ * Add XML datebookresource
+ * -clean up todoaccessxml header
+ * -implement some more stuff in the oeven tester
+ * -extend DefaultFactory to not crash and to use datebook
+ *
+ * -reading of OEvents is working nicely.. saving will be added
+ * tomorrow
+ * -fix spelling in ODateBookAcces
+ *
+ * Revision 1.4 2002/10/14 15:55:18 eilers
+ * Redeactivate SQL.. ;)
+ *
+ * Revision 1.3 2002/10/10 17:08:58 zecke
+ * The Cache is finally in place
+ * I tested it with my todolist and it 'works' for 10.000 todos the hits are awesome ;)
+ * 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....
+ * I still have to fully implement read ahead
+ * This change is bic but sc
+ *
+ * Revision 1.2 2002/10/08 09:27:36 eilers
+ * Fixed libopie.pro to include the new pim-API.
+ * The SQL-Stuff is currently deactivated. Otherwise everyone who wants to
+ * compile itself would need to install libsqlite, libopiesql...
+ * Therefore, the backend currently uses XML only..
+ *
+ * Revision 1.1 2002/10/07 17:35:01 eilers
+ * added OBackendFactory for advanced backend access
+ *
+ *
+ * =====================================================================
+ */
+#ifndef OPIE_BACKENDFACTORY_H_
+#define OPIE_BACKENDFACTORY_H_
+
+#include <qstring.h>
+#include <qasciidict.h>
+#include <qpe/config.h>
+
+#include "otodoaccessxml.h"
+#include "ocontactaccessbackend_xml.h"
+#include "odatebookaccessbackend_xml.h"
+
+#ifdef __USE_SQL
+#include "otodoaccesssql.h"
+#include "ocontactaccessbackend_sql.h"
+#include "odatebookaccessbackend_sql.h"
+#endif
+
+class OBackendPrivate;
+
+/**
+ * This class is our factory. It will give us the default implementations
+ * of at least Todolist, Contacts and Datebook. In the future this class will
+ * allow users to switch the backend with ( XML->SQLite ) without the need
+ * to recompile.#
+ * This class as the whole PIM Api is making use of templates
+ *
+ * <pre>
+ * OTodoAccessBackend* backend = OBackEndFactory<OTodoAccessBackend>::Default("todo", QString::null );
+ * backend->load();
+ * </pre>
+ *
+ * @author Stefan Eilers
+ * @version 0.1
+ */
+template<class T>
+class OBackendFactory
+{
+ public:
+ OBackendFactory() {};
+
+ enum BACKENDS {
+ TODO,
+ CONTACT,
+ DATE
+ };
+
+ /**
+ * Returns a backend implementation for backendName
+ * @param backendName the type of the backend
+ * @param appName will be passed on to the backend
+ */
+ static T* Default( const QString backendName, const QString& appName ){
+
+ // __asm__("int3");
+
+ Config config( "pimaccess" );
+ config.setGroup ( backendName );
+ QString backend = config.readEntry( "usebackend" );
+
+ qWarning("Selected backend for %s is: %s", backendName.latin1(), backend.latin1() );
+
+ QAsciiDict<int> dict ( 3 );
+ dict.setAutoDelete ( TRUE );
+
+ dict.insert( "todo", new int (TODO) );
+ dict.insert( "contact", new int (CONTACT) );
+ dict.insert( "datebook", new int(DATE) );
+
+ int *find = dict[ backendName ];
+ if (!find ) return 0;
+
+ switch ( *find ){
+ case TODO:
+#ifdef __USE_SQL
+ if ( backend == "sql" )
+ return (T*) new OTodoAccessBackendSQL("");
+#else
+ if ( backend == "sql" )
+ qWarning ("OBackendFactory:: sql Backend for TODO not implemented! Using XML instead!");
+#endif
+
+ return (T*) new OTodoAccessXML( appName );
+ case CONTACT:
+#ifdef __USE_SQL
+ if ( backend == "sql" )
+ return (T*) new OContactAccessBackend_SQL("");
+#else
+ if ( backend == "sql" )
+ qWarning ("OBackendFactory:: sql Backend for CONTACT not implemented! Using XML instead!");
+#endif
+
+ return (T*) new OContactAccessBackend_XML( appName );
+ case DATE:
+#ifdef __USE_SQL
+ if ( backend == "sql" )
+ return (T*) new ODateBookAccessBackend_SQL("");
+#else
+ if ( backend == "sql" )
+ qWarning("OBackendFactory:: sql Backend for DATEBOOK not implemented! Using XML instead!");
+#endif
+
+ return (T*) new ODateBookAccessBackend_XML( appName );
+ default:
+ return NULL;
+ }
+
+
+ }
+ private:
+ OBackendPrivate* d;
+};
+
+
+#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 @@
+/**********************************************************************
+** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
+** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de)
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#define QTOPIA_INTERNAL_CONTACT_MRE
+
+#include "ocontact.h"
+#include "opimresolver.h"
+#include "oconversion.h"
+
+#include <qpe/stringutil.h>
+#include <qpe/timestring.h>
+#include <qpe/config.h>
+
+#include <qobject.h>
+#include <qregexp.h>
+#include <qstylesheet.h>
+#include <qfileinfo.h>
+#include <qmap.h>
+
+#include <stdio.h>
+
+/*!
+ \class Contact contact.h
+ \brief The Contact class holds the data of an address book entry.
+
+ This data includes information the name of the person, contact
+ information, and business information such as deparment and job title.
+
+ \ingroup qtopiaemb
+ \ingroup qtopiadesktop
+*/
+
+
+/*!
+ Creates a new, empty contact.
+*/
+OContact::OContact()
+ : OPimRecord(), mMap(), d( 0 )
+{
+}
+
+/*!
+ \internal
+ Creates a new contact. The properties of the contact are
+ set from \a fromMap.
+*/
+OContact::OContact( const QMap<int, QString> &fromMap ) :
+ OPimRecord(), mMap( fromMap ), d( 0 )
+{
+ QString cats = mMap[ Qtopia::AddressCategory ];
+ if ( !cats.isEmpty() )
+ setCategories( idsFromString( cats ) );
+
+ QString uidStr = find( Qtopia::AddressUid );
+
+ if ( uidStr.isEmpty() || (uidStr.toInt() == 0) ){
+ qWarning( "Invalid UID found. Generate new one.." );
+ setUid( uidGen().generate() );
+ }else
+ setUid( uidStr.toInt() );
+
+// if ( !uidStr.isEmpty() )
+// setUid( uidStr.toInt() );
+}
+
+/*!
+ Destroys a contact.
+*/
+OContact::~OContact()
+{
+}
+
+/*! \fn void OContact::setTitle( const QString &str )
+ Sets the title of the contact to \a str.
+*/
+
+/*! \fn void OContact::setFirstName( const QString &str )
+ Sets the first name of the contact to \a str.
+*/
+
+/*! \fn void OContact::setMiddleName( const QString &str )
+ Sets the middle name of the contact to \a str.
+*/
+
+/*! \fn void OContact::setLastName( const QString &str )
+ Sets the last name of the contact to \a str.
+*/
+
+/*! \fn void OContact::setSuffix( const QString &str )
+ Sets the suffix of the contact to \a str.
+*/
+
+/*! \fn void OContact::setFileAs( const QString &str )
+ Sets the contact to filed as \a str.
+*/
+
+/*! \fn void OContact::setDefaultEmail( const QString &str )
+ Sets the default email of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeStreet( const QString &str )
+ Sets the home street address of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeCity( const QString &str )
+ Sets the home city of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeState( const QString &str )
+ Sets the home state of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeZip( const QString &str )
+ Sets the home zip code of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeCountry( const QString &str )
+ Sets the home country of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomePhone( const QString &str )
+ Sets the home phone number of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeFax( const QString &str )
+ Sets the home fax number of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeMobile( const QString &str )
+ Sets the home mobile phone number of the contact to \a str.
+*/
+
+/*! \fn void OContact::setHomeWebpage( const QString &str )
+ Sets the home webpage of the contact to \a str.
+*/
+
+/*! \fn void OContact::setCompany( const QString &str )
+ Sets the company for contact to \a str.
+*/
+
+/*! \fn void OContact::setJobTitle( const QString &str )
+ Sets the job title of the contact to \a str.
+*/
+
+/*! \fn void OContact::setDepartment( const QString &str )
+ Sets the department for contact to \a str.
+*/
+
+/*! \fn void OContact::setOffice( const QString &str )
+ Sets the office for contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessStreet( const QString &str )
+ Sets the business street address of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessCity( const QString &str )
+ Sets the business city of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessState( const QString &str )
+ Sets the business state of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessZip( const QString &str )
+ Sets the business zip code of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessCountry( const QString &str )
+ Sets the business country of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessPhone( const QString &str )
+ Sets the business phone number of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessFax( const QString &str )
+ Sets the business fax number of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessMobile( const QString &str )
+ Sets the business mobile phone number of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessPager( const QString &str )
+ Sets the business pager number of the contact to \a str.
+*/
+
+/*! \fn void OContact::setBusinessWebpage( const QString &str )
+ Sets the business webpage of the contact to \a str.
+*/
+
+/*! \fn void OContact::setProfession( const QString &str )
+ Sets the profession of the contact to \a str.
+*/
+
+/*! \fn void OContact::setAssistant( const QString &str )
+ Sets the assistant of the contact to \a str.
+*/
+
+/*! \fn void OContact::setManager( const QString &str )
+ Sets the manager of the contact to \a str.
+*/
+
+/*! \fn void OContact::setSpouse( const QString &str )
+ Sets the spouse of the contact to \a str.
+*/
+
+/*! \fn void OContact::setGender( const QString &str )
+ Sets the gender of the contact to \a str.
+*/
+
+/*! \fn void OContact::setNickname( const QString &str )
+ Sets the nickname of the contact to \a str.
+*/
+
+/*! \fn void OContact::setNotes( const QString &str )
+ Sets the notes about the contact to \a str.
+*/
+
+/*! \fn QString OContact::title() const
+ Returns the title of the contact.
+*/
+
+/*! \fn QString OContact::firstName() const
+ Returns the first name of the contact.
+*/
+
+/*! \fn QString OContact::middleName() const
+ Returns the middle name of the contact.
+*/
+
+/*! \fn QString OContact::lastName() const
+ Returns the last name of the contact.
+*/
+
+/*! \fn QString OContact::suffix() const
+ Returns the suffix of the contact.
+*/
+
+/*! \fn QString OContact::fileAs() const
+ Returns the string the contact is filed as.
+*/
+
+/*! \fn QString OContact::defaultEmail() const
+ Returns the default email address of the contact.
+*/
+
+/*! \fn QString OContact::emails() const
+ Returns the list of email address for a contact separated by ';'s in a single
+ string.
+*/
+
+/*! \fn QString OContact::homeStreet() const
+ Returns the home street address of the contact.
+*/
+
+/*! \fn QString OContact::homeCity() const
+ Returns the home city of the contact.
+*/
+
+/*! \fn QString OContact::homeState() const
+ Returns the home state of the contact.
+*/
+
+/*! \fn QString OContact::homeZip() const
+ Returns the home zip of the contact.
+*/
+
+/*! \fn QString OContact::homeCountry() const
+ Returns the home country of the contact.
+*/
+
+/*! \fn QString OContact::homePhone() const
+ Returns the home phone number of the contact.
+*/
+
+/*! \fn QString OContact::homeFax() const
+ Returns the home fax number of the contact.
+*/
+
+/*! \fn QString OContact::homeMobile() const
+ Returns the home mobile number of the contact.
+*/
+
+/*! \fn QString OContact::homeWebpage() const
+ Returns the home webpage of the contact.
+*/
+
+/*! \fn QString OContact::company() const
+ Returns the company for the contact.
+*/
+
+/*! \fn QString OContact::department() const
+ Returns the department for the contact.
+*/
+
+/*! \fn QString OContact::office() const
+ Returns the office for the contact.
+*/
+
+/*! \fn QString OContact::jobTitle() const
+ Returns the job title of the contact.
+*/
+
+/*! \fn QString OContact::profession() const
+ Returns the profession of the contact.
+*/
+
+/*! \fn QString OContact::assistant() const
+ Returns the assistant of the contact.
+*/
+
+/*! \fn QString OContact::manager() const
+ Returns the manager of the contact.
+*/
+
+/*! \fn QString OContact::businessStreet() const
+ Returns the business street address of the contact.
+*/
+
+/*! \fn QString OContact::businessCity() const
+ Returns the business city of the contact.
+*/
+
+/*! \fn QString OContact::businessState() const
+ Returns the business state of the contact.
+*/
+
+/*! \fn QString OContact::businessZip() const
+ Returns the business zip of the contact.
+*/
+
+/*! \fn QString OContact::businessCountry() const
+ Returns the business country of the contact.
+*/
+
+/*! \fn QString OContact::businessPhone() const
+ Returns the business phone number of the contact.
+*/
+
+/*! \fn QString OContact::businessFax() const
+ Returns the business fax number of the contact.
+*/
+
+/*! \fn QString OContact::businessMobile() const
+ Returns the business mobile number of the contact.
+*/
+
+/*! \fn QString OContact::businessPager() const
+ Returns the business pager number of the contact.
+*/
+
+/*! \fn QString OContact::businessWebpage() const
+ Returns the business webpage of the contact.
+*/
+
+/*! \fn QString OContact::spouse() const
+ Returns the spouse of the contact.
+*/
+
+/*! \fn QString OContact::gender() const
+ Returns the gender of the contact.
+*/
+
+/*! \fn QString OContact::nickname() const
+ Returns the nickname of the contact.
+*/
+
+/*! \fn QString OContact::children() const
+ Returns the children of the contact.
+*/
+
+/*! \fn QString OContact::notes() const
+ Returns the notes relating to the the contact.
+*/
+
+/*! \fn QString OContact::groups() const
+ \internal
+ Returns the groups for the contact.
+*/
+
+/*! \fn QStringList OContact::groupList() const
+ \internal
+*/
+
+/*! \fn QString OContact::field(int) const
+ \internal
+*/
+
+/*! \fn void OContact::saveJournal( journal_action, const QString & = QString::null )
+ \internal
+*/
+
+/*! \fn void OContact::setUid( int id )
+ \internal
+ Sets the uid for this record to \a id.
+*/
+
+/*! \enum OContact::journal_action
+ \internal
+*/
+
+/*!
+ \internal
+*/
+QMap<int, QString> OContact::toMap() const
+{
+ QMap<int, QString> map = mMap;
+ QString cats = idsToString( categories() );
+ if ( !cats.isEmpty() )
+ map.insert( Qtopia::AddressCategory, cats );
+ return map;
+}
+
+/*!
+ Returns a rich text formatted QString representing the contents the contact.
+*/
+QString OContact::toRichText() const
+{
+ QString text;
+ QString value, comp, state;
+ QString str;
+ bool marker = false;
+
+ Config cfg("qpe");
+ cfg.setGroup("Appearance");
+ int addressformat = cfg.readNumEntry( "AddressFormat", Zip_City_State );
+
+ // name, jobtitle and company
+ if ( !(value = fullName()).isEmpty() )
+ text += "<b><h3><img src=\"addressbook/AddressBook\"> " + Qtopia::escapeString(value) + "</h3></b>";
+
+ if ( !(value = jobTitle()).isEmpty() )
+ text += Qtopia::escapeString(value) + " ";
+
+ comp = company();
+ if ( !(value = department()).isEmpty() ) {
+ text += Qtopia::escapeString(value);
+ if ( comp )
+ text += ", " + Qtopia::escapeString(comp);
+ }else if ( comp )
+ text += "<br>" + Qtopia::escapeString(comp);
+ text += "<br><hr>";
+
+ // defailt email
+ QString defEmail = defaultEmail();
+ if ( !defEmail.isEmpty() ){
+ text += "<b><img src=\"addressbook/email\"> " + QObject::tr("Default Email: ") + "</b>"
+ + Qtopia::escapeString(defEmail);
+ marker = true;
+ }
+
+ // business address
+ if ( !businessStreet().isEmpty() || !businessCity().isEmpty() ||
+ !businessZip().isEmpty() || !businessCountry().isEmpty() ) {
+ text += QObject::tr( "<br><b>Work Address:</b>" );
+ marker = true;
+ }
+
+ if ( !(value = businessStreet()).isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(value);
+ marker = true;
+ }
+
+ switch( addressformat ){
+ case Zip_City_State:{ // Zip_Code City, State
+ state = businessState();
+ if ( !(value = businessZip()).isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(value) + " ";
+ marker = true;
+
+ }
+ if ( !(value = businessCity()).isEmpty() ) {
+ marker = true;
+ if ( businessZip().isEmpty() && !businessStreet().isEmpty() )
+ text += "<br>";
+ text += Qtopia::escapeString(value);
+ if ( state )
+ text += ", " + Qtopia::escapeString(state);
+ } else if ( !state.isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(state);
+ marker = true;
+ }
+ break;
+ }
+ case City_State_Zip:{ // City, State Zip_Code
+ state = businessState();
+ if ( !(value = businessCity()).isEmpty() ) {
+ marker = true;
+ text += "<br>" + Qtopia::escapeString(value);
+ if ( state )
+ text += ", " + Qtopia::escapeString(state);
+ } else if ( !state.isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(state);
+ marker = true;
+ }
+ if ( !(value = businessZip()).isEmpty() ){
+ text += " " + Qtopia::escapeString(value);
+ marker = true;
+ }
+ break;
+ }
+ }
+
+ if ( !(value = businessCountry()).isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(value);
+ marker = true;
+ }
+
+ // rest of Business data
+ str = office();
+ if ( !str.isEmpty() ){
+ text += "<br><b>" + QObject::tr("Office: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = businessWebpage();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/webpagework\"> " + QObject::tr("Business Web Page: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = businessPhone();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/phonework\"> " + QObject::tr("Business Phone: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = businessFax();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/faxwork\"> " + QObject::tr("Business Fax: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = businessMobile();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/mobilework\"> " + QObject::tr("Business Mobile: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = businessPager();
+ if ( !str.isEmpty() ){
+ text += "<br><b>" + QObject::tr("Business Pager: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+
+ // text += "<br>";
+
+ // home address
+ if ( !homeStreet().isEmpty() || !homeCity().isEmpty() ||
+ !homeZip().isEmpty() || !homeCountry().isEmpty() ) {
+ text += QObject::tr( "<br><b>Home Address:</b>" );
+ marker = true;
+ }
+
+ if ( !(value = homeStreet()).isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(value);
+ marker = true;
+ }
+
+ switch( addressformat ){
+ case Zip_City_State:{ // Zip_Code City, State
+ state = homeState();
+ if ( !(value = homeZip()).isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(value) + " ";
+ marker = true;
+ }
+ if ( !(value = homeCity()).isEmpty() ) {
+ marker = true;
+ if ( homeZip().isEmpty() && !homeStreet().isEmpty() )
+ text += "<br>";
+ text += Qtopia::escapeString(value);
+ if ( !state.isEmpty() )
+ text += ", " + Qtopia::escapeString(state);
+ } else if (!state.isEmpty()) {
+ text += "<br>" + Qtopia::escapeString(state);
+ marker = true;
+ }
+ break;
+ }
+ case City_State_Zip:{ // City, State Zip_Code
+ state = homeState();
+ if ( !(value = homeCity()).isEmpty() ) {
+ marker = true;
+ text += "<br>" + Qtopia::escapeString(value);
+ if ( state )
+ text += ", " + Qtopia::escapeString(state);
+ } else if ( !state.isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(state);
+ marker = true;
+ }
+ if ( !(value = homeZip()).isEmpty() ){
+ text += " " + Qtopia::escapeString(value);
+ marker = true;
+ }
+ break;
+ }
+ }
+
+ if ( !(value = homeCountry()).isEmpty() ){
+ text += "<br>" + Qtopia::escapeString(value);
+ marker = true;
+ }
+
+ // rest of Home data
+ str = homeWebpage();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/webpagehome\"> " + QObject::tr("Home Web Page: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = homePhone();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/phonehome\"> " + QObject::tr("Home Phone: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = homeFax();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/faxhome\"> " + QObject::tr("Home Fax: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+ str = homeMobile();
+ if ( !str.isEmpty() ){
+ text += "<br><b><img src=\"addressbook/mobilehome\"> " + QObject::tr("Home Mobile: ") + "</b>"
+ + Qtopia::escapeString(str);
+ marker = true;
+ }
+
+ if ( marker )
+ text += "<br><hr>";
+
+ // the rest...
+ str = emails();
+ if ( !str.isEmpty() && ( str != defEmail ) )
+ text += "<br><b>" + QObject::tr("All Emails: ") + "</b>"
+ + Qtopia::escapeString(str);
+ str = profession();
+ if ( !str.isEmpty() )
+ text += "<br><b>" + QObject::tr("Profession: ") + "</b>"
+ + Qtopia::escapeString(str);
+ str = assistant();
+ if ( !str.isEmpty() )
+ text += "<br><b>" + QObject::tr("Assistant: ") + "</b>"
+ + Qtopia::escapeString(str);
+ str = manager();
+ if ( !str.isEmpty() )
+ text += "<br><b>" + QObject::tr("Manager: ") + "</b>"
+ + Qtopia::escapeString(str);
+ str = gender();
+ if ( !str.isEmpty() && str.toInt() != 0 ) {
+ text += "<br>";
+ if ( str.toInt() == 1 )
+ str = QObject::tr( "Male" );
+ else if ( str.toInt() == 2 )
+ str = QObject::tr( "Female" );
+ text += "<b>" + QObject::tr("Gender: ") + "</b>" + str;
+ }
+ str = spouse();
+ if ( !str.isEmpty() )
+ text += "<br><b>" + QObject::tr("Spouse: ") + "</b>"
+ + Qtopia::escapeString(str);
+ if ( birthday().isValid() ){
+ str = TimeString::numberDateString( birthday() );
+ text += "<br><b>" + QObject::tr("Birthday: ") + "</b>"
+ + Qtopia::escapeString(str);
+ }
+ if ( anniversary().isValid() ){
+ str = TimeString::numberDateString( anniversary() );
+ text += "<br><b>" + QObject::tr("Anniversary: ") + "</b>"
+ + Qtopia::escapeString(str);
+ }
+ str = children();
+ if ( !str.isEmpty() )
+ text += "<br><b>" + QObject::tr("Children: ") + "</b>"
+ + Qtopia::escapeString(str);
+
+ str = nickname();
+ if ( !str.isEmpty() )
+ text += "<br><b>" + QObject::tr("Nickname: ") + "</b>"
+ + Qtopia::escapeString(str);
+
+ // categories
+ if ( categoryNames("Contacts").count() ){
+ text += "<br><b>" + QObject::tr( "Category:") + "</b> ";
+ text += categoryNames("Contacts").join(", ");
+ }
+
+ // notes last
+ if ( !(value = notes()).isEmpty() ) {
+ text += "<br><hr><b>" + QObject::tr( "Notes:") + "</b> ";
+ QRegExp reg("\n");
+
+ //QString tmp = Qtopia::escapeString(value);
+ QString tmp = QStyleSheet::convertFromPlainText(value);
+ //tmp.replace( reg, "<br>" );
+ text += "<br>" + tmp + "<br>";
+ }
+ return text;
+}
+
+/*!
+ \internal
+*/
+void OContact::insert( int key, const QString &v )
+{
+ QString value = v.stripWhiteSpace();
+ if ( value.isEmpty() )
+ mMap.remove( key );
+ else
+ mMap.insert( key, value );
+}
+
+/*!
+ \internal
+*/
+void OContact::replace( int key, const QString & v )
+{
+ QString value = v.stripWhiteSpace();
+ if ( value.isEmpty() )
+ mMap.remove( key );
+ else
+ mMap.replace( key, value );
+}
+
+/*!
+ \internal
+*/
+QString OContact::find( int key ) const
+{
+ return mMap[key];
+}
+
+/*!
+ \internal
+*/
+QString OContact::displayAddress( const QString &street,
+ const QString &city,
+ const QString &state,
+ const QString &zip,
+ const QString &country ) const
+{
+ QString s = street;
+ if ( !street.isEmpty() )
+ s+= "\n";
+ s += city;
+ if ( !city.isEmpty() && !state.isEmpty() )
+ s += ", ";
+ s += state;
+ if ( !state.isEmpty() && !zip.isEmpty() )
+ s += " ";
+ s += zip;
+ if ( !country.isEmpty() && !s.isEmpty() )
+ s += "\n";
+ s += country;
+ return s;
+}
+
+/*!
+ \internal
+*/
+QString OContact::displayBusinessAddress() const
+{
+ return displayAddress( businessStreet(), businessCity(),
+ businessState(), businessZip(),
+ businessCountry() );
+}
+
+/*!
+ \internal
+*/
+QString OContact::displayHomeAddress() const
+{
+ return displayAddress( homeStreet(), homeCity(),
+ homeState(), homeZip(),
+ homeCountry() );
+}
+
+/*!
+ Returns the full name of the contact
+*/
+QString OContact::fullName() const
+{
+ QString title = find( Qtopia::Title );
+ QString firstName = find( Qtopia::FirstName );
+ QString middleName = find( Qtopia::MiddleName );
+ QString lastName = find( Qtopia::LastName );
+ QString suffix = find( Qtopia::Suffix );
+
+ QString name = title;
+ if ( !firstName.isEmpty() ) {
+ if ( !name.isEmpty() )
+ name += " ";
+ name += firstName;
+ }
+ if ( !middleName.isEmpty() ) {
+ if ( !name.isEmpty() )
+ name += " ";
+ name += middleName;
+ }
+ if ( !lastName.isEmpty() ) {
+ if ( !name.isEmpty() )
+ name += " ";
+ name += lastName;
+ }
+ if ( !suffix.isEmpty() ) {
+ if ( !name.isEmpty() )
+ name += " ";
+ name += suffix;
+ }
+ return name.simplifyWhiteSpace();
+}
+
+/*!
+ Returns a list of the names of the children of the contact.
+*/
+QStringList OContact::childrenList() const
+{
+ return QStringList::split( " ", find( Qtopia::Children ) );
+}
+
+/*! \fn void OContact::insertEmail( const QString &email )
+
+ Insert \a email into the email list. Ensures \a email can only be added
+ once. If there is no default email address set, it sets it to the \a email.
+*/
+
+/*! \fn void OContact::removeEmail( const QString &email )
+
+ Removes the \a email from the email list. If the default email was \a email,
+ then the default email address is assigned to the first email in the
+ email list
+*/
+
+/*! \fn void OContact::clearEmails()
+
+ Clears the email list.
+ */
+
+/*! \fn void OContact::insertEmails( const QStringList &emailList )
+
+ Appends the \a emailList to the exiting email list
+ */
+
+/*!
+ Returns a list of email addresses belonging to the contact, including
+ the default email address.
+*/
+QStringList OContact::emailList() const
+{
+ QString emailStr = emails();
+
+ QStringList r;
+ if ( !emailStr.isEmpty() ) {
+ qDebug(" emailstr ");
+ QStringList l = QStringList::split( emailSeparator(), emailStr );
+ for ( QStringList::ConstIterator it = l.begin();it != l.end();++it )
+ r += (*it).simplifyWhiteSpace();
+ }
+
+ return r;
+}
+
+/*!
+ \overload
+
+ Generates the string for the contact to be filed as from the first,
+ middle and last name of the contact.
+*/
+void OContact::setFileAs()
+{
+ QString lastName, firstName, middleName, fileas;
+
+ lastName = find( Qtopia::LastName );
+ firstName = find( Qtopia::FirstName );
+ middleName = find( Qtopia::MiddleName );
+ if ( !lastName.isEmpty() && !firstName.isEmpty()
+ && !middleName.isEmpty() )
+ fileas = lastName + ", " + firstName + " " + middleName;
+ else if ( !lastName.isEmpty() && !firstName.isEmpty() )
+ fileas = lastName + ", " + firstName;
+ else if ( !lastName.isEmpty() || !firstName.isEmpty() ||
+ !middleName.isEmpty() )
+ fileas = firstName + ( firstName.isEmpty() ? "" : " " )
+ + middleName + ( middleName.isEmpty() ? "" : " " )
+ + lastName;
+
+ replace( Qtopia::FileAs, fileas );
+}
+
+/*!
+ \internal
+ Appends the contact information to \a buf.
+*/
+void OContact::save( QString &buf ) const
+{
+ static const QStringList SLFIELDS = fields();
+ // I'm expecting "<Contact " in front of this...
+ for ( QMap<int, QString>::ConstIterator it = mMap.begin();
+ it != mMap.end(); ++it ) {
+ const QString &value = it.data();
+ int key = it.key();
+ if ( !value.isEmpty() ) {
+ if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid)
+ continue;
+
+ key -= Qtopia::AddressCategory+1;
+ buf += SLFIELDS[key];
+ buf += "=\"" + Qtopia::escapeString(value) + "\" ";
+ }
+ }
+ buf += customToXml();
+ if ( categories().count() > 0 )
+ buf += "Categories=\"" + idsToString( categories() ) + "\" ";
+ buf += "Uid=\"" + QString::number( uid() ) + "\" ";
+ // You need to close this yourself
+}
+
+
+/*!
+ \internal
+ Returns the list of fields belonging to a contact
+ Never change order of this list ! It has to be regarding
+ enum AddressBookFields !!
+*/
+QStringList OContact::fields()
+{
+ QStringList list;
+
+ list.append( "Title" ); // Not Used!
+ list.append( "FirstName" );
+ list.append( "MiddleName" );
+ list.append( "LastName" );
+ list.append( "Suffix" );
+ list.append( "FileAs" );
+
+ list.append( "JobTitle" );
+ list.append( "Department" );
+ list.append( "Company" );
+ list.append( "BusinessPhone" );
+ list.append( "BusinessFax" );
+ list.append( "BusinessMobile" );
+
+ list.append( "DefaultEmail" );
+ list.append( "Emails" );
+
+ list.append( "HomePhone" );
+ list.append( "HomeFax" );
+ list.append( "HomeMobile" );
+
+ list.append( "BusinessStreet" );
+ list.append( "BusinessCity" );
+ list.append( "BusinessState" );
+ list.append( "BusinessZip" );
+ list.append( "BusinessCountry" );
+ list.append( "BusinessPager" );
+ list.append( "BusinessWebPage" );
+
+ list.append( "Office" );
+ list.append( "Profession" );
+ list.append( "Assistant" );
+ list.append( "Manager" );
+
+ list.append( "HomeStreet" );
+ list.append( "HomeCity" );
+ list.append( "HomeState" );
+ list.append( "HomeZip" );
+ list.append( "HomeCountry" );
+ list.append( "HomeWebPage" );
+
+ list.append( "Spouse" );
+ list.append( "Gender" );
+ list.append( "Birthday" );
+ list.append( "Anniversary" );
+ list.append( "Nickname" );
+ list.append( "Children" );
+
+ list.append( "Notes" );
+ list.append( "Groups" );
+
+ return list;
+}
+
+
+/*!
+ Sets the list of email address for contact to those contained in \a str.
+ Email address should be separated by ';'s.
+*/
+void OContact::setEmails( const QString &str )
+{
+ replace( Qtopia::Emails, str );
+ if ( str.isEmpty() )
+ setDefaultEmail( QString::null );
+}
+
+/*!
+ Sets the list of children for the contact to those contained in \a str.
+*/
+void OContact::setChildren( const QString &str )
+{
+ replace( Qtopia::Children, str );
+}
+
+/*!
+ \overload
+ Returns TRUE if the contact matches the regular expression \a regexp.
+ Otherwise returns FALSE.
+*/
+bool OContact::match( const QRegExp &r ) const
+{
+ setLastHitField( -1 );
+ bool match;
+ match = false;
+ QMap<int, QString>::ConstIterator it;
+ for ( it = mMap.begin(); it != mMap.end(); ++it ) {
+ if ( (*it).find( r ) > -1 ) {
+ setLastHitField( it.key() );
+ match = true;
+ break;
+ }
+ }
+ return match;
+}
+
+
+QString OContact::toShortText() const
+{
+ return ( fullName() );
+}
+QString OContact::type() const
+{
+ return QString::fromLatin1( "OContact" );
+}
+
+
+
+class QString OContact::recordField( int pos ) const
+{
+ QStringList SLFIELDS = fields(); // ?? why this ? (se)
+ return SLFIELDS[pos];
+}
+
+// In future releases, we should store birthday and anniversary
+// internally as QDate instead of QString !
+// QString is always too complicate to interprete (DD.MM.YY, DD/MM/YY, MM/DD/YY, etc..)(se)
+
+/*! \fn void OContact::setBirthday( const QDate& date )
+ Sets the birthday for the contact to \a date. If date is null
+ the current stored date will be removed.
+*/
+void OContact::setBirthday( const QDate &v )
+{
+ if ( v.isNull() ){
+ qWarning( "Remove Birthday");
+ replace( Qtopia::Birthday, QString::null );
+ return;
+ }
+
+ if ( v.isValid() )
+ replace( Qtopia::Birthday, OConversion::dateToString( v ) );
+
+}
+
+
+/*! \fn void OContact::setAnniversary( const QDate &date )
+ Sets the anniversary of the contact to \a date. If date is
+ null, the current stored date will be removed.
+*/
+void OContact::setAnniversary( const QDate &v )
+{
+ if ( v.isNull() ){
+ qWarning( "Remove Anniversary");
+ replace( Qtopia::Anniversary, QString::null );
+ return;
+ }
+
+ if ( v.isValid() )
+ replace( Qtopia::Anniversary, OConversion::dateToString( v ) );
+}
+
+/*! \fn QDate OContact::birthday() const
+ Returns the birthday of the contact.
+*/
+QDate OContact::birthday() const
+{
+ QString str = find( Qtopia::Birthday );
+ // qWarning ("Birthday %s", str.latin1() );
+ if ( !str.isEmpty() )
+ return OConversion::dateFromString ( str );
+ else
+ return QDate();
+}
+
+
+/*! \fn QDate OContact::anniversary() const
+ Returns the anniversary of the contact.
+*/
+QDate OContact::anniversary() const
+{
+ QDate empty;
+ QString str = find( Qtopia::Anniversary );
+ // qWarning ("Anniversary %s", str.latin1() );
+ if ( !str.isEmpty() )
+ return OConversion::dateFromString ( str );
+ else
+ return empty;
+}
+
+
+void OContact::insertEmail( const QString &v )
+{
+ //qDebug("insertEmail %s", v.latin1());
+ QString e = v.simplifyWhiteSpace();
+ QString def = defaultEmail();
+
+ // if no default, set it as the default email and don't insert
+ if ( def.isEmpty() ) {
+ setDefaultEmail( e ); // will insert into the list for us
+ return;
+ }
+
+ // otherwise, insert assuming doesn't already exist
+ QString emailsStr = find( Qtopia::Emails );
+ if ( emailsStr.contains( e ))
+ return;
+ if ( !emailsStr.isEmpty() )
+ emailsStr += emailSeparator();
+ emailsStr += e;
+ replace( Qtopia::Emails, emailsStr );
+}
+
+void OContact::removeEmail( const QString &v )
+{
+ QString e = v.simplifyWhiteSpace();
+ QString def = defaultEmail();
+ QString emailsStr = find( Qtopia::Emails );
+ QStringList emails = emailList();
+
+ // otherwise, must first contain it
+ if ( !emailsStr.contains( e ) )
+ return;
+
+ // remove it
+ //qDebug(" removing email from list %s", e.latin1());
+ emails.remove( e );
+ // reset the string
+ emailsStr = emails.join(emailSeparator()); // Sharp's brain dead separator
+ replace( Qtopia::Emails, emailsStr );
+
+ // if default, then replace the default email with the first one
+ if ( def == e ) {
+ //qDebug("removeEmail is default; setting new default");
+ if ( !emails.count() )
+ clearEmails();
+ else // setDefaultEmail will remove e from the list
+ setDefaultEmail( emails.first() );
+ }
+}
+void OContact::clearEmails()
+{
+ mMap.remove( Qtopia::DefaultEmail );
+ mMap.remove( Qtopia::Emails );
+}
+void OContact::setDefaultEmail( const QString &v )
+{
+ QString e = v.simplifyWhiteSpace();
+
+ //qDebug("OContact::setDefaultEmail %s", e.latin1());
+ replace( Qtopia::DefaultEmail, e );
+
+ if ( !e.isEmpty() )
+ insertEmail( e );
+
+}
+
+void OContact::insertEmails( const QStringList &v )
+{
+ for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it )
+ insertEmail( *it );
+}
+int OContact::rtti() {
+ return OPimResolver::AddressBook;
+}
+void OContact::setUid( int i )
+{
+ OPimRecord::setUid(i);
+ replace( Qtopia::AddressUid , QString::number(i));
+}
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 @@
+/**********************************************************************
+** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
+** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de)
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#ifndef __OCONTACT_H__
+#define __OCONTACT_H__
+
+#include <opie/opimrecord.h>
+#include <qpe/recordfields.h>
+
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+#if defined(QPC_TEMPLATEDLL)
+// MOC_SKIP_BEGIN
+QPC_TEMPLATEEXTERN template class QPC_EXPORT QMap<int, QString>;
+// MOC_SKIP_END
+#endif
+
+class OContactPrivate;
+
+/**
+ * OContact class represents a specialised PIM Record for contacts.
+ * It does store all kind of persopn related information.
+ *
+ * @short Contact Container
+ * @author TT, Stefan Eiler, Holger Freyther
+ */
+class QPC_EXPORT OContact : public OPimRecord
+{
+ friend class DataSet;
+public:
+ OContact();
+ OContact( const QMap<int, QString> &fromMap );
+ virtual ~OContact();
+
+ enum DateFormat{
+ Zip_City_State = 0,
+ City_State_Zip
+ };
+
+ /*
+ * do we need to inline them
+ * if yes do we need to inline them this way?
+ * -zecke
+ */
+ void setTitle( const QString &v ) { replace( Qtopia::Title, v ); }
+ void setFirstName( const QString &v ) { replace( Qtopia::FirstName, v ); }
+ void setMiddleName( const QString &v ) { replace( Qtopia::MiddleName, v ); }
+ void setLastName( const QString &v ) { replace( Qtopia::LastName, v ); }
+ void setSuffix( const QString &v ) { replace( Qtopia::Suffix, v ); }
+ void setFileAs( const QString &v ) { replace( Qtopia::FileAs, v ); }
+ void setFileAs();
+
+ // default email address
+ void setDefaultEmail( const QString &v );
+ // inserts email to list and ensure's doesn't already exist
+ void insertEmail( const QString &v );
+ void removeEmail( const QString &v );
+ void clearEmails();
+ void insertEmails( const QStringList &v );
+
+ // home
+ void setHomeStreet( const QString &v ) { replace( Qtopia::HomeStreet, v ); }
+ void setHomeCity( const QString &v ) { replace( Qtopia::HomeCity, v ); }
+ void setHomeState( const QString &v ) { replace( Qtopia::HomeState, v ); }
+ void setHomeZip( const QString &v ) { replace( Qtopia::HomeZip, v ); }
+ void setHomeCountry( const QString &v ) { replace( Qtopia::HomeCountry, v ); }
+ void setHomePhone( const QString &v ) { replace( Qtopia::HomePhone, v ); }
+ void setHomeFax( const QString &v ) { replace( Qtopia::HomeFax, v ); }
+ void setHomeMobile( const QString &v ) { replace( Qtopia::HomeMobile, v ); }
+ void setHomeWebpage( const QString &v ) { replace( Qtopia::HomeWebPage, v ); }
+
+ // business
+ void setCompany( const QString &v ) { replace( Qtopia::Company, v ); }
+ void setBusinessStreet( const QString &v ) { replace( Qtopia::BusinessStreet, v ); }
+ void setBusinessCity( const QString &v ) { replace( Qtopia::BusinessCity, v ); }
+ void setBusinessState( const QString &v ) { replace( Qtopia::BusinessState, v ); }
+ void setBusinessZip( const QString &v ) { replace( Qtopia::BusinessZip, v ); }
+ void setBusinessCountry( const QString &v ) { replace( Qtopia::BusinessCountry, v ); }
+ void setBusinessWebpage( const QString &v ) { replace( Qtopia::BusinessWebPage, v ); }
+ void setJobTitle( const QString &v ) { replace( Qtopia::JobTitle, v ); }
+ void setDepartment( const QString &v ) { replace( Qtopia::Department, v ); }
+ void setOffice( const QString &v ) { replace( Qtopia::Office, v ); }
+ void setBusinessPhone( const QString &v ) { replace( Qtopia::BusinessPhone, v ); }
+ void setBusinessFax( const QString &v ) { replace( Qtopia::BusinessFax, v ); }
+ void setBusinessMobile( const QString &v ) { replace( Qtopia::BusinessMobile, v ); }
+ void setBusinessPager( const QString &v ) { replace( Qtopia::BusinessPager, v ); }
+ void setProfession( const QString &v ) { replace( Qtopia::Profession, v ); }
+ void setAssistant( const QString &v ) { replace( Qtopia::Assistant, v ); }
+ void setManager( const QString &v ) { replace( Qtopia::Manager, v ); }
+
+ // personal
+ void setSpouse( const QString &v ) { replace( Qtopia::Spouse, v ); }
+ void setGender( const QString &v ) { replace( Qtopia::Gender, v ); }
+ void setBirthday( const QDate &v );
+ void setAnniversary( const QDate &v );
+ void setNickname( const QString &v ) { replace( Qtopia::Nickname, v ); }
+ void setChildren( const QString &v );
+
+ // other
+ void setNotes( const QString &v ) { replace( Qtopia::Notes, v); }
+
+ virtual bool match( const QRegExp &regexp ) const;
+
+// // custom
+// void setCustomField( const QString &key, const QString &v )
+// { replace(Custom- + key, v ); }
+
+ // name
+ QString fullName() const;
+ QString title() const { return find( Qtopia::Title ); }
+ QString firstName() const { return find( Qtopia::FirstName ); }
+ QString middleName() const { return find( Qtopia::MiddleName ); }
+ QString lastName() const { return find( Qtopia::LastName ); }
+ QString suffix() const { return find( Qtopia::Suffix ); }
+ QString fileAs() const { return find( Qtopia::FileAs ); }
+
+ // email
+ QString defaultEmail() const { return find( Qtopia::DefaultEmail ); }
+ QStringList emailList() const;
+
+ // home
+ /*
+ * OPimAddress address(enum Location)const;
+ * would be some how nicer...
+ * -zecke
+ */
+ QString homeStreet() const { return find( Qtopia::HomeStreet ); }
+ QString homeCity() const { return find( Qtopia::HomeCity ); }
+ QString homeState() const { return find( Qtopia::HomeState ); }
+ QString homeZip() const { return find( Qtopia::HomeZip ); }
+ QString homeCountry() const { return find( Qtopia::HomeCountry ); }
+ QString homePhone() const { return find( Qtopia::HomePhone ); }
+ QString homeFax() const { return find( Qtopia::HomeFax ); }
+ QString homeMobile() const { return find( Qtopia::HomeMobile ); }
+ QString homeWebpage() const { return find( Qtopia::HomeWebPage ); }
+ /** Multi line string containing all non-empty address info in the form
+ * Street
+ * City, State Zip
+ * Country
+ */
+ QString displayHomeAddress() const;
+
+ // business
+ QString company() const { return find( Qtopia::Company ); }
+ QString businessStreet() const { return find( Qtopia::BusinessStreet ); }
+ QString businessCity() const { return find( Qtopia::BusinessCity ); }
+ QString businessState() const { return find( Qtopia::BusinessState ); }
+ QString businessZip() const { return find( Qtopia::BusinessZip ); }
+ QString businessCountry() const { return find( Qtopia::BusinessCountry ); }
+ QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); }
+ QString jobTitle() const { return find( Qtopia::JobTitle ); }
+ QString department() const { return find( Qtopia::Department ); }
+ QString office() const { return find( Qtopia::Office ); }
+ QString businessPhone() const { return find( Qtopia::BusinessPhone ); }
+ QString businessFax() const { return find( Qtopia::BusinessFax ); }
+ QString businessMobile() const { return find( Qtopia::BusinessMobile ); }
+ QString businessPager() const { return find( Qtopia::BusinessPager ); }
+ QString profession() const { return find( Qtopia::Profession ); }
+ QString assistant() const { return find( Qtopia::Assistant ); }
+ QString manager() const { return find( Qtopia::Manager ); }
+ /** Multi line string containing all non-empty address info in the form
+ * Street
+ * City, State Zip
+ * Country
+ */
+ QString displayBusinessAddress() const;
+
+ //personal
+ QString spouse() const { return find( Qtopia::Spouse ); }
+ QString gender() const { return find( Qtopia::Gender ); }
+ QDate birthday() const;
+ QDate anniversary() const;
+ QString nickname() const { return find( Qtopia::Nickname ); }
+ QString children() const { return find( Qtopia::Children ); }
+ QStringList childrenList() const;
+
+ // other
+ QString notes() const { return find( Qtopia::Notes ); }
+ QString groups() const { return find( Qtopia::Groups ); }
+ QStringList groupList() const;
+
+ QString toRichText() const;
+ QMap<int, QString> toMap() const;
+ QString field( int key ) const { return find( key ); }
+
+
+ void setUid( int i );
+
+ QString toShortText()const;
+ QString type()const;
+ class QString recordField(int) const;
+
+ // Why private ? (eilers,se)
+ QString emailSeparator() const { return " "; }
+
+ // the emails should be seperated by a comma
+ void setEmails( const QString &v );
+ QString emails() const { return find( Qtopia::Emails ); }
+ static int rtti();
+
+private:
+ // The XML Backend needs some access to the private functions
+ friend class OContactAccessBackend_XML;
+
+ void insert( int key, const QString &value );
+ void replace( int key, const QString &value );
+ QString find( int key ) const;
+ static QStringList fields();
+
+ void save( QString &buf ) const;
+
+ QString displayAddress( const QString &street,
+ const QString &city,
+ const QString &state,
+ const QString &zip,
+ const QString &country ) const;
+
+ QMap<int, QString> mMap;
+ OContactPrivate *d;
+};
+
+
+#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 @@
+/*
+ * Class to manage the Contacts.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ * Info: This class could just work with a change in the header-file
+ * of the Contact class ! Therefore our libopie only compiles
+ * with our version of libqpe
+ * =====================================================================
+ * ToDo: XML-Backend: Automatic reload if something was changed...
+ *
+ *
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.9 2004/03/02 12:14:22 alwin
+ * run the optimize_connect script
+ * the whole cvs is tagged with "before_optimize_connect" if there are problems you
+ * can check the diff (but it had compiled and run here)
+ *
+ * Revision 1.8 2003/05/08 13:55:09 tille
+ * search stuff
+ * and match, toRichText & toShortText in oevent
+ *
+ * Revision 1.7 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.6 2002/11/01 15:10:42 eilers
+ * Added regExp-search in database for all fields in a contact.
+ *
+ * Revision 1.5 2002/10/16 10:52:40 eilers
+ * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
+ *
+ * Revision 1.4 2002/10/14 16:21:54 eilers
+ * Some minor interface updates
+ *
+ * Revision 1.3 2002/10/07 17:34:24 eilers
+ * added OBackendFactory for advanced backend access
+ *
+ * Revision 1.2 2002/10/02 16:18:11 eilers
+ * debugged and seems to work almost perfectly ..
+ *
+ * Revision 1.1 2002/09/27 17:11:44 eilers
+ * Added API for accessing the Contact-Database ! It is compiling, but
+ * please do not expect that anything is working !
+ * I will debug that stuff in the next time ..
+ * Please read README_COMPILE for compiling !
+ *
+ *
+ */
+
+#include "ocontactaccess.h"
+#include "obackendfactory.h"
+
+#include <qasciidict.h>
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <qlist.h>
+#include <qcopchannel_qws.h>
+
+//#include <qpe/qcopenvelope_qws.h>
+#include <qpe/global.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "ocontactaccessbackend_xml.h"
+
+
+OContactAccess::OContactAccess ( const QString appname, const QString ,
+ OContactAccessBackend* end, bool autosync ):
+ OPimAccessTemplate<OContact>( end )
+{
+ /* take care of the backend. If there is no one defined, we
+ * will use the XML-Backend as default (until we have a cute SQL-Backend..).
+ */
+ if( end == 0 ) {
+ qWarning ("Using BackendFactory !");
+ end = OBackendFactory<OContactAccessBackend>::Default( "contact", appname );
+ }
+ // Set backend locally and in template
+ m_backEnd = end;
+ OPimAccessTemplate<OContact>::setBackEnd (end);
+
+
+ /* Connect signal of external db change to function */
+ QCopChannel *dbchannel = new QCopChannel( "QPE/PIM", this );
+ connect( dbchannel, SIGNAL(received(const QCString&,const QByteArray&)),
+ this, SLOT(copMessage(const QCString&,const QByteArray&)) );
+ if ( autosync ){
+ QCopChannel *syncchannel = new QCopChannel( "QPE/Sync", this );
+ connect( syncchannel, SIGNAL(received(const QCString&,const QByteArray&)),
+ this, SLOT(copMessage(const QCString&,const QByteArray&)) );
+ }
+
+
+}
+OContactAccess::~OContactAccess ()
+{
+ /* The user may forget to save the changed database, therefore try to
+ * do it for him..
+ */
+ save();
+ // delete m_backEnd; is done by template..
+}
+
+
+bool OContactAccess::save ()
+{
+ /* If the database was changed externally, we could not save the
+ * Data. This will remove added items which is unacceptable !
+ * Therefore: Reload database and merge the data...
+ */
+ if ( OPimAccessTemplate<OContact>::wasChangedExternally() )
+ reload();
+
+ bool status = OPimAccessTemplate<OContact>::save();
+ if ( !status ) return false;
+
+ /* Now tell everyone that new data is available.
+ */
+ QCopEnvelope e( "QPE/PIM", "addressbookUpdated()" );
+
+ return true;
+}
+
+const uint OContactAccess::querySettings()
+{
+ return ( m_backEnd->querySettings() );
+}
+
+bool OContactAccess::hasQuerySettings ( int querySettings ) const
+{
+ return ( m_backEnd->hasQuerySettings ( querySettings ) );
+}
+ORecordList<OContact> OContactAccess::sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const
+{
+ QArray<int> matchingContacts = m_backEnd -> sorted( ascending, sortOrder, sortFilter, cat );
+ return ( ORecordList<OContact>(matchingContacts, this) );
+}
+
+
+bool OContactAccess::wasChangedExternally()const
+{
+ return ( m_backEnd->wasChangedExternally() );
+}
+
+
+void OContactAccess::copMessage( const QCString &msg, const QByteArray & )
+{
+ if ( msg == "addressbookUpdated()" ){
+ qWarning ("OContactAccess: Received addressbokUpdated()");
+ emit signalChanged ( this );
+ } else if ( msg == "flush()" ) {
+ qWarning ("OContactAccess: Received flush()");
+ save ();
+ } else if ( msg == "reload()" ) {
+ qWarning ("OContactAccess: Received reload()");
+ reload ();
+ emit signalChanged ( this );
+ }
+}
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 @@
+/*
+ * Class to manage the Contacts.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later
+ * version.
+ * =====================================================================
+ * ToDo: Define enum for query settings
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.10 2003/12/22 10:19:26 eilers
+ * Finishing implementation of sql-backend for datebook. But I have to
+ * port the PIM datebook application to use it, before I could debug the
+ * whole stuff.
+ * Thus, PIM-Database backend is finished, but highly experimental. And some
+ * parts are still generic. For instance, the "queryByExample()" methods are
+ * not (or not fully) implemented. Todo: custom-entries not stored.
+ * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular
+ * expression search in the database, which is not supported by sqlite !
+ * Therefore we need either an extended sqlite or a workaround which would
+ * be very slow and memory consuming..
+ *
+ * Revision 1.9 2003/08/01 12:30:16 eilers
+ * Merging changes from BRANCH_1_0 to HEAD
+ *
+ * Revision 1.8.2.1 2003/06/30 14:34:19 eilers
+ * Patches from Zecke:
+ * Fixing and cleaning up extraMap handling
+ * Adding d_ptr for binary compatibility in the future
+ *
+ * Revision 1.8 2003/05/08 13:55:09 tille
+ * search stuff
+ * and match, toRichText & toShortText in oevent
+ *
+ * Revision 1.7 2003/04/13 18:07:10 zecke
+ * More API doc
+ * QString -> const QString&
+ * QString = 0l -> QString::null
+ *
+ * Revision 1.6 2003/01/02 14:27:12 eilers
+ * Improved query by example: Search by date is possible.. First step
+ * for a today plugin for birthdays..
+ *
+ * Revision 1.5 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.4 2002/11/01 15:10:42 eilers
+ * Added regExp-search in database for all fields in a contact.
+ *
+ * Revision 1.3 2002/10/16 10:52:40 eilers
+ * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
+ *
+ * Revision 1.2 2002/10/14 16:21:54 eilers
+ * Some minor interface updates
+ *
+ * Revision 1.1 2002/09/27 17:11:44 eilers
+ * Added API for accessing the Contact-Database ! It is compiling, but
+ * please do not expect that anything is working !
+ * I will debug that stuff in the next time ..
+ * Please read README_COMPILE for compiling !
+ *
+ * =====================================================================
+ */
+#ifndef _OCONTACTACCESS_H
+#define _OCONTACTACCESS_H
+
+#include <qobject.h>
+
+#include <qpe/qcopenvelope_qws.h>
+
+#include <qvaluelist.h>
+#include <qfileinfo.h>
+
+#include "ocontact.h"
+#include "ocontactaccessbackend.h"
+#include "opimaccesstemplate.h"
+
+/**
+ * Class to access the contacts database.
+ * This is just a frontend for the real database handling which is
+ * done by the backend.
+ * This class is used to access the Contacts on a system. This class as any OPIE PIM
+ * class is backend independent.
+ * @author Stefan Eilers, Holger Freyther
+ * @see OPimAccessTemplate
+ */
+class OContactAccess: public QObject, public OPimAccessTemplate<OContact>
+{
+ Q_OBJECT
+
+ public:
+ /**
+ * Create Database with contacts (addressbook).
+ * @param appname Name of application which wants access to the database
+ * (i.e. "todolist")
+ * @param filename The name of the database file. If not set, the default one
+ * is used.
+ * @param backend Pointer to an alternative Backend. If not set, we will use
+ * the default backend.
+ * @param handlesync If <b>true</b> the database stores the current state
+ * automatically if it receives the signals <i>flush()</i> and <i>reload()</i>
+ * which are used before and after synchronisation. If the application wants
+ * to react itself, it should be disabled by setting it to <b>false</b>
+ * @see OContactAccessBackend
+ */
+ OContactAccess (const QString appname, const QString filename = 0l,
+ OContactAccessBackend* backend = 0l, bool handlesync = true);
+ ~OContactAccess ();
+
+ /** Constants for query.
+ * Use this constants to set the query parameters.
+ * Note: <i>query_IgnoreCase</i> just make sense with one of the other attributes !
+ * @see queryByExample()
+ */
+ enum QuerySettings {
+ WildCards = 0x0001,
+ IgnoreCase = 0x0002,
+ RegExp = 0x0004,
+ ExactMatch = 0x0008,
+ MatchOne = 0x0010, // Only one Entry must match
+ DateDiff = 0x0020, // Find all entries from today until given date
+ DateYear = 0x0040, // The year matches
+ DateMonth = 0x0080, // The month matches
+ DateDay = 0x0100, // The day matches
+ };
+
+
+ /** Return all Contacts in a sorted manner.
+ * @param ascending true: Sorted in acending order.
+ * @param sortOrder Currently not implemented. Just defined to stay compatible to otodoaccess
+ * @param sortFilter Currently not implemented. Just defined to stay compatible to otodoaccess
+ * @param cat Currently not implemented. Just defined to stay compatible to otodoaccess
+ */
+ List sorted( bool ascending, int sortOrder, int sortFilter, int cat ) const;
+
+ /** Return all possible settings.
+ * @return All settings provided by the current backend
+ * (i.e.: query_WildCards & query_IgnoreCase)
+ */
+ const uint querySettings();
+
+ /** Check whether settings are correct.
+ * @return <i>true</i> if the given settings are correct and possible.
+ */
+ bool hasQuerySettings ( int querySettings ) const;
+
+ /**
+ * if the resource was changed externally.
+ * You should use the signal instead of polling possible changes !
+ */
+ bool wasChangedExternally()const;
+
+
+ /** Save contacts database.
+ * Save is more a "commit". After calling this function, all changes are public available.
+ * @return true if successful
+ */
+ bool save();
+
+ signals:
+ /* Signal is emitted if the database was changed. Therefore
+ * we may need to reload to stay consistent.
+ * @param which Pointer to the database who created this event. This pointer
+ * is useful if an application has to handle multiple databases at the same time.
+ * @see reload()
+ */
+ void signalChanged ( const OContactAccess *which );
+
+
+ private:
+ // class OContactAccessPrivate;
+ // OContactAccessPrivate* d;
+ OContactAccessBackend *m_backEnd;
+ bool m_loading:1;
+
+ private slots:
+ void copMessage( const QCString &msg, const QByteArray &data );
+
+ private:
+ class Private;
+ Private *d;
+
+};
+#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 @@
+/**
+ * The class responsible for managing a backend.
+ * The implementation of this abstract class contains
+ * the complete database handling.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later
+ * version.
+ * =====================================================================
+ * ToDo: Define enum for query settings
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.7 2004/02/19 02:05:37 zecke
+ * Add notes for API fixes and BC stuff
+ *
+ * Revision 1.6 2003/08/01 12:30:16 eilers
+ * Merging changes from BRANCH_1_0 to HEAD
+ *
+ * Revision 1.5.4.1 2003/06/30 14:34:19 eilers
+ * Patches from Zecke:
+ * Fixing and cleaning up extraMap handling
+ * Adding d_ptr for binary compatibility in the future
+ *
+ * Revision 1.5 2003/04/13 18:07:10 zecke
+ * More API doc
+ * QString -> const QString&
+ * QString = 0l -> QString::null
+ *
+ * Revision 1.4 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.3 2002/11/01 15:10:42 eilers
+ * Added regExp-search in database for all fields in a contact.
+ *
+ * Revision 1.2 2002/10/07 17:34:24 eilers
+ * added OBackendFactory for advanced backend access
+ *
+ * Revision 1.1 2002/09/27 17:11:44 eilers
+ * Added API for accessing the Contact-Database ! It is compiling, but
+ * please do not expect that anything is working !
+ * I will debug that stuff in the next time ..
+ * Please read README_COMPILE for compiling !
+ *
+ * =====================================================================
+ *
+ */
+
+#ifndef _OCONTACTACCESSBACKEND_H_
+#define _OCONTACTACCESSBACKEND_H_
+
+#include "ocontact.h"
+#include "opimaccessbackend.h"
+
+#include <qregexp.h>
+
+/**
+ * This class represents the interface of all Contact Backends.
+ * Derivates of this class will be used to access the contacts.
+ * As implementation currently XML and vCard exist. This class needs to be implemented
+ * if you want to provide your own storage.
+ * In all queries a list of uids is passed on instead of loading the actual record!
+ *
+ * @see OContactAccessBackend_VCard
+ * @see OContactAccessBackend_XML
+ */
+class OContactAccessBackend: public OPimAccessBackend<OContact> {
+ public:
+ /**
+ * @todo make non line in regard to BC guide of KDE
+ */
+ OContactAccessBackend() {}
+ /**
+ * @todo make non inline in regard to the BC guide of KDE
+ */
+ virtual ~OContactAccessBackend() {}
+
+
+ /**
+ * Return if database was changed externally.
+ * This may just make sense on file based databases like a XML-File.
+ * It is used to prevent to overwrite the current database content
+ * if the file was already changed by something else !
+ * If this happens, we have to reload before save our data.
+ * If we use real databases, this should be handled by the database
+ * management system themselve, therefore this function should always return false in
+ * this case. It is not our problem to handle this conflict ...
+ * @return <i>true</i> if the database was changed and if save without reload will
+ * be dangerous. <i>false</i> if the database was not changed or it is save to write
+ * in this situation.
+ */
+ virtual bool wasChangedExternally() = 0;
+
+ virtual QArray<int> matchRegexp( const QRegExp &r ) const = 0;
+
+ /**
+ * Return all possible settings.
+ * @return All settings provided by the current backend
+ * (i.e.: query_WildCards & query_IgnoreCase)
+ */
+ virtual const uint querySettings() = 0;
+
+ /**
+ * Check whether settings are correct.
+ * @return <i>true</i> if the given settings are correct and possible.
+ */
+ virtual bool hasQuerySettings (uint querySettings) const = 0;
+
+ /**
+ * FIXME!!!
+ * Returns a sorted list of records either ascendinf or descending for a giving criteria and category
+ */
+ virtual QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ) = 0;
+
+
+private:
+ class Private;
+ Private *d;
+};
+#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 @@
+/*
+ * SQL Backend for the OPIE-Contact Database.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.5 2004/03/14 13:50:35 alwin
+ * namespace correction
+ *
+ * Revision 1.4 2003/12/22 10:19:26 eilers
+ * Finishing implementation of sql-backend for datebook. But I have to
+ * port the PIM datebook application to use it, before I could debug the
+ * whole stuff.
+ * Thus, PIM-Database backend is finished, but highly experimental. And some
+ * parts are still generic. For instance, the "queryByExample()" methods are
+ * not (or not fully) implemented. Todo: custom-entries not stored.
+ * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular
+ * expression search in the database, which is not supported by sqlite !
+ * Therefore we need either an extended sqlite or a workaround which would
+ * be very slow and memory consuming..
+ *
+ * Revision 1.3 2003/12/08 15:18:10 eilers
+ * Committing unfinished sql implementation before merging to libopie2 starts..
+ *
+ * Revision 1.2 2003/09/29 07:44:26 eilers
+ * Improvement of PIM-SQL Databases, but search queries are still limited.
+ * Addressbook: Changed table layout. Now, we just need 1/3 of disk-space.
+ * Todo: Started to add new attributes. Some type conversions missing.
+ *
+ * Revision 1.1 2003/09/22 14:31:16 eilers
+ * Added first experimental incarnation of sql-backend for addressbook.
+ * Some modifications to be able to compile the todo sql-backend.
+ * A lot of changes fill follow...
+ *
+ */
+
+#include "ocontactaccessbackend_sql.h"
+
+#include <qarray.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+#include <qpe/global.h>
+#include <qpe/recordfields.h>
+
+#include <opie/ocontactfields.h>
+#include <opie/oconversion.h>
+#include <opie2/osqldriver.h>
+#include <opie2/osqlresult.h>
+#include <opie2/osqlmanager.h>
+#include <opie2/osqlquery.h>
+
+using namespace Opie::DB;
+
+
+// If defined, we use a horizontal table ( uid, attr1, attr2, attr3, ..., attrn ) instead
+// vertical like "uid, type, value".
+// DON'T DEACTIVATE THIS DEFINE IN PRODUCTIVE ENVIRONMENTS !!
+#define __STORE_HORIZONTAL_
+
+// Distinct loading is not very fast. If I expect that every person has just
+// one (and always one) 'Last Name', I can request all uid's for existing lastnames,
+// which is faster..
+// But this may not be true for all entries, like company contacts..
+// The current AddressBook application handles this problem, but other may not.. (eilers)
+#define __USE_SUPERFAST_LOADQUERY
+
+
+/*
+ * Implementation of used query types
+ * CREATE query
+ * LOAD query
+ * INSERT
+ * REMOVE
+ * CLEAR
+ */
+namespace {
+ /**
+ * CreateQuery for the Todolist Table
+ */
+ class CreateQuery : public OSQLQuery {
+ public:
+ CreateQuery();
+ ~CreateQuery();
+ QString query()const;
+ };
+
+ /**
+ * Clears (delete) a Table
+ */
+ class ClearQuery : public OSQLQuery {
+ public:
+ ClearQuery();
+ ~ClearQuery();
+ QString query()const;
+
+ };
+
+
+ /**
+ * LoadQuery
+ * this one queries for all uids
+ */
+ class LoadQuery : public OSQLQuery {
+ public:
+ LoadQuery();
+ ~LoadQuery();
+ QString query()const;
+ };
+
+ /**
+ * inserts/adds a OContact to the table
+ */
+ class InsertQuery : public OSQLQuery {
+ public:
+ InsertQuery(const OContact& );
+ ~InsertQuery();
+ QString query()const;
+ private:
+ OContact m_contact;
+ };
+
+
+ /**
+ * removes one from the table
+ */
+ class RemoveQuery : public OSQLQuery {
+ public:
+ RemoveQuery(int uid );
+ ~RemoveQuery();
+ QString query()const;
+ private:
+ int m_uid;
+ };
+
+ /**
+ * a find query for noncustom elements
+ */
+ class FindQuery : public OSQLQuery {
+ public:
+ FindQuery(int uid);
+ FindQuery(const QArray<int>& );
+ ~FindQuery();
+ QString query()const;
+ private:
+ QString single()const;
+ QString multi()const;
+ QArray<int> m_uids;
+ int m_uid;
+ };
+
+ /**
+ * a find query for custom elements
+ */
+ class FindCustomQuery : public OSQLQuery {
+ public:
+ FindCustomQuery(int uid);
+ FindCustomQuery(const QArray<int>& );
+ ~FindCustomQuery();
+ QString query()const;
+ private:
+ QString single()const;
+ QString multi()const;
+ QArray<int> m_uids;
+ int m_uid;
+ };
+
+
+
+ // We using three tables to store the information:
+ // 1. addressbook : It contains General information about the contact (non custom)
+ // 2. custom_data : Not official supported entries
+ // All tables are connected by the uid of the contact.
+ // Maybe I should add a table for meta-information ?
+ CreateQuery::CreateQuery() : OSQLQuery() {}
+ CreateQuery::~CreateQuery() {}
+ QString CreateQuery::query()const {
+ QString qu;
+#ifdef __STORE_HORIZONTAL_
+
+ qu += "create table addressbook( uid PRIMARY KEY ";
+
+ QStringList fieldList = OContactFields::untrfields( false );
+ for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
+ qu += QString( ",\"%1\" VARCHAR(10)" ).arg( *it );
+ }
+ qu += " );";
+
+ qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
+
+#else
+
+ qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));";
+ qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
+// qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );";
+
+#endif // __STORE_HORIZONTAL_
+ return qu;
+ }
+
+ ClearQuery::ClearQuery()
+ : OSQLQuery() {}
+ ClearQuery::~ClearQuery() {}
+ QString ClearQuery::query()const {
+ QString qu = "drop table addressbook;";
+ qu += "drop table custom_data;";
+// qu += "drop table dates;";
+ return qu;
+ }
+
+
+ LoadQuery::LoadQuery() : OSQLQuery() {}
+ LoadQuery::~LoadQuery() {}
+ QString LoadQuery::query()const {
+ QString qu;
+#ifdef __STORE_HORIZONTAL_
+ qu += "select uid from addressbook";
+#else
+# ifndef __USE_SUPERFAST_LOADQUERY
+ qu += "select distinct uid from addressbook";
+# else
+ qu += "select uid from addressbook where type = 'Last Name'";
+# endif // __USE_SUPERFAST_LOADQUERY
+#endif // __STORE_HORIZONTAL_
+
+ return qu;
+ }
+
+
+ InsertQuery::InsertQuery( const OContact& contact )
+ : OSQLQuery(), m_contact( contact ) {
+ }
+
+ InsertQuery::~InsertQuery() {
+ }
+
+ /*
+ * converts from a OContact to a query
+ */
+ QString InsertQuery::query()const{
+
+#ifdef __STORE_HORIZONTAL_
+ QString qu;
+ qu += "insert into addressbook VALUES( " +
+ QString::number( m_contact.uid() );
+
+ // Get all information out of the contact-class
+ // Remember: The category is stored in contactMap, too !
+ QMap<int, QString> contactMap = m_contact.toMap();
+
+ QStringList fieldList = OContactFields::untrfields( false );
+ QMap<QString, int> translate = OContactFields::untrFieldsToId();
+ for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
+ // Convert Column-String to Id and get value for this id..
+ // Hmmm.. Maybe not very cute solution..
+ int id = translate[*it];
+ switch ( id ){
+ case Qtopia::Birthday:{
+ // These entries should stored in a special format
+ // year-month-day
+ QDate day = m_contact.birthday();
+ if ( day.isValid() ){
+ qu += QString(",\"%1-%2-%3\"")
+ .arg( day.year() )
+ .arg( day.month() )
+ .arg( day.day() );
+ } else {
+ qu += ",\"\"";
+ }
+ }
+ break;
+ case Qtopia::Anniversary:{
+ // These entries should stored in a special format
+ // year-month-day
+ QDate day = m_contact.anniversary();
+ if ( day.isValid() ){
+ qu += QString(",\"%1-%2-%3\"")
+ .arg( day.year() )
+ .arg( day.month() )
+ .arg( day.day() );
+ } else {
+ qu += ",\"\"";
+ }
+ }
+ break;
+
+ default:
+ qu += QString( ",\"%1\"" ).arg( contactMap[id] );
+ }
+ }
+ qu += " );";
+
+
+#else
+ // Get all information out of the contact-class
+ // Remember: The category is stored in contactMap, too !
+ QMap<int, QString> contactMap = m_contact.toMap();
+
+ QMap<QString, QString> addressbook_db;
+
+ // Get the translation from the ID to the String
+ QMap<int, QString> transMap = OContactFields::idToUntrFields();
+
+ for( QMap<int, QString>::Iterator it = contactMap.begin();
+ it != contactMap.end(); ++it ){
+ switch ( it.key() ){
+ case Qtopia::Birthday:{
+ // These entries should stored in a special format
+ // year-month-day
+ QDate day = m_contact.birthday();
+ addressbook_db.insert( transMap[it.key()],
+ QString("%1-%2-%3")
+ .arg( day.year() )
+ .arg( day.month() )
+ .arg( day.day() ) );
+ }
+ break;
+ case Qtopia::Anniversary:{
+ // These entries should stored in a special format
+ // year-month-day
+ QDate day = m_contact.anniversary();
+ addressbook_db.insert( transMap[it.key()],
+ QString("%1-%2-%3")
+ .arg( day.year() )
+ .arg( day.month() )
+ .arg( day.day() ) );
+ }
+ break;
+ case Qtopia::AddressUid: // Ignore UID
+ break;
+ default: // Translate id to String
+ addressbook_db.insert( transMap[it.key()], it.data() );
+ break;
+ }
+
+ }
+
+ // Now convert this whole stuff into a SQL String, beginning with
+ // the addressbook table..
+ QString qu;
+ // qu += "begin transaction;";
+ int id = 0;
+ for( QMap<QString, QString>::Iterator it = addressbook_db.begin();
+ it != addressbook_db.end(); ++it ){
+ qu += "insert into addressbook VALUES("
+ + QString::number( m_contact.uid() )
+ + ","
+ + QString::number( id++ )
+ + ",'"
+ + it.key() //.latin1()
+ + "',"
+ + "0" // Priority for future enhancements
+ + ",'"
+ + it.data() //.latin1()
+ + "');";
+ }
+
+#endif //__STORE_HORIZONTAL_
+ // Now add custom data..
+#ifdef __STORE_HORIZONTAL_
+ int id = 0;
+#endif
+ id = 0;
+ QMap<QString, QString> customMap = m_contact.toExtraMap();
+ for( QMap<QString, QString>::Iterator it = customMap.begin();
+ it != customMap.end(); ++it ){
+ qu += "insert into custom_data VALUES("
+ + QString::number( m_contact.uid() )
+ + ","
+ + QString::number( id++ )
+ + ",'"
+ + it.key() //.latin1()
+ + "',"
+ + "0" // Priority for future enhancements
+ + ",'"
+ + it.data() //.latin1()
+ + "');";
+ }
+ // qu += "commit;";
+ qWarning("add %s", qu.latin1() );
+ return qu;
+ }
+
+
+ RemoveQuery::RemoveQuery(int uid )
+ : OSQLQuery(), m_uid( uid ) {}
+ RemoveQuery::~RemoveQuery() {}
+ QString RemoveQuery::query()const {
+ QString qu = "DELETE from addressbook where uid = "
+ + QString::number(m_uid) + ";";
+ qu += "DELETE from custom_data where uid = "
+ + QString::number(m_uid) + ";";
+ return qu;
+ }
+
+
+
+
+ FindQuery::FindQuery(int uid)
+ : OSQLQuery(), m_uid( uid ) {
+ }
+ FindQuery::FindQuery(const QArray<int>& ints)
+ : OSQLQuery(), m_uids( ints ){
+ }
+ FindQuery::~FindQuery() {
+ }
+ QString FindQuery::query()const{
+// if ( m_uids.count() == 0 )
+ return single();
+ }
+ /*
+ else
+ return multi();
+ }
+ QString FindQuery::multi()const {
+ QString qu = "select uid, type, value from addressbook where";
+ for (uint i = 0; i < m_uids.count(); i++ ) {
+ qu += " UID = " + QString::number( m_uids[i] ) + " OR";
+ }
+ qu.remove( qu.length()-2, 2 ); // Hmmmm..
+ return qu;
+ }
+ */
+#ifdef __STORE_HORIZONTAL_
+ QString FindQuery::single()const{
+ QString qu = "select *";
+ qu += " from addressbook where uid = " + QString::number(m_uid);
+
+ // qWarning("find query: %s", qu.latin1() );
+ return qu;
+ }
+#else
+ QString FindQuery::single()const{
+ QString qu = "select uid, type, value from addressbook where uid = ";
+ qu += QString::number(m_uid);
+ return qu;
+ }
+#endif
+
+
+ FindCustomQuery::FindCustomQuery(int uid)
+ : OSQLQuery(), m_uid( uid ) {
+ }
+ FindCustomQuery::FindCustomQuery(const QArray<int>& ints)
+ : OSQLQuery(), m_uids( ints ){
+ }
+ FindCustomQuery::~FindCustomQuery() {
+ }
+ QString FindCustomQuery::query()const{
+// if ( m_uids.count() == 0 )
+ return single();
+ }
+ QString FindCustomQuery::single()const{
+ QString qu = "select uid, type, value from custom_data where uid = ";
+ qu += QString::number(m_uid);
+ return qu;
+ }
+
+};
+
+
+/* --------------------------------------------------------------------------- */
+
+OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */,
+ const QString& filename ):
+ OContactAccessBackend(), m_changed(false), m_driver( NULL )
+{
+ qWarning("C'tor OContactAccessBackend_SQL starts");
+ QTime t;
+ t.start();
+
+ /* Expecting to access the default filename if nothing else is set */
+ if ( filename.isEmpty() ){
+ m_fileName = Global::applicationFileName( "addressbook","addressbook.db" );
+ } else
+ m_fileName = filename;
+
+ // Get the standart sql-driver from the OSQLManager..
+ OSQLManager man;
+ m_driver = man.standard();
+ m_driver->setUrl( m_fileName );
+
+ load();
+
+ qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() );
+}
+
+OContactAccessBackend_SQL::~OContactAccessBackend_SQL ()
+{
+ if( m_driver )
+ delete m_driver;
+}
+
+bool OContactAccessBackend_SQL::load ()
+{
+ if (!m_driver->open() )
+ return false;
+
+ // Don't expect that the database exists.
+ // It is save here to create the table, even if it
+ // do exist. ( Is that correct for all databases ?? )
+ CreateQuery creat;
+ OSQLResult res = m_driver->query( &creat );
+
+ update();
+
+ return true;
+
+}
+
+bool OContactAccessBackend_SQL::reload()
+{
+ return load();
+}
+
+bool OContactAccessBackend_SQL::save()
+{
+ return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
+}
+
+
+void OContactAccessBackend_SQL::clear ()
+{
+ ClearQuery cle;
+ OSQLResult res = m_driver->query( &cle );
+
+ reload();
+}
+
+bool OContactAccessBackend_SQL::wasChangedExternally()
+{
+ return false;
+}
+
+QArray<int> OContactAccessBackend_SQL::allRecords() const
+{
+
+ // FIXME: Think about cute handling of changed tables..
+ // Thus, we don't have to call update here...
+ if ( m_changed )
+ ((OContactAccessBackend_SQL*)this)->update();
+
+ return m_uids;
+}
+
+bool OContactAccessBackend_SQL::add ( const OContact &newcontact )
+{
+ InsertQuery ins( newcontact );
+ OSQLResult res = m_driver->query( &ins );
+
+ if ( res.state() == OSQLResult::Failure )
+ return false;
+
+ int c = m_uids.count();
+ m_uids.resize( c+1 );
+ m_uids[c] = newcontact.uid();
+
+ return true;
+}
+
+
+bool OContactAccessBackend_SQL::remove ( int uid )
+{
+ RemoveQuery rem( uid );
+ OSQLResult res = m_driver->query(&rem );
+
+ if ( res.state() == OSQLResult::Failure )
+ return false;
+
+ m_changed = true;
+
+ return true;
+}
+
+bool OContactAccessBackend_SQL::replace ( const OContact &contact )
+{
+ if ( !remove( contact.uid() ) )
+ return false;
+
+ return add( contact );
+}
+
+
+OContact OContactAccessBackend_SQL::find ( int uid ) const
+{
+ qWarning("OContactAccessBackend_SQL::find()");
+ QTime t;
+ t.start();
+
+ OContact retContact( requestNonCustom( uid ) );
+ retContact.setExtraMap( requestCustom( uid ) );
+
+ qWarning("OContactAccessBackend_SQL::find() needed: %d ms", t.elapsed() );
+ return retContact;
+}
+
+
+
+QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() )
+{
+ QString qu = "SELECT uid FROM addressbook WHERE";
+
+ QMap<int, QString> queryFields = query.toMap();
+ QStringList fieldList = OContactFields::untrfields( false );
+ QMap<QString, int> translate = OContactFields::untrFieldsToId();
+
+ // Convert every filled field to a SQL-Query
+ bool isAnyFieldSelected = false;
+ for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
+ int id = translate[*it];
+ QString queryStr = queryFields[id];
+ if ( !queryStr.isEmpty() ){
+ isAnyFieldSelected = true;
+ switch( id ){
+ default:
+ // Switching between case sensitive and insensitive...
+ // LIKE is not case sensitive, GLOB is case sensitive
+ // Do exist a better solution to switch this ?
+ if ( settings & OContactAccess::IgnoreCase )
+ qu += "(\"" + *it + "\"" + " LIKE " + "'"
+ + queryStr.replace(QRegExp("\\*"),"%") + "'" + ") AND ";
+ else
+ qu += "(\"" + *it + "\"" + " GLOB " + "'"
+ + queryStr + "'" + ") AND ";
+
+ }
+ }
+ }
+ // Skip trailing "AND"
+ if ( isAnyFieldSelected )
+ qu = qu.left( qu.length() - 4 );
+
+ qWarning( "queryByExample query: %s", qu.latin1() );
+
+ // Execute query and return the received uid's
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ QArray<int> empty;
+ return empty;
+ }
+
+ QArray<int> list = extractUids( res );
+
+ return list;
+}
+
+QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> nix(0);
+ return nix;
+}
+
+const uint OContactAccessBackend_SQL::querySettings()
+{
+ return OContactAccess::IgnoreCase
+ || OContactAccess::WildCards;
+}
+
+bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const
+{
+ /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
+ * may be added with any of the other settings. IgnoreCase should never used alone.
+ * Wildcards, RegExp, ExactMatch should never used at the same time...
+ */
+
+ // Step 1: Check whether the given settings are supported by this backend
+ if ( ( querySettings & (
+ OContactAccess::IgnoreCase
+ | OContactAccess::WildCards
+// | OContactAccess::DateDiff
+// | OContactAccess::DateYear
+// | OContactAccess::DateMonth
+// | OContactAccess::DateDay
+// | OContactAccess::RegExp
+// | OContactAccess::ExactMatch
+ ) ) != querySettings )
+ return false;
+
+ // Step 2: Check whether the given combinations are ok..
+
+ // IngoreCase alone is invalid
+ if ( querySettings == OContactAccess::IgnoreCase )
+ return false;
+
+ // WildCards, RegExp and ExactMatch should never used at the same time
+ switch ( querySettings & ~( OContactAccess::IgnoreCase
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ )
+ ){
+ case OContactAccess::RegExp:
+ return ( true );
+ case OContactAccess::WildCards:
+ return ( true );
+ case OContactAccess::ExactMatch:
+ return ( true );
+ case 0: // one of the upper removed bits were set..
+ return ( true );
+ default:
+ return ( false );
+ }
+
+}
+
+QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int )
+{
+ QTime t;
+ t.start();
+
+#ifdef __STORE_HORIZONTAL_
+ QString query = "SELECT uid FROM addressbook ";
+ query += "ORDER BY \"Last Name\" ";
+#else
+ QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' ";
+ query += "ORDER BY upper( value )";
+#endif
+
+ if ( !asc )
+ query += "DESC";
+
+ // qWarning("sorted query is: %s", query.latin1() );
+
+ OSQLRawQuery raw( query );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ QArray<int> empty;
+ return empty;
+ }
+
+ QArray<int> list = extractUids( res );
+
+ qWarning("sorted needed %d ms!", t.elapsed() );
+ return list;
+}
+
+
+void OContactAccessBackend_SQL::update()
+{
+ qWarning("Update starts");
+ QTime t;
+ t.start();
+
+ // Now load the database set and extract the uid's
+ // which will be held locally
+
+ LoadQuery lo;
+ OSQLResult res = m_driver->query(&lo);
+ if ( res.state() != OSQLResult::Success )
+ return;
+
+ m_uids = extractUids( res );
+
+ m_changed = false;
+
+ qWarning("Update ends %d ms", t.elapsed() );
+}
+
+QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const
+{
+ qWarning("extractUids");
+ QTime t;
+ t.start();
+ OSQLResultItem::ValueList list = res.results();
+ OSQLResultItem::ValueList::Iterator it;
+ QArray<int> ints(list.count() );
+ qWarning(" count = %d", list.count() );
+
+ int i = 0;
+ for (it = list.begin(); it != list.end(); ++it ) {
+ ints[i] = (*it).data("uid").toInt();
+ i++;
+ }
+ qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() );
+
+ return ints;
+
+}
+
+#ifdef __STORE_HORIZONTAL_
+QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const
+{
+ QTime t;
+ t.start();
+
+ QMap<int, QString> nonCustomMap;
+
+ int t2needed = 0;
+ int t3needed = 0;
+ QTime t2;
+ t2.start();
+ FindQuery query( uid );
+ OSQLResult res_noncustom = m_driver->query( &query );
+ t2needed = t2.elapsed();
+
+ OSQLResultItem resItem = res_noncustom.first();
+
+ QTime t3;
+ t3.start();
+ // Now loop through all columns
+ QStringList fieldList = OContactFields::untrfields( false );
+ QMap<QString, int> translate = OContactFields::untrFieldsToId();
+ for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){
+ // Get data for the selected column and store it with the
+ // corresponding id into the map..
+
+ int id = translate[*it];
+ QString value = resItem.data( (*it) );
+
+ // qWarning("Reading %s... found: %s", (*it).latin1(), value.latin1() );
+
+ switch( id ){
+ case Qtopia::Birthday:
+ case Qtopia::Anniversary:{
+ // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
+ QStringList list = QStringList::split( '-', value );
+ QStringList::Iterator lit = list.begin();
+ int year = (*lit).toInt();
+ int month = (*(++lit)).toInt();
+ int day = (*(++lit)).toInt();
+ if ( ( day != 0 ) && ( month != 0 ) && ( year != 0 ) ){
+ QDate date( year, month, day );
+ nonCustomMap.insert( id, OConversion::dateToString( date ) );
+ }
+ }
+ break;
+ case Qtopia::AddressCategory:
+ qWarning("Category is: %s", value.latin1() );
+ default:
+ nonCustomMap.insert( id, value );
+ }
+ }
+
+ // First insert uid
+ nonCustomMap.insert( Qtopia::AddressUid, resItem.data( "uid" ) );
+ t3needed = t3.elapsed();
+
+ // qWarning("Adding UID: %s", resItem.data( "uid" ).latin1() );
+ qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms",
+ t.elapsed(), t2needed, t3needed );
+
+ return nonCustomMap;
+}
+#else
+
+QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const
+{
+ QTime t;
+ t.start();
+
+ QMap<int, QString> nonCustomMap;
+
+ int t2needed = 0;
+ QTime t2;
+ t2.start();
+ FindQuery query( uid );
+ OSQLResult res_noncustom = m_driver->query( &query );
+ t2needed = t2.elapsed();
+
+ if ( res_noncustom.state() == OSQLResult::Failure ) {
+ qWarning("OSQLResult::Failure in find query !!");
+ QMap<int, QString> empty;
+ return empty;
+ }
+
+ int t3needed = 0;
+ QTime t3;
+ t3.start();
+ QMap<QString, int> translateMap = OContactFields::untrFieldsToId();
+
+ OSQLResultItem::ValueList list = res_noncustom.results();
+ OSQLResultItem::ValueList::Iterator it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ if ( (*it).data("type") != "" ){
+ int typeId = translateMap[(*it).data( "type" )];
+ switch( typeId ){
+ case Qtopia::Birthday:
+ case Qtopia::Anniversary:{
+ // Birthday and Anniversary are encoded special ( yyyy-mm-dd )
+ QStringList list = QStringList::split( '-', (*it).data( "value" ) );
+ QStringList::Iterator lit = list.begin();
+ int year = (*lit).toInt();
+ qWarning("1. %s", (*lit).latin1());
+ int month = (*(++lit)).toInt();
+ qWarning("2. %s", (*lit).latin1());
+ int day = (*(++lit)).toInt();
+ qWarning("3. %s", (*lit).latin1());
+ qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day );
+ QDate date( year, month, day );
+ nonCustomMap.insert( typeId, OConversion::dateToString( date ) );
+ }
+ break;
+ default:
+ nonCustomMap.insert( typeId,
+ (*it).data( "value" ) );
+ }
+ }
+ }
+ // Add UID to Map..
+ nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) );
+ t3needed = t3.elapsed();
+
+ qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", t.elapsed(), t2needed, t3needed );
+ return nonCustomMap;
+}
+
+#endif // __STORE_HORIZONTAL_
+
+QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const
+{
+ QTime t;
+ t.start();
+
+ QMap<QString, QString> customMap;
+
+ FindCustomQuery query( uid );
+ OSQLResult res_custom = m_driver->query( &query );
+
+ if ( res_custom.state() == OSQLResult::Failure ) {
+ qWarning("OSQLResult::Failure in find query !!");
+ QMap<QString, QString> empty;
+ return empty;
+ }
+
+ OSQLResultItem::ValueList list = res_custom.results();
+ OSQLResultItem::ValueList::Iterator it = list.begin();
+ for ( ; it != list.end(); ++it ) {
+ customMap.insert( (*it).data( "type" ), (*it).data( "value" ) );
+ }
+
+ qWarning("RequestCustom needed: %d ms", t.elapsed() );
+ return customMap;
+}
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 @@
+/*
+ * SQL Backend for the OPIE-Contact Database.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ *
+ *
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.3 2004/03/14 13:50:35 alwin
+ * namespace correction
+ *
+ * Revision 1.2 2003/12/08 15:18:11 eilers
+ * Committing unfinished sql implementation before merging to libopie2 starts..
+ *
+ * Revision 1.1 2003/09/22 14:31:16 eilers
+ * Added first experimental incarnation of sql-backend for addressbook.
+ * Some modifications to be able to compile the todo sql-backend.
+ * A lot of changes fill follow...
+ *
+ *
+ */
+
+#ifndef _OContactAccessBackend_SQL_
+#define _OContactAccessBackend_SQL_
+
+#include "ocontactaccessbackend.h"
+#include "ocontactaccess.h"
+
+#include <qlist.h>
+#include <qdict.h>
+
+namespace Opie { namespace DB {
+class OSQLDriver;
+class OSQLResult;
+class OSQLResultItem;
+
+}}
+
+/* the default xml implementation */
+/**
+ * This class is the SQL implementation of a Contact backend
+ * it does implement everything available for OContact.
+ * @see OPimAccessBackend for more information of available methods
+ */
+class OContactAccessBackend_SQL : public OContactAccessBackend {
+ public:
+ OContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null );
+
+ ~OContactAccessBackend_SQL ();
+
+ bool save();
+
+ bool load ();
+
+ void clear ();
+
+ bool wasChangedExternally();
+
+ QArray<int> allRecords() const;
+
+ OContact find ( int uid ) const;
+ // FIXME: Add lookahead-cache support !
+ //OContact find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const;
+
+ QArray<int> queryByExample ( const OContact &query, int settings,
+ const QDateTime& d );
+
+ QArray<int> matchRegexp( const QRegExp &r ) const;
+
+ const uint querySettings();
+
+ bool hasQuerySettings (uint querySettings) const;
+
+ // Currently only asc implemented..
+ QArray<int> sorted( bool asc, int , int , int );
+ bool add ( const OContact &newcontact );
+
+ bool replace ( const OContact &contact );
+
+ bool remove ( int uid );
+ bool reload();
+
+ private:
+ QArray<int> extractUids( Opie::DB::OSQLResult& res ) const;
+ QMap<int, QString> requestNonCustom( int uid ) const;
+ QMap<QString, QString> requestCustom( int uid ) const;
+ void update();
+
+ protected:
+ bool m_changed;
+ QString m_fileName;
+ QArray<int> m_uids;
+
+ Opie::DB::OSQLDriver* m_driver;
+};
+
+#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 @@
+/*
+ * VCard Backend for the OPIE-Contact Database.
+ *
+ * Copyright (C) 2000 Trolltech AS. All rights reserved.
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ * ToDo:
+ *
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.11 2003/08/01 12:30:16 eilers
+ * Merging changes from BRANCH_1_0 to HEAD
+ *
+ * Revision 1.10.4.3 2003/07/23 08:54:37 eilers
+ * Default email was added to the list of all emails, which already contains
+ * the default email..
+ * This closes bug #1045
+ *
+ * Revision 1.10.4.2 2003/07/23 08:44:45 eilers
+ * Importing of Notes in vcard files wasn't implemented.
+ * Closes bug #1044
+ *
+ * Revision 1.10.4.1 2003/06/02 13:37:49 eilers
+ * Fixing memory leak
+ *
+ * Revision 1.10 2003/04/13 18:07:10 zecke
+ * More API doc
+ * QString -> const QString&
+ * QString = 0l -> QString::null
+ *
+ * Revision 1.9 2003/03/21 10:33:09 eilers
+ * Merged speed optimized xml backend for contacts to main.
+ * Added QDateTime to querybyexample. For instance, it is now possible to get
+ * all Birthdays/Anniversaries between two dates. This should be used
+ * to show all birthdays in the datebook..
+ * This change is sourcecode backward compatible but you have to upgrade
+ * the binaries for today-addressbook.
+ *
+ * Revision 1.8 2003/02/21 16:52:49 zecke
+ * -Remove old Todo classes they're deprecated and today I already using the
+ * new API
+ * -Guard against self assignment in OTodo
+ * -Add test apps for OPIM
+ * -Opiefied Event classes
+ * -Added TimeZone handling and pinning of TimeZones to OEvent
+ * -Adjust ORecur and the widget to better timezone behaviour
+ *
+ * Revision 1.7 2003/02/16 22:25:46 zecke
+ * 0000276 Fix for that bug.. or better temp workaround
+ * A Preferred Number is HOME|VOICE
+ * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test
+ * triggers both
+ * and the cell phone number overrides the other entries..
+ *
+ * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the
+ * number
+ *
+ * The right and final fix would be to reorder the if statement to make it
+ * if else based and the less common thing put to the bottom
+ *
+ * OTodoAccessVcal fix the date for beaming
+ *
+ * Revision 1.6 2003/01/13 15:49:31 eilers
+ * Fixing crash when businesscard.vcf is missing..
+ *
+ * Revision 1.5 2002/12/07 13:26:22 eilers
+ * Fixing bug in storing anniversary..
+ *
+ * Revision 1.4 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.3 2002/11/11 16:41:09 kergoth
+ * no default arguments in implementation
+ *
+ * Revision 1.2 2002/11/10 15:41:53 eilers
+ * Bugfixes..
+ *
+ * Revision 1.1 2002/11/09 14:34:52 eilers
+ * Added VCard Backend.
+ *
+ */
+#include "ocontactaccessbackend_vcard.h"
+#include "../../library/backend/vobject_p.h"
+#include "../../library/backend/qfiledirect_p.h"
+
+#include <qpe/timeconversion.h>
+
+#include <qfile.h>
+
+OContactAccessBackend_VCard::OContactAccessBackend_VCard ( const QString& , const QString& filename ):
+ m_dirty( false ),
+ m_file( filename )
+{
+ load();
+}
+
+
+bool OContactAccessBackend_VCard::load ()
+{
+ m_map.clear();
+ m_dirty = false;
+
+ VObject* obj = 0l;
+
+ if ( QFile::exists(m_file) ){
+ obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() );
+ if ( !obj )
+ return false;
+ }else{
+ qWarning("File \"%s\" not found !", m_file.latin1() );
+ return false;
+ }
+
+ while ( obj ) {
+ OContact con = parseVObject( obj );
+ /*
+ * if uid is 0 assign a new one
+ * this at least happens on
+ * Nokia6210
+ */
+ if ( con.uid() == 0 ){
+ con.setUid( 1 );
+ qWarning("assigned new uid %d",con.uid() );
+ }
+
+ m_map.insert( con.uid(), con );
+
+ VObject *t = obj;
+ obj = nextVObjectInList(obj);
+ cleanVObject( t );
+ }
+
+ return true;
+
+}
+bool OContactAccessBackend_VCard::reload()
+{
+ return load();
+}
+bool OContactAccessBackend_VCard::save()
+{
+ if (!m_dirty )
+ return true;
+
+ QFileDirect file( m_file );
+ if (!file.open(IO_WriteOnly ) )
+ return false;
+
+ VObject *obj;
+ obj = newVObject( VCCalProp );
+ addPropValue( obj, VCVersionProp, "1.0" );
+
+ VObject *vo;
+ for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){
+ vo = createVObject( *it );
+ writeVObject( file.directHandle() , vo );
+ cleanVObject( vo );
+ }
+ cleanStrTbl();
+ deleteVObject( obj );
+
+ m_dirty = false;
+ return true;
+
+
+}
+void OContactAccessBackend_VCard::clear ()
+{
+ m_map.clear();
+ m_dirty = true; // ??? sure ? (se)
+}
+
+bool OContactAccessBackend_VCard::add ( const OContact& newcontact )
+{
+ m_map.insert( newcontact.uid(), newcontact );
+ m_dirty = true;
+ return true;
+}
+
+bool OContactAccessBackend_VCard::remove ( int uid )
+{
+ m_map.remove( uid );
+ m_dirty = true;
+ return true;
+}
+
+bool OContactAccessBackend_VCard::replace ( const OContact &contact )
+{
+ m_map.replace( contact.uid(), contact );
+ m_dirty = true;
+ return true;
+}
+
+OContact OContactAccessBackend_VCard::find ( int uid ) const
+{
+ return m_map[uid];
+}
+
+QArray<int> OContactAccessBackend_VCard::allRecords() const
+{
+ QArray<int> ar( m_map.count() );
+ QMap<int, OContact>::ConstIterator it;
+ int i = 0;
+ for ( it = m_map.begin(); it != m_map.end(); ++it ) {
+ ar[i] = it.key();
+ i++;
+ }
+ return ar;
+}
+
+// Not implemented
+QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& )
+{
+ QArray<int> ar(0);
+ return ar;
+}
+
+// Not implemented
+QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const
+{
+ QArray<int> ar(0);
+ return ar;
+}
+
+const uint OContactAccessBackend_VCard::querySettings()
+{
+ return 0; // No search possible
+}
+
+bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const
+{
+ return false; // No search possible, therefore all settings invalid ;)
+}
+
+bool OContactAccessBackend_VCard::wasChangedExternally()
+{
+ return false; // Don't expect concurrent access
+}
+
+// Not implemented
+QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int )
+{
+ QArray<int> ar(0);
+ return ar;
+}
+
+// *** Private stuff ***
+
+
+OContact OContactAccessBackend_VCard::parseVObject( VObject *obj )
+{
+ OContact c;
+
+ VObjectIterator it;
+ initPropIterator( &it, obj );
+ while( moreIteration( &it ) ) {
+ VObject *o = nextVObject( &it );
+ QCString name = vObjectName( o );
+ QCString value = vObjectStringZValue( o );
+ if ( name == VCNameProp ) {
+ VObjectIterator nit;
+ initPropIterator( &nit, o );
+ while( moreIteration( &nit ) ) {
+ VObject *o = nextVObject( &nit );
+ QCString name = vObjectTypeInfo( o );
+ QString value = vObjectStringZValue( o );
+ if ( name == VCNamePrefixesProp )
+ c.setTitle( value );
+ else if ( name == VCNameSuffixesProp )
+ c.setSuffix( value );
+ else if ( name == VCFamilyNameProp )
+ c.setLastName( value );
+ else if ( name == VCGivenNameProp )
+ c.setFirstName( value );
+ else if ( name == VCAdditionalNamesProp )
+ c.setMiddleName( value );
+ }
+ }
+ else if ( name == VCAdrProp ) {
+ bool work = TRUE; // default address is work address
+ QString street;
+ QString city;
+ QString region;
+ QString postal;
+ QString country;
+
+ VObjectIterator nit;
+ initPropIterator( &nit, o );
+ while( moreIteration( &nit ) ) {
+ VObject *o = nextVObject( &nit );
+ QCString name = vObjectName( o );
+ QString value = vObjectStringZValue( o );
+ if ( name == VCHomeProp )
+ work = FALSE;
+ else if ( name == VCWorkProp )
+ work = TRUE;
+ else if ( name == VCStreetAddressProp )
+ street = value;
+ else if ( name == VCCityProp )
+ city = value;
+ else if ( name == VCRegionProp )
+ region = value;
+ else if ( name == VCPostalCodeProp )
+ postal = value;
+ else if ( name == VCCountryNameProp )
+ country = value;
+ }
+ if ( work ) {
+ c.setBusinessStreet( street );
+ c.setBusinessCity( city );
+ c.setBusinessCountry( country );
+ c.setBusinessZip( postal );
+ c.setBusinessState( region );
+ } else {
+ c.setHomeStreet( street );
+ c.setHomeCity( city );
+ c.setHomeCountry( country );
+ c.setHomeZip( postal );
+ c.setHomeState( region );
+ }
+ }
+ else if ( name == VCTelephoneProp ) {
+ enum {
+ HOME = 0x01,
+ WORK = 0x02,
+ VOICE = 0x04,
+ CELL = 0x08,
+ FAX = 0x10,
+ PAGER = 0x20,
+ UNKNOWN = 0x80
+ };
+ int type = 0;
+
+ VObjectIterator nit;
+ initPropIterator( &nit, o );
+ while( moreIteration( &nit ) ) {
+ VObject *o = nextVObject( &nit );
+ QCString name = vObjectTypeInfo( o );
+ if ( name == VCHomeProp )
+ type |= HOME;
+ else if ( name == VCWorkProp )
+ type |= WORK;
+ else if ( name == VCVoiceProp )
+ type |= VOICE;
+ else if ( name == VCCellularProp )
+ type |= CELL;
+ else if ( name == VCFaxProp )
+ type |= FAX;
+ else if ( name == VCPagerProp )
+ type |= PAGER;
+ else if ( name == VCPreferredProp )
+ ;
+ else
+ type |= UNKNOWN;
+ }
+ if ( (type & UNKNOWN) != UNKNOWN ) {
+ if ( ( type & (HOME|WORK) ) == 0 ) // default
+ type |= HOME;
+ if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default
+ type |= VOICE;
+
+ qWarning("value %s %d", value.data(), type );
+ if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) )
+ c.setHomePhone( value );
+ if ( ( type & (FAX|HOME) ) == (FAX|HOME) )
+ c.setHomeFax( value );
+ if ( ( type & (CELL|HOME) ) == (CELL|HOME) )
+ c.setHomeMobile( value );
+ if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) )
+ c.setBusinessPhone( value );
+ if ( ( type & (FAX|WORK) ) == (FAX|WORK) )
+ c.setBusinessFax( value );
+ if ( ( type & (CELL|WORK) ) == (CELL|WORK) )
+ c.setBusinessMobile( value );
+ if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) )
+ c.setBusinessPager( value );
+ }
+ }
+ else if ( name == VCEmailAddressProp ) {
+ QString email = vObjectStringZValue( o );
+ bool valid = TRUE;
+ VObjectIterator nit;
+ initPropIterator( &nit, o );
+ while( moreIteration( &nit ) ) {
+ VObject *o = nextVObject( &nit );
+ QCString name = vObjectTypeInfo( o );
+ if ( name != VCInternetProp && name != VCHomeProp &&
+ name != VCWorkProp &&
+ name != VCPreferredProp )
+ // ### preffered should map to default email
+ valid = FALSE;
+ }
+ if ( valid ) {
+ c.insertEmail( email );
+ }
+ }
+ else if ( name == VCURLProp ) {
+ VObjectIterator nit;
+ initPropIterator( &nit, o );
+ while( moreIteration( &nit ) ) {
+ VObject *o = nextVObject( &nit );
+ QCString name = vObjectTypeInfo( o );
+ if ( name == VCHomeProp )
+ c.setHomeWebpage( value );
+ else if ( name == VCWorkProp )
+ c.setBusinessWebpage( value );
+ }
+ }
+ else if ( name == VCOrgProp ) {
+ VObjectIterator nit;
+ initPropIterator( &nit, o );
+ while( moreIteration( &nit ) ) {
+ VObject *o = nextVObject( &nit );
+ QCString name = vObjectName( o );
+ QString value = vObjectStringZValue( o );
+ if ( name == VCOrgNameProp )
+ c.setCompany( value );
+ else if ( name == VCOrgUnitProp )
+ c.setDepartment( value );
+ else if ( name == VCOrgUnit2Prop )
+ c.setOffice( value );
+ }
+ }
+ else if ( name == VCTitleProp ) {
+ c.setJobTitle( value );
+ }
+ else if ( name == "X-Qtopia-Profession" ) {
+ c.setProfession( value );
+ }
+ else if ( name == "X-Qtopia-Manager" ) {
+ c.setManager( value );
+ }
+ else if ( name == "X-Qtopia-Assistant" ) {
+ c.setAssistant( value );
+ }
+ else if ( name == "X-Qtopia-Spouse" ) {
+ c.setSpouse( value );
+ }
+ else if ( name == "X-Qtopia-Gender" ) {
+ c.setGender( value );
+ }
+ else if ( name == "X-Qtopia-Anniversary" ) {
+ c.setAnniversary( convVCardDateToDate( value ) );
+ }
+ else if ( name == "X-Qtopia-Nickname" ) {
+ c.setNickname( value );
+ }
+ else if ( name == "X-Qtopia-Children" ) {
+ c.setChildren( value );
+ }
+ else if ( name == VCBirthDateProp ) {
+ // Reading Birthdate regarding RFC 2425 (5.8.4)
+ c.setBirthday( convVCardDateToDate( value ) );
+
+ }
+ else if ( name == VCCommentProp ) {
+ c.setNotes( value );
+ }
+#if 0
+ else {
+ printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) );
+ VObjectIterator nit;
+ initPropIterator( &nit, o );
+ while( moreIteration( &nit ) ) {
+ VObject *o = nextVObject( &nit );
+ QCString name = vObjectName( o );
+ QString value = vObjectStringZValue( o );
+ printf(" subprop: %s = %s\n", name.data(), value.latin1() );
+ }
+ }
+#endif
+ }
+ c.setFileAs();
+ return c;
+}
+
+
+VObject* OContactAccessBackend_VCard::createVObject( const OContact &c )
+{
+ VObject *vcard = newVObject( VCCardProp );
+ safeAddPropValue( vcard, VCVersionProp, "2.1" );
+ safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) );
+ safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) );
+
+ // full name
+ safeAddPropValue( vcard, VCFullNameProp, c.fullName() );
+
+ // name properties
+ VObject *name = safeAddProp( vcard, VCNameProp );
+ safeAddPropValue( name, VCFamilyNameProp, c.lastName() );
+ safeAddPropValue( name, VCGivenNameProp, c.firstName() );
+ safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() );
+ safeAddPropValue( name, VCNamePrefixesProp, c.title() );
+ safeAddPropValue( name, VCNameSuffixesProp, c.suffix() );
+
+ // home properties
+ VObject *home_adr= safeAddProp( vcard, VCAdrProp );
+ safeAddProp( home_adr, VCHomeProp );
+ safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() );
+ safeAddPropValue( home_adr, VCCityProp, c.homeCity() );
+ safeAddPropValue( home_adr, VCRegionProp, c.homeState() );
+ safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() );
+ safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() );
+
+ VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() );
+ safeAddProp( home_phone, VCHomeProp );
+ home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() );
+ safeAddProp( home_phone, VCHomeProp );
+ safeAddProp( home_phone, VCCellularProp );
+ home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() );
+ safeAddProp( home_phone, VCHomeProp );
+ safeAddProp( home_phone, VCFaxProp );
+
+ VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() );
+ safeAddProp( url, VCHomeProp );
+
+ // work properties
+ VObject *work_adr= safeAddProp( vcard, VCAdrProp );
+ safeAddProp( work_adr, VCWorkProp );
+ safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() );
+ safeAddPropValue( work_adr, VCCityProp, c.businessCity() );
+ safeAddPropValue( work_adr, VCRegionProp, c.businessState() );
+ safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() );
+ safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() );
+
+ VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() );
+ safeAddProp( work_phone, VCWorkProp );
+ work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() );
+ safeAddProp( work_phone, VCWorkProp );
+ safeAddProp( work_phone, VCCellularProp );
+ work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() );
+ safeAddProp( work_phone, VCWorkProp );
+ safeAddProp( work_phone, VCFaxProp );
+ work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() );
+ safeAddProp( work_phone, VCWorkProp );
+ safeAddProp( work_phone, VCPagerProp );
+
+ url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() );
+ safeAddProp( url, VCWorkProp );
+
+ VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() );
+ safeAddProp( title, VCWorkProp );
+
+
+ QStringList emails = c.emailList();
+ // emails.prepend( c.defaultEmail() ); Fix for bugreport #1045
+ for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) {
+ VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it );
+ safeAddProp( email, VCInternetProp );
+ }
+
+ safeAddPropValue( vcard, VCNoteProp, c.notes() );
+
+ // Exporting Birthday regarding RFC 2425 (5.8.4)
+ if ( c.birthday().isValid() ){
+ qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() );
+ safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) );
+ }
+
+ if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) {
+ VObject *org = safeAddProp( vcard, VCOrgProp );
+ safeAddPropValue( org, VCOrgNameProp, c.company() );
+ safeAddPropValue( org, VCOrgUnitProp, c.department() );
+ safeAddPropValue( org, VCOrgUnit2Prop, c.office() );
+ }
+
+ // some values we have to export as custom fields
+ safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() );
+ safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() );
+ safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() );
+
+ safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() );
+ safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() );
+ if ( c.anniversary().isValid() ){
+ qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() );
+ safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) );
+ }
+ safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() );
+ safeAddPropValue( vcard, "X-Qtopia-Children", c.children() );
+
+ return vcard;
+}
+
+QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const
+{
+ QString str_rfc2425 = QString("%1-%2-%3")
+ .arg( d.year() )
+ .arg( d.month(), 2 )
+ .arg( d.day(), 2 );
+ // Now replace spaces with "0"...
+ int pos = 0;
+ while ( ( pos = str_rfc2425.find (' ') ) > 0 )
+ str_rfc2425.replace( pos, 1, "0" );
+
+ return str_rfc2425;
+}
+
+QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr )
+{
+ int monthPos = datestr.find('-');
+ int dayPos = datestr.find('-', monthPos+1 );
+ int sep_ignore = 1;
+ if ( monthPos == -1 || dayPos == -1 ) {
+ qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos );
+ // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD )
+ if ( datestr.length() == 8 ){
+ monthPos = 4;
+ dayPos = 6;
+ sep_ignore = 0;
+ qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos );
+ } else {
+ return QDate();
+ }
+ }
+ int y = datestr.left( monthPos ).toInt();
+ int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt();
+ int d = datestr.mid( dayPos + sep_ignore ).toInt();
+ qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos);
+ QDate date ( y,m,d );
+ return date;
+}
+
+VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value )
+{
+ VObject *ret = 0;
+ if ( o && !value.isEmpty() )
+ ret = addPropValue( o, prop, value.latin1() );
+ return ret;
+}
+
+VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop)
+{
+ VObject *ret = 0;
+ if ( o )
+ ret = addProp( o, prop );
+ return ret;
+}
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 @@
+/*
+ * VCard Backend for the OPIE-Contact Database.
+ *
+ * Copyright (C) 2000 Trolltech AS. All rights reserved.
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ * ToDo:
+ *
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.6 2003/04/13 18:07:10 zecke
+ * More API doc
+ * QString -> const QString&
+ * QString = 0l -> QString::null
+ *
+ * Revision 1.5 2003/03/21 10:33:09 eilers
+ * Merged speed optimized xml backend for contacts to main.
+ * Added QDateTime to querybyexample. For instance, it is now possible to get
+ * all Birthdays/Anniversaries between two dates. This should be used
+ * to show all birthdays in the datebook..
+ * This change is sourcecode backward compatible but you have to upgrade
+ * the binaries for today-addressbook.
+ *
+ * Revision 1.4 2002/12/07 13:26:22 eilers
+ * Fixing bug in storing anniversary..
+ *
+ * Revision 1.3 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.2 2002/11/10 15:41:53 eilers
+ * Bugfixes..
+ *
+ * Revision 1.1 2002/11/09 14:34:52 eilers
+ * Added VCard Backend.
+ *
+ */
+#ifndef __OCONTACTACCESSBACKEND_VCARD_H_
+#define __OCONTACTACCESSBACKEND_VCARD_H_
+
+#include <opie/ocontact.h>
+
+#include "ocontactaccessbackend.h"
+
+class VObject;
+
+/**
+ * This is the vCard 2.1 implementation of the Contact Storage
+ * @see OContactAccessBackend_XML
+ * @see OPimAccessBackend
+ */
+class OContactAccessBackend_VCard : public OContactAccessBackend {
+ public:
+ OContactAccessBackend_VCard ( const QString& appname, const QString& filename = QString::null );
+
+ bool load ();
+ bool reload();
+ bool save();
+ void clear ();
+
+ bool add ( const OContact& newcontact );
+ bool remove ( int uid );
+ bool replace ( const OContact& contact );
+
+ OContact find ( int uid ) const;
+ QArray<int> allRecords() const;
+ QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() );
+ QArray<int> matchRegexp( const QRegExp &r ) const;
+
+ const uint querySettings();
+ bool hasQuerySettings (uint querySettings) const;
+ QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat );
+ bool wasChangedExternally();
+
+private:
+ OContact parseVObject( VObject* obj );
+ VObject* createVObject( const OContact& c );
+ QString convDateToVCardDate( const QDate& c ) const;
+ QDate convVCardDateToDate( const QString& datestr );
+ VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value );
+ VObject *safeAddProp( VObject* o, const char* prop);
+
+ bool m_dirty : 1;
+ QString m_file;
+ QMap<int, OContact> m_map;
+};
+
+#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 @@
+/*
+ * XML Backend for the OPIE-Contact Database.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ *
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.10 2004/03/01 15:44:36 chicken
+ * fix includes
+ *
+ * Revision 1.9 2003/09/22 14:31:16 eilers
+ * Added first experimental incarnation of sql-backend for addressbook.
+ * Some modifications to be able to compile the todo sql-backend.
+ * A lot of changes fill follow...
+ *
+ * Revision 1.8 2003/08/30 15:28:26 eilers
+ * Removed some unimportant debug output which causes slow down..
+ *
+ * Revision 1.7 2003/08/01 12:30:16 eilers
+ * Merging changes from BRANCH_1_0 to HEAD
+ *
+ * Revision 1.6 2003/07/07 16:19:47 eilers
+ * Fixing serious bug in hasQuerySettings()
+ *
+ * Revision 1.5 2003/04/13 18:07:10 zecke
+ * More API doc
+ * QString -> const QString&
+ * QString = 0l -> QString::null
+ *
+ * Revision 1.4 2003/03/21 14:32:54 mickeyl
+ * g++ compliance fix: default arguments belong into the declaration, but not the definition
+ *
+ * Revision 1.3 2003/03/21 12:26:28 eilers
+ * Fixing small bug: If we search a birthday from today to today, it returned
+ * every contact ..
+ *
+ * Revision 1.2 2003/03/21 10:33:09 eilers
+ * Merged speed optimized xml backend for contacts to main.
+ * Added QDateTime to querybyexample. For instance, it is now possible to get
+ * all Birthdays/Anniversaries between two dates. This should be used
+ * to show all birthdays in the datebook..
+ * This change is sourcecode backward compatible but you have to upgrade
+ * the binaries for today-addressbook.
+ *
+ * Revision 1.1.2.2 2003/02/11 12:17:28 eilers
+ * Speed optimization. Removed the sequential search loops.
+ *
+ * Revision 1.1.2.1 2003/02/10 15:31:38 eilers
+ * Writing offsets to debug output..
+ *
+ * Revision 1.1 2003/02/09 15:05:01 eilers
+ * Nothing happened.. Just some cleanup before I will start..
+ *
+ * Revision 1.12 2003/01/03 16:58:03 eilers
+ * Reenable debug output
+ *
+ * Revision 1.11 2003/01/03 12:31:28 eilers
+ * Bugfix for calculating data diffs..
+ *
+ * Revision 1.10 2003/01/02 14:27:12 eilers
+ * Improved query by example: Search by date is possible.. First step
+ * for a today plugin for birthdays..
+ *
+ * Revision 1.9 2002/12/08 12:48:57 eilers
+ * Moved journal-enum from ocontact into i the xml-backend..
+ *
+ * Revision 1.8 2002/11/14 17:04:24 eilers
+ * Sorting will now work if fullname is identical on some entries
+ *
+ * Revision 1.7 2002/11/13 15:02:46 eilers
+ * Small Bug in sorted fixed
+ *
+ * Revision 1.6 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.5 2002/11/01 15:10:42 eilers
+ * Added regExp-search in database for all fields in a contact.
+ *
+ * Revision 1.4 2002/10/16 10:52:40 eilers
+ * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
+ *
+ * Revision 1.3 2002/10/14 16:21:54 eilers
+ * Some minor interface updates
+ *
+ * Revision 1.2 2002/10/07 17:34:24 eilers
+ * added OBackendFactory for advanced backend access
+ *
+ * Revision 1.1 2002/09/27 17:11:44 eilers
+ * Added API for accessing the Contact-Database ! It is compiling, but
+ * please do not expect that anything is working !
+ * I will debug that stuff in the next time ..
+ * Please read README_COMPILE for compiling !
+ *
+ *
+ */
+
+#include "ocontactaccessbackend_xml.h"
+
+#include <qasciidict.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+#include <qarray.h>
+#include <qmap.h>
+
+#include <qpe/global.h>
+
+#include <opie/xmltree.h>
+#include "ocontactaccessbackend.h"
+#include "ocontactaccess.h"
+
+#include <stdlib.h>
+#include <errno.h>
+
+using namespace Opie;
+
+
+OContactAccessBackend_XML::OContactAccessBackend_XML ( const QString& appname, const QString& filename ):
+ m_changed( false )
+{
+ // Just m_contactlist should call delete if an entry
+ // is removed.
+ m_contactList.setAutoDelete( true );
+ m_uidToContact.setAutoDelete( false );
+
+ m_appName = appname;
+
+ /* Set journalfile name ... */
+ m_journalName = getenv("HOME");
+ m_journalName +="/.abjournal" + appname;
+
+ /* Expecting to access the default filename if nothing else is set */
+ if ( filename.isEmpty() ){
+ m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" );
+ } else
+ m_fileName = filename;
+
+ /* Load Database now */
+ load ();
+}
+
+bool OContactAccessBackend_XML::save()
+{
+
+ if ( !m_changed )
+ return true;
+
+ QString strNewFile = m_fileName + ".new";
+ QFile f( strNewFile );
+ if ( !f.open( IO_WriteOnly|IO_Raw ) )
+ return false;
+
+ int total_written;
+ int idx_offset = 0;
+ QString out;
+
+ // Write Header
+ out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n"
+ " <Groups>\n"
+ " </Groups>\n"
+ " <Contacts>\n";
+ QCString cstr = out.utf8();
+ f.writeBlock( cstr.data(), cstr.length() );
+ idx_offset += cstr.length();
+ out = "";
+
+ // Write all contacts
+ QListIterator<OContact> it( m_contactList );
+ for ( ; it.current(); ++it ) {
+ // qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset );
+ out += "<Contact ";
+ (*it)->save( out );
+ out += "/>\n";
+ cstr = out.utf8();
+ total_written = f.writeBlock( cstr.data(), cstr.length() );
+ idx_offset += cstr.length();
+ if ( total_written != int(cstr.length()) ) {
+ f.close();
+ QFile::remove( strNewFile );
+ return false;
+ }
+ out = "";
+ }
+ out += " </Contacts>\n</AddressBook>\n";
+
+ // Write Footer
+ cstr = out.utf8();
+ total_written = f.writeBlock( cstr.data(), cstr.length() );
+ if ( total_written != int( cstr.length() ) ) {
+ f.close();
+ QFile::remove( strNewFile );
+ return false;
+ }
+ f.close();
+
+ // move the file over, I'm just going to use the system call
+ // because, I don't feel like using QDir.
+ if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) {
+ qWarning( "problem renaming file %s to %s, errno: %d",
+ strNewFile.latin1(), m_journalName.latin1(), errno );
+ // remove the tmp file...
+ QFile::remove( strNewFile );
+ }
+
+ /* The journalfile should be removed now... */
+ removeJournal();
+
+ m_changed = false;
+ return true;
+}
+
+bool OContactAccessBackend_XML::load ()
+{
+ m_contactList.clear();
+ m_uidToContact.clear();
+
+ /* Load XML-File and journal if it exists */
+ if ( !load ( m_fileName, false ) )
+ return false;
+ /* The returncode of the journalfile is ignored due to the
+ * fact that it does not exist when this class is instantiated !
+ * But there may such a file exist, if the application crashed.
+ * Therefore we try to load it to get the changes before the #
+ * crash happened...
+ */
+ load (m_journalName, true);
+
+ return true;
+}
+
+void OContactAccessBackend_XML::clear ()
+{
+ m_contactList.clear();
+ m_uidToContact.clear();
+
+ m_changed = false;
+}
+
+bool OContactAccessBackend_XML::wasChangedExternally()
+{
+ QFileInfo fi( m_fileName );
+
+ QDateTime lastmod = fi.lastModified ();
+
+ return (lastmod != m_readtime);
+}
+
+QArray<int> OContactAccessBackend_XML::allRecords() const
+{
+ QArray<int> uid_list( m_contactList.count() );
+
+ uint counter = 0;
+ QListIterator<OContact> it( m_contactList );
+ for( ; it.current(); ++it ){
+ uid_list[counter++] = (*it)->uid();
+ }
+
+ return ( uid_list );
+}
+
+OContact OContactAccessBackend_XML::find ( int uid ) const
+{
+ OContact foundContact; //Create empty contact
+
+ OContact* found = m_uidToContact.find( QString().setNum( uid ) );
+
+ if ( found ){
+ foundContact = *found;
+ }
+
+ return ( foundContact );
+}
+
+QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings,
+ const QDateTime& d )
+{
+
+ QArray<int> m_currentQuery( m_contactList.count() );
+ QListIterator<OContact> it( m_contactList );
+ uint arraycounter = 0;
+
+ for( ; it.current(); ++it ){
+ /* Search all fields and compare them with query object. Store them into list
+ * if all fields matches.
+ */
+ QDate* queryDate = 0l;
+ QDate* checkDate = 0l;
+ bool allcorrect = true;
+ for ( int i = 0; i < Qtopia::Groups; i++ ) {
+ // Birthday and anniversary are special nonstring fields and should
+ // be handled specially
+ switch ( i ){
+ case Qtopia::Birthday:
+ queryDate = new QDate( query.birthday() );
+ checkDate = new QDate( (*it)->birthday() );
+ case Qtopia::Anniversary:
+ if ( queryDate == 0l ){
+ queryDate = new QDate( query.anniversary() );
+ checkDate = new QDate( (*it)->anniversary() );
+ }
+
+ if ( queryDate->isValid() ){
+ if( checkDate->isValid() ){
+ if ( settings & OContactAccess::DateYear ){
+ if ( queryDate->year() != checkDate->year() )
+ allcorrect = false;
+ }
+ if ( settings & OContactAccess::DateMonth ){
+ if ( queryDate->month() != checkDate->month() )
+ allcorrect = false;
+ }
+ if ( settings & OContactAccess::DateDay ){
+ if ( queryDate->day() != checkDate->day() )
+ allcorrect = false;
+ }
+ if ( settings & OContactAccess::DateDiff ) {
+ QDate current;
+ // If we get an additional date, we
+ // will take this date instead of
+ // the current one..
+ if ( !d.date().isValid() )
+ current = QDate::currentDate();
+ else
+ current = d.date();
+
+ // We have to equalize the year, otherwise
+ // the search will fail..
+ checkDate->setYMD( current.year(),
+ checkDate->month(),
+ checkDate->day() );
+ if ( *checkDate < current )
+ checkDate->setYMD( current.year()+1,
+ checkDate->month(),
+ checkDate->day() );
+
+ // Check whether the birthday/anniversary date is between
+ // the current/given date and the maximum date
+ // ( maximum time range ) !
+ qWarning("Checking if %s is between %s and %s ! ",
+ checkDate->toString().latin1(),
+ current.toString().latin1(),
+ queryDate->toString().latin1() );
+ if ( current.daysTo( *queryDate ) >= 0 ){
+ if ( !( ( *checkDate >= current ) &&
+ ( *checkDate <= *queryDate ) ) ){
+ allcorrect = false;
+ qWarning (" Nope!..");
+ }
+ }
+ }
+ } else{
+ // checkDate is invalid. Therefore this entry is always rejected
+ allcorrect = false;
+ }
+ }
+
+ delete queryDate;
+ queryDate = 0l;
+ delete checkDate;
+ checkDate = 0l;
+ break;
+ default:
+ /* Just compare fields which are not empty in the query object */
+ if ( !query.field(i).isEmpty() ){
+ switch ( settings & ~( OContactAccess::IgnoreCase
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ | OContactAccess::MatchOne
+ ) ){
+
+ case OContactAccess::RegExp:{
+ QRegExp expr ( query.field(i),
+ !(settings & OContactAccess::IgnoreCase),
+ false );
+ if ( expr.find ( (*it)->field(i), 0 ) == -1 )
+ allcorrect = false;
+ }
+ break;
+ case OContactAccess::WildCards:{
+ QRegExp expr ( query.field(i),
+ !(settings & OContactAccess::IgnoreCase),
+ true );
+ if ( expr.find ( (*it)->field(i), 0 ) == -1 )
+ allcorrect = false;
+ }
+ break;
+ case OContactAccess::ExactMatch:{
+ if (settings & OContactAccess::IgnoreCase){
+ if ( query.field(i).upper() !=
+ (*it)->field(i).upper() )
+ allcorrect = false;
+ }else{
+ if ( query.field(i) != (*it)->field(i) )
+ allcorrect = false;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ if ( allcorrect ){
+ m_currentQuery[arraycounter++] = (*it)->uid();
+ }
+ }
+
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+}
+
+QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> m_currentQuery( m_contactList.count() );
+ QListIterator<OContact> it( m_contactList );
+ uint arraycounter = 0;
+
+ for( ; it.current(); ++it ){
+ if ( (*it)->match( r ) ){
+ m_currentQuery[arraycounter++] = (*it)->uid();
+ }
+
+ }
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+}
+
+const uint OContactAccessBackend_XML::querySettings()
+{
+ return ( OContactAccess::WildCards
+ | OContactAccess::IgnoreCase
+ | OContactAccess::RegExp
+ | OContactAccess::ExactMatch
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ );
+}
+
+bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const
+{
+ /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay
+ * may be added with any of the other settings. IgnoreCase should never used alone.
+ * Wildcards, RegExp, ExactMatch should never used at the same time...
+ */
+
+ // Step 1: Check whether the given settings are supported by this backend
+ if ( ( querySettings & (
+ OContactAccess::IgnoreCase
+ | OContactAccess::WildCards
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ | OContactAccess::RegExp
+ | OContactAccess::ExactMatch
+ ) ) != querySettings )
+ return false;
+
+ // Step 2: Check whether the given combinations are ok..
+
+ // IngoreCase alone is invalid
+ if ( querySettings == OContactAccess::IgnoreCase )
+ return false;
+
+ // WildCards, RegExp and ExactMatch should never used at the same time
+ switch ( querySettings & ~( OContactAccess::IgnoreCase
+ | OContactAccess::DateDiff
+ | OContactAccess::DateYear
+ | OContactAccess::DateMonth
+ | OContactAccess::DateDay
+ )
+ ){
+ case OContactAccess::RegExp:
+ return ( true );
+ case OContactAccess::WildCards:
+ return ( true );
+ case OContactAccess::ExactMatch:
+ return ( true );
+ case 0: // one of the upper removed bits were set..
+ return ( true );
+ default:
+ return ( false );
+ }
+}
+
+// Currently only asc implemented..
+QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int )
+{
+ QMap<QString, int> nameToUid;
+ QStringList names;
+ QArray<int> m_currentQuery( m_contactList.count() );
+
+ // First fill map and StringList with all Names
+ // Afterwards sort namelist and use map to fill array to return..
+ QListIterator<OContact> it( m_contactList );
+ for( ; it.current(); ++it ){
+ names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) );
+ nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() );
+ }
+ names.sort();
+
+ int i = 0;
+ if ( asc ){
+ for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it )
+ m_currentQuery[i++] = nameToUid[ (*it) ];
+ }else{
+ for ( QStringList::Iterator it = names.end(); it != names.begin(); --it )
+ m_currentQuery[i++] = nameToUid[ (*it) ];
+ }
+
+ return m_currentQuery;
+
+}
+
+bool OContactAccessBackend_XML::add ( const OContact &newcontact )
+{
+ //qWarning("odefaultbackend: ACTION::ADD");
+ updateJournal (newcontact, ACTION_ADD);
+ addContact_p( newcontact );
+
+ m_changed = true;
+
+ return true;
+}
+
+bool OContactAccessBackend_XML::replace ( const OContact &contact )
+{
+ m_changed = true;
+
+ OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) );
+
+ if ( found ) {
+ OContact* newCont = new OContact( contact );
+
+ updateJournal ( *newCont, ACTION_REPLACE);
+ m_contactList.removeRef ( found );
+ m_contactList.append ( newCont );
+ m_uidToContact.remove( QString().setNum( contact.uid() ) );
+ m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont );
+
+ qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid());
+
+ return true;
+ } else
+ return false;
+}
+
+bool OContactAccessBackend_XML::remove ( int uid )
+{
+ m_changed = true;
+
+ OContact* found = m_uidToContact.find ( QString().setNum( uid ) );
+
+ if ( found ) {
+ updateJournal ( *found, ACTION_REMOVE);
+ m_contactList.removeRef ( found );
+ m_uidToContact.remove( QString().setNum( uid ) );
+
+ return true;
+ } else
+ return false;
+}
+
+bool OContactAccessBackend_XML::reload(){
+ /* Reload is the same as load in this implementation */
+ return ( load() );
+}
+
+void OContactAccessBackend_XML::addContact_p( const OContact &newcontact )
+{
+ OContact* contRef = new OContact( newcontact );
+
+ m_contactList.append ( contRef );
+ m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef );
+}
+
+/* This function loads the xml-database and the journalfile */
+bool OContactAccessBackend_XML::load( const QString filename, bool isJournal )
+{
+
+ /* We use the time of the last read to check if the file was
+ * changed externally.
+ */
+ if ( !isJournal ){
+ QFileInfo fi( filename );
+ m_readtime = fi.lastModified ();
+ }
+
+ const int JOURNALACTION = Qtopia::Notes + 1;
+ const int JOURNALROW = JOURNALACTION + 1;
+
+ bool foundAction = false;
+ journal_action action = ACTION_ADD;
+ int journalKey = 0;
+ QMap<int, QString> contactMap;
+ QMap<QString, QString> customMap;
+ QMap<QString, QString>::Iterator customIt;
+ QAsciiDict<int> dict( 47 );
+
+ dict.setAutoDelete( TRUE );
+ dict.insert( "Uid", new int(Qtopia::AddressUid) );
+ dict.insert( "Title", new int(Qtopia::Title) );
+ dict.insert( "FirstName", new int(Qtopia::FirstName) );
+ dict.insert( "MiddleName", new int(Qtopia::MiddleName) );
+ dict.insert( "LastName", new int(Qtopia::LastName) );
+ dict.insert( "Suffix", new int(Qtopia::Suffix) );
+ dict.insert( "FileAs", new int(Qtopia::FileAs) );
+ dict.insert( "Categories", new int(Qtopia::AddressCategory) );
+ dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) );
+ dict.insert( "Emails", new int(Qtopia::Emails) );
+ dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) );
+ dict.insert( "HomeCity", new int(Qtopia::HomeCity) );
+ dict.insert( "HomeState", new int(Qtopia::HomeState) );
+ dict.insert( "HomeZip", new int(Qtopia::HomeZip) );
+ dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) );
+ dict.insert( "HomePhone", new int(Qtopia::HomePhone) );
+ dict.insert( "HomeFax", new int(Qtopia::HomeFax) );
+ dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) );
+ dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) );
+ dict.insert( "Company", new int(Qtopia::Company) );
+ dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) );
+ dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) );
+ dict.insert( "BusinessState", new int(Qtopia::BusinessState) );
+ dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) );
+ dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) );
+ dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) );
+ dict.insert( "JobTitle", new int(Qtopia::JobTitle) );
+ dict.insert( "Department", new int(Qtopia::Department) );
+ dict.insert( "Office", new int(Qtopia::Office) );
+ dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) );
+ dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) );
+ dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) );
+ dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) );
+ dict.insert( "Profession", new int(Qtopia::Profession) );
+ dict.insert( "Assistant", new int(Qtopia::Assistant) );
+ dict.insert( "Manager", new int(Qtopia::Manager) );
+ dict.insert( "Spouse", new int(Qtopia::Spouse) );
+ dict.insert( "Children", new int(Qtopia::Children) );
+ dict.insert( "Gender", new int(Qtopia::Gender) );
+ dict.insert( "Birthday", new int(Qtopia::Birthday) );
+ dict.insert( "Anniversary", new int(Qtopia::Anniversary) );
+ dict.insert( "Nickname", new int(Qtopia::Nickname) );
+ dict.insert( "Notes", new int(Qtopia::Notes) );
+ dict.insert( "action", new int(JOURNALACTION) );
+ dict.insert( "actionrow", new int(JOURNALROW) );
+
+ //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() );
+
+ XMLElement *root = XMLElement::load( filename );
+ if(root != 0l ){ // start parsing
+ /* Parse all XML-Elements and put the data into the
+ * Contact-Class
+ */
+ XMLElement *element = root->firstChild();
+ //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() );
+ element = element->firstChild();
+
+ /* Search Tag "Contacts" which is the parent of all Contacts */
+ while( element && !isJournal ){
+ if( element->tagName() != QString::fromLatin1("Contacts") ){
+ //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s",
+ // element->tagName().latin1());
+ element = element->nextChild();
+ } else {
+ element = element->firstChild();
+ break;
+ }
+ }
+ /* Parse all Contacts and ignore unknown tags */
+ while( element ){
+ if( element->tagName() != QString::fromLatin1("Contact") ){
+ //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s",
+ // element->tagName().latin1());
+ element = element->nextChild();
+ continue;
+ }
+ /* Found alement with tagname "contact", now parse and store all
+ * attributes contained
+ */
+ //qWarning("OContactDefBack::load element tagName() : %s",
+ // element->tagName().latin1() );
+ QString dummy;
+ foundAction = false;
+
+ XMLElement::AttributeMap aMap = element->attributes();
+ XMLElement::AttributeMap::Iterator it;
+ contactMap.clear();
+ customMap.clear();
+ for( it = aMap.begin(); it != aMap.end(); ++it ){
+ // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1());
+
+ int *find = dict[ it.key() ];
+ /* Unknown attributes will be stored as "Custom" elements */
+ if ( !find ) {
+ // qWarning("Attribute %s not known.", it.key().latin1());
+ //contact.setCustomField(it.key(), it.data());
+ customMap.insert( it.key(), it.data() );
+ continue;
+ }
+
+ /* Check if special conversion is needed and add attribute
+ * into Contact class
+ */
+ switch( *find ) {
+ /*
+ case Qtopia::AddressUid:
+ contact.setUid( it.data().toInt() );
+ break;
+ case Qtopia::AddressCategory:
+ contact.setCategories( Qtopia::Record::idsFromString( it.data( )));
+ break;
+ */
+ case JOURNALACTION:
+ action = journal_action(it.data().toInt());
+ foundAction = true;
+ qWarning ("ODefBack(journal)::ACTION found: %d", action);
+ break;
+ case JOURNALROW:
+ journalKey = it.data().toInt();
+ break;
+ default: // no conversion needed add them to the map
+ contactMap.insert( *find, it.data() );
+ break;
+ }
+ }
+ /* now generate the Contact contact */
+ OContact contact( contactMap );
+
+ for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) {
+ contact.setCustomField( customIt.key(), customIt.data() );
+ }
+
+ if (foundAction){
+ foundAction = false;
+ switch ( action ) {
+ case ACTION_ADD:
+ addContact_p (contact);
+ break;
+ case ACTION_REMOVE:
+ if ( !remove (contact.uid()) )
+ qWarning ("ODefBack(journal)::Unable to remove uid: %d",
+ contact.uid() );
+ break;
+ case ACTION_REPLACE:
+ if ( !replace ( contact ) )
+ qWarning ("ODefBack(journal)::Unable to replace uid: %d",
+ contact.uid() );
+ break;
+ default:
+ qWarning ("Unknown action: ignored !");
+ break;
+ }
+ }else{
+ /* Add contact to list */
+ addContact_p (contact);
+ }
+
+ /* Move to next element */
+ element = element->nextChild();
+ }
+ }else {
+ qWarning("ODefBack::could not load");
+ }
+ delete root;
+ qWarning("returning from loading" );
+ return true;
+}
+
+
+void OContactAccessBackend_XML::updateJournal( const OContact& cnt,
+ journal_action action )
+{
+ QFile f( m_journalName );
+ bool created = !f.exists();
+ if ( !f.open(IO_WriteOnly|IO_Append) )
+ return;
+
+ QString buf;
+ QCString str;
+
+ // if the file was created, we have to set the Tag "<CONTACTS>" to
+ // get a XML-File which is readable by our parser.
+ // This is just a cheat, but better than rewrite the parser.
+ if ( created ){
+ buf = "<Contacts>";
+ QCString cstr = buf.utf8();
+ f.writeBlock( cstr.data(), cstr.length() );
+ }
+
+ buf = "<Contact ";
+ cnt.save( buf );
+ buf += " action=\"" + QString::number( (int)action ) + "\" ";
+ buf += "/>\n";
+ QCString cstr = buf.utf8();
+ f.writeBlock( cstr.data(), cstr.length() );
+}
+
+void OContactAccessBackend_XML::removeJournal()
+{
+ QFile f ( m_journalName );
+ if ( f.exists() )
+ f.remove();
+}
+
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 @@
+/*
+ * XML Backend for the OPIE-Contact Database.
+ *
+ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ * ToDo: XML-Backend: Automatic reload if something was changed...
+ * File Locking to protect against concurrent access
+ *
+ *
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:07 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.15 2003/09/22 14:31:16 eilers
+ * Added first experimental incarnation of sql-backend for addressbook.
+ * Some modifications to be able to compile the todo sql-backend.
+ * A lot of changes fill follow...
+ *
+ * Revision 1.14 2003/04/13 18:07:10 zecke
+ * More API doc
+ * QString -> const QString&
+ * QString = 0l -> QString::null
+ *
+ * Revision 1.13 2003/03/21 10:33:09 eilers
+ * Merged speed optimized xml backend for contacts to main.
+ * Added QDateTime to querybyexample. For instance, it is now possible to get
+ * all Birthdays/Anniversaries between two dates. This should be used
+ * to show all birthdays in the datebook..
+ * This change is sourcecode backward compatible but you have to upgrade
+ * the binaries for today-addressbook.
+ *
+ * Revision 1.12.2.2 2003/02/11 12:17:28 eilers
+ * Speed optimization. Removed the sequential search loops.
+ *
+ * Revision 1.12.2.1 2003/02/09 15:05:01 eilers
+ * Nothing happened.. Just some cleanup before I will start..
+ *
+ * Revision 1.12 2003/01/03 16:58:03 eilers
+ * Reenable debug output
+ *
+ * Revision 1.11 2003/01/03 12:31:28 eilers
+ * Bugfix for calculating data diffs..
+ *
+ * Revision 1.10 2003/01/02 14:27:12 eilers
+ * Improved query by example: Search by date is possible.. First step
+ * for a today plugin for birthdays..
+ *
+ * Revision 1.9 2002/12/08 12:48:57 eilers
+ * Moved journal-enum from ocontact into i the xml-backend..
+ *
+ * Revision 1.8 2002/11/14 17:04:24 eilers
+ * Sorting will now work if fullname is identical on some entries
+ *
+ * Revision 1.7 2002/11/13 15:02:46 eilers
+ * Small Bug in sorted fixed
+ *
+ * Revision 1.6 2002/11/13 14:14:51 eilers
+ * Added sorted for Contacts..
+ *
+ * Revision 1.5 2002/11/01 15:10:42 eilers
+ * Added regExp-search in database for all fields in a contact.
+ *
+ * Revision 1.4 2002/10/16 10:52:40 eilers
+ * Added some docu to the interface and now using the cache infrastucture by zecke.. :)
+ *
+ * Revision 1.3 2002/10/14 16:21:54 eilers
+ * Some minor interface updates
+ *
+ * Revision 1.2 2002/10/07 17:34:24 eilers
+ * added OBackendFactory for advanced backend access
+ *
+ * Revision 1.1 2002/09/27 17:11:44 eilers
+ * Added API for accessing the Contact-Database ! It is compiling, but
+ * please do not expect that anything is working !
+ * I will debug that stuff in the next time ..
+ * Please read README_COMPILE for compiling !
+ *
+ *
+ */
+
+#ifndef _OContactAccessBackend_XML_
+#define _OContactAccessBackend_XML_
+
+#include "ocontactaccessbackend.h"
+#include "ocontactaccess.h"
+
+#include <qlist.h>
+#include <qdict.h>
+
+/* the default xml implementation */
+/**
+ * This class is the XML implementation of a Contact backend
+ * it does implement everything available for OContact.
+ * @see OPimAccessBackend for more information of available methods
+ */
+class OContactAccessBackend_XML : public OContactAccessBackend {
+ public:
+ OContactAccessBackend_XML ( const QString& appname, const QString& filename = QString::null );
+
+ bool save();
+
+ bool load ();
+
+ void clear ();
+
+ bool wasChangedExternally();
+
+ QArray<int> allRecords() const;
+
+ OContact find ( int uid ) const;
+
+ QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() );
+
+ QArray<int> matchRegexp( const QRegExp &r ) const;
+
+ const uint querySettings();
+
+ bool hasQuerySettings (uint querySettings) const;
+
+ // Currently only asc implemented..
+ QArray<int> sorted( bool asc, int , int , int );
+ bool add ( const OContact &newcontact );
+
+ bool replace ( const OContact &contact );
+
+ bool remove ( int uid );
+ bool reload();
+
+ private:
+
+ enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE };
+
+ void addContact_p( const OContact &newcontact );
+
+ /* This function loads the xml-database and the journalfile */
+ bool load( const QString filename, bool isJournal );
+
+
+ void updateJournal( const OContact& cnt, journal_action action );
+ void removeJournal();
+
+ protected:
+ bool m_changed;
+ QString m_journalName;
+ QString m_fileName;
+ QString m_appName;
+ QList<OContact> m_contactList;
+ QDateTime m_readtime;
+
+ QDict<OContact> m_uidToContact;
+};
+
+#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 @@
+
+#include "ocontactfields.h"
+
+#include <qstringlist.h>
+#include <qobject.h>
+
+// We should use our own enum in the future ..
+#include <qpe/recordfields.h>
+#include <qpe/config.h>
+#include <opie/ocontact.h>
+
+/*!
+ \internal
+ Returns a list of personal field names for a contact.
+*/
+QStringList OContactFields::personalfields( bool sorted, bool translated )
+{
+ QStringList list;
+ QMap<int, QString> mapIdToStr;
+ if ( translated )
+ mapIdToStr = idToTrFields();
+ else
+ mapIdToStr = idToUntrFields();
+
+ list.append( mapIdToStr[ Qtopia::AddressUid ] );
+ list.append( mapIdToStr[ Qtopia::AddressCategory ] );
+
+ list.append( mapIdToStr[ Qtopia::Title ] );
+ list.append( mapIdToStr[ Qtopia::FirstName ] );
+ list.append( mapIdToStr[ Qtopia::MiddleName ] );
+ list.append( mapIdToStr[ Qtopia::LastName ] );
+ list.append( mapIdToStr[ Qtopia::Suffix ] );
+ list.append( mapIdToStr[ Qtopia::FileAs ] );
+
+ list.append( mapIdToStr[ Qtopia::JobTitle ] );
+ list.append( mapIdToStr[ Qtopia::Department ] );
+ list.append( mapIdToStr[ Qtopia::Company ] );
+
+ list.append( mapIdToStr[ Qtopia::Notes ] );
+ list.append( mapIdToStr[ Qtopia::Groups ] );
+
+ if (sorted) list.sort();
+ return list;
+}
+
+/*!
+ \internal
+ Returns a list of details field names for a contact.
+*/
+QStringList OContactFields::detailsfields( bool sorted, bool translated )
+{
+ QStringList list;
+ QMap<int, QString> mapIdToStr;
+ if ( translated )
+ mapIdToStr = idToTrFields();
+ else
+ mapIdToStr = idToUntrFields();
+
+ list.append( mapIdToStr[ Qtopia::Office ] );
+ list.append( mapIdToStr[ Qtopia::Profession ] );
+ list.append( mapIdToStr[ Qtopia::Assistant ] );
+ list.append( mapIdToStr[ Qtopia::Manager ] );
+
+ list.append( mapIdToStr[ Qtopia::Spouse ] );
+ list.append( mapIdToStr[ Qtopia::Gender ] );
+ list.append( mapIdToStr[ Qtopia::Birthday ] );
+ list.append( mapIdToStr[ Qtopia::Anniversary ] );
+ list.append( mapIdToStr[ Qtopia::Nickname ] );
+ list.append( mapIdToStr[ Qtopia::Children ] );
+
+ if (sorted) list.sort();
+ return list;
+}
+
+/*!
+ \internal
+ Returns a list of phone field names for a contact.
+*/
+QStringList OContactFields::phonefields( bool sorted, bool translated )
+{
+ QStringList list;
+ QMap<int, QString> mapIdToStr;
+ if ( translated )
+ mapIdToStr = idToTrFields();
+ else
+ mapIdToStr = idToUntrFields();
+
+ list.append( mapIdToStr[Qtopia::BusinessPhone] );
+ list.append( mapIdToStr[Qtopia::BusinessFax] );
+ list.append( mapIdToStr[Qtopia::BusinessMobile] );
+ list.append( mapIdToStr[Qtopia::BusinessPager] );
+ list.append( mapIdToStr[Qtopia::BusinessWebPage] );
+
+ list.append( mapIdToStr[Qtopia::DefaultEmail] );
+ list.append( mapIdToStr[Qtopia::Emails] );
+
+ list.append( mapIdToStr[Qtopia::HomePhone] );
+ list.append( mapIdToStr[Qtopia::HomeFax] );
+ list.append( mapIdToStr[Qtopia::HomeMobile] );
+ // list.append( mapIdToStr[Qtopia::HomePager] );
+ list.append( mapIdToStr[Qtopia::HomeWebPage] );
+
+ if (sorted) list.sort();
+
+ return list;
+}
+
+/*!
+ \internal
+ Returns a list of field names for a contact.
+*/
+QStringList OContactFields::fields( bool sorted, bool translated )
+{
+ QStringList list;
+ QMap<int, QString> mapIdToStr;
+ if ( translated )
+ mapIdToStr = idToTrFields();
+ else
+ mapIdToStr = idToUntrFields();
+
+ list += personalfields( sorted, translated );
+
+ list += phonefields( sorted, translated );
+
+ list.append( mapIdToStr[Qtopia::BusinessStreet] );
+ list.append( mapIdToStr[Qtopia::BusinessCity] );
+ list.append( mapIdToStr[Qtopia::BusinessState] );
+ list.append( mapIdToStr[Qtopia::BusinessZip] );
+ list.append( mapIdToStr[Qtopia::BusinessCountry] );
+
+ list.append( mapIdToStr[Qtopia::HomeStreet] );
+ list.append( mapIdToStr[Qtopia::HomeCity] );
+ list.append( mapIdToStr[Qtopia::HomeState] );
+ list.append( mapIdToStr[Qtopia::HomeZip] );
+ list.append( mapIdToStr[Qtopia::HomeCountry] );
+
+ list += detailsfields( sorted, translated );
+
+ if (sorted) list.sort();
+
+ return list;
+}
+
+
+/*!
+ \internal
+ Returns an untranslated list of personal field names for a contact.
+*/
+QStringList OContactFields::untrpersonalfields( bool sorted )
+{
+ return personalfields( sorted, false );
+}
+
+
+/*!
+ \internal
+ Returns a translated list of personal field names for a contact.
+*/
+QStringList OContactFields::trpersonalfields( bool sorted )
+{
+ return personalfields( sorted, true );
+}
+
+
+/*!
+ \internal
+ Returns an untranslated list of details field names for a contact.
+*/
+QStringList OContactFields::untrdetailsfields( bool sorted )
+{
+ return detailsfields( sorted, false );
+}
+
+
+/*!
+ \internal
+ Returns a translated list of details field names for a contact.
+*/
+QStringList OContactFields::trdetailsfields( bool sorted )
+{
+ return detailsfields( sorted, true );
+}
+
+
+/*!
+ \internal
+ Returns a translated list of phone field names for a contact.
+*/
+QStringList OContactFields::trphonefields( bool sorted )
+{
+ return phonefields( sorted, true );
+}
+
+/*!
+ \internal
+ Returns an untranslated list of phone field names for a contact.
+*/
+QStringList OContactFields::untrphonefields( bool sorted )
+{
+ return phonefields( sorted, false );
+}
+
+
+/*!
+ \internal
+ Returns a translated list of field names for a contact.
+*/
+QStringList OContactFields::trfields( bool sorted )
+{
+ return fields( sorted, true );
+}
+
+/*!
+ \internal
+ Returns an untranslated list of field names for a contact.
+*/
+QStringList OContactFields::untrfields( bool sorted )
+{
+ return fields( sorted, false );
+}
+
+QMap<int, QString> OContactFields::idToTrFields()
+{
+ QMap<int, QString> ret_map;
+
+ ret_map.insert( Qtopia::AddressUid, QObject::tr( "User Id" ) );
+ ret_map.insert( Qtopia::AddressCategory, QObject::tr( "Categories" ) );
+
+ ret_map.insert( Qtopia::Title, QObject::tr( "Name Title") );
+ ret_map.insert( Qtopia::FirstName, QObject::tr( "First Name" ) );
+ ret_map.insert( Qtopia::MiddleName, QObject::tr( "Middle Name" ) );
+ ret_map.insert( Qtopia::LastName, QObject::tr( "Last Name" ) );
+ ret_map.insert( Qtopia::Suffix, QObject::tr( "Suffix" ));
+ ret_map.insert( Qtopia::FileAs, QObject::tr( "File As" ) );
+
+ ret_map.insert( Qtopia::JobTitle, QObject::tr( "Job Title" ) );
+ ret_map.insert( Qtopia::Department, QObject::tr( "Department" ) );
+ ret_map.insert( Qtopia::Company, QObject::tr( "Company" ) );
+ ret_map.insert( Qtopia::BusinessPhone, QObject::tr( "Business Phone" ) );
+ ret_map.insert( Qtopia::BusinessFax, QObject::tr( "Business Fax" ) );
+ ret_map.insert( Qtopia::BusinessMobile, QObject::tr( "Business Mobile" ));
+
+ // email
+ ret_map.insert( Qtopia::DefaultEmail, QObject::tr( "Default Email" ) );
+ ret_map.insert( Qtopia::Emails, QObject::tr( "Emails" ) );
+
+ ret_map.insert( Qtopia::HomePhone, QObject::tr( "Home Phone" ) );
+ ret_map.insert( Qtopia::HomeFax, QObject::tr( "Home Fax" ) );
+ ret_map.insert( Qtopia::HomeMobile, QObject::tr( "Home Mobile" ) );
+
+ // business
+ ret_map.insert( Qtopia::BusinessStreet, QObject::tr( "Business Street" ) );
+ ret_map.insert( Qtopia::BusinessCity, QObject::tr( "Business City" ) );
+ ret_map.insert( Qtopia::BusinessState, QObject::tr( "Business State" ) );
+ ret_map.insert( Qtopia::BusinessZip, QObject::tr( "Business Zip" ) );
+ ret_map.insert( Qtopia::BusinessCountry, QObject::tr( "Business Country" ) );
+ ret_map.insert( Qtopia::BusinessPager, QObject::tr( "Business Pager" ) );
+ ret_map.insert( Qtopia::BusinessWebPage, QObject::tr( "Business WebPage" ) );
+
+ ret_map.insert( Qtopia::Office, QObject::tr( "Office" ) );
+ ret_map.insert( Qtopia::Profession, QObject::tr( "Profession" ) );
+ ret_map.insert( Qtopia::Assistant, QObject::tr( "Assistant" ) );
+ ret_map.insert( Qtopia::Manager, QObject::tr( "Manager" ) );
+
+ // home
+ ret_map.insert( Qtopia::HomeStreet, QObject::tr( "Home Street" ) );
+ ret_map.insert( Qtopia::HomeCity, QObject::tr( "Home City" ) );
+ ret_map.insert( Qtopia::HomeState, QObject::tr( "Home State" ) );
+ ret_map.insert( Qtopia::HomeZip, QObject::tr( "Home Zip" ) );
+ ret_map.insert( Qtopia::HomeCountry, QObject::tr( "Home Country" ) );
+ ret_map.insert( Qtopia::HomeWebPage, QObject::tr( "Home Web Page" ) );
+
+ //personal
+ ret_map.insert( Qtopia::Spouse, QObject::tr( "Spouse" ) );
+ ret_map.insert( Qtopia::Gender, QObject::tr( "Gender" ) );
+ ret_map.insert( Qtopia::Birthday, QObject::tr( "Birthday" ) );
+ ret_map.insert( Qtopia::Anniversary, QObject::tr( "Anniversary" ) );
+ ret_map.insert( Qtopia::Nickname, QObject::tr( "Nickname" ) );
+ ret_map.insert( Qtopia::Children, QObject::tr( "Children" ) );
+
+ // other
+ ret_map.insert( Qtopia::Notes, QObject::tr( "Notes" ) );
+
+
+ return ret_map;
+}
+
+QMap<int, QString> OContactFields::idToUntrFields()
+{
+ QMap<int, QString> ret_map;
+
+ ret_map.insert( Qtopia::AddressUid, "User Id" );
+ ret_map.insert( Qtopia::AddressCategory, "Categories" );
+
+ ret_map.insert( Qtopia::Title, "Name Title" );
+ ret_map.insert( Qtopia::FirstName, "First Name" );
+ ret_map.insert( Qtopia::MiddleName, "Middle Name" );
+ ret_map.insert( Qtopia::LastName, "Last Name" );
+ ret_map.insert( Qtopia::Suffix, "Suffix" );
+ ret_map.insert( Qtopia::FileAs, "File As" );
+
+ ret_map.insert( Qtopia::JobTitle, "Job Title" );
+ ret_map.insert( Qtopia::Department, "Department" );
+ ret_map.insert( Qtopia::Company, "Company" );
+ ret_map.insert( Qtopia::BusinessPhone, "Business Phone" );
+ ret_map.insert( Qtopia::BusinessFax, "Business Fax" );
+ ret_map.insert( Qtopia::BusinessMobile, "Business Mobile" );
+
+ // email
+ ret_map.insert( Qtopia::DefaultEmail, "Default Email" );
+ ret_map.insert( Qtopia::Emails, "Emails" );
+
+ ret_map.insert( Qtopia::HomePhone, "Home Phone" );
+ ret_map.insert( Qtopia::HomeFax, "Home Fax" );
+ ret_map.insert( Qtopia::HomeMobile, "Home Mobile" );
+
+ // business
+ ret_map.insert( Qtopia::BusinessStreet, "Business Street" );
+ ret_map.insert( Qtopia::BusinessCity, "Business City" );
+ ret_map.insert( Qtopia::BusinessState, "Business State" );
+ ret_map.insert( Qtopia::BusinessZip, "Business Zip" );
+ ret_map.insert( Qtopia::BusinessCountry, "Business Country" );
+ ret_map.insert( Qtopia::BusinessPager, "Business Pager" );
+ ret_map.insert( Qtopia::BusinessWebPage, "Business WebPage" );
+
+ ret_map.insert( Qtopia::Office, "Office" );
+ ret_map.insert( Qtopia::Profession, "Profession" );
+ ret_map.insert( Qtopia::Assistant, "Assistant" );
+ ret_map.insert( Qtopia::Manager, "Manager" );
+
+ // home
+ ret_map.insert( Qtopia::HomeStreet, "Home Street" );
+ ret_map.insert( Qtopia::HomeCity, "Home City" );
+ ret_map.insert( Qtopia::HomeState, "Home State" );
+ ret_map.insert( Qtopia::HomeZip, "Home Zip" );
+ ret_map.insert( Qtopia::HomeCountry, "Home Country" );
+ ret_map.insert( Qtopia::HomeWebPage, "Home Web Page" );
+
+ //personal
+ ret_map.insert( Qtopia::Spouse, "Spouse" );
+ ret_map.insert( Qtopia::Gender, "Gender" );
+ ret_map.insert( Qtopia::Birthday, "Birthday" );
+ ret_map.insert( Qtopia::Anniversary, "Anniversary" );
+ ret_map.insert( Qtopia::Nickname, "Nickname" );
+ ret_map.insert( Qtopia::Children, "Children" );
+
+ // other
+ ret_map.insert( Qtopia::Notes, "Notes" );
+ ret_map.insert( Qtopia::Groups, "Groups" );
+
+
+ return ret_map;
+}
+
+QMap<QString, int> OContactFields::trFieldsToId()
+{
+ QMap<int, QString> idtostr = idToTrFields();
+ QMap<QString, int> ret_map;
+
+
+ QMap<int, QString>::Iterator it;
+ for( it = idtostr.begin(); it != idtostr.end(); ++it )
+ ret_map.insert( *it, it.key() );
+
+
+ return ret_map;
+}
+
+/* ======================================================================= */
+
+QMap<QString, int> OContactFields::untrFieldsToId()
+{
+ QMap<int, QString> idtostr = idToUntrFields();
+ QMap<QString, int> ret_map;
+
+
+ QMap<int, QString>::Iterator it;
+ for( it = idtostr.begin(); it != idtostr.end(); ++it )
+ ret_map.insert( *it, it.key() );
+
+
+ return ret_map;
+}
+
+
+OContactFields::OContactFields():
+ fieldOrder( DEFAULT_FIELD_ORDER ),
+ changedFieldOrder( false )
+{
+ // Get the global field order from the config file and
+ // use it as a start pattern
+ Config cfg ( "AddressBook" );
+ cfg.setGroup( "ContactFieldOrder" );
+ globalFieldOrder = cfg.readEntry( "General", DEFAULT_FIELD_ORDER );
+}
+
+OContactFields::~OContactFields(){
+
+ // We will store the fieldorder into the config file
+ // to reuse it for the future..
+ if ( changedFieldOrder ){
+ Config cfg ( "AddressBook" );
+ cfg.setGroup( "ContactFieldOrder" );
+ cfg.writeEntry( "General", globalFieldOrder );
+ }
+}
+
+
+
+void OContactFields::saveToRecord( OContact &cnt ){
+
+ qDebug("ocontactfields saveToRecord: >%s<",fieldOrder.latin1());
+
+ // Store fieldorder into this contact.
+ cnt.setCustomField( CONTACT_FIELD_ORDER_NAME, fieldOrder );
+
+ globalFieldOrder = fieldOrder;
+ changedFieldOrder = true;
+
+}
+
+void OContactFields::loadFromRecord( const OContact &cnt ){
+ qDebug("ocontactfields loadFromRecord");
+ qDebug("loading >%s<",cnt.fullName().latin1());
+
+ // Get fieldorder for this contact. If none is defined,
+ // we will use the global one from the config file..
+
+ fieldOrder = cnt.customField( CONTACT_FIELD_ORDER_NAME );
+
+ qDebug("fieldOrder from contact>%s<",fieldOrder.latin1());
+
+ if (fieldOrder.isEmpty()){
+ fieldOrder = globalFieldOrder;
+ }
+
+
+ qDebug("effective fieldOrder in loadFromRecord >%s<",fieldOrder.latin1());
+}
+
+void OContactFields::setFieldOrder( int num, int index ){
+ qDebug("qcontactfields setfieldorder pos %i -> %i",num,index);
+
+ fieldOrder[num] = QString::number( index, 16 )[0];
+
+ // We will store this new fieldorder globally to
+ // remember it for contacts which have none
+ globalFieldOrder = fieldOrder;
+ changedFieldOrder = true;
+
+ qDebug("fieldOrder >%s<",fieldOrder.latin1());
+}
+
+int OContactFields::getFieldOrder( int num, int defIndex ){
+ qDebug("ocontactfields getFieldOrder");
+ qDebug("fieldOrder >%s<",fieldOrder.latin1());
+
+ // Get index of combo as char..
+ QChar poschar = fieldOrder[num];
+
+ bool ok;
+ int ret = 0;
+ // Convert char to number..
+ if ( !( poschar == QChar::null ) )
+ ret = QString( poschar ).toInt(&ok, 16);
+ else
+ ok = false;
+
+ // Return default value if index for
+ // num was not set or if anything else happened..
+ if ( !ok ) ret = defIndex;
+
+ qDebug("returning >%i<",ret);
+
+ return ret;
+
+}
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 @@
+#ifndef OPIE_CONTACTS_FIELDS
+#define OPIE_CONTACTS_FIELDS
+
+class QStringList;
+
+#include <qmap.h>
+#include <qstring.h>
+#include <opie/ocontact.h>
+
+#define CONTACT_FIELD_ORDER_NAME "opie-contactfield-order"
+#define DEFAULT_FIELD_ORDER "__________"
+
+class OContactFields{
+
+ public:
+ OContactFields();
+ ~OContactFields();
+ /** Set the index for combo boxes.
+ * Sets the <b>index</b> of combo <b>num</b>.
+ * @param num selects the number of the combo
+ * @param index sets the index in the combo
+ */
+ void setFieldOrder( int num, int index );
+
+ /** Get the index for combo boxes.
+ * Returns the index of combo <b>num</b> or defindex
+ * if none was defined..
+ * @param num Selects the number of the combo
+ * @param defIndex will be returned if none was defined (either
+ * globally in the config file, nor by the contact which was used
+ * by loadFromRecord() )
+ */
+ int getFieldOrder( int num, int defIndex);
+
+ /** Store fieldorder to contact. */
+ void saveToRecord( OContact& );
+ /** Get Fieldorder from contact. */
+ void loadFromRecord( const OContact& );
+
+ private:
+ QString fieldOrder;
+ QString globalFieldOrder;
+ bool changedFieldOrder;
+
+ public:
+ static QStringList personalfields( bool sorted = true, bool translated = false );
+ static QStringList phonefields( bool sorted = true, bool translated = false );
+ static QStringList detailsfields( bool sorted = true, bool translated = false );
+ static QStringList fields( bool sorted = true, bool translated = false );
+
+ static QStringList trpersonalfields( bool sorted = true );
+ static QStringList untrpersonalfields( bool sorted = true );
+ static QStringList trphonefields( bool sorted = true );
+ static QStringList untrphonefields( bool sorted = true );
+ static QStringList trdetailsfields( bool sorted = true );
+ static QStringList untrdetailsfields( bool sorted = true );
+ static QStringList trfields( bool sorted = true );
+ static QStringList untrfields( bool sorted = true );
+
+ static QMap<int, QString> idToTrFields();
+ static QMap<QString, int> trFieldsToId();
+ static QMap<int, QString> idToUntrFields();
+ static QMap<QString, int> untrFieldsToId();
+
+};
+
+#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 @@
+/**********************************************************************
+** Copyright (C) 2003 by Stefan Eilers (eilers.stefan@epost.de)
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU Lesser General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+**********************************************************************/
+
+#include "oconversion.h"
+#include <qpe/timeconversion.h>
+
+
+QString OConversion::dateToString( const QDate &d )
+{
+ if ( d.isNull() || !d.isValid() )
+ return QString::null;
+
+ // ISO format in year, month, day (YYYYMMDD); e.g. 20021231
+ QString year = QString::number( d.year() );
+ QString month = QString::number( d.month() );
+ month = month.rightJustify( 2, '0' );
+ QString day = QString::number( d.day() );
+ day = day.rightJustify( 2, '0' );
+
+ QString str = year + month + day;
+ //qDebug( "\tPimContact dateToStr = %s", str.latin1() );
+
+ return str;
+}
+
+QDate OConversion::dateFromString( const QString& s )
+{
+ QDate date;
+
+ if ( s.isEmpty() )
+ return date;
+
+ // Be backward compatible to old Opie format:
+ // Try to load old format. If it fails, try new ISO-Format!
+ date = TimeConversion::fromString ( s );
+ if ( date.isValid() )
+ return date;
+
+ // Read ISO-Format (YYYYMMDD)
+ int year = s.mid(0, 4).toInt();
+ int month = s.mid(4,2).toInt();
+ int day = s.mid(6,2).toInt();
+
+ // do some quick sanity checking -eilers
+ // but we isValid() again? -zecke
+ if ( year < 1900 || year > 3000 ) {
+ qWarning( "PimContact year is not in range");
+ return date;
+ }
+ if ( month < 0 || month > 12 ) {
+ qWarning( "PimContact month is not in range");
+ return date;
+ }
+ if ( day < 0 || day > 31 ) {
+ qWarning( "PimContact day is not in range");
+ return date;
+ }
+
+ date.setYMD( year, month, day );
+ if ( !date.isValid() ) {
+ qWarning( "PimContact date is not valid");
+ return date;
+ }
+
+ return date;
+}
+QString OConversion::dateTimeToString( const QDateTime& dt ) {
+ if (!dt.isValid() || dt.isNull() ) return QString::null;
+
+ QString year = QString::number( dt.date().year() );
+ QString month = QString::number( dt.date().month() );
+ QString day = QString::number( dt.date().day() );
+
+ QString hour = QString::number( dt.time().hour() );
+ QString min = QString::number( dt.time().minute() );
+ QString sec = QString::number( dt.time().second() );
+
+ month = month.rightJustify( 2, '0' );
+ day = day. rightJustify( 2, '0' );
+ hour = hour. rightJustify( 2, '0' );
+ min = min. rightJustify( 2, '0' );
+ sec = sec. rightJustify( 2, '0' );
+
+ QString str = day + month + year + hour + min + sec;
+
+ return str;
+}
+QDateTime OConversion::dateTimeFromString( const QString& str) {
+
+ if ( str.isEmpty() ) return QDateTime();
+ int day = str.mid(0, 2).toInt();
+ int month = str.mid(2, 2).toInt();
+ int year = str.mid(4, 4).toInt();
+ int hour = str.mid(8, 2).toInt();
+ int min = str.mid(10, 2).toInt();
+ int sec = str.mid(12, 2).toInt();
+
+ QDate date( year, month, day );
+ QTime time( hour, min, sec );
+ QDateTime dt( date, time );
+ return dt;
+}
+
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 @@
+/**********************************************************************
+** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
+** Copyright (C) 2002-2003 by Stefan Eilers (eilers.stefan@epost.de)
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**********************************************************************/
+
+#ifndef __oconversion_h__
+#define __oconversion_h__
+
+/* #include <time.h> */
+/* #include <sys/types.h> */
+#include <qdatetime.h>
+
+/* FIXME namespace? -zecke */
+class OConversion
+{
+public:
+ static QString dateToString( const QDate &d );
+ static QDate dateFromString( const QString &datestr );
+
+ /**
+ * simple function to store DateTime as string and read from string
+ * no timezone changing is done
+ * DDMMYYYYHHMMSS is the simple format
+ */
+ static QString dateTimeToString( const QDateTime& );
+ static QDateTime dateTimeFromString( const QString& );
+
+private:
+ class Private;
+ Private* d;
+
+};
+
+#endif // __oconversion_h__
+
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 @@
+#include "obackendfactory.h"
+#include "odatebookaccess.h"
+
+/**
+ * Simple constructor
+ * It takes a ODateBookAccessBackend as parent. If it is 0 the default implementation
+ * will be used!
+ * @param back The backend to be used or 0 for the default backend
+ * @param ac What kind of access is intended
+ */
+ODateBookAccess::ODateBookAccess( ODateBookAccessBackend* back, enum Access ac )
+ : OPimAccessTemplate<OEvent>( back )
+{
+ if (!back )
+ back = OBackendFactory<ODateBookAccessBackend>::Default("datebook", QString::null );
+
+ m_backEnd = back;
+ setBackEnd( m_backEnd );
+}
+ODateBookAccess::~ODateBookAccess() {
+}
+
+/**
+ * @return all events available
+ */
+ODateBookAccess::List ODateBookAccess::rawEvents()const {
+ QArray<int> ints = m_backEnd->rawEvents();
+
+ List lis( ints, this );
+ return lis;
+}
+
+/**
+ * @return all repeating events
+ */
+ODateBookAccess::List ODateBookAccess::rawRepeats()const {
+ QArray<int> ints = m_backEnd->rawRepeats();
+
+ List lis( ints, this );
+ return lis;
+}
+
+/**
+ * @return all non repeating events
+ */
+ODateBookAccess::List ODateBookAccess::nonRepeats()const {
+ QArray<int> ints = m_backEnd->nonRepeats();
+
+ List lis( ints, this );
+ return lis;
+}
+
+/**
+ * @return dates in the time span between from and to
+ * @param from Include all events from...
+ * @param to Include all events to...
+ */
+OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDate& from, const QDate& to ) const {
+ return m_backEnd->effectiveEvents( from, to );
+}
+/**
+ * @return all events at a given datetime
+ */
+OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDateTime& start ) const {
+ return m_backEnd->effectiveEvents( start );
+}
+
+/**
+ * @return non repeating dates in the time span between from and to
+ * @param from Include all events from...
+ * @param to Include all events to...
+ */
+OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) const {
+ return m_backEnd->effectiveNonRepeatingEvents( from, to );
+}
+/**
+ * @return all non repeating events at a given datetime
+ */
+OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDateTime& start ) const {
+ return m_backEnd->effectiveNonRepeatingEvents( start );
+}
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 @@
+#ifndef OPIE_DATE_BOOK_ACCESS_H
+#define OPIE_DATE_BOOK_ACCESS_H
+
+#include "odatebookaccessbackend.h"
+#include "opimaccesstemplate.h"
+
+#include "oevent.h"
+
+/**
+ * This is the object orientated datebook database. It'll use OBackendFactory
+ * to query for a backend.
+ * All access to the datebook should be done via this class.
+ * Make sure to load and save the datebook this is not part of
+ * destructing and creating the object
+ *
+ * @author Holger Freyther, Stefan Eilers
+ */
+class ODateBookAccess : public OPimAccessTemplate<OEvent> {
+public:
+ ODateBookAccess( ODateBookAccessBackend* = 0l, enum Access acc = Random );
+ ~ODateBookAccess();
+
+ /* return all events */
+ List rawEvents()const;
+
+ /* return repeating events */
+ List rawRepeats()const;
+
+ /* return non repeating events */
+ List nonRepeats()const;
+
+ /* return non repeating events (from,to) */
+ OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to ) const;
+ OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start ) const;
+ OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) const;
+ OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start ) const;
+
+private:
+ ODateBookAccessBackend* m_backEnd;
+ class Private;
+ Private* d;
+};
+
+#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 @@
+#include <qtl.h>
+
+#include "orecur.h"
+
+#include "odatebookaccessbackend.h"
+
+namespace {
+/* a small helper to get all NonRepeating events for a range of time */
+ void events( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& events,
+ const QDate& from, const QDate& to ) {
+ QDateTime dtStart, dtEnd;
+
+ for ( OEvent::ValueList::ConstIterator it = events.begin(); it != events.end(); ++it ) {
+ dtStart = (*it).startDateTime();
+ dtEnd = (*it).endDateTime();
+
+ /*
+ * If in range
+ */
+ if (dtStart.date() >= from && dtEnd.date() <= to ) {
+ OEffectiveEvent eff;
+ eff.setEvent( (*it) );
+ eff.setDate( dtStart.date() );
+ eff.setStartTime( dtStart.time() );
+
+ /* if not on the same day */
+ if ( dtStart.date() != dtEnd.date() )
+ eff.setEndTime( QTime(23, 59, 0 ) );
+ else
+ eff.setEndTime( dtEnd.time() );
+
+ tmpList.append( eff );
+ }
+
+ /* we must also check for end date information... */
+ if ( dtEnd.date() != dtStart.date() && dtEnd.date() >= from ) {
+ QDateTime dt = dtStart.addDays( 1 );
+ dt.setTime( QTime(0, 0, 0 ) );
+ QDateTime dtStop;
+ if ( dtEnd > to )
+ dtStop = to;
+ else
+ dtStop = dtEnd;
+
+ while ( dt <= dtStop ) {
+ OEffectiveEvent eff;
+ eff.setEvent( (*it) );
+ eff.setDate( dt.date() );
+
+ if ( dt >= from ) {
+ eff.setStartTime( QTime(0, 0, 0 ) );
+ if ( dt.date() == dtEnd.date() )
+ eff.setEndTime( dtEnd.time() );
+ else
+ eff.setEndTime( QTime(23, 59, 0 ) );
+ tmpList.append( eff );
+ }
+ dt = dt.addDays( 1 );
+ }
+ }
+ }
+ }
+
+ void repeat( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& list,
+ const QDate& from, const QDate& to ) {
+ QDate repeat;
+ for ( OEvent::ValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) {
+ int dur = (*it).startDateTime().date().daysTo( (*it).endDateTime().date() );
+ QDate itDate = from.addDays(-dur );
+ ORecur rec = (*it).recurrence();
+ if ( !rec.hasEndDate() || rec.endDate() > to ) {
+ rec.setEndDate( to );
+ rec.setHasEndDate( true );
+ }
+ while (rec.nextOcurrence(itDate, repeat ) ) {
+ if (repeat > to ) break;
+ OEffectiveEvent eff;
+ eff.setDate( repeat );
+ if ( (*it).isAllDay() ) {
+ eff.setStartTime( QTime(0, 0, 0 ) );
+ eff.setEndTime( QTime(23, 59, 59 ) );
+ }else {
+ /* we only occur by days, not hours/minutes/seconds. Hence
+ * the actual end and start times will be the same for
+ * every repeated event. For multi day events this is
+ * fixed up later if on wronge day span
+ */
+ eff.setStartTime( (*it).startDateTime().time() );
+ eff.setEndTime( (*it).endDateTime().time() );
+ }
+ if ( dur != 0 ) {
+ // multi-day repeating events
+ QDate sub_it = QMAX( repeat, from );
+ QDate startDate = repeat;
+ QDate endDate = startDate.addDays( dur );
+
+ while ( sub_it <= endDate && sub_it <= to ) {
+ OEffectiveEvent tmpEff = eff;
+ tmpEff.setEvent( (*it) );
+ if ( sub_it != startDate )
+ tmpEff.setStartTime( QTime(0, 0, 0 ) );
+ if ( sub_it != endDate )
+ tmpEff.setEndTime( QTime( 23, 59, 59 ) );
+
+ tmpEff.setDate( sub_it );
+ tmpEff.setEffectiveDates( startDate, endDate );
+ tmpList.append( tmpEff );
+
+ sub_it = sub_it.addDays( 1 );
+ }
+ itDate = endDate;
+ }else {
+ eff.setEvent( (*it) );
+ tmpList.append( eff );
+ itDate = repeat.addDays( 1 );
+ }
+ }
+ }
+ }
+}
+
+ODateBookAccessBackend::ODateBookAccessBackend()
+ : OPimAccessBackend<OEvent>()
+{
+
+}
+ODateBookAccessBackend::~ODateBookAccessBackend() {
+
+}
+OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDate& from,
+ const QDate& to ) {
+ OEffectiveEvent::ValueList tmpList;
+ OEvent::ValueList list = directNonRepeats();
+
+ events( tmpList, list, from, to );
+ repeat( tmpList, directRawRepeats(),from,to );
+
+ list = directRawRepeats(); // Useless, isn't it ? (eilers)
+
+ qHeapSort( tmpList );
+ return tmpList;
+}
+OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDateTime& dt ) {
+ OEffectiveEvent::ValueList day = effectiveEvents( dt.date(), dt.date() );
+ OEffectiveEvent::ValueList::Iterator it;
+
+ OEffectiveEvent::ValueList tmpList;
+ QDateTime dtTmp;
+ for ( it = day.begin(); it != day.end(); ++it ) {
+ dtTmp = QDateTime( (*it).date(), (*it).startTime() );
+ if ( QABS(dt.secsTo(dtTmp) ) < 60 )
+ tmpList.append( (*it) );
+ }
+
+ return tmpList;
+}
+
+OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDate& from,
+ const QDate& to ) {
+ OEffectiveEvent::ValueList tmpList;
+ OEvent::ValueList list = directNonRepeats();
+
+ events( tmpList, list, from, to );
+
+ qHeapSort( tmpList );
+ return tmpList;
+}
+
+OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt ) {
+ OEffectiveEvent::ValueList day = effectiveNonRepeatingEvents( dt.date(), dt.date() );
+ OEffectiveEvent::ValueList::Iterator it;
+
+ OEffectiveEvent::ValueList tmpList;
+ QDateTime dtTmp;
+ for ( it = day.begin(); it != day.end(); ++it ) {
+ dtTmp = QDateTime( (*it).date(), (*it).startTime() );
+ if ( QABS(dt.secsTo(dtTmp) ) < 60 )
+ tmpList.append( (*it) );
+ }
+
+ return tmpList;
+}
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 @@
+#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_H
+#define OPIE_DATE_BOOK_ACCESS_BACKEND_H
+
+#include <qarray.h>
+
+#include "opimaccessbackend.h"
+#include "oevent.h"
+
+/**
+ * This class is the interface to the storage of Events.
+ * @see OPimAccessBackend
+ *
+ */
+class ODateBookAccessBackend : public OPimAccessBackend<OEvent> {
+public:
+ typedef int UID;
+
+ /**
+ * c'tor without parameter
+ */
+ ODateBookAccessBackend();
+ ~ODateBookAccessBackend();
+
+ /**
+ * This method should return a list of UIDs containing
+ * all events. No filter should be applied
+ * @return list of events
+ */
+ virtual QArray<UID> rawEvents()const = 0;
+
+ /**
+ * This method should return a list of UIDs containing
+ * all repeating events. No filter should be applied
+ * @return list of repeating events
+ */
+ virtual QArray<UID> rawRepeats()const = 0;
+
+ /**
+ * This mthod should return a list of UIDs containing all non
+ * repeating events. No filter should be applied
+ * @return list of nonrepeating events
+ */
+ virtual QArray<UID> nonRepeats() const = 0;
+
+ /**
+ * If you do not want to implement the effectiveEvents methods below
+ * you need to supply it with directNonRepeats.
+ * This method can return empty lists if effectiveEvents is implememted
+ */
+ virtual OEvent::ValueList directNonRepeats() = 0;
+
+ /**
+ * Same as above but return raw repeats!
+ */
+ virtual OEvent::ValueList directRawRepeats() = 0;
+
+ /* is implemented by default but you can reimplement it*/
+ /**
+ * Effective Events are special event occuring during a time frame. This method does calcualte
+ * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method
+ * yourself
+ */
+ virtual OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to );
+
+ /**
+ * this is an overloaded member function
+ * @see effectiveEvents( const QDate& from, const QDate& to )
+ */
+ virtual OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start );
+
+ /**
+ * Effective Events are special event occuring during a time frame. This method does calcualte
+ * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method
+ * yourself
+ */
+ virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to );
+
+ /**
+ * this is an overloaded member function
+ * @see effectiveNonRepeatingEvents( const QDate& from, const QDate& to )
+ */
+ virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start );
+
+private:
+ class Private;
+ Private *d;
+
+};
+
+#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 @@
+/*
+ * SQL Backend for the OPIE-Calender Database.
+ *
+ * Copyright (c) 2003 by Stefan Eilers (Eilers.Stefan@epost.de)
+ *
+ * =====================================================================
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ * =====================================================================
+ * =====================================================================
+ * Version: $Id$
+ * =====================================================================
+ * History:
+ * $Log$
+ * Revision 1.1 2004/11/16 21:46:08 mickeyl
+ * libopie1 goes into unsupported
+ *
+ * Revision 1.4 2004/03/14 13:50:35 alwin
+ * namespace correction
+ *
+ * Revision 1.3 2003/12/22 11:41:39 eilers
+ * Fixing stupid bug, found by sourcode review..
+ *
+ * Revision 1.2 2003/12/22 10:19:26 eilers
+ * Finishing implementation of sql-backend for datebook. But I have to
+ * port the PIM datebook application to use it, before I could debug the
+ * whole stuff.
+ * Thus, PIM-Database backend is finished, but highly experimental. And some
+ * parts are still generic. For instance, the "queryByExample()" methods are
+ * not (or not fully) implemented. Todo: custom-entries not stored.
+ * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular
+ * expression search in the database, which is not supported by sqlite !
+ * Therefore we need either an extended sqlite or a workaround which would
+ * be very slow and memory consuming..
+ *
+ * Revision 1.1 2003/12/08 15:18:12 eilers
+ * Committing unfinished sql implementation before merging to libopie2 starts..
+ *
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qarray.h>
+#include <qstringlist.h>
+
+#include <qpe/global.h>
+
+#include <opie2/osqldriver.h>
+#include <opie2/osqlmanager.h>
+#include <opie2/osqlquery.h>
+
+#include "orecur.h"
+#include "odatebookaccessbackend_sql.h"
+
+using namespace Opie::DB;
+
+
+ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& ,
+ const QString& fileName )
+ : ODateBookAccessBackend(), m_driver( NULL )
+{
+ m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName;
+
+ // Get the standart sql-driver from the OSQLManager..
+ OSQLManager man;
+ m_driver = man.standard();
+ m_driver->setUrl( m_fileName );
+
+ initFields();
+
+ load();
+}
+
+ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() {
+ if( m_driver )
+ delete m_driver;
+}
+
+void ODateBookAccessBackend_SQL::initFields()
+{
+
+ // This map contains the translation of the fieldtype id's to
+ // the names of the table columns
+ m_fieldMap.insert( OEvent::FUid, "uid" );
+ m_fieldMap.insert( OEvent::FCategories, "Categories" );
+ m_fieldMap.insert( OEvent::FDescription, "Description" );
+ m_fieldMap.insert( OEvent::FLocation, "Location" );
+ m_fieldMap.insert( OEvent::FType, "Type" );
+ m_fieldMap.insert( OEvent::FAlarm, "Alarm" );
+ m_fieldMap.insert( OEvent::FSound, "Sound" );
+ m_fieldMap.insert( OEvent::FRType, "RType" );
+ m_fieldMap.insert( OEvent::FRWeekdays, "RWeekdays" );
+ m_fieldMap.insert( OEvent::FRPosition, "RPosition" );
+ m_fieldMap.insert( OEvent::FRFreq, "RFreq" );
+ m_fieldMap.insert( OEvent::FRHasEndDate, "RHasEndDate" );
+ m_fieldMap.insert( OEvent::FREndDate, "REndDate" );
+ m_fieldMap.insert( OEvent::FRCreated, "RCreated" );
+ m_fieldMap.insert( OEvent::FRExceptions, "RExceptions" );
+ m_fieldMap.insert( OEvent::FStart, "Start" );
+ m_fieldMap.insert( OEvent::FEnd, "End" );
+ m_fieldMap.insert( OEvent::FNote, "Note" );
+ m_fieldMap.insert( OEvent::FTimeZone, "TimeZone" );
+ m_fieldMap.insert( OEvent::FRecParent, "RecParent" );
+ m_fieldMap.insert( OEvent::FRecChildren, "Recchildren" );
+
+ // Create a map that maps the column name to the id
+ QMapConstIterator<int, QString> it;
+ for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
+ m_reverseFieldMap.insert( it.data(), it.key() );
+ }
+
+}
+
+bool ODateBookAccessBackend_SQL::load()
+{
+ if (!m_driver->open() )
+ return false;
+
+ // Don't expect that the database exists.
+ // It is save here to create the table, even if it
+ // do exist. ( Is that correct for all databases ?? )
+ QString qu = "create table datebook( uid INTEGER PRIMARY KEY ";
+
+ QMap<int, QString>::Iterator it;
+ for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
+ qu += QString( ",%1 VARCHAR(10)" ).arg( it.data() );
+ }
+ qu += " );";
+
+ qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );";
+
+ qWarning( "command: %s", qu.latin1() );
+
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success )
+ return false;
+
+ update();
+
+ return true;
+}
+
+void ODateBookAccessBackend_SQL::update()
+{
+
+ QString qu = "select uid from datebook";
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ // m_uids.clear();
+ return;
+ }
+
+ m_uids = extractUids( res );
+
+}
+
+bool ODateBookAccessBackend_SQL::reload()
+{
+ return load();
+}
+
+bool ODateBookAccessBackend_SQL::save()
+{
+ return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
+}
+
+QArray<int> ODateBookAccessBackend_SQL::allRecords()const
+{
+ return m_uids;
+}
+
+QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) {
+ return QArray<int>();
+}
+
+void ODateBookAccessBackend_SQL::clear()
+{
+ QString qu = "drop table datebook;";
+ qu += "drop table custom_data;";
+
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+
+ reload();
+}
+
+
+OEvent ODateBookAccessBackend_SQL::find( int uid ) const{
+ QString qu = "select *";
+ qu += "from datebook where uid = " + QString::number(uid);
+
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+
+ OSQLResultItem resItem = res.first();
+
+ // Create Map for date event and insert UID
+ QMap<int,QString> dateEventMap;
+ dateEventMap.insert( OEvent::FUid, QString::number( uid ) );
+
+ // Now insert the data out of the columns into the map.
+ QMapConstIterator<int, QString> it;
+ for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
+ dateEventMap.insert( m_reverseFieldMap[*it], resItem.data( *it ) );
+ }
+
+ // Last step: Put map into date event and return it
+ OEvent retDate( dateEventMap );
+
+ return retDate;
+}
+
+// FIXME: Speed up update of uid's..
+bool ODateBookAccessBackend_SQL::add( const OEvent& ev )
+{
+ QMap<int,QString> eventMap = ev.toMap();
+
+ QString qu = "insert into datebook VALUES( " + QString::number( ev.uid() );
+ QMap<int, QString>::Iterator it;
+ for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){
+ if ( !eventMap[it.key()].isEmpty() )
+ qu += QString( ",\"%1\"" ).arg( eventMap[it.key()] );
+ else
+ qu += QString( ",\"\"" );
+ }
+ qu += " );";
+
+ // Add custom entries
+ int id = 0;
+ QMap<QString, QString> customMap = ev.toExtraMap();
+ for( QMap<QString, QString>::Iterator it = customMap.begin();
+ it != customMap.end(); ++it ){
+ qu += "insert into custom_data VALUES("
+ + QString::number( ev.uid() )
+ + ","
+ + QString::number( id++ )
+ + ",'"
+ + it.key() //.latin1()
+ + "',"
+ + "0" // Priority for future enhancements
+ + ",'"
+ + it.data() //.latin1()
+ + "');";
+ }
+ qWarning("add %s", qu.latin1() );
+
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ return false;
+ }
+
+ // Update list of uid's
+ update();
+
+ return true;
+}
+
+// FIXME: Speed up update of uid's..
+bool ODateBookAccessBackend_SQL::remove( int uid )
+{
+ QString qu = "DELETE from datebook where uid = "
+ + QString::number( uid ) + ";";
+ qu += "DELETE from custom_data where uid = "
+ + QString::number( uid ) + ";";
+
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ return false;
+ }
+
+ // Update list of uid's
+ update();
+
+ return true;
+}
+
+bool ODateBookAccessBackend_SQL::replace( const OEvent& ev )
+{
+ remove( ev.uid() );
+ return add( ev );
+}
+
+QArray<int> ODateBookAccessBackend_SQL::rawEvents()const
+{
+ return allRecords();
+}
+
+QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const
+{
+ QString qu = "select uid from datebook where RType!=\"\" AND RType!=\"NoRepeat\"";
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ QArray<int> nix;
+ return nix;
+ }
+
+ return extractUids( res );
+}
+
+QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const
+{
+ QString qu = "select uid from datebook where RType=\"\" or RType=\"NoRepeat\"";
+ OSQLRawQuery raw( qu );
+ OSQLResult res = m_driver->query( &raw );
+ if ( res.state() != OSQLResult::Success ){
+ QArray<int> nix;
+ return nix;
+ }
+
+ return extractUids( res );
+}
+
+OEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats()
+{
+ QArray<int> nonRepUids = nonRepeats();
+ OEvent::ValueList list;
+
+ for (uint i = 0; i < nonRepUids.count(); ++i ){
+ list.append( find( nonRepUids[i] ) );
+ }
+
+ return list;
+
+}
+OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats()
+{
+ QArray<int> rawRepUids = rawRepeats();
+ OEvent::ValueList list;
+
+ for (uint i = 0; i < rawRepUids.count(); ++i ){
+ list.append( find( rawRepUids[i] ) );
+ }
+
+ return list;
+}
+
+
+QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> null;
+ return null;
+}
+
+/* ===== Private Functions ========================================== */
+
+QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const
+{
+ qWarning("extractUids");
+ QTime t;
+ t.start();
+ OSQLResultItem::ValueList list = res.results();
+ OSQLResultItem::ValueList::Iterator it;
+ QArray<int> ints(list.count() );
+ qWarning(" count = %d", list.count() );
+
+ int i = 0;
+ for (it = list.begin(); it != list.end(); ++it ) {
+ ints[i] = (*it).data("uid").toInt();
+ i++;
+ }
+ qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() );
+
+ return ints;
+
+}
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 @@
+#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H
+#define OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H
+
+#include <qmap.h>
+#include <opie2/osqlresult.h>
+
+#include "odatebookaccessbackend.h"
+
+namespace Opie { namespace DB {
+class OSQLDriver;
+
+}}
+
+/**
+ * This is the default SQL implementation for DateBoook SQL storage
+ * It fully implements the interface
+ * @see ODateBookAccessBackend
+ * @see OPimAccessBackend
+ */
+class ODateBookAccessBackend_SQL : public ODateBookAccessBackend {
+public:
+ ODateBookAccessBackend_SQL( const QString& appName,
+ const QString& fileName = QString::null);
+ ~ODateBookAccessBackend_SQL();
+
+ bool load();
+ bool reload();
+ bool save();
+
+ QArray<int> allRecords()const;
+ QArray<int> matchRegexp(const QRegExp &r) const;
+ QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() );
+ OEvent find( int uid )const;
+ void clear();
+ bool add( const OEvent& ev );
+ bool remove( int uid );
+ bool replace( const OEvent& ev );
+
+ QArray<UID> rawEvents()const;
+ QArray<UID> rawRepeats()const;
+ QArray<UID> nonRepeats()const;
+
+ OEvent::ValueList directNonRepeats();
+ OEvent::ValueList directRawRepeats();
+
+private:
+ bool loadFile();
+ QString m_fileName;
+ QArray<int> m_uids;
+
+ QMap<int, QString> m_fieldMap;
+ QMap<QString, int> m_reverseFieldMap;
+
+ Opie::DB::OSQLDriver* m_driver;
+
+ class Private;
+ Private *d;
+
+ void initFields();
+ void update();
+ QArray<int> extractUids( Opie::DB::OSQLResult& res ) const;
+
+};
+
+#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 @@
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+
+#include <qasciidict.h>
+#include <qfile.h>
+
+#include <qtopia/global.h>
+#include <qtopia/stringutil.h>
+#include <qtopia/timeconversion.h>
+
+#include "opimnotifymanager.h"
+#include "orecur.h"
+#include "otimezone.h"
+#include "odatebookaccessbackend_xml.h"
+
+namespace {
+ // FROM TT again
+char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
+{
+ char needleChar;
+ char haystackChar;
+ if (!needle || !haystack || !hLen || !nLen)
+ return 0;
+
+ const char* hsearch = haystack;
+
+ if ((needleChar = *needle++) != 0) {
+ nLen--; //(to make up for needle++)
+ do {
+ do {
+ if ((haystackChar = *hsearch++) == 0)
+ return (0);
+ if (hsearch >= haystack + hLen)
+ return (0);
+ } while (haystackChar != needleChar);
+ } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
+ hsearch--;
+ }
+ return ((char *)hsearch);
+}
+}
+
+namespace {
+ time_t start, end, created, rp_end;
+ ORecur* rec;
+ ORecur* recur() {
+ if (!rec)
+ rec = new ORecur;
+
+ return rec;
+ }
+ int alarmTime;
+ int snd;
+ enum Attribute{
+ FDescription = 0,
+ FLocation,
+ FCategories,
+ FUid,
+ FType,
+ FAlarm,
+ FSound,
+ FRType,
+ FRWeekdays,
+ FRPosition,
+ FRFreq,
+ FRHasEndDate,
+ FREndDate,
+ FRStart,
+ FREnd,
+ FNote,
+ FCreated, // Should't this be called FRCreated ?
+ FTimeZone,
+ FRecParent,
+ FRecChildren,
+ FExceptions
+ };
+
+ // FIXME: Use OEvent::toMap() here !! (eilers)
+ inline void save( const OEvent& ev, QString& buf ) {
+ qWarning("Saving %d %s", ev.uid(), ev.description().latin1() );
+ buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\"";
+ if (!ev.location().isEmpty() )
+ buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\"";
+
+ buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\"";
+ buf += " uid=\"" + QString::number( ev.uid() ) + "\"";
+
+ if (ev.isAllDay() )
+ buf += " type=\"AllDay\""; // is that all ?? (eilers)
+
+ if (ev.hasNotifiers() ) {
+ OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first
+ int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60;
+ buf += " alarm=\"" + QString::number(minutes) + "\" sound=\"";
+ if ( alarm.sound() == OPimAlarm::Loud )
+ buf += "loud";
+ else
+ buf += "silent";
+ buf += "\"";
+ }
+ if ( ev.hasRecurrence() ) {
+ buf += ev.recurrence().toString();
+ }
+
+ /*
+ * fscking timezones :) well, we'll first convert
+ * the QDateTime to a QDateTime in UTC time
+ * and then we'll create a nice time_t
+ */
+ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
+ buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\"";
+ buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\"";
+ if (!ev.note().isEmpty() ) {
+ buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\"";
+ }
+
+ buf += " timezone=\"";
+ if ( ev.timeZone().isEmpty() )
+ buf += "None";
+ else
+ buf += ev.timeZone();
+ buf += "\"";
+
+ if (ev.parent() != 0 ) {
+ buf += " recparent=\""+QString::number(ev.parent() )+"\"";
+ }
+
+ if (ev.children().count() != 0 ) {
+ QArray<int> children = ev.children();
+ buf += " recchildren=\"";
+ for ( uint i = 0; i < children.count(); i++ ) {
+ if ( i != 0 ) buf += " ";
+ buf += QString::number( children[i] );
+ }
+ buf+= "\"";
+ }
+
+ // skip custom writing
+ }
+
+ inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) {
+ QMap<int, OEvent>::ConstIterator it;
+ QString buf;
+ QCString str;
+ int total_written;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ buf = "<event";
+ save( it.data(), buf );
+ buf += " />\n";
+ str = buf.utf8();
+
+ total_written = file.writeBlock(str.data(), str.length() );
+ if ( total_written != int(str.length() ) )
+ return false;
+ }
+ return true;
+ }
+}
+
+ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& ,
+ const QString& fileName )
+ : ODateBookAccessBackend() {
+ m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName;
+ m_changed = false;
+}
+ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() {
+}
+bool ODateBookAccessBackend_XML::load() {
+ return loadFile();
+}
+bool ODateBookAccessBackend_XML::reload() {
+ clear();
+ return load();
+}
+bool ODateBookAccessBackend_XML::save() {
+ if (!m_changed) return true;
+
+ int total_written;
+ QString strFileNew = m_name + ".new";
+
+ QFile f( strFileNew );
+ if (!f.open( IO_WriteOnly | IO_Raw ) ) return false;
+
+ QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
+ buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
+ buf += "<events>\n";
+ QCString str = buf.utf8();
+ total_written = f.writeBlock( str.data(), str.length() );
+ if ( total_written != int(str.length() ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+
+ if (!forAll( m_raw, f ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+ if (!forAll( m_rep, f ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+
+ buf = "</events>\n</DATEBOOK>\n";
+ str = buf.utf8();
+ total_written = f.writeBlock( str.data(), str.length() );
+ if ( total_written != int(str.length() ) ) {
+ f.close();
+ QFile::remove( strFileNew );
+ return false;
+ }
+ f.close();
+
+ if ( ::rename( strFileNew, m_name ) < 0 ) {
+ QFile::remove( strFileNew );
+ return false;
+ }
+
+ m_changed = false;
+ return true;
+}
+QArray<int> ODateBookAccessBackend_XML::allRecords()const {
+ QArray<int> ints( m_raw.count()+ m_rep.count() );
+ uint i = 0;
+ QMap<int, OEvent>::ConstIterator it;
+
+ for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
+ ints[i] = it.key();
+ i++;
+ }
+ for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
+ ints[i] = it.key();
+ i++;
+ }
+
+ return ints;
+}
+QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) {
+ return QArray<int>();
+}
+void ODateBookAccessBackend_XML::clear() {
+ m_changed = true;
+ m_raw.clear();
+ m_rep.clear();
+}
+OEvent ODateBookAccessBackend_XML::find( int uid ) const{
+ if ( m_raw.contains( uid ) )
+ return m_raw[uid];
+ else
+ return m_rep[uid];
+}
+bool ODateBookAccessBackend_XML::add( const OEvent& ev ) {
+ m_changed = true;
+ if (ev.hasRecurrence() )
+ m_rep.insert( ev.uid(), ev );
+ else
+ m_raw.insert( ev.uid(), ev );
+
+ return true;
+}
+bool ODateBookAccessBackend_XML::remove( int uid ) {
+ m_changed = true;
+ m_rep.remove( uid );
+ m_rep.remove( uid );
+
+ return true;
+}
+bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) {
+ replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers)
+ return add( ev );
+}
+QArray<int> ODateBookAccessBackend_XML::rawEvents()const {
+ return allRecords();
+}
+QArray<int> ODateBookAccessBackend_XML::rawRepeats()const {
+ QArray<int> ints( m_rep.count() );
+ uint i = 0;
+ QMap<int, OEvent>::ConstIterator it;
+
+ for ( it = m_rep.begin(); it != m_rep.end(); ++it ) {
+ ints[i] = it.key();
+ i++;
+ }
+
+ return ints;
+}
+QArray<int> ODateBookAccessBackend_XML::nonRepeats()const {
+ QArray<int> ints( m_raw.count() );
+ uint i = 0;
+ QMap<int, OEvent>::ConstIterator it;
+
+ for ( it = m_raw.begin(); it != m_raw.end(); ++it ) {
+ ints[i] = it.key();
+ i++;
+ }
+
+ return ints;
+}
+OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() {
+ OEvent::ValueList list;
+ QMap<int, OEvent>::ConstIterator it;
+ for (it = m_raw.begin(); it != m_raw.end(); ++it )
+ list.append( it.data() );
+
+ return list;
+}
+OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() {
+ OEvent::ValueList list;
+ QMap<int, OEvent>::ConstIterator it;
+ for (it = m_rep.begin(); it != m_rep.end(); ++it )
+ list.append( it.data() );
+
+ return list;
+}
+
+// FIXME: Use OEvent::fromMap() (eilers)
+bool ODateBookAccessBackend_XML::loadFile() {
+ m_changed = false;
+
+ int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY );
+ if ( fd < 0 ) return false;
+
+ struct stat attribute;
+ if ( ::fstat(fd, &attribute ) == -1 ) {
+ ::close( fd );
+ return false;
+ }
+ void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 );
+ if ( map_addr == ( (caddr_t)-1) ) {
+ ::close( fd );
+ return false;
+ }
+
+ ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL );
+ ::close( fd );
+
+ QAsciiDict<int> dict(FExceptions+1);
+ dict.setAutoDelete( true );
+ dict.insert( "description", new int(FDescription) );
+ dict.insert( "location", new int(FLocation) );
+ dict.insert( "categories", new int(FCategories) );
+ dict.insert( "uid", new int(FUid) );
+ dict.insert( "type", new int(FType) );
+ dict.insert( "alarm", new int(FAlarm) );
+ dict.insert( "sound", new int(FSound) );
+ dict.insert( "rtype", new int(FRType) );
+ dict.insert( "rweekdays", new int(FRWeekdays) );
+ dict.insert( "rposition", new int(FRPosition) );
+ dict.insert( "rfreq", new int(FRFreq) );
+ dict.insert( "rhasenddate", new int(FRHasEndDate) );
+ dict.insert( "enddt", new int(FREndDate) );
+ dict.insert( "start", new int(FRStart) );
+ dict.insert( "end", new int(FREnd) );
+ dict.insert( "note", new int(FNote) );
+ dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ??
+ dict.insert( "recparent", new int(FRecParent) );
+ dict.insert( "recchildren", new int(FRecChildren) );
+ dict.insert( "exceptions", new int(FExceptions) );
+ dict.insert( "timezone", new int(FTimeZone) );
+
+ char* dt = (char*)map_addr;
+ int len = attribute.st_size;
+ int i = 0;
+ char* point;
+ const char* collectionString = "<event ";
+ int strLen = ::strlen(collectionString);
+ int *find;
+ while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) {
+ i = point -dt;
+ i+= strLen;
+
+ alarmTime = -1;
+ snd = 0; // silent
+
+ OEvent ev;
+ rec = 0;
+
+ while ( TRUE ) {
+ while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
+ ++i;
+ if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
+ break;
+
+
+ // we have another attribute, read it.
+ int j = i;
+ while ( j < len && dt[j] != '=' )
+ ++j;
+ QCString attr( dt+i, j-i+1);
+
+ i = ++j; // skip =
+
+ // find the start of quotes
+ while ( i < len && dt[i] != '"' )
+ ++i;
+ j = ++i;
+
+ bool haveUtf = FALSE;
+ bool haveEnt = FALSE;
+ while ( j < len && dt[j] != '"' ) {
+ if ( ((unsigned char)dt[j]) > 0x7f )
+ haveUtf = TRUE;
+ if ( dt[j] == '&' )
+ haveEnt = TRUE;
+ ++j;
+ }
+ if ( i == j ) {
+ // empty value
+ i = j + 1;
+ continue;
+ }
+
+ QCString value( dt+i, j-i+1 );
+ i = j + 1;
+
+ QString str = (haveUtf ? QString::fromUtf8( value )
+ : QString::fromLatin1( value ) );
+ if ( haveEnt )
+ str = Qtopia::plainString( str );
+
+ /*
+ * add key + value
+ */
+ find = dict[attr.data()];
+ if (!find)
+ ev.setCustomField( attr, str );
+ else {
+ setField( ev, *find, str );
+ }
+ }
+ /* time to finalize */
+ finalizeRecord( ev );
+ delete rec;
+ }
+ ::munmap(map_addr, attribute.st_size );
+ m_changed = false; // changed during add
+
+ return true;
+}
+
+// FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers)
+void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
+ /* AllDay is alway in UTC */
+ if ( ev.isAllDay() ) {
+ OTimeZone utc = OTimeZone::utc();
+ ev.setStartDateTime( utc.fromUTCDateTime( start ) );
+ ev.setEndDateTime ( utc.fromUTCDateTime( end ) );
+ ev.setTimeZone( "UTC"); // make sure it is really utc
+ }else {
+ /* to current date time */
+ // qWarning(" Start is %d", start );
+ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
+ QDateTime date = zone.toDateTime( start );
+ qWarning(" Start is %s", date.toString().latin1() );
+ ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
+
+ date = zone.toDateTime( end );
+ ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
+ }
+ if ( rec && rec->doesRecur() ) {
+ OTimeZone utc = OTimeZone::utc();
+ ORecur recu( *rec ); // call copy c'tor;
+ recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() );
+ recu.setCreatedDateTime( utc.fromUTCDateTime( created ) );
+ recu.setStart( ev.startDateTime().date() );
+ ev.setRecurrence( recu );
+ }
+
+ if (alarmTime != -1 ) {
+ QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 );
+ OPimAlarm al( snd , dt );
+ ev.notifiers().add( al );
+ }
+ if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) {
+ qWarning("already contains assign uid");
+ ev.setUid( 1 );
+ }
+ qWarning("addind %d %s", ev.uid(), ev.description().latin1() );
+ if ( ev.hasRecurrence() )
+ m_rep.insert( ev.uid(), ev );
+ else
+ m_raw.insert( ev.uid(), ev );
+
+}
+void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) {
+// qWarning(" setting %s", value.latin1() );
+ switch( id ) {
+ case FDescription:
+ e.setDescription( value );
+ break;
+ case FLocation:
+ e.setLocation( value );
+ break;
+ case FCategories:
+ e.setCategories( e.idsFromString( value ) );
+ break;
+ case FUid:
+ e.setUid( value.toInt() );
+ break;
+ case FType:
+ if ( value == "AllDay" ) {
+ e.setAllDay( true );
+ e.setTimeZone( "UTC" );
+ }
+ break;
+ case FAlarm:
+ alarmTime = value.toInt();
+ break;
+ case FSound:
+ snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent;
+ break;
+ // recurrence stuff
+ case FRType:
+ if ( value == "Daily" )
+ recur()->setType( ORecur::Daily );
+ else if ( value == "Weekly" )
+ recur()->setType( ORecur::Weekly);
+ else if ( value == "MonthlyDay" )
+ recur()->setType( ORecur::MonthlyDay );
+ else if ( value == "MonthlyDate" )
+ recur()->setType( ORecur::MonthlyDate );
+ else if ( value == "Yearly" )
+ recur()->setType( ORecur::Yearly );
+ else
+ recur()->setType( ORecur::NoRepeat );
+ break;
+ case FRWeekdays:
+ recur()->setDays( value.toInt() );
+ break;
+ case FRPosition:
+ recur()->setPosition( value.toInt() );
+ break;
+ case FRFreq:
+ recur()->setFrequency( value.toInt() );
+ break;
+ case FRHasEndDate:
+ recur()->setHasEndDate( value.toInt() );
+ break;
+ case FREndDate: {
+ rp_end = (time_t) value.toLong();
+ break;
+ }
+ case FRStart: {
+ start = (time_t) value.toLong();
+ break;
+ }
+ case FREnd: {
+ end = ( (time_t) value.toLong() );
+ break;
+ }
+ case FNote:
+ e.setNote( value );
+ break;
+ case FCreated:
+ created = value.toInt();
+ break;
+ case FRecParent:
+ e.setParent( value.toInt() );
+ break;
+ case FRecChildren:{
+ QStringList list = QStringList::split(' ', value );
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ e.addChild( (*it).toInt() );
+ }
+ }
+ break;
+ case FExceptions:{
+ QStringList list = QStringList::split(' ', value );
+ for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() );
+ qWarning("adding exception %s", date.toString().latin1() );
+ recur()->exceptions().append( date );
+ }
+ }
+ break;
+ case FTimeZone:
+ if ( value != "None" )
+ e.setTimeZone( value );
+ break;
+ default:
+ break;
+ }
+}
+QArray<int> ODateBookAccessBackend_XML::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> m_currentQuery( m_raw.count()+ m_rep.count() );
+ uint arraycounter = 0;
+ QMap<int, OEvent>::ConstIterator it;
+
+ for ( it = m_raw.begin(); it != m_raw.end(); ++it )
+ if ( it.data().match( r ) )
+ m_currentQuery[arraycounter++] = it.data().uid();
+ for ( it = m_rep.begin(); it != m_rep.end(); ++it )
+ if ( it.data().match( r ) )
+ m_currentQuery[arraycounter++] = it.data().uid();
+
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+}
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 @@
+#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
+#define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H
+
+#include <qmap.h>
+
+#include "odatebookaccessbackend.h"
+
+/**
+ * This is the default XML implementation for DateBoook XML storage
+ * It fully implements the interface
+ * @see ODateBookAccessBackend
+ * @see OPimAccessBackend
+ */
+class ODateBookAccessBackend_XML : public ODateBookAccessBackend {
+public:
+ ODateBookAccessBackend_XML( const QString& appName,
+ const QString& fileName = QString::null);
+ ~ODateBookAccessBackend_XML();
+
+ bool load();
+ bool reload();
+ bool save();
+
+ QArray<int> allRecords()const;
+ QArray<int> matchRegexp(const QRegExp &r) const;
+ QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() );
+ OEvent find( int uid )const;
+ void clear();
+ bool add( const OEvent& ev );
+ bool remove( int uid );
+ bool replace( const OEvent& ev );
+
+ QArray<UID> rawEvents()const;
+ QArray<UID> rawRepeats()const;
+ QArray<UID> nonRepeats()const;
+
+ OEvent::ValueList directNonRepeats();
+ OEvent::ValueList directRawRepeats();
+
+private:
+ bool m_changed :1 ;
+ bool loadFile();
+ inline void finalizeRecord( OEvent& ev );
+ inline void setField( OEvent&, int field, const QString& val );
+ QString m_name;
+ QMap<int, OEvent> m_raw;
+ QMap<int, OEvent> m_rep;
+
+ struct Data;
+ Data* data;
+ class Private;
+ Private *d;
+};
+
+#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 @@
+#include <qshared.h>
+#include <qarray.h>
+
+#include <qpe/palmtopuidgen.h>
+#include <qpe/categories.h>
+#include <qpe/stringutil.h>
+
+#include "orecur.h"
+#include "opimresolver.h"
+#include "opimnotifymanager.h"
+
+#include "oevent.h"
+
+int OCalendarHelper::week( const QDate& date) {
+ // Calculates the week this date is in within that
+ // month. Equals the "row" is is in in the month view
+ int week = 1;
+ QDate tmp( date.year(), date.month(), 1 );
+ if ( date.dayOfWeek() < tmp.dayOfWeek() )
+ ++week;
+
+ week += ( date.day() - 1 ) / 7;
+
+ return week;
+}
+int OCalendarHelper::ocurrence( const QDate& date) {
+ // calculates the number of occurrances of this day of the
+ // week till the given date (e.g 3rd Wednesday of the month)
+ return ( date.day() - 1 ) / 7 + 1;
+}
+int OCalendarHelper::dayOfWeek( char day ) {
+ int dayOfWeek = 1;
+ char i = ORecur::MON;
+ while ( !( i & day ) && i <= ORecur::SUN ) {
+ i <<= 1;
+ ++dayOfWeek;
+ }
+ return dayOfWeek;
+}
+int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) {
+ return ( second.year() - first.year() ) * 12 +
+ second.month() - first.month();
+}
+
+struct OEvent::Data : public QShared {
+ Data() : QShared() {
+ child = 0;
+ recur = 0;
+ manager = 0;
+ isAllDay = false;
+ parent = 0;
+ }
+ ~Data() {
+ delete manager;
+ delete recur;
+ }
+ QString description;
+ QString location;
+ OPimNotifyManager* manager;
+ ORecur* recur;
+ QString note;
+ QDateTime created;
+ QDateTime start;
+ QDateTime end;
+ bool isAllDay : 1;
+ QString timezone;
+ QArray<int>* child;
+ int parent;
+};
+
+OEvent::OEvent( int uid )
+ : OPimRecord( uid ) {
+ data = new Data;
+}
+OEvent::OEvent( const OEvent& ev)
+ : OPimRecord( ev ), data( ev.data )
+{
+ data->ref();
+}
+
+OEvent::OEvent( const QMap<int, QString> map )
+ : OPimRecord( 0 )
+{
+ data = new Data;
+
+ fromMap( map );
+}
+
+OEvent::~OEvent() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0;
+ }
+}
+OEvent& OEvent::operator=( const OEvent& ev) {
+ if ( this == &ev ) return *this;
+
+ OPimRecord::operator=( ev );
+ ev.data->ref();
+ deref();
+ data = ev.data;
+
+
+ return *this;
+}
+QString OEvent::description()const {
+ return data->description;
+}
+void OEvent::setDescription( const QString& description ) {
+ changeOrModify();
+ data->description = description;
+}
+void OEvent::setLocation( const QString& loc ) {
+ changeOrModify();
+ data->location = loc;
+}
+QString OEvent::location()const {
+ return data->location;
+}
+OPimNotifyManager &OEvent::notifiers()const {
+ // I hope we can skip the changeOrModify here
+ // the notifier should take care of it
+ // and OPimNotify is shared too
+ if (!data->manager )
+ data->manager = new OPimNotifyManager;
+
+ return *data->manager;
+}
+bool OEvent::hasNotifiers()const {
+ if (!data->manager )
+ return false;
+ if (data->manager->reminders().isEmpty() &&
+ data->manager->alarms().isEmpty() )
+ return false;
+
+ return true;
+}
+ORecur OEvent::recurrence()const {
+ if (!data->recur)
+ data->recur = new ORecur;
+
+ return *data->recur;
+}
+void OEvent::setRecurrence( const ORecur& rec) {
+ changeOrModify();
+ if (data->recur )
+ (*data->recur) = rec;
+ else
+ data->recur = new ORecur( rec );
+}
+bool OEvent::hasRecurrence()const {
+ if (!data->recur ) return false;
+ return data->recur->doesRecur();
+}
+QString OEvent::note()const {
+ return data->note;
+}
+void OEvent::setNote( const QString& note ) {
+ changeOrModify();
+ data->note = note;
+}
+QDateTime OEvent::createdDateTime()const {
+ return data->created;
+}
+void OEvent::setCreatedDateTime( const QDateTime& time ) {
+ changeOrModify();
+ data->created = time;
+}
+QDateTime OEvent::startDateTime()const {
+ if ( data->isAllDay )
+ return QDateTime( data->start.date(), QTime(0, 0, 0 ) );
+ return data->start;
+}
+QDateTime OEvent::startDateTimeInZone()const {
+ /* if no timezone, or all day event or if the current and this timeZone match... */
+ if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return startDateTime();
+
+ OTimeZone zone(data->timezone );
+ return zone.toDateTime( data->start, OTimeZone::current() );
+}
+void OEvent::setStartDateTime( const QDateTime& dt ) {
+ changeOrModify();
+ data->start = dt;
+}
+QDateTime OEvent::endDateTime()const {
+ /*
+ * if all Day event the end time needs
+ * to be on the same day as the start
+ */
+ if ( data->isAllDay )
+ return QDateTime( data->start.date(), QTime(23, 59, 59 ) );
+ return data->end;
+}
+QDateTime OEvent::endDateTimeInZone()const {
+ /* if no timezone, or all day event or if the current and this timeZone match... */
+ if (data->timezone.isEmpty() || data->isAllDay || data->timezone == OTimeZone::current().timeZone() ) return endDateTime();
+
+ OTimeZone zone(data->timezone );
+ return zone.toDateTime( data->end, OTimeZone::current() );
+}
+void OEvent::setEndDateTime( const QDateTime& dt ) {
+ changeOrModify();
+ data->end = dt;
+}
+bool OEvent::isMultipleDay()const {
+ return data->end.date().day() - data->start.date().day();
+}
+bool OEvent::isAllDay()const {
+ return data->isAllDay;
+}
+void OEvent::setAllDay( bool allDay ) {
+ changeOrModify();
+ data->isAllDay = allDay;
+ if (allDay ) data->timezone = "UTC";
+}
+void OEvent::setTimeZone( const QString& tz ) {
+ changeOrModify();
+ data->timezone = tz;
+}
+QString OEvent::timeZone()const {
+ if (data->isAllDay ) return QString::fromLatin1("UTC");
+ return data->timezone;
+}
+bool OEvent::match( const QRegExp& re )const {
+ if ( re.match( data->description ) != -1 ){
+ setLastHitField( Qtopia::DatebookDescription );
+ return true;
+ }
+ if ( re.match( data->note ) != -1 ){
+ setLastHitField( Qtopia::Note );
+ return true;
+ }
+ if ( re.match( data->location ) != -1 ){
+ setLastHitField( Qtopia::Location );
+ return true;
+ }
+ if ( re.match( data->start.toString() ) != -1 ){
+ setLastHitField( Qtopia::StartDateTime );
+ return true;
+ }
+ if ( re.match( data->end.toString() ) != -1 ){
+ setLastHitField( Qtopia::EndDateTime );
+ return true;
+ }
+ return false;
+}
+QString OEvent::toRichText()const {
+ QString text, value;
+
+ // description
+ text += "<b><h3><img src=\"datebook/DateBook\">";
+ if ( !description().isEmpty() ) {
+ text += Qtopia::escapeString(description() ).replace(QRegExp( "[\n]"), "" );
+ }
+ text += "</h3></b><br><hr><br>";
+
+ // location
+ if ( !(value = location()).isEmpty() ) {
+ text += "<b>" + QObject::tr( "Location:" ) + "</b> ";
+ text += Qtopia::escapeString(value) + "<br>";
+ }
+
+ // all day event
+ if ( isAllDay() ) {
+ text += "<b><i>" + QObject::tr( "This is an all day event" ) + "</i></b><br>";
+ }
+ // multiple day event
+ else if ( isMultipleDay () ) {
+ text += "<b><i>" + QObject::tr( "This is a multiple day event" ) + "</i></b><br>";
+ }
+ // start & end times
+ else {
+ // start time
+ if ( startDateTime().isValid() ) {
+ text += "<b>" + QObject::tr( "Start:") + "</b> ";
+ text += Qtopia::escapeString(startDateTime().toString() ).
+ replace(QRegExp( "[\n]"), "<br>" ) + "<br>";
+ }
+
+ // end time
+ if ( endDateTime().isValid() ) {
+ text += "<b>" + QObject::tr( "End:") + "</b> ";
+ text += Qtopia::escapeString(endDateTime().toString() ).
+ replace(QRegExp( "[\n]"), "<br>" ) + "<br>";
+ }
+ }
+
+ // categories
+ if ( categoryNames("Calendar").count() ){
+ text += "<b>" + QObject::tr( "Category:") + "</b> ";
+ text += categoryNames("Calendar").join(", ");
+ text += "<br>";
+ }
+
+ //notes
+ if ( !note().isEmpty() ) {
+ text += "<b>" + QObject::tr( "Note:") + "</b><br>";
+ text += note();
+// text += Qtopia::escapeString(note() ).
+// replace(QRegExp( "[\n]"), "<br>" ) + "<br>";
+ }
+ return text;
+}
+QString OEvent::toShortText()const {
+ QString text;
+ text += QString::number( startDateTime().date().day() );
+ text += ".";
+ text += QString::number( startDateTime().date().month() );
+ text += ".";
+ text += QString::number( startDateTime().date().year() );
+ text += " ";
+ text += QString::number( startDateTime().time().hour() );
+ text += ":";
+ text += QString::number( startDateTime().time().minute() );
+ text += " - ";
+ text += description();
+ return text;
+}
+QString OEvent::type()const {
+ return QString::fromLatin1("OEvent");
+}
+QString OEvent::recordField( int /*id */ )const {
+ return QString::null;
+}
+int OEvent::rtti() {
+ return OPimResolver::DateBook;
+}
+bool OEvent::loadFromStream( QDataStream& ) {
+ return true;
+}
+bool OEvent::saveToStream( QDataStream& )const {
+ return true;
+}
+void OEvent::changeOrModify() {
+ if ( data->count != 1 ) {
+ data->deref();
+ Data* d2 = new Data;
+ d2->description = data->description;
+ d2->location = data->location;
+
+ if (data->manager )
+ d2->manager = new OPimNotifyManager( *data->manager );
+
+ if ( data->recur )
+ d2->recur = new ORecur( *data->recur );
+
+ d2->note = data->note;
+ d2->created = data->created;
+ d2->start = data->start;
+ d2->end = data->end;
+ d2->isAllDay = data->isAllDay;
+ d2->timezone = data->timezone;
+ d2->parent = data->parent;
+
+ if ( data->child ) {
+ d2->child = new QArray<int>( *data->child );
+ d2->child->detach();
+ }
+
+ data = d2;
+ }
+}
+void OEvent::deref() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0;
+ }
+}
+// Exporting Event data to map. Using the same
+// encoding as ODateBookAccessBackend_xml does..
+// Thus, we could remove the stuff there and use this
+// for it and for all other places..
+// Encoding should happen at one place, only ! (eilers)
+QMap<int, QString> OEvent::toMap()const {
+ QMap<int, QString> retMap;
+
+ retMap.insert( OEvent::FUid, QString::number( uid() ) );
+ retMap.insert( OEvent::FCategories, Qtopia::escapeString( Qtopia::Record::idsToString( categories() ) ));
+ retMap.insert( OEvent::FDescription, Qtopia::escapeString( description() ) );
+ retMap.insert( OEvent::FLocation, Qtopia::escapeString( location() ) );
+ retMap.insert( OEvent::FType, isAllDay() ? "AllDay" : "" );
+ OPimAlarm alarm = notifiers().alarms()[0];
+ retMap.insert( OEvent::FAlarm, QString::number( alarm.dateTime().secsTo( startDateTime() ) / 60 ) );
+ retMap.insert( OEvent::FSound, (alarm.sound() == OPimAlarm::Loud) ? "loud" : "silent" );
+
+ OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() );
+ retMap.insert( OEvent::FStart, QString::number( zone.fromUTCDateTime( zone.toDateTime( startDateTime(), OTimeZone::utc() ) ) ) );
+ retMap.insert( OEvent::FEnd, QString::number( zone.fromUTCDateTime( zone.toDateTime( endDateTime(), OTimeZone::utc() ) ) ) );
+ retMap.insert( OEvent::FNote, Qtopia::escapeString( note() ) );
+ retMap.insert( OEvent::FTimeZone, timeZone().isEmpty() ? QString( "None" ) : timeZone() );
+ if( parent() )
+ retMap.insert( OEvent::FRecParent, QString::number( parent() ) );
+ if( children().count() ){
+ QArray<int> childr = children();
+ QString buf;
+ for ( uint i = 0; i < childr.count(); i++ ) {
+ if ( i != 0 ) buf += " ";
+ buf += QString::number( childr[i] );
+ }
+ retMap.insert( OEvent::FRecChildren, buf );
+ }
+
+ // Add recurrence stuff
+ if( hasRecurrence() ){
+ ORecur recur = recurrence();
+ QMap<int, QString> recFields = recur.toMap();
+ retMap.insert( OEvent::FRType, recFields[ORecur::RType] );
+ retMap.insert( OEvent::FRWeekdays, recFields[ORecur::RWeekdays] );
+ retMap.insert( OEvent::FRPosition, recFields[ORecur::RPosition] );
+ retMap.insert( OEvent::FRFreq, recFields[ORecur::RFreq] );
+ retMap.insert( OEvent::FRHasEndDate, recFields[ORecur::RHasEndDate] );
+ retMap.insert( OEvent::FREndDate, recFields[ORecur::EndDate] );
+ retMap.insert( OEvent::FRCreated, recFields[ORecur::Created] );
+ retMap.insert( OEvent::FRExceptions, recFields[ORecur::Exceptions] );
+ } else {
+ ORecur recur = recurrence();
+ QMap<int, QString> recFields = recur.toMap();
+ retMap.insert( OEvent::FRType, recFields[ORecur::RType] );
+ }
+
+ return retMap;
+}
+
+void OEvent::fromMap( const QMap<int, QString>& map )
+{
+
+ // We just want to set the UID if it is really stored.
+ if ( !map[OEvent::FUid].isEmpty() )
+ setUid( map[OEvent::FUid].toInt() );
+
+ setCategories( idsFromString( map[OEvent::FCategories] ) );
+ setDescription( map[OEvent::FDescription] );
+ setLocation( map[OEvent::FLocation] );
+
+ if ( map[OEvent::FType] == "AllDay" )
+ setAllDay( true );
+ else
+ setAllDay( false );
+
+ int alarmTime = -1;
+ if( !map[OEvent::FAlarm].isEmpty() )
+ alarmTime = map[OEvent::FAlarm].toInt();
+
+ int sound = ( ( map[OEvent::FSound] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent );
+ if ( ( alarmTime != -1 ) ){
+ QDateTime dt = startDateTime().addSecs( -1*alarmTime*60 );
+ OPimAlarm al( sound , dt );
+ notifiers().add( al );
+ }
+ if ( !map[OEvent::FTimeZone].isEmpty() && ( map[OEvent::FTimeZone] != "None" ) ){
+ setTimeZone( map[OEvent::FTimeZone] );
+ }
+
+ time_t start = (time_t) map[OEvent::FStart].toLong();
+ time_t end = (time_t) map[OEvent::FEnd].toLong();
+
+ /* AllDay is always in UTC */
+ if ( isAllDay() ) {
+ OTimeZone utc = OTimeZone::utc();
+ setStartDateTime( utc.fromUTCDateTime( start ) );
+ setEndDateTime ( utc.fromUTCDateTime( end ) );
+ setTimeZone( "UTC"); // make sure it is really utc
+ }else {
+ /* to current date time */
+ // qWarning(" Start is %d", start );
+ OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() );
+ QDateTime date = zone.toDateTime( start );
+ qWarning(" Start is %s", date.toString().latin1() );
+ setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
+
+ date = zone.toDateTime( end );
+ setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
+ }
+
+ if ( !map[OEvent::FRecParent].isEmpty() )
+ setParent( map[OEvent::FRecParent].toInt() );
+
+ if ( !map[OEvent::FRecChildren].isEmpty() ){
+ QStringList list = QStringList::split(' ', map[OEvent::FRecChildren] );
+ for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
+ addChild( (*it).toInt() );
+ }
+ }
+
+ // Fill recurrence stuff and put it directly into the ORecur-Object using fromMap..
+ if( !map[OEvent::FRType].isEmpty() ){
+ QMap<int, QString> recFields;
+ recFields.insert( ORecur::RType, map[OEvent::FRType] );
+ recFields.insert( ORecur::RWeekdays, map[OEvent::FRWeekdays] );
+ recFields.insert( ORecur::RPosition, map[OEvent::FRPosition] );
+ recFields.insert( ORecur::RFreq, map[OEvent::FRFreq] );
+ recFields.insert( ORecur::RHasEndDate, map[OEvent::FRHasEndDate] );
+ recFields.insert( ORecur::EndDate, map[OEvent::FREndDate] );
+ recFields.insert( ORecur::Created, map[OEvent::FRCreated] );
+ recFields.insert( ORecur::Exceptions, map[OEvent::FRExceptions] );
+ ORecur recur( recFields );
+ setRecurrence( recur );
+ }
+
+}
+
+
+int OEvent::parent()const {
+ return data->parent;
+}
+void OEvent::setParent( int uid ) {
+ changeOrModify();
+ data->parent = uid;
+}
+QArray<int> OEvent::children() const{
+ if (!data->child) return QArray<int>();
+ else
+ return data->child->copy();
+}
+void OEvent::setChildren( const QArray<int>& arr ) {
+ changeOrModify();
+ if (data->child) delete data->child;
+
+ data->child = new QArray<int>( arr );
+ data->child->detach();
+}
+void OEvent::addChild( int uid ) {
+ changeOrModify();
+ if (!data->child ) {
+ data->child = new QArray<int>(1);
+ (*data->child)[0] = uid;
+ }else{
+ int count = data->child->count();
+ data->child->resize( count + 1 );
+ (*data->child)[count] = uid;
+ }
+}
+void OEvent::removeChild( int uid ) {
+ if (!data->child || !data->child->contains( uid ) ) return;
+ changeOrModify();
+ QArray<int> newAr( data->child->count() - 1 );
+ int j = 0;
+ uint count = data->child->count();
+ for ( uint i = 0; i < count; i++ ) {
+ if ( (*data->child)[i] != uid ) {
+ newAr[j] = (*data->child)[i];
+ j++;
+ }
+ }
+ (*data->child) = newAr;
+}
+struct OEffectiveEvent::Data : public QShared {
+ Data() : QShared() {
+ }
+ OEvent event;
+ QDate date;
+ QTime start, end;
+ QDate startDate, endDate;
+ bool dates : 1;
+};
+
+OEffectiveEvent::OEffectiveEvent() {
+ data = new Data;
+ data->date = QDate::currentDate();
+ data->start = data->end = QTime::currentTime();
+ data->dates = false;
+}
+OEffectiveEvent::OEffectiveEvent( const OEvent& ev, const QDate& startDate,
+ Position pos ) {
+ data = new Data;
+ data->event = ev;
+ data->date = startDate;
+ if ( pos & Start )
+ data->start = ev.startDateTime().time();
+ else
+ data->start = QTime( 0, 0, 0 );
+
+ if ( pos & End )
+ data->end = ev.endDateTime().time();
+ else
+ data->end = QTime( 23, 59, 59 );
+
+ data->dates = false;
+}
+OEffectiveEvent::OEffectiveEvent( const OEffectiveEvent& ev) {
+ data = ev.data;
+ data->ref();
+}
+OEffectiveEvent::~OEffectiveEvent() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0;
+ }
+}
+OEffectiveEvent& OEffectiveEvent::operator=( const OEffectiveEvent& ev ) {
+ if ( *this == ev ) return *this;
+
+ ev.data->ref();
+ deref();
+ data = ev.data;
+
+ return *this;
+}
+
+void OEffectiveEvent::setStartTime( const QTime& ti) {
+ changeOrModify();
+ data->start = ti;
+}
+void OEffectiveEvent::setEndTime( const QTime& en) {
+ changeOrModify();
+ data->end = en;
+}
+void OEffectiveEvent::setEvent( const OEvent& ev) {
+ changeOrModify();
+ data->event = ev;
+}
+void OEffectiveEvent::setDate( const QDate& da) {
+ changeOrModify();
+ data->date = da;
+}
+void OEffectiveEvent::setEffectiveDates( const QDate& from,
+ const QDate& to ) {
+ if (!from.isValid() ) {
+ data->dates = false;
+ return;
+ }
+
+ data->startDate = from;
+ data->endDate = to;
+}
+QString OEffectiveEvent::description()const {
+ return data->event.description();
+}
+QString OEffectiveEvent::location()const {
+ return data->event.location();
+}
+QString OEffectiveEvent::note()const {
+ return data->event.note();
+}
+OEvent OEffectiveEvent::event()const {
+ return data->event;
+}
+QTime OEffectiveEvent::startTime()const {
+ return data->start;
+}
+QTime OEffectiveEvent::endTime()const {
+ return data->end;
+}
+QDate OEffectiveEvent::date()const {
+ return data->date;
+}
+int OEffectiveEvent::length()const {
+ return (data->end.hour() * 60 - data->start.hour() * 60)
+ + QABS(data->start.minute() - data->end.minute() );
+}
+int OEffectiveEvent::size()const {
+ return ( data->end.hour() - data->start.hour() ) * 3600
+ + (data->end.minute() - data->start.minute() * 60
+ + data->end.second() - data->start.second() );
+}
+QDate OEffectiveEvent::startDate()const {
+ if ( data->dates )
+ return data->startDate;
+ else if ( data->event.hasRecurrence() ) // single day, since multi-day should have a d pointer
+ return data->date;
+ else
+ return data->event.startDateTime().date();
+}
+QDate OEffectiveEvent::endDate()const {
+ if ( data->dates )
+ return data->endDate;
+ else if ( data->event.hasRecurrence() )
+ return data->date;
+ else
+ return data->event.endDateTime().date();
+}
+void OEffectiveEvent::deref() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0;
+ }
+}
+void OEffectiveEvent::changeOrModify() {
+ if ( data->count != 1 ) {
+ data->deref();
+ Data* d2 = new Data;
+ d2->event = data->event;
+ d2->date = data->date;
+ d2->start = data->start;
+ d2->end = data->end;
+ d2->startDate = data->startDate;
+ d2->endDate = data->endDate;
+ d2->dates = data->dates;
+ data = d2;
+ }
+}
+bool OEffectiveEvent::operator<( const OEffectiveEvent &e ) const{
+ if ( data->date < e.date() )
+ return TRUE;
+ if ( data->date == e.date() )
+ return ( startTime() < e.startTime() );
+ else
+ return FALSE;
+}
+bool OEffectiveEvent::operator<=( const OEffectiveEvent &e ) const{
+ return (data->date <= e.date() );
+}
+bool OEffectiveEvent::operator==( const OEffectiveEvent &e ) const {
+ return ( date() == e.date()
+ && startTime() == e.startTime()
+ && endTime()== e.endTime()
+ && event() == e.event() );
+}
+bool OEffectiveEvent::operator!=( const OEffectiveEvent &e ) const {
+ return !(*this == e );
+}
+bool OEffectiveEvent::operator>( const OEffectiveEvent &e ) const {
+ return !(*this <= e );
+}
+bool OEffectiveEvent::operator>= ( const OEffectiveEvent &e ) const {
+ return !(*this < e);
+}
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 @@
+// CONTAINS GPLed code of TT
+
+#ifndef OPIE_PIM_EVENT_H
+#define OPIE_PIM_EVENT_H
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+
+#include <qpe/recordfields.h>
+#include <qpe/palmtopuidgen.h>
+
+#include "otimezone.h"
+#include "opimrecord.h"
+
+struct OCalendarHelper {
+ /** calculate the week number of the date */
+ static int week( const QDate& );
+ /** calculate the occurence of week days since the start of the month */
+ static int ocurrence( const QDate& );
+
+ // returns the dayOfWeek for the *first* day it finds (ignores
+ // any further days!). Returns 1 (Monday) if there isn't any day found
+ static int dayOfWeek( char day );
+
+ /** returns the diff of month */
+ static int monthDiff( const QDate& first, const QDate& second );
+
+};
+
+class OPimNotifyManager;
+class ORecur;
+
+/**
+ * This is the container for all Events. It encapsules all
+ * available information for a single Event
+ * @short container for events.
+ */
+class OEvent : public OPimRecord {
+public:
+ typedef QValueList<OEvent> ValueList;
+ /**
+ * RecordFields contain possible attributes
+ * used in the Results of toMap()..
+ */
+ enum RecordFields {
+ FUid = Qtopia::UID_ID,
+ FCategories = Qtopia::CATEGORY_ID,
+ FDescription = 0,
+ FLocation,
+ FType,
+ FAlarm,
+ FSound,
+ FRType,
+ FRWeekdays,
+ FRPosition,
+ FRFreq,
+ FRHasEndDate,
+ FREndDate,
+ FRCreated,
+ FRExceptions,
+ FStart,
+ FEnd,
+ FNote,
+ FTimeZone,
+ FRecParent,
+ FRecChildren,
+ };
+
+ /**
+ * Start with an Empty OEvent. UID == 0 means that it is empty
+ */
+ OEvent(int uid = 0);
+
+ /**
+ * copy c'tor
+ */
+ OEvent( const OEvent& );
+
+ /**
+ * Create OEvent, initialized by map
+ * @see enum RecordFields
+ */
+ OEvent( const QMap<int, QString> map );
+ ~OEvent();
+ OEvent &operator=( const OEvent& );
+
+ QString description()const;
+ void setDescription( const QString& description );
+
+ QString location()const;
+ void setLocation( const QString& loc );
+
+ bool hasNotifiers()const;
+ OPimNotifyManager &notifiers()const;
+
+ ORecur recurrence()const;
+ void setRecurrence( const ORecur& );
+ bool hasRecurrence()const;
+
+ QString note()const;
+ void setNote( const QString& note );
+
+
+ QDateTime createdDateTime()const;
+ void setCreatedDateTime( const QDateTime& dt);
+
+ /** set the date to dt. dt is the QDateTime in localtime */
+ void setStartDateTime( const QDateTime& );
+ /** returns the datetime in the local timeZone */
+ QDateTime startDateTime()const;
+
+ /** returns the start datetime in the current zone */
+ QDateTime startDateTimeInZone()const;
+
+ /** in current timezone */
+ void setEndDateTime( const QDateTime& );
+ /** in current timezone */
+ QDateTime endDateTime()const;
+ QDateTime endDateTimeInZone()const;
+
+ bool isMultipleDay()const;
+ bool isAllDay()const;
+ void setAllDay( bool isAllDay );
+
+ /* pin this event to a timezone! FIXME */
+ void setTimeZone( const QString& timeZone );
+ QString timeZone()const;
+
+
+ virtual bool match( const QRegExp& )const;
+
+ /** For exception to recurrence here is a list of children... */
+ QArray<int> children()const;
+ void setChildren( const QArray<int>& );
+ void addChild( int uid );
+ void removeChild( int uid );
+
+ /** return the parent OEvent */
+ int parent()const;
+ void setParent( int uid );
+
+
+ /* needed reimp */
+ QString toRichText()const;
+ QString toShortText()const;
+ QString type()const;
+
+ QMap<int, QString> toMap()const;
+ void fromMap( const QMap<int, QString>& map );
+ QString recordField(int )const;
+
+ static int rtti();
+
+ bool loadFromStream( QDataStream& );
+ bool saveToStream( QDataStream& )const;
+
+/* bool operator==( const OEvent& );
+ bool operator!=( const OEvent& );
+ bool operator<( const OEvent& );
+ bool operator<=( const OEvent& );
+ bool operator>( const OEvent& );
+ bool operator>=(const OEvent& );
+*/
+private:
+ inline void changeOrModify();
+ void deref();
+ struct Data;
+ Data* data;
+ class Private;
+ Private* priv;
+
+};
+
+/**
+ * AN Event can span through multiple days. We split up a multiday eve
+ */
+class OEffectiveEvent {
+public:
+ typedef QValueList<OEffectiveEvent> ValueList;
+ enum Position { MidWay, Start, End, StartEnd };
+ // If we calculate the effective event of a multi-day event
+ // we have to figure out whether we are at the first day,
+ // at the end, or anywhere else ("middle"). This is important
+ // for the start/end times (00:00/23:59)
+ // MidWay: 00:00 -> 23:59, as we are "in the middle" of a multi-
+ // day event
+ // Start: start time -> 23:59
+ // End: 00:00 -> end time
+ // Start | End == StartEnd: for single-day events (default)
+ // here we draw start time -> end time
+ OEffectiveEvent();
+ OEffectiveEvent( const OEvent& event, const QDate& startDate, Position pos = StartEnd );
+ OEffectiveEvent( const OEffectiveEvent& );
+ OEffectiveEvent &operator=(const OEffectiveEvent& );
+ ~OEffectiveEvent();
+
+ void setStartTime( const QTime& );
+ void setEndTime( const QTime& );
+ void setEvent( const OEvent& );
+ void setDate( const QDate& );
+
+ void setEffectiveDates( const QDate& from, const QDate& to );
+
+ QString description()const;
+ QString location()const;
+ QString note()const;
+ OEvent event()const;
+ QTime startTime()const;
+ QTime endTime()const;
+ QDate date()const;
+
+ /* return the length in hours */
+ int length()const;
+ int size()const;
+
+ QDate startDate()const;
+ QDate endDate()const;
+
+ bool operator<( const OEffectiveEvent &e ) const;
+ bool operator<=( const OEffectiveEvent &e ) const;
+ bool operator==( const OEffectiveEvent &e ) const;
+ bool operator!=( const OEffectiveEvent &e ) const;
+ bool operator>( const OEffectiveEvent &e ) const;
+ bool operator>= ( const OEffectiveEvent &e ) const;
+
+private:
+ void deref();
+ inline void changeOrModify();
+ class Private;
+ Private* priv;
+ struct Data;
+ Data* data;
+
+};
+#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 @@
+#ifndef OPIE_PIM_ACCESS_BACKEND
+#define OPIE_PIM_ACCESS_BACKEND
+
+#include <qarray.h>
+#include <qdatetime.h>
+
+#include <opie/otemplatebase.h>
+#include <opie/opimrecord.h>
+
+
+class OPimAccessBackendPrivate;
+/**
+ * OPimAccessBackend is the base class
+ * for all private backends
+ * it operates on OPimRecord as the base class
+ * and it's responsible for fast manipulating
+ * the resource the implementation takes care
+ * of
+ */
+template <class T = OPimRecord>
+class OPimAccessBackend {
+public:
+ typedef OTemplateBase<T> Frontend;
+
+ /** The access hint from the frontend */
+ OPimAccessBackend(int access = 0);
+ virtual ~OPimAccessBackend();
+
+ /**
+ * load the resource
+ */
+ virtual bool load() = 0;
+
+ /**
+ * reload the resource
+ */
+ virtual bool reload() = 0;
+
+ /**
+ * save the resource and
+ * all it's changes
+ */
+ virtual bool save() = 0;
+
+ /**
+ * return an array of
+ * all available uids
+ */
+ virtual QArray<int> allRecords()const = 0;
+
+ /**
+ * return a List of records
+ * that match the regex
+ */
+ virtual QArray<int> matchRegexp(const QRegExp &r) const = 0;
+
+ /**
+ * queryByExample for T with the given Settings
+ *
+ */
+ virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0;
+
+ /**
+ * find the OPimRecord with uid @param uid
+ * returns T and T.isEmpty() if nothing was found
+ */
+ virtual T find(int uid )const = 0;
+
+ virtual T find(int uid, const QArray<int>& items,
+ uint current, typename Frontend::CacheDirection )const ;
+ /**
+ * clear the back end
+ */
+ virtual void clear() = 0;
+
+ /**
+ * add T
+ */
+ virtual bool add( const T& t ) = 0;
+
+ /**
+ * remove
+ */
+ virtual bool remove( int uid ) = 0;
+
+ /**
+ * replace a record with T.uid()
+ */
+ virtual bool replace( const T& t ) = 0;
+
+ /*
+ * setTheFrontEnd!!!
+ */
+ void setFrontend( Frontend* front );
+
+ /**
+ * set the read ahead count
+ */
+ void setReadAhead( uint count );
+protected:
+ int access()const;
+ void cache( const T& t )const;
+
+ /**
+ * use a prime number here!
+ */
+ void setSaneCacheSize( int );
+
+ uint readAhead()const;
+
+private:
+ OPimAccessBackendPrivate *d;
+ Frontend* m_front;
+ uint m_read;
+ int m_acc;
+
+};
+
+template <class T>
+OPimAccessBackend<T>::OPimAccessBackend(int acc)
+ : m_acc( acc )
+{
+ m_front = 0l;
+}
+template <class T>
+OPimAccessBackend<T>::~OPimAccessBackend() {
+
+}
+template <class T>
+void OPimAccessBackend<T>::setFrontend( Frontend* fr ) {
+ m_front = fr;
+}
+template <class T>
+void OPimAccessBackend<T>::cache( const T& t )const {
+ if (m_front )
+ m_front->cache( t );
+}
+template <class T>
+void OPimAccessBackend<T>::setSaneCacheSize( int size) {
+ if (m_front )
+ m_front->setSaneCacheSize( size );
+}
+template <class T>
+T OPimAccessBackend<T>::find( int uid, const QArray<int>&,
+ uint, typename Frontend::CacheDirection )const {
+ return find( uid );
+}
+template <class T>
+void OPimAccessBackend<T>::setReadAhead( uint count ) {
+ m_read = count;
+}
+template <class T>
+uint OPimAccessBackend<T>::readAhead()const {
+ return m_read;
+}
+template <class T>
+int OPimAccessBackend<T>::access()const {
+ return m_acc;
+}
+#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 @@
+#ifndef OPIE_PIM_ACCESS_TEMPLATE_H
+#define OPIE_PIM_ACCESS_TEMPLATE_H
+
+#include <qarray.h>
+
+#include <opie/opimrecord.h>
+#include <opie/opimaccessbackend.h>
+#include <opie/orecordlist.h>
+
+#include "opimcache.h"
+#include "otemplatebase.h"
+
+class OPimAccessTemplatePrivate;
+/**
+ * Thats the frontend to our OPIE PIM
+ * Library. Either you want to use it's
+ * interface or you want to implement
+ * your own Access lib
+ * Just create a OPimRecord and inherit from
+ * the plugins
+ */
+
+template <class T = OPimRecord >
+class OPimAccessTemplate : public OTemplateBase<T> {
+public:
+ enum Access {
+ Random = 0,
+ SortedAccess
+ };
+ typedef ORecordList<T> List;
+ typedef OPimAccessBackend<T> BackEnd;
+ typedef OPimCache<T> Cache;
+
+ /**
+ * c'tor BackEnd
+ * enum Access a small hint on how to handle the backend
+ */
+ OPimAccessTemplate( BackEnd* end);
+
+ virtual ~OPimAccessTemplate();
+
+ /**
+ * load from the backend
+ */
+ bool load();
+
+ /** Reload database.
+ * You should execute this function if the external database
+ * was changed.
+ * This function will load the external database and afterwards
+ * rejoin the local changes. Therefore the local database will be set consistent.
+ */
+ virtual bool reload();
+
+ /** Save contacts database.
+ * Save is more a "commit". After calling this function, all changes are public available.
+ * @return true if successful
+ */
+ bool save();
+
+ /**
+ * if the resource was changed externally
+ * You should use the signal handling instead of polling possible changes !
+ * zecke: Do you implement a signal for otodoaccess ?
+ */
+ bool wasChangedExternally()const;
+
+ /**
+ * return a List of records
+ * you can iterate over them
+ */
+ virtual List allRecords()const;
+
+ /**
+ * return a List of records
+ * that match the regex
+ */
+ virtual List matchRegexp( const QRegExp &r ) const;
+
+ /**
+ * queryByExample.
+ * @see otodoaccess, ocontactaccess
+ */
+ virtual List queryByExample( const T& t, int querySettings, const QDateTime& d = QDateTime() );
+
+ /**
+ * find the OPimRecord uid
+ */
+ virtual T find( int uid )const;
+
+ /**
+ * read ahead cache find method ;)
+ */
+ virtual T find( int uid, const QArray<int>&,
+ uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const;
+
+ /* invalidate cache here */
+ /**
+ * clears the backend and invalidates the backend
+ */
+ void clear() ;
+
+ /**
+ * add T to the backend
+ * @param t The item to add.
+ * @return <i>true</i> if added successfully.
+ */
+ virtual bool add( const T& t ) ;
+ bool add( const OPimRecord& );
+
+ /* only the uid matters */
+ /**
+ * remove T from the backend
+ * @param t The item to remove
+ * @return <i>true</i> if successful.
+ */
+ virtual bool remove( const T& t );
+
+ /**
+ * remove the OPimRecord with uid
+ * @param uid The ID of the item to remove
+ * @return <i>true</i> if successful.
+ */
+ bool remove( int uid );
+ bool remove( const OPimRecord& );
+
+ /**
+ * replace T from backend
+ * @param t The item to replace
+ * @return <i>true</i> if successful.
+ */
+ virtual bool replace( const T& t) ;
+
+ void setReadAhead( uint count );
+ /**
+ * @internal
+ */
+ void cache( const T& )const;
+ void setSaneCacheSize( int );
+
+ QArray<int> records()const;
+protected:
+ /**
+ * invalidate the cache
+ */
+ void invalidateCache();
+
+ void setBackEnd( BackEnd* end );
+ /**
+ * returns the backend
+ */
+ BackEnd* backEnd();
+ BackEnd* m_backEnd;
+ Cache m_cache;
+
+private:
+ OPimAccessTemplatePrivate *d;
+
+};
+
+template <class T>
+OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end )
+ : OTemplateBase<T>(), m_backEnd( end )
+{
+ if (end )
+ end->setFrontend( this );
+}
+template <class T>
+OPimAccessTemplate<T>::~OPimAccessTemplate() {
+ qWarning("~OPimAccessTemplate<T>");
+ delete m_backEnd;
+}
+template <class T>
+bool OPimAccessTemplate<T>::load() {
+ invalidateCache();
+ return m_backEnd->load();
+}
+template <class T>
+bool OPimAccessTemplate<T>::reload() {
+ invalidateCache(); // zecke: I think this should be added (se)
+ return m_backEnd->reload();
+}
+template <class T>
+bool OPimAccessTemplate<T>::save() {
+ return m_backEnd->save();
+}
+template <class T>
+typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const {
+ QArray<int> ints = m_backEnd->allRecords();
+ List lis(ints, this );
+ return lis;
+}
+template <class T>
+typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::matchRegexp( const QRegExp &r )const {
+ QArray<int> ints = m_backEnd->matchRegexp( r );
+ List lis(ints, this );
+ return lis;
+}
+template <class T>
+QArray<int> OPimAccessTemplate<T>::records()const {
+ return m_backEnd->allRecords();
+}
+template <class T>
+typename OPimAccessTemplate<T>::List
+OPimAccessTemplate<T>::queryByExample( const T& t, int settings, const QDateTime& d ) {
+ QArray<int> ints = m_backEnd->queryByExample( t, settings, d );
+
+ List lis(ints, this );
+ return lis;
+}
+template <class T>
+T OPimAccessTemplate<T>::find( int uid ) const{
+ T t = m_backEnd->find( uid );
+ cache( t );
+ return t;
+}
+template <class T>
+T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar,
+ uint current, typename OTemplateBase<T>::CacheDirection dir )const {
+ /*
+ * better do T.isEmpty()
+ * after a find this way we would
+ * avoid two finds in QCache...
+ */
+ // qWarning("find it now %d", uid );
+ if (m_cache.contains( uid ) ) {
+ return m_cache.find( uid );
+ }
+
+ T t = m_backEnd->find( uid, ar, current, dir );
+ cache( t );
+ return t;
+}
+template <class T>
+void OPimAccessTemplate<T>::clear() {
+ invalidateCache();
+ m_backEnd->clear();
+}
+template <class T>
+bool OPimAccessTemplate<T>::add( const T& t ) {
+ cache( t );
+ return m_backEnd->add( t );
+}
+template <class T>
+bool OPimAccessTemplate<T>::add( const OPimRecord& rec) {
+ /* same type */
+ if ( rec.rtti() == T::rtti() ) {
+ const T &t = static_cast<const T&>(rec);
+ return add(t);
+ }
+ return false;
+}
+template <class T>
+bool OPimAccessTemplate<T>::remove( const T& t ) {
+ return remove( t.uid() );
+}
+template <class T>
+bool OPimAccessTemplate<T>::remove( int uid ) {
+ m_cache.remove( uid );
+ return m_backEnd->remove( uid );
+}
+template <class T>
+bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) {
+ return remove( rec.uid() );
+}
+template <class T>
+bool OPimAccessTemplate<T>::replace( const T& t ) {
+ m_cache.replace( t );
+ return m_backEnd->replace( t );
+}
+template <class T>
+void OPimAccessTemplate<T>::invalidateCache() {
+ m_cache.invalidate();
+}
+template <class T>
+typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() {
+ return m_backEnd;
+}
+template <class T>
+bool OPimAccessTemplate<T>::wasChangedExternally()const {
+ return false;
+}
+template <class T>
+void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) {
+ m_backEnd = end;
+ if (m_backEnd )
+ m_backEnd->setFrontend( this );
+}
+template <class T>
+void OPimAccessTemplate<T>::cache( const T& t ) const{
+ /* hacky we need to work around the const*/
+ ((OPimAccessTemplate<T>*)this)->m_cache.add( t );
+}
+template <class T>
+void OPimAccessTemplate<T>::setSaneCacheSize( int size ) {
+ m_cache.setSize( size );
+}
+template <class T>
+void OPimAccessTemplate<T>::setReadAhead( uint count ) {
+ m_backEnd->setReadAhead( count );
+}
+#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 @@
+#ifndef OPIE_PIM_CACHE_H
+#define OPIE_PIM_CACHE_H
+
+#include <qintcache.h>
+
+#include "opimrecord.h"
+
+class OPimCacheItemPrivate;
+
+template <class T = OPimRecord>
+class OPimCacheItem {
+public:
+ OPimCacheItem( const T& t = T() );
+ OPimCacheItem( const OPimCacheItem& );
+ ~OPimCacheItem();
+
+ OPimCacheItem &operator=( const OPimCacheItem& );
+
+ T record()const;
+ void setRecord( const T& );
+private:
+ T m_t;
+ OPimCacheItemPrivate *d;
+};
+
+
+class OPimCachePrivate;
+/**
+ * OPimCache for caching the items
+ * We support adding, removing
+ * and finding
+ */
+template <class T = OPimRecord>
+class OPimCache {
+public:
+ typedef OPimCacheItem<T> Item;
+ OPimCache();
+ OPimCache( const OPimCache& );
+ ~OPimCache();
+
+ OPimCache &operator=( const OPimCache& );
+
+ bool contains(int uid)const;
+ void invalidate();
+ void setSize( int size );
+
+ T find(int uid )const;
+ void add( const T& );
+ void remove( int uid );
+ void replace( const T& );
+
+private:
+ QIntCache<Item> m_cache;
+ OPimCachePrivate* d;
+};
+
+// Implementation
+template <class T>
+OPimCacheItem<T>::OPimCacheItem( const T& t )
+ : m_t(t) {
+}
+template <class T>
+OPimCacheItem<T>::~OPimCacheItem() {
+
+}
+template <class T>
+T OPimCacheItem<T>::record()const {
+ return m_t;
+}
+template <class T>
+void OPimCacheItem<T>::setRecord( const T& t ) {
+ m_t = t;
+}
+// Cache
+template <class T>
+OPimCache<T>::OPimCache()
+ : m_cache(100, 53 )
+{
+ m_cache.setAutoDelete( TRUE );
+}
+template <class T>
+OPimCache<T>::~OPimCache() {
+
+}
+template <class T>
+bool OPimCache<T>::contains(int uid )const {
+ Item* it = m_cache.find( uid, FALSE );
+ if (!it)
+ return false;
+ return true;
+}
+template <class T>
+void OPimCache<T>::invalidate() {
+ m_cache.clear();
+}
+template <class T>
+void OPimCache<T>::setSize( int size ) {
+ m_cache.setMaxCost( size );
+}
+template <class T>
+T OPimCache<T>::find(int uid )const {
+ Item *it = m_cache.find( uid );
+ if (it)
+ return it->record();
+ return T();
+}
+template <class T>
+void OPimCache<T>::add( const T& t ) {
+ Item* it = 0l;
+ it = m_cache.find(t.uid(), FALSE );
+
+ if (it )
+ it->setRecord( t );
+
+ it = new Item( t );
+ if (!m_cache.insert( t.uid(), it ) )
+ delete it;
+}
+template <class T>
+void OPimCache<T>::remove( int uid ) {
+ m_cache.remove( uid );
+}
+template <class T>
+void OPimCache<T>::replace( const T& t) {
+ Item *it = m_cache.find( t.uid() );
+ if ( it ) {
+ it->setRecord( t );
+ }
+}
+
+#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 @@
+#include "opimmaintainer.h"
+
+OPimMaintainer::OPimMaintainer( int mode, int uid )
+ : m_mode(mode), m_uid(uid )
+{}
+OPimMaintainer::~OPimMaintainer() {
+}
+OPimMaintainer::OPimMaintainer( const OPimMaintainer& main ) {
+ *this = main;
+}
+OPimMaintainer &OPimMaintainer::operator=( const OPimMaintainer& main ) {
+ m_mode = main.m_mode;
+ m_uid = main.m_uid;
+
+ return *this;
+}
+bool OPimMaintainer::operator==( const OPimMaintainer& main ) {
+ if (m_mode != main.m_mode ) return false;
+ if (m_uid != main.m_uid ) return false;
+
+ return true;
+}
+bool OPimMaintainer::operator!=( const OPimMaintainer& main ) {
+ return !(*this == main );
+}
+int OPimMaintainer::mode()const {
+ return m_mode;
+}
+int OPimMaintainer::uid()const {
+ return m_uid;
+}
+void OPimMaintainer::setMode( int mo) {
+ m_mode = mo;
+}
+void OPimMaintainer::setUid( int uid ) {
+ m_uid = uid;
+}
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 @@
+#ifndef OPIE_PIM_MAINTAINER_H
+#define OPIE_PIM_MAINTAINER_H
+
+#include <qstring.h>
+
+/**
+ * Who maintains what?
+ */
+class OPimMaintainer {
+public:
+ enum Mode { Undefined = -1,
+ Nothing = 0,
+ Responsible,
+ DoneBy,
+ Coordinating,
+ };
+ OPimMaintainer( int mode = Undefined, int uid = 0);
+ OPimMaintainer( const OPimMaintainer& );
+ ~OPimMaintainer();
+
+ OPimMaintainer &operator=( const OPimMaintainer& );
+ bool operator==( const OPimMaintainer& );
+ bool operator!=( const OPimMaintainer& );
+
+
+ int mode()const;
+ int uid()const;
+
+ void setMode( int mode );
+ void setUid( int uid );
+
+private:
+ int m_mode;
+ int m_uid;
+ class Private;
+ Private *d;
+
+};
+
+#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 @@
+#include <qapplication.h>
+#include <qdatetime.h>
+#include <qcopchannel_qws.h>
+
+#include <qpe/sound.h>
+#include <qpe/qcopenvelope_qws.h>
+#include <qpe/qpeapplication.h>
+
+#include "opimresolver.h"
+#include "opimmainwindow.h"
+
+OPimMainWindow::OPimMainWindow( const QString& service, QWidget* parent,
+ const char* name, WFlags flag )
+ : QMainWindow( parent, name, flag ), m_rtti(-1), m_service( service ), m_fallBack(0l) {
+
+ /*
+ * let's generate our QCopChannel
+ */
+ m_str = QString("QPE/"+m_service).local8Bit();
+ m_channel= new QCopChannel(m_str, this );
+ connect(m_channel, SIGNAL(received(const QCString&,const QByteArray&) ),
+ this, SLOT( appMessage(const QCString&,const QByteArray&) ) );
+ connect(qApp, SIGNAL(appMessage(const QCString&,const QByteArray&) ),
+ this, SLOT( appMessage(const QCString&,const QByteArray&) ) );
+
+ /* connect flush and reload */
+ connect(qApp, SIGNAL(flush() ),
+ this, SLOT(flush() ) );
+ connect(qApp, SIGNAL(reload() ),
+ this, SLOT(reload() ) );
+}
+OPimMainWindow::~OPimMainWindow() {
+ delete m_channel;
+}
+QCopChannel* OPimMainWindow::channel() {
+ return m_channel;
+}
+void OPimMainWindow::doSetDocument( const QString& ) {
+
+}
+void OPimMainWindow::appMessage( const QCString& cmd, const QByteArray& array ) {
+ bool needShow = false;
+ /*
+ * create demands to create
+ * a new record...
+ */
+ QDataStream stream(array, IO_ReadOnly);
+ if ( cmd == "create()" ) {
+ raise();
+ int uid = create();
+ QCopEnvelope e(m_str, "created(int)" );
+ e << uid;
+ needShow = true;
+ }else if ( cmd == "remove(int)" ) {
+ int uid;
+ stream >> uid;
+ bool rem = remove( uid );
+ QCopEnvelope e(m_str, "removed(bool)" );
+ e << rem;
+ needShow = true;
+ }else if ( cmd == "beam(int)" ) {
+ int uid;
+ stream >> uid;
+ beam( uid);
+ }else if ( cmd == "show(int)" ) {
+ raise();
+ int uid;
+ stream >> uid;
+ show( uid );
+ needShow = true;
+ }else if ( cmd == "edit(int)" ) {
+ raise();
+ int uid;
+ stream >> uid;
+ edit( uid );
+ }else if ( cmd == "add(int,QByteArray)" ) {
+ int rtti;
+ QByteArray array;
+ stream >> rtti;
+ stream >> array;
+ m_fallBack = record(rtti, array );
+ if (!m_fallBack) return;
+ add( *m_fallBack );
+ delete m_fallBack;
+ }else if ( cmd == "alarm(QDateTime,int)" ) {
+ raise();
+ QDateTime dt; int uid;
+ stream >> dt;
+ stream >> uid;
+ qWarning(" Date: %s Uid: %d", dt.toString().latin1(), uid );
+ QDateTime current = QDateTime::currentDateTime();
+ if ( current.time().hour() != dt.time().hour() && current.time().minute() != dt.time().minute() )
+ return;
+ doAlarm( dt, uid );
+ needShow = true;
+ }
+
+ if (needShow )
+ QPEApplication::setKeepRunning();
+}
+/* implement the url scripting here */
+void OPimMainWindow::setDocument( const QString& str) {
+ doSetDocument( str );
+}
+/*
+ * we now try to get the array demarshalled
+ * check if the rtti matches this one
+ */
+OPimRecord* OPimMainWindow::record( int rtti, const QByteArray& array ) {
+ if ( service() != rtti )
+ return 0l;
+
+ OPimRecord* record = OPimResolver::self()->record( rtti );
+ QDataStream str(array, IO_ReadOnly );
+ if ( !record || !record->loadFromStream(str) ) {
+ delete record;
+ record = 0l;
+ }
+
+ return record;
+}
+/*
+ * get the rtti for the service
+ */
+int OPimMainWindow::service() {
+ if ( m_rtti == -1 )
+ m_rtti = OPimResolver::self()->serviceId( m_service );
+
+ return m_rtti;
+}
+void OPimMainWindow::doAlarm( const QDateTime&, int ) {
+
+}
+void OPimMainWindow::startAlarm(int count ) {
+ m_alarmCount = count;
+ m_playedCount = 0;
+ Sound::soundAlarm();
+ m_timerId = startTimer( 5000 );
+}
+void OPimMainWindow::killAlarm() {
+ killTimer( m_timerId );
+}
+void OPimMainWindow::timerEvent( QTimerEvent* e) {
+ if ( m_playedCount <m_alarmCount ) {
+ m_playedCount++;
+ Sound::soundAlarm();
+ }else {
+ killTimer( e->timerId() );
+ }
+}
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 @@
+#ifndef OPIE_PIM_MAINWINDOW_H
+#define OPIE_PIM_MAINWINDOW_H
+
+#include <qmainwindow.h>
+
+#include <opie/opimrecord.h>
+
+/**
+ * This is a common Opie PIM MainWindow
+ * it takes care of the QCOP internals
+ * and implements some functions
+ * for the URL scripting schema
+ */
+/*
+ * due Qt and Templates with signal and slots
+ * do not work that good :(
+ * (Ok how to moc a template ;) )
+ * We will have the mainwindow which calls a struct which
+ * is normally reimplemented as a template ;)
+ */
+
+class QCopChannel;
+class QDateTime;
+class OPimMainWindow : public QMainWindow {
+ Q_OBJECT
+public:
+ enum TransPort { BlueTooth=0,
+ IrDa };
+
+ OPimMainWindow( const QString& service, QWidget *parent = 0, const char* name = 0,
+ WFlags f = WType_TopLevel);
+ virtual ~OPimMainWindow();
+
+
+protected slots:
+ /*
+ * called when a setDocument
+ * couldn't be handled by this window
+ */
+ virtual void doSetDocument( const QString& );
+ /* for syncing */
+ virtual void flush() = 0;
+ virtual void reload() = 0;
+
+ /** create a new Records and return the uid */
+ virtual int create() = 0;
+ /** remove a record with UID == uid */
+ virtual bool remove( int uid ) = 0;
+ /** beam the record with UID = uid */
+ virtual void beam( int uid ) = 0;
+
+ /** show the record with UID == uid */
+ virtual void show( int uid ) = 0;
+ /** edit the record */
+ virtual void edit( int uid ) = 0;
+
+ /** make a copy of it! */
+ virtual void add( const OPimRecord& ) = 0;
+
+ virtual void doAlarm( const QDateTime&, int uid );
+
+ QCopChannel* channel();
+
+protected:
+ /**
+ * start to play soundAlarm()
+ * @param count How many times the alarm is played
+ */
+ void startAlarm(int count = 10);
+ void killAlarm();
+ void timerEvent( QTimerEvent* );
+
+private slots:
+ void appMessage( const QCString&, const QByteArray& );
+ void setDocument( const QString& );
+
+
+private:
+ class Private;
+ Private* d;
+
+ int m_rtti;
+ QCopChannel* m_channel;
+ QString m_service;
+ QCString m_str;
+ OPimRecord* m_fallBack;
+ int m_alarmCount;
+ int m_playedCount;
+ int m_timerId;
+ /* I would love to do this as a template
+ * but can't think of a right way
+ * because I need signal and slots -zecke
+ */
+ virtual OPimRecord* record( int rtti, const QByteArray& ) ;
+ int service();
+};
+
+
+#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 @@
+#include <qshared.h>
+
+#include "opimnotify.h"
+
+struct OPimNotify::Data : public QShared {
+ Data() : QShared(),dur(-1),parent(0) {
+
+ }
+ QDateTime start;
+ int dur;
+ QString application;
+ int parent;
+};
+
+OPimNotify::OPimNotify( const QDateTime& start, int duration, int parent ) {
+ data = new Data;
+ data->start = start;
+ data->dur = duration;
+ data->parent = parent;
+}
+OPimNotify::OPimNotify( const OPimNotify& noti)
+ : data( noti.data )
+{
+ data->ref();
+}
+OPimNotify::~OPimNotify() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0l;
+ }
+}
+
+OPimNotify &OPimNotify::operator=( const OPimNotify& noti) {
+ noti.data->ref();
+ deref();
+ data = noti.data;
+
+ return *this;
+}
+bool OPimNotify::operator==( const OPimNotify& noti ) {
+ if ( data == noti.data ) return true;
+ if ( data->dur != noti.data->dur ) return false;
+ if ( data->parent != noti.data->parent ) return false;
+ if ( data->application != noti.data->application ) return false;
+ if ( data->start != noti.data->start ) return false;
+
+ return true;
+}
+QDateTime OPimNotify::dateTime()const {
+ return data->start;
+}
+QString OPimNotify::service()const {
+ return data->application;
+}
+int OPimNotify::parent()const {
+ return data->parent;
+}
+int OPimNotify::duration()const {
+ return data->dur;
+}
+QDateTime OPimNotify::endTime()const {
+ return QDateTime( data->start.date(), data->start.time().addSecs( data->dur) );
+}
+void OPimNotify::setDateTime( const QDateTime& time ) {
+ copyIntern();
+ data->start = time;
+}
+void OPimNotify::setDuration( int dur ) {
+ copyIntern();
+ data->dur = dur;
+}
+void OPimNotify::setParent( int uid ) {
+ copyIntern();
+ data->parent = uid;
+}
+void OPimNotify::setService( const QString& str ) {
+ copyIntern();
+ data->application = str;
+}
+void OPimNotify::copyIntern() {
+ if ( data->count != 1 ) {
+ data->deref();
+ Data* dat = new Data;
+ dat->start = data->start;
+ dat->dur = data->dur;
+ dat->application = data->application;
+ dat->parent = data->parent;
+ data = dat;
+ }
+}
+void OPimNotify::deref() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0;
+ }
+}
+
+/***********************************************************/
+struct OPimAlarm::Data : public QShared {
+ Data() : QShared() {
+ sound = 1;
+ }
+ int sound;
+ QString file;
+};
+OPimAlarm::OPimAlarm( int sound, const QDateTime& start, int duration, int parent )
+ : OPimNotify( start, duration, parent )
+{
+ data = new Data;
+ data->sound = sound;
+}
+OPimAlarm::OPimAlarm( const OPimAlarm& al)
+ : OPimNotify(al), data( al.data )
+{
+ data->ref();
+}
+OPimAlarm::~OPimAlarm() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0l;
+ }
+}
+OPimAlarm &OPimAlarm::operator=( const OPimAlarm& al)
+{
+ OPimNotify::operator=( al );
+ deref();
+ al.data->ref();
+
+ data = al.data;
+
+
+ return *this;
+}
+bool OPimAlarm::operator==( const OPimAlarm& al) {
+ if ( data->sound != al.data->sound ) return false;
+ else if ( data->sound == Custom && data->file != al.data->file )
+ return false;
+
+ return OPimNotify::operator==( al );
+}
+QString OPimAlarm::type()const {
+ return QString::fromLatin1("OPimAlarm");
+}
+int OPimAlarm::sound()const {
+ return data->sound;
+}
+QString OPimAlarm::file()const {
+ return data->file;
+}
+void OPimAlarm::setSound( int snd) {
+ copyIntern();
+ data->sound = snd;
+}
+void OPimAlarm::setFile( const QString& sound ) {
+ copyIntern();
+ data->file = sound;
+}
+void OPimAlarm::deref() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0l;
+ }
+}
+void OPimAlarm::copyIntern() {
+ if ( data->count != 1 ) {
+ data->deref();
+ Data *newDat = new Data;
+ newDat->sound = data->sound;
+ newDat->file = data->file;
+ data = newDat;
+ }
+}
+/************************/
+struct OPimReminder::Data : public QShared {
+ Data() : QShared(), record( 0) {
+ }
+ int record;
+
+};
+OPimReminder::OPimReminder( int uid, const QDateTime& start, int dur, int parent )
+ : OPimNotify( start, dur, parent )
+{
+ data = new Data;
+ data->record = uid;
+}
+OPimReminder::OPimReminder( const OPimReminder& rem )
+ : OPimNotify( rem ), data( rem.data )
+{
+ data->ref();
+}
+OPimReminder& OPimReminder::operator=( const OPimReminder& rem) {
+ OPimNotify::operator=(rem );
+
+ deref();
+ rem.data->ref();
+ data = rem.data;
+
+ return *this;
+}
+bool OPimReminder::operator==( const OPimReminder& rem) {
+ if ( data->record != rem.data->record ) return false;
+
+ return OPimNotify::operator==( rem );
+}
+QString OPimReminder::type()const {
+ return QString::fromLatin1("OPimReminder");
+}
+int OPimReminder::recordUid()const {
+ return data->record;
+}
+void OPimReminder::setRecordUid( int uid ) {
+ copyIntern();
+ data->record = uid;
+}
+void OPimReminder::deref() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0l;
+ }
+}
+void OPimReminder::copyIntern() {
+ if ( data->count != 1 ) {
+ Data* da = new Data;
+ da->record = data->record;
+ data = da;
+ }
+}
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 @@
+#ifndef OPIE_PIM_NOTIFY_H
+#define OPIE_PIM_NOTIFY_H
+
+#include <qdatetime.h>
+#include <qvaluelist.h>
+
+/**
+ * This is the base class of Notifiers. Possible
+ * notifiers would be Alarms, Reminders
+ * What they share is that they have
+ * A DateTime, Type, Duration
+ * This is what this base class takes care of
+ * on top of that it's shared
+ */
+/*
+ * TALK to eilers: have a class OPimDuration which sets the Duration
+ * given on the Due/Start Date? -zecke
+ * discuss: do we need a uid for the notify? -zecke
+ */
+class OPimNotify {
+public:
+ typedef QValueList<OPimNotify> ValueList;
+ OPimNotify( const QDateTime& start = QDateTime(), int duration = 0, int parent = 0 );
+ OPimNotify( const OPimNotify& );
+ virtual ~OPimNotify();
+
+ OPimNotify &operator=(const OPimNotify& );
+ bool operator==( const OPimNotify& );
+
+ virtual QString type()const = 0;
+
+ /** start date */
+ QDateTime dateTime()const;
+ QString service()const;
+
+ /**
+ * RETURN the parent uid
+ */
+ int parent()const;
+
+ /**
+ * in Seconds
+ */
+ int duration()const;
+
+ /**
+ * Start Time + Duration
+ */
+ QDateTime endTime()const;
+
+ void setDateTime( const QDateTime& );
+ void setDuration( int dur );
+ void setParent(int uid );
+ void setService( const QString& );
+
+
+private:
+ inline void copyIntern();
+ void deref();
+ struct Data;
+ Data* data;
+
+ /* d-pointer */
+ class NotifyPrivate;
+ NotifyPrivate* d;
+
+};
+/**
+ * An alarm is a sound/mail/buzzer played/send
+ * at a given time to inform about
+ * an Event
+ */
+class OPimAlarm : public OPimNotify {
+public:
+ enum Sound{Loud=1, Silent=0, Custom=2 };
+ OPimAlarm( int sound = Silent, const QDateTime& start = QDateTime(), int duration = 0, int parent = 0 );
+ OPimAlarm( const OPimAlarm& );
+ ~OPimAlarm();
+
+ OPimAlarm &operator=( const OPimAlarm& );
+ bool operator==( const OPimAlarm& );
+ QString type()const;
+
+ int sound()const;
+ QString file()const;
+
+ void setSound( int );
+ /* only when sound is custom... */
+ void setFile( const QString& sound );
+
+private:
+ void deref();
+ void copyIntern();
+ struct Data;
+ Data * data;
+
+ class Private;
+ Private* d;
+
+};
+
+/**
+ * A Reminder will be put into the
+ * datebook
+ * Note that the returned dateTime() may be not valid.
+ * In these cases one must resolve the uid and get the OEvent
+ */
+class OPimReminder : public OPimNotify {
+public:
+
+ /**
+ * c'tor of a reminder
+ * @param uid The uid of the Record inside the Datebook
+ * @param start the StartDate invalid for all day...
+ * @param duration The duration of the event ( -1 for all day )
+ * @param parent The 'parent' record of this reminder
+ */
+ OPimReminder( int uid = 0, const QDateTime& start = QDateTime(),
+ int duration = 0, int parent = 0 );
+ OPimReminder( const OPimReminder& );
+ OPimReminder &operator=(const OPimReminder& );
+
+ QString type()const;
+
+ bool operator==( const OPimReminder& );
+
+ /**
+ * the uid of the alarm
+ * inside the 'datebook' application
+ */
+ int recordUid()const;
+ void setRecordUid( int uid );
+
+private:
+ void deref();
+ void copyIntern();
+
+ struct Data;
+ Data* data;
+ class Private;
+ Private *d;
+};
+
+#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 @@
+#include "opimnotifymanager.h"
+
+#include "oconversion.h"
+
+#include <qstringlist.h>
+
+OPimNotifyManager::OPimNotifyManager( const Reminders& rem, const Alarms& al)
+ : m_rem( rem ), m_al( al )
+{}
+OPimNotifyManager::~OPimNotifyManager() {
+}
+/* use static_cast and type instead of dynamic... */
+void OPimNotifyManager::add( const OPimNotify& noti) {
+ if ( noti.type() == QString::fromLatin1("OPimReminder") ) {
+ const OPimReminder& rem = static_cast<const OPimReminder&>(noti);
+ m_rem.append( rem );
+ }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) {
+ const OPimAlarm& al = static_cast<const OPimAlarm&>(noti);
+ m_al.append( al );
+ }
+}
+void OPimNotifyManager::remove( const OPimNotify& noti) {
+ if ( noti.type() == QString::fromLatin1("OPimReminder") ) {
+ const OPimReminder& rem = static_cast<const OPimReminder&>(noti);
+ m_rem.remove( rem );
+ }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) {
+ const OPimAlarm& al = static_cast<const OPimAlarm&>(noti);
+ m_al.remove( al );
+ }
+}
+void OPimNotifyManager::replace( const OPimNotify& noti) {
+ if ( noti.type() == QString::fromLatin1("OPimReminder") ) {
+ const OPimReminder& rem = static_cast<const OPimReminder&>(noti);
+ m_rem.remove( rem );
+ m_rem.append( rem );
+ }else if ( noti.type() == QString::fromLatin1("OPimAlarm") ) {
+ const OPimAlarm& al = static_cast<const OPimAlarm&>(noti);
+ m_al.remove( al );
+ m_al.append( al );
+ }
+}
+OPimNotifyManager::Reminders OPimNotifyManager::reminders()const {
+ return m_rem;
+}
+OPimNotifyManager::Alarms OPimNotifyManager::alarms()const {
+ return m_al;
+}
+OPimAlarm OPimNotifyManager::alarmAtDateTime( const QDateTime& when, bool& found ) const {
+ Alarms::ConstIterator it;
+ found = true;
+
+ for ( it = m_al.begin(); it != m_al.end(); ++it ){
+ if ( (*it).dateTime() == when )
+ return (*it);
+ }
+
+ // Fall through if nothing could be found
+ found = false;
+ OPimAlarm empty;
+ return empty;
+}
+
+
+void OPimNotifyManager::setAlarms( const Alarms& al) {
+ m_al = al;
+}
+void OPimNotifyManager::setReminders( const Reminders& rem) {
+ m_rem = rem;
+}
+/* FIXME!!! */
+/**
+ * The idea is to check if the provider for our service
+ * is online
+ * if it is we will use QCOP
+ * if not the Factory to get the backend...
+ * Qtopia1.6 services would be kewl to have here....
+ */
+void OPimNotifyManager::registerNotify( const OPimNotify& ) {
+
+}
+/* FIXME!!! */
+/**
+ * same as above...
+ * Also implement Url model
+ * have a MainWindow....
+ */
+void OPimNotifyManager::deregister( const OPimNotify& ) {
+
+}
+
+bool OPimNotifyManager::isEmpty()const {
+ qWarning("is Empty called on OPimNotifyManager %d %d", m_rem.count(), m_al.count() );
+ if ( m_rem.isEmpty() && m_al.isEmpty() ) return true;
+ else return false;
+}
+
+// Taken from otodoaccessxml..
+QString OPimNotifyManager::alarmsToString() const
+{
+ QString str;
+
+ OPimNotifyManager::Alarms alarms = m_al;
+ if ( !alarms.isEmpty() ) {
+ QStringList als;
+ OPimNotifyManager::Alarms::Iterator it = alarms.begin();
+ for ( ; it != alarms.end(); ++it ) {
+ /* only if time is valid */
+ if ( (*it).dateTime().isValid() ) {
+ als << OConversion::dateTimeToString( (*it).dateTime() )
+ + ":" + QString::number( (*it).duration() )
+ + ":" + QString::number( (*it).sound() )
+ + ":";
+ }
+ }
+ // now write the list
+ qWarning("als: %s", als.join("____________").latin1() );
+ str = als.join(";");
+ }
+
+ return str;
+}
+QString OPimNotifyManager::remindersToString() const
+{
+ QString str;
+
+ OPimNotifyManager::Reminders reminders = m_rem;
+ if (!reminders.isEmpty() ) {
+ OPimNotifyManager::Reminders::Iterator it = reminders.begin();
+ QStringList records;
+ for ( ; it != reminders.end(); ++it ) {
+ records << QString::number( (*it).recordUid() );
+ }
+ str = records.join(";");
+ }
+
+ return str;
+}
+
+void OPimNotifyManager::alarmsFromString( const QString& str )
+{
+ QStringList als = QStringList::split(";", str );
+ for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) {
+ QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty
+ qWarning("alarm: %s", alarm.join("___").latin1() );
+ qWarning("alarm[0]: %s %s", alarm[0].latin1(),
+ OConversion::dateTimeFromString( alarm[0] ).toString().latin1() );
+ OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ),
+ alarm[1].toInt() );
+ add( al );
+ }
+}
+
+void OPimNotifyManager::remindersFromString( const QString& str )
+{
+
+ QStringList rems = QStringList::split(";", str );
+ for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) {
+ OPimReminder rem( (*it).toInt() );
+ add( rem );
+ }
+
+}
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 @@
+#ifndef OPIE_PIM_NOTIFY_MANAGER_H
+#define OPIE_PIM_NOTIFY_MANAGER_H
+
+#include <qvaluelist.h>
+
+#include <opie/opimnotify.h>
+
+/**
+ * The notify manager keeps track of the Notifiers....
+ */
+class OPimNotifyManager {
+public:
+ typedef QValueList<OPimReminder> Reminders;
+ typedef QValueList<OPimAlarm> Alarms;
+ OPimNotifyManager( const Reminders& rems = Reminders(), const Alarms& alarms = Alarms() );
+ ~OPimNotifyManager();
+
+ /* we will cast it for you ;) */
+ void add( const OPimNotify& );
+ void remove( const OPimNotify& );
+ /* replaces all with this one! */
+ void replace( const OPimNotify& );
+
+ Reminders reminders()const;
+
+ /**
+ * Return
+ */
+ Alarms alarms()const;
+
+ /**
+ * Return alarm at DateTime "when". If more than one is registered at this
+ * DateTime, the first one is returned.
+ * If none was found, an empty Alarm is returned.
+ * @param when The date and time of the returned alarm
+ * @param found Returns true if anything was found.
+ * @return Returns the found alarm at given DateTime. It is empty if found is false
+ * (nothing could be found at given date and time)
+ */
+ OPimAlarm alarmAtDateTime( const QDateTime& when, bool& found ) const;
+
+ void setAlarms( const Alarms& );
+ void setReminders( const Reminders& );
+
+ /* register is a Ansi C keyword... */
+ /**
+ * This function will register the Notify to the Alarm Server
+ * or datebook depending on the type of the notify
+ */
+ void registerNotify( const OPimNotify& );
+
+ /**
+ * this will do the opposite..
+ */
+ void deregister( const OPimNotify& );
+
+ bool isEmpty()const;
+
+ /**
+ * Return all alarms as string
+ */
+ QString alarmsToString() const;
+ /**
+ * Return all notifiers as string
+ */
+ QString remindersToString() const;
+
+ /**
+ * Convert string to alarms
+ * @param str String created by alarmsToString()
+ */
+ void alarmsFromString( const QString& str );
+
+ /**
+ * Convert string to reminders
+ * @param str String created by remindersToString()
+ */
+ void remindersFromString( const QString& str );
+
+
+
+private:
+ Reminders m_rem;
+ Alarms m_al;
+
+ class Private;
+ Private *d;
+
+};
+
+#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 @@
+#include <qarray.h>
+
+#include <qpe/categories.h>
+#include <qpe/categoryselect.h>
+
+#include "opimrecord.h"
+
+Qtopia::UidGen OPimRecord::m_uidGen( Qtopia::UidGen::Qtopia );
+
+
+OPimRecord::OPimRecord( int uid )
+ : Qtopia::Record() {
+
+ m_lastHit = -1;
+ setUid( uid );
+}
+OPimRecord::~OPimRecord() {
+}
+OPimRecord::OPimRecord( const OPimRecord& rec )
+ : Qtopia::Record( rec )
+{
+ (*this) = rec;
+}
+
+OPimRecord &OPimRecord::operator=( const OPimRecord& rec) {
+ if ( this == &rec ) return *this;
+
+ Qtopia::Record::operator=( rec );
+ m_xrefman = rec.m_xrefman;
+ m_lastHit = rec.m_lastHit;
+
+ return *this;
+}
+/*
+ * category names
+ */
+QStringList OPimRecord::categoryNames( const QString& appname ) const {
+ QStringList list;
+ QArray<int> cats = categories();
+ Categories catDB;
+ catDB.load( categoryFileName() );
+
+ for (uint i = 0; i < cats.count(); i++ ) {
+ list << catDB.label( appname, cats[i] );
+ }
+
+ return list;
+}
+void OPimRecord::setCategoryNames( const QStringList& ) {
+
+}
+void OPimRecord::addCategoryName( const QString& ) {
+ Categories catDB;
+ catDB.load( categoryFileName() );
+
+
+}
+bool OPimRecord::isEmpty()const {
+ return ( uid() == 0 );
+}
+/*QString OPimRecord::crossToString()const {
+ QString str;
+ QMap<QString, QArray<int> >::ConstIterator it;
+ for (it = m_relations.begin(); it != m_relations.end(); ++it ) {
+ QArray<int> id = it.data();
+ for ( uint i = 0; i < id.size(); ++i ) {
+ str += it.key() + "," + QString::number( i ) + ";";
+ }
+ }
+ str = str.remove( str.length()-1, 1); // strip the ;
+ //qWarning("IDS " + str );
+
+ return str;
+ }*/
+/* if uid = 1 assign a new one */
+void OPimRecord::setUid( int uid ) {
+ if ( uid == 1)
+ uid = uidGen().generate();
+
+ Qtopia::Record::setUid( uid );
+};
+Qtopia::UidGen &OPimRecord::uidGen() {
+ return m_uidGen;
+}
+OPimXRefManager &OPimRecord::xrefmanager() {
+ return m_xrefman;
+}
+int OPimRecord::rtti(){
+ return 0;
+}
+
+/**
+ * now let's put our data into the stream
+ */
+/*
+ * First read UID
+ * Categories
+ * XRef
+ */
+bool OPimRecord::loadFromStream( QDataStream& stream ) {
+ int Int;
+ uint UInt;
+ stream >> Int;
+ setUid(Int);
+
+ /** Categories */
+ stream >> UInt;
+ QArray<int> array(UInt);
+ for (uint i = 0; i < UInt; i++ ) {
+ stream >> array[i];
+ }
+ setCategories( array );
+
+ /*
+ * now we do the X-Ref stuff
+ */
+ OPimXRef xref;
+ stream >> UInt;
+ for ( uint i = 0; i < UInt; i++ ) {
+ xref.setPartner( OPimXRef::One, partner( stream ) );
+ xref.setPartner( OPimXRef::Two, partner( stream ) );
+ m_xrefman.add( xref );
+ }
+
+ return true;
+}
+bool OPimRecord::saveToStream( QDataStream& stream )const {
+ /** UIDs */
+
+ stream << uid();
+
+ /** Categories */
+ stream << categories().count();
+ for ( uint i = 0; i < categories().count(); i++ ) {
+ stream << categories()[i];
+ }
+
+ /*
+ * first the XRef count
+ * then the xrefs
+ */
+ stream << m_xrefman.list().count();
+ for ( OPimXRef::ValueList::ConstIterator it = m_xrefman.list().begin();
+ it != m_xrefman.list().end(); ++it ) {
+ flush( (*it).partner( OPimXRef::One), stream );
+ flush( (*it).partner( OPimXRef::Two), stream );
+ }
+ return true;
+}
+void OPimRecord::flush( const OPimXRefPartner& par, QDataStream& str ) const{
+ str << par.service();
+ str << par.uid();
+ str << par.field();
+}
+OPimXRefPartner OPimRecord::partner( QDataStream& stream ) {
+ OPimXRefPartner par;
+ QString str;
+ int i;
+
+ stream >> str;
+ par.setService( str );
+
+ stream >> i;
+ par.setUid( i );
+
+ stream >> i ;
+ par.setField( i );
+
+ return par;
+}
+void OPimRecord::setLastHitField( int lastHit )const {
+ m_lastHit = lastHit;
+}
+int OPimRecord::lastHitField()const{
+ return m_lastHit;
+}
+QMap<QString, QString> OPimRecord::toExtraMap()const {
+ return customMap;
+}
+void OPimRecord::setExtraMap( const QMap<QString, QString>& map) {
+ customMap = map;
+}
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 @@
+#ifndef OPIE_PIM_RECORD_H
+#define OPIE_PIM_RECORD_H
+
+#include <qdatastream.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+/*
+ * we need to get customMap which is private...
+ */
+#define private protected
+#include <qpe/palmtoprecord.h>
+#undef private
+
+#include <opie/opimxrefmanager.h>
+
+/**
+ * This is the base class for
+ * all PIM Records
+ *
+ */
+class OPimRecord : public Qtopia::Record {
+public:
+ /**
+ * c'tor
+ * uid of 0 isEmpty
+ * uid of 1 will be assigned a new one
+ */
+ OPimRecord(int uid = 0);
+ ~OPimRecord();
+
+ /**
+ * copy c'tor
+ */
+ OPimRecord( const OPimRecord& rec );
+
+ /**
+ * copy operator
+ */
+ OPimRecord &operator=( const OPimRecord& );
+
+ /**
+ * category names resolved
+ */
+ QStringList categoryNames( const QString& appname )const;
+
+ /**
+ * set category names they will be resolved
+ */
+ void setCategoryNames( const QStringList& );
+
+ /**
+ * addCategoryName adds a name
+ * to the internal category list
+ */
+ void addCategoryName( const QString& );
+
+ /**
+ * if a Record isEmpty
+ * it's empty if it's 0
+ */
+ virtual bool isEmpty()const;
+
+ /**
+ * toRichText summary
+ */
+ virtual QString toRichText()const = 0;
+
+ /**
+ * a small one line summary
+ */
+ virtual QString toShortText()const = 0;
+
+ /**
+ * the name of the Record
+ */
+ virtual QString type()const = 0;
+
+ /**
+ * matches the Records the regular expression?
+ */
+ virtual bool match( const QString &regexp ) const
+ {setLastHitField( -1 );
+ return Qtopia::Record::match(QRegExp(regexp));};
+
+ /**
+ * if implemented this function returns which item has been
+ * last hit by the match() function.
+ * or -1 if not implemented or no hit has occured
+ */
+ int lastHitField()const;
+
+ /**
+ * converts the internal structure to a map
+ */
+ virtual QMap<int, QString> toMap()const = 0;
+ // virtual fromMap( const <int, QString>& map ) = 0; // Should be added in the future (eilers)
+
+ /**
+ * key value representation of extra items
+ */
+ QMap<QString, QString> toExtraMap()const;
+ void setExtraMap( const QMap<QString, QString>& );
+
+ /**
+ * the name for a recordField
+ */
+ virtual QString recordField(int)const = 0;
+
+ /**
+ * returns a reference of the
+ * Cross Reference Manager
+ * Partner 'One' is THIS PIM RECORD!
+ * 'Two' is the Partner where we link to
+ */
+ OPimXRefManager& xrefmanager();
+
+ /**
+ * set the uid
+ */
+ virtual void setUid( int uid );
+
+ /*
+ * used inside the Templates for casting
+ * REIMPLEMENT in your ....
+ */
+ static int rtti();
+
+ /**
+ * some marshalling and de marshalling code
+ * saves the OPimRecord
+ * to and from a DataStream
+ */
+ virtual bool loadFromStream(QDataStream& );
+ virtual bool saveToStream( QDataStream& stream )const;
+
+protected:
+ // need to be const cause it is called from const methods
+ mutable int m_lastHit;
+ void setLastHitField( int lastHit )const;
+ Qtopia::UidGen &uidGen();
+// QString crossToString()const;
+
+private:
+ class OPimRecordPrivate;
+ OPimRecordPrivate *d;
+ OPimXRefManager m_xrefman;
+ static Qtopia::UidGen m_uidGen;
+
+private:
+ void flush( const OPimXRefPartner&, QDataStream& stream )const;
+ OPimXRefPartner partner( QDataStream& );
+};
+
+
+
+#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 @@
+#include <qcopchannel_qws.h>
+
+#include <qpe/qcopenvelope_qws.h>
+
+#include "otodoaccess.h"
+#include "ocontactaccess.h"
+
+//#include "opimfactory.h"
+#include "opimresolver.h"
+
+OPimResolver* OPimResolver::m_self = 0l;
+
+OPimResolver::OPimResolver() {
+ /* the built in channels */
+ m_builtIns << "Todolist" << "Addressbook" << "Datebook";
+}
+OPimResolver* OPimResolver::self() {
+ if (!m_self)
+ m_self = new OPimResolver();
+
+ return m_self;
+}
+
+/*
+ * FIXME use a cache here too
+ */
+OPimRecord* OPimResolver::record( const QString& service, int uid ) {
+ OPimRecord* rec = 0l;
+ OPimBase* base = backend( service );
+
+ if ( base )
+ rec = base->record( uid );
+ delete base;
+
+ return rec;
+}
+OPimRecord* OPimResolver::record( const QString& service ) {
+ return record( serviceId( service ) );
+}
+OPimRecord* OPimResolver::record( int rtti ) {
+ OPimRecord* rec = 0l;
+ switch( rtti ) {
+ case 1: /* todolist */
+ rec = new OTodo();
+ case 2: /* contact */
+ rec = new OContact();
+ default:
+ break;
+ }
+ /*
+ * FIXME resolve externally
+ */
+ if (!rec ) {
+ ;
+ }
+ return 0l;
+}
+bool OPimResolver::isBuiltIn( const QString& str) const{
+ return m_builtIns.contains( str );
+}
+QCString OPimResolver::qcopChannel( enum BuiltIn& built)const {
+ QCString str("QPE/");
+ switch( built ) {
+ case TodoList:
+ str += "Todolist";
+ break;
+ case DateBook:
+ str += "Datebook";
+ break;
+ case AddressBook:
+ str += "Addressbook";
+ break;
+ default:
+ break;
+ }
+
+ return str;
+}
+QCString OPimResolver::qcopChannel( const QString& service )const {
+ QCString str("QPE/");
+ str += service.latin1();
+ return str;
+}
+/*
+ * Implement services!!
+ * FIXME
+ */
+QCString OPimResolver::applicationChannel( enum BuiltIn& built)const {
+ QCString str("QPE/Application/");
+ switch( built ) {
+ case TodoList:
+ str += "todolist";
+ break;
+ case DateBook:
+ str += "datebook";
+ break;
+ case AddressBook:
+ str += "addressbook";
+ break;
+ }
+
+ return str;
+}
+QCString OPimResolver::applicationChannel( const QString& service )const {
+ QCString str("QPE/Application/");
+
+ if ( isBuiltIn( service ) ) {
+ if ( service == "Todolist" )
+ str += "todolist";
+ else if ( service == "Datebook" )
+ str += "datebook";
+ else if ( service == "Addressbook" )
+ str += "addressbook";
+ }else
+ ; // FIXME for additional stuff
+
+ return str;
+}
+QStringList OPimResolver::services()const {
+ return m_builtIns;
+}
+QString OPimResolver::serviceName( int rtti ) const{
+ QString str;
+ switch ( rtti ) {
+ case TodoList:
+ str = "Todolist";
+ break;
+ case DateBook:
+ str = "Datebook";
+ break;
+ case AddressBook:
+ str = "Addressbook";
+ break;
+ default:
+ break;
+ }
+ return str;
+ // FIXME me for 3rd party
+}
+int OPimResolver::serviceId( const QString& service ) {
+ int rtti = 0;
+ if ( service == "Todolist" )
+ rtti = TodoList;
+ else if ( service == "Datebook" )
+ rtti = DateBook;
+ else if ( service == "Addressbook" )
+ rtti = AddressBook;
+
+ return rtti;
+}
+/**
+ * check if the 'service' is registered and if so we'll
+ */
+bool OPimResolver::add( const QString& service, const OPimRecord& rec) {
+ if ( QCopChannel::isRegistered( applicationChannel( service ) ) ) {
+ QByteArray data;
+ QDataStream arg(data, IO_WriteOnly );
+ if ( rec.saveToStream( arg ) ) {
+ QCopEnvelope env( applicationChannel( service ), "add(int,QByteArray)" );
+ env << rec.rtti();
+ env << data;
+ }else
+ return false;
+ }else{
+ OPimBase* base = backend( service );
+ if (!base ) return false;
+
+ base->load();
+ base->add( rec );
+ base->save();
+ delete base;
+ }
+
+ return true;
+}
+OPimBase* OPimResolver::backend( const QString& service ) {
+ return backend( serviceId( service ) );
+}
+OPimBase* OPimResolver::backend( int rtti ) {
+ OPimBase* base = 0l;
+ switch( rtti ) {
+ case TodoList:
+ base = new OTodoAccess();
+ break;
+ case DateBook:
+ break;
+ case AddressBook:
+ base = new OContactAccess("Resolver");
+ break;
+ default:
+ break;
+ }
+ // FIXME for 3rd party
+ if (!base )
+ ;
+
+ return base;
+}
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 @@
+#ifndef OPIE_PIM_RESOLVER
+#define OPIE_PIM_RESOLVER
+
+#include <qstring.h>
+#include <qvaluelist.h>
+
+#include <opie/otemplatebase.h>
+
+/**
+ * OPimResolver is a MetaClass to access
+ * available backends read only.
+ * It will be used to resolve uids + app names
+ * to full informations
+ * to traverse through a list of alarms, reminders
+ * to get access to built in PIM functionality
+ * and to more stuff
+ * THE PERFORMANCE will depend on THE BACKEND
+ * USING XML is a waste of memory!!!!!
+ */
+class OPimResolver {
+public:
+ enum BuiltIn { TodoList = 0,
+ DateBook,
+ AddressBook
+ };
+ static OPimResolver* self();
+
+
+ /**
+ * return a record for a uid
+ * and an service
+ * You've THE OWNERSHIP NOW!
+ */
+ OPimRecord *record( const QString& service, int uid );
+
+ /**
+ * return the QCopChannel for service
+ * When we will use Qtopia Services it will be used here
+ */
+ QCString qcopChannel( enum BuiltIn& )const;
+ QCString qcopChannel( const QString& service )const;
+
+ /**
+ * The Application channel (QPE/Application/name)
+ */
+ QCString applicationChannel( enum BuiltIn& )const;
+ QCString applicationChannel( const QString& service )const;
+
+ /**
+ * return a list of available services
+ */
+ QStringList services()const;
+ inline QString serviceName(int rrti )const;
+ int serviceId( const QString& Service);
+ /**
+ * add a record to a service... ;)
+ */
+ bool add( const QString& service, const OPimRecord& );
+
+
+ /**
+ * record returns an empty record for a given service.
+ * Be sure to delete it!!!
+ *
+ */
+ OPimRecord* record( const QString& service );
+ OPimRecord* record( int rtti );
+
+ /**
+ * you can cast to your
+ */
+ OPimBase* backend( const QString& service );
+ OPimBase* backend( int rtti );
+private:
+ OPimResolver();
+ void loadData();
+ inline bool isBuiltIn( const QString& )const;
+ OPimRecord* recordExtern( const QString&, int );
+ OPimRecord* recordExtern( const QString& );
+
+ static OPimResolver* m_self;
+ struct Data;
+ class Private;
+
+ Data* data;
+ Private* d;
+ QStringList m_builtIns;
+};
+
+#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 @@
+#include <qshared.h>
+
+#include "opimstate.h"
+
+/*
+ * for one int this does not make
+ * much sense but never the less
+ * we will do it for the future
+ */
+struct OPimState::Data : public QShared {
+ Data() : QShared(),state(Undefined) {
+ }
+ int state;
+};
+
+OPimState::OPimState( int state ) {
+ data = new Data;
+ data->state = state;
+}
+OPimState::OPimState( const OPimState& st) :
+ data( st.data ) {
+ /* ref up */
+ data->ref();
+}
+OPimState::~OPimState() {
+ if ( data->deref() ) {
+ delete data ;
+ data = 0;
+ }
+}
+bool OPimState::operator==( const OPimState& st) {
+ if ( data->state == st.data->state ) return true;
+
+ return false;
+}
+OPimState &OPimState::operator=( const OPimState& st) {
+ st.data->ref();
+ deref();
+ data = st.data;
+
+ return *this;
+}
+void OPimState::setState( int st) {
+ copyInternally();
+ data->state = st;
+}
+int OPimState::state()const {
+ return data->state;
+}
+void OPimState::deref() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0l;
+ }
+}
+void OPimState::copyInternally() {
+ /* we need to change it */
+ if ( data->count != 1 ) {
+ data->deref();
+ Data* d2 = new Data;
+ d2->state = data->state;
+ data = d2;
+ }
+}
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 @@
+#ifndef OPIE_PIM_STATE_H
+#define OPIE_PIM_STATE_H
+
+#include <qstring.h>
+
+/**
+ * The State of a Task
+ * This class encapsules the state of a todo
+ * and it's shared too
+ */
+/*
+ * in c a simple struct would be enough ;)
+ * g_new_state();
+ * g_do_some_thing( state_t* );
+ * ;)
+ */
+class OPimState {
+public:
+ enum State {
+ Started = 0,
+ Postponed,
+ Finished,
+ NotStarted,
+ Undefined
+ };
+ OPimState( int state = Undefined );
+ OPimState( const OPimState& );
+ ~OPimState();
+
+ bool operator==( const OPimState& );
+ OPimState &operator=( const OPimState& );
+ void setState( int state);
+ int state()const;
+private:
+ void deref();
+ inline void copyInternally();
+
+ struct Data;
+ Data* data;
+
+ class Private;
+ Private *d;
+};
+
+
+#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 @@
+#include "opimxref.h"
+
+OPimXRef::OPimXRef( const OPimXRefPartner& one, const OPimXRefPartner& two )
+ : m_partners(2)
+{
+ m_partners[0] = one;
+ m_partners[1] = two;
+}
+OPimXRef::OPimXRef()
+ : m_partners(2)
+{
+
+}
+OPimXRef::OPimXRef( const OPimXRef& ref) {
+ *this = ref;
+}
+OPimXRef::~OPimXRef() {
+}
+OPimXRef &OPimXRef::operator=( const OPimXRef& ref) {
+ m_partners = ref.m_partners;
+ m_partners.detach();
+
+ return* this;
+}
+bool OPimXRef::operator==( const OPimXRef& oper ) {
+ if ( m_partners == oper.m_partners ) return true;
+
+ return false;
+}
+OPimXRefPartner OPimXRef::partner( enum Partners par) const{
+ return m_partners[par];
+}
+void OPimXRef::setPartner( enum Partners par, const OPimXRefPartner& part) {
+ m_partners[par] = part;
+}
+bool OPimXRef::containsString( const QString& string ) const{
+ if ( m_partners[One].service() == string ||
+ m_partners[Two].service() == string ) return true;
+
+ return false;
+}
+bool OPimXRef::containsUid( int uid ) const{
+ if ( m_partners[One].uid() == uid ||
+ m_partners[Two].uid() == uid ) return true;
+
+ return false;
+}
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 @@
+#ifndef OPIM_XREF_H
+#define OPIM_XREF_H
+
+#include <qarray.h>
+#include <qvaluelist.h>
+
+#include <opie/opimxrefpartner.h>
+
+/**
+ * this is a Cross Referecne between
+ * two Cross Reference Partners
+ */
+class OPimXRef {
+public:
+ typedef QValueList<OPimXRef> ValueList;
+ enum Partners { One, Two };
+ OPimXRef( const OPimXRefPartner& ONE, const OPimXRefPartner& );
+ OPimXRef();
+ OPimXRef( const OPimXRef& );
+ ~OPimXRef();
+
+ OPimXRef &operator=( const OPimXRef& );
+ bool operator==( const OPimXRef& );
+
+ OPimXRefPartner partner( enum Partners )const;
+
+ void setPartner( enum Partners, const OPimXRefPartner& );
+
+ bool containsString( const QString& service)const;
+ bool containsUid( int uid )const;
+
+private:
+ QArray<OPimXRefPartner> m_partners;
+
+ class Private;
+ Private *d;
+};
+
+#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 @@
+#include "opimxrefmanager.h"
+
+
+OPimXRefManager::OPimXRefManager() {
+}
+OPimXRefManager::OPimXRefManager( const OPimXRefManager& ref) {
+ m_list = ref.m_list;
+}
+OPimXRefManager::~OPimXRefManager() {
+}
+OPimXRefManager &OPimXRefManager::operator=( const OPimXRefManager& ref) {
+ m_list = ref.m_list;
+ return *this;
+}
+bool OPimXRefManager::operator==( const OPimXRefManager& /*ref*/) {
+ // if ( m_list == ref.m_list ) return true;
+
+ return false;
+}
+void OPimXRefManager::add( const OPimXRef& ref) {
+ m_list.append( ref );
+}
+void OPimXRefManager::remove( const OPimXRef& ref) {
+ m_list.remove( ref );
+}
+void OPimXRefManager::replace( const OPimXRef& ref) {
+ m_list.remove( ref );
+ m_list.append( ref );
+}
+void OPimXRefManager::clear() {
+ m_list.clear();
+}
+QStringList OPimXRefManager::apps()const {
+ OPimXRef::ValueList::ConstIterator it;
+ QStringList list;
+
+ QString str;
+ for ( it = m_list.begin(); it != m_list.end(); ++it ) {
+ str = (*it).partner( OPimXRef::One ).service();
+ if ( !list.contains( str ) ) list << str;
+
+ str = (*it).partner( OPimXRef::Two ).service();
+ if ( !list.contains( str ) ) list << str;
+ }
+ return list;
+}
+OPimXRef::ValueList OPimXRefManager::list()const {
+ return m_list;
+}
+OPimXRef::ValueList OPimXRefManager::list( const QString& appName )const{
+ OPimXRef::ValueList list;
+ OPimXRef::ValueList::ConstIterator it;
+
+ for ( it = m_list.begin(); it != m_list.end(); ++it ) {
+ if ( (*it).containsString( appName ) )
+ list.append( (*it) );
+ }
+
+ return list;
+}
+OPimXRef::ValueList OPimXRefManager::list( int uid )const {
+ OPimXRef::ValueList list;
+ OPimXRef::ValueList::ConstIterator it;
+
+ for ( it = m_list.begin(); it != m_list.end(); ++it ) {
+ if ( (*it).containsUid( uid ) )
+ list.append( (*it) );
+ }
+
+ return list;
+}
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 @@
+#ifndef OPIM_XREF_MANAGER_H
+#define OPIM_XREF_MANAGER_H
+
+#include <qstringlist.h>
+
+#include <opie/opimxref.h>
+
+/**
+ * This is a simple manager for
+ * OPimXRefs.
+ * It allows addition, removing, replacing
+ * clearing and 'querying' the XRef...
+ */
+class OPimXRefManager {
+public:
+ OPimXRefManager();
+ OPimXRefManager( const OPimXRefManager& );
+ ~OPimXRefManager();
+
+ OPimXRefManager& operator=( const OPimXRefManager& );
+ bool operator==( const OPimXRefManager& );
+
+ void add( const OPimXRef& );
+ void remove( const OPimXRef& );
+ void replace( const OPimXRef& );
+
+ void clear();
+
+ /**
+ * apps participating
+ */
+ QStringList apps()const;
+ OPimXRef::ValueList list()const;
+ OPimXRef::ValueList list( const QString& service )const;
+ OPimXRef::ValueList list( int uid )const;
+
+private:
+ OPimXRef::ValueList m_list;
+ class Private;
+ Private *d;
+};
+
+#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 @@
+#include "opimxrefpartner.h"
+
+OPimXRefPartner::OPimXRefPartner( const QString& appName,
+ int uid, int field )
+ : m_app(appName), m_uid(uid), m_field( field ) {
+}
+OPimXRefPartner::OPimXRefPartner( const OPimXRefPartner& ref ) {
+ *this = ref;
+}
+OPimXRefPartner::~OPimXRefPartner() {
+}
+OPimXRefPartner &OPimXRefPartner::operator=( const OPimXRefPartner& par ) {
+ m_app = par.m_app;
+ m_uid = par.m_uid;
+ m_field = par.m_field;
+
+ return *this;
+}
+bool OPimXRefPartner::operator==( const OPimXRefPartner& par ) {
+ if ( m_app != par.m_app ) return false;
+ if ( m_uid != par.m_uid ) return false;
+ if ( m_field != par.m_field ) return false;
+
+ return true;
+}
+QString OPimXRefPartner::service()const {
+ return m_app;
+}
+int OPimXRefPartner::uid()const {
+ return m_uid;
+}
+int OPimXRefPartner::field()const {
+ return m_field;
+}
+void OPimXRefPartner::setService( const QString& appName ) {
+ m_app = appName;
+}
+void OPimXRefPartner::setUid( int uid ) {
+ m_uid = uid;
+}
+void OPimXRefPartner::setField( int field ) {
+ m_field = field;
+}
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 @@
+#ifndef OPIM_XREF_PARTNER_H
+#define OPIM_XREF_PARTNER_H
+
+#include <qstring.h>
+
+/**
+ * This class represents one partner
+ * of a Cross Reference.
+ * In Opie one application
+ * can link one uid
+ * with one tableId( fieldId ) to another.
+ */
+class OPimXRefPartner {
+public:
+ OPimXRefPartner( const QString& service = QString::null,
+ int uid = 0, int field = -1 );
+ OPimXRefPartner( const OPimXRefPartner& );
+ OPimXRefPartner& operator=( const OPimXRefPartner& );
+ ~OPimXRefPartner();
+
+ bool operator==(const OPimXRefPartner& );
+
+ QString service()const;
+ int uid()const;
+ int field()const;
+
+ void setService( const QString& service );
+ void setUid( int uid );
+ void setField( int field );
+private:
+ QString m_app;
+ int m_uid;
+ int m_field;
+
+ class Private;
+ Private* d;
+};
+
+
+#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 @@
+
+#ifndef OPIE_RECORD_LIST_H
+#define OPIE_RECORD_LIST_H
+
+#include <qarray.h>
+
+#include "otemplatebase.h"
+#include "opimrecord.h"
+
+class ORecordListIteratorPrivate;
+/**
+ * Our List Iterator
+ * it behaves like STL or Qt
+ *
+ * for(it = list.begin(); it != list.end(); ++it )
+ * doSomeCoolStuff( (*it) );
+ */
+template <class T> class ORecordList;
+template <class T = OPimRecord>
+class ORecordListIterator {
+ friend class ORecordList<T>;
+public:
+ typedef OTemplateBase<T> Base;
+
+ /**
+ * The c'tor used internally from
+ * ORecordList
+ */
+ ORecordListIterator( const QArray<int>, const Base* );
+
+ /**
+ * The standard c'tor
+ */
+ ORecordListIterator();
+ ~ORecordListIterator();
+
+ ORecordListIterator( const ORecordListIterator& );
+ ORecordListIterator &operator=(const ORecordListIterator& );
+
+ /**
+ * a * operator ;)
+ * use it like this T = (*it);
+ */
+ T operator*();
+ ORecordListIterator &operator++();
+ ORecordListIterator &operator--();
+
+ bool operator==( const ORecordListIterator& it );
+ bool operator!=( const ORecordListIterator& it );
+
+ /**
+ * the current item
+ */
+ uint current()const;
+
+ /**
+ * the number of items
+ */
+ uint count()const;
+
+ /**
+ * sets the current item
+ */
+ void setCurrent( uint cur );
+
+private:
+ QArray<int> m_uids;
+ uint m_current;
+ const Base* m_temp;
+ bool m_end : 1;
+ T m_record;
+ bool m_direction :1;
+
+ /* d pointer for future versions */
+ ORecordListIteratorPrivate *d;
+};
+
+class ORecordListPrivate;
+/**
+ * The recordlist used as a return type
+ * from OPimAccessTemplate
+ */
+template <class T = OPimRecord >
+class ORecordList {
+public:
+ typedef OTemplateBase<T> Base;
+ typedef ORecordListIterator<T> Iterator;
+
+ /**
+ * c'tor
+ */
+ ORecordList () {
+ }
+ORecordList( const QArray<int>& ids,
+ const Base* );
+ ~ORecordList();
+
+ /**
+ * the first iterator
+ */
+ Iterator begin();
+
+ /**
+ * the end
+ */
+ Iterator end();
+
+ /**
+ * the number of items in the list
+ */
+ uint count()const;
+
+ T operator[]( uint i );
+ int uidAt(uint i );
+
+ /**
+ * Remove the contact with given uid
+ */
+ bool remove( int uid );
+
+ /*
+ ConstIterator begin()const;
+ ConstIterator end()const;
+ */
+private:
+ QArray<int> m_ids;
+ const Base* m_acc;
+ ORecordListPrivate *d;
+};
+
+/* ok now implement it */
+template <class T>
+ORecordListIterator<T>::ORecordListIterator() {
+ m_current = 0;
+ m_temp = 0l;
+ m_end = true;
+ m_record = T();
+ /* forward */
+ m_direction = TRUE;
+}
+template <class T>
+ORecordListIterator<T>::~ORecordListIterator() {
+/* nothing to delete */
+}
+
+template <class T>
+ORecordListIterator<T>::ORecordListIterator( const ORecordListIterator<T>& it) {
+// qWarning("ORecordListIterator copy c'tor");
+ m_uids = it.m_uids;
+ m_current = it.m_current;
+ m_temp = it.m_temp;
+ m_end = it.m_end;
+ m_record = it.m_record;
+ m_direction = it.m_direction;
+}
+
+template <class T>
+ORecordListIterator<T> &ORecordListIterator<T>::operator=( const ORecordListIterator<T>& it) {
+ m_uids = it.m_uids;
+ m_current = it.m_current;
+ m_temp = it.m_temp;
+ m_end = it.m_end;
+ m_record = it.m_record;
+
+ return *this;
+}
+
+template <class T>
+T ORecordListIterator<T>::operator*() {
+ //qWarning("operator* %d %d", m_current, m_uids[m_current] );
+ if (!m_end )
+ m_record = m_temp->find( m_uids[m_current], m_uids, m_current,
+ m_direction ? Base::Forward :
+ Base::Reverse );
+ else
+ m_record = T();
+
+ return m_record;
+}
+
+template <class T>
+ORecordListIterator<T> &ORecordListIterator<T>::operator++() {
+ m_direction = true;
+ if (m_current < m_uids.count() ) {
+ m_end = false;
+ ++m_current;
+ }else
+ m_end = true;
+
+ return *this;
+}
+template <class T>
+ORecordListIterator<T> &ORecordListIterator<T>::operator--() {
+ m_direction = false;
+ if ( m_current > 0 ) {
+ --m_current;
+ m_end = false;
+ } else
+ m_end = true;
+
+ return *this;
+}
+
+template <class T>
+bool ORecordListIterator<T>::operator==( const ORecordListIterator<T>& it ) {
+
+ /* if both are at we're the same.... */
+ if ( m_end == it.m_end ) return true;
+
+ if ( m_uids != it.m_uids ) return false;
+ if ( m_current != it.m_current ) return false;
+ if ( m_temp != it.m_temp ) return false;
+
+ return true;
+}
+template <class T>
+bool ORecordListIterator<T>::operator!=( const ORecordListIterator<T>& it ) {
+ return !(*this == it );
+}
+template <class T>
+ORecordListIterator<T>::ORecordListIterator( const QArray<int> uids,
+ const Base* t )
+ : m_uids( uids ), m_current( 0 ), m_temp( t ), m_end( false ),
+ m_direction( false )
+{
+ /* if the list is empty we're already at the end of the list */
+ if (uids.count() == 0 )
+ m_end = true;
+}
+template <class T>
+uint ORecordListIterator<T>::current()const {
+ return m_current;
+}
+template <class T>
+void ORecordListIterator<T>::setCurrent( uint cur ) {
+ if( cur < m_uids.count() ) {
+ m_end = false;
+ m_current= cur;
+ }
+}
+template <class T>
+uint ORecordListIterator<T>::count()const {
+ return m_uids.count();
+}
+template <class T>
+ORecordList<T>::ORecordList( const QArray<int>& ids,
+ const Base* acc )
+ : m_ids( ids ), m_acc( acc )
+{
+}
+template <class T>
+ORecordList<T>::~ORecordList() {
+/* nothing to do here */
+}
+template <class T>
+typename ORecordList<T>::Iterator ORecordList<T>::begin() {
+ Iterator it( m_ids, m_acc );
+ return it;
+}
+template <class T>
+typename ORecordList<T>::Iterator ORecordList<T>::end() {
+ Iterator it( m_ids, m_acc );
+ it.m_end = true;
+ it.m_current = m_ids.count();
+
+ return it;
+}
+template <class T>
+uint ORecordList<T>::count()const {
+return m_ids.count();
+}
+template <class T>
+T ORecordList<T>::operator[]( uint i ) {
+ if ( i >= m_ids.count() )
+ return T();
+ /* forward */
+ return m_acc->find( m_ids[i], m_ids, i );
+}
+template <class T>
+int ORecordList<T>::uidAt( uint i ) {
+ return m_ids[i];
+}
+
+template <class T>
+bool ORecordList<T>::remove( int uid ) {
+ QArray<int> copy( m_ids.count() );
+ int counter = 0;
+ bool ret_val = false;
+
+ for (uint i = 0; i < m_ids.count(); i++){
+ if ( m_ids[i] != uid ){
+ copy[counter++] = m_ids[i];
+
+ }else
+ ret_val = true;
+ }
+
+ copy.resize( counter );
+ m_ids = copy;
+
+
+ return ret_val;
+}
+
+
+#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 @@
+#include <time.h>
+
+#include <qshared.h>
+
+#include <qtopia/timeconversion.h>
+
+#include "otimezone.h"
+#include "orecur.h"
+
+struct ORecur::Data : public QShared {
+ Data() : QShared() {
+ type = ORecur::NoRepeat;
+ freq = -1;
+ days = 0;
+ pos = 0;
+ create = QDateTime::currentDateTime();
+ hasEnd = FALSE;
+ end = QDate::currentDate();
+ }
+ char days; // Q_UINT8 for 8 seven days;)
+ ORecur::RepeatType type;
+ int freq;
+ int pos;
+ bool hasEnd : 1;
+ QDate end;
+ QDateTime create;
+ int rep;
+ QString app;
+ ExceptionList list;
+ QDate start;
+};
+
+
+ORecur::ORecur() {
+ data = new Data;
+}
+
+ORecur::ORecur( const QMap<int, QString>& map )
+{
+ ORecur();
+ fromMap( map );
+}
+
+
+ORecur::ORecur( const ORecur& rec)
+ : data( rec.data )
+{
+ data->ref();
+}
+ORecur::~ORecur() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0l;
+ }
+}
+void ORecur::deref() {
+ if ( data->deref() ) {
+ delete data;
+ data = 0l;
+ }
+}
+bool ORecur::operator==( const ORecur& )const {
+ return false;
+}
+ORecur &ORecur::operator=( const ORecur& re) {
+ if ( *this == re ) return *this;
+
+ re.data->ref();
+ deref();
+ data = re.data;
+
+ return *this;
+}
+bool ORecur::doesRecur()const {
+ return !( type() == NoRepeat );
+}
+/*
+ * we try to be smart here
+ *
+ */
+bool ORecur::doesRecur( const QDate& date ) {
+ /* the day before the recurrance */
+ QDate da = date.addDays(-1);
+
+ QDate recur;
+ if (!nextOcurrence( da, recur ) )
+ return false;
+
+ return (recur == date);
+}
+// FIXME unuglify!
+// GPL from Datebookdb.cpp
+// FIXME exception list!
+bool ORecur::nextOcurrence( const QDate& from, QDate& next ) {
+ bool stillLooking;
+ stillLooking = p_nextOccurrence( from, next );
+ while ( stillLooking && data->list.contains(next) )
+ stillLooking = p_nextOccurrence( next.addDays(1), next );
+
+ return stillLooking;
+}
+bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) {
+
+ // easy checks, first are we too far in the future or too far in the past?
+ QDate tmpDate;
+ int freq = frequency();
+ int diff, diff2, a;
+ int iday, imonth, iyear;
+ int dayOfWeek = 0;
+ int firstOfWeek = 0;
+ int weekOfMonth;
+
+
+ if (hasEndDate() && endDate() < from)
+ return FALSE;
+
+ if (start() >= from ) {
+ next = start();
+ return TRUE;
+ }
+
+ switch ( type() ) {
+ case Weekly:
+ /* weekly is just daily by 7 */
+ /* first convert the repeatPattern.Days() mask to the next
+ day of week valid after from */
+ dayOfWeek = from.dayOfWeek();
+ dayOfWeek--; /* we want 0-6, doco for above specs 1-7 */
+
+ /* this is done in case freq > 1 and from in week not
+ for this round */
+ // firstOfWeek = 0; this is already done at decl.
+ while(!((1 << firstOfWeek) & days() ))
+ firstOfWeek++;
+
+ /* there is at least one 'day', or there would be no event */
+ while(!((1 << (dayOfWeek % 7)) & days() ))
+ dayOfWeek++;
+
+ dayOfWeek = dayOfWeek % 7; /* the actual day of week */
+ dayOfWeek -= start().dayOfWeek() -1;
+
+ firstOfWeek = firstOfWeek % 7; /* the actual first of week */
+ firstOfWeek -= start().dayOfWeek() -1;
+
+ // dayOfWeek may be negitive now
+ // day of week is number of days to add to start day
+
+ freq *= 7;
+ // FALL-THROUGH !!!!!
+ case Daily:
+ // the add is for the possible fall through from weekly */
+ if(start().addDays(dayOfWeek) > from) {
+ /* first week exception */
+ next = QDate(start().addDays(dayOfWeek) );
+ if ((next > endDate())
+ && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ }
+ /* if from is middle of a non-week */
+
+ diff = start().addDays(dayOfWeek).daysTo(from) % freq;
+ diff2 = start().addDays(firstOfWeek).daysTo(from) % freq;
+
+ if(diff != 0)
+ diff = freq - diff;
+ if(diff2 != 0)
+ diff2 = freq - diff2;
+ diff = QMIN(diff, diff2);
+
+ next = QDate(from.addDays(diff));
+ if ( (next > endDate())
+ && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ case MonthlyDay:
+ iday = from.day();
+ iyear = from.year();
+ imonth = from.month();
+ /* find equivelent day of month for this month */
+ dayOfWeek = start().dayOfWeek();
+ weekOfMonth = (start().day() - 1) / 7;
+
+ /* work out when the next valid month is */
+ a = from.year() - start().year();
+ a *= 12;
+ a = a + (imonth - start().month());
+ /* a is e.start()monthsFrom(from); */
+ if(a % freq) {
+ a = freq - (a % freq);
+ imonth = from.month() + a;
+ if (imonth > 12) {
+ imonth--;
+ iyear += imonth / 12;
+ imonth = imonth % 12;
+ imonth++;
+ }
+ }
+ /* imonth is now the first month after or on
+ from that matches the frequency given */
+
+ /* find for this month */
+ tmpDate = QDate( iyear, imonth, 1 );
+
+ iday = 1;
+ iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
+ iday += 7 * weekOfMonth;
+ while (iday > tmpDate.daysInMonth()) {
+ imonth += freq;
+ if (imonth > 12) {
+ imonth--;
+ iyear += imonth / 12;
+ imonth = imonth % 12;
+ imonth++;
+ }
+ tmpDate = QDate( iyear, imonth, 1 );
+ /* these loops could go for a while, check end case now */
+ if ((tmpDate > endDate()) && hasEndDate() )
+ return FALSE;
+ iday = 1;
+ iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
+ iday += 7 * weekOfMonth;
+ }
+ tmpDate = QDate(iyear, imonth, iday);
+
+ if (tmpDate >= from) {
+ next = tmpDate;
+ if ((next > endDate() ) && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ }
+
+ /* need to find the next iteration */
+ do {
+ imonth += freq;
+ if (imonth > 12) {
+ imonth--;
+ iyear += imonth / 12;
+ imonth = imonth % 12;
+ imonth++;
+ }
+ tmpDate = QDate( iyear, imonth, 1 );
+ /* these loops could go for a while, check end case now */
+ if ((tmpDate > endDate()) && hasEndDate() )
+ return FALSE;
+ iday = 1;
+ iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
+ iday += 7 * weekOfMonth;
+ } while (iday > tmpDate.daysInMonth());
+ tmpDate = QDate(iyear, imonth, iday);
+
+ next = tmpDate;
+ if ((next > endDate()) && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ case MonthlyDate:
+ iday = start().day();
+ iyear = from.year();
+ imonth = from.month();
+
+ a = from.year() - start().year();
+ a *= 12;
+ a = a + (imonth - start().month());
+ /* a is e.start()monthsFrom(from); */
+ if(a % freq) {
+ a = freq - (a % freq);
+ imonth = from.month() + a;
+ if (imonth > 12) {
+ imonth--;
+ iyear += imonth / 12;
+ imonth = imonth % 12;
+ imonth++;
+ }
+ }
+ /* imonth is now the first month after or on
+ from that matches the frequencey given */
+
+ /* this could go for a while, worse case, 4*12 iterations, probably */
+ while(!QDate::isValid(iyear, imonth, iday) ) {
+ imonth += freq;
+ if (imonth > 12) {
+ imonth--;
+ iyear += imonth / 12;
+ imonth = imonth % 12;
+ imonth++;
+ }
+ /* these loops could go for a while, check end case now */
+ if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
+ return FALSE;
+ }
+
+ if(QDate(iyear, imonth, iday) >= from) {
+ /* done */
+ next = QDate(iyear, imonth, iday);
+ if ((next > endDate()) && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ }
+
+ /* ok, need to cycle */
+ imonth += freq;
+ imonth--;
+ iyear += imonth / 12;
+ imonth = imonth % 12;
+ imonth++;
+
+ while(!QDate::isValid(iyear, imonth, iday) ) {
+ imonth += freq;
+ imonth--;
+ iyear += imonth / 12;
+ imonth = imonth % 12;
+ imonth++;
+ if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
+ return FALSE;
+ }
+
+ next = QDate(iyear, imonth, iday);
+ if ((next > endDate()) && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ case Yearly:
+ iday = start().day();
+ imonth = start().month();
+ iyear = from.year(); // after all, we want to start in this year
+
+ diff = 1;
+ if(imonth == 2 && iday > 28) {
+ /* leap year, and it counts, calculate actual frequency */
+ if(freq % 4)
+ if (freq % 2)
+ freq = freq * 4;
+ else
+ freq = freq * 2;
+ /* else divides by 4 already, leave freq alone */
+ diff = 4;
+ }
+
+ a = from.year() - start().year();
+ if(a % freq) {
+ a = freq - (a % freq);
+ iyear = iyear + a;
+ }
+
+ /* under the assumption we won't hit one of the special not-leap years twice */
+ if(!QDate::isValid(iyear, imonth, iday)) {
+ /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */
+ iyear += freq;
+ }
+
+ if(QDate(iyear, imonth, iday) >= from) {
+ next = QDate(iyear, imonth, iday);
+
+ if ((next > endDate()) && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ }
+ /* iyear == from.year(), need to advance again */
+ iyear += freq;
+ /* under the assumption we won't hit one of the special not-leap years twice */
+ if(!QDate::isValid(iyear, imonth, iday)) {
+ /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */
+ iyear += freq;
+ }
+
+ next = QDate(iyear, imonth, iday);
+ if ((next > endDate()) && hasEndDate() )
+ return FALSE;
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+ORecur::RepeatType ORecur::type()const{
+ return data->type;
+}
+int ORecur::frequency()const {
+ return data->freq;
+}
+int ORecur::position()const {
+ return data->pos;
+}
+char ORecur::days() const{
+ return data->days;
+}
+bool ORecur::hasEndDate()const {
+ return data->hasEnd;
+}
+QDate ORecur::endDate()const {
+ return data->end;
+}
+QDate ORecur::start()const{
+ return data->start;
+}
+QDateTime ORecur::createdDateTime()const {
+ return data->create;
+}
+int ORecur::repetition()const {
+ return data->rep;
+}
+QString ORecur::service()const {
+ return data->app;
+}
+ORecur::ExceptionList& ORecur::exceptions() {
+ return data->list;
+}
+void ORecur::setType( const RepeatType& z) {
+ checkOrModify();
+ data->type = z;
+}
+void ORecur::setFrequency( int freq ) {
+ checkOrModify();
+ data->freq = freq;
+}
+void ORecur::setPosition( int pos ) {
+ checkOrModify();
+ data->pos = pos;
+}
+void ORecur::setDays( char c ) {
+ checkOrModify();
+ data->days = c;
+}
+void ORecur::setEndDate( const QDate& dt) {
+ checkOrModify();
+ data->end = dt;
+}
+void ORecur::setCreatedDateTime( const QDateTime& t) {
+ checkOrModify();
+ data->create = t;
+}
+void ORecur::setHasEndDate( bool b) {
+ checkOrModify();
+ data->hasEnd = b;
+}
+void ORecur::setRepitition( int rep ) {
+ checkOrModify();
+ data->rep = rep;
+}
+void ORecur::setService( const QString& app ) {
+ checkOrModify();
+ data->app = app;
+}
+void ORecur::setStart( const QDate& dt ) {
+ checkOrModify();
+ data->start = dt;
+}
+void ORecur::checkOrModify() {
+ if ( data->count != 1 ) {
+ data->deref();
+ Data* d2 = new Data;
+ d2->days = data->days;
+ d2->type = data->type;
+ d2->freq = data->freq;
+ d2->pos = data->pos;
+ d2->hasEnd = data->hasEnd;
+ d2->end = data->end;
+ d2->create = data->create;
+ d2->rep = data->rep;
+ d2->app = data->app;
+ d2->list = data->list;
+ d2->start = data->start;
+ data = d2;
+ }
+}
+QString ORecur::toString()const {
+ QString buf;
+ QMap<int, QString> recMap = toMap();
+
+ buf += " rtype=\"";
+ buf += recMap[ORecur::RType];
+ buf += "\"";
+ if (data->days > 0 )
+ buf += " rweekdays=\"" + recMap[ORecur::RWeekdays] + "\"";
+ if ( data->pos != 0 )
+ buf += " rposition=\"" + recMap[ORecur::RPosition] + "\"";
+
+ buf += " rfreq=\"" + recMap[ORecur::RFreq] + "\"";
+ buf += " rhasenddate=\"" + recMap[ORecur::RHasEndDate]+ "\"";
+ if ( data->hasEnd )
+ buf += " enddt=\""
+ + recMap[ORecur::EndDate]
+ + "\"";
+ buf += " created=\"" + recMap[ORecur::Created] + "\"";
+
+ if ( data->list.isEmpty() ) return buf;
+ buf += " exceptions=\"";
+ buf += recMap[ORecur::Exceptions];
+ buf += "\" ";
+
+ return buf;
+}
+
+QString ORecur::rTypeString() const
+{
+ QString retString;
+ switch ( data->type ) {
+ case ORecur::Daily:
+ retString = "Daily";
+ break;
+ case ORecur::Weekly:
+ retString = "Weekly";
+ break;
+ case ORecur::MonthlyDay:
+ retString = "MonthlyDay";
+ break;
+ case ORecur::MonthlyDate:
+ retString = "MonthlyDate";
+ break;
+ case ORecur::Yearly:
+ retString = "Yearly";
+ break;
+ default:
+ retString = "NoRepeat";
+ break;
+
+ }
+
+ return retString;
+}
+
+QMap<QString, ORecur::RepeatType> ORecur::rTypeValueConvertMap() const
+{
+ QMap<QString, RepeatType> convertMap;
+
+ convertMap.insert( QString( "Daily" ), ORecur::Daily );
+ convertMap.insert( QString( "Weekly" ), ORecur::Weekly );
+ convertMap.insert( QString( "MonthlyDay" ), ORecur::MonthlyDay );
+ convertMap.insert( QString( "MonthlyDate" ), ORecur::MonthlyDate );
+ convertMap.insert( QString( "Yearly" ), ORecur::Yearly );
+ convertMap.insert( QString( "NoRepeat" ), ORecur::NoRepeat );
+
+ return convertMap;
+}
+
+
+QMap<int, QString> ORecur::toMap() const
+{
+ QMap<int, QString> retMap;
+
+ retMap.insert( ORecur::RType, rTypeString() );
+ retMap.insert( ORecur::RWeekdays, QString::number( static_cast<int>( data->days ) ) );
+ retMap.insert( ORecur::RPosition, QString::number(data->pos ) );
+ retMap.insert( ORecur::RFreq, QString::number( data->freq ) );
+ retMap.insert( ORecur::RHasEndDate, QString::number( static_cast<int>( data->hasEnd ) ) );
+ if( data -> hasEnd )
+ retMap.insert( ORecur::EndDate, QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) );
+ retMap.insert( ORecur::Created, QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) );
+
+ if ( data->list.isEmpty() ) return retMap;
+
+ // save exceptions list here!!
+ ExceptionList::ConstIterator it;
+ ExceptionList list = data->list;
+ QString exceptBuf;
+ QDate date;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ date = (*it);
+ if ( it != list.begin() ) exceptBuf += " ";
+
+ exceptBuf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() );
+ }
+
+ retMap.insert( ORecur::Exceptions, exceptBuf );
+
+ return retMap;
+}
+
+void ORecur::fromMap( const QMap<int, QString>& map )
+{
+ QMap<QString, RepeatType> repTypeMap = rTypeValueConvertMap();
+
+ data -> type = repTypeMap[ map [ORecur::RType] ];
+ data -> days = (char) map[ ORecur::RWeekdays ].toInt();
+ data -> pos = map[ ORecur::RPosition ].toInt();
+ data -> freq = map[ ORecur::RFreq ].toInt();
+ data -> hasEnd= map[ ORecur::RHasEndDate ].toInt() ? true : false;
+ OTimeZone utc = OTimeZone::utc();
+ if ( data -> hasEnd ){
+ data -> end = utc.fromUTCDateTime( (time_t) map[ ORecur::EndDate ].toLong() ).date();
+ }
+ data -> create = utc.fromUTCDateTime( (time_t) map[ ORecur::Created ].toLong() ).date();
+
+#if 0
+ // FIXME: Exceptions currently not supported...
+ // Convert the list of exceptions from QString into ExceptionList
+ data -> list.clear();
+ QString exceptStr = map[ ORecur::Exceptions ];
+ QStringList exceptList = QStringList::split( " ", exceptStr );
+ ...
+#endif
+
+
+}
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 @@
+/*
+ * GPL from TT
+ */
+
+#ifndef OPIE_RECUR_H
+#define OPIE_RECUR_H
+
+#include <sys/types.h>
+
+#include <qdatetime.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+
+
+/**
+ * Class to handle Recurrencies..
+ */
+
+class ORecur {
+public:
+ typedef QValueList<QDate> ExceptionList;
+ enum RepeatType{ NoRepeat = -1, Daily, Weekly, MonthlyDay,
+ MonthlyDate, Yearly };
+ enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08,
+ FRI = 0x10, SAT = 0x20, SUN = 0x40 };
+ enum Fields{ RType = 0, RWeekdays, RPosition, RFreq, RHasEndDate,
+ EndDate, Created, Exceptions };
+
+ ORecur();
+ ORecur( const QMap<int, QString>& map );
+ ORecur( const ORecur& );
+ ~ORecur();
+
+ ORecur &operator=( const ORecur& );
+ bool operator==(const ORecur& )const;
+
+ bool doesRecur()const;
+ /* if it recurrs on that day */
+ bool doesRecur( const QDate& );
+ RepeatType type()const;
+ int frequency()const;
+ int position()const;
+ char days()const;
+ bool hasEndDate()const;
+ QDate start()const;
+ QDate endDate()const;
+ QDateTime createdDateTime()const;
+ /**
+ * starting on monday=0, sunday=6
+ * for convience
+ */
+ bool repeatOnWeekDay( int day )const;
+
+ /**
+ * FromWhereToStart is not included!!!
+ */
+ bool nextOcurrence( const QDate& FromWhereToStart, QDate &recurDate );
+
+ /**
+ * The module this ORecur belongs to
+ */
+ QString service()const;
+
+ /*
+ * reference to the exception list
+ */
+ ExceptionList &exceptions();
+
+ /**
+ * the current repetition
+ */
+ int repetition()const;
+
+ void setType( const RepeatType& );
+ void setFrequency( int freq );
+ void setPosition( int pos );
+ void setDays( char c);
+ void setEndDate( const QDate& dt );
+ void setStart( const QDate& dt );
+ void setCreatedDateTime( const QDateTime& );
+ void setHasEndDate( bool b );
+ void setRepitition(int );
+
+ void setService( const QString& ser );
+
+ QMap<int, QString> toMap() const;
+ void fromMap( const QMap<int, QString>& map );
+
+ /* almost internal */
+ QString toString()const;
+private:
+ bool p_nextOccurrence( const QDate& from, QDate& next );
+ void deref();
+ inline void checkOrModify();
+
+ /* Converts rType to String */
+ QString rTypeString() const;
+ /* Returns a map to convert Stringname for RType to RepeatType */
+ QMap<QString, RepeatType> rTypeValueConvertMap() const;
+
+ class Data;
+ Data* data;
+ class ORecurPrivate;
+ ORecurPrivate *d;
+};
+
+#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 @@
+#ifndef OPIE_TEMPLATE_BASE_H
+#define OPIE_TEMPLATE_BASE_H
+
+#include <qarray.h>
+
+#include <opie/opimrecord.h>
+
+
+/**
+ * Templates do not have a base class, This is why
+ * we've this class
+ * this is here to give us the possibility
+ * to have a common base class
+ * You may not want to use that interface internaly
+ * POOR mans interface
+ */
+class OPimBasePrivate;
+struct OPimBase {
+ /**
+ * return the rtti
+ */
+ virtual int rtti()= 0;
+ virtual OPimRecord* record()const = 0;
+ virtual OPimRecord* record(int uid)const = 0;
+ virtual bool add( const OPimRecord& ) = 0;
+ virtual bool remove( int uid ) = 0;
+ virtual bool remove( const OPimRecord& ) = 0;
+ virtual void clear() = 0;
+ virtual bool load() = 0;
+ virtual bool save() = 0;
+ virtual QArray<int> records()const = 0;
+ /*
+ * ADD editing here?
+ * -zecke
+ */
+private:
+ OPimBasePrivate* d;
+
+};
+/**
+ * internal template base
+ * T needs to implement the copy c'tor!!!
+ */
+class OTemplateBasePrivate;
+template <class T = OPimRecord>
+class OTemplateBase : public OPimBase {
+public:
+ enum CacheDirection { Forward=0, Reverse };
+ OTemplateBase() {
+ };
+ virtual ~OTemplateBase() {
+ }
+ virtual T find( int uid )const = 0;
+
+ /**
+ * read ahead find
+ */
+ virtual T find( int uid, const QArray<int>& items,
+ uint current, CacheDirection dir = Forward )const = 0;
+ virtual void cache( const T& )const = 0;
+ virtual void setSaneCacheSize( int ) = 0;
+
+ /* reimplement of OPimBase */
+ int rtti();
+ OPimRecord* record()const;
+ OPimRecord* record(int uid )const;
+ static T* rec();
+
+private:
+ OTemplateBasePrivate *d;
+};
+
+/*
+ * implementation
+ */
+template <class T>
+int
+OTemplateBase<T>::rtti() {
+ return T::rtti();
+}
+template <class T>
+OPimRecord* OTemplateBase<T>::record()const {
+ T* t = new T;
+ return t;
+}
+template <class T>
+OPimRecord* OTemplateBase<T>::record(int uid )const {
+ T t2 = find(uid );
+ T* t1 = new T(t2);
+
+ return t1;
+};
+template <class T>
+T* OTemplateBase<T>::rec() {
+ return new T;
+}
+
+#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 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+
+#include "otimezone.h"
+
+namespace {
+
+ QDateTime utcTime( time_t t) {
+ tm* broken = ::gmtime( &t );
+ QDateTime ret;
+ ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) );
+ ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) );
+ return ret;
+ }
+ QDateTime utcTime( time_t t, const QString& zone) {
+ QCString org = ::getenv( "TZ" );
+#ifndef Q_OS_MACX // Following line causes bus errors on Mac
+ ::setenv( "TZ", zone.latin1(), true );
+ ::tzset();
+
+ tm* broken = ::localtime( &t );
+ ::setenv( "TZ", org, true );
+#else
+#warning "Need a replacement for MacOSX!!"
+ tm* broken = ::localtime( &t );
+#endif
+
+ QDateTime ret;
+ ret.setDate( QDate( broken->tm_year + 1900, broken->tm_mon +1, broken->tm_mday ) );
+ ret.setTime( QTime( broken->tm_hour, broken->tm_min, broken->tm_sec ) );
+
+ return ret;
+ }
+ time_t to_Time_t( const QDateTime& utc, const QString& str ) {
+ QDate d = utc.date();
+ QTime t = utc.time();
+
+ tm broken;
+ broken.tm_year = d.year() - 1900;
+ broken.tm_mon = d.month() - 1;
+ broken.tm_mday = d.day();
+ broken.tm_hour = t.hour();
+ broken.tm_min = t.minute();
+ broken.tm_sec = t.second();
+
+ QCString org = ::getenv( "TZ" );
+#ifndef Q_OS_MACX // Following line causes bus errors on Mac
+ ::setenv( "TZ", str.latin1(), true );
+ ::tzset();
+
+ time_t ti = ::mktime( &broken );
+ ::setenv( "TZ", org, true );
+#else
+#warning "Need a replacement for MacOSX!!"
+ time_t ti = ::mktime( &broken );
+#endif
+ return ti;
+ }
+}
+OTimeZone::OTimeZone( const ZoneName& zone )
+ : m_name(zone) {
+}
+OTimeZone::~OTimeZone() {
+}
+
+bool OTimeZone::isValid()const {
+ return !m_name.isEmpty();
+}
+
+/*
+ * we will get the current timezone
+ * and ask it to convert to the timezone date
+ */
+QDateTime OTimeZone::toLocalDateTime( const QDateTime& dt) {
+ return OTimeZone::current().toDateTime( dt, *this );
+}
+QDateTime OTimeZone::toUTCDateTime( const QDateTime& dt ) {
+ return OTimeZone::utc().toDateTime( dt, *this );
+}
+QDateTime OTimeZone::fromUTCDateTime( time_t t) {
+ return utcTime( t );
+}
+QDateTime OTimeZone::toDateTime( time_t t) {
+ return utcTime( t, m_name );
+}
+/*
+ * convert dt to utc using zone.m_name
+ * convert utc -> timeZoneDT using this->m_name
+ */
+QDateTime OTimeZone::toDateTime( const QDateTime& dt, const OTimeZone& zone ) {
+ time_t utc = to_Time_t( dt, zone.m_name );
+ qWarning("%d %s", utc, zone.m_name.latin1() );
+ return utcTime( utc, m_name );
+}
+time_t OTimeZone::fromDateTime( const QDateTime& time ) {
+ return to_Time_t( time, m_name );
+}
+time_t OTimeZone::fromUTCDateTime( const QDateTime& time ) {
+ return to_Time_t( time, "UTC" );
+}
+OTimeZone OTimeZone::current() {
+ QCString str = ::getenv("TZ");
+ OTimeZone zone( str );
+ return zone;
+}
+OTimeZone OTimeZone::utc() {
+ return OTimeZone("UTC");
+}
+QString OTimeZone::timeZone()const {
+ return m_name;
+}
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 @@
+#ifndef OPIE_TIME_ZONE_H
+#define OPIE_TIME_ZONE_H
+
+#include <time.h>
+#include <qdatetime.h>
+
+/**
+ * A very primitive class to convert time
+ * from one timezone to another
+ * and to localtime
+ * and time_t
+ */
+class OTimeZone {
+ public:
+ typedef QString ZoneName;
+ OTimeZone( const ZoneName& = ZoneName::null );
+ virtual ~OTimeZone(); // just in case.
+
+ bool isValid()const;
+
+ /**
+ * converts the QDateTime to a DateTime
+ * in the local timezone
+ * if QDateTime is 25th Jan and takes place in Europe/Berlin at 12h
+ * and the current timezone is Europe/London the returned
+ * time will be 11h.
+ */
+ QDateTime toLocalDateTime( const QDateTime& dt );
+
+ /**
+ * converts the QDateTime to UTC time
+ */
+ QDateTime toUTCDateTime( const QDateTime& dt );
+
+ /**
+ * reads the time_t into a QDateTime using UTC as timezone!
+ */
+ QDateTime fromUTCDateTime( time_t );
+
+ /**
+ * converts the time_t to the time in the timezone
+ */
+ QDateTime toDateTime( time_t );
+
+ /**
+ * converts the QDateTime from one timezone to this timeZone
+ */
+ QDateTime toDateTime( const QDateTime&, const OTimeZone& timeZone );
+
+ /**
+ * converts the date time into a time_t. It takes the timezone into account
+ */
+ time_t fromDateTime( const QDateTime& );
+
+ /**
+ * converts the datetime with timezone UTC
+ */
+ time_t fromUTCDateTime( const QDateTime& );
+
+ static OTimeZone current();
+ static OTimeZone utc();
+
+ QString timeZone()const;
+ private:
+ ZoneName m_name;
+ class Private;
+ Private* d;
+};
+
+
+#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 @@
+
+#include <qobject.h>
+#include <qshared.h>
+
+
+
+#include <qpe/palmtopuidgen.h>
+#include <qpe/palmtoprecord.h>
+#include <qpe/categories.h>
+#include <qpe/categoryselect.h>
+#include <qpe/stringutil.h>
+
+
+#include "opimstate.h"
+#include "orecur.h"
+#include "opimmaintainer.h"
+#include "opimnotifymanager.h"
+#include "opimresolver.h"
+
+#include "otodo.h"
+
+
+struct OTodo::OTodoData : public QShared {
+ OTodoData() : QShared() {
+ recur = 0;
+ state = 0;
+ maintainer = 0;
+ notifiers = 0;
+ };
+ ~OTodoData() {
+ delete recur;
+ delete maintainer;
+ delete notifiers;
+ }
+
+ QDate date;
+ bool isCompleted:1;
+ bool hasDate:1;
+ int priority;
+ QString desc;
+ QString sum;
+ QMap<QString, QString> extra;
+ ushort prog;
+ OPimState *state;
+ ORecur *recur;
+ OPimMaintainer *maintainer;
+ QDate start;
+ QDate completed;
+ OPimNotifyManager *notifiers;
+};
+
+OTodo::OTodo(const OTodo &event )
+ : OPimRecord( event ), data( event.data )
+{
+ data->ref();
+// qWarning("ref up");
+}
+OTodo::~OTodo() {
+
+// qWarning("~OTodo " );
+ if ( data->deref() ) {
+// qWarning("OTodo::dereffing");
+ delete data;
+ data = 0l;
+ }
+}
+OTodo::OTodo(bool completed, int priority,
+ const QArray<int> &category,
+ const QString& summary,
+ const QString &description,
+ ushort progress,
+ bool hasDate, QDate date, int uid )
+ : OPimRecord( uid )
+{
+// qWarning("OTodoData " + summary);
+ setCategories( category );
+
+ data = new OTodoData;
+
+ data->date = date;
+ data->isCompleted = completed;
+ data->hasDate = hasDate;
+ data->priority = priority;
+ data->sum = summary;
+ data->prog = progress;
+ data->desc = Qtopia::simplifyMultiLineSpace(description );
+}
+OTodo::OTodo(bool completed, int priority,
+ const QStringList &category,
+ const QString& summary,
+ const QString &description,
+ ushort progress,
+ bool hasDate, QDate date, int uid )
+ : OPimRecord( uid )
+{
+// qWarning("OTodoData" + summary);
+ setCategories( idsFromString( category.join(";") ) );
+
+ data = new OTodoData;
+
+ data->date = date;
+ data->isCompleted = completed;
+ data->hasDate = hasDate;
+ data->priority = priority;
+ data->sum = summary;
+ data->prog = progress;
+ data->desc = Qtopia::simplifyMultiLineSpace(description );
+}
+bool OTodo::match( const QRegExp &regExp )const
+{
+ if( QString::number( data->priority ).find( regExp ) != -1 ){
+ setLastHitField( Priority );
+ return true;
+ }else if( data->hasDate && data->date.toString().find( regExp) != -1 ){
+ setLastHitField( HasDate );
+ return true;
+ }else if(data->desc.find( regExp ) != -1 ){
+ setLastHitField( Description );
+ return true;
+ }else if(data->sum.find( regExp ) != -1 ) {
+ setLastHitField( Summary );
+ return true;
+ }
+ return false;
+}
+bool OTodo::isCompleted() const
+{
+ return data->isCompleted;
+}
+bool OTodo::hasDueDate() const
+{
+ return data->hasDate;
+}
+bool OTodo::hasStartDate()const {
+ return data->start.isValid();
+}
+bool OTodo::hasCompletedDate()const {
+ return data->completed.isValid();
+}
+int OTodo::priority()const
+{
+ return data->priority;
+}
+QString OTodo::summary() const
+{
+ return data->sum;
+}
+ushort OTodo::progress() const
+{
+ return data->prog;
+}
+QDate OTodo::dueDate()const
+{
+ return data->date;
+}
+QDate OTodo::startDate()const {
+ return data->start;
+}
+QDate OTodo::completedDate()const {
+ return data->completed;
+}
+QString OTodo::description()const
+{
+ return data->desc;
+}
+bool OTodo::hasState() const{
+ if (!data->state ) return false;
+ return ( data->state->state() != OPimState::Undefined );
+}
+OPimState OTodo::state()const {
+ if (!data->state ) {
+ OPimState state;
+ return state;
+ }
+
+ return (*data->state);
+}
+bool OTodo::hasRecurrence()const {
+ if (!data->recur) return false;
+ return data->recur->doesRecur();
+}
+ORecur OTodo::recurrence()const {
+ if (!data->recur) return ORecur();
+
+ return (*data->recur);
+}
+bool OTodo::hasMaintainer()const {
+ if (!data->maintainer) return false;
+
+ return (data->maintainer->mode() != OPimMaintainer::Undefined );
+}
+OPimMaintainer OTodo::maintainer()const {
+ if (!data->maintainer) return OPimMaintainer();
+
+ return (*data->maintainer);
+}
+void OTodo::setCompleted( bool completed )
+{
+ changeOrModify();
+ data->isCompleted = completed;
+}
+void OTodo::setHasDueDate( bool hasDate )
+{
+ changeOrModify();
+ data->hasDate = hasDate;
+}
+void OTodo::setDescription(const QString &desc )
+{
+// qWarning( "desc " + desc );
+ changeOrModify();
+ data->desc = Qtopia::simplifyMultiLineSpace(desc );
+}
+void OTodo::setSummary( const QString& sum )
+{
+ changeOrModify();
+ data->sum = sum;
+}
+void OTodo::setPriority(int prio )
+{
+ changeOrModify();
+ data->priority = prio;
+}
+void OTodo::setDueDate( const QDate& date )
+{
+ changeOrModify();
+ data->date = date;
+}
+void OTodo::setStartDate( const QDate& date ) {
+ changeOrModify();
+ data->start = date;
+}
+void OTodo::setCompletedDate( const QDate& date ) {
+ changeOrModify();
+ data->completed = date;
+}
+void OTodo::setState( const OPimState& state ) {
+ changeOrModify();
+ if (data->state )
+ (*data->state) = state;
+ else
+ data->state = new OPimState( state );
+}
+void OTodo::setRecurrence( const ORecur& rec) {
+ changeOrModify();
+ if (data->recur )
+ (*data->recur) = rec;
+ else
+ data->recur = new ORecur( rec );
+}
+void OTodo::setMaintainer( const OPimMaintainer& pim ) {
+ changeOrModify();
+
+ if (data->maintainer )
+ (*data->maintainer) = pim;
+ else
+ data->maintainer = new OPimMaintainer( pim );
+}
+bool OTodo::isOverdue( )
+{
+ if( data->hasDate && !data->isCompleted)
+ return QDate::currentDate() > data->date;
+ return false;
+}
+void OTodo::setProgress(ushort progress )
+{
+ changeOrModify();
+ data->prog = progress;
+}
+QString OTodo::toShortText() const {
+ return summary();
+}
+/*!
+ Returns a richt text string
+*/
+QString OTodo::toRichText() const
+{
+ QString text;
+ QStringList catlist;
+
+ // summary
+ text += "<b><h3><img src=\"todo/TodoList\"> ";
+ if ( !summary().isEmpty() ) {
+ text += Qtopia::escapeString(summary() ).replace(QRegExp( "[\n]"), "" );
+ }
+ text += "</h3></b><br><hr><br>";
+
+ // description
+ if( !description().isEmpty() ){
+ text += "<b>" + QObject::tr( "Description:" ) + "</b><br>";
+ text += Qtopia::escapeString(description() ).replace(QRegExp( "[\n]"), "<br>" ) + "<br>";
+ }
+
+ // priority
+ int priorityval = priority();
+ text += "<b>" + QObject::tr( "Priority:") +" </b><img src=\"todo/priority" +
+ QString::number( priorityval ) + "\"> ";
+
+ switch ( priorityval )
+ {
+ case 1 : text += QObject::tr( "Very high" );
+ break;
+ case 2 : text += QObject::tr( "High" );
+ break;
+ case 3 : text += QObject::tr( "Normal" );
+ break;
+ case 4 : text += QObject::tr( "Low" );
+ break;
+ case 5 : text += QObject::tr( "Very low" );
+ break;
+ };
+ text += "<br>";
+
+ // progress
+ text += "<b>" + QObject::tr( "Progress:") + " </b>"
+ + QString::number( progress() ) + " %<br>";
+
+ // due date
+ if (hasDueDate() ){
+ QDate dd = dueDate();
+ int off = QDate::currentDate().daysTo( dd );
+
+ text += "<b>" + QObject::tr( "Deadline:" ) + " </b><font color=\"";
+ if ( off < 0 )
+ text += "#FF0000";
+ else if ( off == 0 )
+ text += "#FFFF00";
+ else if ( off > 0 )
+ text += "#00FF00";
+
+ text += "\">" + dd.toString() + "</font><br>";
+ }
+
+ // categories
+ text += "<b>" + QObject::tr( "Category:") + "</b> ";
+ text += categoryNames( "Todo List" ).join(", ");
+ text += "<br>";
+
+ return text;
+}
+bool OTodo::hasNotifiers()const {
+ if (!data->notifiers) return false;
+ return !data->notifiers->isEmpty();
+}
+OPimNotifyManager& OTodo::notifiers() {
+ if (!data->notifiers )
+ data->notifiers = new OPimNotifyManager;
+ return (*data->notifiers);
+}
+const OPimNotifyManager& OTodo::notifiers()const{
+ if (!data->notifiers )
+ data->notifiers = new OPimNotifyManager;
+
+ return (*data->notifiers);
+}
+
+bool OTodo::operator<( const OTodo &toDoEvent )const{
+ if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true;
+ if( !hasDueDate() && toDoEvent.hasDueDate() ) return false;
+ if( hasDueDate() && toDoEvent.hasDueDate() ){
+ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide
+ return priority() < toDoEvent.priority();
+ }else{
+ return dueDate() < toDoEvent.dueDate();
+ }
+ }
+ return false;
+}
+bool OTodo::operator<=(const OTodo &toDoEvent )const
+{
+ if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true;
+ if( !hasDueDate() && toDoEvent.hasDueDate() ) return true;
+ if( hasDueDate() && toDoEvent.hasDueDate() ){
+ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide
+ return priority() <= toDoEvent.priority();
+ }else{
+ return dueDate() <= toDoEvent.dueDate();
+ }
+ }
+ return true;
+}
+bool OTodo::operator>(const OTodo &toDoEvent )const
+{
+ if( !hasDueDate() && !toDoEvent.hasDueDate() ) return false;
+ if( !hasDueDate() && toDoEvent.hasDueDate() ) return false;
+ if( hasDueDate() && toDoEvent.hasDueDate() ){
+ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide
+ return priority() > toDoEvent.priority();
+ }else{
+ return dueDate() > toDoEvent.dueDate();
+ }
+ }
+ return false;
+}
+bool OTodo::operator>=(const OTodo &toDoEvent )const
+{
+ if( !hasDueDate() && !toDoEvent.hasDueDate() ) return true;
+ if( !hasDueDate() && toDoEvent.hasDueDate() ) return false;
+ if( hasDueDate() && toDoEvent.hasDueDate() ){
+ if( dueDate() == toDoEvent.dueDate() ){ // let's the priority decide
+ return priority() > toDoEvent.priority();
+ }else{
+ return dueDate() > toDoEvent.dueDate();
+ }
+ }
+ return true;
+}
+bool OTodo::operator==(const OTodo &toDoEvent )const
+{
+ if ( data->priority != toDoEvent.data->priority ) return false;
+ if ( data->priority != toDoEvent.data->prog ) return false;
+ if ( data->isCompleted != toDoEvent.data->isCompleted ) return false;
+ if ( data->hasDate != toDoEvent.data->hasDate ) return false;
+ if ( data->date != toDoEvent.data->date ) return false;
+ if ( data->sum != toDoEvent.data->sum ) return false;
+ if ( data->desc != toDoEvent.data->desc ) return false;
+ if ( data->maintainer != toDoEvent.data->maintainer )
+ return false;
+
+ return OPimRecord::operator==( toDoEvent );
+}
+void OTodo::deref() {
+
+// qWarning("deref in ToDoEvent");
+ if ( data->deref() ) {
+// qWarning("deleting");
+ delete data;
+ data= 0;
+ }
+}
+OTodo &OTodo::operator=(const OTodo &item )
+{
+ if ( this == &item ) return *this;
+
+ OPimRecord::operator=( item );
+ //qWarning("operator= ref ");
+ item.data->ref();
+ deref();
+ data = item.data;
+
+ return *this;
+}
+
+QMap<int, QString> OTodo::toMap() const {
+ QMap<int, QString> map;
+
+ map.insert( Uid, QString::number( uid() ) );
+ map.insert( Category, idsToString( categories() ) );
+ map.insert( HasDate, QString::number( data->hasDate ) );
+ map.insert( Completed, QString::number( data->isCompleted ) );
+ map.insert( Description, data->desc );
+ map.insert( Summary, data->sum );
+ map.insert( Priority, QString::number( data->priority ) );
+ map.insert( DateDay, QString::number( data->date.day() ) );
+ map.insert( DateMonth, QString::number( data->date.month() ) );
+ map.insert( DateYear, QString::number( data->date.year() ) );
+ map.insert( Progress, QString::number( data->prog ) );
+// map.insert( CrossReference, crossToString() );
+ /* FIXME!!! map.insert( State, );
+ map.insert( Recurrence, );
+ map.insert( Reminders, );
+ map.
+ */
+ return map;
+}
+
+/**
+ * change or modify looks at the ref count and either
+ * creates a new QShared Object or it can modify it
+ * right in place
+ */
+void OTodo::changeOrModify() {
+ if ( data->count != 1 ) {
+ qWarning("changeOrModify");
+ data->deref();
+ OTodoData* d2 = new OTodoData();
+ copy(data, d2 );
+ data = d2;
+ }
+}
+// WATCHOUT
+/*
+ * if you add something to the Data struct
+ * be sure to copy it here
+ */
+void OTodo::copy( OTodoData* src, OTodoData* dest ) {
+ dest->date = src->date;
+ dest->isCompleted = src->isCompleted;
+ dest->hasDate = src->hasDate;
+ dest->priority = src->priority;
+ dest->desc = src->desc;
+ dest->sum = src->sum;
+ dest->extra = src->extra;
+ dest->prog = src->prog;
+
+ if (src->state )
+ dest->state = new OPimState( *src->state );
+
+ if (src->recur )
+ dest->recur = new ORecur( *src->recur );
+
+ if (src->maintainer )
+ dest->maintainer = new OPimMaintainer( *src->maintainer )
+ ;
+ dest->start = src->start;
+ dest->completed = src->completed;
+
+ if (src->notifiers )
+ dest->notifiers = new OPimNotifyManager( *src->notifiers );
+}
+QString OTodo::type() const {
+ return QString::fromLatin1("OTodo");
+}
+QString OTodo::recordField(int /*id*/ )const {
+ return QString::null;
+}
+
+int OTodo::rtti(){
+ return OPimResolver::TodoList;
+}
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 @@
+
+#ifndef OPIE_TODO_EVENT_H
+#define OPIE_TODO_EVENT_H
+
+
+#include <qarray.h>
+#include <qmap.h>
+#include <qregexp.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+#include <qvaluelist.h>
+
+#include <qpe/recordfields.h>
+#include <qpe/palmtopuidgen.h>
+
+#include <opie/opimrecord.h>
+
+
+class OPimState;
+class ORecur;
+class OPimMaintainer;
+class OPimNotifyManager;
+class OTodo : public OPimRecord {
+public:
+ typedef QValueList<OTodo> ValueList;
+ enum RecordFields {
+ Uid = Qtopia::UID_ID,
+ Category = Qtopia::CATEGORY_ID,
+ HasDate,
+ Completed,
+ Description,
+ Summary,
+ Priority,
+ DateDay,
+ DateMonth,
+ DateYear,
+ Progress,
+ CrossReference,
+ State,
+ Recurrence,
+ Alarms,
+ Reminders,
+ Notifiers,
+ Maintainer,
+ StartDate,
+ CompletedDate
+ };
+ public:
+ // priorities from Very low to very high
+ enum TaskPriority { VeryHigh=1, High, Normal, Low, VeryLow };
+
+ /* Constructs a new ToDoEvent
+ @param completed Is the TodoEvent completed
+ @param priority What is the priority of this ToDoEvent
+ @param category Which category does it belong( uid )
+ @param summary A small summary of the todo
+ @param description What is this ToDoEvent about
+ @param hasDate Does this Event got a deadline
+ @param date what is the deadline?
+ @param uid what is the UUID of this Event
+ **/
+ OTodo( bool completed = false, int priority = Normal,
+ const QStringList &category = QStringList(),
+ const QString &summary = QString::null ,
+ const QString &description = QString::null,
+ ushort progress = 0,
+ bool hasDate = false, QDate date = QDate::currentDate(),
+ int uid = 0 /*empty*/ );
+
+ OTodo( bool completed, int priority,
+ const QArray<int>& category,
+ const QString& summary = QString::null,
+ const QString& description = QString::null,
+ ushort progress = 0,
+ bool hasDate = false, QDate date = QDate::currentDate(),
+ int uid = 0 /* empty */ );
+
+ /** Copy c'tor
+ *
+ */
+ OTodo(const OTodo & );
+
+ /**
+ *destructor
+ */
+ ~OTodo();
+
+ /**
+ * Is this event completed?
+ */
+ bool isCompleted() const;
+
+ /**
+ * Does this Event have a deadline
+ */
+ bool hasDueDate() const;
+ bool hasStartDate()const;
+ bool hasCompletedDate()const;
+
+ /**
+ * What is the priority?
+ */
+ int priority()const ;
+
+ /**
+ * progress as ushort 0, 20, 40, 60, 80 or 100%
+ */
+ ushort progress() const;
+
+ /**
+ * The due Date
+ */
+ QDate dueDate()const;
+
+ /**
+ * When did it start?
+ */
+ QDate startDate()const;
+
+ /**
+ * When was it completed?
+ */
+ QDate completedDate()const;
+
+ /**
+ * does it have a state?
+ */
+ bool hasState()const;
+
+ /**
+ * What is the state of this OTodo?
+ */
+ OPimState state()const;
+
+ /**
+ * has recurrence?
+ */
+ bool hasRecurrence()const;
+
+ /**
+ * the recurrance of this
+ */
+ ORecur recurrence()const;
+
+ /**
+ * does this OTodo have a maintainer?
+ */
+ bool hasMaintainer()const;
+
+ /**
+ * the Maintainer of this OTodo
+ */
+ OPimMaintainer maintainer()const;
+
+ /**
+ * The description of the todo
+ */
+ QString description()const;
+
+ /**
+ * A small summary of the todo
+ */
+ QString summary() const;
+
+ /**
+ * @reimplemented
+ * Return this todoevent in a RichText formatted QString
+ */
+ QString toRichText() const;
+
+ bool hasNotifiers()const;
+ /*
+ * FIXME check if the sharing is still fine!! -zecke
+ * ### CHECK If API is fine
+ */
+ /**
+ * return a reference to our notifiers...
+ */
+ OPimNotifyManager &notifiers();
+
+ /**
+ *
+ */
+ const OPimNotifyManager &notifiers()const;
+
+ /**
+ * reimplementations
+ */
+ QString type()const;
+ QString toShortText()const;
+ QString recordField(int id )const;
+
+ /**
+ * toMap puts all data into the map. int relates
+ * to ToDoEvent RecordFields enum
+ */
+ QMap<int, QString> toMap()const;
+
+ /**
+ * Set if this Todo is completed
+ */
+ void setCompleted(bool completed );
+
+ /**
+ * set if this todo got an end data
+ */
+ void setHasDueDate( bool hasDate );
+ // FIXME we do not have these for start, completed
+ // cause we'll use the isNull() of QDate for figuring
+ // out if it's has a date...
+ // decide what to do here? -zecke
+
+ /**
+ * Set the priority of the Todo
+ */
+ void setPriority(int priority );
+
+ /**
+ * Set the progress.
+ */
+ void setProgress( ushort progress );
+
+ /**
+ * set the end date
+ */
+ void setDueDate( const QDate& date );
+
+ /**
+ * set the start date
+ */
+ void setStartDate( const QDate& date );
+
+ /**
+ * set the completed date
+ */
+ void setCompletedDate( const QDate& date );
+
+ void setRecurrence( const ORecur& );
+
+ void setDescription(const QString& );
+ void setSummary(const QString& );
+
+ /**
+ * set the state of a Todo
+ * @param state State what the todo should take
+ */
+ void setState( const OPimState& state);
+
+ /**
+ * set the Maintainer Mode
+ */
+ void setMaintainer( const OPimMaintainer& );
+
+ bool isOverdue();
+
+
+ virtual bool match( const QRegExp &r )const;
+
+ bool operator<(const OTodo &toDoEvent )const;
+ bool operator<=(const OTodo &toDoEvent )const;
+ bool operator!=(const OTodo &toDoEvent )const;
+ bool operator>(const OTodo &toDoEvent )const;
+ bool operator>=(const OTodo &toDoEvent)const;
+ bool operator==(const OTodo &toDoEvent )const;
+ OTodo &operator=(const OTodo &toDoEvent );
+
+ static int rtti();
+
+ private:
+ class OTodoPrivate;
+ struct OTodoData;
+
+ void deref();
+ inline void changeOrModify();
+ void copy( OTodoData* src, OTodoData* dest );
+ OTodoPrivate *d;
+ OTodoData *data;
+
+};
+inline bool OTodo::operator!=(const OTodo &toDoEvent )const {
+ return !(*this == toDoEvent);
+}
+
+
+#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 @@
+#include <qdatetime.h>
+
+#include <qpe/alarmserver.h>
+
+// #include "otodoaccesssql.h"
+#include "otodoaccess.h"
+#include "obackendfactory.h"
+
+OTodoAccess::OTodoAccess( OTodoAccessBackend* end, enum Access )
+ : QObject(), OPimAccessTemplate<OTodo>( end ), m_todoBackEnd( end )
+{
+// if (end == 0l )
+// m_todoBackEnd = new OTodoAccessBackendSQL( QString::null);
+
+ // Zecke: Du musst hier noch für das XML-Backend einen Appnamen übergeben !
+ if (end == 0l )
+ m_todoBackEnd = OBackendFactory<OTodoAccessBackend>::Default ("todo", QString::null);
+
+ setBackEnd( m_todoBackEnd );
+}
+OTodoAccess::~OTodoAccess() {
+// qWarning("~OTodoAccess");
+}
+void OTodoAccess::mergeWith( const QValueList<OTodo>& list ) {
+ QValueList<OTodo>::ConstIterator it;
+ for ( it = list.begin(); it != list.end(); ++it ) {
+ replace( (*it) );
+ }
+}
+OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start,
+ const QDate& end,
+ bool includeNoDates ) {
+ QArray<int> ints = m_todoBackEnd->effectiveToDos( start, end, includeNoDates );
+
+ List lis( ints, this );
+ return lis;
+}
+OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start,
+ bool includeNoDates ) {
+ return effectiveToDos( start, QDate::currentDate(),
+ includeNoDates );
+}
+OTodoAccess::List OTodoAccess::overDue() {
+ List lis( m_todoBackEnd->overDue(), this );
+ return lis;
+}
+/* sort order */
+OTodoAccess::List OTodoAccess::sorted( bool ascending, int sort,int filter, int cat ) {
+ QArray<int> ints = m_todoBackEnd->sorted( ascending, sort,
+ filter, cat );
+ OTodoAccess::List list( ints, this );
+ return list;
+}
+void OTodoAccess::removeAllCompleted() {
+ m_todoBackEnd->removeAllCompleted();
+}
+QBitArray OTodoAccess::backendSupport( const QString& ) const{
+ return m_todoBackEnd->supports();
+}
+bool OTodoAccess::backendSupports( int attr, const QString& ar) const{
+ return backendSupport(ar).testBit( attr );
+}
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 @@
+#ifndef OPIE_TODO_ACCESS_H
+#define OPIE_TODO_ACCESS_H
+
+#include <qobject.h>
+#include <qvaluelist.h>
+
+#include "otodo.h"
+#include "otodoaccessbackend.h"
+#include "opimaccesstemplate.h"
+
+
+/**
+ * OTodoAccess
+ * the class to get access to
+ * the todolist
+ */
+class OTodoAccess : public QObject, public OPimAccessTemplate<OTodo> {
+ Q_OBJECT
+public:
+ enum SortOrder { Completed = 0,
+ Priority,
+ Description,
+ Deadline };
+ enum SortFilter{ Category =1,
+ OnlyOverDue= 2,
+ DoNotShowCompleted =4 };
+ /**
+ * if you use 0l
+ * the default resource will be
+ * picked up
+ */
+ OTodoAccess( OTodoAccessBackend* = 0l, enum Access acc = Random );
+ ~OTodoAccess();
+
+
+ /* our functions here */
+ /**
+ * include todos from start to end
+ * includeNoDates whether or not to include
+ * events with no dates
+ */
+ List effectiveToDos( const QDate& start,
+ const QDate& end,
+ bool includeNoDates = true );
+
+ /**
+ * start
+ * end date taken from the currentDate()
+ */
+ List effectiveToDos( const QDate& start,
+ bool includeNoDates = true );
+
+
+ /**
+ * return overdue OTodos
+ */
+ List overDue();
+
+ /**
+ *
+ */
+ List sorted( bool ascending, int sortOrder, int sortFilter, int cat );
+
+ /**
+ * merge a list of OTodos into
+ * the resource
+ */
+ void mergeWith( const QValueList<OTodo>& );
+
+ /**
+ * delete all already completed items
+ */
+ void removeAllCompleted();
+
+ /**
+ * request information about what a backend supports.
+ * Supports in the sense of beeing able to store.
+ * This is related to the enum in OTodo
+ *
+ * @param backend Will be used in the future when we support multiple backend
+ */
+ QBitArray backendSupport( const QString& backend = QString::null )const;
+
+ /**
+ * see above but for a specefic attribute. This method was added for convience
+ * @param attr The attribute to be queried for
+ * @param backend Will be used in the future when we support multiple backends
+ */
+ bool backendSupports( int attr, const QString& backend = QString::null )const;
+signals:
+ /**
+ * if the OTodoAccess was changed
+ */
+ void changed( const OTodoAccess* );
+ void changed( const OTodoAccess*, int uid );
+ void added( const OTodoAccess*, int uid );
+ void removed( const OTodoAccess*, int uid );
+private:
+ int m_cat;
+ OTodoAccessBackend* m_todoBackEnd;
+ class OTodoAccessPrivate;
+ OTodoAccessPrivate* d;
+};
+
+#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 @@
+
+#include "otodoaccessbackend.h"
+
+OTodoAccessBackend::OTodoAccessBackend()
+ : OPimAccessBackend<OTodo>()
+{
+}
+OTodoAccessBackend::~OTodoAccessBackend() {
+
+}
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 @@
+#ifndef OPIE_TODO_ACCESS_BACKEND_H
+#define OPIE_TODO_ACCESS_BACKEND_H
+
+#include <qbitarray.h>
+
+#include "otodo.h"
+#include "opimaccessbackend.h"
+
+class OTodoAccessBackend : public OPimAccessBackend<OTodo> {
+public:
+ OTodoAccessBackend();
+ ~OTodoAccessBackend();
+ virtual QArray<int> effectiveToDos( const QDate& start,
+ const QDate& end,
+ bool includeNoDates ) = 0;
+ virtual QArray<int> overDue() = 0;
+ virtual QArray<int> sorted( bool asc, int sortOrder, int sortFilter,
+ int cat ) = 0;
+ virtual void removeAllCompleted() = 0;
+ virtual QBitArray supports()const = 0;
+
+private:
+ class Private;
+ Private *d;
+
+};
+
+#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 @@
+
+#include <qdatetime.h>
+
+#include <qpe/global.h>
+
+#include <opie2/osqldriver.h>
+#include <opie2/osqlresult.h>
+#include <opie2/osqlmanager.h>
+#include <opie2/osqlquery.h>
+
+#include "otodoaccesssql.h"
+#include "opimstate.h"
+#include "opimnotifymanager.h"
+#include "orecur.h"
+
+using namespace Opie::DB;
+/*
+ * first some query
+ * CREATE query
+ * LOAD query
+ * INSERT
+ * REMOVE
+ * CLEAR
+ */
+namespace {
+ /**
+ * CreateQuery for the Todolist Table
+ */
+ class CreateQuery : public OSQLQuery {
+ public:
+ CreateQuery();
+ ~CreateQuery();
+ QString query()const;
+ };
+
+ /**
+ * LoadQuery
+ * this one queries for all uids
+ */
+ class LoadQuery : public OSQLQuery {
+ public:
+ LoadQuery();
+ ~LoadQuery();
+ QString query()const;
+ };
+
+ /**
+ * inserts/adds a OTodo to the table
+ */
+ class InsertQuery : public OSQLQuery {
+ public:
+ InsertQuery(const OTodo& );
+ ~InsertQuery();
+ QString query()const;
+ private:
+ OTodo m_todo;
+ };
+
+ /**
+ * removes one from the table
+ */
+ class RemoveQuery : public OSQLQuery {
+ public:
+ RemoveQuery(int uid );
+ ~RemoveQuery();
+ QString query()const;
+ private:
+ int m_uid;
+ };
+
+ /**
+ * Clears (delete) a Table
+ */
+ class ClearQuery : public OSQLQuery {
+ public:
+ ClearQuery();
+ ~ClearQuery();
+ QString query()const;
+
+ };
+
+ /**
+ * a find query
+ */
+ class FindQuery : public OSQLQuery {
+ public:
+ FindQuery(int uid);
+ FindQuery(const QArray<int>& );
+ ~FindQuery();
+ QString query()const;
+ private:
+ QString single()const;
+ QString multi()const;
+ QArray<int> m_uids;
+ int m_uid;
+ };
+
+ /**
+ * overdue query
+ */
+ class OverDueQuery : public OSQLQuery {
+ public:
+ OverDueQuery();
+ ~OverDueQuery();
+ QString query()const;
+ };
+ class EffQuery : public OSQLQuery {
+ public:
+ EffQuery( const QDate&, const QDate&, bool inc );
+ ~EffQuery();
+ QString query()const;
+ private:
+ QString with()const;
+ QString out()const;
+ QDate m_start;
+ QDate m_end;
+ bool m_inc :1;
+ };
+
+
+ CreateQuery::CreateQuery() : OSQLQuery() {}
+ CreateQuery::~CreateQuery() {}
+ QString CreateQuery::query()const {
+ QString qu;
+ qu += "create table todolist( uid PRIMARY KEY, categories, completed, ";
+ qu += "description, summary, priority, DueDate, progress , state, ";
+ // This is the recurrance-stuff .. Exceptions are currently not supported (see ORecur.cpp) ! (eilers)
+ qu += "RType, RWeekdays, RPosition, RFreq, RHasEndDate, EndDate, Created, Exceptions, ";
+ qu += "reminders, alarms, maintainer, startdate, completeddate);";
+ qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );";
+ return qu;
+ }
+
+ LoadQuery::LoadQuery() : OSQLQuery() {}
+ LoadQuery::~LoadQuery() {}
+ QString LoadQuery::query()const {
+ QString qu;
+ // We do not need "distinct" here. The primary key is always unique..
+ //qu += "select distinct uid from todolist";
+ qu += "select uid from todolist";
+
+ return qu;
+ }
+
+ InsertQuery::InsertQuery( const OTodo& todo )
+ : OSQLQuery(), m_todo( todo ) {
+ }
+ InsertQuery::~InsertQuery() {
+ }
+ /*
+ * converts from a OTodo to a query
+ * we leave out X-Ref + Alarms
+ */
+ QString InsertQuery::query()const{
+
+ int year, month, day;
+ year = month = day = 0;
+ if (m_todo.hasDueDate() ) {
+ QDate date = m_todo.dueDate();
+ year = date.year();
+ month = date.month();
+ day = date.day();
+ }
+ int sYear = 0, sMonth = 0, sDay = 0;
+ if( m_todo.hasStartDate() ){
+ QDate sDate = m_todo.startDate();
+ sYear = sDate.year();
+ sMonth= sDate.month();
+ sDay = sDate.day();
+ }
+
+ int eYear = 0, eMonth = 0, eDay = 0;
+ if( m_todo.hasCompletedDate() ){
+ QDate eDate = m_todo.completedDate();
+ eYear = eDate.year();
+ eMonth= eDate.month();
+ eDay = eDate.day();
+ }
+ QString qu;
+ QMap<int, QString> recMap = m_todo.recurrence().toMap();
+ qu = "insert into todolist VALUES("
+ + QString::number( m_todo.uid() ) + ","
+ + "'" + m_todo.idsToString( m_todo.categories() ) + "'" + ","
+ + QString::number( m_todo.isCompleted() ) + ","
+ + "'" + m_todo.description() + "'" + ","
+ + "'" + m_todo.summary() + "'" + ","
+ + QString::number(m_todo.priority() ) + ","
+ + "'" + QString::number(year) + "-"
+ + QString::number(month)
+ + "-" + QString::number( day ) + "'" + ","
+ + QString::number( m_todo.progress() ) + ","
+ + QString::number( m_todo.state().state() ) + ","
+ + "'" + recMap[ ORecur::RType ] + "'" + ","
+ + "'" + recMap[ ORecur::RWeekdays ] + "'" + ","
+ + "'" + recMap[ ORecur::RPosition ] + "'" + ","
+ + "'" + recMap[ ORecur::RFreq ] + "'" + ","
+ + "'" + recMap[ ORecur::RHasEndDate ] + "'" + ","
+ + "'" + recMap[ ORecur::EndDate ] + "'" + ","
+ + "'" + recMap[ ORecur::Created ] + "'" + ","
+ + "'" + recMap[ ORecur::Exceptions ] + "'" + ",";
+
+ if ( m_todo.hasNotifiers() ) {
+ OPimNotifyManager manager = m_todo.notifiers();
+ qu += "'" + manager.remindersToString() + "'" + ","
+ + "'" + manager.alarmsToString() + "'" + ",";
+ }
+ else{
+ qu += QString( "''" ) + ","
+ + "''" + ",";
+ }
+
+ qu += QString( "''" ) + QString( "," ) // Maintainers (cur. not supported !)
+ + "'" + QString::number(sYear) + "-"
+ + QString::number(sMonth)
+ + "-" + QString::number(sDay) + "'" + ","
+ + "'" + QString::number(eYear) + "-"
+ + QString::number(eMonth)
+ + "-"+QString::number(eDay) + "'"
+ + ")";
+
+ qWarning("add %s", qu.latin1() );
+ return qu;
+ }
+
+ RemoveQuery::RemoveQuery(int uid )
+ : OSQLQuery(), m_uid( uid ) {}
+ RemoveQuery::~RemoveQuery() {}
+ QString RemoveQuery::query()const {
+ QString qu = "DELETE from todolist where uid = " + QString::number(m_uid);
+ return qu;
+ }
+
+
+ ClearQuery::ClearQuery()
+ : OSQLQuery() {}
+ ClearQuery::~ClearQuery() {}
+ QString ClearQuery::query()const {
+ QString qu = "drop table todolist";
+ return qu;
+ }
+ FindQuery::FindQuery(int uid)
+ : OSQLQuery(), m_uid(uid ) {
+ }
+ FindQuery::FindQuery(const QArray<int>& ints)
+ : OSQLQuery(), m_uids(ints){
+ }
+ FindQuery::~FindQuery() {
+ }
+ QString FindQuery::query()const{
+ if (m_uids.count() == 0 )
+ return single();
+ else
+ return multi();
+ }
+ QString FindQuery::single()const{
+ QString qu = "select * from todolist where uid = " + QString::number(m_uid);
+ return qu;
+ }
+ QString FindQuery::multi()const {
+ QString qu = "select * from todolist where ";
+ for (uint i = 0; i < m_uids.count(); i++ ) {
+ qu += " UID = " + QString::number( m_uids[i] ) + " OR";
+ }
+ qu.remove( qu.length()-2, 2 );
+ return qu;
+ }
+
+ OverDueQuery::OverDueQuery(): OSQLQuery() {}
+ OverDueQuery::~OverDueQuery() {}
+ QString OverDueQuery::query()const {
+ QDate date = QDate::currentDate();
+ QString str;
+ str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() );
+
+ return str;
+ }
+
+
+ EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc )
+ : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {}
+ EffQuery::~EffQuery() {}
+ QString EffQuery::query()const {
+ return m_inc ? with() : out();
+ }
+ QString EffQuery::with()const {
+ QString str;
+ str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ")
+ .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() )
+ .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() );
+ return str;
+ }
+ QString EffQuery::out()const {
+ QString str;
+ str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'")
+ .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() )
+ .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() );
+
+ return str;
+ }
+};
+
+OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file )
+ : OTodoAccessBackend(), m_dict(15), m_driver(NULL), m_dirty(true)
+{
+ QString fi = file;
+ if ( fi.isEmpty() )
+ fi = Global::applicationFileName( "todolist", "todolist.db" );
+ OSQLManager man;
+ m_driver = man.standard();
+ m_driver->setUrl(fi);
+ // fillDict();
+}
+
+OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){
+ if( m_driver )
+ delete m_driver;
+}
+
+bool OTodoAccessBackendSQL::load(){
+ if (!m_driver->open() )
+ return false;
+
+ CreateQuery creat;
+ OSQLResult res = m_driver->query(&creat );
+
+ m_dirty = true;
+ return true;
+}
+bool OTodoAccessBackendSQL::reload(){
+ return load();
+}
+
+bool OTodoAccessBackendSQL::save(){
+ return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
+}
+QArray<int> OTodoAccessBackendSQL::allRecords()const {
+ if (m_dirty )
+ update();
+
+ return m_uids;
+}
+QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){
+ QArray<int> ints(0);
+ return ints;
+}
+OTodo OTodoAccessBackendSQL::find(int uid ) const{
+ FindQuery query( uid );
+ return todo( m_driver->query(&query) );
+
+}
+OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints,
+ uint cur, Frontend::CacheDirection dir ) const{
+ uint CACHE = readAhead();
+ qWarning("searching for %d", uid );
+ QArray<int> search( CACHE );
+ uint size =0;
+ OTodo to;
+
+ // we try to cache CACHE items
+ switch( dir ) {
+ /* forward */
+ case 0: // FIXME: Not a good style to use magic numbers here (eilers)
+ for (uint i = cur; i < ints.count() && size < CACHE; i++ ) {
+ qWarning("size %d %d", size, ints[i] );
+ search[size] = ints[i];
+ size++;
+ }
+ break;
+ /* reverse */
+ case 1: // FIXME: Not a good style to use magic numbers here (eilers)
+ for (uint i = cur; i != 0 && size < CACHE; i-- ) {
+ search[size] = ints[i];
+ size++;
+ }
+ break;
+ }
+ search.resize( size );
+ FindQuery query( search );
+ OSQLResult res = m_driver->query( &query );
+ if ( res.state() != OSQLResult::Success )
+ return to;
+
+ return todo( res );
+}
+void OTodoAccessBackendSQL::clear() {
+ ClearQuery cle;
+ OSQLResult res = m_driver->query( &cle );
+ CreateQuery qu;
+ res = m_driver->query(&qu);
+}
+bool OTodoAccessBackendSQL::add( const OTodo& t) {
+ InsertQuery ins( t );
+ OSQLResult res = m_driver->query( &ins );
+
+ if ( res.state() == OSQLResult::Failure )
+ return false;
+ int c = m_uids.count();
+ m_uids.resize( c+1 );
+ m_uids[c] = t.uid();
+
+ return true;
+}
+bool OTodoAccessBackendSQL::remove( int uid ) {
+ RemoveQuery rem( uid );
+ OSQLResult res = m_driver->query(&rem );
+
+ if ( res.state() == OSQLResult::Failure )
+ return false;
+
+ m_dirty = true;
+ return true;
+}
+/*
+ * FIXME better set query
+ * but we need the cache for that
+ * now we remove
+ */
+bool OTodoAccessBackendSQL::replace( const OTodo& t) {
+ remove( t.uid() );
+ bool b= add(t);
+ m_dirty = false; // we changed some stuff but the UID stayed the same
+ return b;
+}
+QArray<int> OTodoAccessBackendSQL::overDue() {
+ OverDueQuery qu;
+ return uids( m_driver->query(&qu ) );
+}
+QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s,
+ const QDate& t,
+ bool u) {
+ EffQuery ef(s, t, u );
+ return uids (m_driver->query(&ef) );
+}
+/*
+ *
+ */
+QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder,
+ int sortFilter, int cat ) {
+ qWarning("sorted %d, %d", asc, sortOrder );
+ QString query;
+ query = "select uid from todolist WHERE ";
+
+ /*
+ * Sort Filter stuff
+ * not that straight forward
+ * FIXME: Replace magic numbers
+ *
+ */
+ /* Category */
+ if ( sortFilter & 1 ) {
+ QString str;
+ if (cat != 0 ) str = QString::number( cat );
+ query += " categories like '%" +str+"%' AND";
+ }
+ /* Show only overdue */
+ if ( sortFilter & 2 ) {
+ QDate date = QDate::currentDate();
+ QString due;
+ QString base;
+ base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() );
+ query += " " + base + " AND";
+ }
+ /* not show completed */
+ if ( sortFilter & 4 ) {
+ query += " completed = 0 AND";
+ }else{
+ query += " ( completed = 1 OR completed = 0) AND";
+ }
+ /* srtip the end */
+ query = query.remove( query.length()-3, 3 );
+
+
+ /*
+ * sort order stuff
+ * quite straight forward
+ */
+ query += "ORDER BY ";
+ switch( sortOrder ) {
+ /* completed */
+ case 0:
+ query += "completed";
+ break;
+ case 1:
+ query += "priority";
+ break;
+ case 2:
+ query += "summary";
+ break;
+ case 3:
+ query += "DueDate";
+ break;
+ }
+
+ if ( !asc ) {
+ qWarning("not ascending!");
+ query += " DESC";
+ }
+
+ qWarning( query );
+ OSQLRawQuery raw(query );
+ return uids( m_driver->query(&raw) );
+}
+bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{
+ if ( str == "0-0-0" )
+ return false;
+ else{
+ int day, year, month;
+ QStringList list = QStringList::split("-", str );
+ year = list[0].toInt();
+ month = list[1].toInt();
+ day = list[2].toInt();
+ da.setYMD( year, month, day );
+ return true;
+ }
+}
+OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{
+ if ( res.state() == OSQLResult::Failure ) {
+ OTodo to;
+ return to;
+ }
+
+ OSQLResultItem::ValueList list = res.results();
+ OSQLResultItem::ValueList::Iterator it = list.begin();
+ qWarning("todo1");
+ OTodo to = todo( (*it) );
+ cache( to );
+ ++it;
+
+ for ( ; it != list.end(); ++it ) {
+ qWarning("caching");
+ cache( todo( (*it) ) );
+ }
+ return to;
+}
+OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const {
+ qWarning("todo");
+ bool hasDueDate = false; QDate dueDate = QDate::currentDate();
+ hasDueDate = date( dueDate, item.data("DueDate") );
+ QStringList cats = QStringList::split(";", item.data("categories") );
+
+ qWarning("Item is completed: %d", item.data("completed").toInt() );
+
+ OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(),
+ cats, item.data("summary"), item.data("description"),
+ item.data("progress").toUShort(), hasDueDate, dueDate,
+ item.data("uid").toInt() );
+
+ bool isOk;
+ int prioInt = QString( item.data("priority") ).toInt( &isOk );
+ if ( isOk )
+ to.setPriority( prioInt );
+
+ bool hasStartDate = false; QDate startDate = QDate::currentDate();
+ hasStartDate = date( startDate, item.data("startdate") );
+ bool hasCompletedDate = false; QDate completedDate = QDate::currentDate();
+ hasCompletedDate = date( completedDate, item.data("completeddate") );
+
+ if ( hasStartDate )
+ to.setStartDate( startDate );
+ if ( hasCompletedDate )
+ to.setCompletedDate( completedDate );
+
+ OPimNotifyManager& manager = to.notifiers();
+ manager.alarmsFromString( item.data("alarms") );
+ manager.remindersFromString( item.data("reminders") );
+
+ OPimState pimState;
+ pimState.setState( QString( item.data("state") ).toInt() );
+ to.setState( pimState );
+
+ QMap<int, QString> recMap;
+ recMap.insert( ORecur::RType , item.data("RType") );
+ recMap.insert( ORecur::RWeekdays , item.data("RWeekdays") );
+ recMap.insert( ORecur::RPosition , item.data("RPosition") );
+ recMap.insert( ORecur::RFreq , item.data("RFreq") );
+ recMap.insert( ORecur::RHasEndDate, item.data("RHasEndDate") );
+ recMap.insert( ORecur::EndDate , item.data("EndDate") );
+ recMap.insert( ORecur::Created , item.data("Created") );
+ recMap.insert( ORecur::Exceptions , item.data("Exceptions") );
+
+ ORecur recur;
+ recur.fromMap( recMap );
+ to.setRecurrence( recur );
+
+ return to;
+}
+OTodo OTodoAccessBackendSQL::todo( int uid )const {
+ FindQuery find( uid );
+ return todo( m_driver->query(&find) );
+}
+/*
+ * update the dict
+ */
+void OTodoAccessBackendSQL::fillDict() {
+ /* initialize dict */
+ /*
+ * UPDATE dict if you change anything!!!
+ * FIXME: Isn't this dict obsolete ? (eilers)
+ */
+ m_dict.setAutoDelete( TRUE );
+ m_dict.insert("Categories" , new int(OTodo::Category) );
+ m_dict.insert("Uid" , new int(OTodo::Uid) );
+ m_dict.insert("HasDate" , new int(OTodo::HasDate) );
+ m_dict.insert("Completed" , new int(OTodo::Completed) );
+ m_dict.insert("Description" , new int(OTodo::Description) );
+ m_dict.insert("Summary" , new int(OTodo::Summary) );
+ m_dict.insert("Priority" , new int(OTodo::Priority) );
+ m_dict.insert("DateDay" , new int(OTodo::DateDay) );
+ m_dict.insert("DateMonth" , new int(OTodo::DateMonth) );
+ m_dict.insert("DateYear" , new int(OTodo::DateYear) );
+ m_dict.insert("Progress" , new int(OTodo::Progress) );
+ m_dict.insert("Completed", new int(OTodo::Completed) ); // Why twice ? (eilers)
+ m_dict.insert("CrossReference", new int(OTodo::CrossReference) );
+// m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) ); // old stuff (eilers)
+// m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) ); // old stuff (eilers)
+}
+/*
+ * need to be const so let's fool the
+ * compiler :(
+ */
+void OTodoAccessBackendSQL::update()const {
+ ((OTodoAccessBackendSQL*)this)->m_dirty = false;
+ LoadQuery lo;
+ OSQLResult res = m_driver->query(&lo);
+ if ( res.state() != OSQLResult::Success )
+ return;
+
+ ((OTodoAccessBackendSQL*)this)->m_uids = uids( res );
+}
+QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{
+
+ OSQLResultItem::ValueList list = res.results();
+ OSQLResultItem::ValueList::Iterator it;
+ QArray<int> ints(list.count() );
+ qWarning(" count = %d", list.count() );
+
+ int i = 0;
+ for (it = list.begin(); it != list.end(); ++it ) {
+ ints[i] = (*it).data("uid").toInt();
+ i++;
+ }
+ return ints;
+}
+
+QArray<int> OTodoAccessBackendSQL::matchRegexp( const QRegExp &r ) const
+{
+
+#warning OTodoAccessBackendSQL::matchRegexp() not implemented !!
+
+#if 0
+
+ Copied from xml-backend by not adapted to sql (eilers)
+
+ QArray<int> m_currentQuery( m_events.count() );
+ uint arraycounter = 0;
+
+
+
+ QMap<int, OTodo>::ConstIterator it;
+ for (it = m_events.begin(); it != m_events.end(); ++it ) {
+ if ( it.data().match( r ) )
+ m_currentQuery[arraycounter++] = it.data().uid();
+
+ }
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+#endif
+ QArray<int> empty;
+ return empty;
+}
+QBitArray OTodoAccessBackendSQL::supports()const {
+
+ return sup();
+}
+
+QBitArray OTodoAccessBackendSQL::sup() const{
+
+ QBitArray ar( OTodo::CompletedDate + 1 );
+ ar.fill( true );
+ ar[OTodo::CrossReference] = false;
+ ar[OTodo::State ] = false;
+ ar[OTodo::Reminders] = false;
+ ar[OTodo::Notifiers] = false;
+ ar[OTodo::Maintainer] = false;
+
+ return ar;
+}
+
+void OTodoAccessBackendSQL::removeAllCompleted(){
+#warning OTodoAccessBackendSQL::removeAllCompleted() not implemented !!
+
+}
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 @@
+#ifndef OPIE_PIM_ACCESS_SQL_H
+#define OPIE_PIM_ACCESS_SQL_H
+
+#include <qasciidict.h>
+
+#include "otodoaccessbackend.h"
+
+namespace Opie{
+namespace DB {
+class OSQLDriver;
+class OSQLResult;
+class OSQLResultItem;
+}
+}
+
+class OTodoAccessBackendSQL : public OTodoAccessBackend {
+public:
+ OTodoAccessBackendSQL( const QString& file );
+ ~OTodoAccessBackendSQL();
+
+ bool load();
+ bool reload();
+ bool save();
+ QArray<int> allRecords()const;
+
+ QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() );
+ OTodo find(int uid)const;
+ OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const;
+ void clear();
+ bool add( const OTodo& t );
+ bool remove( int uid );
+ bool replace( const OTodo& t );
+
+ QArray<int> overDue();
+ QArray<int> effectiveToDos( const QDate& start,
+ const QDate& end, bool includeNoDates );
+ QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat );
+
+ QBitArray supports()const;
+ QArray<int> matchRegexp( const QRegExp &r ) const;
+ void removeAllCompleted();
+
+
+private:
+ void update()const;
+ void fillDict();
+ inline bool date( QDate& date, const QString& )const;
+ inline OTodo todo( const Opie::DB::OSQLResult& )const;
+ inline OTodo todo( Opie::DB::OSQLResultItem& )const;
+ inline QArray<int> uids( const Opie::DB::OSQLResult& )const;
+ OTodo todo( int uid )const;
+ QBitArray sup() const;
+
+ QAsciiDict<int> m_dict;
+ Opie::DB::OSQLDriver* m_driver;
+ QArray<int> m_uids;
+ bool m_dirty : 1;
+};
+
+
+#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 @@
+#include <qfile.h>
+
+#include <qtopia/private/vobject_p.h>
+#include <qtopia/timeconversion.h>
+#include <qtopia/private/qfiledirect_p.h>
+
+#include "otodoaccessvcal.h"
+
+namespace {
+ static OTodo eventByVObj( VObject *obj ){
+ OTodo event;
+ VObject *ob;
+ QCString name;
+ // no uid, attendees, ... and no fun
+ // description
+ if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){
+ name = vObjectStringZValue( ob );
+#if 0
+ event.setDescription( name );
+#else
+ event.setSummary( name );
+#endif
+ }
+ // summary
+ if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) {
+ name = vObjectStringZValue( ob );
+#if 0
+ event.setSummary( name );
+#else
+ event.setDescription( name );
+#endif
+ }
+ // completed
+ if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){
+ name = vObjectStringZValue( ob );
+ if( name == "COMPLETED" ){
+ event.setCompleted( true );
+ }else{
+ event.setCompleted( false );
+ }
+ }else
+ event.setCompleted( false );
+ // priority
+ if ((ob = isAPropertyOf(obj, VCPriorityProp))) {
+ name = vObjectStringZValue( ob );
+ bool ok;
+ event.setPriority(name.toInt(&ok) );
+ }
+ //due date
+ if((ob = isAPropertyOf(obj, VCDueProp)) ){
+ event.setHasDueDate( true );
+ name = vObjectStringZValue( ob );
+ event.setDueDate( TimeConversion::fromISO8601( name).date() );
+ }
+ // categories
+ if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){
+ name = vObjectStringZValue( ob );
+ qWarning("Categories:%s", name.data() );
+ }
+
+ event.setUid( 1 );
+ return event;
+ };
+ static VObject *vobjByEvent( const OTodo &event ) {
+ VObject *task = newVObject( VCTodoProp );
+ if( task == 0 )
+ return 0l;
+
+ if( event.hasDueDate() ) {
+ QTime time(0, 0, 0);
+ QDateTime date(event.dueDate(), time );
+ addPropValue( task, VCDueProp,
+ TimeConversion::toISO8601( date ) );
+ }
+
+ if( event.isCompleted() )
+ addPropValue( task, VCStatusProp, "COMPLETED");
+
+ QString string = QString::number(event.priority() );
+ addPropValue( task, VCPriorityProp, string.local8Bit() );
+
+ addPropValue( task, VCCategoriesProp,
+ event.idsToString( event.categories() ).local8Bit() );
+
+#if 0
+
+ // There seems a misrepresentation between summary in otodoevent
+ // and summary in vcard.
+ // The same with description..
+ // Description is summary and vice versa.. Argh.. (eilers)
+
+
+ addPropValue( task, VCDescriptionProp,
+ event.description().local8Bit() );
+
+ addPropValue( task, VCSummaryProp,
+ event.summary().local8Bit() );
+
+#else
+ addPropValue( task, VCDescriptionProp,
+ event.summary().local8Bit() );
+
+ addPropValue( task, VCSummaryProp,
+ event.description().local8Bit() );
+#endif
+ return task;
+};
+}
+
+OTodoAccessVCal::OTodoAccessVCal( const QString& path )
+ : m_dirty(false), m_file( path )
+{
+}
+OTodoAccessVCal::~OTodoAccessVCal() {
+}
+bool OTodoAccessVCal::load() {
+ m_map.clear();
+ m_dirty = false;
+
+ VObject* vcal = 0l;
+ vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() );
+ if (!vcal )
+ return false;
+
+ // Iterate over the list
+ VObjectIterator it;
+ VObject* vobj;
+
+ initPropIterator(&it, vcal);
+
+ while( moreIteration( &it ) ) {
+ vobj = ::nextVObject( &it );
+ QCString name = ::vObjectName( vobj );
+ if( name == VCTodoProp ){
+ OTodo to = eventByVObj( vobj );
+ m_map.insert( to.uid(), to );
+ }
+ }
+
+ // Should I do a delete vcal?
+
+ return true;
+}
+bool OTodoAccessVCal::reload() {
+ return load();
+}
+bool OTodoAccessVCal::save() {
+ if (!m_dirty )
+ return true;
+
+ QFileDirect file( m_file );
+ if (!file.open(IO_WriteOnly ) )
+ return false;
+
+ VObject *obj;
+ obj = newVObject( VCCalProp );
+ addPropValue( obj, VCVersionProp, "1.0" );
+ VObject *vo;
+ for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){
+ vo = vobjByEvent( it.data() );
+ addVObjectProp(obj, vo );
+ }
+ writeVObject( file.directHandle(), obj );
+ cleanVObject( obj );
+ cleanStrTbl();
+
+ m_dirty = false;
+ return true;
+}
+void OTodoAccessVCal::clear() {
+ m_map.clear();
+ m_dirty = true;
+}
+bool OTodoAccessVCal::add( const OTodo& to ) {
+ m_map.insert( to.uid(), to );
+ m_dirty = true;
+ return true;
+}
+bool OTodoAccessVCal::remove( int uid ) {
+ m_map.remove( uid );
+ m_dirty = true;
+ return true;
+}
+void OTodoAccessVCal::removeAllCompleted() {
+ for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) {
+ if ( (*it).isCompleted() )
+ m_map.remove( it );
+ }
+}
+bool OTodoAccessVCal::replace( const OTodo& to ) {
+ m_map.replace( to.uid(), to );
+ m_dirty = true;
+ return true;
+}
+OTodo OTodoAccessVCal::find(int uid )const {
+ return m_map[uid];
+}
+QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) {
+ QArray<int> ar(0);
+ return ar;
+}
+QArray<int> OTodoAccessVCal::allRecords()const {
+ QArray<int> ar( m_map.count() );
+ QMap<int, OTodo>::ConstIterator it;
+ int i = 0;
+ for ( it = m_map.begin(); it != m_map.end(); ++it ) {
+ ar[i] = it.key();
+ i++;
+ }
+ return ar;
+}
+QArray<int> OTodoAccessVCal::matchRegexp(const QRegExp& /* r */)const {
+ QArray<int> ar(0);
+ return ar;
+}
+QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) {
+ QArray<int> ar(0);
+ return ar;
+}
+QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& ,
+ const QDate& ,
+ bool ) {
+ QArray<int> ar(0);
+ return ar;
+}
+QArray<int> OTodoAccessVCal::overDue() {
+ QArray<int> ar(0);
+ return ar;
+}
+QBitArray OTodoAccessVCal::supports()const {
+ static QBitArray ar = sup();
+
+ return ar;
+}
+QBitArray OTodoAccessVCal::sup() {
+ QBitArray ar ( OTodo::CompletedDate +1 );
+ ar.fill( true );
+
+ ar[OTodo::CrossReference] = false;
+ ar[OTodo::State ] = false;
+ ar[OTodo::Reminders] = false;
+ ar[OTodo::Notifiers] = false;
+ ar[OTodo::Maintainer] = false;
+ ar[OTodo::Progress] = false;
+ ar[OTodo::Alarms ] = false;
+ ar[OTodo::Recurrence] = false;
+
+ return ar;
+}
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 @@
+#ifndef OPIE_OTODO_ACCESS_VCAL_H
+#define OPIE_OTODO_ACCESS_VCAL_H
+
+#include "otodoaccessbackend.h"
+
+class OTodoAccessVCal : public OTodoAccessBackend {
+public:
+ OTodoAccessVCal(const QString& );
+ ~OTodoAccessVCal();
+
+ bool load();
+ bool reload();
+ bool save();
+
+ QArray<int> allRecords()const;
+ QArray<int> matchRegexp(const QRegExp &r) const;
+ QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() );
+ QArray<int> effectiveToDos( const QDate& start,
+ const QDate& end,
+ bool includeNoDates );
+ QArray<int> overDue();
+ QArray<int> sorted( bool asc, int sortOrder, int sortFilter,
+ int cat );
+ OTodo find(int uid)const;
+ void clear();
+ bool add( const OTodo& );
+ bool remove( int uid );
+ bool replace( const OTodo& );
+
+ void removeAllCompleted();
+ virtual QBitArray supports()const;
+
+private:
+ static QBitArray sup();
+ bool m_dirty : 1;
+ QString m_file;
+ QMap<int, OTodo> m_map;
+};
+
+#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 @@
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+
+
+#include <qfile.h>
+#include <qvector.h>
+
+#include <qpe/global.h>
+#include <qpe/stringutil.h>
+#include <qpe/timeconversion.h>
+
+#include "oconversion.h"
+#include "opimstate.h"
+#include "otimezone.h"
+#include "opimnotifymanager.h"
+#include "orecur.h"
+#include "otodoaccessxml.h"
+
+namespace {
+ time_t rp_end;
+ ORecur* rec;
+ ORecur *recur() {
+ if (!rec ) rec = new ORecur;
+ return rec;
+ }
+ int snd;
+ enum MoreAttributes {
+ FRType = OTodo::CompletedDate + 2,
+ FRWeekdays,
+ FRPosition,
+ FRFreq,
+ FRHasEndDate,
+ FREndDate,
+ FRStart,
+ FREnd
+ };
+ // FROM TT again
+char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen)
+{
+ char needleChar;
+ char haystackChar;
+ if (!needle || !haystack || !hLen || !nLen)
+ return 0;
+
+ const char* hsearch = haystack;
+
+ if ((needleChar = *needle++) != 0) {
+ nLen--; //(to make up for needle++)
+ do {
+ do {
+ if ((haystackChar = *hsearch++) == 0)
+ return (0);
+ if (hsearch >= haystack + hLen)
+ return (0);
+ } while (haystackChar != needleChar);
+ } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0);
+ hsearch--;
+ }
+ return ((char *)hsearch);
+}
+}
+
+
+OTodoAccessXML::OTodoAccessXML( const QString& appName,
+ const QString& fileName )
+ : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false )
+{
+ if (!fileName.isEmpty() )
+ m_file = fileName;
+ else
+ m_file = Global::applicationFileName( "todolist", "todolist.xml" );
+}
+OTodoAccessXML::~OTodoAccessXML() {
+
+}
+bool OTodoAccessXML::load() {
+ rec = 0;
+ m_opened = true;
+ m_changed = false;
+ /* initialize dict */
+ /*
+ * UPDATE dict if you change anything!!!
+ */
+ QAsciiDict<int> dict(26);
+ dict.setAutoDelete( TRUE );
+ dict.insert("Categories" , new int(OTodo::Category) );
+ dict.insert("Uid" , new int(OTodo::Uid) );
+ dict.insert("HasDate" , new int(OTodo::HasDate) );
+ dict.insert("Completed" , new int(OTodo::Completed) );
+ dict.insert("Description" , new int(OTodo::Description) );
+ dict.insert("Summary" , new int(OTodo::Summary) );
+ dict.insert("Priority" , new int(OTodo::Priority) );
+ dict.insert("DateDay" , new int(OTodo::DateDay) );
+ dict.insert("DateMonth" , new int(OTodo::DateMonth) );
+ dict.insert("DateYear" , new int(OTodo::DateYear) );
+ dict.insert("Progress" , new int(OTodo::Progress) );
+ dict.insert("CompletedDate", new int(OTodo::CompletedDate) );
+ dict.insert("StartDate", new int(OTodo::StartDate) );
+ dict.insert("CrossReference", new int(OTodo::CrossReference) );
+ dict.insert("State", new int(OTodo::State) );
+ dict.insert("Alarms", new int(OTodo::Alarms) );
+ dict.insert("Reminders", new int(OTodo::Reminders) );
+ dict.insert("Notifiers", new int(OTodo::Notifiers) );
+ dict.insert("Maintainer", new int(OTodo::Maintainer) );
+ dict.insert("rtype", new int(FRType) );
+ dict.insert("rweekdays", new int(FRWeekdays) );
+ dict.insert("rposition", new int(FRPosition) );
+ dict.insert("rfreq", new int(FRFreq) );
+ dict.insert("start", new int(FRStart) );
+ dict.insert("rhasenddate", new int(FRHasEndDate) );
+ dict.insert("enddt", new int(FREndDate) );
+
+ // here the custom XML parser from TT it's GPL
+ // but we want to push OpiePIM... to TT.....
+ // mmap part from zecke :)
+ int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY );
+ struct stat attribut;
+ if ( fd < 0 ) return false;
+
+ if ( fstat(fd, &attribut ) == -1 ) {
+ ::close( fd );
+ return false;
+ }
+ void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 );
+ if ( map_addr == ( (caddr_t)-1) ) {
+ ::close(fd );
+ return false;
+ }
+ /* advise the kernel who we want to read it */
+ ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL );
+ /* we do not the file any more */
+ ::close( fd );
+
+ char* dt = (char*)map_addr;
+ int len = attribut.st_size;
+ int i = 0;
+ char *point;
+ const char* collectionString = "<Task ";
+ int strLen = strlen(collectionString);
+ while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) {
+ i = point -dt;
+ i+= strLen;
+ qWarning("Found a start at %d %d", i, (point-dt) );
+
+ OTodo ev;
+ m_year = m_month = m_day = 0;
+
+ while ( TRUE ) {
+ while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
+ ++i;
+ if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
+ break;
+
+ // we have another attribute, read it.
+ int j = i;
+ while ( j < len && dt[j] != '=' )
+ ++j;
+ QCString attr( dt+i, j-i+1);
+
+ i = ++j; // skip =
+
+ // find the start of quotes
+ while ( i < len && dt[i] != '"' )
+ ++i;
+ j = ++i;
+
+ bool haveUtf = FALSE;
+ bool haveEnt = FALSE;
+ while ( j < len && dt[j] != '"' ) {
+ if ( ((unsigned char)dt[j]) > 0x7f )
+ haveUtf = TRUE;
+ if ( dt[j] == '&' )
+ haveEnt = TRUE;
+ ++j;
+ }
+ if ( i == j ) {
+ // empty value
+ i = j + 1;
+ continue;
+ }
+
+ QCString value( dt+i, j-i+1 );
+ i = j + 1;
+
+ QString str = (haveUtf ? QString::fromUtf8( value )
+ : QString::fromLatin1( value ) );
+ if ( haveEnt )
+ str = Qtopia::plainString( str );
+
+ /*
+ * add key + value
+ */
+ todo( &dict, ev, attr, str );
+
+ }
+ /*
+ * now add it
+ */
+ qWarning("End at %d", i );
+ if (m_events.contains( ev.uid() ) || ev.uid() == 0) {
+ ev.setUid( 1 );
+ m_changed = true;
+ }
+ if ( ev.hasDueDate() ) {
+ ev.setDueDate( QDate(m_year, m_month, m_day) );
+ }
+ if ( rec && rec->doesRecur() ) {
+ OTimeZone utc = OTimeZone::utc();
+ ORecur recu( *rec ); // call copy c'tor
+ recu.setEndDate( utc.fromUTCDateTime( rp_end ).date() );
+ recu.setStart( ev.dueDate() );
+ ev.setRecurrence( recu );
+ }
+ m_events.insert(ev.uid(), ev );
+ m_year = m_month = m_day = -1;
+ delete rec;
+ rec = 0;
+ }
+
+ munmap(map_addr, attribut.st_size );
+
+ qWarning("counts %d records loaded!", m_events.count() );
+ return true;
+}
+bool OTodoAccessXML::reload() {
+ m_events.clear();
+ return load();
+}
+bool OTodoAccessXML::save() {
+// qWarning("saving");
+ if (!m_opened || !m_changed ) {
+// qWarning("not saving");
+ return true;
+ }
+ QString strNewFile = m_file + ".new";
+ QFile f( strNewFile );
+ if (!f.open( IO_WriteOnly|IO_Raw ) )
+ return false;
+
+ int written;
+ QString out;
+ out = "<!DOCTYPE Tasks>\n<Tasks>\n";
+
+ // for all todos
+ QMap<int, OTodo>::Iterator it;
+ for (it = m_events.begin(); it != m_events.end(); ++it ) {
+ out+= "<Task " + toString( (*it) ) + " />\n";
+ QCString cstr = out.utf8();
+ written = f.writeBlock( cstr.data(), cstr.length() );
+
+ /* less written then we wanted */
+ if ( written != (int)cstr.length() ) {
+ f.close();
+ QFile::remove( strNewFile );
+ return false;
+ }
+ out = QString::null;
+ }
+
+ out += "</Tasks>";
+ QCString cstr = out.utf8();
+ written = f.writeBlock( cstr.data(), cstr.length() );
+
+ if ( written != (int)cstr.length() ) {
+ f.close();
+ QFile::remove( strNewFile );
+ return false;
+ }
+ /* flush before renaming */
+ f.close();
+
+ if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) {
+// qWarning("error renaming");
+ QFile::remove( strNewFile );
+ }
+
+ m_changed = false;
+ return true;
+}
+QArray<int> OTodoAccessXML::allRecords()const {
+ QArray<int> ids( m_events.count() );
+ QMap<int, OTodo>::ConstIterator it;
+ int i = 0;
+
+ for ( it = m_events.begin(); it != m_events.end(); ++it ) {
+ ids[i] = it.key();
+ i++;
+ }
+ return ids;
+}
+QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) {
+ QArray<int> ids(0);
+ return ids;
+}
+OTodo OTodoAccessXML::find( int uid )const {
+ OTodo todo;
+ todo.setUid( 0 ); // isEmpty()
+ QMap<int, OTodo>::ConstIterator it = m_events.find( uid );
+ if ( it != m_events.end() )
+ todo = it.data();
+
+ return todo;
+}
+void OTodoAccessXML::clear() {
+ if (m_opened )
+ m_changed = true;
+
+ m_events.clear();
+}
+bool OTodoAccessXML::add( const OTodo& todo ) {
+// qWarning("add");
+ m_changed = true;
+ m_events.insert( todo.uid(), todo );
+
+ return true;
+}
+bool OTodoAccessXML::remove( int uid ) {
+ m_changed = true;
+ m_events.remove( uid );
+
+ return true;
+}
+bool OTodoAccessXML::replace( const OTodo& todo) {
+ m_changed = true;
+ m_events.replace( todo.uid(), todo );
+
+ return true;
+}
+QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start,
+ const QDate& end,
+ bool includeNoDates ) {
+ QArray<int> ids( m_events.count() );
+ QMap<int, OTodo>::Iterator it;
+
+ int i = 0;
+ for ( it = m_events.begin(); it != m_events.end(); ++it ) {
+ if ( !it.data().hasDueDate() ) {
+ if ( includeNoDates ) {
+ ids[i] = it.key();
+ i++;
+ }
+ }else if ( it.data().dueDate() >= start &&
+ it.data().dueDate() <= end ) {
+ ids[i] = it.key();
+ i++;
+ }
+ }
+ ids.resize( i );
+ return ids;
+}
+QArray<int> OTodoAccessXML::overDue() {
+ QArray<int> ids( m_events.count() );
+ int i = 0;
+
+ QMap<int, OTodo>::Iterator it;
+ for ( it = m_events.begin(); it != m_events.end(); ++it ) {
+ if ( it.data().isOverdue() ) {
+ ids[i] = it.key();
+ i++;
+ }
+ }
+ ids.resize( i );
+ return ids;
+}
+
+
+/* private */
+void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev,
+ const QCString& attr, const QString& val) {
+// qWarning("parse to do from XMLElement" );
+
+ int *find=0;
+
+ find = (*dict)[ attr.data() ];
+ if (!find ) {
+// qWarning("Unknown option" + it.key() );
+ ev.setCustomField( attr, val );
+ return;
+ }
+
+ switch( *find ) {
+ case OTodo::Uid:
+ ev.setUid( val.toInt() );
+ break;
+ case OTodo::Category:
+ ev.setCategories( ev.idsFromString( val ) );
+ break;
+ case OTodo::HasDate:
+ ev.setHasDueDate( val.toInt() );
+ break;
+ case OTodo::Completed:
+ ev.setCompleted( val.toInt() );
+ break;
+ case OTodo::Description:
+ ev.setDescription( val );
+ break;
+ case OTodo::Summary:
+ ev.setSummary( val );
+ break;
+ case OTodo::Priority:
+ ev.setPriority( val.toInt() );
+ break;
+ case OTodo::DateDay:
+ m_day = val.toInt();
+ break;
+ case OTodo::DateMonth:
+ m_month = val.toInt();
+ break;
+ case OTodo::DateYear:
+ m_year = val.toInt();
+ break;
+ case OTodo::Progress:
+ ev.setProgress( val.toInt() );
+ break;
+ case OTodo::CompletedDate:
+ ev.setCompletedDate( OConversion::dateFromString( val ) );
+ break;
+ case OTodo::StartDate:
+ ev.setStartDate( OConversion::dateFromString( val ) );
+ break;
+ case OTodo::State:
+ ev.setState( val.toInt() );
+ break;
+ case OTodo::Alarms:{
+ OPimNotifyManager &manager = ev.notifiers();
+ QStringList als = QStringList::split(";", val );
+ for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) {
+ QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty
+ qWarning("alarm: %s", alarm.join("___").latin1() );
+ qWarning("alarm[0]: %s %s", alarm[0].latin1(), OConversion::dateTimeFromString( alarm[0] ).toString().latin1() );
+ OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), alarm[1].toInt() );
+ manager.add( al );
+ }
+ }
+ break;
+ case OTodo::Reminders:{
+ OPimNotifyManager &manager = ev.notifiers();
+ QStringList rems = QStringList::split(";", val );
+ for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) {
+ OPimReminder rem( (*it).toInt() );
+ manager.add( rem );
+ }
+ }
+ break;
+ case OTodo::CrossReference:
+ {
+ /*
+ * A cross refernce looks like
+ * appname,id;appname,id
+ * we need to split it up
+ */
+ QStringList refs = QStringList::split(';', val );
+ QStringList::Iterator strIt;
+ for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) {
+ int pos = (*strIt).find(',');
+ if ( pos > -1 )
+ ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() );
+
+ }
+ break;
+ }
+ /* Recurrence stuff below + post processing later */
+ case FRType:
+ if ( val == "Daily" )
+ recur()->setType( ORecur::Daily );
+ else if ( val == "Weekly" )
+ recur()->setType( ORecur::Weekly);
+ else if ( val == "MonthlyDay" )
+ recur()->setType( ORecur::MonthlyDay );
+ else if ( val == "MonthlyDate" )
+ recur()->setType( ORecur::MonthlyDate );
+ else if ( val == "Yearly" )
+ recur()->setType( ORecur::Yearly );
+ else
+ recur()->setType( ORecur::NoRepeat );
+ break;
+ case FRWeekdays:
+ recur()->setDays( val.toInt() );
+ break;
+ case FRPosition:
+ recur()->setPosition( val.toInt() );
+ break;
+ case FRFreq:
+ recur()->setFrequency( val.toInt() );
+ break;
+ case FRHasEndDate:
+ recur()->setHasEndDate( val.toInt() );
+ break;
+ case FREndDate: {
+ rp_end = (time_t) val.toLong();
+ break;
+ }
+ default:
+ ev.setCustomField( attr, val );
+ break;
+ }
+}
+
+// from PalmtopRecord... GPL ### FIXME
+namespace {
+QString customToXml(const QMap<QString, QString>& customMap )
+{
+ //qWarning(QString("writing custom %1").arg(customMap.count()));
+ QString buf(" ");
+ for ( QMap<QString, QString>::ConstIterator cit = customMap.begin();
+ cit != customMap.end(); ++cit) {
+// qWarning(".ITEM.");
+ buf += cit.key();
+ buf += "=\"";
+ buf += Qtopia::escapeString(cit.data());
+ buf += "\" ";
+ }
+ return buf;
+}
+
+
+}
+
+QString OTodoAccessXML::toString( const OTodo& ev )const {
+ QString str;
+
+ str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" ";
+ str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" ";
+ str += "Priority=\"" + QString::number( ev.priority() ) + "\" ";
+ str += "Progress=\"" + QString::number(ev.progress() ) + "\" ";
+
+ str += "Categories=\"" + toString( ev.categories() ) + "\" ";
+ str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" ";
+ str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" ";
+
+ if ( ev.hasDueDate() ) {
+ str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" ";
+ str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" ";
+ str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" ";
+ }
+// qWarning( "Uid %d", ev.uid() );
+ str += "Uid=\"" + QString::number( ev.uid() ) + "\" ";
+
+// append the extra options
+ /* FIXME Qtopia::Record this is currently not
+ * possible you can set custom fields
+ * but don' iterate over the list
+ * I may do #define private protected
+ * for this case - cough --zecke
+ */
+ /*
+ QMap<QString, QString> extras = ev.extras();
+ QMap<QString, QString>::Iterator extIt;
+ for (extIt = extras.begin(); extIt != extras.end(); ++extIt )
+ str += extIt.key() + "=\"" + extIt.data() + "\" ";
+ */
+ // cross refernce
+ if ( ev.hasRecurrence() ) {
+ str += ev.recurrence().toString();
+ }
+ if ( ev.hasStartDate() )
+ str += "StartDate=\""+ OConversion::dateToString( ev.startDate() ) +"\" ";
+ if ( ev.hasCompletedDate() )
+ str += "CompletedDate=\""+ OConversion::dateToString( ev.completedDate() ) +"\" ";
+ if ( ev.hasState() )
+ str += "State=\""+QString::number( ev.state().state() )+"\" ";
+
+ /*
+ * save reminders and notifiers!
+ * DATE_TIME:DURATION:SOUND:NOT_USED_YET;OTHER_DATE_TIME:OTHER_DURATION:SOUND:....
+ */
+ if ( ev.hasNotifiers() ) {
+ OPimNotifyManager manager = ev.notifiers();
+ OPimNotifyManager::Alarms alarms = manager.alarms();
+ if (!alarms.isEmpty() ) {
+ QStringList als;
+ OPimNotifyManager::Alarms::Iterator it = alarms.begin();
+ for ( ; it != alarms.end(); ++it ) {
+ /* only if time is valid */
+ if ( (*it).dateTime().isValid() ) {
+ als << OConversion::dateTimeToString( (*it).dateTime() )
+ + ":" + QString::number( (*it).duration() )
+ + ":" + QString::number( (*it).sound() )
+ + ":";
+ }
+ }
+ // now write the list
+ qWarning("als: %s", als.join("____________").latin1() );
+ str += "Alarms=\""+als.join(";") +"\" ";
+ }
+
+ /*
+ * now the same for reminders but more easy. We just save the uid of the OEvent.
+ */
+ OPimNotifyManager::Reminders reminders = manager.reminders();
+ if (!reminders.isEmpty() ) {
+ OPimNotifyManager::Reminders::Iterator it = reminders.begin();
+ QStringList records;
+ for ( ; it != reminders.end(); ++it ) {
+ records << QString::number( (*it).recordUid() );
+ }
+ str += "Reminders=\""+ records.join(";") +"\" ";
+ }
+ }
+ str += customToXml( ev.toExtraMap() );
+
+
+ return str;
+}
+QString OTodoAccessXML::toString( const QArray<int>& ints ) const {
+ return Qtopia::Record::idsToString( ints );
+}
+
+/* internal class for sorting
+ *
+ * Inspired by todoxmlio.cpp from TT
+ */
+
+struct OTodoXMLContainer {
+ OTodo todo;
+};
+
+namespace {
+ inline QString string( const OTodo& todo) {
+ return todo.summary().isEmpty() ?
+ todo.description().left(20 ) :
+ todo.summary();
+ }
+ inline int completed( const OTodo& todo1, const OTodo& todo2) {
+ int ret = 0;
+ if ( todo1.isCompleted() ) ret++;
+ if ( todo2.isCompleted() ) ret--;
+ return ret;
+ }
+ inline int priority( const OTodo& t1, const OTodo& t2) {
+ return ( t1.priority() - t2.priority() );
+ }
+ inline int description( const OTodo& t1, const OTodo& t2) {
+ return QString::compare( string(t1), string(t2) );
+ }
+ inline int deadline( const OTodo& t1, const OTodo& t2) {
+ int ret = 0;
+ if ( t1.hasDueDate() &&
+ t2.hasDueDate() )
+ ret = t2.dueDate().daysTo( t1.dueDate() );
+ else if ( t1.hasDueDate() )
+ ret = -1;
+ else if ( t2.hasDueDate() )
+ ret = 1;
+ else
+ ret = 0;
+
+ return ret;
+ }
+
+};
+
+/*
+ * Returns:
+ * 0 if item1 == item2
+ *
+ * non-zero if item1 != item2
+ *
+ * This function returns int rather than bool so that reimplementations
+ * can return one of three values and use it to sort by:
+ *
+ * 0 if item1 == item2
+ *
+ * > 0 (positive integer) if item1 > item2
+ *
+ * < 0 (negative integer) if item1 < item2
+ *
+ */
+class OTodoXMLVector : public QVector<OTodoXMLContainer> {
+public:
+ OTodoXMLVector(int size, bool asc, int sort)
+ : QVector<OTodoXMLContainer>( size )
+ {
+ setAutoDelete( true );
+ m_asc = asc;
+ m_sort = sort;
+ }
+ /* return the summary/description */
+ QString string( const OTodo& todo) {
+ return todo.summary().isEmpty() ?
+ todo.description().left(20 ) :
+ todo.summary();
+ }
+ /**
+ * we take the sortorder( switch on it )
+ *
+ */
+ int compareItems( Item d1, Item d2 ) {
+ bool seComp, sePrio, seDesc, seDeadline;
+ seComp = sePrio = seDeadline = seDesc = false;
+ int ret =0;
+ OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1;
+ OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2;
+
+ /* same item */
+ if ( con1->todo.uid() == con2->todo.uid() )
+ return 0;
+
+ switch ( m_sort ) {
+ /* completed */
+ case 0: {
+ ret = completed( con1->todo, con2->todo );
+ seComp = TRUE;
+ break;
+ }
+ /* priority */
+ case 1: {
+ ret = priority( con1->todo, con2->todo );
+ sePrio = TRUE;
+ break;
+ }
+ /* description */
+ case 2: {
+ ret = description( con1->todo, con2->todo );
+ seDesc = TRUE;
+ break;
+ }
+ /* deadline */
+ case 3: {
+ ret = deadline( con1->todo, con2->todo );
+ seDeadline = TRUE;
+ break;
+ }
+ default:
+ ret = 0;
+ break;
+ };
+ /*
+ * FIXME do better sorting if the first sort criteria
+ * ret equals 0 start with complete and so on...
+ */
+
+ /* twist it we're not ascending*/
+ if (!m_asc)
+ ret = ret * -1;
+
+ if ( ret )
+ return ret;
+
+ // default did not gave difference let's try it other way around
+ /*
+ * General try if already checked if not test
+ * and return
+ * 1.Completed
+ * 2.Priority
+ * 3.Description
+ * 4.DueDate
+ */
+ if (!seComp ) {
+ if ( (ret = completed( con1->todo, con2->todo ) ) ) {
+ if (!m_asc ) ret *= -1;
+ return ret;
+ }
+ }
+ if (!sePrio ) {
+ if ( (ret = priority( con1->todo, con2->todo ) ) ) {
+ if (!m_asc ) ret *= -1;
+ return ret;
+ }
+ }
+ if (!seDesc ) {
+ if ( (ret = description(con1->todo, con2->todo ) ) ) {
+ if (!m_asc) ret *= -1;
+ return ret;
+ }
+ }
+ if (!seDeadline) {
+ if ( (ret = deadline( con1->todo, con2->todo ) ) ) {
+ if (!m_asc) ret *= -1;
+ return ret;
+ }
+ }
+
+ return 0;
+ }
+ private:
+ bool m_asc;
+ int m_sort;
+
+};
+
+QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder,
+ int sortFilter, int cat ) {
+ OTodoXMLVector vector(m_events.count(), asc,sortOrder );
+ QMap<int, OTodo>::Iterator it;
+ int item = 0;
+
+ bool bCat = sortFilter & 1 ? true : false;
+ bool bOnly = sortFilter & 2 ? true : false;
+ bool comp = sortFilter & 4 ? true : false;
+ for ( it = m_events.begin(); it != m_events.end(); ++it ) {
+
+ /* show category */
+ /* -1 == unfiled */
+ if ( bCat && cat == -1 ) {
+ if(!(*it).categories().isEmpty() )
+ continue;
+ }else if ( bCat && cat != 0)
+ if (!(*it).categories().contains( cat ) ) {
+ continue;
+ }
+ /* isOverdue but we should not show overdue - why?*/
+/* if ( (*it).isOverdue() && !bOnly ) {
+ qWarning("item is overdue but !bOnly");
+ continue;
+ }
+*/
+ if ( !(*it).isOverdue() && bOnly ) {
+ continue;
+ }
+
+ if ((*it).isCompleted() && comp ) {
+ continue;
+ }
+
+
+ OTodoXMLContainer* con = new OTodoXMLContainer();
+ con->todo = (*it);
+ vector.insert(item, con );
+ item++;
+ }
+ vector.resize( item );
+ /* sort it now */
+ vector.sort();
+ /* now get the uids */
+ QArray<int> array( vector.count() );
+ for (uint i= 0; i < vector.count(); i++ ) {
+ array[i] = ( vector.at(i) )->todo.uid();
+ }
+ return array;
+};
+void OTodoAccessXML::removeAllCompleted() {
+ QMap<int, OTodo> events = m_events;
+ for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) {
+ if ( (*it).isCompleted() )
+ events.remove( it.key() );
+ }
+ m_events = events;
+}
+QBitArray OTodoAccessXML::supports()const {
+ static QBitArray ar = sup();
+ return ar;
+}
+QBitArray OTodoAccessXML::sup() {
+ QBitArray ar( OTodo::CompletedDate +1 );
+ ar.fill( true );
+ ar[OTodo::CrossReference] = false;
+ ar[OTodo::State ] = false;
+ ar[OTodo::Reminders] = false;
+ ar[OTodo::Notifiers] = false;
+ ar[OTodo::Maintainer] = false;
+
+ return ar;
+}
+QArray<int> OTodoAccessXML::matchRegexp( const QRegExp &r ) const
+{
+ QArray<int> m_currentQuery( m_events.count() );
+ uint arraycounter = 0;
+
+ QMap<int, OTodo>::ConstIterator it;
+ for (it = m_events.begin(); it != m_events.end(); ++it ) {
+ if ( it.data().match( r ) )
+ m_currentQuery[arraycounter++] = it.data().uid();
+
+ }
+ // Shrink to fit..
+ m_currentQuery.resize(arraycounter);
+
+ return m_currentQuery;
+}
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 @@
+#ifndef OPIE_TODO_ACCESS_XML_H
+#define OPIE_TODO_ACCESS_XML_H
+
+#include <qasciidict.h>
+#include <qmap.h>
+
+#include "otodoaccessbackend.h"
+
+namespace Opie {
+ class XMLElement;
+};
+
+class OTodoAccessXML : public OTodoAccessBackend {
+public:
+ /**
+ * fileName if Empty we will use the default path
+ */
+ OTodoAccessXML( const QString& appName,
+ const QString& fileName = QString::null );
+ ~OTodoAccessXML();
+
+ bool load();
+ bool reload();
+ bool save();
+
+ QArray<int> allRecords()const;
+ QArray<int> matchRegexp(const QRegExp &r) const;
+ QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() );
+ OTodo find( int uid )const;
+ void clear();
+ bool add( const OTodo& );
+ bool remove( int uid );
+ void removeAllCompleted();
+ bool replace( const OTodo& );
+
+ /* our functions */
+ QArray<int> effectiveToDos( const QDate& start,
+ const QDate& end,
+ bool includeNoDates );
+ QArray<int> overDue();
+ QArray<int> sorted( bool asc, int sortOrder,
+ int sortFilter, int cat );
+ QBitArray supports()const;
+private:
+ static QBitArray sup();
+ void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& );
+ QString toString( const OTodo& )const;
+ QString toString( const QArray<int>& ints ) const;
+ QMap<int, OTodo> m_events;
+ QString m_file;
+ QString m_app;
+ bool m_opened : 1;
+ bool m_changed : 1;
+ class OTodoAccessXMLPrivate;
+ OTodoAccessXMLPrivate* d;
+ int m_year, m_month, m_day;
+
+};
+
+#endif