-rw-r--r-- | libopie2/opiepim/ChangeLog | 4 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend.h | 4 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp | 29 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_sql.h | 2 | ||||
-rw-r--r-- | libopie2/opiepim/backend/odatebookaccessbackend.cpp | 27 | ||||
-rw-r--r-- | libopie2/opiepim/backend/odatebookaccessbackend.h | 15 | ||||
-rw-r--r-- | libopie2/opiepim/backend/opimaccessbackend.h | 6 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccessbackend.cpp | 32 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccessbackend.h | 15 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccesssql.cpp | 34 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccesssql.h | 2 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccessxml.cpp | 5 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccessxml.h | 1 |
13 files changed, 134 insertions, 42 deletions
diff --git a/libopie2/opiepim/ChangeLog b/libopie2/opiepim/ChangeLog index 564e92a..2007744 100644 --- a/libopie2/opiepim/ChangeLog +++ b/libopie2/opiepim/ChangeLog @@ -1,21 +1,23 @@ 2004-12-28 Stefan Eilers <stefan@eilers-online.net> * Make improved query by example accessable via frontend - * Some API improvement + * Some API documentation improvement + * Cleanup of backend api.. + * Fixing bug #1501 2004-11-23 Stefan Eilers <stefan@eilers-online.net> * Implement fast and full featured version of sorted() for addressbook * Implement generic queryByExample for all Addressboook backends. It allows incremental search. * Update of API Documentation 2004-11-18 Holger Freyther <freyther@handhelds.org> * Every Access can give a set of Occurrences for a period or a datetime * QueryByExample, Find, Sort can be generically accessed by OPimBase pointer interface * OPimBackendOccurrence gets split up to OPimOccurrences by OPimTemplateBase * Add safeCast to various OPimRecords * Kill memleak in OPimTodo * Add SortVector implementations for OPimTodo and OPimContact 2004-??-?? The Opie Team <opie@handhelds.org> * Implemented some important modifications to allow to use OPimRecords as it is, without have to cast them. This makes it possible to write applications which handling pim data in a generic manner (see opimconvertion tool) (eilers)
\ No newline at end of file diff --git a/libopie2/opiepim/backend/ocontactaccessbackend.h b/libopie2/opiepim/backend/ocontactaccessbackend.h index ee6dbc2..27d70ab 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend.h @@ -1,111 +1,111 @@ /* 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) * */ #ifndef _OCONTACTACCESSBACKEND_H_ #define _OCONTACTACCESSBACKEND_H_ #include <opie2/opimcontact.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 OPimContactAccessBackend_VCard * @see OPimContactAccessBackend_XML */ class OPimContactAccessBackend: public OPimAccessBackend<OPimContact> { public: OPimContactAccessBackend(); /** * 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; /** * Return all possible settings. * @return All settings provided by the current backend * (i.e.: query_WildCards & query_IgnoreCase) */ - virtual const uint querySettings() const; + const uint querySettings() const; /** * Check whether settings are correct. * @return <i>true</i> if the given settings are correct and possible. */ - virtual bool hasQuerySettings (uint querySettings) const; + bool hasQuerySettings (uint querySettings) const; /** * Advanced search mechanism. */ UIDArray queryByExample( const UIDArray& uidlist, const OPimContact&, int settings, const QDateTime &d = QDateTime() ) const; /** * Slow and inefficent default implementation */ //@{ UIDArray sorted( const UIDArray&, bool asc, int, int, const QArray<int>& )const; OPimBackendOccurrence::List occurrences( const QDate&, const QDate& )const; //@} private: class Private; Private *d; }; } #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp index 9375f43..2368865 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp @@ -1,918 +1,933 @@ /* 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. */ #include "ocontactaccessbackend_sql.h" /* OPIE */ #include <opie2/opimcontact.h> #include <opie2/opimcontactfields.h> #include <opie2/opimdateconversion.h> #include <opie2/osqldriver.h> #include <opie2/osqlresult.h> #include <opie2/osqlmanager.h> #include <opie2/osqlquery.h> #include <opie2/odebug.h> #include <qpe/global.h> #include <qpe/recordfields.h> /* QT */ #include <qarray.h> #include <qdatetime.h> #include <qstringlist.h> using namespace Opie; using namespace Opie::DB; /* * 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 OPimContact to the table */ class InsertQuery : public OSQLQuery { public: InsertQuery(const OPimContact& ); ~InsertQuery(); QString query()const; private: OPimContact 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 UIDArray& ); ~FindQuery(); QString query()const; private: QString single()const; QString multi()const; UIDArray m_uids; int m_uid; }; /** * a find query for custom elements */ class FindCustomQuery : public OSQLQuery { public: FindCustomQuery(int uid); FindCustomQuery(const UIDArray& ); ~FindCustomQuery(); QString query()const; private: QString single()const; QString multi()const; UIDArray m_uids; int m_uid; }; // We using two 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; qu += "create table addressbook( uid PRIMARY KEY "; QStringList fieldList = OPimContactFields::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(10), priority INTEGER, value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );"; 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; qu += "select uid from addressbook"; return qu; } InsertQuery::InsertQuery( const OPimContact& contact ) : OSQLQuery(), m_contact( contact ) { } InsertQuery::~InsertQuery() { } /* * converts from a OPimContact to a query */ QString InsertQuery::query()const{ 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 = OPimContactFields::untrfields( false ); QMap<QString, int> translate = OPimContactFields::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: case Qtopia::Anniversary:{ QDate day; if ( id == Qtopia::Birthday ){ day = m_contact.birthday(); } else { day = m_contact.anniversary(); } // These entries should stored in a special format // year-month-day if ( day.isValid() ){ qu += QString(",\"%1-%2-%3\"") .arg( QString::number( day.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( day.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( day.day() ).rightJustify( 2, '0' ) ); } else { qu += ",\"\""; } } break; default: qu += QString( ",\"%1\"" ).arg( contactMap[id] ); } } qu += " );"; // Now add custom data.. int id = 0; 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() + "'," + "0" // Priority for future enhancements + ",'" + it.data() + "');"; } // qu += "commit;"; odebug << "add " << qu << "" << oendl; 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 UIDArray& ints) : OSQLQuery(), m_uids( ints ){ } FindQuery::~FindQuery() { } QString FindQuery::query()const{ - if ( m_uids.count() == 0 ) - return single(); - else - return multi(); + if ( m_uids.count() == 0 ) + return single(); + else + return multi(); } + + QString FindQuery::multi()const { QString qu = "select * 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.. odebug << "find query: " << qu << "" << oendl; return qu; } QString FindQuery::single()const{ QString qu = "select *"; qu += " from addressbook where uid = " + QString::number(m_uid); // owarn << "find query: " << qu << "" << oendl; return qu; } FindCustomQuery::FindCustomQuery(int uid) : OSQLQuery(), m_uid( uid ) { } FindCustomQuery::FindCustomQuery(const UIDArray& 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 { OPimContactAccessBackend_SQL::OPimContactAccessBackend_SQL ( const QString& /* appname */, const QString& filename ): OPimContactAccessBackend(), m_changed(false), m_driver( NULL ) { odebug << "C'tor OPimContactAccessBackend_SQL starts" << oendl; 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(); odebug << "C'tor OPimContactAccessBackend_SQL ends: " << t.elapsed() << " ms" << oendl; } OPimContactAccessBackend_SQL::~OPimContactAccessBackend_SQL () { if( m_driver ) delete m_driver; } bool OPimContactAccessBackend_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 OPimContactAccessBackend_SQL::reload() { return load(); } bool OPimContactAccessBackend_SQL::save() { return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) } void OPimContactAccessBackend_SQL::clear () { ClearQuery cle; OSQLResult res = m_driver->query( &cle ); reload(); } bool OPimContactAccessBackend_SQL::wasChangedExternally() { return false; } UIDArray OPimContactAccessBackend_SQL::allRecords() const { // FIXME: Think about cute handling of changed tables.. // Thus, we don't have to call update here... if ( m_changed ) ((OPimContactAccessBackend_SQL*)this)->update(); return m_uids; } bool OPimContactAccessBackend_SQL::add ( const OPimContact &newcontact ) { odebug << "add in contact SQL-Backend" << oendl; 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 OPimContactAccessBackend_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 OPimContactAccessBackend_SQL::replace ( const OPimContact &contact ) { if ( !remove( contact.uid() ) ) return false; return add( contact ); } OPimContact OPimContactAccessBackend_SQL::find ( int uid ) const { odebug << "OPimContactAccessBackend_SQL::find(" << uid << ")" << oendl; QTime t; t.start(); OPimContact retContact( requestNonCustom( uid ) ); retContact.setExtraMap( requestCustom( uid ) ); odebug << "OPimContactAccessBackend_SQL::find() needed: " << t.elapsed() << " ms" << oendl; return retContact; } OPimContact OPimContactAccessBackend_SQL::find( int uid, const UIDArray& queryUids, uint current, Frontend::CacheDirection direction ) const { odebug << "OPimContactAccessBackend_SQL::find( ..multi.. )" << oendl; odebug << "searching for " << uid << "" << oendl; QTime t; t.start(); uint numReadAhead = readAhead(); QArray<int> searchList( numReadAhead ); uint size =0; // Build an array with all elements which should be requested and cached // We will just request "numReadAhead" elements, starting from "current" position in // the list of many uids ! switch( direction ) { /* forward */ case Frontend::Forward: for ( uint i = current; i < queryUids.count() && size < numReadAhead; i++ ) { searchList[size] = queryUids[i]; size++; } break; /* reverse */ case Frontend::Reverse: for ( uint i = current; i != 0 && size < numReadAhead; i-- ) { searchList[size] = queryUids[i]; size++; } break; } //Shrink to real size.. searchList.resize( size ); OPimContact retContact( requestContactsAndCache( uid, searchList ) ); odebug << "OPimContactAccessBackend_SQL::find( ..multi.. ) needed: " << t.elapsed() << " ms" << oendl; return retContact; } -UIDArray OPimContactAccessBackend_SQL::queryByExample ( const OPimContact &query, int settings, +UIDArray OPimContactAccessBackend_SQL::queryByExample ( const UIDArray& uidlist, const OPimContact &query, int settings, const QDateTime& qd ) const { QString qu = "SELECT uid FROM addressbook WHERE"; + + // Just add uid's selection if we really try to search in a subset of all uids! Otherwise this would + // just take time and memory! + if ( uidlist.count() != m_uids.count() ) { + qu += " ("; + + for ( uint i = 0; i < uidlist.count(); i++ ) { + qu += " uid = " + QString::number( uidlist[i] ) + " OR"; + } + qu.remove( qu.length()-2, 2 ); // Hmmmm.. + qu += " ) AND "; + } + QString searchQuery =""; QDate startDate; if ( qd.isValid() ) startDate = qd.date(); else startDate = QDate::currentDate(); QMap<int, QString> queryFields = query.toMap(); QStringList fieldList = OPimContactFields::untrfields( false ); QMap<QString, int> translate = OPimContactFields::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]; QDate* endDate = 0l; if ( !queryStr.isEmpty() ){ // If something is alredy stored in the query, add an "AND" // to the end of the string to prepare for the next .. if ( !searchQuery.isEmpty() ) searchQuery += " AND"; // isAnyFieldSelected = true; switch( id ){ case Qtopia::Birthday: endDate = new QDate( query.birthday() ); // Fall through ! case Qtopia::Anniversary: if ( endDate == 0l ) endDate = new QDate( query.anniversary() ); if ( settings & OPimContactAccess::DateDiff ) { searchQuery += QString( " (\"%1\" <= '%2-%3-%4\' AND \"%5\" >= '%6-%7-%8')" ) .arg( *it ) .arg( QString::number( endDate->year() ).rightJustify( 4, '0' ) ) .arg( QString::number( endDate->month() ).rightJustify( 2, '0' ) ) .arg( QString::number( endDate->day() ).rightJustify( 2, '0' ) ) .arg( *it ) .arg( QString::number( startDate.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( startDate.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( startDate.day() ).rightJustify( 2, '0' ) ) ; } if ( settings & OPimContactAccess::DateYear ){ if ( settings & OPimContactAccess::DateDiff ) searchQuery += " AND"; searchQuery += QString( " (\"%1\" LIKE '%2-%')" ) .arg( *it ) .arg( QString::number( endDate->year() ).rightJustify( 4, '0' ) ); } if ( settings & OPimContactAccess::DateMonth ){ if ( ( settings & OPimContactAccess::DateDiff ) || ( settings & OPimContactAccess::DateYear ) ) searchQuery += " AND"; searchQuery += QString( " (\"%1\" LIKE '%-%2-%')" ) .arg( *it ) .arg( QString::number( endDate->month() ).rightJustify( 2, '0' ) ); } if ( settings & OPimContactAccess::DateDay ){ if ( ( settings & OPimContactAccess::DateDiff ) || ( settings & OPimContactAccess::DateYear ) || ( settings & OPimContactAccess::DateMonth ) ) searchQuery += " AND"; searchQuery += QString( " (\"%1\" LIKE '%-%-%2')" ) .arg( *it ) .arg( QString::number( endDate->day() ).rightJustify( 2, '0' ) ); } break; 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 & OPimContactAccess::IgnoreCase ) searchQuery += "(\"" + *it + "\"" + " LIKE " + "'" + queryStr.replace(QRegExp("\\*"),"%") + "'" + ")"; else searchQuery += "(\"" + *it + "\"" + " GLOB " + "'" + queryStr + "'" + ")"; } } delete endDate; } // Skip trailing "AND" // if ( isAnyFieldSelected ) // qu = qu.left( qu.length() - 4 ); qu += searchQuery; odebug << "queryByExample query: " << qu << "" << oendl; // Execute query and return the received uid's OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ UIDArray empty; return empty; } UIDArray list = extractUids( res ); return list; } UIDArray OPimContactAccessBackend_SQL::matchRegexp( const QRegExp &r ) const { #if 0 QArray<int> nix(0); return nix; #else QString qu = "SELECT uid FROM addressbook WHERE ("; QString searchlist; QStringList fieldList = OPimContactFields::untrfields( false ); // QMap<QString, int> translate = OPimContactFields::untrFieldsToId(); for ( QStringList::Iterator it = ++fieldList.begin(); it != fieldList.end(); ++it ){ if ( !searchlist.isEmpty() ) searchlist += " OR "; searchlist += " rlike(\""+ r.pattern() + "\",\"" + *it + "\") "; } qu = qu + searchlist + ")"; odebug << "query: " << qu << "" << oendl; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); return extractUids( res ); #endif } const uint OPimContactAccessBackend_SQL::querySettings() const { return OPimContactAccess::IgnoreCase | OPimContactAccess::WildCards | OPimContactAccess::DateDiff | OPimContactAccess::DateYear | OPimContactAccess::DateMonth | OPimContactAccess::DateDay ; } bool OPimContactAccessBackend_SQL::hasQuerySettings (uint querySettings) const { /* OPimContactAccess::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 & ( OPimContactAccess::IgnoreCase | OPimContactAccess::WildCards | OPimContactAccess::DateDiff | OPimContactAccess::DateYear | OPimContactAccess::DateMonth | OPimContactAccess::DateDay // | OPimContactAccess::RegExp // | OPimContactAccess::ExactMatch ) ) != querySettings ) return false; // Step 2: Check whether the given combinations are ok.. // IngoreCase alone is invalid if ( querySettings == OPimContactAccess::IgnoreCase ) return false; // WildCards, RegExp and ExactMatch should never used at the same time switch ( querySettings & ~( OPimContactAccess::IgnoreCase | OPimContactAccess::DateDiff | OPimContactAccess::DateYear | OPimContactAccess::DateMonth | OPimContactAccess::DateDay ) ){ case OPimContactAccess::RegExp: return ( true ); case OPimContactAccess::WildCards: return ( true ); case OPimContactAccess::ExactMatch: return ( true ); case 0: // one of the upper removed bits were set.. return ( true ); default: return ( false ); } } UIDArray OPimContactAccessBackend_SQL::sorted( const UIDArray& ar, bool asc, int sortOrder, int filter, const QArray<int>& categories )const { QTime t; t.start(); QString query = "SELECT uid FROM addressbook"; query += " WHERE ("; for ( uint i = 0; i < ar.count(); i++ ) { query += " uid = " + QString::number( ar[i] ) + " OR"; } query.remove( query.length()-2, 2 ); // Hmmmm.. query += ")"; if ( filter != OPimBase::FilterOff ){ if ( filter & OPimContactAccess::DoNotShowWithCategory ){ query += " AND ( \"Categories\" == '' )"; } else if ( filter & OPimBase::FilterCategory ){ query += " AND ("; for ( uint i = 0; i < categories.count(); i++ ){ query += "\"Categories\" LIKE"; query += QString( " '%" ) + QString::number( categories[i] ) + "%' OR"; } query.remove( query.length()-2, 2 ); // Hmmmm.. query += ")"; } if ( filter & OPimContactAccess::DoNotShowWithoutChildren ){ query += " AND ( \"Children\" != '' )"; } if ( filter & OPimContactAccess::DoNotShowWithoutAnniversary ){ query += " AND ( \"Anniversary\" != '' )"; } if ( filter & OPimContactAccess::DoNotShowWithoutBirthday ){ query += " AND ( \"Birthday\" != '' )"; } if ( filter & OPimContactAccess::DoNotShowWithoutHomeAddress ){ // Expect that no Street means no Address, too! (eilers) query += " AND ( \"Home Street\" != '' )"; } if ( filter & OPimContactAccess::DoNotShowWithoutBusinessAddress ){ // Expect that no Street means no Address, too! (eilers) query += " AND ( \"Business Street\" != '' )"; } } query += " ORDER BY"; switch ( sortOrder ) { case OPimContactAccess::SortSummary: query += " \"Notes\""; break; case OPimContactAccess::SortByCategory: query += " \"Categories\""; break; case OPimContactAccess::SortByDate: query += " \"\""; break; case OPimContactAccess::SortTitle: query += " \"Name Title\""; break; case OPimContactAccess::SortFirstName: query += " \"First Name\""; break; case OPimContactAccess::SortMiddleName: query += " \"Middle Name\""; break; case OPimContactAccess::SortLastName: query += " \"Last Name\""; break; case OPimContactAccess::SortFileAsName: query += " \"File As\""; break; case OPimContactAccess::SortSuffix: query += " \"Suffix\""; break; case OPimContactAccess::SortEmail: query += " \"Default Email\""; break; case OPimContactAccess::SortNickname: query += " \"Nickname\""; break; case OPimContactAccess::SortAnniversary: query += " \"Anniversary\""; break; case OPimContactAccess::SortBirthday: query += " \"Birthday\""; break; case OPimContactAccess::SortGender: query += " \"Gender\""; break; default: query += " \"Last Name\""; } if ( !asc ) query += " DESC"; odebug << "sorted query is: " << query << "" << oendl; OSQLRawQuery raw( query ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ UIDArray empty; return empty; } UIDArray list = extractUids( res ); odebug << "sorted needed " << t.elapsed() << " ms!" << oendl; return list; } void OPimContactAccessBackend_SQL::update() { odebug << "Update starts" << oendl; 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; odebug << "Update ends " << t.elapsed() << " ms" << oendl; } UIDArray OPimContactAccessBackend_SQL::extractUids( OSQLResult& res ) const { odebug << "extractUids" << oendl; QTime t; t.start(); OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it; UIDArray ints(list.count() ); odebug << " count = " << list.count() << "" << oendl; int i = 0; for (it = list.begin(); it != list.end(); ++it ) { ints[i] = (*it).data("uid").toInt(); i++; } odebug << "extractUids ready: count2 = " << i << " needs " << t.elapsed() << " ms" << oendl; return ints; } QMap<int, QString> OPimContactAccessBackend_SQL::requestNonCustom( int uid ) const { QTime t; t.start(); int t2needed = 0; int t3needed = 0; QTime t2; t2.start(); FindQuery query( uid ); OSQLResult res_noncustom = m_driver->query( &query ); t2needed = t2.elapsed(); diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.h b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h index 299c175..1cf1185 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h @@ -1,115 +1,115 @@ /* 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. */ #ifndef _OPimContactAccessBackend_SQL_ #define _OPimContactAccessBackend_SQL_ #include <opie2/ocontactaccessbackend.h> #include <opie2/ocontactaccess.h> #include <qlist.h> #include <qdict.h> /* aren't in namespace Opie yet - alwin */ namespace Opie { namespace DB { 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 OPimContact. * @see OPimAccessBackend for more information of available methods */ class OPimContactAccessBackend_SQL : public OPimContactAccessBackend { public: OPimContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null ); ~OPimContactAccessBackend_SQL (); bool save(); bool load (); void clear (); bool wasChangedExternally(); UIDArray allRecords() const; OPimContact find( int uid ) const; OPimContact find( int uid, const UIDArray& items, uint cur, Frontend::CacheDirection ) const; - UIDArray queryByExample ( const OPimContact &query, int settings, + UIDArray queryByExample ( const UIDArray& uidlist, const OPimContact &query, int settings, const QDateTime& d ) const; UIDArray matchRegexp( const QRegExp &r ) const; const uint querySettings() const; bool hasQuerySettings (uint querySettings) const; UIDArray sorted( const UIDArray& ar, bool asc, int sortOrder, int filter, const QArray<int>& categories)const; bool add ( const OPimContact &newcontact ); bool replace ( const OPimContact &contact ); bool remove ( int uid ); bool reload(); private: UIDArray extractUids( Opie::DB::OSQLResult& res ) const; QMap<int, QString> requestNonCustom( int uid ) const; QMap<QString, QString> requestCustom( int uid ) const; QMap<int, QString> fillNonCustomMap( const Opie::DB::OSQLResultItem& resultItem ) const; OPimContact requestContactsAndCache( int uid, const QArray<int>& cachelist ) const; void update(); protected: bool m_changed; QString m_fileName; UIDArray m_uids; Opie::DB::OSQLDriver* m_driver; }; } #endif diff --git a/libopie2/opiepim/backend/odatebookaccessbackend.cpp b/libopie2/opiepim/backend/odatebookaccessbackend.cpp index 73c7059..e44912a 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend.cpp @@ -1,164 +1,181 @@ /* 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 <opie2/opimrecurrence.h> #include <opie2/odatebookaccessbackend.h> using namespace Opie; namespace { /* a small helper to get all NonRepeating events for a range of time */ void events( OPimBackendOccurrence::List& tmpList, const OPimEvent::ValueList& events, const QDate& from, const QDate& to ) { QDateTime dtStart, dtEnd; for ( OPimEvent::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 ) { OPimBackendOccurrence eff( dtStart, dtEnd, (*it).uid() );; tmpList.append( eff ); } } } void repeat( OPimBackendOccurrence::List& tmpList, const OPimEvent::ValueList& list, const QDate& from, const QDate& to ) { QDate repeat; for ( OPimEvent::ValueList::ConstIterator it = list.begin(); it != list.end(); ++it ) { int dur = (*it).startDateTime().date().daysTo( (*it).endDateTime().date() ); QDate itDate = from.addDays(-dur ); OPimRecurrence rec = (*it).recurrence(); if ( !rec.hasEndDate() || rec.endDate() > to ) { rec.setEndDate( to ); rec.setHasEndDate( true ); } QDateTime start, end; while (rec.nextOcurrence(itDate, repeat ) ) { if (repeat > to ) break; OPimEvent event = *it; start = QDateTime( repeat, event.startDateTime().time() ); end = QDateTime( repeat.addDays(dur), event.endDateTime().time() ); OPimBackendOccurrence eff(start, end, event.uid() ); tmpList.append( eff ); } } } } namespace Opie { ODateBookAccessBackend::ODateBookAccessBackend() : OPimAccessBackend<OPimEvent>() { } ODateBookAccessBackend::~ODateBookAccessBackend() { } OPimBackendOccurrence::List ODateBookAccessBackend::occurrences( const QDate& from, const QDate& to )const { OPimBackendOccurrence::List tmpList; events( tmpList, directNonRepeats(), from, to ); repeat( tmpList, directRawRepeats(),from,to ); return tmpList; } -OPimBackendOccurrence::List ODateBookAccessBackend::occurrences( const QDateTime& dt )const { + +OPimBackendOccurrence::List ODateBookAccessBackend::occurrences( const QDateTime& dt )const +{ OPimBackendOccurrence::List day = occurrences( dt.date(), dt.date() ); return filterOccurrences( day, dt ); } OPimBackendOccurrence::List ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDate& from, - const QDate& to )const { + const QDate& to )const +{ OPimBackendOccurrence::List tmpList; OPimEvent::ValueList list = directNonRepeats(); events( tmpList, list, from, to ); return tmpList; } -OPimBackendOccurrence::List ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt )const { +OPimBackendOccurrence::List ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt )const +{ OPimBackendOccurrence::List day = effectiveNonRepeatingEvents( dt.date(), dt.date() ); return filterOccurrences( day,dt ); } +const uint ODateBookAccessBackend::querySettings() const +{ + return 0; +} + +bool ODateBookAccessBackend::hasQuerySettings (uint querySettings) const +{ + return false; +} + + -UIDArray ODateBookAccessBackend::queryByExample( const OPimEvent&, int settings, - const QDateTime& d )const { +UIDArray ODateBookAccessBackend::queryByExample( const UIDArray& uidlist, const OPimEvent&, int settings, + const QDateTime& d )const +{ + qDebug( "Accessing ODateBookAccessBackend::queryByExample() which is not implemented!" ); return UIDArray(); } UIDArray ODateBookAccessBackend::sorted( const UIDArray&, bool asc, int, int, const QArray<int>& )const { return UIDArray(); } OPimBackendOccurrence::List ODateBookAccessBackend::filterOccurrences( const OPimBackendOccurrence::List dayList, const QDateTime& dt ) { OPimBackendOccurrence::List tmpList; OPimBackendOccurrence::List::ConstIterator it; for ( it = dayList.begin(); it != dayList.end(); ++it ) { OPimBackendOccurrence occ = *it; /* * Let us find occurrences that are 'now'! * If the dt.date() is on the same day as start or end of the Occurrence * check how near start/end are. * If it is in the middle of a multiday occurrence list it. * * We might want to 'lose' the sixty second offset and list * all Events which are active at that time. */ if ( dt.date() == occ.startDateTime().date() ) { if ( QABS( dt.time().secsTo( occ.startDateTime().time() ) ) < 60 ) tmpList.append( occ ); }else if ( dt.date() == occ.endDateTime().date() ) { if ( QABS( dt.time().secsTo( occ.endDateTime().time() ) ) < 60 ) tmpList.append( occ ); }else if ( dt.date() >= occ.startDateTime().date() && dt.date() >= occ.endDateTime().date() ) tmpList.append( occ ); } return tmpList; } } diff --git a/libopie2/opiepim/backend/odatebookaccessbackend.h b/libopie2/opiepim/backend/odatebookaccessbackend.h index 8927ca1..91f63aa 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend.h @@ -1,114 +1,127 @@ /* 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 <opie2/opimaccessbackend.h> #include <opie2/opimevent.h> namespace Opie { /** * This class is the interface to the storage of Events. * @see OPimAccessBackend * */ class ODateBookAccessBackend : public OPimAccessBackend<OPimEvent> { public: /** * c'tor without parameter */ ODateBookAccessBackend(); ~ODateBookAccessBackend(); /** * This method should return a list of UIDs containing * all repeating events. No filter should be applied * @return list of repeating events */ virtual UIDArray 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 UIDArray 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 OPimEvent::ValueList directNonRepeats()const = 0; /** * Same as above but return raw repeats! */ virtual OPimEvent::ValueList directRawRepeats()const = 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 OPimBackendOccurrence::List effectiveNonRepeatingEvents( const QDate& from, const QDate& to )const; /** * this is an overloaded member function * @see effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) */ virtual OPimBackendOccurrence::List effectiveNonRepeatingEvents( const QDateTime& start )const; /** * Common and probably inefficent implementation * for queryByExample, sorted * and occurrences */ //@{ - UIDArray queryByExample( const OPimEvent&, int settings, const QDateTime& d = QDateTime() )const; + /** + * Return all possible settings. + * @return All settings provided by the current backend + * (i.e.: query_WildCards & query_IgnoreCase) + */ + const uint querySettings() const; + + /** + * Check whether settings are correct. + * @return <i>true</i> if the given settings are correct and possible. + */ + bool hasQuerySettings (uint querySettings) const; + + UIDArray queryByExample( const UIDArray& uidlist, const OPimEvent&, int settings, const QDateTime& d = QDateTime() )const; UIDArray sorted( const UIDArray&, bool asc, int, int, const QArray<int>& )const; OPimBackendOccurrence::List occurrences( const QDate&, const QDate& end )const; OPimBackendOccurrence::List occurrences( const QDateTime& )const; //@} protected: static OPimBackendOccurrence::List filterOccurrences(const OPimBackendOccurrence::List, const QDateTime& time ); private: class Private; Private *d; }; } #endif diff --git a/libopie2/opiepim/backend/opimaccessbackend.h b/libopie2/opiepim/backend/opimaccessbackend.h index 7321758..6666fd6 100644 --- a/libopie2/opiepim/backend/opimaccessbackend.h +++ b/libopie2/opiepim/backend/opimaccessbackend.h @@ -1,445 +1,445 @@ /* 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 <opie2/opimtemplatebase.h> #include <opie2/opimrecord.h> #include <opie2/opimbackendoccurrence.h> namespace Opie { class OPimAccessBackendPrivate; /** * OPimAccessBackend is the Backend Interface to be used * by OTemplateBase based Frontends. * For efficency reasons and to support delayed loading * most of the Frontend functions can be implemented * by this backend. * This allows to utilise the best method on each backend. * For example we can use SQL queries instead of self made * query which is first more efficent and also uses less memory. */ template <class T = OPimRecord> class OPimAccessBackend { public: typedef OTemplateBase<T> Frontend; //@{ OPimAccessBackend(int access = 0); virtual ~OPimAccessBackend(); //@} //@{ virtual bool load() = 0; virtual bool reload() = 0; virtual bool save() = 0; virtual void clear() = 0; //@} //@{ // FIXME: Uncommented some of the abstract functions below. This should be removed as they are implemented in // all typespecifc backenends (eilers) /** * Return all possible settings for queryByExample() * @return All settings provided by the current backend * (i.e.: query_WildCards & query_IgnoreCase) * See implementation in the specific backends for contacts, todo and dates. */ - virtual const uint querySettings() const { return 0; } /* FIXME: Make Abstrakt !! = 0; */ + virtual const uint querySettings() const = 0; /** * Check whether settings are correct for queryByExample() * See implementation in the specific backends for OPimContactAccess, OPimTodoAccess and ODateBookAccess. * @return <i>true</i> if the given settings are correct and possible. */ - virtual bool hasQuerySettings (uint querySettings) const { return false; } /* FIXME: Make Abstrakt !! = 0; */ + virtual bool hasQuerySettings (uint querySettings) const = 0; //@} //@{ virtual UIDArray allRecords()const = 0; virtual UIDArray matchRegexp(const QRegExp &r) const; virtual UIDArray queryByExample( const UIDArray&, const T& t, - int settings, const QDateTime& d = QDateTime() )const { return UIDArray(); } /* FIXME: Make Abstrakt !! = 0; */ + int settings, const QDateTime& d = QDateTime() )const = 0; virtual UIDArray queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() )const; virtual UIDArray queryByExample( const OPimRecord* rec, int settings, const QDateTime& d = QDateTime() )const; virtual UIDArray sorted( const UIDArray&, bool asc, int sortOrder, int sortFilter, const QArray<int>& cats )const = 0; virtual UIDArray sorted( bool asc, int sortOrder, int sortFilter, const QArray<int>& cats )const; virtual OPimBackendOccurrence::List occurrences( const QDate& start, const QDate& end)const; virtual OPimBackendOccurrence::List occurrences( const QDateTime& dt )const; //@} //@{ virtual T find(UID uid )const = 0; virtual T find(UID uid, const QArray<UID>& items, uint current, typename Frontend::CacheDirection )const ; //@} //@{ virtual bool add( const T& t ) = 0; virtual bool remove( UID uid ) = 0; virtual bool replace( const T& t ) = 0; //@} void setFrontend( Frontend* front ); /** * set the read ahead count */ void setReadAhead( uint count ); protected: //@{ int access()const; void cache( const T& t )const; 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() { } /* * Slow but default matchRegexp Implementation * Create a Big Enough QArray and then iterate * over all Records and matchRegexp them. * At the end we will resize the array to the actual * number of items */ template <class T> UIDArray OPimAccessBackend<T>::matchRegexp( const QRegExp& reg )const { UIDArray all_rec = allRecords(); UIDArray result( all_rec.count() ); uint used_records = 0, all_rec_count = all_rec.count(); for ( uint i = 0; i < all_rec_count; ++i ) if (find( all_rec[i], all_rec, i, Frontend::Forward ).match( reg ) ) result[used_records++] = all_rec[i]; /* shrink to fit */ result.resize( used_records ); return result; } template <class T> UIDArray OPimAccessBackend<T>::queryByExample( const T& rec, int settings, const QDateTime& datetime )const { return queryByExample( allRecords(), rec, settings, datetime ); } template <class T> UIDArray OPimAccessBackend<T>::queryByExample( const OPimRecord* rec, int settings, const QDateTime& datetime )const { T* tmp_rec = T::safeCast( rec ); UIDArray ar; if ( tmp_rec ) ar = queryByExample( *tmp_rec, settings, datetime ); return ar; } template <class T> UIDArray OPimAccessBackend<T>::sorted( bool asc, int order, int filter, const QArray<int>& cats )const { return sorted( allRecords(), asc, order, filter, cats ); } template<class T> OPimBackendOccurrence::List OPimAccessBackend<T>::occurrences( const QDate&, const QDate& )const { return OPimBackendOccurrence::List(); } template<class T> OPimBackendOccurrence::List OPimAccessBackend<T>::occurrences( const QDateTime& dt )const { QDate date = dt.date(); return occurrences( date, date ); } 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{ qDebug( "*** Lookahead feature not supported. Fallback to default find!!" ); 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; } } /** * \fn template <class T> OPimAccessBackend<T>::OPimAccessBackend(int hint ) * @param hint The access hint from the frontend */ /** * \fn template <class T> bool OPimAccessBackend<T>::load() * Opens the DataBase and does necessary * initialisation of internal structures. * * @return true If the DataBase could be opened and * Information was successfully loaded */ /** * \fn template <class T> bool OPimAccessBackend<T>::reload() * Reinitialise the DataBase and merges the external changes * with your local changes. * * @return True if the DataBase was reloaded. * */ /** * \fn template <class T> bool OPimAccessBackend<T>::save() * * Save the changes to storage. In case of memory or * disk shortage, return false. * * * @return True if the DataBase could be saved to storage. */ /** * \fn template <class T> bool OPimAccessBackend<T>::clear() * Until a \sa save() changes shouldn't be comitted * * * @return True if the DataBase could be cleared * @todo Introduce a 'Commit' */ /** * \fn template <class T> QArray<UID> OPimAccessBackend<T>::allRecords()const * Return an array of all available uids in the loaded * DataBase. * @see load */ /** * \fn template <class T> QArray<UID> OPimAccessBackend<T>::matchRegexp(const QRegExp& r)const * Return a List of records that match the regex \par r. * * @param r The QRegExp to match. */ /** * \fn template <class T> QArray<UID> OPimAccessBackend<T>::queryByExample(const T& t, int settings, const QDateTime& d = QDateTime() ) * * Implement QueryByExample. An Example record is filled and with the * settings and QDateTime it is determined how the query should be executed. * Return a list of UIDs that match the Example * * @param t The Example record * @param settings Gives * */ /** * \fn template<class T> QArray<UID> OPimAccessBackend<T>::sorted(const QArray<UID>& ids, bool asc, int sortOrder, int sortFilter, int cat) * \brief Sort the List of records according to the preference * * Implement sorting in your backend. The default implementation is * to return the list as it was passed. * The default Backend Implementation should do unaccelerated filtering * * * @param ids The Records to sort * @param asc Sort ascending or descending * @param sortOrder * @param sortFilter Sort filter * @param cat The Category to include */ /** * \fn template <class T> T OPimAccessBackend<T>::find(UID uid)const * \brief Find the Record with the UID * * Find the UID in the database and return the record. * @param uid The uid to be searched for * @return The record or an empty record (T.isEmpty()) * */ /** * \fn template <class T> T OPimAccessBackend<T>::find( UID uid, const QArray<UID>& items, uint current, typename Frontend::CacheDirection d)const * \brief find a Record and do a read ahead or read behind * * @param uid The UID to search for * @param items The list of items from where your search * @param current The index of \param uid * @param d The direction to search for * * @see find */ /** * \fn template<class T> bool OPimAccessBackend<T>::add(const T& t) * * \brief Add the record to the internal database * * If an record with the same t.uid() is already present internally * the behaviour is undefined but the state of the database * needs to be stable. * For modifying a record use \sa replace. * * * @return true if the record could be added or false if not * @todo Eilers your opinion on readd/replace */ /** * \fn template<class T> bool OPimAccessBackend<T>::remove(UID uid) * \brief Remove a record by its UID * * Remove the records with UID from the internal Database. * * @return True if the record could be removed. * */ /** * \fn template<class T> bool OPimAccessBackend<T>::replace(const T& t) * \brief Take this Record and replace the old version. * * Take \param t as the new record for t.uid(). It is not described * what happens if the record is not present in the database. * Normally the record is determined by the UID. * * @param t The record to use internally. */ /** * \fn template<class T> void OPimAccessBackend<T>::setFrontend( Frontend* fron) * \@aram fron The Frontend that uses this backend * * This function is called by the frontend and is used */ /** * \fn template<class T> void OPimAccessBackend<T>::setReadAhead(uint count) * \brief Set the number of items to Read-Ahead/Read-Behind * * @param count The number of records to read ahead */ /** * \fn template<class T> void OPimAccessBackend<T>::cache( const T& t)const * \brief Add the Record to the PIM Cache * * This will add the Record to the PIM cache, which is owned * by the FrontEnd. If no FrontEnd is available the item will * not be cached. * * * @param t The Item to be added to the Cache */ /** * \fn template<class T> void OPimAccessBackend<T>::setSaneCacheSize(int items) * \brief Give a hint on the number of too cached items * * Give the Frontend a hint on the number of items to be cached. Use * a prime number for best performance. * * @param items The number of items to be cached */ /** * \fn template<class T> uint OPimAccessBackend<T>::readAhead()const * \brief Return the number of Items to be ReadAhead * * @return The number of Items to read ahead/read behind */ /** * \fn template<class T> QArray<OPimBackendOccurence> OPimAccessBackend<T>::occurrences(const QDateTime& start,const QDateTime& end) * \brief Get a List of Occurrences for a period of time * * Return an Array of OPimBackendOccurence for a period of time. If start == end date * return only occurrences for the start date. If end is smaller the start date * the result is not defined. You could switch dates or return an empty list. * * @return Return an array of OPimBackendOccurence for the period specified by the parameters * @param start The start of the period. * @param end The end of the period. * */ #endif diff --git a/libopie2/opiepim/backend/otodoaccessbackend.cpp b/libopie2/opiepim/backend/otodoaccessbackend.cpp index 5f86be9..f979976 100644 --- a/libopie2/opiepim/backend/otodoaccessbackend.cpp +++ b/libopie2/opiepim/backend/otodoaccessbackend.cpp @@ -1,155 +1,181 @@ /* 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 <opie2/otodoaccessbackend.h> #include <opie2/private/opimtodosortvector.h> #include <opie2/otodoaccess.h> #include <qintdict.h> namespace Opie { OPimTodoAccessBackend::OPimTodoAccessBackend() : OPimAccessBackend<OPimTodo>() { } OPimTodoAccessBackend::~OPimTodoAccessBackend() { } -UIDArray OPimTodoAccessBackend::queryByExample( const OPimTodo&, int settings, - const QDateTime& d)const { - return UIDArray(); +const uint OPimTodoAccessBackend::querySettings() const +{ + return 0; +} + +bool OPimTodoAccessBackend::hasQuerySettings (uint querySettings) const +{ + return false; +} + + +UIDArray OPimTodoAccessBackend::queryByExample( const UIDArray& uidlist, const OPimTodo& query, int settings, + const QDateTime& endperiod )const +{ + qDebug( "Accessing OPimTodoAccessBackend::queryByExample() which is not implemented!" ); + return UIDArray(); + +// odebug << "Using Unaccelerated OPimContactAccessBackend implementation of queryByExample!" << oendl; + +// UIDArray m_currentQuery( uid_array.count() ); +// uint arraycounter = 0; + +// for( uint it = 0; it < uid_array.count(); ++it ){ +// /* Search all fields and compare them with query object. Store them into list +// * if all fields matches. +// */ +// } + + } UIDArray OPimTodoAccessBackend::sorted( const UIDArray& events, bool asc, int sortOrder, int sortFilter, const QArray<int>& categories )const { odebug << "Using Unaccelerated TodoList sorted Implementation" << oendl; Internal::OPimTodoSortVector vector(events.count(), asc,sortOrder ); int item = 0; bool bCat = sortFilter & OPimTodoAccess::FilterCategory ? true : false; bool bOnly = sortFilter & OPimTodoAccess::OnlyOverDue ? true : false; bool comp = sortFilter & OPimTodoAccess::DoNotShowCompleted ? true : false; bool catPassed = false; int cat; for ( uint i = 0; i < events.count(); ++i ) { OPimTodo todo = find( events[i], events, i, Frontend::Forward ); if ( todo.isEmpty() ) continue; /* show category */ /* -1 == unfiled */ catPassed = false; for ( uint cat_nu = 0; cat_nu < categories.count(); ++cat_nu ) { cat = categories[cat_nu]; if ( bCat && cat == -1 ) { if(!todo.categories().isEmpty() ) continue; } else if ( bCat && cat != 0) if (!todo.categories().contains( cat ) ) continue; catPassed = true; break; } /* * If none of the Categories matched * continue */ if ( !catPassed ) continue; if ( !todo.isOverdue() && bOnly ) continue; if (todo.isCompleted() && comp ) continue; vector.insert(item++, todo ); } vector.resize( item ); /* sort it now */ vector.sort(); /* now get the uids */ UIDArray array( vector.count() ); for (uint i= 0; i < vector.count(); i++ ) array[i] = vector.uidAt( i ); return array; } OPimBackendOccurrence::List OPimTodoAccessBackend::occurrences( const QDate& start, const QDate& end )const { OPimBackendOccurrence::List lst; UIDArray effective = effectiveToDos( start, end, false ); UIDArray overdue = overDue(); uint count = effective.count(); int uid; QIntDict<int> hash; hash.setAutoDelete( true ); OPimTodo todo; for ( uint i = 0; i < count; ++i ) { uid = effective[i]; todo = find( uid, effective, i, Frontend::Forward ); /* * If isOverdue but in the 'normal' range we will fill * the hash so we won't have duplicates in OPimBackendOccurrence */ if ( todo.isOverdue() ) hash.insert( uid, new int(6) ); OPimBackendOccurrence oc = todo.hasStartDate() ? OPimBackendOccurrence( todo.startDate(), todo.dueDate(), uid ) : OPimBackendOccurrence( todo.dueDate(), uid, QString::null ); oc.setSummary( todo.summary() ); lst.append( oc ); } /* * Create the OverDue items but skip * the already handled Records */ if ( !overdue.isEmpty() ) { QDate today = QDate::currentDate(); QDate dueDate = (start >= today && today <= end ) ? today : start; count = overdue.count(); for ( uint i = 0; i < count; ++i ) { uid = overdue[i]; if (!hash.find( uid ) ) continue; todo = find( uid, overdue, i, Frontend::Forward ); lst.append( OPimBackendOccurrence(dueDate, uid, todo.summary() ) ); } } return lst; } } diff --git a/libopie2/opiepim/backend/otodoaccessbackend.h b/libopie2/opiepim/backend/otodoaccessbackend.h index 66297bb..870ee57 100644 --- a/libopie2/opiepim/backend/otodoaccessbackend.h +++ b/libopie2/opiepim/backend/otodoaccessbackend.h @@ -1,79 +1,92 @@ /* 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 <opie2/opimtodo.h> #include <opie2/opimaccessbackend.h> namespace Opie { class OPimTodoAccessBackend : public OPimAccessBackend<OPimTodo> { public: OPimTodoAccessBackend(); ~OPimTodoAccessBackend(); virtual UIDArray effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates )const = 0; virtual UIDArray overDue()const = 0; virtual void removeAllCompleted() = 0; /** * Common and probably inefficent implementation * for queryByExample, matchRegexp, sorted * and occurrences */ //@{ - UIDArray queryByExample( const OPimTodo&, int settings, const QDateTime& d = QDateTime() )const; + /** + * Return all possible settings. + * @return All settings provided by the current backend + * (i.e.: query_WildCards & query_IgnoreCase) + */ + const uint querySettings() const; + + /** + * Check whether settings are correct. + * @return <i>true</i> if the given settings are correct and possible. + */ + bool hasQuerySettings (uint querySettings) const; + + UIDArray queryByExample( const UIDArray& uidlist, const OPimTodo& query, int settings, const QDateTime& endperiod = QDateTime() )const; UIDArray sorted( const UIDArray&, bool asc, int, int, const QArray<int>& )const; OPimBackendOccurrence::List occurrences( const QDate&, const QDate& )const; //@} private: class Private; Private *d; }; } /** * \fn Opie::OPimBackendOccurrence::List Opie::OPimTodoAccessBackend::occurrences(const QDate& start,const QDate& end)const * \brief Return occurrences for a period of time * * This method will return the 'effective' Todos and also * 'Overdue' Todos. Overdues will be shown on the 'current' * day if it is in the range or on \par start. If the overdue * is inside the 'Effective Todos' we will skip the * special overdue handling. * * */ #endif diff --git a/libopie2/opiepim/backend/otodoaccesssql.cpp b/libopie2/opiepim/backend/otodoaccesssql.cpp index 2bcab29..70e40e4 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.cpp +++ b/libopie2/opiepim/backend/otodoaccesssql.cpp @@ -1,830 +1,840 @@ /* This file is part of the Opie Project Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) Copyright (C) Holger Freyther (zecke@handhelds.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. */ /* OPIE */ #include <opie2/osqldriver.h> #include <opie2/osqlresult.h> #include <opie2/osqlmanager.h> #include <opie2/osqlquery.h> #include <opie2/otodoaccesssql.h> #include <opie2/opimstate.h> #include <opie2/opimnotifymanager.h> #include <opie2/opimrecurrence.h> #include <opie2/odebug.h> #include <qpe/global.h> /* QT */ #include <qdatetime.h> #include <qmap.h> #include <qstring.h> using namespace Opie::DB; 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 OPimTodo to the table */ class InsertQuery : public OSQLQuery { public: InsertQuery(const OPimTodo& ); ~InsertQuery(); QString query()const; private: OPimTodo 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; }; /** * 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; }; 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 OPimRecurrence.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), priority INTEGER, 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 OPimTodo& todo ) : OSQLQuery(), m_todo( todo ) { } InsertQuery::~InsertQuery() { } /* * converts from a OPimTodo to a query * we leave out X-Ref + Maintainer * FIXME: Implement/Finish toMap()/fromMap() into OpimTodo to move the encoding * decoding stuff there.. (eilers) */ 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).rightJustify( 4, '0' ) + "-" + QString::number(month).rightJustify( 2, '0' ) + "-" + QString::number( day ).rightJustify( 2, '0' )+ "'" + "," + QString::number( m_todo.progress() ) + "," + QString::number( m_todo.state().state() ) + "," + "'" + recMap[ OPimRecurrence::RType ] + "'" + "," + "'" + recMap[ OPimRecurrence::RWeekdays ] + "'" + "," + "'" + recMap[ OPimRecurrence::RPosition ] + "'" + "," + "'" + recMap[ OPimRecurrence::RFreq ] + "'" + "," + "'" + recMap[ OPimRecurrence::RHasEndDate ] + "'" + "," + "'" + recMap[ OPimRecurrence::EndDate ] + "'" + "," + "'" + recMap[ OPimRecurrence::Created ] + "'" + "," + "'" + recMap[ OPimRecurrence::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).rightJustify( 4, '0' ) + "-" + QString::number(sMonth).rightJustify( 2, '0' ) + "-" + QString::number(sDay).rightJustify( 2, '0' )+ "'" + "," + "'" + QString::number(eYear).rightJustify( 4, '0' ) + "-" + QString::number(eMonth).rightJustify( 2, '0' ) + "-"+QString::number(eDay).rightJustify( 2, '0' ) + "'" + "); "; // Save custom Entries: int id = 0; id = 0; QMap<QString, QString> customMap = m_todo.toExtraMap(); for( QMap<QString, QString>::Iterator it = customMap.begin(); it != customMap.end(); ++it ){ qu += "insert into custom_data VALUES(" + QString::number( m_todo.uid() ) + "," + QString::number( id++ ) + ",'" + it.key() + "'," + "0" // Priority for future enhancements + ",'" + it.data() + "');"; } odebug << "add " << qu << "" << oendl; 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) + " ;"; - qu += "DELETE FROM custom_data WHERE uid = " + QString::number(m_uid); + qu += "DELETE FROM custom_data WHERE uid = " + QString::number(m_uid); return qu; } ClearQuery::ClearQuery() : OSQLQuery() {} ClearQuery::~ClearQuery() {} - QString ClearQuery::query()const { - QString qu = "drop table todolist"; - return qu; + QString ClearQuery::query()const + { + QString qu = "drop table todolist"; + return qu; } + FindQuery::FindQuery(int uid) - : OSQLQuery(), m_uid(uid ) { + : OSQLQuery(), m_uid(uid ) + { } + FindQuery::FindQuery(const QArray<int>& ints) - : OSQLQuery(), m_uids(ints){ + : OSQLQuery(), m_uids(ints) + { } - FindQuery::~FindQuery() { + + 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( QString::number( date.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( date.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( date.day() ) .rightJustify( 2, '0' ) ); 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( QString::number( m_start.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( m_start.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( m_start.day() ).rightJustify( 2, '0' ) ) .arg( QString::number( m_end.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( m_end.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( m_end.day() ).rightJustify( 2, '0' ) ); 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( QString::number( m_start.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( m_start.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( m_start.day() ).rightJustify( 2, '0' ) ) .arg( QString::number( m_end.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( m_end.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( m_end.day() ).rightJustify( 2, '0' ) ); return str; } FindCustomQuery::FindCustomQuery(int uid) : OSQLQuery(), m_uid( uid ) { } FindCustomQuery::FindCustomQuery(const QArray<int>& ints) : OSQLQuery(), m_uids( ints ){ } FindCustomQuery::~FindCustomQuery() { } QString FindCustomQuery::query()const{ return single(); // Multiple requests not supported ! } QString FindCustomQuery::single()const{ QString qu = "select uid, type, value from custom_data where uid = "; qu += QString::number(m_uid); return qu; } }; namespace Opie { OPimTodoAccessBackendSQL::OPimTodoAccessBackendSQL( const QString& file ) : OPimTodoAccessBackend(),/* 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(); } OPimTodoAccessBackendSQL::~OPimTodoAccessBackendSQL(){ if( m_driver ) delete m_driver; } bool OPimTodoAccessBackendSQL::load(){ if (!m_driver->open() ) return false; CreateQuery creat; OSQLResult res = m_driver->query(&creat ); m_dirty = true; return true; } bool OPimTodoAccessBackendSQL::reload(){ return load(); } bool OPimTodoAccessBackendSQL::save(){ return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) } QArray<int> OPimTodoAccessBackendSQL::allRecords()const { if (m_dirty ) update(); return m_uids; } -QArray<int> OPimTodoAccessBackendSQL::queryByExample( const OPimTodo& , int, const QDateTime& ){ - QArray<int> ints(0); - return ints; -} +// QArray<int> OPimTodoAccessBackendSQL::queryByExample( const UIDArray& uidlist, const OPimTodo& , int, const QDateTime& ){ +// QArray<int> ints(0); +// return ints; +// } OPimTodo OPimTodoAccessBackendSQL::find(int uid ) const{ FindQuery query( uid ); return parseResultAndCache( uid, m_driver->query(&query) ); } // Remember: uid is already in the list of uids, called ints ! OPimTodo OPimTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, uint cur, Frontend::CacheDirection dir ) const{ uint CACHE = readAhead(); odebug << "searching for " << uid << "" << oendl; QArray<int> search( CACHE ); uint size =0; // we try to cache CACHE items switch( dir ) { /* forward */ case Frontend::Forward: for (uint i = cur; i < ints.count() && size < CACHE; i++ ) { search[size] = ints[i]; size++; } break; /* reverse */ case Frontend::Reverse: 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 OPimTodo(); return parseResultAndCache( uid, res ); } void OPimTodoAccessBackendSQL::clear() { ClearQuery cle; OSQLResult res = m_driver->query( &cle ); CreateQuery qu; res = m_driver->query(&qu); } bool OPimTodoAccessBackendSQL::add( const OPimTodo& 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 OPimTodoAccessBackendSQL::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 OPimTodoAccessBackendSQL::replace( const OPimTodo& 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> OPimTodoAccessBackendSQL::overDue()const { OverDueQuery qu; return uids( m_driver->query(&qu ) ); } QArray<int> OPimTodoAccessBackendSQL::effectiveToDos( const QDate& s, const QDate& t, bool u)const { EffQuery ef(s, t, u ); return uids (m_driver->query(&ef) ); } #if 0 /* * */ QArray<int> OPimTodoAccessBackendSQL::sorted( bool asc, int sortOrder, int sortFilter, int cat ) { odebug << "sorted " << asc << ", " << sortOrder << "" << oendl; QString query; query = "select uid from todolist WHERE "; /* * Sort Filter stuff * not that straight forward * FIXME: Replace magic numbers * */ /* Category */ if ( sortFilter & OPimTodoAccess::FilterCategory ) { QString str; if (cat != 0 ) str = QString::number( cat ); query += " categories like '%" +str+"%' AND"; } /* Show only overdue */ if ( sortFilter & OPimTodoAccess::OnlyOverDue ) { QDate date = QDate::currentDate(); QString due; QString base; base = QString("DueDate <= '%1-%2-%3' AND completed = 0") .arg( QString::number( date.year() ).rightJustify( 4, '0' ) ) .arg( QString::number( date.month() ).rightJustify( 2, '0' ) ) .arg( QString::number( date.day() ).rightJustify( 2, '0' ) ); query += " " + base + " AND"; } /* not show completed */ if ( sortFilter & OPimTodoAccess::DoNotShowCompleted ) { query += " completed = 0 AND"; }else{ query += " ( completed = 1 OR completed = 0) AND"; } /* strip the end */ query = query.remove( query.length()-3, 3 ); /* * sort order stuff * quite straight forward */ query += "ORDER BY "; switch( sortOrder ) { /* completed */ case OPimTodoAccess::Completed: query += "completed"; break; case OPimTodoAccess::Priority: query += "priority"; break; case OPimTodoAccess::SortSummary: query += "summary"; break; case OPimTodoAccess::Deadline: query += "DueDate"; break; } if ( !asc ) query += " DESC"; odebug << query << oendl; OSQLRawQuery raw(query ); return uids( m_driver->query(&raw) ); } #endif bool OPimTodoAccessBackendSQL::date( QDate& da, const QString& str ) const{ - if ( str == "0-0-0" ) + if ( str == "0000-00-00" ) 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; } } OPimTodo OPimTodoAccessBackendSQL::parseResultAndCache( int uid, const OSQLResult& res ) const{ if ( res.state() == OSQLResult::Failure ) { OPimTodo to; return to; } OPimTodo retTodo; OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it = list.begin(); OPimTodo to, tmp; for ( ; it != list.end(); ++it ) { OPimTodo newTodo = parse( (*it) ); cache( newTodo ); if ( newTodo.uid() == uid ) retTodo = newTodo; } return retTodo; } OPimTodo OPimTodoAccessBackendSQL::parse( OSQLResultItem& item )const { // Request information from addressbook table and create the OPimTodo-object. bool hasDueDate = false; QDate dueDate = QDate::currentDate(); hasDueDate = date( dueDate, item.data("DueDate") ); QStringList cats = QStringList::split(";", item.data("categories") ); OPimTodo 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( OPimRecurrence::RType , item.data("RType") ); recMap.insert( OPimRecurrence::RWeekdays , item.data("RWeekdays") ); recMap.insert( OPimRecurrence::RPosition , item.data("RPosition") ); recMap.insert( OPimRecurrence::RFreq , item.data("RFreq") ); recMap.insert( OPimRecurrence::RHasEndDate, item.data("RHasEndDate") ); recMap.insert( OPimRecurrence::EndDate , item.data("EndDate") ); recMap.insert( OPimRecurrence::Created , item.data("Created") ); recMap.insert( OPimRecurrence::Exceptions , item.data("Exceptions") ); OPimRecurrence recur; recur.fromMap( recMap ); to.setRecurrence( recur ); // Finally load the custom-entries for this UID and put it into the created object to.setExtraMap( requestCustom( to.uid() ) ); return to; } // FIXME: Where is the difference to "find" ? (eilers) OPimTodo OPimTodoAccessBackendSQL::todo( int uid )const { FindQuery find( uid ); return parseResultAndCache( uid, m_driver->query(&find) ); } /* * need to be const so let's fool the * compiler :( */ void OPimTodoAccessBackendSQL::update()const { ((OPimTodoAccessBackendSQL*)this)->m_dirty = false; LoadQuery lo; OSQLResult res = m_driver->query(&lo); if ( res.state() != OSQLResult::Success ) return; ((OPimTodoAccessBackendSQL*)this)->m_uids = uids( res ); } QArray<int> OPimTodoAccessBackendSQL::uids( const OSQLResult& res) const{ OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it; QArray<int> ints(list.count() ); int i = 0; for (it = list.begin(); it != list.end(); ++it ) { ints[i] = (*it).data("uid").toInt(); i++; } return ints; } QArray<int> OPimTodoAccessBackendSQL::matchRegexp( const QRegExp &r ) const { QString qu = "SELECT uid FROM todolist WHERE ("; // Does it make sense to search other fields, too ? qu += " rlike(\""+ r.pattern() + "\",\"description\") OR"; qu += " rlike(\""+ r.pattern() + "\",\"summary\")"; qu += ")"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); return uids( res ); } void OPimTodoAccessBackendSQL::removeAllCompleted(){ // First we need the uids from all entries which are // completed. Then, we just have to remove them... QString qu = "SELECT uid FROM todolist WHERE completed = 1"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); QArray<int> completed_uids = uids( res ); if ( completed_uids.size() == 0 ) return; qu = "DELETE FROM todolist WHERE ("; QString query; for ( uint i = 0; i < completed_uids.size(); i++ ){ if ( !query.isEmpty() ) query += " OR "; query += QString( "uid = %1" ).arg( completed_uids[i] ); } qu += query + " );"; // Put remove of custom entries in this query to speed up.. qu += "DELETE FORM custom_data WHERE ("; query = ""; for ( uint i = 0; i < completed_uids.size(); i++ ){ if ( !query.isEmpty() ) query += " OR "; query += QString( "uid = %1" ).arg( completed_uids[i] ); } qu += query + " );"; OSQLRawQuery raw2( qu ); res = m_driver->query( &raw2 ); if ( res.state() == OSQLResult::Failure ) owarn << "OPimTodoAccessBackendSQL::removeAllCompleted():Failure in query: " << qu << "" << oendl; } QMap<QString, QString> OPimTodoAccessBackendSQL::requestCustom( int uid ) const { QMap<QString, QString> customMap; FindCustomQuery query( uid ); OSQLResult res_custom = m_driver->query( &query ); if ( res_custom.state() == OSQLResult::Failure ) { owarn << "OSQLResult::Failure in find query !!" << oendl; return QMap<QString, QString>(); } 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" ) ); return customMap; } } diff --git a/libopie2/opiepim/backend/otodoaccesssql.h b/libopie2/opiepim/backend/otodoaccesssql.h index 0ba8f3a..ac3476a 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.h +++ b/libopie2/opiepim/backend/otodoaccesssql.h @@ -1,88 +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 <opie2/otodoaccessbackend.h> namespace Opie { namespace DB { class OSQLDriver; class OSQLResult; class OSQLResultItem; } } namespace Opie { class OPimTodoAccessBackendSQL : public OPimTodoAccessBackend { public: OPimTodoAccessBackendSQL( const QString& file ); ~OPimTodoAccessBackendSQL(); bool load(); bool reload(); bool save(); QArray<UID> allRecords()const; - QArray<UID> queryByExample( const OPimTodo& t, int settings, const QDateTime& d = QDateTime() ); +/* QArray<UID> queryByExample( const UIDArray& uidlist, const OPimTodo& t, int settings, const QDateTime& d = QDateTime() ); */ OPimTodo find(UID uid)const; OPimTodo find(UID uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; void clear(); bool add( const OPimTodo& t ); bool remove( UID uid ); bool replace( const OPimTodo& t ); QArray<UID> overDue()const; QArray<UID> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates )const; QArray<UID> matchRegexp( const QRegExp &r ) const; void removeAllCompleted(); private: void update()const; inline bool date( QDate& date, const QString& )const; inline OPimTodo parseResultAndCache( UID uid, const Opie::DB::OSQLResult& )const; inline OPimTodo parse( Opie::DB::OSQLResultItem& )const; inline QArray<UID> uids( const Opie::DB::OSQLResult& )const; OPimTodo todo( UID uid )const; QMap<QString, QString> requestCustom( UID uid ) const; // QAsciiDict<int> m_dict; Opie::DB::OSQLDriver* m_driver; QArray<UID> m_uids; bool m_dirty : 1; }; } #endif diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp index 273f91a..ab50604 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.cpp +++ b/libopie2/opiepim/backend/otodoaccessxml.cpp @@ -1,716 +1,713 @@ /* 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. */ /* OPIE */ #include <opie2/opimdateconversion.h> #include <opie2/opimstate.h> #include <opie2/opimtimezone.h> #include <opie2/opimnotifymanager.h> #include <opie2/opimrecurrence.h> #include <opie2/otodoaccessxml.h> #include <opie2/otodoaccess.h> #include <opie2/odebug.h> #include <opie2/private/opimtodosortvector.h> #include <qpe/global.h> #include <qpe/stringutil.h> #include <qpe/timeconversion.h> /* QT */ #include <qfile.h> #include <qvector.h> /* STD */ #include <errno.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> using namespace Opie; namespace { time_t rp_end; OPimRecurrence* rec; OPimRecurrence *recur() { if (!rec ) rec = new OPimRecurrence; return rec; } int snd; enum MoreAttributes { FRType = OPimTodo::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 { OPimTodoAccessXML::OPimTodoAccessXML( const QString& appName, const QString& fileName ) : OPimTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) { if (!fileName.isEmpty() ) m_file = fileName; else m_file = Global::applicationFileName( "todolist", "todolist.xml" ); } OPimTodoAccessXML::~OPimTodoAccessXML() { } bool OPimTodoAccessXML::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(OPimTodo::Category) ); dict.insert("Uid" , new int(OPimTodo::Uid) ); dict.insert("HasDate" , new int(OPimTodo::HasDate) ); dict.insert("Completed" , new int(OPimTodo::Completed) ); dict.insert("Description" , new int(OPimTodo::Description) ); dict.insert("Summary" , new int(OPimTodo::Summary) ); dict.insert("Priority" , new int(OPimTodo::Priority) ); dict.insert("DateDay" , new int(OPimTodo::DateDay) ); dict.insert("DateMonth" , new int(OPimTodo::DateMonth) ); dict.insert("DateYear" , new int(OPimTodo::DateYear) ); dict.insert("Progress" , new int(OPimTodo::Progress) ); dict.insert("CompletedDate", new int(OPimTodo::CompletedDate) ); dict.insert("StartDate", new int(OPimTodo::StartDate) ); dict.insert("CrossReference", new int(OPimTodo::CrossReference) ); dict.insert("State", new int(OPimTodo::State) ); dict.insert("Alarms", new int(OPimTodo::Alarms) ); dict.insert("Reminders", new int(OPimTodo::Reminders) ); dict.insert("Maintainer", new int(OPimTodo::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; OPimTodo 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 */ 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() ) { OPimTimeZone utc = OPimTimeZone::utc(); OPimRecurrence 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 ); return true; } bool OPimTodoAccessXML::reload() { m_events.clear(); return load(); } bool OPimTodoAccessXML::save() { if (!m_opened || !m_changed ) { 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, OPimTodo>::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 ) { QFile::remove( strNewFile ); } m_changed = false; return true; } QArray<int> OPimTodoAccessXML::allRecords()const { QArray<int> ids( m_events.count() ); QMap<int, OPimTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) ids[i++] = it.key(); return ids; } -QArray<int> OPimTodoAccessXML::queryByExample( const OPimTodo&, int, const QDateTime& ) { - QArray<int> ids(0); - return ids; -} + OPimTodo OPimTodoAccessXML::find( int uid )const { OPimTodo todo; todo.setUid( 0 ); // isEmpty() QMap<int, OPimTodo>::ConstIterator it = m_events.find( uid ); if ( it != m_events.end() ) todo = it.data(); return todo; } void OPimTodoAccessXML::clear() { if (m_opened ) m_changed = true; m_events.clear(); } bool OPimTodoAccessXML::add( const OPimTodo& todo ) { m_changed = true; m_events.insert( todo.uid(), todo ); return true; } bool OPimTodoAccessXML::remove( int uid ) { m_changed = true; m_events.remove( uid ); return true; } bool OPimTodoAccessXML::replace( const OPimTodo& todo) { m_changed = true; m_events.replace( todo.uid(), todo ); return true; } QArray<int> OPimTodoAccessXML::effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates )const { QArray<int> ids( m_events.count() ); QMap<int, OPimTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { if ( !it.data().hasDueDate() && includeNoDates) { ids[i++] = it.key(); }else if ( it.data().dueDate() >= start && it.data().dueDate() <= end ) { ids[i++] = it.key(); } } ids.resize( i ); return ids; } QArray<int> OPimTodoAccessXML::overDue()const { QArray<int> ids( m_events.count() ); int i = 0; QMap<int, OPimTodo>::ConstIterator 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 OPimTodoAccessXML::todo( QAsciiDict<int>* dict, OPimTodo& ev, const QCString& attr, const QString& val) { int *find=0; find = (*dict)[ attr.data() ]; if (!find ) { ev.setCustomField( attr, val ); return; } switch( *find ) { case OPimTodo::Uid: ev.setUid( val.toInt() ); break; case OPimTodo::Category: ev.setCategories( ev.idsFromString( val ) ); break; case OPimTodo::HasDate: ev.setHasDueDate( val.toInt() ); break; case OPimTodo::Completed: ev.setCompleted( val.toInt() ); break; case OPimTodo::Description: ev.setDescription( val ); break; case OPimTodo::Summary: ev.setSummary( val ); break; case OPimTodo::Priority: ev.setPriority( val.toInt() ); break; case OPimTodo::DateDay: m_day = val.toInt(); break; case OPimTodo::DateMonth: m_month = val.toInt(); break; case OPimTodo::DateYear: m_year = val.toInt(); break; case OPimTodo::Progress: ev.setProgress( val.toInt() ); break; case OPimTodo::CompletedDate: ev.setCompletedDate( OPimDateConversion::dateFromString( val ) ); break; case OPimTodo::StartDate: ev.setStartDate( OPimDateConversion::dateFromString( val ) ); break; case OPimTodo::State: ev.setState( val.toInt() ); break; case OPimTodo::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 OPimAlarm al( alarm[2].toInt(), OPimDateConversion::dateTimeFromString( alarm[0] ), alarm[1].toInt() ); manager.add( al ); } } break; case OPimTodo::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 OPimTodo::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( OPimRecurrence::Daily ); else if ( val == "Weekly" ) recur()->setType( OPimRecurrence::Weekly); else if ( val == "MonthlyDay" ) recur()->setType( OPimRecurrence::MonthlyDay ); else if ( val == "MonthlyDate" ) recur()->setType( OPimRecurrence::MonthlyDate ); else if ( val == "Yearly" ) recur()->setType( OPimRecurrence::Yearly ); else recur()->setType( OPimRecurrence::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 ) { QString buf(" "); for ( QMap<QString, QString>::ConstIterator cit = customMap.begin(); cit != customMap.end(); ++cit) { buf += cit.key(); buf += "=\""; buf += Qtopia::escapeString(cit.data()); buf += "\" "; } return buf; } } QString OPimTodoAccessXML::toString( const OPimTodo& 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() ) + "\" "; } 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=\""+ OPimDateConversion::dateToString( ev.startDate() ) +"\" "; if ( ev.hasCompletedDate() ) str += "CompletedDate=\""+ OPimDateConversion::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 << OPimDateConversion::dateTimeToString( (*it).dateTime() ) + ":" + QString::number( (*it).duration() ) + ":" + QString::number( (*it).sound() ) + ":"; } } // now write the list str += "Alarms=\""+als.join(";") +"\" "; } /* * now the same for reminders but more easy. We just save the uid of the OPimEvent. */ 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 OPimTodoAccessXML::toString( const QArray<int>& ints ) const { return Qtopia::Record::idsToString( ints ); } QArray<int> OPimTodoAccessXML::sorted( const UIDArray& events, bool asc, int sortOrder,int sortFilter, const QArray<int>& categories )const { Internal::OPimTodoSortVector vector(events.count(), asc,sortOrder ); int item = 0; bool bCat = sortFilter & OPimTodoAccess::FilterCategory ? true : false; bool bOnly = sortFilter & OPimTodoAccess::OnlyOverDue ? true : false; bool comp = sortFilter & OPimTodoAccess::DoNotShowCompleted ? true : false; bool catPassed = false; int cat; for ( uint i = 0; i < events.count(); ++i ) { /* Guard against creating a new item... */ if ( !m_events.contains( events[i] ) ) continue; OPimTodo todo = m_events[events[i]]; /* show category */ /* -1 == unfiled */ catPassed = false; for ( uint cat_nu = 0; cat_nu < categories.count(); ++cat_nu ) { cat = categories[cat_nu]; if ( bCat && cat == -1 ) { if(!todo.categories().isEmpty() ) continue; } else if ( bCat && cat != 0) if (!todo.categories().contains( cat ) ) continue; catPassed = true; break; } /* * If none of the Categories matched * continue */ if ( !catPassed ) continue; if ( !todo.isOverdue() && bOnly ) continue; if (todo.isCompleted() && comp ) continue; vector.insert(item++, todo ); } vector.resize( item ); /* sort it now */ vector.sort(); /* now get the uids */ UIDArray array( vector.count() ); for (uint i= 0; i < vector.count(); i++ ) array[i] = vector.uidAt( i ); return array; } void OPimTodoAccessXML::removeAllCompleted() { QMap<int, OPimTodo> events = m_events; for ( QMap<int, OPimTodo>::Iterator it = m_events.begin(); it != m_events.end(); ++it ) { if ( (*it).isCompleted() ) events.remove( it.key() ); } m_events = events; } QArray<int> OPimTodoAccessXML::matchRegexp( const QRegExp &r ) const { QArray<int> currentQuery( m_events.count() ); uint arraycounter = 0; QMap<int, OPimTodo>::ConstIterator it; for (it = m_events.begin(); it != m_events.end(); ++it ) { if ( it.data().match( r ) ) currentQuery[arraycounter++] = it.data().uid(); } // Shrink to fit.. currentQuery.resize(arraycounter); diff --git a/libopie2/opiepim/backend/otodoaccessxml.h b/libopie2/opiepim/backend/otodoaccessxml.h index 134a21a..8a71bb7 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.h +++ b/libopie2/opiepim/backend/otodoaccessxml.h @@ -1,88 +1,87 @@ /* 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 <opie2/otodoaccessbackend.h> namespace Opie { class XMLElement; class OPimTodoAccessXML : public OPimTodoAccessBackend { public: /** * fileName if Empty we will use the default path */ OPimTodoAccessXML( const QString& appName, const QString& fileName = QString::null ); ~OPimTodoAccessXML(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> matchRegexp(const QRegExp &r) const; - QArray<int> queryByExample( const OPimTodo&, int querysettings, const QDateTime& d = QDateTime() ); OPimTodo find( int uid )const; void clear(); bool add( const OPimTodo& ); bool remove( int uid ); void removeAllCompleted(); bool replace( const OPimTodo& ); /* our functions */ QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates )const; QArray<int> overDue()const; //@{ UIDArray sorted( const UIDArray&, bool, int, int, const QArray<int>& )const; //@} private: void todo( QAsciiDict<int>*, OPimTodo&,const QCString&,const QString& ); QString toString( const OPimTodo& )const; QString toString( const QArray<int>& ints ) const; QMap<int, OPimTodo> m_events; QString m_file; QString m_app; bool m_opened : 1; bool m_changed : 1; class OPimTodoAccessXMLPrivate; OPimTodoAccessXMLPrivate* d; int m_year, m_month, m_day; }; }; #endif |