/******************************************************************************
* 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()));
}
Esempio n. 5
0
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 );
    }