• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KIO

  • kio
  • kio
kdirlister.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3 2000 Carsten Pfeiffer <pfeiffer@kde.org>
4 2003-2005 David Faure <faure@kde.org>
5 2001-2006 Michael Brade <brade@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#include "kdirlister.h"
24#include "kdirlister_p.h"
25
26#include <QtCore/QRegExp>
27
28#include <kdebug.h>
29#include <kde_file.h>
30#include <klocale.h>
31#include <kio/job.h>
32#include <kio/jobuidelegate.h>
33#include <kmessagebox.h>
34#include "kprotocolmanager.h"
35#include "kmountpoint.h"
36
37#include <QFile>
38
39// Enable this to get printDebug() called often, to see the contents of the cache
40//#define DEBUG_CACHE
41
42// Make really sure it doesn't get activated in the final build
43#ifdef NDEBUG
44#undef DEBUG_CACHE
45#endif
46
47K_GLOBAL_STATIC(KDirListerCache, kDirListerCache)
48
49KDirListerCache::KDirListerCache()
50 : itemsCached( 10 ) // keep the last 10 directories around
51{
52 //kDebug(7004);
53
54 connect( &pendingUpdateTimer, SIGNAL(timeout()), this, SLOT(processPendingUpdates()) );
55 pendingUpdateTimer.setSingleShot( true );
56
57 connect( KDirWatch::self(), SIGNAL(dirty(QString)),
58 this, SLOT(slotFileDirty(QString)) );
59 connect( KDirWatch::self(), SIGNAL(created(QString)),
60 this, SLOT(slotFileCreated(QString)) );
61 connect( KDirWatch::self(), SIGNAL(deleted(QString)),
62 this, SLOT(slotFileDeleted(QString)) );
63
64 kdirnotify = new org::kde::KDirNotify(QString(), QString(), QDBusConnection::sessionBus(), this);
65 connect(kdirnotify, SIGNAL(FileRenamed(QString,QString)), SLOT(slotFileRenamed(QString,QString)));
66 connect(kdirnotify, SIGNAL(FilesAdded(QString)), SLOT(slotFilesAdded(QString)));
67 connect(kdirnotify, SIGNAL(FilesChanged(QStringList)), SLOT(slotFilesChanged(QStringList)));
68 connect(kdirnotify, SIGNAL(FilesRemoved(QStringList)), SLOT(slotFilesRemoved(QStringList)));
69
70 // The use of KUrl::url() in ~DirItem (sendSignal) crashes if the static for QRegExpEngine got deleted already,
71 // so we need to destroy the KDirListerCache before that.
72 qAddPostRoutine(kDirListerCache.destroy);
73}
74
75KDirListerCache::~KDirListerCache()
76{
77 //kDebug(7004);
78
79 qDeleteAll(itemsInUse);
80 itemsInUse.clear();
81
82 itemsCached.clear();
83 directoryData.clear();
84
85 if ( KDirWatch::exists() )
86 KDirWatch::self()->disconnect( this );
87}
88
89// setting _reload to true will emit the old files and
90// call updateDirectory
91bool KDirListerCache::listDir( KDirLister *lister, const KUrl& _u,
92 bool _keep, bool _reload )
93{
94 KUrl _url(_u);
95 _url.cleanPath(); // kill consecutive slashes
96
97 if (!_url.host().isEmpty() && KProtocolInfo::protocolClass(_url.protocol()) == ":local"
98 && _url.protocol() != "file") {
99 // ":local" protocols ignore the hostname, so strip it out preventively - #160057
100 // kio_file is special cased since it does honor the hostname (by redirecting to e.g. smb)
101 _url.setHost(QString());
102 if (_keep == false)
103 emit lister->redirection(_url);
104 }
105
106 // like this we don't have to worry about trailing slashes any further
107 _url.adjustPath(KUrl::RemoveTrailingSlash);
108
109 const QString urlStr = _url.url();
110
111 QString resolved;
112 if (_url.isLocalFile()) {
113 // Resolve symlinks (#213799)
114 const QString local = _url.toLocalFile();
115 resolved = QFileInfo(local).canonicalFilePath();
116 if (local != resolved)
117 canonicalUrls[resolved].append(urlStr);
118 // TODO: remove entry from canonicalUrls again in forgetDirs
119 // Note: this is why we use a QStringList value in there rather than a QSet:
120 // we can just remove one entry and not have to worry about other dirlisters
121 // (the non-unicity of the stringlist gives us the refcounting, basically).
122 }
123
124 if (!validUrl(lister, _url)) {
125 kDebug(7004) << lister << "url=" << _url << "not a valid url";
126 return false;
127 }
128
129 //kDebug(7004) << lister << "url=" << _url << "keep=" << _keep << "reload=" << _reload;
130#ifdef DEBUG_CACHE
131 printDebug();
132#endif
133
134 if (!_keep) {
135 // stop any running jobs for lister
136 stop(lister, true /*silent*/);
137
138 // clear our internal list for lister
139 forgetDirs(lister);
140
141 lister->d->rootFileItem = KFileItem();
142 } else if (lister->d->lstDirs.contains(_url)) {
143 // stop the job listing _url for this lister
144 stopListingUrl(lister, _url, true /*silent*/);
145
146 // remove the _url as well, it will be added in a couple of lines again!
147 // forgetDirs with three args does not do this
148 // TODO: think about moving this into forgetDirs
149 lister->d->lstDirs.removeAll(_url);
150
151 // clear _url for lister
152 forgetDirs(lister, _url, true);
153
154 if (lister->d->url == _url)
155 lister->d->rootFileItem = KFileItem();
156 }
157
158 lister->d->complete = false;
159
160 lister->d->lstDirs.append(_url);
161
162 if (lister->d->url.isEmpty() || !_keep) // set toplevel URL only if not set yet
163 lister->d->url = _url;
164
165 DirItem *itemU = itemsInUse.value(urlStr);
166
167 KDirListerCacheDirectoryData& dirData = directoryData[urlStr]; // find or insert
168
169 if (dirData.listersCurrentlyListing.isEmpty()) {
170 // if there is an update running for _url already we get into
171 // the following case - it will just be restarted by updateDirectory().
172
173 dirData.listersCurrentlyListing.append(lister);
174
175 DirItem *itemFromCache = 0;
176 if (itemU || (!_reload && (itemFromCache = itemsCached.take(urlStr)) ) ) {
177 if (itemU) {
178 kDebug(7004) << "Entry already in use:" << _url;
179 // if _reload is set, then we'll emit cached items and then updateDirectory.
180 } else {
181 kDebug(7004) << "Entry in cache:" << _url;
182 itemsInUse.insert(urlStr, itemFromCache);
183 itemU = itemFromCache;
184 }
185 if (lister->d->autoUpdate) {
186 itemU->incAutoUpdate();
187 }
188 if (itemFromCache && itemFromCache->watchedWhileInCache) {
189 itemFromCache->watchedWhileInCache = false;;
190 itemFromCache->decAutoUpdate();
191 }
192
193 emit lister->started(_url);
194
195 // List items from the cache in a delayed manner, just like things would happen
196 // if we were not using the cache.
197 new KDirLister::Private::CachedItemsJob(lister, _url, _reload);
198
199 } else {
200 // dir not in cache or _reload is true
201 if (_reload) {
202 kDebug(7004) << "Reloading directory:" << _url;
203 itemsCached.remove(urlStr);
204 } else {
205 kDebug(7004) << "Listing directory:" << _url;
206 }
207
208 itemU = new DirItem(_url, resolved);
209 itemsInUse.insert(urlStr, itemU);
210 if (lister->d->autoUpdate)
211 itemU->incAutoUpdate();
212
213// // we have a limit of MAX_JOBS_PER_LISTER concurrently running jobs
214// if ( lister->d->numJobs() >= MAX_JOBS_PER_LISTER )
215// {
216// pendingUpdates.insert( _url );
217// }
218// else
219 {
220 KIO::ListJob* job = KIO::listDir(_url, KIO::HideProgressInfo);
221 runningListJobs.insert(job, KIO::UDSEntryList());
222
223 lister->d->jobStarted(job);
224 lister->d->connectJob(job);
225
226 if (lister->d->window)
227 job->ui()->setWindow(lister->d->window);
228
229 connect(job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)),
230 this, SLOT(slotEntries(KIO::Job*,KIO::UDSEntryList)));
231 connect(job, SIGNAL(result(KJob*)),
232 this, SLOT(slotResult(KJob*)));
233 connect(job, SIGNAL(redirection(KIO::Job*,KUrl)),
234 this, SLOT(slotRedirection(KIO::Job*,KUrl)));
235
236 emit lister->started(_url);
237 }
238 //kDebug(7004) << "Entry now being listed by" << dirData.listersCurrentlyListing;
239 }
240 } else {
241
242 kDebug(7004) << "Entry currently being listed:" << _url << "by" << dirData.listersCurrentlyListing;
243#ifdef DEBUG_CACHE
244 printDebug();
245#endif
246
247 emit lister->started( _url );
248
249 // Maybe listersCurrentlyListing/listersCurrentlyHolding should be QSets?
250 Q_ASSERT(!dirData.listersCurrentlyListing.contains(lister));
251 dirData.listersCurrentlyListing.append( lister );
252
253 KIO::ListJob *job = jobForUrl( urlStr );
254 // job will be 0 if we were listing from cache rather than listing from a kio job.
255 if( job ) {
256 lister->d->jobStarted( job );
257 lister->d->connectJob( job );
258 }
259 Q_ASSERT( itemU );
260
261 // List existing items in a delayed manner, just like things would happen
262 // if we were not using the cache.
263 kDebug(7004) << "Listing" << itemU->lstItems.count() << "cached items soon";
264 KDirLister::Private::CachedItemsJob *cachedItemsJob = new KDirLister::Private::CachedItemsJob(lister, _url, _reload);
265
266 if (job) {
267 // The ListJob will take care of emitting completed.
268 // ### If it finishes before the CachedItemsJob, then we'll emit cached items after completed(), not sure how bad this is.
269 cachedItemsJob->setEmitCompleted(false);
270 }
271
272
273#ifdef DEBUG_CACHE
274 printDebug();
275#endif
276 }
277
278 return true;
279}
280
281KDirLister::Private::CachedItemsJob* KDirLister::Private::cachedItemsJobForUrl(const KUrl& url) const
282{
283 Q_FOREACH(CachedItemsJob* job, m_cachedItemsJobs) {
284 if (job->url() == url)
285 return job;
286 }
287 return 0;
288}
289
290KDirLister::Private::CachedItemsJob::CachedItemsJob(KDirLister* lister, const KUrl& url, bool reload)
291 : KJob(lister),
292 m_lister(lister), m_url(url),
293 m_reload(reload), m_emitCompleted(true)
294{
295 //kDebug() << "Creating CachedItemsJob" << this << "for lister" << lister << url;
296 if (lister->d->cachedItemsJobForUrl(url)) {
297 kWarning(7004) << "Lister" << lister << "has a cached items job already for" << url;
298 }
299 lister->d->m_cachedItemsJobs.append(this);
300 setAutoDelete(true);
301 start();
302}
303
304// Called by start() via QueuedConnection
305void KDirLister::Private::CachedItemsJob::done()
306{
307 if (!m_lister) // job was already killed, but waiting deletion due to deleteLater
308 return;
309 kDirListerCache->emitItemsFromCache(this, m_lister, m_url, m_reload, m_emitCompleted);
310 emitResult();
311}
312
313bool KDirLister::Private::CachedItemsJob::doKill()
314{
315 //kDebug(7004) << this;
316 kDirListerCache->forgetCachedItemsJob(this, m_lister, m_url);
317 if (!property("_kdlc_silent").toBool()) {
318 emit m_lister->canceled(m_url);
319 emit m_lister->canceled();
320 }
321 m_lister = 0;
322 return true;
323}
324
325void KDirListerCache::emitItemsFromCache(KDirLister::Private::CachedItemsJob* cachedItemsJob, KDirLister* lister, const KUrl& _url, bool _reload, bool _emitCompleted)
326{
327 const QString urlStr = _url.url();
328 KDirLister::Private* kdl = lister->d;
329 kdl->complete = false;
330
331 DirItem *itemU = kDirListerCache->itemsInUse.value(urlStr);
332 if (!itemU) {
333 kWarning(7004) << "Can't find item for directory" << urlStr << "anymore";
334 } else {
335 const KFileItemList items = itemU->lstItems;
336 const KFileItem rootItem = itemU->rootItem;
337 _reload = _reload || !itemU->complete;
338
339 if (kdl->rootFileItem.isNull() && !rootItem.isNull() && kdl->url == _url) {
340 kdl->rootFileItem = rootItem;
341 }
342 if (!items.isEmpty()) {
343 //kDebug(7004) << "emitting" << items.count() << "for lister" << lister;
344 kdl->addNewItems(_url, items);
345 kdl->emitItems();
346 }
347 }
348
349 forgetCachedItemsJob(cachedItemsJob, lister, _url);
350
351 // Emit completed, unless we were told not to,
352 // or if listDir() was called while another directory listing for this dir was happening,
353 // so we "joined" it. We detect that using jobForUrl to ensure it's a real ListJob,
354 // not just a lister-specific CachedItemsJob (which wouldn't emit completed for us).
355 if (_emitCompleted) {
356
357 kdl->complete = true;
358 emit lister->completed( _url );
359 emit lister->completed();
360
361 if ( _reload ) {
362 updateDirectory( _url );
363 }
364 }
365}
366
367void KDirListerCache::forgetCachedItemsJob(KDirLister::Private::CachedItemsJob* cachedItemsJob, KDirLister* lister, const KUrl& _url)
368{
369 // Modifications to data structures only below this point;
370 // so that addNewItems is called with a consistent state
371
372 const QString urlStr = _url.url();
373 lister->d->m_cachedItemsJobs.removeAll(cachedItemsJob);
374
375 KDirListerCacheDirectoryData& dirData = directoryData[urlStr];
376 Q_ASSERT(dirData.listersCurrentlyListing.contains(lister));
377
378 KIO::ListJob *listJob = jobForUrl(urlStr);
379 if (!listJob) {
380 Q_ASSERT(!dirData.listersCurrentlyHolding.contains(lister));
381 //kDebug(7004) << "Moving from listing to holding, because no more job" << lister << urlStr;
382 dirData.listersCurrentlyHolding.append( lister );
383 dirData.listersCurrentlyListing.removeAll( lister );
384 } else {
385 //kDebug(7004) << "Still having a listjob" << listJob << ", so not moving to currently-holding.";
386 }
387}
388
389bool KDirListerCache::validUrl( const KDirLister *lister, const KUrl& url ) const
390{
391 if ( !url.isValid() )
392 {
393 if ( lister->d->autoErrorHandling )
394 {
395 QString tmp = i18n("Malformed URL\n%1", url.prettyUrl() );
396 KMessageBox::error( lister->d->errorParent, tmp );
397 }
398 return false;
399 }
400
401 if ( !KProtocolManager::supportsListing( url ) )
402 {
403 if ( lister->d->autoErrorHandling )
404 {
405 QString tmp = i18n("URL cannot be listed\n%1", url.prettyUrl() );
406 KMessageBox::error( lister->d->errorParent, tmp );
407 }
408 return false;
409 }
410
411 return true;
412}
413
414void KDirListerCache::stop( KDirLister *lister, bool silent )
415{
416#ifdef DEBUG_CACHE
417 //printDebug();
418#endif
419 //kDebug(7004) << "lister:" << lister << "silent=" << silent;
420
421 const KUrl::List urls = lister->d->lstDirs;
422 Q_FOREACH(const KUrl& url, urls) {
423 stopListingUrl(lister, url, silent);
424 }
425
426#if 0 // test code
427 QHash<QString,KDirListerCacheDirectoryData>::iterator dirit = directoryData.begin();
428 const QHash<QString,KDirListerCacheDirectoryData>::iterator dirend = directoryData.end();
429 for( ; dirit != dirend ; ++dirit ) {
430 KDirListerCacheDirectoryData& dirData = dirit.value();
431 if (dirData.listersCurrentlyListing.contains(lister)) {
432 kDebug(7004) << "ERROR: found lister" << lister << "in list - for" << dirit.key();
433 Q_ASSERT(false);
434 }
435 }
436#endif
437}
438
439void KDirListerCache::stopListingUrl(KDirLister *lister, const KUrl& _u, bool silent)
440{
441 KUrl url(_u);
442 url.adjustPath( KUrl::RemoveTrailingSlash );
443 const QString urlStr = url.url();
444
445 KDirLister::Private::CachedItemsJob* cachedItemsJob = lister->d->cachedItemsJobForUrl(url);
446 if (cachedItemsJob) {
447 if (silent) {
448 cachedItemsJob->setProperty("_kdlc_silent", true);
449 }
450 cachedItemsJob->kill(); // removes job from list, too
451 }
452
453 // TODO: consider to stop all the "child jobs" of url as well
454 kDebug(7004) << lister << " url=" << url;
455
456 QHash<QString,KDirListerCacheDirectoryData>::iterator dirit = directoryData.find(urlStr);
457 if (dirit == directoryData.end())
458 return;
459 KDirListerCacheDirectoryData& dirData = dirit.value();
460 if (dirData.listersCurrentlyListing.contains(lister)) {
461 //kDebug(7004) << " found lister" << lister << "in list - for" << urlStr;
462 if (dirData.listersCurrentlyListing.count() == 1) {
463 // This was the only dirlister interested in the list job -> kill the job
464 stopListJob(urlStr, silent);
465 } else {
466 // Leave the job running for the other dirlisters, just unsubscribe us.
467 dirData.listersCurrentlyListing.removeAll(lister);
468 if (!silent) {
469 emit lister->canceled();
470 emit lister->canceled(url);
471 }
472 }
473 }
474}
475
476// Helper for stop() and stopListingUrl()
477void KDirListerCache::stopListJob(const QString& url, bool silent)
478{
479 // Old idea: if it's an update job, let's just leave the job running.
480 // After all, update jobs do run for "listersCurrentlyHolding",
481 // so there's no reason to kill them just because @p lister is now a holder.
482
483 // However it could be a long-running non-local job (e.g. filenamesearch), which
484 // the user wants to abort, and which will never be used for updating...
485 // And in any case slotEntries/slotResult is not meant to be called by update jobs.
486 // So, change of plan, let's kill it after all, in a way that triggers slotResult/slotUpdateResult.
487
488 KIO::ListJob *job = jobForUrl(url);
489 if (job) {
490 //kDebug() << "Killing list job" << job << "for" << url;
491 if (silent) {
492 job->setProperty("_kdlc_silent", true);
493 }
494 job->kill(KJob::EmitResult);
495 }
496}
497
498void KDirListerCache::setAutoUpdate( KDirLister *lister, bool enable )
499{
500 // IMPORTANT: this method does not check for the current autoUpdate state!
501
502 for ( KUrl::List::const_iterator it = lister->d->lstDirs.constBegin();
503 it != lister->d->lstDirs.constEnd(); ++it ) {
504 DirItem* dirItem = itemsInUse.value((*it).url());
505 Q_ASSERT(dirItem);
506 if ( enable )
507 dirItem->incAutoUpdate();
508 else
509 dirItem->decAutoUpdate();
510 }
511}
512
513void KDirListerCache::forgetDirs( KDirLister *lister )
514{
515 //kDebug(7004) << lister;
516
517 emit lister->clear();
518 // clear lister->d->lstDirs before calling forgetDirs(), so that
519 // it doesn't contain things that itemsInUse doesn't. When emitting
520 // the canceled signals, lstDirs must not contain anything that
521 // itemsInUse does not contain. (otherwise it might crash in findByName()).
522 const KUrl::List lstDirsCopy = lister->d->lstDirs;
523 lister->d->lstDirs.clear();
524
525 //kDebug() << "Iterating over dirs" << lstDirsCopy;
526 for ( KUrl::List::const_iterator it = lstDirsCopy.begin();
527 it != lstDirsCopy.end(); ++it ) {
528 forgetDirs( lister, *it, false );
529 }
530}
531
532static bool manually_mounted(const QString& path, const KMountPoint::List& possibleMountPoints)
533{
534 KMountPoint::Ptr mp = possibleMountPoints.findByPath(path);
535 if (!mp) { // not listed in fstab -> yes, manually mounted
536 if (possibleMountPoints.isEmpty()) // no fstab at all -> don't assume anything
537 return false;
538 return true;
539 }
540 const bool supermount = mp->mountType() == "supermount";
541 if (supermount) {
542 return true;
543 }
544 // noauto -> manually mounted. Otherwise, mounted at boot time, won't be unmounted any time soon hopefully.
545 return mp->mountOptions().contains("noauto");
546}
547
548
549void KDirListerCache::forgetDirs( KDirLister *lister, const KUrl& _url, bool notify )
550{
551 //kDebug(7004) << lister << " _url: " << _url;
552
553 KUrl url( _url );
554 url.adjustPath( KUrl::RemoveTrailingSlash );
555 const QString urlStr = url.url();
556
557 DirectoryDataHash::iterator dit = directoryData.find(urlStr);
558 if (dit == directoryData.end())
559 return;
560 KDirListerCacheDirectoryData& dirData = *dit;
561 dirData.listersCurrentlyHolding.removeAll(lister);
562
563 // This lister doesn't care for updates running in <url> anymore
564 KIO::ListJob *job = jobForUrl(urlStr);
565 if (job)
566 lister->d->jobDone(job);
567
568 DirItem *item = itemsInUse.value(urlStr);
569 Q_ASSERT(item);
570 bool insertIntoCache = false;
571
572 if ( dirData.listersCurrentlyHolding.isEmpty() && dirData.listersCurrentlyListing.isEmpty() ) {
573 // item not in use anymore -> move into cache if complete
574 directoryData.erase(dit);
575 itemsInUse.remove( urlStr );
576
577 // this job is a running update which nobody cares about anymore
578 if ( job ) {
579 killJob( job );
580 kDebug(7004) << "Killing update job for " << urlStr;
581
582 // Well, the user of KDirLister doesn't really care that we're stopping
583 // a background-running job from a previous URL (in listDir) -> commented out.
584 // stop() already emitted canceled.
585 //emit lister->canceled( url );
586 if ( lister->d->numJobs() == 0 ) {
587 lister->d->complete = true;
588 //emit lister->canceled();
589 }
590 }
591
592 if ( notify ) {
593 lister->d->lstDirs.removeAll( url );
594 emit lister->clear( url );
595 }
596
597 insertIntoCache = item->complete;
598 if (insertIntoCache) {
599 // TODO(afiestas): remove use of KMountPoint+manually_mounted and port to Solid:
600 // 1) find Volume for the local path "item->url.toLocalFile()" (which could be anywhere
601 // under the mount point) -- probably needs a new operator in libsolid query parser
602 // 2) [**] becomes: if (Drive is hotpluggable or Volume is removable) "set to dirty" else "keep watch"
603 const KMountPoint::List possibleMountPoints = KMountPoint::possibleMountPoints(KMountPoint::NeedMountOptions);
604
605 // Should we forget the dir for good, or keep a watch on it?
606 // Generally keep a watch, except when it would prevent
607 // unmounting a removable device (#37780)
608 const bool isLocal = item->url.isLocalFile();
609 bool isManuallyMounted = false;
610 bool containsManuallyMounted = false;
611 if (isLocal) {
612 isManuallyMounted = manually_mounted( item->url.toLocalFile(), possibleMountPoints );
613 if ( !isManuallyMounted ) {
614 // Look for a manually-mounted directory inside
615 // If there's one, we can't keep a watch either, FAM would prevent unmounting the CDROM
616 // I hope this isn't too slow
617 KFileItemList::const_iterator kit = item->lstItems.constBegin();
618 KFileItemList::const_iterator kend = item->lstItems.constEnd();
619 for ( ; kit != kend && !containsManuallyMounted; ++kit )
620 if ( (*kit).isDir() && manually_mounted((*kit).url().toLocalFile(), possibleMountPoints) )
621 containsManuallyMounted = true;
622 }
623 }
624
625 if ( isManuallyMounted || containsManuallyMounted ) // [**]
626 {
627 kDebug(7004) << "Not adding a watch on " << item->url << " because it " <<
628 ( isManuallyMounted ? "is manually mounted" : "contains a manually mounted subdir" );
629 item->complete = false; // set to "dirty"
630 } else {
631 item->incAutoUpdate(); // keep watch
632 item->watchedWhileInCache = true;
633 }
634 }
635 else
636 {
637 delete item;
638 item = 0;
639 }
640 }
641
642 if ( item && lister->d->autoUpdate )
643 item->decAutoUpdate();
644
645 // Inserting into QCache must be done last, since it might delete the item
646 if (item && insertIntoCache) {
647 kDebug(7004) << lister << "item moved into cache:" << url;
648 itemsCached.insert(urlStr, item);
649 }
650}
651
652void KDirListerCache::updateDirectory( const KUrl& _dir )
653{
654 kDebug(7004) << _dir;
655
656 QString urlStr = _dir.url(KUrl::RemoveTrailingSlash);
657 if (!checkUpdate(urlStr)) {
658 if (_dir.isLocalFile() && findByUrl(0, _dir)) {
659 pendingUpdates.insert(_dir.toLocalFile());
660 if (!pendingUpdateTimer.isActive())
661 pendingUpdateTimer.start(500);
662 }
663 return;
664 }
665
666 // A job can be running to
667 // - only list a new directory: the listers are in listersCurrentlyListing
668 // - only update a directory: the listers are in listersCurrentlyHolding
669 // - update a currently running listing: the listers are in both
670
671 KDirListerCacheDirectoryData& dirData = directoryData[urlStr];
672 QList<KDirLister *> listers = dirData.listersCurrentlyListing;
673 QList<KDirLister *> holders = dirData.listersCurrentlyHolding;
674
675 //kDebug(7004) << urlStr << "listers=" << listers << "holders=" << holders;
676
677 // restart the job for _dir if it is running already
678 bool killed = false;
679 QWidget *window = 0;
680 KIO::ListJob *job = jobForUrl( urlStr );
681 if (job) {
682 window = job->ui()->window();
683
684 killJob( job );
685 killed = true;
686
687 foreach ( KDirLister *kdl, listers )
688 kdl->d->jobDone( job );
689
690 foreach ( KDirLister *kdl, holders )
691 kdl->d->jobDone( job );
692 } else {
693 // Emit any cached items.
694 // updateDirectory() is about the diff compared to the cached items...
695 Q_FOREACH(KDirLister *kdl, listers) {
696 KDirLister::Private::CachedItemsJob* cachedItemsJob = kdl->d->cachedItemsJobForUrl(_dir);
697 if (cachedItemsJob) {
698 cachedItemsJob->setEmitCompleted(false);
699 cachedItemsJob->done(); // removes from cachedItemsJobs list
700 delete cachedItemsJob;
701 killed = true;
702 }
703 }
704 }
705 //kDebug(7004) << "Killed=" << killed;
706
707 // we don't need to emit canceled signals since we only replaced the job,
708 // the listing is continuing.
709
710 if (!(listers.isEmpty() || killed)) {
711 kWarning() << "The unexpected happened.";
712 kWarning() << "listers for" << _dir << "=" << listers;
713 kWarning() << "job=" << job;
714 Q_FOREACH(KDirLister *kdl, listers) {
715 kDebug() << "lister" << kdl << "m_cachedItemsJobs=" << kdl->d->m_cachedItemsJobs;
716 }
717#ifndef NDEBUG
718 printDebug();
719#endif
720 }
721 Q_ASSERT( listers.isEmpty() || killed );
722
723 job = KIO::listDir( _dir, KIO::HideProgressInfo );
724 runningListJobs.insert( job, KIO::UDSEntryList() );
725
726 connect( job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)),
727 this, SLOT(slotUpdateEntries(KIO::Job*,KIO::UDSEntryList)) );
728 connect( job, SIGNAL(result(KJob*)),
729 this, SLOT(slotUpdateResult(KJob*)) );
730
731 kDebug(7004) << "update started in" << _dir;
732
733 foreach ( KDirLister *kdl, listers ) {
734 kdl->d->jobStarted( job );
735 }
736
737 if ( !holders.isEmpty() ) {
738 if ( !killed ) {
739 bool first = true;
740 foreach ( KDirLister *kdl, holders ) {
741 kdl->d->jobStarted( job );
742 if ( first && kdl->d->window ) {
743 first = false;
744 job->ui()->setWindow( kdl->d->window );
745 }
746 emit kdl->started( _dir );
747 }
748 } else {
749 job->ui()->setWindow( window );
750
751 foreach ( KDirLister *kdl, holders ) {
752 kdl->d->jobStarted( job );
753 }
754 }
755 }
756}
757
758bool KDirListerCache::checkUpdate( const QString& _dir )
759{
760 if ( !itemsInUse.contains(_dir) )
761 {
762 DirItem *item = itemsCached[_dir];
763 if ( item && item->complete )
764 {
765 // Stop watching items once they are only in the cache and not used anymore.
766 // We'll trigger an update when listing that dir again later.
767 item->complete = false;
768 item->watchedWhileInCache = false;
769 item->decAutoUpdate();
770 // Hmm, this debug output might include login/password from the _dir URL.
771 //kDebug(7004) << "directory " << _dir << " not in use, marked dirty.";
772 }
773 //else
774 //kDebug(7004) << "aborted, directory " << _dir << " not in cache.";
775
776 return false;
777 }
778 else
779 return true;
780}
781
782KFileItem KDirListerCache::itemForUrl( const KUrl& url ) const
783{
784 KFileItem *item = findByUrl( 0, url );
785 if (item) {
786 return *item;
787 } else {
788 return KFileItem();
789 }
790}
791
792KDirListerCache::DirItem *KDirListerCache::dirItemForUrl(const KUrl& dir) const
793{
794 const QString urlStr = dir.url(KUrl::RemoveTrailingSlash);
795 DirItem *item = itemsInUse.value(urlStr);
796 if ( !item )
797 item = itemsCached[urlStr];
798 return item;
799}
800
801KFileItemList *KDirListerCache::itemsForDir(const KUrl& dir) const
802{
803 DirItem *item = dirItemForUrl(dir);
804 return item ? &item->lstItems : 0;
805}
806
807KFileItem KDirListerCache::findByName( const KDirLister *lister, const QString& _name ) const
808{
809 Q_ASSERT(lister);
810
811 for (KUrl::List::const_iterator it = lister->d->lstDirs.constBegin();
812 it != lister->d->lstDirs.constEnd(); ++it) {
813 DirItem* dirItem = itemsInUse.value((*it).url());
814 Q_ASSERT(dirItem);
815 const KFileItem item = dirItem->lstItems.findByName(_name);
816 if (!item.isNull())
817 return item;
818 }
819
820 return KFileItem();
821}
822
823KFileItem *KDirListerCache::findByUrl( const KDirLister *lister, const KUrl& _u ) const
824{
825 KUrl url(_u);
826 url.adjustPath(KUrl::RemoveTrailingSlash);
827
828 KUrl parentDir(url);
829 parentDir.setPath( parentDir.directory() );
830
831 DirItem* dirItem = dirItemForUrl(parentDir);
832 if (dirItem) {
833 // If lister is set, check that it contains this dir
834 if (!lister || lister->d->lstDirs.contains(parentDir)) {
835 KFileItemList::iterator it = dirItem->lstItems.begin();
836 const KFileItemList::iterator end = dirItem->lstItems.end();
837 for (; it != end ; ++it) {
838 if ((*it).url() == url) {
839 return &*it;
840 }
841 }
842 }
843 }
844
845 // Maybe _u is a directory itself? (see KDirModelTest::testChmodDirectory)
846 // We check this last, though, we prefer returning a kfileitem with an actual
847 // name if possible (and we make it '.' for root items later).
848 dirItem = dirItemForUrl(url);
849 if (dirItem && !dirItem->rootItem.isNull() && dirItem->rootItem.url() == url) {
850 // If lister is set, check that it contains this dir
851 if (!lister || lister->d->lstDirs.contains(url)) {
852 return &dirItem->rootItem;
853 }
854 }
855
856 return 0;
857}
858
859void KDirListerCache::slotFilesAdded( const QString &dir /*url*/ ) // from KDirNotify signals
860{
861 KUrl urlDir(dir);
862 kDebug(7004) << urlDir; // output urls, not qstrings, since they might contain a password
863 if (urlDir.isLocalFile()) {
864 Q_FOREACH(const QString& u, directoriesForCanonicalPath(urlDir.toLocalFile())) {
865 updateDirectory(KUrl(u));
866 }
867 } else {
868 updateDirectory(urlDir);
869 }
870}
871
872void KDirListerCache::slotFilesRemoved( const QStringList &fileList ) // from KDirNotify signals
873{
874 // TODO: handling of symlinks-to-directories isn't done here,
875 // because I'm not sure how to do it and keep the performance ok...
876 slotFilesRemoved(KUrl::List(fileList));
877}
878
879void KDirListerCache::slotFilesRemoved(const KUrl::List& fileList)
880{
881 //kDebug(7004) << fileList.count();
882 // Group notifications by parent dirs (usually there would be only one parent dir)
883 QMap<QString, KFileItemList> removedItemsByDir;
884 KUrl::List deletedSubdirs;
885
886 for (KUrl::List::const_iterator it = fileList.begin(); it != fileList.end() ; ++it) {
887 const KUrl url(*it);
888 DirItem* dirItem = dirItemForUrl(url); // is it a listed directory?
889 if (dirItem) {
890 deletedSubdirs.append(url);
891 if (!dirItem->rootItem.isNull()) {
892 removedItemsByDir[url.url()].append(dirItem->rootItem);
893 }
894 }
895
896 KUrl parentDir(url);
897 parentDir.setPath(parentDir.directory());
898 dirItem = dirItemForUrl(parentDir);
899 if (!dirItem)
900 continue;
901 for (KFileItemList::iterator fit = dirItem->lstItems.begin(), fend = dirItem->lstItems.end(); fit != fend ; ++fit) {
902 if ((*fit).url() == url) {
903 const KFileItem fileitem = *fit;
904 removedItemsByDir[parentDir.url()].append(fileitem);
905 // If we found a fileitem, we can test if it's a dir. If not, we'll go to deleteDir just in case.
906 if (fileitem.isNull() || fileitem.isDir()) {
907 deletedSubdirs.append(url);
908 }
909 dirItem->lstItems.erase(fit); // remove fileitem from list
910 break;
911 }
912 }
913 }
914
915 QMap<QString, KFileItemList>::const_iterator rit = removedItemsByDir.constBegin();
916 for(; rit != removedItemsByDir.constEnd(); ++rit) {
917 // Tell the views about it before calling deleteDir.
918 // They might need the subdirs' file items (see the dirtree).
919 DirectoryDataHash::const_iterator dit = directoryData.constFind(rit.key());
920 if (dit != directoryData.constEnd()) {
921 itemsDeleted((*dit).listersCurrentlyHolding, rit.value());
922 }
923 }
924
925 Q_FOREACH(const KUrl& url, deletedSubdirs) {
926 // in case of a dir, check if we have any known children, there's much to do in that case
927 // (stopping jobs, removing dirs from cache etc.)
928 deleteDir(url);
929 }
930}
931
932void KDirListerCache::slotFilesChanged( const QStringList &fileList ) // from KDirNotify signals
933{
934 //kDebug(7004) << fileList;
935 KUrl::List dirsToUpdate;
936 QStringList::const_iterator it = fileList.begin();
937 for (; it != fileList.end() ; ++it) {
938 KUrl url( *it );
939 KFileItem *fileitem = findByUrl(0, url);
940 if (!fileitem) {
941 kDebug(7004) << "item not found for" << url;
942 continue;
943 }
944 if (url.isLocalFile()) {
945 pendingUpdates.insert(url.toLocalFile()); // delegate the work to processPendingUpdates
946 } else {
947 pendingRemoteUpdates.insert(fileitem);
948 // For remote files, we won't be able to figure out the new information,
949 // we have to do a update (directory listing)
950 KUrl dir(url);
951 dir.setPath(dir.directory());
952 if (!dirsToUpdate.contains(dir))
953 dirsToUpdate.prepend(dir);
954 }
955 }
956
957 KUrl::List::const_iterator itdir = dirsToUpdate.constBegin();
958 for (; itdir != dirsToUpdate.constEnd() ; ++itdir)
959 updateDirectory( *itdir );
960 // ## TODO problems with current jobs listing/updating that dir
961 // ( see kde-2.2.2's kdirlister )
962
963 processPendingUpdates();
964}
965
966void KDirListerCache::slotFileRenamed( const QString &_src, const QString &_dst ) // from KDirNotify signals
967{
968 KUrl src( _src );
969 KUrl dst( _dst );
970 kDebug(7004) << src << "->" << dst;
971#ifdef DEBUG_CACHE
972 printDebug();
973#endif
974
975 KUrl oldurl(src);
976 oldurl.adjustPath( KUrl::RemoveTrailingSlash );
977 KFileItem *fileitem = findByUrl(0, oldurl);
978 if (!fileitem) {
979 kDebug(7004) << "Item not found:" << oldurl;
980 return;
981 }
982
983 const KFileItem oldItem = *fileitem;
984
985 // Dest already exists? Was overwritten then (testcase: #151851)
986 // We better emit it as deleted -before- doing the renaming, otherwise
987 // the "update" mechanism will emit the old one as deleted and
988 // kdirmodel will delete the new (renamed) one!
989 KFileItem* existingDestItem = findByUrl(0, dst);
990 if (existingDestItem) {
991 //kDebug() << dst << "already existed, let's delete it";
992 slotFilesRemoved(dst);
993 }
994
995 // If the item had a UDS_URL as well as UDS_NAME set, the user probably wants
996 // to be updating the name only (since they can't see the URL).
997 // Check to see if a URL exists, and if so, if only the file part has changed,
998 // only update the name and not the underlying URL.
999 bool nameOnly = !fileitem->entry().stringValue( KIO::UDSEntry::UDS_URL ).isEmpty();
1000 nameOnly &= src.directory( KUrl::IgnoreTrailingSlash | KUrl::AppendTrailingSlash ) ==
1001 dst.directory( KUrl::IgnoreTrailingSlash | KUrl::AppendTrailingSlash );
1002
1003 if (!nameOnly && fileitem->isDir()) {
1004 renameDir( src, dst );
1005 // #172945 - if the fileitem was the root item of a DirItem that was just removed from the cache,
1006 // then it's a dangling pointer now...
1007 fileitem = findByUrl(0, oldurl);
1008 if (!fileitem) //deleted from cache altogether, #188807
1009 return;
1010 }
1011
1012 // Now update the KFileItem representing that file or dir (not exclusive with the above!)
1013 if (!oldItem.isLocalFile() && !oldItem.localPath().isEmpty()) { // it uses UDS_LOCAL_PATH? ouch, needs an update then
1014 slotFilesChanged( QStringList() << src.url() );
1015 } else {
1016 if( nameOnly )
1017 fileitem->setName( dst.fileName() );
1018 else
1019 fileitem->setUrl( dst );
1020 fileitem->refreshMimeType();
1021 fileitem->determineMimeType();
1022 QSet<KDirLister*> listers = emitRefreshItem( oldItem, *fileitem );
1023 Q_FOREACH(KDirLister * kdl, listers) {
1024 kdl->d->emitItems();
1025 }
1026 }
1027
1028#ifdef DEBUG_CACHE
1029 printDebug();
1030#endif
1031}
1032
1033QSet<KDirLister*> KDirListerCache::emitRefreshItem(const KFileItem& oldItem, const KFileItem& fileitem)
1034{
1035 //kDebug(7004) << "old:" << oldItem.name() << oldItem.url()
1036 // << "new:" << fileitem.name() << fileitem.url();
1037 // Look whether this item was shown in any view, i.e. held by any dirlister
1038 KUrl parentDir( oldItem.url() );
1039 parentDir.setPath( parentDir.directory() );
1040 const QString parentDirURL = parentDir.url();
1041 DirectoryDataHash::iterator dit = directoryData.find(parentDirURL);
1042 QList<KDirLister *> listers;
1043 // Also look in listersCurrentlyListing, in case the user manages to rename during a listing
1044 if (dit != directoryData.end())
1045 listers += (*dit).listersCurrentlyHolding + (*dit).listersCurrentlyListing;
1046 if (oldItem.isDir()) {
1047 // For a directory, look for dirlisters where it's the root item.
1048 dit = directoryData.find(oldItem.url().url());
1049 if (dit != directoryData.end())
1050 listers += (*dit).listersCurrentlyHolding + (*dit).listersCurrentlyListing;
1051 }
1052 QSet<KDirLister*> listersToRefresh;
1053 Q_FOREACH(KDirLister *kdl, listers) {
1054 // For a directory, look for dirlisters where it's the root item.
1055 KUrl directoryUrl(oldItem.url());
1056 if (oldItem.isDir() && kdl->d->rootFileItem == oldItem) {
1057 const KFileItem oldRootItem = kdl->d->rootFileItem;
1058 kdl->d->rootFileItem = fileitem;
1059 kdl->d->addRefreshItem(directoryUrl, oldRootItem, fileitem);
1060 } else {
1061 directoryUrl.setPath(directoryUrl.directory());
1062 kdl->d->addRefreshItem(directoryUrl, oldItem, fileitem);
1063 }
1064 listersToRefresh.insert(kdl);
1065 }
1066 return listersToRefresh;
1067}
1068
1069QStringList KDirListerCache::directoriesForCanonicalPath(const QString& dir) const
1070{
1071 QStringList dirs;
1072 dirs << dir;
1073 dirs << canonicalUrls.value(dir).toSet().toList(); /* make unique; there are faster ways, but this is really small anyway */
1074
1075 if (dirs.count() > 1)
1076 kDebug() << dir << "known as" << dirs;
1077
1078 return dirs;
1079}
1080
1081// private slots
1082
1083// Called by KDirWatch - usually when a dir we're watching has been modified,
1084// but it can also be called for a file.
1085void KDirListerCache::slotFileDirty( const QString& path )
1086{
1087 // kDebug(7004) << path;
1088
1089 KUrl url(path);
1090 url.adjustPath(KUrl::RemoveTrailingSlash);
1091
1092 bool isDir;
1093 const KFileItem item = itemForUrl(url);
1094
1095 if (!item.isNull()) {
1096 isDir = item.isDir();
1097 } else {
1098 KDE_struct_stat buff;
1099 kDebug(7004) << "Doing stat on:" << path;
1100 if ( KDE::stat( path, &buff ) != 0 )
1101 return; // error
1102 isDir = S_ISDIR(buff.st_mode);
1103 }
1104
1105 if (isDir) {
1106 Q_FOREACH(const QString& dir, directoriesForCanonicalPath(url.toLocalFile())) {
1107 handleDirDirty(dir);
1108 }
1109 } else {
1110 Q_FOREACH(const QString& dir, directoriesForCanonicalPath(url.directory())) {
1111 KUrl aliasUrl(dir);
1112 aliasUrl.addPath(url.fileName());
1113 handleFileDirty(aliasUrl);
1114 }
1115 }
1116}
1117
1118// Called by slotFileDirty
1119void KDirListerCache::handleDirDirty(const KUrl& url)
1120{
1121 // A dir: launch an update job if anyone cares about it
1122
1123 // This also means we can forget about pending updates to individual files in that dir
1124 const QString dirPath = url.toLocalFile(KUrl::AddTrailingSlash);
1125 QMutableSetIterator<QString> pendingIt(pendingUpdates);
1126 while (pendingIt.hasNext()) {
1127 const QString updPath = pendingIt.next();
1128 //kDebug(7004) << "had pending update" << updPath;
1129 if (updPath.startsWith(dirPath) &&
1130 updPath.indexOf('/', dirPath.length()) == -1) { // direct child item
1131 kDebug(7004) << "forgetting about individual update to" << updPath;
1132 pendingIt.remove();
1133 }
1134 }
1135
1136 updateDirectory(url);
1137}
1138
1139// Called by slotFileDirty
1140void KDirListerCache::handleFileDirty(const KUrl& url)
1141{
1142 // A file: do we know about it already?
1143 KFileItem* existingItem = findByUrl(0, url);
1144 if (!existingItem) {
1145 // No - update the parent dir then
1146 KUrl dir(url);
1147 dir.setPath(url.directory());
1148 updateDirectory(dir);
1149 } else {
1150 // A known file: delay updating it, FAM is flooding us with events
1151 const QString filePath = url.toLocalFile();
1152 if (!pendingUpdates.contains(filePath)) {
1153 KUrl dir(url);
1154 dir.setPath(dir.directory());
1155 if (checkUpdate(dir.url())) {
1156 pendingUpdates.insert(filePath);
1157 if (!pendingUpdateTimer.isActive())
1158 pendingUpdateTimer.start(500);
1159 }
1160 }
1161 }
1162}
1163
1164void KDirListerCache::slotFileCreated( const QString& path ) // from KDirWatch
1165{
1166 kDebug(7004) << path;
1167 // XXX: how to avoid a complete rescan here?
1168 // We'd need to stat that one file separately and refresh the item(s) for it.
1169 KUrl fileUrl(path);
1170 slotFilesAdded(fileUrl.directory());
1171}
1172
1173void KDirListerCache::slotFileDeleted( const QString& path ) // from KDirWatch
1174{
1175 kDebug(7004) << path;
1176 KUrl u( path );
1177 QStringList fileUrls;
1178 Q_FOREACH(KUrl url, directoriesForCanonicalPath(u.directory())) {
1179 url.addPath(u.fileName());
1180 fileUrls << url.url();
1181 }
1182 slotFilesRemoved(fileUrls);
1183}
1184
1185void KDirListerCache::slotEntries( KIO::Job *job, const KIO::UDSEntryList &entries )
1186{
1187 KUrl url(joburl( static_cast<KIO::ListJob *>(job) ));
1188 url.adjustPath(KUrl::RemoveTrailingSlash);
1189 QString urlStr = url.url();
1190
1191 //kDebug(7004) << "new entries for " << url;
1192
1193 DirItem *dir = itemsInUse.value(urlStr);
1194 if (!dir) {
1195 kError(7004) << "Internal error: job is listing" << url << "but itemsInUse only knows about" << itemsInUse.keys();
1196 Q_ASSERT( dir );
1197 return;
1198 }
1199
1200 DirectoryDataHash::iterator dit = directoryData.find(urlStr);
1201 if (dit == directoryData.end()) {
1202 kError(7004) << "Internal error: job is listing" << url << "but directoryData doesn't know about that url, only about:" << directoryData.keys();
1203 Q_ASSERT(dit != directoryData.end());
1204 return;
1205 }
1206 KDirListerCacheDirectoryData& dirData = *dit;
1207 if (dirData.listersCurrentlyListing.isEmpty()) {
1208 kError(7004) << "Internal error: job is listing" << url << "but directoryData says no listers are currently listing " << urlStr;
1209#ifndef NDEBUG
1210 printDebug();
1211#endif
1212 Q_ASSERT( !dirData.listersCurrentlyListing.isEmpty() );
1213 return;
1214 }
1215
1216 // check if anyone wants the mimetypes immediately
1217 bool delayedMimeTypes = true;
1218 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
1219 delayedMimeTypes &= kdl->d->delayedMimeTypes;
1220
1221 KIO::UDSEntryList::const_iterator it = entries.begin();
1222 const KIO::UDSEntryList::const_iterator end = entries.end();
1223 for ( ; it != end; ++it )
1224 {
1225 const QString name = (*it).stringValue( KIO::UDSEntry::UDS_NAME );
1226
1227 Q_ASSERT( !name.isEmpty() );
1228 if ( name.isEmpty() )
1229 continue;
1230
1231 if ( name == "." )
1232 {
1233 Q_ASSERT( dir->rootItem.isNull() );
1234 // Try to reuse an existing KFileItem (if we listed the parent dir)
1235 // rather than creating a new one. There are many reasons:
1236 // 1) renames and permission changes to the item would have to emit the signals
1237 // twice, otherwise, so that both views manage to recognize the item.
1238 // 2) with kio_ftp we can only know that something is a symlink when
1239 // listing the parent, so prefer that item, which has more info.
1240 // Note that it gives a funky name() to the root item, rather than "." ;)
1241 dir->rootItem = itemForUrl(url);
1242 if (dir->rootItem.isNull())
1243 dir->rootItem = KFileItem( *it, url, delayedMimeTypes, true );
1244
1245 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
1246 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == url )
1247 kdl->d->rootFileItem = dir->rootItem;
1248 }
1249 else if ( name != ".." )
1250 {
1251 KFileItem item( *it, url, delayedMimeTypes, true );
1252
1253 //kDebug(7004)<< "Adding item: " << item.url();
1254 dir->lstItems.append( item );
1255
1256 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
1257 kdl->d->addNewItem(url, item);
1258 }
1259 }
1260
1261 foreach ( KDirLister *kdl, dirData.listersCurrentlyListing )
1262 kdl->d->emitItems();
1263}
1264
1265void KDirListerCache::slotResult( KJob *j )
1266{
1267#ifdef DEBUG_CACHE
1268 //printDebug();
1269#endif
1270
1271 Q_ASSERT( j );
1272 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
1273 runningListJobs.remove( job );
1274
1275 KUrl jobUrl(joburl( job ));
1276 jobUrl.adjustPath(KUrl::RemoveTrailingSlash); // need remove trailing slashes again, in case of redirections
1277 QString jobUrlStr = jobUrl.url();
1278
1279 kDebug(7004) << "finished listing" << jobUrl;
1280
1281 DirectoryDataHash::iterator dit = directoryData.find(jobUrlStr);
1282 if (dit == directoryData.end()) {
1283 kError() << "Nothing found in directoryData for URL" << jobUrlStr;
1284#ifndef NDEBUG
1285 printDebug();
1286#endif
1287 Q_ASSERT(dit != directoryData.end());
1288 return;
1289 }
1290 KDirListerCacheDirectoryData& dirData = *dit;
1291 if ( dirData.listersCurrentlyListing.isEmpty() ) {
1292 kError() << "OOOOPS, nothing in directoryData.listersCurrentlyListing for" << jobUrlStr;
1293 // We're about to assert; dump the current state...
1294#ifndef NDEBUG
1295 printDebug();
1296#endif
1297 Q_ASSERT( !dirData.listersCurrentlyListing.isEmpty() );
1298 }
1299 QList<KDirLister *> listers = dirData.listersCurrentlyListing;
1300
1301 // move all listers to the holding list, do it before emitting
1302 // the signals to make sure it exists in KDirListerCache in case someone
1303 // calls listDir during the signal emission
1304 Q_ASSERT( dirData.listersCurrentlyHolding.isEmpty() );
1305 dirData.moveListersWithoutCachedItemsJob(jobUrl);
1306
1307 if ( job->error() )
1308 {
1309 foreach ( KDirLister *kdl, listers )
1310 {
1311 kdl->d->jobDone( job );
1312 if (job->error() != KJob::KilledJobError) {
1313 kdl->handleError( job );
1314 }
1315 const bool silent = job->property("_kdlc_silent").toBool();
1316 if (!silent) {
1317 emit kdl->canceled( jobUrl );
1318 }
1319
1320 if (kdl->d->numJobs() == 0) {
1321 kdl->d->complete = true;
1322 if (!silent) {
1323 emit kdl->canceled();
1324 }
1325 }
1326 }
1327 }
1328 else
1329 {
1330 DirItem *dir = itemsInUse.value(jobUrlStr);
1331 Q_ASSERT( dir );
1332 dir->complete = true;
1333
1334 foreach ( KDirLister* kdl, listers )
1335 {
1336 kdl->d->jobDone( job );
1337 emit kdl->completed( jobUrl );
1338 if ( kdl->d->numJobs() == 0 )
1339 {
1340 kdl->d->complete = true;
1341 emit kdl->completed();
1342 }
1343 }
1344 }
1345
1346 // TODO: hmm, if there was an error and job is a parent of one or more
1347 // of the pending urls we should cancel it/them as well
1348 processPendingUpdates();
1349
1350#ifdef DEBUG_CACHE
1351 printDebug();
1352#endif
1353}
1354
1355void KDirListerCache::slotRedirection( KIO::Job *j, const KUrl& url )
1356{
1357 Q_ASSERT( j );
1358 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
1359
1360 KUrl oldUrl(job->url()); // here we really need the old url!
1361 KUrl newUrl(url);
1362
1363 // strip trailing slashes
1364 oldUrl.adjustPath(KUrl::RemoveTrailingSlash);
1365 newUrl.adjustPath(KUrl::RemoveTrailingSlash);
1366
1367 if ( oldUrl == newUrl ) {
1368 kDebug(7004) << "New redirection url same as old, giving up.";
1369 return;
1370 } else if (newUrl.isEmpty()) {
1371 kDebug(7004) << "New redirection url is empty, giving up.";
1372 return;
1373 }
1374
1375 const QString oldUrlStr = oldUrl.url();
1376 const QString newUrlStr = newUrl.url();
1377
1378 kDebug(7004) << oldUrl << "->" << newUrl;
1379
1380#ifdef DEBUG_CACHE
1381 // Can't do that here. KDirListerCache::joburl() will use the new url already,
1382 // while our data structures haven't been updated yet -> assert fail.
1383 //printDebug();
1384#endif
1385
1386 // I don't think there can be dirItems that are children of oldUrl.
1387 // Am I wrong here? And even if so, we don't need to delete them, right?
1388 // DF: redirection happens before listDir emits any item. Makes little sense otherwise.
1389
1390 // oldUrl cannot be in itemsCached because only completed items are moved there
1391 DirItem *dir = itemsInUse.take(oldUrlStr);
1392 Q_ASSERT( dir );
1393
1394 DirectoryDataHash::iterator dit = directoryData.find(oldUrlStr);
1395 Q_ASSERT(dit != directoryData.end());
1396 KDirListerCacheDirectoryData oldDirData = *dit;
1397 directoryData.erase(dit);
1398 Q_ASSERT( !oldDirData.listersCurrentlyListing.isEmpty() );
1399 const QList<KDirLister *> listers = oldDirData.listersCurrentlyListing;
1400 Q_ASSERT( !listers.isEmpty() );
1401
1402 foreach ( KDirLister *kdl, listers ) {
1403 kdl->d->redirect(oldUrlStr, newUrl, false /*clear items*/);
1404 }
1405
1406 // when a lister was stopped before the job emits the redirection signal, the old url will
1407 // also be in listersCurrentlyHolding
1408 const QList<KDirLister *> holders = oldDirData.listersCurrentlyHolding;
1409 foreach ( KDirLister *kdl, holders ) {
1410 kdl->d->jobStarted( job );
1411 // do it like when starting a new list-job that will redirect later
1412 // TODO: maybe don't emit started if there's an update running for newUrl already?
1413 emit kdl->started( oldUrl );
1414
1415 kdl->d->redirect(oldUrl, newUrl, false /*clear items*/);
1416 }
1417
1418 DirItem *newDir = itemsInUse.value(newUrlStr);
1419 if ( newDir ) {
1420 kDebug(7004) << newUrl << "already in use";
1421
1422 // only in this case there can newUrl already be in listersCurrentlyListing or listersCurrentlyHolding
1423 delete dir;
1424
1425 // get the job if one's running for newUrl already (can be a list-job or an update-job), but
1426 // do not return this 'job', which would happen because of the use of redirectionURL()
1427 KIO::ListJob *oldJob = jobForUrl( newUrlStr, job );
1428
1429 // listers of newUrl with oldJob: forget about the oldJob and use the already running one
1430 // which will be converted to an updateJob
1431 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
1432
1433 QList<KDirLister *>& curListers = newDirData.listersCurrentlyListing;
1434 if ( !curListers.isEmpty() ) {
1435 kDebug(7004) << "and it is currently listed";
1436
1437 Q_ASSERT( oldJob ); // ?!
1438
1439 foreach ( KDirLister *kdl, curListers ) { // listers of newUrl
1440 kdl->d->jobDone( oldJob );
1441
1442 kdl->d->jobStarted( job );
1443 kdl->d->connectJob( job );
1444 }
1445
1446 // append listers of oldUrl with newJob to listers of newUrl with oldJob
1447 foreach ( KDirLister *kdl, listers )
1448 curListers.append( kdl );
1449 } else {
1450 curListers = listers;
1451 }
1452
1453 if ( oldJob ) // kill the old job, be it a list-job or an update-job
1454 killJob( oldJob );
1455
1456 // holders of newUrl: use the already running job which will be converted to an updateJob
1457 QList<KDirLister *>& curHolders = newDirData.listersCurrentlyHolding;
1458 if ( !curHolders.isEmpty() ) {
1459 kDebug(7004) << "and it is currently held.";
1460
1461 foreach ( KDirLister *kdl, curHolders ) { // holders of newUrl
1462 kdl->d->jobStarted( job );
1463 emit kdl->started( newUrl );
1464 }
1465
1466 // append holders of oldUrl to holders of newUrl
1467 foreach ( KDirLister *kdl, holders )
1468 curHolders.append( kdl );
1469 } else {
1470 curHolders = holders;
1471 }
1472
1473
1474 // emit old items: listers, holders. NOT: newUrlListers/newUrlHolders, they already have them listed
1475 // TODO: make this a separate method?
1476 foreach ( KDirLister *kdl, listers + holders ) {
1477 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == newUrl )
1478 kdl->d->rootFileItem = newDir->rootItem;
1479
1480 kdl->d->addNewItems(newUrl, newDir->lstItems);
1481 kdl->d->emitItems();
1482 }
1483 } else if ( (newDir = itemsCached.take( newUrlStr )) ) {
1484 kDebug(7004) << newUrl << "is unused, but already in the cache.";
1485
1486 delete dir;
1487 itemsInUse.insert( newUrlStr, newDir );
1488 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
1489 newDirData.listersCurrentlyListing = listers;
1490 newDirData.listersCurrentlyHolding = holders;
1491
1492 // emit old items: listers, holders
1493 foreach ( KDirLister *kdl, listers + holders ) {
1494 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == newUrl )
1495 kdl->d->rootFileItem = newDir->rootItem;
1496
1497 kdl->d->addNewItems(newUrl, newDir->lstItems);
1498 kdl->d->emitItems();
1499 }
1500 } else {
1501 kDebug(7004) << newUrl << "has not been listed yet.";
1502
1503 dir->rootItem = KFileItem();
1504 dir->lstItems.clear();
1505 dir->redirect( newUrl );
1506 itemsInUse.insert( newUrlStr, dir );
1507 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
1508 newDirData.listersCurrentlyListing = listers;
1509 newDirData.listersCurrentlyHolding = holders;
1510
1511 if ( holders.isEmpty() ) {
1512#ifdef DEBUG_CACHE
1513 printDebug();
1514#endif
1515 return; // only in this case the job doesn't need to be converted,
1516 }
1517 }
1518
1519 // make the job an update job
1520 job->disconnect( this );
1521
1522 connect( job, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)),
1523 this, SLOT(slotUpdateEntries(KIO::Job*,KIO::UDSEntryList)) );
1524 connect( job, SIGNAL(result(KJob*)),
1525 this, SLOT(slotUpdateResult(KJob*)) );
1526
1527 // FIXME: autoUpdate-Counts!!
1528
1529#ifdef DEBUG_CACHE
1530 printDebug();
1531#endif
1532}
1533
1534struct KDirListerCache::ItemInUseChange
1535{
1536 ItemInUseChange(const QString& old, const QString& newU, DirItem* di)
1537 : oldUrl(old), newUrl(newU), dirItem(di) {}
1538 QString oldUrl;
1539 QString newUrl;
1540 DirItem* dirItem;
1541};
1542
1543void KDirListerCache::renameDir( const KUrl &oldUrl, const KUrl &newUrl )
1544{
1545 kDebug(7004) << oldUrl << "->" << newUrl;
1546 const QString oldUrlStr = oldUrl.url(KUrl::RemoveTrailingSlash);
1547 const QString newUrlStr = newUrl.url(KUrl::RemoveTrailingSlash);
1548
1549 // Not enough. Also need to look at any child dir, even sub-sub-sub-dir.
1550 //DirItem *dir = itemsInUse.take( oldUrlStr );
1551 //emitRedirections( oldUrl, url );
1552
1553 QLinkedList<ItemInUseChange> itemsToChange;
1554 QSet<KDirLister *> listers;
1555
1556 // Look at all dirs being listed/shown
1557 QHash<QString, DirItem *>::iterator itu = itemsInUse.begin();
1558 const QHash<QString, DirItem *>::iterator ituend = itemsInUse.end();
1559 for (; itu != ituend ; ++itu) {
1560 DirItem *dir = itu.value();
1561 KUrl oldDirUrl ( itu.key() );
1562 //kDebug(7004) << "itemInUse:" << oldDirUrl;
1563 // Check if this dir is oldUrl, or a subfolder of it
1564 if ( oldUrl.isParentOf( oldDirUrl ) ) {
1565 // TODO should use KUrl::cleanpath like isParentOf does
1566 QString relPath = oldDirUrl.path().mid( oldUrl.path().length() );
1567
1568 KUrl newDirUrl( newUrl ); // take new base
1569 if ( !relPath.isEmpty() )
1570 newDirUrl.addPath( relPath ); // add unchanged relative path
1571 //kDebug(7004) << "new url=" << newDirUrl;
1572
1573 // Update URL in dir item and in itemsInUse
1574 dir->redirect( newDirUrl );
1575
1576 itemsToChange.append(ItemInUseChange(oldDirUrl.url(KUrl::RemoveTrailingSlash),
1577 newDirUrl.url(KUrl::RemoveTrailingSlash),
1578 dir));
1579 // Rename all items under that dir
1580
1581 for ( KFileItemList::iterator kit = dir->lstItems.begin(), kend = dir->lstItems.end();
1582 kit != kend ; ++kit )
1583 {
1584 const KFileItem oldItem = *kit;
1585
1586 const KUrl oldItemUrl ((*kit).url());
1587 const QString oldItemUrlStr( oldItemUrl.url(KUrl::RemoveTrailingSlash) );
1588 KUrl newItemUrl( oldItemUrl );
1589 newItemUrl.setPath( newDirUrl.path() );
1590 newItemUrl.addPath( oldItemUrl.fileName() );
1591 kDebug(7004) << "renaming" << oldItemUrl << "to" << newItemUrl;
1592 (*kit).setUrl(newItemUrl);
1593
1594 listers |= emitRefreshItem(oldItem, *kit);
1595 }
1596 }
1597 }
1598
1599 Q_FOREACH(KDirLister * kdl, listers) {
1600 kdl->d->emitItems();
1601 }
1602
1603 // Do the changes to itemsInUse out of the loop to avoid messing up iterators,
1604 // and so that emitRefreshItem can find the stuff in the hash.
1605 foreach(const ItemInUseChange& i, itemsToChange) {
1606 itemsInUse.remove(i.oldUrl);
1607 itemsInUse.insert(i.newUrl, i.dirItem);
1608 }
1609 //Now that all the caches are updated and consistent, emit the redirection.
1610 foreach(const ItemInUseChange& i, itemsToChange) {
1611 emitRedirections(i.oldUrl, i.newUrl);
1612 }
1613
1614 // Is oldUrl a directory in the cache?
1615 // Remove any child of oldUrl from the cache - even if the renamed dir itself isn't in it!
1616 removeDirFromCache( oldUrl );
1617 // TODO rename, instead.
1618}
1619
1620// helper for renameDir, not used for redirections from KIO::listDir().
1621void KDirListerCache::emitRedirections( const KUrl &oldUrl, const KUrl &newUrl )
1622{
1623 kDebug(7004) << oldUrl << "->" << newUrl;
1624 const QString oldUrlStr = oldUrl.url(KUrl::RemoveTrailingSlash);
1625 const QString newUrlStr = newUrl.url(KUrl::RemoveTrailingSlash);
1626
1627 KIO::ListJob *job = jobForUrl( oldUrlStr );
1628 if ( job )
1629 killJob( job );
1630
1631 // Check if we were listing this dir. Need to abort and restart with new name in that case.
1632 DirectoryDataHash::iterator dit = directoryData.find(oldUrlStr);
1633 if ( dit == directoryData.end() )
1634 return;
1635 const QList<KDirLister *> listers = (*dit).listersCurrentlyListing;
1636 const QList<KDirLister *> holders = (*dit).listersCurrentlyHolding;
1637
1638 KDirListerCacheDirectoryData& newDirData = directoryData[newUrlStr];
1639
1640 // Tell the world that the job listing the old url is dead.
1641 foreach ( KDirLister *kdl, listers ) {
1642 if ( job )
1643 kdl->d->jobDone( job );
1644
1645 emit kdl->canceled( oldUrl );
1646 }
1647 newDirData.listersCurrentlyListing += listers;
1648
1649 // Check if we are currently displaying this directory (odds opposite wrt above)
1650 foreach ( KDirLister *kdl, holders ) {
1651 if ( job )
1652 kdl->d->jobDone( job );
1653 }
1654 newDirData.listersCurrentlyHolding += holders;
1655 directoryData.erase(dit);
1656
1657 if ( !listers.isEmpty() ) {
1658 updateDirectory( newUrl );
1659
1660 // Tell the world about the new url
1661 foreach ( KDirLister *kdl, listers )
1662 emit kdl->started( newUrl );
1663 }
1664
1665 // And notify the dirlisters of the redirection
1666 foreach ( KDirLister *kdl, holders ) {
1667 kdl->d->redirect(oldUrl, newUrl, true /*keep items*/);
1668 }
1669}
1670
1671void KDirListerCache::removeDirFromCache( const KUrl& dir )
1672{
1673 kDebug(7004) << dir;
1674 const QList<QString> cachedDirs = itemsCached.keys(); // seems slow, but there's no qcache iterator...
1675 foreach(const QString& cachedDir, cachedDirs) {
1676 if ( dir.isParentOf( KUrl( cachedDir ) ) )
1677 itemsCached.remove( cachedDir );
1678 }
1679}
1680
1681void KDirListerCache::slotUpdateEntries( KIO::Job* job, const KIO::UDSEntryList& list )
1682{
1683 runningListJobs[static_cast<KIO::ListJob*>(job)] += list;
1684}
1685
1686void KDirListerCache::slotUpdateResult( KJob * j )
1687{
1688 Q_ASSERT( j );
1689 KIO::ListJob *job = static_cast<KIO::ListJob *>( j );
1690
1691 KUrl jobUrl (joburl( job ));
1692 jobUrl.adjustPath(KUrl::RemoveTrailingSlash); // need remove trailing slashes again, in case of redirections
1693 QString jobUrlStr (jobUrl.url());
1694
1695 kDebug(7004) << "finished update" << jobUrl;
1696
1697 KDirListerCacheDirectoryData& dirData = directoryData[jobUrlStr];
1698 // Collect the dirlisters which were listing the URL using that ListJob
1699 // plus those that were already holding that URL - they all get updated.
1700 dirData.moveListersWithoutCachedItemsJob(jobUrl);
1701 QList<KDirLister *> listers = dirData.listersCurrentlyHolding;
1702 listers += dirData.listersCurrentlyListing;
1703
1704 // once we are updating dirs that are only in the cache this will fail!
1705 Q_ASSERT( !listers.isEmpty() );
1706
1707 if ( job->error() ) {
1708 foreach ( KDirLister* kdl, listers ) {
1709 kdl->d->jobDone( job );
1710
1711 //don't bother the user
1712 //kdl->handleError( job );
1713
1714 const bool silent = job->property("_kdlc_silent").toBool();
1715 if (!silent) {
1716 emit kdl->canceled( jobUrl );
1717 }
1718 if ( kdl->d->numJobs() == 0 ) {
1719 kdl->d->complete = true;
1720 if (!silent) {
1721 emit kdl->canceled();
1722 }
1723 }
1724 }
1725
1726 runningListJobs.remove( job );
1727
1728 // TODO: if job is a parent of one or more
1729 // of the pending urls we should cancel them
1730 processPendingUpdates();
1731 return;
1732 }
1733
1734 DirItem *dir = itemsInUse.value(jobUrlStr, 0);
1735 if (!dir) {
1736 kError(7004) << "Internal error: itemsInUse did not contain" << jobUrlStr;
1737#ifndef NDEBUG
1738 printDebug();
1739#endif
1740 Q_ASSERT(dir);
1741 } else {
1742 dir->complete = true;
1743 }
1744
1745 // check if anyone wants the mimetypes immediately
1746 bool delayedMimeTypes = true;
1747 foreach ( KDirLister *kdl, listers )
1748 delayedMimeTypes &= kdl->d->delayedMimeTypes;
1749
1750 QHash<QString, KFileItem*> fileItems; // fileName -> KFileItem*
1751
1752 // Unmark all items in url
1753 for ( KFileItemList::iterator kit = dir->lstItems.begin(), kend = dir->lstItems.end() ; kit != kend ; ++kit )
1754 {
1755 (*kit).unmark();
1756 fileItems.insert( (*kit).name(), &*kit );
1757 }
1758
1759 const KIO::UDSEntryList& buf = runningListJobs.value( job );
1760 KIO::UDSEntryList::const_iterator it = buf.constBegin();
1761 const KIO::UDSEntryList::const_iterator end = buf.constEnd();
1762 for ( ; it != end; ++it )
1763 {
1764 // Form the complete url
1765 KFileItem item( *it, jobUrl, delayedMimeTypes, true );
1766
1767 const QString name = item.name();
1768 Q_ASSERT( !name.isEmpty() );
1769
1770 // we duplicate the check for dotdot here, to avoid iterating over
1771 // all items again and checking in matchesFilter() that way.
1772 if ( name.isEmpty() || name == ".." )
1773 continue;
1774
1775 if ( name == "." )
1776 {
1777 // if the update was started before finishing the original listing
1778 // there is no root item yet
1779 if ( dir->rootItem.isNull() )
1780 {
1781 dir->rootItem = item;
1782
1783 foreach ( KDirLister *kdl, listers )
1784 if ( kdl->d->rootFileItem.isNull() && kdl->d->url == jobUrl )
1785 kdl->d->rootFileItem = dir->rootItem;
1786 }
1787 continue;
1788 }
1789
1790 // Find this item
1791 if (KFileItem* tmp = fileItems.value(item.name()))
1792 {
1793 QSet<KFileItem*>::iterator pru_it = pendingRemoteUpdates.find(tmp);
1794 const bool inPendingRemoteUpdates = (pru_it != pendingRemoteUpdates.end());
1795
1796 // check if something changed for this file, using KFileItem::cmp()
1797 if (!tmp->cmp( item ) || inPendingRemoteUpdates) {
1798
1799 if (inPendingRemoteUpdates) {
1800 pendingRemoteUpdates.erase(pru_it);
1801 }
1802
1803 //kDebug(7004) << "file changed:" << tmp->name();
1804
1805 const KFileItem oldItem = *tmp;
1806 *tmp = item;
1807 foreach ( KDirLister *kdl, listers )
1808 kdl->d->addRefreshItem(jobUrl, oldItem, *tmp);
1809 }
1810 //kDebug(7004) << "marking" << tmp;
1811 tmp->mark();
1812 }
1813 else // this is a new file
1814 {
1815 //kDebug(7004) << "new file:" << name;
1816
1817 KFileItem pitem(item);
1818 pitem.mark();
1819 dir->lstItems.append( pitem );
1820
1821 foreach ( KDirLister *kdl, listers )
1822 kdl->d->addNewItem(jobUrl, pitem);
1823 }
1824 }
1825
1826 runningListJobs.remove( job );
1827
1828 deleteUnmarkedItems( listers, dir->lstItems );
1829
1830 foreach ( KDirLister *kdl, listers ) {
1831 kdl->d->emitItems();
1832
1833 kdl->d->jobDone( job );
1834
1835 emit kdl->completed( jobUrl );
1836 if ( kdl->d->numJobs() == 0 )
1837 {
1838 kdl->d->complete = true;
1839 emit kdl->completed();
1840 }
1841 }
1842
1843 // TODO: hmm, if there was an error and job is a parent of one or more
1844 // of the pending urls we should cancel it/them as well
1845 processPendingUpdates();
1846}
1847
1848// private
1849
1850KIO::ListJob *KDirListerCache::jobForUrl( const QString& url, KIO::ListJob *not_job )
1851{
1852 QMap< KIO::ListJob *, KIO::UDSEntryList >::const_iterator it = runningListJobs.constBegin();
1853 while ( it != runningListJobs.constEnd() )
1854 {
1855 KIO::ListJob *job = it.key();
1856 if ( joburl( job ).url(KUrl::RemoveTrailingSlash) == url && job != not_job )
1857 return job;
1858 ++it;
1859 }
1860 return 0;
1861}
1862
1863const KUrl& KDirListerCache::joburl( KIO::ListJob *job )
1864{
1865 if ( job->redirectionUrl().isValid() )
1866 return job->redirectionUrl();
1867 else
1868 return job->url();
1869}
1870
1871void KDirListerCache::killJob( KIO::ListJob *job )
1872{
1873 runningListJobs.remove( job );
1874 job->disconnect( this );
1875 job->kill();
1876}
1877
1878void KDirListerCache::deleteUnmarkedItems( const QList<KDirLister *>& listers, KFileItemList &lstItems )
1879{
1880 KFileItemList deletedItems;
1881 // Find all unmarked items and delete them
1882 QMutableListIterator<KFileItem> kit(lstItems);
1883 while (kit.hasNext()) {
1884 const KFileItem& item = kit.next();
1885 if (!item.isMarked()) {
1886 //kDebug(7004) << "deleted:" << item.name() << &item;
1887 deletedItems.append(item);
1888 kit.remove();
1889 }
1890 }
1891 if (!deletedItems.isEmpty())
1892 itemsDeleted(listers, deletedItems);
1893}
1894
1895void KDirListerCache::itemsDeleted(const QList<KDirLister *>& listers, const KFileItemList& deletedItems)
1896{
1897 Q_FOREACH(KDirLister *kdl, listers) {
1898 kdl->d->emitItemsDeleted(deletedItems);
1899 }
1900
1901 Q_FOREACH(const KFileItem& item, deletedItems) {
1902 if (item.isDir())
1903 deleteDir(item.url());
1904 }
1905}
1906
1907void KDirListerCache::deleteDir( const KUrl& dirUrl )
1908{
1909 //kDebug() << dirUrl;
1910 // unregister and remove the children of the deleted item.
1911 // Idea: tell all the KDirListers that they should forget the dir
1912 // and then remove it from the cache.
1913
1914 // Separate itemsInUse iteration and calls to forgetDirs (which modify itemsInUse)
1915 KUrl::List affectedItems;
1916
1917 QHash<QString, DirItem *>::iterator itu = itemsInUse.begin();
1918 const QHash<QString, DirItem *>::iterator ituend = itemsInUse.end();
1919 for ( ; itu != ituend; ++itu ) {
1920 const KUrl deletedUrl( itu.key() );
1921 if ( dirUrl.isParentOf( deletedUrl ) ) {
1922 affectedItems.append(deletedUrl);
1923 }
1924 }
1925
1926 foreach(const KUrl& deletedUrl, affectedItems) {
1927 const QString deletedUrlStr = deletedUrl.url();
1928 // stop all jobs for deletedUrlStr
1929 DirectoryDataHash::iterator dit = directoryData.find(deletedUrlStr);
1930 if (dit != directoryData.end()) {
1931 // we need a copy because stop modifies the list
1932 QList<KDirLister *> listers = (*dit).listersCurrentlyListing;
1933 foreach ( KDirLister *kdl, listers )
1934 stopListingUrl( kdl, deletedUrl );
1935 // tell listers holding deletedUrl to forget about it
1936 // this will stop running updates for deletedUrl as well
1937
1938 // we need a copy because forgetDirs modifies the list
1939 QList<KDirLister *> holders = (*dit).listersCurrentlyHolding;
1940 foreach ( KDirLister *kdl, holders ) {
1941 // lister's root is the deleted item
1942 if ( kdl->d->url == deletedUrl )
1943 {
1944 // tell the view first. It might need the subdirs' items (which forgetDirs will delete)
1945 if ( !kdl->d->rootFileItem.isNull() ) {
1946 emit kdl->deleteItem( kdl->d->rootFileItem );
1947 emit kdl->itemsDeleted(KFileItemList() << kdl->d->rootFileItem);
1948 }
1949 forgetDirs( kdl );
1950 kdl->d->rootFileItem = KFileItem();
1951 }
1952 else
1953 {
1954 const bool treeview = kdl->d->lstDirs.count() > 1;
1955 if ( !treeview )
1956 {
1957 emit kdl->clear();
1958 kdl->d->lstDirs.clear();
1959 }
1960 else
1961 kdl->d->lstDirs.removeAll( deletedUrl );
1962
1963 forgetDirs( kdl, deletedUrl, treeview );
1964 }
1965 }
1966 }
1967
1968 // delete the entry for deletedUrl - should not be needed, it's in
1969 // items cached now
1970 int count = itemsInUse.remove( deletedUrlStr );
1971 Q_ASSERT( count == 0 );
1972 Q_UNUSED( count ); //keep gcc "unused variable" complaining quiet when in release mode
1973 }
1974
1975 // remove the children from the cache
1976 removeDirFromCache( dirUrl );
1977}
1978
1979// delayed updating of files, FAM is flooding us with events
1980void KDirListerCache::processPendingUpdates()
1981{
1982 QSet<KDirLister *> listers;
1983 foreach(const QString& file, pendingUpdates) { // always a local path
1984 kDebug(7004) << file;
1985 KUrl u(file);
1986 KFileItem *item = findByUrl( 0, u ); // search all items
1987 if ( item ) {
1988 // we need to refresh the item, because e.g. the permissions can have changed.
1989 KFileItem oldItem = *item;
1990 item->refresh();
1991 listers |= emitRefreshItem( oldItem, *item );
1992 }
1993 }
1994 pendingUpdates.clear();
1995 Q_FOREACH(KDirLister * kdl, listers) {
1996 kdl->d->emitItems();
1997 }
1998}
1999
2000#ifndef NDEBUG
2001void KDirListerCache::printDebug()
2002{
2003 kDebug(7004) << "Items in use:";
2004 QHash<QString, DirItem *>::const_iterator itu = itemsInUse.constBegin();
2005 const QHash<QString, DirItem *>::const_iterator ituend = itemsInUse.constEnd();
2006 for ( ; itu != ituend ; ++itu ) {
2007 kDebug(7004) << " " << itu.key() << "URL:" << itu.value()->url
2008 << "rootItem:" << ( !itu.value()->rootItem.isNull() ? itu.value()->rootItem.url() : KUrl() )
2009 << "autoUpdates refcount:" << itu.value()->autoUpdates
2010 << "complete:" << itu.value()->complete
2011 << QString("with %1 items.").arg(itu.value()->lstItems.count());
2012 }
2013
2014 QList<KDirLister*> listersWithoutJob;
2015 kDebug(7004) << "Directory data:";
2016 DirectoryDataHash::const_iterator dit = directoryData.constBegin();
2017 for ( ; dit != directoryData.constEnd(); ++dit )
2018 {
2019 QString list;
2020 foreach ( KDirLister* listit, (*dit).listersCurrentlyListing )
2021 list += " 0x" + QString::number( (qlonglong)listit, 16 );
2022 kDebug(7004) << " " << dit.key() << (*dit).listersCurrentlyListing.count() << "listers:" << list;
2023 foreach ( KDirLister* listit, (*dit).listersCurrentlyListing ) {
2024 if (!listit->d->m_cachedItemsJobs.isEmpty()) {
2025 kDebug(7004) << " Lister" << listit << "has CachedItemsJobs" << listit->d->m_cachedItemsJobs;
2026 } else if (KIO::ListJob* listJob = jobForUrl(dit.key())) {
2027 kDebug(7004) << " Lister" << listit << "has ListJob" << listJob;
2028 } else {
2029 listersWithoutJob.append(listit);
2030 }
2031 }
2032
2033 list.clear();
2034 foreach ( KDirLister* listit, (*dit).listersCurrentlyHolding )
2035 list += " 0x" + QString::number( (qlonglong)listit, 16 );
2036 kDebug(7004) << " " << dit.key() << (*dit).listersCurrentlyHolding.count() << "holders:" << list;
2037 }
2038
2039 QMap< KIO::ListJob *, KIO::UDSEntryList >::Iterator jit = runningListJobs.begin();
2040 kDebug(7004) << "Jobs:";
2041 for ( ; jit != runningListJobs.end() ; ++jit )
2042 kDebug(7004) << " " << jit.key() << "listing" << joburl( jit.key() ) << ":" << (*jit).count() << "entries.";
2043
2044 kDebug(7004) << "Items in cache:";
2045 const QList<QString> cachedDirs = itemsCached.keys();
2046 foreach(const QString& cachedDir, cachedDirs) {
2047 DirItem* dirItem = itemsCached.object(cachedDir);
2048 kDebug(7004) << " " << cachedDir << "rootItem:"
2049 << (!dirItem->rootItem.isNull() ? dirItem->rootItem.url().prettyUrl() : QString("NULL") )
2050 << "with" << dirItem->lstItems.count() << "items.";
2051 }
2052
2053 // Abort on listers without jobs -after- showing the full dump. Easier debugging.
2054 Q_FOREACH(KDirLister* listit, listersWithoutJob) {
2055 kFatal() << "HUH? Lister" << listit << "is supposed to be listing, but has no job!";
2056 }
2057}
2058#endif
2059
2060
2061KDirLister::KDirLister( QObject* parent )
2062 : QObject(parent), d(new Private(this))
2063{
2064 //kDebug(7003) << "+KDirLister";
2065
2066 d->complete = true;
2067
2068 setAutoUpdate( true );
2069 setDirOnlyMode( false );
2070 setShowingDotFiles( false );
2071
2072 setAutoErrorHandlingEnabled( true, 0 );
2073}
2074
2075KDirLister::~KDirLister()
2076{
2077 //kDebug(7003) << "~KDirLister" << this;
2078
2079 // Stop all running jobs, remove lister from lists
2080 if (!kDirListerCache.isDestroyed()) {
2081 stop();
2082 kDirListerCache->forgetDirs( this );
2083 }
2084
2085 delete d;
2086}
2087
2088bool KDirLister::openUrl( const KUrl& _url, OpenUrlFlags _flags )
2089{
2090 // emit the current changes made to avoid an inconsistent treeview
2091 if (d->hasPendingChanges && (_flags & Keep))
2092 emitChanges();
2093
2094 d->hasPendingChanges = false;
2095
2096 return kDirListerCache->listDir( this, _url, _flags & Keep, _flags & Reload );
2097}
2098
2099void KDirLister::stop()
2100{
2101 kDirListerCache->stop( this );
2102}
2103
2104void KDirLister::stop( const KUrl& _url )
2105{
2106 kDirListerCache->stopListingUrl( this, _url );
2107}
2108
2109bool KDirLister::autoUpdate() const
2110{
2111 return d->autoUpdate;
2112}
2113
2114void KDirLister::setAutoUpdate( bool _enable )
2115{
2116 if ( d->autoUpdate == _enable )
2117 return;
2118
2119 d->autoUpdate = _enable;
2120 kDirListerCache->setAutoUpdate( this, _enable );
2121}
2122
2123bool KDirLister::showingDotFiles() const
2124{
2125 return d->settings.isShowingDotFiles;
2126}
2127
2128void KDirLister::setShowingDotFiles( bool _showDotFiles )
2129{
2130 if ( d->settings.isShowingDotFiles == _showDotFiles )
2131 return;
2132
2133 d->prepareForSettingsChange();
2134 d->settings.isShowingDotFiles = _showDotFiles;
2135}
2136
2137bool KDirLister::dirOnlyMode() const
2138{
2139 return d->settings.dirOnlyMode;
2140}
2141
2142void KDirLister::setDirOnlyMode( bool _dirsOnly )
2143{
2144 if ( d->settings.dirOnlyMode == _dirsOnly )
2145 return;
2146
2147 d->prepareForSettingsChange();
2148 d->settings.dirOnlyMode = _dirsOnly;
2149}
2150
2151bool KDirLister::autoErrorHandlingEnabled() const
2152{
2153 return d->autoErrorHandling;
2154}
2155
2156void KDirLister::setAutoErrorHandlingEnabled( bool enable, QWidget* parent )
2157{
2158 d->autoErrorHandling = enable;
2159 d->errorParent = parent;
2160}
2161
2162KUrl KDirLister::url() const
2163{
2164 return d->url;
2165}
2166
2167KUrl::List KDirLister::directories() const
2168{
2169 return d->lstDirs;
2170}
2171
2172void KDirLister::emitChanges()
2173{
2174 d->emitChanges();
2175}
2176
2177void KDirLister::Private::emitChanges()
2178{
2179 if (!hasPendingChanges)
2180 return;
2181
2182 // reset 'hasPendingChanges' now, in case of recursion
2183 // (testcase: enabling recursive scan in ktorrent, #174920)
2184 hasPendingChanges = false;
2185
2186 const Private::FilterSettings newSettings = settings;
2187 settings = oldSettings; // temporarily
2188
2189 // Mark all items that are currently visible
2190 Q_FOREACH(const KUrl& dir, lstDirs) {
2191 KFileItemList* itemList = kDirListerCache->itemsForDir(dir);
2192 if (!itemList) {
2193 continue;
2194 }
2195
2196 KFileItemList::iterator kit = itemList->begin();
2197 const KFileItemList::iterator kend = itemList->end();
2198 for (; kit != kend; ++kit) {
2199 if (isItemVisible(*kit) && m_parent->matchesMimeFilter(*kit))
2200 (*kit).mark();
2201 else
2202 (*kit).unmark();
2203 }
2204 }
2205
2206 settings = newSettings;
2207
2208 Q_FOREACH(const KUrl& dir, lstDirs) {
2209 KFileItemList deletedItems;
2210
2211 KFileItemList* itemList = kDirListerCache->itemsForDir(dir);
2212 if (!itemList) {
2213 continue;
2214 }
2215
2216 KFileItemList::iterator kit = itemList->begin();
2217 const KFileItemList::iterator kend = itemList->end();
2218 for (; kit != kend; ++kit) {
2219 KFileItem& item = *kit;
2220 const QString text = item.text();
2221 if (text == "." || text == "..")
2222 continue;
2223 const bool nowVisible = isItemVisible(item) && m_parent->matchesMimeFilter(item);
2224 if (nowVisible && !item.isMarked())
2225 addNewItem(dir, item); // takes care of emitting newItem or itemsFilteredByMime
2226 else if (!nowVisible && item.isMarked())
2227 deletedItems.append(*kit);
2228 }
2229 if (!deletedItems.isEmpty()) {
2230 emit m_parent->itemsDeleted(deletedItems);
2231 // for compat
2232 Q_FOREACH(const KFileItem& item, deletedItems)
2233 emit m_parent->deleteItem(item);
2234 }
2235 emitItems();
2236 }
2237 oldSettings = settings;
2238}
2239
2240void KDirLister::updateDirectory( const KUrl& _u )
2241{
2242 kDirListerCache->updateDirectory( _u );
2243}
2244
2245bool KDirLister::isFinished() const
2246{
2247 return d->complete;
2248}
2249
2250KFileItem KDirLister::rootItem() const
2251{
2252 return d->rootFileItem;
2253}
2254
2255KFileItem KDirLister::findByUrl( const KUrl& _url ) const
2256{
2257 KFileItem *item = kDirListerCache->findByUrl( this, _url );
2258 if (item) {
2259 return *item;
2260 } else {
2261 return KFileItem();
2262 }
2263}
2264
2265KFileItem KDirLister::findByName( const QString& _name ) const
2266{
2267 return kDirListerCache->findByName( this, _name );
2268}
2269
2270
2271// ================ public filter methods ================ //
2272
2273void KDirLister::setNameFilter( const QString& nameFilter )
2274{
2275 if (d->nameFilter == nameFilter)
2276 return;
2277
2278 d->prepareForSettingsChange();
2279
2280 d->settings.lstFilters.clear();
2281 d->nameFilter = nameFilter;
2282 // Split on white space
2283 const QStringList list = nameFilter.split( ' ', QString::SkipEmptyParts );
2284 for (QStringList::const_iterator it = list.begin(); it != list.end(); ++it)
2285 d->settings.lstFilters.append(QRegExp(*it, Qt::CaseInsensitive, QRegExp::Wildcard));
2286}
2287
2288QString KDirLister::nameFilter() const
2289{
2290 return d->nameFilter;
2291}
2292
2293void KDirLister::setMimeFilter( const QStringList& mimeFilter )
2294{
2295 if (d->settings.mimeFilter == mimeFilter)
2296 return;
2297
2298 d->prepareForSettingsChange();
2299 if (mimeFilter.contains(QLatin1String("application/octet-stream")) || mimeFilter.contains(QLatin1String("all/allfiles"))) // all files
2300 d->settings.mimeFilter.clear();
2301 else
2302 d->settings.mimeFilter = mimeFilter;
2303}
2304
2305void KDirLister::setMimeExcludeFilter( const QStringList& mimeExcludeFilter )
2306{
2307 if (d->settings.mimeExcludeFilter == mimeExcludeFilter)
2308 return;
2309
2310 d->prepareForSettingsChange();
2311 d->settings.mimeExcludeFilter = mimeExcludeFilter;
2312}
2313
2314
2315void KDirLister::clearMimeFilter()
2316{
2317 d->prepareForSettingsChange();
2318 d->settings.mimeFilter.clear();
2319 d->settings.mimeExcludeFilter.clear();
2320}
2321
2322QStringList KDirLister::mimeFilters() const
2323{
2324 return d->settings.mimeFilter;
2325}
2326
2327bool KDirLister::matchesFilter( const QString& name ) const
2328{
2329 return doNameFilter(name, d->settings.lstFilters);
2330}
2331
2332bool KDirLister::matchesMimeFilter( const QString& mime ) const
2333{
2334 return doMimeFilter(mime, d->settings.mimeFilter) &&
2335 d->doMimeExcludeFilter(mime, d->settings.mimeExcludeFilter);
2336}
2337
2338// ================ protected methods ================ //
2339
2340bool KDirLister::matchesFilter( const KFileItem& item ) const
2341{
2342 Q_ASSERT( !item.isNull() );
2343
2344 if ( item.text() == ".." )
2345 return false;
2346
2347 if ( !d->settings.isShowingDotFiles && item.isHidden() )
2348 return false;
2349
2350 if ( item.isDir() || d->settings.lstFilters.isEmpty() )
2351 return true;
2352
2353 return matchesFilter( item.text() );
2354}
2355
2356bool KDirLister::matchesMimeFilter( const KFileItem& item ) const
2357{
2358 Q_ASSERT(!item.isNull());
2359 // Don't lose time determining the mimetype if there is no filter
2360 if (d->settings.mimeFilter.isEmpty() && d->settings.mimeExcludeFilter.isEmpty())
2361 return true;
2362 return matchesMimeFilter(item.mimetype());
2363}
2364
2365bool KDirLister::doNameFilter( const QString& name, const QList<QRegExp>& filters ) const
2366{
2367 for ( QList<QRegExp>::const_iterator it = filters.begin(); it != filters.end(); ++it )
2368 if ( (*it).exactMatch( name ) )
2369 return true;
2370
2371 return false;
2372}
2373
2374bool KDirLister::doMimeFilter( const QString& mime, const QStringList& filters ) const
2375{
2376 if ( filters.isEmpty() )
2377 return true;
2378
2379 const KMimeType::Ptr mimeptr = KMimeType::mimeType(mime);
2380 if ( !mimeptr )
2381 return false;
2382
2383 //kDebug(7004) << "doMimeFilter: investigating: "<<mimeptr->name();
2384 QStringList::const_iterator it = filters.begin();
2385 for ( ; it != filters.end(); ++it )
2386 if ( mimeptr->is(*it) )
2387 return true;
2388 //else kDebug(7004) << "doMimeFilter: compared without result to "<<*it;
2389
2390 return false;
2391}
2392
2393bool KDirLister::Private::doMimeExcludeFilter( const QString& mime, const QStringList& filters ) const
2394{
2395 if ( filters.isEmpty() )
2396 return true;
2397
2398 QStringList::const_iterator it = filters.begin();
2399 for ( ; it != filters.end(); ++it )
2400 if ( (*it) == mime )
2401 return false;
2402
2403 return true;
2404}
2405
2406void KDirLister::handleError( KIO::Job *job )
2407{
2408 if ( d->autoErrorHandling )
2409 job->uiDelegate()->showErrorMessage();
2410}
2411
2412
2413// ================= private methods ================= //
2414
2415void KDirLister::Private::addNewItem(const KUrl& directoryUrl, const KFileItem &item)
2416{
2417 if (!isItemVisible(item))
2418 return; // No reason to continue... bailing out here prevents a mimetype scan.
2419
2420 //kDebug(7004) << "in" << directoryUrl << "item:" << item.url();
2421
2422 if ( m_parent->matchesMimeFilter( item ) )
2423 {
2424 if ( !lstNewItems )
2425 {
2426 lstNewItems = new NewItemsHash;
2427 }
2428
2429 Q_ASSERT( !item.isNull() );
2430 (*lstNewItems)[directoryUrl].append( item ); // items not filtered
2431 }
2432 else
2433 {
2434 if ( !lstMimeFilteredItems ) {
2435 lstMimeFilteredItems = new KFileItemList;
2436 }
2437
2438 Q_ASSERT( !item.isNull() );
2439 lstMimeFilteredItems->append( item ); // only filtered by mime
2440 }
2441}
2442
2443void KDirLister::Private::addNewItems(const KUrl& directoryUrl, const KFileItemList& items)
2444{
2445 // TODO: make this faster - test if we have a filter at all first
2446 // DF: was this profiled? The matchesFoo() functions should be fast, w/o filters...
2447 // Of course if there is no filter and we can do a range-insertion instead of a loop, that might be good.
2448 KFileItemList::const_iterator kit = items.begin();
2449 const KFileItemList::const_iterator kend = items.end();
2450 for ( ; kit != kend; ++kit )
2451 addNewItem(directoryUrl, *kit);
2452}
2453
2454void KDirLister::Private::addRefreshItem(const KUrl& directoryUrl, const KFileItem& oldItem, const KFileItem& item)
2455{
2456 const bool refreshItemWasFiltered = !isItemVisible(oldItem) ||
2457 !m_parent->matchesMimeFilter(oldItem);
2458 if (isItemVisible(item) && m_parent->matchesMimeFilter(item)) {
2459 if ( refreshItemWasFiltered )
2460 {
2461 if ( !lstNewItems ) {
2462 lstNewItems = new NewItemsHash;
2463 }
2464
2465 Q_ASSERT( !item.isNull() );
2466 (*lstNewItems)[directoryUrl].append( item );
2467 }
2468 else
2469 {
2470 if ( !lstRefreshItems ) {
2471 lstRefreshItems = new QList<QPair<KFileItem,KFileItem> >;
2472 }
2473
2474 Q_ASSERT( !item.isNull() );
2475 lstRefreshItems->append( qMakePair(oldItem, item) );
2476 }
2477 }
2478 else if ( !refreshItemWasFiltered )
2479 {
2480 if ( !lstRemoveItems ) {
2481 lstRemoveItems = new KFileItemList;
2482 }
2483
2484 // notify the user that the mimetype of a file changed that doesn't match
2485 // a filter or does match an exclude filter
2486 // This also happens when renaming foo to .foo and dot files are hidden (#174721)
2487 Q_ASSERT(!oldItem.isNull());
2488 lstRemoveItems->append(oldItem);
2489 }
2490}
2491
2492void KDirLister::Private::emitItems()
2493{
2494 NewItemsHash *tmpNew = lstNewItems;
2495 lstNewItems = 0;
2496
2497 KFileItemList *tmpMime = lstMimeFilteredItems;
2498 lstMimeFilteredItems = 0;
2499
2500 QList<QPair<KFileItem, KFileItem> > *tmpRefresh = lstRefreshItems;
2501 lstRefreshItems = 0;
2502
2503 KFileItemList *tmpRemove = lstRemoveItems;
2504 lstRemoveItems = 0;
2505
2506 if (tmpNew) {
2507 QHashIterator<KUrl, KFileItemList> it(*tmpNew);
2508 while (it.hasNext()) {
2509 it.next();
2510 emit m_parent->itemsAdded(it.key(), it.value());
2511 emit m_parent->newItems(it.value()); // compat
2512 }
2513 delete tmpNew;
2514 }
2515
2516 if ( tmpMime )
2517 {
2518 emit m_parent->itemsFilteredByMime( *tmpMime );
2519 delete tmpMime;
2520 }
2521
2522 if ( tmpRefresh )
2523 {
2524 emit m_parent->refreshItems( *tmpRefresh );
2525 delete tmpRefresh;
2526 }
2527
2528 if ( tmpRemove )
2529 {
2530 emit m_parent->itemsDeleted( *tmpRemove );
2531 delete tmpRemove;
2532 }
2533}
2534
2535bool KDirLister::Private::isItemVisible(const KFileItem& item) const
2536{
2537 // Note that this doesn't include mime filters, because
2538 // of the itemsFilteredByMime signal. Filtered-by-mime items are
2539 // considered "visible", they are just visible via a different signal...
2540 return (!settings.dirOnlyMode || item.isDir())
2541 && m_parent->matchesFilter(item);
2542}
2543
2544void KDirLister::Private::emitItemsDeleted(const KFileItemList &_items)
2545{
2546 KFileItemList items = _items;
2547 QMutableListIterator<KFileItem> it(items);
2548 while (it.hasNext()) {
2549 const KFileItem& item = it.next();
2550 if (isItemVisible(item) && m_parent->matchesMimeFilter(item)) {
2551 // for compat
2552 emit m_parent->deleteItem(item);
2553 } else {
2554 it.remove();
2555 }
2556 }
2557 if (!items.isEmpty())
2558 emit m_parent->itemsDeleted(items);
2559}
2560
2561// ================ private slots ================ //
2562
2563void KDirLister::Private::_k_slotInfoMessage( KJob *, const QString& message )
2564{
2565 emit m_parent->infoMessage( message );
2566}
2567
2568void KDirLister::Private::_k_slotPercent( KJob *job, unsigned long pcnt )
2569{
2570 jobData[static_cast<KIO::ListJob *>(job)].percent = pcnt;
2571
2572 int result = 0;
2573
2574 KIO::filesize_t size = 0;
2575
2576 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
2577 while ( dataIt != jobData.end() )
2578 {
2579 result += (*dataIt).percent * (*dataIt).totalSize;
2580 size += (*dataIt).totalSize;
2581 ++dataIt;
2582 }
2583
2584 if ( size != 0 )
2585 result /= size;
2586 else
2587 result = 100;
2588 emit m_parent->percent( result );
2589}
2590
2591void KDirLister::Private::_k_slotTotalSize( KJob *job, qulonglong size )
2592{
2593 jobData[static_cast<KIO::ListJob *>(job)].totalSize = size;
2594
2595 KIO::filesize_t result = 0;
2596 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
2597 while ( dataIt != jobData.end() )
2598 {
2599 result += (*dataIt).totalSize;
2600 ++dataIt;
2601 }
2602
2603 emit m_parent->totalSize( result );
2604}
2605
2606void KDirLister::Private::_k_slotProcessedSize( KJob *job, qulonglong size )
2607{
2608 jobData[static_cast<KIO::ListJob *>(job)].processedSize = size;
2609
2610 KIO::filesize_t result = 0;
2611 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
2612 while ( dataIt != jobData.end() )
2613 {
2614 result += (*dataIt).processedSize;
2615 ++dataIt;
2616 }
2617
2618 emit m_parent->processedSize( result );
2619}
2620
2621void KDirLister::Private::_k_slotSpeed( KJob *job, unsigned long spd )
2622{
2623 jobData[static_cast<KIO::ListJob *>(job)].speed = spd;
2624
2625 int result = 0;
2626 QMap< KIO::ListJob *, Private::JobData >::Iterator dataIt = jobData.begin();
2627 while ( dataIt != jobData.end() )
2628 {
2629 result += (*dataIt).speed;
2630 ++dataIt;
2631 }
2632
2633 emit m_parent->speed( result );
2634}
2635
2636uint KDirLister::Private::numJobs()
2637{
2638#ifdef DEBUG_CACHE
2639 // This code helps detecting stale entries in the jobData map.
2640 qDebug() << m_parent << "numJobs:" << jobData.count();
2641 QMapIterator<KIO::ListJob *, JobData> it(jobData);
2642 while (it.hasNext()) {
2643 it.next();
2644 qDebug() << (void*)it.key();
2645 qDebug() << it.key();
2646 }
2647#endif
2648
2649 return jobData.count();
2650}
2651
2652void KDirLister::Private::jobDone( KIO::ListJob *job )
2653{
2654 jobData.remove( job );
2655}
2656
2657void KDirLister::Private::jobStarted( KIO::ListJob *job )
2658{
2659 Private::JobData data;
2660 data.speed = 0;
2661 data.percent = 0;
2662 data.processedSize = 0;
2663 data.totalSize = 0;
2664
2665 jobData.insert( job, data );
2666 complete = false;
2667}
2668
2669void KDirLister::Private::connectJob( KIO::ListJob *job )
2670{
2671 m_parent->connect( job, SIGNAL(infoMessage(KJob*,QString,QString)),
2672 m_parent, SLOT(_k_slotInfoMessage(KJob*,QString)) );
2673 m_parent->connect( job, SIGNAL(percent(KJob*,ulong)),
2674 m_parent, SLOT(_k_slotPercent(KJob*,ulong)) );
2675 m_parent->connect( job, SIGNAL(totalSize(KJob*,qulonglong)),
2676 m_parent, SLOT(_k_slotTotalSize(KJob*,qulonglong)) );
2677 m_parent->connect( job, SIGNAL(processedSize(KJob*,qulonglong)),
2678 m_parent, SLOT(_k_slotProcessedSize(KJob*,qulonglong)) );
2679 m_parent->connect( job, SIGNAL(speed(KJob*,ulong)),
2680 m_parent, SLOT(_k_slotSpeed(KJob*,ulong)) );
2681}
2682
2683void KDirLister::setMainWindow( QWidget *window )
2684{
2685 d->window = window;
2686}
2687
2688QWidget *KDirLister::mainWindow()
2689{
2690 return d->window;
2691}
2692
2693KFileItemList KDirLister::items( WhichItems which ) const
2694{
2695 return itemsForDir( url(), which );
2696}
2697
2698KFileItemList KDirLister::itemsForDir( const KUrl& dir, WhichItems which ) const
2699{
2700 KFileItemList *allItems = kDirListerCache->itemsForDir( dir );
2701 if ( !allItems )
2702 return KFileItemList();
2703
2704 if ( which == AllItems )
2705 return *allItems;
2706 else // only items passing the filters
2707 {
2708 KFileItemList result;
2709 KFileItemList::const_iterator kit = allItems->constBegin();
2710 const KFileItemList::const_iterator kend = allItems->constEnd();
2711 for ( ; kit != kend; ++kit )
2712 {
2713 const KFileItem& item = *kit;
2714 if (d->isItemVisible(item) && matchesMimeFilter(item)) {
2715 result.append(item);
2716 }
2717 }
2718 return result;
2719 }
2720}
2721
2722bool KDirLister::delayedMimeTypes() const
2723{
2724 return d->delayedMimeTypes;
2725}
2726
2727void KDirLister::setDelayedMimeTypes( bool delayedMimeTypes )
2728{
2729 d->delayedMimeTypes = delayedMimeTypes;
2730}
2731
2732// called by KDirListerCache::slotRedirection
2733void KDirLister::Private::redirect(const KUrl& oldUrl, const KUrl& newUrl, bool keepItems)
2734{
2735 if ( url.equals( oldUrl, KUrl::CompareWithoutTrailingSlash ) ) {
2736 if (!keepItems) {
2737 rootFileItem = KFileItem();
2738 } else {
2739 rootFileItem.setUrl(newUrl);
2740 }
2741 url = newUrl;
2742 }
2743
2744 const int idx = lstDirs.indexOf( oldUrl );
2745 if (idx == -1) {
2746 kWarning(7004) << "Unexpected redirection from" << oldUrl << "to" << newUrl
2747 << "but this dirlister is currently listing/holding" << lstDirs;
2748 } else {
2749 lstDirs[ idx ] = newUrl;
2750 }
2751
2752 if ( lstDirs.count() == 1 ) {
2753 if (!keepItems)
2754 emit m_parent->clear();
2755 emit m_parent->redirection( newUrl );
2756 } else {
2757 if (!keepItems)
2758 emit m_parent->clear( oldUrl );
2759 }
2760 emit m_parent->redirection( oldUrl, newUrl );
2761}
2762
2763void KDirListerCacheDirectoryData::moveListersWithoutCachedItemsJob(const KUrl& url)
2764{
2765 // Move dirlisters from listersCurrentlyListing to listersCurrentlyHolding,
2766 // but not those that are still waiting on a CachedItemsJob...
2767 // Unit-testing note:
2768 // Run kdirmodeltest in valgrind to hit the case where an update
2769 // is triggered while a lister has a CachedItemsJob (different timing...)
2770 QMutableListIterator<KDirLister *> lister_it(listersCurrentlyListing);
2771 while (lister_it.hasNext()) {
2772 KDirLister* kdl = lister_it.next();
2773 if (!kdl->d->cachedItemsJobForUrl(url)) {
2774 // OK, move this lister from "currently listing" to "currently holding".
2775
2776 // Huh? The KDirLister was present twice in listersCurrentlyListing, or was in both lists?
2777 Q_ASSERT(!listersCurrentlyHolding.contains(kdl));
2778 if (!listersCurrentlyHolding.contains(kdl)) {
2779 listersCurrentlyHolding.append(kdl);
2780 }
2781 lister_it.remove();
2782 } else {
2783 //kDebug(7004) << "Not moving" << kdl << "to listersCurrentlyHolding because it still has job" << kdl->d->m_cachedItemsJobs;
2784 }
2785 }
2786}
2787
2788KFileItem KDirLister::cachedItemForUrl(const KUrl& url)
2789{
2790 return kDirListerCache->itemForUrl(url);
2791}
2792
2793#include "kdirlister.moc"
2794#include "kdirlister_p.moc"
KDialogJobUiDelegate::window
QWidget * window() const
KDirListerCache
Design of the cache: There is a single KDirListerCache for the whole process.
Definition: kdirlister_p.h:182
KDirListerCache::slotFileRenamed
void slotFileRenamed(const QString &srcUrl, const QString &dstUrl)
Definition: kdirlister.cpp:966
KDirListerCache::setAutoUpdate
void setAutoUpdate(KDirLister *lister, bool enable)
Definition: kdirlister.cpp:498
KDirListerCache::~KDirListerCache
~KDirListerCache()
Definition: kdirlister.cpp:75
KDirListerCache::stop
void stop(KDirLister *lister, bool silent=false)
Definition: kdirlister.cpp:414
KDirListerCache::itemForUrl
KFileItem itemForUrl(const KUrl &url) const
Definition: kdirlister.cpp:782
KDirListerCache::findByUrl
KFileItem * findByUrl(const KDirLister *lister, const KUrl &url) const
Definition: kdirlister.cpp:823
KDirListerCache::updateDirectory
void updateDirectory(const KUrl &dir)
Definition: kdirlister.cpp:652
KDirListerCache::slotFilesRemoved
void slotFilesRemoved(const QStringList &fileList)
Notify that files have been deleted.
Definition: kdirlister.cpp:872
KDirListerCache::slotFilesChanged
void slotFilesChanged(const QStringList &fileList)
Notify that files have been changed.
Definition: kdirlister.cpp:932
KDirListerCache::findByName
KFileItem findByName(const KDirLister *lister, const QString &_name) const
Definition: kdirlister.cpp:807
KDirListerCache::listDir
bool listDir(KDirLister *lister, const KUrl &_url, bool _keep, bool _reload)
Definition: kdirlister.cpp:91
KDirListerCache::slotFilesAdded
void slotFilesAdded(const QString &urlDirectory)
Notify that files have been added in directory The receiver will list that directory again to find th...
Definition: kdirlister.cpp:859
KDirListerCache::forgetDirs
void forgetDirs(KDirLister *lister)
Definition: kdirlister.cpp:513
KDirListerCache::emitItemsFromCache
void emitItemsFromCache(KDirLister::Private::CachedItemsJob *job, KDirLister *lister, const KUrl &_url, bool _reload, bool _emitCompleted)
Definition: kdirlister.cpp:325
KDirListerCache::stopListingUrl
void stopListingUrl(KDirLister *lister, const KUrl &_url, bool silent=false)
Definition: kdirlister.cpp:439
KDirListerCache::itemsForDir
KFileItemList * itemsForDir(const KUrl &dir) const
Definition: kdirlister.cpp:801
KDirListerCache::forgetCachedItemsJob
void forgetCachedItemsJob(KDirLister::Private::CachedItemsJob *job, KDirLister *lister, const KUrl &url)
Definition: kdirlister.cpp:367
KDirLister::Private::CachedItemsJob
Definition: kdirlister_p.h:470
KDirLister::Private::CachedItemsJob::done
void done()
Definition: kdirlister.cpp:305
KDirLister::Private::CachedItemsJob::doKill
virtual bool doKill()
Definition: kdirlister.cpp:313
KDirLister::Private::CachedItemsJob::setEmitCompleted
void setEmitCompleted(bool b)
Definition: kdirlister_p.h:478
KDirLister::Private::CachedItemsJob::url
KUrl url() const
Definition: kdirlister_p.h:480
KDirLister::Private::CachedItemsJob::CachedItemsJob
CachedItemsJob(KDirLister *lister, const KUrl &url, bool reload)
Definition: kdirlister.cpp:290
KDirLister::Private::CachedItemsJob::start
void start()
Definition: kdirlister_p.h:475
KDirLister::Private
Definition: kdirlister_p.h:43
KDirLister::Private::emitChanges
void emitChanges()
Definition: kdirlister.cpp:2177
KDirLister::Private::_k_slotInfoMessage
void _k_slotInfoMessage(KJob *, const QString &)
Definition: kdirlister.cpp:2563
KDirLister::Private::addRefreshItem
void addRefreshItem(const KUrl &directoryUrl, const KFileItem &oldItem, const KFileItem &item)
Definition: kdirlister.cpp:2454
KDirLister::Private::addNewItem
void addNewItem(const KUrl &directoryUrl, const KFileItem &item)
Definition: kdirlister.cpp:2415
KDirLister::Private::delayedMimeTypes
bool delayedMimeTypes
Definition: kdirlister_p.h:127
KDirLister::Private::_k_slotSpeed
void _k_slotSpeed(KJob *, unsigned long)
Definition: kdirlister.cpp:2621
KDirLister::Private::jobStarted
void jobStarted(KIO::ListJob *)
Definition: kdirlister.cpp:2657
KDirLister::Private::oldSettings
FilterSettings oldSettings
Definition: kdirlister_p.h:163
KDirLister::Private::complete
bool complete
Definition: kdirlister_p.h:123
KDirLister::Private::autoUpdate
bool autoUpdate
Definition: kdirlister_p.h:125
KDirLister::Private::nameFilter
QString nameFilter
Definition: kdirlister_p.h:152
KDirLister::Private::settings
FilterSettings settings
Definition: kdirlister_p.h:162
KDirLister::Private::_k_slotProcessedSize
void _k_slotProcessedSize(KJob *, qulonglong)
Definition: kdirlister.cpp:2606
KDirLister::Private::window
QWidget * window
Definition: kdirlister_p.h:149
KDirLister::Private::_k_slotTotalSize
void _k_slotTotalSize(KJob *, qulonglong)
Definition: kdirlister.cpp:2591
KDirLister::Private::url
KUrl url
Definition: kdirlister_p.h:121
KDirLister::Private::hasPendingChanges
bool hasPendingChanges
Definition: kdirlister_p.h:129
KDirLister::Private::emitItemsDeleted
void emitItemsDeleted(const KFileItemList &items)
Definition: kdirlister.cpp:2544
KDirLister::Private::jobDone
void jobDone(KIO::ListJob *)
Definition: kdirlister.cpp:2652
KDirLister::Private::m_parent
KDirLister * m_parent
Definition: kdirlister_p.h:112
KDirLister::Private::autoErrorHandling
bool autoErrorHandling
Definition: kdirlister_p.h:131
KDirLister::Private::emitItems
void emitItems()
Definition: kdirlister.cpp:2492
KDirLister::Private::cachedItemsJobForUrl
CachedItemsJob * cachedItemsJobForUrl(const KUrl &url) const
Definition: kdirlister.cpp:281
KDirLister::Private::numJobs
uint numJobs()
Definition: kdirlister.cpp:2636
KDirLister::Private::_k_slotPercent
void _k_slotPercent(KJob *, unsigned long)
Definition: kdirlister.cpp:2568
KDirLister::Private::isItemVisible
bool isItemVisible(const KFileItem &item) const
Should this item be visible according to the current filter settings?
Definition: kdirlister.cpp:2535
KDirLister::Private::m_cachedItemsJobs
QList< CachedItemsJob * > m_cachedItemsJobs
Definition: kdirlister_p.h:150
KDirLister::Private::errorParent
QWidget * errorParent
Definition: kdirlister_p.h:132
KDirLister::Private::lstDirs
KUrl::List lstDirs
List of dirs handled by this dirlister.
Definition: kdirlister_p.h:118
KDirLister::Private::doMimeExcludeFilter
bool doMimeExcludeFilter(const QString &mimeExclude, const QStringList &filters) const
Definition: kdirlister.cpp:2393
KDirLister::Private::prepareForSettingsChange
void prepareForSettingsChange()
Definition: kdirlister_p.h:99
KDirLister::Private::connectJob
void connectJob(KIO::ListJob *)
Definition: kdirlister.cpp:2669
KDirLister::Private::addNewItems
void addNewItems(const KUrl &directoryUrl, const KFileItemList &items)
Definition: kdirlister.cpp:2443
KDirLister::Private::rootFileItem
KFileItem rootFileItem
Definition: kdirlister_p.h:142
KDirLister::Private::redirect
void redirect(const KUrl &oldUrl, const KUrl &newUrl, bool keepItems)
Redirect this dirlister from oldUrl to newUrl.
Definition: kdirlister.cpp:2733
KDirLister
Helper class for the kiojob used to list and update a directory.
Definition: kdirlister.h:58
KDirLister::handleError
virtual void handleError(KIO::Job *)
Reimplement to customize error handling.
Definition: kdirlister.cpp:2406
KDirLister::nameFilter
QString nameFilter
Definition: kdirlister.h:68
KDirLister::mainWindow
QWidget * mainWindow()
Returns the main window associated with this object.
Definition: kdirlister.cpp:2688
KDirLister::redirection
void redirection(const KUrl &_url)
Signal a redirection.
KDirLister::speed
void speed(int bytes_per_second)
Emitted to display information about the speed of the jobs.
KDirLister::findByName
virtual KFileItem findByName(const QString &name) const
Find an item by its name.
Definition: kdirlister.cpp:2265
KDirLister::matchesFilter
bool matchesFilter(const QString &name) const
Checks whether name matches a filter in the list of name filters.
Definition: kdirlister.cpp:2327
KDirLister::directories
KUrl::List directories() const
Returns all URLs that are listed by this KDirLister.
Definition: kdirlister.cpp:2167
KDirLister::rootItem
KFileItem rootItem() const
Returns the file item of the URL.
Definition: kdirlister.cpp:2250
KDirLister::setMainWindow
void setMainWindow(QWidget *window)
Pass the main window this object is associated with this is used for caching authentication data.
Definition: kdirlister.cpp:2683
KDirLister::isFinished
bool isFinished() const
Returns true if no io operation is currently in progress.
Definition: kdirlister.cpp:2245
KDirLister::setMimeFilter
virtual void setMimeFilter(const QStringList &mimeList)
Set mime-based filter to only list items matching the given mimetypes.
Definition: kdirlister.cpp:2293
KDirLister::updateDirectory
virtual void updateDirectory(const KUrl &_dir)
Update the directory _dir.
Definition: kdirlister.cpp:2240
KDirLister::itemsForDir
KFileItemList itemsForDir(const KUrl &dir, WhichItems which=FilteredItems) const
Returns the items listed for the given dir.
Definition: kdirlister.cpp:2698
KDirLister::itemsDeleted
void itemsDeleted(const KFileItemList &items)
Signal that items have been deleted.
KDirLister::matchesMimeFilter
bool matchesMimeFilter(const QString &mime) const
Checks whether mime matches a filter in the list of mime types.
Definition: kdirlister.cpp:2332
KDirLister::items
KFileItemList items(WhichItems which=FilteredItems) const
Returns the items listed for the current url().
Definition: kdirlister.cpp:2693
KDirLister::clearMimeFilter
virtual void clearMimeFilter()
Clears the mime based filter.
Definition: kdirlister.cpp:2315
KDirLister::delayedMimeTypes
bool delayedMimeTypes
Definition: kdirlister.h:67
KDirLister::infoMessage
void infoMessage(const QString &msg)
Emitted to display information about running jobs.
KDirLister::totalSize
void totalSize(KIO::filesize_t size)
Emitted when we know the size of the jobs.
KDirLister::emitChanges
virtual void emitChanges()
Actually emit the changes made with setShowingDotFiles, setDirOnlyMode, setNameFilter and setMimeFilt...
Definition: kdirlister.cpp:2172
KDirLister::canceled
void canceled()
Tell the view that the user canceled the listing.
KDirLister::setDirOnlyMode
virtual void setDirOnlyMode(bool dirsOnly)
Call this to list only directories.
Definition: kdirlister.cpp:2142
KDirLister::deleteItem
QT_MOC_COMPAT void deleteItem(const KFileItem &_fileItem)
Signals that an item has been deleted.
KDirLister::doMimeFilter
virtual bool doMimeFilter(const QString &mime, const QStringList &filters) const
Called by the public matchesMimeFilter() to do the actual filtering.
Definition: kdirlister.cpp:2374
KDirLister::Keep
@ Keep
Previous directories aren't forgotten (they are still watched by kdirwatch and their items are kept f...
Definition: kdirlister.h:76
KDirLister::Reload
@ Reload
Indicates whether to use the cache or to reread the directory from the disk.
Definition: kdirlister.h:81
KDirLister::completed
void completed()
Tell the view that listing is finished.
KDirLister::dirOnlyMode
bool dirOnlyMode
Definition: kdirlister.h:65
KDirLister::setAutoErrorHandlingEnabled
void setAutoErrorHandlingEnabled(bool enable, QWidget *parent)
Enable or disable auto error handling is enabled.
Definition: kdirlister.cpp:2156
KDirLister::setNameFilter
virtual void setNameFilter(const QString &filter)
Set a name filter to only list items matching this name, e.g.
Definition: kdirlister.cpp:2273
KDirLister::doNameFilter
virtual bool doNameFilter(const QString &name, const QList< QRegExp > &filters) const
Called by the public matchesFilter() to do the actual filtering.
Definition: kdirlister.cpp:2365
KDirLister::processedSize
void processedSize(KIO::filesize_t size)
Regularly emitted to show the progress of this KDirLister.
KDirLister::setMimeExcludeFilter
void setMimeExcludeFilter(const QStringList &mimeList)
Filtering should be done with KFileFilter.
Definition: kdirlister.cpp:2305
KDirLister::mimeFilters
QStringList mimeFilters() const
Returns the list of mime based filters, as set via setMimeFilter().
Definition: kdirlister.cpp:2322
KDirLister::stop
virtual void stop()
Stop listing all directories currently being listed.
Definition: kdirlister.cpp:2099
KDirLister::~KDirLister
virtual ~KDirLister()
Destroy the directory lister.
Definition: kdirlister.cpp:2075
KDirLister::clear
void clear()
Signal to clear all items.
KDirLister::autoUpdate
bool autoUpdate
Definition: kdirlister.h:63
KDirLister::cachedItemForUrl
static KFileItem cachedItemForUrl(const KUrl &url)
Return the KFileItem for the given URL, if we listed it recently and it's still in the cache - which ...
Definition: kdirlister.cpp:2788
KDirLister::openUrl
virtual bool openUrl(const KUrl &_url, OpenUrlFlags _flags=NoFlags)
Run the directory lister on the given url.
Definition: kdirlister.cpp:2088
KDirLister::setShowingDotFiles
virtual void setShowingDotFiles(bool _showDotFiles)
Changes the "is viewing dot files" setting.
Definition: kdirlister.cpp:2128
KDirLister::setDelayedMimeTypes
void setDelayedMimeTypes(bool delayedMimeTypes)
Delayed mimetypes feature: If enabled, mime types will be fetched on demand, which leads to a faster ...
Definition: kdirlister.cpp:2727
KDirLister::started
void started(const KUrl &_url)
Tell the view that we started to list _url.
KDirLister::setAutoUpdate
virtual void setAutoUpdate(bool enable)
Enable/disable automatic directory updating, when a directory changes (using KDirWatch).
Definition: kdirlister.cpp:2114
KDirLister::WhichItems
WhichItems
Used by items() and itemsForDir() to specify whether you want all items for a directory or just the f...
Definition: kdirlister.h:392
KDirLister::AllItems
@ AllItems
Definition: kdirlister.h:393
KDirLister::KDirLister
KDirLister(QObject *parent=0)
Create a directory lister.
Definition: kdirlister.cpp:2061
KDirLister::percent
void percent(int percent)
Progress signal showing the overall progress of the KDirLister.
KDirLister::findByUrl
virtual KFileItem findByUrl(const KUrl &_url) const
Find an item by its URL.
Definition: kdirlister.cpp:2255
KDirLister::url
KUrl url() const
Returns the top level URL that is listed by this KDirLister.
Definition: kdirlister.cpp:2162
KDirLister::autoErrorHandlingEnabled
bool autoErrorHandlingEnabled
Definition: kdirlister.h:66
KDirLister::showingDotFiles
bool showingDotFiles
Definition: kdirlister.h:64
KDirWatch::self
static KDirWatch * self()
KDirWatch::exists
static bool exists()
KFileItemList
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
Definition: kfileitem.h:675
KFileItem
A KFileItem is a generic class to handle a file, local or remote.
Definition: kfileitem.h:46
KFileItem::determineMimeType
KMimeType::Ptr determineMimeType() const
Returns the mimetype of the file item.
Definition: kfileitem.cpp:779
KFileItem::isMarked
bool isMarked() const
Used when updating a directory.
Definition: kfileitem.cpp:1680
KFileItem::setUrl
void setUrl(const KUrl &url)
Sets the item's URL.
Definition: kfileitem.cpp:543
KFileItem::isLocalFile
bool isLocalFile() const
Returns true if the file is a local file.
Definition: kfileitem.cpp:1575
KFileItem::mimetype
QString mimetype() const
Returns the mimetype of the file item.
Definition: kfileitem.cpp:770
KFileItem::refreshMimeType
void refreshMimeType()
Re-reads mimetype information.
Definition: kfileitem.cpp:533
KFileItem::localPath
QString localPath() const
Returns the local path if isLocalFile() == true or the KIO item has a UDS_LOCAL_PATH atom.
Definition: kfileitem.cpp:602
KFileItem::isDir
bool isDir() const
Returns true if this item represents a directory.
Definition: kfileitem.cpp:1141
KFileItem::isNull
bool isNull() const
Return true if default-constructed.
Definition: kfileitem.cpp:1714
KFileItem::entry
KIO::UDSEntry entry() const
Returns the UDS entry.
Definition: kfileitem.cpp:1672
KFileItem::url
KUrl url() const
Returns the url of the file.
Definition: kfileitem.cpp:1543
KFileItem::text
QString text() const
Returns the text of the file item.
Definition: kfileitem.cpp:1583
KFileItem::isHidden
bool isHidden() const
Checks whether the file is hidden.
Definition: kfileitem.cpp:1125
KFileItem::name
QString name(bool lowerCase=false) const
Return the name of the file item (without a path).
Definition: kfileitem.cpp:1591
KFileItem::refresh
void refresh()
Throw away and re-read (for local files) all information about the file.
Definition: kfileitem.cpp:512
KFileItem::setName
void setName(const QString &name)
Sets the item's name (i.e.
Definition: kfileitem.cpp:554
KIO::JobUiDelegate::setWindow
virtual void setWindow(QWidget *window)
Associate this job with a window given by window.
Definition: jobuidelegate.cpp:58
KIO::Job
The base class for all jobs.
Definition: jobclasses.h:94
KIO::Job::ui
JobUiDelegate * ui() const
Retrieves the UI delegate of this job.
Definition: job.cpp:90
KIO::ListJob
A ListJob is allows you to get the get the content of a directory.
Definition: jobclasses.h:936
KIO::ListJob::redirectionUrl
const KUrl & redirectionUrl() const
Returns the ListJob's redirection URL.
Definition: job.cpp:2775
KIO::SimpleJob::url
const KUrl & url() const
Returns the SimpleJob's URL.
Definition: job.cpp:341
KIO::UDSEntry::stringValue
QString stringValue(uint field) const
Definition: udsentry.cpp:73
KIO::UDSEntry::UDS_URL
@ UDS_URL
An alternative URL (If different from the caption).
Definition: udsentry.h:190
KIO::UDSEntry::UDS_NAME
@ UDS_NAME
Filename - as displayed in directory listings etc.
Definition: udsentry.h:163
KJobUiDelegate::showErrorMessage
virtual void showErrorMessage()
KJob
KJob::EmitResult
EmitResult
KJob::error
int error() const
KJob::kill
bool kill(KillVerbosity verbosity=Quietly)
KJob::KilledJobError
KilledJobError
KJob::uiDelegate
KJobUiDelegate * uiDelegate() const
KJob::setAutoDelete
void setAutoDelete(bool autodelete)
KMessageBox::error
static void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
KMimeType::mimeType
static Ptr mimeType(const QString &name, FindByNameOption options=ResolveAliases)
KMountPoint::List
KMountPoint::List::findByPath
Ptr findByPath(const QString &path) const
KMountPoint::NeedMountOptions
NeedMountOptions
KMountPoint::possibleMountPoints
static List possibleMountPoints(DetailsNeededFlags infoNeeded=BasicInfoNeeded)
KProtocolManager::supportsListing
static bool supportsListing(const KUrl &url)
Returns whether the protocol can list files/objects.
Definition: kprotocolmanager.cpp:1033
KSharedPtr
KUrl::List
KUrl
KUrl::cleanPath
void cleanPath(const CleanPathOption &options=SimplifyDirSeparators)
KUrl::prettyUrl
QString prettyUrl(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::AppendTrailingSlash
AppendTrailingSlash
KUrl::IgnoreTrailingSlash
IgnoreTrailingSlash
KUrl::RemoveTrailingSlash
RemoveTrailingSlash
KUrl::AddTrailingSlash
AddTrailingSlash
KUrl::adjustPath
void adjustPath(AdjustPathOption trailing)
KUrl::url
QString url(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::path
QString path(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::directory
QString directory(const DirectoryOptions &options=IgnoreTrailingSlash) const
KUrl::isLocalFile
bool isLocalFile() const
KUrl::CompareWithoutTrailingSlash
CompareWithoutTrailingSlash
KUrl::setPath
void setPath(const QString &path)
KUrl::isParentOf
bool isParentOf(const KUrl &u) const
KUrl::fileName
QString fileName(const DirectoryOptions &options=IgnoreTrailingSlash) const
KUrl::protocol
QString protocol() const
KUrl::toLocalFile
QString toLocalFile(AdjustPathOption trailing=LeaveTrailingSlash) const
KUrl::addPath
void addPath(const QString &txt)
QHash
QList< UDSEntry >
QMap
QObject
QSet
QWidget
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
kDebug
#define kDebug
kWarning
#define kWarning
job.h
jobuidelegate.h
kdebug.h
manually_mounted
static bool manually_mounted(const QString &path, const KMountPoint::List &possibleMountPoints)
Definition: kdirlister.cpp:532
kdirlister.h
kdirlister_p.h
timeout
int timeout
klocale.h
i18n
QString i18n(const char *text)
kmessagebox.h
kmountpoint.h
kprotocolmanager.h
KDE::stat
int stat(const QString &path, KDE_struct_stat *buf)
dirs
KStandardDirs * dirs()
KIO::listDir
ListJob * listDir(const KUrl &url, JobFlags flags=DefaultFlags, bool includeHidden=true)
List the contents of url, which is assumed to be a directory.
Definition: job.cpp:2735
KIO::HideProgressInfo
@ HideProgressInfo
Hide progress information dialog, i.e.
Definition: jobclasses.h:51
KIO::filesize_t
qulonglong filesize_t
64-bit file size
Definition: global.h:57
message
void message(KMessage::MessageType messageType, const QString &text, const QString &caption=QString())
KRecentDirs::dir
QString dir(const QString &fileClass)
Returns the most recently used directory accociated with this file-class.
Definition: krecentdirs.cpp:68
KRecentDirs::list
QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
Definition: krecentdirs.cpp:60
name
const char * name(StandardAction id)
end
const KShortcut & end()
reload
const KShortcut & reload()
org::kde::KDirNotify
::OrgKdeKDirNotifyInterface KDirNotify
Definition: kdirnotify.h:95
KDirListerCacheDirectoryData
Definition: kdirlister_p.h:449
KDirListerCacheDirectoryData::listersCurrentlyListing
QList< KDirLister * > listersCurrentlyListing
Definition: kdirlister_p.h:457
KDirListerCacheDirectoryData::listersCurrentlyHolding
QList< KDirLister * > listersCurrentlyHolding
Definition: kdirlister_p.h:459
KDirListerCacheDirectoryData::moveListersWithoutCachedItemsJob
void moveListersWithoutCachedItemsJob(const KUrl &url)
Definition: kdirlister.cpp:2763
KDirLister::Private::FilterSettings
Definition: kdirlister_p.h:154
KDirLister::Private::FilterSettings::lstFilters
QList< QRegExp > lstFilters
Definition: kdirlister_p.h:158
KDirLister::Private::FilterSettings::dirOnlyMode
bool dirOnlyMode
Definition: kdirlister_p.h:157
KDirLister::Private::FilterSettings::mimeExcludeFilter
QStringList mimeExcludeFilter
Definition: kdirlister_p.h:160
KDirLister::Private::FilterSettings::mimeFilter
QStringList mimeFilter
Definition: kdirlister_p.h:159
KDirLister::Private::FilterSettings::isShowingDotFiles
bool isShowingDotFiles
Definition: kdirlister_p.h:156
KDirLister::Private::JobData
Definition: kdirlister_p.h:134
KDirLister::Private::JobData::totalSize
KIO::filesize_t totalSize
Definition: kdirlister_p.h:136
KDirLister::Private::JobData::percent
long unsigned int percent
Definition: kdirlister_p.h:135
KDirLister::Private::JobData::speed
long unsigned int speed
Definition: kdirlister_p.h:135
KDirLister::Private::JobData::processedSize
KIO::filesize_t processedSize
Definition: kdirlister_p.h:136
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal