void Recurrence::addMonthlyPos( short pos, const QBitArray &days ) { // Allow 53 for yearly! if ( d->mRecurReadOnly || pos > 53 || pos < -53 ) { return; } RecurrenceRule *rrule = defaultRRule( false ); if ( !rrule ) { return; } bool changed = false; QList<RecurrenceRule::WDayPos> positions = rrule->byDays(); for ( int i = 0; i < 7; ++i ) { if ( days.testBit( i ) ) { RecurrenceRule::WDayPos p( pos, i + 1 ); if ( !positions.contains( p ) ) { changed = true; positions.append( p ); } } } if ( changed ) { rrule->setByDays( positions ); updated(); } }
void Recurrence::setWeekly( int freq, int weekStart ) { RecurrenceRule *rrule = setNewRecurrenceType( RecurrenceRule::rWeekly, freq ); if ( !rrule ) { return; } rrule->setWeekStart( weekStart ); updated(); }
// Emulate the old behavior QList<int> Recurrence::monthDays() const { RecurrenceRule *rrule = defaultRRuleConst(); if ( rrule ) { return rrule->byMonthDays(); } else { return QList<int>(); } }
// Emulate the old behaviour. Make this methods just an interface to the // first rrule void Recurrence::setFrequency( int freq ) { if ( d->mRecurReadOnly || freq <= 0 ) { return; } RecurrenceRule *rrule = defaultRRule( true ); if ( rrule ) { rrule->setFrequency( freq ); } updated(); }
void Recurrence::setEndDateTime( const KDateTime &dateTime ) { if ( d->mRecurReadOnly ) { return; } RecurrenceRule *rrule = defaultRRule( true ); if ( !rrule ) { return; } rrule->setEndDt( dateTime ); updated(); }
void Recurrence::setDuration( int duration ) { if ( d->mRecurReadOnly ) { return; } RecurrenceRule *rrule = defaultRRule( true ); if ( !rrule ) { return; } rrule->setDuration( duration ); updated(); }
// Daynumber within year void Recurrence::addYearlyDay( int day ) { RecurrenceRule *rrule = defaultRRule( false ); // It must already exist! if ( !rrule ) { return; } QList<int> days = rrule->byYearDays(); if ( !days.contains( day ) ) { days << day; rrule->setByYearDays( days ); updated(); } }
RecurrenceRule *Recurrence::defaultRRule( bool create ) const { if ( d->mRRules.isEmpty() ) { if ( !create || d->mRecurReadOnly ) { return 0; } RecurrenceRule *rrule = new RecurrenceRule(); rrule->setStartDt( startDateTime() ); const_cast<KCalCore::Recurrence*>( this )->addRRule( rrule ); return rrule; } else { return d->mRRules[0]; } }
void CompatPre35::fixRecurrence( const Incidence::Ptr &incidence ) { Recurrence *recurrence = incidence->recurrence(); if ( recurrence ) { KDateTime start( incidence->dtStart() ); // kde < 3.5 only had one rrule, so no need to loop over all RRULEs. RecurrenceRule *r = recurrence->defaultRRule(); if ( r && !r->dateMatchesRules( start ) ) { recurrence->addExDateTime( start ); } } // Call base class method now that everything else is done Compat::fixRecurrence( incidence ); }
// Emulate the old behavior QBitArray Recurrence::days() const { QBitArray days( 7 ); days.fill( 0 ); RecurrenceRule *rrule = defaultRRuleConst(); if ( rrule ) { QList<RecurrenceRule::WDayPos> bydays = rrule->byDays(); for ( int i = 0; i < bydays.size(); ++i ) { if ( bydays.at( i ).pos() == 0 ) { days.setBit( bydays.at( i ).day() - 1 ); } } } return days; }
Recurrence::Recurrence( const Recurrence &r ) : RecurrenceRule::RuleObserver(), d( new KCalCore::Recurrence::Private( *r.d ) ) { int i, end; for ( i = 0, end = r.d->mRRules.count(); i < end; ++i ) { RecurrenceRule *rule = new RecurrenceRule( *r.d->mRRules[i] ); d->mRRules.append( rule ); rule->addObserver( this ); } for ( i = 0, end = r.d->mExRules.count(); i < end; ++i ) { RecurrenceRule *rule = new RecurrenceRule( *r.d->mExRules[i] ); d->mExRules.append( rule ); rule->addObserver( this ); } }
RecurrenceRule *Recurrence::setNewRecurrenceType( RecurrenceRule::PeriodType type, int freq ) { if ( d->mRecurReadOnly || freq <= 0 ) { return 0; } d->mRRules.clearAll(); updated(); RecurrenceRule *rrule = defaultRRule( true ); if ( !rrule ) { return 0; } rrule->setRecurrenceType( type ); rrule->setFrequency( freq ); rrule->setDuration( -1 ); return rrule; }
// month part of date within year void Recurrence::addYearlyMonth( short month ) { if ( d->mRecurReadOnly || month < 1 || month > 12 ) { return; } RecurrenceRule *rrule = defaultRRule( false ); if ( !rrule ) { return; } QList<int> months = rrule->byMonths(); if ( !months.contains( month ) ) { months << month; rrule->setByMonths( months ); updated(); } }
void Recurrence::addMonthlyDate( short day ) { if ( d->mRecurReadOnly || day > 31 || day < -31 ) { return; } RecurrenceRule *rrule = defaultRRule( true ); if ( !rrule ) { return; } QList<int> monthDays = rrule->byMonthDays(); if ( !monthDays.contains( day ) ) { monthDays.append( day ); rrule->setByMonthDays( monthDays ); updated(); } }
void Recurrence::addMonthlyPos( short pos, ushort day ) { // Allow 53 for yearly! if ( d->mRecurReadOnly || pos > 53 || pos < -53 ) { return; } RecurrenceRule *rrule = defaultRRule( false ); if ( !rrule ) { return; } QList<RecurrenceRule::WDayPos> positions = rrule->byDays(); RecurrenceRule::WDayPos p( pos, day ); if ( !positions.contains( p ) ) { positions.append( p ); rrule->setByDays( positions ); updated(); } }
void CompatPre31::fixRecurrence( const Incidence::Ptr &incidence ) { CompatPre32::fixRecurrence( incidence ); Recurrence *recur = incidence->recurrence(); RecurrenceRule *r = 0; if ( recur ) { r = recur->defaultRRule(); } if ( recur && r ) { int duration = r->duration(); if ( duration > 0 ) { // Backwards compatibility for KDE < 3.1. // rDuration was set to the number of time periods to recur, // with week start always on a Monday. // Convert this to the number of occurrences. r->setDuration( -1 ); QDate end( r->startDt().date() ); bool doNothing = false; // # of periods: int tmp = ( duration - 1 ) * r->frequency(); switch ( r->recurrenceType() ) { case RecurrenceRule::rWeekly: { end = end.addDays( tmp * 7 + 7 - end.dayOfWeek() ); break; } case RecurrenceRule::rMonthly: { int month = end.month() - 1 + tmp; end.setDate( end.year() + month / 12, month % 12 + 1, 31 ); break; } case RecurrenceRule::rYearly: { end.setDate( end.year() + tmp, 12, 31 ); break; } default: doNothing = true; break; } if ( !doNothing ) { duration = r->durationTo( KDateTime( end, QTime( 0, 0, 0 ), incidence->dtStart().timeSpec() ) ); r->setDuration( duration ); } } /* addYearlyNum */ // Dates were stored as day numbers, with a fiddle to take account of // leap years. Convert the day number to a month. QList<int> days = r->byYearDays(); if ( !days.isEmpty() ) { QList<int> months = r->byMonths(); for ( int i = 0; i < months.size(); ++i ) { int newmonth = QDate( r->startDt().date().year(), 1, 1 ).addDays( months.at( i ) - 1 ).month(); if ( !months.contains( newmonth ) ) { months.append( newmonth ); } } r->setByMonths( months ); days.clear(); r->setByYearDays( days ); } } }
/****************************************************************************** * Return the date/time of the last recurrence. */ QDateTime KARecurrence::endDateTime() const { if(mFeb29Type == FEB29_FEB29 || duration() <= 1) { /* Either it doesn't have any special February 29th treatment, * it's infinite (count = -1), the end date is specified * (count = 0), or it ends on the start date (count = 1). * So just use the normal KCal end date calculation. */ return Recurrence::endDateTime(); } /* Create a temporary recurrence rule to find the end date. * In a standard KCal recurrence, the 29th February only occurs once every * 4 years. So shift the temporary recurrence date to the 28th to ensure * that it occurs every year, thus giving the correct occurrence count. */ RecurrenceRule *rrule = new RecurrenceRule(); rrule->setRecurrenceType(RecurrenceRule::rYearly); QDateTime dt = startDateTime(); QDate d = dt.date(); switch(d.day()) { case 29: // The start date is definitely a recurrence date, so shift // start date to the temporary recurrence date of the 28th d.setYMD(d.year(), d.month(), 28); break; case 28: if(d.month() != 2 || mFeb29Type != FEB29_FEB28 || QDate::leapYear(d.year())) { // Start date is not a recurrence date, so shift it to 27th d.setYMD(d.year(), d.month(), 27); } break; case 1: if(d.month() == 3 && mFeb29Type == FEB29_MAR1 && !QDate::leapYear(d.year())) { // Start date is a March 1st recurrence date, so shift // start date to the temporary recurrence date of the 28th d.setYMD(d.year(), 2, 28); } break; default: break; } dt.setDate(d); rrule->setStartDt(dt); rrule->setFloats(doesFloat()); rrule->setFrequency(frequency()); rrule->setDuration(duration()); QValueList<int> ds; ds.append(28); rrule->setByMonthDays(ds); rrule->setByMonths(defaultRRuleConst()->byMonths()); dt = rrule->endDt(); delete rrule; // We've found the end date for a recurrence on the 28th. Unless that date // is a real February 28th recurrence, adjust to the actual recurrence date. if(mFeb29Type == FEB29_FEB28 && dt.date().month() == 2 && !QDate::leapYear(dt.date().year())) return dt; return dt.addDays(1); }
int Recurrence::duration() const { RecurrenceRule *rrule = defaultRRuleConst(); return rrule ? rrule->duration() : 0; }
int Recurrence::durationTo( const KDateTime &datetime ) const { // Emulate old behavior: This is just an interface to the first rule! RecurrenceRule *rrule = defaultRRuleConst(); return rrule ? rrule->durationTo( datetime ) : 0; }
int Recurrence::frequency() const { RecurrenceRule *rrule = defaultRRuleConst(); return rrule ? rrule->frequency() : 0; }
QList<int> Recurrence::yearMonths() const { RecurrenceRule *rrule = defaultRRuleConst(); return rrule ? rrule->byMonths() : QList<int>(); }
// Emulate the old behavior QList<RecurrenceRule::WDayPos> Recurrence::monthPositions() const { RecurrenceRule *rrule = defaultRRuleConst(); return rrule ? rrule->byDays() : QList<RecurrenceRule::WDayPos>(); }
int Recurrence::weekStart() const { RecurrenceRule *rrule = defaultRRuleConst(); return rrule ? rrule->weekStart() : 1; }
/****************************************************************************** * Must be called after presetting with a KCal::Recurrence, to convert the * recurrence to KARecurrence types: * - Convert hourly recurrences to minutely. * - Remove all but the first day in yearly date recurrences. * - Check for yearly recurrences falling on February 29th and adjust them as * necessary. A 29th of the month rule can be combined with either a 60th day * of the year rule or a last day of February rule. */ void KARecurrence::fix() { mCachedType = -1; mFeb29Type = FEB29_FEB29; int convert = 0; int days[2] = { 0, 0 }; RecurrenceRule *rrules[2]; RecurrenceRule::List rrulelist = rRules(); RecurrenceRule::List::ConstIterator rr = rrulelist.begin(); for(int i = 0; i < 2 && rr != rrulelist.end(); ++i, ++rr) { RecurrenceRule *rrule = *rr; rrules[i] = rrule; bool stop = true; int rtype = recurrenceType(rrule); switch(rtype) { case rHourly: // Convert an hourly recurrence to a minutely one rrule->setRecurrenceType(RecurrenceRule::rMinutely); rrule->setFrequency(rrule->frequency() * 60); // fall through to rMinutely case rMinutely: case rDaily: case rWeekly: case rMonthlyDay: case rMonthlyPos: case rYearlyPos: if(!convert) ++rr; // remove all rules except the first break; case rOther: if(dailyType(rrule)) { // it's a daily rule with BYDAYS if(!convert) ++rr; // remove all rules except the first } break; case rYearlyDay: { // Ensure that the yearly day number is 60 (i.e. Feb 29th/Mar 1st) if(convert) { // This is the second rule. // Ensure that it can be combined with the first one. if(days[0] != 29 || rrule->frequency() != rrules[0]->frequency() || rrule->startDt() != rrules[0]->startDt()) break; } QValueList<int> ds = rrule->byYearDays(); if(!ds.isEmpty() && ds.first() == 60) { ++convert; // this rule needs to be converted days[i] = 60; stop = false; break; } break; // not day 60, so remove this rule } case rYearlyMonth: { QValueList<int> ds = rrule->byMonthDays(); if(!ds.isEmpty()) { int day = ds.first(); if(convert) { // This is the second rule. // Ensure that it can be combined with the first one. if(day == days[0] || day == -1 && days[0] == 60 || rrule->frequency() != rrules[0]->frequency() || rrule->startDt() != rrules[0]->startDt()) break; } if(ds.count() > 1) { ds.clear(); // remove all but the first day ds.append(day); rrule->setByMonthDays(ds); } if(day == -1) { // Last day of the month - only combine if it's February QValueList<int> months = rrule->byMonths(); if(months.count() != 1 || months.first() != 2) day = 0; } if(day == 29 || day == -1) { ++convert; // this rule may need to be converted days[i] = day; stop = false; break; } } if(!convert) ++rr; break; } default: break; } if(stop) break; } // Remove surplus rules for(; rr != rrulelist.end(); ++rr) { removeRRule(*rr); delete *rr; } QDate end; int count; QValueList<int> months; if(convert == 2) { // There are two yearly recurrence rules to combine into a February 29th recurrence. // Combine the two recurrence rules into a single rYearlyMonth rule falling on Feb 29th. // Find the duration of the two RRULEs combined, using the shorter of the two if they differ. if(days[0] != 29) { // Swap the two rules so that the 29th rule is the first RecurrenceRule *rr = rrules[0]; rrules[0] = rrules[1]; // the 29th rule rrules[1] = rr; int d = days[0]; days[0] = days[1]; days[1] = d; // the non-29th day } // If February is included in the 29th rule, remove it to avoid duplication months = rrules[0]->byMonths(); if(months.remove(2)) rrules[0]->setByMonths(months); count = combineDurations(rrules[0], rrules[1], end); mFeb29Type = (days[1] == 60) ? FEB29_MAR1 : FEB29_FEB28; } else if(convert == 1 && days[0] == 60) { // There is a single 60th day of the year rule. // Convert it to a February 29th recurrence. count = duration(); if(!count) end = endDate(); mFeb29Type = FEB29_MAR1; } else return; // Create the new February 29th recurrence setNewRecurrenceType(RecurrenceRule::rYearly, frequency()); RecurrenceRule *rrule = defaultRRule(); months.append(2); rrule->setByMonths(months); QValueList<int> ds; ds.append(29); rrule->setByMonthDays(ds); if(count) setDuration(count); else setEndDate(end); }