summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/libopie.pro4
-rw-r--r--libopie/pim/obackendfactory.h24
-rw-r--r--libopie/pim/ocontactaccess.h14
-rw-r--r--libopie/pim/ocontactaccessbackend_sql.cpp18
-rw-r--r--libopie/pim/odatebookaccess.cpp19
-rw-r--r--libopie/pim/odatebookaccess.h9
-rw-r--r--libopie/pim/odatebookaccessbackend.cpp34
-rw-r--r--libopie/pim/odatebookaccessbackend.h19
-rw-r--r--libopie/pim/odatebookaccessbackend_sql.cpp231
-rw-r--r--libopie/pim/odatebookaccessbackend_sql.h2
-rw-r--r--libopie/pim/oevent.cpp13
-rw-r--r--libopie/pim/oevent.h6
-rw-r--r--libopie/pim/otimezone.cpp11
-rw-r--r--libopie/pim/otodoaccesssql.cpp2
-rw-r--r--libopie/pim/test/converter.cpp45
-rwxr-xr-xlibopie/pim/test/converter.h18
-rw-r--r--libopie/pim/test/converter.pro2
-rw-r--r--libopie2/opiepim/backend/obackendfactory.h24
-rw-r--r--libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp18
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend.cpp34
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend.h19
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp231
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend_sql.h2
-rw-r--r--libopie2/opiepim/backend/otodoaccesssql.cpp2
-rw-r--r--libopie2/opiepim/core/ocontactaccess.h14
-rw-r--r--libopie2/opiepim/core/odatebookaccess.cpp19
-rw-r--r--libopie2/opiepim/core/odatebookaccess.h9
-rw-r--r--libopie2/opiepim/core/otimezone.cpp11
-rw-r--r--libopie2/opiepim/oevent.cpp13
-rw-r--r--libopie2/opiepim/oevent.h6
30 files changed, 729 insertions, 144 deletions
diff --git a/libopie/libopie.pro b/libopie/libopie.pro
index 8682e84..a3d01ab 100644
--- a/libopie/libopie.pro
+++ b/libopie/libopie.pro
@@ -8,107 +8,107 @@ HEADERS = ofontmenu.h \
xmltree.h \
colordialog.h colorpopupmenu.h \
oclickablelabel.h oprocctrl.h \
oprocess.h odevice.h odevicebutton.h \
otimepicker.h otabwidget.h \
otabbar.h otabinfo.h \
ofontselector.h \
pim/opimrecord.h \
pim/otodo.h \
pim/orecordlist.h \
pim/opimaccesstemplate.h \
pim/opimaccessbackend.h \
pim/otodoaccess.h \
pim/otodoaccessbackend.h \
pim/oconversion.h \
pim/ocontact.h \
pim/ocontactfields.h \
pim/ocontactaccess.h \
pim/ocontactaccessbackend.h \
pim/ocontactaccessbackend_xml.h \
pim/ocontactaccessbackend_vcard.h \
pim/obackendfactory.h \
pim/opimcache.h \
pim/otodoaccessvcal.h \
pim/orecur.h \
pim/opimstate.h \
pim/opimxrefpartner.h \
pim/opimxref.h \
pim/opimxrefmanager.h \
pim/opimmaintainer.h \
pim/opimnotify.h \
pim/opimnotifymanager.h \
pim/opimmainwindow.h \
pim/opimresolver.h \
pim/oevent.h \
pim/otimezone.h \
pim/odatebookaccess.h \
pim/odatebookaccessbackend.h \
pim/odatebookaccessbackend_xml.h \
orecurrancewidget.h \
oticker.h owait.h
SOURCES = ofontmenu.cc \
ocolorbutton.cpp \
sharp_compat.cpp \
xmltree.cc \
ofiledialog.cc ofileselector.cpp \
ocheckitem.cpp \
colordialog.cpp \
colorpopupmenu.cpp oclickablelabel.cpp \
oprocctrl.cpp oprocess.cpp \
odevice.cpp odevicebutton.cpp otimepicker.cpp \
otabwidget.cpp otabbar.cpp \
ofontselector.cpp \
pim/otodo.cpp \
pim/opimrecord.cpp \
pim/otodoaccess.cpp \
pim/otodoaccessbackend.cpp \
pim/otodoaccessxml.cpp \
pim/oconversion.cpp \
pim/ocontact.cpp \
pim/ocontactfields.cpp \
pim/ocontactaccess.cpp \
pim/ocontactaccessbackend_vcard.cpp \
pim/ocontactaccessbackend_xml.cpp \
pim/otodoaccessvcal.cpp \
pim/orecur.cpp \
pim/opimstate.cpp \
pim/opimxrefpartner.cpp \
pim/opimxref.cpp \
pim/opimxrefmanager.cpp \
pim/opimmaintainer.cpp \
pim/opimnotify.cpp \
pim/opimnotifymanager.cpp \
pim/opimmainwindow.cpp \
pim/opimresolver.cpp \
pim/oevent.cpp \
pim/otimezone.cpp \
pim/odatebookaccess.cpp \
pim/odatebookaccessbackend.cpp \
pim/odatebookaccessbackend_xml.cpp \
orecurrancewidget.cpp \
oticker.cpp owait.cpp
TARGET = opie
INCLUDEPATH += $(OPIEDIR)/include
DESTDIR = $(OPIEDIR)/lib$(PROJMAK)
LIBS += -lqpe
# Add SQL-Support if selected by config (eilers)
CONFTEST = $$system( echo $CONFIG_SQL_PIM_BACKEND )
contains( CONFTEST, y ){
DEFINES += __USE_SQL
LIBS += -lopiedb2
-HEADERS += pim/otodoaccesssql.h pim/ocontactaccessbackend_sql.h
-SOURCES += pim/otodoaccesssql.cpp pim/ocontactaccessbackend_sql.cpp
+HEADERS += pim/otodoaccesssql.h pim/ocontactaccessbackend_sql.h pim/odatebookaccessbackend_sql.h
+SOURCES += pim/otodoaccesssql.cpp pim/ocontactaccessbackend_sql.cpp pim/odatebookaccessbackend_sql.cpp
}
INTERFACES = otimepickerbase.ui orecurrancebase.ui
TARGET = opie
include ( big-screen/big-screen.pro )
include ( $(OPIEDIR)/include.pro )
diff --git a/libopie/pim/obackendfactory.h b/libopie/pim/obackendfactory.h
index 3567687..761ab9a 100644
--- a/libopie/pim/obackendfactory.h
+++ b/libopie/pim/obackendfactory.h
@@ -1,176 +1,194 @@
/*
* 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.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 not implemented! Using XML instead!");
+ 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 not implemented! Using XML instead!");
+ 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" )
- qWarning("OBackendFactory:: sql Backend not implemented! Using XML instead!");
+ 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/libopie/pim/ocontactaccess.h b/libopie/pim/ocontactaccess.h
index 9b0a719..bd6da40 100644
--- a/libopie/pim/ocontactaccess.h
+++ b/libopie/pim/ocontactaccess.h
@@ -1,177 +1,189 @@
/*
* 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.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;
diff --git a/libopie/pim/ocontactaccessbackend_sql.cpp b/libopie/pim/ocontactaccessbackend_sql.cpp
index dd9dbde..a5be4c8 100644
--- a/libopie/pim/ocontactaccessbackend_sql.cpp
+++ b/libopie/pim/ocontactaccessbackend_sql.cpp
@@ -1,112 +1,124 @@
/*
* 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.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>
// 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();
@@ -417,202 +429,202 @@ namespace {
}
*/
#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();
+ 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 );
- CreateQuery qu;
- res = m_driver->query(&qu);
+
+ 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 " + "'"
diff --git a/libopie/pim/odatebookaccess.cpp b/libopie/pim/odatebookaccess.cpp
index a3661a3..82934f9 100644
--- a/libopie/pim/odatebookaccess.cpp
+++ b/libopie/pim/odatebookaccess.cpp
@@ -1,66 +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 ) {
- return m_backEnd->effecticeEvents( from, to );
+ return m_backEnd->effectiveEvents( from, to );
}
/**
* @return all events at a given datetime
*/
OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDateTime& start ) {
- return m_backEnd->effecticeEvents( start );
+ 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 ) {
+ return m_backEnd->effectiveNonRepeatingEvents( from, to );
+}
+/**
+ * @return all non repeating events at a given datetime
+ */
+OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDateTime& start ) {
+ return m_backEnd->effectiveNonRepeatingEvents( start );
}
diff --git a/libopie/pim/odatebookaccess.h b/libopie/pim/odatebookaccess.h
index 7c7a63f..62196da 100644
--- a/libopie/pim/odatebookaccess.h
+++ b/libopie/pim/odatebookaccess.h
@@ -1,41 +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
+ * @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;
- OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to );
- OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start );
+ /* 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/libopie/pim/odatebookaccessbackend.cpp b/libopie/pim/odatebookaccessbackend.cpp
index 8fa1a68..f0c5d65 100644
--- a/libopie/pim/odatebookaccessbackend.cpp
+++ b/libopie/pim/odatebookaccessbackend.cpp
@@ -34,123 +34,149 @@ namespace {
/* 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::effecticeEvents( const QDate& from,
+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();
+ list = directRawRepeats(); // Useless, isn't it ? (eilers)
qHeapSort( tmpList );
return tmpList;
}
-OEffectiveEvent::ValueList ODateBookAccessBackend::effecticeEvents( const QDateTime& dt ) {
- OEffectiveEvent::ValueList day = effecticeEvents( dt.date(), dt.date() );
+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/libopie/pim/odatebookaccessbackend.h b/libopie/pim/odatebookaccessbackend.h
index 3c02c42..3472ab3 100644
--- a/libopie/pim/odatebookaccessbackend.h
+++ b/libopie/pim/odatebookaccessbackend.h
@@ -1,77 +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 effecticeEvents( const QDate& from, const QDate& to );
+ virtual OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to );
/**
* this is an overloaded member function
- * @see effecticeEvents
+ * @see effectiveEvents( const QDate& from, const QDate& to )
*/
- virtual OEffectiveEvent::ValueList effecticeEvents( const QDateTime& start );
+ 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/libopie/pim/odatebookaccessbackend_sql.cpp b/libopie/pim/odatebookaccessbackend_sql.cpp
index 9769bf7..e893b38 100644
--- a/libopie/pim/odatebookaccessbackend_sql.cpp
+++ b/libopie/pim/odatebookaccessbackend_sql.cpp
@@ -1,221 +1,356 @@
/*
* 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.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 "orecur.h"
-#include "odatebookaccessbackend_sql.h"
+#include <qpe/global.h>
#include <opie2/osqldriver.h>
-#include <opie2/osqlresult.h>
#include <opie2/osqlmanager.h>
#include <opie2/osqlquery.h>
-namespace {
-
+#include "orecur.h"
+#include "odatebookaccessbackend_sql.h"
-};
ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& ,
const QString& fileName )
: ODateBookAccessBackend(), m_driver( NULL )
{
- m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName;
+ 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::FRExeptions, "RExceptions" );
+ 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 += 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();
+ // m_uids.clear();
return;
}
m_uids = extractUids( res );
}
-QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const
-{
- qWarning("extractUids");
-
- 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;
-
-}
-
bool ODateBookAccessBackend_SQL::reload()
{
- return load();
+ return load();
}
bool ODateBookAccessBackend_SQL::save()
{
- return m_driver->close();
+ return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
}
QArray<int> ODateBookAccessBackend_SQL::allRecords()const
{
- return m_uids;
+ return m_uids;
}
QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) {
- return QArray<int>();
+ 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;
}
-bool ODateBookAccessBackend_SQL::add( const OEvent& ev ) {
- return true;
+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;
+ }
+
+ return true;
}
-bool ODateBookAccessBackend_SQL::remove( int uid ) {
- return true;
+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;
+ }
+
+ return true;
}
-bool ODateBookAccessBackend_SQL::replace( const OEvent& ev ) {
+
+bool ODateBookAccessBackend_SQL::replace( const OEvent& ev )
+{
remove( ev.uid() );
return add( ev );
}
-QArray<int> ODateBookAccessBackend_SQL::rawEvents()const {
+
+QArray<int> ODateBookAccessBackend_SQL::rawEvents()const
+{
return allRecords();
}
-QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const {
- return ints;
+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 {
- return ints;
+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() {
- return list;
+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() {
+OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats()
+{
+ QArray<int> rawRepUids = rawRepeats();
+ OEvent::ValueList list;
- return 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;
- return m_currentQuery;
}
diff --git a/libopie/pim/odatebookaccessbackend_sql.h b/libopie/pim/odatebookaccessbackend_sql.h
index 85e0d4f..f39e154 100644
--- a/libopie/pim/odatebookaccessbackend_sql.h
+++ b/libopie/pim/odatebookaccessbackend_sql.h
@@ -1,60 +1,62 @@
#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"
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;
OSQLDriver* m_driver;
class Private;
Private *d;
void initFields();
void update();
QArray<int> extractUids( OSQLResult& res ) const;
};
#endif
diff --git a/libopie/pim/oevent.cpp b/libopie/pim/oevent.cpp
index ec05e77..9b31957 100644
--- a/libopie/pim/oevent.cpp
+++ b/libopie/pim/oevent.cpp
@@ -1,175 +1,184 @@
#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;
}
@@ -310,192 +319,196 @@ QString OEvent::toShortText()const {
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();
}
diff --git a/libopie/pim/oevent.h b/libopie/pim/oevent.h
index 9218c97..9eb948f 100644
--- a/libopie/pim/oevent.h
+++ b/libopie/pim/oevent.h
@@ -1,174 +1,180 @@
// 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;
diff --git a/libopie/pim/otimezone.cpp b/libopie/pim/otimezone.cpp
index b2bd3aa..34659c3 100644
--- a/libopie/pim/otimezone.cpp
+++ b/libopie/pim/otimezone.cpp
@@ -1,104 +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/libopie/pim/otodoaccesssql.cpp b/libopie/pim/otodoaccesssql.cpp
index 75a0860..3764c7e 100644
--- a/libopie/pim/otodoaccesssql.cpp
+++ b/libopie/pim/otodoaccesssql.cpp
@@ -237,193 +237,193 @@ namespace {
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();
+ 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) {
diff --git a/libopie/pim/test/converter.cpp b/libopie/pim/test/converter.cpp
index 650d119..bfdb605 100644
--- a/libopie/pim/test/converter.cpp
+++ b/libopie/pim/test/converter.cpp
@@ -1,68 +1,107 @@
#include "converter.h"
#include <qdatetime.h>
#include <qprogressbar.h>
#include <qpe/qpeapplication.h>
#include <opie/ocontactaccess.h>
#include <opie/ocontactaccessbackend_xml.h>
#include <opie/ocontactaccessbackend_sql.h>
+#include <opie/odatebookaccess.h>
+#include <opie/odatebookaccessbackend_xml.h>
+#include <opie/odatebookaccessbackend_sql.h>
+
+// #define _ADDRESSBOOK_ACCESS
+
Converter::Converter(){
}
void Converter::start_conversion(){
qWarning("Converting Contacts from XML to SQL..");
// Creating backends to the requested databases..
+
+#ifdef _ADDRESSBOOK_ACCESS
OContactAccessBackend* xmlBackend = new OContactAccessBackend_XML( "Converter",
QString::null );
OContactAccessBackend* sqlBackend = new OContactAccessBackend_SQL( QString::null,
QString::null );
// Put the created backends into frontends to access them
OContactAccess* xmlAccess = new OContactAccess ( "addressbook_xml",
QString::null , xmlBackend, true );
OContactAccess* sqlAccess = new OContactAccess ( "addressbook_sql",
- QString::null , sqlBackend, true );
+ QString::null );
+#else
+ ODateBookAccessBackend* xmlBackend = new ODateBookAccessBackend_XML( "Converter",
+ QString::null );
+
+ ODateBookAccessBackend* sqlBackend = new ODateBookAccessBackend_SQL( QString::null,
+ QString::null );
+ // Put the created backends into frontends to access them
+ ODateBookAccess* xmlAccess = new ODateBookAccess ( xmlBackend );
+
+ ODateBookAccess* sqlAccess = new ODateBookAccess ( sqlBackend );
+
+ xmlAccess->load();
+
+#endif
+
QTime t;
t.start();
- // Clean the sql-database..
+// Clean the sql-database..
sqlAccess->clear();
+#ifdef _ADDRESSBOOK_ACCESS
// Now trasmit every contact from the xml database to the sql-database
OContactAccess::List contactList = xmlAccess->allRecords();
m_progressBar->setTotalSteps( contactList.count() );
int count = 0;
if ( sqlAccess && xmlAccess ){
OContactAccess::List::Iterator it;
for ( it = contactList.begin(); it != contactList.end(); ++it ){
sqlAccess->add( *it );
m_progressBar->setProgress( ++count );
}
}
-
+#else
+ // Now transmit every contact from the xml database to the sql-database
+ ODateBookAccess::List dateList = xmlAccess->allRecords();
+ m_progressBar->setTotalSteps( dateList.count() );
+ qWarning( "Number of elements to copy: %d", dateList.count() );
+
+ int count = 0;
+ if ( sqlAccess && xmlAccess ){
+ ODateBookAccess::List::Iterator it;
+ for ( it = dateList.begin(); it != dateList.end(); ++it ){
+ sqlAccess->add( *it );
+ m_progressBar->setProgress( ++count );
+ }
+ }
+
+#endif
// Delete the frontends. Backends will be deleted automatically, too !
delete sqlAccess;
qWarning("Conversion is finished and needed %d ms !", t.elapsed());
delete xmlAccess;
}
int main( int argc, char** argv ) {
QPEApplication a( argc, argv );
Converter dlg;
a.showMainWidget( &dlg );
// dlg. showMaximized ( );
return a.exec();
}
diff --git a/libopie/pim/test/converter.h b/libopie/pim/test/converter.h
new file mode 100755
index 0000000..1cc2a7c
--- a/dev/null
+++ b/libopie/pim/test/converter.h
@@ -0,0 +1,18 @@
+#ifndef _CONVERTER_H_
+#define _CONVERTER_H_
+
+
+#include "converter_base.h"
+
+
+class Converter: public converter_base {
+public:
+ Converter();
+
+ void start_conversion();
+private:
+
+};
+
+
+#endif
diff --git a/libopie/pim/test/converter.pro b/libopie/pim/test/converter.pro
index aa74bff..bd9c7a3 100644
--- a/libopie/pim/test/converter.pro
+++ b/libopie/pim/test/converter.pro
@@ -1,12 +1,12 @@
-TEMPLATE = app
+# TEMPLATE = app
CONFIG = qt warn_on debug
# CONFIG = qt warn_on release
#HEADERS =
SOURCES = converter.cpp
INTERFACES = converter_base.ui
INCLUDEPATH += $(OPIEDIR)/include
DEPENDPATH += $(OPIEDIR)/include
LIBS += -lqpe -lopie
TARGET = converter
include ( $(OPIEDIR)/include.pro )
diff --git a/libopie2/opiepim/backend/obackendfactory.h b/libopie2/opiepim/backend/obackendfactory.h
index 3567687..761ab9a 100644
--- a/libopie2/opiepim/backend/obackendfactory.h
+++ b/libopie2/opiepim/backend/obackendfactory.h
@@ -1,176 +1,194 @@
/*
* 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.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 not implemented! Using XML instead!");
+ 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 not implemented! Using XML instead!");
+ 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" )
- qWarning("OBackendFactory:: sql Backend not implemented! Using XML instead!");
+ 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/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
index dd9dbde..a5be4c8 100644
--- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
+++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp
@@ -1,112 +1,124 @@
/*
* 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.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>
// 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();
@@ -417,202 +429,202 @@ namespace {
}
*/
#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();
+ 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 );
- CreateQuery qu;
- res = m_driver->query(&qu);
+
+ 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 " + "'"
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend.cpp b/libopie2/opiepim/backend/odatebookaccessbackend.cpp
index 8fa1a68..f0c5d65 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend.cpp
+++ b/libopie2/opiepim/backend/odatebookaccessbackend.cpp
@@ -34,123 +34,149 @@ namespace {
/* 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::effecticeEvents( const QDate& from,
+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();
+ list = directRawRepeats(); // Useless, isn't it ? (eilers)
qHeapSort( tmpList );
return tmpList;
}
-OEffectiveEvent::ValueList ODateBookAccessBackend::effecticeEvents( const QDateTime& dt ) {
- OEffectiveEvent::ValueList day = effecticeEvents( dt.date(), dt.date() );
+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/libopie2/opiepim/backend/odatebookaccessbackend.h b/libopie2/opiepim/backend/odatebookaccessbackend.h
index 3c02c42..3472ab3 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend.h
+++ b/libopie2/opiepim/backend/odatebookaccessbackend.h
@@ -1,77 +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 effecticeEvents( const QDate& from, const QDate& to );
+ virtual OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to );
/**
* this is an overloaded member function
- * @see effecticeEvents
+ * @see effectiveEvents( const QDate& from, const QDate& to )
*/
- virtual OEffectiveEvent::ValueList effecticeEvents( const QDateTime& start );
+ 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/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp
index 9769bf7..e893b38 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp
+++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp
@@ -1,221 +1,356 @@
/*
* 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.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 "orecur.h"
-#include "odatebookaccessbackend_sql.h"
+#include <qpe/global.h>
#include <opie2/osqldriver.h>
-#include <opie2/osqlresult.h>
#include <opie2/osqlmanager.h>
#include <opie2/osqlquery.h>
-namespace {
-
+#include "orecur.h"
+#include "odatebookaccessbackend_sql.h"
-};
ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& ,
const QString& fileName )
: ODateBookAccessBackend(), m_driver( NULL )
{
- m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName;
+ 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::FRExeptions, "RExceptions" );
+ 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 += 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();
+ // m_uids.clear();
return;
}
m_uids = extractUids( res );
}
-QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const
-{
- qWarning("extractUids");
-
- 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;
-
-}
-
bool ODateBookAccessBackend_SQL::reload()
{
- return load();
+ return load();
}
bool ODateBookAccessBackend_SQL::save()
{
- return m_driver->close();
+ return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers)
}
QArray<int> ODateBookAccessBackend_SQL::allRecords()const
{
- return m_uids;
+ return m_uids;
}
QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) {
- return QArray<int>();
+ 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;
}
-bool ODateBookAccessBackend_SQL::add( const OEvent& ev ) {
- return true;
+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;
+ }
+
+ return true;
}
-bool ODateBookAccessBackend_SQL::remove( int uid ) {
- return true;
+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;
+ }
+
+ return true;
}
-bool ODateBookAccessBackend_SQL::replace( const OEvent& ev ) {
+
+bool ODateBookAccessBackend_SQL::replace( const OEvent& ev )
+{
remove( ev.uid() );
return add( ev );
}
-QArray<int> ODateBookAccessBackend_SQL::rawEvents()const {
+
+QArray<int> ODateBookAccessBackend_SQL::rawEvents()const
+{
return allRecords();
}
-QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const {
- return ints;
+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 {
- return ints;
+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() {
- return list;
+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() {
+OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats()
+{
+ QArray<int> rawRepUids = rawRepeats();
+ OEvent::ValueList list;
- return 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;
- return m_currentQuery;
}
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_sql.h b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h
index 85e0d4f..f39e154 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend_sql.h
+++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h
@@ -1,60 +1,62 @@
#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"
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;
OSQLDriver* m_driver;
class Private;
Private *d;
void initFields();
void update();
QArray<int> extractUids( OSQLResult& res ) const;
};
#endif
diff --git a/libopie2/opiepim/backend/otodoaccesssql.cpp b/libopie2/opiepim/backend/otodoaccesssql.cpp
index 75a0860..3764c7e 100644
--- a/libopie2/opiepim/backend/otodoaccesssql.cpp
+++ b/libopie2/opiepim/backend/otodoaccesssql.cpp
@@ -237,193 +237,193 @@ namespace {
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();
+ 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) {
diff --git a/libopie2/opiepim/core/ocontactaccess.h b/libopie2/opiepim/core/ocontactaccess.h
index 9b0a719..bd6da40 100644
--- a/libopie2/opiepim/core/ocontactaccess.h
+++ b/libopie2/opiepim/core/ocontactaccess.h
@@ -1,177 +1,189 @@
/*
* 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.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;
diff --git a/libopie2/opiepim/core/odatebookaccess.cpp b/libopie2/opiepim/core/odatebookaccess.cpp
index a3661a3..82934f9 100644
--- a/libopie2/opiepim/core/odatebookaccess.cpp
+++ b/libopie2/opiepim/core/odatebookaccess.cpp
@@ -1,66 +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 ) {
- return m_backEnd->effecticeEvents( from, to );
+ return m_backEnd->effectiveEvents( from, to );
}
/**
* @return all events at a given datetime
*/
OEffectiveEvent::ValueList ODateBookAccess::effectiveEvents( const QDateTime& start ) {
- return m_backEnd->effecticeEvents( start );
+ 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 ) {
+ return m_backEnd->effectiveNonRepeatingEvents( from, to );
+}
+/**
+ * @return all non repeating events at a given datetime
+ */
+OEffectiveEvent::ValueList ODateBookAccess::effectiveNonRepeatingEvents( const QDateTime& start ) {
+ return m_backEnd->effectiveNonRepeatingEvents( start );
}
diff --git a/libopie2/opiepim/core/odatebookaccess.h b/libopie2/opiepim/core/odatebookaccess.h
index 7c7a63f..62196da 100644
--- a/libopie2/opiepim/core/odatebookaccess.h
+++ b/libopie2/opiepim/core/odatebookaccess.h
@@ -1,41 +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
+ * @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;
- OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to );
- OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start );
+ /* 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/libopie2/opiepim/core/otimezone.cpp b/libopie2/opiepim/core/otimezone.cpp
index b2bd3aa..34659c3 100644
--- a/libopie2/opiepim/core/otimezone.cpp
+++ b/libopie2/opiepim/core/otimezone.cpp
@@ -1,104 +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/libopie2/opiepim/oevent.cpp b/libopie2/opiepim/oevent.cpp
index ec05e77..9b31957 100644
--- a/libopie2/opiepim/oevent.cpp
+++ b/libopie2/opiepim/oevent.cpp
@@ -1,175 +1,184 @@
#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;
}
@@ -310,192 +319,196 @@ QString OEvent::toShortText()const {
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();
}
diff --git a/libopie2/opiepim/oevent.h b/libopie2/opiepim/oevent.h
index 9218c97..9eb948f 100644
--- a/libopie2/opiepim/oevent.h
+++ b/libopie2/opiepim/oevent.h
@@ -1,174 +1,180 @@
// 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;