diff --git a/agents/newmailnotifier/newmailnotifieragent.cpp b/agents/newmailnotifier/newmailnotifieragent.cpp index 45fab4051..b31c4989c 100644 --- a/agents/newmailnotifier/newmailnotifieragent.cpp +++ b/agents/newmailnotifier/newmailnotifieragent.cpp @@ -1,545 +1,545 @@ /* Copyright (c) 2013 Laurent Montel Copyright (c) 2010 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "newmailnotifieragent.h" #include "util.h" #include "newmailnotifierattribute.h" #include "specialnotifierjob.h" #include "newmailnotifieradaptor.h" #include "newmailnotifieragentsettings.h" #include "newmailnotifiersettingsdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace Akonadi; NewMailNotifierAgent::NewMailNotifierAgent( const QString &id ) : AgentBase( id ) { Akonadi::AttributeFactory::registerAttribute(); new NewMailNotifierAdaptor( this ); mIdentityManager = new KPIMIdentities::IdentityManager( false, this ); connect(mIdentityManager, SIGNAL(changed()), SLOT(slotIdentitiesChanged())); slotIdentitiesChanged(); DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/NewMailNotifierAgent" ), this, QDBusConnection::ExportAdaptors ); DBusConnectionPool::threadConnection().registerService( QLatin1String( "org.freedesktop.Akonadi.NewMailNotifierAgent" ) ); connect( Akonadi::AgentManager::self(), SIGNAL(instanceStatusChanged(Akonadi::AgentInstance)), this, SLOT(slotInstanceStatusChanged(Akonadi::AgentInstance)) ); connect( Akonadi::AgentManager::self(), SIGNAL(instanceRemoved(Akonadi::AgentInstance)), this, SLOT(slotInstanceRemoved(Akonadi::AgentInstance)) ); connect( Akonadi::AgentManager::self(), SIGNAL(instanceAdded(Akonadi::AgentInstance)), this, SLOT(slotInstanceAdded(Akonadi::AgentInstance)) ); connect( Akonadi::AgentManager::self(), SIGNAL(instanceNameChanged(Akonadi::AgentInstance)), this, SLOT(slotInstanceNameChanged(Akonadi::AgentInstance)) ); changeRecorder()->setMimeTypeMonitored( KMime::Message::mimeType() ); changeRecorder()->itemFetchScope().setCacheOnly( true ); changeRecorder()->itemFetchScope().setFetchModificationTime( false ); changeRecorder()->fetchCollection( true ); changeRecorder()->setChangeRecordingEnabled( false ); changeRecorder()->ignoreSession( Akonadi::Session::defaultSession() ); changeRecorder()->collectionFetchScope().setAncestorRetrieval( Akonadi::CollectionFetchScope::All ); changeRecorder()->setCollectionMonitored(Collection::root(), true); mTimer.setInterval( 5 * 1000 ); connect( &mTimer, SIGNAL(timeout()), SLOT(slotShowNotifications()) ); if (NewMailNotifierAgentSettings::textToSpeakEnabled()) Util::testJovieService(); if (isActive()) { mTimer.setSingleShot( true ); } } void NewMailNotifierAgent::slotIdentitiesChanged() { mListEmails = mIdentityManager->allEmails(); } void NewMailNotifierAgent::doSetOnline(bool online) { if (!online) { clearAll(); } } void NewMailNotifierAgent::setExcludeMyselfFromNotification(bool b) { NewMailNotifierAgentSettings::setExcludeEmailsFromMe(b); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::excludeMyselfFromNotification() const { return NewMailNotifierAgentSettings::excludeEmailsFromMe(); } void NewMailNotifierAgent::setShowPhoto(bool show) { NewMailNotifierAgentSettings::setShowPhoto(show); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::showPhoto() const { return NewMailNotifierAgentSettings::showPhoto(); } void NewMailNotifierAgent::setShowFrom(bool show) { NewMailNotifierAgentSettings::setShowFrom(show); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::showFrom() const { return NewMailNotifierAgentSettings::showFrom(); } void NewMailNotifierAgent::setShowSubject(bool show) { NewMailNotifierAgentSettings::setShowSubject(show); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::showSubject() const { return NewMailNotifierAgentSettings::showSubject(); } void NewMailNotifierAgent::setShowFolderName(bool show) { NewMailNotifierAgentSettings::setShowFolder(show); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::showFolderName() const { return NewMailNotifierAgentSettings::showFolder(); } void NewMailNotifierAgent::setEnableAgent(bool enabled) { NewMailNotifierAgentSettings::setEnabled(enabled); NewMailNotifierAgentSettings::self()->writeConfig(); if (!enabled) { clearAll(); } } void NewMailNotifierAgent::setVerboseMailNotification(bool verbose) { NewMailNotifierAgentSettings::setVerboseNotification(verbose); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::verboseMailNotification() const { return NewMailNotifierAgentSettings::verboseNotification(); } void NewMailNotifierAgent::setBeepOnNewMails(bool beep) { NewMailNotifierAgentSettings::setBeepOnNewMails(beep); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::beepOnNewMails() const { return NewMailNotifierAgentSettings::beepOnNewMails(); } void NewMailNotifierAgent::setTextToSpeakEnabled(bool enabled) { NewMailNotifierAgentSettings::setTextToSpeakEnabled(enabled); NewMailNotifierAgentSettings::self()->writeConfig(); } bool NewMailNotifierAgent::textToSpeakEnabled() const { return NewMailNotifierAgentSettings::textToSpeakEnabled(); } void NewMailNotifierAgent::setTextToSpeak(const QString &msg) { NewMailNotifierAgentSettings::setTextToSpeak(msg); NewMailNotifierAgentSettings::self()->writeConfig(); } QString NewMailNotifierAgent::textToSpeak() const { return NewMailNotifierAgentSettings::textToSpeak(); } void NewMailNotifierAgent::clearAll() { mNewMails.clear(); mInstanceNameInProgress.clear(); } bool NewMailNotifierAgent::enabledAgent() const { return NewMailNotifierAgentSettings::enabled(); } void NewMailNotifierAgent::showConfigureDialog(qlonglong windowId) { - configure( windowId ); + configure( reinterpret_cast(windowId)); } void NewMailNotifierAgent::configure( WId windowId ) { QPointer dialog = new NewMailNotifierSettingsDialog; if (windowId) { #ifndef Q_WS_WIN KWindowSystem::setMainWindow( dialog, windowId ); #else KWindowSystem::setMainWindow( dialog, (HWND)windowId ); #endif } dialog->exec(); delete dialog; } bool NewMailNotifierAgent::excludeSpecialCollection(const Akonadi::Collection &collection) const { if ( collection.hasAttribute() ) return true; if ( collection.hasAttribute() ) { if (collection.attribute()->ignoreNewMail()) { return true; } } if (!collection.contentMimeTypes().contains( KMime::Message::mimeType()) ) { return true; } SpecialMailCollections::Type type = SpecialMailCollections::self()->specialCollectionType(collection); switch(type) { case SpecialMailCollections::Invalid: //Not a special collection case SpecialMailCollections::Inbox: return false; default: return true; } } void NewMailNotifierAgent::itemsRemoved(const Item::List &items ) { if (!isActive()) return; QHash< Akonadi::Collection, QList >::iterator end(mNewMails.end()); for ( QHash< Akonadi::Collection, QList >::iterator it = mNewMails.begin(); it != end; ++it ) { QList idList = it.value(); bool itemFound = false; Q_FOREACH( const Item &item, items ) { if (idList.contains(item.id())) { idList.removeAll( item.id() ); itemFound = true; } } if (itemFound) { if (mNewMails[it.key()].isEmpty()) { mNewMails.remove( it.key() ); } else { mNewMails[it.key()] = idList; } } } } void NewMailNotifierAgent::itemsFlagsChanged( const Akonadi::Item::List &items, const QSet &addedFlags, const QSet &removedFlags ) { if (!isActive()) return; Q_FOREACH (const Akonadi::Item &item, items) { QHash< Akonadi::Collection, QList >::iterator end(mNewMails.end()); for ( QHash< Akonadi::Collection, QList >::iterator it = mNewMails.begin(); it != end; ++it ) { QList idList= it.value(); if (idList.contains(item.id()) && addedFlags.contains("\\SEEN")) { idList.removeAll( item.id() ); if ( idList.isEmpty() ) { mNewMails.remove( it.key() ); break; } else { (*it) = idList; } } } } } void NewMailNotifierAgent::itemsMoved( const Akonadi::Item::List &items, const Akonadi::Collection &collectionSource, const Akonadi::Collection &collectionDestination ) { if (!isActive()) return; Q_FOREACH (const Akonadi::Item &item, items) { Akonadi::MessageStatus status; status.setStatusFromFlags( item.flags() ); if ( status.isRead() || status.isSpam() || status.isIgnored() ) continue; if ( excludeSpecialCollection(collectionSource) ) { continue; // outbox, sent-mail, trash, drafts or templates. } if ( mNewMails.contains( collectionSource ) ) { QList idListFrom = mNewMails[ collectionSource ]; if ( idListFrom.contains( item.id() ) ) { idListFrom.removeAll( item.id() ); if ( idListFrom.isEmpty() ) { mNewMails.remove( collectionSource ); } else { mNewMails[ collectionSource ] = idListFrom; } if ( !excludeSpecialCollection(collectionDestination) ) { QList idListTo = mNewMails[ collectionDestination ]; idListTo.append( item.id() ); mNewMails[ collectionDestination ] = idListTo; } } } } } void NewMailNotifierAgent::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection ) { if (!isActive()) return; if ( excludeSpecialCollection(collection) ) { return; // outbox, sent-mail, trash, drafts or templates. } Akonadi::MessageStatus status; status.setStatusFromFlags( item.flags() ); if ( status.isRead() || status.isSpam() || status.isIgnored() ) return; if ( !mTimer.isActive() ) { mTimer.start(); } mNewMails[ collection ].append( item.id() ); } void NewMailNotifierAgent::slotShowNotifications() { if (mNewMails.isEmpty()) return; if (!isActive()) return; if (!mInstanceNameInProgress.isEmpty()) { //Restart timer until all is done. mTimer.start(); return; } QString message; if (NewMailNotifierAgentSettings::verboseNotification()) { bool hasUniqMessage = true; Akonadi::Item::Id item = -1; QString currentPath; QStringList texts; QHash< Akonadi::Collection, QList >::const_iterator end(mNewMails.constEnd()); const int numberOfCollection(mNewMails.count()); if (numberOfCollection > 1) hasUniqMessage = false; for ( QHash< Akonadi::Collection, QList >::const_iterator it = mNewMails.constBegin(); it != end; ++it ) { Akonadi::EntityDisplayAttribute *attr = it.key().attribute(); QString displayName; if ( attr && !attr->displayName().isEmpty() ) displayName = attr->displayName(); else displayName = it.key().name(); if (hasUniqMessage) { if (it.value().count() == 0) { //You can have an unique folder with 0 message return; } else if (it.value().count() == 1 ) { item = it.value().first(); currentPath = displayName; break; } else { hasUniqMessage = false; } } QString resourceName; if (!mCacheResourceName.contains(it.key().resource())) { Q_FOREACH ( const Akonadi::AgentInstance &instance, Akonadi::AgentManager::self()->instances() ) { if (instance.identifier() == it.key().resource()) { mCacheResourceName.insert(instance.identifier(), instance.name()); resourceName = instance.name(); break; } } } else { resourceName = mCacheResourceName.value(it.key().resource()); } const int numberOfEmails(it.value().count()); if (numberOfEmails>0) { texts.append( i18np( "One new email in %2 from \"%3\"", "%1 new emails in %2 from \"%3\"", numberOfEmails, displayName, resourceName ) ); } } if (hasUniqMessage) { SpecialNotifierJob *job = new SpecialNotifierJob(mListEmails, currentPath, item, this); connect(job, SIGNAL(displayNotification(QPixmap,QString)), SLOT(slotDisplayNotification(QPixmap,QString))); mNewMails.clear(); return; } else { message = texts.join( QLatin1String("
") ); } } else { message = i18n( "New mail arrived" ); } kDebug() << message; slotDisplayNotification(Util::defaultPixmap(), message); mNewMails.clear(); } void NewMailNotifierAgent::slotDisplayNotification(const QPixmap &pixmap, const QString &message) { Util::showNotification(pixmap, message); if ( NewMailNotifierAgentSettings::beepOnNewMails() ) { KNotification::beep(); } } void NewMailNotifierAgent::slotInstanceNameChanged(const Akonadi::AgentInstance &instance) { if (!isActive()) return; const QString identifier(instance.identifier()); if (mCacheResourceName.contains(identifier)) { mCacheResourceName.remove(identifier); mCacheResourceName.insert(identifier, instance.name()); } } void NewMailNotifierAgent::slotInstanceStatusChanged(const Akonadi::AgentInstance &instance) { if (!isActive()) return; const QString identifier(instance.identifier()); switch(instance.status()) { case Akonadi::AgentInstance::Broken: case Akonadi::AgentInstance::Idle: { if (mInstanceNameInProgress.contains(identifier)) { mInstanceNameInProgress.removeAll(identifier); } break; } case Akonadi::AgentInstance::Running: { if (!Util::excludeAgentType(instance)) { if (!mInstanceNameInProgress.contains(identifier)) { mInstanceNameInProgress.append(identifier); } } break; } case Akonadi::AgentInstance::NotConfigured: //Nothing break; } } void NewMailNotifierAgent::slotInstanceRemoved(const Akonadi::AgentInstance &instance) { if (!isActive()) return; const QString identifier(instance.identifier()); if (mInstanceNameInProgress.contains(identifier)) { mInstanceNameInProgress.removeAll(identifier); } } void NewMailNotifierAgent::slotInstanceAdded(const Akonadi::AgentInstance &instance) { mCacheResourceName.insert(instance.identifier(), instance.name()); } void NewMailNotifierAgent::printDebug() { kDebug()<<"instance in progress: "< This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "akonadi_serializer_kcalcore.h" #include #include #include #include #include #include #include #include #include using namespace KCalCore; using namespace KCalUtils; using namespace Akonadi; SerializerPluginKCalCore::SerializerPluginKCalCore() : mTimeZones(new ICalTimeZones) { } //// ItemSerializerPlugin interface bool SerializerPluginKCalCore::deserialize( Item &item, const QByteArray &label, QIODevice &data, int version ) { Q_UNUSED( version ); if ( label != Item::FullPayload ) { return false; } qint32 type; quint32 magic, incidenceVersion; QDataStream input( &data ); input >> magic; input >> incidenceVersion; input >> type; data.seek( 0 ); Incidence::Ptr incidence; if (magic == IncidenceBase::magicSerializationIdentifier()) { IncidenceBase::Ptr base; switch ( static_cast( type ) ) { case KCalCore::Incidence::TypeEvent: { base = Event::Ptr( new Event() ); break; } case KCalCore::Incidence::TypeTodo: { base = Todo::Ptr( new Todo() ); break; } case KCalCore::Incidence::TypeJournal: { base = Journal::Ptr( new Journal() ); break; } default: break; } - input >> base; + input >> static_cast(base); incidence = base.staticCast(); } else { // Use the old format incidence = mFormat.readIncidence(data.readAll(), mTimeZones.data()); } if ( !incidence ) { kWarning( 5263 ) << "Failed to parse incidence! Item id = " << item.id() << "Storage collection id " << item.storageCollectionId() << "parentCollectionId = " << item.parentCollection().id(); data.seek( 0 ); kWarning( 5263 ) << QString::fromUtf8( data.readAll() ); return false; } item.setPayload( incidence ); return true; } void SerializerPluginKCalCore::serialize( const Item &item, const QByteArray &label, QIODevice &data, int &version ) { Q_UNUSED( version ); if ( label != Item::FullPayload || !item.hasPayload() ) return; Incidence::Ptr i = item.payload(); // Using an env variable for now while testing if (qgetenv("KCALCORE_BINARY_SERIALIZER") == QByteArray("1")) { QDataStream output(&data); IncidenceBase::Ptr base = i; output << base; } else { // ### I guess this can be done without hardcoding stuff data.write( "BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML libkcal 4.3//EN\nVERSION:2.0\nX-KDE-ICAL-IMPLEMENTATION-VERSION:1.0\n" ); data.write( mFormat.toRawString( i ) ); data.write( "\nEND:VCALENDAR" ); } } //// DifferencesAlgorithmInterface static bool compareString( const QString &left, const QString &right ) { if ( left.isEmpty() && right.isEmpty() ) return true; else return left == right; } static QString toString( const Attendee::Ptr &attendee ) { return attendee->name() + QLatin1Char( '<' ) + attendee->email() + QLatin1Char( '>' ); } static QString toString( const Alarm::Ptr & ) { return QString(); } /* static QString toString( const Incidence::Ptr & ) { return QString(); } */ static QString toString( const Attachment::Ptr & ) { return QString(); } static QString toString( const QDate &date ) { return date.toString(); } static QString toString( const KDateTime &dateTime ) { return dateTime.dateTime().toString(); } static QString toString( const QString &str ) { return str; } static QString toString( bool value ) { if ( value ) return i18n( "Yes" ); else return i18n( "No" ); } template static void compareList( AbstractDifferencesReporter *reporter, const QString &id, const C &left, const C &right ) { for ( typename C::const_iterator it = left.begin(), end = left.end() ; it != end ; ++it ) { if ( !right.contains( *it ) ) reporter->addProperty( AbstractDifferencesReporter::AdditionalLeftMode, id, toString( *it ), QString() ); } for ( typename C::const_iterator it = right.begin(), end = right.end() ; it != end ; ++it ) { if ( !left.contains( *it ) ) reporter->addProperty( AbstractDifferencesReporter::AdditionalRightMode, id, QString(), toString( *it ) ); } } static void compareIncidenceBase( AbstractDifferencesReporter *reporter, const IncidenceBase::Ptr &left, const IncidenceBase::Ptr &right ) { compareList( reporter, i18n( "Attendees" ), left->attendees(), right->attendees() ); if ( !compareString( left->organizer()->fullName(), right->organizer()->fullName() ) ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Organizer" ), left->organizer()->fullName(), right->organizer()->fullName() ); if ( !compareString( left->uid(), right->uid() ) ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "UID" ), left->uid(), right->uid() ); if ( left->allDay() != right->allDay() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Is all-day" ), toString( left->allDay() ), toString( right->allDay() ) ); if ( left->hasDuration() != right->hasDuration() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Has duration" ), toString( left->hasDuration() ), toString( right->hasDuration() ) ); if ( left->duration() != right->duration() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Duration" ), QString::number( left->duration().asSeconds() ), QString::number( right->duration().asSeconds() ) ); } static void compareIncidence( AbstractDifferencesReporter *reporter, const Incidence::Ptr &left, const Incidence::Ptr &right ) { if ( !compareString( left->description(), right->description() ) ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Description" ), left->description(), right->description() ); if ( !compareString( left->summary(), right->summary() ) ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Summary" ), left->summary(), right->summary() ); if ( left->status() != right->status() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Status" ), Stringify::incidenceStatus( left ), Stringify::incidenceStatus( right ) ); if ( left->secrecy() != right->secrecy() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Secrecy" ), toString( left->secrecy() ), toString( right->secrecy() ) ); if ( left->priority() != right->priority() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Priority" ), toString( left->priority() ), toString( right->priority() ) ); if ( !compareString( left->location(), right->location() ) ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Location" ), left->location(), right->location() ); compareList( reporter, i18n( "Categories" ), left->categories(), right->categories() ); compareList( reporter, i18n( "Alarms" ), left->alarms(), right->alarms() ); compareList( reporter, i18n( "Resources" ), left->resources(), right->resources() ); compareList( reporter, i18n( "Attachments" ), left->attachments(), right->attachments() ); compareList( reporter, i18n( "Exception Dates" ), left->recurrence()->exDates(), right->recurrence()->exDates() ); compareList( reporter, i18n( "Exception Times" ), left->recurrence()->exDateTimes(), right->recurrence()->exDateTimes() ); // TODO: recurrence dates and date/times, exrules, rrules if ( left->created() != right->created() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Created" ), left->created().toString(), right->created().toString() ); if ( !compareString( left->relatedTo(), right->relatedTo() ) ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Related Uid" ), left->relatedTo(), right->relatedTo() ); } static void compareEvent( AbstractDifferencesReporter *reporter, const Event::Ptr &left, const Event::Ptr &right ) { if ( left->dtStart() != right->dtStart() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Start time" ), left->dtStart().toString(), right->dtStart().toString() ); if ( left->hasEndDate() != right->hasEndDate() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Has End Date" ), toString( left->hasEndDate() ), toString( right->hasEndDate() ) ); if ( left->dtEnd() != right->dtEnd() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "End Date" ), left->dtEnd().toString(), right->dtEnd().toString() ); // TODO: check transparency } static void compareTodo( AbstractDifferencesReporter *reporter, const Todo::Ptr &left, const Todo::Ptr &right ) { if ( left->hasStartDate() != right->hasStartDate() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Has Start Date" ), toString( left->hasStartDate() ), toString( right->hasStartDate() ) ); if ( left->hasDueDate() != right->hasDueDate() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Has Due Date" ), toString( left->hasDueDate() ), toString( right->hasDueDate() ) ); if ( left->dtDue() != right->dtDue() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Due Date" ), left->dtDue().toString(), right->dtDue().toString() ); if ( left->hasCompletedDate() != right->hasCompletedDate() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Has Complete Date" ), toString( left->hasCompletedDate() ), toString( right->hasCompletedDate() ) ); if ( left->percentComplete() != right->percentComplete() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Complete" ), QString::number( left->percentComplete() ), QString::number( right->percentComplete() ) ); if ( left->completed() != right->completed() ) reporter->addProperty( AbstractDifferencesReporter::ConflictMode, i18n( "Completed" ), toString( left->completed() ), toString( right->completed() ) ); } void SerializerPluginKCalCore::compare( Akonadi::AbstractDifferencesReporter *reporter, const Akonadi::Item &leftItem, const Akonadi::Item &rightItem ) { Q_ASSERT( reporter ); Q_ASSERT( leftItem.hasPayload() ); Q_ASSERT( rightItem.hasPayload() ); const Incidence::Ptr leftIncidencePtr = leftItem.payload(); const Incidence::Ptr rightIncidencePtr = rightItem.payload(); if ( leftIncidencePtr->type() == Incidence::TypeEvent ) { reporter->setLeftPropertyValueTitle( i18n( "Changed Event" ) ); reporter->setRightPropertyValueTitle( i18n( "Conflicting Event" ) ); } else if ( leftIncidencePtr->type() == Incidence::TypeTodo ) { reporter->setLeftPropertyValueTitle( i18n( "Changed Todo" ) ); reporter->setRightPropertyValueTitle( i18n( "Conflicting Todo" ) ); } compareIncidenceBase( reporter, leftIncidencePtr, rightIncidencePtr ); compareIncidence( reporter, leftIncidencePtr, rightIncidencePtr ); const Event::Ptr leftEvent = leftIncidencePtr.dynamicCast() ; const Event::Ptr rightEvent = rightIncidencePtr.dynamicCast() ; if ( leftEvent && rightEvent ) { compareEvent( reporter, leftEvent, rightEvent ); } else { const Todo::Ptr leftTodo = leftIncidencePtr.dynamicCast(); const Todo::Ptr rightTodo = rightIncidencePtr.dynamicCast(); if ( leftTodo && rightTodo ) { compareTodo( reporter, leftTodo, rightTodo ); } } } //// GidExtractorInterface QString SerializerPluginKCalCore::extractGid( const Item &item ) const { if ( !item.hasPayload() ) { return QString(); } return item.payload()->instanceIdentifier(); } Q_EXPORT_PLUGIN2( akonadi_serializer_kcalcore, SerializerPluginKCalCore )