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 "opimrecurrence.h"
00031
00032
00033 #include <opie2/opimtimezone.h>
00034 #include <qpe/timeconversion.h>
00035
00036
00037 #include <qshared.h>
00038
00039
00040 #include <time.h>
00041
00042 namespace Opie {
00043
00044 struct OPimRecurrence::Data : public QShared {
00045 Data() : QShared() {
00046 type = OPimRecurrence::NoRepeat;
00047 freq = -1;
00048 days = 0;
00049 pos = 0;
00050 create = QDateTime::currentDateTime();
00051 hasEnd = FALSE;
00052 end = QDate::currentDate();
00053 }
00054 char days;
00055 OPimRecurrence::RepeatType type;
00056 int freq;
00057 int pos;
00058 bool hasEnd : 1;
00059 QDate end;
00060 QDateTime create;
00061 int rep;
00062 QString app;
00063 ExceptionList list;
00064 QDate start;
00065 };
00066
00067
00068 OPimRecurrence::OPimRecurrence() {
00069 data = new Data;
00070 }
00071
00072 OPimRecurrence::OPimRecurrence( const QMap<int, QString>& map )
00073 {
00074 data = new Data;
00075 fromMap( map );
00076 }
00077
00078
00079 OPimRecurrence::OPimRecurrence( const OPimRecurrence& rec)
00080 : data( rec.data )
00081 {
00082 data->ref();
00083 }
00084
00085
00086 OPimRecurrence::~OPimRecurrence() {
00087 if ( data->deref() ) {
00088 delete data;
00089 data = 0l;
00090 }
00091 }
00092
00093
00094 void OPimRecurrence::deref() {
00095 if ( data->deref() ) {
00096 delete data;
00097 data = 0l;
00098 }
00099 }
00100
00101
00102 bool OPimRecurrence::operator==( const OPimRecurrence& )const {
00103 return false;
00104 }
00105
00106
00107 OPimRecurrence &OPimRecurrence::operator=( const OPimRecurrence& re) {
00108 if ( *this == re ) return *this;
00109
00110 re.data->ref();
00111 deref();
00112 data = re.data;
00113
00114 return *this;
00115 }
00116
00117
00118 bool OPimRecurrence::doesRecur()const {
00119 return !( type() == NoRepeat );
00120 }
00121
00122
00123
00124
00125
00126
00127 bool OPimRecurrence::doesRecur( const QDate& date ) {
00128
00129 QDate da = date.addDays(-1);
00130
00131 QDate recur;
00132 if (!nextOcurrence( da, recur ) )
00133 return false;
00134
00135 return (recur == date);
00136 }
00137
00138
00139
00140
00141
00142 bool OPimRecurrence::nextOcurrence( const QDate& from, QDate& next ) {
00143 bool stillLooking;
00144 stillLooking = p_nextOccurrence( from, next );
00145 while ( stillLooking && data->list.contains(next) )
00146 stillLooking = p_nextOccurrence( next.addDays(1), next );
00147
00148 return stillLooking;
00149 }
00150
00151
00152 bool OPimRecurrence::p_nextOccurrence( const QDate& from, QDate& next ) {
00153
00154
00155 QDate tmpDate;
00156 int freq = frequency();
00157 int diff, diff2, a;
00158 int iday, imonth, iyear;
00159 int dayOfWeek = 0;
00160 int firstOfWeek = 0;
00161 int weekOfMonth;
00162
00163
00164 if (hasEndDate() && endDate() < from)
00165 return FALSE;
00166
00167 if (start() >= from ) {
00168 next = start();
00169 return TRUE;
00170 }
00171
00172 switch ( type() ) {
00173 case Weekly:
00174
00175
00176
00177 dayOfWeek = from.dayOfWeek();
00178 dayOfWeek--;
00179
00180
00181
00182
00183 while(!((1 << firstOfWeek) & days() ))
00184 firstOfWeek++;
00185
00186
00187 while(!((1 << (dayOfWeek % 7)) & days() ))
00188 dayOfWeek++;
00189
00190 dayOfWeek = dayOfWeek % 7;
00191 dayOfWeek -= start().dayOfWeek() -1;
00192
00193 firstOfWeek = firstOfWeek % 7;
00194 firstOfWeek -= start().dayOfWeek() -1;
00195
00196
00197
00198
00199 freq *= 7;
00200
00201 case Daily:
00202
00203 if(start().addDays(dayOfWeek) > from) {
00204
00205 next = QDate(start().addDays(dayOfWeek) );
00206 if ((next > endDate())
00207 && hasEndDate() )
00208 return FALSE;
00209 return TRUE;
00210 }
00211
00212
00213 diff = start().addDays(dayOfWeek).daysTo(from) % freq;
00214 diff2 = start().addDays(firstOfWeek).daysTo(from) % freq;
00215
00216 if(diff != 0)
00217 diff = freq - diff;
00218 if(diff2 != 0)
00219 diff2 = freq - diff2;
00220 diff = QMIN(diff, diff2);
00221
00222 next = QDate(from.addDays(diff));
00223 if ( (next > endDate())
00224 && hasEndDate() )
00225 return FALSE;
00226 return TRUE;
00227 case MonthlyDay:
00228 iday = from.day();
00229 iyear = from.year();
00230 imonth = from.month();
00231
00232 dayOfWeek = start().dayOfWeek();
00233 weekOfMonth = (start().day() - 1) / 7;
00234
00235
00236 a = from.year() - start().year();
00237 a *= 12;
00238 a = a + (imonth - start().month());
00239
00240 if(a % freq) {
00241 a = freq - (a % freq);
00242 imonth = from.month() + a;
00243 if (imonth > 12) {
00244 imonth--;
00245 iyear += imonth / 12;
00246 imonth = imonth % 12;
00247 imonth++;
00248 }
00249 }
00250
00251
00252
00253
00254 tmpDate = QDate( iyear, imonth, 1 );
00255
00256 iday = 1;
00257 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
00258 iday += 7 * weekOfMonth;
00259 while (iday > tmpDate.daysInMonth()) {
00260 imonth += freq;
00261 if (imonth > 12) {
00262 imonth--;
00263 iyear += imonth / 12;
00264 imonth = imonth % 12;
00265 imonth++;
00266 }
00267 tmpDate = QDate( iyear, imonth, 1 );
00268
00269 if ((tmpDate > endDate()) && hasEndDate() )
00270 return FALSE;
00271 iday = 1;
00272 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
00273 iday += 7 * weekOfMonth;
00274 }
00275 tmpDate = QDate(iyear, imonth, iday);
00276
00277 if (tmpDate >= from) {
00278 next = tmpDate;
00279 if ((next > endDate() ) && hasEndDate() )
00280 return FALSE;
00281 return TRUE;
00282 }
00283
00284
00285 do {
00286 imonth += freq;
00287 if (imonth > 12) {
00288 imonth--;
00289 iyear += imonth / 12;
00290 imonth = imonth % 12;
00291 imonth++;
00292 }
00293 tmpDate = QDate( iyear, imonth, 1 );
00294
00295 if ((tmpDate > endDate()) && hasEndDate() )
00296 return FALSE;
00297 iday = 1;
00298 iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7;
00299 iday += 7 * weekOfMonth;
00300 } while (iday > tmpDate.daysInMonth());
00301 tmpDate = QDate(iyear, imonth, iday);
00302
00303 next = tmpDate;
00304 if ((next > endDate()) && hasEndDate() )
00305 return FALSE;
00306 return TRUE;
00307 case MonthlyDate:
00308 iday = start().day();
00309 iyear = from.year();
00310 imonth = from.month();
00311
00312 a = from.year() - start().year();
00313 a *= 12;
00314 a = a + (imonth - start().month());
00315
00316 if(a % freq) {
00317 a = freq - (a % freq);
00318 imonth = from.month() + a;
00319 if (imonth > 12) {
00320 imonth--;
00321 iyear += imonth / 12;
00322 imonth = imonth % 12;
00323 imonth++;
00324 }
00325 }
00326
00327
00328
00329
00330 while(!QDate::isValid(iyear, imonth, iday) ) {
00331 imonth += freq;
00332 if (imonth > 12) {
00333 imonth--;
00334 iyear += imonth / 12;
00335 imonth = imonth % 12;
00336 imonth++;
00337 }
00338
00339 if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
00340 return FALSE;
00341 }
00342
00343 if(QDate(iyear, imonth, iday) >= from) {
00344
00345 next = QDate(iyear, imonth, iday);
00346 if ((next > endDate()) && hasEndDate() )
00347 return FALSE;
00348 return TRUE;
00349 }
00350
00351
00352 imonth += freq;
00353 imonth--;
00354 iyear += imonth / 12;
00355 imonth = imonth % 12;
00356 imonth++;
00357
00358 while(!QDate::isValid(iyear, imonth, iday) ) {
00359 imonth += freq;
00360 imonth--;
00361 iyear += imonth / 12;
00362 imonth = imonth % 12;
00363 imonth++;
00364 if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() )
00365 return FALSE;
00366 }
00367
00368 next = QDate(iyear, imonth, iday);
00369 if ((next > endDate()) && hasEndDate() )
00370 return FALSE;
00371 return TRUE;
00372 case Yearly:
00373 iday = start().day();
00374 imonth = start().month();
00375 iyear = from.year();
00376
00377 diff = 1;
00378 if(imonth == 2 && iday > 28) {
00379
00380 if(freq % 4)
00381 if (freq % 2)
00382 freq = freq * 4;
00383 else
00384 freq = freq * 2;
00385
00386 diff = 4;
00387 }
00388
00389 a = from.year() - start().year();
00390 if(a % freq) {
00391 a = freq - (a % freq);
00392 iyear = iyear + a;
00393 }
00394
00395
00396 if(!QDate::isValid(iyear, imonth, iday)) {
00397
00398 iyear += freq;
00399 }
00400
00401 if(QDate(iyear, imonth, iday) >= from) {
00402 next = QDate(iyear, imonth, iday);
00403
00404 if ((next > endDate()) && hasEndDate() )
00405 return FALSE;
00406 return TRUE;
00407 }
00408
00409 iyear += freq;
00410
00411 if(!QDate::isValid(iyear, imonth, iday)) {
00412
00413 iyear += freq;
00414 }
00415
00416 next = QDate(iyear, imonth, iday);
00417 if ((next > endDate()) && hasEndDate() )
00418 return FALSE;
00419 return TRUE;
00420 default:
00421 return FALSE;
00422 }
00423 }
00424
00425
00426 OPimRecurrence::RepeatType OPimRecurrence::type()const{
00427 return data->type;
00428 }
00429
00430
00431 int OPimRecurrence::frequency()const {
00432 return data->freq;
00433 }
00434
00435
00436 int OPimRecurrence::position()const {
00437 return data->pos;
00438 }
00439
00440
00441 char OPimRecurrence::days() const{
00442 return data->days;
00443 }
00444
00445
00446 bool OPimRecurrence::hasEndDate()const {
00447 return data->hasEnd;
00448 }
00449
00450
00451 QDate OPimRecurrence::endDate()const {
00452 return data->end;
00453 }
00454
00455
00456 QDate OPimRecurrence::start()const{
00457 return data->start;
00458 }
00459
00460
00461 QDateTime OPimRecurrence::createdDateTime()const {
00462 return data->create;
00463 }
00464
00465
00466 int OPimRecurrence::repetition()const {
00467 return data->rep;
00468 }
00469
00470
00471 QString OPimRecurrence::service()const {
00472 return data->app;
00473 }
00474
00475
00476 OPimRecurrence::ExceptionList& OPimRecurrence::exceptions() {
00477 return data->list;
00478 }
00479
00480
00481 void OPimRecurrence::setType( const RepeatType& z) {
00482 checkOrModify();
00483 data->type = z;
00484 }
00485
00486
00487 void OPimRecurrence::setFrequency( int freq ) {
00488 checkOrModify();
00489 data->freq = freq;
00490 }
00491
00492
00493 void OPimRecurrence::setPosition( int pos ) {
00494 checkOrModify();
00495 data->pos = pos;
00496 }
00497
00498
00499 void OPimRecurrence::setDays( char c ) {
00500 checkOrModify();
00501 data->days = c;
00502 }
00503
00504
00505 void OPimRecurrence::setEndDate( const QDate& dt) {
00506 checkOrModify();
00507 data->end = dt;
00508 }
00509
00510
00511 void OPimRecurrence::setCreatedDateTime( const QDateTime& t) {
00512 checkOrModify();
00513 data->create = t;
00514 }
00515
00516
00517 void OPimRecurrence::setHasEndDate( bool b) {
00518 checkOrModify();
00519 data->hasEnd = b;
00520 }
00521
00522
00523 void OPimRecurrence::setRepitition( int rep ) {
00524 checkOrModify();
00525 data->rep = rep;
00526 }
00527
00528
00529 void OPimRecurrence::setService( const QString& app ) {
00530 checkOrModify();
00531 data->app = app;
00532 }
00533
00534
00535 void OPimRecurrence::setStart( const QDate& dt ) {
00536 checkOrModify();
00537 data->start = dt;
00538 }
00539
00540
00541 void OPimRecurrence::checkOrModify() {
00542 if ( data->count != 1 ) {
00543 data->deref();
00544 Data* d2 = new Data;
00545 d2->days = data->days;
00546 d2->type = data->type;
00547 d2->freq = data->freq;
00548 d2->pos = data->pos;
00549 d2->hasEnd = data->hasEnd;
00550 d2->end = data->end;
00551 d2->create = data->create;
00552 d2->rep = data->rep;
00553 d2->app = data->app;
00554 d2->list = data->list;
00555 d2->start = data->start;
00556 data = d2;
00557 }
00558 }
00559
00560
00561 QString OPimRecurrence::toString()const {
00562 QString buf;
00563 QMap<int, QString> recMap = toMap();
00564
00565 buf += " rtype=\"";
00566 buf += recMap[OPimRecurrence::RType];
00567 buf += "\"";
00568 if (data->days > 0 )
00569 buf += " rweekdays=\"" + recMap[OPimRecurrence::RWeekdays] + "\"";
00570 if ( data->pos != 0 )
00571 buf += " rposition=\"" + recMap[OPimRecurrence::RPosition] + "\"";
00572
00573 buf += " rfreq=\"" + recMap[OPimRecurrence::RFreq] + "\"";
00574 buf += " rhasenddate=\"" + recMap[OPimRecurrence::RHasEndDate]+ "\"";
00575 if ( data->hasEnd )
00576 buf += " enddt=\""
00577 + recMap[OPimRecurrence::EndDate]
00578 + "\"";
00579 buf += " created=\"" + recMap[OPimRecurrence::Created] + "\"";
00580
00581 if ( data->list.isEmpty() ) return buf;
00582 buf += " exceptions=\"";
00583 buf += recMap[OPimRecurrence::Exceptions];
00584 buf += "\" ";
00585
00586 return buf;
00587 }
00588
00589 QString OPimRecurrence::rTypeString() const
00590 {
00591 QString retString;
00592 switch ( data->type ) {
00593 case OPimRecurrence::Daily:
00594 retString = "Daily";
00595 break;
00596 case OPimRecurrence::Weekly:
00597 retString = "Weekly";
00598 break;
00599 case OPimRecurrence::MonthlyDay:
00600 retString = "MonthlyDay";
00601 break;
00602 case OPimRecurrence::MonthlyDate:
00603 retString = "MonthlyDate";
00604 break;
00605 case OPimRecurrence::Yearly:
00606 retString = "Yearly";
00607 break;
00608 default:
00609 retString = "NoRepeat";
00610 break;
00611
00612 }
00613
00614 return retString;
00615 }
00616
00617 QMap<QString, OPimRecurrence::RepeatType> OPimRecurrence::rTypeValueConvertMap() const
00618 {
00619 QMap<QString, RepeatType> convertMap;
00620
00621 convertMap.insert( QString( "Daily" ), OPimRecurrence::Daily );
00622 convertMap.insert( QString( "Weekly" ), OPimRecurrence::Weekly );
00623 convertMap.insert( QString( "MonthlyDay" ), OPimRecurrence::MonthlyDay );
00624 convertMap.insert( QString( "MonthlyDate" ), OPimRecurrence::MonthlyDate );
00625 convertMap.insert( QString( "Yearly" ), OPimRecurrence::Yearly );
00626 convertMap.insert( QString( "NoRepeat" ), OPimRecurrence::NoRepeat );
00627
00628 return convertMap;
00629 }
00630
00631
00632 QMap<int, QString> OPimRecurrence::toMap() const
00633 {
00634 QMap<int, QString> retMap;
00635
00636 retMap.insert( OPimRecurrence::RType, rTypeString() );
00637 retMap.insert( OPimRecurrence::RWeekdays, QString::number( static_cast<int>( data->days ) ) );
00638 retMap.insert( OPimRecurrence::RPosition, QString::number(data->pos ) );
00639 retMap.insert( OPimRecurrence::RFreq, QString::number( data->freq ) );
00640 retMap.insert( OPimRecurrence::RHasEndDate, QString::number( static_cast<int>( data->hasEnd ) ) );
00641 if( data -> hasEnd )
00642 retMap.insert( OPimRecurrence::EndDate, QString::number( OPimTimeZone::current().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) );
00643 retMap.insert( OPimRecurrence::Created, QString::number( OPimTimeZone::current().fromUTCDateTime( data->create ) ) );
00644
00645 if ( data->list.isEmpty() ) return retMap;
00646
00647
00648 ExceptionList::ConstIterator it;
00649 ExceptionList list = data->list;
00650 QString exceptBuf;
00651 QDate date;
00652 for ( it = list.begin(); it != list.end(); ++it ) {
00653 date = (*it);
00654 if ( it != list.begin() ) exceptBuf += " ";
00655
00656 exceptBuf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() );
00657 }
00658
00659 retMap.insert( OPimRecurrence::Exceptions, exceptBuf );
00660
00661 return retMap;
00662 }
00663
00664 void OPimRecurrence::fromMap( const QMap<int, QString>& map )
00665 {
00666 QMap<QString, RepeatType> repTypeMap = rTypeValueConvertMap();
00667
00668 data -> type = repTypeMap[ map [OPimRecurrence::RType] ];
00669 data -> days = (char) map[ OPimRecurrence::RWeekdays ].toInt();
00670 data -> pos = map[ OPimRecurrence::RPosition ].toInt();
00671 data -> freq = map[ OPimRecurrence::RFreq ].toInt();
00672 data -> hasEnd= map[ OPimRecurrence::RHasEndDate ].toInt() ? true : false;
00673 OPimTimeZone cur = OPimTimeZone::current();
00674 if ( data -> hasEnd ){
00675 data -> end = cur.fromUTCDateTime( (time_t) map[ OPimRecurrence::EndDate ].toLong() ).date();
00676 }
00677 data -> create = cur.fromUTCDateTime( (time_t) map[ OPimRecurrence::Created ].toLong() ).date();
00678
00679 #if 0
00680
00681
00682 data -> list.clear();
00683 QString exceptStr = map[ OPimRecurrence::Exceptions ];
00684 QStringList exceptList = QStringList::split( " ", exceptStr );
00685 ...
00686 #endif
00687
00688
00689 }
00690
00691 }