void CompatPre32::fixRecurrence( const Incidence::Ptr &incidence ) { Recurrence *recurrence = incidence->recurrence(); if ( recurrence->recurs() && recurrence->duration() > 0 ) { recurrence->setDuration( recurrence->duration() + incidence->recurrence()->exDates().count() ); } // Call base class method now that everything else is done CompatPre35::fixRecurrence( incidence ); }
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 ); }
/****************************************************************************** * Get the previous time the recurrence occurred, strictly before a specified time. */ QDateTime KARecurrence::getPreviousDateTime(const QDateTime &afterDateTime) const { switch(type()) { case ANNUAL_DATE: case ANNUAL_POS: { Recurrence recur; writeRecurrence(recur); return recur.getPreviousDateTime(afterDateTime); } default: return Recurrence::getPreviousDateTime(afterDateTime); } }
/****************************************************************************** * Get the next time the recurrence occurs, strictly after a specified time. */ QDateTime KARecurrence::getNextDateTime(const QDateTime &preDateTime) const { switch(type()) { case ANNUAL_DATE: case ANNUAL_POS: { Recurrence recur; writeRecurrence(recur); return recur.getNextDateTime(preDateTime); } default: return Recurrence::getNextDateTime(preDateTime); } }
//@cond PRIVATE bool Todo::Private::recurTodo( Todo *todo ) { if ( todo->recurs() ) { Recurrence *r = todo->recurrence(); KDateTime endDateTime = r->endDateTime(); KDateTime nextDate = r->getNextDateTime( todo->dtDue() ); if ( ( r->duration() == -1 || ( nextDate.isValid() && endDateTime.isValid() && nextDate <= endDateTime ) ) ) { while ( !todo->recursAt( nextDate ) || nextDate <= KDateTime::currentUtcDateTime() ) { if ( !nextDate.isValid() || ( nextDate > endDateTime && r->duration() != -1 ) ) { return false; } nextDate = r->getNextDateTime( nextDate ); } todo->setDtDue( nextDate ); todo->setCompleted( false ); todo->setRevision( todo->revision() + 1 ); return true; } } return false; }
void KOWhatsNextView::updateView() { KIconLoader kil("kdepim"); QString *ipath = new QString(); kil.loadIcon("kdepim",KIcon::NoGroup,32,KIcon::DefaultState,ipath); mText = "<table width=\"100%\">\n"; mText += "<tr bgcolor=\"#3679AD\"><td><h1>"; mText += "<img src=\""; mText += *ipath; mText += "\">"; mText += "<font color=\"white\"> "; mText += i18n("What's Next?") + "</font></h1>"; mText += "</td></tr>\n<tr><td>"; mText += "<h2>"; if ( mStartDate.daysTo( mEndDate ) < 1 ) { mText += KGlobal::locale()->formatDate( mStartDate ); } else { mText += i18n("Date from - to", "%1 - %2") .arg( KGlobal::locale()->formatDate( mStartDate ) ) .arg( KGlobal::locale()->formatDate( mEndDate ) ); } mText+="</h2>\n"; Event::List events; for ( QDate date = mStartDate; date <= mEndDate; date = date.addDays( 1 ) ) events += calendar()->events(date, EventSortStartDate, SortDirectionAscending); if (events.count() > 0) { mText += "<p></p>"; kil.loadIcon("appointment",KIcon::NoGroup,22,KIcon::DefaultState,ipath); mText += "<h2><img src=\""; mText += *ipath; mText += "\">"; mText += i18n("Events:") + "</h2>\n"; mText += "<table>\n"; Event::List::ConstIterator it; for( it = events.begin(); it != events.end(); ++it ) { Event *ev = *it; if ( !ev->doesRecur() ){ appendEvent(ev); } else { // FIXME: This should actually be cleaned up. Libkcal should // provide a method to return a list of all recurrences in a // given time span. Recurrence *recur = ev->recurrence(); int duration = ev->dtStart().secsTo( ev->dtEnd() ); QDateTime start = recur->getPreviousDateTime( QDateTime( mStartDate, QTime() ) ); QDateTime end = start.addSecs( duration ); if ( end.date() >= mStartDate ) { appendEvent( ev, start, end ); } start = recur->getNextDateTime( start ); while ( start.isValid() && start.date() <= mEndDate ) { appendEvent( ev, start ); start = recur->getNextDateTime( start ); } } } mText += "</table>\n"; } mTodos.clear(); Todo::List todos = calendar()->todos( TodoSortDueDate, SortDirectionAscending ); if ( todos.count() > 0 ) { kil.loadIcon("todo",KIcon::NoGroup,22,KIcon::DefaultState,ipath); mText += "<h2><img src=\""; mText += *ipath; mText += "\">"; mText += i18n("To-do:") + "</h2>\n"; mText += "<ul>\n"; Todo::List::ConstIterator it; for( it = todos.begin(); it != todos.end(); ++it ) { Todo *todo = *it; if ( !todo->isCompleted() && todo->hasDueDate() && todo->dtDue().date() <= mEndDate ) appendTodo(todo); } bool gotone = false; int priority = 1; while (!gotone && priority<=9 ) { for( it = todos.begin(); it != todos.end(); ++it ) { Todo *todo = *it; if (!todo->isCompleted() && (todo->priority() == priority) ) { appendTodo(todo); gotone = true; } } priority++; kdDebug(5850) << "adding the todos..." << endl; } mText += "</ul>\n"; } QStringList myEmails( KOPrefs::instance()->allEmails() ); int replies = 0; events = calendar()->events( QDate::currentDate(), QDate(2975,12,6) ); Event::List::ConstIterator it2; for( it2 = events.begin(); it2 != events.end(); ++it2 ) { Event *ev = *it2; Attendee *me = ev->attendeeByMails( myEmails ); if (me!=0) { if (me->status()==Attendee::NeedsAction && me->RSVP()) { if (replies == 0) { mText += "<p></p>"; kil.loadIcon("reply",KIcon::NoGroup,22,KIcon::DefaultState,ipath); mText += "<h2><img src=\""; mText += *ipath; mText += "\">"; mText += i18n("Events and to-dos that need a reply:") + "</h2>\n"; mText += "<table>\n"; } replies++; appendEvent( ev ); } } } todos = calendar()->todos(); Todo::List::ConstIterator it3; for( it3 = todos.begin(); it3 != todos.end(); ++it3 ) { Todo *to = *it3; Attendee *me = to->attendeeByMails( myEmails ); if (me!=0) { if (me->status()==Attendee::NeedsAction && me->RSVP()) { if (replies == 0) { mText += "<p></p>"; kil.loadIcon("reply",KIcon::NoGroup,22,KIcon::DefaultState,ipath); mText += "<h2><img src=\""; mText += *ipath; mText += "\">"; mText += i18n("Events and to-dos that need a reply:") + "</h2>\n"; mText += "<table>\n"; } replies++; appendEvent(to); } } kdDebug () << "check for todo-replies..." << endl; } if (replies > 0 ) mText += "</table>\n"; mText += "</td></tr>\n</table>\n"; kdDebug(5850) << "KOWhatsNextView::updateView: text: " << mText << endl; delete ipath; mView->setText(mText); }
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 ); } } }
void KCalResourceSlox::parseRecurrence( const QDomNode &node, Event *event ) { QString type; int dailyValue = -1; KDateTime end; int weeklyValue = -1; QBitArray days( 7 ); // days, starting with monday bool daysSet = false; int monthlyValueDay = -1; int monthlyValueMonth = -1; int yearlyValueDay = -1; int yearlyMonth = -1; int monthly2Recurrency = 0; int monthly2Day = 0; int monthly2ValueMonth = -1; int yearly2Recurrency = 0; int yearly2Day = 0; int yearly2Month = -1; DateList deleteExceptions; QDomNode n; for( n = node.firstChild(); !n.isNull(); n = n.nextSibling() ) { QDomElement e = n.toElement(); QString tag = e.tagName(); QString text = decodeText( e.text() ); kDebug() << tag << ":" << text; if ( tag == fieldName( RecurrenceType ) ) { type = text; } else if ( tag == "daily_value" ) { dailyValue = text.toInt(); } else if ( tag == fieldName( RecurrenceEnd ) ) { end = WebdavHandler::sloxToKDateTime( text ); } else if ( tag == "weekly_value" ) { weeklyValue = text.toInt(); } else if ( tag.left( 11 ) == "weekly_day_" ) { int day = tag.mid( 11, 1 ).toInt(); int index; if ( day == 1 ) index = 0; else index = day - 2; days.setBit( index ); } else if ( tag == "monthly_value_day" ) { monthlyValueDay = text.toInt(); } else if ( tag == "monthly_value_month" ) { monthlyValueMonth = text.toInt(); } else if ( tag == "yearly_value_day" ) { yearlyValueDay = text.toInt(); } else if ( tag == "yearly_month" ) { yearlyMonth = text.toInt(); } else if ( tag == "monthly2_recurrency" ) { monthly2Recurrency = text.toInt(); } else if ( tag == "monthly2_day" ) { monthly2Day = text.toInt(); } else if ( tag == "monthly2_value_month" ) { monthly2ValueMonth = text.toInt(); } else if ( tag == "yearly2_reccurency" ) { // this is not a typo, this is what SLOX really sends! yearly2Recurrency = text.toInt(); } else if ( tag == "yearly2_day" ) { yearly2Day = text.toInt(); } else if ( tag == "yearly2_month" ) { yearly2Month = text.toInt() + 1; // OX recurrence fields } else if ( tag == "interval" ) { dailyValue = text.toInt(); weeklyValue = text.toInt(); monthlyValueMonth = text.toInt(); monthly2ValueMonth = text.toInt(); } else if ( tag == "days" ) { int tmp = text.toInt(); // OX encodes days binary: 1=Su, 2=Mo, 4=Tu, ... for ( int i = 0; i < 7; ++i ) { if ( tmp & (1 << i) ) days.setBit( (i + 6) % 7 ); } daysSet = true; } else if ( tag == "day_in_month" ) { monthlyValueDay = text.toInt(); monthly2Recurrency = text.toInt(); yearlyValueDay = text.toInt(); yearly2Recurrency = text.toInt(); } else if ( tag == "month" ) { yearlyMonth = text.toInt() + 1; // starts at 0 yearly2Month = text.toInt() + 1; } else if ( tag == fieldName( RecurrenceDelEx ) ) { QStringList exdates = text.split( "," ); QStringList::ConstIterator it; for ( it = exdates.constBegin(); it != exdates.constEnd(); ++it ) deleteExceptions.append( WebdavHandler::sloxToKDateTime( *it ).date() ); } } if ( daysSet && type == "monthly" ) type = "monthly2"; // HACK: OX doesn't cleanly distinguish between monthly and monthly2 if ( daysSet && type == "yearly" ) type = "yearly2"; Recurrence *r = event->recurrence(); if ( type == "daily" ) { r->setDaily( dailyValue ); } else if ( type == "weekly" ) { r->setWeekly( weeklyValue, days ); } else if ( type == "monthly" ) { r->setMonthly( monthlyValueMonth ); r->addMonthlyDate( monthlyValueDay ); } else if ( type == "yearly" ) { r->setYearly( 1 ); r->addYearlyDate( yearlyValueDay ); r->addYearlyMonth( yearlyMonth ); } else if ( type == "monthly2" ) { r->setMonthly( monthly2ValueMonth ); QBitArray _days( 7 ); if ( daysSet ) _days = days; else _days.setBit( event->dtStart().date().dayOfWeek() ); r->addMonthlyPos( monthly2Recurrency, _days ); } else if ( type == "yearly2" ) { r->setYearly( 1 ); r->addYearlyMonth( yearly2Month ); QBitArray _days( 7 ); if ( daysSet ) _days = days; else _days.setBit( ( yearly2Day + 5 ) % 7 ); r->addYearlyPos( yearly2Recurrency, _days ); } r->setEndDate( end.date() ); r->setExDates( deleteExceptions ); }
void KCalResourceSlox::createRecurrenceAttributes( QDomDocument &doc, QDomElement &parent, KCal::Incidence *incidence ) { if ( !incidence->recurs() ) { WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), type() == "ox" ? "none" : "no" ); return; } Recurrence *r = incidence->recurrence(); int monthOffset = ( type() == "ox" ? -1 : 0 ); switch ( r->recurrenceType() ) { case Recurrence::rDaily: WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "daily" ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceDailyFreq ), QString::number( r->frequency() ) ); break; case Recurrence::rWeekly: { WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "weekly" ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceWeeklyFreq ), QString::number( r->frequency() ) ); // TODO: SLOX support int oxDays = 0; for ( int i = 0; i < 7; ++i ) { if ( r->days()[i] ) oxDays += 1 << ( ( i + 1 ) % 7 ); } if ( type() == "ox" ) WebdavHandler::addSloxElement( this, doc, parent, "days", QString::number( oxDays ) ); break; } case Recurrence::rMonthlyDay: WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "monthly" ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthlyFreq ), QString::number( r->frequency() ) ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthlyDay ), QString::number( r->monthDays().first() ) ); break; case Recurrence::rMonthlyPos: { WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), type() == "ox" ? "monthly" : "monthly2" ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthly2Freq ), QString::number( r->frequency() ) ); RecurrenceRule::WDayPos wdp = r->monthPositions().first(); // TODO: SLOX support WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthly2Day ), QString::number( 1 << wdp.day() ) ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceMonthly2Pos ), QString::number( wdp.pos() ) ); break; } case Recurrence::rYearlyMonth: WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), "yearly" ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearlyDay ), QString::number( r->yearDates().first() ) ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearlyMonth ), QString::number( r->yearMonths().first() + monthOffset ) ); if ( type() == "ox" ) WebdavHandler::addSloxElement( this, doc, parent, "interval", "1" ); break; case Recurrence::rYearlyPos: { WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceType ), type() == "ox" ? "yearly" : "yearly2" ); RecurrenceRule::WDayPos wdp = r->monthPositions().first(); // TODO: SLOX support WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearly2Day ), QString::number( 1 << wdp.day() ) ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearly2Pos ), QString::number( wdp.pos() ) ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceYearly2Month ), QString::number( r->yearMonths().first() + monthOffset ) ); if ( type() == "ox" ) WebdavHandler::addSloxElement( this, doc, parent, "interval", "1" ); break; } default: kDebug() << "unsupported recurrence type:" << r->recurrenceType(); } WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceEnd ), WebdavHandler::kDateTimeToSlox( r->endDateTime() ) ); // delete exceptions DateList exlist = r->exDates(); QStringList res; for ( DateList::ConstIterator it = exlist.constBegin(); it != exlist.constEnd(); ++it ) res.append( WebdavHandler::qDateTimeToSlox( QDateTime( *it ) ) ); WebdavHandler::addSloxElement( this, doc, parent, fieldName( RecurrenceDelEx ), res.join( "," ) ); }
/** Dissociate a single occurrence or all future occurrences from a recurring sequence. The new incidence is returned, but not automatically inserted into the calendar, which is left to the calling application */ Incidence *Calendar::dissociateOccurrence(Incidence *incidence, QDate date, bool single) { if(!incidence || !incidence->doesRecur()) return 0; Incidence *newInc = incidence->clone(); newInc->recreate(); newInc->setRelatedTo(incidence); Recurrence *recur = newInc->recurrence(); if(single) { recur->clear(); } else { // Adjust the recurrence for the future incidences. In particular // adjust the "end after n occurrences" rules! "No end date" and "end by ..." // don't need to be modified. int duration = recur->duration(); if(duration > 0) { int doneduration = recur->durationTo(date.addDays(-1)); if(doneduration >= duration) { kdDebug(5850) << "The dissociated event already occurred more often " << "than it was supposed to ever occur. ERROR!" << endl; recur->clear(); } else { recur->setDuration(duration - doneduration); } } } // Adjust the date of the incidence if(incidence->type() == "Event") { Event *ev = static_cast<Event *>(newInc); QDateTime start(ev->dtStart()); int daysTo = start.date().daysTo(date); ev->setDtStart(start.addDays(daysTo)); ev->setDtEnd(ev->dtEnd().addDays(daysTo)); } else if(incidence->type() == "Todo") { Todo *td = static_cast<Todo *>(newInc); bool haveOffset = false; int daysTo = 0; if(td->hasDueDate()) { QDateTime due(td->dtDue()); daysTo = due.date().daysTo(date); td->setDtDue(due.addDays(daysTo), true); haveOffset = true; } if(td->hasStartDate()) { QDateTime start(td->dtStart()); if(!haveOffset) daysTo = start.date().daysTo(date); td->setDtStart(start.addDays(daysTo)); haveOffset = true; } } recur = incidence->recurrence(); if(recur) { if(single) { recur->addExDate(date); } else { // Make sure the recurrence of the past events ends // at the corresponding day recur->setEndDate(date.addDays(-1)); } } return newInc; }