author | zecke <zecke> | 2002-12-10 17:01:18 (UTC) |
---|---|---|
committer | zecke <zecke> | 2002-12-10 17:01:18 (UTC) |
commit | 4ecbf7407c19b59fc136c334f9386c53db453930 (patch) (side-by-side diff) | |
tree | 1cba438e2533f7109af169b0b77988cec6664192 | |
parent | 36375df6ff103e52455823f7afd64c4f4ae7fcb8 (diff) | |
download | opie-4ecbf7407c19b59fc136c334f9386c53db453930.zip opie-4ecbf7407c19b59fc136c334f9386c53db453930.tar.gz opie-4ecbf7407c19b59fc136c334f9386c53db453930.tar.bz2 |
get in sync with HEAD again
-OPimBase was added to be used as a default struct inside OPimResolver
and to work with DSOs
-TodoListXML backend now uses mmap and madvise to load data
-OContact added/changed rtti
-OTodo added changed rtti
OPimAccess* added stuff necessary for the Resolver and a 'state'/'hint'
on how to load data
OPimResolver which resolves uid + services to Records, rtti to QCOPChannels
loads arbitary Service backends ( will work with DSOs soon )
-OPimMainWindow added some setDocument scripting possibility and
internal marshalling and demarshalling of Records
-OPimRecord added loadDataFromm and saveDataTo for marshalling purposes
much more :)
30 files changed, 1072 insertions, 164 deletions
diff --git a/libopie/pim/ocontact.cpp b/libopie/pim/ocontact.cpp index 6aec62e..38cba72 100644 --- a/libopie/pim/ocontact.cpp +++ b/libopie/pim/ocontact.cpp @@ -1,88 +1,89 @@ /********************************************************************** ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** Copyright (C) 2002 by Stefan Eilers (eilers.stefan@epost.de) ** ** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #define QTOPIA_INTERNAL_CONTACT_MRE #include "ocontact.h" +#include "opimresolver.h" #include <qpe/stringutil.h> #include <qpe/timeconversion.h> #include <qpe/timestring.h> #include <qobject.h> #include <qregexp.h> #include <qstylesheet.h> #include <qfileinfo.h> #include <qmap.h> #include <stdio.h> /*! \class Contact contact.h \brief The Contact class holds the data of an address book entry. This data includes information the name of the person, contact information, and business information such as deparment and job title. \ingroup qtopiaemb \ingroup qtopiadesktop */ /*! Creates a new, empty contact. */ OContact::OContact() : OPimRecord(), mMap(), d( 0 ) { } /*! \internal Creates a new contact. The properties of the contact are set from \a fromMap. */ OContact::OContact( const QMap<int, QString> &fromMap ) : OPimRecord(), mMap( fromMap ), d( 0 ) { QString cats = mMap[ Qtopia::AddressCategory ]; if ( !cats.isEmpty() ) setCategories( idsFromString( cats ) ); QString uidStr = find( Qtopia::AddressUid ); if ( uidStr.isEmpty() || (uidStr.toInt() == 0) ){ qWarning( "Invalid UID found. Generate new one.." ); setUid( uidGen().generate() ); }else setUid( uidStr.toInt() ); // if ( !uidStr.isEmpty() ) // setUid( uidStr.toInt() ); } /*! Destroys a contact. */ OContact::~OContact() { } @@ -768,129 +769,129 @@ QStringList OContact::emailList() const return r; } /*! \overload Generates the string for the contact to be filed as from the first, middle and last name of the contact. */ void OContact::setFileAs() { QString lastName, firstName, middleName, fileas; lastName = find( Qtopia::LastName ); firstName = find( Qtopia::FirstName ); middleName = find( Qtopia::MiddleName ); if ( !lastName.isEmpty() && !firstName.isEmpty() && !middleName.isEmpty() ) fileas = lastName + ", " + firstName + " " + middleName; else if ( !lastName.isEmpty() && !firstName.isEmpty() ) fileas = lastName + ", " + firstName; else if ( !lastName.isEmpty() || !firstName.isEmpty() || !middleName.isEmpty() ) fileas = firstName + ( firstName.isEmpty() ? "" : " " ) + middleName + ( middleName.isEmpty() ? "" : " " ) + lastName; replace( Qtopia::FileAs, fileas ); } /*! \internal Appends the contact information to \a buf. */ void OContact::save( QString &buf ) const { static const QStringList SLFIELDS = fields(); // I'm expecting "<Contact " in front of this... for ( QMap<int, QString>::ConstIterator it = mMap.begin(); it != mMap.end(); ++it ) { const QString &value = it.data(); int key = it.key(); if ( !value.isEmpty() ) { if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid) continue; key -= Qtopia::AddressCategory+1; buf += SLFIELDS[key]; buf += "=\"" + Qtopia::escapeString(value) + "\" "; } } buf += customToXml(); if ( categories().count() > 0 ) buf += "Categories=\"" + idsToString( categories() ) + "\" "; buf += "Uid=\"" + QString::number( uid() ) + "\" "; // You need to close this yourself } /*! \internal Returns the list of fields belonging to a contact Never change order of this list ! It has to be regarding - enum AddressBookFields !! + enum AddressBookFields !! */ QStringList OContact::fields() { QStringList list; list.append( "Title" ); // Not Used! list.append( "FirstName" ); list.append( "MiddleName" ); list.append( "LastName" ); list.append( "Suffix" ); list.append( "FileAs" ); list.append( "JobTitle" ); list.append( "Department" ); list.append( "Company" ); list.append( "BusinessPhone" ); list.append( "BusinessFax" ); list.append( "BusinessMobile" ); list.append( "DefaultEmail" ); list.append( "Emails" ); list.append( "HomePhone" ); list.append( "HomeFax" ); list.append( "HomeMobile" ); list.append( "BusinessStreet" ); list.append( "BusinessCity" ); list.append( "BusinessState" ); list.append( "BusinessZip" ); list.append( "BusinessCountry" ); list.append( "BusinessPager" ); list.append( "BusinessWebPage" ); list.append( "Office" ); list.append( "Profession" ); list.append( "Assistant" ); list.append( "Manager" ); list.append( "HomeStreet" ); list.append( "HomeCity" ); list.append( "HomeState" ); list.append( "HomeZip" ); list.append( "HomeCountry" ); list.append( "HomeWebPage" ); list.append( "Spouse" ); list.append( "Gender" ); list.append( "Birthday" ); list.append( "Anniversary" ); list.append( "Nickname" ); list.append( "Children" ); list.append( "Notes" ); list.append( "Groups" ); return list; } /*! Sets the list of email address for contact to those contained in \a str. Email address should be separated by ';'s. */ @@ -1039,71 +1040,71 @@ void OContact::insertEmail( const QString &v ) setDefaultEmail( e ); // will insert into the list for us return; } // otherwise, insert assuming doesn't already exist QString emailsStr = find( Qtopia::Emails ); if ( emailsStr.contains( e )) return; if ( !emailsStr.isEmpty() ) emailsStr += emailSeparator(); emailsStr += e; replace( Qtopia::Emails, emailsStr ); } void OContact::removeEmail( const QString &v ) { QString e = v.simplifyWhiteSpace(); QString def = defaultEmail(); QString emailsStr = find( Qtopia::Emails ); QStringList emails = emailList(); // otherwise, must first contain it if ( !emailsStr.contains( e ) ) return; // remove it //qDebug(" removing email from list %s", e.latin1()); emails.remove( e ); // reset the string emailsStr = emails.join(emailSeparator()); // Sharp's brain dead separator replace( Qtopia::Emails, emailsStr ); // if default, then replace the default email with the first one if ( def == e ) { //qDebug("removeEmail is default; setting new default"); if ( !emails.count() ) clearEmails(); else // setDefaultEmail will remove e from the list setDefaultEmail( emails.first() ); } } void OContact::clearEmails() { mMap.remove( Qtopia::DefaultEmail ); mMap.remove( Qtopia::Emails ); } void OContact::setDefaultEmail( const QString &v ) { QString e = v.simplifyWhiteSpace(); //qDebug("OContact::setDefaultEmail %s", e.latin1()); replace( Qtopia::DefaultEmail, e ); if ( !e.isEmpty() ) insertEmail( e ); } void OContact::insertEmails( const QStringList &v ) { for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it ) insertEmail( *it ); } int OContact::rtti() { - return 2; + return OPimResolver::AddressBook; } void OContact::setUid( int i ) -{ - OPimRecord::setUid(i); - replace( Qtopia::AddressUid , QString::number(i)); +{ + OPimRecord::setUid(i); + replace( Qtopia::AddressUid , QString::number(i)); } diff --git a/libopie/pim/opimaccessbackend.h b/libopie/pim/opimaccessbackend.h index 4f00bc9..e268f4f 100644 --- a/libopie/pim/opimaccessbackend.h +++ b/libopie/pim/opimaccessbackend.h @@ -1,141 +1,153 @@ #ifndef OPIE_PIM_ACCESS_BACKEND #define OPIE_PIM_ACCESS_BACKEND #include <qarray.h> #include <opie/otemplatebase.h> #include <opie/opimrecord.h> /** * OPimAccessBackend is the base class * for all private backends * it operates on OPimRecord as the base class * and it's responsible for fast manipulating * the resource the implementation takes care * of */ template <class T = OPimRecord> class OPimAccessBackend { public: typedef OTemplateBase<T> Frontend; - OPimAccessBackend(); + + /** The access hint from the frontend */ + OPimAccessBackend(int access = 0); virtual ~OPimAccessBackend(); /** * load the resource */ virtual bool load() = 0; /** * reload the resource */ virtual bool reload() = 0; /** * save the resource and * all it's changes */ virtual bool save() = 0; /** * return an array of * all available uids */ virtual QArray<int> allRecords()const = 0; /** * queryByExample for T with the SortOrder * sort */ virtual QArray<int> queryByExample( const T& t, int sort ) = 0; /** * find the OPimRecord with uid @param uid * returns T and T.isEmpty() if nothing was found */ virtual T find(int uid )const = 0; virtual T find(int uid, const QArray<int>& items, uint current, typename Frontend::CacheDirection )const ; /** * clear the back end */ virtual void clear() = 0; /** * add T */ virtual bool add( const T& t ) = 0; /** * remove */ virtual bool remove( int uid ) = 0; /** * replace a record with T.uid() */ virtual bool replace( const T& t ) = 0; /* * setTheFrontEnd!!! */ void setFrontend( Frontend* front ); /** * set the read ahead count */ void setReadAhead( uint count ); protected: + int access()const; void cache( const T& t )const; /** * use a prime number here! */ void setSaneCacheSize( int ); uint readAhead()const; private: + class Private; + Private* d; Frontend* m_front; uint m_read; + int m_acc; }; template <class T> -OPimAccessBackend<T>::OPimAccessBackend() { +OPimAccessBackend<T>::OPimAccessBackend(int acc) + : m_acc( acc ) +{ m_front = 0l; } template <class T> OPimAccessBackend<T>::~OPimAccessBackend() { } template <class T> void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { m_front = fr; } template <class T> void OPimAccessBackend<T>::cache( const T& t )const { if (m_front ) m_front->cache( t ); } template <class T> void OPimAccessBackend<T>::setSaneCacheSize( int size) { if (m_front ) m_front->setSaneCacheSize( size ); } template <class T> T OPimAccessBackend<T>::find( int uid, const QArray<int>&, uint, typename Frontend::CacheDirection )const { return find( uid ); } template <class T> void OPimAccessBackend<T>::setReadAhead( uint count ) { m_read = count; } template <class T> uint OPimAccessBackend<T>::readAhead()const { return m_read; } +template <class T> +int OPimAccessBackend<T>::access()const { + return m_acc; +} #endif diff --git a/libopie/pim/opimaccesstemplate.h b/libopie/pim/opimaccesstemplate.h index 8cf81c8..259e2c1 100644 --- a/libopie/pim/opimaccesstemplate.h +++ b/libopie/pim/opimaccesstemplate.h @@ -1,269 +1,286 @@ #ifndef OPIE_PIM_ACCESS_TEMPLATE_H #define OPIE_PIM_ACCESS_TEMPLATE_H #include <qarray.h> #include <opie/opimrecord.h> #include <opie/opimaccessbackend.h> #include <opie/orecordlist.h> #include "opimcache.h" #include "otemplatebase.h" /** * Thats the frontend to our OPIE PIM * Library. Either you want to use it's * interface or you want to implement * your own Access lib * Just create a OPimRecord and inherit from * the plugins */ template <class T = OPimRecord > class OPimAccessTemplate : public OTemplateBase<T> { public: + enum Access { + Random = 0, + SortedAccess + }; typedef ORecordList<T> List; typedef OPimAccessBackend<T> BackEnd; typedef OPimCache<T> Cache; /** * c'tor BackEnd + * enum Access a small hint on how to handle the backend */ OPimAccessTemplate( BackEnd* end); + virtual ~OPimAccessTemplate(); /** * load from the backend */ - virtual bool load(); + bool load(); /** Reload database. * You should execute this function if the external database * was changed. * This function will load the external database and afterwards * rejoin the local changes. Therefore the local database will be set consistent. */ virtual bool reload(); /** Save contacts database. * Save is more a "commit". After calling this function, all changes are public available. * @return true if successful */ - virtual bool save(); + bool save(); /** * 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 ); /** * 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 */ - virtual void clear() ; + void clear() ; /** * add T to the backend * @param t The item to add. * @return <i>true</i> if added successfully. */ virtual bool add( const T& t ) ; bool add( const OPimRecord& ); /* only the uid matters */ /** * remove T from the backend * @param t The item to remove * @return <i>true</i> if successful. */ virtual bool remove( const T& t ); /** * remove the OPimRecord with uid * @param uid The ID of the item to remove * @return <i>true</i> if successful. */ - virtual bool remove( int uid ); + bool remove( int uid ); + bool remove( const OPimRecord& ); /** * replace T from backend * @param t The item to replace * @return <i>true</i> if successful. */ virtual bool replace( const T& t) ; void setReadAhead( uint count ); /** * @internal */ void cache( const T& )const; void setSaneCacheSize( int ); + + QArray<int> records()const; protected: /** * invalidate the cache */ void invalidateCache(); void setBackEnd( BackEnd* end ); /** * returns the backend */ BackEnd* backEnd(); BackEnd* m_backEnd; Cache m_cache; }; template <class T> OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) : OTemplateBase<T>(), m_backEnd( end ) { if (end ) end->setFrontend( this ); } template <class T> OPimAccessTemplate<T>::~OPimAccessTemplate() { qWarning("~OPimAccessTemplate<T>"); delete m_backEnd; } template <class T> bool OPimAccessTemplate<T>::load() { invalidateCache(); return m_backEnd->load(); } template <class T> bool OPimAccessTemplate<T>::reload() { invalidateCache(); // zecke: I think this should be added (se) return m_backEnd->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 ); 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 * avoid two finds in QCache... */ // qWarning("find it now %d", uid ); if (m_cache.contains( uid ) ) { return m_cache.find( uid ); } T t = m_backEnd->find( uid, ar, current, dir ); cache( t ); return t; } template <class T> void OPimAccessTemplate<T>::clear() { invalidateCache(); m_backEnd->clear(); } template <class T> bool OPimAccessTemplate<T>::add( const T& t ) { cache( t ); return m_backEnd->add( t ); } template <class T> bool OPimAccessTemplate<T>::add( const OPimRecord& rec) { /* same type */ if ( rec.rtti() == T::rtti() ) { const T &t = static_cast<const T&>(rec); return add(t); } return false; } template <class T> bool OPimAccessTemplate<T>::remove( const T& t ) { return remove( t.uid() ); } template <class T> bool OPimAccessTemplate<T>::remove( int uid ) { m_cache.remove( uid ); return m_backEnd->remove( uid ); } template <class T> +bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) { + return remove( rec.uid() ); +} +template <class T> bool OPimAccessTemplate<T>::replace( const T& t ) { m_cache.replace( t ); return m_backEnd->replace( t ); } template <class T> void OPimAccessTemplate<T>::invalidateCache() { m_cache.invalidate(); } template <class T> typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { return m_backEnd; } template <class T> bool OPimAccessTemplate<T>::wasChangedExternally()const { return false; } template <class T> void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { m_backEnd = end; if (m_backEnd ) m_backEnd->setFrontend( this ); } template <class T> void OPimAccessTemplate<T>::cache( const T& t ) const{ /* hacky we need to work around the const*/ ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); } template <class T> void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { m_cache.setSize( size ); } template <class T> void OPimAccessTemplate<T>::setReadAhead( uint count ) { m_backEnd->setReadAhead( count ); } #endif diff --git a/libopie/pim/opimcache.h b/libopie/pim/opimcache.h index 839550c..73414e5 100644 --- a/libopie/pim/opimcache.h +++ b/libopie/pim/opimcache.h @@ -1,95 +1,101 @@ #ifndef OPIE_PIM_CACHE_H #define OPIE_PIM_CACHE_H #include <qintcache.h> #include "opimrecord.h" template <class T = OPimRecord> class OPimCacheItem { public: OPimCacheItem( const T& t = T() ); + OPimCacheItem( const OPimCacheItem& ); ~OPimCacheItem(); + OPimCacheItem &operator=( const OPimCacheItem& ); + T record()const; void setRecord( const T& ); private: T m_t; }; /** * OPimCache for caching the items * We support adding, removing * and finding */ template <class T = OPimRecord> class OPimCache { public: typedef OPimCacheItem<T> Item; OPimCache(); + OPimCache( const OPimCache& ); ~OPimCache(); + OPimCache &operator=( const OPimCache& ); + bool contains(int uid)const; void invalidate(); void setSize( int size ); T find(int uid )const; void add( const T& ); void remove( int uid ); void replace( const T& ); private: QIntCache<Item> m_cache; }; // Implementation template <class T> OPimCacheItem<T>::OPimCacheItem( const T& t ) : m_t(t) { } template <class T> OPimCacheItem<T>::~OPimCacheItem() { } template <class T> T OPimCacheItem<T>::record()const { return m_t; } template <class T> void OPimCacheItem<T>::setRecord( const T& t ) { m_t = t; } // Cache template <class T> OPimCache<T>::OPimCache() : m_cache(100, 53 ) { m_cache.setAutoDelete( TRUE ); } template <class T> OPimCache<T>::~OPimCache() { } template <class T> bool OPimCache<T>::contains(int uid )const { Item* it = m_cache.find( uid, FALSE ); if (!it) return false; return true; } template <class T> void OPimCache<T>::invalidate() { m_cache.clear(); } template <class T> void OPimCache<T>::setSize( int size ) { m_cache.setMaxCost( size ); } template <class T> T OPimCache<T>::find(int uid )const { Item *it = m_cache.find( uid ); if (it) return it->record(); return T(); } template <class T> diff --git a/libopie/pim/opimmainwindow.cpp b/libopie/pim/opimmainwindow.cpp index 92be2fd..7e57f3a 100644 --- a/libopie/pim/opimmainwindow.cpp +++ b/libopie/pim/opimmainwindow.cpp @@ -1,71 +1,105 @@ #include <qapplication.h> #include <qcopchannel_qws.h> #include <qpe/qcopenvelope_qws.h> +#include "opimresolver.h" #include "opimmainwindow.h" OPimMainWindow::OPimMainWindow( const QString& service, QWidget* parent, const char* name, WFlags flag ) - : QMainWindow( parent, name, flag ), m_service( service ), m_fallBack(0l) { + : QMainWindow( parent, name, flag ), m_rtti(-1), m_service( service ), m_fallBack(0l) { /* * let's generate our QCopChannel */ m_str = QString("QPE/"+m_service).local8Bit(); m_channel= new QCopChannel(m_str, this ); connect(m_channel, SIGNAL(received(const QCString&, const QByteArray& ) ), this, SLOT( appMessage( const QCString&, const QByteArray& ) ) ); /* connect flush and reload */ connect(qApp, SIGNAL(flush() ), this, SLOT(flush() ) ); connect(qApp, SIGNAL(reload() ), this, SLOT(reload() ) ); } OPimMainWindow::~OPimMainWindow() { delete m_channel; } QCopChannel* OPimMainWindow::channel() { return m_channel; } +void OPimMainWindow::doSetDocument( const QString& ) { + +} void OPimMainWindow::appMessage( const QCString& cmd, const QByteArray& array ) { /* * create demands to create * a new record... */ QDataStream stream(array, IO_ReadOnly); if ( cmd == "create()" ) { int uid = create(); QCopEnvelope e(m_str, "created(int)" ); e << uid; }else if ( cmd == "remove(int)" ) { int uid; stream >> uid; bool rem = remove( uid ); QCopEnvelope e(m_str, "removed(bool)" ); e << rem; }else if ( cmd == "beam(int,int)" ) { int uid, trans; stream >> uid; stream >> trans; beam( uid, trans ); }else if ( cmd == "show(int)" ) { int uid; stream >> uid; show( uid ); }else if ( cmd == "edit(int)" ) { int uid; stream >> uid; edit( uid ); }else if ( cmd == "add(int,QByteArray)" ) { int rtti; QByteArray array; stream >> rtti; stream >> array; m_fallBack = record(rtti, array ); if (!m_fallBack) return; add( *m_fallBack ); delete m_fallBack; } } +/* implement the url scripting here */ +void OPimMainWindow::setDocument( const QString& str) { + doSetDocument( str ); +} +/* + * we now try to get the array demarshalled + * check if the rtti matches this one + */ +OPimRecord* OPimMainWindow::record( int rtti, const QByteArray& array ) { + if ( service() != rtti ) + return 0l; + + OPimRecord* record = OPimResolver::self()->record( rtti ); + QDataStream str(array, IO_ReadOnly ); + if ( !record || !record->loadFromStream(str) ) { + delete record; + record = 0l; + } + + return record; +} +/* + * get the rtti for the service + */ +int OPimMainWindow::service() { + if ( m_rtti == -1 ) + m_rtti = OPimResolver::self()->serviceId( m_service ); + + return m_rtti; +} diff --git a/libopie/pim/opimmainwindow.h b/libopie/pim/opimmainwindow.h index 94100bd..34b8a71 100644 --- a/libopie/pim/opimmainwindow.h +++ b/libopie/pim/opimmainwindow.h @@ -1,79 +1,89 @@ #ifndef OPIE_PIM_MAINWINDOW_H #define OPIE_PIM_MAINWINDOW_H #include <qmainwindow.h> #include <opie/opimrecord.h> /** * This is a common Opie PIM MainWindow * it takes care of the QCOP internals * and implements some functions * for the URL scripting schema */ /* * due Qt and Templates with signal and slots * do not work that good :( * (Ok how to moc a template ;) ) * We will have the mainwindow which calls a struct which * is normally reimplemented as a template ;) */ class QCopChannel; class OPimMainWindow : public QMainWindow { Q_OBJECT public: enum TransPort { BlueTooth=0, IrDa }; OPimMainWindow( const QString& service, QWidget *parent = 0, const char* name = 0, WFlags f = WType_TopLevel); virtual ~OPimMainWindow(); protected slots: + /* + * called when a setDocument + * couldn't be handled by this window + */ + virtual void doSetDocument( const QString& ); /* for syncing */ virtual void flush() = 0; virtual void reload() = 0; /** create a new Records and return the uid */ virtual int create() = 0; /** remove a record with UID == uid */ virtual bool remove( int uid ) = 0; /** beam the record with UID = uid */ virtual void beam( int uid , int transport = IrDa) = 0; /** show the record with UID == uid */ virtual void show( int uid ) = 0; /** edit the record */ virtual void edit( int uid ) = 0; /** make a copy of it! */ virtual void add( const OPimRecord& ) = 0; - /* I would love to do this as a template - * but can't think of a right way - * because I need signal and slots -zecke - */ - /* - * the only pointer in the whole PIM API :( - */ - virtual OPimRecord* record( int rtti, const QByteArray& ) = 0; + QCopChannel* channel(); private slots: void appMessage( const QCString&, const QByteArray& ); + void setDocument( const QString& ); private: class Private; Private* d; + int m_rtti; QCopChannel* m_channel; QString m_service; QCString m_str; OPimRecord* m_fallBack; + + /* I would love to do this as a template + * but can't think of a right way + * because I need signal and slots -zecke + */ + /* + * the only pointer in the whole PIM API :( + */ + virtual OPimRecord* record( int rtti, const QByteArray& ) ; + int service(); }; #endif diff --git a/libopie/pim/opimrecord.cpp b/libopie/pim/opimrecord.cpp index 49b5bf9..ac0f4a9 100644 --- a/libopie/pim/opimrecord.cpp +++ b/libopie/pim/opimrecord.cpp @@ -1,84 +1,166 @@ +#include <qarray.h> + #include <qpe/categories.h> #include <qpe/categoryselect.h> #include "opimrecord.h" Qtopia::UidGen OPimRecord::m_uidGen( Qtopia::UidGen::Qtopia ); OPimRecord::OPimRecord( int uid ) : Qtopia::Record() { setUid( uid ); } OPimRecord::~OPimRecord() { } OPimRecord::OPimRecord( const OPimRecord& rec ) : Qtopia::Record( rec ) { (*this) = rec; } OPimRecord &OPimRecord::operator=( const OPimRecord& rec) { Qtopia::Record::operator=( rec ); m_xrefman = rec.m_xrefman; return *this; } /* * category names */ QStringList OPimRecord::categoryNames()const { QStringList list; QArray<int> cats = categories(); Categories catDB; catDB.load( categoryFileName() ); for (uint i = 0; i < cats.count(); i++ ) { list << catDB.label("Todo List", cats[i] ); } return list; } void OPimRecord::setCategoryNames( const QStringList& ) { } void OPimRecord::addCategoryName( const QString& ) { Categories catDB; catDB.load( categoryFileName() ); } bool OPimRecord::isEmpty()const { return ( uid() == 0 ); } /*QString OPimRecord::crossToString()const { QString str; QMap<QString, QArray<int> >::ConstIterator it; for (it = m_relations.begin(); it != m_relations.end(); ++it ) { QArray<int> id = it.data(); for ( uint i = 0; i < id.size(); ++i ) { str += it.key() + "," + QString::number( i ) + ";"; } } str = str.remove( str.length()-1, 1); // strip the ; //qWarning("IDS " + str ); return str; }*/ /* if uid = 1 assign a new one */ void OPimRecord::setUid( int uid ) { if ( uid == 1) uid = uidGen().generate(); Qtopia::Record::setUid( uid ); }; Qtopia::UidGen &OPimRecord::uidGen() { return m_uidGen; } OPimXRefManager &OPimRecord::xrefmanager() { return m_xrefman; } int OPimRecord::rtti(){ return 0; } + +/** + * now let's put our data into the stream + */ +/* + * First read UID + * Categories + * XRef + */ +bool OPimRecord::loadFromStream( QDataStream& stream ) { + int Int; + uint UInt; + stream >> Int; + setUid(Int); + + /** Categories */ + stream >> UInt; + QArray<int> array(UInt); + for (uint i = 0; i < UInt; i++ ) { + stream >> array[i]; + } + setCategories( array ); + + /* + * now we do the X-Ref stuff + */ + OPimXRef xref; + stream >> UInt; + for ( uint i = 0; i < UInt; i++ ) { + xref.setPartner( OPimXRef::One, partner( stream ) ); + xref.setPartner( OPimXRef::Two, partner( stream ) ); + m_xrefman.add( xref ); + } + + return true; +} +bool OPimRecord::saveToStream( QDataStream& stream )const { + /** UIDs */ + + stream << uid(); + + /** Categories */ + stream << categories().count(); + for ( uint i = 0; i < categories().count(); i++ ) { + stream << categories()[i]; + } + + /* + * first the XRef count + * then the xrefs + */ + stream << m_xrefman.list().count(); + for ( OPimXRef::ValueList::ConstIterator it = m_xrefman.list().begin(); + it != m_xrefman.list().end(); ++it ) { + flush( (*it).partner( OPimXRef::One), stream ); + flush( (*it).partner( OPimXRef::Two), stream ); + } + return true; +} +void OPimRecord::flush( const OPimXRefPartner& par, QDataStream& str ) const{ + str << par.service(); + str << par.uid(); + str << par.field(); +} +OPimXRefPartner OPimRecord::partner( QDataStream& stream ) { + OPimXRefPartner par; + QString str; + int i; + + stream >> str; + par.setService( str ); + + stream >> i; + par.setUid( i ); + + stream >> i ; + par.setField( i ); + + return par; +} diff --git a/libopie/pim/opimrecord.h b/libopie/pim/opimrecord.h index ec99a13..665530f 100644 --- a/libopie/pim/opimrecord.h +++ b/libopie/pim/opimrecord.h @@ -1,122 +1,134 @@ #ifndef OPIE_PIM_RECORD_H #define OPIE_PIM_RECORD_H +#include <qdatastream.h> #include <qmap.h> #include <qstring.h> #include <qstringlist.h> #include <qpe/palmtoprecord.h> #include <opie/opimxrefmanager.h> /** * This is the base class for * all PIM Records * */ class OPimRecord : public Qtopia::Record { public: /** * c'tor * uid of 0 isEmpty * uid of 1 will be assigned a new one */ OPimRecord(int uid = 0); ~OPimRecord(); /** * copy c'tor */ OPimRecord( const OPimRecord& rec ); /** * copy operator */ OPimRecord &operator=( const OPimRecord& ); /** * category names resolved */ QStringList categoryNames()const; /** * set category names they will be resolved */ void setCategoryNames( const QStringList& ); /** * addCategoryName adds a name * to the internal category list */ void addCategoryName( const QString& ); /** * if a Record isEmpty * it's empty if it's 0 */ virtual bool isEmpty()const; /** * toRichText summary */ virtual QString toRichText()const = 0; /** * a small one line summary */ virtual QString toShortText()const = 0; /** * the name of the Record */ virtual QString type()const = 0; /** * converts the internal structure to a map */ virtual QMap<int, QString> toMap()const = 0; /** * key value representation of extra items */ virtual QMap<QString, QString> toExtraMap()const = 0; /** * the name for a recordField */ virtual QString recordField(int)const = 0; /** * returns a reference of the * Cross Reference Manager * Partner 'One' is THIS PIM RECORD! * 'Two' is the Partner where we link to */ OPimXRefManager& xrefmanager(); /** * set the uid */ virtual void setUid( int uid ); /* * used inside the Templates for casting * REIMPLEMENT in your .... */ static int rtti(); + /** + * some marshalling and de marshalling code + * saves the OPimRecord + * to and from a DataStream + */ + virtual bool loadFromStream(QDataStream& ); + virtual bool saveToStream( QDataStream& stream )const; + protected: Qtopia::UidGen &uidGen(); // QString crossToString()const; private: class OPimRecordPrivate; OPimRecordPrivate *d; OPimXRefManager m_xrefman; static Qtopia::UidGen m_uidGen; +private: + void flush( const OPimXRefPartner&, QDataStream& stream )const; + OPimXRefPartner partner( QDataStream& ); }; #endif diff --git a/libopie/pim/opimresolver.cpp b/libopie/pim/opimresolver.cpp new file mode 100644 index 0000000..4ebbd6e --- a/dev/null +++ b/libopie/pim/opimresolver.cpp @@ -0,0 +1,198 @@ +#include <qcopchannel_qws.h> + +#include <qpe/qcopenvelope_qws.h> + +#include "otodoaccess.h" +#include "ocontactaccess.h" + +//#include "opimfactory.h" +#include "opimresolver.h" + +OPimResolver* OPimResolver::m_self = 0l; + +OPimResolver::OPimResolver() { + /* the built in channels */ + m_builtIns << "Todolist" << "Addressbook" << "Datebook"; +} +OPimResolver* OPimResolver::self() { + if (!m_self) + m_self = new OPimResolver(); + + return m_self; +} + +/* + * FIXME use a cache here too + */ +OPimRecord* OPimResolver::record( const QString& service, int uid ) { + OPimRecord* rec = 0l; + OPimBase* base = backend( service ); + + if ( base ) + rec = base->record( uid ); + delete base; + + return rec; +} +OPimRecord* OPimResolver::record( const QString& service ) { + return record( serviceId( service ) ); +} +OPimRecord* OPimResolver::record( int rtti ) { + OPimRecord* rec = 0l; + switch( rtti ) { + case 1: /* todolist */ + rec = new OTodo(); + case 2: /* contact */ + rec = new OContact(); + default: + break; + } + /* + * FIXME resolve externally + */ + if (!rec ) { + ; + } + return 0l; +} +bool OPimResolver::isBuiltIn( const QString& str) const{ + return m_builtIns.contains( str ); +} +QCString OPimResolver::qcopChannel( enum BuiltIn& built)const { + QCString str("QPE/"); + switch( built ) { + case TodoList: + str += "Todolist"; + break; + case DateBook: + str += "Datebook"; + break; + case AddressBook: + str += "Addressbook"; + break; + default: + break; + } + + return str; +} +QCString OPimResolver::qcopChannel( const QString& service )const { + QCString str("QPE/"); + str += service.latin1(); + return str; +} +/* + * Implement services!! + * FIXME + */ +QCString OPimResolver::applicationChannel( enum BuiltIn& built)const { + QCString str("QPE/Application/"); + switch( built ) { + case TodoList: + str += "todolist"; + break; + case DateBook: + str += "datebook"; + break; + case AddressBook: + str += "addressbook"; + break; + } + + return str; +} +QCString OPimResolver::applicationChannel( const QString& service )const { + QCString str("QPE/Application/"); + + if ( isBuiltIn( service ) ) { + if ( service == "Todolist" ) + str += "todolist"; + else if ( service == "Datebook" ) + str += "datebook"; + else if ( service == "Addressbook" ) + str += "addressbook"; + }else + ; // FIXME for additional stuff + + return str; +} +QStringList OPimResolver::services()const { + return m_builtIns; +} +QString OPimResolver::serviceName( int rtti ) const{ + QString str; + switch ( rtti ) { + case TodoList: + str = "Todolist"; + break; + case DateBook: + str = "Datebook"; + break; + case AddressBook: + str = "Addressbook"; + break; + default: + break; + } + return str; + // FIXME me for 3rd party +} +int OPimResolver::serviceId( const QString& service ) { + int rtti = 0; + if ( service == "Todolist" ) + rtti = TodoList; + else if ( service == "Datebook" ) + rtti = DateBook; + else if ( service == "Addressbook" ) + rtti = AddressBook; + + return rtti; +} +/** + * check if the 'service' is registered and if so we'll + */ +bool OPimResolver::add( const QString& service, const OPimRecord& rec) { + if ( QCopChannel::isRegistered( applicationChannel( service ) ) ) { + QByteArray data; + QDataStream arg(data, IO_WriteOnly ); + if ( rec.saveToStream( arg ) ) { + QCopEnvelope env( applicationChannel( service ), "add(int,QByteArray)" ); + env << rec.rtti(); + env << data; + }else + return false; + }else{ + OPimBase* base = backend( service ); + if (!base ) return false; + + base->load(); + base->add( rec ); + base->save(); + delete base; + } + + return true; +} +OPimBase* OPimResolver::backend( const QString& service ) { + return backend( serviceId( service ) ); +} +OPimBase* OPimResolver::backend( int rtti ) { + OPimBase* base = 0l; + switch( rtti ) { + case TodoList: + base = new OTodoAccess(); + break; + case DateBook: + break; + case AddressBook: + base = new OContactAccess("Resolver"); + break; + default: + break; + } + // FIXME for 3rd party + if (!base ) + ; + + return base; +} diff --git a/libopie/pim/opimresolver.h b/libopie/pim/opimresolver.h index 86ae3eb..1ce1619 100644 --- a/libopie/pim/opimresolver.h +++ b/libopie/pim/opimresolver.h @@ -1,56 +1,90 @@ #ifndef OPIE_PIM_RESOLVER #define OPIE_PIM_RESOLVER #include <qstring.h> #include <qvaluelist.h> +#include <opie/otemplatebase.h> + /** * OPimResolver is a MetaClass to access * available backends read only. * It will be used to resolve uids + app names * to full informations * to traverse through a list of alarms, reminders * to get access to built in PIM functionality * and to more stuff * THE PERFORMANCE will depend on THE BACKEND * USING XML is a waste of memory!!!!! */ -class OPimResolver : public QObject { +class OPimResolver { public: enum BuiltIn { TodoList = 0, DateBook, AddressBook }; static OPimResolver* self(); - /* + /** * return a record for a uid - * and an app + * and an service + * You've THE OWNERSHIP NOW! */ - OPimRecord &record( const QString& service, int uid ); + OPimRecord *record( const QString& service, int uid ); /** * return the QCopChannel for service * When we will use Qtopia Services it will be used here */ - QString qcopChannel( enum BuiltIn& )const; - QString qcopChannel( const QString& service ); + QCString qcopChannel( enum BuiltIn& )const; + QCString qcopChannel( const QString& service )const; + + /** + * The Application channel (QPE/Application/name) + */ + QCString applicationChannel( enum BuiltIn& )const; + QCString applicationChannel( const QString& service )const; /** * return a list of available services */ QStringList services()const; - + inline QString serviceName(int rrti )const; + int serviceId( const QString& Service); /** * add a record to a service... ;) */ bool add( const QString& service, const OPimRecord& ); + + /** + * record returns an empty record for a given service. + * Be sure to delete it!!! + * + */ + OPimRecord* record( const QString& service ); + OPimRecord* record( int rtti ); + + /** + * you can cast to your + */ + OPimBase* backend( const QString& service ); + OPimBase* backend( int rtti ); private: OPimResolver(); - OPimRecord *m_last; + void loadData(); + inline bool isBuiltIn( const QString& )const; + OPimRecord* recordExtern( const QString&, int ); + OPimRecord* recordExtern( const QString& ); + + static OPimResolver* m_self; + struct Data; + class Private; -}: + Data* data; + Private* d; + QStringList m_builtIns; +}; #endif diff --git a/libopie/pim/otemplatebase.h b/libopie/pim/otemplatebase.h index b855919..29fb6ec 100644 --- a/libopie/pim/otemplatebase.h +++ b/libopie/pim/otemplatebase.h @@ -1,32 +1,91 @@ #ifndef OPIE_TEMPLATE_BASE_H #define OPIE_TEMPLATE_BASE_H #include <qarray.h> -#include "opimrecord.h" +#include <opie/opimrecord.h> + /** + * Templates do not have a base class, This is why + * we've this class + * this is here to give us the possibility + * to have a common base class + * You may not want to use that interface internaly + * POOR mans interface + */ +struct OPimBase { + /** + * return the rtti + */ + virtual int rtti()= 0; + virtual OPimRecord* record()const = 0; + virtual OPimRecord* record(int uid)const = 0; + virtual bool add( const OPimRecord& ) = 0; + virtual bool remove( int uid ) = 0; + virtual bool remove( const OPimRecord& ) = 0; + virtual void clear() = 0; + virtual bool load() = 0; + virtual bool save() = 0; + virtual QArray<int> records()const = 0; + /* + * ADD editing here? + * -zecke + */ + +}; +/** * internal template base + * T needs to implement the copy c'tor!!! */ template <class T = OPimRecord> -class OTemplateBase { +class OTemplateBase : public OPimBase { public: enum CacheDirection { Forward=0, Reverse }; OTemplateBase() { }; virtual ~OTemplateBase() { } virtual T find( int uid )const = 0; /** * read ahead find */ virtual T find( int uid, const QArray<int>& items, uint current, CacheDirection dir = Forward )const = 0; virtual void cache( const T& )const = 0; virtual void setSaneCacheSize( int ) = 0; + /* reimplement of OPimBase */ + int rtti(); + OPimRecord* record()const; + OPimRecord* record(int uid )const; + static T* rec(); }; +/* + * implementation + */ +template <class T> +int +OTemplateBase<T>::rtti() { + return T::rtti(); +} +template <class T> +OPimRecord* OTemplateBase<T>::record()const { + T* t = new T; + return t; +} +template <class T> +OPimRecord* OTemplateBase<T>::record(int uid )const { + T t2 = find(uid ); + T* t1 = new T(t2); + + return t1; +}; +template <class T> +T* OTemplateBase<T>::rec() { + return new T; +} #endif diff --git a/libopie/pim/otodo.cpp b/libopie/pim/otodo.cpp index ece624a..cde2b3d 100644 --- a/libopie/pim/otodo.cpp +++ b/libopie/pim/otodo.cpp @@ -1,82 +1,83 @@ #include <qobject.h> #include <qshared.h> #include <qpe/palmtopuidgen.h> #include <qpe/stringutil.h> #include <qpe/palmtoprecord.h> #include <qpe/stringutil.h> #include <qpe/categories.h> #include <qpe/categoryselect.h> #include "opimstate.h" #include "orecur.h" #include "opimmaintainer.h" #include "opimnotifymanager.h" +#include "opimresolver.h" #include "otodo.h" struct OTodo::OTodoData : public QShared { OTodoData() : QShared() { }; QDate date; bool isCompleted:1; bool hasDate:1; int priority; QString desc; QString sum; QMap<QString, QString> extra; ushort prog; OPimState state; ORecur recur; OPimMaintainer maintainer; QDate start; QDate completed; OPimNotifyManager notifiers; }; OTodo::OTodo(const OTodo &event ) : OPimRecord( event ), data( event.data ) { data->ref(); // qWarning("ref up"); } OTodo::~OTodo() { // qWarning("~OTodo " ); if ( data->deref() ) { // qWarning("OTodo::dereffing"); delete data; data = 0l; } } OTodo::OTodo(bool completed, int priority, const QArray<int> &category, const QString& summary, const QString &description, ushort progress, bool hasDate, QDate date, int uid ) : OPimRecord( uid ) { // qWarning("OTodoData " + summary); setCategories( category ); data = new OTodoData; data->date = date; data->isCompleted = completed; data->hasDate = hasDate; data->priority = priority; data->sum = summary; data->prog = progress; data->desc = Qtopia::simplifyMultiLineSpace(description ); } OTodo::OTodo(bool completed, int priority, const QStringList &category, const QString& summary, const QString &description, @@ -356,66 +357,66 @@ QMap<int, QString> OTodo::toMap() const { map.insert( HasDate, QString::number( data->hasDate ) ); map.insert( Completed, QString::number( data->isCompleted ) ); map.insert( Description, data->desc ); map.insert( Summary, data->sum ); map.insert( Priority, QString::number( data->priority ) ); map.insert( DateDay, QString::number( data->date.day() ) ); map.insert( DateMonth, QString::number( data->date.month() ) ); map.insert( DateYear, QString::number( data->date.year() ) ); map.insert( Progress, QString::number( data->prog ) ); // map.insert( CrossReference, crossToString() ); /* FIXME!!! map.insert( State, ); map.insert( Recurrence, ); map.insert( Reminders, ); map. */ return map; } QMap<QString, QString> OTodo::toExtraMap()const { return data->extra; } /** * change or modify looks at the ref count and either * creates a new QShared Object or it can modify it * right in place */ void OTodo::changeOrModify() { if ( data->count != 1 ) { qWarning("changeOrModify"); data->deref(); OTodoData* d2 = new OTodoData(); copy(data, d2 ); data = d2; } } // WATCHOUT /* * if you add something to the Data struct * be sure to copy it here */ void OTodo::copy( OTodoData* src, OTodoData* dest ) { dest->date = src->date; dest->isCompleted = src->isCompleted; dest->hasDate = src->hasDate; dest->priority = src->priority; dest->desc = src->desc; dest->sum = src->sum; dest->extra = src->extra; dest->prog = src->prog; dest->state = src->state; dest->recur = src->recur; dest->maintainer = src->maintainer; dest->start = src->start; dest->completed = src->completed; dest->notifiers = src->notifiers; } QString OTodo::type() const { return QString::fromLatin1("OTodo"); } QString OTodo::recordField(int /*id*/ )const { return QString::null; } int OTodo::rtti(){ - return 1; + return OPimResolver::TodoList; } diff --git a/libopie/pim/otodoaccess.cpp b/libopie/pim/otodoaccess.cpp index d860411..5e89a1b 100644 --- a/libopie/pim/otodoaccess.cpp +++ b/libopie/pim/otodoaccess.cpp @@ -1,86 +1,56 @@ #include <qdatetime.h> #include <qpe/alarmserver.h> // #include "otodoaccesssql.h" #include "otodoaccess.h" #include "obackendfactory.h" -OTodoAccess::OTodoAccess( OTodoAccessBackend* end ) +OTodoAccess::OTodoAccess( OTodoAccessBackend* end, enum Access ) : QObject(), OPimAccessTemplate<OTodo>( end ), m_todoBackEnd( end ) { // if (end == 0l ) // m_todoBackEnd = new OTodoAccessBackendSQL( QString::null); // Zecke: Du musst hier noch für das XML-Backend einen Appnamen übergeben ! if (end == 0l ) m_todoBackEnd = OBackendFactory<OTodoAccessBackend>::Default ("todo", QString::null); setBackEnd( m_todoBackEnd ); } OTodoAccess::~OTodoAccess() { // qWarning("~OTodoAccess"); } void OTodoAccess::mergeWith( const QValueList<OTodo>& list ) { QValueList<OTodo>::ConstIterator it; for ( it = list.begin(); it != list.end(); ++it ) { replace( (*it) ); } } OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ) { QArray<int> ints = m_todoBackEnd->effectiveToDos( start, end, includeNoDates ); List lis( ints, this ); return lis; } OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, bool includeNoDates ) { return effectiveToDos( start, QDate::currentDate(), includeNoDates ); } OTodoAccess::List OTodoAccess::overDue() { List lis( m_todoBackEnd->overDue(), this ); return lis; } -void OTodoAccess::addAlarm( const OTodo& event) { -/* FIXME use the new notifier architecture - if (!event.hasAlarmDateTime() ) - return; - - QDateTime now = QDateTime::currentDateTime(); - QDateTime schedule = event.alarmDateTime(); - - if ( schedule > now ){ - AlarmServer::addAlarm( schedule, - "QPE/Application/todolist", - "alarm(QDateTime,int)", event.uid() ); - - } -*/ -} -void OTodoAccess::delAlarm( int uid) { - - QDateTime schedule; // Create null DateTime - - // I hope this will remove all scheduled alarms - // with the given uid !? - // If not: I have to rethink how to remove already - // scheduled events... (se) - // it should be fine -zecke -// qWarning("Removing alarm for event with uid %d", uid ); - AlarmServer::deleteAlarm( schedule , - "QPE/Application/todolist", - "alarm(QDateTime,int)", uid ); -} /* sort order */ OTodoAccess::List OTodoAccess::sorted( bool ascending, int sort,int filter, int cat ) { QArray<int> ints = m_todoBackEnd->sorted( ascending, sort, filter, cat ); OTodoAccess::List list( ints, this ); return list; } void OTodoAccess::removeAllCompleted() { m_todoBackEnd->removeAllCompleted(); } diff --git a/libopie/pim/otodoaccess.h b/libopie/pim/otodoaccess.h index c079155..2bb87dc 100644 --- a/libopie/pim/otodoaccess.h +++ b/libopie/pim/otodoaccess.h @@ -1,98 +1,87 @@ #ifndef OPIE_TODO_ACCESS_H #define OPIE_TODO_ACCESS_H #include <qobject.h> #include <qvaluelist.h> #include "otodo.h" #include "otodoaccessbackend.h" #include "opimaccesstemplate.h" /** * OTodoAccess * the class to get access to * the todolist */ class OTodoAccess : public QObject, public OPimAccessTemplate<OTodo> { Q_OBJECT public: enum SortOrder { Completed = 0, Priority, Description, Deadline }; enum SortFilter{ Category =1, OnlyOverDue= 2, DoNotShowCompleted =4 }; /** * if you use 0l * the default resource will be * picked up */ - OTodoAccess( OTodoAccessBackend* = 0l); + OTodoAccess( OTodoAccessBackend* = 0l, enum Access acc = Random ); ~OTodoAccess(); /* our functions here */ /** * include todos from start to end * includeNoDates whether or not to include * events with no dates */ List effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates = true ); /** * start * end date taken from the currentDate() */ List effectiveToDos( const QDate& start, bool includeNoDates = true ); /** * return overdue OTodos */ List overDue(); /** * */ List sorted( bool ascending, int sortOrder, int sortFilter, int cat ); /** * merge a list of OTodos into * the resource */ void mergeWith( const QValueList<OTodo>& ); /** * delete all already completed items */ void removeAllCompleted(); signals: /** * if the OTodoAccess was changed */ void signalChanged( const OTodoAccess* ); private: - /** - * add an Alarm to the AlarmServer - */ - void addAlarm( const OTodo& ); - - /** - * delete an alarm with the uid from - * the alarm server - */ - void delAlarm( int uid ); - int m_cat; OTodoAccessBackend* m_todoBackEnd; class OTodoAccessPrivate; OTodoAccessPrivate* d; }; #endif diff --git a/libopie/pim/otodoaccessxml.cpp b/libopie/pim/otodoaccessxml.cpp index b2dfe80..21f93a0 100644 --- a/libopie/pim/otodoaccessxml.cpp +++ b/libopie/pim/otodoaccessxml.cpp @@ -1,197 +1,226 @@ +#include <errno.h> +#include <fcntl.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <unistd.h> + + #include <qfile.h> #include <qvector.h> #include <qpe/global.h> #include <qpe/stringutil.h> #include <qpe/timeconversion.h> #include <opie/xmltree.h> #include "otodoaccessxml.h" OTodoAccessXML::OTodoAccessXML( const QString& appName, const QString& fileName ) : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) { if (!fileName.isEmpty() ) m_file = fileName; else m_file = Global::applicationFileName( "todolist", "todolist.xml" ); } OTodoAccessXML::~OTodoAccessXML() { } bool OTodoAccessXML::load() { m_opened = true; m_changed = false; /* initialize dict */ /* * UPDATE dict if you change anything!!! */ QAsciiDict<int> dict(21); dict.setAutoDelete( TRUE ); dict.insert("Categories" , new int(OTodo::Category) ); dict.insert("Uid" , new int(OTodo::Uid) ); dict.insert("HasDate" , new int(OTodo::HasDate) ); dict.insert("Completed" , new int(OTodo::Completed) ); dict.insert("Description" , new int(OTodo::Description) ); dict.insert("Summary" , new int(OTodo::Summary) ); dict.insert("Priority" , new int(OTodo::Priority) ); dict.insert("DateDay" , new int(OTodo::DateDay) ); dict.insert("DateMonth" , new int(OTodo::DateMonth) ); dict.insert("DateYear" , new int(OTodo::DateYear) ); dict.insert("Progress" , new int(OTodo::Progress) ); dict.insert("Completed", new int(OTodo::Completed) ); dict.insert("CrossReference", new int(OTodo::CrossReference) ); dict.insert("State", new int(OTodo::State) ); dict.insert("Recurrence", new int(OTodo::Recurrence) ); dict.insert("Alarms", new int(OTodo::Alarms) ); dict.insert("Reminders", new int(OTodo::Reminders) ); dict.insert("Notifiers", new int(OTodo::Notifiers) ); dict.insert("Maintainer", new int(OTodo::Maintainer) ); // here the custom XML parser from TT it's GPL // but we want to push OpiePIM... to TT..... - QFile f(m_file ); - if (!f.open(IO_ReadOnly) ) + // mmap part from zecke :) + int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); + struct stat attribut; + if ( fd < 0 ) return false; + + if ( fstat(fd, &attribut ) == -1 ) { + ::close( fd ); return false; + } + void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); + if ( map_addr == ( (caddr_t)-1) ) { + ::close(fd ); + return false; + } + /* advise the kernel who we want to read it */ + ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); + /* we do not the file any more */ + ::close( fd ); - QByteArray ba = f.readAll(); - f.close(); - char* dt = ba.data(); - int len = ba.size(); + char* dt = (char*)map_addr; + int len = attribut.st_size; int i = 0; char *point; const char* collectionString = "<Task "; + int strLen = strlen(collectionString); while ( dt+i != 0 && ( point = strstr( dt+i, collectionString ) ) != 0l ) { i = point -dt; - i+= strlen(collectionString); + i+= strLen; + qWarning("Found a start at %d %d", i, (point-dt) ); + OTodo ev; m_year = m_month = m_day = 0; while ( TRUE ) { while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) ++i; if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) break; // we have another attribute, read it. int j = i; while ( j < len && dt[j] != '=' ) ++j; QCString attr( dt+i, j-i+1); i = ++j; // skip = // find the start of quotes while ( i < len && dt[i] != '"' ) ++i; j = ++i; bool haveUtf = FALSE; bool haveEnt = FALSE; while ( j < len && dt[j] != '"' ) { if ( ((unsigned char)dt[j]) > 0x7f ) haveUtf = TRUE; if ( dt[j] == '&' ) haveEnt = TRUE; ++j; } if ( i == j ) { // empty value i = j + 1; continue; } QCString value( dt+i, j-i+1 ); i = j + 1; QString str = (haveUtf ? QString::fromUtf8( value ) : QString::fromLatin1( value ) ); if ( haveEnt ) str = Qtopia::plainString( str ); /* * add key + value */ todo( &dict, ev, attr, str ); } /* * now add it */ + qWarning("End at %d", i ); if (m_events.contains( ev.uid() ) || ev.uid() == 0) { ev.setUid( 1 ); m_changed = true; } if ( ev.hasDueDate() ) { ev.setDueDate( QDate(m_year, m_month, m_day) ); } m_events.insert(ev.uid(), ev ); m_year = m_month = m_day = -1; } + munmap(map_addr, attribut.st_size ); + qWarning("counts %d records loaded!", m_events.count() ); return true; } bool OTodoAccessXML::reload() { return load(); } bool OTodoAccessXML::save() { // qWarning("saving"); if (!m_opened || !m_changed ) { // qWarning("not saving"); return true; } QString strNewFile = m_file + ".new"; QFile f( strNewFile ); if (!f.open( IO_WriteOnly|IO_Raw ) ) return false; int written; QString out; out = "<!DOCTYPE Tasks>\n<Tasks>\n"; // for all todos QMap<int, OTodo>::Iterator it; for (it = m_events.begin(); it != m_events.end(); ++it ) { out+= "<Task " + toString( (*it) ) + " />\n"; QCString cstr = out.utf8(); written = f.writeBlock( cstr.data(), cstr.length() ); /* less written then we wanted */ if ( written != (int)cstr.length() ) { f.close(); QFile::remove( strNewFile ); return false; } out = QString::null; } out += "</Tasks>"; QCString cstr = out.utf8(); written = f.writeBlock( cstr.data(), cstr.length() ); if ( written != (int)cstr.length() ) { f.close(); QFile::remove( strNewFile ); return false; } /* flush before renaming */ f.close(); if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { // qWarning("error renaming"); QFile::remove( strNewFile ); } m_changed = false; return true; } QArray<int> OTodoAccessXML::allRecords()const { QArray<int> ids( m_events.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { ids[i] = it.key(); diff --git a/libopie2/opiepim/backend/opimaccessbackend.h b/libopie2/opiepim/backend/opimaccessbackend.h index 4f00bc9..e268f4f 100644 --- a/libopie2/opiepim/backend/opimaccessbackend.h +++ b/libopie2/opiepim/backend/opimaccessbackend.h @@ -1,141 +1,153 @@ #ifndef OPIE_PIM_ACCESS_BACKEND #define OPIE_PIM_ACCESS_BACKEND #include <qarray.h> #include <opie/otemplatebase.h> #include <opie/opimrecord.h> /** * OPimAccessBackend is the base class * for all private backends * it operates on OPimRecord as the base class * and it's responsible for fast manipulating * the resource the implementation takes care * of */ template <class T = OPimRecord> class OPimAccessBackend { public: typedef OTemplateBase<T> Frontend; - OPimAccessBackend(); + + /** The access hint from the frontend */ + OPimAccessBackend(int access = 0); virtual ~OPimAccessBackend(); /** * load the resource */ virtual bool load() = 0; /** * reload the resource */ virtual bool reload() = 0; /** * save the resource and * all it's changes */ virtual bool save() = 0; /** * return an array of * all available uids */ virtual QArray<int> allRecords()const = 0; /** * queryByExample for T with the SortOrder * sort */ virtual QArray<int> queryByExample( const T& t, int sort ) = 0; /** * find the OPimRecord with uid @param uid * returns T and T.isEmpty() if nothing was found */ virtual T find(int uid )const = 0; virtual T find(int uid, const QArray<int>& items, uint current, typename Frontend::CacheDirection )const ; /** * clear the back end */ virtual void clear() = 0; /** * add T */ virtual bool add( const T& t ) = 0; /** * remove */ virtual bool remove( int uid ) = 0; /** * replace a record with T.uid() */ virtual bool replace( const T& t ) = 0; /* * setTheFrontEnd!!! */ void setFrontend( Frontend* front ); /** * set the read ahead count */ void setReadAhead( uint count ); protected: + int access()const; void cache( const T& t )const; /** * use a prime number here! */ void setSaneCacheSize( int ); uint readAhead()const; private: + class Private; + Private* d; Frontend* m_front; uint m_read; + int m_acc; }; template <class T> -OPimAccessBackend<T>::OPimAccessBackend() { +OPimAccessBackend<T>::OPimAccessBackend(int acc) + : m_acc( acc ) +{ m_front = 0l; } template <class T> OPimAccessBackend<T>::~OPimAccessBackend() { } template <class T> void OPimAccessBackend<T>::setFrontend( Frontend* fr ) { m_front = fr; } template <class T> void OPimAccessBackend<T>::cache( const T& t )const { if (m_front ) m_front->cache( t ); } template <class T> void OPimAccessBackend<T>::setSaneCacheSize( int size) { if (m_front ) m_front->setSaneCacheSize( size ); } template <class T> T OPimAccessBackend<T>::find( int uid, const QArray<int>&, uint, typename Frontend::CacheDirection )const { return find( uid ); } template <class T> void OPimAccessBackend<T>::setReadAhead( uint count ) { m_read = count; } template <class T> uint OPimAccessBackend<T>::readAhead()const { return m_read; } +template <class T> +int OPimAccessBackend<T>::access()const { + return m_acc; +} #endif diff --git a/libopie2/opiepim/backend/otodoaccessxml.cpp b/libopie2/opiepim/backend/otodoaccessxml.cpp index b2dfe80..21f93a0 100644 --- a/libopie2/opiepim/backend/otodoaccessxml.cpp +++ b/libopie2/opiepim/backend/otodoaccessxml.cpp @@ -1,197 +1,226 @@ +#include <errno.h> +#include <fcntl.h> + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include <unistd.h> + + #include <qfile.h> #include <qvector.h> #include <qpe/global.h> #include <qpe/stringutil.h> #include <qpe/timeconversion.h> #include <opie/xmltree.h> #include "otodoaccessxml.h" OTodoAccessXML::OTodoAccessXML( const QString& appName, const QString& fileName ) : OTodoAccessBackend(), m_app( appName ), m_opened( false ), m_changed( false ) { if (!fileName.isEmpty() ) m_file = fileName; else m_file = Global::applicationFileName( "todolist", "todolist.xml" ); } OTodoAccessXML::~OTodoAccessXML() { } bool OTodoAccessXML::load() { m_opened = true; m_changed = false; /* initialize dict */ /* * UPDATE dict if you change anything!!! */ QAsciiDict<int> dict(21); dict.setAutoDelete( TRUE ); dict.insert("Categories" , new int(OTodo::Category) ); dict.insert("Uid" , new int(OTodo::Uid) ); dict.insert("HasDate" , new int(OTodo::HasDate) ); dict.insert("Completed" , new int(OTodo::Completed) ); dict.insert("Description" , new int(OTodo::Description) ); dict.insert("Summary" , new int(OTodo::Summary) ); dict.insert("Priority" , new int(OTodo::Priority) ); dict.insert("DateDay" , new int(OTodo::DateDay) ); dict.insert("DateMonth" , new int(OTodo::DateMonth) ); dict.insert("DateYear" , new int(OTodo::DateYear) ); dict.insert("Progress" , new int(OTodo::Progress) ); dict.insert("Completed", new int(OTodo::Completed) ); dict.insert("CrossReference", new int(OTodo::CrossReference) ); dict.insert("State", new int(OTodo::State) ); dict.insert("Recurrence", new int(OTodo::Recurrence) ); dict.insert("Alarms", new int(OTodo::Alarms) ); dict.insert("Reminders", new int(OTodo::Reminders) ); dict.insert("Notifiers", new int(OTodo::Notifiers) ); dict.insert("Maintainer", new int(OTodo::Maintainer) ); // here the custom XML parser from TT it's GPL // but we want to push OpiePIM... to TT..... - QFile f(m_file ); - if (!f.open(IO_ReadOnly) ) + // mmap part from zecke :) + int fd = ::open( QFile::encodeName(m_file).data(), O_RDONLY ); + struct stat attribut; + if ( fd < 0 ) return false; + + if ( fstat(fd, &attribut ) == -1 ) { + ::close( fd ); return false; + } + void* map_addr = ::mmap(NULL, attribut.st_size, PROT_READ, MAP_SHARED, fd, 0 ); + if ( map_addr == ( (caddr_t)-1) ) { + ::close(fd ); + return false; + } + /* advise the kernel who we want to read it */ + ::madvise( map_addr, attribut.st_size, MADV_SEQUENTIAL ); + /* we do not the file any more */ + ::close( fd ); - QByteArray ba = f.readAll(); - f.close(); - char* dt = ba.data(); - int len = ba.size(); + char* dt = (char*)map_addr; + int len = attribut.st_size; int i = 0; char *point; const char* collectionString = "<Task "; + int strLen = strlen(collectionString); while ( dt+i != 0 && ( point = strstr( dt+i, collectionString ) ) != 0l ) { i = point -dt; - i+= strlen(collectionString); + i+= strLen; + qWarning("Found a start at %d %d", i, (point-dt) ); + OTodo ev; m_year = m_month = m_day = 0; while ( TRUE ) { while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') ) ++i; if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') ) break; // we have another attribute, read it. int j = i; while ( j < len && dt[j] != '=' ) ++j; QCString attr( dt+i, j-i+1); i = ++j; // skip = // find the start of quotes while ( i < len && dt[i] != '"' ) ++i; j = ++i; bool haveUtf = FALSE; bool haveEnt = FALSE; while ( j < len && dt[j] != '"' ) { if ( ((unsigned char)dt[j]) > 0x7f ) haveUtf = TRUE; if ( dt[j] == '&' ) haveEnt = TRUE; ++j; } if ( i == j ) { // empty value i = j + 1; continue; } QCString value( dt+i, j-i+1 ); i = j + 1; QString str = (haveUtf ? QString::fromUtf8( value ) : QString::fromLatin1( value ) ); if ( haveEnt ) str = Qtopia::plainString( str ); /* * add key + value */ todo( &dict, ev, attr, str ); } /* * now add it */ + qWarning("End at %d", i ); if (m_events.contains( ev.uid() ) || ev.uid() == 0) { ev.setUid( 1 ); m_changed = true; } if ( ev.hasDueDate() ) { ev.setDueDate( QDate(m_year, m_month, m_day) ); } m_events.insert(ev.uid(), ev ); m_year = m_month = m_day = -1; } + munmap(map_addr, attribut.st_size ); + qWarning("counts %d records loaded!", m_events.count() ); return true; } bool OTodoAccessXML::reload() { return load(); } bool OTodoAccessXML::save() { // qWarning("saving"); if (!m_opened || !m_changed ) { // qWarning("not saving"); return true; } QString strNewFile = m_file + ".new"; QFile f( strNewFile ); if (!f.open( IO_WriteOnly|IO_Raw ) ) return false; int written; QString out; out = "<!DOCTYPE Tasks>\n<Tasks>\n"; // for all todos QMap<int, OTodo>::Iterator it; for (it = m_events.begin(); it != m_events.end(); ++it ) { out+= "<Task " + toString( (*it) ) + " />\n"; QCString cstr = out.utf8(); written = f.writeBlock( cstr.data(), cstr.length() ); /* less written then we wanted */ if ( written != (int)cstr.length() ) { f.close(); QFile::remove( strNewFile ); return false; } out = QString::null; } out += "</Tasks>"; QCString cstr = out.utf8(); written = f.writeBlock( cstr.data(), cstr.length() ); if ( written != (int)cstr.length() ) { f.close(); QFile::remove( strNewFile ); return false; } /* flush before renaming */ f.close(); if( ::rename( strNewFile.latin1(), m_file.latin1() ) < 0 ) { // qWarning("error renaming"); QFile::remove( strNewFile ); } m_changed = false; return true; } QArray<int> OTodoAccessXML::allRecords()const { QArray<int> ids( m_events.count() ); QMap<int, OTodo>::ConstIterator it; int i = 0; for ( it = m_events.begin(); it != m_events.end(); ++it ) { ids[i] = it.key(); diff --git a/libopie2/opiepim/core/opimaccesstemplate.h b/libopie2/opiepim/core/opimaccesstemplate.h index 8cf81c8..259e2c1 100644 --- a/libopie2/opiepim/core/opimaccesstemplate.h +++ b/libopie2/opiepim/core/opimaccesstemplate.h @@ -1,269 +1,286 @@ #ifndef OPIE_PIM_ACCESS_TEMPLATE_H #define OPIE_PIM_ACCESS_TEMPLATE_H #include <qarray.h> #include <opie/opimrecord.h> #include <opie/opimaccessbackend.h> #include <opie/orecordlist.h> #include "opimcache.h" #include "otemplatebase.h" /** * Thats the frontend to our OPIE PIM * Library. Either you want to use it's * interface or you want to implement * your own Access lib * Just create a OPimRecord and inherit from * the plugins */ template <class T = OPimRecord > class OPimAccessTemplate : public OTemplateBase<T> { public: + enum Access { + Random = 0, + SortedAccess + }; typedef ORecordList<T> List; typedef OPimAccessBackend<T> BackEnd; typedef OPimCache<T> Cache; /** * c'tor BackEnd + * enum Access a small hint on how to handle the backend */ OPimAccessTemplate( BackEnd* end); + virtual ~OPimAccessTemplate(); /** * load from the backend */ - virtual bool load(); + bool load(); /** Reload database. * You should execute this function if the external database * was changed. * This function will load the external database and afterwards * rejoin the local changes. Therefore the local database will be set consistent. */ virtual bool reload(); /** Save contacts database. * Save is more a "commit". After calling this function, all changes are public available. * @return true if successful */ - virtual bool save(); + bool save(); /** * 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 ); /** * 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 */ - virtual void clear() ; + void clear() ; /** * add T to the backend * @param t The item to add. * @return <i>true</i> if added successfully. */ virtual bool add( const T& t ) ; bool add( const OPimRecord& ); /* only the uid matters */ /** * remove T from the backend * @param t The item to remove * @return <i>true</i> if successful. */ virtual bool remove( const T& t ); /** * remove the OPimRecord with uid * @param uid The ID of the item to remove * @return <i>true</i> if successful. */ - virtual bool remove( int uid ); + bool remove( int uid ); + bool remove( const OPimRecord& ); /** * replace T from backend * @param t The item to replace * @return <i>true</i> if successful. */ virtual bool replace( const T& t) ; void setReadAhead( uint count ); /** * @internal */ void cache( const T& )const; void setSaneCacheSize( int ); + + QArray<int> records()const; protected: /** * invalidate the cache */ void invalidateCache(); void setBackEnd( BackEnd* end ); /** * returns the backend */ BackEnd* backEnd(); BackEnd* m_backEnd; Cache m_cache; }; template <class T> OPimAccessTemplate<T>::OPimAccessTemplate( BackEnd* end ) : OTemplateBase<T>(), m_backEnd( end ) { if (end ) end->setFrontend( this ); } template <class T> OPimAccessTemplate<T>::~OPimAccessTemplate() { qWarning("~OPimAccessTemplate<T>"); delete m_backEnd; } template <class T> bool OPimAccessTemplate<T>::load() { invalidateCache(); return m_backEnd->load(); } template <class T> bool OPimAccessTemplate<T>::reload() { invalidateCache(); // zecke: I think this should be added (se) return m_backEnd->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 ); 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 * avoid two finds in QCache... */ // qWarning("find it now %d", uid ); if (m_cache.contains( uid ) ) { return m_cache.find( uid ); } T t = m_backEnd->find( uid, ar, current, dir ); cache( t ); return t; } template <class T> void OPimAccessTemplate<T>::clear() { invalidateCache(); m_backEnd->clear(); } template <class T> bool OPimAccessTemplate<T>::add( const T& t ) { cache( t ); return m_backEnd->add( t ); } template <class T> bool OPimAccessTemplate<T>::add( const OPimRecord& rec) { /* same type */ if ( rec.rtti() == T::rtti() ) { const T &t = static_cast<const T&>(rec); return add(t); } return false; } template <class T> bool OPimAccessTemplate<T>::remove( const T& t ) { return remove( t.uid() ); } template <class T> bool OPimAccessTemplate<T>::remove( int uid ) { m_cache.remove( uid ); return m_backEnd->remove( uid ); } template <class T> +bool OPimAccessTemplate<T>::remove( const OPimRecord& rec) { + return remove( rec.uid() ); +} +template <class T> bool OPimAccessTemplate<T>::replace( const T& t ) { m_cache.replace( t ); return m_backEnd->replace( t ); } template <class T> void OPimAccessTemplate<T>::invalidateCache() { m_cache.invalidate(); } template <class T> typename OPimAccessTemplate<T>::BackEnd* OPimAccessTemplate<T>::backEnd() { return m_backEnd; } template <class T> bool OPimAccessTemplate<T>::wasChangedExternally()const { return false; } template <class T> void OPimAccessTemplate<T>::setBackEnd( BackEnd* end ) { m_backEnd = end; if (m_backEnd ) m_backEnd->setFrontend( this ); } template <class T> void OPimAccessTemplate<T>::cache( const T& t ) const{ /* hacky we need to work around the const*/ ((OPimAccessTemplate<T>*)this)->m_cache.add( t ); } template <class T> void OPimAccessTemplate<T>::setSaneCacheSize( int size ) { m_cache.setSize( size ); } template <class T> void OPimAccessTemplate<T>::setReadAhead( uint count ) { m_backEnd->setReadAhead( count ); } #endif diff --git a/libopie2/opiepim/core/opimcache.h b/libopie2/opiepim/core/opimcache.h index 839550c..73414e5 100644 --- a/libopie2/opiepim/core/opimcache.h +++ b/libopie2/opiepim/core/opimcache.h @@ -1,95 +1,101 @@ #ifndef OPIE_PIM_CACHE_H #define OPIE_PIM_CACHE_H #include <qintcache.h> #include "opimrecord.h" template <class T = OPimRecord> class OPimCacheItem { public: OPimCacheItem( const T& t = T() ); + OPimCacheItem( const OPimCacheItem& ); ~OPimCacheItem(); + OPimCacheItem &operator=( const OPimCacheItem& ); + T record()const; void setRecord( const T& ); private: T m_t; }; /** * OPimCache for caching the items * We support adding, removing * and finding */ template <class T = OPimRecord> class OPimCache { public: typedef OPimCacheItem<T> Item; OPimCache(); + OPimCache( const OPimCache& ); ~OPimCache(); + OPimCache &operator=( const OPimCache& ); + bool contains(int uid)const; void invalidate(); void setSize( int size ); T find(int uid )const; void add( const T& ); void remove( int uid ); void replace( const T& ); private: QIntCache<Item> m_cache; }; // Implementation template <class T> OPimCacheItem<T>::OPimCacheItem( const T& t ) : m_t(t) { } template <class T> OPimCacheItem<T>::~OPimCacheItem() { } template <class T> T OPimCacheItem<T>::record()const { return m_t; } template <class T> void OPimCacheItem<T>::setRecord( const T& t ) { m_t = t; } // Cache template <class T> OPimCache<T>::OPimCache() : m_cache(100, 53 ) { m_cache.setAutoDelete( TRUE ); } template <class T> OPimCache<T>::~OPimCache() { } template <class T> bool OPimCache<T>::contains(int uid )const { Item* it = m_cache.find( uid, FALSE ); if (!it) return false; return true; } template <class T> void OPimCache<T>::invalidate() { m_cache.clear(); } template <class T> void OPimCache<T>::setSize( int size ) { m_cache.setMaxCost( size ); } template <class T> T OPimCache<T>::find(int uid )const { Item *it = m_cache.find( uid ); if (it) return it->record(); return T(); } template <class T> diff --git a/libopie2/opiepim/core/opimrecord.cpp b/libopie2/opiepim/core/opimrecord.cpp index 49b5bf9..ac0f4a9 100644 --- a/libopie2/opiepim/core/opimrecord.cpp +++ b/libopie2/opiepim/core/opimrecord.cpp @@ -1,84 +1,166 @@ +#include <qarray.h> + #include <qpe/categories.h> #include <qpe/categoryselect.h> #include "opimrecord.h" Qtopia::UidGen OPimRecord::m_uidGen( Qtopia::UidGen::Qtopia ); OPimRecord::OPimRecord( int uid ) : Qtopia::Record() { setUid( uid ); } OPimRecord::~OPimRecord() { } OPimRecord::OPimRecord( const OPimRecord& rec ) : Qtopia::Record( rec ) { (*this) = rec; } OPimRecord &OPimRecord::operator=( const OPimRecord& rec) { Qtopia::Record::operator=( rec ); m_xrefman = rec.m_xrefman; return *this; } /* * category names */ QStringList OPimRecord::categoryNames()const { QStringList list; QArray<int> cats = categories(); Categories catDB; catDB.load( categoryFileName() ); for (uint i = 0; i < cats.count(); i++ ) { list << catDB.label("Todo List", cats[i] ); } return list; } void OPimRecord::setCategoryNames( const QStringList& ) { } void OPimRecord::addCategoryName( const QString& ) { Categories catDB; catDB.load( categoryFileName() ); } bool OPimRecord::isEmpty()const { return ( uid() == 0 ); } /*QString OPimRecord::crossToString()const { QString str; QMap<QString, QArray<int> >::ConstIterator it; for (it = m_relations.begin(); it != m_relations.end(); ++it ) { QArray<int> id = it.data(); for ( uint i = 0; i < id.size(); ++i ) { str += it.key() + "," + QString::number( i ) + ";"; } } str = str.remove( str.length()-1, 1); // strip the ; //qWarning("IDS " + str ); return str; }*/ /* if uid = 1 assign a new one */ void OPimRecord::setUid( int uid ) { if ( uid == 1) uid = uidGen().generate(); Qtopia::Record::setUid( uid ); }; Qtopia::UidGen &OPimRecord::uidGen() { return m_uidGen; } OPimXRefManager &OPimRecord::xrefmanager() { return m_xrefman; } int OPimRecord::rtti(){ return 0; } + +/** + * now let's put our data into the stream + */ +/* + * First read UID + * Categories + * XRef + */ +bool OPimRecord::loadFromStream( QDataStream& stream ) { + int Int; + uint UInt; + stream >> Int; + setUid(Int); + + /** Categories */ + stream >> UInt; + QArray<int> array(UInt); + for (uint i = 0; i < UInt; i++ ) { + stream >> array[i]; + } + setCategories( array ); + + /* + * now we do the X-Ref stuff + */ + OPimXRef xref; + stream >> UInt; + for ( uint i = 0; i < UInt; i++ ) { + xref.setPartner( OPimXRef::One, partner( stream ) ); + xref.setPartner( OPimXRef::Two, partner( stream ) ); + m_xrefman.add( xref ); + } + + return true; +} +bool OPimRecord::saveToStream( QDataStream& stream )const { + /** UIDs */ + + stream << uid(); + + /** Categories */ + stream << categories().count(); + for ( uint i = 0; i < categories().count(); i++ ) { + stream << categories()[i]; + } + + /* + * first the XRef count + * then the xrefs + */ + stream << m_xrefman.list().count(); + for ( OPimXRef::ValueList::ConstIterator it = m_xrefman.list().begin(); + it != m_xrefman.list().end(); ++it ) { + flush( (*it).partner( OPimXRef::One), stream ); + flush( (*it).partner( OPimXRef::Two), stream ); + } + return true; +} +void OPimRecord::flush( const OPimXRefPartner& par, QDataStream& str ) const{ + str << par.service(); + str << par.uid(); + str << par.field(); +} +OPimXRefPartner OPimRecord::partner( QDataStream& stream ) { + OPimXRefPartner par; + QString str; + int i; + + stream >> str; + par.setService( str ); + + stream >> i; + par.setUid( i ); + + stream >> i ; + par.setField( i ); + + return par; +} diff --git a/libopie2/opiepim/core/opimrecord.h b/libopie2/opiepim/core/opimrecord.h index ec99a13..665530f 100644 --- a/libopie2/opiepim/core/opimrecord.h +++ b/libopie2/opiepim/core/opimrecord.h @@ -1,122 +1,134 @@ #ifndef OPIE_PIM_RECORD_H #define OPIE_PIM_RECORD_H +#include <qdatastream.h> #include <qmap.h> #include <qstring.h> #include <qstringlist.h> #include <qpe/palmtoprecord.h> #include <opie/opimxrefmanager.h> /** * This is the base class for * all PIM Records * */ class OPimRecord : public Qtopia::Record { public: /** * c'tor * uid of 0 isEmpty * uid of 1 will be assigned a new one */ OPimRecord(int uid = 0); ~OPimRecord(); /** * copy c'tor */ OPimRecord( const OPimRecord& rec ); /** * copy operator */ OPimRecord &operator=( const OPimRecord& ); /** * category names resolved */ QStringList categoryNames()const; /** * set category names they will be resolved */ void setCategoryNames( const QStringList& ); /** * addCategoryName adds a name * to the internal category list */ void addCategoryName( const QString& ); /** * if a Record isEmpty * it's empty if it's 0 */ virtual bool isEmpty()const; /** * toRichText summary */ virtual QString toRichText()const = 0; /** * a small one line summary */ virtual QString toShortText()const = 0; /** * the name of the Record */ virtual QString type()const = 0; /** * converts the internal structure to a map */ virtual QMap<int, QString> toMap()const = 0; /** * key value representation of extra items */ virtual QMap<QString, QString> toExtraMap()const = 0; /** * the name for a recordField */ virtual QString recordField(int)const = 0; /** * returns a reference of the * Cross Reference Manager * Partner 'One' is THIS PIM RECORD! * 'Two' is the Partner where we link to */ OPimXRefManager& xrefmanager(); /** * set the uid */ virtual void setUid( int uid ); /* * used inside the Templates for casting * REIMPLEMENT in your .... */ static int rtti(); + /** + * some marshalling and de marshalling code + * saves the OPimRecord + * to and from a DataStream + */ + virtual bool loadFromStream(QDataStream& ); + virtual bool saveToStream( QDataStream& stream )const; + protected: Qtopia::UidGen &uidGen(); // QString crossToString()const; private: class OPimRecordPrivate; OPimRecordPrivate *d; OPimXRefManager m_xrefman; static Qtopia::UidGen m_uidGen; +private: + void flush( const OPimXRefPartner&, QDataStream& stream )const; + OPimXRefPartner partner( QDataStream& ); }; #endif diff --git a/libopie2/opiepim/core/opimresolver.cpp b/libopie2/opiepim/core/opimresolver.cpp new file mode 100644 index 0000000..4ebbd6e --- a/dev/null +++ b/libopie2/opiepim/core/opimresolver.cpp @@ -0,0 +1,198 @@ +#include <qcopchannel_qws.h> + +#include <qpe/qcopenvelope_qws.h> + +#include "otodoaccess.h" +#include "ocontactaccess.h" + +//#include "opimfactory.h" +#include "opimresolver.h" + +OPimResolver* OPimResolver::m_self = 0l; + +OPimResolver::OPimResolver() { + /* the built in channels */ + m_builtIns << "Todolist" << "Addressbook" << "Datebook"; +} +OPimResolver* OPimResolver::self() { + if (!m_self) + m_self = new OPimResolver(); + + return m_self; +} + +/* + * FIXME use a cache here too + */ +OPimRecord* OPimResolver::record( const QString& service, int uid ) { + OPimRecord* rec = 0l; + OPimBase* base = backend( service ); + + if ( base ) + rec = base->record( uid ); + delete base; + + return rec; +} +OPimRecord* OPimResolver::record( const QString& service ) { + return record( serviceId( service ) ); +} +OPimRecord* OPimResolver::record( int rtti ) { + OPimRecord* rec = 0l; + switch( rtti ) { + case 1: /* todolist */ + rec = new OTodo(); + case 2: /* contact */ + rec = new OContact(); + default: + break; + } + /* + * FIXME resolve externally + */ + if (!rec ) { + ; + } + return 0l; +} +bool OPimResolver::isBuiltIn( const QString& str) const{ + return m_builtIns.contains( str ); +} +QCString OPimResolver::qcopChannel( enum BuiltIn& built)const { + QCString str("QPE/"); + switch( built ) { + case TodoList: + str += "Todolist"; + break; + case DateBook: + str += "Datebook"; + break; + case AddressBook: + str += "Addressbook"; + break; + default: + break; + } + + return str; +} +QCString OPimResolver::qcopChannel( const QString& service )const { + QCString str("QPE/"); + str += service.latin1(); + return str; +} +/* + * Implement services!! + * FIXME + */ +QCString OPimResolver::applicationChannel( enum BuiltIn& built)const { + QCString str("QPE/Application/"); + switch( built ) { + case TodoList: + str += "todolist"; + break; + case DateBook: + str += "datebook"; + break; + case AddressBook: + str += "addressbook"; + break; + } + + return str; +} +QCString OPimResolver::applicationChannel( const QString& service )const { + QCString str("QPE/Application/"); + + if ( isBuiltIn( service ) ) { + if ( service == "Todolist" ) + str += "todolist"; + else if ( service == "Datebook" ) + str += "datebook"; + else if ( service == "Addressbook" ) + str += "addressbook"; + }else + ; // FIXME for additional stuff + + return str; +} +QStringList OPimResolver::services()const { + return m_builtIns; +} +QString OPimResolver::serviceName( int rtti ) const{ + QString str; + switch ( rtti ) { + case TodoList: + str = "Todolist"; + break; + case DateBook: + str = "Datebook"; + break; + case AddressBook: + str = "Addressbook"; + break; + default: + break; + } + return str; + // FIXME me for 3rd party +} +int OPimResolver::serviceId( const QString& service ) { + int rtti = 0; + if ( service == "Todolist" ) + rtti = TodoList; + else if ( service == "Datebook" ) + rtti = DateBook; + else if ( service == "Addressbook" ) + rtti = AddressBook; + + return rtti; +} +/** + * check if the 'service' is registered and if so we'll + */ +bool OPimResolver::add( const QString& service, const OPimRecord& rec) { + if ( QCopChannel::isRegistered( applicationChannel( service ) ) ) { + QByteArray data; + QDataStream arg(data, IO_WriteOnly ); + if ( rec.saveToStream( arg ) ) { + QCopEnvelope env( applicationChannel( service ), "add(int,QByteArray)" ); + env << rec.rtti(); + env << data; + }else + return false; + }else{ + OPimBase* base = backend( service ); + if (!base ) return false; + + base->load(); + base->add( rec ); + base->save(); + delete base; + } + + return true; +} +OPimBase* OPimResolver::backend( const QString& service ) { + return backend( serviceId( service ) ); +} +OPimBase* OPimResolver::backend( int rtti ) { + OPimBase* base = 0l; + switch( rtti ) { + case TodoList: + base = new OTodoAccess(); + break; + case DateBook: + break; + case AddressBook: + base = new OContactAccess("Resolver"); + break; + default: + break; + } + // FIXME for 3rd party + if (!base ) + ; + + return base; +} diff --git a/libopie2/opiepim/core/opimresolver.h b/libopie2/opiepim/core/opimresolver.h index 86ae3eb..1ce1619 100644 --- a/libopie2/opiepim/core/opimresolver.h +++ b/libopie2/opiepim/core/opimresolver.h @@ -1,56 +1,90 @@ #ifndef OPIE_PIM_RESOLVER #define OPIE_PIM_RESOLVER #include <qstring.h> #include <qvaluelist.h> +#include <opie/otemplatebase.h> + /** * OPimResolver is a MetaClass to access * available backends read only. * It will be used to resolve uids + app names * to full informations * to traverse through a list of alarms, reminders * to get access to built in PIM functionality * and to more stuff * THE PERFORMANCE will depend on THE BACKEND * USING XML is a waste of memory!!!!! */ -class OPimResolver : public QObject { +class OPimResolver { public: enum BuiltIn { TodoList = 0, DateBook, AddressBook }; static OPimResolver* self(); - /* + /** * return a record for a uid - * and an app + * and an service + * You've THE OWNERSHIP NOW! */ - OPimRecord &record( const QString& service, int uid ); + OPimRecord *record( const QString& service, int uid ); /** * return the QCopChannel for service * When we will use Qtopia Services it will be used here */ - QString qcopChannel( enum BuiltIn& )const; - QString qcopChannel( const QString& service ); + QCString qcopChannel( enum BuiltIn& )const; + QCString qcopChannel( const QString& service )const; + + /** + * The Application channel (QPE/Application/name) + */ + QCString applicationChannel( enum BuiltIn& )const; + QCString applicationChannel( const QString& service )const; /** * return a list of available services */ QStringList services()const; - + inline QString serviceName(int rrti )const; + int serviceId( const QString& Service); /** * add a record to a service... ;) */ bool add( const QString& service, const OPimRecord& ); + + /** + * record returns an empty record for a given service. + * Be sure to delete it!!! + * + */ + OPimRecord* record( const QString& service ); + OPimRecord* record( int rtti ); + + /** + * you can cast to your + */ + OPimBase* backend( const QString& service ); + OPimBase* backend( int rtti ); private: OPimResolver(); - OPimRecord *m_last; + void loadData(); + inline bool isBuiltIn( const QString& )const; + OPimRecord* recordExtern( const QString&, int ); + OPimRecord* recordExtern( const QString& ); + + static OPimResolver* m_self; + struct Data; + class Private; -}: + Data* data; + Private* d; + QStringList m_builtIns; +}; #endif diff --git a/libopie2/opiepim/core/otemplatebase.h b/libopie2/opiepim/core/otemplatebase.h index b855919..29fb6ec 100644 --- a/libopie2/opiepim/core/otemplatebase.h +++ b/libopie2/opiepim/core/otemplatebase.h @@ -1,32 +1,91 @@ #ifndef OPIE_TEMPLATE_BASE_H #define OPIE_TEMPLATE_BASE_H #include <qarray.h> -#include "opimrecord.h" +#include <opie/opimrecord.h> + /** + * Templates do not have a base class, This is why + * we've this class + * this is here to give us the possibility + * to have a common base class + * You may not want to use that interface internaly + * POOR mans interface + */ +struct OPimBase { + /** + * return the rtti + */ + virtual int rtti()= 0; + virtual OPimRecord* record()const = 0; + virtual OPimRecord* record(int uid)const = 0; + virtual bool add( const OPimRecord& ) = 0; + virtual bool remove( int uid ) = 0; + virtual bool remove( const OPimRecord& ) = 0; + virtual void clear() = 0; + virtual bool load() = 0; + virtual bool save() = 0; + virtual QArray<int> records()const = 0; + /* + * ADD editing here? + * -zecke + */ + +}; +/** * internal template base + * T needs to implement the copy c'tor!!! */ template <class T = OPimRecord> -class OTemplateBase { +class OTemplateBase : public OPimBase { public: enum CacheDirection { Forward=0, Reverse }; OTemplateBase() { }; virtual ~OTemplateBase() { } virtual T find( int uid )const = 0; /** * read ahead find */ virtual T find( int uid, const QArray<int>& items, uint current, CacheDirection dir = Forward )const = 0; virtual void cache( const T& )const = 0; virtual void setSaneCacheSize( int ) = 0; + /* reimplement of OPimBase */ + int rtti(); + OPimRecord* record()const; + OPimRecord* record(int uid )const; + static T* rec(); }; +/* + * implementation + */ +template <class T> +int +OTemplateBase<T>::rtti() { + return T::rtti(); +} +template <class T> +OPimRecord* OTemplateBase<T>::record()const { + T* t = new T; + return t; +} +template <class T> +OPimRecord* OTemplateBase<T>::record(int uid )const { + T t2 = find(uid ); + T* t1 = new T(t2); + + return t1; +}; +template <class T> +T* OTemplateBase<T>::rec() { + return new T; +} #endif diff --git a/libopie2/opiepim/core/otodoaccess.cpp b/libopie2/opiepim/core/otodoaccess.cpp index d860411..5e89a1b 100644 --- a/libopie2/opiepim/core/otodoaccess.cpp +++ b/libopie2/opiepim/core/otodoaccess.cpp @@ -1,86 +1,56 @@ #include <qdatetime.h> #include <qpe/alarmserver.h> // #include "otodoaccesssql.h" #include "otodoaccess.h" #include "obackendfactory.h" -OTodoAccess::OTodoAccess( OTodoAccessBackend* end ) +OTodoAccess::OTodoAccess( OTodoAccessBackend* end, enum Access ) : QObject(), OPimAccessTemplate<OTodo>( end ), m_todoBackEnd( end ) { // if (end == 0l ) // m_todoBackEnd = new OTodoAccessBackendSQL( QString::null); // Zecke: Du musst hier noch für das XML-Backend einen Appnamen übergeben ! if (end == 0l ) m_todoBackEnd = OBackendFactory<OTodoAccessBackend>::Default ("todo", QString::null); setBackEnd( m_todoBackEnd ); } OTodoAccess::~OTodoAccess() { // qWarning("~OTodoAccess"); } void OTodoAccess::mergeWith( const QValueList<OTodo>& list ) { QValueList<OTodo>::ConstIterator it; for ( it = list.begin(); it != list.end(); ++it ) { replace( (*it) ); } } OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates ) { QArray<int> ints = m_todoBackEnd->effectiveToDos( start, end, includeNoDates ); List lis( ints, this ); return lis; } OTodoAccess::List OTodoAccess::effectiveToDos( const QDate& start, bool includeNoDates ) { return effectiveToDos( start, QDate::currentDate(), includeNoDates ); } OTodoAccess::List OTodoAccess::overDue() { List lis( m_todoBackEnd->overDue(), this ); return lis; } -void OTodoAccess::addAlarm( const OTodo& event) { -/* FIXME use the new notifier architecture - if (!event.hasAlarmDateTime() ) - return; - - QDateTime now = QDateTime::currentDateTime(); - QDateTime schedule = event.alarmDateTime(); - - if ( schedule > now ){ - AlarmServer::addAlarm( schedule, - "QPE/Application/todolist", - "alarm(QDateTime,int)", event.uid() ); - - } -*/ -} -void OTodoAccess::delAlarm( int uid) { - - QDateTime schedule; // Create null DateTime - - // I hope this will remove all scheduled alarms - // with the given uid !? - // If not: I have to rethink how to remove already - // scheduled events... (se) - // it should be fine -zecke -// qWarning("Removing alarm for event with uid %d", uid ); - AlarmServer::deleteAlarm( schedule , - "QPE/Application/todolist", - "alarm(QDateTime,int)", uid ); -} /* sort order */ OTodoAccess::List OTodoAccess::sorted( bool ascending, int sort,int filter, int cat ) { QArray<int> ints = m_todoBackEnd->sorted( ascending, sort, filter, cat ); OTodoAccess::List list( ints, this ); return list; } void OTodoAccess::removeAllCompleted() { m_todoBackEnd->removeAllCompleted(); } diff --git a/libopie2/opiepim/core/otodoaccess.h b/libopie2/opiepim/core/otodoaccess.h index c079155..2bb87dc 100644 --- a/libopie2/opiepim/core/otodoaccess.h +++ b/libopie2/opiepim/core/otodoaccess.h @@ -1,98 +1,87 @@ #ifndef OPIE_TODO_ACCESS_H #define OPIE_TODO_ACCESS_H #include <qobject.h> #include <qvaluelist.h> #include "otodo.h" #include "otodoaccessbackend.h" #include "opimaccesstemplate.h" /** * OTodoAccess * the class to get access to * the todolist */ class OTodoAccess : public QObject, public OPimAccessTemplate<OTodo> { Q_OBJECT public: enum SortOrder { Completed = 0, Priority, Description, Deadline }; enum SortFilter{ Category =1, OnlyOverDue= 2, DoNotShowCompleted =4 }; /** * if you use 0l * the default resource will be * picked up */ - OTodoAccess( OTodoAccessBackend* = 0l); + OTodoAccess( OTodoAccessBackend* = 0l, enum Access acc = Random ); ~OTodoAccess(); /* our functions here */ /** * include todos from start to end * includeNoDates whether or not to include * events with no dates */ List effectiveToDos( const QDate& start, const QDate& end, bool includeNoDates = true ); /** * start * end date taken from the currentDate() */ List effectiveToDos( const QDate& start, bool includeNoDates = true ); /** * return overdue OTodos */ List overDue(); /** * */ List sorted( bool ascending, int sortOrder, int sortFilter, int cat ); /** * merge a list of OTodos into * the resource */ void mergeWith( const QValueList<OTodo>& ); /** * delete all already completed items */ void removeAllCompleted(); signals: /** * if the OTodoAccess was changed */ void signalChanged( const OTodoAccess* ); private: - /** - * add an Alarm to the AlarmServer - */ - void addAlarm( const OTodo& ); - - /** - * delete an alarm with the uid from - * the alarm server - */ - void delAlarm( int uid ); - int m_cat; OTodoAccessBackend* m_todoBackEnd; class OTodoAccessPrivate; OTodoAccessPrivate* d; }; #endif diff --git a/libopie2/opiepim/ocontact.cpp b/libopie2/opiepim/ocontact.cpp index 6aec62e..38cba72 100644 --- a/libopie2/opiepim/ocontact.cpp +++ b/libopie2/opiepim/ocontact.cpp @@ -1,88 +1,89 @@ /********************************************************************** ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** Copyright (C) 2002 by Stefan Eilers (eilers.stefan@epost.de) ** ** This file is part of the Qtopia Environment. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #define QTOPIA_INTERNAL_CONTACT_MRE #include "ocontact.h" +#include "opimresolver.h" #include <qpe/stringutil.h> #include <qpe/timeconversion.h> #include <qpe/timestring.h> #include <qobject.h> #include <qregexp.h> #include <qstylesheet.h> #include <qfileinfo.h> #include <qmap.h> #include <stdio.h> /*! \class Contact contact.h \brief The Contact class holds the data of an address book entry. This data includes information the name of the person, contact information, and business information such as deparment and job title. \ingroup qtopiaemb \ingroup qtopiadesktop */ /*! Creates a new, empty contact. */ OContact::OContact() : OPimRecord(), mMap(), d( 0 ) { } /*! \internal Creates a new contact. The properties of the contact are set from \a fromMap. */ OContact::OContact( const QMap<int, QString> &fromMap ) : OPimRecord(), mMap( fromMap ), d( 0 ) { QString cats = mMap[ Qtopia::AddressCategory ]; if ( !cats.isEmpty() ) setCategories( idsFromString( cats ) ); QString uidStr = find( Qtopia::AddressUid ); if ( uidStr.isEmpty() || (uidStr.toInt() == 0) ){ qWarning( "Invalid UID found. Generate new one.." ); setUid( uidGen().generate() ); }else setUid( uidStr.toInt() ); // if ( !uidStr.isEmpty() ) // setUid( uidStr.toInt() ); } /*! Destroys a contact. */ OContact::~OContact() { } @@ -768,129 +769,129 @@ QStringList OContact::emailList() const return r; } /*! \overload Generates the string for the contact to be filed as from the first, middle and last name of the contact. */ void OContact::setFileAs() { QString lastName, firstName, middleName, fileas; lastName = find( Qtopia::LastName ); firstName = find( Qtopia::FirstName ); middleName = find( Qtopia::MiddleName ); if ( !lastName.isEmpty() && !firstName.isEmpty() && !middleName.isEmpty() ) fileas = lastName + ", " + firstName + " " + middleName; else if ( !lastName.isEmpty() && !firstName.isEmpty() ) fileas = lastName + ", " + firstName; else if ( !lastName.isEmpty() || !firstName.isEmpty() || !middleName.isEmpty() ) fileas = firstName + ( firstName.isEmpty() ? "" : " " ) + middleName + ( middleName.isEmpty() ? "" : " " ) + lastName; replace( Qtopia::FileAs, fileas ); } /*! \internal Appends the contact information to \a buf. */ void OContact::save( QString &buf ) const { static const QStringList SLFIELDS = fields(); // I'm expecting "<Contact " in front of this... for ( QMap<int, QString>::ConstIterator it = mMap.begin(); it != mMap.end(); ++it ) { const QString &value = it.data(); int key = it.key(); if ( !value.isEmpty() ) { if ( key == Qtopia::AddressCategory || key == Qtopia::AddressUid) continue; key -= Qtopia::AddressCategory+1; buf += SLFIELDS[key]; buf += "=\"" + Qtopia::escapeString(value) + "\" "; } } buf += customToXml(); if ( categories().count() > 0 ) buf += "Categories=\"" + idsToString( categories() ) + "\" "; buf += "Uid=\"" + QString::number( uid() ) + "\" "; // You need to close this yourself } /*! \internal Returns the list of fields belonging to a contact Never change order of this list ! It has to be regarding - enum AddressBookFields !! + enum AddressBookFields !! */ QStringList OContact::fields() { QStringList list; list.append( "Title" ); // Not Used! list.append( "FirstName" ); list.append( "MiddleName" ); list.append( "LastName" ); list.append( "Suffix" ); list.append( "FileAs" ); list.append( "JobTitle" ); list.append( "Department" ); list.append( "Company" ); list.append( "BusinessPhone" ); list.append( "BusinessFax" ); list.append( "BusinessMobile" ); list.append( "DefaultEmail" ); list.append( "Emails" ); list.append( "HomePhone" ); list.append( "HomeFax" ); list.append( "HomeMobile" ); list.append( "BusinessStreet" ); list.append( "BusinessCity" ); list.append( "BusinessState" ); list.append( "BusinessZip" ); list.append( "BusinessCountry" ); list.append( "BusinessPager" ); list.append( "BusinessWebPage" ); list.append( "Office" ); list.append( "Profession" ); list.append( "Assistant" ); list.append( "Manager" ); list.append( "HomeStreet" ); list.append( "HomeCity" ); list.append( "HomeState" ); list.append( "HomeZip" ); list.append( "HomeCountry" ); list.append( "HomeWebPage" ); list.append( "Spouse" ); list.append( "Gender" ); list.append( "Birthday" ); list.append( "Anniversary" ); list.append( "Nickname" ); list.append( "Children" ); list.append( "Notes" ); list.append( "Groups" ); return list; } /*! Sets the list of email address for contact to those contained in \a str. Email address should be separated by ';'s. */ @@ -1039,71 +1040,71 @@ void OContact::insertEmail( const QString &v ) setDefaultEmail( e ); // will insert into the list for us return; } // otherwise, insert assuming doesn't already exist QString emailsStr = find( Qtopia::Emails ); if ( emailsStr.contains( e )) return; if ( !emailsStr.isEmpty() ) emailsStr += emailSeparator(); emailsStr += e; replace( Qtopia::Emails, emailsStr ); } void OContact::removeEmail( const QString &v ) { QString e = v.simplifyWhiteSpace(); QString def = defaultEmail(); QString emailsStr = find( Qtopia::Emails ); QStringList emails = emailList(); // otherwise, must first contain it if ( !emailsStr.contains( e ) ) return; // remove it //qDebug(" removing email from list %s", e.latin1()); emails.remove( e ); // reset the string emailsStr = emails.join(emailSeparator()); // Sharp's brain dead separator replace( Qtopia::Emails, emailsStr ); // if default, then replace the default email with the first one if ( def == e ) { //qDebug("removeEmail is default; setting new default"); if ( !emails.count() ) clearEmails(); else // setDefaultEmail will remove e from the list setDefaultEmail( emails.first() ); } } void OContact::clearEmails() { mMap.remove( Qtopia::DefaultEmail ); mMap.remove( Qtopia::Emails ); } void OContact::setDefaultEmail( const QString &v ) { QString e = v.simplifyWhiteSpace(); //qDebug("OContact::setDefaultEmail %s", e.latin1()); replace( Qtopia::DefaultEmail, e ); if ( !e.isEmpty() ) insertEmail( e ); } void OContact::insertEmails( const QStringList &v ) { for ( QStringList::ConstIterator it = v.begin(); it != v.end(); ++it ) insertEmail( *it ); } int OContact::rtti() { - return 2; + return OPimResolver::AddressBook; } void OContact::setUid( int i ) -{ - OPimRecord::setUid(i); - replace( Qtopia::AddressUid , QString::number(i)); +{ + OPimRecord::setUid(i); + replace( Qtopia::AddressUid , QString::number(i)); } diff --git a/libopie2/opiepim/otodo.cpp b/libopie2/opiepim/otodo.cpp index ece624a..cde2b3d 100644 --- a/libopie2/opiepim/otodo.cpp +++ b/libopie2/opiepim/otodo.cpp @@ -1,82 +1,83 @@ #include <qobject.h> #include <qshared.h> #include <qpe/palmtopuidgen.h> #include <qpe/stringutil.h> #include <qpe/palmtoprecord.h> #include <qpe/stringutil.h> #include <qpe/categories.h> #include <qpe/categoryselect.h> #include "opimstate.h" #include "orecur.h" #include "opimmaintainer.h" #include "opimnotifymanager.h" +#include "opimresolver.h" #include "otodo.h" struct OTodo::OTodoData : public QShared { OTodoData() : QShared() { }; QDate date; bool isCompleted:1; bool hasDate:1; int priority; QString desc; QString sum; QMap<QString, QString> extra; ushort prog; OPimState state; ORecur recur; OPimMaintainer maintainer; QDate start; QDate completed; OPimNotifyManager notifiers; }; OTodo::OTodo(const OTodo &event ) : OPimRecord( event ), data( event.data ) { data->ref(); // qWarning("ref up"); } OTodo::~OTodo() { // qWarning("~OTodo " ); if ( data->deref() ) { // qWarning("OTodo::dereffing"); delete data; data = 0l; } } OTodo::OTodo(bool completed, int priority, const QArray<int> &category, const QString& summary, const QString &description, ushort progress, bool hasDate, QDate date, int uid ) : OPimRecord( uid ) { // qWarning("OTodoData " + summary); setCategories( category ); data = new OTodoData; data->date = date; data->isCompleted = completed; data->hasDate = hasDate; data->priority = priority; data->sum = summary; data->prog = progress; data->desc = Qtopia::simplifyMultiLineSpace(description ); } OTodo::OTodo(bool completed, int priority, const QStringList &category, const QString& summary, const QString &description, @@ -356,66 +357,66 @@ QMap<int, QString> OTodo::toMap() const { map.insert( HasDate, QString::number( data->hasDate ) ); map.insert( Completed, QString::number( data->isCompleted ) ); map.insert( Description, data->desc ); map.insert( Summary, data->sum ); map.insert( Priority, QString::number( data->priority ) ); map.insert( DateDay, QString::number( data->date.day() ) ); map.insert( DateMonth, QString::number( data->date.month() ) ); map.insert( DateYear, QString::number( data->date.year() ) ); map.insert( Progress, QString::number( data->prog ) ); // map.insert( CrossReference, crossToString() ); /* FIXME!!! map.insert( State, ); map.insert( Recurrence, ); map.insert( Reminders, ); map. */ return map; } QMap<QString, QString> OTodo::toExtraMap()const { return data->extra; } /** * change or modify looks at the ref count and either * creates a new QShared Object or it can modify it * right in place */ void OTodo::changeOrModify() { if ( data->count != 1 ) { qWarning("changeOrModify"); data->deref(); OTodoData* d2 = new OTodoData(); copy(data, d2 ); data = d2; } } // WATCHOUT /* * if you add something to the Data struct * be sure to copy it here */ void OTodo::copy( OTodoData* src, OTodoData* dest ) { dest->date = src->date; dest->isCompleted = src->isCompleted; dest->hasDate = src->hasDate; dest->priority = src->priority; dest->desc = src->desc; dest->sum = src->sum; dest->extra = src->extra; dest->prog = src->prog; dest->state = src->state; dest->recur = src->recur; dest->maintainer = src->maintainer; dest->start = src->start; dest->completed = src->completed; dest->notifiers = src->notifiers; } QString OTodo::type() const { return QString::fromLatin1("OTodo"); } QString OTodo::recordField(int /*id*/ )const { return QString::null; } int OTodo::rtti(){ - return 1; + return OPimResolver::TodoList; } diff --git a/libopie2/opiepim/ui/opimmainwindow.cpp b/libopie2/opiepim/ui/opimmainwindow.cpp index 92be2fd..7e57f3a 100644 --- a/libopie2/opiepim/ui/opimmainwindow.cpp +++ b/libopie2/opiepim/ui/opimmainwindow.cpp @@ -1,71 +1,105 @@ #include <qapplication.h> #include <qcopchannel_qws.h> #include <qpe/qcopenvelope_qws.h> +#include "opimresolver.h" #include "opimmainwindow.h" OPimMainWindow::OPimMainWindow( const QString& service, QWidget* parent, const char* name, WFlags flag ) - : QMainWindow( parent, name, flag ), m_service( service ), m_fallBack(0l) { + : QMainWindow( parent, name, flag ), m_rtti(-1), m_service( service ), m_fallBack(0l) { /* * let's generate our QCopChannel */ m_str = QString("QPE/"+m_service).local8Bit(); m_channel= new QCopChannel(m_str, this ); connect(m_channel, SIGNAL(received(const QCString&, const QByteArray& ) ), this, SLOT( appMessage( const QCString&, const QByteArray& ) ) ); /* connect flush and reload */ connect(qApp, SIGNAL(flush() ), this, SLOT(flush() ) ); connect(qApp, SIGNAL(reload() ), this, SLOT(reload() ) ); } OPimMainWindow::~OPimMainWindow() { delete m_channel; } QCopChannel* OPimMainWindow::channel() { return m_channel; } +void OPimMainWindow::doSetDocument( const QString& ) { + +} void OPimMainWindow::appMessage( const QCString& cmd, const QByteArray& array ) { /* * create demands to create * a new record... */ QDataStream stream(array, IO_ReadOnly); if ( cmd == "create()" ) { int uid = create(); QCopEnvelope e(m_str, "created(int)" ); e << uid; }else if ( cmd == "remove(int)" ) { int uid; stream >> uid; bool rem = remove( uid ); QCopEnvelope e(m_str, "removed(bool)" ); e << rem; }else if ( cmd == "beam(int,int)" ) { int uid, trans; stream >> uid; stream >> trans; beam( uid, trans ); }else if ( cmd == "show(int)" ) { int uid; stream >> uid; show( uid ); }else if ( cmd == "edit(int)" ) { int uid; stream >> uid; edit( uid ); }else if ( cmd == "add(int,QByteArray)" ) { int rtti; QByteArray array; stream >> rtti; stream >> array; m_fallBack = record(rtti, array ); if (!m_fallBack) return; add( *m_fallBack ); delete m_fallBack; } } +/* implement the url scripting here */ +void OPimMainWindow::setDocument( const QString& str) { + doSetDocument( str ); +} +/* + * we now try to get the array demarshalled + * check if the rtti matches this one + */ +OPimRecord* OPimMainWindow::record( int rtti, const QByteArray& array ) { + if ( service() != rtti ) + return 0l; + + OPimRecord* record = OPimResolver::self()->record( rtti ); + QDataStream str(array, IO_ReadOnly ); + if ( !record || !record->loadFromStream(str) ) { + delete record; + record = 0l; + } + + return record; +} +/* + * get the rtti for the service + */ +int OPimMainWindow::service() { + if ( m_rtti == -1 ) + m_rtti = OPimResolver::self()->serviceId( m_service ); + + return m_rtti; +} diff --git a/libopie2/opiepim/ui/opimmainwindow.h b/libopie2/opiepim/ui/opimmainwindow.h index 94100bd..34b8a71 100644 --- a/libopie2/opiepim/ui/opimmainwindow.h +++ b/libopie2/opiepim/ui/opimmainwindow.h @@ -1,79 +1,89 @@ #ifndef OPIE_PIM_MAINWINDOW_H #define OPIE_PIM_MAINWINDOW_H #include <qmainwindow.h> #include <opie/opimrecord.h> /** * This is a common Opie PIM MainWindow * it takes care of the QCOP internals * and implements some functions * for the URL scripting schema */ /* * due Qt and Templates with signal and slots * do not work that good :( * (Ok how to moc a template ;) ) * We will have the mainwindow which calls a struct which * is normally reimplemented as a template ;) */ class QCopChannel; class OPimMainWindow : public QMainWindow { Q_OBJECT public: enum TransPort { BlueTooth=0, IrDa }; OPimMainWindow( const QString& service, QWidget *parent = 0, const char* name = 0, WFlags f = WType_TopLevel); virtual ~OPimMainWindow(); protected slots: + /* + * called when a setDocument + * couldn't be handled by this window + */ + virtual void doSetDocument( const QString& ); /* for syncing */ virtual void flush() = 0; virtual void reload() = 0; /** create a new Records and return the uid */ virtual int create() = 0; /** remove a record with UID == uid */ virtual bool remove( int uid ) = 0; /** beam the record with UID = uid */ virtual void beam( int uid , int transport = IrDa) = 0; /** show the record with UID == uid */ virtual void show( int uid ) = 0; /** edit the record */ virtual void edit( int uid ) = 0; /** make a copy of it! */ virtual void add( const OPimRecord& ) = 0; - /* I would love to do this as a template - * but can't think of a right way - * because I need signal and slots -zecke - */ - /* - * the only pointer in the whole PIM API :( - */ - virtual OPimRecord* record( int rtti, const QByteArray& ) = 0; + QCopChannel* channel(); private slots: void appMessage( const QCString&, const QByteArray& ); + void setDocument( const QString& ); private: class Private; Private* d; + int m_rtti; QCopChannel* m_channel; QString m_service; QCString m_str; OPimRecord* m_fallBack; + + /* I would love to do this as a template + * but can't think of a right way + * because I need signal and slots -zecke + */ + /* + * the only pointer in the whole PIM API :( + */ + virtual OPimRecord* record( int rtti, const QByteArray& ) ; + int service(); }; #endif |