12#include "kcoredirlister.h"
13#include "kcoredirlister_p.h"
15#include "../utils_p.h"
16#include "kiocoredebug.h"
17#include "kmountpoint.h"
18#include <kio/listjob.h>
20#include <KJobUiDelegate>
21#include <KLocalizedString>
26#include <QMimeDatabase>
27#include <QRegularExpression>
29#include <QThreadStorage>
31#include <QLoggingCategory>
32Q_DECLARE_LOGGING_CATEGORY(KIO_CORE_DIRLISTER)
33Q_LOGGING_CATEGORY(KIO_CORE_DIRLISTER,
"kf.kio.core.dirlister", QtWarningMsg)
45KCoreDirListerCache::KCoreDirListerCache()
48 m_cacheHiddenFiles(10)
50 qCDebug(KIO_CORE_DIRLISTER);
53 pendingUpdateTimer.setSingleShot(
true);
59#ifndef KIO_ANDROID_STUB
61 connect(kdirnotify, &org::kde::KDirNotify::FileRenamedWithLocalPath,
this, &KCoreDirListerCache::slotFileRenamed);
62 connect(kdirnotify, &org::kde::KDirNotify::FilesAdded,
this, &KCoreDirListerCache::slotFilesAdded);
63 connect(kdirnotify, &org::kde::KDirNotify::FilesChanged,
this, &KCoreDirListerCache::slotFilesChanged);
64 connect(kdirnotify, &org::kde::KDirNotify::FilesRemoved,
this, qOverload<const QStringList &>(&KCoreDirListerCache::slotFilesRemoved));
68KCoreDirListerCache::~KCoreDirListerCache()
70 qCDebug(KIO_CORE_DIRLISTER);
72 qDeleteAll(itemsInUse);
76 directoryData.clear();
77 m_cacheHiddenFiles.clear();
86bool KCoreDirListerCache::listDir(
KCoreDirLister *lister,
const QUrl &dirUrl,
bool _keep,
bool _reload)
95 if (_url.isLocalFile()) {
97 const QString local = _url.toLocalFile();
99 if (local != resolved) {
108 qCDebug(KIO_CORE_DIRLISTER) << lister <<
"url=" << _url <<
"keep=" << _keep <<
"reload=" << _reload;
121 }
else if (lister->d->lstDirs.contains(_url)) {
123 stopListingUrl(lister, _url,
true );
128 lister->d->lstDirs.removeAll(_url);
131 forgetDirs(lister, _url,
true);
133 if (lister->d->url == _url) {
138 lister->d->complete =
false;
140 lister->d->lstDirs.append(_url);
142 if (lister->d->url.isEmpty() || !_keep) {
143 lister->d->url = _url;
146 DirItem *itemU = itemsInUse.value(_url);
148 KCoreDirListerCacheDirectoryData &dirData = directoryData[_url];
150 if (dirData.listersCurrentlyListing.isEmpty()) {
154 dirData.listersCurrentlyListing.append(lister);
156 DirItem *itemFromCache =
nullptr;
157 if (itemU || (!_reload && (itemFromCache = itemsCached.take(_url)))) {
159 qCDebug(KIO_CORE_DIRLISTER) <<
"Entry already in use:" << _url;
162 qCDebug(KIO_CORE_DIRLISTER) <<
"Entry in cache:" << _url;
163 itemsInUse.insert(_url, itemFromCache);
164 itemU = itemFromCache;
166 if (lister->d->autoUpdate) {
167 itemU->incAutoUpdate();
169 if (itemFromCache && itemFromCache->watchedWhileInCache) {
171 itemFromCache->watchedWhileInCache =
false;
172 itemFromCache->decAutoUpdate();
179 new KCoreDirListerPrivate::CachedItemsJob(lister, _url, _reload);
184 qCDebug(KIO_CORE_DIRLISTER) <<
"Reloading directory:" << _url;
185 itemsCached.remove(_url);
187 qCDebug(KIO_CORE_DIRLISTER) <<
"Listing directory:" << _url;
190 itemU =
new DirItem(_url, resolved);
191 itemsInUse.insert(_url, itemU);
192 if (lister->d->autoUpdate) {
193 itemU->incAutoUpdate();
197 if (lister->requestMimeTypeWhileListing()) {
203 lister->d->connectJob(job);
211 qCDebug(KIO_CORE_DIRLISTER) <<
"Entry now being listed by" << dirData.listersCurrentlyListing;
214 qCDebug(KIO_CORE_DIRLISTER) <<
"Entry currently being listed:" << _url <<
"by" << dirData.listersCurrentlyListing;
222 Q_ASSERT(!dirData.listersCurrentlyListing.contains(lister));
223 dirData.listersCurrentlyListing.append(lister);
226 if (lister->d->autoUpdate) {
227 itemU->incAutoUpdate();
234 lister->d->connectJob(job);
240 qCDebug(KIO_CORE_DIRLISTER) <<
"Listing" << itemU->lstItems.count() <<
"cached items soon";
241 auto *cachedItemsJob =
new KCoreDirListerPrivate::CachedItemsJob(lister, _url, _reload);
245 cachedItemsJob->setEmitCompleted(
false);
256KCoreDirListerPrivate::CachedItemsJob *KCoreDirListerPrivate::cachedItemsJobForUrl(
const QUrl &url)
const
258 for (CachedItemsJob *job : m_cachedItemsJobs) {
259 if (job->
url() == url) {
266KCoreDirListerPrivate::CachedItemsJob::CachedItemsJob(
KCoreDirLister *lister,
const QUrl &url,
bool reload)
271 , m_emitCompleted(true)
273 qCDebug(KIO_CORE_DIRLISTER) <<
"Creating CachedItemsJob" <<
this <<
"for lister" << lister << url;
274 if (lister->d->cachedItemsJobForUrl(url)) {
275 qCWarning(KIO_CORE) <<
"Lister" << lister <<
"has a cached items job already for" << url;
277 lister->d->m_cachedItemsJobs.append(
this);
283void KCoreDirListerPrivate::CachedItemsJob::done()
288 s_kDirListerCache.localData().emitItemsFromCache(
this, m_lister, m_url, m_reload, m_emitCompleted);
292bool KCoreDirListerPrivate::CachedItemsJob::doKill()
294 qCDebug(KIO_CORE_DIRLISTER) <<
this;
295 s_kDirListerCache.localData().forgetCachedItemsJob(
this, m_lister, m_url);
296 if (!property(
"_kdlc_silent").toBool()) {
297 Q_EMIT m_lister->listingDirCanceled(m_url);
299 Q_EMIT m_lister->canceled();
305void KCoreDirListerCache::emitItemsFromCache(KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob,
311 lister->d->complete =
false;
313 DirItem *itemU = s_kDirListerCache.localData().itemsInUse.value(_url);
315 qCWarning(KIO_CORE) <<
"Can't find item for directory" << _url <<
"anymore";
318 const KFileItem rootItem = itemU->rootItem;
319 _reload = _reload || !itemU->complete;
321 if (lister->d->rootFileItem.isNull() && !rootItem.
isNull() && lister->d->url == _url) {
322 lister->d->rootFileItem = rootItem;
325 qCDebug(KIO_CORE_DIRLISTER) <<
"emitting" << items.
count() <<
"for lister" << lister;
326 lister->d->addNewItems(_url, items);
327 lister->d->emitItems();
331 forgetCachedItemsJob(cachedItemsJob, lister, _url);
337 if (_emitCompleted) {
338 lister->d->complete =
true;
344 updateDirectory(_url);
349void KCoreDirListerCache::forgetCachedItemsJob(KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob,
KCoreDirLister *lister,
const QUrl &_url)
354 lister->d->m_cachedItemsJobs.removeAll(cachedItemsJob);
356 KCoreDirListerCacheDirectoryData &dirData = directoryData[_url];
357 Q_ASSERT(dirData.listersCurrentlyListing.contains(lister));
361 Q_ASSERT(!dirData.listersCurrentlyHolding.contains(lister));
362 qCDebug(KIO_CORE_DIRLISTER) <<
"Moving from listing to holding, because no more job" << lister << _url;
363 dirData.listersCurrentlyHolding.append(lister);
364 dirData.listersCurrentlyListing.removeAll(lister);
366 qCDebug(KIO_CORE_DIRLISTER) <<
"Still having a listjob" << listJob <<
", so not moving to currently-holding.";
370void KCoreDirListerCache::stop(
KCoreDirLister *lister,
bool silent)
372 qCDebug(KIO_CORE_DIRLISTER) <<
"lister:" << lister <<
"silent=" << silent;
375 for (
const QUrl &url : urls) {
376 stopListingUrl(lister, url, silent);
380void KCoreDirListerCache::stopListingUrl(
KCoreDirLister *lister,
const QUrl &_u,
bool silent)
385 KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob = lister->d->cachedItemsJobForUrl(url);
386 if (cachedItemsJob) {
388 cachedItemsJob->setProperty(
"_kdlc_silent",
true);
390 cachedItemsJob->kill();
394 qCDebug(KIO_CORE_DIRLISTER) << lister <<
" url=" << url;
396 const auto dirit = directoryData.find(url);
397 if (dirit == directoryData.end()) {
400 KCoreDirListerCacheDirectoryData &dirData = dirit.value();
401 if (dirData.listersCurrentlyListing.contains(lister)) {
402 qCDebug(KIO_CORE_DIRLISTER) <<
" found lister" << lister <<
"in list - for" << url;
403 if (dirData.listersCurrentlyListing.count() == 1) {
405 stopListJob(url, silent);
408 dirData.listersCurrentlyListing.removeAll(lister);
418void KCoreDirListerCache::stopListJob(
const QUrl &url,
bool silent)
431 qCDebug(KIO_CORE_DIRLISTER) <<
"Killing list job" << job <<
"for" << url;
435 job->
kill(KJob::EmitResult);
439void KCoreDirListerCache::setAutoUpdate(
KCoreDirLister *lister,
bool enable)
443 for (
const QUrl &url :
std::as_const(lister->d->lstDirs)) {
444 DirItem *dirItem = itemsInUse.value(url);
447 dirItem->incAutoUpdate();
449 dirItem->decAutoUpdate();
456 qCDebug(KIO_CORE_DIRLISTER) << lister;
458 Q_EMIT lister->
clear();
463 const QList<QUrl> lstDirsCopy = lister->d->lstDirs;
464 lister->d->lstDirs.clear();
466 qCDebug(KIO_CORE_DIRLISTER) <<
"Iterating over dirs" << lstDirsCopy;
467 for (
const QUrl &dir : lstDirsCopy) {
468 forgetDirs(lister, dir,
false);
476 if (possibleMountPoints.
isEmpty()) {
485void KCoreDirListerCache::forgetDirs(
KCoreDirLister *lister,
const QUrl &_url,
bool notify)
487 qCDebug(KIO_CORE_DIRLISTER) << lister <<
" _url: " << _url;
491 DirectoryDataHash::iterator dit = directoryData.find(url);
492 if (dit == directoryData.end()) {
495 KCoreDirListerCacheDirectoryData &dirData = *dit;
496 dirData.listersCurrentlyHolding.removeAll(lister);
501 lister->d->jobDone(job);
504 DirItem *item = itemsInUse.value(url);
506 bool insertIntoCache =
false;
508 if (dirData.listersCurrentlyHolding.isEmpty() && dirData.listersCurrentlyListing.isEmpty()) {
510 directoryData.erase(dit);
511 itemsInUse.remove(url);
516 qCDebug(KIO_CORE_DIRLISTER) <<
"Killing update job for " << url;
522 if (lister->d->numJobs() == 0) {
523 lister->d->complete =
true;
529 lister->d->lstDirs.removeAll(url);
533 insertIntoCache = item->complete;
534 if (insertIntoCache) {
544 const bool isLocal = item->url.isLocalFile();
545 bool isManuallyMounted =
false;
546 bool containsManuallyMounted =
false;
548 isManuallyMounted = manually_mounted(item->url.toLocalFile(), possibleMountPoints);
549 if (!isManuallyMounted) {
553 auto kit = item->lstItems.constBegin();
554 const auto kend = item->lstItems.constEnd();
555 for (; kit != kend && !containsManuallyMounted; ++kit) {
556 if ((*kit).isDir() && manually_mounted((*kit).url().toLocalFile(), possibleMountPoints)) {
557 containsManuallyMounted =
true;
563 if (isManuallyMounted || containsManuallyMounted) {
564 qCDebug(KIO_CORE_DIRLISTER) <<
"Not adding a watch on " << item->url <<
" because it "
565 << (isManuallyMounted ?
"is manually mounted" :
"contains a manually mounted subdir");
566 item->complete =
false;
568 item->incAutoUpdate();
569 item->watchedWhileInCache =
true;
577 if (item && lister->d->autoUpdate) {
578 item->decAutoUpdate();
582 if (item && insertIntoCache) {
583 qCDebug(KIO_CORE_DIRLISTER) << lister <<
"item moved into cache:" << url;
584 itemsCached.insert(url, item);
588void KCoreDirListerCache::updateDirectory(
const QUrl &_dir)
590 qCDebug(KIO_CORE_DIRLISTER) << _dir;
593 if (!checkUpdate(dir)) {
595 if (checkUpdate(parentDir)) {
608 KCoreDirListerCacheDirectoryData &dirData = directoryData[
dir];
612 qCDebug(KIO_CORE_DIRLISTER) <<
dir <<
"listers=" << listers <<
"holders=" << holders;
625 KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob = kdl->d->cachedItemsJobForUrl(dir);
626 if (cachedItemsJob) {
627 cachedItemsJob->setEmitCompleted(
false);
628 cachedItemsJob->done();
629 delete cachedItemsJob;
634 qCDebug(KIO_CORE_DIRLISTER) <<
"Killed=" << killed;
639 if (!(listers.
isEmpty() || killed)) {
640 qCWarning(KIO_CORE) <<
"The unexpected happened.";
641 qCWarning(KIO_CORE) <<
"listers for" <<
dir <<
"=" << listers;
642 qCWarning(KIO_CORE) <<
"job=" << job;
644 qCDebug(KIO_CORE_DIRLISTER) <<
"lister" << kdl <<
"m_cachedItemsJobs=" << kdl->d->m_cachedItemsJobs;
650 Q_ASSERT(listers.
isEmpty() || killed);
656 return lister->requestMimeTypeWhileListing();
659 return lister->requestMimeTypeWhileListing();
662 if (requestFromListers || requestFromholders) {
669 qCDebug(KIO_CORE_DIRLISTER) <<
"update started in" <<
dir;
672 kdl->jobStarted(job);
678 kdl->jobStarted(job);
679 Q_EMIT kdl->started(dir);
683 kdl->jobStarted(job);
689bool KCoreDirListerCache::checkUpdate(
const QUrl &_dir)
691 if (!itemsInUse.contains(_dir)) {
692 DirItem *item = itemsCached[_dir];
693 if (item && item->complete) {
694 item->complete =
false;
695 item->watchedWhileInCache =
false;
696 item->decAutoUpdate();
697 qCDebug(KIO_CORE_DIRLISTER) <<
"directory " << _dir <<
" not in use, marked dirty.";
700 qCDebug(KIO_CORE_DIRLISTER) <<
"aborted, directory " << _dir <<
" not in cache.";
707KFileItem KCoreDirListerCache::itemForUrl(
const QUrl &url)
const
709 return findByUrl(
nullptr, url);
712KCoreDirListerCache::DirItem *KCoreDirListerCache::dirItemForUrl(
const QUrl &dir)
const
715 DirItem *item = itemsInUse.value(url);
717 item = itemsCached[url];
724 DirItem *item = dirItemForUrl(dir);
725 return item ? &item->lstItems :
nullptr;
732 auto isMatch = [&_name](
const KFileItem &item) {
733 return _name == item.name();
736 for (
const auto &dirUrl :
std::as_const(lister->d->lstDirs)) {
737 DirItem *dirItem = itemsInUse.value(dirUrl);
740 auto it = std::find_if(dirItem->lstItems.cbegin(), dirItem->lstItems.cend(), isMatch);
741 if (it != dirItem->lstItems.cend()) {
755 DirItem *dirItem = dirItemForUrl(parentDir);
758 if (!lister || lister->d->lstDirs.contains(parentDir)) {
760 auto it = std::lower_bound(dirItem->lstItems.begin(), dirItem->lstItems.end(), url);
761 if (it != dirItem->lstItems.end() && it->url() == url) {
770 dirItem = dirItemForUrl(url);
771 if (dirItem && !dirItem->rootItem.isNull() && dirItem->rootItem.url() == url) {
773 if (!lister || lister->d->lstDirs.contains(url)) {
774 return dirItem->rootItem;
781void KCoreDirListerCache::slotFilesAdded(
const QString &dir )
784 itemsAddedInDirectory(urlDir);
787void KCoreDirListerCache::itemsAddedInDirectory(
const QUrl &urlDir)
789 qCDebug(KIO_CORE_DIRLISTER) << urlDir;
790 const QList<QUrl> urls = directoriesForCanonicalPath(urlDir);
791 for (
const QUrl &u : urls) {
796void KCoreDirListerCache::slotFilesRemoved(
const QStringList &fileList)
801void KCoreDirListerCache::slotFilesRemoved(
const QList<QUrl> &fileList)
803 qCDebug(KIO_CORE_DIRLISTER) << fileList.
count();
808 for (
const QUrl &url : fileList) {
809 const QList<QUrl> dirUrls = directoriesForCanonicalPath(url);
810 for (
const QUrl &dir : dirUrls) {
811 DirItem *dirItem = dirItemForUrl(dir);
813 deletedSubdirs.
append(dir);
814 if (!dirItem->rootItem.isNull()) {
815 removedItemsByDir[url].append(dirItem->rootItem);
821 const QList<QUrl> parentDirUrls = directoriesForCanonicalPath(parentDir);
822 for (
const QUrl &dir : parentDirUrls) {
823 DirItem *dirItem = dirItemForUrl(dir);
828 const auto dirItemIt = std::find_if(dirItem->lstItems.cbegin(), dirItem->lstItems.cend(), [&url](
const KFileItem &fitem) {
829 return fitem.name() == url.fileName();
831 if (dirItemIt != dirItem->lstItems.cend()) {
833 removedItemsByDir[
dir].append(fileitem);
835 if (fileitem.
isNull() || fileitem.isDir()) {
836 deletedSubdirs.
append(url);
838 dirItem->lstItems.erase(dirItemIt);
843 for (
auto rit = removedItemsByDir.
constBegin(), cend = removedItemsByDir.
constEnd(); rit != cend; ++rit) {
846 auto dit = directoryData.constFind(rit.key());
847 if (dit != directoryData.constEnd()) {
848 itemsDeleted((*dit).listersCurrentlyHolding, rit.value());
852 for (
const QUrl &url :
std::as_const(deletedSubdirs)) {
859void KCoreDirListerCache::slotFilesChanged(
const QStringList &fileList)
861 qCDebug(KIO_CORE_DIRLISTER) << fileList;
863 for (
const QString &fileUrl : fileList) {
864 const QUrl url(fileUrl);
865 const KFileItem &fileitem = findByUrl(
nullptr, url);
867 qCDebug(KIO_CORE_DIRLISTER) <<
"item not found for" << url;
873 pendingRemoteUpdates.insert(fileitem);
883 for (
const QUrl &dirUrl :
std::as_const(dirsToUpdate)) {
884 updateDirectory(dirUrl);
889 processPendingUpdates();
892void KCoreDirListerCache::slotFileRenamed(
const QString &_src,
const QString &_dst,
const QString &dstPath)
896 qCDebug(KIO_CORE_DIRLISTER) << src <<
"->" << dst;
902 KFileItem fileitem = findByUrl(
nullptr, oldurl);
904 qCDebug(KIO_CORE_DIRLISTER) <<
"Item not found:" << oldurl;
914 const KFileItem &existingDestItem = findByUrl(
nullptr, dst);
915 if (!existingDestItem.
isNull()) {
916 qCDebug(KIO_CORE_DIRLISTER) << dst <<
"already existed, let's delete it";
927 if (!nameOnly && fileitem.isDir()) {
928 renameDir(oldurl, dst);
931 fileitem = findByUrl(
nullptr, oldurl);
938 if (!oldItem.isLocalFile() && !oldItem.localPath().
isEmpty()
942 const QUrl &itemOldUrl = fileitem.url();
944 fileitem.
setName(dst.fileName());
954 fileitem.determineMimeType();
955 reinsert(fileitem, itemOldUrl);
957 const std::set<KCoreDirLister *> listers = emitRefreshItem(oldItem, fileitem);
968std::set<KCoreDirLister *> KCoreDirListerCache::emitRefreshItem(
const KFileItem &oldItem,
const KFileItem &fileitem)
970 qCDebug(KIO_CORE_DIRLISTER) <<
"old:" << oldItem.name() << oldItem.url() <<
"new:" << fileitem.name() << fileitem.url();
973 DirectoryDataHash::iterator dit = directoryData.find(parentDir);
976 if (dit != directoryData.end()) {
977 listers += (*dit).listersCurrentlyHolding + (*dit).listersCurrentlyListing;
979 if (oldItem.isDir()) {
981 dit = directoryData.find(oldItem.url());
982 if (dit != directoryData.end()) {
983 listers += (*dit).listersCurrentlyHolding + (*dit).listersCurrentlyListing;
986 std::set<KCoreDirLister *> listersToRefresh;
989 listersToRefresh.
insert(kdl);
993 QUrl directoryUrl(oldItem.url());
994 if (oldItem.isDir() && kdl->d->rootFileItem == oldItem) {
995 const KFileItem oldRootItem = kdl->d->rootFileItem;
996 kdl->d->rootFileItem = fileitem;
997 kdl->d->addRefreshItem(directoryUrl, oldRootItem, fileitem);
1000 kdl->d->addRefreshItem(directoryUrl, oldItem, fileitem);
1003 return listersToRefresh;
1006QList<QUrl> KCoreDirListerCache::directoriesForCanonicalPath(
const QUrl &dir)
const
1010 if (urlList.
size() > 1) {
1011 std::sort(urlList.
begin(), urlList.
end());
1012 auto end_unique = std::unique(urlList.
begin(), urlList.
end());
1013 urlList.
erase(end_unique, urlList.
end());
1019 if (dirs.count() > 1) {
1020 qCDebug(KIO_CORE_DIRLISTER) <<
dir <<
"known as" << dirs;
1029void KCoreDirListerCache::slotFileDirty(
const QString &path)
1031 qCDebug(KIO_CORE_DIRLISTER) <<
path;
1038 isDir = item.isDir();
1041 if (!info.exists()) {
1044 isDir = info.isDir();
1048 const QList<QUrl> urls = directoriesForCanonicalPath(url);
1049 for (
const QUrl &dir : urls) {
1050 handleDirDirty(dir);
1055 for (
const QUrl &dir : urls) {
1057 aliasUrl.setPath(Utils::concatPaths(aliasUrl.path(), url.
fileName()));
1058 handleFileDirty(aliasUrl);
1063void KCoreDirListerCache::handleDirDirty(
const QUrl &url)
1069 const QString dirPath = Utils::slashAppended(dir);
1071 for (
auto pendingIt = pendingUpdates.cbegin(); pendingIt != pendingUpdates.cend(); ) {
1072 const QString updPath = *pendingIt;
1073 qCDebug(KIO_CORE_DIRLISTER) <<
"had pending update" << updPath;
1075 qCDebug(KIO_CORE_DIRLISTER) <<
"forgetting about individual update to" << updPath;
1076 pendingIt = pendingUpdates.
erase(pendingIt);
1082 if (checkUpdate(url)) {
1083 const auto [it, isInserted] = pendingDirectoryUpdates.insert(dir);
1084 if (isInserted && !pendingUpdateTimer.isActive()) {
1085 pendingUpdateTimer.start(200);
1091void KCoreDirListerCache::handleFileDirty(
const QUrl &url)
1094 const KFileItem &existingItem = findByUrl(
nullptr, url);
1096 if (existingItem.
isNull()) {
1098 handleDirDirty(dir);
1102 if (checkUpdate(dir)) {
1104 const auto [it, isInserted] = pendingUpdates.
insert(filePath);
1105 if (isInserted && !pendingUpdateTimer.isActive()) {
1106 pendingUpdateTimer.start(200);
1111void KCoreDirListerCache::slotFileCreated(
const QString &path)
1113 qCDebug(KIO_CORE_DIRLISTER) <<
path;
1120void KCoreDirListerCache::slotFileDeleted(
const QString &path)
1122 qCDebug(KIO_CORE_DIRLISTER) <<
path;
1127 for (
const QUrl &url : urls) {
1129 urlInfo.setPath(Utils::concatPaths(urlInfo.path(), fileName));
1130 fileUrls << urlInfo.toString();
1132 slotFilesRemoved(fileUrls);
1140 qCDebug(KIO_CORE_DIRLISTER) <<
"new entries for " << url;
1142 DirItem *
dir = itemsInUse.value(url);
1144 qCWarning(KIO_CORE) <<
"Internal error: job is listing" << url <<
"but itemsInUse only knows about" << itemsInUse.keys();
1149 DirectoryDataHash::iterator dit = directoryData.find(url);
1150 if (dit == directoryData.end()) {
1151 qCWarning(KIO_CORE) <<
"Internal error: job is listing" << url <<
"but directoryData doesn't know about that url, only about:" << directoryData.keys();
1152 Q_ASSERT(dit != directoryData.end());
1155 KCoreDirListerCacheDirectoryData &dirData = *dit;
1158 qCWarning(KIO_CORE) <<
"Internal error: job is listing" << url <<
"but directoryData says no listers are currently listing " << url;
1167 bool delayedMimeTypes =
true;
1169 delayedMimeTypes &= kdl->d->delayedMimeTypes;
1172 CacheHiddenFile *cachedHidden =
nullptr;
1173 bool dotHiddenChecked =
false;
1175 for (
const auto &entry : entries) {
1191 dir->rootItem = itemForUrl(url);
1193 dir->rootItem =
KFileItem(entry, url, delayedMimeTypes,
true);
1197 if (kdl->d->rootFileItem.isNull() && kdl->d->url == url) {
1198 kdl->d->rootFileItem =
dir->rootItem;
1202 KFileItem item(entry, url, delayedMimeTypes,
true);
1205 if (!dotHiddenChecked) {
1206 const QString localPath = item.localPath();
1209 cachedHidden = cachedDotHiddenForDir(rootItemPath);
1211 dotHiddenChecked =
true;
1215 if (cachedHidden && cachedHidden->listedFiles.find(name) != cachedHidden->listedFiles.cend()) {
1219 qCDebug(KIO_CORE_DIRLISTER) <<
"Adding item: " << item.url();
1225 std::sort(newItems.
begin(), newItems.
end());
1228 dir->insertSortedItems(newItems);
1231 kdl->d->addNewItems(url, newItems);
1235 kdl->d->emitItems();
1239void KCoreDirListerCache::slotResult(
KJob *j)
1247 runningListJobs.remove(job);
1249 QUrl jobUrl(joburl(job));
1252 qCDebug(KIO_CORE_DIRLISTER) <<
"finished listing" << jobUrl;
1254 const auto dit = directoryData.find(jobUrl);
1255 if (dit == directoryData.end()) {
1256 qCWarning(KIO_CORE) <<
"Nothing found in directoryData for URL" << jobUrl;
1260 Q_ASSERT(dit != directoryData.end());
1263 KCoreDirListerCacheDirectoryData &dirData = *dit;
1264 if (dirData.listersCurrentlyListing.isEmpty()) {
1265 qCWarning(KIO_CORE) <<
"OOOOPS, nothing in directoryData.listersCurrentlyListing for" << jobUrl;
1270 Q_ASSERT(!dirData.listersCurrentlyListing.isEmpty());
1277 Q_ASSERT(dirData.listersCurrentlyHolding.isEmpty());
1278 dirData.moveListersWithoutCachedItemsJob(jobUrl);
1281 bool errorShown =
false;
1283 kdl->d->jobDone(job);
1284 if (job->
error() != KJob::KilledJobError) {
1285 Q_EMIT kdl->jobError(job);
1286 if (kdl->d->m_autoErrorHandling && !errorShown) {
1295 Q_EMIT kdl->listingDirCanceled(jobUrl);
1298 if (kdl->d->numJobs() == 0) {
1299 kdl->d->complete =
true;
1301 Q_EMIT kdl->canceled();
1306 DirItem *
dir = itemsInUse.value(jobUrl);
1308 dir->complete =
true;
1311 kdl->d->jobDone(job);
1312 Q_EMIT kdl->listingDirCompleted(jobUrl);
1313 if (kdl->d->numJobs() == 0) {
1314 kdl->d->complete =
true;
1315 Q_EMIT kdl->completed();
1322 processPendingUpdates();
1325 updateDirectory(jobUrl);
1333void KCoreDirListerCache::slotRedirection(
KIO::Job *j,
const QUrl &url)
1345 if (oldUrl == newUrl) {
1346 qCDebug(KIO_CORE_DIRLISTER) <<
"New redirection url same as old, giving up.";
1348 }
else if (newUrl.isEmpty()) {
1349 qCDebug(KIO_CORE_DIRLISTER) <<
"New redirection url is empty, giving up.";
1353 qCDebug(KIO_CORE_DIRLISTER) << oldUrl <<
"->" << newUrl;
1366 DirItem *
dir = itemsInUse.take(oldUrl);
1369 DirectoryDataHash::iterator dit = directoryData.find(oldUrl);
1370 Q_ASSERT(dit != directoryData.end());
1371 KCoreDirListerCacheDirectoryData oldDirData = *dit;
1372 directoryData.erase(dit);
1373 Q_ASSERT(!oldDirData.listersCurrentlyListing.isEmpty());
1378 kdl->d->redirect(oldUrl, newUrl,
false );
1385 kdl->jobStarted(job);
1388 Q_EMIT kdl->started(oldUrl);
1390 kdl->d->redirect(oldUrl, newUrl,
false );
1395 DirItem *newDir = itemsInUse.
value(newUrl);
1397 qCDebug(KIO_CORE_DIRLISTER) << newUrl <<
"already in use";
1408 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1412 qCDebug(KIO_CORE_DIRLISTER) <<
"and it is currently listed";
1417 kdl->d->jobDone(oldJob);
1419 kdl->jobStarted(job);
1420 kdl->d->connectJob(job);
1428 curListers = listers;
1438 qCDebug(KIO_CORE_DIRLISTER) <<
"and it is currently held.";
1441 kdl->jobStarted(job);
1442 Q_EMIT kdl->started(newUrl);
1450 curHolders = holders;
1456 if (kdl->d->rootFileItem.isNull() && kdl->d->url == newUrl) {
1457 kdl->d->rootFileItem = newDir->rootItem;
1460 kdl->d->addNewItems(newUrl, newDir->lstItems);
1461 kdl->d->emitItems();
1463 }
else if ((newDir = itemsCached.take(newUrl))) {
1464 qCDebug(KIO_CORE_DIRLISTER) << newUrl <<
"is unused, but already in the cache.";
1467 itemsInUse.
insert(newUrl, newDir);
1468 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1469 newDirData.listersCurrentlyListing = listers;
1470 newDirData.listersCurrentlyHolding = holders;
1474 if (kdl->d->rootFileItem.isNull() && kdl->d->url == newUrl) {
1475 kdl->d->rootFileItem = newDir->rootItem;
1478 kdl->d->addNewItems(newUrl, newDir->lstItems);
1479 kdl->d->emitItems();
1482 qCDebug(KIO_CORE_DIRLISTER) << newUrl <<
"has not been listed yet.";
1486 dir->redirect(newUrl);
1487 itemsInUse.
insert(newUrl, dir);
1488 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1489 newDirData.listersCurrentlyListing = listers;
1490 newDirData.listersCurrentlyHolding = holders;
1492 if (holders.isEmpty()) {
1513struct KCoreDirListerCache::ItemInUseChange {
1514 ItemInUseChange(
const QUrl &old,
const QUrl &newU, DirItem *di)
1525void KCoreDirListerCache::renameDir(
const QUrl &oldUrl,
const QUrl &newUrl)
1527 qCDebug(KIO_CORE_DIRLISTER) << oldUrl <<
"->" << newUrl;
1529 std::vector<ItemInUseChange> itemsToChange;
1530 std::set<KCoreDirLister *> listers;
1533 for (
auto itu = itemsInUse.begin(), ituend = itemsInUse.end(); itu != ituend; ++itu) {
1534 DirItem *
dir = itu.value();
1535 const QUrl &oldDirUrl = itu.key();
1536 qCDebug(KIO_CORE_DIRLISTER) <<
"itemInUse:" << oldDirUrl;
1538 if (oldDirUrl == oldUrl || oldUrl.
isParentOf(oldDirUrl)) {
1542 QUrl newDirUrl(newUrl);
1544 newDirUrl.setPath(Utils::concatPaths(newDirUrl.path(), relPath));
1546 qCDebug(KIO_CORE_DIRLISTER) <<
"new url=" << newDirUrl;
1549 dir->redirect(newDirUrl);
1558 const QUrl &oldItemUrl = oldItem.url();
1559 QUrl newItemUrl(oldItemUrl);
1560 newItemUrl.setPath(Utils::concatPaths(newDirUrl.path(), oldItemUrl.
fileName()));
1561 qCDebug(KIO_CORE_DIRLISTER) <<
"renaming" << oldItemUrl <<
"to" << newItemUrl;
1562 newItem.
setUrl(newItemUrl);
1564 listers.merge(emitRefreshItem(oldItem, newItem));
1572 kdl->d->emitItems();
1577 for (
const ItemInUseChange &i : itemsToChange) {
1578 itemsInUse.remove(i.oldUrl);
1579 itemsInUse.insert(i.newUrl, i.dirItem);
1582 for (
const ItemInUseChange &i : itemsToChange) {
1583 emitRedirections(
QUrl(i.oldUrl),
QUrl(i.newUrl));
1587 removeDirFromCache(oldUrl);
1592void KCoreDirListerCache::emitRedirections(
const QUrl &_oldUrl,
const QUrl &_newUrl)
1594 qCDebug(KIO_CORE_DIRLISTER) << _oldUrl <<
"->" << _newUrl;
1604 DirectoryDataHash::iterator dit = directoryData.find(oldUrl);
1605 if (dit == directoryData.end()) {
1611 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1616 kdl->d->jobDone(job);
1618 Q_EMIT kdl->listingDirCanceled(oldUrl);
1620 newDirData.listersCurrentlyListing += listers;
1625 kdl->d->jobDone(job);
1628 newDirData.listersCurrentlyHolding += holders;
1629 directoryData.
erase(dit);
1632 updateDirectory(newUrl);
1636 Q_EMIT kdl->started(newUrl);
1642 kdl->d->redirect(oldUrl, newUrl,
true );
1646void KCoreDirListerCache::removeDirFromCache(
const QUrl &dir)
1648 qCDebug(KIO_CORE_DIRLISTER) <<
dir;
1649 const QList<QUrl> cachedDirs = itemsCached.keys();
1650 for (
const QUrl &cachedDir : cachedDirs) {
1651 if (dir == cachedDir ||
dir.isParentOf(cachedDir)) {
1652 itemsCached.
remove(cachedDir);
1659 runningListJobs[
static_cast<KIO::ListJob *
>(job)] += list;
1662void KCoreDirListerCache::slotUpdateResult(
KJob *j)
1667 QUrl jobUrl(joburl(job));
1670 qCDebug(KIO_CORE_DIRLISTER) <<
"finished update" << jobUrl;
1672 KCoreDirListerCacheDirectoryData &dirData = directoryData[jobUrl];
1675 dirData.moveListersWithoutCachedItemsJob(jobUrl);
1683 kdl->d->jobDone(job);
1689 Q_EMIT kdl->listingDirCanceled(jobUrl);
1691 if (kdl->d->numJobs() == 0) {
1692 kdl->d->complete =
true;
1694 Q_EMIT kdl->canceled();
1699 runningListJobs.remove(job);
1703 processPendingUpdates();
1707 DirItem *
dir = itemsInUse.value(jobUrl,
nullptr);
1709 qCWarning(KIO_CORE) <<
"Internal error: itemsInUse did not contain" << jobUrl;
1715 dir->complete =
true;
1719 bool delayedMimeTypes =
true;
1721 delayedMimeTypes &= kdl->d->delayedMimeTypes;
1725 FileItemHash fileItems;
1730 fileItems.
insert(item.name(), item);
1733 CacheHiddenFile *cachedHidden =
nullptr;
1734 bool dotHiddenChecked =
false;
1737 for (
const auto &entry : buf) {
1739 KFileItem item(entry, jobUrl, delayedMimeTypes,
true);
1754 dir->rootItem = item;
1757 if (kdl->d->rootFileItem.isNull() && kdl->d->url == jobUrl) {
1758 kdl->d->rootFileItem =
dir->rootItem;
1765 if (!dotHiddenChecked) {
1766 const QString localPath = item.localPath();
1769 cachedHidden = cachedDotHiddenForDir(rootItemPath);
1771 dotHiddenChecked =
true;
1776 if (cachedHidden && cachedHidden->listedFiles.find(name) != cachedHidden->listedFiles.cend()) {
1781 FileItemHash::iterator fiit = fileItems.find(item.name());
1782 if (fiit != fileItems.end()) {
1784 auto pru_it = pendingRemoteUpdates.find(tmp);
1785 const bool inPendingRemoteUpdates = pru_it != pendingRemoteUpdates.end();
1788 if (!tmp.
cmp(item) || inPendingRemoteUpdates) {
1789 if (inPendingRemoteUpdates) {
1790 pendingRemoteUpdates.erase(pru_it);
1793 qCDebug(KIO_CORE_DIRLISTER) <<
"file changed:" << tmp.name();
1795 reinsert(item, tmp.url());
1797 kdl->d->addRefreshItem(jobUrl, tmp, item);
1801 fileItems.erase(fiit);
1803 qCDebug(KIO_CORE_DIRLISTER) <<
"new file:" <<
name;
1809 std::sort(newItems.
begin(), newItems.
end());
1812 dir->insertSortedItems(newItems);
1815 kdl->d->addNewItems(jobUrl, newItems);
1818 runningListJobs.
remove(job);
1820 if (!fileItems.isEmpty()) {
1821 deleteUnmarkedItems(listers,
dir->lstItems, fileItems);
1825 kdl->d->emitItems();
1827 kdl->d->jobDone(job);
1828 Q_EMIT kdl->listingDirCompleted(jobUrl);
1829 if (kdl->d->numJobs() == 0) {
1830 kdl->d->complete =
true;
1831 Q_EMIT kdl->completed();
1837 processPendingUpdates();
1840 updateDirectory(jobUrl);
1848 for (
auto it = runningListJobs.cbegin(); it != runningListJobs.cend(); ++it) {
1852 if (jobUrl == url && job != not_job) {
1870 runningListJobs.remove(job);
1882 for (
auto kit = itemsToDelete.
cbegin(), endIt = itemsToDelete.
cend(); kit != endIt; ++kit) {
1884 deletedItems.
append(item);
1885 qCDebug(KIO_CORE_DIRLISTER) <<
"deleted:" << item.name() << item;
1889 auto it = std::remove_if(lstItems.
begin(), lstItems.
end(), [&itemsToDelete](
const KFileItem &item) {
1890 return itemsToDelete.contains(item.name());
1892 lstItems.
erase(it, lstItems.
end());
1894 itemsDeleted(listers, deletedItems);
1900 kdl->d->emitItemsDeleted(deletedItems);
1903 for (
const KFileItem &item : deletedItems) {
1905 deleteDir(item.url());
1910void KCoreDirListerCache::deleteDir(
const QUrl &_dirUrl)
1912 qCDebug(KIO_CORE_DIRLISTER) << _dirUrl;
1922 auto itu = itemsInUse.
cbegin();
1923 const auto ituend = itemsInUse.cend();
1924 for (; itu != ituend; ++itu) {
1925 const QUrl &deletedUrl = itu.key();
1926 if (dirUrl == deletedUrl || dirUrl.
isParentOf(deletedUrl)) {
1927 affectedItems.
append(deletedUrl);
1931 for (
const QUrl &deletedUrl :
std::as_const(affectedItems)) {
1933 auto dit = directoryData.constFind(deletedUrl);
1934 if (dit != directoryData.cend()) {
1938 stopListingUrl(kdl, deletedUrl);
1947 if (kdl->d->url == deletedUrl) {
1949 if (!kdl->d->rootFileItem.isNull()) {
1950 Q_EMIT kdl->itemsDeleted(
KFileItemList{kdl->d->rootFileItem});
1955 const bool treeview = kdl->d->lstDirs.count() > 1;
1957 Q_EMIT kdl->clear();
1958 kdl->d->lstDirs.clear();
1960 kdl->d->lstDirs.removeAll(deletedUrl);
1963 forgetDirs(kdl, deletedUrl, treeview);
1970 int count = itemsInUse.remove(deletedUrl);
1971 Q_ASSERT(count == 0);
1976 removeDirFromCache(dirUrl);
1980void KCoreDirListerCache::processPendingUpdates()
1982 std::set<KCoreDirLister *> listers;
1984 for (
const QString &file : pendingUpdates) {
1985 qCDebug(KIO_CORE_DIRLISTER) << file;
1993 if (!oldItem.
cmp(item)) {
1995 removedUrls.
append(oldItem.url());
1997 reinsert(item, oldItem.url());
1999 listers.merge(emitRefreshItem(oldItem, item));
2003 pendingUpdates.clear();
2005 kdl->d->emitItems();
2009 for (
const auto &removedUrl : removedUrls) {
2014 for (
const QString &dir : pendingDirectoryUpdates) {
2017 pendingDirectoryUpdates.clear();
2021void KCoreDirListerCache::printDebug()
2023 qCDebug(KIO_CORE_DIRLISTER) <<
"Items in use:";
2024 auto itu = itemsInUse.constBegin();
2025 const auto ituend = itemsInUse.constEnd();
2026 for (; itu != ituend; ++itu) {
2027 qCDebug(KIO_CORE_DIRLISTER) <<
" " << itu.key() <<
"URL:" << itu.value()->url
2028 <<
"rootItem:" << (!itu.value()->rootItem.isNull() ? itu.value()->rootItem.url() :
QUrl())
2029 <<
"autoUpdates refcount:" << itu.value()->autoUpdates <<
"complete:" << itu.value()->complete
2030 << QStringLiteral(
"with %1 items.").arg(itu.value()->lstItems.count());
2034 qCDebug(KIO_CORE_DIRLISTER) <<
"Directory data:";
2036 for (; dit != directoryData.constEnd(); ++dit) {
2042 qCDebug(KIO_CORE_DIRLISTER) <<
" " << dit.key() << listers.
count() <<
"listers:" <<
list;
2044 if (!listit->d->m_cachedItemsJobs.isEmpty()) {
2045 qCDebug(KIO_CORE_DIRLISTER) <<
" Lister" << listit <<
"has CachedItemsJobs" << listit->d->m_cachedItemsJobs;
2046 }
else if (
KIO::ListJob *listJob = jobForUrl(dit.key())) {
2047 qCDebug(KIO_CORE_DIRLISTER) <<
" Lister" << listit <<
"has ListJob" << listJob;
2049 listersWithoutJob.
append(listit);
2058 qCDebug(KIO_CORE_DIRLISTER) <<
" " << dit.key() << holders.
count() <<
"holders:" <<
list;
2062 qCDebug(KIO_CORE_DIRLISTER) <<
"Jobs:";
2063 for (; jit != runningListJobs.
end(); ++jit) {
2064 qCDebug(KIO_CORE_DIRLISTER) <<
" " << jit.
key() <<
"listing" << joburl(jit.
key()) <<
":" << (*jit).count() <<
"entries.";
2067 qCDebug(KIO_CORE_DIRLISTER) <<
"Items in cache:";
2068 const QList<QUrl> cachedDirs = itemsCached.keys();
2069 for (
const QUrl &cachedDir : cachedDirs) {
2070 DirItem *dirItem = itemsCached.object(cachedDir);
2071 qCDebug(KIO_CORE_DIRLISTER) <<
" " << cachedDir
2072 <<
"rootItem:" << (!dirItem->rootItem.isNull() ? dirItem->rootItem.url().toString() : QStringLiteral(
"NULL")) <<
"with"
2073 << dirItem->lstItems.
count() <<
"items.";
2078 qCWarning(KIO_CORE) <<
"Fatal Error: HUH? Lister" << listit <<
"is supposed to be listing, but has no job!";
2086 , d(new KCoreDirListerPrivate(this))
2088 qCDebug(KIO_CORE_DIRLISTER) <<
"+KCoreDirLister";
2099 qCDebug(KIO_CORE_DIRLISTER) <<
"~KCoreDirLister" <<
this;
2102 if (!qApp->closingDown()) {
2104 s_kDirListerCache.localData().forgetDirs(
this);
2112 if (d->hasPendingChanges && (_flags &
Keep)) {
2116 d->hasPendingChanges =
false;
2118 return s_kDirListerCache.localData().listDir(
this, _url, _flags &
Keep, _flags &
Reload);
2123 s_kDirListerCache.localData().stop(
this);
2128 s_kDirListerCache.localData().stopListingUrl(
this, _url);
2133 s_kDirListerCache.localData().forgetDirs(
this, _url,
true);
2136bool KCoreDirLister::autoUpdate()
const
2138 return d->autoUpdate;
2143 if (d->autoUpdate == enable) {
2147 d->autoUpdate = enable;
2148 s_kDirListerCache.localData().setAutoUpdate(
this, enable);
2151bool KCoreDirLister::showHiddenFiles()
const
2153 return d->settings.isShowingDotFiles;
2162 d->prepareForSettingsChange();
2166bool KCoreDirLister::dirOnlyMode()
const
2168 return d->settings.dirOnlyMode;
2173 if (d->settings.dirOnlyMode == dirsOnly) {
2177 d->prepareForSettingsChange();
2178 d->settings.dirOnlyMode = dirsOnly;
2181bool KCoreDirLister::requestMimeTypeWhileListing()
const
2183 return d->requestMimeTypeWhileListing;
2188 if (d->requestMimeTypeWhileListing == request) {
2192 d->requestMimeTypeWhileListing = request;
2193 if (d->requestMimeTypeWhileListing) {
2197 s_kDirListerCache.localData().forgetDirs(
this);
2216void KCoreDirListerPrivate::emitChanges()
2218 if (!hasPendingChanges) {
2224 hasPendingChanges =
false;
2226 const KCoreDirListerPrivate::FilterSettings newSettings = settings;
2227 settings = oldSettings;
2230 std::set<QString> oldVisibleItems;
2231 for (
const QUrl &dir :
std::as_const(lstDirs)) {
2232 const QList<KFileItem> *itemList = s_kDirListerCache.localData().itemsForDir(dir);
2237 for (
const KFileItem &item : *itemList) {
2238 if (isItemVisible(item) && matchesMimeFilter(item)) {
2239 oldVisibleItems.insert(item.name());
2244 settings = newSettings;
2247 for (
const QUrl &dir : dirs) {
2250 const QList<KFileItem> *itemList = s_kDirListerCache.localData().itemsForDir(dir);
2255 for (
const auto &item : *itemList) {
2256 const QString text = item.text();
2260 const bool wasVisible = oldVisibleItems.find(item.name()) != oldVisibleItems.
cend();
2261 const bool mimeFiltered = matchesMimeFilter(item);
2262 const bool nowVisible = isItemVisible(item) && mimeFiltered;
2263 if (nowVisible && !wasVisible) {
2264 addNewItem(dir, item);
2265 }
else if (!nowVisible && wasVisible) {
2266 if (!mimeFiltered) {
2267 lstMimeFilteredItems.append(item);
2269 deletedItems.
append(item);
2272 if (!deletedItems.
isEmpty()) {
2273 Q_EMIT q->itemsDeleted(deletedItems);
2277 oldSettings = settings;
2282 s_kDirListerCache.localData().updateDirectory(dirUrl);
2292 return d->rootFileItem;
2297 return s_kDirListerCache.localData().findByUrl(
this,
url);
2302 return s_kDirListerCache.localData().findByName(
this, name);
2309 if (d->nameFilter == nameFilter) {
2313 d->prepareForSettingsChange();
2315 d->settings.lstFilters.clear();
2316 d->nameFilter = nameFilter;
2326 return d->nameFilter;
2331 if (d->settings.mimeFilter == mimeFilter) {
2335 d->prepareForSettingsChange();
2337 d->settings.mimeFilter.clear();
2339 d->settings.mimeFilter = mimeFilter;
2345 if (d->settings.mimeExcludeFilter == mimeExcludeFilter) {
2349 d->prepareForSettingsChange();
2350 d->settings.mimeExcludeFilter = mimeExcludeFilter;
2355 d->prepareForSettingsChange();
2356 d->settings.mimeFilter.clear();
2357 d->settings.mimeExcludeFilter.clear();
2362 return d->settings.mimeFilter;
2367bool KCoreDirListerPrivate::matchesFilter(
const KFileItem &item)
const
2369 Q_ASSERT(!item.
isNull());
2375 if (!settings.isShowingDotFiles && item.isHidden()) {
2379 if (item.isDir() || settings.lstFilters.isEmpty()) {
2383 return std::any_of(settings.lstFilters.cbegin(), settings.lstFilters.cend(), [&item](
const QRegularExpression &filter) {
2384 return filter.match(item.text()).hasMatch();
2388bool KCoreDirListerPrivate::matchesMimeFilter(
const KFileItem &item)
const
2390 Q_ASSERT(!item.
isNull());
2392 if (settings.mimeFilter.isEmpty() && settings.mimeExcludeFilter.isEmpty()) {
2395 return doMimeFilter(item.mimetype(), settings.mimeFilter) && doMimeExcludeFilter(item.mimetype(), settings.mimeExcludeFilter);
2398bool KCoreDirListerPrivate::doMimeFilter(
const QString &mime,
const QStringList &filters)
const
2410 qCDebug(KIO_CORE_DIRLISTER) <<
"doMimeFilter: investigating:" << mimeptr.
name();
2411 return std::any_of(filters.
cbegin(), filters.
cend(), [&mimeptr](
const QString &filter) {
2412 return mimeptr.inherits(filter);
2416bool KCoreDirListerPrivate::doMimeExcludeFilter(
const QString &mime,
const QStringList &filters)
const
2418 return !std::any_of(filters.
cbegin(), filters.
cend(), [&mime](
const QString &filter) {
2419 return mime == filter;
2425void KCoreDirListerPrivate::addNewItem(
const QUrl &directoryUrl,
const KFileItem &item)
2427 if (!isItemVisible(item)) {
2431 qCDebug(KIO_CORE_DIRLISTER) <<
"in" << directoryUrl <<
"item:" << item.url();
2433 if (matchesMimeFilter(item)) {
2434 Q_ASSERT(!item.
isNull());
2435 lstNewItems[directoryUrl].append(item);
2437 Q_ASSERT(!item.
isNull());
2438 lstMimeFilteredItems.append(item);
2442void KCoreDirListerPrivate::addNewItems(
const QUrl &directoryUrl,
const QList<KFileItem> &items)
2447 for (
const auto &item : items) {
2448 addNewItem(directoryUrl, item);
2452void KCoreDirListerPrivate::addRefreshItem(
const QUrl &directoryUrl,
const KFileItem &oldItem,
const KFileItem &item)
2455 if (directoryUrl == item.url()) {
2456 lstRefreshItems.append({oldItem, item});
2460 const bool refreshItemWasFiltered = !isItemVisible(oldItem) || !matchesMimeFilter(oldItem);
2461 if (item.
exists() && isItemVisible(item) && matchesMimeFilter(item)) {
2462 if (refreshItemWasFiltered) {
2463 Q_ASSERT(!item.
isNull());
2464 lstNewItems[directoryUrl].append(item);
2466 Q_ASSERT(!item.
isNull());
2467 lstRefreshItems.append(qMakePair(oldItem, item));
2469 }
else if (!refreshItemWasFiltered) {
2473 Q_ASSERT(!oldItem.
isNull());
2474 lstRemoveItems.append(oldItem);
2478void KCoreDirListerPrivate::emitItems()
2480 if (!lstNewItems.empty()) {
2481 for (
auto it = lstNewItems.cbegin(); it != lstNewItems.cend(); ++it) {
2482 const auto &val = it.value();
2483 Q_EMIT q->itemsAdded(it.key(), val);
2484 Q_EMIT q->newItems(val);
2486 lstNewItems.clear();
2489 if (!lstMimeFilteredItems.empty()) {
2490 Q_EMIT q->itemsFilteredByMime(lstMimeFilteredItems);
2491 lstMimeFilteredItems.clear();
2494 if (!lstRefreshItems.empty()) {
2495 Q_EMIT q->refreshItems(lstRefreshItems);
2496 lstRefreshItems.clear();
2499 if (!lstRemoveItems.empty()) {
2500 Q_EMIT q->itemsDeleted(lstRemoveItems);
2501 lstRemoveItems.clear();
2505bool KCoreDirListerPrivate::isItemVisible(
const KFileItem &item)
const
2510 return (!settings.dirOnlyMode || item.isDir()) && matchesFilter(item);
2513void KCoreDirListerPrivate::emitItemsDeleted(
const KFileItemList &itemsList)
2516 std::copy_if(itemsList.
cbegin(), itemsList.
cend(), std::back_inserter(items), [
this](
const KFileItem &item) {
2517 return isItemVisible(item) || matchesMimeFilter(item);
2520 Q_EMIT q->itemsDeleted(items);
2531void KCoreDirListerPrivate::slotInfoMessage(
KJob *,
const QString &message)
2533 Q_EMIT q->infoMessage(message);
2536void KCoreDirListerPrivate::slotPercent(
KJob *job,
unsigned long pcnt)
2538 jobData[
static_cast<KIO::ListJob *
>(job)].percent = pcnt;
2544 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2545 const JobData &data = dataIt.value();
2546 result += data.percent * data.totalSize;
2547 size += data.totalSize;
2555 Q_EMIT q->percent(result);
2558void KCoreDirListerPrivate::slotTotalSize(
KJob *job, qulonglong size)
2560 jobData[
static_cast<KIO::ListJob *
>(job)].totalSize = size;
2563 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2564 result += dataIt.value().totalSize;
2567 Q_EMIT q->totalSize(result);
2570void KCoreDirListerPrivate::slotProcessedSize(
KJob *job, qulonglong size)
2572 jobData[
static_cast<KIO::ListJob *
>(job)].processedSize = size;
2575 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2576 result += dataIt.value().processedSize;
2579 Q_EMIT q->processedSize(result);
2582void KCoreDirListerPrivate::slotSpeed(
KJob *job,
unsigned long spd)
2587 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2588 result += dataIt.value().speed;
2591 Q_EMIT q->speed(result);
2594uint KCoreDirListerPrivate::numJobs()
2598 qCDebug(KIO_CORE_DIRLISTER) << q <<
"numJobs:" << jobData.count();
2599 for (
auto it = jobData.cbegin(); it != jobData.cend(); ++it) {
2600 qCDebug(KIO_CORE_DIRLISTER) << (
void *)it.key();
2601 qCDebug(KIO_CORE_DIRLISTER) << it.key();
2605 return jobData.count();
2610 jobData.remove(job);
2615 KCoreDirListerPrivate::JobData data;
2618 data.processedSize = 0;
2621 d->jobData.insert(job, data);
2622 d->complete =
false;
2625void KCoreDirListerPrivate::connectJob(
KIO::ListJob *job)
2628 slotInfoMessage(job, plain);
2632 slotPercent(job, _percent);
2636 slotTotalSize(job, _size);
2639 slotProcessedSize(job, _psize);
2641 q->connect(job, &
KJob::speed, q, [
this](
KJob *job, qulonglong _speed) {
2642 slotSpeed(job, _speed);
2653 QList<KFileItem> *allItems = s_kDirListerCache.localData().itemsForDir(dir);
2659 if (which == AllItems) {
2662 std::copy_if(allItems->
cbegin(), allItems->
cend(), std::back_inserter(result), [
this](
const KFileItem &item) {
2663 return d->isItemVisible(item) && d->matchesMimeFilter(item);
2669bool KCoreDirLister::delayedMimeTypes()
const
2671 return d->delayedMimeTypes;
2676 d->delayedMimeTypes = delayedMimeTypes;
2680void KCoreDirListerPrivate::redirect(
const QUrl &oldUrl,
const QUrl &newUrl,
bool keepItems)
2686 rootFileItem.setUrl(newUrl);
2691 const int idx = lstDirs.indexOf(oldUrl);
2693 qCWarning(KIO_CORE) <<
"Unexpected redirection from" << oldUrl <<
"to" << newUrl <<
"but this dirlister is currently listing/holding" << lstDirs;
2695 lstDirs[idx] = newUrl;
2698 if (lstDirs.count() == 1) {
2704 Q_EMIT q->clearDir(oldUrl);
2707 Q_EMIT q->redirection(oldUrl, newUrl);
2710void KCoreDirListerCacheDirectoryData::moveListersWithoutCachedItemsJob(
const QUrl &url)
2718 while (lister_it.hasNext()) {
2720 if (!kdl->d->cachedItemsJobForUrl(url)) {
2724 Q_ASSERT(!listersCurrentlyHolding.contains(kdl));
2725 if (!listersCurrentlyHolding.contains(kdl)) {
2726 listersCurrentlyHolding.append(kdl);
2730 qCDebug(KIO_CORE_DIRLISTER) <<
"Not moving" << kdl <<
"to listersCurrentlyHolding because it still has job" << kdl->d->m_cachedItemsJobs;
2737 if (s_kDirListerCache.hasLocalData()) {
2738 return s_kDirListerCache.localData().itemForUrl(
url);
2744bool KCoreDirLister::autoErrorHandlingEnabled()
const
2746 return d->m_autoErrorHandling;
2751 d->m_autoErrorHandling = enable;
2754KCoreDirListerCache::CacheHiddenFile *KCoreDirListerCache::cachedDotHiddenForDir(
const QString &dir)
2757 QFile dotHiddenFile(path);
2759 if (dotHiddenFile.exists()) {
2761 CacheHiddenFile *cachedDotHiddenFile = m_cacheHiddenFiles.object(path);
2763 if (cachedDotHiddenFile && mtime <= cachedDotHiddenFile->mtime) {
2766 return cachedDotHiddenFile;
2770 std::set<QString> filesToHide;
2772 while (!stream.atEnd()) {
2775 filesToHide.
insert(name);
2779 m_cacheHiddenFiles.
insert(path,
new CacheHiddenFile(mtime, std::move(filesToHide)));
2781 return m_cacheHiddenFiles.object(path);
2789#include "moc_kcoredirlister.cpp"
2790#include "moc_kcoredirlister_p.cpp"
Helper class for the kiojob used to list and update a directory.
void emitChanges()
Actually emit the changes made with setShowHiddenFiles, setDirOnlyMode, setNameFilter and setMimeFilt...
virtual void jobStarted(KIO::ListJob *)
Reimplemented by KDirLister to associate windows with jobs.
void stop()
Stop listing all directories currently being listed.
void forgetDirs(const QUrl &dirUrl)
Stop listening for further changes in the given directory.
static KFileItem cachedItemForUrl(const QUrl &url)
Return the KFileItem for the given URL, if it was listed recently and it's still in the cache,...
void setShowHiddenFiles(bool showHiddenFiles)
Toggles whether hidden files (e.g.
void listingDirCompleted(const QUrl &dirUrl)
Tell the view that the listing of the directory dirUrl is finished.
WhichItems
Used by items() and itemsForDir() to specify whether you want all items for a directory or just the f...
void updateDirectory(const QUrl &dirUrl)
Update the directory dirUrl.
void clear()
Signals to the view to remove all items (when e.g. going from dirA to dirB).
void setNameFilter(const QString &filter)
Set a name filter to only list items matching this name, e.g. "*.cpp".
QList< QUrl > directories() const
Returns all URLs that are listed by this KCoreDirLister.
bool openUrl(const QUrl &dirUrl, OpenUrlFlags flags=NoFlags)
Run the directory lister on the given url.
void setMimeExcludeFilter(const QStringList &mimeList)
Filtering should be done with KFileFilter.
QUrl url() const
Returns the top level URL that is listed by this KCoreDirLister.
void setRequestMimeTypeWhileListing(bool request)
Toggles whether to request MIME types from the worker or in-process.
void started(const QUrl &dirUrl)
Tell the view that this KCoreDirLister has started to list dirUrl.
KFileItemList items(WhichItems which=FilteredItems) const
Returns the items listed for the current url().
KFileItem findByUrl(const QUrl &url) const
Find an item by its URL.
void setDelayedMimeTypes(bool delayedMimeTypes)
Delayed MIME types feature: If enabled, MIME types will be fetched on demand, which leads to a faster...
QStringList mimeFilters() const
Returns the list of MIME type based filters, as set via setMimeFilter().
void clearDir(const QUrl &dirUrl)
Signals to the view to clear all items from directory dirUrl.
void setAutoUpdate(bool enable)
Toggle automatic directory updating, when a directory changes (using KDirWatch).
~KCoreDirLister() override
Destroy the directory lister.
void setMimeFilter(const QStringList &mimeList)
Set MIME type based filter to only list items matching the given MIME types.
KFileItem findByName(const QString &name) const
Find an item by its name.
void setDirOnlyMode(bool dirsOnly)
Call this to list only directories (by default all items (directories and files) are listed).
KCoreDirLister(QObject *parent=nullptr)
Create a directory lister.
@ Reload
Indicates whether to use the cache or to reread the directory from the disk.
@ Keep
Previous directories aren't forgotten.
KFileItem rootItem() const
Returns the file item of the URL.
void listingDirCanceled(const QUrl &dirUrl)
Tell the view that the listing of the directory dirUrl was canceled.
bool isFinished() const
Returns true if no I/O operation is currently in progress.
void canceled()
Tell the view that the user canceled the listing.
void completed()
Tell the view that listing is finished.
KFileItemList itemsForDir(const QUrl &dirUrl, WhichItems which=FilteredItems) const
Returns the items listed for the given dirUrl.
void clearMimeFilter()
Clears the MIME type based filter.
void setAutoErrorHandlingEnabled(bool enable)
Enable or disable auto error handling.
static KDirWatch * self()
void deleted(const QString &path)
void dirty(const QString &path)
void created(const QString &path)
List of KFileItems, which adds a few helper methods to QList<KFileItem>.
A KFileItem is a generic class to handle a file, local or remote.
void setUrl(const QUrl &url)
Sets the item's URL.
bool cmp(const KFileItem &item) const
Somewhat like a comparison operator, but more explicit, and it can detect that two fileitems differ i...
void refreshMimeType()
Re-reads MIME type information.
bool exists() const
returns whether the KFileItem exists on-disk Call only after initialization (i.e KIO::stat or refresh...
bool isNull() const
Return true if default-constructed.
KIO::UDSEntry entry() const
Returns the UDS entry.
void setLocalPath(const QString &path)
Sets the item's local path (UDS_LOCAL_PATH).
void refresh()
Throw away and re-read (for local files) all information about the file.
void setName(const QString &name)
Sets the item's name (i.e. the filename).
The base class for all jobs.
void addMetaData(const QString &key, const QString &value)
Add key/value pair to the meta data that is sent to the worker.
A ListJob is allows you to get the get the content of a directory.
const QUrl & redirectionUrl() const
Returns the ListJob's redirection URL.
void redirection(KIO::Job *job, const QUrl &url)
Signals a redirection.
void entries(KIO::Job *job, const KIO::UDSEntryList &list)
This signal emits the entry found by the job while listing.
const QUrl & url() const
Returns the SimpleJob's URL.
QString stringValue(uint field) const
@ UDS_URL
An alternative URL (If different from the caption).
@ UDS_NAME
Filename - as displayed in directory listings etc.
virtual void showErrorMessage()
void processedSize(KJob *job, qulonglong size)
KJobUiDelegate * uiDelegate() const
void infoMessage(KJob *job, const QString &message)
void totalSize(KJob *job, qulonglong size)
bool kill(KJob::KillVerbosity verbosity=KJob::Quietly)
void percentChanged(KJob *job, unsigned long percent)
void speed(KJob *job, unsigned long speed)
Ptr findByPath(const QString &path) const
Find the mountpoint on which resides path For instance if /home is a separate partition,...
@ NeedMountOptions
Also fetch the options used when mounting, see KMountPoint::mountOptions().
static List possibleMountPoints(DetailsNeededFlags infoNeeded=BasicInfoNeeded)
This function gives a list of all possible mountpoints.
void stop(Ekos::AlignState mode)
Q_SCRIPTABLE Q_NOREPLY void abort()
Q_SCRIPTABLE Q_NOREPLY void start()
KIOCORE_EXPORT ListJob * listDir(const QUrl &url, JobFlags flags=DefaultFlags, ListJob::ListFlags listFlags=ListJob::ListFlag::IncludeHidden)
List the contents of url, which is assumed to be a directory.
@ HideProgressInfo
Hide progress information dialog, i.e. don't show a GUI.
qulonglong filesize_t
64-bit file size
@ StatDefaultDetails
Default StatDetail flag when creating a StatJob.
QString path(const QString &relativePath)
KIOCORE_EXPORT QString dir(const QString &fileClass)
Returns the most recently used directory associated with this file-class.
KIOCORE_EXPORT QStringList list(const QString &fileClass)
Returns a list of directories associated with this file-class.
const QList< QKeySequence > & reload()
QString name(StandardShortcut id)
QDBusConnection sessionBus()
QString cleanPath(const QString &path)
QString absolutePath() const const
QString canonicalFilePath() const const
QString fileName() const const
QDateTime lastModified() const const
const_iterator cbegin() const const
const_iterator cend() const const
iterator insert(const Key &key, const T &value)
qsizetype size() const const
void append(QList< T > &&value)
const_iterator cbegin() const const
const_iterator cend() const const
const_iterator constBegin() const const
bool contains(const AT &value) const const
qsizetype count() const const
iterator erase(const_iterator begin, const_iterator end)
iterator insert(const_iterator before, parameter_type value)
bool isEmpty() const const
void prepend(parameter_type value)
void remove(qsizetype i, qsizetype n)
void reserve(qsizetype size)
qsizetype size() const const
T value(qsizetype i) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
Key key(const T &value, const Key &defaultKey) const const
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
bool isValid() const const
bool disconnect(const QMetaObject::Connection &connection)
QVariant property(const char *name) const const
bool setProperty(const char *name, QVariant &&value)
QString wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
QString & append(QChar ch)
const_iterator cend() const const
iterator erase(const_iterator first, const_iterator last)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
QString & insert(qsizetype position, QChar ch)
bool isEmpty() const const
bool isNull() const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
QString number(double n, char format, int precision)
QString & remove(QChar ch, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
QUrl adjusted(FormattingOptions options) const const
QString fileName(ComponentFormattingOptions options) const const
QUrl fromLocalFile(const QString &localFile)
QList< QUrl > fromStringList(const QStringList &urls, ParsingMode mode)
bool isLocalFile() const const
bool isParentOf(const QUrl &childUrl) const const
bool isValid() const const
bool matches(const QUrl &url, FormattingOptions options) const const
QString path(ComponentFormattingOptions options) const const
QString toLocalFile() const const
bool toBool() const const