00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "opimevent.h"
00031
00032
00033 #include <opie2/opimrecurrence.h>
00034 #include <opie2/opimresolver.h>
00035 #include <opie2/opimnotifymanager.h>
00036 #include <opie2/odebug.h>
00037
00038 #include <qpe/categories.h>
00039 #include <qpe/stringutil.h>
00040
00041
00042
00043 namespace Opie
00044 {
00045
00046 int OCalendarHelper::week( const QDate& date )
00047 {
00048
00049
00050 int week = 1;
00051 QDate tmp( date.year(), date.month(), 1 );
00052 if ( date.dayOfWeek() < tmp.dayOfWeek() )
00053 ++week;
00054
00055 week += ( date.day() - 1 ) / 7;
00056
00057 return week;
00058 }
00059
00060
00061 int OCalendarHelper::ocurrence( const QDate& date )
00062 {
00063
00064
00065 return ( date.day() - 1 ) / 7 + 1;
00066 }
00067
00068
00069 int OCalendarHelper::dayOfWeek( char day )
00070 {
00071 int dayOfWeek = 1;
00072 char i = OPimRecurrence::MON;
00073 while ( !( i & day ) && i <= static_cast<char>(OPimRecurrence::SUN) )
00074 {
00075 i <<= 1;
00076 ++dayOfWeek;
00077 }
00078 return dayOfWeek;
00079 }
00080
00081
00082 int OCalendarHelper::monthDiff( const QDate& first, const QDate& second )
00083 {
00084 return ( second.year() - first.year() ) * 12 +
00085 second.month() - first.month();
00086 }
00087
00088
00089 struct OPimEvent::Data : public QShared
00090 {
00091 Data() : QShared()
00092 {
00093 child = 0;
00094 recur = 0;
00095 manager = 0;
00096 isAllDay = false;
00097 parent = 0;
00098 }
00099 ~Data()
00100 {
00101 delete manager;
00102 delete recur;
00103 }
00104 QString description;
00105 QString location;
00106 OPimNotifyManager* manager;
00107 OPimRecurrence* recur;
00108 QString note;
00109 QDateTime created;
00110 QDateTime start;
00111 QDateTime end;
00112 bool isAllDay : 1;
00113 QString timezone;
00114 QArray<int>* child;
00115 int parent;
00116 };
00117
00118
00119 OPimEvent::OPimEvent( int uid )
00120 : OPimRecord( uid )
00121 {
00122 data = new Data;
00123 }
00124
00125
00126 OPimEvent::OPimEvent( const OPimEvent& ev )
00127 : OPimRecord( ev ), data( ev.data )
00128 {
00129 data->ref();
00130 }
00131
00132
00133 OPimEvent::OPimEvent( const QMap<int, QString> map )
00134 : OPimRecord( 0 )
00135 {
00136 data = new Data;
00137
00138 fromMap( map );
00139 }
00140
00141
00142 OPimEvent::~OPimEvent()
00143 {
00144 if ( data->deref() )
00145 {
00146 delete data;
00147 data = 0;
00148 }
00149 }
00150
00151
00152 OPimEvent& OPimEvent::operator=( const OPimEvent& ev )
00153 {
00154 if ( this == &ev ) return * this;
00155
00156 OPimRecord::operator=( ev );
00157 ev.data->ref();
00158 deref();
00159 data = ev.data;
00160
00161
00162 return *this;
00163 }
00164
00165
00166 QString OPimEvent::description() const
00167 {
00168 return data->description;
00169 }
00170
00171
00172 void OPimEvent::setDescription( const QString& description )
00173 {
00174 changeOrModify();
00175 data->description = description;
00176 }
00177
00178
00179 void OPimEvent::setLocation( const QString& loc )
00180 {
00181 changeOrModify();
00182 data->location = loc;
00183 }
00184
00185
00186 QString OPimEvent::location() const
00187 {
00188 return data->location;
00189 }
00190
00191
00192 OPimNotifyManager &OPimEvent::notifiers() const
00193 {
00194
00195
00196
00197 if ( !data->manager )
00198 data->manager = new OPimNotifyManager;
00199
00200 return *data->manager;
00201 }
00202
00203
00204 bool OPimEvent::hasNotifiers() const
00205 {
00206 if ( !data->manager )
00207 return false;
00208 if ( data->manager->reminders().isEmpty() &&
00209 data->manager->alarms().isEmpty() )
00210 return false;
00211
00212 return true;
00213 }
00214
00215
00216 OPimRecurrence OPimEvent::recurrence() const
00217 {
00218 if ( !data->recur )
00219 data->recur = new OPimRecurrence;
00220
00221 return *data->recur;
00222 }
00223
00224
00225 void OPimEvent::setRecurrence( const OPimRecurrence& rec )
00226 {
00227 changeOrModify();
00228 if ( data->recur )
00229 ( *data->recur ) = rec;
00230 else
00231 data->recur = new OPimRecurrence( rec );
00232 }
00233
00234
00235 bool OPimEvent::hasRecurrence() const
00236 {
00237 if ( !data->recur ) return false;
00238 return data->recur->doesRecur();
00239 }
00240
00241
00242 QString OPimEvent::note() const
00243 {
00244 return data->note;
00245 }
00246
00247
00248 void OPimEvent::setNote( const QString& note )
00249 {
00250 changeOrModify();
00251 data->note = note;
00252 }
00253
00254
00255 QDateTime OPimEvent::createdDateTime() const
00256 {
00257 return data->created;
00258 }
00259
00260
00261 void OPimEvent::setCreatedDateTime( const QDateTime& time )
00262 {
00263 changeOrModify();
00264 data->created = time;
00265 }
00266
00267
00268 QDateTime OPimEvent::startDateTime() const
00269 {
00270 if ( data->isAllDay )
00271 return QDateTime( data->start.date(), QTime( 0, 0, 0 ) );
00272 return data->start;
00273 }
00274
00275
00276 QDateTime OPimEvent::startDateTimeInZone() const
00277 {
00278
00279 if ( data->timezone.isEmpty() || data->isAllDay || data->timezone == OPimTimeZone::current().timeZone() ) return startDateTime();
00280
00281 OPimTimeZone zone( data->timezone );
00282 return zone.toDateTime( data->start, OPimTimeZone::current() );
00283 }
00284
00285
00286 void OPimEvent::setStartDateTime( const QDateTime& dt )
00287 {
00288 changeOrModify();
00289 data->start = dt;
00290 }
00291
00292
00293 QDateTime OPimEvent::endDateTime() const
00294 {
00295
00296
00297
00298
00299 if ( data->isAllDay ) {
00300 QDate end = data->end.isValid() ? data->end.date() : data->start.date() ;
00301 return QDateTime( end, QTime( 23, 59, 59 ) );
00302 }
00303 return data->end;
00304 }
00305
00306
00307 QDateTime OPimEvent::endDateTimeInZone() const
00308 {
00309
00310 if ( data->timezone.isEmpty() || data->isAllDay || data->timezone == OPimTimeZone::current().timeZone() ) return endDateTime();
00311
00312 OPimTimeZone zone( data->timezone );
00313 return zone.toDateTime( data->end, OPimTimeZone::current() );
00314 }
00315
00316
00317 void OPimEvent::setEndDateTime( const QDateTime& dt )
00318 {
00319 changeOrModify();
00320 data->end = dt;
00321 }
00322
00323
00324 bool OPimEvent::isMultipleDay() const
00325 {
00326 return data->end.date().day() - data->start.date().day();
00327 }
00328
00329
00330 bool OPimEvent::isAllDay() const
00331 {
00332 return data->isAllDay;
00333 }
00334
00335
00336 void OPimEvent::setAllDay( bool allDay )
00337 {
00338 changeOrModify();
00339 data->isAllDay = allDay;
00340 }
00341
00342
00343 void OPimEvent::setTimeZone( const QString& tz )
00344 {
00345 changeOrModify();
00346 data->timezone = tz;
00347 }
00348
00349
00350 QString OPimEvent::timeZone() const
00351 {
00352 if ( data->isAllDay ) return QString::fromLatin1( "Europe/London" );
00353 return data->timezone;
00354 }
00355
00356
00357 bool OPimEvent::match( const QRegExp& re ) const
00358 {
00359 if ( re.match( data->description ) != -1 )
00360 {
00361 setLastHitField( Qtopia::DatebookDescription );
00362 return true;
00363 }
00364 if ( re.match( data->note ) != -1 )
00365 {
00366 setLastHitField( Qtopia::Note );
00367 return true;
00368 }
00369 if ( re.match( data->location ) != -1 )
00370 {
00371 setLastHitField( Qtopia::Location );
00372 return true;
00373 }
00374 if ( re.match( data->start.toString() ) != -1 )
00375 {
00376 setLastHitField( Qtopia::StartDateTime );
00377 return true;
00378 }
00379 if ( re.match( data->end.toString() ) != -1 )
00380 {
00381 setLastHitField( Qtopia::EndDateTime );
00382 return true;
00383 }
00384 return false;
00385 }
00386
00387
00388 QString OPimEvent::toRichText() const
00389 {
00390 QString text, value;
00391
00392
00393 text += "<b><h3><img src=\"datebook/DateBook\">";
00394 if ( !description().isEmpty() )
00395 {
00396 text += Qtopia::escapeString( description() ).replace( QRegExp( "[\n]" ), "" );
00397 }
00398 text += "</h3></b><br><hr><br>";
00399
00400
00401 if ( !( value = location() ).isEmpty() )
00402 {
00403 text += "<b>" + QObject::tr( "Location:" ) + "</b> ";
00404 text += Qtopia::escapeString( value ) + "<br>";
00405 }
00406
00407
00408 if ( isAllDay() )
00409 {
00410 text += "<b><i>" + QObject::tr( "This is an all day event" ) + "</i></b><br>";
00411 }
00412
00413 else if ( isMultipleDay () )
00414 {
00415 text += "<b><i>" + QObject::tr( "This is a multiple day event" ) + "</i></b><br>";
00416 }
00417
00418 else
00419 {
00420
00421 if ( startDateTime().isValid() )
00422 {
00423 text += "<b>" + QObject::tr( "Start:" ) + "</b> ";
00424 text += Qtopia::escapeString( startDateTime().toString() ).
00425 replace( QRegExp( "[\n]" ), "<br>" ) + "<br>";
00426 }
00427
00428
00429 if ( endDateTime().isValid() )
00430 {
00431 text += "<b>" + QObject::tr( "End:" ) + "</b> ";
00432 text += Qtopia::escapeString( endDateTime().toString() ).
00433 replace( QRegExp( "[\n]" ), "<br>" ) + "<br>";
00434 }
00435 }
00436
00437
00438 if ( categoryNames( "Calendar" ).count() )
00439 {
00440 text += "<b>" + QObject::tr( "Category:" ) + "</b> ";
00441 text += categoryNames( "Calendar" ).join( ", " );
00442 text += "<br>";
00443 }
00444
00445
00446 if ( !note().isEmpty() )
00447 {
00448 text += "<b>" + QObject::tr( "Note:" ) + "</b><br>";
00449 text += note();
00450
00451
00452 }
00453 return text;
00454 }
00455
00456
00457 QString OPimEvent::toShortText() const
00458 {
00459 QString text;
00460 text += QString::number( startDateTime().date().day() );
00461 text += ".";
00462 text += QString::number( startDateTime().date().month() );
00463 text += ".";
00464 text += QString::number( startDateTime().date().year() );
00465 text += " ";
00466 text += QString::number( startDateTime().time().hour() );
00467 text += ":";
00468 text += QString::number( startDateTime().time().minute() );
00469 text += " - ";
00470 text += description();
00471 return text;
00472 }
00473
00474
00475 QString OPimEvent::type() const
00476 {
00477 return QString::fromLatin1( "OPimEvent" );
00478 }
00479
00480
00481 QString OPimEvent::recordField( int ) const
00482 {
00483 return QString::null;
00484 }
00485
00486
00487 int OPimEvent::rtti() const
00488 {
00489 return OPimResolver::DateBook;
00490 }
00491
00504 OPimEvent* OPimEvent::safeCast( const OPimRecord* rec) {
00505 return ( rec && rec->rtti() == OPimResolver::DateBook ) ?
00506 static_cast<OPimEvent*>( const_cast<OPimRecord*>(rec) ) :
00507 0l;
00508 }
00509
00510
00511
00512 bool OPimEvent::loadFromStream( QDataStream& )
00513 {
00514 return true;
00515 }
00516
00517
00518 bool OPimEvent::saveToStream( QDataStream& ) const
00519 {
00520 return true;
00521 }
00522
00523
00524 void OPimEvent::changeOrModify()
00525 {
00526 if ( data->count != 1 )
00527 {
00528 data->deref();
00529 Data* d2 = new Data;
00530 d2->description = data->description;
00531 d2->location = data->location;
00532
00533 if ( data->manager )
00534 d2->manager = new OPimNotifyManager( *data->manager );
00535
00536 if ( data->recur )
00537 d2->recur = new OPimRecurrence( *data->recur );
00538
00539 d2->note = data->note;
00540 d2->created = data->created;
00541 d2->start = data->start;
00542 d2->end = data->end;
00543 d2->isAllDay = data->isAllDay;
00544 d2->timezone = data->timezone;
00545 d2->parent = data->parent;
00546
00547 if ( data->child )
00548 {
00549 d2->child = new QArray<int>( *data->child );
00550 d2->child->detach();
00551 }
00552
00553 data = d2;
00554 }
00555 }
00556
00557
00558 void OPimEvent::deref()
00559 {
00560 if ( data->deref() )
00561 {
00562 delete data;
00563 data = 0;
00564 }
00565 }
00566
00567
00568
00569
00570
00571 QMap<int, QString> OPimEvent::toMap() const
00572 {
00573 QMap<int, QString> retMap;
00574
00575 retMap.insert( OPimEvent::FUid, QString::number( uid() ) );
00576 retMap.insert( OPimEvent::FCategories, Qtopia::escapeString( Qtopia::Record::idsToString( categories() ) ) );
00577 retMap.insert( OPimEvent::FDescription, Qtopia::escapeString( description() ) );
00578 retMap.insert( OPimEvent::FLocation, Qtopia::escapeString( location() ) );
00579 retMap.insert( OPimEvent::FType, isAllDay() ? "AllDay" : "" );
00580 if ( notifiers().alarms().count() ){
00581
00582 OPimAlarm alarm = notifiers().alarms() [ 0 ];
00583 retMap.insert( OPimEvent::FAlarm, QString::number( alarm.dateTime().secsTo( startDateTime() ) / 60 ) );
00584 retMap.insert( OPimEvent::FSound, ( alarm.sound() == OPimAlarm::Loud ) ? "loud" : "silent" );
00585 }
00586
00587
00588 OPimTimeZone zone( (timeZone().isEmpty()||isAllDay()) ? OPimTimeZone::utc() : OPimTimeZone::current() );
00589 retMap.insert( OPimEvent::FStart, QString::number( zone.fromDateTime( startDateTime())));
00590 retMap.insert( OPimEvent::FEnd, QString::number( zone.fromDateTime( endDateTime() )));
00591 retMap.insert( OPimEvent::FNote, Qtopia::escapeString( note() ) );
00592 retMap.insert( OPimEvent::FTimeZone, timeZone().isEmpty() ? QString( "None" ) : timeZone() );
00593 if ( parent() )
00594 retMap.insert( OPimEvent::FRecParent, QString::number( parent() ) );
00595 if ( children().count() )
00596 {
00597 QArray<int> childr = children();
00598 QString buf;
00599 for ( uint i = 0; i < childr.count(); i++ )
00600 {
00601 if ( i != 0 ) buf += " ";
00602 buf += QString::number( childr[ i ] );
00603 }
00604 retMap.insert( OPimEvent::FRecChildren, buf );
00605 }
00606
00607
00608 if ( hasRecurrence() )
00609 {
00610 OPimRecurrence recur = recurrence();
00611 QMap<int, QString> recFields = recur.toMap();
00612 retMap.insert( OPimEvent::FRType, recFields[ OPimRecurrence::RType ] );
00613 retMap.insert( OPimEvent::FRWeekdays, recFields[ OPimRecurrence::RWeekdays ] );
00614 retMap.insert( OPimEvent::FRPosition, recFields[ OPimRecurrence::RPosition ] );
00615 retMap.insert( OPimEvent::FRFreq, recFields[ OPimRecurrence::RFreq ] );
00616 retMap.insert( OPimEvent::FRHasEndDate, recFields[ OPimRecurrence::RHasEndDate ] );
00617 retMap.insert( OPimEvent::FREndDate, recFields[ OPimRecurrence::EndDate ] );
00618 retMap.insert( OPimEvent::FRCreated, recFields[ OPimRecurrence::Created ] );
00619 retMap.insert( OPimEvent::FRExceptions, recFields[ OPimRecurrence::Exceptions ] );
00620 }
00621 else
00622 {
00623 OPimRecurrence recur = recurrence();
00624 QMap<int, QString> recFields = recur.toMap();
00625 retMap.insert( OPimEvent::FRType, recFields[ OPimRecurrence::RType ] );
00626 }
00627
00628 return retMap;
00629 }
00630
00631
00632 void OPimEvent::fromMap( const QMap<int, QString>& map )
00633 {
00634
00635
00636 if ( !map[ OPimEvent::FUid ].isEmpty() )
00637 setUid( map[ OPimEvent::FUid ].toInt() );
00638
00639 setCategories( idsFromString( map[ OPimEvent::FCategories ] ) );
00640 setDescription( map[ OPimEvent::FDescription ] );
00641 setLocation( map[ OPimEvent::FLocation ] );
00642
00643 if ( map[ OPimEvent::FType ] == "AllDay" )
00644 setAllDay( true );
00645 else
00646 setAllDay( false );
00647
00648 if ( !map[ OPimEvent::FTimeZone ].isEmpty() && ( map[ OPimEvent::FTimeZone ] != "None" ) )
00649 {
00650 setTimeZone( map[ OPimEvent::FTimeZone ] );
00651 }
00652
00653 time_t start = ( time_t ) map[ OPimEvent::FStart ].toLong();
00654 time_t end = ( time_t ) map[ OPimEvent::FEnd ].toLong();
00655
00656
00657 if ( isAllDay() )
00658 {
00659 OPimTimeZone utc = OPimTimeZone::utc();
00660 setStartDateTime(utc.toDateTime( start ) );
00661 setEndDateTime ( utc.toDateTime( end ) );
00662 }
00663 else {
00664
00665 OPimTimeZone to_zone( timeZone().isEmpty() ? OPimTimeZone::utc() : OPimTimeZone::current() );
00666
00667 setStartDateTime(to_zone.toDateTime( start));
00668 setEndDateTime (to_zone.toDateTime( end));
00669 }
00670
00671 int alarmTime = -1;
00672 if ( !map[ OPimEvent::FAlarm ].isEmpty() )
00673 alarmTime = map[ OPimEvent::FAlarm ].toInt();
00674
00675 int sound = ( ( map[ OPimEvent::FSound ] == "loud" ) ? OPimAlarm::Loud : OPimAlarm::Silent );
00676 if ( ( alarmTime != -1 ) )
00677 {
00678 QDateTime dt = startDateTime().addSecs( -1 * alarmTime * 60 );
00679 OPimAlarm al( sound , dt );
00680 notifiers().add( al );
00681 }
00682
00683
00684 if ( !map[ OPimEvent::FNote ].isEmpty() )
00685 setNote( map[ OPimEvent::FNote ] );
00686
00687 if ( !map[ OPimEvent::FRecParent ].isEmpty() )
00688 setParent( map[ OPimEvent::FRecParent ].toInt() );
00689
00690 if ( !map[ OPimEvent::FRecChildren ].isEmpty() )
00691 {
00692 QStringList list = QStringList::split( ' ', map[ OPimEvent::FRecChildren ] );
00693 for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
00694 {
00695 addChild( ( *it ).toInt() );
00696 }
00697 }
00698
00699
00700 if ( !map[ OPimEvent::FRType ].isEmpty() )
00701 {
00702 QMap<int, QString> recFields;
00703 recFields.insert( OPimRecurrence::RType, map[ OPimEvent::FRType ] );
00704 recFields.insert( OPimRecurrence::RWeekdays, map[ OPimEvent::FRWeekdays ] );
00705 recFields.insert( OPimRecurrence::RPosition, map[ OPimEvent::FRPosition ] );
00706 recFields.insert( OPimRecurrence::RFreq, map[ OPimEvent::FRFreq ] );
00707 recFields.insert( OPimRecurrence::RHasEndDate, map[ OPimEvent::FRHasEndDate ] );
00708 recFields.insert( OPimRecurrence::EndDate, map[ OPimEvent::FREndDate ] );
00709 recFields.insert( OPimRecurrence::Created, map[ OPimEvent::FRCreated ] );
00710 recFields.insert( OPimRecurrence::Exceptions, map[ OPimEvent::FRExceptions ] );
00711 OPimRecurrence recur( recFields );
00712 setRecurrence( recur );
00713 }
00714
00715 }
00716
00717
00718 int OPimEvent::parent() const
00719 {
00720 return data->parent;
00721 }
00722
00723
00724 void OPimEvent::setParent( int uid )
00725 {
00726 changeOrModify();
00727 data->parent = uid;
00728 }
00729
00730
00731 QArray<int> OPimEvent::children() const
00732 {
00733 if ( !data->child ) return QArray<int>();
00734 else
00735 return data->child->copy();
00736 }
00737
00738
00739 void OPimEvent::setChildren( const QArray<int>& arr )
00740 {
00741 changeOrModify();
00742 if ( data->child ) delete data->child;
00743
00744 data->child = new QArray<int>( arr );
00745 data->child->detach();
00746 }
00747
00748
00749 void OPimEvent::addChild( int uid )
00750 {
00751 changeOrModify();
00752 if ( !data->child )
00753 {
00754 data->child = new QArray<int>( 1 );
00755 ( *data->child ) [ 0 ] = uid;
00756 }
00757 else
00758 {
00759 int count = data->child->count();
00760 data->child->resize( count + 1 );
00761 ( *data->child ) [ count ] = uid;
00762 }
00763 }
00764
00765
00766 void OPimEvent::removeChild( int uid )
00767 {
00768 if ( !data->child || !data->child->contains( uid ) ) return ;
00769 changeOrModify();
00770 QArray<int> newAr( data->child->count() - 1 );
00771 int j = 0;
00772 uint count = data->child->count();
00773 for ( uint i = 0; i < count; i++ )
00774 {
00775 if ( ( *data->child ) [ i ] != uid )
00776 {
00777 newAr[ j ] = ( *data->child ) [ i ];
00778 j++;
00779 }
00780 }
00781 ( *data->child ) = newAr;
00782 }
00783
00784 }