summaryrefslogtreecommitdiff
authorzecke <zecke>2003-02-22 16:11:16 (UTC)
committer zecke <zecke>2003-02-22 16:11:16 (UTC)
commit397a7b1635488deda02b36df70692e27f59bb3e0 (patch) (unidiff)
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) (show whitespace changes)
-rw-r--r--libopie/pim/odatebookaccessbackend_xml.cpp174
-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.cpp174
-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, 621 insertions, 25 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,6 +1,9 @@
1#include <errno.h> 1#include <errno.h>
2#include <fcntl.h> 2#include <fcntl.h>
3 3
4#include <stdio.h>
5#include <stdlib.h>
6
4#include <sys/types.h> 7#include <sys/types.h>
5#include <sys/mman.h> 8#include <sys/mman.h>
6#include <sys/stat.h> 9#include <sys/stat.h>
@@ -12,6 +15,7 @@
12 15
13#include <qtopia/global.h> 16#include <qtopia/global.h>
14#include <qtopia/stringutil.h> 17#include <qtopia/stringutil.h>
18#include <qtopia/timeconversion.h>
15 19
16#include "opimnotifymanager.h" 20#include "opimnotifymanager.h"
17#include "orecur.h" 21#include "orecur.h"
@@ -46,8 +50,89 @@ namespace {
46 FRStart, 50 FRStart,
47 FREnd, 51 FREnd,
48 FNote, 52 FNote,
49 FCreated 53 FCreated,
54 FTimeZone,
55 FRecParent,
56 FRecChildren,
57 FExceptions
50 }; 58 };
59 inline void save( const OEvent& ev, QString& buf ) {
60 buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\"";
61 if (!ev.location().isEmpty() )
62 buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\"";
63
64 buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\"";
65 buf += " uid=\"" + QString::number( ev.uid() ) + "\"";
66
67 if (ev.isAllDay() )
68 buf += " type=\"AllDay\"";
69
70 if (ev.hasNotifiers() ) {
71 OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first
72 int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60;
73 buf += " alarm=\"" + QString::number(minutes) + "\" sound=\"";
74 if ( alarm.sound() == OPimAlarm::Loud )
75 buf += "loud";
76 else
77 buf += "silent";
78 buf += "\"";
79 }
80 if ( ev.hasRecurrence() ) {
81 buf += ev.recurrence().toString();
82 }
83
84 /*
85 * fscking timezones :) well, we'll first convert
86 * the QDateTime to a QDateTime in UTC time
87 * and then we'll create a nice time_t
88 */
89 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
90 buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\"";
91 buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\"";
92 if (!ev.note().isEmpty() ) {
93 buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\"";
94 }
95
96 buf += " timezone=\"";
97 if ( ev.timeZone().isEmpty() )
98 buf += "None";
99 else
100 buf += ev.timeZone();
101
102 if (ev.parent() != 0 ) {
103 buf += " recparent=\""+QString::number(ev.parent() )+"\"";
104 }
105
106 if (ev.children().count() != 0 ) {
107 QArray<int> children = ev.children();
108 buf += " recchildren=\"";
109 for ( uint i = 0; i < children.count(); i++ ) {
110 if ( i != 0 ) buf += " ";
111 buf += QString::number( children[i] );
112 }
113 buf+= "\"";
114 }
115
116 // skip custom writing
117 }
118
119 inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) {
120 QMap<int, OEvent>::ConstIterator it;
121 QString buf;
122 QCString str;
123 int total_written;
124 for ( it = list.begin(); it != list.end(); ++it ) {
125 buf = "<event";
126 save( it.data(), buf );
127 buf += " />\n";
128 str = buf.utf8();
129
130 total_written = file.writeBlock(str.data(), str.length() );
131 if ( total_written != int(str.length() ) )
132 return false;
133 }
134 return true;
135 }
51} 136}
52 137
53ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , 138ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& ,
@@ -66,9 +151,54 @@ bool ODateBookAccessBackend_XML::reload() {
66 return load(); 151 return load();
67} 152}
68bool ODateBookAccessBackend_XML::save() { 153bool ODateBookAccessBackend_XML::save() {
69 if (!m_changed) return true; 154 qWarning("going to save now");
70 m_changed = false; 155// if (!m_changed) return true;
156
157 int total_written;
158 QString strFileNew = m_name + ".new";
159
160 QFile f( strFileNew );
161 if (!f.open( IO_WriteOnly | IO_Raw ) ) return false;
162
163 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
164 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
165 buf += "<events>\n";
166 QCString str = buf.utf8();
167 total_written = f.writeBlock( str.data(), str.length() );
168 if ( total_written != int(str.length() ) ) {
169 f.close();
170 QFile::remove( strFileNew );
171 return false;
172 }
173
174 if (!forAll( m_raw, f ) ) {
175 f.close();
176 QFile::remove( strFileNew );
177 return false;
178 }
179 if (!forAll( m_rep, f ) ) {
180 f.close();
181 QFile::remove( strFileNew );
182 return false;
183 }
184
185 buf = "</events>\n</DATEBOOK>\n";
186 str = buf.utf8();
187 total_written = f.writeBlock( str.data(), str.length() );
188 if ( total_written != int(str.length() ) ) {
189 f.close();
190 QFile::remove( strFileNew );
191 return false;
192 }
193 f.close();
194
195 exit(0);
196 if ( ::rename( strFileNew, m_name ) < 0 ) {
197 QFile::remove( strFileNew );
198 return false;
199 }
71 200
201 m_changed = false;
72 return true; 202 return true;
73} 203}
74QArray<int> ODateBookAccessBackend_XML::allRecords()const { 204QArray<int> ODateBookAccessBackend_XML::allRecords()const {
@@ -183,7 +313,7 @@ bool ODateBookAccessBackend_XML::loadFile() {
183 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); 313 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL );
184 ::close( fd ); 314 ::close( fd );
185 315
186 QAsciiDict<int> dict(FCreated+1); 316 QAsciiDict<int> dict(FExceptions+1);
187 dict.setAutoDelete( true ); 317 dict.setAutoDelete( true );
188 dict.insert( "description", new int(FDescription) ); 318 dict.insert( "description", new int(FDescription) );
189 dict.insert( "location", new int(FLocation) ); 319 dict.insert( "location", new int(FLocation) );
@@ -202,6 +332,10 @@ bool ODateBookAccessBackend_XML::loadFile() {
202 dict.insert( "end", new int(FREnd) ); 332 dict.insert( "end", new int(FREnd) );
203 dict.insert( "note", new int(FNote) ); 333 dict.insert( "note", new int(FNote) );
204 dict.insert( "created", new int(FCreated) ); 334 dict.insert( "created", new int(FCreated) );
335 dict.insert( "recparent", new int(FRecParent) );
336 dict.insert( "recchildren", new int(FRecChildren) );
337 dict.insert( "exceptions", new int(FExceptions) );
338 dict.insert( "timezone", new int(FTimeZone) );
205 339
206 char* dt = (char*)map_addr; 340 char* dt = (char*)map_addr;
207 int len = attribute.st_size; 341 int len = attribute.st_size;
@@ -289,10 +423,15 @@ void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
289 OTimeZone utc = OTimeZone::utc(); 423 OTimeZone utc = OTimeZone::utc();
290 ev.setStartDateTime( utc.fromUTCDateTime( start ) ); 424 ev.setStartDateTime( utc.fromUTCDateTime( start ) );
291 ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); 425 ev.setEndDateTime ( utc.fromUTCDateTime( end ) );
426 ev.setTimeZone( "UTC"); // make sure it is really utc
292 }else { 427 }else {
428 /* to current date time */
293 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); 429 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
294 ev.setStartDateTime( zone.toDateTime( start ) ); 430 QDateTime date = zone.toDateTime( start );
295 ev.setEndDateTime ( zone.toDateTime( end ) ); 431 ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
432
433 date = zone.toDateTime( end );
434 ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
296 } 435 }
297 if ( rec && rec->doesRecur() ) { 436 if ( rec && rec->doesRecur() ) {
298 OTimeZone utc = OTimeZone::utc(); 437 OTimeZone utc = OTimeZone::utc();
@@ -389,6 +528,29 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val
389 case FCreated: 528 case FCreated:
390 created = value.toInt(); 529 created = value.toInt();
391 break; 530 break;
531 case FRecParent:
532 e.setParent( value.toInt() );
533 break;
534 case FRecChildren:{
535 QStringList list = QStringList::split(' ', value );
536 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
537 e.addChild( (*it).toInt() );
538 }
539 }
540 break;
541 case FExceptions:{
542 QStringList list = QStringList::split(' ', value );
543 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
544 QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() );
545 qWarning("adding exception %s", date.toString().latin1() );
546 recur()->exceptions().append( date );
547 }
548 }
549 break;
550 case FTimeZone:
551 if ( value != "None" )
552 e.setTimeZone( value );
553 break;
392 default: 554 default:
393 break; 555 break;
394 } 556 }
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
@@ -42,9 +42,11 @@ int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) {
42 42
43struct OEvent::Data : public QShared { 43struct OEvent::Data : public QShared {
44 Data() : QShared() { 44 Data() : QShared() {
45 child = 0;
45 recur = 0; 46 recur = 0;
46 manager = 0; 47 manager = 0;
47 isAllDay = false; 48 isAllDay = false;
49 parent = 0;
48 } 50 }
49 ~Data() { 51 ~Data() {
50 delete manager; 52 delete manager;
@@ -60,6 +62,8 @@ struct OEvent::Data : public QShared {
60 QDateTime end; 62 QDateTime end;
61 bool isAllDay : 1; 63 bool isAllDay : 1;
62 QString timezone; 64 QString timezone;
65 QArray<int>* child;
66 int parent;
63}; 67};
64 68
65OEvent::OEvent( int uid ) 69OEvent::OEvent( int uid )
@@ -102,7 +106,7 @@ void OEvent::setLocation( const QString& loc ) {
102QString OEvent::location()const { 106QString OEvent::location()const {
103 return data->location; 107 return data->location;
104} 108}
105OPimNotifyManager &OEvent::notifiers() { 109OPimNotifyManager &OEvent::notifiers()const {
106 // I hope we can skip the changeOrModify here 110 // I hope we can skip the changeOrModify here
107 // the notifier should take care of it 111 // the notifier should take care of it
108 // and OPimNotify is shared too 112 // and OPimNotify is shared too
@@ -112,7 +116,13 @@ OPimNotifyManager &OEvent::notifiers() {
112 return *data->manager; 116 return *data->manager;
113} 117}
114bool OEvent::hasNotifiers()const { 118bool OEvent::hasNotifiers()const {
115 return ( data->manager); 119 if (!data->manager )
120 return false;
121 if (data->manager->reminders().isEmpty() &&
122 data->manager->alarms().isEmpty() )
123 return false;
124
125 return true;
116} 126}
117ORecur OEvent::recurrence()const { 127ORecur OEvent::recurrence()const {
118 if (!data->recur) 128 if (!data->recur)
@@ -197,6 +207,7 @@ void OEvent::setTimeZone( const QString& tz ) {
197 data->timezone = tz; 207 data->timezone = tz;
198} 208}
199QString OEvent::timeZone()const { 209QString OEvent::timeZone()const {
210 if (data->isAllDay ) return QString::fromLatin1("UTC");
200 return data->timezone; 211 return data->timezone;
201} 212}
202bool OEvent::match( const QRegExp& )const { 213bool OEvent::match( const QRegExp& )const {
@@ -239,6 +250,11 @@ void OEvent::changeOrModify() {
239 d2->end = data->end; 250 d2->end = data->end;
240 d2->isAllDay = data->isAllDay; 251 d2->isAllDay = data->isAllDay;
241 d2->timezone = data->timezone; 252 d2->timezone = data->timezone;
253 d2->parent = data->parent;
254 d2->child = data->child;
255
256 if (d2->child )
257 d2->child->detach();
242 258
243 data = d2; 259 data = d2;
244 } 260 }
@@ -256,8 +272,50 @@ QMap<int, QString> OEvent::toMap()const {
256QMap<QString, QString> OEvent::toExtraMap()const { 272QMap<QString, QString> OEvent::toExtraMap()const {
257 return QMap<QString, QString>(); 273 return QMap<QString, QString>();
258} 274}
275int OEvent::parent()const {
276 return data->parent;
277}
278void OEvent::setParent( int uid ) {
279 changeOrModify();
280 data->parent = uid;
281}
282QArray<int> OEvent::children() const{
283 if (!data->child) return QArray<int>();
284 else
285 return data->child->copy();
286}
287void OEvent::setChildren( const QArray<int>& arr ) {
288 changeOrModify();
289 if (data->child) delete data->child;
259 290
260 291 data->child = new QArray<int>( arr );
292 data->child->detach();
293}
294void OEvent::addChild( int uid ) {
295 changeOrModify();
296 if (!data->child ) {
297 data->child = new QArray<int>(1);
298 (*data->child)[0] = uid;
299 }else{
300 int count = data->child->count();
301 data->child->resize( count + 1 );
302 (*data->child)[count] = uid;
303 }
304}
305void OEvent::removeChild( int uid ) {
306 if (!data->child || !data->child->contains( uid ) ) return;
307 changeOrModify();
308 QArray<int> newAr( data->child->count() - 1 );
309 int j = 0;
310 uint count = data->child->count();
311 for ( uint i = 0; i < count; i++ ) {
312 if ( (*data->child)[i] != uid ) {
313 newAr[j] = (*data->child)[i];
314 j++;
315 }
316 }
317 (*data->child) = newAr;
318}
261struct OEffectiveEvent::Data : public QShared { 319struct OEffectiveEvent::Data : public QShared {
262 Data() : QShared() { 320 Data() : QShared() {
263 } 321 }
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
@@ -61,7 +61,7 @@ public:
61 void setLocation( const QString& loc ); 61 void setLocation( const QString& loc );
62 62
63 bool hasNotifiers()const; 63 bool hasNotifiers()const;
64 OPimNotifyManager &notifiers(); 64 OPimNotifyManager &notifiers()const;
65 65
66 ORecur recurrence()const; 66 ORecur recurrence()const;
67 void setRecurrence( const ORecur& ); 67 void setRecurrence( const ORecur& );
@@ -99,7 +99,15 @@ public:
99 99
100 bool match( const QRegExp& )const; 100 bool match( const QRegExp& )const;
101 101
102 /** For exception to recurrence here is a list of children... */
103 QArray<int> children()const;
104 void setChildren( const QArray<int>& );
105 void addChild( int uid );
106 void removeChild( int uid );
102 107
108 /** return the parent OEvent */
109 int parent()const;
110 void setParent( int uid );
103 111
104 112
105 /* needed reimp */ 113 /* needed reimp */
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,7 +1,10 @@
1#include <time.h>
2
1#include <qshared.h> 3#include <qshared.h>
2 4
3#include <qtopia/timeconversion.h> 5#include <qtopia/timeconversion.h>
4 6
7#include "otimezone.h"
5#include "orecur.h" 8#include "orecur.h"
6 9
7struct ORecur::Data : public QShared { 10struct ORecur::Data : public QShared {
@@ -81,6 +84,14 @@ bool ORecur::doesRecur( const QDate& date ) {
81// GPL from Datebookdb.cpp 84// GPL from Datebookdb.cpp
82// FIXME exception list! 85// FIXME exception list!
83bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { 86bool ORecur::nextOcurrence( const QDate& from, QDate& next ) {
87 bool stillLooking;
88 stillLooking = p_nextOccurrence( from, next );
89 while ( stillLooking && data->list.contains(next) )
90 stillLooking = p_nextOccurrence( next.addDays(1), next );
91
92 return stillLooking;
93}
94bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) {
84 95
85 // easy checks, first are we too far in the future or too far in the past? 96 // easy checks, first are we too far in the future or too far in the past?
86 QDate tmpDate; 97 QDate tmpDate;
@@ -443,4 +454,57 @@ void ORecur::checkOrModify() {
443 data = d2; 454 data = d2;
444 } 455 }
445} 456}
446 457QString ORecur::toString()const {
458 QString buf;
459
460 buf += " rtype=\"";
461 switch ( data->type ) {
462 case ORecur::Daily:
463 buf += "Daily";
464 break;
465 case ORecur::Weekly:
466 buf += "Weekly";
467 break;
468 case ORecur::MonthlyDay:
469 buf += "MonthlyDay";
470 break;
471 case ORecur::MonthlyDate:
472 buf += "MonthlyDate";
473 break;
474 case ORecur::Yearly:
475 buf += "Yearly";
476 break;
477 default:
478 buf += "NoRepeat";
479 break;
480 }
481 buf += "\"";
482 if (data->days > 0 )
483 buf += " rweekdays=\"" + QString::number( static_cast<int>( data->days ) ) + "\"";
484 if ( data->pos != 0 )
485 buf += " rposition=\"" + QString::number(data->pos ) + "\"";
486
487 buf += " rfreq=\"" + QString::number( data->freq ) + "\"";
488 buf += " rhasenddate=\"" + QString::number( static_cast<int>( data->hasEnd ) ) + "\"";
489 if ( data->hasEnd )
490 buf += " enddt=\""
491 + QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) )
492 + "\"";
493 buf += " created=\"" + QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) + "\"";
494
495 if ( data->list.isEmpty() ) return buf;
496 // save exceptions list here!!
497 ExceptionList::ConstIterator it;
498 ExceptionList list = data->list;
499 buf += " exceptions=\"";
500 QDate date;
501 for ( it = list.begin(); it != list.end(); ++it ) {
502 date = (*it);
503 if ( it != list.begin() ) buf += " ";
504
505 buf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() );
506 }
507 buf += "\"";
508
509 return buf;
510}
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
@@ -73,7 +73,11 @@ public:
73 void setRepitition(int ); 73 void setRepitition(int );
74 74
75 void setService( const QString& ser ); 75 void setService( const QString& ser );
76
77 /* almost internal */
78 QString toString()const;
76private: 79private:
80 bool p_nextOccurrence( const QDate& from, QDate& next );
77 void deref(); 81 void deref();
78 inline void checkOrModify(); 82 inline void checkOrModify();
79 83
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
@@ -5,12 +5,12 @@
5 5
6int main(int argc, char* argv ) { 6int main(int argc, char* argv ) {
7 OEvent ev; 7 OEvent ev;
8 ev.setUid( 20 ); 8// ev.setUid( 20 );
9 9
10 ev.setDescription( "Foo" ); 10 ev.setDescription( "Foo Descsfewrf" );
11 11
12 OEvent ev2 = ev; 12 OEvent ev2 = ev;
13 ev2.setDescription("Foo2"); 13 ev2.setDescription("Foo3");
14 qWarning("%s", ev2.description().latin1() ); 14 qWarning("%s", ev2.description().latin1() );
15 qWarning("%s", ev.description().latin1() ); 15 qWarning("%s", ev.description().latin1() );
16 16
@@ -20,6 +20,7 @@ int main(int argc, char* argv ) {
20 20
21 qWarning("%s", ev2.startDateTime().toString().latin1() ); 21 qWarning("%s", ev2.startDateTime().toString().latin1() );
22 qWarning("%s", ev2.startDateTimeInZone().toString().latin1() ); 22 qWarning("%s", ev2.startDateTimeInZone().toString().latin1() );
23 qWarning("%d %d", ev.isAllDay(), ev2.isAllDay() );
23 24
24 ODateBookAccess acc; 25 ODateBookAccess acc;
25 if(!acc.load() ) qWarning("could not load"); 26 if(!acc.load() ) qWarning("could not load");
@@ -45,6 +46,9 @@ int main(int argc, char* argv ) {
45 qWarning("Summary: %s", ef.description().latin1() ); 46 qWarning("Summary: %s", ef.description().latin1() );
46 qWarning("Date: %s", ef.date().toString().latin1() ); 47 qWarning("Date: %s", ef.date().toString().latin1() );
47 } 48 }
49 ev.setUid( 1 );
50 acc.add( ev );
51 acc.save();
48 52
49 return 0; 53 return 0;
50} 54}
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,6 +1,9 @@
1#include <errno.h> 1#include <errno.h>
2#include <fcntl.h> 2#include <fcntl.h>
3 3
4#include <stdio.h>
5#include <stdlib.h>
6
4#include <sys/types.h> 7#include <sys/types.h>
5#include <sys/mman.h> 8#include <sys/mman.h>
6#include <sys/stat.h> 9#include <sys/stat.h>
@@ -12,6 +15,7 @@
12 15
13#include <qtopia/global.h> 16#include <qtopia/global.h>
14#include <qtopia/stringutil.h> 17#include <qtopia/stringutil.h>
18#include <qtopia/timeconversion.h>
15 19
16#include "opimnotifymanager.h" 20#include "opimnotifymanager.h"
17#include "orecur.h" 21#include "orecur.h"
@@ -46,8 +50,89 @@ namespace {
46 FRStart, 50 FRStart,
47 FREnd, 51 FREnd,
48 FNote, 52 FNote,
49 FCreated 53 FCreated,
54 FTimeZone,
55 FRecParent,
56 FRecChildren,
57 FExceptions
50 }; 58 };
59 inline void save( const OEvent& ev, QString& buf ) {
60 buf += " description=\"" + Qtopia::escapeString(ev.description() ) + "\"";
61 if (!ev.location().isEmpty() )
62 buf += " location=\"" + Qtopia::escapeString(ev.location() ) + "\"";
63
64 buf += " categories=\""+ Qtopia::escapeString( Qtopia::Record::idsToString( ev.categories() ) ) + "\"";
65 buf += " uid=\"" + QString::number( ev.uid() ) + "\"";
66
67 if (ev.isAllDay() )
68 buf += " type=\"AllDay\"";
69
70 if (ev.hasNotifiers() ) {
71 OPimAlarm alarm = ev.notifiers().alarms()[0]; // take only the first
72 int minutes = alarm.dateTime().secsTo( ev.startDateTime() ) / 60;
73 buf += " alarm=\"" + QString::number(minutes) + "\" sound=\"";
74 if ( alarm.sound() == OPimAlarm::Loud )
75 buf += "loud";
76 else
77 buf += "silent";
78 buf += "\"";
79 }
80 if ( ev.hasRecurrence() ) {
81 buf += ev.recurrence().toString();
82 }
83
84 /*
85 * fscking timezones :) well, we'll first convert
86 * the QDateTime to a QDateTime in UTC time
87 * and then we'll create a nice time_t
88 */
89 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
90 buf += " start=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.startDateTime(), OTimeZone::utc() ) ) ) + "\"";
91 buf += " end=\"" + QString::number( zone.fromUTCDateTime( zone.toDateTime( ev.endDateTime() , OTimeZone::utc() ) ) ) + "\"";
92 if (!ev.note().isEmpty() ) {
93 buf += " note=\"" + Qtopia::escapeString( ev.note() ) + "\"";
94 }
95
96 buf += " timezone=\"";
97 if ( ev.timeZone().isEmpty() )
98 buf += "None";
99 else
100 buf += ev.timeZone();
101
102 if (ev.parent() != 0 ) {
103 buf += " recparent=\""+QString::number(ev.parent() )+"\"";
104 }
105
106 if (ev.children().count() != 0 ) {
107 QArray<int> children = ev.children();
108 buf += " recchildren=\"";
109 for ( uint i = 0; i < children.count(); i++ ) {
110 if ( i != 0 ) buf += " ";
111 buf += QString::number( children[i] );
112 }
113 buf+= "\"";
114 }
115
116 // skip custom writing
117 }
118
119 inline bool forAll( const QMap<int, OEvent>& list, QFile& file ) {
120 QMap<int, OEvent>::ConstIterator it;
121 QString buf;
122 QCString str;
123 int total_written;
124 for ( it = list.begin(); it != list.end(); ++it ) {
125 buf = "<event";
126 save( it.data(), buf );
127 buf += " />\n";
128 str = buf.utf8();
129
130 total_written = file.writeBlock(str.data(), str.length() );
131 if ( total_written != int(str.length() ) )
132 return false;
133 }
134 return true;
135 }
51} 136}
52 137
53ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& , 138ODateBookAccessBackend_XML::ODateBookAccessBackend_XML( const QString& ,
@@ -66,9 +151,54 @@ bool ODateBookAccessBackend_XML::reload() {
66 return load(); 151 return load();
67} 152}
68bool ODateBookAccessBackend_XML::save() { 153bool ODateBookAccessBackend_XML::save() {
69 if (!m_changed) return true; 154 qWarning("going to save now");
70 m_changed = false; 155// if (!m_changed) return true;
156
157 int total_written;
158 QString strFileNew = m_name + ".new";
159
160 QFile f( strFileNew );
161 if (!f.open( IO_WriteOnly | IO_Raw ) ) return false;
162
163 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
164 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
165 buf += "<events>\n";
166 QCString str = buf.utf8();
167 total_written = f.writeBlock( str.data(), str.length() );
168 if ( total_written != int(str.length() ) ) {
169 f.close();
170 QFile::remove( strFileNew );
171 return false;
172 }
173
174 if (!forAll( m_raw, f ) ) {
175 f.close();
176 QFile::remove( strFileNew );
177 return false;
178 }
179 if (!forAll( m_rep, f ) ) {
180 f.close();
181 QFile::remove( strFileNew );
182 return false;
183 }
184
185 buf = "</events>\n</DATEBOOK>\n";
186 str = buf.utf8();
187 total_written = f.writeBlock( str.data(), str.length() );
188 if ( total_written != int(str.length() ) ) {
189 f.close();
190 QFile::remove( strFileNew );
191 return false;
192 }
193 f.close();
194
195 exit(0);
196 if ( ::rename( strFileNew, m_name ) < 0 ) {
197 QFile::remove( strFileNew );
198 return false;
199 }
71 200
201 m_changed = false;
72 return true; 202 return true;
73} 203}
74QArray<int> ODateBookAccessBackend_XML::allRecords()const { 204QArray<int> ODateBookAccessBackend_XML::allRecords()const {
@@ -183,7 +313,7 @@ bool ODateBookAccessBackend_XML::loadFile() {
183 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL ); 313 ::madvise( map_addr, attribute.st_size, MADV_SEQUENTIAL );
184 ::close( fd ); 314 ::close( fd );
185 315
186 QAsciiDict<int> dict(FCreated+1); 316 QAsciiDict<int> dict(FExceptions+1);
187 dict.setAutoDelete( true ); 317 dict.setAutoDelete( true );
188 dict.insert( "description", new int(FDescription) ); 318 dict.insert( "description", new int(FDescription) );
189 dict.insert( "location", new int(FLocation) ); 319 dict.insert( "location", new int(FLocation) );
@@ -202,6 +332,10 @@ bool ODateBookAccessBackend_XML::loadFile() {
202 dict.insert( "end", new int(FREnd) ); 332 dict.insert( "end", new int(FREnd) );
203 dict.insert( "note", new int(FNote) ); 333 dict.insert( "note", new int(FNote) );
204 dict.insert( "created", new int(FCreated) ); 334 dict.insert( "created", new int(FCreated) );
335 dict.insert( "recparent", new int(FRecParent) );
336 dict.insert( "recchildren", new int(FRecChildren) );
337 dict.insert( "exceptions", new int(FExceptions) );
338 dict.insert( "timezone", new int(FTimeZone) );
205 339
206 char* dt = (char*)map_addr; 340 char* dt = (char*)map_addr;
207 int len = attribute.st_size; 341 int len = attribute.st_size;
@@ -289,10 +423,15 @@ void ODateBookAccessBackend_XML::finalizeRecord( OEvent& ev ) {
289 OTimeZone utc = OTimeZone::utc(); 423 OTimeZone utc = OTimeZone::utc();
290 ev.setStartDateTime( utc.fromUTCDateTime( start ) ); 424 ev.setStartDateTime( utc.fromUTCDateTime( start ) );
291 ev.setEndDateTime ( utc.fromUTCDateTime( end ) ); 425 ev.setEndDateTime ( utc.fromUTCDateTime( end ) );
426 ev.setTimeZone( "UTC"); // make sure it is really utc
292 }else { 427 }else {
428 /* to current date time */
293 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() ); 429 OTimeZone zone( ev.timeZone().isEmpty() ? OTimeZone::current() : ev.timeZone() );
294 ev.setStartDateTime( zone.toDateTime( start ) ); 430 QDateTime date = zone.toDateTime( start );
295 ev.setEndDateTime ( zone.toDateTime( end ) ); 431 ev.setStartDateTime( zone.toDateTime( date, OTimeZone::current() ) );
432
433 date = zone.toDateTime( end );
434 ev.setEndDateTime ( zone.toDateTime( date, OTimeZone::current() ) );
296 } 435 }
297 if ( rec && rec->doesRecur() ) { 436 if ( rec && rec->doesRecur() ) {
298 OTimeZone utc = OTimeZone::utc(); 437 OTimeZone utc = OTimeZone::utc();
@@ -389,6 +528,29 @@ void ODateBookAccessBackend_XML::setField( OEvent& e, int id, const QString& val
389 case FCreated: 528 case FCreated:
390 created = value.toInt(); 529 created = value.toInt();
391 break; 530 break;
531 case FRecParent:
532 e.setParent( value.toInt() );
533 break;
534 case FRecChildren:{
535 QStringList list = QStringList::split(' ', value );
536 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
537 e.addChild( (*it).toInt() );
538 }
539 }
540 break;
541 case FExceptions:{
542 QStringList list = QStringList::split(' ', value );
543 for (QStringList::Iterator it = list.begin(); it != list.end(); ++it ) {
544 QDate date( (*it).left(4).toInt(), (*it).mid(4, 2).toInt(), (*it).right(2).toInt() );
545 qWarning("adding exception %s", date.toString().latin1() );
546 recur()->exceptions().append( date );
547 }
548 }
549 break;
550 case FTimeZone:
551 if ( value != "None" )
552 e.setTimeZone( value );
553 break;
392 default: 554 default:
393 break; 555 break;
394 } 556 }
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,7 +1,10 @@
1#include <time.h>
2
1#include <qshared.h> 3#include <qshared.h>
2 4
3#include <qtopia/timeconversion.h> 5#include <qtopia/timeconversion.h>
4 6
7#include "otimezone.h"
5#include "orecur.h" 8#include "orecur.h"
6 9
7struct ORecur::Data : public QShared { 10struct ORecur::Data : public QShared {
@@ -81,6 +84,14 @@ bool ORecur::doesRecur( const QDate& date ) {
81// GPL from Datebookdb.cpp 84// GPL from Datebookdb.cpp
82// FIXME exception list! 85// FIXME exception list!
83bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { 86bool ORecur::nextOcurrence( const QDate& from, QDate& next ) {
87 bool stillLooking;
88 stillLooking = p_nextOccurrence( from, next );
89 while ( stillLooking && data->list.contains(next) )
90 stillLooking = p_nextOccurrence( next.addDays(1), next );
91
92 return stillLooking;
93}
94bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) {
84 95
85 // easy checks, first are we too far in the future or too far in the past? 96 // easy checks, first are we too far in the future or too far in the past?
86 QDate tmpDate; 97 QDate tmpDate;
@@ -443,4 +454,57 @@ void ORecur::checkOrModify() {
443 data = d2; 454 data = d2;
444 } 455 }
445} 456}
446 457QString ORecur::toString()const {
458 QString buf;
459
460 buf += " rtype=\"";
461 switch ( data->type ) {
462 case ORecur::Daily:
463 buf += "Daily";
464 break;
465 case ORecur::Weekly:
466 buf += "Weekly";
467 break;
468 case ORecur::MonthlyDay:
469 buf += "MonthlyDay";
470 break;
471 case ORecur::MonthlyDate:
472 buf += "MonthlyDate";
473 break;
474 case ORecur::Yearly:
475 buf += "Yearly";
476 break;
477 default:
478 buf += "NoRepeat";
479 break;
480 }
481 buf += "\"";
482 if (data->days > 0 )
483 buf += " rweekdays=\"" + QString::number( static_cast<int>( data->days ) ) + "\"";
484 if ( data->pos != 0 )
485 buf += " rposition=\"" + QString::number(data->pos ) + "\"";
486
487 buf += " rfreq=\"" + QString::number( data->freq ) + "\"";
488 buf += " rhasenddate=\"" + QString::number( static_cast<int>( data->hasEnd ) ) + "\"";
489 if ( data->hasEnd )
490 buf += " enddt=\""
491 + QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) )
492 + "\"";
493 buf += " created=\"" + QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) + "\"";
494
495 if ( data->list.isEmpty() ) return buf;
496 // save exceptions list here!!
497 ExceptionList::ConstIterator it;
498 ExceptionList list = data->list;
499 buf += " exceptions=\"";
500 QDate date;
501 for ( it = list.begin(); it != list.end(); ++it ) {
502 date = (*it);
503 if ( it != list.begin() ) buf += " ";
504
505 buf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() );
506 }
507 buf += "\"";
508
509 return buf;
510}
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
@@ -73,7 +73,11 @@ public:
73 void setRepitition(int ); 73 void setRepitition(int );
74 74
75 void setService( const QString& ser ); 75 void setService( const QString& ser );
76
77 /* almost internal */
78 QString toString()const;
76private: 79private:
80 bool p_nextOccurrence( const QDate& from, QDate& next );
77 void deref(); 81 void deref();
78 inline void checkOrModify(); 82 inline void checkOrModify();
79 83
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
@@ -42,9 +42,11 @@ int OCalendarHelper::monthDiff( const QDate& first, const QDate& second ) {
42 42
43struct OEvent::Data : public QShared { 43struct OEvent::Data : public QShared {
44 Data() : QShared() { 44 Data() : QShared() {
45 child = 0;
45 recur = 0; 46 recur = 0;
46 manager = 0; 47 manager = 0;
47 isAllDay = false; 48 isAllDay = false;
49 parent = 0;
48 } 50 }
49 ~Data() { 51 ~Data() {
50 delete manager; 52 delete manager;
@@ -60,6 +62,8 @@ struct OEvent::Data : public QShared {
60 QDateTime end; 62 QDateTime end;
61 bool isAllDay : 1; 63 bool isAllDay : 1;
62 QString timezone; 64 QString timezone;
65 QArray<int>* child;
66 int parent;
63}; 67};
64 68
65OEvent::OEvent( int uid ) 69OEvent::OEvent( int uid )
@@ -102,7 +106,7 @@ void OEvent::setLocation( const QString& loc ) {
102QString OEvent::location()const { 106QString OEvent::location()const {
103 return data->location; 107 return data->location;
104} 108}
105OPimNotifyManager &OEvent::notifiers() { 109OPimNotifyManager &OEvent::notifiers()const {
106 // I hope we can skip the changeOrModify here 110 // I hope we can skip the changeOrModify here
107 // the notifier should take care of it 111 // the notifier should take care of it
108 // and OPimNotify is shared too 112 // and OPimNotify is shared too
@@ -112,7 +116,13 @@ OPimNotifyManager &OEvent::notifiers() {
112 return *data->manager; 116 return *data->manager;
113} 117}
114bool OEvent::hasNotifiers()const { 118bool OEvent::hasNotifiers()const {
115 return ( data->manager); 119 if (!data->manager )
120 return false;
121 if (data->manager->reminders().isEmpty() &&
122 data->manager->alarms().isEmpty() )
123 return false;
124
125 return true;
116} 126}
117ORecur OEvent::recurrence()const { 127ORecur OEvent::recurrence()const {
118 if (!data->recur) 128 if (!data->recur)
@@ -197,6 +207,7 @@ void OEvent::setTimeZone( const QString& tz ) {
197 data->timezone = tz; 207 data->timezone = tz;
198} 208}
199QString OEvent::timeZone()const { 209QString OEvent::timeZone()const {
210 if (data->isAllDay ) return QString::fromLatin1("UTC");
200 return data->timezone; 211 return data->timezone;
201} 212}
202bool OEvent::match( const QRegExp& )const { 213bool OEvent::match( const QRegExp& )const {
@@ -239,6 +250,11 @@ void OEvent::changeOrModify() {
239 d2->end = data->end; 250 d2->end = data->end;
240 d2->isAllDay = data->isAllDay; 251 d2->isAllDay = data->isAllDay;
241 d2->timezone = data->timezone; 252 d2->timezone = data->timezone;
253 d2->parent = data->parent;
254 d2->child = data->child;
255
256 if (d2->child )
257 d2->child->detach();
242 258
243 data = d2; 259 data = d2;
244 } 260 }
@@ -256,8 +272,50 @@ QMap<int, QString> OEvent::toMap()const {
256QMap<QString, QString> OEvent::toExtraMap()const { 272QMap<QString, QString> OEvent::toExtraMap()const {
257 return QMap<QString, QString>(); 273 return QMap<QString, QString>();
258} 274}
275int OEvent::parent()const {
276 return data->parent;
277}
278void OEvent::setParent( int uid ) {
279 changeOrModify();
280 data->parent = uid;
281}
282QArray<int> OEvent::children() const{
283 if (!data->child) return QArray<int>();
284 else
285 return data->child->copy();
286}
287void OEvent::setChildren( const QArray<int>& arr ) {
288 changeOrModify();
289 if (data->child) delete data->child;
259 290
260 291 data->child = new QArray<int>( arr );
292 data->child->detach();
293}
294void OEvent::addChild( int uid ) {
295 changeOrModify();
296 if (!data->child ) {
297 data->child = new QArray<int>(1);
298 (*data->child)[0] = uid;
299 }else{
300 int count = data->child->count();
301 data->child->resize( count + 1 );
302 (*data->child)[count] = uid;
303 }
304}
305void OEvent::removeChild( int uid ) {
306 if (!data->child || !data->child->contains( uid ) ) return;
307 changeOrModify();
308 QArray<int> newAr( data->child->count() - 1 );
309 int j = 0;
310 uint count = data->child->count();
311 for ( uint i = 0; i < count; i++ ) {
312 if ( (*data->child)[i] != uid ) {
313 newAr[j] = (*data->child)[i];
314 j++;
315 }
316 }
317 (*data->child) = newAr;
318}
261struct OEffectiveEvent::Data : public QShared { 319struct OEffectiveEvent::Data : public QShared {
262 Data() : QShared() { 320 Data() : QShared() {
263 } 321 }
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
@@ -61,7 +61,7 @@ public:
61 void setLocation( const QString& loc ); 61 void setLocation( const QString& loc );
62 62
63 bool hasNotifiers()const; 63 bool hasNotifiers()const;
64 OPimNotifyManager &notifiers(); 64 OPimNotifyManager &notifiers()const;
65 65
66 ORecur recurrence()const; 66 ORecur recurrence()const;
67 void setRecurrence( const ORecur& ); 67 void setRecurrence( const ORecur& );
@@ -99,7 +99,15 @@ public:
99 99
100 bool match( const QRegExp& )const; 100 bool match( const QRegExp& )const;
101 101
102 /** For exception to recurrence here is a list of children... */
103 QArray<int> children()const;
104 void setChildren( const QArray<int>& );
105 void addChild( int uid );
106 void removeChild( int uid );
102 107
108 /** return the parent OEvent */
109 int parent()const;
110 void setParent( int uid );
103 111
104 112
105 /* needed reimp */ 113 /* needed reimp */