KIO
kdirlister_p.h
Go to the documentation of this file.
00001 /* This file is part of the KDE project 00002 Copyright (C) 2002-2006 Michael Brade <brade@kde.org> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public 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 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #ifndef kdirlister_p_h 00021 #define kdirlister_p_h 00022 00023 #include "kfileitem.h" 00024 00025 #include <QtCore/QMap> 00026 #include <QtCore/QHash> 00027 #include <QtCore/QCache> 00028 #include <QtCore/QSet> 00029 #include <QtCore/QTimer> 00030 #include <QtGui/QWidget> 00031 00032 #include <kurl.h> 00033 #include <kdebug.h> 00034 #include <kio/global.h> 00035 #include <kdirwatch.h> 00036 00037 class KDirLister; 00038 namespace KIO { class Job; class ListJob; } 00039 class OrgKdeKDirNotifyInterface; 00040 struct KDirListerCacheDirectoryData; 00041 00042 class KDirLister::Private 00043 { 00044 public: 00045 Private(KDirLister *parent) 00046 : m_parent(parent) 00047 { 00048 complete = false; 00049 00050 autoUpdate = false; 00051 00052 autoErrorHandling = false; 00053 errorParent = 0; 00054 00055 delayedMimeTypes = false; 00056 00057 rootFileItem = KFileItem(); 00058 00059 lstNewItems = 0; 00060 lstRefreshItems = 0; 00061 lstMimeFilteredItems = 0; 00062 lstRemoveItems = 0; 00063 00064 hasPendingChanges = false; 00065 00066 window = 0; 00067 } 00068 00069 void _k_emitCachedItems(const KUrl&, bool, bool); 00070 void _k_slotInfoMessage( KJob*, const QString& ); 00071 void _k_slotPercent( KJob*, unsigned long ); 00072 void _k_slotTotalSize( KJob*, qulonglong ); 00073 void _k_slotProcessedSize( KJob*, qulonglong ); 00074 void _k_slotSpeed( KJob*, unsigned long ); 00075 00076 bool doMimeExcludeFilter( const QString& mimeExclude, const QStringList& filters ) const; 00077 void jobStarted( KIO::ListJob * ); 00078 void connectJob( KIO::ListJob * ); 00079 void jobDone( KIO::ListJob * ); 00080 uint numJobs(); 00081 void addNewItem(const KUrl& directoryUrl, const KFileItem& item); 00082 void addNewItems(const KUrl& directoryUrl, const KFileItemList& items); 00083 void addRefreshItem(const KUrl& directoryUrl, const KFileItem& oldItem, const KFileItem& item); 00084 void emitItems(); 00085 void emitItemsDeleted(const KFileItemList &items); 00086 00092 void redirect(const KUrl& oldUrl, const KUrl& newUrl, bool keepItems); 00093 00097 bool isItemVisible(const KFileItem& item) const; 00098 00099 void prepareForSettingsChange() { 00100 if (!hasPendingChanges) { 00101 hasPendingChanges = true; 00102 oldSettings = settings; 00103 } 00104 } 00105 00106 void emitChanges(); 00107 00108 class CachedItemsJob; 00109 CachedItemsJob* cachedItemsJobForUrl(const KUrl& url) const; 00110 00111 00112 KDirLister *m_parent; 00113 00118 KUrl::List lstDirs; 00119 00120 // toplevel URL 00121 KUrl url; 00122 00123 bool complete:1; 00124 00125 bool autoUpdate:1; 00126 00127 bool delayedMimeTypes:1; 00128 00129 bool hasPendingChanges:1; // i.e. settings != oldSettings 00130 00131 bool autoErrorHandling:2; 00132 QWidget *errorParent; 00133 00134 struct JobData { 00135 long unsigned int percent, speed; 00136 KIO::filesize_t processedSize, totalSize; 00137 }; 00138 00139 QMap<KIO::ListJob *, JobData> jobData; 00140 00141 // file item for the root itself (".") 00142 KFileItem rootFileItem; 00143 00144 typedef QHash<KUrl, KFileItemList> NewItemsHash; 00145 NewItemsHash *lstNewItems; 00146 QList<QPair<KFileItem,KFileItem> > *lstRefreshItems; 00147 KFileItemList *lstMimeFilteredItems, *lstRemoveItems; 00148 00149 QWidget *window; // Main window this lister is associated with 00150 QList<CachedItemsJob*> m_cachedItemsJobs; 00151 00152 QString nameFilter; // parsed into lstFilters 00153 00154 struct FilterSettings { 00155 FilterSettings() : isShowingDotFiles(false), dirOnlyMode(false) {} 00156 bool isShowingDotFiles; 00157 bool dirOnlyMode; 00158 QList<QRegExp> lstFilters; 00159 QStringList mimeFilter; 00160 QStringList mimeExcludeFilter; 00161 }; 00162 FilterSettings settings; 00163 FilterSettings oldSettings; 00164 00165 friend class KDirListerCache; 00166 }; 00167 00181 class KDirListerCache : public QObject 00182 { 00183 Q_OBJECT 00184 public: 00185 KDirListerCache(); // only called by K_GLOBAL_STATIC 00186 ~KDirListerCache(); 00187 00188 void updateDirectory( const KUrl& dir ); 00189 00190 KFileItem itemForUrl( const KUrl& url ) const; 00191 KFileItemList *itemsForDir(const KUrl& dir) const; 00192 00193 bool listDir( KDirLister *lister, const KUrl& _url, bool _keep, bool _reload ); 00194 00195 // stop all running jobs for lister 00196 void stop( KDirLister *lister, bool silent = false ); 00197 // stop just the job listing url for lister 00198 void stopListingUrl( KDirLister *lister, const KUrl &_url, bool silent = false ); 00199 00200 void setAutoUpdate( KDirLister *lister, bool enable ); 00201 00202 void forgetDirs( KDirLister *lister ); 00203 void forgetDirs( KDirLister *lister, const KUrl &_url, bool notify ); 00204 00205 KFileItem findByName( const KDirLister *lister, const QString &_name ) const; 00206 // findByUrl returns a pointer so that it's possible to modify the item. 00207 // See itemForUrl for the version that returns a readonly kfileitem. 00208 // @param lister can be 0. If set, it is checked that the url is held by the lister 00209 KFileItem *findByUrl(const KDirLister *lister, const KUrl &url) const; 00210 00211 // Called by CachedItemsJob: 00212 // Emits the cached items, for this lister and this url 00213 void emitItemsFromCache(KDirLister::Private::CachedItemsJob* job, KDirLister* lister, 00214 const KUrl& _url, bool _reload, bool _emitCompleted); 00215 // Called by CachedItemsJob: 00216 void forgetCachedItemsJob(KDirLister::Private::CachedItemsJob* job, KDirLister* lister, 00217 const KUrl& url); 00218 00219 public Q_SLOTS: 00226 void slotFilesAdded( const QString& urlDirectory ); 00227 00235 void slotFilesRemoved( const QStringList& fileList ); 00236 00243 void slotFilesChanged( const QStringList& fileList ); 00244 void slotFileRenamed( const QString& srcUrl, const QString& dstUrl ); 00245 00246 private Q_SLOTS: 00247 void slotFileDirty( const QString &_file ); 00248 void slotFileCreated( const QString &_file ); 00249 void slotFileDeleted( const QString &_file ); 00250 00251 void slotEntries( KIO::Job *job, const KIO::UDSEntryList &entries ); 00252 void slotResult( KJob *j ); 00253 void slotRedirection( KIO::Job *job, const KUrl &url ); 00254 00255 void slotUpdateEntries( KIO::Job *job, const KIO::UDSEntryList &entries ); 00256 void slotUpdateResult( KJob *job ); 00257 void processPendingUpdates(); 00258 00259 private: 00260 class DirItem; 00261 DirItem* dirItemForUrl(const KUrl& dir) const; 00262 00263 bool validUrl( const KDirLister *lister, const KUrl& _url ) const; 00264 00265 void stopListJob(const QString& url, bool silent); 00266 00267 KIO::ListJob *jobForUrl( const QString& url, KIO::ListJob *not_job = 0 ); 00268 const KUrl& joburl( KIO::ListJob *job ); 00269 00270 void killJob( KIO::ListJob *job ); 00271 00272 // Called when something tells us that the directory @p url has changed. 00273 // Returns true if @p url is held by some lister (meaning: do the update now) 00274 // otherwise mark the cached item as not-up-to-date for later and return false 00275 bool checkUpdate( const QString& url ); 00276 00277 // Helper method for slotFileDirty 00278 void handleFileDirty(const KUrl& url); 00279 void handleDirDirty(const KUrl& url); 00280 00281 // when there were items deleted from the filesystem all the listers holding 00282 // the parent directory need to be notified, the unmarked items have to be deleted 00283 // and removed from the cache including all the children. 00284 void deleteUnmarkedItems( const QList<KDirLister *>&, KFileItemList & ); 00285 // Helper method called when we know that a list of items was deleted 00286 void itemsDeleted(const QList<KDirLister *>& listers, const KFileItemList& deletedItems); 00287 void slotFilesRemoved(const KUrl::List& urls); 00288 // common for slotRedirection and slotFileRenamed 00289 void renameDir( const KUrl &oldUrl, const KUrl &url ); 00290 // common for deleteUnmarkedItems and slotFilesRemoved 00291 void deleteDir( const KUrl& dirUrl ); 00292 // remove directory from cache (itemsCached), including all child dirs 00293 void removeDirFromCache( const KUrl& dir ); 00294 // helper for renameDir 00295 void emitRedirections( const KUrl &oldUrl, const KUrl &url ); 00296 00302 QSet<KDirLister *> emitRefreshItem(const KFileItem& oldItem, const KFileItem& fileitem); 00303 00308 QStringList directoriesForCanonicalPath(const QString& dir) const; 00309 00310 #ifndef NDEBUG 00311 void printDebug(); 00312 #endif 00313 00314 class DirItem 00315 { 00316 public: 00317 DirItem(const KUrl &dir, const QString& canonicalPath) 00318 : url(dir), m_canonicalPath(canonicalPath) 00319 { 00320 autoUpdates = 0; 00321 complete = false; 00322 } 00323 00324 ~DirItem() 00325 { 00326 if ( autoUpdates ) 00327 { 00328 if ( KDirWatch::exists() && url.isLocalFile() ) 00329 KDirWatch::self()->removeDir(m_canonicalPath); 00330 sendSignal( false, url ); 00331 } 00332 lstItems.clear(); 00333 } 00334 00335 void sendSignal( bool entering, const KUrl& url ) 00336 { 00337 // Note that "entering" means "start watching", and "leaving" means "stop watching" 00338 // (i.e. it's not when the user leaves the directory, it's when the directory is removed from the cache) 00339 if (entering) 00340 org::kde::KDirNotify::emitEnteredDirectory( url.url() ); 00341 else 00342 org::kde::KDirNotify::emitLeftDirectory( url.url() ); 00343 } 00344 00345 void redirect( const KUrl& newUrl ) 00346 { 00347 if ( autoUpdates ) 00348 { 00349 if ( url.isLocalFile() ) 00350 KDirWatch::self()->removeDir(m_canonicalPath); 00351 sendSignal( false, url ); 00352 00353 if (newUrl.isLocalFile()) { 00354 m_canonicalPath = QFileInfo(newUrl.toLocalFile()).canonicalFilePath(); 00355 KDirWatch::self()->addDir(m_canonicalPath); 00356 } 00357 sendSignal( true, newUrl ); 00358 } 00359 00360 url = newUrl; 00361 00362 if ( !rootItem.isNull() ) 00363 rootItem.setUrl( newUrl ); 00364 } 00365 00366 void incAutoUpdate() 00367 { 00368 if ( autoUpdates++ == 0 ) 00369 { 00370 if ( url.isLocalFile() ) 00371 KDirWatch::self()->addDir(m_canonicalPath); 00372 sendSignal( true, url ); 00373 } 00374 } 00375 00376 void decAutoUpdate() 00377 { 00378 if ( --autoUpdates == 0 ) 00379 { 00380 if ( url.isLocalFile() ) 00381 KDirWatch::self()->removeDir(m_canonicalPath); 00382 sendSignal( false, url ); 00383 } 00384 00385 else if ( autoUpdates < 0 ) 00386 autoUpdates = 0; 00387 } 00388 00389 // number of KDirListers using autoUpdate for this dir 00390 short autoUpdates; 00391 00392 // this directory is up-to-date 00393 bool complete; 00394 00395 // the complete url of this directory 00396 KUrl url; 00397 00398 // the local path, with symlinks resolved, so that KDirWatch works 00399 QString m_canonicalPath; 00400 00401 // KFileItem representing the root of this directory. 00402 // Remember that this is optional. FTP sites don't return '.' in 00403 // the list, so they give no root item 00404 KFileItem rootItem; 00405 KFileItemList lstItems; 00406 }; 00407 00408 //static const unsigned short MAX_JOBS_PER_LISTER; 00409 00410 QMap<KIO::ListJob *, KIO::UDSEntryList> runningListJobs; 00411 00412 // an item is a complete directory 00413 QHash<QString /*url*/, DirItem*> itemsInUse; 00414 QCache<QString /*url*/, DirItem> itemsCached; 00415 00416 typedef QHash<QString /*url*/, KDirListerCacheDirectoryData> DirectoryDataHash; 00417 DirectoryDataHash directoryData; 00418 00419 // Symlink-to-directories are registered here so that we can 00420 // find the url that changed, when kdirwatch tells us about 00421 // changes in the canonical url. (#213799) 00422 QHash<QString /*canonical path*/, QStringList /*dirlister urls*/> canonicalUrls; 00423 00424 // Set of local files that we have changed recently (according to KDirWatch) 00425 // We temporize the notifications by keeping them 500ms in this list. 00426 QSet<QString /*path*/> pendingUpdates; 00427 // The timer for doing the delayed updates 00428 QTimer pendingUpdateTimer; 00429 00430 // Set of remote files that have changed recently -- but we can't emit those 00431 // changes yet, we need to wait for the "update" directory listing. 00432 // The cmp() call can't differ mimetypes since they are determined on demand, 00433 // this is why we need to remember those files here. 00434 QSet<KFileItem*> pendingRemoteUpdates; 00435 00436 // the KDirNotify signals 00437 OrgKdeKDirNotifyInterface *kdirnotify; 00438 00439 struct ItemInUseChange; 00440 }; 00441 00442 // Data associated with a directory url 00443 // This could be in DirItem but only in the itemsInUse dict... 00444 struct KDirListerCacheDirectoryData 00445 { 00446 // A lister can be EITHER in listersCurrentlyListing OR listersCurrentlyHolding 00447 // but NOT in both at the same time. 00448 // But both lists can have different listers at the same time; this 00449 // happens if more listers are requesting url at the same time and 00450 // one lister was stopped during the listing of files. 00451 00452 // Listers that are currently listing this url 00453 QList<KDirLister *> listersCurrentlyListing; 00454 // Listers that are currently holding this url 00455 QList<KDirLister *> listersCurrentlyHolding; 00456 00457 void moveListersWithoutCachedItemsJob(const KUrl& url); 00458 }; 00459 00460 //const unsigned short KDirListerCache::MAX_JOBS_PER_LISTER = 5; 00461 00462 // This job tells KDirListerCache to emit cached items asynchronously from listDir() 00463 // to give the KDirLister user enough time for connecting to its signals, and so 00464 // that KDirListerCache behaves just like when a real KIO::Job is used: nothing 00465 // is emitted during the openUrl call itself. 00466 class KDirLister::Private::CachedItemsJob : public KJob { 00467 Q_OBJECT 00468 public: 00469 CachedItemsJob(KDirLister* lister, const KUrl& url, bool reload); 00470 00471 /*reimp*/ void start() { QMetaObject::invokeMethod(this, "done", Qt::QueuedConnection); } 00472 00473 // For updateDirectory() to cancel m_emitCompleted; 00474 void setEmitCompleted(bool b) { m_emitCompleted = b; } 00475 00476 KUrl url() const { return m_url; } 00477 00478 protected: 00479 virtual bool doKill(); 00480 00481 public Q_SLOTS: 00482 void done(); 00483 00484 private: 00485 KDirLister* m_lister; 00486 KUrl m_url; 00487 bool m_reload; 00488 bool m_emitCompleted; 00489 }; 00490 00491 #endif
KDE 4.6 API Reference