/****************************************************************************** * Return the KAlarm version which wrote the calendar which has been loaded. * The format is, for example, 000507 for 0.5.7. * Reply = 0 if the calendar was created by the current version of KAlarm * = -1 if it was created by KAlarm pre-0.3.5, or another program * = version number if created by another KAlarm version. */ int CalendarCompat::readKAlarmVersion(KCal::CalendarLocal& calendar, const QString& localFile, QString& subVersion, QString& versionString) { subVersion.clear(); versionString = calendar.customProperty(KCalendar::APPNAME, VERSION_PROPERTY); if (versionString.isEmpty()) { // Pre-KAlarm 1.4 defined the KAlarm version number in the PRODID field. // If another application has written to the file, this may not be present. const QString prodid = calendar.productId(); if (prodid.isEmpty()) { // Check whether the calendar file is empty, in which case // it can be written to freely. QFileInfo fi(localFile); if (!fi.size()) return 0; } // Find the KAlarm identifier QString progname = QLatin1String(" KAlarm "); int i = prodid.indexOf(progname, 0, Qt::CaseInsensitive); if (i < 0) { // Older versions used KAlarm's translated name in the product ID, which // could have created problems using a calendar in different locales. progname = QString(" ") + KGlobal::mainComponent().aboutData()->programName() + ' '; i = prodid.indexOf(progname, 0, Qt::CaseInsensitive); if (i < 0) return -1; // calendar wasn't created by KAlarm } // Extract the KAlarm version string versionString = prodid.mid(i + progname.length()).trimmed(); i = versionString.indexOf('/'); int j = versionString.indexOf(' '); if (j >= 0 && j < i) i = j; if (i <= 0) return -1; // missing version string versionString = versionString.left(i); // 'versionString' now contains the KAlarm version string } if (versionString == KAEventData::currentCalendarVersionString()) return 0; // the calendar is in the current KAlarm format int ver = KAlarm::getVersionNumber(versionString, &subVersion); if (ver >= KAEventData::currentCalendarVersion() && ver <= KAlarm::Version()) return 0; // the calendar is in the current KAlarm format return KAlarm::getVersionNumber(versionString, &subVersion); }
/****************************************************************************** * Find the version of KAlarm which wrote the calendar file, and do any * necessary conversions to the current format. If it is a resource calendar, * the user is prompted whether to save the conversions. For a local calendar * file, any conversions will only be saved if changes are made later. * If the calendar only contains the wrong alarm types, 'wrongType' is set true. * Reply = true if the calendar file is now in the current format. */ KCalendar::Status CalendarCompat::fix(KCal::CalendarLocal& calendar, const QString& localFile, AlarmResource* resource, AlarmResource::FixFunc conv, bool* wrongType) { if (wrongType) *wrongType = false; bool version057_UTC = false; QString subVersion, versionString; int version = readKAlarmVersion(calendar, localFile, subVersion, versionString); if (version < 0 || version > KAlarm::Version()) return KCalendar::Incompatible; // calendar was created by another program, or an unknown version of KAlarm if (version) { // Calendar was created by an earlier version of KAlarm. // Convert it to the current format. if (version == KAlarm::Version(0,5,7) && !localFile.isEmpty()) { // KAlarm version 0.5.7 - check whether times are stored in UTC, in which // case it is the KDE 3.0.0 version, which needs adjustment of summer times. version057_UTC = isUTC(localFile); kDebug() << "KAlarm version 0.5.7 (" << (version057_UTC ?"" :"non-") << "UTC)"; } else kDebug() << "KAlarm version" << version; // Convert events to current KAlarm format for if the calendar is saved KAEventData::convertKCalEvents(calendar, version, version057_UTC, Preferences::startOfDay()); } if (!resource) return KCalendar::Current; // update non-shared calendars regardless // Check whether the alarm types in the calendar correspond with the resource's alarm type if (wrongType) *wrongType = !resource->checkAlarmTypes(calendar); if (!version) return KCalendar::Current; // calendar is in current KAlarm format if (resource->ResourceCached::readOnly() || conv == AlarmResource::NO_CONVERT) return KCalendar::Convertible; // Update the calendar file now if the user wants it to be read-write if (conv == AlarmResource::PROMPT || conv == AlarmResource::PROMPT_PART) { QString msg = (conv == AlarmResource::PROMPT) ? i18nc("@info", "Calendar <resource>%1</resource> is in an old format (<application>KAlarm</application> version %2), and will be read-only unless " "you choose to update it to the current format.", resource->resourceName(), versionString) : i18nc("@info", "Some or all of the alarms in calendar <resource>%1</resource> are in an old <application>KAlarm</application> format, and will be read-only unless " "you choose to update them to the current format.", resource->resourceName()); if (KMessageBox::warningYesNo(0, i18nc("@info", "<para>%1</para><para>" "<warning>Do not update the calendar if it is shared with other users who run an older version " "of <application>KAlarm</application>. If you do so, they may be unable to use it any more.</warning></para>" "<para>Do you wish to update the calendar?</para>", msg)) != KMessageBox::Yes) return KCalendar::Convertible; } calendar.setCustomProperty(KCalendar::APPNAME, VERSION_PROPERTY, QLatin1String(KALARM_VERSION)); return KCalendar::Converted; }
/****************************************************************************** * Check whether the alarm types in a calendar correspond with the resource's * alarm type. * Reply = true if at least 1 alarm is the right type. */ bool AlarmResource::checkAlarmTypes(KCal::CalendarLocal& calendar) const { KCalEvent::Status type = kcalEventType(); if (type != KCalEvent::EMPTY) { bool have = false; bool other = false; const Event::List events = calendar.rawEvents(); for (int i = 0, iend = events.count(); i < iend; ++i) { KCalEvent::Status s = KCalEvent::status(events[i]); if (type == s) have = true; else other = true; if (have && other) break; } if (!have && other) return false; // contains only wrong alarm types } return true; }
/****************************************************************************** * Write the X-KDE-KALARM-VERSION custom property into the calendar. */ void CalendarCompat::setID(KCal::CalendarLocal& calendar) { calendar.setCustomProperty(KCalendar::APPNAME, VERSION_PROPERTY, QString::fromLatin1(KAEventData::currentCalendarVersionString())); }
bool ICalReport::generate() { #if KDE_IS_VERSION(3,4,89) KCal::CalendarLocal cal("UTC"); #else KCal::CalendarLocal cal; #endif if( !open()) { tjWarning(i18n("Can not open ICal File '%1' for writing!") .arg(fileName)); return false; } TaskList filteredList; if (!filterTaskList(filteredList, 0, getHideTask(), getRollUpTask())) return false; // Make sure that parents are in front of childs. We need this later to set // the relation. filteredList.setSorting(CoreAttributesList::TreeMode, 0); filteredList.setSorting(CoreAttributesList::StartUp, 1); sortTaskList(filteredList); ResourceList filteredResourceList; if (!filterResourceList(filteredResourceList, 0, hideResource, rollUpResource)) return false; sortResourceList(filteredResourceList); QPtrDict<KCal::Todo> toDoDict; QPtrDict<KCal::Event> eventDict; for (TaskListIterator tli(filteredList); *tli != 0; ++tli) { // Generate a TODO item for each task. KCal::Todo* todo = generateTODO(*tli, filteredResourceList); // In case we have the parent in the list set the relation pointer. if((*tli)->getParent() && toDoDict.find((*tli)->getParent())) todo->setRelatedTo(toDoDict[(*tli)->getParent()]); // Insert the just created TODO into the calendar. cal.addTodo(todo); // Insert the TODO into the dict. We might need it as a parent. toDoDict.insert(*tli, todo); if ((*tli)->isLeaf() && !(*tli)->isMilestone()) { // Generate an event item for each task. KCal::Event* event = generateEvent(*tli, filteredResourceList); // In case we have the parent in the list set the relation pointer. if((*tli)->getParent() && eventDict.find((*tli)->getParent())) event->setRelatedTo(eventDict[(*tli)->getParent()]); // Insert the just created EVENT into the calendar. cal.addEvent(event); // Insert the EVENT into the dict. We might need it as a parent. eventDict.insert(*tli, event); } } // Dump the calendar in ICal format into a text file. KCal::ICalFormat format; s << format.toString(&cal) << endl; return close(); }
void SummaryEventTester::test_Multiday() { QDate today = QDate::currentDate(); QString multidayWithTimeInProgress = "Multiday, time specified, in progress"; KCal::CalendarLocal *cal = new KCal::CalendarLocal( KDateTime().timeSpec() ); KCal::Event *event = new KCal::Event(); event->setDtStart( KDateTime( today.addDays( -1 ) ) ); event->setDtEnd( KDateTime( today.addDays( 5 ) ) ); event->setSummary( "Multiday, allday, in progress (day 2/6)" ); QVERIFY( cal->addEvent( event ) ); event = new KCal::Event(); event->setDtStart( KDateTime( today.addDays( -1 ), QTime::fromString("12:00","hh:mm") ) ); event->setDtEnd( KDateTime( today.addDays( 5 ), QTime::fromString("12:00","hh:mm") ) ); event->setSummary( multidayWithTimeInProgress ); QVERIFY( cal->addEvent( event ) ); for ( int i = 0; i < 5; i++ ) { SummaryEventInfo::List events4 = SummaryEventInfo::eventsForDate( today.addDays( i ), cal ); QCOMPARE( 1, events4.size() ); SummaryEventInfo *ev4 = events4.at(0); QCOMPARE( ev4->summaryText, QString(multidayWithTimeInProgress + " (%1/7)").arg(i+2)); QCOMPARE( ev4->timeRange, QString("00:00 - 23:59") ); // QCOMPARE( ev4->startDate, KGlobal::locale()->formatDate( QDate( today.addDays( i ) ), KLocale::FancyLongDate ) ); QCOMPARE( ev4->makeBold, i == 0 ); qDeleteAll( events4 ); } // Test date a multiday event in the future has to correct DaysTo set QString multiDayWithTimeFuture = "Multiday, with time, in the future"; event = new KCal::Event(); event->setDtStart( KDateTime( today.addDays( 100 ), QTime::fromString("12:00","hh:mm") ) ); event->setDtEnd( KDateTime( today.addDays( 106 ), QTime::fromString("12:00","hh:mm") ) ); event->setSummary( multiDayWithTimeFuture ); QVERIFY( cal->addEvent( event ) ); for ( int i = 100; i <= 106; i++ ) { SummaryEventInfo::List events5 = SummaryEventInfo::eventsForDate( today.addDays( i ), cal ); QCOMPARE( 1, events5.size() ); SummaryEventInfo *ev5 = events5.at(0); /*qDebug() << ev5->summaryText; qDebug() << ev5->daysToGo; qDebug() << i;*/ QCOMPARE( ev5->summaryText, QString(multiDayWithTimeFuture + " (%1/7)").arg(i-100+1)); QCOMPARE( ev5->daysToGo, QString("in %1 days").arg(i) ); qDeleteAll( events5 ); } QString multiDayAllDayInFuture = "Multiday, allday, in future"; int multiDayFuture = 30; event = new KCal::Event(); event->setDtStart( KDateTime( today.addDays( multiDayFuture ) ) ); event->setDtEnd( KDateTime( today.addDays( multiDayFuture + 5 ) ) ); event->setSummary( multiDayAllDayInFuture ); QVERIFY( cal->addEvent( event ) ); event = new KCal::Event(); event->setDtStart( KDateTime( today.addDays( 2 ), QTime::fromString("12:00","hh:mm") ) ); event->setDtEnd( KDateTime( today.addDays( 5 ), QTime::fromString("12:00","hh:mm") ) ); event->setSummary( "Multiday, time specified, in future" ); QVERIFY( cal->addEvent( event ) ); QString multiDayAllDayStartingToday = "Multiday, allday, starting today"; event = new KCal::Event(); event->setDtStart( KDateTime( today ) ); event->setDtEnd( KDateTime( today.addDays( 5 ) ) ); event->setSummary( multiDayAllDayStartingToday ); QVERIFY( cal->addEvent( event ) ); event = new KCal::Event(); event->setDtStart( KDateTime( today.addDays(-10), QTime::fromString("12:00","hh:mm") ) ); event->setDtEnd( KDateTime( today.addDays( -5 ), QTime::fromString("10:00","hh:mm") ) ); event->setSummary( "Some event in the past" ); QVERIFY( cal->addEvent( event ) ); SummaryEventInfo::List eventsToday = SummaryEventInfo::eventsForDate( today, cal ); QCOMPARE( 2, eventsToday.size() ); foreach( const SummaryEventInfo *ev, eventsToday ) { if ( ev->summaryText == multidayWithTimeInProgress + " (2/7)" ) { QCOMPARE( ev->timeRange, QString("00:00 - 23:59") ); QCOMPARE( ev->startDate, QString("Today") ); QCOMPARE( ev->daysToGo, QString("now") ); QCOMPARE( ev->makeBold, true ); } else if ( ev->summaryText == multiDayAllDayStartingToday ) { QVERIFY( ev->timeRange.isEmpty() ); QCOMPARE( ev->startDate, QString("Today") ); QCOMPARE( ev->daysToGo, QString("all day") ); QCOMPARE( ev->makeBold, true ); } else Q_ASSERT( false ); // unexpected event! } SummaryEventInfo::List events2 = SummaryEventInfo::eventsForDate( today.addDays( multiDayFuture ), cal ); QCOMPARE( 1, events2.size() ); SummaryEventInfo *ev1 = events2.at( 0 ); QCOMPARE( ev1->summaryText, multiDayAllDayInFuture ); QVERIFY( ev1->timeRange.isEmpty() ); QCOMPARE( ev1->startDate, KGlobal::locale()->formatDate( QDate( today.addDays( multiDayFuture ) ) ) ); QCOMPARE( ev1->daysToGo, QString("in %1 days").arg(multiDayFuture) ); QCOMPARE( ev1->makeBold, false ); // Make sure multiday is only displayed once for ( int i = 1; i < 30; i++ ) { SummaryEventInfo::List events3 = SummaryEventInfo::eventsForDate( today.addDays( multiDayFuture + i ), cal ); foreach(SummaryEventInfo *ev, events3 ) { QVERIFY( ev->summaryText.contains( multiDayAllDayInFuture ) ); } qDeleteAll( events3 ); }