1 /* This file is part of the KDE project
2 Copyright (C) 2002-2006 Michael Brade <brade@kde.org>
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #ifndef kdirlister_p_h
21 #define kdirlister_p_h
23 #include "kfileitem.h"
25 #include <QtCore/QMap>
26 #include <QtCore/QHash>
27 #include <QtCore/QCache>
28 #include <QtCore/QSet>
29 #include <QtCore/QTimer>
30 #include <QtGui/QWidget>
33 #include <kio/global.h>
34 #include <kdirwatch.h>
37 namespace KIO
{ class Job
; class ListJob
; }
38 class OrgKdeKDirNotifyInterface
;
39 struct KDirListerCacheDirectoryData
;
41 class KDirLister::Private
44 Private(KDirLister
*parent
)
51 autoErrorHandling
= false;
54 delayedMimeTypes
= false;
56 rootFileItem
= KFileItem();
60 lstMimeFilteredItems
= 0;
63 refreshItemWasFiltered
= false;
64 hasPendingChanges
= false;
70 void _k_emitCachedItems(const KUrl
&, bool, bool);
71 void _k_slotInfoMessage( KJob
*, const QString
& );
72 void _k_slotPercent( KJob
*, unsigned long );
73 void _k_slotTotalSize( KJob
*, qulonglong
);
74 void _k_slotProcessedSize( KJob
*, qulonglong
);
75 void _k_slotSpeed( KJob
*, unsigned long );
77 bool doMimeExcludeFilter( const QString
& mimeExclude
, const QStringList
& filters
) const;
78 void jobStarted( KIO::ListJob
* );
79 void connectJob( KIO::ListJob
* );
80 void jobDone( KIO::ListJob
* );
82 void addNewItem(const KUrl
& directoryUrl
, const KFileItem
& item
);
83 void addNewItems(const KUrl
& directoryUrl
, const KFileItemList
& items
);
84 void aboutToRefreshItem(const KFileItem
& item
);
85 void addRefreshItem(const KUrl
& directoryUrl
, const KFileItem
& oldItem
, const KFileItem
& item
);
87 void emitItemsDeleted(const KFileItemList
&items
);
90 * Redirect this dirlister from oldUrl to newUrl.
91 * @param keepItems if true, keep the fileitems (e.g. when renaming an existing dir);
92 * if false, clear out everything (e.g. when redirecting during listing).
94 void redirect(const KUrl
& oldUrl
, const KUrl
& newUrl
, bool keepItems
);
97 * Should this item be visible according to the current filter settings?
99 bool isItemVisible(const KFileItem
& item
) const;
101 void prepareForSettingsChange() {
102 if (!hasPendingChanges
) {
103 hasPendingChanges
= true;
104 oldSettings
= settings
;
111 KDirLister
*m_parent
;
114 * List of dirs handled by this dirlister. The first entry is the base URL.
115 * For a tree view, it contains all the dirs shown.
126 bool delayedMimeTypes
:1;
128 bool refreshItemWasFiltered
:1;
129 bool hasPendingChanges
:1; // i.e. settings != oldSettings
131 bool autoErrorHandling
:2;
132 QWidget
*errorParent
;
135 long unsigned int percent
, speed
;
136 KIO::filesize_t processedSize
, totalSize
;
139 QMap
<KIO::ListJob
*, JobData
> jobData
;
141 // file item for the root itself (".")
142 KFileItem rootFileItem
;
144 typedef QHash
<KUrl
, KFileItemList
> NewItemsHash
;
145 NewItemsHash
*lstNewItems
;
146 QList
<QPair
<KFileItem
,KFileItem
> > *lstRefreshItems
;
147 KFileItemList
*lstMimeFilteredItems
, *lstRemoveItems
;
149 QWidget
*window
; // Main window this lister is associated with
150 class CachedItemsJob
;
151 CachedItemsJob
* m_cachedItemsJob
;
153 QString nameFilter
; // parsed into lstFilters
155 struct FilterSettings
{
156 FilterSettings() : isShowingDotFiles(false), dirOnlyMode(false) {}
157 bool isShowingDotFiles
;
159 QList
<QRegExp
> lstFilters
;
160 QStringList mimeFilter
;
161 QStringList mimeExcludeFilter
;
163 FilterSettings settings
;
164 FilterSettings oldSettings
;
166 friend class KDirListerCache
;
170 * Design of the cache:
171 * There is a single KDirListerCache for the whole process.
172 * It holds all the items used by the dir listers (itemsInUse)
173 * as well as a cache of the recently used items (itemsCached).
174 * Those items are grouped by directory (a DirItem represents a whole directory).
176 * KDirListerCache also runs all the jobs for listing directories, whether they are for
177 * normal listing or for updates.
178 * For faster lookups, it also stores a hash table, which gives for a directory URL:
179 * - the dirlisters holding that URL (listersCurrentlyHolding)
180 * - the dirlisters currently listing that URL (listersCurrentlyListing)
182 class KDirListerCache
: public QObject
186 KDirListerCache(); // only called by K_GLOBAL_STATIC
189 void updateDirectory( const KUrl
& dir
);
191 KFileItem
itemForUrl( const KUrl
& url
) const;
192 KFileItemList
*itemsForDir(const KUrl
& dir
) const;
194 bool listDir( KDirLister
*lister
, const KUrl
& _url
, bool _keep
, bool _reload
);
196 // stop all running jobs for lister
197 void stop( KDirLister
*lister
, bool silent
= false );
198 // stop just the job listing url for lister
199 void stop( KDirLister
*lister
, const KUrl
&_url
, bool silent
= false );
201 void setAutoUpdate( KDirLister
*lister
, bool enable
);
203 void forgetDirs( KDirLister
*lister
);
204 void forgetDirs( KDirLister
*lister
, const KUrl
&_url
, bool notify
);
206 KFileItem
findByName( const KDirLister
*lister
, const QString
&_name
) const;
207 // findByUrl returns a pointer so that it's possible to modify the item.
208 // See itemForUrl for the version that returns a readonly kfileitem.
209 // @param lister can be 0. If set, it is checked that the url is held by the lister
210 KFileItem
*findByUrl(const KDirLister
*lister
, const KUrl
&url
) const;
212 // Called by CachedItemsJob:
213 // Emits those items, for this lister and this url
214 void emitItemsFromCache(KDirLister
* lister
, const KFileItemList
& lst
, const KFileItem
& rootItem
,
215 const KUrl
& _url
, bool _reload
, bool _emitCompleted
);
219 * Notify that files have been added in @p directory
220 * The receiver will list that directory again to find
221 * the new items (since it needs more than just the names anyway).
222 * Connected to the DBus signal from the KDirNotify interface.
224 void slotFilesAdded( const QString
& urlDirectory
);
227 * Notify that files have been deleted.
228 * This call passes the exact urls of the deleted files
229 * so that any view showing them can simply remove them
230 * or be closed (if its current dir was deleted)
231 * Connected to the DBus signal from the KDirNotify interface.
233 void slotFilesRemoved( const QStringList
& fileList
);
236 * Notify that files have been changed.
237 * At the moment, this is only used for new icon, but it could be
238 * used for size etc. as well.
239 * Connected to the DBus signal from the KDirNotify interface.
241 void slotFilesChanged( const QStringList
& fileList
);
242 void slotFileRenamed( const QString
& srcUrl
, const QString
& dstUrl
);
245 void slotFileDirty( const QString
&_file
);
246 void slotFileCreated( const QString
&_file
);
247 void slotFileDeleted( const QString
&_file
);
249 void slotEntries( KIO::Job
*job
, const KIO::UDSEntryList
&entries
);
250 void slotResult( KJob
*j
);
251 void slotRedirection( KIO::Job
*job
, const KUrl
&url
);
253 void slotUpdateEntries( KIO::Job
*job
, const KIO::UDSEntryList
&entries
);
254 void slotUpdateResult( KJob
*job
);
255 void processPendingUpdates();
259 DirItem
* dirItemForUrl(const KUrl
& dir
) const;
261 bool validUrl( const KDirLister
*lister
, const KUrl
& _url
) const;
263 // helper for both stop methods
264 void stopLister(KDirLister
* lister
, const QString
& url
, KDirListerCacheDirectoryData
& dirData
, bool silent
);
266 KIO::ListJob
*jobForUrl( const QString
& url
, KIO::ListJob
*not_job
= 0 );
267 const KUrl
& joburl( KIO::ListJob
*job
);
269 void killJob( KIO::ListJob
*job
);
271 // Called when something tells us that the directory @p url has changed.
272 // Returns true if @p url is held by some lister (meaning: do the update now)
273 // otherwise mark the cached item as not-up-to-date for later and return false
274 bool checkUpdate( const QString
& url
);
276 // when there were items deleted from the filesystem all the listers holding
277 // the parent directory need to be notified, the unmarked items have to be deleted
278 // and removed from the cache including all the children.
279 void deleteUnmarkedItems( const QList
<KDirLister
*>&, KFileItemList
& );
280 // Helper method called when we know that a list of items was deleted
281 void itemsDeleted(const QList
<KDirLister
*>& listers
, const KFileItemList
& deletedItems
);
282 void slotFilesRemoved(const KUrl::List
& urls
);
283 // common for slotRedirection and slotFileRenamed
284 void renameDir( const KUrl
&oldUrl
, const KUrl
&url
);
285 // common for deleteUnmarkedItems and slotFilesRemoved
286 void deleteDir( const KUrl
& dirUrl
);
287 // remove directory from cache (itemsCached), including all child dirs
288 void removeDirFromCache( const KUrl
& dir
);
289 // helper for renameDir
290 void emitRedirections( const KUrl
&oldUrl
, const KUrl
&url
);
292 void aboutToRefreshItem( const KFileItem
& fileitem
);
295 * Emits refreshItem() in the directories that cared for oldItem.
297 void emitRefreshItem(const KFileItem
& oldItem
, const KFileItem
& fileitem
);
306 DirItem( const KUrl
&dir
)
317 if ( KDirWatch::exists() && url
.isLocalFile() )
318 KDirWatch::self()->removeDir( url
.path() );
319 sendSignal( false, url
);
324 void sendSignal( bool entering
, const KUrl
& url
)
326 // Note that "entering" means "start watching", and "leaving" means "stop watching"
327 // (i.e. it's not when the user leaves the directory, it's when the directory is removed from the cache)
329 org::kde::KDirNotify::emitEnteredDirectory( url
.url() );
331 org::kde::KDirNotify::emitLeftDirectory( url
.url() );
334 void redirect( const KUrl
& newUrl
)
338 if ( url
.isLocalFile() )
339 KDirWatch::self()->removeDir( url
.path() );
340 sendSignal( false, url
);
342 if ( newUrl
.isLocalFile() )
343 KDirWatch::self()->addDir( newUrl
.path() );
344 sendSignal( true, newUrl
);
349 if ( !rootItem
.isNull() )
350 rootItem
.setUrl( newUrl
);
355 if ( autoUpdates
++ == 0 )
357 if ( url
.isLocalFile() )
358 KDirWatch::self()->addDir( url
.path() );
359 sendSignal( true, url
);
365 if ( --autoUpdates
== 0 )
367 if ( url
.isLocalFile() )
368 KDirWatch::self()->removeDir( url
.path() );
369 sendSignal( false, url
);
372 else if ( autoUpdates
< 0 )
376 // number of KDirListers using autoUpdate for this dir
379 // this directory is up-to-date
382 // the complete url of this directory
385 // KFileItem representing the root of this directory.
386 // Remember that this is optional. FTP sites don't return '.' in
387 // the list, so they give no root item
389 KFileItemList lstItems
;
392 //static const unsigned short MAX_JOBS_PER_LISTER;
394 QMap
<KIO::ListJob
*, KIO::UDSEntryList
> runningListJobs
;
396 // an item is a complete directory
397 QHash
<QString
/*url*/, DirItem
*> itemsInUse
;
398 QCache
<QString
/*url*/, DirItem
> itemsCached
;
400 typedef QHash
<QString
/*url*/, KDirListerCacheDirectoryData
> DirectoryDataHash
;
401 DirectoryDataHash directoryData
;
403 // Set of local files that we have changed recently (according to KDirWatch)
404 // We temporize the notifications by keeping them 500ms in this list.
405 QSet
<QString
/*url*/> pendingUpdates
;
406 // The timer for doing the delayed updates
407 QTimer pendingUpdateTimer
;
409 // Set of remote files that have changed recently -- but we can't emit those
410 // changes yet, we need to wait for the "update" directory listing.
411 // The cmp() call can't differ mimetypes since they are determined on demand,
412 // this is why we need to remember those files here.
413 QSet
<KFileItem
*> pendingRemoteUpdates
;
415 // the KDirNotify signals
416 OrgKdeKDirNotifyInterface
*kdirnotify
;
418 struct ItemInUseChange
;
421 // Data associated with a directory url
422 // This could be in DirItem but only in the itemsInUse dict...
423 struct KDirListerCacheDirectoryData
425 // A lister can be EITHER in listersCurrentlyListing OR listersCurrentlyHolding
426 // but NOT in both at the same time.
427 // But both lists can have different listers at the same time; this
428 // happens if more listers are requesting url at the same time and
429 // one lister was stopped during the listing of files.
431 // Listers that are currently listing this url
432 QList
<KDirLister
*> listersCurrentlyListing
;
433 // Listers that are currently holding this url
434 QList
<KDirLister
*> listersCurrentlyHolding
;
436 void moveListersWithoutCachedItemsJob();
439 //const unsigned short KDirListerCache::MAX_JOBS_PER_LISTER = 5;
441 // This job tells KDirListerCache to emit cached items asynchronously from listDir()
442 // to give the KDirLister user enough time for connecting to its signals, and so
443 // that KDirListerCache behaves just like when a real KIO::Job is used: nothing
444 // is emitted during the openUrl call itself.
445 class KDirLister::Private::CachedItemsJob
: public KJob
{
448 CachedItemsJob(KDirLister
* lister
, const KFileItemList
& items
, const KFileItem
& rootItem
,
449 const KUrl
& url
, bool reload
)
451 m_lister(lister
), m_url(url
),
452 m_items(items
), m_rootItem(rootItem
),
453 m_reload(reload
), m_emitCompleted(true) {
454 Q_ASSERT(lister
->d
->m_cachedItemsJob
== 0);
455 lister
->d
->m_cachedItemsJob
= this;
460 /*reimp*/ void start() { QMetaObject::invokeMethod(this, "done", Qt::QueuedConnection
); }
462 // For updateDirectory() to cancel m_emitCompleted;
463 void setEmitCompleted(bool b
) { m_emitCompleted
= b
; }
465 KUrl
url() const { return m_url
; }
471 KDirLister
* m_lister
;
473 KFileItemList m_items
;
474 KFileItem m_rootItem
;
476 bool m_emitCompleted
;