00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qasciidict.h>
00022 #include <qfile.h>
00023 #include <qmessagebox.h>
00024 #include <qstring.h>
00025 #include <qtextcodec.h>
00026 #include <qtextstream.h>
00027 #include <qtl.h>
00028
00029 #include <qpe/alarmserver.h>
00030 #include <qpe/global.h>
00031 #include "datebookdb.h"
00032 #include <qpe/stringutil.h>
00033 #include <qpe/timeconversion.h>
00034
00035 #include <errno.h>
00036 #include <stdlib.h>
00037
00038
00039 class DateBookDBPrivate
00040 {
00041 public:
00042 bool clean;
00043 };
00044
00045
00046
00047
00048 static QString dateBookJournalFile()
00049 {
00050 QString str = getenv("HOME");
00051 return QString( str +"/.caljournal" );
00052 }
00053
00054 static QString dateBookFilename()
00055 {
00056 return Global::applicationFileName("datebook","datebook.xml");
00057 }
00058
00059
00060
00061
00062
00063
00064 bool nextOccurance(const Event &e, const QDate &from, QDateTime &next)
00065 {
00066
00067 QDate tmpDate;
00068 int freq = e.repeatPattern().frequency;
00069 int diff, diff2, a;
00070 int iday, imonth, iyear;
00071 int dayOfWeek = 0;
00072 int firstOfWeek = 0;
00073 int weekOfMonth;
00074
00075
00076 if (e.repeatPattern().hasEndDate && e.repeatPattern().endDate() < from)
00077 return FALSE;
00078
00079 if (e.start() >= from) {
00080 next = e.start();
00081 return TRUE;
00082 }
00083
00084 switch ( e.repeatPattern().type ) {
00085 case Event::Weekly:
00086
00087
00088
00089 dayOfWeek = from.dayOfWeek();
00090 dayOfWeek--;
00091
00092
00093
00094
00095 while(!((1 << firstOfWeek) & e.repeatPattern().days))
00096 firstOfWeek++;
00097
00098
00099
00100
00101 while(!((1 << (dayOfWeek % 7)) & e.repeatPattern().days))
00102 dayOfWeek++;
00103
00104
00105 dayOfWeek = dayOfWeek % 7;
00106 dayOfWeek -= e.start().date().dayOfWeek() -1;
00107
00108 firstOfWeek = firstOfWeek % 7;
00109 firstOfWeek -= e.start().date().dayOfWeek() -1;
00110
00111
00112
00113
00114 freq *= 7;
00115
00116 case Event::Daily:
00117
00118 if(e.start().date().addDays(dayOfWeek) > from) {
00119
00120 next = QDateTime(e.start().date().addDays(dayOfWeek),
00121 e.start().time());
00122 if ((next.date() > e.repeatPattern().endDate())
00123 && e.repeatPattern().hasEndDate)
00124 return FALSE;
00125 return TRUE;
00126 }
00127
00128
00129 diff = e.start().date().addDays(dayOfWeek).daysTo(from) % freq;
00130 diff2 = e.start().date().addDays(firstOfWeek).daysTo(from) % freq;
00131
00132 if(diff != 0)
00133 diff = freq - diff;
00134 if(diff2 != 0)
00135 diff2 = freq - diff2;
00136 diff = QMIN(diff, diff2);
00137
00138 next = QDateTime(from.addDays(diff), e.start().time());
00139 if ( (next.date() > e.repeatPattern().endDate())
00140 && e.repeatPattern().hasEndDate )
00141 return FALSE;
00142 return TRUE;
00143 case Event::MonthlyDay:
00144 iday = from.day();
00145 iyear = from.year();
00146 imonth = from.month();
00147
00148 dayOfWeek = e.start().date().dayOfWeek();
00149 weekOfMonth = (e.start().date().day() - 1) / 7;
00150
00151
00152 a = from.year() - e.start().date().year();
00153 a *= 12;
00154 a = a + (imonth - e.start().date().month());
00155
00156 if(a % freq) {
00157 a = freq - (a % freq);
00158 imonth = from.month() + a;
00159 if (imonth > 12) {
00160 imonth--;
00161 iyear += imonth / 12;
00162 imonth = imonth % 12;
00163 imonth++;
00164 }
00165 }
00166
00167
00168
00169
00170 tmpDate = QDate( iyear, imonth, 1 );
00171
00172 iday = 1;
00173 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
00174 iday += 7 * weekOfMonth;
00175 while (iday > tmpDate.daysInMonth()) {
00176 imonth += freq;
00177 if (imonth > 12) {
00178 imonth--;
00179 iyear += imonth / 12;
00180 imonth = imonth % 12;
00181 imonth++;
00182 }
00183 tmpDate = QDate( iyear, imonth, 1 );
00184
00185 if ((tmpDate > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00186 return FALSE;
00187 iday = 1;
00188 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
00189 iday += 7 * weekOfMonth;
00190 }
00191 tmpDate = QDate(iyear, imonth, iday);
00192
00193 if (tmpDate >= from) {
00194 next = QDateTime(tmpDate, e.start().time());
00195 if ((next.date() > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00196 return FALSE;
00197 return TRUE;
00198 }
00199
00200
00201 do {
00202 imonth += freq;
00203 if (imonth > 12) {
00204 imonth--;
00205 iyear += imonth / 12;
00206 imonth = imonth % 12;
00207 imonth++;
00208 }
00209 tmpDate = QDate( iyear, imonth, 1 );
00210
00211 if ((tmpDate > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00212 return FALSE;
00213 iday = 1;
00214 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
00215 iday += 7 * weekOfMonth;
00216 } while (iday > tmpDate.daysInMonth());
00217 tmpDate = QDate(iyear, imonth, iday);
00218
00219 next = QDateTime(tmpDate, e.start().time());
00220 if ((next.date() > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00221 return FALSE;
00222 return TRUE;
00223 case Event::MonthlyDate:
00224 iday = e.start().date().day();
00225 iyear = from.year();
00226 imonth = from.month();
00227
00228 a = from.year() - e.start().date().year();
00229 a *= 12;
00230 a = a + (imonth - e.start().date().month());
00231
00232 if(a % freq) {
00233 a = freq - (a % freq);
00234 imonth = from.month() + a;
00235 if (imonth > 12) {
00236 imonth--;
00237 iyear += imonth / 12;
00238 imonth = imonth % 12;
00239 imonth++;
00240 }
00241 }
00242
00243
00244
00245
00246 while(!QDate::isValid(iyear, imonth, iday) ) {
00247 imonth += freq;
00248 if (imonth > 12) {
00249 imonth--;
00250 iyear += imonth / 12;
00251 imonth = imonth % 12;
00252 imonth++;
00253 }
00254
00255 if ((QDate(iyear, imonth, 1) > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00256 return FALSE;
00257 }
00258
00259 if(QDate(iyear, imonth, iday) >= from) {
00260
00261 next = QDateTime(QDate(iyear, imonth, iday),
00262 e.start().time());
00263 if ((next.date() > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00264 return FALSE;
00265 return TRUE;
00266 }
00267
00268
00269 imonth += freq;
00270 imonth--;
00271 iyear += imonth / 12;
00272 imonth = imonth % 12;
00273 imonth++;
00274
00275 while(!QDate::isValid(iyear, imonth, iday) ) {
00276 imonth += freq;
00277 imonth--;
00278 iyear += imonth / 12;
00279 imonth = imonth % 12;
00280 imonth++;
00281 if ((QDate(iyear, imonth, 1) > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00282 return FALSE;
00283 }
00284
00285 next = QDateTime(QDate(iyear, imonth, iday), e.start().time());
00286 if ((next.date() > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00287 return FALSE;
00288 return TRUE;
00289 case Event::Yearly:
00290 iday = e.start().date().day();
00291 imonth = e.start().date().month();
00292 iyear = from.year();
00293
00294 diff = 1;
00295 if(imonth == 2 && iday > 28) {
00296
00297 if(freq % 4)
00298 if (freq % 2)
00299 freq = freq * 4;
00300 else
00301 freq = freq * 2;
00302
00303 diff = 4;
00304 }
00305
00306 a = from.year() - e.start().date().year();
00307 if(a % freq) {
00308 a = freq - (a % freq);
00309 iyear = iyear + a;
00310 }
00311
00312
00313 if(!QDate::isValid(iyear, imonth, iday)) {
00314
00315 iyear += freq;
00316 }
00317
00318 if(QDate(iyear, imonth, iday) >= from) {
00319 next = QDateTime(QDate(iyear, imonth, iday),
00320 e.start().time());
00321 if ((next.date() > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00322 return FALSE;
00323 return TRUE;
00324 }
00325
00326 iyear += freq;
00327
00328 if(!QDate::isValid(iyear, imonth, iday)) {
00329
00330 iyear += freq;
00331 }
00332
00333 next = QDateTime(QDate(iyear, imonth, iday), e.start().time());
00334 if ((next.date() > e.repeatPattern().endDate()) && e.repeatPattern().hasEndDate)
00335 return FALSE;
00336 return TRUE;
00337 default:
00338 return FALSE;
00339 }
00340 }
00341
00342 static bool nextAlarm( const Event &ev, QDateTime& when, int& warn)
00343 {
00344 QDateTime now = QDateTime::currentDateTime();
00345 if ( ev.hasRepeat() ) {
00346 QDateTime ralarm;
00347 if (nextOccurance(ev, now.date(), ralarm)) {
00348 ralarm = ralarm.addSecs(-ev.alarmTime()*60);
00349 if ( ralarm > now ) {
00350 when = ralarm;
00351 warn = ev.alarmTime();
00352 } else if ( nextOccurance(ev, now.date().addDays(1), ralarm) ) {
00353 ralarm = ralarm.addSecs( -ev.alarmTime()*60 );
00354 if ( ralarm > now ) {
00355 when = ralarm;
00356 warn = ev.alarmTime();
00357 }
00358 }
00359 }
00360 } else {
00361 warn = ev.alarmTime();
00362 when = ev.start().addSecs( -ev.alarmTime()*60 );
00363 }
00364 return when > now;
00365 }
00366
00367 static void addEventAlarm( const Event &ev )
00368 {
00369 QDateTime when;
00370 int warn;
00371 if ( nextAlarm(ev,when,warn) )
00372 AlarmServer::addAlarm( when,
00373 "QPE/Application/datebook",
00374 "alarm(QDateTime,int)", warn );
00375 }
00376
00377 static void delEventAlarm( const Event &ev )
00378 {
00379 QDateTime when;
00380 int warn;
00381 if ( nextAlarm(ev,when,warn) )
00382 AlarmServer::deleteAlarm( when,
00383 "QPE/Application/datebook",
00384 "alarm(QDateTime,int)", warn );
00385 }
00386
00387
00388 DateBookDB::DateBookDB()
00389 {
00390 init();
00391 }
00392
00393 DateBookDB::~DateBookDB()
00394 {
00395 save();
00396 eventList.clear();
00397 repeatEvents.clear();
00398 }
00399
00400
00401
00402
00403 QValueList<Event> DateBookDB::getEvents( const QDate &from, const QDate &to )
00404 {
00405 QValueList<Event> tmpList;
00406 tmpList = getNonRepeatingEvents( from, to );
00407
00408
00409 for (QValueList<Event>::ConstIterator it = repeatEvents.begin();
00410 it != repeatEvents.end(); ++it) {
00411 QDate itDate = from;
00412 QDateTime due;
00413
00414
00415
00416 Event dummy_event = *it;
00417 Event::RepeatPattern r = dummy_event.repeatPattern();
00418 if ( !r.hasEndDate || r.endDate() > to ) {
00419 r.setEndDate( to );
00420 r.hasEndDate = TRUE;
00421 }
00422 dummy_event.setRepeat(TRUE, r);
00423
00424 while (nextOccurance(dummy_event, itDate, due)) {
00425 if (due.date() > to)
00426 break;
00427 Event newEvent = *it;
00428 newEvent.setStart(due);
00429 newEvent.setEnd(due.addSecs((*it).start().secsTo((*it).end())));
00430
00431 tmpList.append(newEvent);
00432 itDate = due.date().addDays(1);
00433 }
00434 }
00435 qHeapSort(tmpList);
00436 return tmpList;
00437 }
00438
00439 QValueList<Event> DateBookDB::getEvents( const QDateTime &start )
00440 {
00441 QValueList<Event> day = getEvents(start.date(),start.date());
00442
00443 QValueListConstIterator<Event> it;
00444 QDateTime dtTmp;
00445 QValueList<Event> tmpList;
00446 for (it = day.begin(); it != day.end(); ++it ) {
00447 dtTmp = (*it).start(TRUE);
00448 if ( dtTmp == start )
00449 tmpList.append( *it );
00450 }
00451 return tmpList;
00452 }
00453
00454
00455
00456 QValueList<EffectiveEvent> DateBookDB::getEffectiveEvents( const QDate &from,
00457 const QDate &to )
00458 {
00459 QValueList<EffectiveEvent> tmpList;
00460 QValueListIterator<Event> it;
00461
00462 EffectiveEvent effEv;
00463 QDateTime dtTmp,
00464 dtEnd;
00465
00466 for (it = eventList.begin(); it != eventList.end(); ++it ) {
00467 if (!(*it).isValidUid())
00468 (*it).assignUid();
00469
00470 dtTmp = (*it).start(TRUE);
00471 dtEnd = (*it).end(TRUE);
00472
00473 if ( dtTmp.date() >= from && dtTmp.date() <= to ) {
00474 Event tmpEv = *it;
00475 effEv.setEvent(tmpEv);
00476 effEv.setDate( dtTmp.date() );
00477 effEv.setStart( dtTmp.time() );
00478 if ( dtTmp.date() != dtEnd.date() )
00479 effEv.setEnd( QTime(23, 59, 0) );
00480 else
00481 effEv.setEnd( dtEnd.time() );
00482 tmpList.append( effEv );
00483 }
00484
00485 if ( dtEnd.date() != dtTmp.date() && dtEnd.date() >= from ) {
00486 QDateTime dt = dtTmp.addDays( 1 );
00487 dt.setTime( QTime(0, 0, 0) );
00488 QDateTime dtStop;
00489 if ( dtEnd > to ) {
00490 dtStop = to;
00491 } else
00492 dtStop = dtEnd;
00493 while ( dt <= dtStop ) {
00494 Event tmpEv = *it;
00495 effEv.setEvent( tmpEv );
00496 effEv.setDate( dt.date() );
00497 if ( dt >= from ) {
00498 effEv.setStart( QTime(0, 0, 0) );
00499 if ( dt.date() == dtEnd.date() )
00500 effEv.setEnd( dtEnd.time() );
00501 else
00502 effEv.setEnd( QTime(23, 59, 59) );
00503 tmpList.append( effEv );
00504 }
00505 dt = dt.addDays( 1 );
00506 }
00507 }
00508 }
00509
00510 QDateTime repeat;
00511 for ( it = repeatEvents.begin(); it != repeatEvents.end(); ++it ) {
00512 if (!(*it).isValidUid())
00513 (*it).assignUid();
00514
00515
00516
00517 Event dummy_event = *it;
00518 int duration = (*it).start().date().daysTo( (*it).end().date() );
00519 QDate itDate = from.addDays(-duration);
00520
00521 Event::RepeatPattern r = dummy_event.repeatPattern();
00522 if ( !r.hasEndDate || r.endDate() > to ) {
00523 r.setEndDate( to );
00524 r.hasEndDate = TRUE;
00525 }
00526 dummy_event.setRepeat(TRUE, r);
00527
00528 while (nextOccurance(dummy_event, itDate, repeat)) {
00529 if(repeat.date() > to)
00530 break;
00531 effEv.setDate( repeat.date() );
00532 if ((*it).type() == Event::AllDay) {
00533 effEv.setStart( QTime(0,0,0) );
00534 effEv.setEnd( QTime(23,59,59) );
00535 } else {
00536
00537
00538
00539
00540 effEv.setStart( (*it).start().time() );
00541 effEv.setEnd( (*it).end().time() );
00542 }
00543 if ( duration != 0 ) {
00544
00545 QDate sub_it = QMAX( repeat.date(), from );
00546 QDate startDate = repeat.date();
00547 QDate endDate = startDate.addDays( duration );
00548
00549 while ( sub_it <= endDate && sub_it <= to ) {
00550 EffectiveEvent tmpEffEv = effEv;
00551 Event tmpEv = *it;
00552 tmpEffEv.setEvent( tmpEv );
00553
00554 if ( sub_it != startDate )
00555 tmpEffEv.setStart( QTime(0,0,0) );
00556 if ( sub_it != endDate )
00557 tmpEffEv.setEnd( QTime(23,59,59) );
00558 tmpEffEv.setDate( sub_it );
00559 tmpEffEv.setEffectiveDates( startDate, endDate );
00560 tmpList.append( tmpEffEv );
00561 sub_it = sub_it.addDays( 1 );
00562 }
00563 itDate = endDate;
00564 } else {
00565 Event tmpEv = *it;
00566 effEv.setEvent( tmpEv );
00567 tmpList.append( effEv );
00568 itDate = repeat.date().addDays( 1 );
00569 }
00570 }
00571 }
00572
00573 qHeapSort( tmpList );
00574 return tmpList;
00575 }
00576
00577 QValueList<EffectiveEvent> DateBookDB::getEffectiveEvents( const QDateTime &dt)
00578 {
00579 QValueList<EffectiveEvent> day = getEffectiveEvents(dt.date(), dt.date());
00580 QValueListConstIterator<EffectiveEvent> it;
00581 QValueList<EffectiveEvent> tmpList;
00582 QDateTime dtTmp;
00583
00584 for (it = day.begin(); it != day.end(); ++it ) {
00585 dtTmp = QDateTime( (*it).date(), (*it).start() );
00586
00587 if ( QABS(dt.secsTo(dtTmp)) < 60 )
00588 tmpList.append( *it );
00589 }
00590 return tmpList;
00591 }
00592
00593 void DateBookDB::addEvent( const Event &ev, bool doalarm )
00594 {
00595
00596 saveJournalEntry( ev, ACTION_ADD, -1, false );
00597 addJFEvent( ev, doalarm );
00598 d->clean = false;
00599 }
00600
00601 void DateBookDB::addJFEvent( const Event &ev, bool doalarm )
00602 {
00603 if ( doalarm && ev.hasAlarm() )
00604 addEventAlarm( ev );
00605 if ( ev.hasRepeat() )
00606 repeatEvents.append( ev );
00607 else
00608 eventList.append( ev );
00609 }
00610
00611 void DateBookDB::editEvent( const Event &old, Event &editedEv )
00612 {
00613 int oldIndex=0;
00614 bool oldHadRepeat = old.hasRepeat();
00615 Event orig;
00616
00617
00618 if ( oldHadRepeat ) {
00619 if ( origRepeat( old, orig ) )
00620 oldIndex = repeatEvents.findIndex( orig );
00621 } else
00622 oldIndex = eventList.findIndex( old );
00623 saveJournalEntry( editedEv, ACTION_REPLACE, oldIndex, oldHadRepeat );
00624
00625
00626 if ( old.hasAlarm() )
00627 delEventAlarm( old );
00628 if ( oldHadRepeat ) {
00629 if ( editedEv.hasRepeat() ) {
00630
00631
00632
00633
00634 repeatEvents.remove( orig );
00635 } else
00636 removeRepeat( old );
00637 } else {
00638 QValueList<Event>::Iterator it = eventList.find( old );
00639 if ( it != eventList.end() )
00640 eventList.remove( it );
00641 }
00642
00643
00644 if ( editedEv.hasAlarm() )
00645 addEventAlarm( editedEv );
00646 if ( editedEv.hasRepeat() )
00647 repeatEvents.append( editedEv );
00648 else
00649 eventList.append( editedEv );
00650
00651 d->clean = false;
00652 }
00653
00654 void DateBookDB::removeEvent( const Event &ev )
00655 {
00656
00657 saveJournalEntry( ev, ACTION_REMOVE, -1, false );
00658 removeJFEvent( ev );
00659 d->clean = false;
00660 }
00661
00662 void DateBookDB::removeJFEvent( const Event&ev )
00663 {
00664 if ( ev.hasAlarm() )
00665 delEventAlarm( ev );
00666 if ( ev.hasRepeat() ) {
00667 removeRepeat( ev );
00668 } else {
00669 QValueList<Event>::Iterator it = eventList.find( ev );
00670 if ( it != eventList.end() )
00671 eventList.remove( it );
00672 }
00673 }
00674
00675
00676 void DateBookDB::loadFile( const QString &strFile )
00677 {
00678
00679 QFile f( strFile );
00680 if ( !f.open( IO_ReadOnly ) )
00681 return;
00682
00683 enum Attribute {
00684 FDescription = 0,
00685 FLocation,
00686 FCategories,
00687 FUid,
00688 FType,
00689 FAlarm,
00690 FSound,
00691 FRType,
00692 FRWeekdays,
00693 FRPosition,
00694 FRFreq,
00695 FRHasEndDate,
00696 FREndDate,
00697 FRStart,
00698 FREnd,
00699 FNote,
00700 FCreated,
00701 FAction,
00702 FActionKey,
00703 FJournalOrigHadRepeat
00704 };
00705
00706 QAsciiDict<int> dict( 97 );
00707 dict.setAutoDelete( TRUE );
00708 dict.insert( "description", new int(FDescription) );
00709 dict.insert( "location", new int(FLocation) );
00710 dict.insert( "categories", new int(FCategories) );
00711 dict.insert( "uid", new int(FUid) );
00712 dict.insert( "type", new int(FType) );
00713 dict.insert( "alarm", new int(FAlarm) );
00714 dict.insert( "sound", new int(FSound) );
00715 dict.insert( "rtype", new int(FRType) );
00716 dict.insert( "rweekdays", new int(FRWeekdays) );
00717 dict.insert( "rposition", new int(FRPosition) );
00718 dict.insert( "rfreq", new int(FRFreq) );
00719 dict.insert( "rhasenddate", new int(FRHasEndDate) );
00720 dict.insert( "enddt", new int(FREndDate) );
00721 dict.insert( "start", new int(FRStart) );
00722 dict.insert( "end", new int(FREnd) );
00723 dict.insert( "note", new int(FNote) );
00724 dict.insert( "created", new int(FCreated) );
00725 dict.insert( "action", new int(FAction) );
00726 dict.insert( "actionkey", new int(FActionKey) );
00727 dict.insert( "actionorig", new int (FJournalOrigHadRepeat) );
00728
00729
00730 QByteArray ba = f.readAll();
00731 char* dt = ba.data();
00732 int len = ba.size();
00733 int currentAction,
00734 journalKey,
00735 origHadRepeat;
00736
00737 int i = 0;
00738 char *point;
00739
00740 while ( (dt+i != 0) && (( point = strstr( dt+i, "<event " ) ) != 0 )) {
00741 i = point - dt;
00742
00743
00744 currentAction = ACTION_ADD;
00745 journalKey = -1;
00746 origHadRepeat = -1;
00747
00748
00749
00750
00751
00752
00753 int alarmTime = -1; Event::SoundTypeChoice alarmSound = Event::Silent;
00754
00755 Event::RepeatPattern rp;
00756 Event e;
00757
00758 i += 7;
00759
00760 while( 1 ) {
00761 while ( i < len && (dt[i] == ' ' || dt[i] == '\n' || dt[i] == '\r') )
00762 ++i;
00763 if ( i >= len-2 || (dt[i] == '/' && dt[i+1] == '>') )
00764 break;
00765
00766 int j = i;
00767 while ( j < len && dt[j] != '=' )
00768 ++j;
00769 char *attr = dt+i;
00770 dt[j] = '\0';
00771 i = ++j;
00772 while ( i < len && dt[i] != '"' )
00773 ++i;
00774 j = ++i;
00775 bool haveAmp = FALSE;
00776 bool haveUtf = FALSE;
00777 while ( j < len && dt[j] != '"' ) {
00778 if ( dt[j] == '&' )
00779 haveAmp = TRUE;
00780 if ( ((unsigned char)dt[j]) > 0x7f )
00781 haveUtf = TRUE;
00782 ++j;
00783 }
00784
00785 if ( i == j ) {
00786
00787 i = j + 1;
00788 continue;
00789 }
00790
00791 QString value = haveUtf ? QString::fromUtf8( dt+i, j-i )
00792 : QString::fromLatin1( dt+i, j-i );
00793 if ( haveAmp )
00794 value = Qtopia::plainString( value );
00795 i = j + 1;
00796
00797
00798 int * find = dict[ attr ];
00799 #if 1
00800 if ( !find ) {
00801
00802 e.setCustomField(attr, value);
00803 continue;
00804 }
00805
00806 switch( *find ) {
00807 case FDescription:
00808 e.setDescription( value );
00809 break;
00810 case FLocation:
00811 e.setLocation( value );
00812 break;
00813 case FCategories:
00814 e.setCategories( Qtopia::Record::idsFromString( value ) );
00815 break;
00816 case FUid:
00817 e.setUid( value.toInt() );
00818 break;
00819 case FType:
00820 if ( value == "AllDay" )
00821 e.setType( Event::AllDay );
00822 else
00823 e.setType( Event::Normal );
00824 break;
00825 case FAlarm:
00826 alarmTime = value.toInt();
00827 break;
00828 case FSound:
00829 alarmSound = value == "loud" ? Event::Loud : Event::Silent;
00830 break;
00831
00832 case FRType:
00833 if ( value == "Daily" )
00834 rp.type = Event::Daily;
00835 else if ( value == "Weekly" )
00836 rp.type = Event::Weekly;
00837 else if ( value == "MonthlyDay" )
00838 rp.type = Event::MonthlyDay;
00839 else if ( value == "MonthlyDate" )
00840 rp.type = Event::MonthlyDate;
00841 else if ( value == "Yearly" )
00842 rp.type = Event::Yearly;
00843 else
00844 rp.type = Event::NoRepeat;
00845 break;
00846 case FRWeekdays:
00847
00848
00849 if ( value.toInt() != 0 )
00850 rp.days = value.toInt();
00851 else
00852 rp.days = 1;
00853 break;
00854 case FRPosition:
00855 rp.position = value.toInt();
00856 break;
00857 case FRFreq:
00858 rp.frequency = value.toInt();
00859 break;
00860 case FRHasEndDate:
00861 rp.hasEndDate = value.toInt();
00862 break;
00863 case FREndDate: {
00864 rp.endDateUTC = (time_t) value.toLong();
00865 break;
00866 }
00867 case FRStart: {
00868 e.setStart( (time_t) value.toLong() );
00869 break;
00870 }
00871 case FREnd: {
00872 e.setEnd( (time_t) value.toLong() );
00873 break;
00874 }
00875 case FNote:
00876 e.setNotes( value );
00877 break;
00878 case FCreated:
00879 rp.createTime = value.toInt();
00880 break;
00881 case FAction:
00882 currentAction = value.toInt();
00883 break;
00884 case FActionKey:
00885 journalKey = value.toInt();
00886 break;
00887 case FJournalOrigHadRepeat:
00888 origHadRepeat = value.toInt();
00889 break;
00890 default:
00891 qDebug( "huh??? missing enum? -- attr.: %s", attr );
00892 break;
00893 }
00894 #endif
00895 }
00896
00897
00898
00899
00900 if ( rp.type == Event::Weekly && rp.days == 0 )
00901 rp.days = Event::day( e.start().date().dayOfWeek() );
00902
00903
00904
00905 e.setRepeat( rp.type != Event::NoRepeat, rp );
00906
00907 if ( alarmTime != -1 )
00908 e.setAlarm( TRUE, alarmTime, alarmSound );
00909
00910
00911 switch ( currentAction ) {
00912 case ACTION_ADD:
00913 addJFEvent( e );
00914 break;
00915 case ACTION_REMOVE:
00916 removeJFEvent( e );
00917 break;
00918 case ACTION_REPLACE:
00919
00920
00921 if ( journalKey > -1 && origHadRepeat > -1 ) {
00922
00923 if ( origHadRepeat )
00924 removeJFEvent( *(repeatEvents.at(journalKey)) );
00925 else
00926 removeJFEvent( *(eventList.at(journalKey)) );
00927 addJFEvent( e );
00928 }
00929 break;
00930 default:
00931 break;
00932 }
00933 }
00934 f.close();
00935 }
00936
00937 void DateBookDB::init()
00938 {
00939 d = new DateBookDBPrivate;
00940 d->clean = false;
00941 QString str = dateBookFilename();
00942 if ( str.isNull() ) {
00943 QMessageBox::warning( 0, QObject::tr("Out of Space"),
00944 QObject::tr("Unable to create start up files\n"
00945 "Please free up some space\n"
00946 "before entering data") );
00947 }
00948
00949
00950
00951 loadFile( dateBookFilename() );
00952
00953 if ( QFile::exists( dateBookJournalFile() ) ) {
00954
00955 loadFile( dateBookJournalFile() );
00956
00957 save();
00958 }
00959 d->clean = true;
00960 }
00961
00962 bool DateBookDB::save()
00963 {
00964 if ( d->clean == true )
00965 return true;
00966 QValueListIterator<Event> it;
00967 int total_written;
00968 QString strFileNew = dateBookFilename() + ".new";
00969
00970 QFile f( strFileNew );
00971 if ( !f.open( IO_WriteOnly|IO_Raw ) )
00972 return FALSE;
00973
00974 QString buf( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
00975 buf += "<!DOCTYPE DATEBOOK><DATEBOOK>\n";
00976 buf += "<events>\n";
00977 QCString str = buf.utf8();
00978 total_written = f.writeBlock( str.data(), str.length() );
00979 if ( total_written != int(str.length()) ) {
00980 f.close();
00981 QFile::remove( strFileNew );
00982 return false;
00983 }
00984
00985 for ( it = eventList.begin(); it != eventList.end(); ++it ) {
00986 buf = "<event";
00987 (*it).save( buf );
00988 buf += " />\n";
00989 str = buf.utf8();
00990 total_written = f.writeBlock( str.data(), str.length() );
00991 if ( total_written != int(str.length()) ) {
00992 f.close();
00993 QFile::remove( strFileNew );
00994 return false;
00995 }
00996 }
00997 for ( it = repeatEvents.begin(); it != repeatEvents.end(); ++it ) {
00998 buf = "<event";
00999 (*it).save( buf );
01000 buf += " />\n";
01001 str = buf.utf8();
01002 total_written = f.writeBlock( str.data(), str.length() );
01003 if ( total_written != int(str.length()) ) {
01004 f.close();
01005 QFile::remove( strFileNew );
01006 return false;
01007 }
01008 }
01009 buf = "</events>\n</DATEBOOK>\n";
01010 str = buf.utf8();
01011 total_written = f.writeBlock( str.data(), str.length() );
01012 if ( total_written != int(str.length()) ) {
01013 f.close();
01014 QFile::remove( strFileNew );
01015 return false;
01016 }
01017 f.close();
01018
01019
01020 if ( ::rename( strFileNew, dateBookFilename() ) < 0 ) {
01021 qWarning( "problem renaming file %s to %s errno %d",
01022 strFileNew.latin1(), dateBookFilename().latin1(), errno );
01023
01024 QFile::remove( strFileNew );
01025 }
01026
01027
01028 QFile::remove( dateBookJournalFile() );
01029 d->clean = true;
01030 return true;
01031 }
01032
01033 void DateBookDB::reload()
01034 {
01035 QValueList<Event>::Iterator it = eventList.begin();
01036 for ( ; it != eventList.end(); ++it ) {
01037 if ( (*it).hasAlarm() )
01038 delEventAlarm( *it );
01039 if ( (*it).hasRepeat() )
01040 removeRepeat( *it );
01041 }
01042 eventList.clear();
01043 repeatEvents.clear();
01044 init();
01045 }
01046
01047 bool DateBookDB::removeRepeat( const Event &ev )
01048 {
01049 time_t removeMe = ev.repeatPattern().createTime;
01050 QValueListIterator<Event> it;
01051 for ( it = repeatEvents.begin(); it != repeatEvents.end(); ++it ) {
01052 if ( removeMe == (*it).repeatPattern().createTime ) {
01053 (void)repeatEvents.remove( it );
01054
01055 return TRUE;
01056 }
01057 }
01058 return FALSE;
01059 }
01060
01061 bool DateBookDB::origRepeat( const Event &ev, Event &orig ) const
01062 {
01063 time_t removeMe = ev.repeatPattern().createTime;
01064 QValueListConstIterator<Event> it;
01065 for ( it = repeatEvents.begin(); it != repeatEvents.end(); ++it ) {
01066 if ( removeMe == (*it).repeatPattern().createTime ) {
01067 orig = (*it);
01068 return TRUE;
01069 }
01070 }
01071 return FALSE;
01072 }
01073
01074 void DateBookDB::saveJournalEntry( const Event &ev, journal_action action )
01075 {
01076 saveJournalEntry( ev, action, -1, false );
01077 }
01078
01079 bool DateBookDB::saveJournalEntry( const Event &evOld, journal_action action,
01080 int key, bool origHadRepeat )
01081 {
01082 bool status = false;
01083 Event ev = evOld;
01084
01085 QFile f( dateBookJournalFile() );
01086 if ( !f.open( IO_WriteOnly|IO_Append ) )
01087 return false;
01088 QString buf = "<event";
01089 ev.save( buf );
01090 buf += " action=";
01091 buf += "\"" + QString::number(action) + "\"";
01092 buf += " actionkey=\"" + QString::number(key) + "\"";
01093 buf += " actionorig=\"" + QString::number(origHadRepeat) +"\"";
01094 buf += " />\n";
01095 QString str = buf.utf8();
01096 status = ( f.writeBlock( str.data(), str.length() ) == int(str.length()) );
01097 f.close();
01098 return status;
01099 }
01100
01101 QValueList<Event> DateBookDB::getRawRepeats() const
01102 {
01103 return repeatEvents;
01104 }
01105
01106 QValueList<Event> DateBookDB::getNonRepeatingEvents( const QDate &from,
01107 const QDate &to ) const
01108 {
01109 QValueListConstIterator<Event> it;
01110 QDateTime dtTmp, dtEnd;
01111 QValueList<Event> tmpList;
01112 for (it = eventList.begin(); it != eventList.end(); ++it ) {
01113 dtTmp = (*it).start(TRUE);
01114 dtEnd = (*it).end(TRUE);
01115
01116 if ( dtTmp.date() >= from && dtTmp.date() <= to ) {
01117 Event e = *it;
01118 if ( dtTmp.date() != dtEnd.date() )
01119 e.setEnd( QDateTime(dtTmp.date(), QTime(23, 59, 0)) );
01120 tmpList.append( e );
01121 }
01122
01123 if ( dtEnd.date() != dtTmp.date() && dtEnd.date() >= from ) {
01124 QDateTime dt = dtTmp.addDays( 1 );
01125 dt.setTime( QTime(0, 0, 0) );
01126 QDateTime dtStop;
01127 if ( dtEnd > to ) {
01128 dtStop = to;
01129 } else
01130 dtStop = dtEnd;
01131 while ( dt <= dtStop ) {
01132 Event ev = *it;
01133 if ( dt >= from ) {
01134 ev.setStart( QDateTime(dt.date(), QTime(0, 0, 0)) );
01135 if ( dt.date() == dtEnd.date() )
01136 ev.setEnd( QDateTime(dt.date(), dtEnd.time()) );
01137 else
01138 ev.setEnd( QDateTime(dt.date(), QTime(23, 59, 0)) );
01139 tmpList.append( ev );
01140 }
01141 dt = dt.addDays( 1 );
01142 }
01143 }
01144 }
01145 return tmpList;
01146 }