-rw-r--r-- | libopie/pim/orecur.cpp | 147 |
1 files changed, 111 insertions, 36 deletions
diff --git a/libopie/pim/orecur.cpp b/libopie/pim/orecur.cpp index eae1fdc..8c9ad46 100644 --- a/libopie/pim/orecur.cpp +++ b/libopie/pim/orecur.cpp @@ -1,510 +1,585 @@ #include <time.h> #include <qshared.h> #include <qtopia/timeconversion.h> #include "otimezone.h" #include "orecur.h" struct ORecur::Data : public QShared { Data() : QShared() { type = ORecur::NoRepeat; freq = -1; days = 0; pos = 0; create = QDateTime::currentDateTime(); hasEnd = FALSE; end = QDate::currentDate(); } char days; // Q_UINT8 for 8 seven days;) ORecur::RepeatType type; int freq; int pos; bool hasEnd : 1; QDate end; QDateTime create; int rep; QString app; ExceptionList list; QDate start; }; ORecur::ORecur() { data = new Data; } ORecur::ORecur( const ORecur& rec) : data( rec.data ) { data->ref(); } ORecur::~ORecur() { if ( data->deref() ) { delete data; data = 0l; } } void ORecur::deref() { if ( data->deref() ) { delete data; data = 0l; } } bool ORecur::operator==( const ORecur& )const { return false; } ORecur &ORecur::operator=( const ORecur& re) { if ( *this == re ) return *this; re.data->ref(); deref(); data = re.data; return *this; } bool ORecur::doesRecur()const { return !( type() == NoRepeat ); } /* * we try to be smart here * */ bool ORecur::doesRecur( const QDate& date ) { /* the day before the recurrance */ QDate da = date.addDays(-1); QDate recur; if (!nextOcurrence( da, recur ) ) return false; return (recur == date); } // FIXME unuglify! // GPL from Datebookdb.cpp // FIXME exception list! bool ORecur::nextOcurrence( const QDate& from, QDate& next ) { bool stillLooking; stillLooking = p_nextOccurrence( from, next ); while ( stillLooking && data->list.contains(next) ) stillLooking = p_nextOccurrence( next.addDays(1), next ); return stillLooking; } bool ORecur::p_nextOccurrence( const QDate& from, QDate& next ) { // easy checks, first are we too far in the future or too far in the past? QDate tmpDate; int freq = frequency(); int diff, diff2, a; int iday, imonth, iyear; int dayOfWeek = 0; int firstOfWeek = 0; int weekOfMonth; if (hasEndDate() && endDate() < from) return FALSE; if (start() >= from ) { next = start(); return TRUE; } switch ( type() ) { case Weekly: /* weekly is just daily by 7 */ /* first convert the repeatPattern.Days() mask to the next day of week valid after from */ dayOfWeek = from.dayOfWeek(); dayOfWeek--; /* we want 0-6, doco for above specs 1-7 */ /* this is done in case freq > 1 and from in week not for this round */ // firstOfWeek = 0; this is already done at decl. while(!((1 << firstOfWeek) & days() )) firstOfWeek++; /* there is at least one 'day', or there would be no event */ while(!((1 << (dayOfWeek % 7)) & days() )) dayOfWeek++; dayOfWeek = dayOfWeek % 7; /* the actual day of week */ dayOfWeek -= start().dayOfWeek() -1; firstOfWeek = firstOfWeek % 7; /* the actual first of week */ firstOfWeek -= start().dayOfWeek() -1; // dayOfWeek may be negitive now // day of week is number of days to add to start day freq *= 7; // FALL-THROUGH !!!!! case Daily: // the add is for the possible fall through from weekly */ if(start().addDays(dayOfWeek) > from) { /* first week exception */ next = QDate(start().addDays(dayOfWeek) ); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; } /* if from is middle of a non-week */ diff = start().addDays(dayOfWeek).daysTo(from) % freq; diff2 = start().addDays(firstOfWeek).daysTo(from) % freq; if(diff != 0) diff = freq - diff; if(diff2 != 0) diff2 = freq - diff2; diff = QMIN(diff, diff2); next = QDate(from.addDays(diff)); if ( (next > endDate()) && hasEndDate() ) return FALSE; return TRUE; case MonthlyDay: iday = from.day(); iyear = from.year(); imonth = from.month(); /* find equivelent day of month for this month */ dayOfWeek = start().dayOfWeek(); weekOfMonth = (start().day() - 1) / 7; /* work out when the next valid month is */ a = from.year() - start().year(); a *= 12; a = a + (imonth - start().month()); /* a is e.start()monthsFrom(from); */ if(a % freq) { a = freq - (a % freq); imonth = from.month() + a; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } } /* imonth is now the first month after or on from that matches the frequency given */ /* find for this month */ tmpDate = QDate( iyear, imonth, 1 ); iday = 1; iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; iday += 7 * weekOfMonth; while (iday > tmpDate.daysInMonth()) { imonth += freq; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } tmpDate = QDate( iyear, imonth, 1 ); /* these loops could go for a while, check end case now */ if ((tmpDate > endDate()) && hasEndDate() ) return FALSE; iday = 1; iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; iday += 7 * weekOfMonth; } tmpDate = QDate(iyear, imonth, iday); if (tmpDate >= from) { next = tmpDate; if ((next > endDate() ) && hasEndDate() ) return FALSE; return TRUE; } /* need to find the next iteration */ do { imonth += freq; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } tmpDate = QDate( iyear, imonth, 1 ); /* these loops could go for a while, check end case now */ if ((tmpDate > endDate()) && hasEndDate() ) return FALSE; iday = 1; iday += (7 + dayOfWeek - tmpDate.dayOfWeek()) % 7; iday += 7 * weekOfMonth; } while (iday > tmpDate.daysInMonth()); tmpDate = QDate(iyear, imonth, iday); next = tmpDate; if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; case MonthlyDate: iday = start().day(); iyear = from.year(); imonth = from.month(); a = from.year() - start().year(); a *= 12; a = a + (imonth - start().month()); /* a is e.start()monthsFrom(from); */ if(a % freq) { a = freq - (a % freq); imonth = from.month() + a; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } } /* imonth is now the first month after or on from that matches the frequencey given */ /* this could go for a while, worse case, 4*12 iterations, probably */ while(!QDate::isValid(iyear, imonth, iday) ) { imonth += freq; if (imonth > 12) { imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; } /* these loops could go for a while, check end case now */ if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) return FALSE; } if(QDate(iyear, imonth, iday) >= from) { /* done */ next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; } /* ok, need to cycle */ imonth += freq; imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; while(!QDate::isValid(iyear, imonth, iday) ) { imonth += freq; imonth--; iyear += imonth / 12; imonth = imonth % 12; imonth++; if ((QDate(iyear, imonth, 1) > endDate()) && hasEndDate() ) return FALSE; } next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; case Yearly: iday = start().day(); imonth = start().month(); iyear = from.year(); // after all, we want to start in this year diff = 1; if(imonth == 2 && iday > 28) { /* leap year, and it counts, calculate actual frequency */ if(freq % 4) if (freq % 2) freq = freq * 4; else freq = freq * 2; /* else divides by 4 already, leave freq alone */ diff = 4; } a = from.year() - start().year(); if(a % freq) { a = freq - (a % freq); iyear = iyear + a; } /* under the assumption we won't hit one of the special not-leap years twice */ if(!QDate::isValid(iyear, imonth, iday)) { /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ iyear += freq; } if(QDate(iyear, imonth, iday) >= from) { next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; } /* iyear == from.year(), need to advance again */ iyear += freq; /* under the assumption we won't hit one of the special not-leap years twice */ if(!QDate::isValid(iyear, imonth, iday)) { /* must have been skipping by leap years and hit one that wasn't, (e.g. 2100) */ iyear += freq; } next = QDate(iyear, imonth, iday); if ((next > endDate()) && hasEndDate() ) return FALSE; return TRUE; default: return FALSE; } } ORecur::RepeatType ORecur::type()const{ return data->type; } int ORecur::frequency()const { return data->freq; } int ORecur::position()const { return data->pos; } char ORecur::days() const{ return data->days; } bool ORecur::hasEndDate()const { return data->hasEnd; } QDate ORecur::endDate()const { return data->end; } QDate ORecur::start()const{ return data->start; } QDateTime ORecur::createdDateTime()const { return data->create; } int ORecur::repetition()const { return data->rep; } QString ORecur::service()const { return data->app; } ORecur::ExceptionList& ORecur::exceptions() { return data->list; } void ORecur::setType( const RepeatType& z) { checkOrModify(); data->type = z; } void ORecur::setFrequency( int freq ) { checkOrModify(); data->freq = freq; } void ORecur::setPosition( int pos ) { checkOrModify(); data->pos = pos; } void ORecur::setDays( char c ) { checkOrModify(); data->days = c; } void ORecur::setEndDate( const QDate& dt) { checkOrModify(); data->end = dt; } void ORecur::setCreatedDateTime( const QDateTime& t) { checkOrModify(); data->create = t; } void ORecur::setHasEndDate( bool b) { checkOrModify(); data->hasEnd = b; } void ORecur::setRepitition( int rep ) { checkOrModify(); data->rep = rep; } void ORecur::setService( const QString& app ) { checkOrModify(); data->app = app; } void ORecur::setStart( const QDate& dt ) { checkOrModify(); data->start = dt; } void ORecur::checkOrModify() { if ( data->count != 1 ) { data->deref(); Data* d2 = new Data; d2->days = data->days; d2->type = data->type; d2->freq = data->freq; d2->pos = data->pos; d2->hasEnd = data->hasEnd; d2->end = data->end; d2->create = data->create; d2->rep = data->rep; d2->app = data->app; d2->list = data->list; d2->start = data->start; data = d2; } } QString ORecur::toString()const { QString buf; + QMap<int, QString> recMap = toMap(); buf += " rtype=\""; - switch ( data->type ) { - case ORecur::Daily: - buf += "Daily"; - break; - case ORecur::Weekly: - buf += "Weekly"; - break; - case ORecur::MonthlyDay: - buf += "MonthlyDay"; - break; - case ORecur::MonthlyDate: - buf += "MonthlyDate"; - break; - case ORecur::Yearly: - buf += "Yearly"; - break; - default: - buf += "NoRepeat"; - break; - } + buf += recMap[ORecur::RType]; buf += "\""; if (data->days > 0 ) - buf += " rweekdays=\"" + QString::number( static_cast<int>( data->days ) ) + "\""; + buf += " rweekdays=\"" + recMap[ORecur::RWeekdays] + "\""; if ( data->pos != 0 ) - buf += " rposition=\"" + QString::number(data->pos ) + "\""; + buf += " rposition=\"" + recMap[ORecur::RPosition] + "\""; - buf += " rfreq=\"" + QString::number( data->freq ) + "\""; - buf += " rhasenddate=\"" + QString::number( static_cast<int>( data->hasEnd ) ) + "\""; + buf += " rfreq=\"" + recMap[ORecur::RFreq] + "\""; + buf += " rhasenddate=\"" + recMap[ORecur::RHasEndDate]+ "\""; if ( data->hasEnd ) buf += " enddt=\"" - + QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) + + recMap[ORecur::EndDate] + "\""; - buf += " created=\"" + QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) + "\""; + buf += " created=\"" + recMap[ORecur::Created] + "\""; if ( data->list.isEmpty() ) return buf; - // save exceptions list here!! - ExceptionList::ConstIterator it; - ExceptionList list = data->list; buf += " exceptions=\""; - QDate date; - for ( it = list.begin(); it != list.end(); ++it ) { - date = (*it); - if ( it != list.begin() ) buf += " "; - - buf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() ); - } + buf += recMap[ORecur::Exceptions]; buf += "\" "; return buf; } + +QString ORecur::rTypeString() const +{ + QString retString; + switch ( data->type ) { + case ORecur::Daily: + retString = "Daily"; + break; + case ORecur::Weekly: + retString = "Weekly"; + break; + case ORecur::MonthlyDay: + retString = "MonthlyDay"; + break; + case ORecur::MonthlyDate: + retString = "MonthlyDate"; + break; + case ORecur::Yearly: + retString = "Yearly"; + break; + default: + retString = "NoRepeat"; + break; + + } + + return retString; +} + +QMap<QString, ORecur::RepeatType> ORecur::rTypeValueConvertMap() const +{ + QMap<QString, RepeatType> convertMap; + + convertMap.insert( QString( "Daily" ), ORecur::Daily ); + convertMap.insert( QString( "Weekly" ), ORecur::Weekly ); + convertMap.insert( QString( "MonthlyDay" ), ORecur::MonthlyDay ); + convertMap.insert( QString( "MonthlyDate" ), ORecur::MonthlyDate ); + convertMap.insert( QString( "Yearly" ), ORecur::Yearly ); + convertMap.insert( QString( "NoRepeat" ), ORecur::NoRepeat ); + + return convertMap; +} + + +QMap<int, QString> ORecur::toMap() const +{ + QMap<int, QString> retMap; + + retMap.insert( ORecur::RType, rTypeString() ); + retMap.insert( ORecur::RWeekdays, QString::number( static_cast<int>( data->days ) ) ); + retMap.insert( ORecur::RPosition, QString::number(data->pos ) ); + retMap.insert( ORecur::RFreq, QString::number( data->freq ) ); + retMap.insert( ORecur::RHasEndDate, QString::number( static_cast<int>( data->hasEnd ) ) ); + if( data -> hasEnd ) + retMap.insert( ORecur::EndDate, QString::number( OTimeZone::utc().fromUTCDateTime( QDateTime( data->end, QTime(12,0,0) ) ) ) ); + retMap.insert( ORecur::Created, QString::number( OTimeZone::utc().fromUTCDateTime( data->create ) ) ); + + if ( data->list.isEmpty() ) return retMap; + + // save exceptions list here!! + ExceptionList::ConstIterator it; + ExceptionList list = data->list; + QString exceptBuf; + QDate date; + for ( it = list.begin(); it != list.end(); ++it ) { + date = (*it); + if ( it != list.begin() ) exceptBuf += " "; + + exceptBuf += QCString().sprintf("%04d%02d%02d", date.year(), date.month(), date.day() ); + } + + retMap.insert( ORecur::Exceptions, exceptBuf ); + + return retMap; +} + +void ORecur::fromMap( const QMap<int, QString>& map ) +{ + QMap<QString, RepeatType> repTypeMap = rTypeValueConvertMap(); + + data -> type = repTypeMap[ map [ORecur::RType] ]; + data -> days = (char) map[ ORecur::RWeekdays ].toInt(); + data -> pos = map[ ORecur::RPosition ].toInt(); + data -> freq = map[ ORecur::RFreq ].toInt(); + data -> hasEnd= map[ ORecur::RHasEndDate ].toInt() ? true : false; + OTimeZone utc = OTimeZone::utc(); + if ( data -> hasEnd ){ + data -> end = utc.fromUTCDateTime( (time_t) map[ ORecur::EndDate ].toLong() ).date(); + } + data -> create = utc.fromUTCDateTime( (time_t) map[ ORecur::Created ].toLong() ).date(); + +#if 0 + // FIXME: Exceptions currently not supported... + // Convert the list of exceptions from QString into ExceptionList + data -> list.clear(); + QString exceptStr = map[ ORecur::Exceptions ]; + QStringList exceptList = QStringList::split( " ", exceptStr ); + ... +#endif + + +} |