summaryrefslogtreecommitdiff
authorzecke <zecke>2003-02-22 16:11:16 (UTC)
committer zecke <zecke>2003-02-22 16:11:16 (UTC)
commit397a7b1635488deda02b36df70692e27f59bb3e0 (patch) (side-by-side diff)
tree1232b1b7e8ac84c5d48df79b635ba61acbdf0f62
parente7981098a5c373748d98158e8a6c59750bb0d7dc (diff)
downloadopie-397a7b1635488deda02b36df70692e27f59bb3e0.zip
opie-397a7b1635488deda02b36df70692e27f59bb3e0.tar.gz
opie-397a7b1635488deda02b36df70692e27f59bb3e0.tar.bz2
Implement saving of events
Implement the ExceptionList Add Children and parent to OEvent Make ORecur honor exceptions Extend the test app to add and save
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.cpp184
-rw-r--r--libopie/pim/oevent.cpp64
-rw-r--r--libopie/pim/oevent.h10
-rw-r--r--libopie/pim/orecur.cpp66
-rw-r--r--libopie/pim/orecur.h4
-rw-r--r--libopie/pim/test/oevent_test.cpp10
-rw-r--r--libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp184
-rw-r--r--libopie2/opiepim/core/orecur.cpp66
-rw-r--r--libopie2/opiepim/core/orecur.h4
-rw-r--r--libopie2/opiepim/oevent.cpp64
-rw-r--r--libopie2/opiepim/oevent.h10
11 files changed, 631 insertions, 35 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,7 +1,10 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -11,8 +14,9 @@
#include <qfile.h>
#include <qtopia/global.h>
#include <qtopia/stringutil.h>
+#include <qtopia/timeconversion.h>
#include "opimnotifymanager.h"
#include "orecur.h"
#include "otimezone.h"
@@ -29,13 +33,13 @@ namespace {
}
int alarmTime;
int snd;
enum Attribute{
- FDescription = 0,
- FLocation,
- FCategories,
- FUid,
- FType,
+ FDescription = 0,
+ FLocation,
+ FCategories,
+ FUid,
+ FType,
FAlarm,
FSound,
FRType,
FRWeekdays,
@@ -45,10 +49,91 @@ namespace {
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 )
@@ -65,11 +150,56 @@ 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() );
@@ -182,9 +312,9 @@ bool ODateBookAccessBackend_XML::loadFile() {
::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) );
@@ -201,8 +331,12 @@ bool ODateBookAccessBackend_XML::loadFile() {
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;
@@ -288,12 +422,17 @@ void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
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;
@@ -388,8 +527,31 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val
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
@@ -41,11 +41,13 @@ int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) {
}
struct OEvent::Data : public QShared {
Data() : QShared() {
+ child = 0;
recur = 0;
manager = 0;
isAllDay = false;
+ parent = 0;
}
~Data() {
delete manager;
delete recur;
@@ -59,8 +61,10 @@ struct OEvent::Data : public QShared {
QDateTime start;
QDateTime end;
bool isAllDay : 1;
QString timezone;
+ QArray<int>* child;
+ int parent;
};
OEvent::OEvent( int uid )
: OPimRecord( uid ) {
@@ -101,9 +105,9 @@ void OEvent::setLocation( const QString& 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 )
@@ -111,9 +115,15 @@ OPimNotifyManager &OEvent::notifiers() {
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;
@@ -196,8 +206,9 @@ 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
@@ -238,8 +249,13 @@ void OEvent::changeOrModify() {
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;
}
}
@@ -255,10 +271,52 @@ QMap<int, QString> OEvent::toMap()const {
}
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;
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
@@ -60,9 +60,9 @@ public:
QString location()const;
void setLocation( const QString& loc );
bool hasNotifiers()const;
- OPimNotifyManager &notifiers();
+ OPimNotifyManager &notifiers()const;
ORecur recurrence()const;
void setRecurrence( const ORecur& );
bool hasRecurrence()const;
@@ -98,9 +98,17 @@ public:
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;
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,8 +1,11 @@
+#include <time.h>
+
#include <qshared.h>
#include <qtopia/timeconversion.h>
+#include "otimezone.h"
#include "orecur.h"
struct ORecur::Data : public QShared {
Data() : QShared() {
@@ -80,8 +83,16 @@ bool ORecur::doesRecur( const QDate& 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();
@@ -94,9 +105,9 @@ bool ORecur::nextOcurrence( const QDate& from, QDate& next ) {
if (hasEndDate() && endDate() < from)
return FALSE;
- if (start() >= from) {
+ if (start() >= from ) {
next = start();
return TRUE;
}
@@ -442,5 +453,58 @@ void ORecur::checkOrModify() {
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
@@ -72,9 +72,13 @@ public:
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();
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
@@ -4,14 +4,14 @@
#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();
@@ -19,8 +19,9 @@ int main(int argc, char* argv ) {
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");
@@ -44,7 +45,10 @@ int main(int argc, char* argv ) {
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;
}
diff --git a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
index a4c514b..5239d84 100644
--- a/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
+++ b/libopie2/opiepim/backend/odatebookaccessbackend_xml.cpp
@@ -1,7 +1,10 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -11,8 +14,9 @@
#include <qfile.h>
#include <qtopia/global.h>
#include <qtopia/stringutil.h>
+#include <qtopia/timeconversion.h>
#include "opimnotifymanager.h"
#include "orecur.h"
#include "otimezone.h"
@@ -29,13 +33,13 @@ namespace {
}
int alarmTime;
int snd;
enum Attribute{
- FDescription = 0,
- FLocation,
- FCategories,
- FUid,
- FType,
+ FDescription = 0,
+ FLocation,
+ FCategories,
+ FUid,
+ FType,
FAlarm,
FSound,
FRType,
FRWeekdays,
@@ -45,10 +49,91 @@ namespace {
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 )
@@ -65,11 +150,56 @@ 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() );
@@ -182,9 +312,9 @@ bool ODateBookAccessBackend_XML::loadFile() {
::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) );
@@ -201,8 +331,12 @@ bool ODateBookAccessBackend_XML::loadFile() {
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;
@@ -288,12 +422,17 @@ void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
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;
@@ -388,8 +527,31 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val
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/libopie2/opiepim/core/orecur.cpp b/libopie2/opiepim/core/orecur.cpp
index e6a4787..e3b45b4 100644
--- a/libopie2/opiepim/core/orecur.cpp
+++ b/libopie2/opiepim/core/orecur.cpp
@@ -1,8 +1,11 @@
+#include <time.h>
+
#include <qshared.h>
#include <qtopia/timeconversion.h>
+#include "otimezone.h"
#include "orecur.h"
struct ORecur::Data : public QShared {
Data() : QShared() {
@@ -80,8 +83,16 @@ bool ORecur::doesRecur( const QDate& 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();
@@ -94,9 +105,9 @@ bool ORecur::nextOcurrence( const QDate& from, QDate& next ) {
if (hasEndDate() && endDate() < from)
return FALSE;
- if (start() >= from) {
+ if (start() >= from ) {
next = start();
return TRUE;
}
@@ -442,5 +453,58 @@ void ORecur::checkOrModify() {
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/libopie2/opiepim/core/orecur.h b/libopie2/opiepim/core/orecur.h
index 1e0014b..b214b3f 100644
--- a/libopie2/opiepim/core/orecur.h
+++ b/libopie2/opiepim/core/orecur.h
@@ -72,9 +72,13 @@ public:
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();
diff --git a/libopie2/opiepim/oevent.cpp b/libopie2/opiepim/oevent.cpp
index ada596c..c3eeee2 100644
--- a/libopie2/opiepim/oevent.cpp
+++ b/libopie2/opiepim/oevent.cpp
@@ -41,11 +41,13 @@ int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) {
}
struct OEvent::Data : public QShared {
Data() : QShared() {
+ child = 0;
recur = 0;
manager = 0;
isAllDay = false;
+ parent = 0;
}
~Data() {
delete manager;
delete recur;
@@ -59,8 +61,10 @@ struct OEvent::Data : public QShared {
QDateTime start;
QDateTime end;
bool isAllDay : 1;
QString timezone;
+ QArray<int>* child;
+ int parent;
};
OEvent::OEvent( int uid )
: OPimRecord( uid ) {
@@ -101,9 +105,9 @@ void OEvent::setLocation( const QString& 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 )
@@ -111,9 +115,15 @@ OPimNotifyManager &OEvent::notifiers() {
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;
@@ -196,8 +206,9 @@ 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
@@ -238,8 +249,13 @@ void OEvent::changeOrModify() {
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;
}
}
@@ -255,10 +271,52 @@ QMap<int, QString> OEvent::toMap()const {
}
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;
diff --git a/libopie2/opiepim/oevent.h b/libopie2/opiepim/oevent.h
index c718e2e..585515c 100644
--- a/libopie2/opiepim/oevent.h
+++ b/libopie2/opiepim/oevent.h
@@ -60,9 +60,9 @@ public:
QString location()const;
void setLocation( const QString& loc );
bool hasNotifiers()const;
- OPimNotifyManager &notifiers();
+ OPimNotifyManager &notifiers()const;
ORecur recurrence()const;
void setRecurrence( const ORecur& );
bool hasRecurrence()const;
@@ -98,9 +98,17 @@ public:
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;