00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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 );
00047 void releaseLock();
00048 void nextResource();
00049 void resourceScanResult( KJob *job );
00050 void createRequestedFolders( ResourceScanJob *job, QHash<QByteArray, bool> &requestedFolders );
00051 void collectionCreateResult( KJob *job );
00052
00053 SpecialCollectionsRequestJob *q;
00054 SpecialCollections *mSpecialCollections;
00055 int mPendingCreateJobs;
00056
00057 QByteArray mRequestedType;
00058 AgentInstance mRequestedResource;
00059
00060
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
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
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 kDebug() << "All requested folders already known.";
00113 return true;
00114 }
00115
00116 void SpecialCollectionsRequestJobPrivate::lockResult( KJob *job )
00117 {
00118 if ( job->error() ) {
00119 kWarning() << "Failed to get lock:" << job->errorString();
00120 q->setError( job->error() );
00121 q->setErrorText( job->errorString() );
00122 q->emitResult();
00123 return;
00124 }
00125
00126 if ( mRequestingDefaultFolders ) {
00127
00128 DefaultResourceJob *resjob = new DefaultResourceJob( mSpecialCollections->d->mSettings, q );
00129 resjob->setDefaultResourceType( mDefaultResourceType );
00130 resjob->setDefaultResourceOptions( mDefaultResourceOptions );
00131 resjob->setTypes( mKnownTypes );
00132 resjob->setNameForTypeMap( mNameForTypeMap );
00133 resjob->setIconForTypeMap( mIconForTypeMap );
00134 QObject::connect( resjob, SIGNAL( result( KJob* ) ), q, SLOT( resourceScanResult( KJob* ) ) );
00135 } else {
00136
00137 nextResource();
00138 }
00139 }
00140
00141 void SpecialCollectionsRequestJobPrivate::releaseLock()
00142 {
00143 const bool ok = Akonadi::releaseLock();
00144 if ( !ok ) {
00145 kWarning() << "WTF, can't release lock.";
00146 }
00147 }
00148
00149 void SpecialCollectionsRequestJobPrivate::nextResource()
00150 {
00151 if ( mFoldersForResource.isEmpty() ) {
00152 kDebug() << "All done! Comitting.";
00153
00154 mSpecialCollections->d->beginBatchRegister();
00155
00156
00157 foreach ( const QString &resourceId, mToForget ) {
00158 mSpecialCollections->d->forgetFoldersForResource( resourceId );
00159 }
00160
00161
00162 typedef QPair<Collection, QByteArray> RegisterPair;
00163 foreach ( const RegisterPair &pair, mToRegister ) {
00164 const bool ok = mSpecialCollections->registerCollection( pair.second, pair.first );
00165 Q_ASSERT( ok );
00166 Q_UNUSED( ok );
00167 }
00168
00169 mSpecialCollections->d->endBatchRegister();
00170
00171
00172 QObject::connect( q, SIGNAL( result( KJob* ) ), q, SLOT( releaseLock() ) );
00173
00174
00175 q->commit();
00176
00177 } else {
00178 const QString resourceId = mFoldersForResource.keys().first();
00179 kDebug() << "A resource is done," << mFoldersForResource.count()
00180 << "more to do. Now doing resource" << resourceId;
00181 ResourceScanJob *resjob = new ResourceScanJob( resourceId, mSpecialCollections->d->mSettings, q );
00182 QObject::connect( resjob, SIGNAL( result( KJob* ) ), q, SLOT( resourceScanResult( KJob* ) ) );
00183 }
00184 }
00185
00186 void SpecialCollectionsRequestJobPrivate::resourceScanResult( KJob *job )
00187 {
00188 ResourceScanJob *resjob = qobject_cast<ResourceScanJob*>( job );
00189 Q_ASSERT( resjob );
00190
00191 const QString resourceId = resjob->resourceId();
00192 kDebug() << "resourceId" << resourceId;
00193
00194 if ( job->error() ) {
00195 kWarning() << "Failed to request resource" << resourceId << ":" << job->errorString();
00196 return;
00197 }
00198
00199 if ( qobject_cast<DefaultResourceJob*>( job ) ) {
00200
00201 if ( resourceId != mSpecialCollections->d->defaultResourceId() ) {
00202 kError() << "Resource id's don't match: " << resourceId
00203 << mSpecialCollections->d->defaultResourceId();
00204 Q_ASSERT( false );
00205 }
00206
00207 createRequestedFolders( resjob, mDefaultFolders );
00208 } else {
00209
00210 QHash<QByteArray, bool> requestedFolders = mFoldersForResource[ resourceId ];
00211 mFoldersForResource.remove( resourceId );
00212 createRequestedFolders( resjob, requestedFolders );
00213 }
00214 }
00215
00216 void SpecialCollectionsRequestJobPrivate::createRequestedFolders( ResourceScanJob *scanJob,
00217 QHash<QByteArray, bool> &requestedFolders )
00218 {
00219
00220 foreach ( const Collection &collection, scanJob->specialCollections() ) {
00221 Q_ASSERT( collection.hasAttribute<SpecialCollectionAttribute>() );
00222 const SpecialCollectionAttribute *attr = collection.attribute<SpecialCollectionAttribute>();
00223 const QByteArray type = attr->collectionType();
00224
00225 if ( !type.isEmpty() ) {
00226 mToRegister.append( qMakePair( collection, type ) );
00227 requestedFolders.insert( type, false );
00228 }
00229 }
00230 mToForget.append( scanJob->resourceId() );
00231
00232
00233 Q_ASSERT( mPendingCreateJobs == 0 );
00234 Q_ASSERT( scanJob->rootResourceCollection().isValid() );
00235
00236 QHashIterator<QByteArray, bool> it( requestedFolders );
00237 while ( it.hasNext() ) {
00238 it.next();
00239
00240 if ( it.value() ) {
00241 Collection collection;
00242 collection.setParentCollection( scanJob->rootResourceCollection() );
00243 collection.setName( mNameForTypeMap.value( it.key() ) );
00244
00245 setCollectionAttributes( collection, it.key(), mNameForTypeMap, mIconForTypeMap );
00246
00247 CollectionCreateJob *createJob = new CollectionCreateJob( collection, q );
00248 createJob->setProperty( "type", it.key() );
00249 QObject::connect( createJob, SIGNAL( result( KJob* ) ), q, SLOT( collectionCreateResult( KJob* ) ) );
00250
00251 mPendingCreateJobs++;
00252 }
00253 }
00254
00255 if ( mPendingCreateJobs == 0 )
00256 nextResource();
00257 }
00258
00259 void SpecialCollectionsRequestJobPrivate::collectionCreateResult( KJob *job )
00260 {
00261 if ( job->error() ) {
00262 kWarning() << "Failed CollectionCreateJob." << job->errorString();
00263 return;
00264 }
00265
00266 CollectionCreateJob *createJob = qobject_cast<CollectionCreateJob*>( job );
00267 Q_ASSERT( createJob );
00268
00269 const Collection collection = createJob->collection();
00270 mToRegister.append( qMakePair( collection, createJob->property( "type" ).toByteArray() ) );
00271
00272 Q_ASSERT( mPendingCreateJobs > 0 );
00273 mPendingCreateJobs--;
00274 kDebug() << "mPendingCreateJobs now" << mPendingCreateJobs;
00275
00276 if ( mPendingCreateJobs == 0 )
00277 nextResource();
00278 }
00279
00280
00281
00282
00283 SpecialCollectionsRequestJob::SpecialCollectionsRequestJob( SpecialCollections *collections, QObject *parent )
00284 : TransactionSequence( parent ),
00285 d( new SpecialCollectionsRequestJobPrivate( collections, this ) )
00286 {
00287 setProperty( "transactionsDisabled", true );
00288 }
00289
00290 SpecialCollectionsRequestJob::~SpecialCollectionsRequestJob()
00291 {
00292 delete d;
00293 }
00294
00295 void SpecialCollectionsRequestJob::requestDefaultCollection( const QByteArray &type )
00296 {
00297 d->mDefaultFolders[ type ] = true;
00298 d->mRequestingDefaultFolders = true;
00299 d->mRequestedType = type;
00300 }
00301
00302 void SpecialCollectionsRequestJob::requestCollection( const QByteArray &type, const AgentInstance &instance )
00303 {
00304 if ( !d->mFoldersForResource.contains( instance.identifier() ) ) {
00305
00306 d->mFoldersForResource[ instance.identifier() ] = QHash<QByteArray, bool>();
00307 }
00308 d->mFoldersForResource[ instance.identifier() ][ type ] = true;
00309
00310 d->mRequestedType = type;
00311 d->mRequestedResource = instance;
00312 }
00313
00314 Akonadi::Collection SpecialCollectionsRequestJob::collection() const
00315 {
00316 if ( d->mRequestedResource.isValid() )
00317 return d->mSpecialCollections->collection( d->mRequestedType, d->mRequestedResource );
00318 else
00319 return d->mSpecialCollections->defaultCollection( d->mRequestedType );
00320 }
00321
00322 void SpecialCollectionsRequestJob::setDefaultResourceType( const QString &type )
00323 {
00324 d->mDefaultResourceType = type;
00325 }
00326
00327 void SpecialCollectionsRequestJob::setDefaultResourceOptions( const QVariantMap &options )
00328 {
00329 d->mDefaultResourceOptions = options;
00330 }
00331
00332 void SpecialCollectionsRequestJob::setTypes( const QList<QByteArray> &types )
00333 {
00334 d->mKnownTypes = types;
00335 }
00336
00337 void SpecialCollectionsRequestJob::setNameForTypeMap( const QMap<QByteArray, QString> &map )
00338 {
00339 d->mNameForTypeMap = map;
00340 }
00341
00342 void SpecialCollectionsRequestJob::setIconForTypeMap( const QMap<QByteArray, QString> &map )
00343 {
00344 d->mIconForTypeMap = map;
00345 }
00346
00347 void SpecialCollectionsRequestJob::doStart()
00348 {
00349 if ( d->isEverythingReady() ) {
00350 emitResult();
00351 } else {
00352 GetLockJob *lockJob = new GetLockJob( this );
00353 connect( lockJob, SIGNAL( result( KJob* ) ), this, SLOT( lockResult( KJob* ) ) );
00354 lockJob->start();
00355 }
00356 }
00357
00358 void SpecialCollectionsRequestJob::slotResult( KJob *job )
00359 {
00360 if ( job->error() ) {
00361
00362 kWarning() << "Failed SpecialCollectionsRequestJob::slotResult" << job->errorString();
00363
00364 d->releaseLock();
00365 }
00366 TransactionSequence::slotResult( job );
00367 }
00368
00369 #include "specialcollectionsrequestjob.moc"