diff --git a/akonadi/agentmanager.cpp b/akonadi/agentmanager.cpp index e87969b8c..87ee16aba 100644 --- a/akonadi/agentmanager.cpp +++ b/akonadi/agentmanager.cpp @@ -1,362 +1,391 @@ /* Copyright (c) 2006-2008 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. */ #include "agentmanager.h" #include "agentmanager_p.h" #include "agenttype_p.h" #include "agentinstance_p.h" #include "collection.h" #include #include #include using namespace Akonadi; // @cond PRIVATE +#define AKONADI_CONTROL_SERVICE QLatin1String( "org.freedesktop.Akonadi.Control" ) AgentInstance AgentManagerPrivate::createInstance( const AgentType &type ) { const QString &identifier = mManager->createAgentInstance( type.identifier() ); if ( identifier.isEmpty() ) return AgentInstance(); return fillAgentInstanceLight( identifier ); } void AgentManagerPrivate::agentTypeAdded( const QString &identifier ) { // Ignore agent types we already know about, for example because we called // readAgentTypes before. if ( mTypes.contains( identifier ) ) return; const AgentType type = fillAgentType( identifier ); if ( type.isValid() ) { mTypes.insert( identifier, type ); // The Akonadi ServerManager assumes that the server is up and running as soon // as it knows about at least one agent type. // If we emit the typeAdded() signal here, it therefore thinks the server is // running. However, the AgentManager does not know about all agent types yet, // as the server might still have pending agentTypeAdded() signals, even though // it internally knows all agent types already. // This can cause situations where the client gets told by the ServerManager that // the server is running, yet the client will encounter an error because the // AgentManager doesn't know all types yet. // // Therefore, we read all agent types from the server here so they are known. readAgentTypes(); emit mParent->typeAdded( type ); } } void AgentManagerPrivate::agentTypeRemoved( const QString &identifier ) { if ( !mTypes.contains( identifier ) ) return; const AgentType type = mTypes.take( identifier ); emit mParent->typeRemoved( type ); } void AgentManagerPrivate::agentInstanceAdded( const QString &identifier ) { const AgentInstance instance = fillAgentInstance( identifier ); if ( instance.isValid() ) { // It is possible that this function is called when the instance is already // in our list we filled initially in the constructor. // This happens when the constructor is called during Akonadi startup, when // the agent processes are not fully loaded and have no D-Bus interface yet. // The server-side agent manager then emits the instance added signal when // the D-Bus interface for the agent comes up. // In this case, we simply notify that the instance status has changed. bool newAgentInstance = !mInstances.contains( identifier ); if ( newAgentInstance ) { mInstances.insert( identifier, instance ); emit mParent->instanceAdded( instance ); } else { mInstances.remove( identifier ); mInstances.insert( identifier, instance ); emit mParent->instanceStatusChanged( instance ); } } } void AgentManagerPrivate::agentInstanceRemoved( const QString &identifier ) { if ( !mInstances.contains( identifier ) ) return; const AgentInstance instance = mInstances.take( identifier ); emit mParent->instanceRemoved( instance ); } void AgentManagerPrivate::agentInstanceStatusChanged( const QString &identifier, int status, const QString &msg ) { if ( !mInstances.contains( identifier ) ) return; AgentInstance &instance = mInstances[ identifier ]; instance.d->mStatus = status; instance.d->mStatusMessage = msg; emit mParent->instanceStatusChanged( instance ); } void AgentManagerPrivate::agentInstanceProgressChanged( const QString &identifier, uint progress, const QString &msg ) { if ( !mInstances.contains( identifier ) ) return; AgentInstance &instance = mInstances[ identifier ]; instance.d->mProgress = progress; if ( !msg.isEmpty() ) instance.d->mStatusMessage = msg; emit mParent->instanceProgressChanged( instance ); } void AgentManagerPrivate::agentInstanceWarning( const QString &identifier, const QString &msg ) { if ( !mInstances.contains( identifier ) ) return; AgentInstance &instance = mInstances[ identifier ]; emit mParent->instanceWarning( instance, msg ); } void AgentManagerPrivate::agentInstanceError( const QString &identifier, const QString &msg ) { if ( !mInstances.contains( identifier ) ) return; AgentInstance &instance = mInstances[ identifier ]; emit mParent->instanceError( instance, msg ); } void AgentManagerPrivate::agentInstanceOnlineChanged( const QString &identifier, bool state ) { if ( !mInstances.contains( identifier ) ) return; AgentInstance &instance = mInstances[ identifier ]; instance.d->mIsOnline = state; emit mParent->instanceOnline( instance, state ); } void AgentManagerPrivate::agentInstanceNameChanged( const QString &identifier, const QString &name ) { if ( !mInstances.contains( identifier ) ) return; AgentInstance &instance = mInstances[ identifier ]; instance.d->mName = name; emit mParent->instanceNameChanged( instance ); } +void AgentManagerPrivate::serviceOwnerChanged( const QString &service, const QString &oldOwner, const QString &newOwner ) +{ + Q_UNUSED( oldOwner ); + Q_UNUSED( newOwner ); + + if ( service != AKONADI_CONTROL_SERVICE ) + return; + + createDBusInterface(); +} + void AgentManagerPrivate::readAgentTypes() { QDBusReply types = mManager->agentTypes(); if ( types.isValid() ) { foreach ( const QString &type, types.value() ) { if ( !mTypes.contains( type ) ) agentTypeAdded( type ); } } } AgentType AgentManagerPrivate::fillAgentType( const QString &identifier ) const { AgentType type; type.d->mIdentifier = identifier; type.d->mName = mManager->agentName( identifier, KGlobal::locale()->language() ); type.d->mDescription = mManager->agentComment( identifier, KGlobal::locale()->language() ); type.d->mIconName = mManager->agentIcon( identifier ); type.d->mMimeTypes = mManager->agentMimeTypes( identifier ); type.d->mCapabilities = mManager->agentCapabilities( identifier ); return type; } void AgentManagerPrivate::setName( const AgentInstance &instance, const QString &name ) { mManager->setAgentInstanceName( instance.identifier(), name ); } void AgentManagerPrivate::setOnline( const AgentInstance &instance, bool state ) { mManager->setAgentInstanceOnline( instance.identifier(), state ); } void AgentManagerPrivate::configure( const AgentInstance &instance, QWidget *parent ) { qlonglong winId = 0; if ( parent ) winId = (qlonglong)( parent->window()->winId() ); mManager->agentInstanceConfigure( instance.identifier(), winId ); } void AgentManagerPrivate::synchronize( const AgentInstance &instance ) { mManager->agentInstanceSynchronize( instance.identifier() ); } void AgentManagerPrivate::synchronizeCollectionTree( const AgentInstance &instance ) { mManager->agentInstanceSynchronizeCollectionTree( instance.identifier() ); } AgentInstance AgentManagerPrivate::fillAgentInstance( const QString &identifier ) const { AgentInstance instance; const QString agentTypeIdentifier = mManager->agentInstanceType( identifier ); if ( !mTypes.contains( agentTypeIdentifier ) ) return instance; instance.d->mType = mTypes.value( agentTypeIdentifier ); instance.d->mIdentifier = identifier; instance.d->mName = mManager->agentInstanceName( identifier ); instance.d->mStatus = mManager->agentInstanceStatus( identifier ); instance.d->mStatusMessage = mManager->agentInstanceStatusMessage( identifier ); instance.d->mProgress = mManager->agentInstanceProgress( identifier ); instance.d->mIsOnline = mManager->agentInstanceOnline( identifier ); return instance; } AgentInstance AgentManagerPrivate::fillAgentInstanceLight( const QString &identifier ) const { AgentInstance instance; const QString agentTypeIdentifier = mManager->agentInstanceType( identifier ); Q_ASSERT_X( mTypes.contains( agentTypeIdentifier ), "fillAgentInstanceLight", "Requests non-existing agent type" ); instance.d->mType = mTypes.value( agentTypeIdentifier ); instance.d->mIdentifier = identifier; return instance; } -AgentManager* AgentManagerPrivate::mSelf = 0; - -AgentManager::AgentManager() - : QObject( 0 ), d( new AgentManagerPrivate( this ) ) +void AgentManagerPrivate::createDBusInterface() { - d->mManager = new org::freedesktop::Akonadi::AgentManager( QLatin1String( "org.freedesktop.Akonadi.Control" ), - QLatin1String( "/AgentManager" ), - QDBusConnection::sessionBus(), this ); - - connect( d->mManager, SIGNAL( agentTypeAdded( const QString& ) ), - this, SLOT( agentTypeAdded( const QString& ) ) ); - connect( d->mManager, SIGNAL( agentTypeRemoved( const QString& ) ), - this, SLOT( agentTypeRemoved( const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceAdded( const QString& ) ), - this, SLOT( agentInstanceAdded( const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceRemoved( const QString& ) ), - this, SLOT( agentInstanceRemoved( const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceStatusChanged( const QString&, int, const QString& ) ), - this, SLOT( agentInstanceStatusChanged( const QString&, int, const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceProgressChanged( const QString&, uint, const QString& ) ), - this, SLOT( agentInstanceProgressChanged( const QString&, uint, const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceNameChanged( const QString&, const QString& ) ), - this, SLOT( agentInstanceNameChanged( const QString&, const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceWarning( const QString&, const QString& ) ), - this, SLOT( agentInstanceWarning( const QString&, const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceError( const QString&, const QString& ) ), - this, SLOT( agentInstanceError( const QString&, const QString& ) ) ); - connect( d->mManager, SIGNAL( agentInstanceOnlineChanged( const QString&, bool ) ), - this, SLOT( agentInstanceOnlineChanged( const QString&, bool ) ) ); - - if ( d->mManager->isValid() ) { - QDBusReply result = d->mManager->agentTypes(); + mTypes.clear(); + mInstances.clear(); + + delete mManager; + mManager = new org::freedesktop::Akonadi::AgentManager( AKONADI_CONTROL_SERVICE, + QLatin1String( "/AgentManager" ), + QDBusConnection::sessionBus(), mParent ); + + QObject::connect( mManager, SIGNAL( agentTypeAdded( const QString& ) ), + mParent, SLOT( agentTypeAdded( const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentTypeRemoved( const QString& ) ), + mParent, SLOT( agentTypeRemoved( const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceAdded( const QString& ) ), + mParent, SLOT( agentInstanceAdded( const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceRemoved( const QString& ) ), + mParent, SLOT( agentInstanceRemoved( const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceStatusChanged( const QString&, int, const QString& ) ), + mParent, SLOT( agentInstanceStatusChanged( const QString&, int, const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceProgressChanged( const QString&, uint, const QString& ) ), + mParent, SLOT( agentInstanceProgressChanged( const QString&, uint, const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceNameChanged( const QString&, const QString& ) ), + mParent, SLOT( agentInstanceNameChanged( const QString&, const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceWarning( const QString&, const QString& ) ), + mParent, SLOT( agentInstanceWarning( const QString&, const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceError( const QString&, const QString& ) ), + mParent, SLOT( agentInstanceError( const QString&, const QString& ) ) ); + QObject::connect( mManager, SIGNAL( agentInstanceOnlineChanged( const QString&, bool ) ), + mParent, SLOT( agentInstanceOnlineChanged( const QString&, bool ) ) ); + + if ( mManager->isValid() ) { + QDBusReply result = mManager->agentTypes(); if ( result.isValid() ) { foreach( const QString &type, result.value() ) { - const AgentType agentType = d->fillAgentType( type ); - d->mTypes.insert( type, agentType ); + const AgentType agentType = fillAgentType( type ); + mTypes.insert( type, agentType ); } } - result = d->mManager->agentInstances(); + result = mManager->agentInstances(); if ( result.isValid() ) { foreach( const QString &instance, result.value() ) { - const AgentInstance agentInstance = d->fillAgentInstance( instance ); - d->mInstances.insert( instance, agentInstance ); + const AgentInstance agentInstance = fillAgentInstance( instance ); + mInstances.insert( instance, agentInstance ); } } } } +AgentManager* AgentManagerPrivate::mSelf = 0; + +AgentManager::AgentManager() + : QObject( 0 ), d( new AgentManagerPrivate( this ) ) +{ + d->createDBusInterface(); + + // if the D-Bus interface is not valid at this point, watch for the + // service to appear and create a new one then + if ( !d->mManager->isValid() ) { + connect( QDBusConnection::sessionBus().interface(), + SIGNAL(serviceOwnerChanged(QString,QString,QString)), + SLOT(serviceOwnerChanged(QString,QString,QString)) ); + } +} + // @endcond AgentManager::~AgentManager() { delete d; } AgentManager* AgentManager::self() { if ( !AgentManagerPrivate::mSelf ) AgentManagerPrivate::mSelf = new AgentManager(); return AgentManagerPrivate::mSelf; } AgentType::List AgentManager::types() const { return d->mTypes.values(); } AgentType AgentManager::type( const QString &identifier ) const { return d->mTypes.value( identifier ); } AgentInstance::List AgentManager::instances() const { return d->mInstances.values(); } AgentInstance AgentManager::instance( const QString &identifier ) const { return d->mInstances.value( identifier ); } void AgentManager::removeInstance( const AgentInstance &instance ) { d->mManager->removeAgentInstance( instance.identifier() ); } void AgentManager::synchronizeCollection(const Collection & collection) { const QString resId = collection.resource(); Q_ASSERT( !resId.isEmpty() ); d->mManager->agentInstanceSynchronizeCollection( resId, collection.id() ); } #include "agentmanager.moc" diff --git a/akonadi/agentmanager.h b/akonadi/agentmanager.h index f56f81d6e..21141a036 100644 --- a/akonadi/agentmanager.h +++ b/akonadi/agentmanager.h @@ -1,206 +1,207 @@ /* Copyright (c) 2006-2008 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_AGENTMANAGER_H #define AKONADI_AGENTMANAGER_H #include "akonadi_export.h" #include #include #include namespace Akonadi { class AgentManagerPrivate; class Collection; /** * @short Provides an interface to retrieve agent types and manage agent instances. * * This singleton class can be used to create or remove agent instances or trigger * synchronization of collections. Furthermore it provides information about status * changes of the agents. * * @code * * Akonadi::AgentManager *manager = Akonadi::AgentManager::self(); * * Akonadi::AgentType::List types = manager->types(); * foreach( const Akonadi::AgentType& type, types ) { * qDebug() << "Type:" << type.name() << type.description(); * } * * @endcode * * @author Tobias Koenig */ class AKONADI_EXPORT AgentManager : public QObject { friend class AgentInstance; friend class AgentInstanceCreateJob; friend class AgentManagerPrivate; Q_OBJECT public: /** * Returns the global instance of the agent manager. */ static AgentManager *self(); /** * Destroys the agent manager. */ ~AgentManager(); /** * Returns the list of all available agent types. */ AgentType::List types() const; /** * Returns the agent type with the given @p identifier or * an invalid agent type if the identifier does not exist. */ AgentType type( const QString &identifier ) const; /** * Returns the list of all available agent instances. */ AgentInstance::List instances() const; /** * Returns the agent instance with the given @p identifier or * an invalid agent instance if the identifier does not exist. */ AgentInstance instance( const QString &identifier ) const; /** * Removes the given agent @p instance. */ void removeInstance( const AgentInstance &instance ); /** * Trigger a synchronization of the given collection by its owning resource agent. * * @param collection The collection to synchronize. */ void synchronizeCollection( const Collection &collection ); Q_SIGNALS: /** * This signal is emitted whenever a new agent type was installed on the system. * * @param type The new agent type. */ void typeAdded( const Akonadi::AgentType &type ); /** * This signal is emitted whenever an agent type was removed from the system. * * @param type The removed agent type. */ void typeRemoved( const Akonadi::AgentType &type ); /** * This signal is emitted whenever a new agent instance was created. * * @param instance The new agent instance. */ void instanceAdded( const Akonadi::AgentInstance &instance ); /** * This signal is emitted whenever an agent instance was removed. * * @param instance The removed agent instance. */ void instanceRemoved( const Akonadi::AgentInstance &instance ); /** * This signal is emitted whenever the status of an agent instance has * changed. * * @param instance The agent instance that status has changed. */ void instanceStatusChanged( const Akonadi::AgentInstance &instance ); /** * This signal is emitted whenever the progress of an agent instance has * changed. * * @param instance The agent instance that progress has changed. */ void instanceProgressChanged( const Akonadi::AgentInstance &instance ); /** * This signal is emitted whenever the name of the agent instance has changed. * * @param instance The agent instance that name has changed. */ void instanceNameChanged( const Akonadi::AgentInstance &instance ); /** * This signal is emitted whenever the agent instance raised an error. * * @param instance The agent instance that raised the error. * @param message The i18n'ed error message. */ void instanceError( const Akonadi::AgentInstance &instance, const QString &message ); /** * This signal is emitted whenever the agent instance raised a warning. * * @param instance The agent instance that raised the warning. * @param message The i18n'ed warning message. */ void instanceWarning( const Akonadi::AgentInstance &instance, const QString &message ); /** * This signal is emitted whenever the online state of an agent changed. * * @param instance The agent instance that changed its online state. * @param online The new online state. * @since 4.2 */ void instanceOnline( const Akonadi::AgentInstance &instance, bool online ); private: //@cond PRIVATE AgentManager(); AgentManagerPrivate* const d; Q_PRIVATE_SLOT( d, void agentTypeAdded( const QString& ) ) Q_PRIVATE_SLOT( d, void agentTypeRemoved( const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceAdded( const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceRemoved( const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceStatusChanged( const QString&, int, const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceProgressChanged( const QString&, uint, const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceNameChanged( const QString&, const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceWarning( const QString&, const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceError( const QString&, const QString& ) ) Q_PRIVATE_SLOT( d, void agentInstanceOnlineChanged( const QString&, bool ) ) + Q_PRIVATE_SLOT( d, void serviceOwnerChanged( QString, QString, QString ) ) //@endcond }; } #endif diff --git a/akonadi/agentmanager_p.h b/akonadi/agentmanager_p.h index 7d6e9ff5d..ee98e900f 100644 --- a/akonadi/agentmanager_p.h +++ b/akonadi/agentmanager_p.h @@ -1,93 +1,96 @@ /* Copyright (c) 2006-2008 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_AGENTMANAGER_P_H #define AKONADI_AGENTMANAGER_P_H #include "agentmanagerinterface.h" #include "agenttype.h" #include "agentinstance.h" #include namespace Akonadi { class AgentManager; /** * @internal */ class AgentManagerPrivate { friend class AgentManager; public: AgentManagerPrivate( AgentManager *parent ) - : mParent( parent ) + : mParent( parent ), mManager( 0 ) { } /* * Used by AgentInstanceCreateJob */ AgentInstance createInstance( const AgentType &type ); void agentTypeAdded( const QString& ); void agentTypeRemoved( const QString& ); void agentInstanceAdded( const QString& ); void agentInstanceRemoved( const QString& ); void agentInstanceStatusChanged( const QString&, int, const QString& ); void agentInstanceProgressChanged( const QString&, uint, const QString& ); void agentInstanceNameChanged( const QString&, const QString& ); void agentInstanceWarning( const QString&, const QString& ); void agentInstanceError( const QString&, const QString& ); void agentInstanceOnlineChanged( const QString&, bool ); + void serviceOwnerChanged( const QString&, const QString&, const QString& ); /** * Reads the information about all known agent types from the serverside * agent manager and updates mTypes, like agentTypeAdded() does. * * This will not remove agents from the internal map that are no longer on * the server. */ void readAgentTypes(); void setName( const AgentInstance&, const QString& ); void setOnline( const AgentInstance&, bool ); void configure( const AgentInstance&, QWidget* ); void synchronize( const AgentInstance& ); void synchronizeCollectionTree( const AgentInstance& ); AgentType fillAgentType( const QString &identifier ) const; AgentInstance fillAgentInstance( const QString &identifier ) const; AgentInstance fillAgentInstanceLight( const QString &identifier ) const; + void createDBusInterface(); + static AgentManager *mSelf; AgentManager *mParent; org::freedesktop::Akonadi::AgentManager *mManager; QHash mTypes; QHash mInstances; }; } #endif