-rw-r--r-- | libopie2/opiepim/backend/obackendfactory.h | 16 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp | 664 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_sql.h | 96 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp | 7 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_xml.h | 6 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccesssql.cpp | 73 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccesssql.h | 6 | ||||
-rw-r--r-- | libopie2/opiepim/ocontact.h | 13 | ||||
-rw-r--r-- | libopie2/opiepim/ocontactfields.cpp | 456 | ||||
-rw-r--r-- | libopie2/opiepim/ocontactfields.h | 60 |
10 files changed, 1373 insertions, 24 deletions
diff --git a/libopie2/opiepim/backend/obackendfactory.h b/libopie2/opiepim/backend/obackendfactory.h index f3c339d..3567687 100644 --- a/libopie2/opiepim/backend/obackendfactory.h +++ b/libopie2/opiepim/backend/obackendfactory.h @@ -1,166 +1,176 @@ /* * Class to manage Backends. * * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * either version 2 of the License, or (at your option) any later * version. * ===================================================================== * ToDo: Use plugins * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.8 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * * Revision 1.7 2003/08/01 12:30:16 eilers * Merging changes from BRANCH_1_0 to HEAD * * Revision 1.6.4.1 2003/06/30 14:34:19 eilers * Patches from Zecke: * Fixing and cleaning up extraMap handling * Adding d_ptr for binary compatibility in the future * * Revision 1.6 2003/04/13 18:07:10 zecke * More API doc * QString -> const QString& * QString = 0l -> QString::null * * Revision 1.5 2003/02/21 23:31:52 zecke * Add XML datebookresource * -clean up todoaccessxml header * -implement some more stuff in the oeven tester * -extend DefaultFactory to not crash and to use datebook * * -reading of OEvents is working nicely.. saving will be added * tomorrow * -fix spelling in ODateBookAcces * * Revision 1.4 2002/10/14 15:55:18 eilers * Redeactivate SQL.. ;) * * Revision 1.3 2002/10/10 17:08:58 zecke * The Cache is finally in place * I tested it with my todolist and it 'works' for 10.000 todos the hits are awesome ;) * The read ahead functionality does not make sense for XMLs backends because most of the stuff is already in memory. While using readahead on SQL makes things a lot faster.... * I still have to fully implement read ahead * This change is bic but sc * * Revision 1.2 2002/10/08 09:27:36 eilers * Fixed libopie.pro to include the new pim-API. * The SQL-Stuff is currently deactivated. Otherwise everyone who wants to * compile itself would need to install libsqlite, libopiesql... * Therefore, the backend currently uses XML only.. * * Revision 1.1 2002/10/07 17:35:01 eilers * added OBackendFactory for advanced backend access * * * ===================================================================== */ #ifndef OPIE_BACKENDFACTORY_H_ #define OPIE_BACKENDFACTORY_H_ #include <qstring.h> #include <qasciidict.h> #include <qpe/config.h> #include "otodoaccessxml.h" #include "ocontactaccessbackend_xml.h" #include "odatebookaccessbackend_xml.h" #ifdef __USE_SQL #include "otodoaccesssql.h" +#include "ocontactaccessbackend_sql.h" #endif class OBackendPrivate; /** * This class is our factory. It will give us the default implementations * of at least Todolist, Contacts and Datebook. In the future this class will * allow users to switch the backend with ( XML->SQLite ) without the need * to recompile.# * This class as the whole PIM Api is making use of templates * * <pre> * OTodoAccessBackend* backend = OBackEndFactory<OTodoAccessBackend>::Default("todo", QString::null ); * backend->load(); * </pre> * * @author Stefan Eilers * @version 0.1 */ template<class T> class OBackendFactory { public: OBackendFactory() {}; enum BACKENDS { TODO, CONTACT, DATE }; /** * Returns a backend implementation for backendName * @param backendName the type of the backend * @param appName will be passed on to the backend */ static T* Default( const QString backendName, const QString& appName ){ // __asm__("int3"); Config config( "pimaccess" ); config.setGroup ( backendName ); QString backend = config.readEntry( "usebackend" ); + qWarning("Selected backend for %s is: %s", backendName.latin1(), backend.latin1() ); + QAsciiDict<int> dict ( 3 ); dict.setAutoDelete ( TRUE ); dict.insert( "todo", new int (TODO) ); dict.insert( "contact", new int (CONTACT) ); dict.insert( "datebook", new int(DATE) ); - qWarning ("TODO is: %d", TODO); - qWarning ("CONTACT is: %d", CONTACT); - int *find = dict[ backendName ]; if (!find ) return 0; switch ( *find ){ case TODO: #ifdef __USE_SQL if ( backend == "sql" ) return (T*) new OTodoAccessBackendSQL(""); #else if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!"); #endif return (T*) new OTodoAccessXML( appName ); case CONTACT: +#ifdef __USE_SQL + if ( backend == "sql" ) + return (T*) new OContactAccessBackend_SQL(""); +#else if ( backend == "sql" ) qWarning ("OBackendFactory:: sql Backend not implemented! Using XML instead!"); +#endif return (T*) new OContactAccessBackend_XML( appName ); case DATE: if ( backend == "sql" ) qWarning("OBackendFactory:: sql Backend not implemented! Using XML instead!"); return (T*) new ODateBookAccessBackend_XML( appName ); default: return NULL; } } private: OBackendPrivate* d; }; #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp new file mode 100644 index 0000000..4afa5f3 --- a/dev/null +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp @@ -0,0 +1,664 @@ +/* + * SQL Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * + */ + +#include "ocontactaccessbackend_sql.h" + +#include <qarray.h> +#include <qdatetime.h> +#include <qstringlist.h> + +#include <qpe/global.h> +#include <qpe/recordfields.h> + +#include <opie/ocontactfields.h> +#include <opie/oconversion.h> +#include <opie2/osqldriver.h> +#include <opie2/osqlresult.h> +#include <opie2/osqlmanager.h> +#include <opie2/osqlquery.h> + +/* + * Implementation of used query types + * CREATE query + * LOAD query + * INSERT + * REMOVE + * CLEAR + */ +namespace { + /** + * CreateQuery for the Todolist Table + */ + class CreateQuery : public OSQLQuery { + public: + CreateQuery(); + ~CreateQuery(); + QString query()const; + }; + + /** + * Clears (delete) a Table + */ + class ClearQuery : public OSQLQuery { + public: + ClearQuery(); + ~ClearQuery(); + QString query()const; + + }; + + + /** + * LoadQuery + * this one queries for all uids + */ + class LoadQuery : public OSQLQuery { + public: + LoadQuery(); + ~LoadQuery(); + QString query()const; + }; + + /** + * inserts/adds a OContact to the table + */ + class InsertQuery : public OSQLQuery { + public: + InsertQuery(const OContact& ); + ~InsertQuery(); + QString query()const; + private: + OContact m_contact; + }; + + + /** + * removes one from the table + */ + class RemoveQuery : public OSQLQuery { + public: + RemoveQuery(int uid ); + ~RemoveQuery(); + QString query()const; + private: + int m_uid; + }; + + /** + * a find query for noncustom elements + */ + class FindQuery : public OSQLQuery { + public: + FindQuery(int uid); + FindQuery(const QArray<int>& ); + ~FindQuery(); + QString query()const; + private: + QString single()const; + QString multi()const; + QArray<int> m_uids; + int m_uid; + }; + + /** + * a find query for custom elements + */ + class FindCustomQuery : public OSQLQuery { + public: + FindCustomQuery(int uid); + FindCustomQuery(const QArray<int>& ); + ~FindCustomQuery(); + QString query()const; + private: + QString single()const; + QString multi()const; + QArray<int> m_uids; + int m_uid; + }; + + + + // We using three tables to store the information: + // 1. addressbook : It contains General information about the contact (non custom) + // 2. dates : Stuff like birthdays, anniversaries, etc. + // 3. 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; + 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 );"; + 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; + } + +// 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 + + LoadQuery::LoadQuery() : OSQLQuery() {} + LoadQuery::~LoadQuery() {} + QString LoadQuery::query()const { + QString qu; +#ifndef __USE_SUPERFAST_LOADQUERY + qu += "select distinct uid from addressbook"; +#else + qu += "select uid from addressbook where type = 'Last Name'"; +#endif + + return qu; + } + + + InsertQuery::InsertQuery( const OContact& contact ) + : OSQLQuery(), m_contact( contact ) { + } + + InsertQuery::~InsertQuery() { + } + + /* + * converts from a OContact to a query + */ + QString InsertQuery::query()const{ + + // 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> customMap = m_contact.toExtraMap(); + + 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() + + "');"; + } + + // Now add custom data.. + id = 0; + 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 dates 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; + } + */ + QString FindQuery::single()const{ + QString qu = "select uid, type, value from addressbook where uid = "; + qu += QString::number(m_uid); + return qu; + } + + + FindCustomQuery::FindCustomQuery(int uid) + : OSQLQuery(), m_uid( uid ) { + } + FindCustomQuery::FindCustomQuery(const QArray<int>& ints) + : OSQLQuery(), m_uids( ints ){ + } + FindCustomQuery::~FindCustomQuery() { + } + QString FindCustomQuery::query()const{ +// if ( m_uids.count() == 0 ) + return single(); + } + QString FindCustomQuery::single()const{ + QString qu = "select uid, type, value from custom_data where uid = "; + qu += QString::number(m_uid); + return qu; + } + +}; + + +/* --------------------------------------------------------------------------- */ + +OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, + const QString& filename ): m_changed(false) +{ + 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", t.elapsed() ); +} + + +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(); +} + + +void OContactAccessBackend_SQL::clear () +{ + ClearQuery cle; + OSQLResult res = m_driver->query( &cle ); + CreateQuery qu; + res = m_driver->query(&qu); +} + +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", t.elapsed() ); + return retContact; +} + + + +QArray<int> OContactAccessBackend_SQL::queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ) +{ + QArray<int> nix(0); + return nix; +} + +QArray<int> OContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const +{ + QArray<int> nix(0); + return nix; +} + +const uint OContactAccessBackend_SQL::querySettings() +{ + return 0; +} + +bool OContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const +{ + return false; +} + +QArray<int> OContactAccessBackend_SQL::sorted( bool asc, int , int , int ) +{ + QTime t; + t.start(); + + // Not implemented.. + QString query = "SELECT uid FROM addressbook WHERE type = 'Last Name' "; + + query += "ORDER BY value "; + 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", 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; + +} + +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: ins:%d, query: %d, mapping: %d", t.elapsed(), t2needed, t3needed ); + return nonCustomMap; +} + +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", t.elapsed() ); + return customMap; +} diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.h b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h new file mode 100644 index 0000000..bb22551 --- a/dev/null +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h @@ -0,0 +1,96 @@ +/* + * SQL Backend for the OPIE-Contact Database. + * + * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * + * + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2003/09/22 14:31:16 eilers + * Added first experimental incarnation of sql-backend for addressbook. + * Some modifications to be able to compile the todo sql-backend. + * A lot of changes fill follow... + * + * + */ + +#ifndef _OContactAccessBackend_SQL_ +#define _OContactAccessBackend_SQL_ + +#include "ocontactaccessbackend.h" +#include "ocontactaccess.h" + +#include <qlist.h> +#include <qdict.h> + +class OSQLDriver; +class OSQLResult; +class OSQLResultItem; + +/* the default xml implementation */ +/** + * This class is the SQL implementation of a Contact backend + * it does implement everything available for OContact. + * @see OPimAccessBackend for more information of available methods + */ +class OContactAccessBackend_SQL : public OContactAccessBackend { + public: + OContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null ); + + 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_xml.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp index 1b5af2f..aae7fca 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp @@ -1,67 +1,70 @@ /* * 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... - * * * ===================================================================== * 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.. * diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h index 7b5365b..a0cae4d 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h @@ -1,67 +1,73 @@ /* * 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 diff --git a/libopie2/opiepim/backend/otodoaccesssql.cpp b/libopie2/opiepim/backend/otodoaccesssql.cpp index ec9c14c..23e0c3e 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.cpp +++ b/libopie2/opiepim/backend/otodoaccesssql.cpp @@ -1,57 +1,57 @@ #include <qdatetime.h> #include <qpe/global.h> -#include <opie/osqldriver.h> -#include <opie/osqlresult.h> -#include <opie/osqlmanager.h> -#include <opie/osqlquery.h> +#include <opie2/osqldriver.h> +#include <opie2/osqlresult.h> +#include <opie2/osqlmanager.h> +#include <opie2/osqlquery.h> #include "otodoaccesssql.h" /* * 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 */ @@ -204,228 +204,229 @@ namespace { } qu.remove( qu.length()-2, 2 ); return qu; } OverDueQuery::OverDueQuery(): OSQLQuery() {} OverDueQuery::~OverDueQuery() {} QString OverDueQuery::query()const { QDate date = QDate::currentDate(); QString str; str = QString("select uid from todolist where DueDate ='%1-%2-%3'").arg(date.year() ).arg(date.month() ).arg(date.day() ); return str; } EffQuery::EffQuery( const QDate& start, const QDate& end, bool inc ) : OSQLQuery(), m_start( start ), m_end( end ),m_inc(inc) {} EffQuery::~EffQuery() {} QString EffQuery::query()const { return m_inc ? with() : out(); } QString EffQuery::with()const { QString str; str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); return str; } QString EffQuery::out()const { QString str; str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); return str; } }; OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) : OTodoAccessBackend(), m_dict(15), m_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(); + // fillDict(); } OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ } 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(); } 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{ int 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: + 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: + 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 ) { @@ -447,94 +448,146 @@ bool OTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{ 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 has = false; QDate da = QDate::currentDate(); has = date( da, item.data("DueDate") ); QStringList cats = QStringList::split(";", item.data("categories") ); OTodo to( (bool)item.data("completed").toInt(), item.data("priority").toInt(), cats, item.data("summary"), item.data("description"), item.data("progress").toUShort(), has, da, item.data("uid").toInt() ); 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) ); + 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) ); - m_dict.insert("AlarmDateTime", new int(OTodo::AlarmDateTime) ); +// 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 { + + static QBitArray ar = sup(); + return ar; +} + +QBitArray OTodoAccessBackendSQL::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; +} + +void OTodoAccessBackendSQL::removeAllCompleted(){ +#warning OTodoAccessBackendSQL::removeAllCompleted() not implemented !! + +} diff --git a/libopie2/opiepim/backend/otodoaccesssql.h b/libopie2/opiepim/backend/otodoaccesssql.h index 6a4257c..77d8b77 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.h +++ b/libopie2/opiepim/backend/otodoaccesssql.h @@ -1,50 +1,56 @@ #ifndef OPIE_PIM_ACCESS_SQL_H #define OPIE_PIM_ACCESS_SQL_H #include <qasciidict.h> #include "otodoaccessbackend.h" class OSQLDriver; class OSQLResult; class OSQLResultItem; class OTodoAccessBackendSQL : public OTodoAccessBackend { public: OTodoAccessBackendSQL( const QString& file ); ~OTodoAccessBackendSQL(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() ); OTodo find(int uid)const; OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; void clear(); bool add( const OTodo& t ); bool remove( int uid ); bool replace( const OTodo& t ); QArray<int> overDue(); QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); + QBitArray supports()const; + QArray<int> matchRegexp( const QRegExp &r ) const; + void removeAllCompleted(); + + private: void update()const; void fillDict(); inline bool date( QDate& date, const QString& )const; inline OTodo todo( const OSQLResult& )const; inline OTodo todo( OSQLResultItem& )const; inline QArray<int> uids( const OSQLResult& )const; OTodo todo( int uid )const; + QBitArray sup(); QAsciiDict<int> m_dict; OSQLDriver* m_driver; QArray<int> m_uids; bool m_dirty : 1; }; #endif diff --git a/libopie2/opiepim/ocontact.h b/libopie2/opiepim/ocontact.h index 9a1a8dc..1d46b81 100644 --- a/libopie2/opiepim/ocontact.h +++ b/libopie2/opiepim/ocontact.h @@ -151,95 +151,90 @@ public: QString homeMobile() const { return find( Qtopia::HomeMobile ); } QString homeWebpage() const { return find( Qtopia::HomeWebPage ); } /** Multi line string containing all non-empty address info in the form * Street * City, State Zip * Country */ QString displayHomeAddress() const; // business QString company() const { return find( Qtopia::Company ); } QString businessStreet() const { return find( Qtopia::BusinessStreet ); } QString businessCity() const { return find( Qtopia::BusinessCity ); } QString businessState() const { return find( Qtopia::BusinessState ); } QString businessZip() const { return find( Qtopia::BusinessZip ); } QString businessCountry() const { return find( Qtopia::BusinessCountry ); } QString businessWebpage() const { return find( Qtopia::BusinessWebPage ); } QString jobTitle() const { return find( Qtopia::JobTitle ); } QString department() const { return find( Qtopia::Department ); } QString office() const { return find( Qtopia::Office ); } QString businessPhone() const { return find( Qtopia::BusinessPhone ); } QString businessFax() const { return find( Qtopia::BusinessFax ); } QString businessMobile() const { return find( Qtopia::BusinessMobile ); } QString businessPager() const { return find( Qtopia::BusinessPager ); } QString profession() const { return find( Qtopia::Profession ); } QString assistant() const { return find( Qtopia::Assistant ); } QString manager() const { return find( Qtopia::Manager ); } /** Multi line string containing all non-empty address info in the form * Street * City, State Zip * Country */ QString displayBusinessAddress() const; //personal QString spouse() const { return find( Qtopia::Spouse ); } QString gender() const { return find( Qtopia::Gender ); } QDate birthday() const; QDate anniversary() const; QString nickname() const { return find( Qtopia::Nickname ); } QString children() const { return find( Qtopia::Children ); } QStringList childrenList() const; // other QString notes() const { return find( Qtopia::Notes ); } QString groups() const { return find( Qtopia::Groups ); } QStringList groupList() const; -// // custom -// const QString &customField( const QString &key ) -// { return find( Custom- + key ); } - - QString toRichText() const; QMap<int, QString> toMap() const; QString field( int key ) const { return find( key ); } void setUid( int i ); QString toShortText()const; - QString OContact::type()const; - QMap<QString,QString> OContact::toExtraMap() const; - class QString OContact::recordField(int) const; + QString type()const; + class QString recordField(int) const; // Why private ? (eilers,se) QString emailSeparator() const { return " "; } + // the emails should be seperated by a comma void setEmails( const QString &v ); QString emails() const { return find( Qtopia::Emails ); } static int rtti(); private: - // The XML-Backend needs some access to the private functions + // The XML Backend needs some access to the private functions friend class OContactAccessBackend_XML; void insert( int key, const QString &value ); void replace( int key, const QString &value ); QString find( int key ) const; static QStringList fields(); void save( QString &buf ) const; QString displayAddress( const QString &street, const QString &city, const QString &state, const QString &zip, const QString &country ) const; QMap<int, QString> mMap; OContactPrivate *d; }; #endif diff --git a/libopie2/opiepim/ocontactfields.cpp b/libopie2/opiepim/ocontactfields.cpp new file mode 100644 index 0000000..831a596 --- a/dev/null +++ b/libopie2/opiepim/ocontactfields.cpp @@ -0,0 +1,456 @@ + +#include "ocontactfields.h" + +#include <qstringlist.h> +#include <qobject.h> + +// We should use our own enum in the future .. +#include <qpe/recordfields.h> +#include <qpe/config.h> +#include <opie/ocontact.h> + +/*! + \internal + Returns a list of details field names for a contact. +*/ +QStringList OContactFields::untrdetailsfields( bool sorted ) +{ + QStringList list; + QMap<int, QString> mapIdToStr = idToUntrFields(); + + list.append( mapIdToStr[ Qtopia::Office ] ); + list.append( mapIdToStr[ Qtopia::Profession ] ); + list.append( mapIdToStr[ Qtopia::Assistant ] ); + list.append( mapIdToStr[ Qtopia::Manager ] ); + + list.append( mapIdToStr[ Qtopia::Spouse ] ); + list.append( mapIdToStr[ Qtopia::Gender ] ); + list.append( mapIdToStr[ Qtopia::Birthday ] ); + list.append( mapIdToStr[ Qtopia::Anniversary ] ); + list.append( mapIdToStr[ Qtopia::Nickname ] ); + list.append( mapIdToStr[ Qtopia::Children ] ); + + if (sorted) list.sort(); + return list; +} + +/*! + \internal + Returns a translated list of details field names for a contact. +*/ +QStringList OContactFields::trdetailsfields( bool sorted ) +{ + QStringList list; + QMap<int, QString> mapIdToStr = idToTrFields(); + + list.append( mapIdToStr[Qtopia::Office] ); + list.append( mapIdToStr[Qtopia::Profession] ); + list.append( mapIdToStr[Qtopia::Assistant] ); + list.append( mapIdToStr[Qtopia::Manager] ); + + list.append( mapIdToStr[Qtopia::Spouse] ); + list.append( mapIdToStr[Qtopia::Gender] ); + list.append( mapIdToStr[Qtopia::Birthday] ); + list.append( mapIdToStr[Qtopia::Anniversary] ); + list.append( mapIdToStr[Qtopia::Nickname] ); + list.append( mapIdToStr[Qtopia::Children] ); + + if (sorted) list.sort(); + return list; +} + + +/*! + \internal + Returns a translated list of phone field names for a contact. +*/ +QStringList OContactFields::trphonefields( bool sorted ) +{ + QStringList list; + QMap<int, QString> mapIdToStr = idToTrFields(); + + list.append( mapIdToStr[Qtopia::BusinessPhone] ); + list.append( mapIdToStr[Qtopia::BusinessFax] ); + list.append( mapIdToStr[Qtopia::BusinessMobile] ); + list.append( mapIdToStr[Qtopia::BusinessPager] ); + list.append( mapIdToStr[Qtopia::BusinessWebPage] ); + + list.append( mapIdToStr[Qtopia::DefaultEmail] ); + list.append( mapIdToStr[Qtopia::Emails] ); + + list.append( mapIdToStr[Qtopia::HomePhone] ); + list.append( mapIdToStr[Qtopia::HomeFax] ); + list.append( mapIdToStr[Qtopia::HomeMobile] ); + // list.append( mapIdToStr[Qtopia::HomePager] ); + list.append( mapIdToStr[Qtopia::HomeWebPage] ); + + if (sorted) list.sort(); + + return list; +} + + +/*! + \internal + Returns a list of phone field names for a contact. +*/ +QStringList OContactFields::untrphonefields( bool sorted ) +{ + QStringList list; + QMap<int, QString> mapIdToStr = idToUntrFields(); + + list.append( mapIdToStr[ Qtopia::BusinessPhone ] ); + list.append( mapIdToStr[ Qtopia::BusinessFax ] ); + list.append( mapIdToStr[ Qtopia::BusinessMobile ] ); + list.append( mapIdToStr[ Qtopia::BusinessPager ] ); + list.append( mapIdToStr[ Qtopia::BusinessWebPage ] ); + + list.append( mapIdToStr[ Qtopia::DefaultEmail ] ); + list.append( mapIdToStr[ Qtopia::Emails ] ); + + list.append( mapIdToStr[ Qtopia::HomePhone ] ); + list.append( mapIdToStr[ Qtopia::HomeFax ] ); + list.append( mapIdToStr[ Qtopia::HomeMobile ] ); + //list.append( mapIdToStr[Qtopia::HomePager] ); + list.append( mapIdToStr[Qtopia::HomeWebPage] ); + + if (sorted) list.sort(); + + return list; +} + + +/*! + \internal + Returns a translated list of field names for a contact. +*/ +QStringList OContactFields::trfields( bool sorted ) +{ + QStringList list; + QMap<int, QString> mapIdToStr = idToTrFields(); + + list.append( mapIdToStr[Qtopia::Title]); + list.append( mapIdToStr[Qtopia::FirstName] ); + list.append( mapIdToStr[Qtopia::MiddleName] ); + list.append( mapIdToStr[Qtopia::LastName] ); + list.append( mapIdToStr[Qtopia::Suffix] ); + list.append( mapIdToStr[Qtopia::FileAs] ); + + list.append( mapIdToStr[Qtopia::JobTitle] ); + list.append( mapIdToStr[Qtopia::Department] ); + list.append( mapIdToStr[Qtopia::Company] ); + + list += trphonefields( sorted ); + + list.append( mapIdToStr[Qtopia::BusinessStreet] ); + list.append( mapIdToStr[Qtopia::BusinessCity] ); + list.append( mapIdToStr[Qtopia::BusinessState] ); + list.append( mapIdToStr[Qtopia::BusinessZip] ); + list.append( mapIdToStr[Qtopia::BusinessCountry] ); + + list.append( mapIdToStr[Qtopia::HomeStreet] ); + list.append( mapIdToStr[Qtopia::HomeCity] ); + list.append( mapIdToStr[Qtopia::HomeState] ); + list.append( mapIdToStr[Qtopia::HomeZip] ); + list.append( mapIdToStr[Qtopia::HomeCountry] ); + + list += trdetailsfields( sorted ); + + list.append( mapIdToStr[Qtopia::Notes] ); + list.append( mapIdToStr[Qtopia::Groups] ); + + if (sorted) list.sort(); + + return list; +} + +/*! + \internal + Returns an untranslated list of field names for a contact. +*/ +QStringList OContactFields::untrfields( bool sorted ) +{ + QStringList list; + QMap<int, QString> mapIdToStr = idToUntrFields(); + + list.append( mapIdToStr[ Qtopia::Title ] ); + list.append( mapIdToStr[ Qtopia::FirstName ] ); + list.append( mapIdToStr[ Qtopia::MiddleName ] ); + list.append( mapIdToStr[ Qtopia::LastName ] ); + list.append( mapIdToStr[ Qtopia::Suffix ] ); + list.append( mapIdToStr[ Qtopia::FileAs ] ); + + list.append( mapIdToStr[ Qtopia::JobTitle ] ); + list.append( mapIdToStr[ Qtopia::Department ] ); + list.append( mapIdToStr[ Qtopia::Company ] ); + + list += untrphonefields( sorted ); + + list.append( mapIdToStr[ Qtopia::BusinessStreet ] ); + list.append( mapIdToStr[ Qtopia::BusinessCity ] ); + list.append( mapIdToStr[ Qtopia::BusinessState ] ); + list.append( mapIdToStr[ Qtopia::BusinessZip ] ); + list.append( mapIdToStr[ Qtopia::BusinessCountry ] ); + + list.append( mapIdToStr[ Qtopia::HomeStreet ] ); + list.append( mapIdToStr[ Qtopia::HomeCity ] ); + list.append( mapIdToStr[ Qtopia::HomeState ] ); + list.append( mapIdToStr[ Qtopia::HomeZip ] ); + list.append( mapIdToStr[ Qtopia::HomeCountry ] ); + + list += untrdetailsfields( sorted ); + + list.append( mapIdToStr[ Qtopia::Notes ] ); + list.append( mapIdToStr[ Qtopia::Groups ] ); + + if (sorted) list.sort(); + + return list; +} +QMap<int, QString> OContactFields::idToTrFields() +{ + QMap<int, QString> ret_map; + + ret_map.insert( Qtopia::Title, QObject::tr( "Name Title") ); + ret_map.insert( Qtopia::FirstName, QObject::tr( "First Name" ) ); + ret_map.insert( Qtopia::MiddleName, QObject::tr( "Middle Name" ) ); + ret_map.insert( Qtopia::LastName, QObject::tr( "Last Name" ) ); + ret_map.insert( Qtopia::Suffix, QObject::tr( "Suffix" )); + ret_map.insert( Qtopia::FileAs, QObject::tr( "File As" ) ); + + ret_map.insert( Qtopia::JobTitle, QObject::tr( "Job Title" ) ); + ret_map.insert( Qtopia::Department, QObject::tr( "Department" ) ); + ret_map.insert( Qtopia::Company, QObject::tr( "Company" ) ); + ret_map.insert( Qtopia::BusinessPhone, QObject::tr( "Business Phone" ) ); + ret_map.insert( Qtopia::BusinessFax, QObject::tr( "Business Fax" ) ); + ret_map.insert( Qtopia::BusinessMobile, QObject::tr( "Business Mobile" )); + + // email + ret_map.insert( Qtopia::DefaultEmail, QObject::tr( "Default Email" ) ); + ret_map.insert( Qtopia::Emails, QObject::tr( "Emails" ) ); + + ret_map.insert( Qtopia::HomePhone, QObject::tr( "Home Phone" ) ); + ret_map.insert( Qtopia::HomeFax, QObject::tr( "Home Fax" ) ); + ret_map.insert( Qtopia::HomeMobile, QObject::tr( "Home Mobile" ) ); + + // business + ret_map.insert( Qtopia::BusinessStreet, QObject::tr( "Business Street" ) ); + ret_map.insert( Qtopia::BusinessCity, QObject::tr( "Business City" ) ); + ret_map.insert( Qtopia::BusinessState, QObject::tr( "Business State" ) ); + ret_map.insert( Qtopia::BusinessZip, QObject::tr( "Business Zip" ) ); + ret_map.insert( Qtopia::BusinessCountry, QObject::tr( "Business Country" ) ); + ret_map.insert( Qtopia::BusinessPager, QObject::tr( "Business Pager" ) ); + ret_map.insert( Qtopia::BusinessWebPage, QObject::tr( "Business WebPage" ) ); + + ret_map.insert( Qtopia::Office, QObject::tr( "Office" ) ); + ret_map.insert( Qtopia::Profession, QObject::tr( "Profession" ) ); + ret_map.insert( Qtopia::Assistant, QObject::tr( "Assistant" ) ); + ret_map.insert( Qtopia::Manager, QObject::tr( "Manager" ) ); + + // home + ret_map.insert( Qtopia::HomeStreet, QObject::tr( "Home Street" ) ); + ret_map.insert( Qtopia::HomeCity, QObject::tr( "Home City" ) ); + ret_map.insert( Qtopia::HomeState, QObject::tr( "Home State" ) ); + ret_map.insert( Qtopia::HomeZip, QObject::tr( "Home Zip" ) ); + ret_map.insert( Qtopia::HomeCountry, QObject::tr( "Home Country" ) ); + ret_map.insert( Qtopia::HomeWebPage, QObject::tr( "Home Web Page" ) ); + + //personal + ret_map.insert( Qtopia::Spouse, QObject::tr( "Spouse" ) ); + ret_map.insert( Qtopia::Gender, QObject::tr( "Gender" ) ); + ret_map.insert( Qtopia::Birthday, QObject::tr( "Birthday" ) ); + ret_map.insert( Qtopia::Anniversary, QObject::tr( "Anniversary" ) ); + ret_map.insert( Qtopia::Nickname, QObject::tr( "Nickname" ) ); + ret_map.insert( Qtopia::Children, QObject::tr( "Children" ) ); + + // other + ret_map.insert( Qtopia::Notes, QObject::tr( "Notes" ) ); + + + return ret_map; +} + +QMap<int, QString> OContactFields::idToUntrFields() +{ + QMap<int, QString> ret_map; + + ret_map.insert( Qtopia::Title, "Name Title" ); + ret_map.insert( Qtopia::FirstName, "First Name" ); + ret_map.insert( Qtopia::MiddleName, "Middle Name" ); + ret_map.insert( Qtopia::LastName, "Last Name" ); + ret_map.insert( Qtopia::Suffix, "Suffix" ); + ret_map.insert( Qtopia::FileAs, "File As" ); + + ret_map.insert( Qtopia::JobTitle, "Job Title" ); + ret_map.insert( Qtopia::Department, "Department" ); + ret_map.insert( Qtopia::Company, "Company" ); + ret_map.insert( Qtopia::BusinessPhone, "Business Phone" ); + ret_map.insert( Qtopia::BusinessFax, "Business Fax" ); + ret_map.insert( Qtopia::BusinessMobile, "Business Mobile" ); + + // email + ret_map.insert( Qtopia::DefaultEmail, "Default Email" ); + ret_map.insert( Qtopia::Emails, "Emails" ); + + ret_map.insert( Qtopia::HomePhone, "Home Phone" ); + ret_map.insert( Qtopia::HomeFax, "Home Fax" ); + ret_map.insert( Qtopia::HomeMobile, "Home Mobile" ); + + // business + ret_map.insert( Qtopia::BusinessStreet, "Business Street" ); + ret_map.insert( Qtopia::BusinessCity, "Business City" ); + ret_map.insert( Qtopia::BusinessState, "Business State" ); + ret_map.insert( Qtopia::BusinessZip, "Business Zip" ); + ret_map.insert( Qtopia::BusinessCountry, "Business Country" ); + ret_map.insert( Qtopia::BusinessPager, "Business Pager" ); + ret_map.insert( Qtopia::BusinessWebPage, "Business WebPage" ); + + ret_map.insert( Qtopia::Office, "Office" ); + ret_map.insert( Qtopia::Profession, "Profession" ); + ret_map.insert( Qtopia::Assistant, "Assistant" ); + ret_map.insert( Qtopia::Manager, "Manager" ); + + // home + ret_map.insert( Qtopia::HomeStreet, "Home Street" ); + ret_map.insert( Qtopia::HomeCity, "Home City" ); + ret_map.insert( Qtopia::HomeState, "Home State" ); + ret_map.insert( Qtopia::HomeZip, "Home Zip" ); + ret_map.insert( Qtopia::HomeCountry, "Home Country" ); + ret_map.insert( Qtopia::HomeWebPage, "Home Web Page" ); + + //personal + ret_map.insert( Qtopia::Spouse, "Spouse" ); + ret_map.insert( Qtopia::Gender, "Gender" ); + ret_map.insert( Qtopia::Birthday, "Birthday" ); + ret_map.insert( Qtopia::Anniversary, "Anniversary" ); + ret_map.insert( Qtopia::Nickname, "Nickname" ); + ret_map.insert( Qtopia::Children, "Children" ); + + // other + ret_map.insert( Qtopia::Notes, "Notes" ); + + + return ret_map; +} + +QMap<QString, int> OContactFields::trFieldsToId() +{ + QMap<int, QString> idtostr = idToTrFields(); + QMap<QString, int> ret_map; + + + QMap<int, QString>::Iterator it; + for( it = idtostr.begin(); it != idtostr.end(); ++it ) + ret_map.insert( *it, it.key() ); + + + return ret_map; +} + +QMap<QString, int> OContactFields::untrFieldsToId() +{ + QMap<int, QString> idtostr = idToUntrFields(); + QMap<QString, int> ret_map; + + + QMap<int, QString>::Iterator it; + for( it = idtostr.begin(); it != idtostr.end(); ++it ) + ret_map.insert( *it, it.key() ); + + + return ret_map; +} + + +OContactFields::OContactFields(): + fieldOrder( DEFAULT_FIELD_ORDER ), + changedFieldOrder( false ) +{ + // Get the global field order from the config file and + // use it as a start pattern + Config cfg ( "AddressBook" ); + cfg.setGroup( "ContactFieldOrder" ); + globalFieldOrder = cfg.readEntry( "General", DEFAULT_FIELD_ORDER ); +} + +OContactFields::~OContactFields(){ + + // We will store the fieldorder into the config file + // to reuse it for the future.. + if ( changedFieldOrder ){ + Config cfg ( "AddressBook" ); + cfg.setGroup( "ContactFieldOrder" ); + cfg.writeEntry( "General", globalFieldOrder ); + } +} + + + +void OContactFields::saveToRecord( OContact &cnt ){ + + qDebug("ocontactfields saveToRecord: >%s<",fieldOrder.latin1()); + + // Store fieldorder into this contact. + cnt.setCustomField( CONTACT_FIELD_ORDER_NAME, fieldOrder ); + + globalFieldOrder = fieldOrder; + changedFieldOrder = true; + +} + +void OContactFields::loadFromRecord( const OContact &cnt ){ + qDebug("ocontactfields loadFromRecord"); + qDebug("loading >%s<",cnt.fullName().latin1()); + + // Get fieldorder for this contact. If none is defined, + // we will use the global one from the config file.. + + fieldOrder = cnt.customField( CONTACT_FIELD_ORDER_NAME ); + + qDebug("fieldOrder from contact>%s<",fieldOrder.latin1()); + + if (fieldOrder.isEmpty()){ + fieldOrder = globalFieldOrder; + } + + + qDebug("effective fieldOrder in loadFromRecord >%s<",fieldOrder.latin1()); +} + +void OContactFields::setFieldOrder( int num, int index ){ + qDebug("qcontactfields setfieldorder pos %i -> %i",num,index); + + fieldOrder[num] = QString::number( index, 16 )[0]; + + // We will store this new fieldorder globally to + // remember it for contacts which have none + globalFieldOrder = fieldOrder; + changedFieldOrder = true; + + qDebug("fieldOrder >%s<",fieldOrder.latin1()); +} + +int OContactFields::getFieldOrder( int num, int defIndex ){ + qDebug("ocontactfields getFieldOrder"); + qDebug("fieldOrder >%s<",fieldOrder.latin1()); + + // Get index of combo as char.. + QChar poschar = fieldOrder[num]; + + bool ok; + int ret = 0; + // Convert char to number.. + if ( !( poschar == QChar::null ) ) + ret = QString( poschar ).toInt(&ok, 16); + else + ok = false; + + // Return default value if index for + // num was not set or if anything else happened.. + if ( !ok ) ret = defIndex; + + qDebug("returning >%i<",ret); + + return ret; + +} diff --git a/libopie2/opiepim/ocontactfields.h b/libopie2/opiepim/ocontactfields.h new file mode 100644 index 0000000..9f6171b --- a/dev/null +++ b/libopie2/opiepim/ocontactfields.h @@ -0,0 +1,60 @@ +#ifndef OPIE_CONTACTS_FIELDS +#define OPIE_CONTACTS_FIELDS + +class QStringList; + +#include <qmap.h> +#include <qstring.h> +#include <opie/ocontact.h> + +#define CONTACT_FIELD_ORDER_NAME "opie-contactfield-order" +#define DEFAULT_FIELD_ORDER "__________" + +class OContactFields{ + + public: + OContactFields(); + ~OContactFields(); + /** Set the index for combo boxes. + * Sets the <b>index</b> of combo <b>num</b>. + * @param num selects the number of the combo + * @param index sets the index in the combo + */ + void setFieldOrder( int num, int index ); + + /** Get the index for combo boxes. + * Returns the index of combo <b>num</b> or defindex + * if none was defined.. + * @param num Selects the number of the combo + * @param defIndex will be returned if none was defined (either + * globally in the config file, nor by the contact which was used + * by loadFromRecord() ) + */ + int getFieldOrder( int num, int defIndex); + + /** Store fieldorder to contact. */ + void saveToRecord( OContact& ); + /** Get Fieldorder from contact. */ + void loadFromRecord( const OContact& ); + + private: + QString fieldOrder; + QString globalFieldOrder; + bool changedFieldOrder; + + public: + static QStringList trphonefields( bool sorted = true ); + static QStringList untrphonefields( bool sorted = true ); + static QStringList trdetailsfields( bool sorted = true ); + static QStringList untrdetailsfields( bool sorted = true ); + static QStringList trfields( bool sorted = true ); + static QStringList untrfields( bool sorted = true ); + + static QMap<int, QString> idToTrFields(); + static QMap<QString, int> trFieldsToId(); + static QMap<int, QString> idToUntrFields(); + static QMap<QString, int> untrFieldsToId(); + +}; + +#endif |