24 files changed, 815 insertions, 583 deletions
diff --git a/libopie2/opiepim/backend/backends.pro b/libopie2/opiepim/backend/backends.pro new file mode 100644 index 0000000..4231a00 --- a/dev/null +++ b/libopie2/opiepim/backend/backends.pro @@ -0,0 +1,31 @@ +SOURCES += core/backends/ocontactaccessbackend_sql.cpp \ + core/backends/ocontactaccessbackend_vcard.cpp \ + core/backends/ocontactaccessbackend_xml.cpp \ + core/backends/ocontactaccess.cpp \ + core/backends/odatebookaccessbackend.cpp \ + core/backends/odatebookaccessbackend_xml.cpp \ + core/backends/otodoaccessbackend.cpp \ + core/backends/otodoaccess.cpp \ + core/backends/otodoaccesssql.cpp \ + core/backends/otodoaccessvcal.cpp \ + core/backends/otodoaccessxml.cpp \ + core/backends/odatebookaccess.cpp \ + core/backends/odatebookaccessbackend_sql.cpp + +HEADERS += core/backends/obackendfactory.h \ + core/backends/ocontactaccessbackend.h \ + core/backends/ocontactaccessbackend_sql.h \ + core/backends/ocontactaccessbackend_vcard.h \ + core/backends/ocontactaccessbackend_xml.h \ + core/backends/ocontactaccess.h \ + core/backends/odatebookaccessbackend.h \ + core/backends/odatebookaccessbackend_sql.h \ + core/backends/odatebookaccessbackend_xml.h \ + core/backends/opimaccessbackend.h \ + core/backends/opimaccesstemplate.h \ + core/backends/otodoaccessbackend.h \ + core/backends/otodoaccess.h \ + core/backends/otodoaccesssql.h \ + core/backends/otodoaccessvcal.h \ + core/backends/otodoaccessxml.h \ + core/backends/odatebookaccess.h diff --git a/libopie2/opiepim/backend/obackendfactory.h b/libopie2/opiepim/backend/obackendfactory.h index 761ab9a..346e2f5 100644 --- a/libopie2/opiepim/backend/obackendfactory.h +++ b/libopie2/opiepim/backend/obackendfactory.h @@ -1,194 +1,150 @@ /* - * 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. + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * ===================================================================== * 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" +#include <opie2/otodoaccessxml.h> +#include <opie2/ocontactaccessbackend_xml.h> +#include <opie2/odatebookaccessbackend_xml.h> #ifdef __USE_SQL -#include "otodoaccesssql.h" -#include "ocontactaccessbackend_sql.h" -#include "odatebookaccessbackend_sql.h" +#include <opie2/otodoaccesssql.h> +#include <opie2/ocontactaccessbackend_sql.h> +#include <opie2/odatebookaccessbackend_sql.h> #endif +namespace Opie { + class OBackendPrivate; /** * This class is our factory. It will give us the default implementations * of at least Todolist, Contacts and Datebook. In the future this class will * allow users to switch the backend with ( XML->SQLite ) without the need * to recompile.# * This class as the whole PIM Api is making use of templates * * <pre> * OTodoAccessBackend* backend = OBackEndFactory<OTodoAccessBackend>::Default("todo", QString::null ); * backend->load(); * </pre> * * @author Stefan Eilers * @version 0.1 */ template<class T> class OBackendFactory { public: OBackendFactory() {}; enum BACKENDS { TODO, CONTACT, DATE }; /** * Returns a backend implementation for backendName * @param backendName the type of the backend * @param appName will be passed on to the backend */ static T* Default( const QString backendName, const QString& appName ){ // __asm__("int3"); Config config( "pimaccess" ); config.setGroup ( backendName ); QString backend = config.readEntry( "usebackend" ); qWarning("Selected backend for %s is: %s", backendName.latin1(), backend.latin1() ); QAsciiDict<int> dict ( 3 ); dict.setAutoDelete ( TRUE ); dict.insert( "todo", new int (TODO) ); dict.insert( "contact", new int (CONTACT) ); dict.insert( "datebook", new int(DATE) ); int *find = dict[ backendName ]; if (!find ) return 0; switch ( *find ){ case TODO: #ifdef __USE_SQL if ( backend == "sql" ) return (T*) new OTodoAccessBackendSQL(""); #else if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend for TODO not implemented! Using XML instead!"); #endif return (T*) new OTodoAccessXML( appName ); case CONTACT: #ifdef __USE_SQL if ( backend == "sql" ) return (T*) new OContactAccessBackend_SQL(""); #else if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend for CONTACT not implemented! Using XML instead!"); #endif return (T*) new OContactAccessBackend_XML( appName ); case DATE: #ifdef __USE_SQL if ( backend == "sql" ) return (T*) new ODateBookAccessBackend_SQL(""); #else if ( backend == "sql" ) qWarning("OBackendFactory:: sql Backend for DATEBOOK not implemented! Using XML instead!"); #endif return (T*) new ODateBookAccessBackend_XML( appName ); default: return NULL; } } private: OBackendPrivate* d; }; +} #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend.h b/libopie2/opiepim/backend/ocontactaccessbackend.h index 0eac6dc..6113cea 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend.h @@ -1,128 +1,114 @@ +/* + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ /** * The class responsible for managing a backend. * The implementation of this abstract class contains * the complete database handling. * * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * Copyright (c) 2002 by Holger Freyther (zecke@handhelds.org) * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; - * either version 2 of the License, or (at your option) any later - * version. - * ===================================================================== - * ToDo: Define enum for query settings - * ===================================================================== - * Version: $Id$ - * ===================================================================== - * History: - * $Log$ - * Revision 1.7 2004/02/19 02:05:37 zecke - * Add notes for API fixes and BC stuff - * - * Revision 1.6 2003/08/01 12:30:16 eilers - * Merging changes from BRANCH_1_0 to HEAD - * - * Revision 1.5.4.1 2003/06/30 14:34:19 eilers - * Patches from Zecke: - * Fixing and cleaning up extraMap handling - * Adding d_ptr for binary compatibility in the future - * - * Revision 1.5 2003/04/13 18:07:10 zecke - * More API doc - * QString -> const QString& - * QString = 0l -> QString::null - * - * Revision 1.4 2002/11/13 14:14:51 eilers - * Added sorted for Contacts.. - * - * Revision 1.3 2002/11/01 15:10:42 eilers - * Added regExp-search in database for all fields in a contact. - * - * Revision 1.2 2002/10/07 17:34:24 eilers - * added OBackendFactory for advanced backend access - * - * Revision 1.1 2002/09/27 17:11:44 eilers - * Added API for accessing the Contact-Database ! It is compiling, but - * please do not expect that anything is working ! - * I will debug that stuff in the next time .. - * Please read README_COMPILE for compiling ! - * - * ===================================================================== - * */ #ifndef _OCONTACTACCESSBACKEND_H_ #define _OCONTACTACCESSBACKEND_H_ -#include "ocontact.h" -#include "opimaccessbackend.h" +#include <opie2/ocontact.h> +#include <opie2/opimaccessbackend.h> #include <qregexp.h> +namespace Opie { /** * This class represents the interface of all Contact Backends. * Derivates of this class will be used to access the contacts. * As implementation currently XML and vCard exist. This class needs to be implemented * if you want to provide your own storage. * In all queries a list of uids is passed on instead of loading the actual record! * * @see OContactAccessBackend_VCard * @see OContactAccessBackend_XML */ class OContactAccessBackend: public OPimAccessBackend<OContact> { public: /** * @todo make non line in regard to BC guide of KDE */ OContactAccessBackend() {} /** * @todo make non inline in regard to the BC guide of KDE */ virtual ~OContactAccessBackend() {} /** * Return if database was changed externally. * This may just make sense on file based databases like a XML-File. * It is used to prevent to overwrite the current database content * if the file was already changed by something else ! * If this happens, we have to reload before save our data. * If we use real databases, this should be handled by the database * management system themselve, therefore this function should always return false in * this case. It is not our problem to handle this conflict ... * @return <i>true</i> if the database was changed and if save without reload will * be dangerous. <i>false</i> if the database was not changed or it is save to write * in this situation. */ virtual bool wasChangedExternally() = 0; virtual QArray<int> matchRegexp( const QRegExp &r ) const = 0; /** * Return all possible settings. * @return All settings provided by the current backend * (i.e.: query_WildCards & query_IgnoreCase) */ virtual const uint querySettings() = 0; /** * Check whether settings are correct. * @return <i>true</i> if the given settings are correct and possible. */ virtual bool hasQuerySettings (uint querySettings) const = 0; /** * FIXME!!! * Returns a sorted list of records either ascendinf or descending for a giving criteria and category */ virtual QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ) = 0; private: class Private; Private *d; }; + +} + #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp index a5be4c8..d0c8052 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp @@ -1,942 +1,935 @@ /* + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * 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/ocontactfields.h> +#include <opie2/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 { +namespace Opie { /** * CreateQuery for the Todolist Table */ class CreateQuery : public OSQLQuery { public: CreateQuery(); ~CreateQuery(); QString query()const; }; /** * Clears (delete) a Table */ class ClearQuery : public OSQLQuery { public: ClearQuery(); ~ClearQuery(); QString query()const; }; /** * LoadQuery * this one queries for all uids */ class LoadQuery : public OSQLQuery { public: LoadQuery(); ~LoadQuery(); QString query()const; }; /** * inserts/adds a OContact to the table */ class InsertQuery : public OSQLQuery { public: InsertQuery(const OContact& ); ~InsertQuery(); QString query()const; private: OContact m_contact; }; /** * removes one from the table */ class RemoveQuery : public OSQLQuery { public: RemoveQuery(int uid ); ~RemoveQuery(); QString query()const; private: int m_uid; }; /** * a find query for noncustom elements */ class FindQuery : public OSQLQuery { public: FindQuery(int uid); FindQuery(const QArray<int>& ); ~FindQuery(); QString query()const; private: QString single()const; QString multi()const; QArray<int> m_uids; int m_uid; }; /** * a find query for custom elements */ class FindCustomQuery : public OSQLQuery { public: FindCustomQuery(int uid); FindCustomQuery(const QArray<int>& ); ~FindCustomQuery(); QString query()const; private: QString single()const; QString multi()const; QArray<int> m_uids; int m_uid; }; // We using three tables to store the information: // 1. addressbook : It contains General information about the contact (non custom) // 2. custom_data : Not official supported entries // All tables are connected by the uid of the contact. // Maybe I should add a table for meta-information ? CreateQuery::CreateQuery() : OSQLQuery() {} CreateQuery::~CreateQuery() {} QString CreateQuery::query()const { QString qu; #ifdef __STORE_HORIZONTAL_ qu += "create table addressbook( uid PRIMARY KEY "; QStringList fieldList = OContactFields::untrfields( false ); for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ qu += QString( ",\"%1\" VARCHAR(10)" ).arg( *it ); } qu += " );"; qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; #else qu += "create table addressbook( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id));"; qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; // qu += "create table dates( uid PRIMARY KEY, type, day, month, year, hour, minute, second );"; #endif // __STORE_HORIZONTAL_ return qu; } ClearQuery::ClearQuery() : OSQLQuery() {} ClearQuery::~ClearQuery() {} QString ClearQuery::query()const { QString qu = "drop table addressbook;"; qu += "drop table custom_data;"; // qu += "drop table dates;"; return qu; } LoadQuery::LoadQuery() : OSQLQuery() {} LoadQuery::~LoadQuery() {} QString LoadQuery::query()const { QString qu; #ifdef __STORE_HORIZONTAL_ qu += "select uid from addressbook"; #else # ifndef __USE_SUPERFAST_LOADQUERY qu += "select distinct uid from addressbook"; # else qu += "select uid from addressbook where type = 'Last Name'"; # endif // __USE_SUPERFAST_LOADQUERY #endif // __STORE_HORIZONTAL_ return qu; } InsertQuery::InsertQuery( const OContact& contact ) : OSQLQuery(), m_contact( contact ) { } InsertQuery::~InsertQuery() { } /* * converts from a OContact to a query */ QString InsertQuery::query()const{ #ifdef __STORE_HORIZONTAL_ QString qu; qu += "insert into addressbook VALUES( " + QString::number( m_contact.uid() ); // Get all information out of the contact-class // Remember: The category is stored in contactMap, too ! QMap<int, QString> contactMap = m_contact.toMap(); QStringList fieldList = OContactFields::untrfields( false ); QMap<QString, int> translate = OContactFields::untrFieldsToId(); for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ // Convert Column-String to Id and get value for this id.. // Hmmm.. Maybe not very cute solution.. int id = translate[*it]; switch ( id ){ case Qtopia::Birthday:{ // These entries should stored in a special format // year-month-day QDate day = m_contact.birthday(); if ( day.isValid() ){ qu += QString(",\"%1-%2-%3\"") .arg( day.year() ) .arg( day.month() ) .arg( day.day() ); } else { qu += ",\"\""; } } break; case Qtopia::Anniversary:{ // These entries should stored in a special format // year-month-day QDate day = m_contact.anniversary(); if ( day.isValid() ){ qu += QString(",\"%1-%2-%3\"") .arg( day.year() ) .arg( day.month() ) .arg( day.day() ); } else { qu += ",\"\""; } } break; default: qu += QString( ",\"%1\"" ).arg( contactMap[id] ); } } qu += " );"; #else // Get all information out of the contact-class // Remember: The category is stored in contactMap, too ! QMap<int, QString> contactMap = m_contact.toMap(); QMap<QString, QString> addressbook_db; // Get the translation from the ID to the String QMap<int, QString> transMap = OContactFields::idToUntrFields(); for( QMap<int, QString>::Iterator it = contactMap.begin(); it != contactMap.end(); ++it ){ switch ( it.key() ){ case Qtopia::Birthday:{ // These entries should stored in a special format // year-month-day QDate day = m_contact.birthday(); addressbook_db.insert( transMap[it.key()], QString("%1-%2-%3") .arg( day.year() ) .arg( day.month() ) .arg( day.day() ) ); } break; case Qtopia::Anniversary:{ // These entries should stored in a special format // year-month-day QDate day = m_contact.anniversary(); addressbook_db.insert( transMap[it.key()], QString("%1-%2-%3") .arg( day.year() ) .arg( day.month() ) .arg( day.day() ) ); } break; case Qtopia::AddressUid: // Ignore UID break; default: // Translate id to String addressbook_db.insert( transMap[it.key()], it.data() ); break; } } // Now convert this whole stuff into a SQL String, beginning with // the addressbook table.. QString qu; // qu += "begin transaction;"; int id = 0; for( QMap<QString, QString>::Iterator it = addressbook_db.begin(); it != addressbook_db.end(); ++it ){ qu += "insert into addressbook VALUES(" + QString::number( m_contact.uid() ) + "," + QString::number( id++ ) + ",'" + it.key() //.latin1() + "'," + "0" // Priority for future enhancements + ",'" + it.data() //.latin1() + "');"; } #endif //__STORE_HORIZONTAL_ // Now add custom data.. #ifdef __STORE_HORIZONTAL_ int id = 0; #endif id = 0; QMap<QString, QString> customMap = m_contact.toExtraMap(); for( QMap<QString, QString>::Iterator it = customMap.begin(); it != customMap.end(); ++it ){ qu += "insert into custom_data VALUES(" + QString::number( m_contact.uid() ) + "," + QString::number( id++ ) + ",'" + it.key() //.latin1() + "'," + "0" // Priority for future enhancements + ",'" + it.data() //.latin1() + "');"; } // qu += "commit;"; qWarning("add %s", qu.latin1() ); return qu; } RemoveQuery::RemoveQuery(int uid ) : OSQLQuery(), m_uid( uid ) {} RemoveQuery::~RemoveQuery() {} QString RemoveQuery::query()const { QString qu = "DELETE from addressbook where uid = " + QString::number(m_uid) + ";"; qu += "DELETE from custom_data where uid = " + QString::number(m_uid) + ";"; return qu; } FindQuery::FindQuery(int uid) : OSQLQuery(), m_uid( uid ) { } FindQuery::FindQuery(const QArray<int>& ints) : OSQLQuery(), m_uids( ints ){ } FindQuery::~FindQuery() { } QString FindQuery::query()const{ // if ( m_uids.count() == 0 ) return single(); } /* else return multi(); } QString FindQuery::multi()const { QString qu = "select uid, type, value from addressbook where"; for (uint i = 0; i < m_uids.count(); i++ ) { qu += " UID = " + QString::number( m_uids[i] ) + " OR"; } qu.remove( qu.length()-2, 2 ); // Hmmmm.. return qu; } */ #ifdef __STORE_HORIZONTAL_ QString FindQuery::single()const{ QString qu = "select *"; qu += " from addressbook where uid = " + QString::number(m_uid); // qWarning("find query: %s", qu.latin1() ); return qu; } #else QString FindQuery::single()const{ QString qu = "select uid, type, value from addressbook where uid = "; qu += QString::number(m_uid); return qu; } #endif FindCustomQuery::FindCustomQuery(int uid) : OSQLQuery(), m_uid( uid ) { } FindCustomQuery::FindCustomQuery(const QArray<int>& ints) : OSQLQuery(), m_uids( ints ){ } FindCustomQuery::~FindCustomQuery() { } QString FindCustomQuery::query()const{ // if ( m_uids.count() == 0 ) return single(); } QString FindCustomQuery::single()const{ QString qu = "select uid, type, value from custom_data where uid = "; qu += QString::number(m_uid); return qu; } }; /* --------------------------------------------------------------------------- */ +namespace Opie { + OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, const QString& filename ): OContactAccessBackend(), m_changed(false), m_driver( NULL ) { qWarning("C'tor OContactAccessBackend_SQL starts"); QTime t; t.start(); /* Expecting to access the default filename if nothing else is set */ if ( filename.isEmpty() ){ m_fileName = Global::applicationFileName( "addressbook","addressbook.db" ); } else m_fileName = filename; // Get the standart sql-driver from the OSQLManager.. OSQLManager man; m_driver = man.standard(); m_driver->setUrl( m_fileName ); load(); qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() ); } OContactAccessBackend_SQL::~OContactAccessBackend_SQL () { if( m_driver ) delete m_driver; } bool OContactAccessBackend_SQL::load () { if (!m_driver->open() ) return false; // Don't expect that the database exists. // It is save here to create the table, even if it // do exist. ( Is that correct for all databases ?? ) CreateQuery creat; OSQLResult res = m_driver->query( &creat ); update(); return true; } bool OContactAccessBackend_SQL::reload() { return load(); } bool OContactAccessBackend_SQL::save() { return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) } void OContactAccessBackend_SQL::clear () { ClearQuery cle; OSQLResult res = m_driver->query( &cle ); reload(); } bool OContactAccessBackend_SQL::wasChangedExternally() { return false; } QArray<int> OContactAccessBackend_SQL::allRecords() const { // FIXME: Think about cute handling of changed tables.. // Thus, we don't have to call update here... if ( m_changed ) ((OContactAccessBackend_SQL*)this)->update(); return m_uids; } bool OContactAccessBackend_SQL::add ( const OContact &newcontact ) { InsertQuery ins( newcontact ); OSQLResult res = m_driver->query( &ins ); if ( res.state() == OSQLResult::Failure ) return false; int c = m_uids.count(); m_uids.resize( c+1 ); m_uids[c] = newcontact.uid(); return true; } bool OContactAccessBackend_SQL::remove ( int uid ) { RemoveQuery rem( uid ); OSQLResult res = m_driver->query(&rem ); if ( res.state() == OSQLResult::Failure ) return false; m_changed = true; return true; } bool OContactAccessBackend_SQL::replace ( const OContact &contact ) { if ( !remove( contact.uid() ) ) return false; return add( contact ); } OContact OContactAccessBackend_SQL::find ( int uid ) const { qWarning("OContactAccessBackend_SQL::find()"); QTime t; t.start(); OContact retContact( requestNonCustom( uid ) ); retContact.setExtraMap( requestCustom( uid ) ); qWarning("OContactAccessBackend_SQL::find() needed: %d ms", t.elapsed() ); return retContact; } QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ) { QString qu = "SELECT uid FROM addressbook WHERE"; QMap<int, QString> queryFields = query.toMap(); QStringList fieldList = OContactFields::untrfields( false ); QMap<QString, int> translate = OContactFields::untrFieldsToId(); // Convert every filled field to a SQL-Query bool isAnyFieldSelected = false; for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ int id = translate[*it]; QString queryStr = queryFields[id]; if ( !queryStr.isEmpty() ){ isAnyFieldSelected = true; switch( id ){ default: // Switching between case sensitive and insensitive... // LIKE is not case sensitive, GLOB is case sensitive // Do exist a better solution to switch this ? if ( settings & OContactAccess::IgnoreCase ) qu += "(\"" + *it + "\"" + " LIKE " + "'" + queryStr.replace(QRegExp("\\*"),"%") + "'" + ") AND "; else qu += "(\"" + *it + "\"" + " GLOB " + "'" + queryStr + "'" + ") AND "; } } } // Skip trailing "AND" if ( isAnyFieldSelected ) qu = qu.left( qu.length() - 4 ); qWarning( "queryByExample query: %s", qu.latin1() ); // Execute query and return the received uid's OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> empty; return empty; } QArray<int> list = extractUids( res ); return list; } QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const { QArray<int> nix(0); return nix; } const uint OContactAccessBackend_SQL::querySettings() { return OContactAccess::IgnoreCase || OContactAccess::WildCards; } bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const { /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay * may be added with any of the other settings. IgnoreCase should never used alone. * Wildcards, RegExp, ExactMatch should never used at the same time... */ // Step 1: Check whether the given settings are supported by this backend if ( ( querySettings & ( OContactAccess::IgnoreCase | OContactAccess::WildCards // | OContactAccess::DateDiff // | OContactAccess::DateYear // | OContactAccess::DateMonth // | OContactAccess::DateDay // | OContactAccess::RegExp // | OContactAccess::ExactMatch ) ) != querySettings ) return false; // Step 2: Check whether the given combinations are ok.. // IngoreCase alone is invalid if ( querySettings == OContactAccess::IgnoreCase ) return false; // WildCards, RegExp and ExactMatch should never used at the same time switch ( querySettings & ~( OContactAccess::IgnoreCase | OContactAccess::DateDiff | OContactAccess::DateYear | OContactAccess::DateMonth | OContactAccess::DateDay ) ){ case OContactAccess::RegExp: return ( true ); case OContactAccess::WildCards: return ( true ); case OContactAccess::ExactMatch: return ( true ); case 0: // one of the upper removed bits were set.. return ( true ); default: return ( false ); } } QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int ) { QTime t; t.start(); #ifdef __STORE_HORIZONTAL_ QString query = "SELECT uid FROM addressbook "; query += "ORDER BY \"Last Name\" "; #else QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' "; query += "ORDER BY upper( value )"; #endif if ( !asc ) query += "DESC"; // qWarning("sorted query is: %s", query.latin1() ); OSQLRawQuery raw( query ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> empty; return empty; } QArray<int> list = extractUids( res ); qWarning("sorted needed %d ms!", t.elapsed() ); return list; } void OContactAccessBackend_SQL::update() { qWarning("Update starts"); QTime t; t.start(); // Now load the database set and extract the uid's // which will be held locally LoadQuery lo; OSQLResult res = m_driver->query(&lo); if ( res.state() != OSQLResult::Success ) return; m_uids = extractUids( res ); m_changed = false; qWarning("Update ends %d ms", t.elapsed() ); } QArray<int> OContactAccessBackend_SQL::extractUids( OSQLResult& res ) const { qWarning("extractUids"); QTime t; t.start(); OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it; QArray<int> ints(list.count() ); qWarning(" count = %d", list.count() ); int i = 0; for (it = list.begin(); it != list.end(); ++it ) { ints[i] = (*it).data("uid").toInt(); i++; } qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); return ints; } #ifdef __STORE_HORIZONTAL_ QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const { QTime t; t.start(); QMap<int, QString> nonCustomMap; int t2needed = 0; int t3needed = 0; QTime t2; t2.start(); FindQuery query( uid ); OSQLResult res_noncustom = m_driver->query( &query ); t2needed = t2.elapsed(); OSQLResultItem resItem = res_noncustom.first(); QTime t3; t3.start(); // Now loop through all columns QStringList fieldList = OContactFields::untrfields( false ); QMap<QString, int> translate = OContactFields::untrFieldsToId(); for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ // Get data for the selected column and store it with the // corresponding id into the map.. int id = translate[*it]; QString value = resItem.data( (*it) ); // qWarning("Reading %s... found: %s", (*it).latin1(), value.latin1() ); switch( id ){ case Qtopia::Birthday: case Qtopia::Anniversary:{ // Birthday and Anniversary are encoded special ( yyyy-mm-dd ) QStringList list = QStringList::split( '-', value ); QStringList::Iterator lit = list.begin(); int year = (*lit).toInt(); int month = (*(++lit)).toInt(); int day = (*(++lit)).toInt(); if ( ( day != 0 ) && ( month != 0 ) && ( year != 0 ) ){ QDate date( year, month, day ); nonCustomMap.insert( id, OConversion::dateToString( date ) ); } } break; case Qtopia::AddressCategory: qWarning("Category is: %s", value.latin1() ); default: nonCustomMap.insert( id, value ); } } // First insert uid nonCustomMap.insert( Qtopia::AddressUid, resItem.data( "uid" ) ); t3needed = t3.elapsed(); // qWarning("Adding UID: %s", resItem.data( "uid" ).latin1() ); qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", t.elapsed(), t2needed, t3needed ); return nonCustomMap; } #else QMap<int, QString> OContactAccessBackend_SQL::requestNonCustom( int uid ) const { QTime t; t.start(); QMap<int, QString> nonCustomMap; int t2needed = 0; QTime t2; t2.start(); FindQuery query( uid ); OSQLResult res_noncustom = m_driver->query( &query ); t2needed = t2.elapsed(); if ( res_noncustom.state() == OSQLResult::Failure ) { qWarning("OSQLResult::Failure in find query !!"); QMap<int, QString> empty; return empty; } int t3needed = 0; QTime t3; t3.start(); QMap<QString, int> translateMap = OContactFields::untrFieldsToId(); OSQLResultItem::ValueList list = res_noncustom.results(); OSQLResultItem::ValueList::Iterator it = list.begin(); for ( ; it != list.end(); ++it ) { if ( (*it).data("type") != "" ){ int typeId = translateMap[(*it).data( "type" )]; switch( typeId ){ case Qtopia::Birthday: case Qtopia::Anniversary:{ // Birthday and Anniversary are encoded special ( yyyy-mm-dd ) QStringList list = QStringList::split( '-', (*it).data( "value" ) ); QStringList::Iterator lit = list.begin(); int year = (*lit).toInt(); qWarning("1. %s", (*lit).latin1()); int month = (*(++lit)).toInt(); qWarning("2. %s", (*lit).latin1()); int day = (*(++lit)).toInt(); qWarning("3. %s", (*lit).latin1()); qWarning( "RequestNonCustom->Converting:%s to Year: %d, Month: %d, Day: %d ", (*it).data( "value" ).latin1(), year, month, day ); QDate date( year, month, day ); nonCustomMap.insert( typeId, OConversion::dateToString( date ) ); } break; default: nonCustomMap.insert( typeId, (*it).data( "value" ) ); } } } // Add UID to Map.. nonCustomMap.insert( Qtopia::AddressUid, QString::number( uid ) ); t3needed = t3.elapsed(); qWarning("RequestNonCustom needed: insg.:%d ms, query: %d ms, mapping: %d ms", t.elapsed(), t2needed, t3needed ); return nonCustomMap; } #endif // __STORE_HORIZONTAL_ QMap<QString, QString> OContactAccessBackend_SQL::requestCustom( int uid ) const { QTime t; t.start(); QMap<QString, QString> customMap; FindCustomQuery query( uid ); OSQLResult res_custom = m_driver->query( &query ); if ( res_custom.state() == OSQLResult::Failure ) { qWarning("OSQLResult::Failure in find query !!"); QMap<QString, QString> empty; return empty; } OSQLResultItem::ValueList list = res_custom.results(); OSQLResultItem::ValueList::Iterator it = list.begin(); for ( ; it != list.end(); ++it ) { customMap.insert( (*it).data( "type" ), (*it).data( "value" ) ); } qWarning("RequestCustom needed: %d ms", t.elapsed() ); return customMap; } + +} diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.h b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h index b8f1d8d..55b95fd 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h @@ -1,101 +1,109 @@ /* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * 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.2 2003/12/08 15:18:11 eilers - * Committing unfinished sql implementation before merging to libopie2 starts.. - * - * Revision 1.1 2003/09/22 14:31:16 eilers - * Added first experimental incarnation of sql-backend for addressbook. - * Some modifications to be able to compile the todo sql-backend. - * A lot of changes fill follow... - * - * */ #ifndef _OContactAccessBackend_SQL_ #define _OContactAccessBackend_SQL_ -#include "ocontactaccessbackend.h" -#include "ocontactaccess.h" +#include <opie2/ocontactaccessbackend.h> +#include <opie2/ocontactaccess.h> #include <qlist.h> #include <qdict.h> +/* aren't in namespace Opie yet - alwin */ class OSQLDriver; class OSQLResult; class OSQLResultItem; +namespace Opie { + /* the default xml implementation */ /** * This class is the SQL implementation of a Contact backend * it does implement everything available for OContact. * @see OPimAccessBackend for more information of available methods */ class OContactAccessBackend_SQL : public OContactAccessBackend { public: OContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null ); ~OContactAccessBackend_SQL (); bool save(); bool load (); void clear (); bool wasChangedExternally(); QArray<int> allRecords() const; OContact find ( int uid ) const; // FIXME: Add lookahead-cache support ! //OContact find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d ); QArray<int> matchRegexp( const QRegExp &r ) const; const uint querySettings(); bool hasQuerySettings (uint querySettings) const; // Currently only asc implemented.. QArray<int> sorted( bool asc, int , int , int ); bool add ( const OContact &newcontact ); bool replace ( const OContact &contact ); bool remove ( int uid ); bool reload(); private: QArray<int> extractUids( OSQLResult& res ) const; QMap<int, QString> requestNonCustom( int uid ) const; QMap<QString, QString> requestCustom( int uid ) const; void update(); protected: bool m_changed; QString m_fileName; QArray<int> m_uids; OSQLDriver* m_driver; }; +} + #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp index b60c5be..f85cf38 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp @@ -1,646 +1,591 @@ /* + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * VCard Backend for the OPIE-Contact Database. - * - * Copyright (C) 2000 Trolltech AS. All rights reserved. - * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * ===================================================================== - * ToDo: - * - * ===================================================================== - * Version: $Id$ - * ===================================================================== - * History: - * $Log$ - * Revision 1.11 2003/08/01 12:30:16 eilers - * Merging changes from BRANCH_1_0 to HEAD - * - * Revision 1.10.4.3 2003/07/23 08:54:37 eilers - * Default email was added to the list of all emails, which already contains - * the default email.. - * This closes bug #1045 - * - * Revision 1.10.4.2 2003/07/23 08:44:45 eilers - * Importing of Notes in vcard files wasn't implemented. - * Closes bug #1044 - * - * Revision 1.10.4.1 2003/06/02 13:37:49 eilers - * Fixing memory leak - * - * Revision 1.10 2003/04/13 18:07:10 zecke - * More API doc - * QString -> const QString& - * QString = 0l -> QString::null - * - * Revision 1.9 2003/03/21 10:33:09 eilers - * Merged speed optimized xml backend for contacts to main. - * Added QDateTime to querybyexample. For instance, it is now possible to get - * all Birthdays/Anniversaries between two dates. This should be used - * to show all birthdays in the datebook.. - * This change is sourcecode backward compatible but you have to upgrade - * the binaries for today-addressbook. - * - * Revision 1.8 2003/02/21 16:52:49 zecke - * -Remove old Todo classes they're deprecated and today I already using the - * new API - * -Guard against self assignment in OTodo - * -Add test apps for OPIM - * -Opiefied Event classes - * -Added TimeZone handling and pinning of TimeZones to OEvent - * -Adjust ORecur and the widget to better timezone behaviour - * - * Revision 1.7 2003/02/16 22:25:46 zecke - * 0000276 Fix for that bug.. or better temp workaround - * A Preferred Number is HOME|VOICE - * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test - * triggers both - * and the cell phone number overrides the other entries.. - * - * as a temp I check that it's not equal to HOME|VOICE|CELL before setting the - * number - * - * The right and final fix would be to reorder the if statement to make it - * if else based and the less common thing put to the bottom - * - * OTodoAccessVcal fix the date for beaming - * - * Revision 1.6 2003/01/13 15:49:31 eilers - * Fixing crash when businesscard.vcf is missing.. - * - * Revision 1.5 2002/12/07 13:26:22 eilers - * Fixing bug in storing anniversary.. - * - * Revision 1.4 2002/11/13 14:14:51 eilers - * Added sorted for Contacts.. - * - * Revision 1.3 2002/11/11 16:41:09 kergoth - * no default arguments in implementation - * - * Revision 1.2 2002/11/10 15:41:53 eilers - * Bugfixes.. - * - * Revision 1.1 2002/11/09 14:34:52 eilers - * Added VCard Backend. - * */ -#include "ocontactaccessbackend_vcard.h" -#include "../../library/backend/vobject_p.h" -#include "../../library/backend/qfiledirect_p.h" +#include <opie2/ocontactaccessbackend_vcard.h> +#include "../../../../library/backend/vobject_p.h" +#include "../../../../library/backend/qfiledirect_p.h" #include <qpe/timeconversion.h> #include <qfile.h> +namespace Opie { + OContactAccessBackend_VCard::OContactAccessBackend_VCard ( const QString& , const QString& filename ): m_dirty( false ), m_file( filename ) { load(); } bool OContactAccessBackend_VCard::load () { m_map.clear(); m_dirty = false; VObject* obj = 0l; if ( QFile::exists(m_file) ){ obj = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); if ( !obj ) return false; }else{ qWarning("File \"%s\" not found !", m_file.latin1() ); return false; } while ( obj ) { OContact con = parseVObject( obj ); /* * if uid is 0 assign a new one * this at least happens on * Nokia6210 */ if ( con.uid() == 0 ){ con.setUid( 1 ); qWarning("assigned new uid %d",con.uid() ); } m_map.insert( con.uid(), con ); VObject *t = obj; obj = nextVObjectInList(obj); cleanVObject( t ); } return true; } bool OContactAccessBackend_VCard::reload() { return load(); } bool OContactAccessBackend_VCard::save() { if (!m_dirty ) return true; QFileDirect file( m_file ); if (!file.open(IO_WriteOnly ) ) return false; VObject *obj; obj = newVObject( VCCalProp ); addPropValue( obj, VCVersionProp, "1.0" ); VObject *vo; for(QMap<int, OContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ vo = createVObject( *it ); writeVObject( file.directHandle() , vo ); cleanVObject( vo ); } cleanStrTbl(); deleteVObject( obj ); m_dirty = false; return true; } void OContactAccessBackend_VCard::clear () { m_map.clear(); m_dirty = true; // ??? sure ? (se) } bool OContactAccessBackend_VCard::add ( const OContact& newcontact ) { m_map.insert( newcontact.uid(), newcontact ); m_dirty = true; return true; } bool OContactAccessBackend_VCard::remove ( int uid ) { m_map.remove( uid ); m_dirty = true; return true; } bool OContactAccessBackend_VCard::replace ( const OContact &contact ) { m_map.replace( contact.uid(), contact ); m_dirty = true; return true; } OContact OContactAccessBackend_VCard::find ( int uid ) const { return m_map[uid]; } QArray<int> OContactAccessBackend_VCard::allRecords() const { QArray<int> ar( m_map.count() ); QMap<int, OContact>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } // Not implemented QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& ) { QArray<int> ar(0); return ar; } // Not implemented QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const { QArray<int> ar(0); return ar; } const uint OContactAccessBackend_VCard::querySettings() { return 0; // No search possible } bool OContactAccessBackend_VCard::hasQuerySettings (uint ) const { return false; // No search possible, therefore all settings invalid ;) } bool OContactAccessBackend_VCard::wasChangedExternally() { return false; // Don't expect concurrent access } // Not implemented QArray<int> OContactAccessBackend_VCard::sorted( bool , int, int, int ) { QArray<int> ar(0); return ar; } // *** Private stuff *** OContact OContactAccessBackend_VCard::parseVObject( VObject *obj ) { OContact c; VObjectIterator it; initPropIterator( &it, obj ); while( moreIteration( &it ) ) { VObject *o = nextVObject( &it ); QCString name = vObjectName( o ); QCString value = vObjectStringZValue( o ); if ( name == VCNameProp ) { VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); QString value = vObjectStringZValue( o ); if ( name == VCNamePrefixesProp ) c.setTitle( value ); else if ( name == VCNameSuffixesProp ) c.setSuffix( value ); else if ( name == VCFamilyNameProp ) c.setLastName( value ); else if ( name == VCGivenNameProp ) c.setFirstName( value ); else if ( name == VCAdditionalNamesProp ) c.setMiddleName( value ); } } else if ( name == VCAdrProp ) { bool work = TRUE; // default address is work address QString street; QString city; QString region; QString postal; QString country; VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectName( o ); QString value = vObjectStringZValue( o ); if ( name == VCHomeProp ) work = FALSE; else if ( name == VCWorkProp ) work = TRUE; else if ( name == VCStreetAddressProp ) street = value; else if ( name == VCCityProp ) city = value; else if ( name == VCRegionProp ) region = value; else if ( name == VCPostalCodeProp ) postal = value; else if ( name == VCCountryNameProp ) country = value; } if ( work ) { c.setBusinessStreet( street ); c.setBusinessCity( city ); c.setBusinessCountry( country ); c.setBusinessZip( postal ); c.setBusinessState( region ); } else { c.setHomeStreet( street ); c.setHomeCity( city ); c.setHomeCountry( country ); c.setHomeZip( postal ); c.setHomeState( region ); } } else if ( name == VCTelephoneProp ) { enum { HOME = 0x01, WORK = 0x02, VOICE = 0x04, CELL = 0x08, FAX = 0x10, PAGER = 0x20, UNKNOWN = 0x80 }; int type = 0; VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); if ( name == VCHomeProp ) type |= HOME; else if ( name == VCWorkProp ) type |= WORK; else if ( name == VCVoiceProp ) type |= VOICE; else if ( name == VCCellularProp ) type |= CELL; else if ( name == VCFaxProp ) type |= FAX; else if ( name == VCPagerProp ) type |= PAGER; else if ( name == VCPreferredProp ) ; else type |= UNKNOWN; } if ( (type & UNKNOWN) != UNKNOWN ) { if ( ( type & (HOME|WORK) ) == 0 ) // default type |= HOME; if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default type |= VOICE; qWarning("value %s %d", value.data(), type ); if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) ) c.setHomePhone( value ); if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) c.setHomeFax( value ); if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) c.setHomeMobile( value ); if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) ) c.setBusinessPhone( value ); if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) c.setBusinessFax( value ); if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) c.setBusinessMobile( value ); if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) c.setBusinessPager( value ); } } else if ( name == VCEmailAddressProp ) { QString email = vObjectStringZValue( o ); bool valid = TRUE; VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); if ( name != VCInternetProp && name != VCHomeProp && name != VCWorkProp && name != VCPreferredProp ) // ### preffered should map to default email valid = FALSE; } if ( valid ) { c.insertEmail( email ); } } else if ( name == VCURLProp ) { VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); if ( name == VCHomeProp ) c.setHomeWebpage( value ); else if ( name == VCWorkProp ) c.setBusinessWebpage( value ); } } else if ( name == VCOrgProp ) { VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectName( o ); QString value = vObjectStringZValue( o ); if ( name == VCOrgNameProp ) c.setCompany( value ); else if ( name == VCOrgUnitProp ) c.setDepartment( value ); else if ( name == VCOrgUnit2Prop ) c.setOffice( value ); } } else if ( name == VCTitleProp ) { c.setJobTitle( value ); } else if ( name == "X-Qtopia-Profession" ) { c.setProfession( value ); } else if ( name == "X-Qtopia-Manager" ) { c.setManager( value ); } else if ( name == "X-Qtopia-Assistant" ) { c.setAssistant( value ); } else if ( name == "X-Qtopia-Spouse" ) { c.setSpouse( value ); } else if ( name == "X-Qtopia-Gender" ) { c.setGender( value ); } else if ( name == "X-Qtopia-Anniversary" ) { c.setAnniversary( convVCardDateToDate( value ) ); } else if ( name == "X-Qtopia-Nickname" ) { c.setNickname( value ); } else if ( name == "X-Qtopia-Children" ) { c.setChildren( value ); } else if ( name == VCBirthDateProp ) { // Reading Birthdate regarding RFC 2425 (5.8.4) c.setBirthday( convVCardDateToDate( value ) ); } else if ( name == VCCommentProp ) { c.setNotes( value ); } #if 0 else { printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectName( o ); QString value = vObjectStringZValue( o ); printf(" subprop: %s = %s\n", name.data(), value.latin1() ); } } #endif } c.setFileAs(); return c; } VObject* OContactAccessBackend_VCard::createVObject( const OContact &c ) { VObject *vcard = newVObject( VCCardProp ); safeAddPropValue( vcard, VCVersionProp, "2.1" ); safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); // full name safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); // name properties VObject *name = safeAddProp( vcard, VCNameProp ); safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); safeAddPropValue( name, VCGivenNameProp, c.firstName() ); safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); safeAddPropValue( name, VCNamePrefixesProp, c.title() ); safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); // home properties VObject *home_adr= safeAddProp( vcard, VCAdrProp ); safeAddProp( home_adr, VCHomeProp ); safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); safeAddProp( home_phone, VCHomeProp ); home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); safeAddProp( home_phone, VCHomeProp ); safeAddProp( home_phone, VCCellularProp ); home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); safeAddProp( home_phone, VCHomeProp ); safeAddProp( home_phone, VCFaxProp ); VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); safeAddProp( url, VCHomeProp ); // work properties VObject *work_adr= safeAddProp( vcard, VCAdrProp ); safeAddProp( work_adr, VCWorkProp ); safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); safeAddProp( work_phone, VCWorkProp ); work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); safeAddProp( work_phone, VCWorkProp ); safeAddProp( work_phone, VCCellularProp ); work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); safeAddProp( work_phone, VCWorkProp ); safeAddProp( work_phone, VCFaxProp ); work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); safeAddProp( work_phone, VCWorkProp ); safeAddProp( work_phone, VCPagerProp ); url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); safeAddProp( url, VCWorkProp ); VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); safeAddProp( title, VCWorkProp ); QStringList emails = c.emailList(); // emails.prepend( c.defaultEmail() ); Fix for bugreport #1045 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); safeAddProp( email, VCInternetProp ); } safeAddPropValue( vcard, VCNoteProp, c.notes() ); // Exporting Birthday regarding RFC 2425 (5.8.4) if ( c.birthday().isValid() ){ qWarning("Exporting birthday as: %s", convDateToVCardDate( c.birthday() ).latin1() ); safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) ); } if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { VObject *org = safeAddProp( vcard, VCOrgProp ); safeAddPropValue( org, VCOrgNameProp, c.company() ); safeAddPropValue( org, VCOrgUnitProp, c.department() ); safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); } // some values we have to export as custom fields safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); if ( c.anniversary().isValid() ){ qWarning("Exporting anniversary as: %s", convDateToVCardDate( c.anniversary() ).latin1() ); safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) ); } safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); return vcard; } QString OContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const { QString str_rfc2425 = QString("%1-%2-%3") .arg( d.year() ) .arg( d.month(), 2 ) .arg( d.day(), 2 ); // Now replace spaces with "0"... int pos = 0; while ( ( pos = str_rfc2425.find (' ') ) > 0 ) str_rfc2425.replace( pos, 1, "0" ); return str_rfc2425; } QDate OContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr ) { int monthPos = datestr.find('-'); int dayPos = datestr.find('-', monthPos+1 ); int sep_ignore = 1; if ( monthPos == -1 || dayPos == -1 ) { qDebug("fromString didn't find - in str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD ) if ( datestr.length() == 8 ){ monthPos = 4; dayPos = 6; sep_ignore = 0; qDebug("Try with follwing positions str = %s; mpos = %d ypos = %d", datestr.latin1(), monthPos, dayPos ); } else { return QDate(); } } int y = datestr.left( monthPos ).toInt(); int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt(); int d = datestr.mid( dayPos + sep_ignore ).toInt(); qDebug("TimeConversion::fromString ymd = %s => %d %d %d; mpos = %d ypos = %d", datestr.latin1(), y, m, d, monthPos, dayPos); QDate date ( y,m,d ); return date; } VObject* OContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value ) { VObject *ret = 0; if ( o && !value.isEmpty() ) ret = addPropValue( o, prop, value.latin1() ); return ret; } VObject* OContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop) { VObject *ret = 0; if ( o ) ret = addProp( o, prop ); return ret; } + +} diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h index 712d769..11be027 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h @@ -1,96 +1,85 @@ /* + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * VCard Backend for the OPIE-Contact Database. - * - * Copyright (C) 2000 Trolltech AS. All rights reserved. - * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * ===================================================================== - * ToDo: - * - * ===================================================================== - * Version: $Id$ - * ===================================================================== - * History: - * $Log$ - * Revision 1.6 2003/04/13 18:07:10 zecke - * More API doc - * QString -> const QString& - * QString = 0l -> QString::null - * - * Revision 1.5 2003/03/21 10:33:09 eilers - * Merged speed optimized xml backend for contacts to main. - * Added QDateTime to querybyexample. For instance, it is now possible to get - * all Birthdays/Anniversaries between two dates. This should be used - * to show all birthdays in the datebook.. - * This change is sourcecode backward compatible but you have to upgrade - * the binaries for today-addressbook. - * - * Revision 1.4 2002/12/07 13:26:22 eilers - * Fixing bug in storing anniversary.. - * - * Revision 1.3 2002/11/13 14:14:51 eilers - * Added sorted for Contacts.. - * - * Revision 1.2 2002/11/10 15:41:53 eilers - * Bugfixes.. - * - * Revision 1.1 2002/11/09 14:34:52 eilers - * Added VCard Backend. - * */ #ifndef __OCONTACTACCESSBACKEND_VCARD_H_ #define __OCONTACTACCESSBACKEND_VCARD_H_ -#include <opie/ocontact.h> +#include <opie2/ocontact.h> -#include "ocontactaccessbackend.h" +#include <opie2/ocontactaccessbackend.h> class VObject; +namespace Opie { /** * This is the vCard 2.1 implementation of the Contact Storage * @see OContactAccessBackend_XML * @see OPimAccessBackend */ class OContactAccessBackend_VCard : public OContactAccessBackend { public: OContactAccessBackend_VCard ( const QString& appname, const QString& filename = QString::null ); bool load (); bool reload(); bool save(); void clear (); bool add ( const OContact& newcontact ); bool remove ( int uid ); bool replace ( const OContact& contact ); OContact find ( int uid ) const; QArray<int> allRecords() const; QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); QArray<int> matchRegexp( const QRegExp &r ) const; const uint querySettings(); bool hasQuerySettings (uint querySettings) const; QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); bool wasChangedExternally(); private: OContact parseVObject( VObject* obj ); VObject* createVObject( const OContact& c ); QString convDateToVCardDate( const QDate& c ) const; QDate convVCardDateToDate( const QString& datestr ); VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); VObject *safeAddProp( VObject* o, const char* prop); bool m_dirty : 1; QString m_file; QMap<int, OContact> m_map; }; +} + #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp index aae7fca..4c3da0c 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp @@ -1,820 +1,751 @@ /* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * XML Backend for the OPIE-Contact Database. - * - * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * ===================================================================== - * - * ===================================================================== - * Version: $Id$ - * ===================================================================== - * History: - * $Log$ - * Revision 1.9 2003/09/22 14:31:16 eilers - * Added first experimental incarnation of sql-backend for addressbook. - * Some modifications to be able to compile the todo sql-backend. - * A lot of changes fill follow... - * - * Revision 1.8 2003/08/30 15:28:26 eilers - * Removed some unimportant debug output which causes slow down.. - * - * Revision 1.7 2003/08/01 12:30:16 eilers - * Merging changes from BRANCH_1_0 to HEAD - * - * Revision 1.6 2003/07/07 16:19:47 eilers - * Fixing serious bug in hasQuerySettings() - * - * Revision 1.5 2003/04/13 18:07:10 zecke - * More API doc - * QString -> const QString& - * QString = 0l -> QString::null - * - * Revision 1.4 2003/03/21 14:32:54 mickeyl - * g++ compliance fix: default arguments belong into the declaration, but not the definition - * - * Revision 1.3 2003/03/21 12:26:28 eilers - * Fixing small bug: If we search a birthday from today to today, it returned - * every contact .. - * - * Revision 1.2 2003/03/21 10:33:09 eilers - * Merged speed optimized xml backend for contacts to main. - * Added QDateTime to querybyexample. For instance, it is now possible to get - * all Birthdays/Anniversaries between two dates. This should be used - * to show all birthdays in the datebook.. - * This change is sourcecode backward compatible but you have to upgrade - * the binaries for today-addressbook. - * - * Revision 1.1.2.2 2003/02/11 12:17:28 eilers - * Speed optimization. Removed the sequential search loops. - * - * Revision 1.1.2.1 2003/02/10 15:31:38 eilers - * Writing offsets to debug output.. - * - * Revision 1.1 2003/02/09 15:05:01 eilers - * Nothing happened.. Just some cleanup before I will start.. - * - * Revision 1.12 2003/01/03 16:58:03 eilers - * Reenable debug output - * - * Revision 1.11 2003/01/03 12:31:28 eilers - * Bugfix for calculating data diffs.. - * - * Revision 1.10 2003/01/02 14:27:12 eilers - * Improved query by example: Search by date is possible.. First step - * for a today plugin for birthdays.. - * - * Revision 1.9 2002/12/08 12:48:57 eilers - * Moved journal-enum from ocontact into i the xml-backend.. - * - * Revision 1.8 2002/11/14 17:04:24 eilers - * Sorting will now work if fullname is identical on some entries - * - * Revision 1.7 2002/11/13 15:02:46 eilers - * Small Bug in sorted fixed - * - * Revision 1.6 2002/11/13 14:14:51 eilers - * Added sorted for Contacts.. - * - * Revision 1.5 2002/11/01 15:10:42 eilers - * Added regExp-search in database for all fields in a contact. - * - * Revision 1.4 2002/10/16 10:52:40 eilers - * Added some docu to the interface and now using the cache infrastucture by zecke.. :) - * - * Revision 1.3 2002/10/14 16:21:54 eilers - * Some minor interface updates - * - * Revision 1.2 2002/10/07 17:34:24 eilers - * added OBackendFactory for advanced backend access - * - * Revision 1.1 2002/09/27 17:11:44 eilers - * Added API for accessing the Contact-Database ! It is compiling, but - * please do not expect that anything is working ! - * I will debug that stuff in the next time .. - * Please read README_COMPILE for compiling ! - * - * */ -#include "ocontactaccessbackend_xml.h" +#include <opie2/ocontactaccessbackend_xml.h> #include <qasciidict.h> #include <qdatetime.h> #include <qfile.h> #include <qfileinfo.h> #include <qregexp.h> #include <qarray.h> #include <qmap.h> #include <qdatetime.h> #include <qpe/global.h> #include <opie/xmltree.h> -#include "ocontactaccessbackend.h" -#include "ocontactaccess.h" +#include <opie2/ocontactaccessbackend.h> +#include <opie2/ocontactaccess.h> #include <stdlib.h> #include <errno.h> using namespace Opie; +namespace Opie { OContactAccessBackend_XML::OContactAccessBackend_XML ( const QString& appname, const QString& filename ): m_changed( false ) { // Just m_contactlist should call delete if an entry // is removed. m_contactList.setAutoDelete( true ); m_uidToContact.setAutoDelete( false ); m_appName = appname; /* Set journalfile name ... */ m_journalName = getenv("HOME"); m_journalName +="/.abjournal" + appname; /* Expecting to access the default filename if nothing else is set */ if ( filename.isEmpty() ){ m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); } else m_fileName = filename; /* Load Database now */ load (); } bool OContactAccessBackend_XML::save() { if ( !m_changed ) return true; QString strNewFile = m_fileName + ".new"; QFile f( strNewFile ); if ( !f.open( IO_WriteOnly|IO_Raw ) ) return false; int total_written; int idx_offset = 0; QString out; // Write Header out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" " <Groups>\n" " </Groups>\n" " <Contacts>\n"; QCString cstr = out.utf8(); f.writeBlock( cstr.data(), cstr.length() ); idx_offset += cstr.length(); out = ""; // Write all contacts QListIterator<OContact> it( m_contactList ); for ( ; it.current(); ++it ) { // qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset ); out += "<Contact "; (*it)->save( out ); out += "/>\n"; cstr = out.utf8(); total_written = f.writeBlock( cstr.data(), cstr.length() ); idx_offset += cstr.length(); if ( total_written != int(cstr.length()) ) { f.close(); QFile::remove( strNewFile ); return false; } out = ""; } out += " </Contacts>\n</AddressBook>\n"; // Write Footer cstr = out.utf8(); total_written = f.writeBlock( cstr.data(), cstr.length() ); if ( total_written != int( cstr.length() ) ) { f.close(); QFile::remove( strNewFile ); return false; } f.close(); // move the file over, I'm just going to use the system call // because, I don't feel like using QDir. if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { qWarning( "problem renaming file %s to %s, errno: %d", strNewFile.latin1(), m_journalName.latin1(), errno ); // remove the tmp file... QFile::remove( strNewFile ); } /* The journalfile should be removed now... */ removeJournal(); m_changed = false; return true; } bool OContactAccessBackend_XML::load () { m_contactList.clear(); m_uidToContact.clear(); /* Load XML-File and journal if it exists */ if ( !load ( m_fileName, false ) ) return false; /* The returncode of the journalfile is ignored due to the * fact that it does not exist when this class is instantiated ! * But there may such a file exist, if the application crashed. * Therefore we try to load it to get the changes before the # * crash happened... */ load (m_journalName, true); return true; } void OContactAccessBackend_XML::clear () { m_contactList.clear(); m_uidToContact.clear(); m_changed = false; } bool OContactAccessBackend_XML::wasChangedExternally() { QFileInfo fi( m_fileName ); QDateTime lastmod = fi.lastModified (); return (lastmod != m_readtime); } QArray<int> OContactAccessBackend_XML::allRecords() const { QArray<int> uid_list( m_contactList.count() ); uint counter = 0; QListIterator<OContact> it( m_contactList ); for( ; it.current(); ++it ){ uid_list[counter++] = (*it)->uid(); } return ( uid_list ); } OContact OContactAccessBackend_XML::find ( int uid ) const { OContact foundContact; //Create empty contact OContact* found = m_uidToContact.find( QString().setNum( uid ) ); if ( found ){ foundContact = *found; } return ( foundContact ); } QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings, const QDateTime& d ) { QArray<int> m_currentQuery( m_contactList.count() ); QListIterator<OContact> it( m_contactList ); uint arraycounter = 0; for( ; it.current(); ++it ){ /* Search all fields and compare them with query object. Store them into list * if all fields matches. */ QDate* queryDate = 0l; QDate* checkDate = 0l; bool allcorrect = true; for ( int i = 0; i < Qtopia::Groups; i++ ) { // Birthday and anniversary are special nonstring fields and should // be handled specially switch ( i ){ case Qtopia::Birthday: queryDate = new QDate( query.birthday() ); checkDate = new QDate( (*it)->birthday() ); case Qtopia::Anniversary: if ( queryDate == 0l ){ queryDate = new QDate( query.anniversary() ); checkDate = new QDate( (*it)->anniversary() ); } if ( queryDate->isValid() ){ if( checkDate->isValid() ){ if ( settings & OContactAccess::DateYear ){ if ( queryDate->year() != checkDate->year() ) allcorrect = false; } if ( settings & OContactAccess::DateMonth ){ if ( queryDate->month() != checkDate->month() ) allcorrect = false; } if ( settings & OContactAccess::DateDay ){ if ( queryDate->day() != checkDate->day() ) allcorrect = false; } if ( settings & OContactAccess::DateDiff ) { QDate current; // If we get an additional date, we // will take this date instead of // the current one.. if ( !d.date().isValid() ) current = QDate::currentDate(); else current = d.date(); // We have to equalize the year, otherwise // the search will fail.. checkDate->setYMD( current.year(), checkDate->month(), checkDate->day() ); if ( *checkDate < current ) checkDate->setYMD( current.year()+1, checkDate->month(), checkDate->day() ); // Check whether the birthday/anniversary date is between // the current/given date and the maximum date // ( maximum time range ) ! qWarning("Checking if %s is between %s and %s ! ", checkDate->toString().latin1(), current.toString().latin1(), queryDate->toString().latin1() ); if ( current.daysTo( *queryDate ) >= 0 ){ if ( !( ( *checkDate >= current ) && ( *checkDate <= *queryDate ) ) ){ allcorrect = false; qWarning (" Nope!.."); } } } } else{ // checkDate is invalid. Therefore this entry is always rejected allcorrect = false; } } delete queryDate; queryDate = 0l; delete checkDate; checkDate = 0l; break; default: /* Just compare fields which are not empty in the query object */ if ( !query.field(i).isEmpty() ){ switch ( settings & ~( OContactAccess::IgnoreCase | OContactAccess::DateDiff | OContactAccess::DateYear | OContactAccess::DateMonth | OContactAccess::DateDay | OContactAccess::MatchOne ) ){ case OContactAccess::RegExp:{ QRegExp expr ( query.field(i), !(settings & OContactAccess::IgnoreCase), false ); if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OContactAccess::WildCards:{ QRegExp expr ( query.field(i), !(settings & OContactAccess::IgnoreCase), true ); if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OContactAccess::ExactMatch:{ if (settings & OContactAccess::IgnoreCase){ if ( query.field(i).upper() != (*it)->field(i).upper() ) allcorrect = false; }else{ if ( query.field(i) != (*it)->field(i) ) allcorrect = false; } } break; } } } } if ( allcorrect ){ m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const { QArray<int> m_currentQuery( m_contactList.count() ); QListIterator<OContact> it( m_contactList ); uint arraycounter = 0; for( ; it.current(); ++it ){ if ( (*it)->match( r ) ){ m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } const uint OContactAccessBackend_XML::querySettings() { return ( OContactAccess::WildCards | OContactAccess::IgnoreCase | OContactAccess::RegExp | OContactAccess::ExactMatch | OContactAccess::DateDiff | OContactAccess::DateYear | OContactAccess::DateMonth | OContactAccess::DateDay ); } bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const { /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay * may be added with any of the other settings. IgnoreCase should never used alone. * Wildcards, RegExp, ExactMatch should never used at the same time... */ // Step 1: Check whether the given settings are supported by this backend if ( ( querySettings & ( OContactAccess::IgnoreCase | OContactAccess::WildCards | OContactAccess::DateDiff | OContactAccess::DateYear | OContactAccess::DateMonth | OContactAccess::DateDay | OContactAccess::RegExp | OContactAccess::ExactMatch ) ) != querySettings ) return false; // Step 2: Check whether the given combinations are ok.. // IngoreCase alone is invalid if ( querySettings == OContactAccess::IgnoreCase ) return false; // WildCards, RegExp and ExactMatch should never used at the same time switch ( querySettings & ~( OContactAccess::IgnoreCase | OContactAccess::DateDiff | OContactAccess::DateYear | OContactAccess::DateMonth | OContactAccess::DateDay ) ){ case OContactAccess::RegExp: return ( true ); case OContactAccess::WildCards: return ( true ); case OContactAccess::ExactMatch: return ( true ); case 0: // one of the upper removed bits were set.. return ( true ); default: return ( false ); } } // Currently only asc implemented.. QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) { QMap<QString, int> nameToUid; QStringList names; QArray<int> m_currentQuery( m_contactList.count() ); // First fill map and StringList with all Names // Afterwards sort namelist and use map to fill array to return.. QListIterator<OContact> it( m_contactList ); for( ; it.current(); ++it ){ names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) ); nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() ); } names.sort(); int i = 0; if ( asc ){ for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) m_currentQuery[i++] = nameToUid[ (*it) ]; }else{ for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) m_currentQuery[i++] = nameToUid[ (*it) ]; } return m_currentQuery; } bool OContactAccessBackend_XML::add ( const OContact &newcontact ) { //qWarning("odefaultbackend: ACTION::ADD"); updateJournal (newcontact, ACTION_ADD); addContact_p( newcontact ); m_changed = true; return true; } bool OContactAccessBackend_XML::replace ( const OContact &contact ) { m_changed = true; OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) ); if ( found ) { OContact* newCont = new OContact( contact ); updateJournal ( *newCont, ACTION_REPLACE); m_contactList.removeRef ( found ); m_contactList.append ( newCont ); m_uidToContact.remove( QString().setNum( contact.uid() ) ); m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont ); qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid()); return true; } else return false; } bool OContactAccessBackend_XML::remove ( int uid ) { m_changed = true; OContact* found = m_uidToContact.find ( QString().setNum( uid ) ); if ( found ) { updateJournal ( *found, ACTION_REMOVE); m_contactList.removeRef ( found ); m_uidToContact.remove( QString().setNum( uid ) ); return true; } else return false; } bool OContactAccessBackend_XML::reload(){ /* Reload is the same as load in this implementation */ return ( load() ); } void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) { OContact* contRef = new OContact( newcontact ); m_contactList.append ( contRef ); m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef ); } /* This function loads the xml-database and the journalfile */ bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) { /* We use the time of the last read to check if the file was * changed externally. */ if ( !isJournal ){ QFileInfo fi( filename ); m_readtime = fi.lastModified (); } const int JOURNALACTION = Qtopia::Notes + 1; const int JOURNALROW = JOURNALACTION + 1; bool foundAction = false; journal_action action = ACTION_ADD; int journalKey = 0; QMap<int, QString> contactMap; QMap<QString, QString> customMap; QMap<QString, QString>::Iterator customIt; QAsciiDict<int> dict( 47 ); dict.setAutoDelete( TRUE ); dict.insert( "Uid", new int(Qtopia::AddressUid) ); dict.insert( "Title", new int(Qtopia::Title) ); dict.insert( "FirstName", new int(Qtopia::FirstName) ); dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); dict.insert( "LastName", new int(Qtopia::LastName) ); dict.insert( "Suffix", new int(Qtopia::Suffix) ); dict.insert( "FileAs", new int(Qtopia::FileAs) ); dict.insert( "Categories", new int(Qtopia::AddressCategory) ); dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); dict.insert( "Emails", new int(Qtopia::Emails) ); dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); dict.insert( "HomeState", new int(Qtopia::HomeState) ); dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); dict.insert( "Company", new int(Qtopia::Company) ); dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); dict.insert( "Department", new int(Qtopia::Department) ); dict.insert( "Office", new int(Qtopia::Office) ); dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); dict.insert( "Profession", new int(Qtopia::Profession) ); dict.insert( "Assistant", new int(Qtopia::Assistant) ); dict.insert( "Manager", new int(Qtopia::Manager) ); dict.insert( "Spouse", new int(Qtopia::Spouse) ); dict.insert( "Children", new int(Qtopia::Children) ); dict.insert( "Gender", new int(Qtopia::Gender) ); dict.insert( "Birthday", new int(Qtopia::Birthday) ); dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); dict.insert( "Nickname", new int(Qtopia::Nickname) ); dict.insert( "Notes", new int(Qtopia::Notes) ); dict.insert( "action", new int(JOURNALACTION) ); dict.insert( "actionrow", new int(JOURNALROW) ); //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); XMLElement *root = XMLElement::load( filename ); if(root != 0l ){ // start parsing /* Parse all XML-Elements and put the data into the * Contact-Class */ XMLElement *element = root->firstChild(); //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); element = element->firstChild(); /* Search Tag "Contacts" which is the parent of all Contacts */ while( element && !isJournal ){ if( element->tagName() != QString::fromLatin1("Contacts") ){ //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", // element->tagName().latin1()); element = element->nextChild(); } else { element = element->firstChild(); break; } } /* Parse all Contacts and ignore unknown tags */ while( element ){ if( element->tagName() != QString::fromLatin1("Contact") ){ //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", // element->tagName().latin1()); element = element->nextChild(); continue; } /* Found alement with tagname "contact", now parse and store all * attributes contained */ //qWarning("OContactDefBack::load element tagName() : %s", // element->tagName().latin1() ); QString dummy; foundAction = false; XMLElement::AttributeMap aMap = element->attributes(); XMLElement::AttributeMap::Iterator it; contactMap.clear(); customMap.clear(); for( it = aMap.begin(); it != aMap.end(); ++it ){ // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); int *find = dict[ it.key() ]; /* Unknown attributes will be stored as "Custom" elements */ if ( !find ) { // qWarning("Attribute %s not known.", it.key().latin1()); //contact.setCustomField(it.key(), it.data()); customMap.insert( it.key(), it.data() ); continue; } /* Check if special conversion is needed and add attribute * into Contact class */ switch( *find ) { /* case Qtopia::AddressUid: contact.setUid( it.data().toInt() ); break; case Qtopia::AddressCategory: contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); break; */ case JOURNALACTION: action = journal_action(it.data().toInt()); foundAction = true; qWarning ("ODefBack(journal)::ACTION found: %d", action); break; case JOURNALROW: journalKey = it.data().toInt(); break; default: // no conversion needed add them to the map contactMap.insert( *find, it.data() ); break; } } /* now generate the Contact contact */ OContact contact( contactMap ); for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { contact.setCustomField( customIt.key(), customIt.data() ); } if (foundAction){ foundAction = false; switch ( action ) { case ACTION_ADD: addContact_p (contact); break; case ACTION_REMOVE: if ( !remove (contact.uid()) ) qWarning ("ODefBack(journal)::Unable to remove uid: %d", contact.uid() ); break; case ACTION_REPLACE: if ( !replace ( contact ) ) qWarning ("ODefBack(journal)::Unable to replace uid: %d", contact.uid() ); break; default: qWarning ("Unknown action: ignored !"); break; } }else{ /* Add contact to list */ addContact_p (contact); } /* Move to next element */ element = element->nextChild(); } }else { qWarning("ODefBack::could not load"); } delete root; qWarning("returning from loading" ); return true; } void OContactAccessBackend_XML::updateJournal( const OContact& cnt, journal_action action ) { QFile f( m_journalName ); bool created = !f.exists(); if ( !f.open(IO_WriteOnly|IO_Append) ) return; QString buf; QCString str; // if the file was created, we have to set the Tag "<CONTACTS>" to // get a XML-File which is readable by our parser. // This is just a cheat, but better than rewrite the parser. if ( created ){ buf = "<Contacts>"; QCString cstr = buf.utf8(); f.writeBlock( cstr.data(), cstr.length() ); } buf = "<Contact "; cnt.save( buf ); buf += " action=\"" + QString::number( (int)action ) + "\" "; buf += "/>\n"; QCString cstr = buf.utf8(); f.writeBlock( cstr.data(), cstr.length() ); } void OContactAccessBackend_XML::removeJournal() { QFile f ( m_journalName ); if ( f.exists() ) f.remove(); } +} diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h index a0cae4d..f439c4c 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h @@ -1,160 +1,108 @@ /* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * XML Backend for the OPIE-Contact Database. - * - * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) - * - * ===================================================================== - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * ===================================================================== - * ToDo: XML-Backend: Automatic reload if something was changed... - * File Locking to protect against concurrent access - * - * - * ===================================================================== - * Version: $Id$ - * ===================================================================== - * History: - * $Log$ - * Revision 1.15 2003/09/22 14:31:16 eilers - * Added first experimental incarnation of sql-backend for addressbook. - * Some modifications to be able to compile the todo sql-backend. - * A lot of changes fill follow... - * - * Revision 1.14 2003/04/13 18:07:10 zecke - * More API doc - * QString -> const QString& - * QString = 0l -> QString::null - * - * Revision 1.13 2003/03/21 10:33:09 eilers - * Merged speed optimized xml backend for contacts to main. - * Added QDateTime to querybyexample. For instance, it is now possible to get - * all Birthdays/Anniversaries between two dates. This should be used - * to show all birthdays in the datebook.. - * This change is sourcecode backward compatible but you have to upgrade - * the binaries for today-addressbook. - * - * Revision 1.12.2.2 2003/02/11 12:17:28 eilers - * Speed optimization. Removed the sequential search loops. - * - * Revision 1.12.2.1 2003/02/09 15:05:01 eilers - * Nothing happened.. Just some cleanup before I will start.. - * - * Revision 1.12 2003/01/03 16:58:03 eilers - * Reenable debug output - * - * Revision 1.11 2003/01/03 12:31:28 eilers - * Bugfix for calculating data diffs.. - * - * Revision 1.10 2003/01/02 14:27:12 eilers - * Improved query by example: Search by date is possible.. First step - * for a today plugin for birthdays.. - * - * Revision 1.9 2002/12/08 12:48:57 eilers - * Moved journal-enum from ocontact into i the xml-backend.. - * - * Revision 1.8 2002/11/14 17:04:24 eilers - * Sorting will now work if fullname is identical on some entries - * - * Revision 1.7 2002/11/13 15:02:46 eilers - * Small Bug in sorted fixed - * - * Revision 1.6 2002/11/13 14:14:51 eilers - * Added sorted for Contacts.. - * - * Revision 1.5 2002/11/01 15:10:42 eilers - * Added regExp-search in database for all fields in a contact. - * - * Revision 1.4 2002/10/16 10:52:40 eilers - * Added some docu to the interface and now using the cache infrastucture by zecke.. :) - * - * Revision 1.3 2002/10/14 16:21:54 eilers - * Some minor interface updates - * - * Revision 1.2 2002/10/07 17:34:24 eilers - * added OBackendFactory for advanced backend access - * - * Revision 1.1 2002/09/27 17:11:44 eilers - * Added API for accessing the Contact-Database ! It is compiling, but - * please do not expect that anything is working ! - * I will debug that stuff in the next time .. - * Please read README_COMPILE for compiling ! - * - * */ #ifndef _OContactAccessBackend_XML_ #define _OContactAccessBackend_XML_ -#include "ocontactaccessbackend.h" -#include "ocontactaccess.h" +#include <opie2/ocontactaccessbackend.h> +#include <opie2/ocontactaccess.h> #include <qlist.h> #include <qdict.h> +namespace Opie { /* the default xml implementation */ /** * This class is the XML implementation of a Contact backend * it does implement everything available for OContact. * @see OPimAccessBackend for more information of available methods */ class OContactAccessBackend_XML : public OContactAccessBackend { public: OContactAccessBackend_XML ( const QString& appname, const QString& filename = QString::null ); bool save(); bool load (); void clear (); bool wasChangedExternally(); QArray<int> allRecords() const; OContact find ( int uid ) const; QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); QArray<int> matchRegexp( const QRegExp &r ) const; const uint querySettings(); bool hasQuerySettings (uint querySettings) const; // Currently only asc implemented.. QArray<int> sorted( bool asc, int , int , int ); bool add ( const OContact &newcontact ); bool replace ( const OContact &contact ); bool remove ( int uid ); bool reload(); private: enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; void addContact_p( const OContact &newcontact ); /* This function loads the xml-database and the journalfile */ bool load( const QString filename, bool isJournal ); void updateJournal( const OContact& cnt, journal_action action ); void removeJournal(); protected: bool m_changed; QString m_journalName; QString m_fileName; QString m_appName; QList<OContact> m_contactList; QDateTime m_readtime; QDict<OContact> m_uidToContact; }; +} + #endif diff --git a/libopie2/opiepim/backend/odatebookaccessbackend.cpp b/libopie2/opiepim/backend/odatebookaccessbackend.cpp index f0c5d65..9bf4bf0 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend.cpp @@ -1,182 +1,216 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #include <qtl.h> -#include "orecur.h" +#include <opie2/orecur.h> -#include "odatebookaccessbackend.h" +#include <opie2/odatebookaccessbackend.h> + +using namespace Opie; namespace { /* a small helper to get all NonRepeating events for a range of time */ void events( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& events, const QDate& from, const QDate& to ) { QDateTime dtStart, dtEnd; for ( OEvent::ValueList::ConstIterator it = events.begin(); it != events.end(); ++it ) { dtStart = (*it).startDateTime(); dtEnd = (*it).endDateTime(); /* * If in range */ if (dtStart.date() >= from && dtEnd.date() <= to ) { OEffectiveEvent eff; eff.setEvent( (*it) ); eff.setDate( dtStart.date() ); eff.setStartTime( dtStart.time() ); /* if not on the same day */ if ( dtStart.date() != dtEnd.date() ) eff.setEndTime( QTime(23, 59, 0 ) ); else eff.setEndTime( dtEnd.time() ); tmpList.append( eff ); } /* we must also check for end date information... */ if ( dtEnd.date() != dtStart.date() && dtEnd.date() >= from ) { QDateTime dt = dtStart.addDays( 1 ); dt.setTime( QTime(0, 0, 0 ) ); QDateTime dtStop; if ( dtEnd > to ) dtStop = to; else dtStop = dtEnd; while ( dt <= dtStop ) { OEffectiveEvent eff; eff.setEvent( (*it) ); eff.setDate( dt.date() ); if ( dt >= from ) { eff.setStartTime( QTime(0, 0, 0 ) ); if ( dt.date() == dtEnd.date() ) eff.setEndTime( dtEnd.time() ); else eff.setEndTime( QTime(23, 59, 0 ) ); tmpList.append( eff ); } dt = dt.addDays( 1 ); } } } } void repeat( OEffectiveEvent::ValueList& tmpList, const OEvent::ValueList& list, const QDate& from, const QDate& to ) { QDate repeat; for ( OEvent::ValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) { int dur = (*it).startDateTime().date().daysTo( (*it).endDateTime().date() ); QDate itDate = from.addDays(-dur ); ORecur rec = (*it).recurrence(); if ( !rec.hasEndDate() || rec.endDate() > to ) { rec.setEndDate( to ); rec.setHasEndDate( true ); } while (rec.nextOcurrence(itDate, repeat ) ) { if (repeat > to ) break; OEffectiveEvent eff; eff.setDate( repeat ); if ( (*it).isAllDay() ) { eff.setStartTime( QTime(0, 0, 0 ) ); eff.setEndTime( QTime(23, 59, 59 ) ); }else { /* we only occur by days, not hours/minutes/seconds. Hence * the actual end and start times will be the same for * every repeated event. For multi day events this is * fixed up later if on wronge day span */ eff.setStartTime( (*it).startDateTime().time() ); eff.setEndTime( (*it).endDateTime().time() ); } if ( dur != 0 ) { // multi-day repeating events QDate sub_it = QMAX( repeat, from ); QDate startDate = repeat; QDate endDate = startDate.addDays( dur ); while ( sub_it <= endDate && sub_it <= to ) { OEffectiveEvent tmpEff = eff; tmpEff.setEvent( (*it) ); if ( sub_it != startDate ) tmpEff.setStartTime( QTime(0, 0, 0 ) ); if ( sub_it != endDate ) tmpEff.setEndTime( QTime( 23, 59, 59 ) ); tmpEff.setDate( sub_it ); tmpEff.setEffectiveDates( startDate, endDate ); tmpList.append( tmpEff ); sub_it = sub_it.addDays( 1 ); } itDate = endDate; }else { eff.setEvent( (*it) ); tmpList.append( eff ); itDate = repeat.addDays( 1 ); } } } } } +namespace Opie { + ODateBookAccessBackend::ODateBookAccessBackend() : OPimAccessBackend<OEvent>() { } ODateBookAccessBackend::~ODateBookAccessBackend() { } OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDate& from, const QDate& to ) { OEffectiveEvent::ValueList tmpList; OEvent::ValueList list = directNonRepeats(); events( tmpList, list, from, to ); repeat( tmpList, directRawRepeats(),from,to ); list = directRawRepeats(); // Useless, isn't it ? (eilers) qHeapSort( tmpList ); return tmpList; } OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDateTime& dt ) { OEffectiveEvent::ValueList day = effectiveEvents( dt.date(), dt.date() ); OEffectiveEvent::ValueList::Iterator it; OEffectiveEvent::ValueList tmpList; QDateTime dtTmp; for ( it = day.begin(); it != day.end(); ++it ) { dtTmp = QDateTime( (*it).date(), (*it).startTime() ); if ( QABS(dt.secsTo(dtTmp) ) < 60 ) tmpList.append( (*it) ); } return tmpList; } OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) { OEffectiveEvent::ValueList tmpList; OEvent::ValueList list = directNonRepeats(); events( tmpList, list, from, to ); qHeapSort( tmpList ); return tmpList; } OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt ) { OEffectiveEvent::ValueList day = effectiveNonRepeatingEvents( dt.date(), dt.date() ); OEffectiveEvent::ValueList::Iterator it; OEffectiveEvent::ValueList tmpList; QDateTime dtTmp; for ( it = day.begin(); it != day.end(); ++it ) { dtTmp = QDateTime( (*it).date(), (*it).startTime() ); if ( QABS(dt.secsTo(dtTmp) ) < 60 ) tmpList.append( (*it) ); } return tmpList; } + +} diff --git a/libopie2/opiepim/backend/odatebookaccessbackend.h b/libopie2/opiepim/backend/odatebookaccessbackend.h index 3472ab3..6853670 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend.h @@ -1,90 +1,121 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_H #define OPIE_DATE_BOOK_ACCESS_BACKEND_H #include <qarray.h> -#include "opimaccessbackend.h" -#include "oevent.h" +#include <opie2/opimaccessbackend.h> +#include <opie2/oevent.h> +namespace Opie { /** * This class is the interface to the storage of Events. * @see OPimAccessBackend * */ class ODateBookAccessBackend : public OPimAccessBackend<OEvent> { public: typedef int UID; /** * c'tor without parameter */ ODateBookAccessBackend(); ~ODateBookAccessBackend(); /** * This method should return a list of UIDs containing * all events. No filter should be applied * @return list of events */ virtual QArray<UID> rawEvents()const = 0; /** * This method should return a list of UIDs containing * all repeating events. No filter should be applied * @return list of repeating events */ virtual QArray<UID> rawRepeats()const = 0; /** * This mthod should return a list of UIDs containing all non * repeating events. No filter should be applied * @return list of nonrepeating events */ virtual QArray<UID> nonRepeats() const = 0; /** * If you do not want to implement the effectiveEvents methods below * you need to supply it with directNonRepeats. * This method can return empty lists if effectiveEvents is implememted */ virtual OEvent::ValueList directNonRepeats() = 0; /** * Same as above but return raw repeats! */ virtual OEvent::ValueList directRawRepeats() = 0; /* is implemented by default but you can reimplement it*/ /** * Effective Events are special event occuring during a time frame. This method does calcualte * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method * yourself */ virtual OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to ); /** * this is an overloaded member function * @see effectiveEvents( const QDate& from, const QDate& to ) */ virtual OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start ); /** * Effective Events are special event occuring during a time frame. This method does calcualte * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method * yourself */ virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to ); /** * this is an overloaded member function * @see effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) */ virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start ); private: class Private; Private *d; }; +} + #endif diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp index 756f405..e79696c 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp @@ -1,367 +1,366 @@ /* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* * 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.3 2003/12/22 11:41:39 eilers - * Fixing stupid bug, found by sourcode review.. - * - * Revision 1.2 2003/12/22 10:19:26 eilers - * Finishing implementation of sql-backend for datebook. But I have to - * port the PIM datebook application to use it, before I could debug the - * whole stuff. - * Thus, PIM-Database backend is finished, but highly experimental. And some - * parts are still generic. For instance, the "queryByExample()" methods are - * not (or not fully) implemented. Todo: custom-entries not stored. - * The big show stopper: matchRegExp() (needed by OpieSearch) needs regular - * expression search in the database, which is not supported by sqlite ! - * Therefore we need either an extended sqlite or a workaround which would - * be very slow and memory consuming.. - * - * Revision 1.1 2003/12/08 15:18:12 eilers - * Committing unfinished sql implementation before merging to libopie2 starts.. - * - * */ #include <stdio.h> #include <stdlib.h> #include <qarray.h> #include <qstringlist.h> #include <qpe/global.h> #include <opie2/osqldriver.h> #include <opie2/osqlmanager.h> #include <opie2/osqlquery.h> -#include "orecur.h" -#include "odatebookaccessbackend_sql.h" +#include <opie2/orecur.h> +#include <opie2/odatebookaccessbackend_sql.h> +namespace Opie { ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& , const QString& fileName ) : ODateBookAccessBackend(), m_driver( NULL ) { m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName; // Get the standart sql-driver from the OSQLManager.. OSQLManager man; m_driver = man.standard(); m_driver->setUrl( m_fileName ); initFields(); load(); } ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() { if( m_driver ) delete m_driver; } void ODateBookAccessBackend_SQL::initFields() { // This map contains the translation of the fieldtype id's to // the names of the table columns m_fieldMap.insert( OEvent::FUid, "uid" ); m_fieldMap.insert( OEvent::FCategories, "Categories" ); m_fieldMap.insert( OEvent::FDescription, "Description" ); m_fieldMap.insert( OEvent::FLocation, "Location" ); m_fieldMap.insert( OEvent::FType, "Type" ); m_fieldMap.insert( OEvent::FAlarm, "Alarm" ); m_fieldMap.insert( OEvent::FSound, "Sound" ); m_fieldMap.insert( OEvent::FRType, "RType" ); m_fieldMap.insert( OEvent::FRWeekdays, "RWeekdays" ); m_fieldMap.insert( OEvent::FRPosition, "RPosition" ); m_fieldMap.insert( OEvent::FRFreq, "RFreq" ); m_fieldMap.insert( OEvent::FRHasEndDate, "RHasEndDate" ); m_fieldMap.insert( OEvent::FREndDate, "REndDate" ); m_fieldMap.insert( OEvent::FRCreated, "RCreated" ); m_fieldMap.insert( OEvent::FRExceptions, "RExceptions" ); m_fieldMap.insert( OEvent::FStart, "Start" ); m_fieldMap.insert( OEvent::FEnd, "End" ); m_fieldMap.insert( OEvent::FNote, "Note" ); m_fieldMap.insert( OEvent::FTimeZone, "TimeZone" ); m_fieldMap.insert( OEvent::FRecParent, "RecParent" ); m_fieldMap.insert( OEvent::FRecChildren, "Recchildren" ); // Create a map that maps the column name to the id QMapConstIterator<int, QString> it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ m_reverseFieldMap.insert( it.data(), it.key() ); } } bool ODateBookAccessBackend_SQL::load() { if (!m_driver->open() ) return false; // Don't expect that the database exists. // It is save here to create the table, even if it // do exist. ( Is that correct for all databases ?? ) QString qu = "create table datebook( uid INTEGER PRIMARY KEY "; QMap<int, QString>::Iterator it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ qu += QString( ",%1 VARCHAR(10)" ).arg( it.data() ); } qu += " );"; qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; qWarning( "command: %s", qu.latin1() ); OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ) return false; update(); return true; } void ODateBookAccessBackend_SQL::update() { QString qu = "select uid from datebook"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ // m_uids.clear(); return; } m_uids = extractUids( res ); } bool ODateBookAccessBackend_SQL::reload() { return load(); } bool ODateBookAccessBackend_SQL::save() { return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) } QArray<int> ODateBookAccessBackend_SQL::allRecords()const { return m_uids; } QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) { return QArray<int>(); } void ODateBookAccessBackend_SQL::clear() { QString qu = "drop table datebook;"; qu += "drop table custom_data;"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); reload(); } OEvent ODateBookAccessBackend_SQL::find( int uid ) const{ QString qu = "select *"; qu += "from datebook where uid = " + QString::number(uid); OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); OSQLResultItem resItem = res.first(); // Create Map for date event and insert UID QMap<int,QString> dateEventMap; dateEventMap.insert( OEvent::FUid, QString::number( uid ) ); // Now insert the data out of the columns into the map. QMapConstIterator<int, QString> it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ dateEventMap.insert( m_reverseFieldMap[*it], resItem.data( *it ) ); } // Last step: Put map into date event and return it OEvent retDate( dateEventMap ); return retDate; } // FIXME: Speed up update of uid's.. bool ODateBookAccessBackend_SQL::add( const OEvent& ev ) { QMap<int,QString> eventMap = ev.toMap(); QString qu = "insert into datebook VALUES( " + QString::number( ev.uid() ); QMap<int, QString>::Iterator it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ if ( !eventMap[it.key()].isEmpty() ) qu += QString( ",\"%1\"" ).arg( eventMap[it.key()] ); else qu += QString( ",\"\"" ); } qu += " );"; // Add custom entries int id = 0; QMap<QString, QString> customMap = ev.toExtraMap(); for( QMap<QString, QString>::Iterator it = customMap.begin(); it != customMap.end(); ++it ){ qu += "insert into custom_data VALUES(" + QString::number( ev.uid() ) + "," + QString::number( id++ ) + ",'" + it.key() //.latin1() + "'," + "0" // Priority for future enhancements + ",'" + it.data() //.latin1() + "');"; } qWarning("add %s", qu.latin1() ); OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ return false; } // Update list of uid's update(); return true; } // FIXME: Speed up update of uid's.. bool ODateBookAccessBackend_SQL::remove( int uid ) { QString qu = "DELETE from datebook where uid = " + QString::number( uid ) + ";"; qu += "DELETE from custom_data where uid = " + QString::number( uid ) + ";"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ return false; } // Update list of uid's update(); return true; } bool ODateBookAccessBackend_SQL::replace( const OEvent& ev ) { remove( ev.uid() ); return add( ev ); } QArray<int> ODateBookAccessBackend_SQL::rawEvents()const { return allRecords(); } QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const { QString qu = "select uid from datebook where RType!=\"\" AND RType!=\"NoRepeat\""; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> nix; return nix; } return extractUids( res ); } QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const { QString qu = "select uid from datebook where RType=\"\" or RType=\"NoRepeat\""; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> nix; return nix; } return extractUids( res ); } OEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats() { QArray<int> nonRepUids = nonRepeats(); OEvent::ValueList list; for (uint i = 0; i < nonRepUids.count(); ++i ){ list.append( find( nonRepUids[i] ) ); } return list; } OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats() { QArray<int> rawRepUids = rawRepeats(); OEvent::ValueList list; for (uint i = 0; i < rawRepUids.count(); ++i ){ list.append( find( rawRepUids[i] ) ); } return list; } QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const { QArray<int> null; return null; } /* ===== Private Functions ========================================== */ QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const { qWarning("extractUids"); QTime t; t.start(); OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it; QArray<int> ints(list.count() ); qWarning(" count = %d", list.count() ); int i = 0; for (it = list.begin(); it != list.end(); ++it ) { ints[i] = (*it).data("uid").toInt(); i++; } qWarning("extractUids ready: count2 = %d needs %d ms", i, t.elapsed() ); return ints; } + +} diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_sql.h b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h index f39e154..89939ef 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_sql.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h @@ -1,62 +1,93 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #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" +#include <opie2/odatebookaccessbackend.h> class OSQLDriver; +namespace Opie { /** * 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/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp index 929d004..0ebda98 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp @@ -1,612 +1,645 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <qasciidict.h> #include <qfile.h> #include <qtopia/global.h> #include <qtopia/stringutil.h> #include <qtopia/timeconversion.h> -#include "opimnotifymanager.h" -#include "orecur.h" -#include "otimezone.h" -#include "odatebookaccessbackend_xml.h" +#include <opie2/opimnotifymanager.h> +#include <opie2/orecur.h> +#include <opie2/otimezone.h> +#include <opie2/odatebookaccessbackend_xml.h> + +using namespace Opie; namespace { // FROM TT again char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) { char needleChar; char haystackChar; if (!needle || !haystack || !hLen || !nLen) return 0; const char* hsearch = haystack; if ((needleChar = *needle++) != 0) { nLen--; //(to make up for needle++) do { do { if ((haystackChar = *hsearch++) == 0) return (0); if (hsearch >= haystack + hLen) return (0); } while (haystackChar != needleChar); } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); hsearch--; } return ((char *)hsearch); } } namespace { time_t start, end, created, rp_end; ORecur* rec; ORecur* recur() { if (!rec) rec = new ORecur; return rec; } int alarmTime; int snd; enum Attribute{ FDescription = 0, FLocation, FCategories, FUid, FType, FAlarm, FSound, FRType, FRWeekdays, FRPosition, FRFreq, FRHasEndDate, FREndDate, FRStart, FREnd, FNote, FCreated, // Should't this be called FRCreated ? FTimeZone, FRecParent, FRecChildren, FExceptions }; // FIXME: Use OEvent::toMap() here !! (eilers) inline void save( const OEvent& ev, QString& buf ) { qWarning("Saving %d %s", ev.uid(), ev.description().latin1() ); buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; if (!ev.location().isEmpty() ) buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; buf += " uid=\"" + QString::number( ev.uid() ) + "\""; if (ev.isAllDay() ) buf += " type=\"AllDay\""; // is that all ?? (eilers) if (ev.hasNotifiers() ) { OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; if ( alarm.sound() == OPimAlarm::Loud ) buf += "loud"; else buf += "silent"; buf += "\""; } if ( ev.hasRecurrence() ) { buf += ev.recurrence().toString(); } /* * fscking timezones :) well, we'll first convert * the QDateTime to a QDateTime in UTC time * and then we'll create a nice time_t */ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; if (!ev.note().isEmpty() ) { buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; } buf += " timezone=\""; if ( ev.timeZone().isEmpty() ) buf += "None"; else buf += ev.timeZone(); buf += "\""; if (ev.parent() != 0 ) { buf += " recparent=\""+QString::number(ev.parent() )+"\""; } if (ev.children().count() != 0 ) { QArray<int> children = ev.children(); buf += " recchildren=\""; for ( uint i = 0; i < children.count(); i++ ) { if ( i != 0 ) buf += " "; buf += QString::number( children[i] ); } buf+= "\""; } // skip custom writing } inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { QMap<int, OEvent>::ConstIterator it; QString buf; QCString str; int total_written; for ( it = list.begin(); it != list.end(); ++it ) { buf = "<event"; save( it.data(), buf ); buf += " />\n"; str = buf.utf8(); total_written = file.writeBlock(str.data(), str.length() ); if ( total_written != int(str.length() ) ) return false; } return true; } } +namespace Opie { ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , const QString& fileName ) : ODateBookAccessBackend() { m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; m_changed = false; } ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { } bool ODateBookAccessBackend_XML::load() { return loadFile(); } bool ODateBookAccessBackend_XML::reload() { clear(); return load(); } bool ODateBookAccessBackend_XML::save() { if (!m_changed) return true; int total_written; QString strFileNew = m_name + ".new"; QFile f( strFileNew ); if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; buf += "<events>\n"; QCString str = buf.utf8(); total_written = f.writeBlock( str.data(), str.length() ); if ( total_written != int(str.length() ) ) { f.close(); QFile::remove( strFileNew ); return false; } if (!forAll( m_raw, f ) ) { f.close(); QFile::remove( strFileNew ); return false; } if (!forAll( m_rep, f ) ) { f.close(); QFile::remove( strFileNew ); return false; } buf = "</events>\n</DATEBOOK>\n"; str = buf.utf8(); total_written = f.writeBlock( str.data(), str.length() ); if ( total_written != int(str.length() ) ) { f.close(); QFile::remove( strFileNew ); return false; } f.close(); if ( ::rename( strFileNew, m_name ) < 0 ) { QFile::remove( strFileNew ); return false; } m_changed = false; return true; } QArray<int> ODateBookAccessBackend_XML::allRecords()const { QArray<int> ints( m_raw.count()+ m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { ints[i] = it.key(); i++; } for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) { return QArray<int>(); } void ODateBookAccessBackend_XML::clear() { m_changed = true; m_raw.clear(); m_rep.clear(); } OEvent ODateBookAccessBackend_XML::find( int uid ) const{ if ( m_raw.contains( uid ) ) return m_raw[uid]; else return m_rep[uid]; } bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { m_changed = true; if (ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); else m_raw.insert( ev.uid(), ev ); return true; } bool ODateBookAccessBackend_XML::remove( int uid ) { m_changed = true; m_rep.remove( uid ); m_rep.remove( uid ); return true; } bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) { replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers) return add( ev ); } QArray<int> ODateBookAccessBackend_XML::rawEvents()const { return allRecords(); } QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { QArray<int> ints( m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { QArray<int> ints( m_raw.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { OEvent::ValueList list; QMap<int, OEvent>::ConstIterator it; for (it = m_raw.begin(); it != m_raw.end(); ++it ) list.append( it.data() ); return list; } OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { OEvent::ValueList list; QMap<int, OEvent>::ConstIterator it; for (it = m_rep.begin(); it != m_rep.end(); ++it ) list.append( it.data() ); return list; } // FIXME: Use OEvent::fromMap() (eilers) bool ODateBookAccessBackend_XML::loadFile() { m_changed = false; int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); if ( fd < 0 ) return false; struct stat attribute; if ( ::fstat(fd, &attribute ) == -1 ) { ::close( fd ); return false; } void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if ( map_addr == ( (caddr_t)-1) ) { ::close( fd ); return false; } ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); ::close( fd ); QAsciiDict<int> dict(FExceptions+1); dict.setAutoDelete( true ); dict.insert( "description", new int(FDescription) ); dict.insert( "location", new int(FLocation) ); dict.insert( "categories", new int(FCategories) ); dict.insert( "uid", new int(FUid) ); dict.insert( "type", new int(FType) ); dict.insert( "alarm", new int(FAlarm) ); dict.insert( "sound", new int(FSound) ); dict.insert( "rtype", new int(FRType) ); dict.insert( "rweekdays", new int(FRWeekdays) ); dict.insert( "rposition", new int(FRPosition) ); dict.insert( "rfreq", new int(FRFreq) ); dict.insert( "rhasenddate", new int(FRHasEndDate) ); dict.insert( "enddt", new int(FREndDate) ); dict.insert( "start", new int(FRStart) ); dict.insert( "end", new int(FREnd) ); dict.insert( "note", new int(FNote) ); dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ?? dict.insert( "recparent", new int(FRecParent) ); dict.insert( "recchildren", new int(FRecChildren) ); dict.insert( "exceptions", new int(FExceptions) ); dict.insert( "timezone", new int(FTimeZone) ); char* dt = (char*)map_addr; int len = attribute.st_size; int i = 0; char* point; const char* collectionString = "<event "; int strLen = ::strlen(collectionString); int *find; while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { i = point -dt; i+= strLen; alarmTime = -1; snd = 0; // silent OEvent ev; rec = 0; while ( TRUE ) { while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) ++i; if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) break; // we have another attribute, read it. int j = i; while ( j < len && dt[j] != '=' ) ++j; QCString attr( dt+i, j-i+1); i = ++j; // skip = // find the start of quotes while ( i < len && dt[i] != '"' ) ++i; j = ++i; bool haveUtf = FALSE; bool haveEnt = FALSE; while ( j < len && dt[j] != '"' ) { if ( ((unsigned char)dt[j]) > 0x7f ) haveUtf = TRUE; if ( dt[j] == '&' ) haveEnt = TRUE; ++j; } if ( i == j ) { // empty value i = j + 1; continue; } QCString value( dt+i, j-i+1 ); i = j + 1; QString str = (haveUtf ? QString::fromUtf8( value ) : QString::fromLatin1( value ) ); if ( haveEnt ) str = Qtopia::plainString( str ); /* * add key + value */ find = dict[attr.data()]; if (!find) ev.setCustomField( attr, str ); else { setField( ev, *find, str ); } } /* time to finalize */ finalizeRecord( ev ); delete rec; } ::munmap(map_addr, attribute.st_size ); m_changed = false; // changed during add return true; } // FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers) void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { /* AllDay is alway in UTC */ if ( ev.isAllDay() ) { OTimeZone utc = OTimeZone::utc(); ev.setStartDateTime( utc.fromUTCDateTime( start ) ); ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); ev.setTimeZone( "UTC"); // make sure it is really utc }else { /* to current date time */ // qWarning(" Start is %d", start ); OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); QDateTime date = zone.toDateTime( start ); qWarning(" Start is %s", date.toString().latin1() ); ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); date = zone.toDateTime( end ); ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); } if ( rec && rec->doesRecur() ) { OTimeZone utc = OTimeZone::utc(); ORecur recu( *rec ); // call copy c'tor; recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); recu.setStart( ev.startDateTime().date() ); ev.setRecurrence( recu ); } if (alarmTime != -1 ) { QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); OPimAlarm al( snd , dt ); ev.notifiers().add( al ); } if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) { qWarning("already contains assign uid"); ev.setUid( 1 ); } qWarning("addind %d %s", ev.uid(), ev.description().latin1() ); if ( ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); else m_raw.insert( ev.uid(), ev ); } void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& value) { // qWarning(" setting %s", value.latin1() ); switch( id ) { case FDescription: e.setDescription( value ); break; case FLocation: e.setLocation( value ); break; case FCategories: e.setCategories( e.idsFromString( value ) ); break; case FUid: e.setUid( value.toInt() ); break; case FType: if ( value == "AllDay" ) { e.setAllDay( true ); e.setTimeZone( "UTC" ); } break; case FAlarm: alarmTime = value.toInt(); break; case FSound: snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent; break; // recurrence stuff case FRType: if ( value == "Daily" ) recur()->setType( ORecur::Daily ); else if ( value == "Weekly" ) recur()->setType( ORecur::Weekly); else if ( value == "MonthlyDay" ) recur()->setType( ORecur::MonthlyDay ); else if ( value == "MonthlyDate" ) recur()->setType( ORecur::MonthlyDate ); else if ( value == "Yearly" ) recur()->setType( ORecur::Yearly ); else recur()->setType( ORecur::NoRepeat ); break; case FRWeekdays: recur()->setDays( value.toInt() ); break; case FRPosition: recur()->setPosition( value.toInt() ); break; case FRFreq: recur()->setFrequency( value.toInt() ); break; case FRHasEndDate: recur()->setHasEndDate( value.toInt() ); break; case FREndDate: { rp_end = (time_t) value.toLong(); break; } case FRStart: { start = (time_t) value.toLong(); break; } case FREnd: { end = ( (time_t) value.toLong() ); break; } case FNote: e.setNote( value ); break; case FCreated: created = value.toInt(); break; case FRecParent: e.setParent( value.toInt() ); break; case FRecChildren:{ QStringList list = QStringList::split(' ', value ); for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { e.addChild( (*it).toInt() ); } } break; case FExceptions:{ QStringList list = QStringList::split(' ', value ); for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); qWarning("adding exception %s", date.toString().latin1() ); recur()->exceptions().append( date ); } } break; case FTimeZone: if ( value != "None" ) e.setTimeZone( value ); break; default: break; } } QArray<int> ODateBookAccessBackend_XML::matchRegexp( const QRegExp &r ) const { QArray<int> m_currentQuery( m_raw.count()+ m_rep.count() ); uint arraycounter = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) if ( it.data().match( r ) ) m_currentQuery[arraycounter++] = it.data().uid(); for ( it = m_rep.begin(); it != m_rep.end(); ++it ) if ( it.data().match( r ) ) m_currentQuery[arraycounter++] = it.data().uid(); // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } + +} diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h b/libopie2/opiepim/backend/odatebookaccessbackend_xml.h index a5cc0fc..29f5f4f 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.h @@ -1,55 +1,86 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H #define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H #include <qmap.h> -#include "odatebookaccessbackend.h" +#include <opie2/odatebookaccessbackend.h> +namespace Opie { /** * This is the default XML implementation for DateBoook XML storage * It fully implements the interface * @see ODateBookAccessBackend * @see OPimAccessBackend */ class ODateBookAccessBackend_XML : public ODateBookAccessBackend { public: ODateBookAccessBackend_XML( const QString& appName, const QString& fileName = QString::null); ~ODateBookAccessBackend_XML(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> matchRegexp(const QRegExp &r) const; QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); OEvent find( int uid )const; void clear(); bool add( const OEvent& ev ); bool remove( int uid ); bool replace( const OEvent& ev ); QArray<UID> rawEvents()const; QArray<UID> rawRepeats()const; QArray<UID> nonRepeats()const; OEvent::ValueList directNonRepeats(); OEvent::ValueList directRawRepeats(); private: bool m_changed :1 ; bool loadFile(); inline void finalizeRecord( OEvent& ev ); inline void setField( OEvent&, int field, const QString& val ); QString m_name; QMap<int, OEvent> m_raw; QMap<int, OEvent> m_rep; struct Data; Data* data; class Private; Private *d; }; +} + #endif diff --git a/libopie2/opiepim/backend/opimaccessbackend.h b/libopie2/opiepim/backend/opimaccessbackend.h index fd264fc..505358e 100644 --- a/libopie2/opiepim/backend/opimaccessbackend.h +++ b/libopie2/opiepim/backend/opimaccessbackend.h @@ -1,160 +1,192 @@ +/* + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #ifndef OPIE_PIM_ACCESS_BACKEND #define OPIE_PIM_ACCESS_BACKEND #include <qarray.h> #include <qdatetime.h> -#include <opie/otemplatebase.h> -#include <opie/opimrecord.h> +#include <opie2/otemplatebase.h> +#include <opie2/opimrecord.h> +namespace Opie { class OPimAccessBackendPrivate; /** * OPimAccessBackend is the base class * for all private backends * it operates on OPimRecord as the base class * and it's responsible for fast manipulating * the resource the implementation takes care * of */ template <class T = OPimRecord> class OPimAccessBackend { public: typedef OTemplateBase<T> Frontend; /** The access hint from the frontend */ OPimAccessBackend(int access = 0); virtual ~OPimAccessBackend(); /** * load the resource */ virtual bool load() = 0; /** * reload the resource */ virtual bool reload() = 0; /** * save the resource and * all it's changes */ virtual bool save() = 0; /** * return an array of * all available uids */ virtual QArray<int> allRecords()const = 0; /** * return a List of records * that match the regex */ virtual QArray<int> matchRegexp(const QRegExp &r) const = 0; /** * queryByExample for T with the given Settings * */ virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0; /** * find the OPimRecord with uid @param uid * returns T and T.isEmpty() if nothing was found */ virtual T find(int uid )const = 0; virtual T find(int uid, const QArray<int>& items, uint current, typename Frontend::CacheDirection )const ; /** * clear the back end */ virtual void clear() = 0; /** * add T */ virtual bool add( const T& t ) = 0; /** * remove */ virtual bool remove( int uid ) = 0; /** * replace a record with T.uid() */ virtual bool replace( const T& t ) = 0; /* * setTheFrontEnd!!! */ void setFrontend( Frontend* front ); /** * set the read ahead count */ void setReadAhead( uint count ); protected: int access()const; void cache( const T& t )const; /** * use a prime number here! */ void setSaneCacheSize( int ); uint readAhead()const; private: OPimAccessBackendPrivate *d; Frontend* m_front; uint m_read; int m_acc; }; template <class T> OPimAccessBackend<T>::OPimAccessBackend(int acc) : m_acc( acc ) { m_front = 0l; } template <class T> OPimAccessBackend<T>::~OPimAccessBackend() { } template <class T> void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { m_front = fr; } template <class T> void OPimAccessBackend<T>::cache( const T& t )const { if (m_front ) m_front->cache( t ); } template <class T> void OPimAccessBackend<T>::setSaneCacheSize( int size) { if (m_front ) m_front->setSaneCacheSize( size ); } template <class T> T OPimAccessBackend<T>::find( int uid, const QArray<int>&, uint, typename Frontend::CacheDirection )const { return find( uid ); } template <class T> void OPimAccessBackend<T>::setReadAhead( uint count ) { m_read = count; } template <class T> uint OPimAccessBackend<T>::readAhead()const { return m_read; } template <class T> int OPimAccessBackend<T>::access()const { return m_acc; } + +} + #endif diff --git a/libopie2/opiepim/backend/otodoaccessbackend.cpp b/libopie2/opiepim/backend/otodoaccessbackend.cpp index baaeecc..d27f5ef 100644 --- a/libopie2/opiepim/backend/otodoaccessbackend.cpp +++ b/libopie2/opiepim/backend/otodoaccessbackend.cpp @@ -1,10 +1,41 @@ +/* + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ -#include "otodoaccessbackend.h" +#include <opie2/otodoaccessbackend.h> +namespace Opie { OTodoAccessBackend::OTodoAccessBackend() : OPimAccessBackend<OTodo>() { } OTodoAccessBackend::~OTodoAccessBackend() { } + +} diff --git a/libopie2/opiepim/backend/otodoaccessbackend.h b/libopie2/opiepim/backend/otodoaccessbackend.h index 6be95bc..54b52cc 100644 --- a/libopie2/opiepim/backend/otodoaccessbackend.h +++ b/libopie2/opiepim/backend/otodoaccessbackend.h @@ -1,28 +1,59 @@ +/* + This file is part of the Opie Project + Copyright (C) The Main Author <main-author@whereever.org> + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #ifndef OPIE_TODO_ACCESS_BACKEND_H #define OPIE_TODO_ACCESS_BACKEND_H #include <qbitarray.h> -#include "otodo.h" -#include "opimaccessbackend.h" +#include <opie2/otodo.h> +#include <opie2/opimaccessbackend.h> +namespace Opie { class OTodoAccessBackend : public OPimAccessBackend<OTodo> { public: OTodoAccessBackend(); ~OTodoAccessBackend(); virtual QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ) = 0; virtual QArray<int> overDue() = 0; virtual QArray<int> sorted( bool asc, int sortOrder, int sortFilter, int cat ) = 0; virtual void removeAllCompleted() = 0; virtual QBitArray supports()const = 0; private: class Private; Private *d; }; +} + #endif diff --git a/libopie2/opiepim/backend/otodoaccesssql.cpp b/libopie2/opiepim/backend/otodoaccesssql.cpp index 3764c7e..944f82a 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.cpp +++ b/libopie2/opiepim/backend/otodoaccesssql.cpp @@ -1,693 +1,726 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #include <qdatetime.h> #include <qpe/global.h> #include <opie2/osqldriver.h> #include <opie2/osqlresult.h> #include <opie2/osqlmanager.h> #include <opie2/osqlquery.h> -#include "otodoaccesssql.h" -#include "opimstate.h" -#include "opimnotifymanager.h" -#include "orecur.h" +#include <opie2/otodoaccesssql.h> +#include <opie2/opimstate.h> +#include <opie2/opimnotifymanager.h> +#include <opie2/orecur.h> +using namespace Opie; /* * first some query * CREATE query * LOAD query * INSERT * REMOVE * CLEAR */ namespace { /** * CreateQuery for the Todolist Table */ class CreateQuery : public OSQLQuery { public: CreateQuery(); ~CreateQuery(); QString query()const; }; /** * LoadQuery * this one queries for all uids */ class LoadQuery : public OSQLQuery { public: LoadQuery(); ~LoadQuery(); QString query()const; }; /** * inserts/adds a OTodo to the table */ class InsertQuery : public OSQLQuery { public: InsertQuery(const OTodo& ); ~InsertQuery(); QString query()const; private: OTodo m_todo; }; /** * removes one from the table */ class RemoveQuery : public OSQLQuery { public: RemoveQuery(int uid ); ~RemoveQuery(); QString query()const; private: int m_uid; }; /** * Clears (delete) a Table */ class ClearQuery : public OSQLQuery { public: ClearQuery(); ~ClearQuery(); QString query()const; }; /** * a find query */ class FindQuery : public OSQLQuery { public: FindQuery(int uid); FindQuery(const QArray<int>& ); ~FindQuery(); QString query()const; private: QString single()const; QString multi()const; QArray<int> m_uids; int m_uid; }; /** * overdue query */ class OverDueQuery : public OSQLQuery { public: OverDueQuery(); ~OverDueQuery(); QString query()const; }; class EffQuery : public OSQLQuery { public: EffQuery( const QDate&, const QDate&, bool inc ); ~EffQuery(); QString query()const; private: QString with()const; QString out()const; QDate m_start; QDate m_end; bool m_inc :1; }; CreateQuery::CreateQuery() : OSQLQuery() {} CreateQuery::~CreateQuery() {} QString CreateQuery::query()const { QString qu; qu += "create table todolist( uid PRIMARY KEY, categories, completed, "; qu += "description, summary, priority, DueDate, progress , state, "; // This is the recurrance-stuff .. Exceptions are currently not supported (see ORecur.cpp) ! (eilers) qu += "RType, RWeekdays, RPosition, RFreq, RHasEndDate, EndDate, Created, Exceptions, "; qu += "reminders, alarms, maintainer, startdate, completeddate);"; qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );"; return qu; } LoadQuery::LoadQuery() : OSQLQuery() {} LoadQuery::~LoadQuery() {} QString LoadQuery::query()const { QString qu; // We do not need "distinct" here. The primary key is always unique.. //qu += "select distinct uid from todolist"; qu += "select uid from todolist"; return qu; } InsertQuery::InsertQuery( const OTodo& todo ) : OSQLQuery(), m_todo( todo ) { } InsertQuery::~InsertQuery() { } /* * converts from a OTodo to a query * we leave out X-Ref + Alarms */ QString InsertQuery::query()const{ int year, month, day; year = month = day = 0; if (m_todo.hasDueDate() ) { QDate date = m_todo.dueDate(); year = date.year(); month = date.month(); day = date.day(); } int sYear = 0, sMonth = 0, sDay = 0; if( m_todo.hasStartDate() ){ QDate sDate = m_todo.startDate(); sYear = sDate.year(); sMonth= sDate.month(); sDay = sDate.day(); } int eYear = 0, eMonth = 0, eDay = 0; if( m_todo.hasCompletedDate() ){ QDate eDate = m_todo.completedDate(); eYear = eDate.year(); eMonth= eDate.month(); eDay = eDate.day(); } QString qu; QMap<int, QString> recMap = m_todo.recurrence().toMap(); qu = "insert into todolist VALUES(" + QString::number( m_todo.uid() ) + "," + "'" + m_todo.idsToString( m_todo.categories() ) + "'" + "," + QString::number( m_todo.isCompleted() ) + "," + "'" + m_todo.description() + "'" + "," + "'" + m_todo.summary() + "'" + "," + QString::number(m_todo.priority() ) + "," + "'" + QString::number(year) + "-" + QString::number(month) + "-" + QString::number( day ) + "'" + "," + QString::number( m_todo.progress() ) + "," + QString::number( m_todo.state().state() ) + "," + "'" + recMap[ ORecur::RType ] + "'" + "," + "'" + recMap[ ORecur::RWeekdays ] + "'" + "," + "'" + recMap[ ORecur::RPosition ] + "'" + "," + "'" + recMap[ ORecur::RFreq ] + "'" + "," + "'" + recMap[ ORecur::RHasEndDate ] + "'" + "," + "'" + recMap[ ORecur::EndDate ] + "'" + "," + "'" + recMap[ ORecur::Created ] + "'" + "," + "'" + recMap[ ORecur::Exceptions ] + "'" + ","; if ( m_todo.hasNotifiers() ) { OPimNotifyManager manager = m_todo.notifiers(); qu += "'" + manager.remindersToString() + "'" + "," + "'" + manager.alarmsToString() + "'" + ","; } else{ qu += QString( "''" ) + "," + "''" + ","; } qu += QString( "''" ) + QString( "," ) // Maintainers (cur. not supported !) + "'" + QString::number(sYear) + "-" + QString::number(sMonth) + "-" + QString::number(sDay) + "'" + "," + "'" + QString::number(eYear) + "-" + QString::number(eMonth) + "-"+QString::number(eDay) + "'" + ")"; qWarning("add %s", qu.latin1() ); return qu; } RemoveQuery::RemoveQuery(int uid ) : OSQLQuery(), m_uid( uid ) {} RemoveQuery::~RemoveQuery() {} QString RemoveQuery::query()const { QString qu = "DELETE from todolist where uid = " + QString::number(m_uid); return qu; } ClearQuery::ClearQuery() : OSQLQuery() {} ClearQuery::~ClearQuery() {} QString ClearQuery::query()const { QString qu = "drop table todolist"; return qu; } FindQuery::FindQuery(int uid) : OSQLQuery(), m_uid(uid ) { } FindQuery::FindQuery(const QArray<int>& ints) : OSQLQuery(), m_uids(ints){ } FindQuery::~FindQuery() { } QString FindQuery::query()const{ if (m_uids.count() == 0 ) return single(); else return multi(); } QString FindQuery::single()const{ QString qu = "select * from todolist where uid = " + QString::number(m_uid); return qu; } QString FindQuery::multi()const { QString qu = "select * from todolist where "; for (uint i = 0; i < m_uids.count(); i++ ) { qu += " UID = " + QString::number( m_uids[i] ) + " OR"; } qu.remove( qu.length()-2, 2 ); return qu; } OverDueQuery::OverDueQuery(): OSQLQuery() {} OverDueQuery::~OverDueQuery() {} QString OverDueQuery::query()const { QDate date = QDate::currentDate(); QString str; str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() ); return str; } EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc ) : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {} EffQuery::~EffQuery() {} QString EffQuery::query()const { return m_inc ? with() : out(); } QString EffQuery::with()const { QString str; str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); return str; } QString EffQuery::out()const { QString str; str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); return str; } }; + +namespace Opie { OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) : OTodoAccessBackend(), m_dict(15), m_driver(NULL), m_dirty(true) { QString fi = file; if ( fi.isEmpty() ) fi = Global::applicationFileName( "todolist", "todolist.db" ); OSQLManager man; m_driver = man.standard(); m_driver->setUrl(fi); // fillDict(); } OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ if( m_driver ) delete m_driver; } bool OTodoAccessBackendSQL::load(){ if (!m_driver->open() ) return false; CreateQuery creat; OSQLResult res = m_driver->query(&creat ); m_dirty = true; return true; } bool OTodoAccessBackendSQL::reload(){ return load(); } bool OTodoAccessBackendSQL::save(){ return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) } QArray<int> OTodoAccessBackendSQL::allRecords()const { if (m_dirty ) update(); return m_uids; } QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){ QArray<int> ints(0); return ints; } OTodo OTodoAccessBackendSQL::find(int uid ) const{ FindQuery query( uid ); return todo( m_driver->query(&query) ); } OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, uint cur, Frontend::CacheDirection dir ) const{ uint CACHE = readAhead(); qWarning("searching for %d", uid ); QArray<int> search( CACHE ); uint size =0; OTodo to; // we try to cache CACHE items switch( dir ) { /* forward */ case 0: // FIXME: Not a good style to use magic numbers here (eilers) for (uint i = cur; i < ints.count() && size < CACHE; i++ ) { qWarning("size %d %d", size, ints[i] ); search[size] = ints[i]; size++; } break; /* reverse */ case 1: // FIXME: Not a good style to use magic numbers here (eilers) for (uint i = cur; i != 0 && size < CACHE; i-- ) { search[size] = ints[i]; size++; } break; } search.resize( size ); FindQuery query( search ); OSQLResult res = m_driver->query( &query ); if ( res.state() != OSQLResult::Success ) return to; return todo( res ); } void OTodoAccessBackendSQL::clear() { ClearQuery cle; OSQLResult res = m_driver->query( &cle ); CreateQuery qu; res = m_driver->query(&qu); } bool OTodoAccessBackendSQL::add( const OTodo& t) { InsertQuery ins( t ); OSQLResult res = m_driver->query( &ins ); if ( res.state() == OSQLResult::Failure ) return false; int c = m_uids.count(); m_uids.resize( c+1 ); m_uids[c] = t.uid(); return true; } bool OTodoAccessBackendSQL::remove( int uid ) { RemoveQuery rem( uid ); OSQLResult res = m_driver->query(&rem ); if ( res.state() == OSQLResult::Failure ) return false; m_dirty = true; return true; } /* * FIXME better set query * but we need the cache for that * now we remove */ bool OTodoAccessBackendSQL::replace( const OTodo& t) { remove( t.uid() ); bool b= add(t); m_dirty = false; // we changed some stuff but the UID stayed the same return b; } QArray<int> OTodoAccessBackendSQL::overDue() { OverDueQuery qu; return uids( m_driver->query(&qu ) ); } QArray<int> OTodoAccessBackendSQL::effectiveToDos( const QDate& s, const QDate& t, bool u) { EffQuery ef(s, t, u ); return uids (m_driver->query(&ef) ); } /* * */ QArray<int> OTodoAccessBackendSQL::sorted( bool asc, int sortOrder, int sortFilter, int cat ) { qWarning("sorted %d, %d", asc, sortOrder ); QString query; query = "select uid from todolist WHERE "; /* * Sort Filter stuff * not that straight forward * FIXME: Replace magic numbers * */ /* Category */ if ( sortFilter & 1 ) { QString str; if (cat != 0 ) str = QString::number( cat ); query += " categories like '%" +str+"%' AND"; } /* Show only overdue */ if ( sortFilter & 2 ) { QDate date = QDate::currentDate(); QString due; QString base; base = QString("DueDate <= '%1-%2-%3' AND completed = 0").arg( date.year() ).arg( date.month() ).arg( date.day() ); query += " " + base + " AND"; } /* not show completed */ if ( sortFilter & 4 ) { query += " completed = 0 AND"; }else{ query += " ( completed = 1 OR completed = 0) AND"; } /* srtip the end */ query = query.remove( query.length()-3, 3 ); /* * sort order stuff * quite straight forward */ query += "ORDER BY "; switch( sortOrder ) { /* completed */ case 0: query += "completed"; break; case 1: query += "priority"; break; case 2: query += "summary"; break; case 3: query += "DueDate"; break; } if ( !asc ) { qWarning("not ascending!"); query += " DESC"; } qWarning( query ); OSQLRawQuery raw(query ); return uids( m_driver->query(&raw) ); } bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{ if ( str == "0-0-0" ) return false; else{ int day, year, month; QStringList list = QStringList::split("-", str ); year = list[0].toInt(); month = list[1].toInt(); day = list[2].toInt(); da.setYMD( year, month, day ); return true; } } OTodo OTodoAccessBackendSQL::todo( const OSQLResult& res) const{ if ( res.state() == OSQLResult::Failure ) { OTodo to; return to; } OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it = list.begin(); qWarning("todo1"); OTodo to = todo( (*it) ); cache( to ); ++it; for ( ; it != list.end(); ++it ) { qWarning("caching"); cache( todo( (*it) ) ); } return to; } OTodo OTodoAccessBackendSQL::todo( OSQLResultItem& item )const { qWarning("todo"); bool hasDueDate = false; QDate dueDate = QDate::currentDate(); hasDueDate = date( dueDate, item.data("DueDate") ); QStringList cats = QStringList::split(";", item.data("categories") ); qWarning("Item is completed: %d", item.data("completed").toInt() ); OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(), cats, item.data("summary"), item.data("description"), item.data("progress").toUShort(), hasDueDate, dueDate, item.data("uid").toInt() ); bool isOk; int prioInt = QString( item.data("priority") ).toInt( &isOk ); if ( isOk ) to.setPriority( prioInt ); bool hasStartDate = false; QDate startDate = QDate::currentDate(); hasStartDate = date( startDate, item.data("startdate") ); bool hasCompletedDate = false; QDate completedDate = QDate::currentDate(); hasCompletedDate = date( completedDate, item.data("completeddate") ); if ( hasStartDate ) to.setStartDate( startDate ); if ( hasCompletedDate ) to.setCompletedDate( completedDate ); OPimNotifyManager& manager = to.notifiers(); manager.alarmsFromString( item.data("alarms") ); manager.remindersFromString( item.data("reminders") ); OPimState pimState; pimState.setState( QString( item.data("state") ).toInt() ); to.setState( pimState ); QMap<int, QString> recMap; recMap.insert( ORecur::RType , item.data("RType") ); recMap.insert( ORecur::RWeekdays , item.data("RWeekdays") ); recMap.insert( ORecur::RPosition , item.data("RPosition") ); recMap.insert( ORecur::RFreq , item.data("RFreq") ); recMap.insert( ORecur::RHasEndDate, item.data("RHasEndDate") ); recMap.insert( ORecur::EndDate , item.data("EndDate") ); recMap.insert( ORecur::Created , item.data("Created") ); recMap.insert( ORecur::Exceptions , item.data("Exceptions") ); ORecur recur; recur.fromMap( recMap ); to.setRecurrence( recur ); return to; } OTodo OTodoAccessBackendSQL::todo( int uid )const { FindQuery find( uid ); return todo( m_driver->query(&find) ); } /* * update the dict */ void OTodoAccessBackendSQL::fillDict() { /* initialize dict */ /* * UPDATE dict if you change anything!!! * FIXME: Isn't this dict obsolete ? (eilers) */ m_dict.setAutoDelete( TRUE ); m_dict.insert("Categories" , new int(OTodo::Category) ); m_dict.insert("Uid" , new int(OTodo::Uid) ); m_dict.insert("HasDate" , new int(OTodo::HasDate) ); m_dict.insert("Completed" , new int(OTodo::Completed) ); m_dict.insert("Description" , new int(OTodo::Description) ); m_dict.insert("Summary" , new int(OTodo::Summary) ); m_dict.insert("Priority" , new int(OTodo::Priority) ); m_dict.insert("DateDay" , new int(OTodo::DateDay) ); m_dict.insert("DateMonth" , new int(OTodo::DateMonth) ); m_dict.insert("DateYear" , new int(OTodo::DateYear) ); m_dict.insert("Progress" , new int(OTodo::Progress) ); m_dict.insert("Completed", new int(OTodo::Completed) ); // Why twice ? (eilers) m_dict.insert("CrossReference", new int(OTodo::CrossReference) ); // m_dict.insert("HasAlarmDateTime",new int(OTodo::HasAlarmDateTime) ); // old stuff (eilers) // m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) ); // old stuff (eilers) } /* * need to be const so let's fool the * compiler :( */ void OTodoAccessBackendSQL::update()const { ((OTodoAccessBackendSQL*)this)->m_dirty = false; LoadQuery lo; OSQLResult res = m_driver->query(&lo); if ( res.state() != OSQLResult::Success ) return; ((OTodoAccessBackendSQL*)this)->m_uids = uids( res ); } QArray<int> OTodoAccessBackendSQL::uids( const OSQLResult& res) const{ OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it; QArray<int> ints(list.count() ); qWarning(" count = %d", list.count() ); int i = 0; for (it = list.begin(); it != list.end(); ++it ) { ints[i] = (*it).data("uid").toInt(); i++; } return ints; } QArray<int> OTodoAccessBackendSQL::matchRegexp( const QRegExp &r ) const { #warning OTodoAccessBackendSQL::matchRegexp() not implemented !! #if 0 Copied from xml-backend by not adapted to sql (eilers) QArray<int> m_currentQuery( m_events.count() ); uint arraycounter = 0; QMap<int, OTodo>::ConstIterator it; for (it = m_events.begin(); it != m_events.end(); ++it ) { if ( it.data().match( r ) ) m_currentQuery[arraycounter++] = it.data().uid(); } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; #endif QArray<int> empty; return empty; } QBitArray OTodoAccessBackendSQL::supports()const { return sup(); } QBitArray OTodoAccessBackendSQL::sup() const{ QBitArray ar( OTodo::CompletedDate + 1 ); ar.fill( true ); ar[OTodo::CrossReference] = false; ar[OTodo::State ] = false; ar[OTodo::Reminders] = false; ar[OTodo::Notifiers] = false; ar[OTodo::Maintainer] = false; return ar; } void OTodoAccessBackendSQL::removeAllCompleted(){ #warning OTodoAccessBackendSQL::removeAllCompleted() not implemented !! } + +} diff --git a/libopie2/opiepim/backend/otodoaccesssql.h b/libopie2/opiepim/backend/otodoaccesssql.h index 1c55567..1a6f614 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.h +++ b/libopie2/opiepim/backend/otodoaccesssql.h @@ -1,56 +1,88 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #ifndef OPIE_PIM_ACCESS_SQL_H #define OPIE_PIM_ACCESS_SQL_H #include <qasciidict.h> -#include "otodoaccessbackend.h" +#include <opie2/otodoaccessbackend.h> class OSQLDriver; class OSQLResult; class OSQLResultItem; + +namespace Opie { + class OTodoAccessBackendSQL : public OTodoAccessBackend { public: OTodoAccessBackendSQL( const QString& file ); ~OTodoAccessBackendSQL(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() ); OTodo find(int uid)const; OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; void clear(); bool add( const OTodo& t ); bool remove( int uid ); bool replace( const OTodo& t ); QArray<int> overDue(); QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); QBitArray supports()const; QArray<int> matchRegexp( const QRegExp &r ) const; void removeAllCompleted(); private: void update()const; void fillDict(); inline bool date( QDate& date, const QString& )const; inline OTodo todo( const OSQLResult& )const; inline OTodo todo( OSQLResultItem& )const; inline QArray<int> uids( const OSQLResult& )const; OTodo todo( int uid )const; QBitArray sup() const; QAsciiDict<int> m_dict; OSQLDriver* m_driver; QArray<int> m_uids; bool m_dirty : 1; }; +} #endif diff --git a/libopie2/opiepim/backend/otodoaccessvcal.cpp b/libopie2/opiepim/backend/otodoaccessvcal.cpp index 6415952..e364ee2 100644 --- a/libopie2/opiepim/backend/otodoaccessvcal.cpp +++ b/libopie2/opiepim/backend/otodoaccessvcal.cpp @@ -1,249 +1,282 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #include <qfile.h> #include <qtopia/private/vobject_p.h> #include <qtopia/timeconversion.h> #include <qtopia/private/qfiledirect_p.h> -#include "otodoaccessvcal.h" +#include <opie2/otodoaccessvcal.h> + +using namespace Opie; namespace { static OTodo eventByVObj( VObject *obj ){ OTodo event; VObject *ob; QCString name; // no uid, attendees, ... and no fun // description if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){ name = vObjectStringZValue( ob ); #if 0 event.setDescription( name ); #else event.setSummary( name ); #endif } // summary if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) { name = vObjectStringZValue( ob ); #if 0 event.setSummary( name ); #else event.setDescription( name ); #endif } // completed if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){ name = vObjectStringZValue( ob ); if( name == "COMPLETED" ){ event.setCompleted( true ); }else{ event.setCompleted( false ); } }else event.setCompleted( false ); // priority if ((ob = isAPropertyOf(obj, VCPriorityProp))) { name = vObjectStringZValue( ob ); bool ok; event.setPriority(name.toInt(&ok) ); } //due date if((ob = isAPropertyOf(obj, VCDueProp)) ){ event.setHasDueDate( true ); name = vObjectStringZValue( ob ); event.setDueDate( TimeConversion::fromISO8601( name).date() ); } // categories if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){ name = vObjectStringZValue( ob ); qWarning("Categories:%s", name.data() ); } event.setUid( 1 ); return event; }; static VObject *vobjByEvent( const OTodo &event ) { VObject *task = newVObject( VCTodoProp ); if( task == 0 ) return 0l; if( event.hasDueDate() ) { QTime time(0, 0, 0); QDateTime date(event.dueDate(), time ); addPropValue( task, VCDueProp, TimeConversion::toISO8601( date ) ); } if( event.isCompleted() ) addPropValue( task, VCStatusProp, "COMPLETED"); QString string = QString::number(event.priority() ); addPropValue( task, VCPriorityProp, string.local8Bit() ); addPropValue( task, VCCategoriesProp, event.idsToString( event.categories() ).local8Bit() ); #if 0 // There seems a misrepresentation between summary in otodoevent // and summary in vcard. // The same with description.. // Description is summary and vice versa.. Argh.. (eilers) addPropValue( task, VCDescriptionProp, event.description().local8Bit() ); addPropValue( task, VCSummaryProp, event.summary().local8Bit() ); #else addPropValue( task, VCDescriptionProp, event.summary().local8Bit() ); addPropValue( task, VCSummaryProp, event.description().local8Bit() ); #endif return task; }; } +namespace Opie { OTodoAccessVCal::OTodoAccessVCal( const QString& path ) : m_dirty(false), m_file( path ) { } OTodoAccessVCal::~OTodoAccessVCal() { } bool OTodoAccessVCal::load() { m_map.clear(); m_dirty = false; VObject* vcal = 0l; vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); if (!vcal ) return false; // Iterate over the list VObjectIterator it; VObject* vobj; initPropIterator(&it, vcal); while( moreIteration( &it ) ) { vobj = ::nextVObject( &it ); QCString name = ::vObjectName( vobj ); if( name == VCTodoProp ){ OTodo to = eventByVObj( vobj ); m_map.insert( to.uid(), to ); } } // Should I do a delete vcal? return true; } bool OTodoAccessVCal::reload() { return load(); } bool OTodoAccessVCal::save() { if (!m_dirty ) return true; QFileDirect file( m_file ); if (!file.open(IO_WriteOnly ) ) return false; VObject *obj; obj = newVObject( VCCalProp ); addPropValue( obj, VCVersionProp, "1.0" ); VObject *vo; for(QMap<int, OTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ vo = vobjByEvent( it.data() ); addVObjectProp(obj, vo ); } writeVObject( file.directHandle(), obj ); cleanVObject( obj ); cleanStrTbl(); m_dirty = false; return true; } void OTodoAccessVCal::clear() { m_map.clear(); m_dirty = true; } bool OTodoAccessVCal::add( const OTodo& to ) { m_map.insert( to.uid(), to ); m_dirty = true; return true; } bool OTodoAccessVCal::remove( int uid ) { m_map.remove( uid ); m_dirty = true; return true; } void OTodoAccessVCal::removeAllCompleted() { for ( QMap<int, OTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) { if ( (*it).isCompleted() ) m_map.remove( it ); } } bool OTodoAccessVCal::replace( const OTodo& to ) { m_map.replace( to.uid(), to ); m_dirty = true; return true; } OTodo OTodoAccessVCal::find(int uid )const { return m_map[uid]; } QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::allRecords()const { QArray<int> ar( m_map.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } QArray<int> OTodoAccessVCal::matchRegexp(const QRegExp& /* r */)const { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& , const QDate& , bool ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::overDue() { QArray<int> ar(0); return ar; } QBitArray OTodoAccessVCal::supports()const { static QBitArray ar = sup(); return ar; } QBitArray OTodoAccessVCal::sup() { QBitArray ar ( OTodo::CompletedDate +1 ); ar.fill( true ); ar[OTodo::CrossReference] = false; ar[OTodo::State ] = false; ar[OTodo::Reminders] = false; ar[OTodo::Notifiers] = false; ar[OTodo::Maintainer] = false; ar[OTodo::Progress] = false; ar[OTodo::Alarms ] = false; ar[OTodo::Recurrence] = false; return ar; } + +} diff --git a/libopie2/opiepim/backend/otodoaccessvcal.h b/libopie2/opiepim/backend/otodoaccessvcal.h index 2b17147..f9323fb 100644 --- a/libopie2/opiepim/backend/otodoaccessvcal.h +++ b/libopie2/opiepim/backend/otodoaccessvcal.h @@ -1,40 +1,72 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #ifndef OPIE_OTODO_ACCESS_VCAL_H #define OPIE_OTODO_ACCESS_VCAL_H -#include "otodoaccessbackend.h" +#include <opie2/otodoaccessbackend.h> + +namespace Opie { class OTodoAccessVCal : public OTodoAccessBackend { public: OTodoAccessVCal(const QString& ); ~OTodoAccessVCal(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> matchRegexp(const QRegExp &r) const; QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() ); QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> overDue(); QArray<int> sorted( bool asc, int sortOrder, int sortFilter, int cat ); OTodo find(int uid)const; void clear(); bool add( const OTodo& ); bool remove( int uid ); bool replace( const OTodo& ); void removeAllCompleted(); virtual QBitArray supports()const; private: static QBitArray sup(); bool m_dirty : 1; QString m_file; QMap<int, OTodo> m_map; }; +} + #endif diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp index 4a5cb33..2d50ecd 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.cpp +++ b/libopie2/opiepim/backend/otodoaccessxml.cpp @@ -1,876 +1,909 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #include <errno.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <qfile.h> #include <qvector.h> #include <qpe/global.h> #include <qpe/stringutil.h> #include <qpe/timeconversion.h> -#include "oconversion.h" -#include "opimstate.h" -#include "otimezone.h" -#include "opimnotifymanager.h" -#include "orecur.h" -#include "otodoaccessxml.h" +#include <opie2/oconversion.h> +#include <opie2/opimstate.h> +#include <opie2/otimezone.h> +#include <opie2/opimnotifymanager.h> +#include <opie2/orecur.h> +#include <opie2/otodoaccessxml.h> + +using namespace Opie; namespace { time_t rp_end; ORecur* rec; ORecur *recur() { if (!rec ) rec = new ORecur; return rec; } int snd; enum MoreAttributes { FRType = OTodo::CompletedDate + 2, FRWeekdays, FRPosition, FRFreq, FRHasEndDate, FREndDate, FRStart, FREnd }; // FROM TT again char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) { char needleChar; char haystackChar; if (!needle || !haystack || !hLen || !nLen) return 0; const char* hsearch = haystack; if ((needleChar = *needle++) != 0) { nLen--; //(to make up for needle++) do { do { if ((haystackChar = *hsearch++) == 0) return (0); if (hsearch >= haystack + hLen) return (0); } while (haystackChar != needleChar); } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); hsearch--; } return ((char *)hsearch); } } +namespace Opie { OTodoAccessXML::OTodoAccessXML( const QString& appName, const QString& fileName ) : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) { if (!fileName.isEmpty() ) m_file = fileName; else m_file = Global::applicationFileName( "todolist", "todolist.xml" ); } OTodoAccessXML::~OTodoAccessXML() { } bool OTodoAccessXML::load() { rec = 0; m_opened = true; m_changed = false; /* initialize dict */ /* * UPDATE dict if you change anything!!! */ QAsciiDict<int> dict(26); dict.setAutoDelete( TRUE ); dict.insert("Categories" , new int(OTodo::Category) ); dict.insert("Uid" , new int(OTodo::Uid) ); dict.insert("HasDate" , new int(OTodo::HasDate) ); dict.insert("Completed" , new int(OTodo::Completed) ); dict.insert("Description" , new int(OTodo::Description) ); dict.insert("Summary" , new int(OTodo::Summary) ); dict.insert("Priority" , new int(OTodo::Priority) ); dict.insert("DateDay" , new int(OTodo::DateDay) ); dict.insert("DateMonth" , new int(OTodo::DateMonth) ); dict.insert("DateYear" , new int(OTodo::DateYear) ); dict.insert("Progress" , new int(OTodo::Progress) ); dict.insert("CompletedDate", new int(OTodo::CompletedDate) ); dict.insert("StartDate", new int(OTodo::StartDate) ); dict.insert("CrossReference", new int(OTodo::CrossReference) ); dict.insert("State", new int(OTodo::State) ); dict.insert("Alarms", new int(OTodo::Alarms) ); dict.insert("Reminders", new int(OTodo::Reminders) ); dict.insert("Notifiers", new int(OTodo::Notifiers) ); dict.insert("Maintainer", new int(OTodo::Maintainer) ); dict.insert("rtype", new int(FRType) ); dict.insert("rweekdays", new int(FRWeekdays) ); dict.insert("rposition", new int(FRPosition) ); dict.insert("rfreq", new int(FRFreq) ); dict.insert("start", new int(FRStart) ); dict.insert("rhasenddate", new int(FRHasEndDate) ); dict.insert("enddt", new int(FREndDate) ); // here the custom XML parser from TT it's GPL // but we want to push OpiePIM... to TT..... // mmap part from zecke :) int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); struct stat attribut; if ( fd < 0 ) return false; if ( fstat(fd, &attribut ) == -1 ) { ::close( fd ); return false; } void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if ( map_addr == ( (caddr_t)-1) ) { ::close(fd ); return false; } /* advise the kernel who we want to read it */ ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); /* we do not the file any more */ ::close( fd ); char* dt = (char*)map_addr; int len = attribut.st_size; int i = 0; char *point; const char* collectionString = "<Task "; int strLen = strlen(collectionString); while ( ( point = strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0l ) { i = point -dt; i+= strLen; qWarning("Found a start at %d %d", i, (point-dt) ); OTodo ev; m_year = m_month = m_day = 0; while ( TRUE ) { while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) ++i; if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) break; // we have another attribute, read it. int j = i; while ( j < len && dt[j] != '=' ) ++j; QCString attr( dt+i, j-i+1); i = ++j; // skip = // find the start of quotes while ( i < len && dt[i] != '"' ) ++i; j = ++i; bool haveUtf = FALSE; bool haveEnt = FALSE; while ( j < len && dt[j] != '"' ) { if ( ((unsigned char)dt[j]) > 0x7f ) haveUtf = TRUE; if ( dt[j] == '&' ) haveEnt = TRUE; ++j; } if ( i == j ) { // empty value i = j + 1; continue; } QCString value( dt+i, j-i+1 ); i = j + 1; QString str = (haveUtf ? QString::fromUtf8( value ) : QString::fromLatin1( value ) ); if ( haveEnt ) str = Qtopia::plainString( str ); /* * add key + value */ todo( &dict, ev, attr, str ); } /* * now add it */ qWarning("End at %d", i ); if (m_events.contains( ev.uid() ) || ev.uid() == 0) { ev.setUid( 1 ); m_changed = true; } if ( ev.hasDueDate() ) { ev.setDueDate( QDate(m_year, m_month, m_day) ); } if ( rec && rec->doesRecur() ) { OTimeZone utc = OTimeZone::utc(); ORecur recu( *rec ); // call copy c'tor recu.setEndDate( utc.fromUTCDateTime( rp_end ).date() ); recu.setStart( ev.dueDate() ); ev.setRecurrence( recu ); } m_events.insert(ev.uid(), ev ); m_year = m_month = m_day = -1; delete rec; rec = 0; } munmap(map_addr, attribut.st_size ); qWarning("counts %d records loaded!", m_events.count() ); return true; } bool OTodoAccessXML::reload() { m_events.clear(); return load(); } bool OTodoAccessXML::save() { // qWarning("saving"); if (!m_opened || !m_changed ) { // qWarning("not saving"); return true; } QString strNewFile = m_file + ".new"; QFile f( strNewFile ); if (!f.open( IO_WriteOnly|IO_Raw ) ) return false; int written; QString out; out = "<!DOCTYPE Tasks>\n<Tasks>\n"; // for all todos QMap<int, OTodo>::Iterator it; for (it = m_events.begin(); it != m_events.end(); ++it ) { out+= "<Task " + toString( (*it) ) + " />\n"; QCString cstr = out.utf8(); written = f.writeBlock( cstr.data(), cstr.length() ); /* less written then we wanted */ if ( written != (int)cstr.length() ) { f.close(); QFile::remove( strNewFile ); return false; } out = QString::null; } out += "</Tasks>"; QCString cstr = out.utf8(); written = f.writeBlock( cstr.data(), cstr.length() ); if ( written != (int)cstr.length() ) { f.close(); QFile::remove( strNewFile ); return false; } /* flush before renaming */ f.close(); if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { // qWarning("error renaming"); QFile::remove( strNewFile ); } m_changed = false; return true; } QArray<int> OTodoAccessXML::allRecords()const { QArray<int> ids( m_events.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { ids[i] = it.key(); i++; } return ids; } QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { QArray<int> ids(0); return ids; } OTodo OTodoAccessXML::find( int uid )const { OTodo todo; todo.setUid( 0 ); // isEmpty() QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); if ( it != m_events.end() ) todo = it.data(); return todo; } void OTodoAccessXML::clear() { if (m_opened ) m_changed = true; m_events.clear(); } bool OTodoAccessXML::add( const OTodo& todo ) { // qWarning("add"); m_changed = true; m_events.insert( todo.uid(), todo ); return true; } bool OTodoAccessXML::remove( int uid ) { m_changed = true; m_events.remove( uid ); return true; } bool OTodoAccessXML::replace( const OTodo& todo) { m_changed = true; m_events.replace( todo.uid(), todo ); return true; } QArray<int> OTodoAccessXML::effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ) { QArray<int> ids( m_events.count() ); QMap<int, OTodo>::Iterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { if ( !it.data().hasDueDate() ) { if ( includeNoDates ) { ids[i] = it.key(); i++; } }else if ( it.data().dueDate() >= start && it.data().dueDate() <= end ) { ids[i] = it.key(); i++; } } ids.resize( i ); return ids; } QArray<int> OTodoAccessXML::overDue() { QArray<int> ids( m_events.count() ); int i = 0; QMap<int, OTodo>::Iterator it; for ( it = m_events.begin(); it != m_events.end(); ++it ) { if ( it.data().isOverdue() ) { ids[i] = it.key(); i++; } } ids.resize( i ); return ids; } /* private */ void OTodoAccessXML::todo( QAsciiDict<int>* dict, OTodo& ev, const QCString& attr, const QString& val) { // qWarning("parse to do from XMLElement" ); int *find=0; find = (*dict)[ attr.data() ]; if (!find ) { // qWarning("Unknown option" + it.key() ); ev.setCustomField( attr, val ); return; } switch( *find ) { case OTodo::Uid: ev.setUid( val.toInt() ); break; case OTodo::Category: ev.setCategories( ev.idsFromString( val ) ); break; case OTodo::HasDate: ev.setHasDueDate( val.toInt() ); break; case OTodo::Completed: ev.setCompleted( val.toInt() ); break; case OTodo::Description: ev.setDescription( val ); break; case OTodo::Summary: ev.setSummary( val ); break; case OTodo::Priority: ev.setPriority( val.toInt() ); break; case OTodo::DateDay: m_day = val.toInt(); break; case OTodo::DateMonth: m_month = val.toInt(); break; case OTodo::DateYear: m_year = val.toInt(); break; case OTodo::Progress: ev.setProgress( val.toInt() ); break; case OTodo::CompletedDate: ev.setCompletedDate( OConversion::dateFromString( val ) ); break; case OTodo::StartDate: ev.setStartDate( OConversion::dateFromString( val ) ); break; case OTodo::State: ev.setState( val.toInt() ); break; case OTodo::Alarms:{ OPimNotifyManager &manager = ev.notifiers(); QStringList als = QStringList::split(";", val ); for (QStringList::Iterator it = als.begin(); it != als.end(); ++it ) { QStringList alarm = QStringList::split(":", (*it), TRUE ); // allow empty qWarning("alarm: %s", alarm.join("___").latin1() ); qWarning("alarm[0]: %s %s", alarm[0].latin1(), OConversion::dateTimeFromString( alarm[0] ).toString().latin1() ); OPimAlarm al( alarm[2].toInt(), OConversion::dateTimeFromString( alarm[0] ), alarm[1].toInt() ); manager.add( al ); } } break; case OTodo::Reminders:{ OPimNotifyManager &manager = ev.notifiers(); QStringList rems = QStringList::split(";", val ); for (QStringList::Iterator it = rems.begin(); it != rems.end(); ++it ) { OPimReminder rem( (*it).toInt() ); manager.add( rem ); } } break; case OTodo::CrossReference: { /* * A cross refernce looks like * appname,id;appname,id * we need to split it up */ QStringList refs = QStringList::split(';', val ); QStringList::Iterator strIt; for (strIt = refs.begin(); strIt != refs.end(); ++strIt ) { int pos = (*strIt).find(','); if ( pos > -1 ) ; // ev.addRelation( (*strIt).left(pos), (*strIt).mid(pos+1).toInt() ); } break; } /* Recurrence stuff below + post processing later */ case FRType: if ( val == "Daily" ) recur()->setType( ORecur::Daily ); else if ( val == "Weekly" ) recur()->setType( ORecur::Weekly); else if ( val == "MonthlyDay" ) recur()->setType( ORecur::MonthlyDay ); else if ( val == "MonthlyDate" ) recur()->setType( ORecur::MonthlyDate ); else if ( val == "Yearly" ) recur()->setType( ORecur::Yearly ); else recur()->setType( ORecur::NoRepeat ); break; case FRWeekdays: recur()->setDays( val.toInt() ); break; case FRPosition: recur()->setPosition( val.toInt() ); break; case FRFreq: recur()->setFrequency( val.toInt() ); break; case FRHasEndDate: recur()->setHasEndDate( val.toInt() ); break; case FREndDate: { rp_end = (time_t) val.toLong(); break; } default: ev.setCustomField( attr, val ); break; } } // from PalmtopRecord... GPL ### FIXME namespace { QString customToXml(const QMap<QString, QString>& customMap ) { //qWarning(QString("writing custom %1").arg(customMap.count())); QString buf(" "); for ( QMap<QString, QString>::ConstIterator cit = customMap.begin(); cit != customMap.end(); ++cit) { // qWarning(".ITEM."); buf += cit.key(); buf += "=\""; buf += Qtopia::escapeString(cit.data()); buf += "\" "; } return buf; } } QString OTodoAccessXML::toString( const OTodo& ev )const { QString str; str += "Completed=\"" + QString::number( ev.isCompleted() ) + "\" "; str += "HasDate=\"" + QString::number( ev.hasDueDate() ) + "\" "; str += "Priority=\"" + QString::number( ev.priority() ) + "\" "; str += "Progress=\"" + QString::number(ev.progress() ) + "\" "; str += "Categories=\"" + toString( ev.categories() ) + "\" "; str += "Description=\"" + Qtopia::escapeString( ev.description() ) + "\" "; str += "Summary=\"" + Qtopia::escapeString( ev.summary() ) + "\" "; if ( ev.hasDueDate() ) { str += "DateYear=\"" + QString::number( ev.dueDate().year() ) + "\" "; str += "DateMonth=\"" + QString::number( ev.dueDate().month() ) + "\" "; str += "DateDay=\"" + QString::number( ev.dueDate().day() ) + "\" "; } // qWarning( "Uid %d", ev.uid() ); str += "Uid=\"" + QString::number( ev.uid() ) + "\" "; // append the extra options /* FIXME Qtopia::Record this is currently not * possible you can set custom fields * but don' iterate over the list * I may do #define private protected * for this case - cough --zecke */ /* QMap<QString, QString> extras = ev.extras(); QMap<QString, QString>::Iterator extIt; for (extIt = extras.begin(); extIt != extras.end(); ++extIt ) str += extIt.key() + "=\"" + extIt.data() + "\" "; */ // cross refernce if ( ev.hasRecurrence() ) { str += ev.recurrence().toString(); } if ( ev.hasStartDate() ) str += "StartDate=\""+ OConversion::dateToString( ev.startDate() ) +"\" "; if ( ev.hasCompletedDate() ) str += "CompletedDate=\""+ OConversion::dateToString( ev.completedDate() ) +"\" "; if ( ev.hasState() ) str += "State=\""+QString::number( ev.state().state() )+"\" "; /* * save reminders and notifiers! * DATE_TIME:DURATION:SOUND:NOT_USED_YET;OTHER_DATE_TIME:OTHER_DURATION:SOUND:.... */ if ( ev.hasNotifiers() ) { OPimNotifyManager manager = ev.notifiers(); OPimNotifyManager::Alarms alarms = manager.alarms(); if (!alarms.isEmpty() ) { QStringList als; OPimNotifyManager::Alarms::Iterator it = alarms.begin(); for ( ; it != alarms.end(); ++it ) { /* only if time is valid */ if ( (*it).dateTime().isValid() ) { als << OConversion::dateTimeToString( (*it).dateTime() ) + ":" + QString::number( (*it).duration() ) + ":" + QString::number( (*it).sound() ) + ":"; } } // now write the list qWarning("als: %s", als.join("____________").latin1() ); str += "Alarms=\""+als.join(";") +"\" "; } /* * now the same for reminders but more easy. We just save the uid of the OEvent. */ OPimNotifyManager::Reminders reminders = manager.reminders(); if (!reminders.isEmpty() ) { OPimNotifyManager::Reminders::Iterator it = reminders.begin(); QStringList records; for ( ; it != reminders.end(); ++it ) { records << QString::number( (*it).recordUid() ); } str += "Reminders=\""+ records.join(";") +"\" "; } } str += customToXml( ev.toExtraMap() ); return str; } QString OTodoAccessXML::toString( const QArray<int>& ints ) const { return Qtopia::Record::idsToString( ints ); } /* internal class for sorting * * Inspired by todoxmlio.cpp from TT */ struct OTodoXMLContainer { OTodo todo; }; namespace { inline QString string( const OTodo& todo) { return todo.summary().isEmpty() ? todo.description().left(20 ) : todo.summary(); } inline int completed( const OTodo& todo1, const OTodo& todo2) { int ret = 0; if ( todo1.isCompleted() ) ret++; if ( todo2.isCompleted() ) ret--; return ret; } inline int priority( const OTodo& t1, const OTodo& t2) { return ( t1.priority() - t2.priority() ); } inline int description( const OTodo& t1, const OTodo& t2) { return QString::compare( string(t1), string(t2) ); } inline int deadline( const OTodo& t1, const OTodo& t2) { int ret = 0; if ( t1.hasDueDate() && t2.hasDueDate() ) ret = t2.dueDate().daysTo( t1.dueDate() ); else if ( t1.hasDueDate() ) ret = -1; else if ( t2.hasDueDate() ) ret = 1; else ret = 0; return ret; } }; /* * Returns: * 0 if item1 == item2 * * non-zero if item1 != item2 * * This function returns int rather than bool so that reimplementations * can return one of three values and use it to sort by: * * 0 if item1 == item2 * * > 0 (positive integer) if item1 > item2 * * < 0 (negative integer) if item1 < item2 * */ class OTodoXMLVector : public QVector<OTodoXMLContainer> { public: OTodoXMLVector(int size, bool asc, int sort) : QVector<OTodoXMLContainer>( size ) { setAutoDelete( true ); m_asc = asc; m_sort = sort; } /* return the summary/description */ QString string( const OTodo& todo) { return todo.summary().isEmpty() ? todo.description().left(20 ) : todo.summary(); } /** * we take the sortorder( switch on it ) * */ int compareItems( Item d1, Item d2 ) { bool seComp, sePrio, seDesc, seDeadline; seComp = sePrio = seDeadline = seDesc = false; int ret =0; OTodoXMLContainer* con1 = (OTodoXMLContainer*)d1; OTodoXMLContainer* con2 = (OTodoXMLContainer*)d2; /* same item */ if ( con1->todo.uid() == con2->todo.uid() ) return 0; switch ( m_sort ) { /* completed */ case 0: { ret = completed( con1->todo, con2->todo ); seComp = TRUE; break; } /* priority */ case 1: { ret = priority( con1->todo, con2->todo ); sePrio = TRUE; break; } /* description */ case 2: { ret = description( con1->todo, con2->todo ); seDesc = TRUE; break; } /* deadline */ case 3: { ret = deadline( con1->todo, con2->todo ); seDeadline = TRUE; break; } default: ret = 0; break; }; /* * FIXME do better sorting if the first sort criteria * ret equals 0 start with complete and so on... */ /* twist it we're not ascending*/ if (!m_asc) ret = ret * -1; if ( ret ) return ret; // default did not gave difference let's try it other way around /* * General try if already checked if not test * and return * 1.Completed * 2.Priority * 3.Description * 4.DueDate */ if (!seComp ) { if ( (ret = completed( con1->todo, con2->todo ) ) ) { if (!m_asc ) ret *= -1; return ret; } } if (!sePrio ) { if ( (ret = priority( con1->todo, con2->todo ) ) ) { if (!m_asc ) ret *= -1; return ret; } } if (!seDesc ) { if ( (ret = description(con1->todo, con2->todo ) ) ) { if (!m_asc) ret *= -1; return ret; } } if (!seDeadline) { if ( (ret = deadline( con1->todo, con2->todo ) ) ) { if (!m_asc) ret *= -1; return ret; } } return 0; } private: bool m_asc; int m_sort; }; QArray<int> OTodoAccessXML::sorted( bool asc, int sortOrder, int sortFilter, int cat ) { OTodoXMLVector vector(m_events.count(), asc,sortOrder ); QMap<int, OTodo>::Iterator it; int item = 0; bool bCat = sortFilter & 1 ? true : false; bool bOnly = sortFilter & 2 ? true : false; bool comp = sortFilter & 4 ? true : false; for ( it = m_events.begin(); it != m_events.end(); ++it ) { /* show category */ /* -1 == unfiled */ if ( bCat && cat == -1 ) { if(!(*it).categories().isEmpty() ) continue; }else if ( bCat && cat != 0) if (!(*it).categories().contains( cat ) ) { continue; } /* isOverdue but we should not show overdue - why?*/ /* if ( (*it).isOverdue() && !bOnly ) { qWarning("item is overdue but !bOnly"); continue; } */ if ( !(*it).isOverdue() && bOnly ) { continue; } if ((*it).isCompleted() && comp ) { continue; } OTodoXMLContainer* con = new OTodoXMLContainer(); con->todo = (*it); vector.insert(item, con ); item++; } vector.resize( item ); /* sort it now */ vector.sort(); /* now get the uids */ QArray<int> array( vector.count() ); for (uint i= 0; i < vector.count(); i++ ) { array[i] = ( vector.at(i) )->todo.uid(); } return array; }; void OTodoAccessXML::removeAllCompleted() { QMap<int, OTodo> events = m_events; for ( QMap<int, OTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { if ( (*it).isCompleted() ) events.remove( it.key() ); } m_events = events; } QBitArray OTodoAccessXML::supports()const { static QBitArray ar = sup(); return ar; } QBitArray OTodoAccessXML::sup() { QBitArray ar( OTodo::CompletedDate +1 ); ar.fill( true ); ar[OTodo::CrossReference] = false; ar[OTodo::State ] = false; ar[OTodo::Reminders] = false; ar[OTodo::Notifiers] = false; ar[OTodo::Maintainer] = false; return ar; } QArray<int> OTodoAccessXML::matchRegexp( const QRegExp &r ) const { QArray<int> m_currentQuery( m_events.count() ); uint arraycounter = 0; QMap<int, OTodo>::ConstIterator it; for (it = m_events.begin(); it != m_events.end(); ++it ) { if ( it.data().match( r ) ) m_currentQuery[arraycounter++] = it.data().uid(); } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } + +} diff --git a/libopie2/opiepim/backend/otodoaccessxml.h b/libopie2/opiepim/backend/otodoaccessxml.h index e4850a1..d634398 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.h +++ b/libopie2/opiepim/backend/otodoaccessxml.h @@ -1,60 +1,89 @@ +/* + This file is part of the Opie Project + Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) + =. Copyright (C) The Opie Team <opie-devel@handhelds.org> + .=l. + .>+-= + _;:, .> :=|. This program is free software; you can +.> <`_, > . <= redistribute it and/or modify it under +:`=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; either version 2 of the License, + ._= =} : or (at your option) any later version. + .%`+i> _;_. + .i_,=:_. -<s. This program is distributed in the hope that + + . -:. = it will be useful, but WITHOUT ANY WARRANTY; + : .. .:, . . . without even the implied warranty of + =_ + =;=|` MERCHANTABILITY or FITNESS FOR A + _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU +..}^=.= = ; Library General Public License for more +++= -. .` .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-=` this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ #ifndef OPIE_TODO_ACCESS_XML_H #define OPIE_TODO_ACCESS_XML_H #include <qasciidict.h> #include <qmap.h> -#include "otodoaccessbackend.h" +#include <opie2/otodoaccessbackend.h> namespace Opie { class XMLElement; -}; class OTodoAccessXML : public OTodoAccessBackend { public: /** * fileName if Empty we will use the default path */ OTodoAccessXML( const QString& appName, const QString& fileName = QString::null ); ~OTodoAccessXML(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> matchRegexp(const QRegExp &r) const; QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() ); OTodo find( int uid )const; void clear(); bool add( const OTodo& ); bool remove( int uid ); void removeAllCompleted(); bool replace( const OTodo& ); /* our functions */ QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> overDue(); QArray<int> sorted( bool asc, int sortOrder, int sortFilter, int cat ); QBitArray supports()const; private: static QBitArray sup(); void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& ); QString toString( const OTodo& )const; QString toString( const QArray<int>& ints ) const; QMap<int, OTodo> m_events; QString m_file; QString m_app; bool m_opened : 1; bool m_changed : 1; class OTodoAccessXMLPrivate; OTodoAccessXMLPrivate* d; int m_year, m_month, m_day; }; +}; + #endif |