akonadi
agentbase.cpp
00001 /* 00002 Copyright (c) 2006 Till Adam <adam@kde.org> 00003 Copyright (c) 2007 Volker Krause <vkrause@kde.org> 00004 Copyright (c) 2007 Bruno Virlet <bruno.virlet@gmail.com> 00005 Copyright (c) 2008 Kevin Krammer <kevin.krammer@gmx.at> 00006 00007 This library is free software; you can redistribute it and/or modify it 00008 under the terms of the GNU Library General Public License as published by 00009 the Free Software Foundation; either version 2 of the License, or (at your 00010 option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, but WITHOUT 00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00014 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00015 License for more details. 00016 00017 You should have received a copy of the GNU Library General Public License 00018 along with this library; see the file COPYING.LIB. If not, write to the 00019 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00020 02110-1301, USA. 00021 */ 00022 00023 #include "agentbase.h" 00024 #include "agentbase_p.h" 00025 00026 #include "changerecorder.h" 00027 #include "controladaptor.h" 00028 #include "dbusconnectionpool.h" 00029 #include "itemfetchjob.h" 00030 #include "monitor_p.h" 00031 #include "servermanager_p.h" 00032 #include "session.h" 00033 #include "session_p.h" 00034 #include "statusadaptor.h" 00035 #include "xdgbasedirs_p.h" 00036 00037 #include <kaboutdata.h> 00038 #include <kcmdlineargs.h> 00039 #include <kdebug.h> 00040 #include <klocale.h> 00041 #include <kstandarddirs.h> 00042 00043 #include <QtCore/QDir> 00044 #include <QtCore/QSettings> 00045 #include <QtCore/QTimer> 00046 #include <QtDBus/QtDBus> 00047 #include <QtGui/QApplication> 00048 00049 #include <signal.h> 00050 #include <stdlib.h> 00051 00052 //#define EXPERIMENTAL_INPROCESS_AGENTS 1 00053 00054 using namespace Akonadi; 00055 00056 static AgentBase *sAgentBase = 0; 00057 00058 AgentBase::Observer::Observer() 00059 { 00060 } 00061 00062 AgentBase::Observer::~Observer() 00063 { 00064 } 00065 00066 void AgentBase::Observer::itemAdded( const Item &item, const Collection &collection ) 00067 { 00068 Q_UNUSED( item ); 00069 Q_UNUSED( collection ); 00070 if ( sAgentBase != 0 ) 00071 sAgentBase->d_ptr->changeProcessed(); 00072 } 00073 00074 void AgentBase::Observer::itemChanged( const Item &item, const QSet<QByteArray> &partIdentifiers ) 00075 { 00076 Q_UNUSED( item ); 00077 Q_UNUSED( partIdentifiers ); 00078 if ( sAgentBase != 0 ) 00079 sAgentBase->d_ptr->changeProcessed(); 00080 } 00081 00082 void AgentBase::Observer::itemRemoved( const Item &item ) 00083 { 00084 Q_UNUSED( item ); 00085 if ( sAgentBase != 0 ) 00086 sAgentBase->d_ptr->changeProcessed(); 00087 } 00088 00089 void AgentBase::Observer::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) 00090 { 00091 Q_UNUSED( collection ); 00092 Q_UNUSED( parent ); 00093 if ( sAgentBase != 0 ) 00094 sAgentBase->d_ptr->changeProcessed(); 00095 } 00096 00097 void AgentBase::Observer::collectionChanged( const Collection &collection ) 00098 { 00099 Q_UNUSED( collection ); 00100 if ( sAgentBase != 0 ) 00101 sAgentBase->d_ptr->changeProcessed(); 00102 } 00103 00104 void AgentBase::Observer::collectionRemoved( const Collection &collection ) 00105 { 00106 Q_UNUSED( collection ); 00107 if ( sAgentBase != 0 ) 00108 sAgentBase->d_ptr->changeProcessed(); 00109 } 00110 00111 void AgentBase::ObserverV2::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00112 { 00113 Q_UNUSED( item ); 00114 Q_UNUSED( source ); 00115 Q_UNUSED( dest ); 00116 if ( sAgentBase != 0 ) 00117 sAgentBase->d_ptr->changeProcessed(); 00118 } 00119 00120 void AgentBase::ObserverV2::itemLinked( const Akonadi::Item& item, const Akonadi::Collection& collection ) 00121 { 00122 Q_UNUSED( item ); 00123 Q_UNUSED( collection ); 00124 if ( sAgentBase != 0 ) { 00125 // not implementation, let's disconnect the signal to enable optimizations in Monitor 00126 QObject::disconnect( sAgentBase->changeRecorder(), SIGNAL( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00127 sAgentBase->d_ptr, SLOT( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00128 sAgentBase->d_ptr->changeProcessed(); 00129 } 00130 } 00131 00132 void AgentBase::ObserverV2::itemUnlinked( const Akonadi::Item& item, const Akonadi::Collection& collection ) 00133 { 00134 Q_UNUSED( item ); 00135 Q_UNUSED( collection ); 00136 if ( sAgentBase != 0 ) { 00137 // not implementation, let's disconnect the signal to enable optimizations in Monitor 00138 QObject::disconnect( sAgentBase->changeRecorder(), SIGNAL( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00139 sAgentBase->d_ptr, SLOT( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00140 sAgentBase->d_ptr->changeProcessed(); 00141 } 00142 } 00143 00144 void AgentBase::ObserverV2::collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00145 { 00146 Q_UNUSED( collection ); 00147 Q_UNUSED( source ); 00148 Q_UNUSED( dest ); 00149 if ( sAgentBase != 0 ) 00150 sAgentBase->d_ptr->changeProcessed(); 00151 } 00152 00153 void AgentBase::ObserverV2::collectionChanged( const Akonadi::Collection &collection, const QSet<QByteArray> &partIdentifiers ) 00154 { 00155 Q_UNUSED( partIdentifiers ); 00156 collectionChanged( collection ); 00157 } 00158 00159 //@cond PRIVATE 00160 00161 AgentBasePrivate::AgentBasePrivate( AgentBase *parent ) 00162 : q_ptr( parent ), 00163 mDBusConnection( QString() ), 00164 mStatusCode( AgentBase::Idle ), 00165 mProgress( 0 ), 00166 mNeedsNetwork( false ), 00167 mOnline( false ), 00168 mSettings( 0 ), 00169 mObserver( 0 ) 00170 { 00171 #ifdef _WIN32_WCE 00172 QThread::currentThread()->setPriority(QThread::LowPriority); 00173 #endif 00174 Internal::setClientType( Internal::Agent ); 00175 } 00176 00177 AgentBasePrivate::~AgentBasePrivate() 00178 { 00179 mChangeRecorder->setConfig( 0 ); 00180 delete mSettings; 00181 } 00182 00183 void AgentBasePrivate::init() 00184 { 00185 Q_Q( AgentBase ); 00186 00190 SessionPrivate::createDefaultSession( mId.toLatin1() ); 00191 00192 if ( QThread::currentThread() != QCoreApplication::instance()->thread() ) { 00193 mDBusConnection = QDBusConnection::connectToBus( QDBusConnection::SessionBus, q->identifier() ); 00194 Q_ASSERT( mDBusConnection.isConnected() ); 00195 } 00196 00197 mTracer = new org::freedesktop::Akonadi::Tracer( QLatin1String( "org.freedesktop.Akonadi" ), 00198 QLatin1String( "/tracing" ), 00199 DBusConnectionPool::threadConnection(), q ); 00200 00201 new Akonadi__ControlAdaptor( q ); 00202 new Akonadi__StatusAdaptor( q ); 00203 if ( !DBusConnectionPool::threadConnection().registerObject( QLatin1String( "/" ), q, QDBusConnection::ExportAdaptors ) ) 00204 q->error( QString::fromLatin1( "Unable to register object at dbus: %1" ).arg( DBusConnectionPool::threadConnection().lastError().message() ) ); 00205 00206 mSettings = new QSettings( QString::fromLatin1( "%1/agent_config_%2" ).arg( XdgBaseDirs::saveDir( "config", QLatin1String( "akonadi" ) ), mId ), QSettings::IniFormat ); 00207 00208 mChangeRecorder = new ChangeRecorder( q ); 00209 mChangeRecorder->ignoreSession( Session::defaultSession() ); 00210 mChangeRecorder->itemFetchScope().setCacheOnly( true ); 00211 mChangeRecorder->setConfig( mSettings ); 00212 00213 mOnline = mSettings->value( QLatin1String( "Agent/Online" ), true ).toBool(); 00214 00215 // reinitialize the status message now that online state is available 00216 mStatusMessage = defaultReadyMessage(); 00217 00218 mName = mSettings->value( QLatin1String( "Agent/Name" ) ).toString(); 00219 if ( mName.isEmpty() ) { 00220 mName = mSettings->value( QLatin1String( "Resource/Name" ) ).toString(); 00221 if ( !mName.isEmpty() ) { 00222 mSettings->remove( QLatin1String( "Resource/Name" ) ); 00223 mSettings->setValue( QLatin1String( "Agent/Name" ), mName ); 00224 } 00225 } 00226 00227 connect( mChangeRecorder, SIGNAL( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ), 00228 SLOT( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00229 connect( mChangeRecorder, SIGNAL( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ), 00230 SLOT( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ) ); 00231 connect( mChangeRecorder, SIGNAL( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ), 00232 SLOT( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00233 connect( mChangeRecorder, SIGNAL( itemRemoved( const Akonadi::Item& ) ), 00234 SLOT( itemRemoved( const Akonadi::Item& ) ) ); 00235 connect( mChangeRecorder, SIGNAL( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ), 00236 SLOT( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00237 connect( mChangeRecorder, SIGNAL( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00238 SLOT( itemLinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00239 connect( mChangeRecorder, SIGNAL( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ), 00240 SLOT( itemUnlinked( const Akonadi::Item&, const Akonadi::Collection& ) ) ); 00241 connect( mChangeRecorder, SIGNAL( collectionChanged( const Akonadi::Collection& ) ), 00242 SLOT( collectionChanged( const Akonadi::Collection& ) ) ); 00243 connect( mChangeRecorder, SIGNAL( collectionChanged( const Akonadi::Collection&, const QSet<QByteArray>& ) ), 00244 SLOT( collectionChanged( const Akonadi::Collection&, const QSet<QByteArray>& ) ) ); 00245 connect( mChangeRecorder, SIGNAL( collectionMoved( const Akonadi::Collection&, const Akonadi::Collection&, const Akonadi::Collection& ) ), 00246 SLOT( collectionMoved( const Akonadi::Collection&, const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00247 connect( mChangeRecorder, SIGNAL( collectionRemoved( const Akonadi::Collection& ) ), 00248 SLOT( collectionRemoved( const Akonadi::Collection& ) ) ); 00249 connect( mChangeRecorder, SIGNAL( collectionSubscribed( const Akonadi::Collection&, const Akonadi::Collection& ) ), 00250 SLOT( collectionSubscribed( const Akonadi::Collection&, const Akonadi::Collection& ) ) ); 00251 connect( mChangeRecorder, SIGNAL( collectionUnsubscribed( const Akonadi::Collection& ) ), 00252 SLOT( collectionUnsubscribed( const Akonadi::Collection& ) ) ); 00253 00254 connect( q, SIGNAL( status( int, const QString& ) ), q, SLOT( slotStatus( int, const QString& ) ) ); 00255 connect( q, SIGNAL( percent( int ) ), q, SLOT( slotPercent( int ) ) ); 00256 connect( q, SIGNAL( warning( const QString& ) ), q, SLOT( slotWarning( const QString& ) ) ); 00257 connect( q, SIGNAL( error( const QString& ) ), q, SLOT( slotError( const QString& ) ) ); 00258 00259 // Use reference counting to allow agents to finish internal jobs when the 00260 // agent is stopped. 00261 KGlobal::ref(); 00262 if ( QThread::currentThread() == QCoreApplication::instance()->thread() ) 00263 KGlobal::setAllowQuit( true ); 00264 00265 #ifndef Q_OS_WINCE 00266 // disable session management 00267 if ( KApplication::kApplication() ) 00268 KApplication::kApplication()->disableSessionManagement(); 00269 #endif 00270 00271 QTimer::singleShot( 0, q, SLOT( delayedInit() ) ); 00272 } 00273 00274 void AgentBasePrivate::delayedInit() 00275 { 00276 Q_Q( AgentBase ); 00277 if ( !DBusConnectionPool::threadConnection().registerService( QLatin1String( "org.freedesktop.Akonadi.Agent." ) + mId ) ) 00278 kFatal() << "Unable to register service at dbus:" << DBusConnectionPool::threadConnection().lastError().message(); 00279 q->setOnline( mOnline ); 00280 } 00281 00282 void AgentBasePrivate::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection ) 00283 { 00284 if ( mObserver != 0 ) 00285 mObserver->itemAdded( item, collection ); 00286 } 00287 00288 void AgentBasePrivate::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers ) 00289 { 00290 if ( mObserver != 0 ) 00291 mObserver->itemChanged( item, partIdentifiers ); 00292 } 00293 00294 void AgentBasePrivate::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00295 { 00296 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00297 if ( mObserver ) { 00298 // inter-resource moves, requires we know which resources the source and destination are in though 00299 if ( !source.resource().isEmpty() && !dest.resource().isEmpty() ) { 00300 if ( source.resource() != dest.resource() ) { 00301 if ( source.resource() == q_ptr->identifier() ) { // moved away from us 00302 Akonadi::Item i( item ); 00303 i.setParentCollection( source ); 00304 mObserver->itemRemoved( i ); 00305 } 00306 else if ( dest.resource() == q_ptr->identifier() ) // moved to us 00307 mObserver->itemAdded( item, dest ); 00308 else if ( observer2 ) 00309 observer2->itemMoved( item, source, dest ); 00310 else 00311 // not for us, not sure if we should get here at all 00312 changeProcessed(); 00313 return; 00314 } 00315 } 00316 // intra-resource move 00317 if ( observer2 ) { 00318 observer2->itemMoved( item, source, dest ); 00319 } else { 00320 // ### we cannot just call itemRemoved here as this will already trigger changeProcessed() 00321 // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway 00322 // without using ObserverV2 00323 mObserver->itemAdded( item, dest ); 00324 // mObserver->itemRemoved( item ); 00325 } 00326 } 00327 } 00328 00329 void AgentBasePrivate::itemRemoved( const Akonadi::Item &item ) 00330 { 00331 if ( mObserver != 0 ) 00332 mObserver->itemRemoved( item ); 00333 } 00334 00335 void AgentBasePrivate::itemLinked( const Akonadi::Item &item, const Akonadi::Collection &collection ) 00336 { 00337 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00338 if ( observer2 ) 00339 observer2->itemLinked( item, collection ); 00340 else 00341 changeProcessed(); 00342 } 00343 00344 void AgentBasePrivate::itemUnlinked( const Akonadi::Item &item, const Akonadi::Collection &collection ) 00345 { 00346 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00347 if ( observer2 ) 00348 observer2->itemUnlinked( item, collection ); 00349 else 00350 changeProcessed(); 00351 } 00352 00353 void AgentBasePrivate::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) 00354 { 00355 if ( mObserver != 0 ) 00356 mObserver->collectionAdded( collection, parent ); 00357 } 00358 00359 void AgentBasePrivate::collectionChanged( const Akonadi::Collection &collection ) 00360 { 00361 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00362 if ( mObserver != 0 && observer2 == 0 ) // For ObserverV2 we use the variant with the part identifiers 00363 mObserver->collectionChanged( collection ); 00364 } 00365 00366 void AgentBasePrivate::collectionChanged( const Akonadi::Collection &collection, const QSet<QByteArray> &partIdentifiers ) 00367 { 00368 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00369 if ( observer2 != 0 ) 00370 observer2->collectionChanged( collection, partIdentifiers ); 00371 } 00372 00373 void AgentBasePrivate::collectionMoved( const Akonadi::Collection &collection, const Akonadi::Collection &source, const Akonadi::Collection &dest ) 00374 { 00375 AgentBase::ObserverV2 *observer2 = dynamic_cast<AgentBase::ObserverV2*>( mObserver ); 00376 if ( mObserver ) { 00377 // inter-resource moves, requires we know which resources the source and destination are in though 00378 if ( !source.resource().isEmpty() && !dest.resource().isEmpty() ) { 00379 if ( source.resource() != dest.resource() ) { 00380 if ( source.resource() == q_ptr->identifier() ) // moved away from us 00381 mObserver->collectionRemoved( collection ); 00382 else if ( dest.resource() == q_ptr->identifier() ) // moved to us 00383 mObserver->collectionAdded( collection, dest ); 00384 else if ( observer2 ) 00385 observer2->collectionMoved( collection, source, dest ); 00386 else // not for us, not sure if we should get here at all 00387 changeProcessed(); 00388 return; 00389 } 00390 } 00391 // intra-resource move 00392 if ( observer2 ) { 00393 observer2->collectionMoved( collection, source, dest ); 00394 } else { 00395 // ### we cannot just call collectionRemoved here as this will already trigger changeProcessed() 00396 // so, just collectionAdded() is good enough as no resource can have implemented intra-resource moves anyway 00397 // without using ObserverV2 00398 mObserver->collectionAdded( collection, dest ); 00399 } 00400 } 00401 } 00402 00403 void AgentBasePrivate::collectionRemoved( const Akonadi::Collection &collection ) 00404 { 00405 if ( mObserver != 0 ) 00406 mObserver->collectionRemoved( collection ); 00407 } 00408 00409 void AgentBasePrivate::collectionSubscribed( const Akonadi::Collection &collection, const Akonadi::Collection &parent ) 00410 { 00411 Q_UNUSED( collection ); 00412 Q_UNUSED( parent ); 00413 changeProcessed(); 00414 } 00415 00416 void AgentBasePrivate::collectionUnsubscribed( const Akonadi::Collection &collection ) 00417 { 00418 Q_UNUSED( collection ); 00419 changeProcessed(); 00420 } 00421 00422 void AgentBasePrivate::changeProcessed() 00423 { 00424 mChangeRecorder->changeProcessed(); 00425 QTimer::singleShot( 0, mChangeRecorder, SLOT( replayNext() ) ); 00426 } 00427 00428 void AgentBasePrivate::slotStatus( int status, const QString &message ) 00429 { 00430 mStatusMessage = message; 00431 mStatusCode = 0; 00432 00433 switch ( status ) { 00434 case AgentBase::Idle: 00435 if ( mStatusMessage.isEmpty() ) 00436 mStatusMessage = defaultReadyMessage(); 00437 00438 mStatusCode = 0; 00439 break; 00440 case AgentBase::Running: 00441 if ( mStatusMessage.isEmpty() ) 00442 mStatusMessage = defaultSyncingMessage(); 00443 00444 mStatusCode = 1; 00445 break; 00446 case AgentBase::Broken: 00447 if ( mStatusMessage.isEmpty() ) 00448 mStatusMessage = defaultErrorMessage(); 00449 00450 mStatusCode = 2; 00451 break; 00452 default: 00453 Q_ASSERT( !"Unknown status passed" ); 00454 break; 00455 } 00456 } 00457 00458 void AgentBasePrivate::slotPercent( int progress ) 00459 { 00460 mProgress = progress; 00461 } 00462 00463 void AgentBasePrivate::slotWarning( const QString& message ) 00464 { 00465 mTracer->warning( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message ); 00466 } 00467 00468 void AgentBasePrivate::slotError( const QString& message ) 00469 { 00470 mTracer->error( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message ); 00471 } 00472 00473 void AgentBasePrivate::slotNetworkStatusChange( Solid::Networking::Status stat ) 00474 { 00475 Q_Q( AgentBase ); 00476 q->setOnline( stat == Solid::Networking::Unknown || stat == Solid::Networking::Connected ); 00477 } 00478 00479 AgentBase::AgentBase( const QString & id ) 00480 : d_ptr( new AgentBasePrivate( this ) ) 00481 { 00482 sAgentBase = this; 00483 d_ptr->mId = id; 00484 d_ptr->init(); 00485 } 00486 00487 AgentBase::AgentBase( AgentBasePrivate* d, const QString &id ) : 00488 d_ptr( d ) 00489 { 00490 sAgentBase = this; 00491 d_ptr->mId = id; 00492 d_ptr->init(); 00493 } 00494 00495 AgentBase::~AgentBase() 00496 { 00497 delete d_ptr; 00498 } 00499 00500 QString AgentBase::parseArguments( int argc, char **argv ) 00501 { 00502 QString identifier; 00503 if ( argc < 3 ) { 00504 kDebug() << "Not enough arguments passed..."; 00505 exit( 1 ); 00506 } 00507 00508 for ( int i = 1; i < argc - 1; ++i ) { 00509 if ( QLatin1String( argv[ i ] ) == QLatin1String( "--identifier" ) ) 00510 identifier = QLatin1String( argv[ i + 1 ] ); 00511 } 00512 00513 if ( identifier.isEmpty() ) { 00514 kDebug() << "Identifier argument missing"; 00515 exit( 1 ); 00516 } 00517 00518 const QFileInfo fi( QString::fromLocal8Bit( argv[0] ) ); 00519 // strip off full path and possible .exe suffix 00520 const QByteArray catalog = fi.baseName().toLatin1(); 00521 00522 KCmdLineArgs::init( argc, argv, identifier.toLatin1(), catalog, ki18n( "Akonadi Agent" ), "0.1", 00523 ki18n( "Akonadi Agent" ) ); 00524 00525 KCmdLineOptions options; 00526 options.add( "identifier <argument>", ki18n( "Agent identifier" ) ); 00527 KCmdLineArgs::addCmdLineOptions( options ); 00528 00529 return identifier; 00530 } 00531 00532 // @endcond 00533 00534 int AgentBase::init( AgentBase *r ) 00535 { 00536 QApplication::setQuitOnLastWindowClosed( false ); 00537 KGlobal::locale()->insertCatalog( QLatin1String( "libakonadi" ) ); 00538 int rv = kapp->exec(); 00539 delete r; 00540 return rv; 00541 } 00542 00543 int AgentBase::status() const 00544 { 00545 Q_D( const AgentBase ); 00546 00547 return d->mStatusCode; 00548 } 00549 00550 QString AgentBase::statusMessage() const 00551 { 00552 Q_D( const AgentBase ); 00553 00554 return d->mStatusMessage; 00555 } 00556 00557 int AgentBase::progress() const 00558 { 00559 Q_D( const AgentBase ); 00560 00561 return d->mProgress; 00562 } 00563 00564 QString AgentBase::progressMessage() const 00565 { 00566 Q_D( const AgentBase ); 00567 00568 return d->mProgressMessage; 00569 } 00570 00571 bool AgentBase::isOnline() const 00572 { 00573 Q_D( const AgentBase ); 00574 00575 return d->mOnline; 00576 } 00577 00578 void AgentBase::setNeedsNetwork( bool needsNetwork ) 00579 { 00580 Q_D( AgentBase ); 00581 d->mNeedsNetwork = needsNetwork; 00582 00583 if ( d->mNeedsNetwork ) { 00584 connect( Solid::Networking::notifier() 00585 , SIGNAL( statusChanged( Solid::Networking::Status ) ) 00586 , this, SLOT( slotNetworkStatusChange( Solid::Networking::Status ) ) ); 00587 } else { 00588 disconnect( Solid::Networking::notifier(), 0, 0, 0 ); 00589 setOnline( true ); 00590 } 00591 } 00592 00593 void AgentBase::setOnline( bool state ) 00594 { 00595 Q_D( AgentBase ); 00596 d->mOnline = state; 00597 d->mSettings->setValue( QLatin1String( "Agent/Online" ), state ); 00598 doSetOnline( state ); 00599 emit onlineChanged( state ); 00600 } 00601 00602 void AgentBase::doSetOnline( bool online ) 00603 { 00604 Q_UNUSED( online ); 00605 } 00606 00607 void AgentBase::configure( WId windowId ) 00608 { 00609 Q_UNUSED( windowId ); 00610 emit configurationDialogAccepted(); 00611 } 00612 00613 #ifdef Q_OS_WIN //krazy:exclude=cpp 00614 void AgentBase::configure( qlonglong windowId ) 00615 { 00616 configure( reinterpret_cast<WId>( windowId ) ); 00617 } 00618 #endif 00619 00620 WId AgentBase::winIdForDialogs() const 00621 { 00622 const bool registered = DBusConnectionPool::threadConnection().interface()->isServiceRegistered( QLatin1String( "org.freedesktop.akonaditray" ) ); 00623 if ( !registered ) 00624 return 0; 00625 00626 QDBusInterface dbus( QLatin1String( "org.freedesktop.akonaditray" ), QLatin1String( "/Actions" ), 00627 QLatin1String( "org.freedesktop.Akonadi.Tray" ) ); 00628 const QDBusMessage reply = dbus.call( QLatin1String( "getWinId" ) ); 00629 00630 if ( reply.type() == QDBusMessage::ErrorMessage ) 00631 return 0; 00632 00633 const WId winid = (WId)reply.arguments().at( 0 ).toLongLong(); 00634 00635 return winid; 00636 } 00637 00638 void AgentBase::quit() 00639 { 00640 Q_D( AgentBase ); 00641 aboutToQuit(); 00642 00643 if ( d->mSettings ) { 00644 d->mChangeRecorder->setConfig( 0 ); 00645 d->mSettings->sync(); 00646 } 00647 00648 KGlobal::deref(); 00649 } 00650 00651 void AgentBase::aboutToQuit() 00652 { 00653 } 00654 00655 void AgentBase::cleanup() 00656 { 00657 Q_D( AgentBase ); 00658 // prevent the monitor from picking up deletion signals for our own data if we are a resource 00659 // and thus avoid that we kill our own data as last act before our own death 00660 d->mChangeRecorder->blockSignals( true ); 00661 00662 aboutToQuit(); 00663 00664 const QString fileName = d->mSettings->fileName(); 00665 00666 /* 00667 * First destroy the settings object... 00668 */ 00669 d->mChangeRecorder->setConfig( 0 ); 00670 delete d->mSettings; 00671 d->mSettings = 0; 00672 00673 /* 00674 * ... then remove the file from hd. 00675 */ 00676 QFile::remove( fileName ); 00677 00678 /* 00679 * ... and remove the changes file from hd. 00680 */ 00681 QFile::remove( fileName + QLatin1String( "_changes.dat" ) ); 00682 00683 /* 00684 * ... and also remove the agent configuration file if there is one. 00685 */ 00686 QString configFile = KStandardDirs::locateLocal( "config", config()->name() ); 00687 QFile::remove( configFile ); 00688 00689 KGlobal::deref(); 00690 } 00691 00692 void AgentBase::registerObserver( Observer *observer ) 00693 { 00694 // TODO in theory we should re-connect change recorder signals here that we disconnected previously 00695 d_ptr->mObserver = observer; 00696 } 00697 00698 QString AgentBase::identifier() const 00699 { 00700 return d_ptr->mId; 00701 } 00702 00703 void AgentBase::setAgentName( const QString &name ) 00704 { 00705 Q_D( AgentBase ); 00706 if ( name == d->mName ) 00707 return; 00708 00709 // TODO: rename collection 00710 d->mName = name; 00711 00712 if ( d->mName.isEmpty() || d->mName == d->mId ) { 00713 d->mSettings->remove( QLatin1String( "Resource/Name" ) ); 00714 d->mSettings->remove( QLatin1String( "Agent/Name" ) ); 00715 } else 00716 d->mSettings->setValue( QLatin1String( "Agent/Name" ), d->mName ); 00717 00718 d->mSettings->sync(); 00719 00720 emit agentNameChanged( d->mName ); 00721 } 00722 00723 QString AgentBase::agentName() const 00724 { 00725 Q_D( const AgentBase ); 00726 if ( d->mName.isEmpty() ) 00727 return d->mId; 00728 else 00729 return d->mName; 00730 } 00731 00732 void AgentBase::changeProcessed() 00733 { 00734 Q_D( AgentBase ); 00735 d->changeProcessed(); 00736 } 00737 00738 ChangeRecorder * AgentBase::changeRecorder() const 00739 { 00740 return d_ptr->mChangeRecorder; 00741 } 00742 00743 KSharedConfigPtr AgentBase::config() 00744 { 00745 if ( QCoreApplication::instance()->thread() == QThread::currentThread() ) 00746 return KGlobal::config(); 00747 else 00748 return componentData().config(); 00749 } 00750 00751 void AgentBase::abort() 00752 { 00753 emit abortRequested(); 00754 } 00755 00756 void AgentBase::reconfigure() 00757 { 00758 emit reloadConfiguration(); 00759 } 00760 00761 extern QThreadStorage<KComponentData*> s_agentComponentDatas; 00762 00763 KComponentData AgentBase::componentData() 00764 { 00765 if ( QThread::currentThread() == QCoreApplication::instance()->thread() ) { 00766 if ( s_agentComponentDatas.hasLocalData() ) 00767 return *(s_agentComponentDatas.localData()); 00768 else 00769 return KGlobal::mainComponent(); 00770 } 00771 00772 Q_ASSERT( s_agentComponentDatas.hasLocalData() ); 00773 return *(s_agentComponentDatas.localData()); 00774 } 00775 00776 #include "agentbase.moc" 00777 #include "agentbase_p.moc"