diff --git a/akonadi/monitor_p.cpp b/akonadi/monitor_p.cpp index 606a586ed..ebb98040e 100644 --- a/akonadi/monitor_p.cpp +++ b/akonadi/monitor_p.cpp @@ -1,362 +1,386 @@ /* Copyright (c) 2007 Tobias Koenig 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. */ // @cond PRIVATE #include "monitor_p.h" #include "collectionfetchjob.h" #include "collectionstatistics.h" #include "itemfetchjob.h" #include "notificationmessage_p.h" #include "session.h" #include using namespace Akonadi; MonitorPrivate::MonitorPrivate(Monitor * parent) : q_ptr( parent ), nm( 0 ), monitorAll( false ), fetchCollection( false ), fetchCollectionStatistics( false ) { } bool MonitorPrivate::connectToNotificationManager() { NotificationMessage::registerDBusTypes(); if ( !nm ) nm = new org::freedesktop::Akonadi::NotificationManager( QLatin1String( "org.freedesktop.Akonadi" ), QLatin1String( "/notifications" ), QDBusConnection::sessionBus(), q_ptr ); else return true; if ( !nm ) { kWarning( 5250 ) << "Unable to connect to notification manager"; } else { QObject::connect( nm, SIGNAL(notify(Akonadi::NotificationMessage::List)), q_ptr, SLOT(slotNotify(Akonadi::NotificationMessage::List)) ); return true; } return false; } bool MonitorPrivate::acceptNotification(const NotificationMessage & msg) { if ( isSessionIgnored( msg.sessionId() ) ) return false; switch ( msg.type() ) { case NotificationMessage::InvalidType: kWarning( 5250 ) << "Received invalid change notification!"; return false; case NotificationMessage::Item: return isItemMonitored( msg.uid(), msg.parentCollection(), msg.parentDestCollection(), msg.mimeType(), msg.resource() ) || isCollectionMonitored( msg.parentCollection(), msg.resource() ) || isCollectionMonitored( msg.parentDestCollection(), msg.resource() ); case NotificationMessage::Collection: return isCollectionMonitored( msg.uid(), msg.resource() ); } Q_ASSERT( false ); return false; } bool MonitorPrivate::processNotification(const NotificationMessage & msg) { if ( !acceptNotification( msg ) ) return false; if ( msg.type() == NotificationMessage::Item ) { notifyCollectionStatisticsWatchers( msg.parentCollection(), msg.resource() ); if ( !mItemFetchScope.isEmpty() && ( msg.operation() == NotificationMessage::Add || msg.operation() == NotificationMessage::Move || msg.operation() == NotificationMessage::Remove + 1 ) ) { // ### Link, change when protocol lib is releaded in the next version Item item( msg.uid() ); item.setRemoteId( msg.remoteId() ); - ItemCollectionFetchJob *job = new ItemCollectionFetchJob( item, msg.parentCollection(), q_ptr ); + ItemCollectionFetchJob *job = new ItemCollectionFetchJob( item, msg.parentCollection(), msg.parentDestCollection(), q_ptr ); job->setFetchScope( mItemFetchScope ); pendingJobs.insert( job, msg ); QObject::connect( job, SIGNAL(result(KJob*)), q_ptr, SLOT(slotItemJobFinished(KJob*)) ); return true; } if ( !mItemFetchScope.isEmpty() && msg.operation() == NotificationMessage::Modify ) { Item item( msg.uid() ); item.setRemoteId( msg.remoteId() ); ItemFetchJob *job = new ItemFetchJob( item, q_ptr ); job->setFetchScope( mItemFetchScope ); pendingJobs.insert( job, msg ); QObject::connect( job, SIGNAL(result(KJob*)), q_ptr, SLOT(slotItemJobFinished(KJob*)) ); return true; } emitItemNotification( msg ); return true; } else if ( msg.type() == NotificationMessage::Collection ) { if ( msg.operation() != NotificationMessage::Remove && fetchCollection ) { Collection::List list; list << Collection( msg.uid() ); if ( msg.operation() == NotificationMessage::Add ) list << Collection( msg.parentCollection() ); CollectionFetchJob *job = new CollectionFetchJob( list, q_ptr ); pendingJobs.insert( job, msg ); QObject::connect( job, SIGNAL(result(KJob*)), q_ptr, SLOT(slotCollectionJobFinished(KJob*)) ); return true; } if ( msg.operation() == NotificationMessage::Remove ) { // no need for statistics updates anymore recentlyChangedCollections.remove( msg.uid() ); } emitCollectionNotification( msg ); return true; } else { kWarning( 5250 ) << "Received unknown change notification!"; } return false; } void MonitorPrivate::sessionDestroyed( QObject * object ) { Session* session = qobject_cast( object ); if ( session ) sessions.removeAll( session->sessionId() ); } void MonitorPrivate::slotStatisticsChangedFinished( KJob* job ) { if ( job->error() ) { kWarning( 5250 ) << "Error on fetching collection statistics: " << job->errorText(); } else { CollectionStatisticsJob *statisticsJob = static_cast( job ); emit q_ptr->collectionStatisticsChanged( statisticsJob->collection().id(), statisticsJob->statistics() ); } } void MonitorPrivate::slotFlushRecentlyChangedCollections() { foreach( Collection::Id collection, recentlyChangedCollections ) { if ( fetchCollectionStatistics ) { fetchStatistics( collection ); } else { static const CollectionStatistics dummyStatistics; emit q_ptr->collectionStatisticsChanged( collection, dummyStatistics ); } } recentlyChangedCollections.clear(); } void MonitorPrivate::slotNotify( const NotificationMessage::List &msgs ) { foreach ( const NotificationMessage &msg, msgs ) processNotification( msg ); } void MonitorPrivate::emitItemNotification( const NotificationMessage &msg, const Item &item, const Collection &collection, const Collection &collectionDest ) { Q_ASSERT( msg.type() == NotificationMessage::Item ); Collection col = collection; Collection colDest = collectionDest; if ( !col.isValid() ) { col = Collection( msg.parentCollection() ); col.setResource( QString::fromUtf8( msg.resource() ) ); } if ( !colDest.isValid() ) { colDest = Collection( msg.parentDestCollection() ); // FIXME setResource here required ? } Item it = item; if ( !it.isValid() ) { it = Item( msg.uid() ); it.setRemoteId( msg.remoteId() ); it.setMimeType( msg.mimeType() ); } switch ( msg.operation() ) { case NotificationMessage::Add: emit q_ptr->itemAdded( it, col ); break; case NotificationMessage::Modify: emit q_ptr->itemChanged( it, msg.itemParts() ); break; case NotificationMessage::Move: emit q_ptr->itemMoved( it, col, colDest ); break; case NotificationMessage::Remove: emit q_ptr->itemRemoved( it ); break; case NotificationMessage::Remove + 1: // ### change as soon as the new protocol lib is released, NotificationMessage::Link emit q_ptr->itemLinked( it, col ); break; case NotificationMessage::Remove + 2: // ### change as soon as the new protocol lib is released, NotificationMessage::Unlink emit q_ptr->itemUnlinked( it, col ); break; default: kDebug() << "Unknown operation type" << msg.operation() << "in item change notification"; break; } } void MonitorPrivate::emitCollectionNotification( const NotificationMessage &msg, const Collection &col, const Collection &par ) { Q_ASSERT( msg.type() == NotificationMessage::Collection ); Collection collection = col; if ( !collection.isValid() ) { collection = Collection( msg.uid() ); collection.setParent( msg.parentCollection() ); collection.setResource( QString::fromUtf8( msg.resource() ) ); collection.setRemoteId( msg.remoteId() ); } Collection parent = par; if ( !parent.isValid() ) parent = Collection( msg.parentCollection() ); switch ( msg.operation() ) { case NotificationMessage::Add: emit q_ptr->collectionAdded( collection, parent ); break; case NotificationMessage::Modify: emit q_ptr->collectionChanged( collection ); break; case NotificationMessage::Remove: emit q_ptr->collectionRemoved( collection ); break; default: Q_ASSERT_X( false, "MonitorPrivate::emitCollectionNotification", "Invalid enum value" ); } } void MonitorPrivate::slotItemJobFinished( KJob* job ) { if ( !pendingJobs.contains( job ) ) { kWarning( 5250 ) << "Unknown job - wtf is going on here?"; return; } NotificationMessage msg = pendingJobs.take( job ); if ( job->error() ) { kWarning( 5250 ) << "Error on fetching item:" << job->errorText(); } else { Item item; Collection col; + Collection destCol; ItemFetchJob *fetchJob = qobject_cast( job ); if ( fetchJob && fetchJob->items().count() > 0 ) item = fetchJob->items().first(); ItemCollectionFetchJob *cfjob = qobject_cast( job ); if ( cfjob ) { item = cfjob->item(); col = cfjob->collection(); + destCol = cfjob->destCollection(); } - emitItemNotification( msg, item, col ); + emitItemNotification( msg, item, col, destCol ); } } void MonitorPrivate::slotCollectionJobFinished( KJob* job ) { if ( !pendingJobs.contains( job ) ) { kWarning( 5250 ) << "Unknown job - wtf is going on here?"; return; } NotificationMessage msg = pendingJobs.take( job ); if ( job->error() ) { kWarning( 5250 ) << "Error on fetching collection:" << job->errorText(); } else { Collection col, parent; CollectionFetchJob *listJob = qobject_cast( job ); if ( listJob && listJob->collections().count() > 0 ) col = listJob->collections().first(); if ( listJob && listJob->collections().count() > 1 && msg.operation() == NotificationMessage::Add ) { parent = listJob->collections().at( 1 ); if ( col.id() != msg.uid() ) qSwap( col, parent ); } emitCollectionNotification( msg, col, parent ); } } -ItemCollectionFetchJob::ItemCollectionFetchJob( const Item &item, Collection::Id collectionId, QObject *parent ) +ItemCollectionFetchJob::ItemCollectionFetchJob( const Item &item, Collection::Id collectionId, Collection::Id destCollectionId, QObject *parent ) : Job( parent ), - mReferenceItem( item ), mCollectionId( collectionId ) + mReferenceItem( item ), mCollectionId( collectionId ), mDestCollectionId( destCollectionId ) { } ItemCollectionFetchJob::~ItemCollectionFetchJob() { } Item ItemCollectionFetchJob::item() const { return mItem; } Collection ItemCollectionFetchJob::collection() const { return mCollection; } +Collection ItemCollectionFetchJob::destCollection() const +{ + return mDestCollection; +} + void ItemCollectionFetchJob::setFetchScope( const ItemFetchScope &fetchScope ) { mFetchScope = fetchScope; } void ItemCollectionFetchJob::doStart() { CollectionFetchJob *listJob = new CollectionFetchJob( Collection( mCollectionId ), CollectionFetchJob::Base, this ); connect( listJob, SIGNAL( result( KJob* ) ), SLOT( collectionJobDone( KJob* ) ) ); addSubjob( listJob ); + CollectionFetchJob *destListJob = new CollectionFetchJob( Collection( mDestCollectionId ), CollectionFetchJob::Base, this ); + connect( destListJob, SIGNAL( result( KJob* ) ), SLOT( destCollectionJobDone( KJob* ) ) ); + addSubjob( destListJob ); + + ItemFetchJob *fetchJob = new ItemFetchJob( mReferenceItem, this ); fetchJob->setFetchScope( mFetchScope ); connect( fetchJob, SIGNAL( result( KJob* ) ), SLOT( itemJobDone( KJob* ) ) ); addSubjob( fetchJob ); } void ItemCollectionFetchJob::collectionJobDone( KJob* job ) { if ( !job->error() ) { CollectionFetchJob *listJob = qobject_cast( job ); if ( listJob->collections().isEmpty() ) { setError( 1 ); setErrorText( QLatin1String( "No collection found" ) ); } else mCollection = listJob->collections().first(); } } +void ItemCollectionFetchJob::destCollectionJobDone( KJob* job ) +{ + if ( !job->error() ) { + CollectionFetchJob *listJob = qobject_cast( job ); + if ( listJob->collections().isEmpty() ) { + setError( 1 ); + setErrorText( QLatin1String( "No collection found" ) ); + } else + mDestCollection = listJob->collections().first(); + } +} + void ItemCollectionFetchJob::itemJobDone( KJob* job ) { if ( !job->error() ) { ItemFetchJob *fetchJob = qobject_cast( job ); if ( fetchJob->items().isEmpty() ) { setError( 2 ); setErrorText( QLatin1String( "No item found" ) ); } else mItem = fetchJob->items().first(); emitResult(); } } // @endcond #include "monitor_p.moc" diff --git a/akonadi/monitor_p.h b/akonadi/monitor_p.h index d7f03ce38..49ab0a606 100644 --- a/akonadi/monitor_p.h +++ b/akonadi/monitor_p.h @@ -1,188 +1,192 @@ /* Copyright (c) 2007 Tobias Koenig 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. */ #ifndef AKONADI_MONITOR_P_H #define AKONADI_MONITOR_P_H #include "monitor.h" #include "collection.h" #include "collectionstatisticsjob.h" #include "item.h" #include "itemfetchscope.h" #include "job.h" #include #include "notificationmanagerinterface.h" #include #include #include namespace Akonadi { class Monitor; /** * @internal */ class MonitorPrivate { public: MonitorPrivate( Monitor *parent ); virtual ~MonitorPrivate() {} Monitor *q_ptr; Q_DECLARE_PUBLIC( Monitor ) org::freedesktop::Akonadi::NotificationManager *nm; Collection::List collections; QSet resources; QSet items; QSet mimetypes; bool monitorAll; QList sessions; ItemFetchScope mItemFetchScope; QHash pendingJobs; bool isCollectionMonitored( Collection::Id collection, const QByteArray &resource ) const { if ( monitorAll || isCollectionMonitored( collection ) || resources.contains( resource ) ) return true; return false; } bool isItemMonitored( Item::Id item, Collection::Id collection, Collection::Id collectionDest, const QString &mimetype, const QByteArray &resource ) const { if ( monitorAll || isCollectionMonitored( collection ) || isCollectionMonitored( collectionDest ) ||items.contains( item ) || resources.contains( resource ) || isMimeTypeMonitored( mimetype ) ) return true; return false; } bool isSessionIgnored( const QByteArray &sessionId ) const { return sessions.contains( sessionId ); } bool connectToNotificationManager(); bool acceptNotification( const NotificationMessage &msg ); bool processNotification( const NotificationMessage &msg ); // private slots void sessionDestroyed( QObject* ); void slotStatisticsChangedFinished( KJob* ); void slotFlushRecentlyChangedCollections(); virtual void slotNotify( const NotificationMessage::List &msgs ); void slotItemJobFinished( KJob* job ); void slotCollectionJobFinished( KJob *job ); void emitItemNotification( const NotificationMessage &msg, const Item &item = Item(), const Collection &collection = Collection(), const Collection &collectionDest = Collection() ); void emitCollectionNotification( const NotificationMessage &msg, const Collection &col = Collection(), const Collection &par = Collection() ); bool fetchCollection; bool fetchCollectionStatistics; private: // collections that need a statistics update QSet recentlyChangedCollections; bool isCollectionMonitored( Collection::Id collection ) const { if ( collections.contains( Collection( collection ) ) ) return true; if ( collections.contains( Collection::root() ) ) return true; return false; } bool isMimeTypeMonitored( const QString& mimetype ) const { if ( mimetypes.contains( mimetype ) ) return true; KMimeType::Ptr mimeType = KMimeType::mimeType( mimetype, KMimeType::ResolveAliases ); if ( mimeType.isNull() ) return false; foreach ( const QString &mt, mimetypes ) { if ( mimeType->is( mt ) ) return true; } return false; } void fetchStatistics( Collection::Id colId ) { CollectionStatisticsJob *job = new CollectionStatisticsJob( Collection( colId ), q_ptr ); QObject::connect( job, SIGNAL(result(KJob*)), q_ptr, SLOT(slotStatisticsChangedFinished(KJob*)) ); } void notifyCollectionStatisticsWatchers( Collection::Id collection, const QByteArray &resource ) { if ( isCollectionMonitored( collection, resource ) ) { if (recentlyChangedCollections.empty() ) QTimer::singleShot( 500, q_ptr, SLOT(slotFlushRecentlyChangedCollections()) ); recentlyChangedCollections.insert( collection ); } } }; /** * @internal * * A job which fetches an item and a collection. */ class AKONADI_EXPORT ItemCollectionFetchJob : public Job { Q_OBJECT public: - explicit ItemCollectionFetchJob( const Item &item, Collection::Id collectionId, QObject *parent = 0 ); + explicit ItemCollectionFetchJob( const Item &item, Collection::Id collectionId, Collection::Id destCollectionId, QObject *parent = 0 ); ~ItemCollectionFetchJob(); Item item() const; Collection collection() const; + Collection destCollection() const; void setFetchScope( const ItemFetchScope &fetchScope ); protected: virtual void doStart(); private Q_SLOTS: void collectionJobDone( KJob* job ); + void destCollectionJobDone( KJob* job ); void itemJobDone( KJob* job ); private: Item mReferenceItem; Collection::Id mCollectionId; + Collection::Id mDestCollectionId; Item mItem; Collection mCollection; + Collection mDestCollection; ItemFetchScope mFetchScope; }; } #endif