author | eilers <eilers> | 2003-03-21 10:33:09 (UTC) |
---|---|---|
committer | eilers <eilers> | 2003-03-21 10:33:09 (UTC) |
commit | 8136284c38384b169cd2843ee61480d45b6c1cba (patch) (side-by-side diff) | |
tree | ad798e3df8dc27a41f431a2130dbf50947fbca49 | |
parent | 6f5f148ff9eac1e4d76bea4460a7984d1e3069b7 (diff) | |
download | opie-8136284c38384b169cd2843ee61480d45b6c1cba.zip opie-8136284c38384b169cd2843ee61480d45b6c1cba.tar.gz opie-8136284c38384b169cd2843ee61480d45b6c1cba.tar.bz2 |
Merged speed optimized xml backend for contacts to main.
Added QDateTime to querybyexample. For instance, it is now possible to get
all Birthdays/Anniversaries between two dates. This should be used
to show all birthdays in the datebook..
This change is sourcecode backward compatible but you have to upgrade
the binaries for today-addressbook.
29 files changed, 347 insertions, 1436 deletions
diff --git a/libopie/libopie.pro b/libopie/libopie.pro index 391f30e..2bf9985 100644 --- a/libopie/libopie.pro +++ b/libopie/libopie.pro @@ -52,32 +52,33 @@ SOURCES = ofontmenu.cc \ ofiledialog.cc ofileselector.cc \ ocheckitem.cpp \ colordialog.cpp \ colorpopupmenu.cpp oclickablelabel.cpp \ oprocctrl.cpp oprocess.cpp \ odevice.cpp odevicebutton.cpp otimepicker.cpp \ otabwidget.cpp otabbar.cpp \ ofontselector.cpp \ pim/otodo.cpp \ pim/opimrecord.cpp \ pim/otodoaccess.cpp \ pim/otodoaccessbackend.cpp \ pim/otodoaccessxml.cpp \ pim/ocontact.cpp \ pim/ocontactaccess.cpp \ pim/ocontactaccessbackend_vcard.cpp \ + pim/ocontactaccessbackend_xml.cpp \ pim/otodoaccessvcal.cpp \ pim/orecur.cpp \ pim/opimstate.cpp \ pim/opimxrefpartner.cpp \ pim/opimxref.cpp \ pim/opimxrefmanager.cpp \ pim/opimmaintainer.cpp \ pim/opimnotify.cpp \ pim/opimnotifymanager.cpp \ pim/opimmainwindow.cpp \ pim/opimresolver.cpp \ pim/oevent.cpp \ pim/otimezone.cpp \ pim/odatebookaccess.cpp \ pim/odatebookaccessbackend.cpp \ pim/odatebookaccessbackend_xml.cpp \ diff --git a/libopie/pim/ocontactaccessbackend_vcard.cpp b/libopie/pim/ocontactaccessbackend_vcard.cpp index e537269..f24523f 100644 --- a/libopie/pim/ocontactaccessbackend_vcard.cpp +++ b/libopie/pim/ocontactaccessbackend_vcard.cpp @@ -4,32 +4,40 @@ * Copyright (C) 2000 Trolltech AS. All rights reserved. * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.9 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * * Revision 1.8 2003/02/21 16:52:49 zecke * -Remove old Todo classes they're deprecated and today I already using the * new API * -Guard against self assignment in OTodo * -Add test apps for OPIM * -Opiefied Event classes * -Added TimeZone handling and pinning of TimeZones to OEvent * -Adjust ORecur and the widget to better timezone behaviour * * Revision 1.7 2003/02/16 22:25:46 zecke * 0000276 Fix for that bug.. or better temp workaround * A Preferred Number is HOME|VOICE * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test * triggers both * and the cell phone number overrides the other entries.. * @@ -176,33 +184,33 @@ OContact OContactAccessBackend_VCard::find ( int uid ) const return m_map[uid]; } QArray<int> OContactAccessBackend_VCard::allRecords() const { QArray<int> ar( m_map.count() ); QMap<int, OContact>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } // Not implemented -QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int ) +QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& ) { QArray<int> ar(0); return ar; } // Not implemented QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const { QArray<int> ar(0); return ar; } const uint OContactAccessBackend_VCard::querySettings() { return 0; // No search possible } diff --git a/libopie/pim/ocontactaccessbackend_vcard.h b/libopie/pim/ocontactaccessbackend_vcard.h index 236da00..93e2da3 100644 --- a/libopie/pim/ocontactaccessbackend_vcard.h +++ b/libopie/pim/ocontactaccessbackend_vcard.h @@ -4,32 +4,40 @@ * Copyright (C) 2000 Trolltech AS. All rights reserved. * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.5 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * * Revision 1.4 2002/12/07 13:26:22 eilers * Fixing bug in storing anniversary.. * * Revision 1.3 2002/11/13 14:14:51 eilers * Added sorted for Contacts.. * * Revision 1.2 2002/11/10 15:41:53 eilers * Bugfixes.. * * Revision 1.1 2002/11/09 14:34:52 eilers * Added VCard Backend. * */ #ifndef __OCONTACTACCESSBACKEND_VCARD_H_ #define __OCONTACTACCESSBACKEND_VCARD_H_ @@ -41,33 +49,33 @@ class VObject; class OContactAccessBackend_VCard : public OContactAccessBackend { public: OContactAccessBackend_VCard ( QString appname, QString filename = 0l ); bool load (); bool reload(); bool save(); void clear (); bool add ( const OContact& newcontact ); bool remove ( int uid ); bool replace ( const OContact& contact ); OContact find ( int uid ) const; QArray<int> allRecords() const; - QArray<int> queryByExample ( const OContact &query, int settings ); + QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); QArray<int> matchRegexp( const QRegExp &r ) const; const uint querySettings(); bool hasQuerySettings (uint querySettings) const; QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); bool wasChangedExternally(); private: OContact parseVObject( VObject* obj ); VObject* createVObject( const OContact& c ); QString convDateToVCardDate( const QDate& c ) const; QDate convVCardDateToDate( const QString& datestr ); VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); VObject *safeAddProp( VObject* o, const char* prop); bool m_dirty : 1; diff --git a/libopie/pim/ocontactaccessbackend_xml.cpp b/libopie/pim/ocontactaccessbackend_xml.cpp index 2df6757..4abf4d9 100644 --- a/libopie/pim/ocontactaccessbackend_xml.cpp +++ b/libopie/pim/ocontactaccessbackend_xml.cpp @@ -4,32 +4,46 @@ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: XML-Backend: Automatic reload if something was changed... * * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.2 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.1.2.2 2003/02/11 12:17:28 eilers + * Speed optimization. Removed the sequential search loops. + * + * Revision 1.1.2.1 2003/02/10 15:31:38 eilers + * Writing offsets to debug output.. + * * Revision 1.1 2003/02/09 15:05:01 eilers * Nothing happened.. Just some cleanup before I will start.. * * Revision 1.12 2003/01/03 16:58:03 eilers * Reenable debug output * * Revision 1.11 2003/01/03 12:31:28 eilers * Bugfix for calculating data diffs.. * * Revision 1.10 2003/01/02 14:27:12 eilers * Improved query by example: Search by date is possible.. First step * for a today plugin for birthdays.. * * Revision 1.9 2002/12/08 12:48:57 eilers * Moved journal-enum from ocontact into i the xml-backend.. * @@ -76,310 +90,335 @@ #include <qpe/global.h> #include <opie/xmltree.h> #include "ocontactaccessbackend.h" #include "ocontactaccess.h" #include <stdlib.h> #include <errno.h> using namespace Opie; OContactAccessBackend_XML::OContactAccessBackend_XML ( QString appname, QString filename = 0l ): m_changed( false ) { + // Just m_contactlist should call delete if an entry + // is removed. + m_contactList.setAutoDelete( true ); + m_uidToContact.setAutoDelete( false ); + m_appName = appname; /* Set journalfile name ... */ m_journalName = getenv("HOME"); m_journalName +="/.abjournal" + appname; /* Expecting to access the default filename if nothing else is set */ if ( filename.isEmpty() ){ m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); } else m_fileName = filename; /* Load Database now */ load (); } bool OContactAccessBackend_XML::save() { if ( !m_changed ) return true; QString strNewFile = m_fileName + ".new"; QFile f( strNewFile ); if ( !f.open( IO_WriteOnly|IO_Raw ) ) return false; int total_written; + int idx_offset = 0; QString out; + + // Write Header out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" " <Groups>\n" " </Groups>\n" " <Contacts>\n"; - //QValueList<Contact>::iterator it; - QValueListConstIterator<OContact> it; - for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { + QCString cstr = out.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); + idx_offset += cstr.length(); + out = ""; + + // Write all contacts + QListIterator<OContact> it( m_contactList ); + for ( ; it.current(); ++it ) { + qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset ); out += "<Contact "; - (*it).save( out ); + (*it)->save( out ); out += "/>\n"; - QCString cstr = out.utf8(); + 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"; - QCString cstr = out.utf8(); + // Write Footer + cstr = out.utf8(); total_written = f.writeBlock( cstr.data(), cstr.length() ); if ( total_written != int( cstr.length() ) ) { f.close(); QFile::remove( strNewFile ); return false; } f.close(); // move the file over, I'm just going to use the system call // because, I don't feel like using QDir. if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { qWarning( "problem renaming file %s to %s, errno: %d", strNewFile.latin1(), m_journalName.latin1(), errno ); // remove the tmp file... QFile::remove( strNewFile ); } /* The journalfile should be removed now... */ removeJournal(); m_changed = false; return true; } bool OContactAccessBackend_XML::load () { m_contactList.clear(); + m_uidToContact.clear(); /* Load XML-File and journal if it exists */ if ( !load ( m_fileName, false ) ) return false; /* The returncode of the journalfile is ignored due to the * fact that it does not exist when this class is instantiated ! * But there may such a file exist, if the application crashed. * Therefore we try to load it to get the changes before the # * crash happened... */ load (m_journalName, true); return true; } void OContactAccessBackend_XML::clear () { m_contactList.clear(); + m_uidToContact.clear(); + m_changed = false; - } bool OContactAccessBackend_XML::wasChangedExternally() { QFileInfo fi( m_fileName ); QDateTime lastmod = fi.lastModified (); return (lastmod != m_readtime); } QArray<int> OContactAccessBackend_XML::allRecords() const { QArray<int> uid_list( m_contactList.count() ); uint counter = 0; - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - uid_list[counter++] = (*it).uid(); + QListIterator<OContact> it( m_contactList ); + for( ; it.current(); ++it ){ + uid_list[counter++] = (*it)->uid(); } return ( uid_list ); } OContact OContactAccessBackend_XML::find ( int uid ) const { - bool found = false; OContact foundContact; //Create empty contact - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } + OContact* found = m_uidToContact.find( QString().setNum( uid ) ); + if ( found ){ - foundContact = *it; + foundContact = *found; } return ( foundContact ); } -QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings ) +QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings, + const QDateTime& d ) { QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; + QListIterator<OContact> it( m_contactList ); uint arraycounter = 0; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ + 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() ); + checkDate = new QDate( (*it)->birthday() ); case Qtopia::Anniversary: if ( queryDate == 0l ){ queryDate = new QDate( query.anniversary() ); - checkDate = new QDate( (*it).anniversary() ); + checkDate = new QDate( (*it)->anniversary() ); } if ( queryDate->isValid() ){ if( checkDate->isValid() ){ if ( settings & OContactAccess::DateYear ){ if ( queryDate->year() != checkDate->year() ) allcorrect = false; } if ( settings & OContactAccess::DateMonth ){ if ( queryDate->month() != checkDate->month() ) allcorrect = false; } if ( settings & OContactAccess::DateDay ){ if ( queryDate->day() != checkDate->day() ) allcorrect = false; } if ( settings & OContactAccess::DateDiff ) { - QDate current = QDate::currentDate(); + QDate current; + // If we get an additional date, we + // will take this date instead of + // the current one.. + if ( !d.date().isValid() ) + current = QDate::currentDate(); + else + current = d.date(); + // We have to equalize the year, otherwise // the search will fail.. checkDate->setYMD( current.year(), checkDate->month(), checkDate->day() ); if ( *checkDate < current ) checkDate->setYMD( current.year()+1, checkDate->month(), checkDate->day() ); + + // Check whether the birthday/anniversary date is between + // the current/given date and the maximum date + // ( maximum time range ) ! qWarning("Checking if %s is between %s and %s ! ", checkDate->toString().latin1(), current.toString().latin1(), queryDate->toString().latin1() ); if ( current.daysTo( *queryDate ) > 0 ){ if ( !( ( *checkDate >= current ) && ( *checkDate <= *queryDate ) ) ){ allcorrect = false; qWarning (" Nope!.."); } } } } else{ - // checkDate is invalid. Therfore this entry is always rejected + // checkDate is invalid. Therefore this entry is always rejected allcorrect = false; } } delete queryDate; queryDate = 0l; delete checkDate; checkDate = 0l; break; default: /* Just compare fields which are not empty in the query object */ if ( !query.field(i).isEmpty() ){ switch ( settings & ~( OContactAccess::IgnoreCase | OContactAccess::DateDiff | OContactAccess::DateYear | OContactAccess::DateMonth | OContactAccess::DateDay | OContactAccess::MatchOne ) ){ case OContactAccess::RegExp:{ QRegExp expr ( query.field(i), !(settings & OContactAccess::IgnoreCase), false ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) + if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OContactAccess::WildCards:{ QRegExp expr ( query.field(i), !(settings & OContactAccess::IgnoreCase), true ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) + if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OContactAccess::ExactMatch:{ if (settings & OContactAccess::IgnoreCase){ if ( query.field(i).upper() != - (*it).field(i).upper() ) + (*it)->field(i).upper() ) allcorrect = false; }else{ - if ( query.field(i) != (*it).field(i) ) + if ( query.field(i) != (*it)->field(i) ) allcorrect = false; } } break; } } } } if ( allcorrect ){ - m_currentQuery[arraycounter++] = (*it).uid(); + m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const { QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; + QListIterator<OContact> it( m_contactList ); uint arraycounter = 0; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).match( r ) ){ - m_currentQuery[arraycounter++] = (*it).uid(); + for( ; it.current(); ++it ){ + if ( (*it)->match( r ) ){ + m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } const uint OContactAccessBackend_XML::querySettings() { return ( OContactAccess::WildCards | OContactAccess::IgnoreCase | OContactAccess::RegExp | OContactAccess::ExactMatch | OContactAccess::DateDiff @@ -413,113 +452,112 @@ bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const case OContactAccess::ExactMatch: return ( true ); default: return ( false ); } } // Currently only asc implemented.. QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) { QMap<QString, int> nameToUid; QStringList names; QArray<int> m_currentQuery( m_contactList.count() ); // First fill map and StringList with all Names // Afterwards sort namelist and use map to fill array to return.. - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); - nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); + QListIterator<OContact> it( m_contactList ); + for( ; it.current(); ++it ){ + names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) ); + nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() ); } names.sort(); int i = 0; if ( asc ){ for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) m_currentQuery[i++] = nameToUid[ (*it) ]; }else{ for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) m_currentQuery[i++] = nameToUid[ (*it) ]; } return m_currentQuery; } bool OContactAccessBackend_XML::add ( const OContact &newcontact ) { //qWarning("odefaultbackend: ACTION::ADD"); updateJournal (newcontact, ACTION_ADD); addContact_p( newcontact ); m_changed = true; return true; } bool OContactAccessBackend_XML::replace ( const OContact &contact ) { m_changed = true; - bool found = false; - - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).uid() == contact.uid() ){ - found = true; - break; - } - } - if (found) { - updateJournal (contact, ACTION_REPLACE); - m_contactList.remove (it); - m_contactList.append (contact); + OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) ); + + if ( found ) { + OContact* newCont = new OContact( contact ); + + updateJournal ( *newCont, ACTION_REPLACE); + m_contactList.removeRef ( found ); + m_contactList.append ( newCont ); + m_uidToContact.remove( QString().setNum( contact.uid() ) ); + m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont ); + + qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid()); + return true; } else return false; } bool OContactAccessBackend_XML::remove ( int uid ) { m_changed = true; - bool found = false; - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } - if (found) { - updateJournal ( *it, ACTION_REMOVE); - m_contactList.remove (it); + OContact* found = m_uidToContact.find ( QString().setNum( uid ) ); + + if ( found ) { + updateJournal ( *found, ACTION_REMOVE); + m_contactList.removeRef ( found ); + m_uidToContact.remove( QString().setNum( uid ) ); + return true; } else return false; } bool OContactAccessBackend_XML::reload(){ /* Reload is the same as load in this implementation */ return ( load() ); } void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) { - m_contactList.append (newcontact); + OContact* contRef = new OContact( newcontact ); + + m_contactList.append ( contRef ); + m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef ); } /* This function loads the xml-database and the journalfile */ bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) { /* We use the time of the last read to check if the file was * changed externally. */ if ( !isJournal ){ QFileInfo fi( filename ); m_readtime = fi.lastModified (); } const int JOURNALACTION = Qtopia::Notes + 1; const int JOURNALROW = JOURNALACTION + 1; diff --git a/libopie/pim/ocontactaccessbackend_xml.h b/libopie/pim/ocontactaccessbackend_xml.h index 6477705..4d6a7ef 100644 --- a/libopie/pim/ocontactaccessbackend_xml.h +++ b/libopie/pim/ocontactaccessbackend_xml.h @@ -4,32 +4,46 @@ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: XML-Backend: Automatic reload if something was changed... * * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.13 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.12.2.2 2003/02/11 12:17:28 eilers + * Speed optimization. Removed the sequential search loops. + * + * Revision 1.12.2.1 2003/02/09 15:05:01 eilers + * Nothing happened.. Just some cleanup before I will start.. + * * Revision 1.12 2003/01/03 16:58:03 eilers * Reenable debug output * * Revision 1.11 2003/01/03 12:31:28 eilers * Bugfix for calculating data diffs.. * * Revision 1.10 2003/01/02 14:27:12 eilers * Improved query by example: Search by date is possible.. First step * for a today plugin for birthdays.. * * Revision 1.9 2002/12/08 12:48:57 eilers * Moved journal-enum from ocontact into i the xml-backend.. * * Revision 1.8 2002/11/14 17:04:24 eilers * Sorting will now work if fullname is identical on some entries * @@ -50,694 +64,81 @@ * * Revision 1.2 2002/10/07 17:34:24 eilers * added OBackendFactory for advanced backend access * * Revision 1.1 2002/09/27 17:11:44 eilers * Added API for accessing the Contact-Database ! It is compiling, but * please do not expect that anything is working ! * I will debug that stuff in the next time .. * Please read README_COMPILE for compiling ! * * */ #ifndef _OContactAccessBackend_XML_ #define _OContactAccessBackend_XML_ -#include <qasciidict.h> -#include <qdatetime.h> -#include <qfile.h> -#include <qfileinfo.h> -#include <qregexp.h> -#include <qarray.h> -#include <qmap.h> -#include <qdatetime.h> - -#include <qpe/global.h> - -#include <opie/xmltree.h> #include "ocontactaccessbackend.h" #include "ocontactaccess.h" -#include <stdlib.h> -#include <errno.h> - -using namespace Opie; +#include <qlist.h> +#include <qdict.h> /* the default xml implementation */ class OContactAccessBackend_XML : public OContactAccessBackend { public: - OContactAccessBackend_XML ( QString appname, QString filename = 0l ): - m_changed( 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 (); - } + OContactAccessBackend_XML ( QString appname, QString filename = 0l ); - bool 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; - QString out; - out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" - " <Groups>\n" - " </Groups>\n" - " <Contacts>\n"; - //QValueList<Contact>::iterator it; - QValueListConstIterator<OContact> it; - for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { - out += "<Contact "; - (*it).save( out ); - out += "/>\n"; - QCString cstr = out.utf8(); - total_written = f.writeBlock( cstr.data(), cstr.length() ); - if ( total_written != int(cstr.length()) ) { - f.close(); - QFile::remove( strNewFile ); - return false; - } - out = ""; - } - out += " </Contacts>\n</AddressBook>\n"; - - QCString cstr = out.utf8(); - total_written = f.writeBlock( cstr.data(), cstr.length() ); - if ( total_written != int( cstr.length() ) ) { - f.close(); - QFile::remove( strNewFile ); - return false; - } - f.close(); - - // move the file over, I'm just going to use the system call - // because, I don't feel like using QDir. - if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { - qWarning( "problem renaming file %s to %s, errno: %d", - strNewFile.latin1(), m_journalName.latin1(), errno ); - // remove the tmp file... - QFile::remove( strNewFile ); - } - - /* The journalfile should be removed now... */ - removeJournal(); - - m_changed = false; - return true; - } + bool save(); - bool load () { - m_contactList.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 clear () { - m_contactList.clear(); - m_changed = false; + bool load (); - } + void clear (); - bool wasChangedExternally() - { - QFileInfo fi( m_fileName ); - - QDateTime lastmod = fi.lastModified (); - - return (lastmod != m_readtime); - } + bool wasChangedExternally(); - QArray<int> allRecords() const { - QArray<int> uid_list( m_contactList.count() ); - - uint counter = 0; - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - uid_list[counter++] = (*it).uid(); - } - - return ( uid_list ); - } + QArray<int> allRecords() const; - OContact find ( int uid ) const - { - bool found = false; - OContact foundContact; //Create empty contact - - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } - if ( found ){ - foundContact = *it; - } - - return ( foundContact ); - } + OContact find ( int uid ) const; - QArray<int> queryByExample ( const OContact &query, int settings ){ - - QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; - uint arraycounter = 0; - - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - /* Search all fields and compare them with query object. Store them into list - * if all fields matches. - */ - QDate* queryDate = 0l; - QDate* checkDate = 0l; - bool allcorrect = true; - for ( int i = 0; i < Qtopia::Groups; i++ ) { - // Birthday and anniversary are special nonstring fields and should - // be handled specially - switch ( i ){ - case Qtopia::Birthday: - queryDate = new QDate( query.birthday() ); - checkDate = new QDate( (*it).birthday() ); - case Qtopia::Anniversary: - if ( queryDate == 0l ){ - queryDate = new QDate( query.anniversary() ); - checkDate = new QDate( (*it).anniversary() ); - } - - if ( queryDate->isValid() ){ - if( checkDate->isValid() ){ - if ( settings & OContactAccess::DateYear ){ - if ( queryDate->year() != checkDate->year() ) - allcorrect = false; - } - if ( settings & OContactAccess::DateMonth ){ - if ( queryDate->month() != checkDate->month() ) - allcorrect = false; - } - if ( settings & OContactAccess::DateDay ){ - if ( queryDate->day() != checkDate->day() ) - allcorrect = false; - } - if ( settings & OContactAccess::DateDiff ) { - QDate current = QDate::currentDate(); - // 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() ); - qWarning("Checking if %s is between %s and %s ! ", - checkDate->toString().latin1(), - current.toString().latin1(), - queryDate->toString().latin1() ); - if ( current.daysTo( *queryDate ) > 0 ){ - if ( !( ( *checkDate >= current ) && - ( *checkDate <= *queryDate ) ) ){ - allcorrect = false; - qWarning (" Nope!.."); - } - } - } - } else{ - // checkDate is invalid. Therfore this entry is always rejected - allcorrect = false; - } - } - - delete queryDate; - queryDate = 0l; - delete checkDate; - checkDate = 0l; - break; - default: - /* Just compare fields which are not empty in the query object */ - if ( !query.field(i).isEmpty() ){ - switch ( settings & ~( OContactAccess::IgnoreCase - | OContactAccess::DateDiff - | OContactAccess::DateYear - | OContactAccess::DateMonth - | OContactAccess::DateDay - | OContactAccess::MatchOne - ) ){ + QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); - case OContactAccess::RegExp:{ - QRegExp expr ( query.field(i), - !(settings & OContactAccess::IgnoreCase), - false ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) - allcorrect = false; - } - break; - case OContactAccess::WildCards:{ - QRegExp expr ( query.field(i), - !(settings & OContactAccess::IgnoreCase), - true ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) - allcorrect = false; - } - break; - case OContactAccess::ExactMatch:{ - if (settings & OContactAccess::IgnoreCase){ - if ( query.field(i).upper() != - (*it).field(i).upper() ) - allcorrect = false; - }else{ - if ( query.field(i) != (*it).field(i) ) - allcorrect = false; - } - } - break; - } - } - } - } - if ( allcorrect ){ - m_currentQuery[arraycounter++] = (*it).uid(); - } - } - - // Shrink to fit.. - m_currentQuery.resize(arraycounter); + QArray<int> matchRegexp( const QRegExp &r ) const; - return m_currentQuery; - } - - QArray<int> matchRegexp( const QRegExp &r ) const{ - QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; - uint arraycounter = 0; - - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).match( r ) ){ - m_currentQuery[arraycounter++] = (*it).uid(); - } - - } - // Shrink to fit.. - m_currentQuery.resize(arraycounter); - - return m_currentQuery; - } - - const uint querySettings() - { - return ( OContactAccess::WildCards - | OContactAccess::IgnoreCase - | OContactAccess::RegExp - | OContactAccess::ExactMatch - | OContactAccess::DateDiff - | OContactAccess::DateYear - | OContactAccess::DateMonth - | OContactAccess::DateDay - ); - } + const uint querySettings(); - bool hasQuerySettings (uint querySettings) const - { - /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay - * may be added with any of the other settings. IgnoreCase should never used alone. - * Wildcards, RegExp, ExactMatch should never used at the same time... - */ - - if ( querySettings == OContactAccess::IgnoreCase ) - return false; - - switch ( querySettings & ~( OContactAccess::IgnoreCase - | OContactAccess::DateDiff - | OContactAccess::DateYear - | OContactAccess::DateMonth - | OContactAccess::DateDay - ) - ){ - case OContactAccess::RegExp: - return ( true ); - case OContactAccess::WildCards: - return ( true ); - case OContactAccess::ExactMatch: - return ( true ); - default: - return ( false ); - } - } + bool hasQuerySettings (uint querySettings) const; // Currently only asc implemented.. - QArray<int> 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.. - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); - nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); - } - names.sort(); - - int i = 0; - if ( asc ){ - for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) - m_currentQuery[i++] = nameToUid[ (*it) ]; - }else{ - for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) - m_currentQuery[i++] = nameToUid[ (*it) ]; - } - - return m_currentQuery; - - } - bool add ( const OContact &newcontact ) - { - //qWarning("odefaultbackend: ACTION::ADD"); - updateJournal (newcontact, ACTION_ADD); - addContact_p( newcontact ); - - m_changed = true; - - return true; - } - - bool replace ( const OContact &contact ) - { - m_changed = true; - - bool found = false; - - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).uid() == contact.uid() ){ - found = true; - break; - } - } - if (found) { - updateJournal (contact, ACTION_REPLACE); - m_contactList.remove (it); - m_contactList.append (contact); - return true; - } else - return false; - } + QArray<int> sorted( bool asc, int , int , int ); + bool add ( const OContact &newcontact ); - bool remove ( int uid ) - { - m_changed = true; - - bool found = false; - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } - if (found) { - updateJournal ( *it, ACTION_REMOVE); - m_contactList.remove (it); - return true; - } else - return false; - } + bool replace ( const OContact &contact ); - bool reload(){ - /* Reload is the same as load in this implementation */ - return ( load() ); - } + bool remove ( int uid ); + bool reload(); private: enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; - void addContact_p( const OContact &newcontact ){ - m_contactList.append (newcontact); - } + void addContact_p( const OContact &newcontact ); /* This function loads the xml-database and the journalfile */ - bool load( const QString filename, bool isJournal ) { - - /* We use the time of the last read to check if the file was - * changed externally. - */ - if ( !isJournal ){ - QFileInfo fi( filename ); - m_readtime = fi.lastModified (); - } - - const int JOURNALACTION = Qtopia::Notes + 1; - const int JOURNALROW = JOURNALACTION + 1; - - bool foundAction = false; - journal_action action = ACTION_ADD; - int journalKey = 0; - QMap<int, QString> contactMap; - QMap<QString, QString> customMap; - QMap<QString, QString>::Iterator customIt; - QAsciiDict<int> dict( 47 ); - - dict.setAutoDelete( TRUE ); - dict.insert( "Uid", new int(Qtopia::AddressUid) ); - dict.insert( "Title", new int(Qtopia::Title) ); - dict.insert( "FirstName", new int(Qtopia::FirstName) ); - dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); - dict.insert( "LastName", new int(Qtopia::LastName) ); - dict.insert( "Suffix", new int(Qtopia::Suffix) ); - dict.insert( "FileAs", new int(Qtopia::FileAs) ); - dict.insert( "Categories", new int(Qtopia::AddressCategory) ); - dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); - dict.insert( "Emails", new int(Qtopia::Emails) ); - dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); - dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); - dict.insert( "HomeState", new int(Qtopia::HomeState) ); - dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); - dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); - dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); - dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); - dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); - dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); - dict.insert( "Company", new int(Qtopia::Company) ); - dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); - dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); - dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); - dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); - dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); - dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); - dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); - dict.insert( "Department", new int(Qtopia::Department) ); - dict.insert( "Office", new int(Qtopia::Office) ); - dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); - dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); - dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); - dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); - dict.insert( "Profession", new int(Qtopia::Profession) ); - dict.insert( "Assistant", new int(Qtopia::Assistant) ); - dict.insert( "Manager", new int(Qtopia::Manager) ); - dict.insert( "Spouse", new int(Qtopia::Spouse) ); - dict.insert( "Children", new int(Qtopia::Children) ); - dict.insert( "Gender", new int(Qtopia::Gender) ); - dict.insert( "Birthday", new int(Qtopia::Birthday) ); - dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); - dict.insert( "Nickname", new int(Qtopia::Nickname) ); - dict.insert( "Notes", new int(Qtopia::Notes) ); - dict.insert( "action", new int(JOURNALACTION) ); - dict.insert( "actionrow", new int(JOURNALROW) ); - - //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); - - XMLElement *root = XMLElement::load( filename ); - if(root != 0l ){ // start parsing - /* Parse all XML-Elements and put the data into the - * Contact-Class - */ - XMLElement *element = root->firstChild(); - //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); - element = element->firstChild(); - - /* Search Tag "Contacts" which is the parent of all Contacts */ - while( element && !isJournal ){ - if( element->tagName() != QString::fromLatin1("Contacts") ){ - //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", - // element->tagName().latin1()); - element = element->nextChild(); - } else { - element = element->firstChild(); - break; - } - } - /* Parse all Contacts and ignore unknown tags */ - while( element ){ - if( element->tagName() != QString::fromLatin1("Contact") ){ - //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", - // element->tagName().latin1()); - element = element->nextChild(); - continue; - } - /* Found alement with tagname "contact", now parse and store all - * attributes contained - */ - //qWarning("OContactDefBack::load element tagName() : %s", - // element->tagName().latin1() ); - QString dummy; - foundAction = false; - - XMLElement::AttributeMap aMap = element->attributes(); - XMLElement::AttributeMap::Iterator it; - contactMap.clear(); - customMap.clear(); - for( it = aMap.begin(); it != aMap.end(); ++it ){ - // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); - - int *find = dict[ it.key() ]; - /* Unknown attributes will be stored as "Custom" elements */ - if ( !find ) { - qWarning("Attribute %s not known.", it.key().latin1()); - //contact.setCustomField(it.key(), it.data()); - customMap.insert( it.key(), it.data() ); - continue; - } - - /* Check if special conversion is needed and add attribute - * into Contact class - */ - switch( *find ) { - /* - case Qtopia::AddressUid: - contact.setUid( it.data().toInt() ); - break; - case Qtopia::AddressCategory: - contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); - break; - */ - case JOURNALACTION: - action = journal_action(it.data().toInt()); - foundAction = true; - qWarning ("ODefBack(journal)::ACTION found: %d", action); - break; - case JOURNALROW: - journalKey = it.data().toInt(); - break; - default: // no conversion needed add them to the map - contactMap.insert( *find, it.data() ); - break; - } - } - /* now generate the Contact contact */ - OContact contact( contactMap ); - - for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { - contact.setCustomField( customIt.key(), customIt.data() ); - } - - if (foundAction){ - foundAction = false; - switch ( action ) { - case ACTION_ADD: - addContact_p (contact); - break; - case ACTION_REMOVE: - if ( !remove (contact.uid()) ) - qWarning ("ODefBack(journal)::Unable to remove uid: %d", - contact.uid() ); - break; - case ACTION_REPLACE: - if ( !replace ( contact ) ) - qWarning ("ODefBack(journal)::Unable to replace uid: %d", - contact.uid() ); - break; - default: - qWarning ("Unknown action: ignored !"); - break; - } - }else{ - /* Add contact to list */ - addContact_p (contact); - } - - /* Move to next element */ - element = element->nextChild(); - } - }else { - qWarning("ODefBack::could not load"); - } - delete root; - qWarning("returning from loading" ); - return true; - } - + bool load( const QString filename, bool isJournal ); - void updateJournal( const OContact& cnt, - journal_action action ) { - QFile f( m_journalName ); - bool created = !f.exists(); - if ( !f.open(IO_WriteOnly|IO_Append) ) - return; - - QString buf; - QCString str; - - // if the file was created, we have to set the Tag "<CONTACTS>" to - // get a XML-File which is readable by our parser. - // This is just a cheat, but better than rewrite the parser. - if ( created ){ - buf = "<Contacts>"; - QCString cstr = buf.utf8(); - f.writeBlock( cstr.data(), cstr.length() ); - } - - buf = "<Contact "; - cnt.save( buf ); - buf += " action=\"" + QString::number( (int)action ) + "\" "; - buf += "/>\n"; - QCString cstr = buf.utf8(); - f.writeBlock( cstr.data(), cstr.length() ); - } - void removeJournal() - { - QFile f ( m_journalName ); - if ( f.exists() ) - f.remove(); - } + void updateJournal( const OContact& cnt, journal_action action ); + void removeJournal(); protected: bool m_changed; QString m_journalName; QString m_fileName; QString m_appName; - QValueList<OContact> m_contactList; + QList<OContact> m_contactList; QDateTime m_readtime; + + QDict<OContact> m_uidToContact; }; #endif diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp index 4a6b7b8..11e19d9 100644 --- a/libopie/pim/odatebookaccessbackend_xml.cpp +++ b/libopie/pim/odatebookaccessbackend_xml.cpp @@ -231,33 +231,33 @@ bool ODateBookAccessBackend_XML::save() { QArray<int> ODateBookAccessBackend_XML::allRecords()const { QArray<int> ints( m_raw.count()+ m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { ints[i] = it.key(); i++; } for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } -QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int ) { +QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) { return QArray<int>(); } void ODateBookAccessBackend_XML::clear() { m_raw.clear(); m_rep.clear(); } OEvent ODateBookAccessBackend_XML::find( int uid ) const{ if ( m_raw.contains( uid ) ) return m_raw[uid]; else return m_rep[uid]; } bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { m_changed = true; if (ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); diff --git a/libopie/pim/odatebookaccessbackend_xml.h b/libopie/pim/odatebookaccessbackend_xml.h index 40f69d8..563c31f 100644 --- a/libopie/pim/odatebookaccessbackend_xml.h +++ b/libopie/pim/odatebookaccessbackend_xml.h @@ -3,33 +3,33 @@ #include <qmap.h> #include "odatebookaccessbackend.h" 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> queryByExample( const OEvent&, int ); + QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); OEvent find( int uid )const; void clear(); bool add( const OEvent& ev ); bool remove( int uid ); bool replace( const OEvent& ev ); QArray<UID> rawEvents()const; QArray<UID> rawRepeats()const; QArray<UID> nonRepeats()const; OEvent::ValueList directNonRepeats(); OEvent::ValueList directRawRepeats(); private: bool m_changed :1 ; bool loadFile(); diff --git a/libopie/pim/opimaccessbackend.h b/libopie/pim/opimaccessbackend.h index e268f4f..01a0c86 100644 --- a/libopie/pim/opimaccessbackend.h +++ b/libopie/pim/opimaccessbackend.h @@ -34,36 +34,36 @@ public: */ virtual bool reload() = 0; /** * save the resource and * all it's changes */ virtual bool save() = 0; /** * return an array of * all available uids */ virtual QArray<int> allRecords()const = 0; /** - * queryByExample for T with the SortOrder - * sort + * queryByExample for T with the given Settings + * */ - virtual QArray<int> queryByExample( const T& t, int sort ) = 0; + virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0; /** * find the OPimRecord with uid @param uid * returns T and T.isEmpty() if nothing was found */ virtual T find(int uid )const = 0; virtual T find(int uid, const QArray<int>& items, uint current, typename Frontend::CacheDirection )const ; /** * clear the back end */ virtual void clear() = 0; /** * add T diff --git a/libopie/pim/opimaccesstemplate.h b/libopie/pim/opimaccesstemplate.h index 259e2c1..6a3a0db 100644 --- a/libopie/pim/opimaccesstemplate.h +++ b/libopie/pim/opimaccesstemplate.h @@ -61,33 +61,33 @@ public: * if the resource was changed externally * You should use the signal handling instead of polling possible changes ! * zecke: Do you implement a signal for otodoaccess ? */ bool wasChangedExternally()const; /** * return a List of records * you can iterate over them */ virtual List allRecords()const; /** * queryByExample. * @see otodoaccess, ocontactaccess */ - virtual List queryByExample( const T& t, int querySettings ); + virtual List queryByExample( const T& t, int querySettings, const QDateTime& d = QDateTime() ); /** * find the OPimRecord uid */ virtual T find( int uid )const; /** * read ahead cache find method ;) */ virtual T find( int uid, const QArray<int>&, uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const; /* invalidate cache here */ /** * clears the backend and invalidates the backend */ @@ -173,34 +173,34 @@ bool OPimAccessTemplate<T>::reload() { template <class T> bool OPimAccessTemplate<T>::save() { return m_backEnd->save(); } template <class T> typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { QArray<int> ints = m_backEnd->allRecords(); List lis(ints, this ); return lis; } template <class T> QArray<int> OPimAccessTemplate<T>::records()const { return m_backEnd->allRecords(); } template <class T> typename OPimAccessTemplate<T>::List -OPimAccessTemplate<T>::queryByExample( const T& t, int sortOrder ) { - QArray<int> ints = m_backEnd->queryByExample( t, sortOrder ); +OPimAccessTemplate<T>::queryByExample( const T& t, int settings, const QDateTime& d ) { + QArray<int> ints = m_backEnd->queryByExample( t, settings, d ); List lis(ints, this ); return lis; } template <class T> T OPimAccessTemplate<T>::find( int uid ) const{ T t = m_backEnd->find( uid ); cache( t ); return t; } template <class T> T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, uint current, typename OTemplateBase<T>::CacheDirection dir )const { /* * better do T.isEmpty() * after a find this way we would diff --git a/libopie/pim/otodoaccesssql.cpp b/libopie/pim/otodoaccesssql.cpp index 761d7d8..ec9c14c 100644 --- a/libopie/pim/otodoaccesssql.cpp +++ b/libopie/pim/otodoaccesssql.cpp @@ -264,33 +264,33 @@ bool OTodoAccessBackendSQL::load(){ m_dirty = true; return true; } bool OTodoAccessBackendSQL::reload(){ return load(); } bool OTodoAccessBackendSQL::save(){ return m_driver->close(); } QArray<int> OTodoAccessBackendSQL::allRecords()const { if (m_dirty ) update(); return m_uids; } -QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int ){ +QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){ QArray<int> ints(0); return ints; } OTodo OTodoAccessBackendSQL::find(int uid ) const{ FindQuery query( uid ); return todo( m_driver->query(&query) ); } OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, uint cur, Frontend::CacheDirection dir ) const{ int CACHE = readAhead(); qWarning("searching for %d", uid ); QArray<int> search( CACHE ); uint size =0; OTodo to; diff --git a/libopie/pim/otodoaccesssql.h b/libopie/pim/otodoaccesssql.h index 0f6dd2c..6a4257c 100644 --- a/libopie/pim/otodoaccesssql.h +++ b/libopie/pim/otodoaccesssql.h @@ -5,33 +5,33 @@ #include "otodoaccessbackend.h" class OSQLDriver; class OSQLResult; class OSQLResultItem; class OTodoAccessBackendSQL : public OTodoAccessBackend { public: OTodoAccessBackendSQL( const QString& file ); ~OTodoAccessBackendSQL(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; - QArray<int> queryByExample( const OTodo& t, int sort ); + QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() ); OTodo find(int uid)const; OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; void clear(); bool add( const OTodo& t ); bool remove( int uid ); bool replace( const OTodo& t ); QArray<int> overDue(); QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); private: void update()const; void fillDict(); inline bool date( QDate& date, const QString& )const; diff --git a/libopie/pim/otodoaccessvcal.cpp b/libopie/pim/otodoaccessvcal.cpp index 309f9e1..2136283 100644 --- a/libopie/pim/otodoaccessvcal.cpp +++ b/libopie/pim/otodoaccessvcal.cpp @@ -172,30 +172,30 @@ OTodo OTodoAccessVCal::find(int uid )const { return m_map[uid]; } QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::allRecords()const { QArray<int> ar( m_map.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } -QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int ) { +QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& , const QDate& , bool ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::overDue() { QArray<int> ar(0); return ar; } diff --git a/libopie/pim/otodoaccessvcal.h b/libopie/pim/otodoaccessvcal.h index 452f602..a90ee9c 100644 --- a/libopie/pim/otodoaccessvcal.h +++ b/libopie/pim/otodoaccessvcal.h @@ -1,32 +1,32 @@ #ifndef OPIE_OTODO_ACCESS_VCAL_H #define OPIE_OTODO_ACCESS_VCAL_H #include "otodoaccessbackend.h" class OTodoAccessVCal : public OTodoAccessBackend { public: OTodoAccessVCal(const QString& ); ~OTodoAccessVCal(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; - QArray<int> queryByExample( const OTodo& t, int sort ); + QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() ); QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> overDue(); QArray<int> sorted( bool asc, int sortOrder, int sortFilter, int cat ); OTodo find(int uid)const; void clear(); bool add( const OTodo& ); bool remove( int uid ); bool replace( const OTodo& ); void removeAllCompleted(); private: bool m_dirty : 1; diff --git a/libopie/pim/otodoaccessxml.cpp b/libopie/pim/otodoaccessxml.cpp index cda300b..71e8787 100644 --- a/libopie/pim/otodoaccessxml.cpp +++ b/libopie/pim/otodoaccessxml.cpp @@ -242,33 +242,33 @@ bool OTodoAccessXML::save() { } m_changed = false; return true; } QArray<int> OTodoAccessXML::allRecords()const { QArray<int> ids( m_events.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { ids[i] = it.key(); i++; } return ids; } -QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int ) { +QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { QArray<int> ids(0); return ids; } OTodo OTodoAccessXML::find( int uid )const { OTodo todo; todo.setUid( 0 ); // isEmpty() QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); if ( it != m_events.end() ) todo = it.data(); return todo; } void OTodoAccessXML::clear() { if (m_opened ) m_changed = true; diff --git a/libopie/pim/otodoaccessxml.h b/libopie/pim/otodoaccessxml.h index 93609fe..1032c92 100644 --- a/libopie/pim/otodoaccessxml.h +++ b/libopie/pim/otodoaccessxml.h @@ -11,33 +11,33 @@ namespace Opie { }; class OTodoAccessXML : public OTodoAccessBackend { public: /** * fileName if Empty we will use the default path */ OTodoAccessXML( const QString& appName, const QString& fileName = QString::null ); ~OTodoAccessXML(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; - QArray<int> queryByExample( const OTodo&, int querysettings ); + QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() ); OTodo find( int uid )const; void clear(); bool add( const OTodo& ); bool remove( int uid ); void removeAllCompleted(); bool replace( const OTodo& ); /* our functions */ QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> overDue(); QArray<int> sorted( bool asc, int sortOrder, int sortFilter, int cat ); private: void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& ); diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp index e537269..f24523f 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.cpp @@ -4,32 +4,40 @@ * Copyright (C) 2000 Trolltech AS. All rights reserved. * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.9 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * * Revision 1.8 2003/02/21 16:52:49 zecke * -Remove old Todo classes they're deprecated and today I already using the * new API * -Guard against self assignment in OTodo * -Add test apps for OPIM * -Opiefied Event classes * -Added TimeZone handling and pinning of TimeZones to OEvent * -Adjust ORecur and the widget to better timezone behaviour * * Revision 1.7 2003/02/16 22:25:46 zecke * 0000276 Fix for that bug.. or better temp workaround * A Preferred Number is HOME|VOICE * A CellPhone is HOME|VOICE|CELL the type & HOME|VOICE test * triggers both * and the cell phone number overrides the other entries.. * @@ -176,33 +184,33 @@ OContact OContactAccessBackend_VCard::find ( int uid ) const return m_map[uid]; } QArray<int> OContactAccessBackend_VCard::allRecords() const { QArray<int> ar( m_map.count() ); QMap<int, OContact>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } // Not implemented -QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int ) +QArray<int> OContactAccessBackend_VCard::queryByExample ( const OContact&, int, const QDateTime& ) { QArray<int> ar(0); return ar; } // Not implemented QArray<int> OContactAccessBackend_VCard::matchRegexp( const QRegExp& ) const { QArray<int> ar(0); return ar; } const uint OContactAccessBackend_VCard::querySettings() { return 0; // No search possible } diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h index 236da00..93e2da3 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_vcard.h @@ -4,32 +4,40 @@ * Copyright (C) 2000 Trolltech AS. All rights reserved. * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.5 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * * Revision 1.4 2002/12/07 13:26:22 eilers * Fixing bug in storing anniversary.. * * Revision 1.3 2002/11/13 14:14:51 eilers * Added sorted for Contacts.. * * Revision 1.2 2002/11/10 15:41:53 eilers * Bugfixes.. * * Revision 1.1 2002/11/09 14:34:52 eilers * Added VCard Backend. * */ #ifndef __OCONTACTACCESSBACKEND_VCARD_H_ #define __OCONTACTACCESSBACKEND_VCARD_H_ @@ -41,33 +49,33 @@ class VObject; class OContactAccessBackend_VCard : public OContactAccessBackend { public: OContactAccessBackend_VCard ( QString appname, QString filename = 0l ); bool load (); bool reload(); bool save(); void clear (); bool add ( const OContact& newcontact ); bool remove ( int uid ); bool replace ( const OContact& contact ); OContact find ( int uid ) const; QArray<int> allRecords() const; - QArray<int> queryByExample ( const OContact &query, int settings ); + QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); QArray<int> matchRegexp( const QRegExp &r ) const; const uint querySettings(); bool hasQuerySettings (uint querySettings) const; QArray<int> sorted( bool ascending, int sortOrder, int sortFilter, int cat ); bool wasChangedExternally(); private: OContact parseVObject( VObject* obj ); VObject* createVObject( const OContact& c ); QString convDateToVCardDate( const QDate& c ) const; QDate convVCardDateToDate( const QString& datestr ); VObject *safeAddPropValue( VObject *o, const char* prop, const QString& value ); VObject *safeAddProp( VObject* o, const char* prop); bool m_dirty : 1; diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp index 2df6757..4abf4d9 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.cpp @@ -4,32 +4,46 @@ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: XML-Backend: Automatic reload if something was changed... * * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.2 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.1.2.2 2003/02/11 12:17:28 eilers + * Speed optimization. Removed the sequential search loops. + * + * Revision 1.1.2.1 2003/02/10 15:31:38 eilers + * Writing offsets to debug output.. + * * Revision 1.1 2003/02/09 15:05:01 eilers * Nothing happened.. Just some cleanup before I will start.. * * Revision 1.12 2003/01/03 16:58:03 eilers * Reenable debug output * * Revision 1.11 2003/01/03 12:31:28 eilers * Bugfix for calculating data diffs.. * * Revision 1.10 2003/01/02 14:27:12 eilers * Improved query by example: Search by date is possible.. First step * for a today plugin for birthdays.. * * Revision 1.9 2002/12/08 12:48:57 eilers * Moved journal-enum from ocontact into i the xml-backend.. * @@ -76,310 +90,335 @@ #include <qpe/global.h> #include <opie/xmltree.h> #include "ocontactaccessbackend.h" #include "ocontactaccess.h" #include <stdlib.h> #include <errno.h> using namespace Opie; OContactAccessBackend_XML::OContactAccessBackend_XML ( QString appname, QString filename = 0l ): m_changed( false ) { + // Just m_contactlist should call delete if an entry + // is removed. + m_contactList.setAutoDelete( true ); + m_uidToContact.setAutoDelete( false ); + m_appName = appname; /* Set journalfile name ... */ m_journalName = getenv("HOME"); m_journalName +="/.abjournal" + appname; /* Expecting to access the default filename if nothing else is set */ if ( filename.isEmpty() ){ m_fileName = Global::applicationFileName( "addressbook","addressbook.xml" ); } else m_fileName = filename; /* Load Database now */ load (); } bool OContactAccessBackend_XML::save() { if ( !m_changed ) return true; QString strNewFile = m_fileName + ".new"; QFile f( strNewFile ); if ( !f.open( IO_WriteOnly|IO_Raw ) ) return false; int total_written; + int idx_offset = 0; QString out; + + // Write Header out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" " <Groups>\n" " </Groups>\n" " <Contacts>\n"; - //QValueList<Contact>::iterator it; - QValueListConstIterator<OContact> it; - for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { + QCString cstr = out.utf8(); + f.writeBlock( cstr.data(), cstr.length() ); + idx_offset += cstr.length(); + out = ""; + + // Write all contacts + QListIterator<OContact> it( m_contactList ); + for ( ; it.current(); ++it ) { + qWarning(" Uid %d at Offset: %x", (*it)->uid(), idx_offset ); out += "<Contact "; - (*it).save( out ); + (*it)->save( out ); out += "/>\n"; - QCString cstr = out.utf8(); + 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"; - QCString cstr = out.utf8(); + // Write Footer + cstr = out.utf8(); total_written = f.writeBlock( cstr.data(), cstr.length() ); if ( total_written != int( cstr.length() ) ) { f.close(); QFile::remove( strNewFile ); return false; } f.close(); // move the file over, I'm just going to use the system call // because, I don't feel like using QDir. if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { qWarning( "problem renaming file %s to %s, errno: %d", strNewFile.latin1(), m_journalName.latin1(), errno ); // remove the tmp file... QFile::remove( strNewFile ); } /* The journalfile should be removed now... */ removeJournal(); m_changed = false; return true; } bool OContactAccessBackend_XML::load () { m_contactList.clear(); + m_uidToContact.clear(); /* Load XML-File and journal if it exists */ if ( !load ( m_fileName, false ) ) return false; /* The returncode of the journalfile is ignored due to the * fact that it does not exist when this class is instantiated ! * But there may such a file exist, if the application crashed. * Therefore we try to load it to get the changes before the # * crash happened... */ load (m_journalName, true); return true; } void OContactAccessBackend_XML::clear () { m_contactList.clear(); + m_uidToContact.clear(); + m_changed = false; - } bool OContactAccessBackend_XML::wasChangedExternally() { QFileInfo fi( m_fileName ); QDateTime lastmod = fi.lastModified (); return (lastmod != m_readtime); } QArray<int> OContactAccessBackend_XML::allRecords() const { QArray<int> uid_list( m_contactList.count() ); uint counter = 0; - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - uid_list[counter++] = (*it).uid(); + QListIterator<OContact> it( m_contactList ); + for( ; it.current(); ++it ){ + uid_list[counter++] = (*it)->uid(); } return ( uid_list ); } OContact OContactAccessBackend_XML::find ( int uid ) const { - bool found = false; OContact foundContact; //Create empty contact - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } + OContact* found = m_uidToContact.find( QString().setNum( uid ) ); + if ( found ){ - foundContact = *it; + foundContact = *found; } return ( foundContact ); } -QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings ) +QArray<int> OContactAccessBackend_XML::queryByExample ( const OContact &query, int settings, + const QDateTime& d ) { QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; + QListIterator<OContact> it( m_contactList ); uint arraycounter = 0; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ + 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() ); + checkDate = new QDate( (*it)->birthday() ); case Qtopia::Anniversary: if ( queryDate == 0l ){ queryDate = new QDate( query.anniversary() ); - checkDate = new QDate( (*it).anniversary() ); + checkDate = new QDate( (*it)->anniversary() ); } if ( queryDate->isValid() ){ if( checkDate->isValid() ){ if ( settings & OContactAccess::DateYear ){ if ( queryDate->year() != checkDate->year() ) allcorrect = false; } if ( settings & OContactAccess::DateMonth ){ if ( queryDate->month() != checkDate->month() ) allcorrect = false; } if ( settings & OContactAccess::DateDay ){ if ( queryDate->day() != checkDate->day() ) allcorrect = false; } if ( settings & OContactAccess::DateDiff ) { - QDate current = QDate::currentDate(); + QDate current; + // If we get an additional date, we + // will take this date instead of + // the current one.. + if ( !d.date().isValid() ) + current = QDate::currentDate(); + else + current = d.date(); + // We have to equalize the year, otherwise // the search will fail.. checkDate->setYMD( current.year(), checkDate->month(), checkDate->day() ); if ( *checkDate < current ) checkDate->setYMD( current.year()+1, checkDate->month(), checkDate->day() ); + + // Check whether the birthday/anniversary date is between + // the current/given date and the maximum date + // ( maximum time range ) ! qWarning("Checking if %s is between %s and %s ! ", checkDate->toString().latin1(), current.toString().latin1(), queryDate->toString().latin1() ); if ( current.daysTo( *queryDate ) > 0 ){ if ( !( ( *checkDate >= current ) && ( *checkDate <= *queryDate ) ) ){ allcorrect = false; qWarning (" Nope!.."); } } } } else{ - // checkDate is invalid. Therfore this entry is always rejected + // checkDate is invalid. Therefore this entry is always rejected allcorrect = false; } } delete queryDate; queryDate = 0l; delete checkDate; checkDate = 0l; break; default: /* Just compare fields which are not empty in the query object */ if ( !query.field(i).isEmpty() ){ switch ( settings & ~( OContactAccess::IgnoreCase | OContactAccess::DateDiff | OContactAccess::DateYear | OContactAccess::DateMonth | OContactAccess::DateDay | OContactAccess::MatchOne ) ){ case OContactAccess::RegExp:{ QRegExp expr ( query.field(i), !(settings & OContactAccess::IgnoreCase), false ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) + if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OContactAccess::WildCards:{ QRegExp expr ( query.field(i), !(settings & OContactAccess::IgnoreCase), true ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) + if ( expr.find ( (*it)->field(i), 0 ) == -1 ) allcorrect = false; } break; case OContactAccess::ExactMatch:{ if (settings & OContactAccess::IgnoreCase){ if ( query.field(i).upper() != - (*it).field(i).upper() ) + (*it)->field(i).upper() ) allcorrect = false; }else{ - if ( query.field(i) != (*it).field(i) ) + if ( query.field(i) != (*it)->field(i) ) allcorrect = false; } } break; } } } } if ( allcorrect ){ - m_currentQuery[arraycounter++] = (*it).uid(); + m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } QArray<int> OContactAccessBackend_XML::matchRegexp( const QRegExp &r ) const { QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; + QListIterator<OContact> it( m_contactList ); uint arraycounter = 0; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).match( r ) ){ - m_currentQuery[arraycounter++] = (*it).uid(); + for( ; it.current(); ++it ){ + if ( (*it)->match( r ) ){ + m_currentQuery[arraycounter++] = (*it)->uid(); } } // Shrink to fit.. m_currentQuery.resize(arraycounter); return m_currentQuery; } const uint OContactAccessBackend_XML::querySettings() { return ( OContactAccess::WildCards | OContactAccess::IgnoreCase | OContactAccess::RegExp | OContactAccess::ExactMatch | OContactAccess::DateDiff @@ -413,113 +452,112 @@ bool OContactAccessBackend_XML::hasQuerySettings (uint querySettings) const case OContactAccess::ExactMatch: return ( true ); default: return ( false ); } } // Currently only asc implemented.. QArray<int> OContactAccessBackend_XML::sorted( bool asc, int , int , int ) { QMap<QString, int> nameToUid; QStringList names; QArray<int> m_currentQuery( m_contactList.count() ); // First fill map and StringList with all Names // Afterwards sort namelist and use map to fill array to return.. - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); - nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); + QListIterator<OContact> it( m_contactList ); + for( ; it.current(); ++it ){ + names.append( (*it)->fileAs() + QString::number( (*it)->uid() ) ); + nameToUid.insert( (*it)->fileAs() + QString::number( (*it)->uid() ), (*it)->uid() ); } names.sort(); int i = 0; if ( asc ){ for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) m_currentQuery[i++] = nameToUid[ (*it) ]; }else{ for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) m_currentQuery[i++] = nameToUid[ (*it) ]; } return m_currentQuery; } bool OContactAccessBackend_XML::add ( const OContact &newcontact ) { //qWarning("odefaultbackend: ACTION::ADD"); updateJournal (newcontact, ACTION_ADD); addContact_p( newcontact ); m_changed = true; return true; } bool OContactAccessBackend_XML::replace ( const OContact &contact ) { m_changed = true; - bool found = false; - - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).uid() == contact.uid() ){ - found = true; - break; - } - } - if (found) { - updateJournal (contact, ACTION_REPLACE); - m_contactList.remove (it); - m_contactList.append (contact); + OContact* found = m_uidToContact.find ( QString().setNum( contact.uid() ) ); + + if ( found ) { + OContact* newCont = new OContact( contact ); + + updateJournal ( *newCont, ACTION_REPLACE); + m_contactList.removeRef ( found ); + m_contactList.append ( newCont ); + m_uidToContact.remove( QString().setNum( contact.uid() ) ); + m_uidToContact.insert( QString().setNum( newCont->uid() ), newCont ); + + qWarning("Nur zur Sicherheit: %d == %d ?",contact.uid(), newCont->uid()); + return true; } else return false; } bool OContactAccessBackend_XML::remove ( int uid ) { m_changed = true; - bool found = false; - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } - if (found) { - updateJournal ( *it, ACTION_REMOVE); - m_contactList.remove (it); + OContact* found = m_uidToContact.find ( QString().setNum( uid ) ); + + if ( found ) { + updateJournal ( *found, ACTION_REMOVE); + m_contactList.removeRef ( found ); + m_uidToContact.remove( QString().setNum( uid ) ); + return true; } else return false; } bool OContactAccessBackend_XML::reload(){ /* Reload is the same as load in this implementation */ return ( load() ); } void OContactAccessBackend_XML::addContact_p( const OContact &newcontact ) { - m_contactList.append (newcontact); + OContact* contRef = new OContact( newcontact ); + + m_contactList.append ( contRef ); + m_uidToContact.insert( QString().setNum( newcontact.uid() ), contRef ); } /* This function loads the xml-database and the journalfile */ bool OContactAccessBackend_XML::load( const QString filename, bool isJournal ) { /* We use the time of the last read to check if the file was * changed externally. */ if ( !isJournal ){ QFileInfo fi( filename ); m_readtime = fi.lastModified (); } const int JOURNALACTION = Qtopia::Notes + 1; const int JOURNALROW = JOURNALACTION + 1; diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h index 6477705..4d6a7ef 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_xml.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_xml.h @@ -4,32 +4,46 @@ * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ToDo: XML-Backend: Automatic reload if something was changed... * * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.13 2003/03/21 10:33:09 eilers + * Merged speed optimized xml backend for contacts to main. + * Added QDateTime to querybyexample. For instance, it is now possible to get + * all Birthdays/Anniversaries between two dates. This should be used + * to show all birthdays in the datebook.. + * This change is sourcecode backward compatible but you have to upgrade + * the binaries for today-addressbook. + * + * Revision 1.12.2.2 2003/02/11 12:17:28 eilers + * Speed optimization. Removed the sequential search loops. + * + * Revision 1.12.2.1 2003/02/09 15:05:01 eilers + * Nothing happened.. Just some cleanup before I will start.. + * * Revision 1.12 2003/01/03 16:58:03 eilers * Reenable debug output * * Revision 1.11 2003/01/03 12:31:28 eilers * Bugfix for calculating data diffs.. * * Revision 1.10 2003/01/02 14:27:12 eilers * Improved query by example: Search by date is possible.. First step * for a today plugin for birthdays.. * * Revision 1.9 2002/12/08 12:48:57 eilers * Moved journal-enum from ocontact into i the xml-backend.. * * Revision 1.8 2002/11/14 17:04:24 eilers * Sorting will now work if fullname is identical on some entries * @@ -50,694 +64,81 @@ * * Revision 1.2 2002/10/07 17:34:24 eilers * added OBackendFactory for advanced backend access * * Revision 1.1 2002/09/27 17:11:44 eilers * Added API for accessing the Contact-Database ! It is compiling, but * please do not expect that anything is working ! * I will debug that stuff in the next time .. * Please read README_COMPILE for compiling ! * * */ #ifndef _OContactAccessBackend_XML_ #define _OContactAccessBackend_XML_ -#include <qasciidict.h> -#include <qdatetime.h> -#include <qfile.h> -#include <qfileinfo.h> -#include <qregexp.h> -#include <qarray.h> -#include <qmap.h> -#include <qdatetime.h> - -#include <qpe/global.h> - -#include <opie/xmltree.h> #include "ocontactaccessbackend.h" #include "ocontactaccess.h" -#include <stdlib.h> -#include <errno.h> - -using namespace Opie; +#include <qlist.h> +#include <qdict.h> /* the default xml implementation */ class OContactAccessBackend_XML : public OContactAccessBackend { public: - OContactAccessBackend_XML ( QString appname, QString filename = 0l ): - m_changed( 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 (); - } + OContactAccessBackend_XML ( QString appname, QString filename = 0l ); - bool 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; - QString out; - out = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE Addressbook ><AddressBook>\n" - " <Groups>\n" - " </Groups>\n" - " <Contacts>\n"; - //QValueList<Contact>::iterator it; - QValueListConstIterator<OContact> it; - for ( it = m_contactList.begin(); it != m_contactList.end(); ++it ) { - out += "<Contact "; - (*it).save( out ); - out += "/>\n"; - QCString cstr = out.utf8(); - total_written = f.writeBlock( cstr.data(), cstr.length() ); - if ( total_written != int(cstr.length()) ) { - f.close(); - QFile::remove( strNewFile ); - return false; - } - out = ""; - } - out += " </Contacts>\n</AddressBook>\n"; - - QCString cstr = out.utf8(); - total_written = f.writeBlock( cstr.data(), cstr.length() ); - if ( total_written != int( cstr.length() ) ) { - f.close(); - QFile::remove( strNewFile ); - return false; - } - f.close(); - - // move the file over, I'm just going to use the system call - // because, I don't feel like using QDir. - if ( ::rename( strNewFile.latin1(), m_fileName.latin1() ) < 0 ) { - qWarning( "problem renaming file %s to %s, errno: %d", - strNewFile.latin1(), m_journalName.latin1(), errno ); - // remove the tmp file... - QFile::remove( strNewFile ); - } - - /* The journalfile should be removed now... */ - removeJournal(); - - m_changed = false; - return true; - } + bool save(); - bool load () { - m_contactList.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 clear () { - m_contactList.clear(); - m_changed = false; + bool load (); - } + void clear (); - bool wasChangedExternally() - { - QFileInfo fi( m_fileName ); - - QDateTime lastmod = fi.lastModified (); - - return (lastmod != m_readtime); - } + bool wasChangedExternally(); - QArray<int> allRecords() const { - QArray<int> uid_list( m_contactList.count() ); - - uint counter = 0; - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - uid_list[counter++] = (*it).uid(); - } - - return ( uid_list ); - } + QArray<int> allRecords() const; - OContact find ( int uid ) const - { - bool found = false; - OContact foundContact; //Create empty contact - - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } - if ( found ){ - foundContact = *it; - } - - return ( foundContact ); - } + OContact find ( int uid ) const; - QArray<int> queryByExample ( const OContact &query, int settings ){ - - QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; - uint arraycounter = 0; - - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - /* Search all fields and compare them with query object. Store them into list - * if all fields matches. - */ - QDate* queryDate = 0l; - QDate* checkDate = 0l; - bool allcorrect = true; - for ( int i = 0; i < Qtopia::Groups; i++ ) { - // Birthday and anniversary are special nonstring fields and should - // be handled specially - switch ( i ){ - case Qtopia::Birthday: - queryDate = new QDate( query.birthday() ); - checkDate = new QDate( (*it).birthday() ); - case Qtopia::Anniversary: - if ( queryDate == 0l ){ - queryDate = new QDate( query.anniversary() ); - checkDate = new QDate( (*it).anniversary() ); - } - - if ( queryDate->isValid() ){ - if( checkDate->isValid() ){ - if ( settings & OContactAccess::DateYear ){ - if ( queryDate->year() != checkDate->year() ) - allcorrect = false; - } - if ( settings & OContactAccess::DateMonth ){ - if ( queryDate->month() != checkDate->month() ) - allcorrect = false; - } - if ( settings & OContactAccess::DateDay ){ - if ( queryDate->day() != checkDate->day() ) - allcorrect = false; - } - if ( settings & OContactAccess::DateDiff ) { - QDate current = QDate::currentDate(); - // 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() ); - qWarning("Checking if %s is between %s and %s ! ", - checkDate->toString().latin1(), - current.toString().latin1(), - queryDate->toString().latin1() ); - if ( current.daysTo( *queryDate ) > 0 ){ - if ( !( ( *checkDate >= current ) && - ( *checkDate <= *queryDate ) ) ){ - allcorrect = false; - qWarning (" Nope!.."); - } - } - } - } else{ - // checkDate is invalid. Therfore this entry is always rejected - allcorrect = false; - } - } - - delete queryDate; - queryDate = 0l; - delete checkDate; - checkDate = 0l; - break; - default: - /* Just compare fields which are not empty in the query object */ - if ( !query.field(i).isEmpty() ){ - switch ( settings & ~( OContactAccess::IgnoreCase - | OContactAccess::DateDiff - | OContactAccess::DateYear - | OContactAccess::DateMonth - | OContactAccess::DateDay - | OContactAccess::MatchOne - ) ){ + QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d = QDateTime() ); - case OContactAccess::RegExp:{ - QRegExp expr ( query.field(i), - !(settings & OContactAccess::IgnoreCase), - false ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) - allcorrect = false; - } - break; - case OContactAccess::WildCards:{ - QRegExp expr ( query.field(i), - !(settings & OContactAccess::IgnoreCase), - true ); - if ( expr.find ( (*it).field(i), 0 ) == -1 ) - allcorrect = false; - } - break; - case OContactAccess::ExactMatch:{ - if (settings & OContactAccess::IgnoreCase){ - if ( query.field(i).upper() != - (*it).field(i).upper() ) - allcorrect = false; - }else{ - if ( query.field(i) != (*it).field(i) ) - allcorrect = false; - } - } - break; - } - } - } - } - if ( allcorrect ){ - m_currentQuery[arraycounter++] = (*it).uid(); - } - } - - // Shrink to fit.. - m_currentQuery.resize(arraycounter); + QArray<int> matchRegexp( const QRegExp &r ) const; - return m_currentQuery; - } - - QArray<int> matchRegexp( const QRegExp &r ) const{ - QArray<int> m_currentQuery( m_contactList.count() ); - QValueListConstIterator<OContact> it; - uint arraycounter = 0; - - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).match( r ) ){ - m_currentQuery[arraycounter++] = (*it).uid(); - } - - } - // Shrink to fit.. - m_currentQuery.resize(arraycounter); - - return m_currentQuery; - } - - const uint querySettings() - { - return ( OContactAccess::WildCards - | OContactAccess::IgnoreCase - | OContactAccess::RegExp - | OContactAccess::ExactMatch - | OContactAccess::DateDiff - | OContactAccess::DateYear - | OContactAccess::DateMonth - | OContactAccess::DateDay - ); - } + const uint querySettings(); - bool hasQuerySettings (uint querySettings) const - { - /* OContactAccess::IgnoreCase, DateDiff, DateYear, DateMonth, DateDay - * may be added with any of the other settings. IgnoreCase should never used alone. - * Wildcards, RegExp, ExactMatch should never used at the same time... - */ - - if ( querySettings == OContactAccess::IgnoreCase ) - return false; - - switch ( querySettings & ~( OContactAccess::IgnoreCase - | OContactAccess::DateDiff - | OContactAccess::DateYear - | OContactAccess::DateMonth - | OContactAccess::DateDay - ) - ){ - case OContactAccess::RegExp: - return ( true ); - case OContactAccess::WildCards: - return ( true ); - case OContactAccess::ExactMatch: - return ( true ); - default: - return ( false ); - } - } + bool hasQuerySettings (uint querySettings) const; // Currently only asc implemented.. - QArray<int> 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.. - QValueListConstIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - names.append( (*it).fileAs() + QString::number( (*it).uid() ) ); - nameToUid.insert( (*it).fileAs() + QString::number( (*it).uid() ), (*it).uid() ); - } - names.sort(); - - int i = 0; - if ( asc ){ - for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) - m_currentQuery[i++] = nameToUid[ (*it) ]; - }else{ - for ( QStringList::Iterator it = names.end(); it != names.begin(); --it ) - m_currentQuery[i++] = nameToUid[ (*it) ]; - } - - return m_currentQuery; - - } - bool add ( const OContact &newcontact ) - { - //qWarning("odefaultbackend: ACTION::ADD"); - updateJournal (newcontact, ACTION_ADD); - addContact_p( newcontact ); - - m_changed = true; - - return true; - } - - bool replace ( const OContact &contact ) - { - m_changed = true; - - bool found = false; - - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ( (*it).uid() == contact.uid() ){ - found = true; - break; - } - } - if (found) { - updateJournal (contact, ACTION_REPLACE); - m_contactList.remove (it); - m_contactList.append (contact); - return true; - } else - return false; - } + QArray<int> sorted( bool asc, int , int , int ); + bool add ( const OContact &newcontact ); - bool remove ( int uid ) - { - m_changed = true; - - bool found = false; - QValueListIterator<OContact> it; - for( it = m_contactList.begin(); it != m_contactList.end(); ++it ){ - if ((*it).uid() == uid){ - found = true; - break; - } - } - if (found) { - updateJournal ( *it, ACTION_REMOVE); - m_contactList.remove (it); - return true; - } else - return false; - } + bool replace ( const OContact &contact ); - bool reload(){ - /* Reload is the same as load in this implementation */ - return ( load() ); - } + bool remove ( int uid ); + bool reload(); private: enum journal_action { ACTION_ADD, ACTION_REMOVE, ACTION_REPLACE }; - void addContact_p( const OContact &newcontact ){ - m_contactList.append (newcontact); - } + void addContact_p( const OContact &newcontact ); /* This function loads the xml-database and the journalfile */ - bool load( const QString filename, bool isJournal ) { - - /* We use the time of the last read to check if the file was - * changed externally. - */ - if ( !isJournal ){ - QFileInfo fi( filename ); - m_readtime = fi.lastModified (); - } - - const int JOURNALACTION = Qtopia::Notes + 1; - const int JOURNALROW = JOURNALACTION + 1; - - bool foundAction = false; - journal_action action = ACTION_ADD; - int journalKey = 0; - QMap<int, QString> contactMap; - QMap<QString, QString> customMap; - QMap<QString, QString>::Iterator customIt; - QAsciiDict<int> dict( 47 ); - - dict.setAutoDelete( TRUE ); - dict.insert( "Uid", new int(Qtopia::AddressUid) ); - dict.insert( "Title", new int(Qtopia::Title) ); - dict.insert( "FirstName", new int(Qtopia::FirstName) ); - dict.insert( "MiddleName", new int(Qtopia::MiddleName) ); - dict.insert( "LastName", new int(Qtopia::LastName) ); - dict.insert( "Suffix", new int(Qtopia::Suffix) ); - dict.insert( "FileAs", new int(Qtopia::FileAs) ); - dict.insert( "Categories", new int(Qtopia::AddressCategory) ); - dict.insert( "DefaultEmail", new int(Qtopia::DefaultEmail) ); - dict.insert( "Emails", new int(Qtopia::Emails) ); - dict.insert( "HomeStreet", new int(Qtopia::HomeStreet) ); - dict.insert( "HomeCity", new int(Qtopia::HomeCity) ); - dict.insert( "HomeState", new int(Qtopia::HomeState) ); - dict.insert( "HomeZip", new int(Qtopia::HomeZip) ); - dict.insert( "HomeCountry", new int(Qtopia::HomeCountry) ); - dict.insert( "HomePhone", new int(Qtopia::HomePhone) ); - dict.insert( "HomeFax", new int(Qtopia::HomeFax) ); - dict.insert( "HomeMobile", new int(Qtopia::HomeMobile) ); - dict.insert( "HomeWebPage", new int(Qtopia::HomeWebPage) ); - dict.insert( "Company", new int(Qtopia::Company) ); - dict.insert( "BusinessStreet", new int(Qtopia::BusinessStreet) ); - dict.insert( "BusinessCity", new int(Qtopia::BusinessCity) ); - dict.insert( "BusinessState", new int(Qtopia::BusinessState) ); - dict.insert( "BusinessZip", new int(Qtopia::BusinessZip) ); - dict.insert( "BusinessCountry", new int(Qtopia::BusinessCountry) ); - dict.insert( "BusinessWebPage", new int(Qtopia::BusinessWebPage) ); - dict.insert( "JobTitle", new int(Qtopia::JobTitle) ); - dict.insert( "Department", new int(Qtopia::Department) ); - dict.insert( "Office", new int(Qtopia::Office) ); - dict.insert( "BusinessPhone", new int(Qtopia::BusinessPhone) ); - dict.insert( "BusinessFax", new int(Qtopia::BusinessFax) ); - dict.insert( "BusinessMobile", new int(Qtopia::BusinessMobile) ); - dict.insert( "BusinessPager", new int(Qtopia::BusinessPager) ); - dict.insert( "Profession", new int(Qtopia::Profession) ); - dict.insert( "Assistant", new int(Qtopia::Assistant) ); - dict.insert( "Manager", new int(Qtopia::Manager) ); - dict.insert( "Spouse", new int(Qtopia::Spouse) ); - dict.insert( "Children", new int(Qtopia::Children) ); - dict.insert( "Gender", new int(Qtopia::Gender) ); - dict.insert( "Birthday", new int(Qtopia::Birthday) ); - dict.insert( "Anniversary", new int(Qtopia::Anniversary) ); - dict.insert( "Nickname", new int(Qtopia::Nickname) ); - dict.insert( "Notes", new int(Qtopia::Notes) ); - dict.insert( "action", new int(JOURNALACTION) ); - dict.insert( "actionrow", new int(JOURNALROW) ); - - //qWarning( "OContactDefaultBackEnd::loading %s", filename.latin1() ); - - XMLElement *root = XMLElement::load( filename ); - if(root != 0l ){ // start parsing - /* Parse all XML-Elements and put the data into the - * Contact-Class - */ - XMLElement *element = root->firstChild(); - //qWarning("OContactAccess::load tagName(): %s", root->tagName().latin1() ); - element = element->firstChild(); - - /* Search Tag "Contacts" which is the parent of all Contacts */ - while( element && !isJournal ){ - if( element->tagName() != QString::fromLatin1("Contacts") ){ - //qWarning ("OContactDefBack::Searching for Tag \"Contacts\"! Found: %s", - // element->tagName().latin1()); - element = element->nextChild(); - } else { - element = element->firstChild(); - break; - } - } - /* Parse all Contacts and ignore unknown tags */ - while( element ){ - if( element->tagName() != QString::fromLatin1("Contact") ){ - //qWarning ("OContactDefBack::Searching for Tag \"Contact\"! Found: %s", - // element->tagName().latin1()); - element = element->nextChild(); - continue; - } - /* Found alement with tagname "contact", now parse and store all - * attributes contained - */ - //qWarning("OContactDefBack::load element tagName() : %s", - // element->tagName().latin1() ); - QString dummy; - foundAction = false; - - XMLElement::AttributeMap aMap = element->attributes(); - XMLElement::AttributeMap::Iterator it; - contactMap.clear(); - customMap.clear(); - for( it = aMap.begin(); it != aMap.end(); ++it ){ - // qWarning ("Read Attribute: %s=%s", it.key().latin1(),it.data().latin1()); - - int *find = dict[ it.key() ]; - /* Unknown attributes will be stored as "Custom" elements */ - if ( !find ) { - qWarning("Attribute %s not known.", it.key().latin1()); - //contact.setCustomField(it.key(), it.data()); - customMap.insert( it.key(), it.data() ); - continue; - } - - /* Check if special conversion is needed and add attribute - * into Contact class - */ - switch( *find ) { - /* - case Qtopia::AddressUid: - contact.setUid( it.data().toInt() ); - break; - case Qtopia::AddressCategory: - contact.setCategories( Qtopia::Record::idsFromString( it.data( ))); - break; - */ - case JOURNALACTION: - action = journal_action(it.data().toInt()); - foundAction = true; - qWarning ("ODefBack(journal)::ACTION found: %d", action); - break; - case JOURNALROW: - journalKey = it.data().toInt(); - break; - default: // no conversion needed add them to the map - contactMap.insert( *find, it.data() ); - break; - } - } - /* now generate the Contact contact */ - OContact contact( contactMap ); - - for (customIt = customMap.begin(); customIt != customMap.end(); ++customIt ) { - contact.setCustomField( customIt.key(), customIt.data() ); - } - - if (foundAction){ - foundAction = false; - switch ( action ) { - case ACTION_ADD: - addContact_p (contact); - break; - case ACTION_REMOVE: - if ( !remove (contact.uid()) ) - qWarning ("ODefBack(journal)::Unable to remove uid: %d", - contact.uid() ); - break; - case ACTION_REPLACE: - if ( !replace ( contact ) ) - qWarning ("ODefBack(journal)::Unable to replace uid: %d", - contact.uid() ); - break; - default: - qWarning ("Unknown action: ignored !"); - break; - } - }else{ - /* Add contact to list */ - addContact_p (contact); - } - - /* Move to next element */ - element = element->nextChild(); - } - }else { - qWarning("ODefBack::could not load"); - } - delete root; - qWarning("returning from loading" ); - return true; - } - + bool load( const QString filename, bool isJournal ); - void updateJournal( const OContact& cnt, - journal_action action ) { - QFile f( m_journalName ); - bool created = !f.exists(); - if ( !f.open(IO_WriteOnly|IO_Append) ) - return; - - QString buf; - QCString str; - - // if the file was created, we have to set the Tag "<CONTACTS>" to - // get a XML-File which is readable by our parser. - // This is just a cheat, but better than rewrite the parser. - if ( created ){ - buf = "<Contacts>"; - QCString cstr = buf.utf8(); - f.writeBlock( cstr.data(), cstr.length() ); - } - - buf = "<Contact "; - cnt.save( buf ); - buf += " action=\"" + QString::number( (int)action ) + "\" "; - buf += "/>\n"; - QCString cstr = buf.utf8(); - f.writeBlock( cstr.data(), cstr.length() ); - } - void removeJournal() - { - QFile f ( m_journalName ); - if ( f.exists() ) - f.remove(); - } + void updateJournal( const OContact& cnt, journal_action action ); + void removeJournal(); protected: bool m_changed; QString m_journalName; QString m_fileName; QString m_appName; - QValueList<OContact> m_contactList; + QList<OContact> m_contactList; QDateTime m_readtime; + + QDict<OContact> m_uidToContact; }; #endif diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp index 4a6b7b8..11e19d9 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp @@ -231,33 +231,33 @@ bool ODateBookAccessBackend_XML::save() { QArray<int> ODateBookAccessBackend_XML::allRecords()const { QArray<int> ints( m_raw.count()+ m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_raw.begin(); it != m_raw.end(); ++it ) { ints[i] = it.key(); i++; } for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; } -QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int ) { +QArray<int> ODateBookAccessBackend_XML::queryByExample(const OEvent&, int, const QDateTime& ) { return QArray<int>(); } void ODateBookAccessBackend_XML::clear() { m_raw.clear(); m_rep.clear(); } OEvent ODateBookAccessBackend_XML::find( int uid ) const{ if ( m_raw.contains( uid ) ) return m_raw[uid]; else return m_rep[uid]; } bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { m_changed = true; if (ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h b/libopie2/opiepim/backend/odatebookaccessbackend_xml.h index 40f69d8..563c31f 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.h +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.h @@ -3,33 +3,33 @@ #include <qmap.h> #include "odatebookaccessbackend.h" 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> queryByExample( const OEvent&, int ); + QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); OEvent find( int uid )const; void clear(); bool add( const OEvent& ev ); bool remove( int uid ); bool replace( const OEvent& ev ); QArray<UID> rawEvents()const; QArray<UID> rawRepeats()const; QArray<UID> nonRepeats()const; OEvent::ValueList directNonRepeats(); OEvent::ValueList directRawRepeats(); private: bool m_changed :1 ; bool loadFile(); diff --git a/libopie2/opiepim/backend/opimaccessbackend.h b/libopie2/opiepim/backend/opimaccessbackend.h index e268f4f..01a0c86 100644 --- a/libopie2/opiepim/backend/opimaccessbackend.h +++ b/libopie2/opiepim/backend/opimaccessbackend.h @@ -34,36 +34,36 @@ public: */ virtual bool reload() = 0; /** * save the resource and * all it's changes */ virtual bool save() = 0; /** * return an array of * all available uids */ virtual QArray<int> allRecords()const = 0; /** - * queryByExample for T with the SortOrder - * sort + * queryByExample for T with the given Settings + * */ - virtual QArray<int> queryByExample( const T& t, int sort ) = 0; + virtual QArray<int> queryByExample( const T& t, int settings, const QDateTime& d = QDateTime() ) = 0; /** * find the OPimRecord with uid @param uid * returns T and T.isEmpty() if nothing was found */ virtual T find(int uid )const = 0; virtual T find(int uid, const QArray<int>& items, uint current, typename Frontend::CacheDirection )const ; /** * clear the back end */ virtual void clear() = 0; /** * add T diff --git a/libopie2/opiepim/backend/otodoaccesssql.cpp b/libopie2/opiepim/backend/otodoaccesssql.cpp index 761d7d8..ec9c14c 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.cpp +++ b/libopie2/opiepim/backend/otodoaccesssql.cpp @@ -264,33 +264,33 @@ bool OTodoAccessBackendSQL::load(){ m_dirty = true; return true; } bool OTodoAccessBackendSQL::reload(){ return load(); } bool OTodoAccessBackendSQL::save(){ return m_driver->close(); } QArray<int> OTodoAccessBackendSQL::allRecords()const { if (m_dirty ) update(); return m_uids; } -QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int ){ +QArray<int> OTodoAccessBackendSQL::queryByExample( const OTodo& , int, const QDateTime& ){ QArray<int> ints(0); return ints; } OTodo OTodoAccessBackendSQL::find(int uid ) const{ FindQuery query( uid ); return todo( m_driver->query(&query) ); } OTodo OTodoAccessBackendSQL::find( int uid, const QArray<int>& ints, uint cur, Frontend::CacheDirection dir ) const{ int CACHE = readAhead(); qWarning("searching for %d", uid ); QArray<int> search( CACHE ); uint size =0; OTodo to; diff --git a/libopie2/opiepim/backend/otodoaccesssql.h b/libopie2/opiepim/backend/otodoaccesssql.h index 0f6dd2c..6a4257c 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.h +++ b/libopie2/opiepim/backend/otodoaccesssql.h @@ -5,33 +5,33 @@ #include "otodoaccessbackend.h" class OSQLDriver; class OSQLResult; class OSQLResultItem; class OTodoAccessBackendSQL : public OTodoAccessBackend { public: OTodoAccessBackendSQL( const QString& file ); ~OTodoAccessBackendSQL(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; - QArray<int> queryByExample( const OTodo& t, int sort ); + QArray<int> queryByExample( const OTodo& t, int settings, const QDateTime& d = QDateTime() ); OTodo find(int uid)const; OTodo find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; void clear(); bool add( const OTodo& t ); bool remove( int uid ); bool replace( const OTodo& t ); QArray<int> overDue(); QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> sorted(bool asc, int sortOrder, int sortFilter, int cat ); private: void update()const; void fillDict(); inline bool date( QDate& date, const QString& )const; diff --git a/libopie2/opiepim/backend/otodoaccessvcal.cpp b/libopie2/opiepim/backend/otodoaccessvcal.cpp index 309f9e1..2136283 100644 --- a/libopie2/opiepim/backend/otodoaccessvcal.cpp +++ b/libopie2/opiepim/backend/otodoaccessvcal.cpp @@ -172,30 +172,30 @@ OTodo OTodoAccessVCal::find(int uid )const { return m_map[uid]; } QArray<int> OTodoAccessVCal::sorted( bool, int, int, int ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::allRecords()const { QArray<int> ar( m_map.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_map.begin(); it != m_map.end(); ++it ) { ar[i] = it.key(); i++; } return ar; } -QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int ) { +QArray<int> OTodoAccessVCal::queryByExample( const OTodo&, int, const QDateTime& ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::effectiveToDos( const QDate& , const QDate& , bool ) { QArray<int> ar(0); return ar; } QArray<int> OTodoAccessVCal::overDue() { QArray<int> ar(0); return ar; } diff --git a/libopie2/opiepim/backend/otodoaccessvcal.h b/libopie2/opiepim/backend/otodoaccessvcal.h index 452f602..a90ee9c 100644 --- a/libopie2/opiepim/backend/otodoaccessvcal.h +++ b/libopie2/opiepim/backend/otodoaccessvcal.h @@ -1,32 +1,32 @@ #ifndef OPIE_OTODO_ACCESS_VCAL_H #define OPIE_OTODO_ACCESS_VCAL_H #include "otodoaccessbackend.h" class OTodoAccessVCal : public OTodoAccessBackend { public: OTodoAccessVCal(const QString& ); ~OTodoAccessVCal(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; - QArray<int> queryByExample( const OTodo& t, int sort ); + QArray<int> queryByExample( const OTodo& t, int sort, const QDateTime& d = QDateTime() ); QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> overDue(); QArray<int> sorted( bool asc, int sortOrder, int sortFilter, int cat ); OTodo find(int uid)const; void clear(); bool add( const OTodo& ); bool remove( int uid ); bool replace( const OTodo& ); void removeAllCompleted(); private: bool m_dirty : 1; diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp index cda300b..71e8787 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.cpp +++ b/libopie2/opiepim/backend/otodoaccessxml.cpp @@ -242,33 +242,33 @@ bool OTodoAccessXML::save() { } m_changed = false; return true; } QArray<int> OTodoAccessXML::allRecords()const { QArray<int> ids( m_events.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { ids[i] = it.key(); i++; } return ids; } -QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int ) { +QArray<int> OTodoAccessXML::queryByExample( const OTodo&, int, const QDateTime& ) { QArray<int> ids(0); return ids; } OTodo OTodoAccessXML::find( int uid )const { OTodo todo; todo.setUid( 0 ); // isEmpty() QMap<int, OTodo>::ConstIterator it = m_events.find( uid ); if ( it != m_events.end() ) todo = it.data(); return todo; } void OTodoAccessXML::clear() { if (m_opened ) m_changed = true; diff --git a/libopie2/opiepim/backend/otodoaccessxml.h b/libopie2/opiepim/backend/otodoaccessxml.h index 93609fe..1032c92 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.h +++ b/libopie2/opiepim/backend/otodoaccessxml.h @@ -11,33 +11,33 @@ namespace Opie { }; class OTodoAccessXML : public OTodoAccessBackend { public: /** * fileName if Empty we will use the default path */ OTodoAccessXML( const QString& appName, const QString& fileName = QString::null ); ~OTodoAccessXML(); bool load(); bool reload(); bool save(); QArray<int> allRecords()const; - QArray<int> queryByExample( const OTodo&, int querysettings ); + QArray<int> queryByExample( const OTodo&, int querysettings, const QDateTime& d = QDateTime() ); OTodo find( int uid )const; void clear(); bool add( const OTodo& ); bool remove( int uid ); void removeAllCompleted(); bool replace( const OTodo& ); /* our functions */ QArray<int> effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ); QArray<int> overDue(); QArray<int> sorted( bool asc, int sortOrder, int sortFilter, int cat ); private: void todo( QAsciiDict<int>*, OTodo&,const QCString&,const QString& ); diff --git a/libopie2/opiepim/core/opimaccesstemplate.h b/libopie2/opiepim/core/opimaccesstemplate.h index 259e2c1..6a3a0db 100644 --- a/libopie2/opiepim/core/opimaccesstemplate.h +++ b/libopie2/opiepim/core/opimaccesstemplate.h @@ -61,33 +61,33 @@ public: * if the resource was changed externally * You should use the signal handling instead of polling possible changes ! * zecke: Do you implement a signal for otodoaccess ? */ bool wasChangedExternally()const; /** * return a List of records * you can iterate over them */ virtual List allRecords()const; /** * queryByExample. * @see otodoaccess, ocontactaccess */ - virtual List queryByExample( const T& t, int querySettings ); + virtual List queryByExample( const T& t, int querySettings, const QDateTime& d = QDateTime() ); /** * find the OPimRecord uid */ virtual T find( int uid )const; /** * read ahead cache find method ;) */ virtual T find( int uid, const QArray<int>&, uint current, typename OTemplateBase<T>::CacheDirection dir = OTemplateBase<T>::Forward )const; /* invalidate cache here */ /** * clears the backend and invalidates the backend */ @@ -173,34 +173,34 @@ bool OPimAccessTemplate<T>::reload() { template <class T> bool OPimAccessTemplate<T>::save() { return m_backEnd->save(); } template <class T> typename OPimAccessTemplate<T>::List OPimAccessTemplate<T>::allRecords()const { QArray<int> ints = m_backEnd->allRecords(); List lis(ints, this ); return lis; } template <class T> QArray<int> OPimAccessTemplate<T>::records()const { return m_backEnd->allRecords(); } template <class T> typename OPimAccessTemplate<T>::List -OPimAccessTemplate<T>::queryByExample( const T& t, int sortOrder ) { - QArray<int> ints = m_backEnd->queryByExample( t, sortOrder ); +OPimAccessTemplate<T>::queryByExample( const T& t, int settings, const QDateTime& d ) { + QArray<int> ints = m_backEnd->queryByExample( t, settings, d ); List lis(ints, this ); return lis; } template <class T> T OPimAccessTemplate<T>::find( int uid ) const{ T t = m_backEnd->find( uid ); cache( t ); return t; } template <class T> T OPimAccessTemplate<T>::find( int uid, const QArray<int>& ar, uint current, typename OTemplateBase<T>::CacheDirection dir )const { /* * better do T.isEmpty() * after a find this way we would |