-rw-r--r-- | libopie/pim/odatebookaccessbackend_xml.cpp | 174 | ||||
-rw-r--r-- | libopie/pim/oevent.cpp | 64 | ||||
-rw-r--r-- | libopie/pim/oevent.h | 10 | ||||
-rw-r--r-- | libopie/pim/orecur.cpp | 66 | ||||
-rw-r--r-- | libopie/pim/orecur.h | 4 | ||||
-rw-r--r-- | libopie/pim/test/oevent_test.cpp | 10 |
6 files changed, 314 insertions, 14 deletions
diff --git a/libopie/pim/odatebookaccessbackend_xml.cpp b/libopie/pim/odatebookaccessbackend_xml.cpp index a4c514b..5239d84 100644 --- a/libopie/pim/odatebookaccessbackend_xml.cpp +++ b/libopie/pim/odatebookaccessbackend_xml.cpp @@ -1,20 +1,24 @@ #include <errno.h> #include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> + #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <unistd.h> #include <qasciidict.h> #include <qfile.h> #include <qtopia/global.h> #include <qtopia/stringutil.h> +#include <qtopia/timeconversion.h> #include "opimnotifymanager.h" #include "orecur.h" #include "otimezone.h" #include "odatebookaccessbackend_xml.h" @@ -43,14 +47,95 @@ namespace { FRFreq, FRHasEndDate, FREndDate, FRStart, FREnd, FNote, - FCreated + FCreated, + FTimeZone, + FRecParent, + FRecChildren, + FExceptions }; + inline void save( const OEvent& ev, QString& buf ) { + 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\""; + + if (ev.hasNotifiers() ) { + OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first + int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60; + buf += " alarm=\"" + QString::number(minutes) + "\" sound=\""; + if ( alarm.sound() == OPimAlarm::Loud ) + buf += "loud"; + else + buf += "silent"; + buf += "\""; + } + if ( ev.hasRecurrence() ) { + buf += ev.recurrence().toString(); + } + + /* + * fscking timezones :) well, we'll first convert + * the QDateTime to a QDateTime in UTC time + * and then we'll create a nice time_t + */ + OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); + buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\""; + buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\""; + if (!ev.note().isEmpty() ) { + buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\""; + } + + buf += " timezone=\""; + if ( ev.timeZone().isEmpty() ) + buf += "None"; + else + buf += ev.timeZone(); + + if (ev.parent() != 0 ) { + buf += " recparent=\""+QString::number(ev.parent() )+"\""; + } + + if (ev.children().count() != 0 ) { + QArray<int> children = ev.children(); + buf += " recchildren=\""; + for ( uint i = 0; i < children.count(); i++ ) { + if ( i != 0 ) buf += " "; + buf += QString::number( children[i] ); + } + buf+= "\""; + } + + // skip custom writing + } + + inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) { + QMap<int, OEvent>::ConstIterator it; + QString buf; + QCString str; + int total_written; + for ( it = list.begin(); it != list.end(); ++it ) { + buf = "<event"; + save( it.data(), buf ); + buf += " />\n"; + str = buf.utf8(); + + total_written = file.writeBlock(str.data(), str.length() ); + if ( total_written != int(str.length() ) ) + return false; + } + return true; + } } ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , const QString& fileName ) : ODateBookAccessBackend() { m_name = fileName.isEmpty() ? Global::applicationFileName( "datebook", "datebook.xml" ) : fileName; @@ -63,15 +148,60 @@ bool ODateBookAccessBackend_XML::load() { } bool ODateBookAccessBackend_XML::reload() { clear(); return load(); } bool ODateBookAccessBackend_XML::save() { - if (!m_changed) return true; - m_changed = false; + qWarning("going to save now"); +// if (!m_changed) return true; + + int total_written; + QString strFileNew = m_name + ".new"; + + QFile f( strFileNew ); + if (!f.open( IO_WriteOnly | IO_Raw ) ) return false; + + QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ); + buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n"; + buf += "<events>\n"; + QCString str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length() ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + + if (!forAll( m_raw, f ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + if (!forAll( m_rep, f ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + + buf = "</events>\n</DATEBOOK>\n"; + str = buf.utf8(); + total_written = f.writeBlock( str.data(), str.length() ); + if ( total_written != int(str.length() ) ) { + f.close(); + QFile::remove( strFileNew ); + return false; + } + f.close(); + + exit(0); + if ( ::rename( strFileNew, m_name ) < 0 ) { + QFile::remove( strFileNew ); + return false; + } + m_changed = false; return true; } QArray<int> ODateBookAccessBackend_XML::allRecords()const { QArray<int> ints( m_raw.count()+ m_rep.count() ); uint i = 0; QMap<int, OEvent>::ConstIterator it; @@ -180,13 +310,13 @@ bool ODateBookAccessBackend_XML::loadFile() { return false; } ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); ::close( fd ); - QAsciiDict<int> dict(FCreated+1); + QAsciiDict<int> dict(FExceptions+1); dict.setAutoDelete( true ); dict.insert( "description", new int(FDescription) ); dict.insert( "location", new int(FLocation) ); dict.insert( "categories", new int(FCategories) ); dict.insert( "uid", new int(FUid) ); dict.insert( "type", new int(FType) ); @@ -199,12 +329,16 @@ bool ODateBookAccessBackend_XML::loadFile() { 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( "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 "; @@ -286,16 +420,21 @@ bool ODateBookAccessBackend_XML::loadFile() { 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 */ OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); - ev.setStartDateTime( zone.toDateTime( start ) ); - ev.setEndDateTime ( zone.toDateTime( end ) ); + QDateTime date = zone.toDateTime( start ); + ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) ); + + date = zone.toDateTime( end ); + ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) ); } if ( rec && rec->doesRecur() ) { OTimeZone utc = OTimeZone::utc(); ORecur recu( *rec ); // call copy c'tor; recu.setEndDate ( utc.fromUTCDateTime( rp_end ).date() ); recu.setCreatedDateTime( utc.fromUTCDateTime( created ) ); @@ -386,10 +525,33 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val case FNote: e.setNote( value ); break; case FCreated: created = value.toInt(); break; + case FRecParent: + e.setParent( value.toInt() ); + break; + case FRecChildren:{ + QStringList list = QStringList::split(' ', value ); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + e.addChild( (*it).toInt() ); + } + } + break; + case FExceptions:{ + QStringList list = QStringList::split(' ', value ); + for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() ); + qWarning("adding exception %s", date.toString().latin1() ); + recur()->exceptions().append( date ); + } + } + break; + case FTimeZone: + if ( value != "None" ) + e.setTimeZone( value ); + break; default: break; } } diff --git a/libopie/pim/oevent.cpp b/libopie/pim/oevent.cpp index ada596c..c3eeee2 100644 --- a/libopie/pim/oevent.cpp +++ b/libopie/pim/oevent.cpp @@ -39,15 +39,17 @@ int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) { return ( second.year() - first.year() ) * 12 + second.month() - first.month(); } struct OEvent::Data : public QShared { Data() : QShared() { + child = 0; recur = 0; manager = 0; isAllDay = false; + parent = 0; } ~Data() { delete manager; delete recur; } QString description; @@ -57,12 +59,14 @@ struct OEvent::Data : public QShared { QString note; QDateTime created; QDateTime start; QDateTime end; bool isAllDay : 1; QString timezone; + QArray<int>* child; + int parent; }; OEvent::OEvent( int uid ) : OPimRecord( uid ) { data = new Data; } @@ -99,23 +103,29 @@ void OEvent::setLocation( const QString& loc ) { changeOrModify(); data->location = loc; } QString OEvent::location()const { return data->location; } -OPimNotifyManager &OEvent::notifiers() { +OPimNotifyManager &OEvent::notifiers()const { // I hope we can skip the changeOrModify here // the notifier should take care of it // and OPimNotify is shared too if (!data->manager ) data->manager = new OPimNotifyManager; return *data->manager; } bool OEvent::hasNotifiers()const { - return ( data->manager); + if (!data->manager ) + return false; + if (data->manager->reminders().isEmpty() && + data->manager->alarms().isEmpty() ) + return false; + + return true; } ORecur OEvent::recurrence()const { if (!data->recur) data->recur = new ORecur; return *data->recur; @@ -194,12 +204,13 @@ void OEvent::setAllDay( bool allDay ) { } void OEvent::setTimeZone( const QString& tz ) { changeOrModify(); data->timezone = tz; } QString OEvent::timeZone()const { + if (data->isAllDay ) return QString::fromLatin1("UTC"); return data->timezone; } bool OEvent::match( const QRegExp& )const { // FIXME return false; } @@ -236,12 +247,17 @@ void OEvent::changeOrModify() { d2->note = data->note; d2->created = data->created; d2->start = data->start; d2->end = data->end; d2->isAllDay = data->isAllDay; d2->timezone = data->timezone; + d2->parent = data->parent; + d2->child = data->child; + + if (d2->child ) + d2->child->detach(); data = d2; } } void OEvent::deref() { if ( data->deref() ) { @@ -253,14 +269,56 @@ void OEvent::deref() { QMap<int, QString> OEvent::toMap()const { return QMap<int, QString>(); } QMap<QString, QString> OEvent::toExtraMap()const { return QMap<QString, QString>(); } +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; - + data->child = new QArray<int>( arr ); + data->child->detach(); +} +void OEvent::addChild( int uid ) { + changeOrModify(); + if (!data->child ) { + data->child = new QArray<int>(1); + (*data->child)[0] = uid; + }else{ + int count = data->child->count(); + data->child->resize( count + 1 ); + (*data->child)[count] = uid; + } +} +void OEvent::removeChild( int uid ) { + if (!data->child || !data->child->contains( uid ) ) return; + changeOrModify(); + QArray<int> newAr( data->child->count() - 1 ); + int j = 0; + uint count = data->child->count(); + for ( uint i = 0; i < count; i++ ) { + if ( (*data->child)[i] != uid ) { + newAr[j] = (*data->child)[i]; + j++; + } + } + (*data->child) = newAr; +} struct OEffectiveEvent::Data : public QShared { Data() : QShared() { } OEvent event; QDate date; QTime start, end; diff --git a/libopie/pim/oevent.h b/libopie/pim/oevent.h index c718e2e..585515c 100644 --- a/libopie/pim/oevent.h +++ b/libopie/pim/oevent.h @@ -58,13 +58,13 @@ public: void setDescription( const QString& description ); QString location()const; void setLocation( const QString& loc ); bool hasNotifiers()const; - OPimNotifyManager ¬ifiers(); + OPimNotifyManager ¬ifiers()const; ORecur recurrence()const; void setRecurrence( const ORecur& ); bool hasRecurrence()const; QString note()const; @@ -96,13 +96,21 @@ public: void setTimeZone( const QString& timeZone ); QString timeZone()const; bool match( const QRegExp& )const; + /** For exception to recurrence here is a list of children... */ + 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; diff --git a/libopie/pim/orecur.cpp b/libopie/pim/orecur.cpp index e6a4787..e3b45b4 100644 --- a/libopie/pim/orecur.cpp +++ b/libopie/pim/orecur.cpp @@ -1,10 +1,13 @@ +#include <time.h> + #include <qshared.h> #include <qtopia/timeconversion.h> +#include "otimezone.h" #include "orecur.h" struct ORecur::Data : public QShared { Data() : QShared() { type = ORecur::NoRepeat; freq = -1; @@ -78,12 +81,20 @@ bool ORecur::doesRecur( const QDate& date ) { return (recur == date); } // FIXME unuglify! // GPL from Datebookdb.cpp // FIXME exception list! bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { + bool stillLooking; + stillLooking = p_nextOccurrence( from, next ); + while ( stillLooking && data->list.contains(next) ) + stillLooking = p_nextOccurrence( next.addDays(1), next ); + + return stillLooking; +} +bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) { // easy checks, first are we too far in the future or too far in the past? QDate tmpDate; int freq = frequency(); int diff, diff2, a; int iday, imonth, iyear; @@ -440,7 +451,60 @@ void ORecur::checkOrModify() { d2->app = data->app; d2->list = data->list; d2->start = data->start; data = d2; } } - +QString ORecur::toString()const { + QString buf; + + buf += " rtype=\""; + switch ( data->type ) { + case ORecur::Daily: + buf += "Daily"; + break; + case ORecur::Weekly: + buf += "Weekly"; + break; + case ORecur::MonthlyDay: + buf += "MonthlyDay"; + break; + case ORecur::MonthlyDate: + buf += "MonthlyDate"; + break; + case ORecur::Yearly: + buf += "Yearly"; + break; + default: + buf += "NoRepeat"; + break; + } + buf += "\""; + if (data->days > 0 ) + buf += " rweekdays=\"" + QString::number( static_cast<int>( data->days ) ) + "\""; + if ( data->pos != 0 ) + buf += " rposition=\"" + QString::number(data->pos ) + "\""; + + buf += " rfreq=\"" + QString::number( data->freq ) + "\""; + buf += " rhasenddate=\"" + QString::number( static_cast<int>( data->hasEnd ) ) + "\""; + if ( data->hasEnd ) + buf += " enddt=\"" + + QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) + + "\""; + buf += " created=\"" + QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) + "\""; + + if ( data->list.isEmpty() ) return buf; + // save exceptions list here!! + ExceptionList::ConstIterator it; + ExceptionList list = data->list; + buf += " exceptions=\""; + QDate date; + for ( it = list.begin(); it != list.end(); ++it ) { + date = (*it); + if ( it != list.begin() ) buf += " "; + + buf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() ); + } + buf += "\""; + + return buf; +} diff --git a/libopie/pim/orecur.h b/libopie/pim/orecur.h index 1e0014b..b214b3f 100644 --- a/libopie/pim/orecur.h +++ b/libopie/pim/orecur.h @@ -70,13 +70,17 @@ public: void setStart( const QDate& dt ); void setCreatedDateTime( const QDateTime& ); void setHasEndDate( bool b ); void setRepitition(int ); void setService( const QString& ser ); + + /* almost internal */ + QString toString()const; private: + bool p_nextOccurrence( const QDate& from, QDate& next ); void deref(); inline void checkOrModify(); class Data; Data* data; diff --git a/libopie/pim/test/oevent_test.cpp b/libopie/pim/test/oevent_test.cpp index 6f04995..247b83b 100644 --- a/libopie/pim/test/oevent_test.cpp +++ b/libopie/pim/test/oevent_test.cpp @@ -2,27 +2,28 @@ #include "../oevent.h" #include "../odatebookaccess.h" int main(int argc, char* argv ) { OEvent ev; - ev.setUid( 20 ); +// ev.setUid( 20 ); - ev.setDescription( "Foo" ); + ev.setDescription( "Foo Descsfewrf" ); OEvent ev2 = ev; - ev2.setDescription("Foo2"); + ev2.setDescription("Foo3"); qWarning("%s", ev2.description().latin1() ); qWarning("%s", ev.description().latin1() ); QDateTime time = QDateTime::currentDateTime(); ev2.setStartDateTime( time ); ev2.setTimeZone( "Europe/London" ); qWarning("%s", ev2.startDateTime().toString().latin1() ); qWarning("%s", ev2.startDateTimeInZone().toString().latin1() ); + qWarning("%d %d", ev.isAllDay(), ev2.isAllDay() ); ODateBookAccess acc; if(!acc.load() ) qWarning("could not load"); ODateBookAccess::List::Iterator it; ODateBookAccess::List list = acc.allRecords(); @@ -42,9 +43,12 @@ int main(int argc, char* argv ) { for( effIt = effList.begin(); effIt != effList.end(); ++effIt ){ OEffectiveEvent ef = (*effIt); qWarning("Summary: %s", ef.description().latin1() ); qWarning("Date: %s", ef.date().toString().latin1() ); } + ev.setUid( 1 ); + acc.add( ev ); + acc.save(); return 0; } |