akonadi
specialcollectionsrequestjob.cpp
00001 /* 00002 Copyright (c) 2009 Constantin Berzan <exit3219@gmail.com> 00003 00004 This library is free software; you can redistribute it and/or modify it 00005 under the terms of the GNU Library General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or (at your 00007 option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, but WITHOUT 00010 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00011 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00012 License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to the 00016 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00017 02110-1301, USA. 00018 */ 00019 00020 #include "specialcollectionsrequestjob.h" 00021 00022 #include "specialcollectionattribute_p.h" 00023 #include "specialcollections.h" 00024 #include "specialcollections_p.h" 00025 #include "specialcollectionshelperjobs_p.h" 00026 00027 #include "akonadi/agentmanager.h" 00028 #include "akonadi/collectioncreatejob.h" 00029 #include "akonadi/entitydisplayattribute.h" 00030 00031 #include <KDebug> 00032 00033 #include <QtCore/QVariant> 00034 00035 using namespace Akonadi; 00036 00040 class Akonadi::SpecialCollectionsRequestJobPrivate 00041 { 00042 public: 00043 SpecialCollectionsRequestJobPrivate( SpecialCollections *collections, SpecialCollectionsRequestJob *qq ); 00044 00045 bool isEverythingReady(); 00046 void lockResult( KJob *job ); // slot 00047 void releaseLock(); // slot 00048 void nextResource(); 00049 void resourceScanResult( KJob *job ); // slot 00050 void createRequestedFolders( ResourceScanJob *job, QHash<QByteArray, bool> &requestedFolders ); 00051 void collectionCreateResult( KJob *job ); // slot 00052 00053 SpecialCollectionsRequestJob *q; 00054 SpecialCollections *mSpecialCollections; 00055 int mPendingCreateJobs; 00056 00057 QByteArray mRequestedType; 00058 AgentInstance mRequestedResource; 00059 00060 // Input: 00061 QHash<QByteArray, bool> mDefaultFolders; 00062 bool mRequestingDefaultFolders; 00063 QHash< QString, QHash<QByteArray, bool> > mFoldersForResource; 00064 QString mDefaultResourceType; 00065 QVariantMap mDefaultResourceOptions; 00066 QList<QByteArray> mKnownTypes; 00067 QMap<QByteArray, QString> mNameForTypeMap; 00068 QMap<QByteArray, QString> mIconForTypeMap; 00069 00070 // Output: 00071 QStringList mToForget; 00072 QVector< QPair<Collection, QByteArray> > mToRegister; 00073 }; 00074 00075 00076 00077 SpecialCollectionsRequestJobPrivate::SpecialCollectionsRequestJobPrivate( SpecialCollections *collections, 00078 SpecialCollectionsRequestJob *qq ) 00079 : q( qq ), 00080 mSpecialCollections( collections ), 00081 mPendingCreateJobs( 0 ), 00082 mRequestingDefaultFolders( false ) 00083 { 00084 } 00085 00086 bool SpecialCollectionsRequestJobPrivate::isEverythingReady() 00087 { 00088 // check if all requested folders are known already 00089 if ( mRequestingDefaultFolders ) { 00090 QHashIterator<QByteArray, bool> it( mDefaultFolders ); 00091 while ( it.hasNext() ) { 00092 it.next(); 00093 if ( it.value() && !mSpecialCollections->hasDefaultCollection( it.key() ) ) 00094 return false; 00095 } 00096 } 00097 00098 const QStringList resourceIds = mFoldersForResource.keys(); 00099 QHashIterator< QString, QHash<QByteArray, bool> > resourceIt( mFoldersForResource ); 00100 while ( resourceIt.hasNext() ) { 00101 resourceIt.next(); 00102 00103 const QHash<QByteArray, bool> &requested = resourceIt.value(); 00104 QHashIterator<QByteArray, bool> it( requested ); 00105 while ( it.hasNext() ) { 00106 it.next(); 00107 if ( it.value() && !mSpecialCollections->hasCollection( it.key(), AgentManager::self()->instance( resourceIt.key() ) ) ) 00108 return false; 00109 } 00110 } 00111 00112 return true; 00113 } 00114 00115 void SpecialCollectionsRequestJobPrivate::lockResult( KJob *job ) 00116 { 00117 if ( job->error() ) { 00118 kWarning() << "Failed to get lock:" << job->errorString(); 00119 q->setError( job->error() ); 00120 q->setErrorText( job->errorString() ); 00121 q->emitResult(); 00122 return; 00123 } 00124 00125 if ( mRequestingDefaultFolders ) { 00126 // If default folders are requested, deal with that first. 00127 DefaultResourceJob *resjob = new DefaultResourceJob( mSpecialCollections->d->mSettings, q ); 00128 resjob->setDefaultResourceType( mDefaultResourceType ); 00129 resjob->setDefaultResourceOptions( mDefaultResourceOptions ); 00130 resjob->setTypes( mKnownTypes ); 00131 resjob->setNameForTypeMap( mNameForTypeMap ); 00132 resjob->setIconForTypeMap( mIconForTypeMap ); 00133 QObject::connect( resjob, SIGNAL(result(KJob*)), q, SLOT(resourceScanResult(KJob*)) ); 00134 } else { 00135 // If no default folders are requested, go straight to the next step. 00136 nextResource(); 00137 } 00138 } 00139 00140 void SpecialCollectionsRequestJobPrivate::releaseLock() 00141 { 00142 const bool ok = Akonadi::releaseLock(); 00143 if ( !ok ) { 00144 kWarning() << "WTF, can't release lock."; 00145 } 00146 } 00147 00148 void SpecialCollectionsRequestJobPrivate::nextResource() 00149 { 00150 if ( mFoldersForResource.isEmpty() ) { 00151 kDebug() << "All done! Comitting."; 00152 00153 mSpecialCollections->d->beginBatchRegister(); 00154 00155 // Forget everything we knew before about these resources. 00156 foreach ( const QString &resourceId, mToForget ) { 00157 mSpecialCollections->d->forgetFoldersForResource( resourceId ); 00158 } 00159 00160 // Register all the collections that we fetched / created. 00161 typedef QPair<Collection, QByteArray> RegisterPair; 00162 foreach ( const RegisterPair &pair, mToRegister ) { 00163 const bool ok = mSpecialCollections->registerCollection( pair.second, pair.first ); 00164 Q_ASSERT( ok ); 00165 Q_UNUSED( ok ); 00166 } 00167 00168 mSpecialCollections->d->endBatchRegister(); 00169 00170 // Release the lock once the transaction has been committed. 00171 QObject::connect( q, SIGNAL(result(KJob*)), q, SLOT(releaseLock()) ); 00172 00173 // We are done! 00174 q->commit(); 00175 00176 } else { 00177 const QString resourceId = mFoldersForResource.keys().first(); 00178 kDebug() << "A resource is done," << mFoldersForResource.count() 00179 << "more to do. Now doing resource" << resourceId; 00180 ResourceScanJob *resjob = new ResourceScanJob( resourceId, mSpecialCollections->d->mSettings, q ); 00181 QObject::connect( resjob, SIGNAL(result(KJob*)), q, SLOT(resourceScanResult(KJob*)) ); 00182 } 00183 } 00184 00185 void SpecialCollectionsRequestJobPrivate::resourceScanResult( KJob *job ) 00186 { 00187 ResourceScanJob *resjob = qobject_cast<ResourceScanJob*>( job ); 00188 Q_ASSERT( resjob ); 00189 00190 const QString resourceId = resjob->resourceId(); 00191 kDebug() << "resourceId" << resourceId; 00192 00193 if ( job->error() ) { 00194 kWarning() << "Failed to request resource" << resourceId << ":" << job->errorString(); 00195 return; 00196 } 00197 00198 if ( qobject_cast<DefaultResourceJob*>( job ) ) { 00199 // This is the default resource. 00200 if ( resourceId != mSpecialCollections->d->defaultResourceId() ) { 00201 kError() << "Resource id's don't match: " << resourceId 00202 << mSpecialCollections->d->defaultResourceId(); 00203 Q_ASSERT( false ); 00204 } 00205 //mToForget.append( mSpecialCollections->defaultResourceId() ); 00206 createRequestedFolders( resjob, mDefaultFolders ); 00207 } else { 00208 // This is not the default resource. 00209 QHash<QByteArray, bool> requestedFolders = mFoldersForResource[ resourceId ]; 00210 mFoldersForResource.remove( resourceId ); 00211 createRequestedFolders( resjob, requestedFolders ); 00212 } 00213 } 00214 00215 void SpecialCollectionsRequestJobPrivate::createRequestedFolders( ResourceScanJob *scanJob, 00216 QHash<QByteArray, bool> &requestedFolders ) 00217 { 00218 // Remove from the request list the folders which already exist. 00219 foreach ( const Collection &collection, scanJob->specialCollections() ) { 00220 Q_ASSERT( collection.hasAttribute<SpecialCollectionAttribute>() ); 00221 const SpecialCollectionAttribute *attr = collection.attribute<SpecialCollectionAttribute>(); 00222 const QByteArray type = attr->collectionType(); 00223 00224 if ( !type.isEmpty() ) { 00225 mToRegister.append( qMakePair( collection, type ) ); 00226 requestedFolders.insert( type, false ); 00227 } 00228 } 00229 mToForget.append( scanJob->resourceId() ); 00230 00231 // Folders left in the request list must be created. 00232 Q_ASSERT( mPendingCreateJobs == 0 ); 00233 Q_ASSERT( scanJob->rootResourceCollection().isValid() ); 00234 00235 QHashIterator<QByteArray, bool> it( requestedFolders ); 00236 while ( it.hasNext() ) { 00237 it.next(); 00238 00239 if ( it.value() ) { 00240 Collection collection; 00241 collection.setParentCollection( scanJob->rootResourceCollection() ); 00242 collection.setName( mNameForTypeMap.value( it.key() ) ); 00243 00244 setCollectionAttributes( collection, it.key(), mNameForTypeMap, mIconForTypeMap ); 00245 00246 CollectionCreateJob *createJob = new CollectionCreateJob( collection, q ); 00247 createJob->setProperty( "type", it.key() ); 00248 QObject::connect( createJob, SIGNAL(result(KJob*)), q, SLOT(collectionCreateResult(KJob*)) ); 00249 00250 mPendingCreateJobs++; 00251 } 00252 } 00253 00254 if ( mPendingCreateJobs == 0 ) 00255 nextResource(); 00256 } 00257 00258 void SpecialCollectionsRequestJobPrivate::collectionCreateResult( KJob *job ) 00259 { 00260 if ( job->error() ) { 00261 kWarning() << "Failed CollectionCreateJob." << job->errorString(); 00262 return; 00263 } 00264 00265 CollectionCreateJob *createJob = qobject_cast<CollectionCreateJob*>( job ); 00266 Q_ASSERT( createJob ); 00267 00268 const Collection collection = createJob->collection(); 00269 mToRegister.append( qMakePair( collection, createJob->property( "type" ).toByteArray() ) ); 00270 00271 Q_ASSERT( mPendingCreateJobs > 0 ); 00272 mPendingCreateJobs--; 00273 kDebug() << "mPendingCreateJobs now" << mPendingCreateJobs; 00274 00275 if ( mPendingCreateJobs == 0 ) 00276 nextResource(); 00277 } 00278 00279 00280 00281 // TODO KDE5: do not inherit from TransactionSequence 00282 SpecialCollectionsRequestJob::SpecialCollectionsRequestJob( SpecialCollections *collections, QObject *parent ) 00283 : TransactionSequence( parent ), 00284 d( new SpecialCollectionsRequestJobPrivate( collections, this ) ) 00285 { 00286 setProperty( "transactionsDisabled", true ); 00287 } 00288 00289 SpecialCollectionsRequestJob::~SpecialCollectionsRequestJob() 00290 { 00291 delete d; 00292 } 00293 00294 void SpecialCollectionsRequestJob::requestDefaultCollection( const QByteArray &type ) 00295 { 00296 d->mDefaultFolders[ type ] = true; 00297 d->mRequestingDefaultFolders = true; 00298 d->mRequestedType = type; 00299 } 00300 00301 void SpecialCollectionsRequestJob::requestCollection( const QByteArray &type, const AgentInstance &instance ) 00302 { 00303 if ( !d->mFoldersForResource.contains( instance.identifier() ) ) { 00304 // This resource was previously unknown. 00305 d->mFoldersForResource[ instance.identifier() ] = QHash<QByteArray, bool>(); 00306 } 00307 d->mFoldersForResource[ instance.identifier() ][ type ] = true; 00308 00309 d->mRequestedType = type; 00310 d->mRequestedResource = instance; 00311 } 00312 00313 Akonadi::Collection SpecialCollectionsRequestJob::collection() const 00314 { 00315 if ( d->mRequestedResource.isValid() ) 00316 return d->mSpecialCollections->collection( d->mRequestedType, d->mRequestedResource ); 00317 else 00318 return d->mSpecialCollections->defaultCollection( d->mRequestedType ); 00319 } 00320 00321 void SpecialCollectionsRequestJob::setDefaultResourceType( const QString &type ) 00322 { 00323 d->mDefaultResourceType = type; 00324 } 00325 00326 void SpecialCollectionsRequestJob::setDefaultResourceOptions( const QVariantMap &options ) 00327 { 00328 d->mDefaultResourceOptions = options; 00329 } 00330 00331 void SpecialCollectionsRequestJob::setTypes( const QList<QByteArray> &types ) 00332 { 00333 d->mKnownTypes = types; 00334 } 00335 00336 void SpecialCollectionsRequestJob::setNameForTypeMap( const QMap<QByteArray, QString> &map ) 00337 { 00338 d->mNameForTypeMap = map; 00339 } 00340 00341 void SpecialCollectionsRequestJob::setIconForTypeMap( const QMap<QByteArray, QString> &map ) 00342 { 00343 d->mIconForTypeMap = map; 00344 } 00345 00346 void SpecialCollectionsRequestJob::doStart() 00347 { 00348 if ( d->isEverythingReady() ) { 00349 emitResult(); 00350 } else { 00351 GetLockJob *lockJob = new GetLockJob( this ); 00352 connect( lockJob, SIGNAL(result(KJob*)), this, SLOT(lockResult(KJob*)) ); 00353 lockJob->start(); 00354 } 00355 } 00356 00357 void SpecialCollectionsRequestJob::slotResult( KJob *job ) 00358 { 00359 if ( job->error() ) { 00360 // If we failed, let others try. 00361 kWarning() << "Failed SpecialCollectionsRequestJob::slotResult" << job->errorString(); 00362 00363 d->releaseLock(); 00364 } 00365 TransactionSequence::slotResult( job ); 00366 } 00367 00368 #include "specialcollectionsrequestjob.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:49:16 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Apr 30 2012 21:49:16 by doxygen 1.8.0 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.