author | zecke <zecke> | 2004-11-18 21:49:23 (UTC) |
---|---|---|
committer | zecke <zecke> | 2004-11-18 21:49:23 (UTC) |
commit | 1e7f8f22fc10e3ed85b6563332ddc348c95792d0 (patch) (side-by-side diff) | |
tree | 59498ba1d4a7dbff05228c09bebcf0c849e916be | |
parent | 41fa1c196965f17f9748f835d90c307b7e594883 (diff) | |
download | opie-1e7f8f22fc10e3ed85b6563332ddc348c95792d0.zip opie-1e7f8f22fc10e3ed85b6563332ddc348c95792d0.tar.gz opie-1e7f8f22fc10e3ed85b6563332ddc348c95792d0.tar.bz2 |
Backend Changes:
Each Backend can:
-Sort and Filter a set of Records/AllRecords (which can be filtered again)
-QueryByExample by every Backend
-Occurrences for a period of time and a QDateTime
-More common implementation
-OPimBackendOccurrence with common splitting to OPimOccurrence
25 files changed, 1218 insertions, 819 deletions
diff --git a/libopie2/opiepim/backend/backends.pro b/libopie2/opiepim/backend/backends.pro index 42d807c..739f74e 100644 --- a/libopie2/opiepim/backend/backends.pro +++ b/libopie2/opiepim/backend/backends.pro @@ -1,37 +1,40 @@ SOURCES += \ + backend/ocontactaccessbackend.cpp \ backend/ocontactaccessbackend_vcard.cpp \ backend/ocontactaccessbackend_xml.cpp \ backend/odatebookaccessbackend.cpp \ backend/odatebookaccessbackend_xml.cpp \ + backend/opimbackendoccurrence.cpp \ backend/otodoaccessbackend.cpp \ backend/otodoaccessvcal.cpp \ backend/otodoaccessxml.cpp HEADERS += \ backend/obackendfactory.h \ backend/ocontactaccessbackend.h \ backend/ocontactaccessbackend_vcard.h \ backend/ocontactaccessbackend_xml.h \ backend/odatebookaccessbackend.h \ backend/odatebookaccessbackend_xml.h \ - backend/opimaccessbackend.h \ + backend/opimaccessbackend.h \ + backend/opimbackendoccurrence.h \ backend/otodoaccessbackend.h \ backend/otodoaccessvcal.h \ backend/otodoaccessxml.h contains( ENABLE_SQL_PIM_BACKEND, y ) { message ( Enabling the SQL Backend for libopiepim2 ) DEFINES += __USE_SQL LIBS += -lopiedb2 HEADERS += backend/otodoaccesssql.h \ backend/ocontactaccessbackend_sql.h \ backend/odatebookaccessbackend_sql.h SOURCES += backend/otodoaccesssql.cpp \ backend/ocontactaccessbackend_sql.cpp \ backend/odatebookaccessbackend_sql.cpp } !contains( ENABLE_SQL_PIM_BACKEND, y ) { message ( No SQL Backend in libopiepim2 ) } diff --git a/libopie2/opiepim/backend/obackendfactory.h b/libopie2/opiepim/backend/obackendfactory.h index 9f3a823..25e247b 100644 --- a/libopie2/opiepim/backend/obackendfactory.h +++ b/libopie2/opiepim/backend/obackendfactory.h @@ -1,230 +1,232 @@ /* 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. */ /* * ===================================================================== * ToDo: Use plugins * ===================================================================== */ #ifndef OPIE_BACKENDFACTORY_H_ #define OPIE_BACKENDFACTORY_H_ /* OPIE */ #include <opie2/opimaccessbackend.h> #include <opie2/opimglobal.h> #include <opie2/otodoaccessxml.h> #include <opie2/otodoaccessvcal.h> #include <opie2/ocontactaccessbackend_xml.h> #include <opie2/ocontactaccessbackend_vcard.h> #include <opie2/odatebookaccessbackend_xml.h> #include <opie2/odebug.h> #ifdef __USE_SQL #include <opie2/otodoaccesssql.h> #include <opie2/ocontactaccessbackend_sql.h> #include <opie2/odatebookaccessbackend_sql.h> #endif #include <qpe/config.h> /* QT */ #include <qstring.h> #include <qasciidict.h> using namespace Opie; using namespace Opie::Pim; namespace Opie { - + class OBackendPrivate; - + /** * This class is our factory. It will give us the default implementations * of at least Todolist, Contacts and Datebook. In the future this class will * allow users to switch the backend with ( XML->SQLite ) without the need * to recompile.# * This class - as the whole PIM Api - is making use of templates * * <pre> * OPimTodoAccessBackend* backend = OBackEndFactory<OPimTodoAccessBackend>::Default( OPimGlobal::TODOLIST, QString::null ); * backend->load(); * </pre> * * @author Stefan Eilers * @version 0.1 */ template<class T> class OBackendFactory { public: - OBackendFactory() {}; - + OBackendFactory() {}; + /** * Returns a selected backend implementation * @param type the type of the backend * @param database the type of the used database * @param appName The name of your application. It will be passed on to the backend. * @param filename Filename of the database file if you don't want to access the default * @see OPimGlobal() */ static T* create( OPimGlobal::PimType type, OPimGlobal::DatabaseStyle database, const QString& appName, const QString& filename = QString::null ){ - owarn << "Selected backend for " << type << " is: " << database << oendl; - // If we should use the dafult database style, we have to request it + owarn << "Selected backend for " << type << " is: " << +database << oendl; + + // If we should use the dafult database style, we have to request it OPimGlobal::DatabaseStyle use_database = database; if ( use_database == OPimGlobal::DEFAULT ){ use_database = defaultDB( type ); } - + switch ( type ){ case OPimGlobal::TODOLIST: - + switch ( use_database ){ default: // Use SQL if something weird is given. // Fall through !! case OPimGlobal::SQL: #ifdef __USE_SQL return (T*) new OPimTodoAccessBackendSQL( filename ); break; #else owarn << "OBackendFactory:: sql Backend for TODO not implemented! Using XML instead!" << oendl; // Fall through !! #endif case OPimGlobal::XML: return (T*) new OPimTodoAccessXML( appName, filename ); break; case OPimGlobal::VCARD: return (T*) new OPimTodoAccessVCal( filename ); break; } case OPimGlobal::CONTACTLIST: switch ( use_database ){ default: // Use SQL if something weird is given. // Fall through !! case OPimGlobal::SQL: #ifdef __USE_SQL return (T*) new OPimContactAccessBackend_SQL( appName, filename ); break; #else owarn << "OBackendFactory:: sql Backend for CONTACT not implemented! Using XML instead!" << oendl; // Fall through !! #endif case OPimGlobal::XML: return (T*) new OPimContactAccessBackend_XML( appName, filename ); break; case OPimGlobal::VCARD: return (T*) new OPimContactAccessBackend_VCard( appName, filename ); break; } case OPimGlobal::DATEBOOK: switch ( use_database ){ default: // Use SQL if something weird is given. // Fall through !! case OPimGlobal::SQL: #ifdef __USE_SQL return (T*) new ODateBookAccessBackend_SQL( appName, filename ); break; #else owarn << "OBackendFactory:: sql Backend for DATEBOOK not implemented! Using XML instead!" << oendl; // Fall through !! #endif case OPimGlobal::XML: return (T*) new ODateBookAccessBackend_XML( appName, filename ); break; case OPimGlobal::VCARD: owarn << "OBackendFactory:: VCal Backend for DATEBOOK not implemented!" << oendl; return (T*) NULL; break; } default: return (T*) NULL; } - + } - + /** * Returns the style of the default database which is used to contact PIM data. * @param type the type of the backend * @see OPimGlobal() */ static OPimGlobal::DatabaseStyle defaultDB( OPimGlobal::PimType type ){ QString group_name; switch ( type ){ case OPimGlobal::TODOLIST: group_name = "todo"; break; case OPimGlobal::CONTACTLIST: group_name = "contact"; break; case OPimGlobal::DATEBOOK: group_name = "datebook"; break; default: group_name = "unknown"; } - + Config config( "pimaccess" ); config.setGroup ( group_name ); QString db_String = config.readEntry( "usebackend", "xml" ); - + QAsciiDict<int> dictDbTypes( OPimGlobal::_END_DatabaseStyle ); dictDbTypes.setAutoDelete( TRUE ); - + dictDbTypes.insert( "xml", new int (OPimGlobal::XML) ); dictDbTypes.insert( "sql", new int (OPimGlobal::SQL) ); dictDbTypes.insert( "vcard", new int (OPimGlobal::VCARD) ); - + int* db_find = dictDbTypes[ db_String ]; - + if ( !db_find ) return OPimGlobal::UNKNOWN; - + return (OPimGlobal::DatabaseStyle) *db_find; } - - + + /** * Returns the default backend implementation for backendName. Which one is used, is defined * by the configfile "pimaccess.conf". * @param type The type of the backend (@see OPimGlobal()) * @param appName The name of your application. It will be passed on to the backend * @see OPimGlobal() */ static T* defaultBackend( OPimGlobal::PimType type, const QString& appName ){ return create( type, OPimGlobal::DEFAULT, appName ); } private: OBackendPrivate* d; - + }; - + } #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend.cpp b/libopie2/opiepim/backend/ocontactaccessbackend.cpp new file mode 100644 index 0000000..6ef60eb --- a/dev/null +++ b/libopie2/opiepim/backend/ocontactaccessbackend.cpp @@ -0,0 +1,121 @@ +/* + This file is part of the Opie Project + Copyright (C) 2004 Holger Freyther <freyther@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. +*/ + +#include "ocontactaccessbackend.h" +#include <opie2/private/opimcontactsortvector.h> +#include <opie2/ocontactaccess.h> + +#include <opie2/odebug.h> + +namespace Opie { +OPimContactAccessBackend::OPimContactAccessBackend() {} + +UIDArray +OPimContactAccessBackend::queryByExample( const OPimContact&, int, + const QDateTime& )const { + return UIDArray(); +} + +UIDArray +OPimContactAccessBackend::sorted( const UIDArray& ar, bool asc, int sortOrder, + int filter, const QArray<int>& categories)const { + odebug << "Using Unaccelerated OPimContactAccessBackend sorted Implementation" << oendl; + + Internal::OPimContactSortVector vector(ar.count(), asc, sortOrder ); + + int item = 0; + uint cat_count = categories.count(); + uint eve_count = ar.count(); + bool bCat = filter & OPimContactAccess::FilterCategory ? true : false; + bool catPassed = false; + int cat; + + for ( uint i = 0; i < eve_count; ++i ) { + OPimContact contact = find( ar[i], ar, i, Frontend::Forward ); + if ( contact.isEmpty() ) + continue; + + /* show category */ + /* -1 == unfiled */ + catPassed = false; + for ( uint cat_nu = 0; cat_nu < cat_count; ++cat_nu ) { + cat = categories[cat_nu]; + if ( bCat && cat == -1 ) { + if(!contact.categories().isEmpty() ) + continue; + } else if ( bCat && cat != 0) + if (!contact.categories().contains( cat ) ) + continue; + catPassed = true; + break; + } + + /* + * If none of the Categories matched + * continue + */ + if ( !catPassed ) + continue; + + vector.insert(item++, contact ); + } + + 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 OPimContactAccessBackend::occurrences( const QDate& start, + const QDate& end)const { + OPimBackendOccurrence::List lst; + + UIDArray records = allRecords(); + const uint count = records.count(); + int uid; + + for ( uint i = 0; i < count; ++i ) { + uid = records[i]; + OPimContact contact = find(uid, records, i, Frontend::Forward ); + + QDate date = contact.anniversary(); + date = QDate( start.year(), date.month(),date.day() ); + +// if ( date.isValid() && date.) { +// } + } + + return lst; +} +} diff --git a/libopie2/opiepim/backend/ocontactaccessbackend.h b/libopie2/opiepim/backend/ocontactaccessbackend.h index 8436adc..efb04c7 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend.h @@ -1,114 +1,108 @@ /* 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: - /** - * @todo make non line in regard to BC guide of KDE - */ - OPimContactAccessBackend() {} - /** - * @todo make non inline in regard to the BC guide of KDE - */ - virtual ~OPimContactAccessBackend() {} + 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 if database was changed externally. + * This may just make sense on file based databases like a XML-File. + * It is used to prevent to overwrite the current database content + * if the file was already changed by something else ! + * If this happens, we have to reload before save our data. + * If we use real databases, this should be handled by the database + * management system themselve, therefore this function should always return false in + * this case. It is not our problem to handle this conflict ... + * @return <i>true</i> if the database was changed and if save without reload will + * be dangerous. <i>false</i> if the database was not changed or it is save to write + * in this situation. + */ + virtual bool wasChangedExternally() = 0; - virtual QArray<int> matchRegexp( const QRegExp &r ) const = 0; + /** + * Return all possible settings. + * @return All settings provided by the current backend + * (i.e.: query_WildCards & query_IgnoreCase) + */ + virtual const uint querySettings() = 0; - /** - * Return all possible settings. - * @return All settings provided by the current backend - * (i.e.: query_WildCards & query_IgnoreCase) - */ - virtual const uint querySettings() = 0; + /** + * Check whether settings are correct. + * @return <i>true</i> if the given settings are correct and possible. + */ + virtual bool hasQuerySettings (uint querySettings) const = 0; + + /** + * Slow and inefficent default implementation + */ +//@{ + UIDArray queryByExample( const OPimContact&, 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& )const; +//@} - /** - * Check whether settings are correct. - * @return <i>true</i> if the given settings are correct and possible. - */ - virtual bool hasQuerySettings (uint querySettings) const = 0; - /** - * FIXME!!! - * Returns a sorted list of records either ascendinf or descending for a giving criteria and category - */ - virtual QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ) = 0; - - private: - class Private; - Private *d; + class Private; + Private *d; }; } #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp index af77a05..43e530a 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp @@ -74,346 +74,322 @@ bool OPimContactAccessBackend_VCard::load () OPimContact con = parseVObject( obj ); /* * if uid is 0 assign a new one * this at least happens on * Nokia6210 */ if ( con.uid() == 0 ){ con.setUid( 1 ); owarn << "assigned new uid " << con.uid() << "" << oendl; } m_map.insert( con.uid(), con ); VObject *t = obj; obj = nextVObjectInList(obj); cleanVObject( t ); } return true; } bool OPimContactAccessBackend_VCard::reload() { return load(); } bool OPimContactAccessBackend_VCard::save() { if (!m_dirty ) return true; QFile file( m_file ); if (!file.open(IO_WriteOnly ) ) return false; VObject *obj; obj = newVObject( VCCalProp ); addPropValue( obj, VCVersionProp, "1.0" ); VObject *vo; for(QMap<int, OPimContact>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ vo = createVObject( *it ); writeVObject( file.fh, vo ); //FIXME: HACK!!! cleanVObject( vo ); } cleanStrTbl(); deleteVObject( obj ); m_dirty = false; return true; } void OPimContactAccessBackend_VCard::clear () { m_map.clear(); m_dirty = true; // ??? sure ? (se) } bool OPimContactAccessBackend_VCard::add ( const OPimContact& newcontact ) { m_map.insert( newcontact.uid(), newcontact ); m_dirty = true; return true; } bool OPimContactAccessBackend_VCard::remove ( int uid ) { m_map.remove( uid ); m_dirty = true; return true; } bool OPimContactAccessBackend_VCard::replace ( const OPimContact &contact ) { m_map.replace( contact.uid(), contact ); m_dirty = true; return true; } OPimContact OPimContactAccessBackend_VCard::find ( int uid ) const { return m_map[uid]; } QArray<int> OPimContactAccessBackend_VCard::allRecords() const { QArray<int> ar( m_map.count() ); QMap<int, OPimContact>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } -// Not implemented -QArray<int> OPimContactAccessBackend_VCard::queryByExample ( const OPimContact&, int, const QDateTime& ) -{ - QArray<int> ar(0); - return ar; -} - -// Not implemented -QArray<int> OPimContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const -{ - QArray<int> ar(0); - return ar; -} - const uint OPimContactAccessBackend_VCard::querySettings() { return 0; // No search possible } bool OPimContactAccessBackend_VCard::hasQuerySettings (uint ) const { return false; // No search possible, therefore all settings invalid ;) } bool OPimContactAccessBackend_VCard::wasChangedExternally() { return false; // Don't expect concurrent access } -// Not implemented -QArray<int> OPimContactAccessBackend_VCard::sorted( bool , int, int, int ) -{ - QArray<int> ar(0); - return ar; -} - // *** Private stuff *** - - OPimContact OPimContactAccessBackend_VCard::parseVObject( VObject *obj ) { OPimContact c; VObjectIterator it; initPropIterator( &it, obj ); while( moreIteration( &it ) ) { VObject *o = nextVObject( &it ); QCString name = vObjectName( o ); QString value = QString::fromUtf8( vObjectStringZValue( o ) ); odebug << "(1)Read: %s" << QString( value ).latin1() << oendl; if ( name == VCNameProp ) { VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); QString value = QString::fromUtf8( vObjectStringZValue( o ) ); odebug << "(2)Read: %s" << value.latin1() << oendl; if ( name == VCNamePrefixesProp ) c.setTitle( value ); else if ( name == VCNameSuffixesProp ) c.setSuffix( value ); else if ( name == VCFamilyNameProp ) c.setLastName( value ); else if ( name == VCGivenNameProp ) c.setFirstName( value ); else if ( name == VCAdditionalNamesProp ) c.setMiddleName( value ); } } else if ( name == VCAdrProp ) { bool work = TRUE; // default address is work address QString street; QString city; QString region; QString postal; QString country; VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectName( o ); QString value = QString::fromUtf8( vObjectStringZValue( o ) ); if ( name == VCHomeProp ) work = FALSE; else if ( name == VCWorkProp ) work = TRUE; else if ( name == VCStreetAddressProp ) street = value; else if ( name == VCCityProp ) city = value; else if ( name == VCRegionProp ) region = value; else if ( name == VCPostalCodeProp ) postal = value; else if ( name == VCCountryNameProp ) country = value; } if ( work ) { c.setBusinessStreet( street ); c.setBusinessCity( city ); c.setBusinessCountry( country ); c.setBusinessZip( postal ); c.setBusinessState( region ); } else { c.setHomeStreet( street ); c.setHomeCity( city ); c.setHomeCountry( country ); c.setHomeZip( postal ); c.setHomeState( region ); } } else if ( name == VCTelephoneProp ) { enum { HOME = 0x01, WORK = 0x02, VOICE = 0x04, CELL = 0x08, FAX = 0x10, PAGER = 0x20, UNKNOWN = 0x80 }; int type = 0; VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); if ( name == VCHomeProp ) type |= HOME; else if ( name == VCWorkProp ) type |= WORK; else if ( name == VCVoiceProp ) type |= VOICE; else if ( name == VCCellularProp ) type |= CELL; else if ( name == VCFaxProp ) type |= FAX; else if ( name == VCPagerProp ) type |= PAGER; else if ( name == VCPreferredProp ) ; else type |= UNKNOWN; } if ( (type & UNKNOWN) != UNKNOWN ) { if ( ( type & (HOME|WORK) ) == 0 ) // default type |= HOME; if ( ( type & (VOICE|CELL|FAX|PAGER) ) == 0 ) // default type |= VOICE; - owarn << "value %s %d" << value.data() << type << oendl; if ( (type & (VOICE|HOME) ) == (VOICE|HOME) && (type & (CELL|HOME) ) != (CELL|HOME) ) c.setHomePhone( value ); if ( ( type & (FAX|HOME) ) == (FAX|HOME) ) c.setHomeFax( value ); if ( ( type & (CELL|HOME) ) == (CELL|HOME) ) c.setHomeMobile( value ); if ( ( type & (VOICE|WORK) ) == (VOICE|WORK) && (type & (CELL|WORK) ) != (CELL|WORK) ) c.setBusinessPhone( value ); if ( ( type & (FAX|WORK) ) == (FAX|WORK) ) c.setBusinessFax( value ); if ( ( type & (CELL|WORK) ) == (CELL|WORK) ) c.setBusinessMobile( value ); if ( ( type & (PAGER|WORK) ) == (PAGER|WORK) ) c.setBusinessPager( value ); } } else if ( name == VCEmailAddressProp ) { QString email = QString::fromUtf8( vObjectStringZValue( o ) ); bool valid = TRUE; VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); if ( name != VCInternetProp && name != VCHomeProp && name != VCWorkProp && name != VCPreferredProp ) // ### preffered should map to default email valid = FALSE; } if ( valid ) { c.insertEmail( email ); } } else if ( name == VCURLProp ) { VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectTypeInfo( o ); if ( name == VCHomeProp ) c.setHomeWebpage( value ); else if ( name == VCWorkProp ) c.setBusinessWebpage( value ); } } else if ( name == VCOrgProp ) { VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectName( o ); QString value = QString::fromUtf8( vObjectStringZValue( o ) ); if ( name == VCOrgNameProp ) c.setCompany( value ); else if ( name == VCOrgUnitProp ) c.setDepartment( value ); else if ( name == VCOrgUnit2Prop ) c.setOffice( value ); } } else if ( name == VCTitleProp ) { c.setJobTitle( value ); } else if ( name == "X-Qtopia-Profession" ) { c.setProfession( value ); } else if ( name == "X-Qtopia-Manager" ) { c.setManager( value ); } else if ( name == "X-Qtopia-Assistant" ) { c.setAssistant( value ); } else if ( name == "X-Qtopia-Spouse" ) { c.setSpouse( value ); } else if ( name == "X-Qtopia-Gender" ) { c.setGender( value ); } else if ( name == "X-Qtopia-Anniversary" ) { c.setAnniversary( convVCardDateToDate( value ) ); } else if ( name == "X-Qtopia-Nickname" ) { c.setNickname( value ); } else if ( name == "X-Qtopia-Children" ) { c.setChildren( value ); } else if ( name == VCBirthDateProp ) { // Reading Birthdate regarding RFC 2425 (5.8.4) c.setBirthday( convVCardDateToDate( value ) ); } else if ( name == VCCommentProp ) { c.setNotes( value ); } @@ -432,180 +408,178 @@ OPimContact OPimContactAccessBackend_VCard::parseVObject( VObject *obj ) else { printf("Name: %s, value=%s\n", name.data(), vObjectStringZValue( o ) ); VObjectIterator nit; initPropIterator( &nit, o ); while( moreIteration( &nit ) ) { VObject *o = nextVObject( &nit ); QCString name = vObjectName( o ); QString value = vObjectStringZValue( o ); printf(" subprop: %s = %s\n", name.data(), value.latin1() ); } } #endif } c.setFileAs(); return c; } VObject* OPimContactAccessBackend_VCard::createVObject( const OPimContact &c ) { VObject *vcard = newVObject( VCCardProp ); safeAddPropValue( vcard, VCVersionProp, "2.1" ); safeAddPropValue( vcard, VCLastRevisedProp, TimeConversion::toISO8601( QDateTime::currentDateTime() ) ); safeAddPropValue( vcard, VCUniqueStringProp, QString::number(c.uid()) ); // full name safeAddPropValue( vcard, VCFullNameProp, c.fullName() ); // name properties VObject *name = safeAddProp( vcard, VCNameProp ); safeAddPropValue( name, VCFamilyNameProp, c.lastName() ); safeAddPropValue( name, VCGivenNameProp, c.firstName() ); safeAddPropValue( name, VCAdditionalNamesProp, c.middleName() ); safeAddPropValue( name, VCNamePrefixesProp, c.title() ); safeAddPropValue( name, VCNameSuffixesProp, c.suffix() ); // home properties VObject *home_adr= safeAddProp( vcard, VCAdrProp ); safeAddProp( home_adr, VCHomeProp ); safeAddPropValue( home_adr, VCStreetAddressProp, c.homeStreet() ); safeAddPropValue( home_adr, VCCityProp, c.homeCity() ); safeAddPropValue( home_adr, VCRegionProp, c.homeState() ); safeAddPropValue( home_adr, VCPostalCodeProp, c.homeZip() ); safeAddPropValue( home_adr, VCCountryNameProp, c.homeCountry() ); VObject *home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homePhone() ); safeAddProp( home_phone, VCHomeProp ); home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeMobile() ); safeAddProp( home_phone, VCHomeProp ); safeAddProp( home_phone, VCCellularProp ); home_phone = safeAddPropValue( vcard, VCTelephoneProp, c.homeFax() ); safeAddProp( home_phone, VCHomeProp ); safeAddProp( home_phone, VCFaxProp ); VObject *url = safeAddPropValue( vcard, VCURLProp, c.homeWebpage() ); safeAddProp( url, VCHomeProp ); // work properties VObject *work_adr= safeAddProp( vcard, VCAdrProp ); safeAddProp( work_adr, VCWorkProp ); safeAddPropValue( work_adr, VCStreetAddressProp, c.businessStreet() ); safeAddPropValue( work_adr, VCCityProp, c.businessCity() ); safeAddPropValue( work_adr, VCRegionProp, c.businessState() ); safeAddPropValue( work_adr, VCPostalCodeProp, c.businessZip() ); safeAddPropValue( work_adr, VCCountryNameProp, c.businessCountry() ); VObject *work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPhone() ); safeAddProp( work_phone, VCWorkProp ); work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessMobile() ); safeAddProp( work_phone, VCWorkProp ); safeAddProp( work_phone, VCCellularProp ); work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessFax() ); safeAddProp( work_phone, VCWorkProp ); safeAddProp( work_phone, VCFaxProp ); work_phone = safeAddPropValue( vcard, VCTelephoneProp, c.businessPager() ); safeAddProp( work_phone, VCWorkProp ); safeAddProp( work_phone, VCPagerProp ); url = safeAddPropValue( vcard, VCURLProp, c.businessWebpage() ); safeAddProp( url, VCWorkProp ); VObject *title = safeAddPropValue( vcard, VCTitleProp, c.jobTitle() ); safeAddProp( title, VCWorkProp ); QStringList emails = c.emailList(); // emails.prepend( c.defaultEmail() ); Fix for bugreport #1045 for( QStringList::Iterator it = emails.begin(); it != emails.end(); ++it ) { VObject *email = safeAddPropValue( vcard, VCEmailAddressProp, *it ); safeAddProp( email, VCInternetProp ); } safeAddPropValue( vcard, VCNoteProp, c.notes() ); // Exporting Birthday regarding RFC 2425 (5.8.4) if ( c.birthday().isValid() ){ - owarn << "Exporting birthday as: " << convDateToVCardDate( c.birthday() ) << "" << oendl; safeAddPropValue( vcard, VCBirthDateProp, convDateToVCardDate( c.birthday() ) ); } if ( !c.company().isEmpty() || !c.department().isEmpty() || !c.office().isEmpty() ) { VObject *org = safeAddProp( vcard, VCOrgProp ); safeAddPropValue( org, VCOrgNameProp, c.company() ); safeAddPropValue( org, VCOrgUnitProp, c.department() ); safeAddPropValue( org, VCOrgUnit2Prop, c.office() ); } // some values we have to export as custom fields safeAddPropValue( vcard, "X-Qtopia-Profession", c.profession() ); safeAddPropValue( vcard, "X-Qtopia-Manager", c.manager() ); safeAddPropValue( vcard, "X-Qtopia-Assistant", c.assistant() ); safeAddPropValue( vcard, "X-Qtopia-Spouse", c.spouse() ); safeAddPropValue( vcard, "X-Qtopia-Gender", c.gender() ); if ( c.anniversary().isValid() ){ - owarn << "Exporting anniversary as: " << convDateToVCardDate( c.anniversary() ) << "" << oendl; safeAddPropValue( vcard, "X-Qtopia-Anniversary", convDateToVCardDate( c.anniversary() ) ); } safeAddPropValue( vcard, "X-Qtopia-Nickname", c.nickname() ); safeAddPropValue( vcard, "X-Qtopia-Children", c.children() ); return vcard; } QString OPimContactAccessBackend_VCard::convDateToVCardDate( const QDate& d ) const { QString str_rfc2425 = QString("%1-%2-%3") .arg( d.year() ) .arg( d.month(), 2 ) .arg( d.day(), 2 ); // Now replace spaces with "0"... int pos = 0; while ( ( pos = str_rfc2425.find (' ') ) > 0 ) str_rfc2425.replace( pos, 1, "0" ); return str_rfc2425; } QDate OPimContactAccessBackend_VCard::convVCardDateToDate( const QString& datestr ) { int monthPos = datestr.find('-'); int dayPos = datestr.find('-', monthPos+1 ); int sep_ignore = 1; if ( monthPos == -1 || dayPos == -1 ) { odebug << "fromString didn't find - in str = " << datestr << "; mpos = " << monthPos << " ypos = " << dayPos << "" << oendl; // Ok.. No "-" found, therefore we will try to read other format ( YYYYMMDD ) if ( datestr.length() == 8 ){ monthPos = 4; dayPos = 6; sep_ignore = 0; odebug << "Try with follwing positions str = " << datestr << "; mpos = " << monthPos << " ypos = " << dayPos << "" << oendl; } else { return QDate(); } } int y = datestr.left( monthPos ).toInt(); int m = datestr.mid( monthPos + sep_ignore, dayPos - monthPos - sep_ignore ).toInt(); int d = datestr.mid( dayPos + sep_ignore ).toInt(); odebug << "TimeConversion::fromString ymd = " << datestr << " => " << y << " " << m << " " << d << "; mpos = " << monthPos << " ypos = " << dayPos << "" << oendl; QDate date ( y,m,d ); return date; } VObject* OPimContactAccessBackend_VCard::safeAddPropValue( VObject *o, const char *prop, const QString &value ) { VObject *ret = 0; if ( o && !value.isEmpty() ) ret = addPropValue( o, prop, value.utf8() ); return ret; } VObject* OPimContactAccessBackend_VCard::safeAddProp( VObject *o, const char *prop) { VObject *ret = 0; if ( o ) ret = addProp( o, prop ); return ret; } } diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h index 2a786af..1faf747 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h @@ -1,85 +1,82 @@ /* This file is part of the Opie Project Copyright (C) The Main Author <main-author@whereever.org> =. Copyright (C) The Opie Team <opie-devel@handhelds.org> .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU Library General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * VCard Backend for the OPIE-Contact Database. */ #ifndef __OCONTACTACCESSBACKEND_VCARD_H_ #define __OCONTACTACCESSBACKEND_VCARD_H_ #include <opie2/opimcontact.h> #include <opie2/ocontactaccessbackend.h> class VObject; namespace Opie { /** * This is the vCard 2.1 implementation of the Contact Storage * @see OPimContactAccessBackend_XML * @see OPimAccessBackend */ class OPimContactAccessBackend_VCard : public OPimContactAccessBackend { public: OPimContactAccessBackend_VCard ( const QString& appname, const QString& filename = QString::null ); bool load (); bool reload(); bool save(); void clear (); bool add ( const OPimContact& newcontact ); bool remove ( int uid ); bool replace ( const OPimContact& contact ); OPimContact find ( int uid ) const; QArray<int> allRecords() const; - QArray<int> queryByExample ( const OPimContact &query, int settings, const QDateTime& d = QDateTime() ); - QArray<int> matchRegexp( const QRegExp &r ) const; const uint querySettings(); bool hasQuerySettings (uint querySettings) const; - QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); bool wasChangedExternally(); private: OPimContact parseVObject( VObject* obj ); VObject* createVObject( const OPimContact& c ); QString convDateToVCardDate( const QDate& c ) const; QDate convVCardDateToDate( const QString& datestr ); VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); VObject *safeAddProp( VObject* o, const char* prop); bool m_dirty : 1; QString m_file; QMap<int, OPimContact> m_map; }; } #endif diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp index 18113c2..5df7253 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp @@ -15,736 +15,715 @@ + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * XML Backend for the OPIE-Contact Database. */ /* OPIE */ #include <opie2/ocontactaccessbackend_xml.h> #include <opie2/xmltree.h> #include <opie2/ocontactaccessbackend.h> #include <opie2/ocontactaccess.h> #include <opie2/odebug.h> #include <qpe/global.h> /* QT */ #include <qasciidict.h> #include <qfile.h> #include <qfileinfo.h> #include <qregexp.h> #include <qarray.h> #include <qmap.h> /* STD */ #include <stdlib.h> #include <errno.h> using namespace Opie::Core; namespace Opie { OPimContactAccessBackend_XML::OPimContactAccessBackend_XML ( const QString& appname, const QString& filename ): m_changed( false ) { // Just m_contactlist should call delete if an entry // is removed. m_contactList.setAutoDelete( true ); m_uidToContact.setAutoDelete( false ); m_appName = appname; /* Set journalfile name ... */ m_journalName = getenv("HOME"); m_journalName +="/.abjournal" + appname; /* Expecting to access the default filename if nothing else is set */ if ( filename.isEmpty() ){ m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); } else m_fileName = filename; /* Load Database now */ load (); } bool OPimContactAccessBackend_XML::save() { if ( !m_changed ) return true; QString strNewFile = m_fileName + ".new"; QFile f( strNewFile ); if ( !f.open( IO_WriteOnly|IO_Raw ) ) return false; int total_written; int idx_offset = 0; QString out; // Write Header out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" " <Groups>\n" " </Groups>\n" " <Contacts>\n"; QCString cstr = out.utf8(); f.writeBlock( cstr.data(), cstr.length() ); idx_offset += cstr.length(); out = ""; // Write all contacts QListIterator<OPimContact> it( m_contactList ); for ( ; it.current(); ++it ) { - // owarn << " Uid " << (*it)->uid() << " at Offset: " << idx_offset << "" << oendl; out += "<Contact "; (*it)->save( out ); out += "/>\n"; cstr = out.utf8(); total_written = f.writeBlock( cstr.data(), cstr.length() ); idx_offset += cstr.length(); if ( total_written != int(cstr.length()) ) { f.close(); QFile::remove( strNewFile ); return false; } out = ""; } out += " </Contacts>\n</AddressBook>\n"; // Write Footer cstr = out.utf8(); total_written = f.writeBlock( cstr.data(), cstr.length() ); if ( total_written != int( cstr.length() ) ) { f.close(); QFile::remove( strNewFile ); return false; } f.close(); // move the file over, I'm just going to use the system call // because, I don't feel like using QDir. if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { - owarn << "problem renaming file " << strNewFile << " to " << m_journalName - << ", errno: " << errno << oendl; // remove the tmp file... QFile::remove( strNewFile ); } /* The journalfile should be removed now... */ removeJournal(); m_changed = false; return true; } bool OPimContactAccessBackend_XML::load () { m_contactList.clear(); m_uidToContact.clear(); /* Load XML-File and journal if it exists */ if ( !load ( m_fileName, false ) ) return false; /* The returncode of the journalfile is ignored due to the * fact that it does not exist when this class is instantiated ! * But there may such a file exist, if the application crashed. * Therefore we try to load it to get the changes before the # * crash happened... */ load (m_journalName, true); return true; } void OPimContactAccessBackend_XML::clear () { m_contactList.clear(); m_uidToContact.clear(); m_changed = false; } bool OPimContactAccessBackend_XML::wasChangedExternally() { QFileInfo fi( m_fileName ); QDateTime lastmod = fi.lastModified (); return (lastmod != m_readtime); } QArray<int> OPimContactAccessBackend_XML::allRecords() const { QArray<int> uid_list( m_contactList.count() ); uint counter = 0; QListIterator<OPimContact> it( m_contactList ); for( ; it.current(); ++it ){ uid_list[counter++] = (*it)->uid(); } return ( uid_list ); } OPimContact OPimContactAccessBackend_XML::find ( int uid ) const { OPimContact foundContact; //Create empty contact OPimContact* found = m_uidToContact.find( QString().setNum( uid ) ); if ( found ){ foundContact = *found; } return ( foundContact ); } QArray<int> OPimContactAccessBackend_XML::queryByExample ( const OPimContact &query, int settings, - const QDateTime& d ) + const QDateTime& d )const { - QArray<int> m_currentQuery( m_contactList.count() ); QListIterator<OPimContact> it( m_contactList ); uint arraycounter = 0; for( ; it.current(); ++it ){ /* Search all fields and compare them with query object. Store them into list * if all fields matches. */ QDate* queryDate = 0l; QDate* checkDate = 0l; bool allcorrect = true; for ( int i = 0; i < Qtopia::Groups; i++ ) { // Birthday and anniversary are special nonstring fields and should // be handled specially switch ( i ){ case Qtopia::Birthday: queryDate = new QDate( query.birthday() ); checkDate = new QDate( (*it)->birthday() ); // fall through case Qtopia::Anniversary: if ( queryDate == 0l ){ queryDate = new QDate( query.anniversary() ); checkDate = new QDate( (*it)->anniversary() ); } if ( queryDate->isValid() ){ if( checkDate->isValid() ){ if ( settings & OPimContactAccess::DateYear ){ if ( queryDate->year() != checkDate->year() ) allcorrect = false; } if ( settings & OPimContactAccess::DateMonth ){ if ( queryDate->month() != checkDate->month() ) allcorrect = false; } if ( settings & OPimContactAccess::DateDay ){ if ( queryDate->day() != checkDate->day() ) allcorrect = false; } if ( settings & OPimContactAccess::DateDiff ) { QDate current; // If we get an additional date, we // will take this date instead of // the current one.. if ( !d.date().isValid() ) current = QDate::currentDate(); else current = d.date(); // We have to equalize the year, otherwise // the search will fail.. checkDate->setYMD( current.year(), checkDate->month(), checkDate->day() ); if ( *checkDate < current ) checkDate->setYMD( current.year()+1, checkDate->month(), checkDate->day() ); // Check whether the birthday/anniversary date is between // the current/given date and the maximum date // ( maximum time range ) ! - owarn << "Checking if " << checkDate->toString() << " is between " << current.toString() - << " and " << queryDate->toString() << " ! " << oendl; if ( current.daysTo( *queryDate ) >= 0 ){ if ( !( ( *checkDate >= current ) && ( *checkDate <= *queryDate ) ) ){ allcorrect = false; - owarn << " Nope!.." << oendl; } } } } else{ // checkDate is invalid. Therefore this entry is always rejected allcorrect = false; } } delete queryDate; queryDate = 0l; delete checkDate; checkDate = 0l; break; default: /* Just compare fields which are not empty in the query object */ if ( !query.field(i).isEmpty() ){ switch ( settings & ~( OPimContactAccess::IgnoreCase | OPimContactAccess::DateDiff | OPimContactAccess::DateYear | OPimContactAccess::DateMonth | OPimContactAccess::DateDay | OPimContactAccess::MatchOne ) ){ case OPimContactAccess::RegExp:{ QRegExp expr ( query.field(i), !(settings & OPimContactAccess::IgnoreCase), false ); if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OPimContactAccess::WildCards:{ QRegExp expr ( query.field(i), !(settings & OPimContactAccess::IgnoreCase), true ); if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OPimContactAccess::ExactMatch:{ if (settings & OPimContactAccess::IgnoreCase){ if ( query.field(i).upper() != (*it)->field(i).upper() ) allcorrect = false; }else{ if ( query.field(i) != (*it)->field(i) ) allcorrect = false; } } break; } } } } if ( allcorrect ){ m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } QArray<int> OPimContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const { QArray<int> m_currentQuery( m_contactList.count() ); QListIterator<OPimContact> it( m_contactList ); uint arraycounter = 0; for( ; it.current(); ++it ){ if ( (*it)->match( r ) ){ m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } const uint OPimContactAccessBackend_XML::querySettings() { return ( OPimContactAccess::WildCards | OPimContactAccess::IgnoreCase | OPimContactAccess::RegExp | OPimContactAccess::ExactMatch | OPimContactAccess::DateDiff | OPimContactAccess::DateYear | OPimContactAccess::DateMonth | OPimContactAccess::DateDay ); } bool OPimContactAccessBackend_XML::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 ); } } +#if 0 // Currently only asc implemented.. QArray<int> OPimContactAccessBackend_XML::sorted( bool asc, int , int , int ) { QMap<QString, int> nameToUid; QStringList names; QArray<int> m_currentQuery( m_contactList.count() ); // First fill map and StringList with all Names // Afterwards sort namelist and use map to fill array to return.. QListIterator<OPimContact> it( m_contactList ); for( ; it.current(); ++it ){ names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) ); nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() ); } names.sort(); int i = 0; if ( asc ){ for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) m_currentQuery[i++] = nameToUid[ (*it) ]; }else{ for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) m_currentQuery[i++] = nameToUid[ (*it) ]; } return m_currentQuery; } +#endif + bool OPimContactAccessBackend_XML::add ( const OPimContact &newcontact ) { - //owarn << "odefaultbackend: ACTION::ADD" << oendl; updateJournal (newcontact, ACTION_ADD); addContact_p( newcontact ); m_changed = true; return true; } bool OPimContactAccessBackend_XML::replace ( const OPimContact &contact ) { m_changed = true; OPimContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) ); if ( found ) { OPimContact* newCont = new OPimContact( contact ); updateJournal ( *newCont, ACTION_REPLACE); m_contactList.removeRef ( found ); m_contactList.append ( newCont ); m_uidToContact.remove( QString().setNum( contact.uid() ) ); m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont ); - owarn << "Nur zur Sicherheit: " << contact.uid() << " == " << newCont->uid() << " ?" << oendl; - return true; } else return false; } bool OPimContactAccessBackend_XML::remove ( int uid ) { m_changed = true; OPimContact* found = m_uidToContact.find ( QString().setNum( uid ) ); if ( found ) { updateJournal ( *found, ACTION_REMOVE); m_contactList.removeRef ( found ); m_uidToContact.remove( QString().setNum( uid ) ); return true; } else return false; } bool OPimContactAccessBackend_XML::reload(){ /* Reload is the same as load in this implementation */ return ( load() ); } void OPimContactAccessBackend_XML::addContact_p( const OPimContact &newcontact ) { OPimContact* contRef = new OPimContact( newcontact ); m_contactList.append ( contRef ); m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef ); } /* This function loads the xml-database and the journalfile */ bool OPimContactAccessBackend_XML::load( const QString filename, bool isJournal ) { /* We use the time of the last read to check if the file was * changed externally. */ if ( !isJournal ){ QFileInfo fi( filename ); m_readtime = fi.lastModified (); } const int JOURNALACTION = Qtopia::Notes + 1; const int JOURNALROW = JOURNALACTION + 1; bool foundAction = false; journal_action action = ACTION_ADD; int journalKey = 0; QMap<int, QString> contactMap; QMap<QString, QString> customMap; QMap<QString, QString>::Iterator customIt; QAsciiDict<int> dict( 47 ); dict.setAutoDelete( TRUE ); dict.insert( "Uid", new int(Qtopia::AddressUid) ); dict.insert( "Title", new int(Qtopia::Title) ); dict.insert( "FirstName", new int(Qtopia::FirstName) ); dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); dict.insert( "LastName", new int(Qtopia::LastName) ); dict.insert( "Suffix", new int(Qtopia::Suffix) ); dict.insert( "FileAs", new int(Qtopia::FileAs) ); dict.insert( "Categories", new int(Qtopia::AddressCategory) ); dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); dict.insert( "Emails", new int(Qtopia::Emails) ); dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); dict.insert( "HomeState", new int(Qtopia::HomeState) ); dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); dict.insert( "Company", new int(Qtopia::Company) ); dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); dict.insert( "Department", new int(Qtopia::Department) ); dict.insert( "Office", new int(Qtopia::Office) ); dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); dict.insert( "Profession", new int(Qtopia::Profession) ); dict.insert( "Assistant", new int(Qtopia::Assistant) ); dict.insert( "Manager", new int(Qtopia::Manager) ); dict.insert( "Spouse", new int(Qtopia::Spouse) ); dict.insert( "Children", new int(Qtopia::Children) ); dict.insert( "Gender", new int(Qtopia::Gender) ); dict.insert( "Birthday", new int(Qtopia::Birthday) ); dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); dict.insert( "Nickname", new int(Qtopia::Nickname) ); dict.insert( "Notes", new int(Qtopia::Notes) ); dict.insert( "action", new int(JOURNALACTION) ); dict.insert( "actionrow", new int(JOURNALROW) ); - //owarn << "OPimContactDefaultBackEnd::loading " << filename << "" << oendl; - XMLElement *root = XMLElement::load( filename ); if(root != 0l ){ // start parsing /* Parse all XML-Elements and put the data into the * Contact-Class */ XMLElement *element = root->firstChild(); - //owarn << "OPimContactAccess::load tagName(): " << root->tagName() << "" << oendl; element = element ? element->firstChild() : 0; /* Search Tag "Contacts" which is the parent of all Contacts */ while( element && !isJournal ){ if( element->tagName() != QString::fromLatin1("Contacts") ){ - //owarn << "OPimContactDefBack::Searching for Tag \"Contacts\"! Found: " - // << element->tagName() << oendl; element = element->nextChild(); } else { element = element->firstChild(); break; } } /* Parse all Contacts and ignore unknown tags */ while( element ){ if( element->tagName() != QString::fromLatin1("Contact") ){ - //owarn << "OPimContactDefBack::Searching for Tag \"Contact\"! Found: " - // << element->tagName() << oendl; element = element->nextChild(); continue; } /* Found alement with tagname "contact", now parse and store all * attributes contained */ - //owarn << "OPimContactDefBack::load element tagName() : " - // << element->tagName() << oendl; QString dummy; foundAction = false; XMLElement::AttributeMap aMap = element->attributes(); XMLElement::AttributeMap::Iterator it; contactMap.clear(); customMap.clear(); for( it = aMap.begin(); it != aMap.end(); ++it ){ - // owarn << "Read Attribute: " << it.key() << "=" << it.data() << oendl; - int *find = dict[ it.key() ]; /* Unknown attributes will be stored as "Custom" elements */ if ( !find ) { - // owarn << "Attribute " << it.key() << " not known." << oendl; //contact.setCustomField(it.key(), it.data()); customMap.insert( it.key(), it.data() ); continue; } /* Check if special conversion is needed and add attribute * into Contact class */ switch( *find ) { /* case Qtopia::AddressUid: contact.setUid( it.data().toInt() ); break; case Qtopia::AddressCategory: contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); break; */ case JOURNALACTION: action = journal_action(it.data().toInt()); foundAction = true; owarn << "ODefBack(journal)::ACTION found: " << action << oendl; break; case JOURNALROW: journalKey = it.data().toInt(); break; default: // no conversion needed add them to the map contactMap.insert( *find, it.data() ); break; } } /* now generate the Contact contact */ OPimContact contact( contactMap ); for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { contact.setCustomField( customIt.key(), customIt.data() ); } if (foundAction){ foundAction = false; switch ( action ) { case ACTION_ADD: addContact_p (contact); break; case ACTION_REMOVE: if ( !remove (contact.uid()) ) owarn << "ODefBack(journal)::Unable to remove uid: " << contact.uid() << oendl; break; case ACTION_REPLACE: if ( !replace ( contact ) ) owarn << "ODefBack(journal)::Unable to replace uid: " << contact.uid() << oendl; break; default: owarn << "Unknown action: ignored !" << oendl; break; } }else{ /* Add contact to list */ addContact_p (contact); } /* Move to next element */ element = element->nextChild(); } }else { - owarn << "ODefBack::could not load" << oendl; } delete root; - owarn << "returning from loading" << oendl; return true; } void OPimContactAccessBackend_XML::updateJournal( const OPimContact& cnt, journal_action action ) { QFile f( m_journalName ); bool created = !f.exists(); if ( !f.open(IO_WriteOnly|IO_Append) ) return; QString buf; QCString str; // if the file was created, we have to set the Tag "<CONTACTS>" to // get a XML-File which is readable by our parser. // This is just a cheat, but better than rewrite the parser. if ( created ){ buf = "<Contacts>"; QCString cstr = buf.utf8(); f.writeBlock( cstr.data(), cstr.length() ); } buf = "<Contact "; cnt.save( buf ); buf += " action=\"" + QString::number( (int)action ) + "\" "; buf += "/>\n"; QCString cstr = buf.utf8(); f.writeBlock( cstr.data(), cstr.length() ); } void OPimContactAccessBackend_XML::removeJournal() { QFile f ( m_journalName ); if ( f.exists() ) f.remove(); } } diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h index eaea352..3e4f1e1 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h @@ -1,108 +1,105 @@ /* This file is part of the Opie Project Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) =. Copyright (C) The Opie Team <opie-devel@handhelds.org> .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU Library General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * XML Backend for the OPIE-Contact Database. */ #ifndef _OPimContactAccessBackend_XML_ #define _OPimContactAccessBackend_XML_ #include <opie2/ocontactaccessbackend.h> #include <opie2/ocontactaccess.h> #include <qlist.h> #include <qdict.h> namespace Opie { /* the default xml implementation */ /** * This class is the XML implementation of a Contact backend * it does implement everything available for OPimContact. * @see OPimAccessBackend for more information of available methods */ class OPimContactAccessBackend_XML : public OPimContactAccessBackend { public: OPimContactAccessBackend_XML ( const QString& appname, const QString& filename = QString::null ); bool save(); bool load (); void clear (); bool wasChangedExternally(); QArray<int> allRecords() const; OPimContact find ( int uid ) const; - QArray<int> queryByExample ( const OPimContact &query, int settings, const QDateTime& d = QDateTime() ); - + QArray<int> queryByExample ( const OPimContact &query, int settings, const QDateTime& d )const; QArray<int> matchRegexp( const QRegExp &r ) const; const uint querySettings(); bool hasQuerySettings (uint querySettings) const; - // Currently only asc implemented.. - QArray<int> sorted( bool asc, int , int , int ); bool add ( const OPimContact &newcontact ); bool replace ( const OPimContact &contact ); bool remove ( int uid ); bool reload(); private: enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; void addContact_p( const OPimContact &newcontact ); /* This function loads the xml-database and the journalfile */ bool load( const QString filename, bool isJournal ); void updateJournal( const OPimContact& cnt, journal_action action ); void removeJournal(); protected: bool m_changed; QString m_journalName; QString m_fileName; QString m_appName; QList<OPimContact> m_contactList; QDateTime m_readtime; QDict<OPimContact> m_uidToContact; }; } #endif diff --git a/libopie2/opiepim/backend/odatebookaccessbackend.cpp b/libopie2/opiepim/backend/odatebookaccessbackend.cpp index f3b7b5f..73c7059 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend.cpp @@ -1,216 +1,164 @@ /* 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( OEffectiveEvent::ValueList& 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 ) { - OEffectiveEvent eff; - eff.setEvent( (*it) ); - eff.setDate( dtStart.date() ); - eff.setStartTime( dtStart.time() ); - - /* if not on the same day */ - if ( dtStart.date() != dtEnd.date() ) - eff.setEndTime( QTime(23, 59, 0 ) ); - else - eff.setEndTime( dtEnd.time() ); - - tmpList.append( eff ); - } - - /* we must also check for end date information... */ - if ( dtEnd.date() != dtStart.date() && dtEnd.date() >= from ) { - QDateTime dt = dtStart.addDays( 1 ); - dt.setTime( QTime(0, 0, 0 ) ); - QDateTime dtStop; - if ( dtEnd > to ) - dtStop = to; - else - dtStop = dtEnd; - - while ( dt <= dtStop ) { - OEffectiveEvent eff; - eff.setEvent( (*it) ); - eff.setDate( dt.date() ); - - if ( dt >= from ) { - eff.setStartTime( QTime(0, 0, 0 ) ); - if ( dt.date() == dtEnd.date() ) - eff.setEndTime( dtEnd.time() ); - else - eff.setEndTime( QTime(23, 59, 0 ) ); - tmpList.append( eff ); - } - dt = dt.addDays( 1 ); - } - } +void 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( OEffectiveEvent::ValueList& 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 ); - } - while (rec.nextOcurrence(itDate, repeat ) ) { - if (repeat > to ) break; - OEffectiveEvent eff; - eff.setDate( repeat ); - if ( (*it).isAllDay() ) { - eff.setStartTime( QTime(0, 0, 0 ) ); - eff.setEndTime( QTime(23, 59, 59 ) ); - }else { - /* we only occur by days, not hours/minutes/seconds. Hence - * the actual end and start times will be the same for - * every repeated event. For multi day events this is - * fixed up later if on wronge day span - */ - eff.setStartTime( (*it).startDateTime().time() ); - eff.setEndTime( (*it).endDateTime().time() ); - } - if ( dur != 0 ) { - // multi-day repeating events - QDate sub_it = QMAX( repeat, from ); - QDate startDate = repeat; - QDate endDate = startDate.addDays( dur ); - - while ( sub_it <= endDate && sub_it <= to ) { - OEffectiveEvent tmpEff = eff; - tmpEff.setEvent( (*it) ); - if ( sub_it != startDate ) - tmpEff.setStartTime( QTime(0, 0, 0 ) ); - if ( sub_it != endDate ) - tmpEff.setEndTime( QTime( 23, 59, 59 ) ); - - tmpEff.setDate( sub_it ); - tmpEff.setEffectiveDates( startDate, endDate ); - tmpList.append( tmpEff ); - - sub_it = sub_it.addDays( 1 ); - } - itDate = endDate; - }else { - eff.setEvent( (*it) ); - tmpList.append( eff ); - itDate = repeat.addDays( 1 ); - } - } +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() { } -OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDate& from, - const QDate& to ) { - OEffectiveEvent::ValueList tmpList; - OPimEvent::ValueList list = directNonRepeats(); +OPimBackendOccurrence::List ODateBookAccessBackend::occurrences( const QDate& from, + const QDate& to )const { + OPimBackendOccurrence::List tmpList; - events( tmpList, list, from, to ); + events( tmpList, directNonRepeats(), from, to ); repeat( tmpList, directRawRepeats(),from,to ); - list = directRawRepeats(); // Useless, isn't it ? (eilers) - - qHeapSort( tmpList ); return tmpList; } -OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveEvents( const QDateTime& dt ) { - OEffectiveEvent::ValueList day = effectiveEvents( dt.date(), dt.date() ); - OEffectiveEvent::ValueList::Iterator it; - - OEffectiveEvent::ValueList tmpList; - QDateTime dtTmp; - for ( it = day.begin(); it != day.end(); ++it ) { - dtTmp = QDateTime( (*it).date(), (*it).startTime() ); - if ( QABS(dt.secsTo(dtTmp) ) < 60 ) - tmpList.append( (*it) ); - } +OPimBackendOccurrence::List ODateBookAccessBackend::occurrences( const QDateTime& dt )const { + OPimBackendOccurrence::List day = occurrences( dt.date(), dt.date() ); - return tmpList; + return filterOccurrences( day, dt ); } -OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDate& from, - const QDate& to ) { - OEffectiveEvent::ValueList tmpList; +OPimBackendOccurrence::List ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDate& from, + const QDate& to )const { + OPimBackendOccurrence::List tmpList; OPimEvent::ValueList list = directNonRepeats(); events( tmpList, list, from, to ); - qHeapSort( tmpList ); return tmpList; } -OEffectiveEvent::ValueList ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt ) { - OEffectiveEvent::ValueList day = effectiveNonRepeatingEvents( dt.date(), dt.date() ); - OEffectiveEvent::ValueList::Iterator it; +OPimBackendOccurrence::List ODateBookAccessBackend::effectiveNonRepeatingEvents( const QDateTime& dt )const { + OPimBackendOccurrence::List day = effectiveNonRepeatingEvents( dt.date(), dt.date() ); + return filterOccurrences( day,dt ); +} + + +UIDArray ODateBookAccessBackend::queryByExample( const OPimEvent&, int settings, + const QDateTime& d )const { + return UIDArray(); +} + +UIDArray ODateBookAccessBackend::sorted( const UIDArray&, bool asc, int, int, const QArray<int>& )const { + return UIDArray(); +} - OEffectiveEvent::ValueList tmpList; - QDateTime dtTmp; - for ( it = day.begin(); it != day.end(); ++it ) { - dtTmp = QDateTime( (*it).date(), (*it).startTime() ); - if ( QABS(dt.secsTo(dtTmp) ) < 60 ) - tmpList.append( (*it) ); +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 a9cce6a..8927ca1 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend.h @@ -1,121 +1,114 @@ /* 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: - typedef int UID; - /** * c'tor without parameter */ ODateBookAccessBackend(); ~ODateBookAccessBackend(); /** * This method should return a list of UIDs containing - * all events. No filter should be applied - * @return list of events - */ - virtual QArray<UID> rawEvents()const = 0; - - /** - * This method should return a list of UIDs containing * all repeating events. No filter should be applied * @return list of repeating events */ - virtual QArray<UID> rawRepeats()const = 0; + 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 QArray<UID> nonRepeats() const = 0; + 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() = 0; + virtual OPimEvent::ValueList directNonRepeats()const = 0; /** * Same as above but return raw repeats! */ - virtual OPimEvent::ValueList directRawRepeats() = 0; + 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 OEffectiveEvent::ValueList effectiveEvents( const QDate& from, const QDate& to ); + virtual OPimBackendOccurrence::List effectiveNonRepeatingEvents( const QDate& from, const QDate& to )const; /** * this is an overloaded member function - * @see effectiveEvents( const QDate& from, const QDate& to ) - */ - virtual OEffectiveEvent::ValueList effectiveEvents( const QDateTime& start ); - - /** - * Effective Events are special event occuring during a time frame. This method does calcualte - * EffectiveEvents bases on the directNonRepeats and directRawRepeats. You may implement this method - * yourself + * @see effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) */ - virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDate& from, const QDate& to ); + virtual OPimBackendOccurrence::List effectiveNonRepeatingEvents( const QDateTime& start )const; /** - * this is an overloaded member function - * @see effectiveNonRepeatingEvents( const QDate& from, const QDate& to ) + * Common and probably inefficent implementation + * for queryByExample, sorted + * and occurrences */ - virtual OEffectiveEvent::ValueList effectiveNonRepeatingEvents( const QDateTime& start ); - +//@{ + UIDArray queryByExample( 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/odatebookaccessbackend_sql.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp index 105c106..41b714e 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp @@ -74,386 +74,375 @@ namespace { : OSQLQuery(), m_uid( uid ) { } FindCustomQuery::FindCustomQuery(const QArray<int>& ints) : OSQLQuery(), m_uids( ints ){ } FindCustomQuery::~FindCustomQuery() { } QString FindCustomQuery::query()const{ // if ( m_uids.count() == 0 ) return single(); } QString FindCustomQuery::single()const{ QString qu = "select uid, type, value from custom_data where uid = "; qu += QString::number(m_uid); return qu; } } namespace Opie { ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& , const QString& fileName ) : ODateBookAccessBackend(), m_driver( NULL ) { m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName; // Get the standart sql-driver from the OSQLManager.. OSQLManager man; m_driver = man.standard(); m_driver->setUrl( m_fileName ); initFields(); load(); } ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() { if( m_driver ) delete m_driver; } void ODateBookAccessBackend_SQL::initFields() { // This map contains the translation of the fieldtype id's to // the names of the table columns m_fieldMap.insert( OPimEvent::FUid, "uid" ); m_fieldMap.insert( OPimEvent::FCategories, "Categories" ); m_fieldMap.insert( OPimEvent::FDescription, "Description" ); m_fieldMap.insert( OPimEvent::FLocation, "Location" ); m_fieldMap.insert( OPimEvent::FType, "Type" ); m_fieldMap.insert( OPimEvent::FAlarm, "Alarm" ); m_fieldMap.insert( OPimEvent::FSound, "Sound" ); m_fieldMap.insert( OPimEvent::FRType, "RType" ); m_fieldMap.insert( OPimEvent::FRWeekdays, "RWeekdays" ); m_fieldMap.insert( OPimEvent::FRPosition, "RPosition" ); m_fieldMap.insert( OPimEvent::FRFreq, "RFreq" ); m_fieldMap.insert( OPimEvent::FRHasEndDate, "RHasEndDate" ); m_fieldMap.insert( OPimEvent::FREndDate, "REndDate" ); m_fieldMap.insert( OPimEvent::FRCreated, "RCreated" ); m_fieldMap.insert( OPimEvent::FRExceptions, "RExceptions" ); m_fieldMap.insert( OPimEvent::FStart, "Start" ); m_fieldMap.insert( OPimEvent::FEnd, "End" ); m_fieldMap.insert( OPimEvent::FNote, "Note" ); m_fieldMap.insert( OPimEvent::FTimeZone, "TimeZone" ); m_fieldMap.insert( OPimEvent::FRecParent, "RecParent" ); m_fieldMap.insert( OPimEvent::FRecChildren, "Recchildren" ); // Create a map that maps the column name to the id QMapConstIterator<int, QString> it; for ( it = m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ m_reverseFieldMap.insert( it.data(), it.key() ); } } bool ODateBookAccessBackend_SQL::load() { if (!m_driver->open() ) return false; // Don't expect that the database exists. // It is save here to create the table, even if it // do exist. ( Is that correct for all databases ?? ) QString qu = "create table datebook( uid INTEGER PRIMARY KEY "; QMap<int, QString>::Iterator it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ qu += QString( ",%1 VARCHAR(10)" ).arg( it.data() ); } qu += " );"; qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR(10), priority INTEGER, value VARCHAR(10), PRIMARY KEY /* identifier */ (uid, id) );"; - owarn << "command: " << qu << "" << oendl; - OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ) return false; update(); return true; } void ODateBookAccessBackend_SQL::update() { QString qu = "select uid from datebook"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ // m_uids.clear(); return; } m_uids = extractUids( res ); } bool ODateBookAccessBackend_SQL::reload() { return load(); } bool ODateBookAccessBackend_SQL::save() { return m_driver->close(); // Shouldn't m_driver->sync be better than close ? (eilers) } QArray<int> ODateBookAccessBackend_SQL::allRecords()const { return m_uids; } QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OPimEvent&, int, const QDateTime& ) { return QArray<int>(); } void ODateBookAccessBackend_SQL::clear() { QString qu = "drop table datebook;"; qu += "drop table custom_data;"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); reload(); } OPimEvent ODateBookAccessBackend_SQL::find( int uid ) const{ odebug << "ODateBookAccessBackend_SQL::find( " << uid << " )" << oendl; QString qu = "select *"; qu += "from datebook where uid = " + QString::number(uid); odebug << "Query: " << qu << "" << oendl; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); OSQLResultItem resItem = res.first(); // Create Map for date event and insert UID QMap<int,QString> dateEventMap; dateEventMap.insert( OPimEvent::FUid, QString::number( uid ) ); // Now insert the data out of the columns into the map. QMapConstIterator<int, QString> it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ dateEventMap.insert( m_reverseFieldMap[*it], resItem.data( *it ) ); } // Last step: Put map into date event, add custom map and return it OPimEvent retDate( dateEventMap ); retDate.setExtraMap( requestCustom( uid ) ); odebug << "ODateBookAccessBackend_SQL::find( " << uid << " ) end" << oendl; return retDate; } // FIXME: Speed up update of uid's.. bool ODateBookAccessBackend_SQL::add( const OPimEvent& ev ) { QMap<int,QString> eventMap = ev.toMap(); QString qu = "insert into datebook VALUES( " + QString::number( ev.uid() ); QMap<int, QString>::Iterator it; for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ if ( !eventMap[it.key()].isEmpty() ) qu += QString( ",\"%1\"" ).arg( eventMap[it.key()] ); else qu += QString( ",\"\"" ); } qu += " );"; // Add custom entries int id = 0; QMap<QString, QString> customMap = ev.toExtraMap(); for( QMap<QString, QString>::Iterator it = customMap.begin(); it != customMap.end(); ++it ){ qu += "insert into custom_data VALUES(" + QString::number( ev.uid() ) + "," + QString::number( id++ ) + ",'" + it.key() //.latin1() + "'," + "0" // Priority for future enhancements + ",'" + it.data() //.latin1() + "');"; } - owarn << "add " << qu << "" << oendl; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ return false; } // Update list of uid's update(); return true; } // FIXME: Speed up update of uid's.. bool ODateBookAccessBackend_SQL::remove( int uid ) { QString qu = "DELETE from datebook where uid = " + QString::number( uid ) + ";"; qu += "DELETE from custom_data where uid = " + QString::number( uid ) + ";"; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ return false; } // Update list of uid's update(); return true; } bool ODateBookAccessBackend_SQL::replace( const OPimEvent& ev ) { remove( ev.uid() ); return add( ev ); } -QArray<int> ODateBookAccessBackend_SQL::rawEvents()const -{ - return allRecords(); -} QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const { QString qu = "select uid from datebook where RType!=\"\" AND RType!=\"NoRepeat\""; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> nix; return nix; } return extractUids( res ); } QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const { QString qu = "select uid from datebook where RType=\"\" or RType=\"NoRepeat\""; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); if ( res.state() != OSQLResult::Success ){ QArray<int> nix; return nix; } return extractUids( res ); } -OPimEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats() +OPimEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats()const { QArray<int> nonRepUids = nonRepeats(); OPimEvent::ValueList list; for (uint i = 0; i < nonRepUids.count(); ++i ){ list.append( find( nonRepUids[i] ) ); } return list; } -OPimEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats() +OPimEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats()const { QArray<int> rawRepUids = rawRepeats(); OPimEvent::ValueList list; for (uint i = 0; i < rawRepUids.count(); ++i ){ list.append( find( rawRepUids[i] ) ); } return list; } QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const { QString qu = "SELECT uid FROM datebook WHERE ("; // Do it make sense to search other fields, too ? qu += " rlike(\""+ r.pattern() + "\", Location ) OR"; qu += " rlike(\""+ r.pattern() + "\", Note )"; qu += " )"; odebug << "query: " << qu << "" << oendl; OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); return extractUids( res ); } /* ===== Private Functions ========================================== */ QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const { - owarn << "extractUids" << oendl; QTime t; t.start(); OSQLResultItem::ValueList list = res.results(); OSQLResultItem::ValueList::Iterator it; QArray<int> ints(list.count() ); - owarn << " count = " << list.count() << "" << oendl; int i = 0; for (it = list.begin(); it != list.end(); ++it ) { ints[i] = (*it).data("uid").toInt(); i++; } - owarn << "extractUids ready: count2 = " << i << " needs " << t.elapsed() << " ms" << oendl; return ints; } QMap<QString, QString> ODateBookAccessBackend_SQL::requestCustom( int uid ) const { QTime t; t.start(); QMap<QString, QString> customMap; FindCustomQuery query( uid ); OSQLResult res_custom = m_driver->query( &query ); if ( res_custom.state() == OSQLResult::Failure ) { - owarn << "OSQLResult::Failure in find query !!" << oendl; QMap<QString, QString> empty; return empty; } OSQLResultItem::ValueList list = res_custom.results(); OSQLResultItem::ValueList::Iterator it = list.begin(); for ( ; it != list.end(); ++it ) { customMap.insert( (*it).data( "type" ), (*it).data( "value" ) ); } odebug << "RequestCustom needed: " << t.elapsed() << " ms" << oendl; return customMap; } } diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_sql.h b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h index b624159..a649d25 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_sql.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h @@ -1,99 +1,98 @@ /* This file is part of the Opie Project Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) =. Copyright (C) The Opie Team <opie-devel@handhelds.org> .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU Library General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H #define OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H #include <qmap.h> #include <opie2/osqlresult.h> #include <opie2/odatebookaccessbackend.h> namespace Opie { namespace DB { class OSQLDriver; } } namespace Opie { /** * This is the default SQL implementation for DateBoook SQL storage * It fully implements the interface * @see ODateBookAccessBackend * @see OPimAccessBackend */ class ODateBookAccessBackend_SQL : public ODateBookAccessBackend { public: ODateBookAccessBackend_SQL( const QString& appName, const QString& fileName = QString::null); ~ODateBookAccessBackend_SQL(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> matchRegexp(const QRegExp &r) const; QArray<int> queryByExample( const OPimEvent&, int, const QDateTime& d = QDateTime() ); OPimEvent find( int uid )const; void clear(); bool add( const OPimEvent& ev ); bool remove( int uid ); bool replace( const OPimEvent& ev ); - QArray<UID> rawEvents()const; QArray<UID> rawRepeats()const; QArray<UID> nonRepeats()const; - OPimEvent::ValueList directNonRepeats(); - OPimEvent::ValueList directRawRepeats(); + OPimEvent::ValueList directNonRepeats()const; + OPimEvent::ValueList directRawRepeats()const; private: bool loadFile(); QString m_fileName; QArray<int> m_uids; QMap<int, QString> m_fieldMap; QMap<QString, int> m_reverseFieldMap; Opie::DB::OSQLDriver* m_driver; class Private; Private *d; void initFields(); void update(); QArray<int> extractUids( Opie::DB::OSQLResult& res ) const; QMap<QString, QString> requestCustom( int uid ) const; }; } #endif diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp index 0f99d50..55e47e2 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp @@ -29,193 +29,192 @@ /* OPIE */ #include <opie2/opimnotifymanager.h> #include <opie2/opimrecurrence.h> #include <opie2/opimtimezone.h> #include <opie2/odatebookaccessbackend_xml.h> #include <opie2/odebug.h> #include <qtopia/global.h> #include <qtopia/stringutil.h> #include <qtopia/timeconversion.h> /* QT */ #include <qasciidict.h> #include <qfile.h> /* STD */ #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> using namespace Opie; namespace { // FROM TT again char *strstrlen(const char *haystack, int hLen, const char* needle, int nLen) { char needleChar; char haystackChar; if (!needle || !haystack || !hLen || !nLen) return 0; const char* hsearch = haystack; if ((needleChar = *needle++) != 0) { nLen--; //(to make up for needle++) do { do { if ((haystackChar = *hsearch++) == 0) return (0); if (hsearch >= haystack + hLen) return (0); } while (haystackChar != needleChar); } while (strncmp(hsearch, needle, QMIN(hLen - (hsearch - haystack), nLen)) != 0); hsearch--; } return ((char *)hsearch); } } namespace { time_t start, end, created, rp_end; OPimRecurrence* rec; static OPimRecurrence* recur() { if (!rec) rec = new OPimRecurrence; return rec; } int alarmTime; int snd; enum Attribute{ FDescription = 0, FLocation, FCategories, FUid, FType, FAlarm, FSound, FRType, FRWeekdays, FRPosition, FRFreq, FRHasEndDate, FREndDate, FRStart, FREnd, FNote, FCreated, // Should't this be called FRCreated ? FTimeZone, FRecParent, FRecChildren, FExceptions }; // FIXME: Use OPimEvent::toMap() here !! (eilers) static void save( const OPimEvent& ev, QString& buf ) { - owarn << "Saving " << ev.uid() << " " << ev.description() << "" << oendl; buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; if (!ev.location().isEmpty() ) buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; if (!ev.categories().isEmpty() ) buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; buf += " uid=\"" + QString::number( ev.uid() ) + "\""; if (ev.isAllDay() ) buf += " type=\"AllDay\""; // is that all ?? (eilers) if (ev.hasNotifiers() ) { OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; if ( alarm.sound() == OPimAlarm::Loud ) buf += "loud"; else buf += "silent"; buf += "\""; } if ( ev.hasRecurrence() ) { buf += ev.recurrence().toString(); } /* * fscking timezones :) well, we'll first convert * the QDateTime to a QDateTime in UTC time * and then we'll create a nice time_t */ OPimTimeZone zone( (ev.timeZone().isEmpty()||ev.isAllDay()) ? OPimTimeZone::utc() : OPimTimeZone::current() ); buf += " start=\"" + QString::number( zone.fromDateTime( ev.startDateTime())) + "\""; buf += " end=\"" + QString::number( zone.fromDateTime( ev.endDateTime() )) + "\""; if (!ev.note().isEmpty() ) { buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; } /* * Don't save a timezone if AllDay Events * as they're UTC only anyway */ if (!ev.isAllDay() ) { buf += " timezone=\""; if ( ev.timeZone().isEmpty() ) buf += "None"; else buf += ev.timeZone(); buf += "\""; } if (ev.parent() != 0 ) { buf += " recparent=\""+QString::number(ev.parent() )+"\""; } if (ev.children().count() != 0 ) { QArray<int> children = ev.children(); buf += " recchildren=\""; for ( uint i = 0; i < children.count(); i++ ) { if ( i != 0 ) buf += " "; buf += QString::number( children[i] ); } buf+= "\""; } // skip custom writing } static bool saveEachEvent( const QMap<int, OPimEvent>& list, QFile& file ) { QMap<int, OPimEvent>::ConstIterator it; QString buf; QCString str; int total_written; for ( it = list.begin(); it != list.end(); ++it ) { buf = "<event"; save( it.data(), buf ); buf += " />\n"; str = buf.utf8(); total_written = file.writeBlock(str.data(), str.length() ); if ( total_written != int(str.length() ) ) return false; } return true; } } namespace Opie { ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , const QString& fileName ) : ODateBookAccessBackend() { m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; m_changed = false; } ODateBookAccessBackend_XML::~ODateBookAccessBackend_XML() { @@ -233,438 +232,433 @@ bool ODateBookAccessBackend_XML::save() { int total_written; QString strFileNew = m_name + ".new"; QFile f( strFileNew ); if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; buf += "<events>\n"; QCString str = buf.utf8(); total_written = f.writeBlock( str.data(), str.length() ); if ( total_written != int(str.length() ) ) { f.close(); QFile::remove( strFileNew ); return false; } if (!saveEachEvent( m_raw, f ) ) { f.close(); QFile::remove( strFileNew ); return false; } if (!saveEachEvent( m_rep, f ) ) { f.close(); QFile::remove( strFileNew ); return false; } buf = "</events>\n</DATEBOOK>\n"; str = buf.utf8(); total_written = f.writeBlock( str.data(), str.length() ); if ( total_written != int(str.length() ) ) { f.close(); QFile::remove( strFileNew ); return false; } f.close(); if ( ::rename( strFileNew, m_name ) < 0 ) { QFile::remove( strFileNew ); return false; } m_changed = false; return true; } QArray<int> ODateBookAccessBackend_XML::allRecords()const { QArray<int> ints( m_raw.count()+ m_rep.count() ); uint i = 0; QMap<int, OPimEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { ints[i] = it.key(); i++; } for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } QArray<int> ODateBookAccessBackend_XML::queryByExample(const OPimEvent&, int, const QDateTime& ) { return QArray<int>(); } void ODateBookAccessBackend_XML::clear() { m_changed = true; m_raw.clear(); m_rep.clear(); } OPimEvent ODateBookAccessBackend_XML::find( int uid ) const{ if ( m_raw.contains( uid ) ) return m_raw[uid]; else return m_rep[uid]; } bool ODateBookAccessBackend_XML::add( const OPimEvent& ev ) { m_changed = true; if (ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); else m_raw.insert( ev.uid(), ev ); return true; } bool ODateBookAccessBackend_XML::remove( int uid ) { m_changed = true; m_raw.remove( uid ); m_rep.remove( uid ); return true; } bool ODateBookAccessBackend_XML::replace( const OPimEvent& ev ) { replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers) return add( ev ); } -QArray<int> ODateBookAccessBackend_XML::rawEvents()const { - return allRecords(); -} + QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { QArray<int> ints( m_rep.count() ); uint i = 0; QMap<int, OPimEvent>::ConstIterator it; for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { QArray<int> ints( m_raw.count() ); uint i = 0; QMap<int, OPimEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } -OPimEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { +OPimEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats()const { OPimEvent::ValueList list; QMap<int, OPimEvent>::ConstIterator it; for (it = m_raw.begin(); it != m_raw.end(); ++it ) list.append( it.data() ); return list; } -OPimEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { +OPimEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats()const { OPimEvent::ValueList list; QMap<int, OPimEvent>::ConstIterator it; for (it = m_rep.begin(); it != m_rep.end(); ++it ) list.append( it.data() ); return list; } // FIXME: Use OPimEvent::fromMap() (eilers) bool ODateBookAccessBackend_XML::loadFile() { m_changed = false; int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); if ( fd < 0 ) return false; struct stat attribute; if ( ::fstat(fd, &attribute ) == -1 ) { ::close( fd ); return false; } void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if ( map_addr == ( (caddr_t)-1) ) { ::close( fd ); return false; } ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); ::close( fd ); QAsciiDict<int> dict(FExceptions+1); dict.setAutoDelete( true ); dict.insert( "description", new int(FDescription) ); dict.insert( "location", new int(FLocation) ); dict.insert( "categories", new int(FCategories) ); dict.insert( "uid", new int(FUid) ); dict.insert( "type", new int(FType) ); dict.insert( "alarm", new int(FAlarm) ); dict.insert( "sound", new int(FSound) ); dict.insert( "rtype", new int(FRType) ); dict.insert( "rweekdays", new int(FRWeekdays) ); dict.insert( "rposition", new int(FRPosition) ); dict.insert( "rfreq", new int(FRFreq) ); dict.insert( "rhasenddate", new int(FRHasEndDate) ); dict.insert( "enddt", new int(FREndDate) ); dict.insert( "start", new int(FRStart) ); dict.insert( "end", new int(FREnd) ); dict.insert( "note", new int(FNote) ); dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ?? dict.insert( "recparent", new int(FRecParent) ); dict.insert( "recchildren", new int(FRecChildren) ); dict.insert( "exceptions", new int(FExceptions) ); dict.insert( "timezone", new int(FTimeZone) ); // initialiaze db hack m_noTimeZone = true; char* dt = (char*)map_addr; int len = attribute.st_size; int i = 0; char* point; const char* collectionString = "<event "; int strLen = ::strlen(collectionString); int *find; while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { i = point -dt; i+= strLen; alarmTime = -1; snd = 0; // silent OPimEvent ev; rec = 0; while ( TRUE ) { while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) ++i; if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) break; // we have another attribute, read it. int j = i; while ( j < len && dt[j] != '=' ) ++j; QCString attr( dt+i, j-i+1); i = ++j; // skip = // find the start of quotes while ( i < len && dt[i] != '"' ) ++i; j = ++i; bool haveUtf = FALSE; bool haveEnt = FALSE; while ( j < len && dt[j] != '"' ) { if ( ((unsigned char)dt[j]) > 0x7f ) haveUtf = TRUE; if ( dt[j] == '&' ) haveEnt = TRUE; ++j; } if ( i == j ) { // empty value i = j + 1; continue; } QCString value( dt+i, j-i+1 ); i = j + 1; QString str = (haveUtf ? QString::fromUtf8( value ) : QString::fromLatin1( value ) ); if ( haveEnt ) str = Qtopia::plainString( str ); /* * add key + value */ find = dict[attr.data()]; if (!find) ev.setCustomField( attr, str ); else { setField( ev, *find, str ); } } /* time to finalize */ finalizeRecord( ev ); delete rec; m_noTimeZone = true; } ::munmap(map_addr, attribute.st_size ); m_changed = false; // changed during add return true; } // FIXME: Use OPimEvent::fromMap() which makes this obsolete.. (eilers) void ODateBookAccessBackend_XML::finalizeRecord( OPimEvent& ev ) { /* * quirk to import datebook files. They normally don't have a * timeZone attribute and we treat this as to use OPimTimeZone::current() */ if (m_noTimeZone ) ev.setTimeZone( OPimTimeZone::current().timeZone() ); /* AllDay is alway in UTC */ if ( ev.isAllDay() ) { OPimTimeZone utc = OPimTimeZone::utc(); ev.setStartDateTime( utc.toDateTime( start ) ); ev.setEndDateTime ( utc.toDateTime( end ) ); }else { /* to current date time */ OPimTimeZone to_zone( ev.timeZone().isEmpty() ? OPimTimeZone::utc() : OPimTimeZone::current() ); ev.setStartDateTime(to_zone.toDateTime( start)); ev.setEndDateTime (to_zone.toDateTime( end)); } if ( rec && rec->doesRecur() ) { OPimTimeZone utc = OPimTimeZone::utc(); OPimRecurrence recu( *rec ); // call copy c'tor; recu.setEndDate ( utc.toDateTime( rp_end ).date() ); recu.setCreatedDateTime( utc.toDateTime( created ) ); recu.setStart( ev.startDateTime().date() ); ev.setRecurrence( recu ); } if (alarmTime != -1 ) { QDateTime dt = ev.startDateTime().addSecs( -1*alarmTime*60 ); OPimAlarm al( snd , dt ); ev.notifiers().add( al ); } if ( m_raw.contains( ev.uid() ) || m_rep.contains( ev.uid() ) ) { - owarn << "already contains assign uid" << oendl; ev.setUid( 1 ); } if ( ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); else m_raw.insert( ev.uid(), ev ); } void ODateBookAccessBackend_XML::setField( OPimEvent& e, int id, const QString& value) { -// owarn << " setting " << value << "" << oendl; switch( id ) { case FDescription: e.setDescription( value ); break; case FLocation: e.setLocation( value ); break; case FCategories: e.setCategories( e.idsFromString( value ) ); break; case FUid: e.setUid( value.toInt() ); break; case FType: if ( value == "AllDay" ) { e.setAllDay( true ); } break; case FAlarm: alarmTime = value.toInt(); break; case FSound: snd = value == "loud" ? OPimAlarm::Loud : OPimAlarm::Silent; break; // recurrence stuff case FRType: if ( value == "Daily" ) recur()->setType( OPimRecurrence::Daily ); else if ( value == "Weekly" ) recur()->setType( OPimRecurrence::Weekly); else if ( value == "MonthlyDay" ) recur()->setType( OPimRecurrence::MonthlyDay ); else if ( value == "MonthlyDate" ) recur()->setType( OPimRecurrence::MonthlyDate ); else if ( value == "Yearly" ) recur()->setType( OPimRecurrence::Yearly ); else recur()->setType( OPimRecurrence::NoRepeat ); break; case FRWeekdays: recur()->setDays( value.toInt() ); break; case FRPosition: recur()->setPosition( value.toInt() ); break; case FRFreq: recur()->setFrequency( value.toInt() ); break; case FRHasEndDate: recur()->setHasEndDate( value.toInt() ); break; case FREndDate: { rp_end = (time_t) value.toLong(); break; } case FRStart: { start = (time_t) value.toLong(); break; } case FREnd: { end = ( (time_t) value.toLong() ); break; } case FNote: e.setNote( value ); break; case FCreated: created = value.toInt(); break; case FRecParent: e.setParent( value.toInt() ); break; case FRecChildren:{ QStringList list = QStringList::split(' ', value ); for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { e.addChild( (*it).toInt() ); } } break; case FExceptions:{ QStringList list = QStringList::split(' ', value ); for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); - owarn << "adding exception " << date.toString() << "" << oendl; recur()->exceptions().append( date ); } } break; case FTimeZone: m_noTimeZone = false; if ( value != "None" ) e.setTimeZone( value ); break; default: break; } } QArray<int> ODateBookAccessBackend_XML::matchRegexp( const QRegExp &r ) const { QArray<int> m_currentQuery( m_raw.count()+ m_rep.count() ); uint arraycounter = 0; QMap<int, OPimEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) if ( it.data().match( r ) ) m_currentQuery[arraycounter++] = it.data().uid(); for ( it = m_rep.begin(); it != m_rep.end(); ++it ) if ( it.data().match( r ) ) m_currentQuery[arraycounter++] = it.data().uid(); // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } } diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h b/libopie2/opiepim/backend/odatebookaccessbackend_xml.h index af5b114..cb19f76 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.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_DATE_BOOK_ACCESS_BACKEND_XML__H #define OPIE_DATE_BOOK_ACCESS_BACKEND_XML__H #include <qmap.h> #include <opie2/odatebookaccessbackend.h> namespace Opie { /** * This is the default XML implementation for DateBoook XML storage * It fully implements the interface * @see ODateBookAccessBackend * @see OPimAccessBackend */ class ODateBookAccessBackend_XML : public ODateBookAccessBackend { public: ODateBookAccessBackend_XML( const QString& appName, const QString& fileName = QString::null); ~ODateBookAccessBackend_XML(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; QArray<int> matchRegexp(const QRegExp &r) const; QArray<int> queryByExample( const OPimEvent&, int, const QDateTime& d = QDateTime() ); OPimEvent find( int uid )const; void clear(); bool add( const OPimEvent& ev ); bool remove( int uid ); bool replace( const OPimEvent& ev ); QArray<UID> rawEvents()const; QArray<UID> rawRepeats()const; QArray<UID> nonRepeats()const; - OPimEvent::ValueList directNonRepeats(); - OPimEvent::ValueList directRawRepeats(); + OPimEvent::ValueList directNonRepeats()const; + OPimEvent::ValueList directRawRepeats()const; private: bool m_changed :1 ; bool m_noTimeZone : 1; bool loadFile(); inline void finalizeRecord( OPimEvent& ev ); inline void setField( OPimEvent&, int field, const QString& val ); QString m_name; QMap<int, OPimEvent> m_raw; QMap<int, OPimEvent> m_rep; struct Data; Data* data; class Private; Private *d; }; } #endif diff --git a/libopie2/opiepim/backend/opimaccessbackend.h b/libopie2/opiepim/backend/opimaccessbackend.h index 26af762..0d112c9 100644 --- a/libopie2/opiepim/backend/opimaccessbackend.h +++ b/libopie2/opiepim/backend/opimaccessbackend.h @@ -1,196 +1,423 @@ /* 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 base class - * for all private backends - * it operates on OPimRecord as the base class - * and it's responsible for fast manipulating - * the resource the implementation takes care - * of + * 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; - /** The access hint from the frontend */ + //@{ OPimAccessBackend(int access = 0); virtual ~OPimAccessBackend(); + //@} - /** - * load the resource - */ + //@{ virtual bool load() = 0; - - /** - * reload the resource - */ virtual bool reload() = 0; - - /** - * save the resource and - * all it's changes - */ virtual bool save() = 0; + virtual void clear() = 0; + //@} - /** - * return an array of - * all available uids - */ - virtual QArray<int> allRecords()const = 0; - /** - * return a List of records - * that match the regex - */ - virtual QArray<int> matchRegexp(const QRegExp &r) const = 0; + //@{ + virtual UIDArray allRecords()const = 0; + virtual UIDArray matchRegexp(const QRegExp &r) const; + virtual UIDArray queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() )const = 0; + virtual UIDArray queryByExample( const OPimRecord* rec, int, const QDateTime& d = QDateTime() )const; + virtual UIDArray sorted( const UIDArray&, bool asc, int sortOrder, int sortFilter, const QArray<int>& cats )const; + 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; + //@} - /** - * queryByExample for T with the given Settings - * - */ - virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0; - /** - * find the OPimRecord with uid @param uid - * returns T and T.isEmpty() if nothing was found - */ - virtual T find( int uid )const = 0; + //@{ + virtual T find(UID uid )const = 0; + virtual T find(UID uid, const QArray<UID>& items, + uint current, typename Frontend::CacheDirection )const ; + //@} - virtual T find( int uid, const QArray<int>& items, - uint current, typename Frontend::CacheDirection ) const; - /** - * clear the back end - */ - virtual void clear() = 0; - /** - * add T - */ + //@{ virtual bool add( const T& t ) = 0; + virtual bool remove( UID uid ) = 0; + virtual bool replace( const T& t ) = 0; + //@} - /** - * remove - */ - virtual bool remove( int uid ) = 0; - /** - * replace a record with T.uid() - */ - virtual bool replace( const T& t ) = 0; - /* - * setTheFrontEnd!!! - */ void setFrontend( Frontend* front ); /** * set the read ahead count */ void setReadAhead( uint count ); protected: + //@{ int access()const; - void cache( const T& t )const; - - /** - * use a prime number here! - */ void setSaneCacheSize( int ); - uint readAhead()const; + //@} private: OPimAccessBackendPrivate *d; Frontend* m_front; uint m_read; int m_acc; }; template <class T> OPimAccessBackend<T>::OPimAccessBackend(int acc) : m_acc( acc ) { m_front = 0l; } template <class T> OPimAccessBackend<T>::~OPimAccessBackend() { } + +/* + * 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 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( const UIDArray& ids, bool, + int, int, const QArray<int>& ) const { + return ids; +} + +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/opimbackendoccurrence.cpp b/libopie2/opiepim/backend/opimbackendoccurrence.cpp new file mode 100644 index 0000000..8af930d --- a/dev/null +++ b/libopie2/opiepim/backend/opimbackendoccurrence.cpp @@ -0,0 +1,241 @@ +/* + This file is part of the Opie Project + Copyright (C) 2004 Holger Hans Peter 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. +*/ + +#include "opimbackendoccurrence.h" + +namespace Opie { + +OPimBackendOccurrence::OPimBackendOccurrence() {} +/** + * \brief The occurence is only on the specefic Day + * + * If an occurrence is only a day without any time associated + * use this Constructor. + * \sa timeAssociated() will return false. + * + * @param date The Date this Occurence takes place + * @param uid The \sa UID of the associated OPimRecord + * @param sum The optional summary + * + */ +OPimBackendOccurrence::OPimBackendOccurrence( const QDate& date, + const UID& uid, + const QString& sum ) + : m_start( date ), m_end( date ), m_uid( uid ), + m_haveTime(false ), m_summary( sum ) +{} + +/** + * \brief An Occurrence with a start day and end day without time + * + * Overloaded Constructor. Use this if you've a start date and + * end date but no time. If you need to overwrite the summary + * use setSummary. + * \sa timeAssociated() will return false. + * + * @param date The Start Date + * @param end Tne End Date + * @param uid The UID of the associated record + * + * @see setSummary + */ +OPimBackendOccurrence::OPimBackendOccurrence( const QDate& date, + const QDate& end, + const UID& uid) + : m_start( date ), m_end( end ), m_uid( uid ), m_haveTime( false ) +{} + + +/** + * \brief Use Start and End Date with Time + * + * Overloaded Constructor to use Dates with Time time associated + * to it. \sa timeAssociated() will return true. + * + * @param date The Start Date and Time of the occurrence + * @param end The End Date and Time of the occurrence + * @param uid The UID of the \sa OPimRecord. + */ +OPimBackendOccurrence::OPimBackendOccurrence( const QDateTime& date, + const QDateTime& end, + const UID& uid ) + : m_start( date ), m_end( end ), m_uid( uid ), m_haveTime( true ) +{} + +/** + * \brief Return the Start Date and Time + * + * @return This method will return the start + * Date and Time. Time is only valid if + * \sa timeAssociated() is true. + * + */ +QDateTime OPimBackendOccurrence::startDateTime()const { + return m_start; +} + +/** + * \brief Return the Start Date and Time + * + * @return This will return the end Date and Time. The + * limitation for Time is the same as in startDateTime + * + * @see startDateTime() + */ +QDateTime OPimBackendOccurrence::endDateTime()const { + return m_end; +} + +/** + * \brief Return the UID of the Associated OPimRecord + * + * @return the associated OPimRecord + */ +UID OPimBackendOccurrence::uid()const { + return m_uid; +} + +/** + * \brief Return if there is a time associated or not + * + * If a time is present with start and end date this method + * will return true. There is no direct way to manipulate + * that attribute. But \sa setStartDate and \sa setStartDateTime + * will change it. + * + * @return Return true if a time is available with the date + * + */ +bool OPimBackendOccurrence::isAllDay()const { + return m_haveTime; +} + +/** + * @return The special summary that will overwrite OPimRecord::summary + */ +QString OPimBackendOccurrence::summary()const { + return m_summary; +} + +QString OPimBackendOccurrence::location()const { + return m_location; +} + +QString OPimBackendOccurrence::note()const { + return m_note; +} + +/** + * \brief Set the Start Date + * + * This method will set the start date and internally will mark + * this occurrence to have no time associated to both start + * and end date. + * A call to timeAssociated will return false after using this + * method. + * + * @param start The Start Date + * + */ +void OPimBackendOccurrence::setStartDate( const QDate& start) { + m_start = start; + m_haveTime = false; +} + +/** + * \brief Set the Start Date and Time + * + * Set the Start Date and Time. After this call + * \sa timeAssociated will return true. + * + * @param dt The Start Date and Time to be set + */ +void OPimBackendOccurrence::setStartDateTime( const QDateTime& dt ) { + m_start = dt; + m_haveTime = true; +} + +/** + * \brief This will set the End Date. + * + * This method will set the End Date. The timeAssociated attribute + * will not be changed. + * + * @param end The End Date to be set + */ +void OPimBackendOccurrence::setEndDate( const QDate& end ) { + m_end = end; +} + +/** + * \brief Set the End Date and Time of the occurrence + * + * This will set the End Date and Time but will not change + * the timeAssociated attribute. + * + * @param dt The End Date and Time to be set. + */ +void OPimBackendOccurrence::setEndDateTime( const QDateTime& dt ) { + m_end = dt; +} + +/** + * \brief This method will set the UID of the Record + * + * Set the UID of the OPimRecord to be associated with + * this OPimRecurrence. + * + * @param uid The UID of the associated OPimRecord to be set + */ +void OPimBackendOccurrence::setUid( const UID& uid ) { + m_uid = uid; +} + + +/** + * \brief Set a special summary instead of \sa OPimRecord::summary() + * + * If \sa OPimRecord::summary() doesn't describe the occurrence + * reason you can set a custom summary for the Occurrence. + * + * @param str The to be set Summary + */ +void OPimBackendOccurrence::setSummary( const QString& str ) { + m_summary = str; +} + +void OPimBackendOccurrence::setLocation( const QString& str ) { + m_location = str; +} + +void OPimBackendOccurrence::setNote( const QString& str ) { + m_note = str; +} + +} diff --git a/libopie2/opiepim/backend/opimbackendoccurrence.h b/libopie2/opiepim/backend/opimbackendoccurrence.h new file mode 100644 index 0000000..08c3cdf --- a/dev/null +++ b/libopie2/opiepim/backend/opimbackendoccurrence.h @@ -0,0 +1,108 @@ +/* + This file is part of the Opie Project + Copyright (C) 2004 Holger Hans Peter 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. +*/ + +#ifndef OPIE_PIM_BACKEND_OCCURRENCE_H +#define OPIE_PIM_BACKEND_OCCURRENCE_H + +#include <opie2/opimglobal.h> + +#include <qarray.h> +#include <qdatetime.h> +#include <qvaluelist.h> + +namespace Opie { + +/** + * \brief Internal representation of an Occurence + * + * This class is used by the Backends to express + * Occurences for the Period Based Query to + * the by the Backend represanted Database. + * In the Frontend this single representation is splitted + * into per day \sa OPimOccurrence 's. + * OPimBackendOccurrence can be understand as a hint to + * the Frontend and must contain the \sa UID, the Start Date + * and End Date of the Occurence. If you have no time associated + * to the datetime use the QDate constructors. + * If OPimRecord::summary() does not describe the Occurrence + * right you can call setSummary() and then the supplied + * summary will be used. + * All Dates and Times are in the local time. + * + * @version 1.0 + * @author Holger Hans Peter Freyther zecke@handhelds.org + */ +class OPimBackendOccurrence { +public: + typedef QValueList<OPimBackendOccurrence> List; + + //@{ + OPimBackendOccurrence(); + OPimBackendOccurrence( const QDate& date, + const UID& , const QString& = QString::null ); + OPimBackendOccurrence( const QDate& date, const QDate& end, + const UID& ); + OPimBackendOccurrence( const QDateTime& start, + const QDateTime& end, + const UID& uid ); + //@} + + //@{ + QDateTime startDateTime()const; + QDateTime endDateTime()const; + UID uid()const; + bool isAllDay()const; + QString summary()const; + QString location()const; + QString note()const; + //@} + + //@{ + void setStartDate( const QDate& ); + void setStartDateTime( const QDateTime& dt ); + void setEndDate( const QDate& ); + void setEndDateTime( const QDateTime& dt ); + void setUid( const UID& ); + void setSummary( const QString& ); + void setLocation( const QString& ); + void setNote( const QString& ); + //@} + +private: + QDateTime m_start, m_end; + UID m_uid; + bool m_haveTime : 1; + QString m_summary, m_note, m_location; + + struct Private; + Private *d; +}; +} + +#endif diff --git a/libopie2/opiepim/backend/otodoaccessbackend.cpp b/libopie2/opiepim/backend/otodoaccessbackend.cpp index 790a764..5f86be9 100644 --- a/libopie2/opiepim/backend/otodoaccessbackend.cpp +++ b/libopie2/opiepim/backend/otodoaccessbackend.cpp @@ -1,41 +1,155 @@ /* 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(); +} + +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 9dfda45..66297bb 100644 --- a/libopie2/opiepim/backend/otodoaccessbackend.h +++ b/libopie2/opiepim/backend/otodoaccessbackend.h @@ -1,59 +1,79 @@ /* 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 QArray<int> effectiveToDos( const QDate& start, - const QDate& end, - bool includeNoDates ) = 0; - virtual QArray<int> overDue() = 0; - virtual QArray<int> sorted( bool asc, int sortOrder, int sortFilter, - int cat ) = 0; - virtual void removeAllCompleted() = 0; - virtual QBitArray supports()const = 0; - + 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; + 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 4e3e47b..2bcab29 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.cpp +++ b/libopie2/opiepim/backend/otodoaccesssql.cpp @@ -362,534 +362,469 @@ namespace { 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; } 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; - OPimTodo to; // we try to cache CACHE items switch( dir ) { - /* forward */ + /* forward */ case Frontend::Forward: for (uint i = cur; i < ints.count() && size < CACHE; i++ ) { - odebug << "size " << size << " " << ints[i] << "" << oendl; search[size] = ints[i]; size++; } break; - /* reverse */ - case Frontend::Reverse: + /* 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 to; + 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() { +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) { + 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 & 1 ) { + if ( sortFilter & OPimTodoAccess::FilterCategory ) { QString str; if (cat != 0 ) str = QString::number( cat ); query += " categories like '%" +str+"%' AND"; } /* Show only overdue */ - if ( sortFilter & 2 ) { + 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 & 4 ) { + 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 0: + case OPimTodoAccess::Completed: query += "completed"; break; - case 1: + case OPimTodoAccess::Priority: query += "priority"; break; - case 2: + case OPimTodoAccess::SortSummary: query += "summary"; break; - case 3: + case OPimTodoAccess::Deadline: query += "DueDate"; break; } - if ( !asc ) { - odebug << "not ascending!" << oendl; + 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" ) 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(); - odebug << "todo1" << oendl; - OPimTodo to = todo( (*it) ); - cache( to ); - ++it; + OPimTodo to, tmp; for ( ; it != list.end(); ++it ) { - odebug << "caching" << oendl; - OPimTodo newTodo = todo( (*it) ); + OPimTodo newTodo = parse( (*it) ); cache( newTodo ); if ( newTodo.uid() == uid ) retTodo = newTodo; } return retTodo; } -OPimTodo OPimTodoAccessBackendSQL::todo( OSQLResultItem& item )const { - odebug << "todo(ResultItem)" << oendl; +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") ); - odebug << "Item is completed: " << item.data("completed").toInt() << "" << oendl; - 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) ); } -/* - * update the dict - */ -void OPimTodoAccessBackendSQL::fillDict() { -#if 0 - /* initialize dict */ - /* - * UPDATE dict if you change anything!!! - * FIXME: Isn't this dict obsolete ? (eilers) - */ - m_dict.setAutoDelete( TRUE ); - m_dict.insert("Categories" , new int(OPimTodo::Category) ); - m_dict.insert("Uid" , new int(OPimTodo::Uid) ); - m_dict.insert("HasDate" , new int(OPimTodo::HasDate) ); - m_dict.insert("Completed" , new int(OPimTodo::Completed) ); - m_dict.insert("Description" , new int(OPimTodo::Description) ); - m_dict.insert("Summary" , new int(OPimTodo::Summary) ); - m_dict.insert("Priority" , new int(OPimTodo::Priority) ); - m_dict.insert("DateDay" , new int(OPimTodo::DateDay) ); - m_dict.insert("DateMonth" , new int(OPimTodo::DateMonth) ); - m_dict.insert("DateYear" , new int(OPimTodo::DateYear) ); - m_dict.insert("Progress" , new int(OPimTodo::Progress) ); - m_dict.insert("Completed", new int(OPimTodo::Completed) ); // Why twice ? (eilers) - m_dict.insert("CrossReference", new int(OPimTodo::CrossReference) ); -// m_dict.insert("HasAlarmDateTime",new int(OPimTodo::HasAlarmDateTime) ); // old stuff (eilers) -// m_dict.insert("AlarmDateTime", new int(OPimTodo::AlarmDateTime) ); // old stuff (eilers) -#endif -} /* * 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() ); - odebug << " count = " << list.count() << "" << oendl; 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 { - -#if 0 - QArray<int> empty; - return empty; - -#else QString qu = "SELECT uid FROM todolist WHERE ("; - // Do it make sense to search other fields, too ? + // Does it make sense to search other fields, too ? qu += " rlike(\""+ r.pattern() + "\",\"description\") OR"; qu += " rlike(\""+ r.pattern() + "\",\"summary\")"; qu += ")"; - odebug << "query: " << qu << "" << oendl; - OSQLRawQuery raw( qu ); OSQLResult res = m_driver->query( &raw ); return uids( res ); - - -#endif - -} -QBitArray OPimTodoAccessBackendSQL::supports()const { - - return sup(); -} - -QBitArray OPimTodoAccessBackendSQL::sup() const{ - - QBitArray ar( OPimTodo::CompletedDate + 1 ); - ar.fill( true ); - ar[OPimTodo::CrossReference] = false; - ar[OPimTodo::State ] = false; - ar[OPimTodo::Reminders] = false; - ar[OPimTodo::Notifiers] = false; - ar[OPimTodo::Maintainer] = false; - - return ar; } 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 ); - odebug << "Number of completed: " << completed_uids.size() << "" << oendl; - if ( completed_uids.size() == 0 ) return; qu = "DELETE FROM todolist WHERE ("; QString query; - for ( int i = 0; i < completed_uids.size(); i++ ){ + 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 ( int i = 0; i < completed_uids.size(); i++ ){ + for ( uint i = 0; i < completed_uids.size(); i++ ){ if ( !query.isEmpty() ) query += " OR "; query += QString( "uid = %1" ).arg( completed_uids[i] ); } qu += query + " );"; - odebug << "query: " << qu << "" << oendl; - OSQLRawQuery raw2( qu ); res = m_driver->query( &raw2 ); - if ( res.state() == OSQLResult::Failure ) { + + 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; - QMap<QString, QString> empty; - return empty; + return QMap<QString, QString>(); } OSQLResultItem::ValueList list = res_custom.results(); OSQLResultItem::ValueList::Iterator it = list.begin(); - for ( ; it != list.end(); ++it ) { + 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 415f791..0ba8f3a 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.h +++ b/libopie2/opiepim/backend/otodoaccesssql.h @@ -1,93 +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<int> allRecords()const; + QArray<UID> allRecords()const; - QArray<int> queryByExample( const OPimTodo& t, int settings, const QDateTime& d = QDateTime() ); - OPimTodo find(int uid)const; - OPimTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; + QArray<UID> queryByExample( 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( int uid ); + bool remove( UID uid ); bool replace( const OPimTodo& t ); - QArray<int> overDue(); - QArray<int> effectiveToDos( const QDate& start, - const QDate& end, bool includeNoDates ); - QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); - - QBitArray supports()const; - QArray<int> matchRegexp( const QRegExp &r ) const; + 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; - void fillDict(); inline bool date( QDate& date, const QString& )const; - inline OPimTodo parseResultAndCache( int uid, const Opie::DB::OSQLResult& )const; - inline OPimTodo todo( Opie::DB::OSQLResultItem& )const; - inline QArray<int> uids( const Opie::DB::OSQLResult& )const; - OPimTodo todo( int uid )const; - QBitArray sup() const; - QMap<QString, QString> requestCustom( int uid ) 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<int> m_uids; + QArray<UID> m_uids; bool m_dirty : 1; }; } #endif diff --git a/libopie2/opiepim/backend/otodoaccessvcal.cpp b/libopie2/opiepim/backend/otodoaccessvcal.cpp index 7d58a40..aa8a7eb 100644 --- a/libopie2/opiepim/backend/otodoaccessvcal.cpp +++ b/libopie2/opiepim/backend/otodoaccessvcal.cpp @@ -1,289 +1,259 @@ /* 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 <opie2/private/vobject_p.h> /* OPIE */ #include <opie2/otodoaccessvcal.h> #include <opie2/odebug.h> #include <qpe/timeconversion.h> /* QT */ //FIXME: Hack to allow direct access to FILE* fh. Rewrite this! #define protected public #include <qfile.h> #undef protected using namespace Opie; namespace { static OPimTodo eventByVObj( VObject *obj ){ OPimTodo event; VObject *ob; QCString name; // no uid, attendees, ... and no fun // description if( ( ob = isAPropertyOf( obj, VCDescriptionProp )) != 0 ){ name = vObjectStringZValue( ob ); #if 0 event.setDescription( name ); #else event.setSummary( name ); #endif } // summary if ( ( ob = isAPropertyOf( obj, VCSummaryProp ) ) != 0 ) { name = vObjectStringZValue( ob ); #if 0 event.setSummary( name ); #else event.setDescription( name ); #endif } // completed if( ( ob = isAPropertyOf( obj, VCStatusProp )) != 0 ){ name = vObjectStringZValue( ob ); if( name == "COMPLETED" ){ event.setCompleted( true ); }else{ event.setCompleted( false ); } }else event.setCompleted( false ); // priority if ((ob = isAPropertyOf(obj, VCPriorityProp))) { name = vObjectStringZValue( ob ); bool ok; event.setPriority(name.toInt(&ok) ); } //due date if((ob = isAPropertyOf(obj, VCDueProp)) ){ event.setHasDueDate( true ); name = vObjectStringZValue( ob ); event.setDueDate( TimeConversion::fromISO8601( name).date() ); } // categories if((ob = isAPropertyOf( obj, VCCategoriesProp )) != 0 ){ name = vObjectStringZValue( ob ); - owarn << "Categories:" << name.data() << "" << oendl; } event.setUid( 1 ); return event; }; static VObject *vobjByEvent( const OPimTodo &event ) { VObject *task = newVObject( VCTodoProp ); if( task == 0 ) return 0l; if( event.hasDueDate() ) { QTime time(0, 0, 0); QDateTime date(event.dueDate(), time ); addPropValue( task, VCDueProp, TimeConversion::toISO8601( date ) ); } if( event.isCompleted() ) addPropValue( task, VCStatusProp, "COMPLETED"); QString string = QString::number(event.priority() ); addPropValue( task, VCPriorityProp, string.local8Bit() ); addPropValue( task, VCCategoriesProp, event.idsToString( event.categories() ).local8Bit() ); #if 0 // There seems a misrepresentation between summary in otodoevent // and summary in vcard. // The same with description.. // Description is summary and vice versa.. Argh.. (eilers) addPropValue( task, VCDescriptionProp, event.description().local8Bit() ); addPropValue( task, VCSummaryProp, event.summary().local8Bit() ); #else addPropValue( task, VCDescriptionProp, event.summary().local8Bit() ); addPropValue( task, VCSummaryProp, event.description().local8Bit() ); #endif return task; }; } namespace Opie { OPimTodoAccessVCal::OPimTodoAccessVCal( const QString& path ) : m_dirty(false), m_file( path ) { } OPimTodoAccessVCal::~OPimTodoAccessVCal() { } bool OPimTodoAccessVCal::load() { m_map.clear(); m_dirty = false; VObject* vcal = 0l; vcal = Parse_MIME_FromFileName( QFile::encodeName(m_file).data() ); if (!vcal ) return false; // Iterate over the list VObjectIterator it; VObject* vobj; initPropIterator(&it, vcal); while( moreIteration( &it ) ) { vobj = ::nextVObject( &it ); QCString name = ::vObjectName( vobj ); if( name == VCTodoProp ){ OPimTodo to = eventByVObj( vobj ); m_map.insert( to.uid(), to ); } } // Should I do a delete vcal? return true; } bool OPimTodoAccessVCal::reload() { return load(); } bool OPimTodoAccessVCal::save() { if (!m_dirty ) return true; QFile file( m_file ); if (!file.open(IO_WriteOnly ) ) return false; VObject *obj; obj = newVObject( VCCalProp ); addPropValue( obj, VCVersionProp, "1.0" ); VObject *vo; for(QMap<int, OPimTodo>::ConstIterator it=m_map.begin(); it !=m_map.end(); ++it ){ vo = vobjByEvent( it.data() ); addVObjectProp(obj, vo ); } writeVObject( file.fh, obj ); //FIXME: HACK!!! cleanVObject( obj ); cleanStrTbl(); m_dirty = false; return true; } void OPimTodoAccessVCal::clear() { m_map.clear(); m_dirty = true; } bool OPimTodoAccessVCal::add( const OPimTodo& to ) { m_map.insert( to.uid(), to ); m_dirty = true; return true; } bool OPimTodoAccessVCal::remove( int uid ) { m_map.remove( uid ); m_dirty = true; return true; } void OPimTodoAccessVCal::removeAllCompleted() { for ( QMap<int, OPimTodo>::Iterator it = m_map.begin(); it != m_map.end(); ++it ) { if ( (*it).isCompleted() ) m_map.remove( it ); } } bool OPimTodoAccessVCal::replace( const OPimTodo& to ) { m_map.replace( to.uid(), to ); m_dirty = true; return true; } OPimTodo OPimTodoAccessVCal::find(int uid )const { return m_map[uid]; } -QArray<int> OPimTodoAccessVCal::sorted( bool, int, int, int ) { - QArray<int> ar(0); - return ar; -} + QArray<int> OPimTodoAccessVCal::allRecords()const { QArray<int> ar( m_map.count() ); QMap<int, OPimTodo>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } -QArray<int> OPimTodoAccessVCal::matchRegexp(const QRegExp& /* r */)const { - QArray<int> ar(0); - return ar; -} -QArray<int> OPimTodoAccessVCal::queryByExample( const OPimTodo&, int, const QDateTime& ) { - QArray<int> ar(0); - return ar; -} + QArray<int> OPimTodoAccessVCal::effectiveToDos( const QDate& , const QDate& , - bool ) { - QArray<int> ar(0); - return ar; -} -QArray<int> OPimTodoAccessVCal::overDue() { + bool )const { QArray<int> ar(0); return ar; } -QBitArray OPimTodoAccessVCal::supports()const { - static QBitArray ar = sup(); - - return ar; -} -QBitArray OPimTodoAccessVCal::sup() { - QBitArray ar ( OPimTodo::CompletedDate +1 ); - ar.fill( true ); - - ar[OPimTodo::CrossReference] = false; - ar[OPimTodo::State ] = false; - ar[OPimTodo::Reminders] = false; - ar[OPimTodo::Notifiers] = false; - ar[OPimTodo::Maintainer] = false; - ar[OPimTodo::Progress] = false; - ar[OPimTodo::Alarms ] = false; - ar[OPimTodo::Recurrence] = false; +QArray<int> OPimTodoAccessVCal::overDue()const { + QArray<int> ar(0); return ar; } } diff --git a/libopie2/opiepim/backend/otodoaccessvcal.h b/libopie2/opiepim/backend/otodoaccessvcal.h index 1e106d3..05dd76b 100644 --- a/libopie2/opiepim/backend/otodoaccessvcal.h +++ b/libopie2/opiepim/backend/otodoaccessvcal.h @@ -1,72 +1,66 @@ /* This file is part of the Opie Project Copyright (C) Stefan Eilers (Eilers.Stefan@epost.de) =. Copyright (C) The Opie Team <opie-devel@handhelds.org> .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU Library General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef OPIE_OTODO_ACCESS_VCAL_H #define OPIE_OTODO_ACCESS_VCAL_H #include <opie2/otodoaccessbackend.h> namespace Opie { class OPimTodoAccessVCal : public OPimTodoAccessBackend { public: OPimTodoAccessVCal(const QString& ); ~OPimTodoAccessVCal(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; - QArray<int> matchRegexp(const QRegExp &r) const; - QArray<int> queryByExample( const OPimTodo& t, int sort, const QDateTime& d = QDateTime() ); QArray<int> effectiveToDos( const QDate& start, const QDate& end, - bool includeNoDates ); - QArray<int> overDue(); - QArray<int> sorted( bool asc, int sortOrder, int sortFilter, - int cat ); + bool includeNoDates )const; + QArray<int> overDue()const; OPimTodo find(int uid)const; void clear(); bool add( const OPimTodo& ); bool remove( int uid ); bool replace( const OPimTodo& ); void removeAllCompleted(); - virtual QBitArray supports()const; private: - static QBitArray sup(); bool m_dirty : 1; QString m_file; QMap<int, OPimTodo> m_map; }; } #endif diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp index 3e06d88..273f91a 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.cpp +++ b/libopie2/opiepim/backend/otodoaccessxml.cpp @@ -1,914 +1,720 @@ /* 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("Notifiers", new int(OPimTodo::Notifiers) ); 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; - owarn << "Found a start at " << i << " " << (point-dt) << "" << oendl; 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 */ - owarn << "End at " << i << "" << oendl; 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 ); - owarn << "counts " << m_events.count() << " records loaded!" << oendl; return true; } bool OPimTodoAccessXML::reload() { m_events.clear(); return load(); } bool OPimTodoAccessXML::save() { -// owarn << "saving" << oendl; if (!m_opened || !m_changed ) { -// owarn << "not saving" << oendl; 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 ) { -// owarn << "error renaming" << oendl; 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(); - i++; - } + 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 ) { -// owarn << "add" << oendl; 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 ) { + bool includeNoDates )const { QArray<int> ids( m_events.count() ); - QMap<int, OPimTodo>::Iterator it; + QMap<int, OPimTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { - if ( !it.data().hasDueDate() ) { - if ( includeNoDates ) { - ids[i] = it.key(); - i++; - } + if ( !it.data().hasDueDate() && includeNoDates) { + ids[i++] = it.key(); }else if ( it.data().dueDate() >= start && it.data().dueDate() <= end ) { - ids[i] = it.key(); - i++; + ids[i++] = it.key(); } } ids.resize( i ); return ids; } -QArray<int> OPimTodoAccessXML::overDue() { +QArray<int> OPimTodoAccessXML::overDue()const { QArray<int> ids( m_events.count() ); int i = 0; - QMap<int, OPimTodo>::Iterator it; + 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) { -// owarn << "parse to do from XMLElement" << oendl; int *find=0; find = (*dict)[ attr.data() ]; if (!find ) { -// owarn << "Unknown option" + it.key() << oendl; 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 - owarn << "alarm: " << alarm.join("___") << "" << oendl; - owarn << "alarm[0]: " << alarm[0] << " " << OPimDateConversion::dateTimeFromString( alarm[0] ).toString() << "" << oendl; 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 ) { - //owarn << QString("writing custom %1").arg(customMap.count()) << oendl; QString buf(" "); for ( QMap<QString, QString>::ConstIterator cit = customMap.begin(); cit != customMap.end(); ++cit) { -// owarn << ".ITEM." << oendl; 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() ) + "\" "; } -// owarn << "Uid " << ev.uid() << "" << oendl; 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 - owarn << "als: " << als.join("____________") << "" << oendl; 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 ); } -/* internal class for sorting - * - * Inspired by todoxmlio.cpp from TT - */ -struct OPimTodoXMLContainer { - OPimTodo todo; -}; +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; -namespace { - inline QString string( const OPimTodo& todo) { - return todo.summary().isEmpty() ? - todo.description().left(20 ) : - todo.summary(); - } - inline int completed( const OPimTodo& todo1, const OPimTodo& todo2) { - int ret = 0; - if ( todo1.isCompleted() ) ret++; - if ( todo2.isCompleted() ) ret--; - return ret; - } - inline int priority( const OPimTodo& t1, const OPimTodo& t2) { - return ( t1.priority() - t2.priority() ); - } - inline int description( const OPimTodo& t1, const OPimTodo& t2) { - return QString::compare( string(t1), string(t2) ); - } - inline int deadline( const OPimTodo& t1, const OPimTodo& t2) { - int ret = 0; - if ( t1.hasDueDate() && - t2.hasDueDate() ) - ret = t2.dueDate().daysTo( t1.dueDate() ); - else if ( t1.hasDueDate() ) - ret = -1; - else if ( t2.hasDueDate() ) - ret = 1; - else - ret = 0; + 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; - return ret; - } + 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]]; -/* - * Returns: - * 0 if item1 == item2 - * - * non-zero if item1 != item2 - * - * This function returns int rather than bool so that reimplementations - * can return one of three values and use it to sort by: - * - * 0 if item1 == item2 - * - * > 0 (positive integer) if item1 > item2 - * - * < 0 (negative integer) if item1 < item2 - * - */ -class OPimTodoXMLVector : public QVector<OPimTodoXMLContainer> { -public: - OPimTodoXMLVector(int size, bool asc, int sort) - : QVector<OPimTodoXMLContainer>( size ) - { - setAutoDelete( true ); - m_asc = asc; - m_sort = sort; - } - /* return the summary/description */ - QString string( const OPimTodo& todo) { - return todo.summary().isEmpty() ? - todo.description().left(20 ) : - todo.summary(); - } - /** - * we take the sortorder( switch on it ) - * - */ - int compareItems( Item d1, Item d2 ) { - bool seComp, sePrio, seDesc, seDeadline; - seComp = sePrio = seDeadline = seDesc = false; - int ret =0; - OPimTodoXMLContainer* con1 = (OPimTodoXMLContainer*)d1; - OPimTodoXMLContainer* con2 = (OPimTodoXMLContainer*)d2; - - /* same item */ - if ( con1->todo.uid() == con2->todo.uid() ) - return 0; - - switch ( m_sort ) { - /* completed */ - case 0: { - ret = completed( con1->todo, con2->todo ); - seComp = TRUE; - break; - } - /* priority */ - case 1: { - ret = priority( con1->todo, con2->todo ); - sePrio = TRUE; - break; - } - /* description */ - case 2: { - ret = description( con1->todo, con2->todo ); - seDesc = TRUE; - break; - } - /* deadline */ - case 3: { - ret = deadline( con1->todo, con2->todo ); - seDeadline = TRUE; + /* 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; } - default: - ret = 0; - break; - }; - /* - * FIXME do better sorting if the first sort criteria - * ret equals 0 start with complete and so on... - */ - - /* twist it we're not ascending*/ - if (!m_asc) - ret = ret * -1; - if ( ret ) - return ret; - - // default did not gave difference let's try it other way around /* - * General try if already checked if not test - * and return - * 1.Completed - * 2.Priority - * 3.Description - * 4.DueDate + * If none of the Categories matched + * continue */ - if (!seComp ) { - if ( (ret = completed( con1->todo, con2->todo ) ) ) { - if (!m_asc ) ret *= -1; - return ret; - } - } - if (!sePrio ) { - if ( (ret = priority( con1->todo, con2->todo ) ) ) { - if (!m_asc ) ret *= -1; - return ret; - } - } - if (!seDesc ) { - if ( (ret = description(con1->todo, con2->todo ) ) ) { - if (!m_asc) ret *= -1; - return ret; - } - } - if (!seDeadline) { - if ( (ret = deadline( con1->todo, con2->todo ) ) ) { - if (!m_asc) ret *= -1; - return ret; - } - } - - return 0; - } - private: - bool m_asc; - int m_sort; - -}; - -QArray<int> OPimTodoAccessXML::sorted( bool asc, int sortOrder, - int sortFilter, int cat ) { - OPimTodoXMLVector vector(m_events.count(), asc,sortOrder ); - QMap<int, OPimTodo>::Iterator it; - int item = 0; - - bool bCat = sortFilter & 1 ? true : false; - bool bOnly = sortFilter & 2 ? true : false; - bool comp = sortFilter & 4 ? true : false; - for ( it = m_events.begin(); it != m_events.end(); ++it ) { - - /* show category */ - /* -1 == unfiled */ - if ( bCat && cat == -1 ) { - if(!(*it).categories().isEmpty() ) - continue; - }else if ( bCat && cat != 0) - if (!(*it).categories().contains( cat ) ) { - continue; - } - /* isOverdue but we should not show overdue - why?*/ -/* if ( (*it).isOverdue() && !bOnly ) { - owarn << "item is overdue but !bOnly" << oendl; + if ( !catPassed ) continue; - } -*/ - if ( !(*it).isOverdue() && bOnly ) { + if ( !todo.isOverdue() && bOnly ) continue; - } - - if ((*it).isCompleted() && comp ) { + if (todo.isCompleted() && comp ) continue; - } - - OPimTodoXMLContainer* con = new OPimTodoXMLContainer(); - con->todo = (*it); - vector.insert(item, con ); - item++; + vector.insert(item++, todo ); } + vector.resize( item ); /* sort it now */ vector.sort(); /* now get the uids */ - QArray<int> array( vector.count() ); - for (uint i= 0; i < vector.count(); i++ ) { - array[i] = ( vector.at(i) )->todo.uid(); - } + 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; } -QBitArray OPimTodoAccessXML::supports()const { - static QBitArray ar = sup(); - return ar; -} -QBitArray OPimTodoAccessXML::sup() { - QBitArray ar( OPimTodo::CompletedDate +1 ); - ar.fill( true ); - ar[OPimTodo::CrossReference] = false; - ar[OPimTodo::State ] = false; - ar[OPimTodo::Reminders] = false; - ar[OPimTodo::Notifiers] = false; - ar[OPimTodo::Maintainer] = false; - - return ar; -} + QArray<int> OPimTodoAccessXML::matchRegexp( const QRegExp &r ) const { - QArray<int> m_currentQuery( m_events.count() ); + QArray<int> currentQuery( m_events.count() ); uint arraycounter = 0; - QMap<int, OPimTodo>::ConstIterator it; - for (it = m_events.begin(); it != m_events.end(); ++it ) { + QMap<int, OPimTodo>::ConstIterator it; + for (it = m_events.begin(); it != m_events.end(); ++it ) { if ( it.data().match( r ) ) - m_currentQuery[arraycounter++] = it.data().uid(); + currentQuery[arraycounter++] = it.data().uid(); } // Shrink to fit.. - m_currentQuery.resize(arraycounter); + currentQuery.resize(arraycounter); - return m_currentQuery; + return currentQuery; } } diff --git a/libopie2/opiepim/backend/otodoaccessxml.h b/libopie2/opiepim/backend/otodoaccessxml.h index 3a51543..134a21a 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.h +++ b/libopie2/opiepim/backend/otodoaccessxml.h @@ -1,89 +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_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 ); - QArray<int> overDue(); - QArray<int> sorted( bool asc, int sortOrder, - int sortFilter, int cat ); - QBitArray supports()const; + bool includeNoDates )const; + QArray<int> overDue()const; + +//@{ + UIDArray sorted( const UIDArray&, bool, int, int, const QArray<int>& )const; +//@} private: - static QBitArray sup(); 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 |