-rw-r--r-- | libopie/pim/ocontactaccessbackend_sql.cpp | 11 | ||||
-rw-r--r-- | libopie/pim/ocontactaccessbackend_sql.h | 5 | ||||
-rw-r--r-- | libopie/pim/odatebookaccessbackend_sql.cpp | 221 | ||||
-rw-r--r-- | libopie/pim/odatebookaccessbackend_sql.h | 60 | ||||
-rw-r--r-- | libopie/pim/odatebookaccessbackend_xml.cpp | 12 | ||||
-rw-r--r-- | libopie/pim/oevent.cpp | 131 | ||||
-rw-r--r-- | libopie/pim/oevent.h | 38 | ||||
-rw-r--r-- | libopie/pim/orecur.cpp | 8 | ||||
-rw-r--r-- | libopie/pim/orecur.h | 1 | ||||
-rw-r--r-- | libopie/pim/otodoaccesssql.cpp | 5 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp | 11 | ||||
-rw-r--r-- | libopie2/opiepim/backend/ocontactaccessbackend_sql.h | 5 | ||||
-rw-r--r-- | libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp | 221 | ||||
-rw-r--r-- | libopie2/opiepim/backend/odatebookaccessbackend_sql.h | 60 | ||||
-rw-r--r-- | libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp | 12 | ||||
-rw-r--r-- | libopie2/opiepim/backend/otodoaccesssql.cpp | 5 | ||||
-rw-r--r-- | libopie2/opiepim/core/orecur.cpp | 8 | ||||
-rw-r--r-- | libopie2/opiepim/core/orecur.h | 1 | ||||
-rw-r--r-- | libopie2/opiepim/oevent.cpp | 131 | ||||
-rw-r--r-- | libopie2/opiepim/oevent.h | 38 |
20 files changed, 942 insertions, 42 deletions
diff --git a/libopie/pim/ocontactaccessbackend_sql.cpp b/libopie/pim/ocontactaccessbackend_sql.cpp index 132c9fc..dd9dbde 100644 --- a/libopie/pim/ocontactaccessbackend_sql.cpp +++ b/libopie/pim/ocontactaccessbackend_sql.cpp @@ -1,32 +1,35 @@ /* * SQL Backend for the OPIE-Contact Database. * * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.3 2003/12/08 15:18:10 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * * Revision 1.2 2003/09/29 07:44:26 eilers * Improvement of PIM-SQL Databases, but search queries are still limited. * Addressbook: Changed table layout. Now, we just need 1/3 of disk-space. * Todo: Started to add new attributes. Some type conversions missing. * * Revision 1.1 2003/09/22 14:31:16 eilers * Added first experimental incarnation of sql-backend for addressbook. * Some modifications to be able to compile the todo sql-backend. * A lot of changes fill follow... * */ #include "ocontactaccessbackend_sql.h" #include <qarray.h> #include <qdatetime.h> @@ -441,54 +444,60 @@ namespace { QString FindCustomQuery::query()const{ // if ( m_uids.count() == 0 ) return single(); } QString FindCustomQuery::single()const{ QString qu = "select uid, type, value from custom_data where uid = "; qu += QString::number(m_uid); return qu; } }; /* --------------------------------------------------------------------------- */ OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, - const QString& filename ): m_changed(false) + const QString& filename ): + OContactAccessBackend(), m_changed(false), m_driver( NULL ) { qWarning("C'tor OContactAccessBackend_SQL starts"); QTime t; t.start(); /* Expecting to access the default filename if nothing else is set */ if ( filename.isEmpty() ){ m_fileName = Global::applicationFileName( "addressbook","addressbook.db" ); } else m_fileName = filename; // Get the standart sql-driver from the OSQLManager.. OSQLManager man; m_driver = man.standard(); m_driver->setUrl( m_fileName ); load(); qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() ); } +OContactAccessBackend_SQL::~OContactAccessBackend_SQL () +{ + if( m_driver ) + delete m_driver; +} bool OContactAccessBackend_SQL::load () { if (!m_driver->open() ) return false; // Don't expect that the database exists. // It is save here to create the table, even if it // do exist. ( Is that correct for all databases ?? ) CreateQuery creat; OSQLResult res = m_driver->query( &creat ); update(); return true; diff --git a/libopie/pim/ocontactaccessbackend_sql.h b/libopie/pim/ocontactaccessbackend_sql.h index bb22551..b8f1d8d 100644 --- a/libopie/pim/ocontactaccessbackend_sql.h +++ b/libopie/pim/ocontactaccessbackend_sql.h @@ -3,63 +3,68 @@ * * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.2 2003/12/08 15:18:11 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * * Revision 1.1 2003/09/22 14:31:16 eilers * Added first experimental incarnation of sql-backend for addressbook. * Some modifications to be able to compile the todo sql-backend. * A lot of changes fill follow... * * */ #ifndef _OContactAccessBackend_SQL_ #define _OContactAccessBackend_SQL_ #include "ocontactaccessbackend.h" #include "ocontactaccess.h" #include <qlist.h> #include <qdict.h> class OSQLDriver; class OSQLResult; class OSQLResultItem; /* the default xml implementation */ /** * This class is the SQL implementation of a Contact backend * it does implement everything available for OContact. * @see OPimAccessBackend for more information of available methods */ class OContactAccessBackend_SQL : public OContactAccessBackend { public: OContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null ); + ~OContactAccessBackend_SQL (); + bool save(); bool load (); void clear (); bool wasChangedExternally(); QArray<int> allRecords() const; OContact find ( int uid ) const; // FIXME: Add lookahead-cache support ! //OContact find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d ); diff --git a/libopie/pim/odatebookaccessbackend_sql.cpp b/libopie/pim/odatebookaccessbackend_sql.cpp new file mode 100644 index 0000000..9769bf7 --- a/dev/null +++ b/libopie/pim/odatebookaccessbackend_sql.cpp @@ -0,0 +1,221 @@ +/* + * SQL Backend for the OPIE-Calender Database. + * + * Copyright (c) 2003 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2003/12/08 15:18:12 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <qarray.h> +#include <qstringlist.h> + +#include "orecur.h" +#include "odatebookaccessbackend_sql.h" + +#include <opie2/osqldriver.h> +#include <opie2/osqlresult.h> +#include <opie2/osqlmanager.h> +#include <opie2/osqlquery.h> + +namespace { + + + +}; + +ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& , + const QString& fileName ) + : ODateBookAccessBackend(), m_driver( NULL ) +{ + m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName; + + // Get the standart sql-driver from the OSQLManager.. + OSQLManager man; + m_driver = man.standard(); + m_driver->setUrl( m_fileName ); + + initFields(); + + load(); +} + +ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() { +} + +void ODateBookAccessBackend_SQL::initFields() +{ + + // This map contains the translation of the fieldtype id's to + // the names of the table columns + m_fieldMap.insert( OEvent::FUid, "uid" ); + m_fieldMap.insert( OEvent::FCategories, "Categories" ); + m_fieldMap.insert( OEvent::FDescription, "Description" ); + m_fieldMap.insert( OEvent::FLocation, "Location" ); + m_fieldMap.insert( OEvent::FType, "Type" ); + m_fieldMap.insert( OEvent::FAlarm, "Alarm" ); + m_fieldMap.insert( OEvent::FSound, "Sound" ); + m_fieldMap.insert( OEvent::FRType, "RType" ); + m_fieldMap.insert( OEvent::FRWeekdays, "RWeekdays" ); + m_fieldMap.insert( OEvent::FRPosition, "RPosition" ); + m_fieldMap.insert( OEvent::FRFreq, "RFreq" ); + m_fieldMap.insert( OEvent::FRHasEndDate, "RHasEndDate" ); + m_fieldMap.insert( OEvent::FREndDate, "REndDate" ); + m_fieldMap.insert( OEvent::FRCreated, "RCreated" ); + m_fieldMap.insert( OEvent::FRExeptions, "RExceptions" ); + m_fieldMap.insert( OEvent::FStart, "Start" ); + m_fieldMap.insert( OEvent::FEnd, "End" ); + m_fieldMap.insert( OEvent::FNote, "Note" ); + m_fieldMap.insert( OEvent::FTimeZone, "TimeZone" ); + m_fieldMap.insert( OEvent::FRecParent, "RecParent" ); + m_fieldMap.insert( OEvent::FRecChildren, "Recchildren" ); +} + +bool ODateBookAccessBackend_SQL::load() +{ + if (!m_driver->open() ) + return false; + + // Don't expect that the database exists. + // It is save here to create the table, even if it + // do exist. ( Is that correct for all databases ?? ) + QString qu = "create table datebook( uid INTEGER PRIMARY KEY "; + + QMap<int, QString>::Iterator it; + for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ + qu += QString( ",\"%1\" VARCHAR(10)" ).arg( it.data() ); + } + qu += " );"; + + qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ) + return false; + + update(); + + return true; +} + +void ODateBookAccessBackend_SQL::update() +{ + + QString qu = "select uid from datebook"; + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + m_uids.clear(); + return; + } + + m_uids = extractUids( res ); + +} + +QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const +{ + qWarning("extractUids"); + + OSQLResultItem::ValueList list = res.results(); + OSQLResultItem::ValueList::Iterator it; + QArray<int> ints(list.count() ); + qWarning(" count = %d", list.count() ); + + int i = 0; + for (it = list.begin(); it != list.end(); ++it ) { + ints[i] = (*it).data("uid").toInt(); + i++; + } + + return ints; + +} + +bool ODateBookAccessBackend_SQL::reload() +{ + return load(); +} + +bool ODateBookAccessBackend_SQL::save() +{ + return m_driver->close(); +} + +QArray<int> ODateBookAccessBackend_SQL::allRecords()const +{ + return m_uids; +} + +QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) { + return QArray<int>(); +} + +void ODateBookAccessBackend_SQL::clear() +{ + QString qu = "drop table datebook;"; + qu += "drop table custom_data;"; + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + +} + + +OEvent ODateBookAccessBackend_SQL::find( int uid ) const{ +} + +bool ODateBookAccessBackend_SQL::add( const OEvent& ev ) { + return true; +} +bool ODateBookAccessBackend_SQL::remove( int uid ) { + + return true; +} +bool ODateBookAccessBackend_SQL::replace( const OEvent& ev ) { + remove( ev.uid() ); + return add( ev ); +} +QArray<int> ODateBookAccessBackend_SQL::rawEvents()const { + return allRecords(); +} +QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const { + + return ints; +} +QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const { + + return ints; +} +OEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats() { + + return list; +} +OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats() { + + return list; +} + + +QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const +{ + + return m_currentQuery; +} diff --git a/libopie/pim/odatebookaccessbackend_sql.h b/libopie/pim/odatebookaccessbackend_sql.h new file mode 100644 index 0000000..85e0d4f --- a/dev/null +++ b/libopie/pim/odatebookaccessbackend_sql.h @@ -0,0 +1,60 @@ +#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H +#define OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H + +#include <qmap.h> + +#include "odatebookaccessbackend.h" + +class OSQLDriver; + +/** + * This is the default SQL implementation for DateBoook SQL storage + * It fully implements the interface + * @see ODateBookAccessBackend + * @see OPimAccessBackend + */ +class ODateBookAccessBackend_SQL : public ODateBookAccessBackend { +public: + ODateBookAccessBackend_SQL( const QString& appName, + const QString& fileName = QString::null); + ~ODateBookAccessBackend_SQL(); + + bool load(); + bool reload(); + bool save(); + + QArray<int> allRecords()const; + QArray<int> matchRegexp(const QRegExp &r) const; + QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); + OEvent find( int uid )const; + void clear(); + bool add( const OEvent& ev ); + bool remove( int uid ); + bool replace( const OEvent& ev ); + + QArray<UID> rawEvents()const; + QArray<UID> rawRepeats()const; + QArray<UID> nonRepeats()const; + + OEvent::ValueList directNonRepeats(); + OEvent::ValueList directRawRepeats(); + +private: + bool loadFile(); + QString m_fileName; + QArray<int> m_uids; + + QMap<int, QString> m_fieldMap; + + OSQLDriver* m_driver; + + class Private; + Private *d; + + void initFields(); + void update(); + QArray<int> extractUids( OSQLResult& res ) const; + +}; + +#endif diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp index 39c43c5..929d004 100644 --- a/libopie/pim/odatebookaccessbackend_xml.cpp +++ b/libopie/pim/odatebookaccessbackend_xml.cpp @@ -64,38 +64,40 @@ namespace { FDescription = 0, FLocation, FCategories, FUid, FType, FAlarm, FSound, FRType, FRWeekdays, FRPosition, FRFreq, FRHasEndDate, FREndDate, FRStart, FREnd, FNote, - FCreated, + FCreated, // Should't this be called FRCreated ? FTimeZone, FRecParent, FRecChildren, FExceptions }; + + // FIXME: Use OEvent::toMap() here !! (eilers) inline void save( const OEvent& ev, QString& buf ) { qWarning("Saving %d %s", ev.uid(), ev.description().latin1() ); buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; if (!ev.location().isEmpty() ) buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; buf += " uid=\"" + QString::number( ev.uid() ) + "\""; if (ev.isAllDay() ) buf += " type=\"AllDay\""; // is that all ?? (eilers) if (ev.hasNotifiers() ) { OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; @@ -262,33 +264,33 @@ bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { m_changed = true; if (ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); else m_raw.insert( ev.uid(), ev ); return true; } bool ODateBookAccessBackend_XML::remove( int uid ) { m_changed = true; m_rep.remove( uid ); m_rep.remove( uid ); return true; } bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) { - replace( ev.uid() ); + replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers) return add( ev ); } QArray<int> ODateBookAccessBackend_XML::rawEvents()const { return allRecords(); } QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { QArray<int> ints( m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; @@ -308,32 +310,34 @@ QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { OEvent::ValueList list; QMap<int, OEvent>::ConstIterator it; for (it = m_raw.begin(); it != m_raw.end(); ++it ) list.append( it.data() ); return list; } OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { OEvent::ValueList list; QMap<int, OEvent>::ConstIterator it; for (it = m_rep.begin(); it != m_rep.end(); ++it ) list.append( it.data() ); return list; } + +// FIXME: Use OEvent::fromMap() (eilers) bool ODateBookAccessBackend_XML::loadFile() { m_changed = false; int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); if ( fd < 0 ) return false; struct stat attribute; if ( ::fstat(fd, &attribute ) == -1 ) { ::close( fd ); return false; } void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if ( map_addr == ( (caddr_t)-1) ) { ::close( fd ); return false; } @@ -346,33 +350,33 @@ bool ODateBookAccessBackend_XML::loadFile() { dict.insert( "description", new int(FDescription) ); dict.insert( "location", new int(FLocation) ); dict.insert( "categories", new int(FCategories) ); dict.insert( "uid", new int(FUid) ); dict.insert( "type", new int(FType) ); dict.insert( "alarm", new int(FAlarm) ); dict.insert( "sound", new int(FSound) ); dict.insert( "rtype", new int(FRType) ); dict.insert( "rweekdays", new int(FRWeekdays) ); dict.insert( "rposition", new int(FRPosition) ); dict.insert( "rfreq", new int(FRFreq) ); dict.insert( "rhasenddate", new int(FRHasEndDate) ); dict.insert( "enddt", new int(FREndDate) ); dict.insert( "start", new int(FRStart) ); dict.insert( "end", new int(FREnd) ); dict.insert( "note", new int(FNote) ); - dict.insert( "created", new int(FCreated) ); + dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ?? dict.insert( "recparent", new int(FRecParent) ); dict.insert( "recchildren", new int(FRecChildren) ); dict.insert( "exceptions", new int(FExceptions) ); dict.insert( "timezone", new int(FTimeZone) ); char* dt = (char*)map_addr; int len = attribute.st_size; int i = 0; char* point; const char* collectionString = "<event "; int strLen = ::strlen(collectionString); int *find; while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { i = point -dt; i+= strLen; @@ -431,32 +435,34 @@ bool ODateBookAccessBackend_XML::loadFile() { find = dict[attr.data()]; if (!find) ev.setCustomField( attr, str ); else { setField( ev, *find, str ); } } /* time to finalize */ finalizeRecord( ev ); delete rec; } ::munmap(map_addr, attribute.st_size ); m_changed = false; // changed during add return true; } + +// FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers) void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { /* AllDay is alway in UTC */ if ( ev.isAllDay() ) { OTimeZone utc = OTimeZone::utc(); ev.setStartDateTime( utc.fromUTCDateTime( start ) ); ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); ev.setTimeZone( "UTC"); // make sure it is really utc }else { /* to current date time */ // qWarning(" Start is %d", start ); OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); QDateTime date = zone.toDateTime( start ); qWarning(" Start is %s", date.toString().latin1() ); ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); date = zone.toDateTime( end ); diff --git a/libopie/pim/oevent.cpp b/libopie/pim/oevent.cpp index 7bcf944..c916297 100644 --- a/libopie/pim/oevent.cpp +++ b/libopie/pim/oevent.cpp @@ -1,17 +1,18 @@ #include <qshared.h> +#include <qarray.h> #include <qpe/palmtopuidgen.h> #include <qpe/categories.h> #include <qpe/stringutil.h> #include "orecur.h" #include "opimresolver.h" #include "opimnotifymanager.h" #include "oevent.h" int OCalendarHelper::week( const QDate& date) { // Calculates the week this date is in within that // month. Equals the "row" is is in in the month view int week = 1; QDate tmp( date.year(), date.month(), 1 ); @@ -343,36 +344,162 @@ void OEvent::changeOrModify() { d2->parent = data->parent; if ( data->child ) { d2->child = new QArray<int>( *data->child ); d2->child->detach(); } data = d2; } } void OEvent::deref() { if ( data->deref() ) { delete data; data = 0; } } -// FIXME +// Exporting Event data to map. Using the same +// encoding as ODateBookAccessBackend_xml does.. +// Thus, we could remove the stuff there and use this +// for it and for all other places.. +// Encoding should happen at one place, only ! (eilers) QMap<int, QString> OEvent::toMap()const { - return QMap<int, QString>(); + QMap<int, QString> retMap; + + retMap.insert( OEvent::FUid, QString::number( uid() ) ); + retMap.insert( OEvent::FCategories, Qtopia::escapeString( Qtopia::Record::idsToString( categories() ) )); + retMap.insert( OEvent::FDescription, Qtopia::escapeString( description() ) ); + retMap.insert( OEvent::FLocation, Qtopia::escapeString( location() ) ); + retMap.insert( OEvent::FType, isAllDay() ? "AllDay" : "" ); + OPimAlarm alarm = notifiers().alarms()[0]; + retMap.insert( OEvent::FAlarm, QString::number( alarm.dateTime().secsTo( startDateTime() ) / 60 ) ); + retMap.insert( OEvent::FSound, (alarm.sound() == OPimAlarm::Loud) ? "loud" : "silent" ); + + OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); + retMap.insert( OEvent::FStart, QString::number( zone.fromUTCDateTime( zone.toDateTime( startDateTime(), OTimeZone::utc() ) ) ) ); + retMap.insert( OEvent::FEnd, QString::number( zone.fromUTCDateTime( zone.toDateTime( endDateTime(), OTimeZone::utc() ) ) ) ); + retMap.insert( OEvent::FNote, Qtopia::escapeString( note() ) ); + retMap.insert( OEvent::FTimeZone, timeZone().isEmpty() ? "None" : timeZone() ); + if( parent() ) + retMap.insert( OEvent::FRecParent, QString::number( parent() ) ); + if( children().count() ){ + QArray<int> childr = children(); + QString buf; + for ( uint i = 0; i < childr.count(); i++ ) { + if ( i != 0 ) buf += " "; + buf += QString::number( childr[i] ); + } + retMap.insert( OEvent::FRecChildren, buf ); + } + + // Add recurrence stuff + if( hasRecurrence() ){ + ORecur recur = recurrence(); + QMap<int, QString> recFields = recur.toMap(); + retMap.insert( OEvent::FRType, recFields[ORecur::RType] ); + retMap.insert( OEvent::FRWeekdays, recFields[ORecur::RWeekdays] ); + retMap.insert( OEvent::FRPosition, recFields[ORecur::RPosition] ); + retMap.insert( OEvent::FRFreq, recFields[ORecur::RFreq] ); + retMap.insert( OEvent::FRHasEndDate, recFields[ORecur::RHasEndDate] ); + retMap.insert( OEvent::FREndDate, recFields[ORecur::EndDate] ); + retMap.insert( OEvent::FRCreated, recFields[ORecur::Created] ); + retMap.insert( OEvent::FRExceptions, recFields[ORecur::Exceptions] ); + } + + return retMap; +} + +void OEvent::fromMap( const QMap<int, QString>& map ) +{ + + // We just want to set the UID if it is really stored. + if ( !map[OEvent::FUid].isEmpty() ) + setUid( map[OEvent::FUid].toInt() ); + + setCategories( idsFromString( map[OEvent::FCategories] ) ); + setDescription( map[OEvent::FDescription] ); + setLocation( map[OEvent::FLocation] ); + + if ( map[OEvent::FType] == "AllDay" ) + setAllDay( true ); + else + setAllDay( false ); + + int alarmTime = -1; + if( !map[OEvent::FAlarm].isEmpty() ) + alarmTime = map[OEvent::FAlarm].toInt(); + + int sound = ( ( map[OEvent::FSound] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent ); + if ( ( alarmTime != -1 ) ){ + QDateTime dt = startDateTime().addSecs( -1*alarmTime*60 ); + OPimAlarm al( sound , dt ); + notifiers().add( al ); + } + if ( !map[OEvent::FTimeZone].isEmpty() && ( map[OEvent::FTimeZone] != "None" ) ){ + setTimeZone( map[OEvent::FTimeZone] ); + } + + time_t start = (time_t) map[OEvent::FStart].toLong(); + time_t end = (time_t) map[OEvent::FEnd].toLong(); + + /* AllDay is always in UTC */ + if ( isAllDay() ) { + OTimeZone utc = OTimeZone::utc(); + setStartDateTime( utc.fromUTCDateTime( start ) ); + setEndDateTime ( utc.fromUTCDateTime( end ) ); + setTimeZone( "UTC"); // make sure it is really utc + }else { + /* to current date time */ + // qWarning(" Start is %d", start ); + OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); + QDateTime date = zone.toDateTime( start ); + qWarning(" Start is %s", date.toString().latin1() ); + setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); + + date = zone.toDateTime( end ); + setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); + } + + if ( !map[OEvent::FRecParent].isEmpty() ) + setParent( map[OEvent::FRecParent].toInt() ); + + if ( !map[OEvent::FRecChildren].isEmpty() ){ + QStringList list = QStringList::split(' ', map[OEvent::FRecChildren] ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + addChild( (*it).toInt() ); + } + } + + // Fill recurrence stuff and put it directly into the ORecur-Object using fromMap.. + if( !map[OEvent::FRType].isEmpty() ){ + QMap<int, QString> recFields; + recFields.insert( ORecur::RType, map[OEvent::FRType] ); + recFields.insert( ORecur::RWeekdays, map[OEvent::FRWeekdays] ); + recFields.insert( ORecur::RPosition, map[OEvent::FRPosition] ); + recFields.insert( ORecur::RFreq, map[OEvent::FRFreq] ); + recFields.insert( ORecur::RHasEndDate, map[OEvent::FRHasEndDate] ); + recFields.insert( ORecur::EndDate, map[OEvent::FREndDate] ); + recFields.insert( ORecur::Created, map[OEvent::FRCreated] ); + recFields.insert( ORecur::Exceptions, map[OEvent::FRExceptions] ); + ORecur recur( recFields ); + setRecurrence( recur ); + } + } + + int OEvent::parent()const { return data->parent; } void OEvent::setParent( int uid ) { changeOrModify(); data->parent = uid; } QArray<int> OEvent::children() const{ if (!data->child) return QArray<int>(); else return data->child->copy(); } void OEvent::setChildren( const QArray<int>& arr ) { changeOrModify(); if (data->child) delete data->child; diff --git a/libopie/pim/oevent.h b/libopie/pim/oevent.h index 30f442e..9218c97 100644 --- a/libopie/pim/oevent.h +++ b/libopie/pim/oevent.h @@ -28,66 +28,75 @@ struct OCalendarHelper { }; class OPimNotifyManager; class ORecur; /** * This is the container for all Events. It encapsules all * available information for a single Event * @short container for events. */ class OEvent : public OPimRecord { public: typedef QValueList<OEvent> ValueList; /** * RecordFields contain possible attributes + * used in the Results of toMap().. */ enum RecordFields { - Uid = Qtopia::UID_ID, - Category = Qtopia::CATEGORY_ID, - Description, - Location, - Alarm, - Reminder, - Recurrence, - Note, - Created, - StartDate, - EndDate, - AllDay, - TimeZone + FUid = Qtopia::UID_ID, + FCategories = Qtopia::CATEGORY_ID, + FDescription = 0, + FLocation, + FType, + FAlarm, + FSound, + FRType, + FRWeekdays, + FRPosition, + FRFreq, + FRHasEndDate, + FREndDate, + FRCreated, + FRExceptions, + FStart, + FEnd, + FNote, + FTimeZone, + FRecParent, + FRecChildren, }; /** * Start with an Empty OEvent. UID == 0 means that it is empty */ OEvent(int uid = 0); /** * copy c'tor */ OEvent( const OEvent& ); ~OEvent(); OEvent &operator=( const OEvent& ); QString description()const; void setDescription( const QString& description ); QString location()const; - void setLocation( const QString& loc ); + void setLocation( const QString& loc ); bool hasNotifiers()const; OPimNotifyManager ¬ifiers()const; ORecur recurrence()const; void setRecurrence( const ORecur& ); bool hasRecurrence()const; QString note()const; void setNote( const QString& note ); QDateTime createdDateTime()const; void setCreatedDateTime( const QDateTime& dt); /** set the date to dt. dt is the QDateTime in localtime */ @@ -119,32 +128,33 @@ public: QArray<int> children()const; void setChildren( const QArray<int>& ); void addChild( int uid ); void removeChild( int uid ); /** return the parent OEvent */ int parent()const; void setParent( int uid ); /* needed reimp */ QString toRichText()const; QString toShortText()const; QString type()const; QMap<int, QString> toMap()const; + void fromMap( const QMap<int, QString>& map ); QString recordField(int )const; static int rtti(); bool loadFromStream( QDataStream& ); bool saveToStream( QDataStream& )const; /* bool operator==( const OEvent& ); bool operator!=( const OEvent& ); bool operator<( const OEvent& ); bool operator<=( const OEvent& ); bool operator>( const OEvent& ); bool operator>=(const OEvent& ); */ private: inline void changeOrModify(); diff --git a/libopie/pim/orecur.cpp b/libopie/pim/orecur.cpp index 8c9ad46..f46f22e 100644 --- a/libopie/pim/orecur.cpp +++ b/libopie/pim/orecur.cpp @@ -21,32 +21,40 @@ struct ORecur::Data : public QShared { ORecur::RepeatType type; int freq; int pos; bool hasEnd : 1; QDate end; QDateTime create; int rep; QString app; ExceptionList list; QDate start; }; ORecur::ORecur() { data = new Data; } + +ORecur::ORecur( const QMap<int, QString>& map ) +{ + ORecur(); + fromMap( map ); +} + + ORecur::ORecur( const ORecur& rec) : data( rec.data ) { data->ref(); } ORecur::~ORecur() { if ( data->deref() ) { delete data; data = 0l; } } void ORecur::deref() { if ( data->deref() ) { delete data; data = 0l; } diff --git a/libopie/pim/orecur.h b/libopie/pim/orecur.h index 47901b0..7750c12 100644 --- a/libopie/pim/orecur.h +++ b/libopie/pim/orecur.h @@ -9,32 +9,33 @@ #include <qdatetime.h> #include <qvaluelist.h> #include <qmap.h> class ORecur { public: typedef QValueList<QDate> ExceptionList; enum RepeatType{ NoRepeat = -1, Daily, Weekly, MonthlyDay, MonthlyDate, Yearly }; enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08, FRI = 0x10, SAT = 0x20, SUN = 0x40 }; enum Fields{ RType = 0, RWeekdays, RPosition, RFreq, RHasEndDate, EndDate, Created, Exceptions }; ORecur(); + ORecur( const QMap<int, QString>& map ); ORecur( const ORecur& ); ~ORecur(); ORecur &operator=( const ORecur& ); bool operator==(const ORecur& )const; bool doesRecur()const; /* if it recurrs on that day */ bool doesRecur( const QDate& ); RepeatType type()const; int frequency()const; int position()const; char days()const; bool hasEndDate()const; QDate start()const; QDate endDate()const; diff --git a/libopie/pim/otodoaccesssql.cpp b/libopie/pim/otodoaccesssql.cpp index 3913661..75a0860 100644 --- a/libopie/pim/otodoaccesssql.cpp +++ b/libopie/pim/otodoaccesssql.cpp @@ -286,45 +286,48 @@ namespace { str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); return str; } QString EffQuery::out()const { QString str; str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); return str; } }; OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) - : OTodoAccessBackend(), m_dict(15), m_dirty(true) + : OTodoAccessBackend(), m_dict(15), m_driver(NULL), m_dirty(true) { QString fi = file; if ( fi.isEmpty() ) fi = Global::applicationFileName( "todolist", "todolist.db" ); OSQLManager man; m_driver = man.standard(); m_driver->setUrl(fi); // fillDict(); } OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ + if( m_driver ) + delete m_driver; } + bool OTodoAccessBackendSQL::load(){ if (!m_driver->open() ) return false; CreateQuery creat; OSQLResult res = m_driver->query(&creat ); m_dirty = true; return true; } bool OTodoAccessBackendSQL::reload(){ return load(); } bool OTodoAccessBackendSQL::save(){ return m_driver->close(); diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp index 132c9fc..dd9dbde 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.cpp @@ -1,32 +1,35 @@ /* * SQL Backend for the OPIE-Contact Database. * * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.3 2003/12/08 15:18:10 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * * Revision 1.2 2003/09/29 07:44:26 eilers * Improvement of PIM-SQL Databases, but search queries are still limited. * Addressbook: Changed table layout. Now, we just need 1/3 of disk-space. * Todo: Started to add new attributes. Some type conversions missing. * * Revision 1.1 2003/09/22 14:31:16 eilers * Added first experimental incarnation of sql-backend for addressbook. * Some modifications to be able to compile the todo sql-backend. * A lot of changes fill follow... * */ #include "ocontactaccessbackend_sql.h" #include <qarray.h> #include <qdatetime.h> @@ -441,54 +444,60 @@ namespace { QString FindCustomQuery::query()const{ // if ( m_uids.count() == 0 ) return single(); } QString FindCustomQuery::single()const{ QString qu = "select uid, type, value from custom_data where uid = "; qu += QString::number(m_uid); return qu; } }; /* --------------------------------------------------------------------------- */ OContactAccessBackend_SQL::OContactAccessBackend_SQL ( const QString& /* appname */, - const QString& filename ): m_changed(false) + const QString& filename ): + OContactAccessBackend(), m_changed(false), m_driver( NULL ) { qWarning("C'tor OContactAccessBackend_SQL starts"); QTime t; t.start(); /* Expecting to access the default filename if nothing else is set */ if ( filename.isEmpty() ){ m_fileName = Global::applicationFileName( "addressbook","addressbook.db" ); } else m_fileName = filename; // Get the standart sql-driver from the OSQLManager.. OSQLManager man; m_driver = man.standard(); m_driver->setUrl( m_fileName ); load(); qWarning("C'tor OContactAccessBackend_SQL ends: %d ms", t.elapsed() ); } +OContactAccessBackend_SQL::~OContactAccessBackend_SQL () +{ + if( m_driver ) + delete m_driver; +} bool OContactAccessBackend_SQL::load () { if (!m_driver->open() ) return false; // Don't expect that the database exists. // It is save here to create the table, even if it // do exist. ( Is that correct for all databases ?? ) CreateQuery creat; OSQLResult res = m_driver->query( &creat ); update(); return true; diff --git a/libopie2/opiepim/backend/ocontactaccessbackend_sql.h b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h index bb22551..b8f1d8d 100644 --- a/libopie2/opiepim/backend/ocontactaccessbackend_sql.h +++ b/libopie2/opiepim/backend/ocontactaccessbackend_sql.h @@ -3,63 +3,68 @@ * * Copyright (c) 2002 by Stefan Eilers (Eilers.Stefan@epost.de) * * ===================================================================== * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * ===================================================================== * * * ===================================================================== * Version: $Id$ * ===================================================================== * History: * $Log$ + * Revision 1.2 2003/12/08 15:18:11 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * * Revision 1.1 2003/09/22 14:31:16 eilers * Added first experimental incarnation of sql-backend for addressbook. * Some modifications to be able to compile the todo sql-backend. * A lot of changes fill follow... * * */ #ifndef _OContactAccessBackend_SQL_ #define _OContactAccessBackend_SQL_ #include "ocontactaccessbackend.h" #include "ocontactaccess.h" #include <qlist.h> #include <qdict.h> class OSQLDriver; class OSQLResult; class OSQLResultItem; /* the default xml implementation */ /** * This class is the SQL implementation of a Contact backend * it does implement everything available for OContact. * @see OPimAccessBackend for more information of available methods */ class OContactAccessBackend_SQL : public OContactAccessBackend { public: OContactAccessBackend_SQL ( const QString& appname, const QString& filename = QString::null ); + ~OContactAccessBackend_SQL (); + bool save(); bool load (); void clear (); bool wasChangedExternally(); QArray<int> allRecords() const; OContact find ( int uid ) const; // FIXME: Add lookahead-cache support ! //OContact find(int uid, const QArray<int>&, uint cur, Frontend::CacheDirection )const; QArray<int> queryByExample ( const OContact &query, int settings, const QDateTime& d ); diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp new file mode 100644 index 0000000..9769bf7 --- a/dev/null +++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.cpp @@ -0,0 +1,221 @@ +/* + * SQL Backend for the OPIE-Calender Database. + * + * Copyright (c) 2003 by Stefan Eilers (Eilers.Stefan@epost.de) + * + * ===================================================================== + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * ===================================================================== + * ===================================================================== + * Version: $Id$ + * ===================================================================== + * History: + * $Log$ + * Revision 1.1 2003/12/08 15:18:12 eilers + * Committing unfinished sql implementation before merging to libopie2 starts.. + * + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include <qarray.h> +#include <qstringlist.h> + +#include "orecur.h" +#include "odatebookaccessbackend_sql.h" + +#include <opie2/osqldriver.h> +#include <opie2/osqlresult.h> +#include <opie2/osqlmanager.h> +#include <opie2/osqlquery.h> + +namespace { + + + +}; + +ODateBookAccessBackend_SQL::ODateBookAccessBackend_SQL( const QString& , + const QString& fileName ) + : ODateBookAccessBackend(), m_driver( NULL ) +{ + m_fileName = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.db" ) : fileName; + + // Get the standart sql-driver from the OSQLManager.. + OSQLManager man; + m_driver = man.standard(); + m_driver->setUrl( m_fileName ); + + initFields(); + + load(); +} + +ODateBookAccessBackend_SQL::~ODateBookAccessBackend_SQL() { +} + +void ODateBookAccessBackend_SQL::initFields() +{ + + // This map contains the translation of the fieldtype id's to + // the names of the table columns + m_fieldMap.insert( OEvent::FUid, "uid" ); + m_fieldMap.insert( OEvent::FCategories, "Categories" ); + m_fieldMap.insert( OEvent::FDescription, "Description" ); + m_fieldMap.insert( OEvent::FLocation, "Location" ); + m_fieldMap.insert( OEvent::FType, "Type" ); + m_fieldMap.insert( OEvent::FAlarm, "Alarm" ); + m_fieldMap.insert( OEvent::FSound, "Sound" ); + m_fieldMap.insert( OEvent::FRType, "RType" ); + m_fieldMap.insert( OEvent::FRWeekdays, "RWeekdays" ); + m_fieldMap.insert( OEvent::FRPosition, "RPosition" ); + m_fieldMap.insert( OEvent::FRFreq, "RFreq" ); + m_fieldMap.insert( OEvent::FRHasEndDate, "RHasEndDate" ); + m_fieldMap.insert( OEvent::FREndDate, "REndDate" ); + m_fieldMap.insert( OEvent::FRCreated, "RCreated" ); + m_fieldMap.insert( OEvent::FRExeptions, "RExceptions" ); + m_fieldMap.insert( OEvent::FStart, "Start" ); + m_fieldMap.insert( OEvent::FEnd, "End" ); + m_fieldMap.insert( OEvent::FNote, "Note" ); + m_fieldMap.insert( OEvent::FTimeZone, "TimeZone" ); + m_fieldMap.insert( OEvent::FRecParent, "RecParent" ); + m_fieldMap.insert( OEvent::FRecChildren, "Recchildren" ); +} + +bool ODateBookAccessBackend_SQL::load() +{ + if (!m_driver->open() ) + return false; + + // Don't expect that the database exists. + // It is save here to create the table, even if it + // do exist. ( Is that correct for all databases ?? ) + QString qu = "create table datebook( uid INTEGER PRIMARY KEY "; + + QMap<int, QString>::Iterator it; + for ( it = ++m_fieldMap.begin(); it != m_fieldMap.end(); ++it ){ + qu += QString( ",\"%1\" VARCHAR(10)" ).arg( it.data() ); + } + qu += " );"; + + qu += "create table custom_data( uid INTEGER, id INTEGER, type VARCHAR, priority INTEGER, value VARCHAR, PRIMARY KEY /* identifier */ (uid, id) );"; + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ) + return false; + + update(); + + return true; +} + +void ODateBookAccessBackend_SQL::update() +{ + + QString qu = "select uid from datebook"; + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + if ( res.state() != OSQLResult::Success ){ + m_uids.clear(); + return; + } + + m_uids = extractUids( res ); + +} + +QArray<int> ODateBookAccessBackend_SQL::extractUids( OSQLResult& res ) const +{ + qWarning("extractUids"); + + OSQLResultItem::ValueList list = res.results(); + OSQLResultItem::ValueList::Iterator it; + QArray<int> ints(list.count() ); + qWarning(" count = %d", list.count() ); + + int i = 0; + for (it = list.begin(); it != list.end(); ++it ) { + ints[i] = (*it).data("uid").toInt(); + i++; + } + + return ints; + +} + +bool ODateBookAccessBackend_SQL::reload() +{ + return load(); +} + +bool ODateBookAccessBackend_SQL::save() +{ + return m_driver->close(); +} + +QArray<int> ODateBookAccessBackend_SQL::allRecords()const +{ + return m_uids; +} + +QArray<int> ODateBookAccessBackend_SQL::queryByExample(const OEvent&, int, const QDateTime& ) { + return QArray<int>(); +} + +void ODateBookAccessBackend_SQL::clear() +{ + QString qu = "drop table datebook;"; + qu += "drop table custom_data;"; + + OSQLRawQuery raw( qu ); + OSQLResult res = m_driver->query( &raw ); + +} + + +OEvent ODateBookAccessBackend_SQL::find( int uid ) const{ +} + +bool ODateBookAccessBackend_SQL::add( const OEvent& ev ) { + return true; +} +bool ODateBookAccessBackend_SQL::remove( int uid ) { + + return true; +} +bool ODateBookAccessBackend_SQL::replace( const OEvent& ev ) { + remove( ev.uid() ); + return add( ev ); +} +QArray<int> ODateBookAccessBackend_SQL::rawEvents()const { + return allRecords(); +} +QArray<int> ODateBookAccessBackend_SQL::rawRepeats()const { + + return ints; +} +QArray<int> ODateBookAccessBackend_SQL::nonRepeats()const { + + return ints; +} +OEvent::ValueList ODateBookAccessBackend_SQL::directNonRepeats() { + + return list; +} +OEvent::ValueList ODateBookAccessBackend_SQL::directRawRepeats() { + + return list; +} + + +QArray<int> ODateBookAccessBackend_SQL::matchRegexp( const QRegExp &r ) const +{ + + return m_currentQuery; +} diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_sql.h b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h new file mode 100644 index 0000000..85e0d4f --- a/dev/null +++ b/libopie2/opiepim/backend/odatebookaccessbackend_sql.h @@ -0,0 +1,60 @@ +#ifndef OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H +#define OPIE_DATE_BOOK_ACCESS_BACKEND_SQL__H + +#include <qmap.h> + +#include "odatebookaccessbackend.h" + +class OSQLDriver; + +/** + * This is the default SQL implementation for DateBoook SQL storage + * It fully implements the interface + * @see ODateBookAccessBackend + * @see OPimAccessBackend + */ +class ODateBookAccessBackend_SQL : public ODateBookAccessBackend { +public: + ODateBookAccessBackend_SQL( const QString& appName, + const QString& fileName = QString::null); + ~ODateBookAccessBackend_SQL(); + + bool load(); + bool reload(); + bool save(); + + QArray<int> allRecords()const; + QArray<int> matchRegexp(const QRegExp &r) const; + QArray<int> queryByExample( const OEvent&, int, const QDateTime& d = QDateTime() ); + OEvent find( int uid )const; + void clear(); + bool add( const OEvent& ev ); + bool remove( int uid ); + bool replace( const OEvent& ev ); + + QArray<UID> rawEvents()const; + QArray<UID> rawRepeats()const; + QArray<UID> nonRepeats()const; + + OEvent::ValueList directNonRepeats(); + OEvent::ValueList directRawRepeats(); + +private: + bool loadFile(); + QString m_fileName; + QArray<int> m_uids; + + QMap<int, QString> m_fieldMap; + + OSQLDriver* m_driver; + + class Private; + Private *d; + + void initFields(); + void update(); + QArray<int> extractUids( OSQLResult& res ) const; + +}; + +#endif diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp index 39c43c5..929d004 100644 --- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp +++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp @@ -64,38 +64,40 @@ namespace { FDescription = 0, FLocation, FCategories, FUid, FType, FAlarm, FSound, FRType, FRWeekdays, FRPosition, FRFreq, FRHasEndDate, FREndDate, FRStart, FREnd, FNote, - FCreated, + FCreated, // Should't this be called FRCreated ? FTimeZone, FRecParent, FRecChildren, FExceptions }; + + // FIXME: Use OEvent::toMap() here !! (eilers) inline void save( const OEvent& ev, QString& buf ) { qWarning("Saving %d %s", ev.uid(), ev.description().latin1() ); buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\""; if (!ev.location().isEmpty() ) buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\""; buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\""; buf += " uid=\"" + QString::number( ev.uid() ) + "\""; if (ev.isAllDay() ) buf += " type=\"AllDay\""; // is that all ?? (eilers) if (ev.hasNotifiers() ) { OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; @@ -262,33 +264,33 @@ bool ODateBookAccessBackend_XML::add( const OEvent& ev ) { m_changed = true; if (ev.hasRecurrence() ) m_rep.insert( ev.uid(), ev ); else m_raw.insert( ev.uid(), ev ); return true; } bool ODateBookAccessBackend_XML::remove( int uid ) { m_changed = true; m_rep.remove( uid ); m_rep.remove( uid ); return true; } bool ODateBookAccessBackend_XML::replace( const OEvent& ev ) { - replace( ev.uid() ); + replace( ev.uid() ); // ??? Shouldn't this be "remove( ev.uid() ) ??? (eilers) return add( ev ); } QArray<int> ODateBookAccessBackend_XML::rawEvents()const { return allRecords(); } QArray<int> ODateBookAccessBackend_XML::rawRepeats()const { QArray<int> ints( m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; for ( it = m_rep.begin(); it != m_rep.end(); ++it ) { ints[i] = it.key(); i++; } return ints; @@ -308,32 +310,34 @@ QArray<int> ODateBookAccessBackend_XML::nonRepeats()const { OEvent::ValueList ODateBookAccessBackend_XML::directNonRepeats() { OEvent::ValueList list; QMap<int, OEvent>::ConstIterator it; for (it = m_raw.begin(); it != m_raw.end(); ++it ) list.append( it.data() ); return list; } OEvent::ValueList ODateBookAccessBackend_XML::directRawRepeats() { OEvent::ValueList list; QMap<int, OEvent>::ConstIterator it; for (it = m_rep.begin(); it != m_rep.end(); ++it ) list.append( it.data() ); return list; } + +// FIXME: Use OEvent::fromMap() (eilers) bool ODateBookAccessBackend_XML::loadFile() { m_changed = false; int fd = ::open( QFile::encodeName(m_name).data(), O_RDONLY ); if ( fd < 0 ) return false; struct stat attribute; if ( ::fstat(fd, &attribute ) == -1 ) { ::close( fd ); return false; } void* map_addr = ::mmap(NULL, attribute.st_size, PROT_READ, MAP_SHARED, fd, 0 ); if ( map_addr == ( (caddr_t)-1) ) { ::close( fd ); return false; } @@ -346,33 +350,33 @@ bool ODateBookAccessBackend_XML::loadFile() { dict.insert( "description", new int(FDescription) ); dict.insert( "location", new int(FLocation) ); dict.insert( "categories", new int(FCategories) ); dict.insert( "uid", new int(FUid) ); dict.insert( "type", new int(FType) ); dict.insert( "alarm", new int(FAlarm) ); dict.insert( "sound", new int(FSound) ); dict.insert( "rtype", new int(FRType) ); dict.insert( "rweekdays", new int(FRWeekdays) ); dict.insert( "rposition", new int(FRPosition) ); dict.insert( "rfreq", new int(FRFreq) ); dict.insert( "rhasenddate", new int(FRHasEndDate) ); dict.insert( "enddt", new int(FREndDate) ); dict.insert( "start", new int(FRStart) ); dict.insert( "end", new int(FREnd) ); dict.insert( "note", new int(FNote) ); - dict.insert( "created", new int(FCreated) ); + dict.insert( "created", new int(FCreated) ); // Shouldn't this be FRCreated ?? dict.insert( "recparent", new int(FRecParent) ); dict.insert( "recchildren", new int(FRecChildren) ); dict.insert( "exceptions", new int(FExceptions) ); dict.insert( "timezone", new int(FTimeZone) ); char* dt = (char*)map_addr; int len = attribute.st_size; int i = 0; char* point; const char* collectionString = "<event "; int strLen = ::strlen(collectionString); int *find; while ( ( point = ::strstrlen( dt+i, len -i, collectionString, strLen ) ) != 0 ) { i = point -dt; i+= strLen; @@ -431,32 +435,34 @@ bool ODateBookAccessBackend_XML::loadFile() { find = dict[attr.data()]; if (!find) ev.setCustomField( attr, str ); else { setField( ev, *find, str ); } } /* time to finalize */ finalizeRecord( ev ); delete rec; } ::munmap(map_addr, attribute.st_size ); m_changed = false; // changed during add return true; } + +// FIXME: Use OEvent::fromMap() which makes this obsolete.. (eilers) void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) { /* AllDay is alway in UTC */ if ( ev.isAllDay() ) { OTimeZone utc = OTimeZone::utc(); ev.setStartDateTime( utc.fromUTCDateTime( start ) ); ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); ev.setTimeZone( "UTC"); // make sure it is really utc }else { /* to current date time */ // qWarning(" Start is %d", start ); OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); QDateTime date = zone.toDateTime( start ); qWarning(" Start is %s", date.toString().latin1() ); ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); date = zone.toDateTime( end ); diff --git a/libopie2/opiepim/backend/otodoaccesssql.cpp b/libopie2/opiepim/backend/otodoaccesssql.cpp index 3913661..75a0860 100644 --- a/libopie2/opiepim/backend/otodoaccesssql.cpp +++ b/libopie2/opiepim/backend/otodoaccesssql.cpp @@ -286,45 +286,48 @@ namespace { str = QString("select uid from todolist where ( DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6' ) OR DueDate = '0-0-0' ") .arg( m_start.year() ).arg( m_start.month() ).arg( m_start.day() ) .arg( m_end .year() ).arg( m_end .month() ).arg( m_end .day() ); return str; } QString EffQuery::out()const { QString str; str = QString("select uid from todolist where DueDate >= '%1-%2-%3' AND DueDate <= '%4-%5-%6'") .arg(m_start.year() ).arg(m_start.month() ).arg( m_start.day() ) .arg(m_end. year() ).arg(m_end. month() ).arg(m_end.day() ); return str; } }; OTodoAccessBackendSQL::OTodoAccessBackendSQL( const QString& file ) - : OTodoAccessBackend(), m_dict(15), m_dirty(true) + : OTodoAccessBackend(), m_dict(15), m_driver(NULL), m_dirty(true) { QString fi = file; if ( fi.isEmpty() ) fi = Global::applicationFileName( "todolist", "todolist.db" ); OSQLManager man; m_driver = man.standard(); m_driver->setUrl(fi); // fillDict(); } OTodoAccessBackendSQL::~OTodoAccessBackendSQL(){ + if( m_driver ) + delete m_driver; } + bool OTodoAccessBackendSQL::load(){ if (!m_driver->open() ) return false; CreateQuery creat; OSQLResult res = m_driver->query(&creat ); m_dirty = true; return true; } bool OTodoAccessBackendSQL::reload(){ return load(); } bool OTodoAccessBackendSQL::save(){ return m_driver->close(); diff --git a/libopie2/opiepim/core/orecur.cpp b/libopie2/opiepim/core/orecur.cpp index 8c9ad46..f46f22e 100644 --- a/libopie2/opiepim/core/orecur.cpp +++ b/libopie2/opiepim/core/orecur.cpp @@ -21,32 +21,40 @@ struct ORecur::Data : public QShared { ORecur::RepeatType type; int freq; int pos; bool hasEnd : 1; QDate end; QDateTime create; int rep; QString app; ExceptionList list; QDate start; }; ORecur::ORecur() { data = new Data; } + +ORecur::ORecur( const QMap<int, QString>& map ) +{ + ORecur(); + fromMap( map ); +} + + ORecur::ORecur( const ORecur& rec) : data( rec.data ) { data->ref(); } ORecur::~ORecur() { if ( data->deref() ) { delete data; data = 0l; } } void ORecur::deref() { if ( data->deref() ) { delete data; data = 0l; } diff --git a/libopie2/opiepim/core/orecur.h b/libopie2/opiepim/core/orecur.h index 47901b0..7750c12 100644 --- a/libopie2/opiepim/core/orecur.h +++ b/libopie2/opiepim/core/orecur.h @@ -9,32 +9,33 @@ #include <qdatetime.h> #include <qvaluelist.h> #include <qmap.h> class ORecur { public: typedef QValueList<QDate> ExceptionList; enum RepeatType{ NoRepeat = -1, Daily, Weekly, MonthlyDay, MonthlyDate, Yearly }; enum Days { MON = 0x01, TUE = 0x02, WED = 0x04, THU = 0x08, FRI = 0x10, SAT = 0x20, SUN = 0x40 }; enum Fields{ RType = 0, RWeekdays, RPosition, RFreq, RHasEndDate, EndDate, Created, Exceptions }; ORecur(); + ORecur( const QMap<int, QString>& map ); ORecur( const ORecur& ); ~ORecur(); ORecur &operator=( const ORecur& ); bool operator==(const ORecur& )const; bool doesRecur()const; /* if it recurrs on that day */ bool doesRecur( const QDate& ); RepeatType type()const; int frequency()const; int position()const; char days()const; bool hasEndDate()const; QDate start()const; QDate endDate()const; diff --git a/libopie2/opiepim/oevent.cpp b/libopie2/opiepim/oevent.cpp index 7bcf944..c916297 100644 --- a/libopie2/opiepim/oevent.cpp +++ b/libopie2/opiepim/oevent.cpp @@ -1,17 +1,18 @@ #include <qshared.h> +#include <qarray.h> #include <qpe/palmtopuidgen.h> #include <qpe/categories.h> #include <qpe/stringutil.h> #include "orecur.h" #include "opimresolver.h" #include "opimnotifymanager.h" #include "oevent.h" int OCalendarHelper::week( const QDate& date) { // Calculates the week this date is in within that // month. Equals the "row" is is in in the month view int week = 1; QDate tmp( date.year(), date.month(), 1 ); @@ -343,36 +344,162 @@ void OEvent::changeOrModify() { d2->parent = data->parent; if ( data->child ) { d2->child = new QArray<int>( *data->child ); d2->child->detach(); } data = d2; } } void OEvent::deref() { if ( data->deref() ) { delete data; data = 0; } } -// FIXME +// Exporting Event data to map. Using the same +// encoding as ODateBookAccessBackend_xml does.. +// Thus, we could remove the stuff there and use this +// for it and for all other places.. +// Encoding should happen at one place, only ! (eilers) QMap<int, QString> OEvent::toMap()const { - return QMap<int, QString>(); + QMap<int, QString> retMap; + + retMap.insert( OEvent::FUid, QString::number( uid() ) ); + retMap.insert( OEvent::FCategories, Qtopia::escapeString( Qtopia::Record::idsToString( categories() ) )); + retMap.insert( OEvent::FDescription, Qtopia::escapeString( description() ) ); + retMap.insert( OEvent::FLocation, Qtopia::escapeString( location() ) ); + retMap.insert( OEvent::FType, isAllDay() ? "AllDay" : "" ); + OPimAlarm alarm = notifiers().alarms()[0]; + retMap.insert( OEvent::FAlarm, QString::number( alarm.dateTime().secsTo( startDateTime() ) / 60 ) ); + retMap.insert( OEvent::FSound, (alarm.sound() == OPimAlarm::Loud) ? "loud" : "silent" ); + + OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); + retMap.insert( OEvent::FStart, QString::number( zone.fromUTCDateTime( zone.toDateTime( startDateTime(), OTimeZone::utc() ) ) ) ); + retMap.insert( OEvent::FEnd, QString::number( zone.fromUTCDateTime( zone.toDateTime( endDateTime(), OTimeZone::utc() ) ) ) ); + retMap.insert( OEvent::FNote, Qtopia::escapeString( note() ) ); + retMap.insert( OEvent::FTimeZone, timeZone().isEmpty() ? "None" : timeZone() ); + if( parent() ) + retMap.insert( OEvent::FRecParent, QString::number( parent() ) ); + if( children().count() ){ + QArray<int> childr = children(); + QString buf; + for ( uint i = 0; i < childr.count(); i++ ) { + if ( i != 0 ) buf += " "; + buf += QString::number( childr[i] ); + } + retMap.insert( OEvent::FRecChildren, buf ); + } + + // Add recurrence stuff + if( hasRecurrence() ){ + ORecur recur = recurrence(); + QMap<int, QString> recFields = recur.toMap(); + retMap.insert( OEvent::FRType, recFields[ORecur::RType] ); + retMap.insert( OEvent::FRWeekdays, recFields[ORecur::RWeekdays] ); + retMap.insert( OEvent::FRPosition, recFields[ORecur::RPosition] ); + retMap.insert( OEvent::FRFreq, recFields[ORecur::RFreq] ); + retMap.insert( OEvent::FRHasEndDate, recFields[ORecur::RHasEndDate] ); + retMap.insert( OEvent::FREndDate, recFields[ORecur::EndDate] ); + retMap.insert( OEvent::FRCreated, recFields[ORecur::Created] ); + retMap.insert( OEvent::FRExceptions, recFields[ORecur::Exceptions] ); + } + + return retMap; +} + +void OEvent::fromMap( const QMap<int, QString>& map ) +{ + + // We just want to set the UID if it is really stored. + if ( !map[OEvent::FUid].isEmpty() ) + setUid( map[OEvent::FUid].toInt() ); + + setCategories( idsFromString( map[OEvent::FCategories] ) ); + setDescription( map[OEvent::FDescription] ); + setLocation( map[OEvent::FLocation] ); + + if ( map[OEvent::FType] == "AllDay" ) + setAllDay( true ); + else + setAllDay( false ); + + int alarmTime = -1; + if( !map[OEvent::FAlarm].isEmpty() ) + alarmTime = map[OEvent::FAlarm].toInt(); + + int sound = ( ( map[OEvent::FSound] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent ); + if ( ( alarmTime != -1 ) ){ + QDateTime dt = startDateTime().addSecs( -1*alarmTime*60 ); + OPimAlarm al( sound , dt ); + notifiers().add( al ); + } + if ( !map[OEvent::FTimeZone].isEmpty() && ( map[OEvent::FTimeZone] != "None" ) ){ + setTimeZone( map[OEvent::FTimeZone] ); + } + + time_t start = (time_t) map[OEvent::FStart].toLong(); + time_t end = (time_t) map[OEvent::FEnd].toLong(); + + /* AllDay is always in UTC */ + if ( isAllDay() ) { + OTimeZone utc = OTimeZone::utc(); + setStartDateTime( utc.fromUTCDateTime( start ) ); + setEndDateTime ( utc.fromUTCDateTime( end ) ); + setTimeZone( "UTC"); // make sure it is really utc + }else { + /* to current date time */ + // qWarning(" Start is %d", start ); + OTimeZone zone( timeZone().isEmpty() ? OTimeZone::current() : timeZone() ); + QDateTime date = zone.toDateTime( start ); + qWarning(" Start is %s", date.toString().latin1() ); + setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); + + date = zone.toDateTime( end ); + setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); + } + + if ( !map[OEvent::FRecParent].isEmpty() ) + setParent( map[OEvent::FRecParent].toInt() ); + + if ( !map[OEvent::FRecChildren].isEmpty() ){ + QStringList list = QStringList::split(' ', map[OEvent::FRecChildren] ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + addChild( (*it).toInt() ); + } + } + + // Fill recurrence stuff and put it directly into the ORecur-Object using fromMap.. + if( !map[OEvent::FRType].isEmpty() ){ + QMap<int, QString> recFields; + recFields.insert( ORecur::RType, map[OEvent::FRType] ); + recFields.insert( ORecur::RWeekdays, map[OEvent::FRWeekdays] ); + recFields.insert( ORecur::RPosition, map[OEvent::FRPosition] ); + recFields.insert( ORecur::RFreq, map[OEvent::FRFreq] ); + recFields.insert( ORecur::RHasEndDate, map[OEvent::FRHasEndDate] ); + recFields.insert( ORecur::EndDate, map[OEvent::FREndDate] ); + recFields.insert( ORecur::Created, map[OEvent::FRCreated] ); + recFields.insert( ORecur::Exceptions, map[OEvent::FRExceptions] ); + ORecur recur( recFields ); + setRecurrence( recur ); + } + } + + int OEvent::parent()const { return data->parent; } void OEvent::setParent( int uid ) { changeOrModify(); data->parent = uid; } QArray<int> OEvent::children() const{ if (!data->child) return QArray<int>(); else return data->child->copy(); } void OEvent::setChildren( const QArray<int>& arr ) { changeOrModify(); if (data->child) delete data->child; diff --git a/libopie2/opiepim/oevent.h b/libopie2/opiepim/oevent.h index 30f442e..9218c97 100644 --- a/libopie2/opiepim/oevent.h +++ b/libopie2/opiepim/oevent.h @@ -28,66 +28,75 @@ struct OCalendarHelper { }; class OPimNotifyManager; class ORecur; /** * This is the container for all Events. It encapsules all * available information for a single Event * @short container for events. */ class OEvent : public OPimRecord { public: typedef QValueList<OEvent> ValueList; /** * RecordFields contain possible attributes + * used in the Results of toMap().. */ enum RecordFields { - Uid = Qtopia::UID_ID, - Category = Qtopia::CATEGORY_ID, - Description, - Location, - Alarm, - Reminder, - Recurrence, - Note, - Created, - StartDate, - EndDate, - AllDay, - TimeZone + FUid = Qtopia::UID_ID, + FCategories = Qtopia::CATEGORY_ID, + FDescription = 0, + FLocation, + FType, + FAlarm, + FSound, + FRType, + FRWeekdays, + FRPosition, + FRFreq, + FRHasEndDate, + FREndDate, + FRCreated, + FRExceptions, + FStart, + FEnd, + FNote, + FTimeZone, + FRecParent, + FRecChildren, }; /** * Start with an Empty OEvent. UID == 0 means that it is empty */ OEvent(int uid = 0); /** * copy c'tor */ OEvent( const OEvent& ); ~OEvent(); OEvent &operator=( const OEvent& ); QString description()const; void setDescription( const QString& description ); QString location()const; - void setLocation( const QString& loc ); + void setLocation( const QString& loc ); bool hasNotifiers()const; OPimNotifyManager ¬ifiers()const; ORecur recurrence()const; void setRecurrence( const ORecur& ); bool hasRecurrence()const; QString note()const; void setNote( const QString& note ); QDateTime createdDateTime()const; void setCreatedDateTime( const QDateTime& dt); /** set the date to dt. dt is the QDateTime in localtime */ @@ -119,32 +128,33 @@ public: QArray<int> children()const; void setChildren( const QArray<int>& ); void addChild( int uid ); void removeChild( int uid ); /** return the parent OEvent */ int parent()const; void setParent( int uid ); /* needed reimp */ QString toRichText()const; QString toShortText()const; QString type()const; QMap<int, QString> toMap()const; + void fromMap( const QMap<int, QString>& map ); QString recordField(int )const; static int rtti(); bool loadFromStream( QDataStream& ); bool saveToStream( QDataStream& )const; /* bool operator==( const OEvent& ); bool operator!=( const OEvent& ); bool operator<( const OEvent& ); bool operator<=( const OEvent& ); bool operator>( const OEvent& ); bool operator>=(const OEvent& ); */ private: inline void changeOrModify(); |