akonadi
specialcollections.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 "specialcollections.h" 00021 00022 #include "specialcollections_p.h" 00023 #include "specialcollectionattribute_p.h" 00024 00025 #include "akonadi/agentinstance.h" 00026 #include "akonadi/agentmanager.h" 00027 #include "akonadi/collectionmodifyjob.h" 00028 #include "akonadi/collectionfetchjob.h" 00029 #include "akonadi/monitor.h" 00030 00031 #include <KDebug> 00032 #include <kcoreconfigskeleton.h> 00033 00034 #include <QtCore/QHash> 00035 #include <QtCore/QObject> 00036 #include <QtCore/QSet> 00037 #include <akonadi/collectionfetchscope.h> 00038 00039 using namespace Akonadi; 00040 00041 SpecialCollectionsPrivate::SpecialCollectionsPrivate( KCoreConfigSkeleton *settings, SpecialCollections *qq ) 00042 : q( qq ), 00043 mSettings( settings ), 00044 mBatchMode( false ) 00045 { 00046 mMonitor = new Monitor( q ); 00047 mMonitor->fetchCollectionStatistics( true ); 00048 00053 QObject::connect( mMonitor, SIGNAL( collectionRemoved( const Akonadi::Collection& ) ), 00054 q, SLOT( collectionRemoved( const Akonadi::Collection& ) ) ); 00055 QObject::connect( mMonitor, SIGNAL( collectionStatisticsChanged( Akonadi::Collection::Id, const Akonadi::CollectionStatistics& ) ), 00056 q, SLOT( collectionStatisticsChanged( Akonadi::Collection::Id, const Akonadi::CollectionStatistics& ) ) ); 00057 } 00058 00059 SpecialCollectionsPrivate::~SpecialCollectionsPrivate() 00060 { 00061 } 00062 00063 QString SpecialCollectionsPrivate::defaultResourceId() const 00064 { 00065 mSettings->readConfig(); 00066 const KConfigSkeletonItem *item = mSettings->findItem( QLatin1String( "DefaultResourceId" ) ); 00067 Q_ASSERT( item ); 00068 00069 mDefaultResourceId = item->property().toString(); 00070 return mDefaultResourceId; 00071 } 00072 00073 void SpecialCollectionsPrivate::emitChanged( const QString &resourceId ) 00074 { 00075 if ( mBatchMode ) { 00076 mToEmitChangedFor.insert( resourceId ); 00077 } else { 00078 kDebug() << "Emitting changed for" << resourceId; 00079 const AgentInstance agentInstance = AgentManager::self()->instance( resourceId ); 00080 emit q->collectionsChanged( agentInstance ); 00081 // first compare with local value then with config value (which also updates the local value) 00082 if ( resourceId == mDefaultResourceId || resourceId == defaultResourceId() ) { 00083 kDebug() << "Emitting defaultFoldersChanged."; 00084 emit q->defaultCollectionsChanged(); 00085 } 00086 } 00087 } 00088 00089 void SpecialCollectionsPrivate::collectionRemoved( const Collection &collection ) 00090 { 00091 kDebug() << "Collection" << collection.id() << "resource" << collection.resource(); 00092 if ( mFoldersForResource.contains( collection.resource() ) ) { 00093 00094 // Retrieve the list of special folders for the resource the collection belongs to 00095 QHash<QByteArray, Collection> &folders = mFoldersForResource[ collection.resource() ]; 00096 { 00097 QMutableHashIterator<QByteArray, Collection> it( folders ); 00098 while ( it.hasNext() ) { 00099 it.next(); 00100 if ( it.value() == collection ) { 00101 // The collection to be removed is a special folder 00102 it.remove(); 00103 emitChanged( collection.resource() ); 00104 } 00105 } 00106 } 00107 00108 if ( folders.isEmpty() ) { 00109 // This resource has no more folders, so remove it completely. 00110 mFoldersForResource.remove( collection.resource() ); 00111 } 00112 } 00113 } 00114 00115 void SpecialCollectionsPrivate::collectionStatisticsChanged( Akonadi::Collection::Id collectionId, const Akonadi::CollectionStatistics &statistics ) 00116 { 00117 // need to get the name of the collection in order to be able to check if we are storing it, 00118 // but we have the id from the monitor, so fetch the name. 00119 Akonadi::CollectionFetchJob* fetchJob = new Akonadi::CollectionFetchJob( Collection( collectionId ), Akonadi::CollectionFetchJob::Base ); 00120 fetchJob->fetchScope().setAncestorRetrieval( Akonadi::CollectionFetchScope::None ); 00121 fetchJob->setProperty( "statistics", QVariant::fromValue( statistics ) ); 00122 00123 q->connect( fetchJob, SIGNAL( result( KJob* ) ), q, SLOT( collectionFetchJobFinished( KJob* ) ) ); 00124 } 00125 00126 00127 void SpecialCollectionsPrivate::collectionFetchJobFinished( KJob* job ) 00128 { 00129 if ( job->error() ) { 00130 kWarning() << "Error fetching collection to get name from id for statistics updating in specialcollections!"; 00131 return; 00132 } 00133 00134 const Akonadi::CollectionFetchJob *fetchJob = qobject_cast<Akonadi::CollectionFetchJob*>( job ); 00135 00136 Q_ASSERT( fetchJob->collections().size() > 0 ); 00137 const Akonadi::Collection collection = fetchJob->collections().first(); 00138 const Akonadi::CollectionStatistics statistics = fetchJob->property( "statistics" ).value<Akonadi::CollectionStatistics>(); 00139 00140 mFoldersForResource[ collection.resource() ][ collection.name().toUtf8() ].setStatistics( statistics ); 00141 } 00142 00143 void SpecialCollectionsPrivate::beginBatchRegister() 00144 { 00145 Q_ASSERT( !mBatchMode ); 00146 mBatchMode = true; 00147 Q_ASSERT( mToEmitChangedFor.isEmpty() ); 00148 } 00149 00150 void SpecialCollectionsPrivate::endBatchRegister() 00151 { 00152 Q_ASSERT( mBatchMode ); 00153 mBatchMode = false; 00154 00155 foreach ( const QString &resourceId, mToEmitChangedFor ) { 00156 emitChanged( resourceId ); 00157 } 00158 00159 mToEmitChangedFor.clear(); 00160 } 00161 00162 void SpecialCollectionsPrivate::forgetFoldersForResource( const QString &resourceId ) 00163 { 00164 if ( mFoldersForResource.contains( resourceId ) ) { 00165 const Collection::List folders = mFoldersForResource[ resourceId ].values(); 00166 00167 foreach ( const Collection &collection, folders ) { 00168 mMonitor->setCollectionMonitored( collection, false ); 00169 } 00170 00171 mFoldersForResource.remove( resourceId ); 00172 emitChanged( resourceId ); 00173 } 00174 } 00175 00176 AgentInstance SpecialCollectionsPrivate::defaultResource() const 00177 { 00178 const QString identifier = defaultResourceId(); 00179 return AgentManager::self()->instance( identifier ); 00180 } 00181 00182 00183 SpecialCollections::SpecialCollections( KCoreConfigSkeleton *settings, QObject *parent ) 00184 : QObject( parent ), 00185 d( new SpecialCollectionsPrivate( settings, this ) ) 00186 { 00187 } 00188 00189 SpecialCollections::~SpecialCollections() 00190 { 00191 delete d; 00192 } 00193 00194 bool SpecialCollections::hasCollection( const QByteArray &type, const AgentInstance &instance ) const 00195 { 00196 kDebug() << "Type" << type << "resourceId" << instance.identifier(); 00197 00198 if ( !d->mFoldersForResource.contains( instance.identifier() ) ) { 00199 // We do not know any folders in this resource. 00200 return false; 00201 } 00202 00203 return d->mFoldersForResource[ instance.identifier() ].contains( type ); 00204 } 00205 00206 Akonadi::Collection SpecialCollections::collection( const QByteArray &type, const AgentInstance &instance ) const 00207 { 00208 if ( !d->mFoldersForResource.contains( instance.identifier() ) ) { 00209 // We do not know any folders in this resource. 00210 return Collection( -1 ); 00211 } 00212 return d->mFoldersForResource[ instance.identifier() ][ type ]; 00213 } 00214 00215 bool SpecialCollections::registerCollection( const QByteArray &type, const Collection &collection ) 00216 { 00217 if ( !collection.isValid() ) { 00218 kWarning() << "Invalid collection."; 00219 return false; 00220 } 00221 00222 const QString &resourceId = collection.resource(); 00223 if ( resourceId.isEmpty() ) { 00224 kWarning() << "Collection has empty resourceId."; 00225 return false; 00226 } 00227 00228 if ( !collection.hasAttribute<SpecialCollectionAttribute>() || collection.attribute<SpecialCollectionAttribute>()->collectionType() != type ) { 00229 Collection attributeCollection( collection ); 00230 SpecialCollectionAttribute *attribute = attributeCollection.attribute<SpecialCollectionAttribute>( Collection::AddIfMissing ); 00231 attribute->setCollectionType( type ); 00232 00233 new CollectionModifyJob( attributeCollection ); 00234 } 00235 00236 if ( !d->mFoldersForResource.contains( resourceId ) ) { 00237 // We do not know any folders in this resource yet. 00238 d->mFoldersForResource.insert( resourceId, QHash<QByteArray, Collection>() ); 00239 } 00240 00241 if ( !d->mFoldersForResource[ resourceId ].contains( type ) ) 00242 d->mFoldersForResource[ resourceId ].insert( type, Collection() ); 00243 00244 if ( d->mFoldersForResource[ resourceId ][ type ] != collection ) { 00245 d->mMonitor->setCollectionMonitored( d->mFoldersForResource[ resourceId ][ type ], false ); 00246 d->mMonitor->setCollectionMonitored( collection, true ); 00247 d->mFoldersForResource[ resourceId ].insert( type, collection ); 00248 d->emitChanged( resourceId ); 00249 } 00250 00251 kDebug() << "Registered collection" << collection.id() << "as folder of type" << type 00252 << "in resource" << resourceId; 00253 return true; 00254 } 00255 00256 bool SpecialCollections::hasDefaultCollection( const QByteArray &type ) const 00257 { 00258 return hasCollection( type, d->defaultResource() ); 00259 } 00260 00261 Akonadi::Collection SpecialCollections::defaultCollection( const QByteArray &type ) const 00262 { 00263 return collection( type, d->defaultResource() ); 00264 } 00265 00266 #include "specialcollections.moc"