diff --git a/akonadi/agentbase.cpp b/akonadi/agentbase.cpp index 20ff940f3..6c1585de9 100644 --- a/akonadi/agentbase.cpp +++ b/akonadi/agentbase.cpp @@ -1,519 +1,520 @@ /* Copyright (c) 2006 Till Adam Copyright (c) 2007 Volker Krause Copyright (c) 2007 Bruno Virlet Copyright (c) 2008 Kevin Krammer 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 "agentbase.h" #include "agentbase_p.h" #include "controladaptor.h" #include "statusadaptor.h" #include "monitor_p.h" #include "xdgbasedirs_p.h" #include "session.h" #include "session_p.h" #include "changerecorder.h" #include "itemfetchjob.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace Akonadi; static AgentBase *sAgentBase = 0; AgentBase::Observer::Observer() { } AgentBase::Observer::~Observer() { } void AgentBase::Observer::itemAdded( const Item &item, const Collection &collection ) { kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this; Q_UNUSED( item ); Q_UNUSED( collection ); if ( sAgentBase != 0 ) sAgentBase->d_ptr->changeProcessed(); } void AgentBase::Observer::itemChanged( const Item &item, const QSet &partIdentifiers ) { kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this; Q_UNUSED( item ); Q_UNUSED( partIdentifiers ); if ( sAgentBase != 0 ) sAgentBase->d_ptr->changeProcessed(); } void AgentBase::Observer::itemRemoved( const Item &item ) { kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this; Q_UNUSED( item ); if ( sAgentBase != 0 ) sAgentBase->d_ptr->changeProcessed(); } void AgentBase::Observer::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) { kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this; Q_UNUSED( collection ); Q_UNUSED( parent ); if ( sAgentBase != 0 ) sAgentBase->d_ptr->changeProcessed(); } void AgentBase::Observer::collectionChanged( const Collection &collection ) { kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this; Q_UNUSED( collection ); if ( sAgentBase != 0 ) sAgentBase->d_ptr->changeProcessed(); } void AgentBase::Observer::collectionRemoved( const Collection &collection ) { kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this; Q_UNUSED( collection ); if ( sAgentBase != 0 ) sAgentBase->d_ptr->changeProcessed(); } //@cond PRIVATE AgentBasePrivate::AgentBasePrivate( AgentBase *parent ) : q_ptr( parent ), mStatusCode( AgentBase::Idle ), mProgress( 0 ), mNeedsNetwork( false ), mOnline( false ), mSettings( 0 ), mObserver( 0 ) { } AgentBasePrivate::~AgentBasePrivate() { mMonitor->setConfig( 0 ); delete mSettings; } void AgentBasePrivate::init() { Q_Q( AgentBase ); /** * Create a default session for this process. */ SessionPrivate::createDefaultSession( mId.toLatin1() ); mTracer = new org::freedesktop::Akonadi::Tracer( QLatin1String( "org.freedesktop.Akonadi" ), QLatin1String( "/tracing" ), QDBusConnection::sessionBus(), q ); new ControlAdaptor( q ); new StatusAdaptor( q ); if ( !QDBusConnection::sessionBus().registerObject( QLatin1String( "/" ), q, QDBusConnection::ExportAdaptors ) ) q->error( QString::fromLatin1( "Unable to register object at dbus: %1" ).arg( QDBusConnection::sessionBus().lastError().message() ) ); mSettings = new QSettings( QString::fromLatin1( "%1/agent_config_%2" ).arg( XdgBaseDirs::saveDir( "config", QLatin1String( "akonadi" ) ), mId ), QSettings::IniFormat ); mMonitor = new ChangeRecorder( q ); mMonitor->ignoreSession( Session::defaultSession() ); mMonitor->itemFetchScope().setCacheOnly( true ); mMonitor->setConfig( mSettings ); mOnline = mSettings->value( QLatin1String( "Agent/Online" ), true ).toBool(); connect( mMonitor, SIGNAL( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ), SLOT( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ) ); connect( mMonitor, SIGNAL( itemChanged( const Akonadi::Item&, const QSet& ) ), SLOT( itemChanged( const Akonadi::Item&, const QSet& ) ) ); connect( mMonitor, SIGNAL( itemRemoved( const Akonadi::Item& ) ), SLOT( itemRemoved( const Akonadi::Item& ) ) ); connect( mMonitor, SIGNAL(collectionAdded(Akonadi::Collection,Akonadi::Collection)), SLOT(collectionAdded(Akonadi::Collection,Akonadi::Collection)) ); connect( mMonitor, SIGNAL( collectionChanged( const Akonadi::Collection& ) ), SLOT( collectionChanged( const Akonadi::Collection& ) ) ); connect( mMonitor, SIGNAL( collectionRemoved( const Akonadi::Collection& ) ), SLOT( collectionRemoved( const Akonadi::Collection& ) ) ); connect( q, SIGNAL( status( int, QString ) ), q, SLOT( slotStatus( int, QString ) ) ); connect( q, SIGNAL( percent( int ) ), q, SLOT( slotPercent( int ) ) ); connect( q, SIGNAL( warning( QString ) ), q, SLOT( slotWarning( QString ) ) ); connect( q, SIGNAL( error( QString ) ), q, SLOT( slotError( QString ) ) ); // Use reference counting to allow agents to finish internal jobs when the // agent is stopped. KGlobal::ref(); KGlobal::setAllowQuit(true); - + QTimer::singleShot( 0, q, SLOT( delayedInit() ) ); } void AgentBasePrivate::delayedInit() { Q_Q( AgentBase ); if ( !QDBusConnection::sessionBus().registerService( QLatin1String( "org.freedesktop.Akonadi.Agent." ) + mId ) ) kFatal() << "Unable to register service at dbus:" << QDBusConnection::sessionBus().lastError().message(); q->setOnline( mOnline ); } void AgentBasePrivate::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection ) { kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this; if ( mObserver != 0 ) mObserver->itemAdded( item, collection ); } void AgentBasePrivate::itemChanged( const Akonadi::Item &item, const QSet &partIdentifiers ) { kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this; if ( mObserver != 0 ) mObserver->itemChanged( item, partIdentifiers ); } void AgentBasePrivate::itemRemoved( const Akonadi::Item &item ) { kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this; if ( mObserver != 0 ) mObserver->itemRemoved( item ); } void AgentBasePrivate::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) { kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this; if ( mObserver != 0 ) mObserver->collectionAdded( collection, parent ); } void AgentBasePrivate::collectionChanged( const Akonadi::Collection &collection ) { kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this; if ( mObserver != 0 ) mObserver->collectionChanged( collection ); } void AgentBasePrivate::collectionRemoved( const Akonadi::Collection &collection ) { kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this; if ( mObserver != 0 ) mObserver->collectionRemoved( collection ); } void AgentBasePrivate::changeProcessed() { mMonitor->changeProcessed(); QTimer::singleShot( 0, mMonitor, SLOT( replayNext() ) ); } void AgentBasePrivate::slotStatus( int status, const QString &message ) { mStatusMessage = message; mStatusCode = 0; switch ( status ) { case AgentBase::Idle: if ( mStatusMessage.isEmpty() ) mStatusMessage = defaultReadyMessage(); mStatusCode = 0; break; case AgentBase::Running: if ( mStatusMessage.isEmpty() ) mStatusMessage = defaultSyncingMessage(); mStatusCode = 1; break; case AgentBase::Broken: if ( mStatusMessage.isEmpty() ) mStatusMessage = defaultErrorMessage(); mStatusCode = 2; break; default: Q_ASSERT( !"Unknown status passed" ); break; } } void AgentBasePrivate::slotPercent( int progress ) { mProgress = progress; } void AgentBasePrivate::slotWarning( const QString& message ) { mTracer->warning( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message ); } void AgentBasePrivate::slotError( const QString& message ) { mTracer->error( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message ); } void AgentBasePrivate::slotNetworkStatusChange( Solid::Networking::Status stat ) { Q_Q( AgentBase ); q->setOnline( stat == Solid::Networking::Connected ); } AgentBase::AgentBase( const QString & id ) : d_ptr( new AgentBasePrivate( this ) ) { sAgentBase = this; d_ptr->mId = id; d_ptr->init(); } AgentBase::AgentBase( AgentBasePrivate* d, const QString &id ) : d_ptr( d ) { sAgentBase = this; d_ptr->mId = id; d_ptr->init(); } AgentBase::~AgentBase() { delete d_ptr; } static char* sAgentAppName = 0; QString AgentBase::parseArguments( int argc, char **argv ) { QString identifier; if ( argc < 3 ) { kDebug( 5250 ) << "Not enough arguments passed..."; exit( 1 ); } for ( int i = 1; i < argc - 1; ++i ) { if ( QLatin1String( argv[ i ] ) == QLatin1String( "--identifier" ) ) identifier = QLatin1String( argv[ i + 1 ] ); } if ( identifier.isEmpty() ) { kDebug( 5250 ) << "Identifier argument missing"; exit( 1 ); } sAgentAppName = qstrdup( identifier.toLatin1().constData() ); KCmdLineArgs::init( argc, argv, sAgentAppName, 0, ki18n("Akonadi Agent"),"0.1" , ki18n("Akonadi Agent") ); KCmdLineOptions options; options.add("identifier ", ki18n("Agent identifier")); KCmdLineArgs::addCmdLineOptions( options ); return identifier; } // @endcond int AgentBase::init( AgentBase *r ) { QApplication::setQuitOnLastWindowClosed( false ); int rv = kapp->exec(); delete r; delete[] sAgentAppName; return rv; } int AgentBase::status() const { Q_D( const AgentBase ); return d->mStatusCode; } QString AgentBase::statusMessage() const { Q_D( const AgentBase ); return d->mStatusMessage; } int AgentBase::progress() const { Q_D( const AgentBase ); return d->mProgress; } QString AgentBase::progressMessage() const { Q_D( const AgentBase ); return d->mProgressMessage; } bool AgentBase::isOnline() const { Q_D( const AgentBase ); return d->mOnline; } void AgentBase::setNeedsNetwork( bool needsNetwork ) { Q_D( AgentBase ); d->mNeedsNetwork = needsNetwork; if ( d->mNeedsNetwork ) { connect( Solid::Networking::notifier() , SIGNAL( statusChanged( Solid::Networking::Status ) ) , d, SLOT( slotNetworkStatusChange( Solid::Networking::Status ) ) ); } else { disconnect( Solid::Networking::notifier(), 0, 0, 0 ); setOnline( true ); } } void AgentBase::setOnline( bool state ) { Q_D( AgentBase ); d->mOnline = state; d->mSettings->setValue( QLatin1String( "Agent/Online" ), state ); doSetOnline( state ); + emit onlineChanged( state ); } void AgentBase::doSetOnline( bool online ) { Q_UNUSED( online ); } void AgentBase::configure( WId windowId ) { Q_UNUSED( windowId ); } #ifdef Q_OS_WIN void AgentBase::configure( qlonglong windowId ) { configure( reinterpret_cast( windowId ) ); } #endif WId AgentBase::winIdForDialogs() const { bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered( QLatin1String("org.freedesktop.akonaditray") ); if ( !registered ) return 0; QDBusInterface dbus( QLatin1String("org.freedesktop.akonaditray"), QLatin1String("/Actions"), QLatin1String("org.freedesktop.Akonadi.Tray") ); QDBusMessage reply = dbus.call( QLatin1String("getWinId") ); if ( reply.type() == QDBusMessage::ErrorMessage ) return 0; WId winid = (WId)reply.arguments().at( 0 ).toLongLong(); return winid; } void AgentBase::quit() { Q_D( AgentBase ); aboutToQuit(); if ( d->mSettings ) { d->mMonitor->setConfig( 0 ); d->mSettings->sync(); } KGlobal::deref(); } void AgentBase::aboutToQuit() { } void AgentBase::cleanup() { Q_D( AgentBase ); const QString fileName = d->mSettings->fileName(); /* * First destroy the settings object... */ d->mMonitor->setConfig( 0 ); delete d->mSettings; d->mSettings = 0; /* * ... then remove the file from hd. */ QFile::remove( fileName ); /* * ... and also remove the agent configuration file if there is one. */ QString configFile = KStandardDirs::locateLocal( "config", KGlobal::config()->name() ); QFile::remove( configFile ); QCoreApplication::quit(); } void AgentBase::registerObserver( Observer *observer ) { kDebug() << "observer=" << (void*) observer << "this=" << (void*) this; d_ptr->mObserver = observer; } QString AgentBase::identifier() const { return d_ptr->mId; } void AgentBase::changeProcessed() { Q_D( AgentBase ); d->changeProcessed(); } ChangeRecorder * AgentBase::changeRecorder() const { return d_ptr->mMonitor; } void AgentBase::reconfigure() { emit reloadConfiguration(); } #include "agentbase.moc" #include "agentbase_p.moc" diff --git a/akonadi/agentbase.h b/akonadi/agentbase.h index 7dc13997b..f0485559b 100644 --- a/akonadi/agentbase.h +++ b/akonadi/agentbase.h @@ -1,465 +1,472 @@ /* This file is part of akonadiresources. Copyright (c) 2006 Till Adam Copyright (c) 2007 Volker Krause Copyright (c) 2008 Kevin Krammer 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_AGENTBASE_H #define AKONADI_AGENTBASE_H #include "akonadi_export.h" #include #include class ControlAdaptor; class StatusAdaptor; namespace Akonadi { class AgentBasePrivate; class ChangeRecorder; class Collection; class Item; class Session; /** * @short The base class for all Akonadi agents and resources. * * This class is a base class for all Akonadi agents, which covers the real * agent processes and all resources. * * It provides: * - lifetime management * - change monitoring and recording * - configuration interface * - problem reporting * * @author Till Adam , Volker Krause */ class AKONADI_EXPORT AgentBase : public QObject, protected QDBusContext { Q_OBJECT public: /** * @short The interface for reacting on monitored or replayed changes. * * The Observer provides an interface to react on monitored or replayed changes. * * Since the this base class does only tell the change recorder that the change * has been processed, an AgentBase subclass which wants to actually process * the change needs to subclass Observer and reimplement the methods it is * interested in. * * Such an agent specific Observer implementation can either be done * stand-alone, i.e. as a separate object, or by inheriting both AgentBase * and AgentBase::Observer. * * The observer implementation then has registered with the agent, so it * can forward the incoming changes to the observer. * * @note In the multiple inheritance approach the init() method automatically * registers itself as the observer. * * Example for stand-alone observer: * @code * class ExampleAgent : public AgentBase * { * public: * ExampleAgent( const QString &id ); * * ~ExampleAgent(); * * private: * AgentBase::Observer *mObserver; * }; * * class ExampleObserver : public AgentBase::Observer * { * protected: * void itemChanged( const Item &item ); * }; * * ExampleAgent::ExampleAgent( const QString &id ) * : AgentBase( id ), mObserver( 0 ) * { * mObserver = new ExampleObserver(); * registerObserver( mObserver ); * } * * ExampleAgent::~ExampleAgent() * { * delete mObserver; * } * * void ExampleObserver::itemChanged( const Item &item ) * { * // do something with item * kDebug() << "Item id=" << item.id(); * * // let base implementation tell the change recorder that we * // have processed the change * AgentBase::Observer::itemChanged( item ); * } * @endcode * * Example for observer through multiple inheritance: * @code * class ExampleAgent : public AgentBase, public AgentBase::Observer * { * public: * ExampleAgent( const QString &id ); * * protected: * void itemChanged( const Item &item ); * }; * * ExampleAgent::ExampleAgent( const QString &id ) * : AgentBase( id ) * { * // no need to create or register observer since * // we are the observer and registration happens automatically * // in init() * } * * void ExampleAgent::itemChanged( const Item &item ) * { * // do something with item * kDebug() << "Item id=" << item.id(); * * // let base implementation tell the change recorder that we * // have processed the change * AgentBase::Observer::itemChanged( item ); * } * @endcode * * @author Kevin Krammer */ class AKONADI_EXPORT Observer // krazy:exclude=dpointer { public: /** * Creates an observer instance. */ Observer(); /** * Destroys the observer instance. */ virtual ~Observer(); /** * Reimplement to handle adding of new items. * @param item The newly added item. * @param collection The collection @p item got added to. */ virtual void itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection ); /** * Reimplement to handle changes to existing items. * @param item The changed item. * @param partIdentifiers The identifiers of the item parts that has been changed. */ virtual void itemChanged( const Akonadi::Item &item, const QSet &partIdentifiers ); /** * Reimplement to handle deletion of items. * @param item The deleted item. */ virtual void itemRemoved( const Akonadi::Item &item ); /** * Reimplement to handle adding of new collections. * @param collection The newly added collection. * @param parent The parent collection. */ virtual void collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent ); /** * Reimplement to handle changes to existing collections. * @param collection The changed collection. */ virtual void collectionChanged( const Akonadi::Collection &collection ); /** * Reimplement to handle deletion of collections. * @param collection The deleted collection. */ virtual void collectionRemoved( const Akonadi::Collection &collection ); }; /** * This enum describes the different states the * agent can be in. */ enum Status { Idle = 0, ///< The agent does currently nothing. Running, ///< The agent is working on something. Broken ///< The agent encountered an error state. }; /** * Use this method in the main function of your agent * application to initialize your agent subclass. * This method also takes care of creating a KApplication * object and parsing command line arguments. * * @note In case the given class is also derived from AgentBase::Observer * it gets registered as its own observer (see AgentBase::Observer), e.g. * agentInstance->registerObserver( agentInstance ); * * @code * * class MyAgent : public AgentBase * { * ... * }; * * AKONADI_AGENT_MAIN( MyAgent ) * * @endcode */ template static int init( int argc, char **argv ) { const QString id = parseArguments( argc, argv ); KApplication app; T* r = new T( id ); // check if T also inherits AgentBase::Observer and // if it does, automatically register it on itself Observer *observer = dynamic_cast( r ); if ( observer != 0 ) r->registerObserver( observer ); return init( r ); } /** * This method returns the current status code of the agent. * * The following return values are possible: * * - 0 - Idle * - 1 - Running * - 2 - Broken */ virtual int status() const; /** * This method returns an i18n'ed description of the current status code. */ virtual QString statusMessage() const; /** * This method returns the current progress of the agent in percentage. */ virtual int progress() const; /** * This method returns an i18n'ed description of the current progress. */ virtual QString progressMessage() const; /** * This method is called whenever the agent shall show its configuration dialog * to the user. It will be automatically called when the agent is started for * the first time. * @param windowId The parent window id. */ virtual void configure( WId windowId ); /** * This method returns the windows id, which should be used for dialogs. */ WId winIdForDialogs() const; #ifdef Q_OS_WIN /** * Overload of @ref configure needed because WId cannot be automatically casted * to qlonglong on Windows. */ void configure( qlonglong windowId ); #endif /** * Returns the instance identifier of this agent. */ QString identifier() const; /** * This method is called when the agent is removed from * the system, so it can do some cleanup stuff. */ virtual void cleanup(); /** * Registers the given observer for reacting on monitored or recorded changes. * * @param observer The change handler to register. No ownership transfer, i.e. * the caller stays owner of the pointer and can reset * the registration by calling this method with @c 0 */ void registerObserver( Observer *observer ); Q_SIGNALS: /** * This signal should be emitted whenever the status of the agent has been changed. * @param status The new Status code. * @param message A i18n'ed description of the new status. */ void status( int status, const QString &message = QString() ); /** * This signal should be emitted whenever the progress of an action in the agent * (e.g. data transfer, connection establishment to remote server etc.) has changed. * * @param progress The progress of the action in percent. */ void percent( int progress ); /** * This signal shall be used to report warnings. * * @param message The i18n'ed warning message. */ void warning( const QString& message ); /** * This signal shall be used to report errors. * * @param message The i18n'ed error message. */ void error( const QString& message ); /** * Emitted if another application has changed the agents configuration remotely * and called AgentInstance::reconfigure(). * * @since 4.2 */ void reloadConfiguration(); + /** + * Emitted when the online state changed. + * @param state The online state. + * @since 4.2 + */ + void onlineChanged( bool b ); + protected: /** * Creates an agent base. * * @param id The instance id of the agent. */ AgentBase( const QString & id ); /** * Destroys the agent base. */ ~AgentBase(); /** * This method is called whenever the agent application is about to * quit. * * Reimplement this method to do session cleanup (e.g. disconnecting * from groupware server). */ virtual void aboutToQuit(); /** * Returns the Akonadi::ChangeRecorder object used for monitoring. * Use this to configure which parts you want to monitor. */ ChangeRecorder* changeRecorder() const; /** * Marks the current change as processes and replays the next change if change * recording is enabled (noop otherwise). This method is called * from the default implementation of the change notification slots. While not * required when not using change recording, it is nevertheless recommended * to call this method when done with processing a change notification. */ void changeProcessed(); /** * Returns whether the agent is currently online. */ bool isOnline() const; /** * Sets whether the agent needs network or not. - * + * * @since 4.2 * @todo use this in combination with Solid::Networking::Notifier to change * the onLine status of the agent. */ void setNeedsNetwork( bool needsNetwork ); - + /** * Sets whether the agent shall be online or not. */ void setOnline( bool state ); protected: //@cond PRIVATE AgentBasePrivate *d_ptr; explicit AgentBase( AgentBasePrivate* d, const QString &id ); //@endcond /** * This method is called whenever the @p online status has changed. * Reimplement this method to react on online status changes. */ virtual void doSetOnline( bool online ); private: //@cond PRIVATE static QString parseArguments( int, char** ); static int init( AgentBase *r ); // D-Bus interface stuff void reconfigure(); void quit(); // dbus agent interface friend class ::StatusAdaptor; friend class ::ControlAdaptor; Q_DECLARE_PRIVATE( AgentBase ) Q_PRIVATE_SLOT( d_func(), void delayedInit() ) Q_PRIVATE_SLOT( d_func(), void slotStatus( int, const QString& ) ) Q_PRIVATE_SLOT( d_func(), void slotPercent( int ) ) Q_PRIVATE_SLOT( d_func(), void slotWarning( const QString& ) ) Q_PRIVATE_SLOT( d_func(), void slotError( const QString& ) ) //@endcond }; } #ifndef AKONADI_AGENT_MAIN /** * Convenience Macro for the most common main() function for Akonadi agents. */ #define AKONADI_AGENT_MAIN( agentClass ) \ int main( int argc, char **argv ) \ { \ return Akonadi::AgentBase::init( argc, argv ); \ } #endif #endif diff --git a/akonadi/agentinstancemodel.cpp b/akonadi/agentinstancemodel.cpp index 2df1ce9a2..d8f182009 100644 --- a/akonadi/agentinstancemodel.cpp +++ b/akonadi/agentinstancemodel.cpp @@ -1,227 +1,229 @@ /* Copyright (c) 2006 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 "agentinstancemodel.h" #include "agentinstance.h" #include "agentmanager.h" #include #include #include using namespace Akonadi; /** * @internal */ class AgentInstanceModel::Private { public: Private( AgentInstanceModel *parent ) : mParent( parent ) { } AgentInstanceModel *mParent; AgentInstance::List mInstances; void instanceAdded( const AgentInstance& ); void instanceRemoved( const AgentInstance& ); void instanceChanged( const AgentInstance& ); }; void AgentInstanceModel::Private::instanceAdded( const AgentInstance &instance ) { mInstances.append( instance ); emit mParent->layoutChanged(); } void AgentInstanceModel::Private::instanceRemoved( const AgentInstance &instance ) { mInstances.removeAll( instance ); emit mParent->layoutChanged(); } void AgentInstanceModel::Private::instanceChanged( const AgentInstance &instance ) { for ( int i = 0; i < mInstances.count(); ++i ) { if ( mInstances[ i ] == instance ) { mInstances[ i ] = instance; const QModelIndex idx = mParent->index( i, 0 ); emit mParent->dataChanged( idx, idx ); return; } } } AgentInstanceModel::AgentInstanceModel( QObject *parent ) : QAbstractItemModel( parent ), d( new Private( this ) ) { d->mInstances = AgentManager::self()->instances(); connect( AgentManager::self(), SIGNAL( instanceAdded( const Akonadi::AgentInstance& ) ), this, SLOT( instanceAdded( const Akonadi::AgentInstance& ) ) ); connect( AgentManager::self(), SIGNAL( instanceRemoved( const Akonadi::AgentInstance& ) ), this, SLOT( instanceRemoved( const Akonadi::AgentInstance& ) ) ); connect( AgentManager::self(), SIGNAL( instanceStatusChanged( const Akonadi::AgentInstance& ) ), this, SLOT( instanceChanged( const Akonadi::AgentInstance& ) ) ); connect( AgentManager::self(), SIGNAL( instanceProgressChanged( const Akonadi::AgentInstance& ) ), this, SLOT( instanceChanged( const Akonadi::AgentInstance& ) ) ); connect( AgentManager::self(), SIGNAL( instanceNameChanged( const Akonadi::AgentInstance& ) ), this, SLOT( instanceChanged( const Akonadi::AgentInstance& ) ) ); + connect( AgentManager::self(), SIGNAL(instanceOnline(Akonadi::AgentInstance,bool)), + SLOT(instanceChanged(Akonadi::AgentInstance)) ); } AgentInstanceModel::~AgentInstanceModel() { delete d; } int AgentInstanceModel::columnCount( const QModelIndex& ) const { return 1; } int AgentInstanceModel::rowCount( const QModelIndex& ) const { return d->mInstances.count(); } QVariant AgentInstanceModel::data( const QModelIndex &index, int role ) const { if ( !index.isValid() ) return QVariant(); if ( index.row() < 0 || index.row() >= d->mInstances.count() ) return QVariant(); const AgentInstance &instance = d->mInstances[ index.row() ]; switch ( role ) { case Qt::DisplayRole: return instance.name(); case Qt::DecorationRole: return instance.type().icon(); case InstanceRole: { QVariant var; var.setValue( instance ); return var; } case InstanceIdentifierRole: return instance.identifier(); case Qt::ToolTipRole: return QString::fromLatin1( "

%1

%2
" ).arg( instance.name(), instance.type().description() ); case StatusRole: return instance.status(); case StatusMessageRole: return instance.statusMessage(); case ProgressRole: return instance.progress(); case OnlineRole: return instance.isOnline(); case TypeRole: { QVariant var; var.setValue( instance.type() ); return var; } case TypeIdentifierRole: return instance.type().identifier(); case DescriptionRole: return instance.type().description(); case CapabilitiesRole: return instance.type().capabilities(); case MimeTypesRole: return instance.type().mimeTypes(); } return QVariant(); } QVariant AgentInstanceModel::headerData( int section, Qt::Orientation orientation, int role ) const { if ( orientation == Qt::Vertical ) return QVariant(); if ( role != Qt::DisplayRole ) return QVariant(); switch ( section ) { case 0: return i18nc( "@title:column, name of a thing", "Name" ); break; default: return QVariant(); break; } } QModelIndex AgentInstanceModel::index( int row, int column, const QModelIndex& ) const { if ( row < 0 || row >= d->mInstances.count() ) return QModelIndex(); if ( column != 0 ) return QModelIndex(); return createIndex( row, column, 0 ); } QModelIndex AgentInstanceModel::parent( const QModelIndex& ) const { return QModelIndex(); } Qt::ItemFlags AgentInstanceModel::flags( const QModelIndex & index ) const { if ( !index.isValid() || index.row() < 0 || index.row() >= d->mInstances.count() ) return QAbstractItemModel::flags( index ); return QAbstractItemModel::flags( index ) | Qt::ItemIsEditable; } bool AgentInstanceModel::setData( const QModelIndex & index, const QVariant & value, int role ) { if ( !index.isValid() ) return false; if ( index.row() < 0 || index.row() >= d->mInstances.count() ) return false; AgentInstance &instance = d->mInstances[ index.row() ]; switch ( role ) { case OnlineRole: instance.setIsOnline( value.toBool() ); emit dataChanged( index, index ); return true; default: return false; } return false; } #include "agentinstancemodel.moc" diff --git a/akonadi/agentinstancewidget.cpp b/akonadi/agentinstancewidget.cpp index 66233fdd9..eb527386f 100644 --- a/akonadi/agentinstancewidget.cpp +++ b/akonadi/agentinstancewidget.cpp @@ -1,292 +1,295 @@ /* 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 "agentinstancewidget.h" #include "agentfilterproxymodel.h" #include "agentinstance.h" #include "agentinstancemodel.h" #include #include #include #include #include #include #include #include #include using namespace Akonadi; struct Icons { Icons() : readyPixmap( KIcon( QLatin1String("user-online") ).pixmap( QSize( 16, 16 ) ) ) , syncPixmap( KIcon( QLatin1String("network-connect") ).pixmap( QSize( 16, 16 ) ) ) , errorPixmap( KIcon( QLatin1String("dialog-error") ).pixmap( QSize( 16, 16 ) ) ) + , offlinePixmap( KIcon( QLatin1String("network-disconnect") ).pixmap( QSize( 16, 16 ) ) ) { } - QPixmap readyPixmap, syncPixmap, errorPixmap; + QPixmap readyPixmap, syncPixmap, errorPixmap, offlinePixmap; }; K_GLOBAL_STATIC( Icons, s_icons ) /** * @internal */ class AgentInstanceWidgetDelegate : public QAbstractItemDelegate { public: AgentInstanceWidgetDelegate( QObject *parent = 0 ); virtual void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const; virtual QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const; private: void drawFocus( QPainter*, const QStyleOptionViewItem&, const QRect& ) const; QTextDocument* document( const QStyleOptionViewItem &option, const QModelIndex &index ) const; }; /** * @internal */ class AgentInstanceWidget::Private { public: Private( AgentInstanceWidget *parent ) : mParent( parent ) { } void currentAgentInstanceChanged( const QModelIndex&, const QModelIndex& ); void currentAgentInstanceDoubleClicked( const QModelIndex& ); AgentInstanceWidget *mParent; QListView *mView; AgentInstanceModel *mModel; AgentFilterProxyModel *proxy; }; void AgentInstanceWidget::Private::currentAgentInstanceChanged( const QModelIndex ¤tIndex, const QModelIndex &previousIndex ) { AgentInstance currentInstance; if ( currentIndex.isValid() ) currentInstance = currentIndex.data( AgentInstanceModel::InstanceRole ).value(); AgentInstance previousInstance; if ( previousIndex.isValid() ) previousInstance = previousIndex.data( AgentInstanceModel::InstanceRole ).value(); emit mParent->currentChanged( currentInstance, previousInstance ); } void AgentInstanceWidget::Private::currentAgentInstanceDoubleClicked( const QModelIndex ¤tIndex ) { AgentInstance currentInstance; if ( currentIndex.isValid() ) currentInstance = currentIndex.data( AgentInstanceModel::InstanceRole ).value(); emit mParent->doubleClicked( currentInstance ); } AgentInstanceWidget::AgentInstanceWidget( QWidget *parent ) : QWidget( parent ), d( new Private( this ) ) { QHBoxLayout *layout = new QHBoxLayout( this ); layout->setMargin( 0 ); layout->setSpacing( 0 ); d->mView = new QListView( this ); d->mView->setItemDelegate( new AgentInstanceWidgetDelegate( d->mView ) ); layout->addWidget( d->mView ); d->mModel = new AgentInstanceModel( this ); d->proxy = new AgentFilterProxyModel( this ); d->proxy->setSourceModel( d->mModel ); d->mView->setModel( d->proxy ); d->mView->selectionModel()->setCurrentIndex( d->mView->model()->index( 0, 0 ), QItemSelectionModel::Select ); d->mView->scrollTo( d->mView->model()->index( 0, 0 ) ); connect( d->mView->selectionModel(), SIGNAL( currentChanged( const QModelIndex&, const QModelIndex& ) ), this, SLOT( currentAgentInstanceChanged( const QModelIndex&, const QModelIndex& ) ) ); connect( d->mView, SIGNAL( doubleClicked( const QModelIndex& ) ), this, SLOT( currentAgentInstanceDoubleClicked( const QModelIndex& ) ) ); } AgentInstanceWidget::~AgentInstanceWidget() { delete d; } AgentInstance AgentInstanceWidget::currentAgentInstance() const { QItemSelectionModel *selectionModel = d->mView->selectionModel(); if ( !selectionModel ) return AgentInstance(); QModelIndex index = selectionModel->currentIndex(); if ( !index.isValid() ) return AgentInstance(); return index.data( AgentInstanceModel::InstanceRole ).value(); } AgentFilterProxyModel* AgentInstanceWidget::agentFilterProxyModel() const { return d->proxy; } AgentInstanceWidgetDelegate::AgentInstanceWidgetDelegate( QObject *parent ) : QAbstractItemDelegate( parent ) { } QTextDocument* AgentInstanceWidgetDelegate::document( const QStyleOptionViewItem &option, const QModelIndex &index ) const { if ( !index.isValid() ) return 0; const QString name = index.model()->data( index, Qt::DisplayRole ).toString(); int status = index.model()->data( index, AgentInstanceModel::StatusRole ).toInt(); uint progress = index.model()->data( index, AgentInstanceModel::ProgressRole ).toUInt(); const QString statusMessage = index.model()->data( index, AgentInstanceModel::StatusMessageRole ).toString(); const QStringList capabilities = index.model()->data( index, AgentInstanceModel::CapabilitiesRole ).toStringList(); QTextDocument *document = new QTextDocument( 0 ); const QVariant data = index.model()->data( index, Qt::DecorationRole ); if ( data.isValid() && data.type() == QVariant::Icon ) { document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "agent_icon" ) ), qvariant_cast( data ).pixmap( QSize( 64, 64 ) ) ); } - if ( status == 0 ) + if ( !index.data( AgentInstanceModel::OnlineRole ).toBool() ) + document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->offlinePixmap ); + else if ( status == AgentInstance::Idle ) document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->readyPixmap ); - else if ( status == 1 ) + else if ( status == AgentInstance::Running ) document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->syncPixmap ); else document->addResource( QTextDocument::ImageResource, QUrl( QLatin1String( "status_icon" ) ), s_icons->errorPixmap ); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if ( cg == QPalette::Normal && !(option.state & QStyle::State_Active) ) cg = QPalette::Inactive; QColor textColor; if ( option.state & QStyle::State_Selected ) { textColor = option.palette.color( cg, QPalette::HighlightedText ); } else { textColor = option.palette.color( cg, QPalette::Text ); } QString content = QString::fromLatin1( "" "" "" "" "" "" "" ).arg(textColor.name().toUpper()).arg( name ); if ( capabilities.contains( QLatin1String( "Resource" ) ) ) { content += QString::fromLatin1( "" "" "" ).arg( statusMessage ).arg( status == 1 ? QString( QLatin1String( "(%1%)" ) ).arg( progress ) : QLatin1String( "" ) ); } content += QLatin1String( "
%2
%1 %2
" ); document->setHtml( content ); return document; } void AgentInstanceWidgetDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { if ( !index.isValid() ) return; QTextDocument *doc = document( option, index ); if ( !doc ) return; painter->setRenderHint( QPainter::Antialiasing ); QPen pen = painter->pen(); QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled; if ( cg == QPalette::Normal && !(option.state & QStyle::State_Active) ) cg = QPalette::Inactive; if ( option.state & QStyle::State_Selected ) { painter->fillRect( option.rect, option.palette.brush( cg, QPalette::Highlight ) ); painter->setPen( option.palette.color( cg, QPalette::HighlightedText ) ); } else { painter->setPen(option.palette.color( cg, QPalette::Text ) ); } painter->save(); painter->translate( option.rect.topLeft() ); doc->drawContents( painter ); delete doc; painter->restore(); painter->setPen(pen); drawFocus( painter, option, option.rect ); } QSize AgentInstanceWidgetDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const { if ( !index.isValid() ) return QSize( 0, 0 ); QTextDocument *doc = document( option, index ); if ( !doc ) return QSize( 0, 0 ); const QSize size = doc->documentLayout()->documentSize().toSize(); delete doc; return size; } void AgentInstanceWidgetDelegate::drawFocus( QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect ) const { if ( option.state & QStyle::State_HasFocus ) { QStyleOptionFocusRect o; o.QStyleOption::operator=( option ); o.rect = rect; o.state |= QStyle::State_KeyboardFocusChange; QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled) ? QPalette::Normal : QPalette::Disabled; o.backgroundColor = option.palette.color( cg, (option.state & QStyle::State_Selected) ? QPalette::Highlight : QPalette::Background ); QApplication::style()->drawPrimitive( QStyle::PE_FrameFocusRect, &o, painter ); } } #include "agentinstancewidget.moc" diff --git a/akonadi/agentmanager.cpp b/akonadi/agentmanager.cpp index 55d3515c3..f0ce4e259 100644 --- a/akonadi/agentmanager.cpp +++ b/akonadi/agentmanager.cpp @@ -1,310 +1,322 @@ /* 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 using namespace Akonadi; // @cond PRIVATE 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 ) { const AgentType type = fillAgentType( identifier ); if ( type.isValid() ) { mTypes.insert( identifier, type ); 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 initally 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; 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 ); } AgentType AgentManagerPrivate::fillAgentType( const QString &identifier ) const { AgentType type; type.d->mIdentifier = identifier; type.d->mName = mManager->agentName( identifier ); type.d->mDescription = mManager->agentComment( identifier ); 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 ); Q_ASSERT_X( mTypes.contains( agentTypeIdentifier ), "fillAgentInstance", "Requests non-existing agent type" ); 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 ) ) { 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(QString,bool)), + SLOT(agentInstanceOnlineChanged(QString,bool)) ); const QStringList typeIdentifiers = d->mManager->agentTypes(); foreach( const QString &type, typeIdentifiers ) { const AgentType agentType = d->fillAgentType( type ); d->mTypes.insert( type, agentType ); } const QStringList instanceIdentifiers = d->mManager->agentInstances(); foreach( const QString &instance, instanceIdentifiers ) { const AgentInstance agentInstance = d->fillAgentInstance( instance ); d->mInstances.insert( instance, agentInstance ); } } // @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 1cd02ff92..9740ea1d8 100644 --- a/akonadi/agentmanager.h +++ b/akonadi/agentmanager.h @@ -1,196 +1,206 @@ /* 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 &identififer ) 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 &identififer ) 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 ) ) //@endcond }; } #endif diff --git a/akonadi/agentmanager_p.h b/akonadi/agentmanager_p.h index ba301c452..412339a69 100644 --- a/akonadi/agentmanager_p.h +++ b/akonadi/agentmanager_p.h @@ -1,83 +1,84 @@ /* 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 ) { } /* * 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 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; static AgentManager *mSelf; AgentManager *mParent; org::freedesktop::Akonadi::AgentManager *mManager; QHash mTypes; QHash mInstances; }; } #endif