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