diff --git a/akonadi/agentbase.cpp b/akonadi/agentbase.cpp index 7ed317e28..64b4a2a26 100644 --- a/akonadi/agentbase.cpp +++ b/akonadi/agentbase.cpp @@ -1,598 +1,597 @@ /* 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(); mName = mSettings->value( QLatin1String( "Agent/Name" ) ).toString(); - if (mName.isEmpty()) { + if ( mName.isEmpty() ) { mName = mSettings->value( QLatin1String( "Resource/Name" ) ).toString(); - if (!mName.isEmpty()) { + if ( !mName.isEmpty() ) { mSettings->remove( QLatin1String( "Resource/Name" ) ); mSettings->setValue( QLatin1String( "Agent/Name" ), mName ); } } - 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(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)), - SLOT(itemMoved(Akonadi::Item,Akonadi::Collection,Akonadi::Collection)) ); + connect( mMonitor, SIGNAL( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ), + SLOT( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 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( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ), + SLOT( collectionAdded( const Akonadi::Collection&, const 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( status( int, const QString& ) ), q, SLOT( slotStatus( int, const 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 ) ) ); + connect( q, SIGNAL( warning( const QString& ) ), q, SLOT( slotWarning( const QString& ) ) ); + connect( q, SIGNAL( error( const QString& ) ), q, SLOT( slotError( const 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::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest ) { kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this; if ( mObserver ) { // inter-resource moves, requires we know which resources the source and destination are in though if ( !source.resource().isEmpty() && !dest.resource().isEmpty() ) { if ( source.resource() != dest.resource() ) { if ( source.resource() == q_ptr->identifier() ) // moved away from us mObserver->itemRemoved( item ); else if ( dest.resource() == q_ptr->identifier() ) // moved to us mObserver->itemAdded( item, dest ); else // not for us, not sure if we should get here at all changeProcessed(); return; } } // either incomplete information or intra-resource move // ### we cannot just call itemRemoved here as this will already trigger changeProcessed() // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway // without using Observer2 mObserver->itemAdded( item, dest ); // mObserver->itemRemoved( item ); } } 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(); if ( KApplication::kApplication() ) KApplication::kApplication()->disableSessionManagement(); } AgentBase::AgentBase( AgentBasePrivate* d, const QString &id ) : d_ptr( d ) { sAgentBase = this; d_ptr->mId = id; d_ptr->init(); } AgentBase::~AgentBase() { delete d_ptr; } 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 ); } QByteArray catalog; char *p = strrchr( argv[0], '/' ); if ( p ) catalog = QByteArray( p + 1 ); else catalog = QByteArray( argv[0] ); KCmdLineArgs::init( argc, argv, identifier.toLatin1(), catalog, 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 ); KGlobal::locale()->insertCatalog( QLatin1String("libakonadi") ); int rv = kapp->exec(); delete r; 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 ) ) , this, 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 //krazy:exclude=cpp 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 ); // prevent the monitor from picking up deletion signals for our own data if we are a resource // and thus avoid that we kill our own data as last act before our own death d->mMonitor->blockSignals( true ); aboutToQuit(); 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 ); KGlobal::deref(); } 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::setAgentName( const QString &name ) { Q_D( AgentBase ); if ( name == d->mName ) return; // TODO: rename collection d->mName = name; if ( d->mName.isEmpty() || d->mName == d->mId ) { d->mSettings->remove( QLatin1String( "Resource/Name" ) ); d->mSettings->remove( QLatin1String( "Agent/Name" ) ); } else d->mSettings->setValue( QLatin1String( "Agent/Name" ), d->mName ); d->mSettings->sync(); emit agentNameChanged( d->mName ); } QString AgentBase::agentName() const { Q_D( const AgentBase ); if ( d->mName.isEmpty() ) return d->mId; else return d->mName; } 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 07285ce2b..caa2742ba 100644 --- a/akonadi/agentbase.h +++ b/akonadi/agentbase.h @@ -1,492 +1,498 @@ /* 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 ); /** * This method is used to set the name of the agent. + * + * @since 4.3 */ //FIXME_API: make sure location is renamed to this by agentbase void setAgentName( const QString &name ); /** * Returns the name of the agent. + * + * @since 4.3 */ QString agentName() const; Q_SIGNALS: /** * This signal is emitted whenever the name of the agent has changed. * * @param name The new name of the agent. + * + * @since 4.3 */ void agentNameChanged( const QString &name ); /** * 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& ) ) Q_PRIVATE_SLOT( d_func(), void slotNetworkStatusChange( Solid::Networking::Status ) ) //@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/collectiondeletejob.h b/akonadi/collectiondeletejob.h index 9850fa46e..ab06a264a 100644 --- a/akonadi/collectiondeletejob.h +++ b/akonadi/collectiondeletejob.h @@ -1,76 +1,76 @@ /* Copyright (c) 2006 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_COLLECTIONDELETEJOB_H #define AKONADI_COLLECTIONDELETEJOB_H #include namespace Akonadi { class Collection; class CollectionDeleteJobPrivate; /** * @short Job that deletes a collection in the Akonadi storage. * * This job deletes a collection and all its sub-collections as well as all associated content. * * @code * * Akonadi::Collection collection = ... * * Akonadi::CollectionDeleteJob *job = new Akonadi::CollectionDeleteJob( collection ); - * connect( job, SIGNAL(result(KJob*)), this, SLOT(deletionResult(KJob*)) ); + * connect( job, SIGNAL( result( KJob* ) ), this, SLOT( deletionResult( KJob* ) ) ); * * @endcode * * @author Volker Krause */ class AKONADI_EXPORT CollectionDeleteJob : public Job { Q_OBJECT public: /** * Creates a new collection delete job. The collection needs to either have a unique * identifier or a remote identifier set. Note that using a remote identifier only works * in a resource context (that is from within ResourceBase), as remote identifiers * are not guaranteed to be globally unique. * * @param collection The collection to delete. * @param parent The parent object. */ explicit CollectionDeleteJob( const Collection &collection, QObject *parent = 0 ); /** * Destroys the collection delete job. */ ~CollectionDeleteJob(); protected: virtual void doStart(); private: Q_DECLARE_PRIVATE( CollectionDeleteJob ) }; } #endif diff --git a/akonadi/collectionmodifyjob.h b/akonadi/collectionmodifyjob.h index d7f42823b..e05b75415 100644 --- a/akonadi/collectionmodifyjob.h +++ b/akonadi/collectionmodifyjob.h @@ -1,80 +1,80 @@ /* Copyright (c) 2006 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_COLLECTIONMODIFYJOB_H #define AKONADI_COLLECTIONMODIFYJOB_H #include "akonadi_export.h" #include namespace Akonadi { class CachePolicy; class Collection; class CollectionModifyJobPrivate; /** * @short Job that modifies a collection in the Akonadi storage. * * This job modifies the properties of an existing collection. * * @code * * Akonadi::Collection collection = ... * * Akonadi::CollectionModifyJob *job = new Akonadi::CollectionModifyJob( collection ); - * connect( job, SIGNAL(result(KJob*)), this, SLOT(modifyResult(KJob*)) ); + * connect( job, SIGNAL( result( KJob* ) ), this, SLOT( modifyResult( KJob* ) ) ); * * @endcode * * @author Volker Krause */ class AKONADI_EXPORT CollectionModifyJob : public Job { Q_OBJECT public: /** * Creates a new collection modify job for the given collection. The collection can be * identified either by its unique identifier or its remote identifier. Since the remote * identifier is not necessarily globally unique, identification by remote identifier only * works inside a resource context (that is from within ResourceBase) and is therefore * limited to one resource. * * @param collection The collection to modify. * @param parent The parent object. */ explicit CollectionModifyJob( const Collection &collection, QObject *parent = 0 ); /** * Destroys the collection modify job. */ ~CollectionModifyJob(); protected: virtual void doStart(); private: Q_DECLARE_PRIVATE( CollectionModifyJob ) }; } #endif diff --git a/akonadi/collectionmovejob.h b/akonadi/collectionmovejob.h index f81bacd10..979827cc0 100644 --- a/akonadi/collectionmovejob.h +++ b/akonadi/collectionmovejob.h @@ -1,60 +1,72 @@ /* Copyright (c) 2009 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef AKONADI_COLLECTIONMOVEJOB_H #define AKONADI_COLLECTIONMOVEJOB_H #include "akonadi_export.h" #include namespace Akonadi { class Collection; class CollectionMoveJobPrivate; /** * @short Job that moves a collection in the Akonadi storage to a new parent collection. * * This job moves an existing collection to a new parent collection. + * + * @code + * + * const Akonadi::Collection collection = ... + * const Akonadi::Collection newParent = ... + * + * Akonadi::CollectionMoveJob *job = new Akonadi::CollectionMoveJob( collection, newParent ); + * connect( job, SIGNAL( result( KJob* ) ), this, SLOT( moveResult( KJob* ) ) ); + * + * @endcode + * + * @author Volker Krause */ class AKONADI_EXPORT CollectionMoveJob : public Job { Q_OBJECT public: /** * Creates a new collection move job for the given collection and destination * * @param collection The collection to move. * @param destination The destination collection where @p collection should be moved to. * @param parent The parent object. */ CollectionMoveJob( const Collection &collection, const Collection &destination, QObject *parent = 0 ); protected: virtual void doStart(); private: Q_DECLARE_PRIVATE( CollectionMoveJob ) }; } #endif diff --git a/akonadi/resourcebase.cpp b/akonadi/resourcebase.cpp index be798b66e..8c4eccee6 100644 --- a/akonadi/resourcebase.cpp +++ b/akonadi/resourcebase.cpp @@ -1,604 +1,606 @@ /* Copyright (c) 2006 Till Adam Copyright (c) 2007 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "resourcebase.h" #include "agentbase_p.h" #include "resourceadaptor.h" #include "collectiondeletejob.h" #include "collectionsync_p.h" #include "itemsync.h" #include "resourcescheduler_p.h" #include "tracerinterface.h" #include "xdgbasedirs_p.h" #include "changerecorder.h" #include "collectionfetchjob.h" #include "collectionmodifyjob.h" #include "itemfetchjob.h" #include "itemfetchscope.h" #include "itemmodifyjob.h" #include "itemmodifyjob_p.h" #include "session.h" #include "resourceselectjob_p.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Akonadi; class Akonadi::ResourceBasePrivate : public AgentBasePrivate { public: ResourceBasePrivate( ResourceBase *parent ) : AgentBasePrivate( parent ), scheduler( 0 ), mItemSyncer( 0 ), mCollectionSyncer( 0 ) { mStatusMessage = defaultReadyMessage(); } Q_DECLARE_PUBLIC( ResourceBase ) void delayedInit() { if ( !QDBusConnection::sessionBus().registerService( QLatin1String( "org.freedesktop.Akonadi.Resource." ) + mId ) ) kFatal() << "Unable to register service at D-Bus: " << QDBusConnection::sessionBus().lastError().message(); AgentBasePrivate::delayedInit(); } virtual void changeProcessed() { mMonitor->changeProcessed(); if ( !mMonitor->isEmpty() ) scheduler->scheduleChangeReplay(); scheduler->taskDone(); } void slotDeliveryDone( KJob* job ); void slotCollectionSyncDone( KJob *job ); void slotLocalListDone( KJob *job ); void slotSynchronizeCollection( const Collection &col ); void slotCollectionListDone( KJob *job ); void slotItemSyncDone( KJob *job ); void slotPercent( KJob* job, unsigned long percent ); void slotDeleteResourceCollection(); void slotDeleteResourceCollectionDone( KJob *job ); void slotCollectionDeletionDone( KJob *job ); // synchronize states Collection currentCollection; ResourceScheduler *scheduler; ItemSync *mItemSyncer; CollectionSync *mCollectionSyncer; }; ResourceBase::ResourceBase( const QString & id ) : AgentBase( new ResourceBasePrivate( this ), id ) { Q_D( ResourceBase ); new ResourceAdaptor( this ); d->scheduler = new ResourceScheduler( this ); d->mMonitor->setChangeRecordingEnabled( true ); - connect( d->mMonitor, SIGNAL(changesAdded()), - d->scheduler, SLOT(scheduleChangeReplay()) ); + connect( d->mMonitor, SIGNAL( changesAdded() ), + d->scheduler, SLOT( scheduleChangeReplay() ) ); d->mMonitor->setResourceMonitored( d->mId.toLatin1() ); - connect( d->scheduler, SIGNAL(executeFullSync()), - SLOT(retrieveCollections()) ); - connect( d->scheduler, SIGNAL(executeCollectionTreeSync()), - SLOT(retrieveCollections()) ); - connect( d->scheduler, SIGNAL(executeCollectionSync(Akonadi::Collection)), - SLOT(slotSynchronizeCollection(Akonadi::Collection)) ); - connect( d->scheduler, SIGNAL(executeItemFetch(Akonadi::Item,QSet)), - SLOT(retrieveItem(Akonadi::Item,QSet)) ); - connect( d->scheduler, SIGNAL(executeResourceCollectionDeletion()), - SLOT(slotDeleteResourceCollection()) ); - connect( d->scheduler, SIGNAL( status( int, QString ) ), - SIGNAL( status( int, QString ) ) ); - connect( d->scheduler, SIGNAL(executeChangeReplay()), - d->mMonitor, SLOT(replayNext()) ); - connect( d->scheduler, SIGNAL(fullSyncComplete()), SIGNAL(synchronized()) ); - connect( d->mMonitor, SIGNAL(nothingToReplay()), d->scheduler, SLOT(taskDone()) ); - connect( this, SIGNAL(synchronized()), d->scheduler, SLOT(taskDone()) ); - connect( this, SIGNAL(agentNameChanged(QString)), this, SIGNAL(nameChanged(QString))); + connect( d->scheduler, SIGNAL( executeFullSync() ), + SLOT( retrieveCollections() ) ); + connect( d->scheduler, SIGNAL( executeCollectionTreeSync() ), + SLOT( retrieveCollections() ) ); + connect( d->scheduler, SIGNAL( executeCollectionSync( const Akonadi::Collection& ) ), + SLOT( slotSynchronizeCollection( const Akonadi::Collection& ) ) ); + connect( d->scheduler, SIGNAL( executeItemFetch( const Akonadi::Item&, const QSet& ) ), + SLOT( retrieveItem( const Akonadi::Item&, const QSet& ) ) ); + connect( d->scheduler, SIGNAL( executeResourceCollectionDeletion() ), + SLOT( slotDeleteResourceCollection() ) ); + connect( d->scheduler, SIGNAL( status( int, const QString& ) ), + SIGNAL( status( int, const QString& ) ) ); + connect( d->scheduler, SIGNAL( executeChangeReplay() ), + d->mMonitor, SLOT( replayNext() ) ); + connect( d->scheduler, SIGNAL( fullSyncComplete() ), SIGNAL( synchronized() ) ); + connect( d->mMonitor, SIGNAL( nothingToReplay() ), d->scheduler, SLOT( taskDone() ) ); + connect( this, SIGNAL( synchronized() ), d->scheduler, SLOT( taskDone() ) ); + connect( this, SIGNAL( agentNameChanged( const QString& ) ), + this, SIGNAL( nameChanged( const QString& ) ) ); d->scheduler->setOnline( d->mOnline ); if ( !d->mMonitor->isEmpty() ) d->scheduler->scheduleChangeReplay(); new ResourceSelectJob( identifier() ); } ResourceBase::~ResourceBase() { } void ResourceBase::synchronize() { d_func()->scheduler->scheduleFullSync(); } void ResourceBase::setName( const QString &name ) { - AgentBase::setAgentName(name); + AgentBase::setAgentName( name ); } QString ResourceBase::name() const { - return AgentBase::agentName(); + return AgentBase::agentName(); } QString ResourceBase::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 ); } QByteArray catalog; char *p = strrchr( argv[0], '/' ); if ( p ) catalog = QByteArray( p + 1 ); else catalog = QByteArray( argv[0] ); KCmdLineArgs::init( argc, argv, identifier.toLatin1(), catalog, ki18nc("@title, application name", "Akonadi Resource"), "0.1", ki18nc("@title, application description", "Akonadi Resource") ); KCmdLineOptions options; - options.add("identifier ", - ki18nc("@label, commandline option", "Resource identifier")); + options.add( "identifier ", + ki18nc("@label, commandline option", "Resource identifier") ); KCmdLineArgs::addCmdLineOptions( options ); return identifier; } int ResourceBase::init( ResourceBase *r ) { QApplication::setQuitOnLastWindowClosed( false ); int rv = kapp->exec(); delete r; return rv; } void ResourceBase::itemRetrieved( const Item &item ) { Q_D( ResourceBase ); Q_ASSERT( d->scheduler->currentTask().type == ResourceScheduler::FetchItem ); if ( !item.isValid() ) { QDBusMessage reply( d->scheduler->currentTask().dbusMsg ); reply << false; QDBusConnection::sessionBus().send( reply ); d->scheduler->taskDone(); return; } Item i( item ); QSet requestedParts = d->scheduler->currentTask().itemParts; foreach ( const QByteArray &part, requestedParts ) { if ( !item.loadedPayloadParts().contains( part ) ) { kWarning( 5250 ) << "Item does not provide part" << part; } } ItemModifyJob *job = new ItemModifyJob( i ); // FIXME: remove once the item with which we call retrieveItem() has a revision number job->disableRevisionCheck(); - connect( job, SIGNAL(result(KJob*)), SLOT(slotDeliveryDone(KJob*)) ); + connect( job, SIGNAL( result( KJob* ) ), SLOT( slotDeliveryDone( KJob* ) ) ); } void ResourceBasePrivate::slotDeliveryDone(KJob * job) { Q_Q( ResourceBase ); Q_ASSERT( scheduler->currentTask().type == ResourceScheduler::FetchItem ); QDBusMessage reply( scheduler->currentTask().dbusMsg ); if ( job->error() ) { emit q->error( QLatin1String( "Error while creating item: " ) + job->errorString() ); reply << false; } else { reply << true; } QDBusConnection::sessionBus().send( reply ); scheduler->taskDone(); } void ResourceBasePrivate::slotDeleteResourceCollection() { Q_Q( ResourceBase ); CollectionFetchJob *job = new CollectionFetchJob( Collection::root(), CollectionFetchJob::FirstLevel ); job->setResource( q->identifier() ); - connect( job, SIGNAL(result(KJob*)), q, SLOT(slotDeleteResourceCollectionDone(KJob*)) ); + connect( job, SIGNAL( result( KJob* ) ), q, SLOT( slotDeleteResourceCollectionDone( KJob* ) ) ); } void ResourceBasePrivate::slotDeleteResourceCollectionDone( KJob *job ) { Q_Q( ResourceBase ); if ( job->error() ) { emit q->error( job->errorString() ); scheduler->taskDone(); } else { const CollectionFetchJob *fetchJob = static_cast( job ); if ( !fetchJob->collections().isEmpty() ) { CollectionDeleteJob *job = new CollectionDeleteJob( fetchJob->collections().first() ); connect( job, SIGNAL( result( KJob* ) ), q, SLOT( slotCollectionDeletionDone( KJob* ) ) ); } else { // there is no resource collection, so just ignore the request scheduler->taskDone(); } } } void ResourceBasePrivate::slotCollectionDeletionDone( KJob *job ) { Q_Q( ResourceBase ); if ( job->error() ) { emit q->error( job->errorString() ); } scheduler->taskDone(); } -void ResourceBase::changeCommitted(const Item& item) +void ResourceBase::changeCommitted( const Item& item ) { Q_D( ResourceBase ); ItemModifyJob *job = new ItemModifyJob( item ); job->d_func()->setClean(); job->disableRevisionCheck(); // TODO: remove, but where/how do we handle the error? job->ignorePayload(); // we only want to reset the dirty flag and update the remote id d->changeProcessed(); } void ResourceBase::changeCommitted( const Collection &collection ) { Q_D( ResourceBase ); CollectionModifyJob *job = new CollectionModifyJob( collection ); Q_UNUSED( job ); //TODO: error checking d->changeProcessed(); } bool ResourceBase::requestItemDelivery( qint64 uid, const QString & remoteId, const QString &mimeType, const QStringList &_parts ) { Q_D( ResourceBase ); if ( !isOnline() ) { emit error( i18nc( "@info", "Cannot fetch item in offline mode." ) ); return false; } setDelayedReply( true ); // FIXME: we need at least the revision number too Item item( uid ); item.setMimeType( mimeType ); item.setRemoteId( remoteId ); QSet parts; Q_FOREACH( const QString &str, _parts ) parts.insert( str.toLatin1() ); d->scheduler->scheduleItemFetch( item, parts, message().createReply() ); return true; } -void ResourceBase::collectionsRetrieved(const Collection::List & collections) +void ResourceBase::collectionsRetrieved( const Collection::List & collections ) { Q_D( ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || d->scheduler->currentTask().type == ResourceScheduler::SyncAll, "ResourceBase::collectionsRetrieved()", "Calling collectionsRetrieved() although no collection retrieval is in progress" ); if ( !d->mCollectionSyncer ) { d->mCollectionSyncer = new CollectionSync( identifier() ); - connect( d->mCollectionSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) ); - connect( d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) ); + connect( d->mCollectionSyncer, SIGNAL( percent( KJob*, unsigned long ) ), SLOT( slotPercent( KJob*, unsigned long ) ) ); + connect( d->mCollectionSyncer, SIGNAL( result( KJob* ) ), SLOT( slotCollectionSyncDone( KJob* ) ) ); } d->mCollectionSyncer->setRemoteCollections( collections ); } -void ResourceBase::collectionsRetrievedIncremental(const Collection::List & changedCollections, const Collection::List & removedCollections) +void ResourceBase::collectionsRetrievedIncremental( const Collection::List & changedCollections, + const Collection::List & removedCollections ) { Q_D( ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || d->scheduler->currentTask().type == ResourceScheduler::SyncAll, "ResourceBase::collectionsRetrievedIncremental()", "Calling collectionsRetrievedIncremental() although no collection retrieval is in progress" ); if ( !d->mCollectionSyncer ) { d->mCollectionSyncer = new CollectionSync( identifier() ); - connect( d->mCollectionSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) ); - connect( d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) ); + connect( d->mCollectionSyncer, SIGNAL( percent( KJob*, unsigned long ) ), SLOT( slotPercent( KJob*, unsigned long ) ) ); + connect( d->mCollectionSyncer, SIGNAL( result( KJob* ) ), SLOT( slotCollectionSyncDone( KJob* ) ) ); } d->mCollectionSyncer->setRemoteCollections( changedCollections, removedCollections ); } -void ResourceBase::setCollectionStreamingEnabled(bool enable) +void ResourceBase::setCollectionStreamingEnabled( bool enable ) { Q_D( ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || d->scheduler->currentTask().type == ResourceScheduler::SyncAll, "ResourceBase::setCollectionStreamingEnabled()", "Calling setCollectionStreamingEnabled() although no collection retrieval is in progress" ); if ( !d->mCollectionSyncer ) { d->mCollectionSyncer = new CollectionSync( identifier() ); - connect( d->mCollectionSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) ); - connect( d->mCollectionSyncer, SIGNAL(result(KJob*)), SLOT(slotCollectionSyncDone(KJob*)) ); + connect( d->mCollectionSyncer, SIGNAL( percent( KJob*, unsigned long ) ), SLOT( slotPercent( KJob*, unsigned long ) ) ); + connect( d->mCollectionSyncer, SIGNAL( result( KJob* ) ), SLOT( slotCollectionSyncDone( KJob* ) ) ); } d->mCollectionSyncer->setStreamingEnabled( enable ); } void ResourceBase::collectionsRetrievalDone() { Q_D( ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollectionTree || d->scheduler->currentTask().type == ResourceScheduler::SyncAll, "ResourceBase::collectionsRetrievalDone()", "Calling collectionsRetrievalDone() although no collection retrieval is in progress" ); // streaming enabled, so finalize the sync if ( d->mCollectionSyncer ) { d->mCollectionSyncer->retrievalDone(); } // user did the sync himself, we are done now else { d->scheduler->taskDone(); } } -void ResourceBasePrivate::slotCollectionSyncDone(KJob * job) +void ResourceBasePrivate::slotCollectionSyncDone( KJob * job ) { Q_Q( ResourceBase ); mCollectionSyncer = 0; if ( job->error() ) { emit q->error( job->errorString() ); } else { if ( scheduler->currentTask().type == ResourceScheduler::SyncAll ) { CollectionFetchJob *list = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive ); list->setResource( mId ); - q->connect( list, SIGNAL(result(KJob*)), q, SLOT(slotLocalListDone(KJob*)) ); + q->connect( list, SIGNAL( result( KJob* ) ), q, SLOT( slotLocalListDone( KJob* ) ) ); return; } } scheduler->taskDone(); } -void ResourceBasePrivate::slotLocalListDone(KJob * job) +void ResourceBasePrivate::slotLocalListDone( KJob * job ) { Q_Q( ResourceBase ); if ( job->error() ) { emit q->error( job->errorString() ); } else { Collection::List cols = static_cast( job )->collections(); foreach ( const Collection &col, cols ) { scheduler->scheduleSync( col ); } scheduler->scheduleFullSyncCompletion(); } scheduler->taskDone(); } void ResourceBasePrivate::slotSynchronizeCollection( const Collection &col ) { Q_Q( ResourceBase ); currentCollection = col; // check if this collection actually can contain anything QStringList contentTypes = currentCollection.contentMimeTypes(); contentTypes.removeAll( Collection::mimeType() ); if ( !contentTypes.isEmpty() ) { emit q->status( AgentBase::Running, i18nc( "@info:status", "Syncing collection '%1'", currentCollection.name() ) ); q->retrieveItems( currentCollection ); return; } scheduler->taskDone(); } void ResourceBase::itemsRetrievalDone() { Q_D( ResourceBase ); // streaming enabled, so finalize the sync if ( d->mItemSyncer ) { d->mItemSyncer->deliveryDone(); } // user did the sync himself, we are done now else { d->scheduler->taskDone(); } } void ResourceBase::clearCache() { Q_D( ResourceBase ); d->scheduler->scheduleResourceCollectionDeletion(); } Collection ResourceBase::currentCollection() const { Q_D( const ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection , "ResourceBase::currentCollection()", "Trying to access current collection although no item retrieval is in progress" ); return d->currentCollection; } Item ResourceBase::currentItem() const { Q_D( const ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::FetchItem , "ResourceBase::currentItem()", "Trying to access current item although no item retrieval is in progress" ); return d->scheduler->currentTask().item; } void ResourceBase::synchronizeCollectionTree() { d_func()->scheduler->scheduleCollectionTreeSync(); } void ResourceBase::cancelTask() { Q_D( ResourceBase ); switch ( d->scheduler->currentTask().type ) { case ResourceScheduler::FetchItem: itemRetrieved( Item() ); // sends the error reply and break; case ResourceScheduler::ChangeReplay: d->changeProcessed(); break; default: d->scheduler->taskDone(); } } void ResourceBase::cancelTask( const QString &msg ) { cancelTask(); emit error( msg ); } void ResourceBase::deferTask() { Q_D( ResourceBase ); d->scheduler->deferTask(); } void ResourceBase::doSetOnline( bool state ) { d_func()->scheduler->setOnline( state ); } -void ResourceBase::synchronizeCollection(qint64 collectionId ) +void ResourceBase::synchronizeCollection( qint64 collectionId ) { - CollectionFetchJob* job = new CollectionFetchJob( Collection(collectionId), CollectionFetchJob::Base ); + CollectionFetchJob* job = new CollectionFetchJob( Collection( collectionId ), CollectionFetchJob::Base ); job->setResource( identifier() ); - connect( job, SIGNAL(result(KJob*)), SLOT(slotCollectionListDone(KJob*)) ); + connect( job, SIGNAL( result( KJob* ) ), SLOT( slotCollectionListDone( KJob* ) ) ); } void ResourceBasePrivate::slotCollectionListDone( KJob *job ) { if ( !job->error() ) { Collection::List list = static_cast( job )->collections(); if ( !list.isEmpty() ) { Collection col = list.first(); scheduler->scheduleSync( col ); } } // TODO: error handling } void ResourceBase::setTotalItems( int amount ) { kDebug() << amount; Q_D( ResourceBase ); setItemStreamingEnabled( true ); d->mItemSyncer->setTotalItems( amount ); } void ResourceBase::setItemStreamingEnabled( bool enable ) { Q_D( ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection, "ResourceBase::setItemStreamingEnabled()", "Calling setItemStreamingEnabled() although no item retrieval is in progress" ); if ( !d->mItemSyncer ) { d->mItemSyncer = new ItemSync( currentCollection() ); - connect( d->mItemSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) ); - connect( d->mItemSyncer, SIGNAL(result(KJob*)), SLOT(slotItemSyncDone(KJob*)) ); + connect( d->mItemSyncer, SIGNAL( percent( KJob*, unsigned long ) ), SLOT( slotPercent( KJob*, unsigned long ) ) ); + connect( d->mItemSyncer, SIGNAL( result( KJob* ) ), SLOT( slotItemSyncDone( KJob* ) ) ); } d->mItemSyncer->setStreamingEnabled( enable ); } void ResourceBase::itemsRetrieved( const Item::List &items ) { Q_D( ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection, "ResourceBase::itemsRetrieved()", "Calling itemsRetrieved() although no item retrieval is in progress" ); if ( !d->mItemSyncer ) { d->mItemSyncer = new ItemSync( currentCollection() ); - connect( d->mItemSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) ); - connect( d->mItemSyncer, SIGNAL(result(KJob*)), SLOT(slotItemSyncDone(KJob*)) ); + connect( d->mItemSyncer, SIGNAL( percent( KJob*, unsigned long ) ), SLOT( slotPercent( KJob*, unsigned long ) ) ); + connect( d->mItemSyncer, SIGNAL( result( KJob* ) ), SLOT( slotItemSyncDone( KJob* ) ) ); } d->mItemSyncer->setFullSyncItems( items ); } -void ResourceBase::itemsRetrievedIncremental(const Item::List &changedItems, const Item::List &removedItems) +void ResourceBase::itemsRetrievedIncremental( const Item::List &changedItems, const Item::List &removedItems ) { Q_D( ResourceBase ); Q_ASSERT_X( d->scheduler->currentTask().type == ResourceScheduler::SyncCollection, "ResourceBase::itemsRetrievedIncremental()", "Calling itemsRetrievedIncremental() although no item retrieval is in progress" ); if ( !d->mItemSyncer ) { d->mItemSyncer = new ItemSync( currentCollection() ); - connect( d->mItemSyncer, SIGNAL(percent(KJob*,unsigned long)), SLOT(slotPercent(KJob*,unsigned long)) ); - connect( d->mItemSyncer, SIGNAL(result(KJob*)), SLOT(slotItemSyncDone(KJob*)) ); + connect( d->mItemSyncer, SIGNAL( percent( KJob*, unsigned long ) ), SLOT( slotPercent( KJob*, unsigned long ) ) ); + connect( d->mItemSyncer, SIGNAL( result( KJob* ) ), SLOT( slotItemSyncDone( KJob* ) ) ); } d->mItemSyncer->setIncrementalSyncItems( changedItems, removedItems ); } void ResourceBasePrivate::slotItemSyncDone( KJob *job ) { mItemSyncer = 0; Q_Q( ResourceBase ); if ( job->error() ) { emit q->error( job->errorString() ); } scheduler->taskDone(); } void ResourceBasePrivate::slotPercent( KJob *job, unsigned long percent ) { Q_Q( ResourceBase ); Q_UNUSED( job ); emit q->percent( percent ); } #include "resourcebase.moc"