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