• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

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 "controladaptor.h"
00027 #include "statusadaptor.h"
00028 #include "monitor_p.h"
00029 #include "xdgbasedirs_p.h"
00030 
00031 #include "session.h"
00032 #include "session_p.h"
00033 #include "changerecorder.h"
00034 #include "itemfetchjob.h"
00035 
00036 #include <kaboutdata.h>
00037 #include <kcmdlineargs.h>
00038 #include <kdebug.h>
00039 #include <klocale.h>
00040 #include <kstandarddirs.h>
00041 
00042 #include <QtCore/QDir>
00043 #include <QtCore/QSettings>
00044 #include <QtCore/QTimer>
00045 #include <QtGui/QApplication>
00046 #include <QtDBus/QtDBus>
00047 
00048 #include <signal.h>
00049 #include <stdlib.h>
00050 
00051 using namespace Akonadi;
00052 
00053 static AgentBase *sAgentBase = 0;
00054 
00055 AgentBase::Observer::Observer()
00056 {
00057 }
00058 
00059 AgentBase::Observer::~Observer()
00060 {
00061 }
00062 
00063 void AgentBase::Observer::itemAdded( const Item &item, const Collection &collection )
00064 {
00065   kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00066   Q_UNUSED( item );
00067   Q_UNUSED( collection );
00068   if ( sAgentBase != 0 )
00069     sAgentBase->d_ptr->changeProcessed();
00070 }
00071 
00072 void AgentBase::Observer::itemChanged( const Item &item, const QSet<QByteArray> &partIdentifiers )
00073 {
00074   kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00075   Q_UNUSED( item );
00076   Q_UNUSED( partIdentifiers );
00077   if ( sAgentBase != 0 )
00078     sAgentBase->d_ptr->changeProcessed();
00079 }
00080 
00081 void AgentBase::Observer::itemRemoved( const Item &item )
00082 {
00083   kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
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   kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00092   Q_UNUSED( collection );
00093   Q_UNUSED( parent );
00094   if ( sAgentBase != 0 )
00095     sAgentBase->d_ptr->changeProcessed();
00096 }
00097 
00098 void AgentBase::Observer::collectionChanged( const Collection &collection )
00099 {
00100   kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00101   Q_UNUSED( collection );
00102   if ( sAgentBase != 0 )
00103     sAgentBase->d_ptr->changeProcessed();
00104 }
00105 
00106 void AgentBase::Observer::collectionRemoved( const Collection &collection )
00107 {
00108   kDebug() << "sAgentBase=" << (void*) sAgentBase << "this=" << (void*) this;
00109   Q_UNUSED( collection );
00110   if ( sAgentBase != 0 )
00111     sAgentBase->d_ptr->changeProcessed();
00112 }
00113 
00114 //@cond PRIVATE
00115 
00116 AgentBasePrivate::AgentBasePrivate( AgentBase *parent )
00117   : q_ptr( parent ),
00118     mStatusCode( AgentBase::Idle ),
00119     mProgress( 0 ),
00120     mNeedsNetwork( false ),
00121     mOnline( false ),
00122     mSettings( 0 ),
00123     mObserver( 0 )
00124 {
00125 }
00126 
00127 AgentBasePrivate::~AgentBasePrivate()
00128 {
00129   mMonitor->setConfig( 0 );
00130   delete mSettings;
00131 }
00132 
00133 void AgentBasePrivate::init()
00134 {
00135   Q_Q( AgentBase );
00136 
00140   SessionPrivate::createDefaultSession( mId.toLatin1() );
00141 
00142   mTracer = new org::freedesktop::Akonadi::Tracer( QLatin1String( "org.freedesktop.Akonadi" ), QLatin1String( "/tracing" ),
00143                                            QDBusConnection::sessionBus(), q );
00144 
00145   new ControlAdaptor( q );
00146   new StatusAdaptor( q );
00147   if ( !QDBusConnection::sessionBus().registerObject( QLatin1String( "/" ), q, QDBusConnection::ExportAdaptors ) )
00148     q->error( QString::fromLatin1( "Unable to register object at dbus: %1" ).arg( QDBusConnection::sessionBus().lastError().message() ) );
00149 
00150   mSettings = new QSettings( QString::fromLatin1( "%1/agent_config_%2" ).arg( XdgBaseDirs::saveDir( "config", QLatin1String( "akonadi" ) ), mId ), QSettings::IniFormat );
00151 
00152   mMonitor = new ChangeRecorder( q );
00153   mMonitor->ignoreSession( Session::defaultSession() );
00154   mMonitor->itemFetchScope().setCacheOnly( true );
00155   mMonitor->setConfig( mSettings );
00156 
00157   mOnline = mSettings->value( QLatin1String( "Agent/Online" ), true ).toBool();
00158 
00159   mName = mSettings->value( QLatin1String( "Agent/Name" ) ).toString();
00160   if ( mName.isEmpty() ) {
00161     mName = mSettings->value( QLatin1String( "Resource/Name" ) ).toString();
00162     if ( !mName.isEmpty() ) {
00163       mSettings->remove( QLatin1String( "Resource/Name" ) );
00164       mSettings->setValue( QLatin1String( "Agent/Name" ), mName );
00165     }
00166   }
00167 
00168   connect( mMonitor, SIGNAL( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ),
00169            SLOT( itemAdded( const Akonadi::Item&, const Akonadi::Collection& ) ) );
00170   connect( mMonitor, SIGNAL( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ),
00171            SLOT( itemChanged( const Akonadi::Item&, const QSet<QByteArray>& ) ) );
00172   connect( mMonitor, SIGNAL( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ),
00173            SLOT( itemMoved( const Akonadi::Item&, const Akonadi::Collection&, const Akonadi::Collection& ) ) );
00174   connect( mMonitor, SIGNAL( itemRemoved( const Akonadi::Item& ) ),
00175            SLOT( itemRemoved( const Akonadi::Item& ) ) );
00176   connect( mMonitor, SIGNAL( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ),
00177            SLOT( collectionAdded( const Akonadi::Collection&, const Akonadi::Collection& ) ) );
00178   connect( mMonitor, SIGNAL( collectionChanged( const Akonadi::Collection& ) ),
00179            SLOT( collectionChanged( const Akonadi::Collection& ) ) );
00180   connect( mMonitor, SIGNAL( collectionRemoved( const Akonadi::Collection& ) ),
00181            SLOT( collectionRemoved( const Akonadi::Collection& ) ) );
00182 
00183   connect( q, SIGNAL( status( int, const QString& ) ), q, SLOT( slotStatus( int, const QString& ) ) );
00184   connect( q, SIGNAL( percent( int ) ), q, SLOT( slotPercent( int ) ) );
00185   connect( q, SIGNAL( warning( const QString& ) ), q, SLOT( slotWarning( const QString& ) ) );
00186   connect( q, SIGNAL( error( const QString& ) ), q, SLOT( slotError( const QString& ) ) );
00187 
00188   // Use reference counting to allow agents to finish internal jobs when the
00189   // agent is stopped.
00190   KGlobal::ref();
00191   KGlobal::setAllowQuit(true);
00192 
00193   QTimer::singleShot( 0, q, SLOT( delayedInit() ) );
00194 }
00195 
00196 void AgentBasePrivate::delayedInit()
00197 {
00198   Q_Q( AgentBase );
00199   if ( !QDBusConnection::sessionBus().registerService( QLatin1String( "org.freedesktop.Akonadi.Agent." ) + mId ) )
00200     kFatal() << "Unable to register service at dbus:" << QDBusConnection::sessionBus().lastError().message();
00201   q->setOnline( mOnline );
00202 }
00203 
00204 void AgentBasePrivate::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
00205 {
00206   kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00207   if ( mObserver != 0 )
00208     mObserver->itemAdded( item, collection );
00209 }
00210 
00211 void AgentBasePrivate::itemChanged( const Akonadi::Item &item, const QSet<QByteArray> &partIdentifiers )
00212 {
00213   kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00214   if ( mObserver != 0 )
00215     mObserver->itemChanged( item, partIdentifiers );
00216 }
00217 
00218 void AgentBasePrivate::itemMoved( const Akonadi::Item &item, const Akonadi::Collection &source, const Akonadi::Collection &dest )
00219 {
00220   kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00221   if ( mObserver ) {
00222     // inter-resource moves, requires we know which resources the source and destination are in though
00223     if ( !source.resource().isEmpty() && !dest.resource().isEmpty() ) {
00224       if ( source.resource() != dest.resource() ) {
00225         if ( source.resource() == q_ptr->identifier() ) // moved away from us
00226           mObserver->itemRemoved( item );
00227         else if ( dest.resource() == q_ptr->identifier() ) // moved to us
00228           mObserver->itemAdded( item, dest );
00229         else // not for us, not sure if we should get here at all
00230           changeProcessed();
00231         return;
00232       }
00233     }
00234     // either incomplete information or intra-resource move
00235     // ### we cannot just call itemRemoved here as this will already trigger changeProcessed()
00236     // so, just itemAdded() is good enough as no resource can have implemented intra-resource moves anyway
00237     // without using Observer2
00238     mObserver->itemAdded( item, dest );
00239     // mObserver->itemRemoved( item );
00240   }
00241 }
00242 
00243 void AgentBasePrivate::itemRemoved( const Akonadi::Item &item )
00244 {
00245   kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00246   if ( mObserver != 0 )
00247     mObserver->itemRemoved( item );
00248 }
00249 
00250 void AgentBasePrivate::collectionAdded( const Akonadi::Collection &collection, const Akonadi::Collection &parent )
00251 {
00252   kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00253   if ( mObserver != 0 )
00254     mObserver->collectionAdded( collection, parent );
00255 }
00256 
00257 void AgentBasePrivate::collectionChanged( const Akonadi::Collection &collection )
00258 {
00259   kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00260   if ( mObserver != 0 )
00261     mObserver->collectionChanged( collection );
00262 }
00263 
00264 void AgentBasePrivate::collectionRemoved( const Akonadi::Collection &collection )
00265 {
00266   kDebug() << "mObserver=" << (void*) mObserver << "this=" << (void*) this;
00267   if ( mObserver != 0 )
00268     mObserver->collectionRemoved( collection );
00269 }
00270 
00271 void AgentBasePrivate::changeProcessed()
00272 {
00273   mMonitor->changeProcessed();
00274   QTimer::singleShot( 0, mMonitor, SLOT( replayNext() ) );
00275 }
00276 
00277 void AgentBasePrivate::slotStatus( int status, const QString &message )
00278 {
00279   mStatusMessage = message;
00280   mStatusCode = 0;
00281 
00282   switch ( status ) {
00283     case AgentBase::Idle:
00284       if ( mStatusMessage.isEmpty() )
00285         mStatusMessage = defaultReadyMessage();
00286 
00287       mStatusCode = 0;
00288       break;
00289     case AgentBase::Running:
00290       if ( mStatusMessage.isEmpty() )
00291         mStatusMessage = defaultSyncingMessage();
00292 
00293       mStatusCode = 1;
00294       break;
00295     case AgentBase::Broken:
00296       if ( mStatusMessage.isEmpty() )
00297         mStatusMessage = defaultErrorMessage();
00298 
00299       mStatusCode = 2;
00300       break;
00301     default:
00302       Q_ASSERT( !"Unknown status passed" );
00303       break;
00304   }
00305 }
00306 
00307 void AgentBasePrivate::slotPercent( int progress )
00308 {
00309   mProgress = progress;
00310 }
00311 
00312 void AgentBasePrivate::slotWarning( const QString& message )
00313 {
00314   mTracer->warning( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message );
00315 }
00316 
00317 void AgentBasePrivate::slotError( const QString& message )
00318 {
00319   mTracer->error( QString::fromLatin1( "AgentBase(%1)" ).arg( mId ), message );
00320 }
00321 
00322 void AgentBasePrivate::slotNetworkStatusChange( Solid::Networking::Status stat )
00323 {
00324   Q_Q( AgentBase );
00325   q->setOnline( stat == Solid::Networking::Connected );
00326 }
00327 
00328 
00329 AgentBase::AgentBase( const QString & id )
00330   : d_ptr( new AgentBasePrivate( this ) )
00331 {
00332   sAgentBase = this;
00333   d_ptr->mId = id;
00334   d_ptr->init();
00335   if ( KApplication::kApplication() )
00336     KApplication::kApplication()->disableSessionManagement();
00337 }
00338 
00339 AgentBase::AgentBase( AgentBasePrivate* d, const QString &id ) :
00340     d_ptr( d )
00341 {
00342   sAgentBase = this;
00343   d_ptr->mId = id;
00344   d_ptr->init();
00345 }
00346 
00347 AgentBase::~AgentBase()
00348 {
00349   delete d_ptr;
00350 }
00351 
00352 QString AgentBase::parseArguments( int argc, char **argv )
00353 {
00354   QString identifier;
00355   if ( argc < 3 ) {
00356     kDebug( 5250 ) << "Not enough arguments passed...";
00357     exit( 1 );
00358   }
00359 
00360   for ( int i = 1; i < argc - 1; ++i ) {
00361     if ( QLatin1String( argv[ i ] ) == QLatin1String( "--identifier" ) )
00362       identifier = QLatin1String( argv[ i + 1 ] );
00363   }
00364 
00365   if ( identifier.isEmpty() ) {
00366     kDebug( 5250 ) << "Identifier argument missing";
00367     exit( 1 );
00368   }
00369 
00370   QByteArray catalog;
00371   char *p = strrchr( argv[0], '/' );
00372   if ( p )
00373     catalog = QByteArray( p + 1 );
00374   else
00375     catalog = QByteArray( argv[0] );
00376 
00377   KCmdLineArgs::init( argc, argv, identifier.toLatin1(), catalog, ki18n("Akonadi Agent"),"0.1" ,
00378                       ki18n("Akonadi Agent") );
00379 
00380   KCmdLineOptions options;
00381   options.add("identifier <argument>", ki18n("Agent identifier"));
00382   KCmdLineArgs::addCmdLineOptions( options );
00383 
00384   return identifier;
00385 }
00386 
00387 // @endcond
00388 
00389 int AgentBase::init( AgentBase *r )
00390 {
00391   QApplication::setQuitOnLastWindowClosed( false );
00392   KGlobal::locale()->insertCatalog( QLatin1String("libakonadi") );
00393   int rv = kapp->exec();
00394   delete r;
00395   return rv;
00396 }
00397 
00398 int AgentBase::status() const
00399 {
00400   Q_D( const AgentBase );
00401 
00402   return d->mStatusCode;
00403 }
00404 
00405 QString AgentBase::statusMessage() const
00406 {
00407   Q_D( const AgentBase );
00408 
00409   return d->mStatusMessage;
00410 }
00411 
00412 int AgentBase::progress() const
00413 {
00414   Q_D( const AgentBase );
00415 
00416   return d->mProgress;
00417 }
00418 
00419 QString AgentBase::progressMessage() const
00420 {
00421   Q_D( const AgentBase );
00422 
00423   return d->mProgressMessage;
00424 }
00425 
00426 bool AgentBase::isOnline() const
00427 {
00428   Q_D( const AgentBase );
00429 
00430   return d->mOnline;
00431 }
00432 
00433 void AgentBase::setNeedsNetwork( bool needsNetwork )
00434 {
00435   Q_D( AgentBase );
00436   d->mNeedsNetwork = needsNetwork;
00437 
00438   if ( d->mNeedsNetwork ) {
00439     connect( Solid::Networking::notifier()
00440            , SIGNAL( statusChanged( Solid::Networking::Status ) )
00441            , this, SLOT( slotNetworkStatusChange( Solid::Networking::Status ) ) );
00442   } else {
00443     disconnect( Solid::Networking::notifier(), 0, 0, 0 );
00444     setOnline( true );
00445   }
00446 }
00447 
00448 void AgentBase::setOnline( bool state )
00449 {
00450   Q_D( AgentBase );
00451   d->mOnline = state;
00452   d->mSettings->setValue( QLatin1String( "Agent/Online" ), state );
00453   doSetOnline( state );
00454   emit onlineChanged( state );
00455 }
00456 
00457 void AgentBase::doSetOnline( bool online )
00458 {
00459   Q_UNUSED( online );
00460 }
00461 
00462 void AgentBase::configure( WId windowId )
00463 {
00464   Q_UNUSED( windowId );
00465 }
00466 
00467 #ifdef Q_OS_WIN //krazy:exclude=cpp
00468 void AgentBase::configure( qlonglong windowId )
00469 {
00470   configure( reinterpret_cast<WId>( windowId ) );
00471 }
00472 #endif
00473 
00474 WId AgentBase::winIdForDialogs() const
00475 {
00476   bool registered = QDBusConnection::sessionBus().interface()->isServiceRegistered( QLatin1String("org.freedesktop.akonaditray") );
00477   if ( !registered )
00478     return 0;
00479 
00480   QDBusInterface dbus( QLatin1String("org.freedesktop.akonaditray"), QLatin1String("/Actions"),
00481                        QLatin1String("org.freedesktop.Akonadi.Tray") );
00482   QDBusMessage reply = dbus.call( QLatin1String("getWinId") );
00483 
00484   if ( reply.type() == QDBusMessage::ErrorMessage )
00485     return 0;
00486 
00487   WId winid = (WId)reply.arguments().at( 0 ).toLongLong();
00488   return winid;
00489 }
00490 
00491 void AgentBase::quit()
00492 {
00493   Q_D( AgentBase );
00494   aboutToQuit();
00495 
00496   if ( d->mSettings ) {
00497     d->mMonitor->setConfig( 0 );
00498     d->mSettings->sync();
00499   }
00500 
00501   KGlobal::deref();
00502 }
00503 
00504 void AgentBase::aboutToQuit()
00505 {
00506 }
00507 
00508 void AgentBase::cleanup()
00509 {
00510   Q_D( AgentBase );
00511   // prevent the monitor from picking up deletion signals for our own data if we are a resource
00512   // and thus avoid that we kill our own data as last act before our own death
00513   d->mMonitor->blockSignals( true );
00514 
00515   aboutToQuit();
00516 
00517   const QString fileName = d->mSettings->fileName();
00518 
00519   /*
00520    * First destroy the settings object...
00521    */
00522   d->mMonitor->setConfig( 0 );
00523   delete d->mSettings;
00524   d->mSettings = 0;
00525 
00526   /*
00527    * ... then remove the file from hd.
00528    */
00529   QFile::remove( fileName );
00530 
00531   /*
00532    * ... and also remove the agent configuration file if there is one.
00533    */
00534   QString configFile = KStandardDirs::locateLocal( "config", KGlobal::config()->name() );
00535   QFile::remove( configFile );
00536 
00537   KGlobal::deref();
00538 }
00539 
00540 void AgentBase::registerObserver( Observer *observer )
00541 {
00542   kDebug() << "observer=" << (void*) observer << "this=" << (void*) this;
00543   d_ptr->mObserver = observer;
00544 }
00545 
00546 QString AgentBase::identifier() const
00547 {
00548   return d_ptr->mId;
00549 }
00550 
00551 void AgentBase::setAgentName( const QString &name )
00552 {
00553   Q_D( AgentBase );
00554   if ( name == d->mName )
00555     return;
00556 
00557   // TODO: rename collection
00558   d->mName = name;
00559 
00560   if ( d->mName.isEmpty() || d->mName == d->mId ) {
00561     d->mSettings->remove( QLatin1String( "Resource/Name" ) );
00562     d->mSettings->remove( QLatin1String( "Agent/Name" ) );
00563   } else
00564     d->mSettings->setValue( QLatin1String( "Agent/Name" ), d->mName );
00565 
00566   d->mSettings->sync();
00567 
00568   emit agentNameChanged( d->mName );
00569 }
00570 
00571 QString AgentBase::agentName() const
00572 {
00573   Q_D( const AgentBase );
00574   if ( d->mName.isEmpty() )
00575     return d->mId;
00576   else
00577     return d->mName;
00578 }
00579 
00580 void AgentBase::changeProcessed()
00581 {
00582   Q_D( AgentBase );
00583   d->changeProcessed();
00584 }
00585 
00586 ChangeRecorder * AgentBase::changeRecorder() const
00587 {
00588   return d_ptr->mMonitor;
00589 }
00590 
00591 void AgentBase::reconfigure()
00592 {
00593   emit reloadConfiguration();
00594 }
00595 
00596 #include "agentbase.moc"
00597 #include "agentbase_p.moc"

akonadi

Skip menu "akonadi"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal