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()) {
1785 bool inPendingUpdates =
false;
1786 bool inPendingRemoteUpdates =
false;
1788 std::set<QString>::iterator pu_it;
1789 std::set<KFileItem>::iterator pru_it;
1791 pu_it = pendingUpdates.find(tmp.url().
toLocalFile());
1792 inPendingUpdates = pu_it != pendingUpdates.end();
1794 pru_it = pendingRemoteUpdates.find(tmp);
1795 inPendingRemoteUpdates = pru_it != pendingRemoteUpdates.end();
1799 if (inPendingRemoteUpdates || inPendingUpdates || !tmp.
cmp(item)) {
1800 if (inPendingRemoteUpdates) {
1801 pendingRemoteUpdates.erase(pru_it);
1803 if (inPendingUpdates) {
1804 pendingUpdates.erase(pu_it);
1807 qCDebug(KIO_CORE_DIRLISTER) <<
"file changed:" << tmp.name();
1809 reinsert(item, tmp.url());
1811 kdl->d->addRefreshItem(jobUrl, tmp, item);
1815 fileItems.erase(fiit);
1817 qCDebug(KIO_CORE_DIRLISTER) <<
"new file:" <<
name;
1823 std::sort(newItems.
begin(), newItems.
end());
1826 dir->insertSortedItems(newItems);
1829 kdl->d->addNewItems(jobUrl, newItems);
1832 runningListJobs.
remove(job);
1834 if (!fileItems.isEmpty()) {
1835 deleteUnmarkedItems(listers,
dir->lstItems, fileItems);
1839 kdl->d->emitItems();
1841 kdl->d->jobDone(job);
1842 Q_EMIT kdl->listingDirCompleted(jobUrl);
1843 if (kdl->d->numJobs() == 0) {
1844 kdl->d->complete =
true;
1845 Q_EMIT kdl->completed();
1851 processPendingUpdates();
1854 updateDirectory(jobUrl);
1862 for (
auto it = runningListJobs.cbegin(); it != runningListJobs.cend(); ++it) {
1866 if (jobUrl == url && job != not_job) {
1884 runningListJobs.remove(job);
1896 for (
auto kit = itemsToDelete.
cbegin(), endIt = itemsToDelete.
cend(); kit != endIt; ++kit) {
1898 deletedItems.
append(item);
1899 qCDebug(KIO_CORE_DIRLISTER) <<
"deleted:" << item.name() << item;
1903 auto it = std::remove_if(lstItems.
begin(), lstItems.
end(), [&itemsToDelete](
const KFileItem &item) {
1904 return itemsToDelete.contains(item.name());
1906 lstItems.
erase(it, lstItems.
end());
1908 itemsDeleted(listers, deletedItems);
1914 kdl->d->emitItemsDeleted(deletedItems);
1917 for (
const KFileItem &item : deletedItems) {
1919 deleteDir(item.url());
1924void KCoreDirListerCache::deleteDir(
const QUrl &_dirUrl)
1926 qCDebug(KIO_CORE_DIRLISTER) << _dirUrl;
1936 auto itu = itemsInUse.
cbegin();
1937 const auto ituend = itemsInUse.cend();
1938 for (; itu != ituend; ++itu) {
1939 const QUrl &deletedUrl = itu.key();
1940 if (dirUrl == deletedUrl || dirUrl.
isParentOf(deletedUrl)) {
1941 affectedItems.
append(deletedUrl);
1945 for (
const QUrl &deletedUrl :
std::as_const(affectedItems)) {
1947 auto dit = directoryData.constFind(deletedUrl);
1948 if (dit != directoryData.cend()) {
1952 stopListingUrl(kdl, deletedUrl);
1961 if (kdl->d->url == deletedUrl) {
1963 if (!kdl->d->rootFileItem.isNull()) {
1964 Q_EMIT kdl->itemsDeleted(
KFileItemList{kdl->d->rootFileItem});
1969 const bool treeview = kdl->d->lstDirs.count() > 1;
1971 Q_EMIT kdl->clear();
1972 kdl->d->lstDirs.clear();
1974 kdl->d->lstDirs.removeAll(deletedUrl);
1977 forgetDirs(kdl, deletedUrl, treeview);
1984 int count = itemsInUse.remove(deletedUrl);
1985 Q_ASSERT(count == 0);
1990 removeDirFromCache(dirUrl);
1994void KCoreDirListerCache::processPendingUpdates()
1996 std::set<KCoreDirLister *> listers;
1998 for (
const QString &file : pendingUpdates) {
1999 qCDebug(KIO_CORE_DIRLISTER) << file;
2007 if (!oldItem.
cmp(item)) {
2009 removedUrls.
append(oldItem.url());
2011 reinsert(item, oldItem.url());
2013 listers.merge(emitRefreshItem(oldItem, item));
2017 pendingUpdates.clear();
2019 kdl->d->emitItems();
2023 for (
const auto &removedUrl : removedUrls) {
2028 for (
const QString &dir : pendingDirectoryUpdates) {
2031 pendingDirectoryUpdates.clear();
2035void KCoreDirListerCache::printDebug()
2037 qCDebug(KIO_CORE_DIRLISTER) <<
"Items in use:";
2038 auto itu = itemsInUse.constBegin();
2039 const auto ituend = itemsInUse.constEnd();
2040 for (; itu != ituend; ++itu) {
2041 qCDebug(KIO_CORE_DIRLISTER) <<
" " << itu.key() <<
"URL:" << itu.value()->url
2042 <<
"rootItem:" << (!itu.value()->rootItem.isNull() ? itu.value()->rootItem.url() :
QUrl())
2043 <<
"autoUpdates refcount:" << itu.value()->autoUpdates <<
"complete:" << itu.value()->complete
2044 << QStringLiteral(
"with %1 items.").arg(itu.value()->lstItems.count());
2048 qCDebug(KIO_CORE_DIRLISTER) <<
"Directory data:";
2050 for (; dit != directoryData.constEnd(); ++dit) {
2056 qCDebug(KIO_CORE_DIRLISTER) <<
" " << dit.key() << listers.
count() <<
"listers:" <<
list;
2058 if (!listit->d->m_cachedItemsJobs.isEmpty()) {
2059 qCDebug(KIO_CORE_DIRLISTER) <<
" Lister" << listit <<
"has CachedItemsJobs" << listit->d->m_cachedItemsJobs;
2060 }
else if (
KIO::ListJob *listJob = jobForUrl(dit.key())) {
2061 qCDebug(KIO_CORE_DIRLISTER) <<
" Lister" << listit <<
"has ListJob" << listJob;
2063 listersWithoutJob.
append(listit);
2072 qCDebug(KIO_CORE_DIRLISTER) <<
" " << dit.key() << holders.
count() <<
"holders:" <<
list;
2076 qCDebug(KIO_CORE_DIRLISTER) <<
"Jobs:";
2077 for (; jit != runningListJobs.
end(); ++jit) {
2078 qCDebug(KIO_CORE_DIRLISTER) <<
" " << jit.
key() <<
"listing" << joburl(jit.
key()) <<
":" << (*jit).count() <<
"entries.";
2081 qCDebug(KIO_CORE_DIRLISTER) <<
"Items in cache:";
2082 const QList<QUrl> cachedDirs = itemsCached.keys();
2083 for (
const QUrl &cachedDir : cachedDirs) {
2084 DirItem *dirItem = itemsCached.object(cachedDir);
2085 qCDebug(KIO_CORE_DIRLISTER) <<
" " << cachedDir
2086 <<
"rootItem:" << (!dirItem->rootItem.isNull() ? dirItem->rootItem.url().toString() : QStringLiteral(
"NULL")) <<
"with"
2087 << dirItem->lstItems.
count() <<
"items.";
2092 qCWarning(KIO_CORE) <<
"Fatal Error: HUH? Lister" << listit <<
"is supposed to be listing, but has no job!";
2100 , d(new KCoreDirListerPrivate(this))
2102 qCDebug(KIO_CORE_DIRLISTER) <<
"+KCoreDirLister";
2113 qCDebug(KIO_CORE_DIRLISTER) <<
"~KCoreDirLister" <<
this;
2116 if (!qApp->closingDown()) {
2118 s_kDirListerCache.localData().forgetDirs(
this);
2126 if (d->hasPendingChanges && (_flags &
Keep)) {
2130 d->hasPendingChanges =
false;
2132 return s_kDirListerCache.localData().listDir(
this, _url, _flags &
Keep, _flags &
Reload);
2137 s_kDirListerCache.localData().stop(
this);
2142 s_kDirListerCache.localData().stopListingUrl(
this, _url);
2147 s_kDirListerCache.localData().forgetDirs(
this, _url,
true);
2150bool KCoreDirLister::autoUpdate()
const
2152 return d->autoUpdate;
2157 if (d->autoUpdate == enable) {
2161 d->autoUpdate = enable;
2162 s_kDirListerCache.localData().setAutoUpdate(
this, enable);
2165bool KCoreDirLister::showHiddenFiles()
const
2167 return d->settings.isShowingDotFiles;
2176 d->prepareForSettingsChange();
2180bool KCoreDirLister::dirOnlyMode()
const
2182 return d->settings.dirOnlyMode;
2187 if (d->settings.dirOnlyMode == dirsOnly) {
2191 d->prepareForSettingsChange();
2192 d->settings.dirOnlyMode = dirsOnly;
2195bool KCoreDirLister::requestMimeTypeWhileListing()
const
2197 return d->requestMimeTypeWhileListing;
2202 if (d->requestMimeTypeWhileListing == request) {
2206 d->requestMimeTypeWhileListing = request;
2207 if (d->requestMimeTypeWhileListing) {
2211 s_kDirListerCache.localData().forgetDirs(
this);
2230void KCoreDirListerPrivate::emitChanges()
2232 if (!hasPendingChanges) {
2238 hasPendingChanges =
false;
2240 const KCoreDirListerPrivate::FilterSettings newSettings = settings;
2241 settings = oldSettings;
2244 std::set<QString> oldVisibleItems;
2245 for (
const QUrl &dir :
std::as_const(lstDirs)) {
2246 const QList<KFileItem> *itemList = s_kDirListerCache.localData().itemsForDir(dir);
2251 for (
const KFileItem &item : *itemList) {
2252 if (isItemVisible(item) && matchesMimeFilter(item)) {
2253 oldVisibleItems.insert(item.name());
2258 settings = newSettings;
2261 for (
const QUrl &dir : dirs) {
2264 const QList<KFileItem> *itemList = s_kDirListerCache.localData().itemsForDir(dir);
2269 for (
const auto &item : *itemList) {
2270 const QString text = item.text();
2274 const bool wasVisible = oldVisibleItems.find(item.name()) != oldVisibleItems.
cend();
2275 const bool mimeFiltered = matchesMimeFilter(item);
2276 const bool nowVisible = isItemVisible(item) && mimeFiltered;
2277 if (nowVisible && !wasVisible) {
2278 addNewItem(dir, item);
2279 }
else if (!nowVisible && wasVisible) {
2280 if (!mimeFiltered) {
2281 lstMimeFilteredItems.append(item);
2283 deletedItems.
append(item);
2286 if (!deletedItems.
isEmpty()) {
2287 Q_EMIT q->itemsDeleted(deletedItems);
2291 oldSettings = settings;
2296 s_kDirListerCache.localData().updateDirectory(dirUrl);
2306 return d->rootFileItem;
2311 return s_kDirListerCache.localData().findByUrl(
this,
url);
2316 return s_kDirListerCache.localData().findByName(
this, name);
2323 if (d->nameFilter == nameFilter) {
2327 d->prepareForSettingsChange();
2329 d->settings.lstFilters.clear();
2330 d->nameFilter = nameFilter;
2340 return d->nameFilter;
2345 if (d->settings.mimeFilter == mimeFilter) {
2349 d->prepareForSettingsChange();
2351 d->settings.mimeFilter.clear();
2353 d->settings.mimeFilter = mimeFilter;
2359 if (d->settings.mimeExcludeFilter == mimeExcludeFilter) {
2363 d->prepareForSettingsChange();
2364 d->settings.mimeExcludeFilter = mimeExcludeFilter;
2369 d->prepareForSettingsChange();
2370 d->settings.mimeFilter.clear();
2371 d->settings.mimeExcludeFilter.clear();
2376 return d->settings.mimeFilter;
2381bool KCoreDirListerPrivate::matchesFilter(
const KFileItem &item)
const
2383 Q_ASSERT(!item.
isNull());
2389 if (!settings.isShowingDotFiles && item.isHidden()) {
2393 if (item.isDir() || settings.lstFilters.isEmpty()) {
2397 return std::any_of(settings.lstFilters.cbegin(), settings.lstFilters.cend(), [&item](
const QRegularExpression &filter) {
2398 return filter.match(item.text()).hasMatch();
2402bool KCoreDirListerPrivate::matchesMimeFilter(
const KFileItem &item)
const
2404 Q_ASSERT(!item.
isNull());
2406 if (settings.mimeFilter.isEmpty() && settings.mimeExcludeFilter.isEmpty()) {
2409 return doMimeFilter(item.mimetype(), settings.mimeFilter) && doMimeExcludeFilter(item.mimetype(), settings.mimeExcludeFilter);
2412bool KCoreDirListerPrivate::doMimeFilter(
const QString &mime,
const QStringList &filters)
const
2424 qCDebug(KIO_CORE_DIRLISTER) <<
"doMimeFilter: investigating:" << mimeptr.
name();
2425 return std::any_of(filters.
cbegin(), filters.
cend(), [&mimeptr](
const QString &filter) {
2426 return mimeptr.inherits(filter);
2430bool KCoreDirListerPrivate::doMimeExcludeFilter(
const QString &mime,
const QStringList &filters)
const
2432 return !std::any_of(filters.
cbegin(), filters.
cend(), [&mime](
const QString &filter) {
2433 return mime == filter;
2439void KCoreDirListerPrivate::addNewItem(
const QUrl &directoryUrl,
const KFileItem &item)
2441 if (!isItemVisible(item)) {
2445 qCDebug(KIO_CORE_DIRLISTER) <<
"in" << directoryUrl <<
"item:" << item.url();
2447 if (matchesMimeFilter(item)) {
2448 Q_ASSERT(!item.
isNull());
2449 lstNewItems[directoryUrl].append(item);
2451 Q_ASSERT(!item.
isNull());
2452 lstMimeFilteredItems.append(item);
2456void KCoreDirListerPrivate::addNewItems(
const QUrl &directoryUrl,
const QList<KFileItem> &items)
2461 for (
const auto &item : items) {
2462 addNewItem(directoryUrl, item);
2466void KCoreDirListerPrivate::addRefreshItem(
const QUrl &directoryUrl,
const KFileItem &oldItem,
const KFileItem &item)
2469 if (directoryUrl == item.url()) {
2470 lstRefreshItems.append({oldItem, item});
2474 const bool refreshItemWasFiltered = !isItemVisible(oldItem) || !matchesMimeFilter(oldItem);
2475 if (item.
exists() && isItemVisible(item) && matchesMimeFilter(item)) {
2476 if (refreshItemWasFiltered) {
2477 Q_ASSERT(!item.
isNull());
2478 lstNewItems[directoryUrl].append(item);
2480 Q_ASSERT(!item.
isNull());
2481 lstRefreshItems.append(qMakePair(oldItem, item));
2483 }
else if (!refreshItemWasFiltered) {
2487 Q_ASSERT(!oldItem.
isNull());
2488 lstRemoveItems.append(oldItem);
2492void KCoreDirListerPrivate::emitItems()
2494 if (!lstNewItems.empty()) {
2495 for (
auto it = lstNewItems.cbegin(); it != lstNewItems.cend(); ++it) {
2496 const auto &val = it.value();
2497 Q_EMIT q->itemsAdded(it.key(), val);
2498 Q_EMIT q->newItems(val);
2500 lstNewItems.clear();
2503 if (!lstMimeFilteredItems.empty()) {
2504 Q_EMIT q->itemsFilteredByMime(lstMimeFilteredItems);
2505 lstMimeFilteredItems.clear();
2508 if (!lstRefreshItems.empty()) {
2509 Q_EMIT q->refreshItems(lstRefreshItems);
2510 lstRefreshItems.clear();
2513 if (!lstRemoveItems.empty()) {
2514 Q_EMIT q->itemsDeleted(lstRemoveItems);
2515 lstRemoveItems.clear();
2519bool KCoreDirListerPrivate::isItemVisible(
const KFileItem &item)
const
2524 return (!settings.dirOnlyMode || item.isDir()) && matchesFilter(item);
2527void KCoreDirListerPrivate::emitItemsDeleted(
const KFileItemList &itemsList)
2530 std::copy_if(itemsList.
cbegin(), itemsList.
cend(), std::back_inserter(items), [
this](
const KFileItem &item) {
2531 return isItemVisible(item) || matchesMimeFilter(item);
2534 Q_EMIT q->itemsDeleted(items);
2545void KCoreDirListerPrivate::slotInfoMessage(
KJob *,
const QString &message)
2547 Q_EMIT q->infoMessage(message);
2550void KCoreDirListerPrivate::slotPercent(
KJob *job,
unsigned long pcnt)
2552 jobData[
static_cast<KIO::ListJob *
>(job)].percent = pcnt;
2558 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2559 const JobData &data = dataIt.value();
2560 result += data.percent * data.totalSize;
2561 size += data.totalSize;
2569 Q_EMIT q->percent(result);
2572void KCoreDirListerPrivate::slotTotalSize(
KJob *job, qulonglong size)
2574 jobData[
static_cast<KIO::ListJob *
>(job)].totalSize = size;
2577 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2578 result += dataIt.value().totalSize;
2581 Q_EMIT q->totalSize(result);
2584void KCoreDirListerPrivate::slotProcessedSize(
KJob *job, qulonglong size)
2586 jobData[
static_cast<KIO::ListJob *
>(job)].processedSize = size;
2589 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2590 result += dataIt.value().processedSize;
2593 Q_EMIT q->processedSize(result);
2596void KCoreDirListerPrivate::slotSpeed(
KJob *job,
unsigned long spd)
2601 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2602 result += dataIt.value().speed;
2605 Q_EMIT q->speed(result);
2608uint KCoreDirListerPrivate::numJobs()
2612 qCDebug(KIO_CORE_DIRLISTER) << q <<
"numJobs:" << jobData.count();
2613 for (
auto it = jobData.cbegin(); it != jobData.cend(); ++it) {
2614 qCDebug(KIO_CORE_DIRLISTER) << (
void *)it.key();
2615 qCDebug(KIO_CORE_DIRLISTER) << it.key();
2619 return jobData.count();
2624 jobData.remove(job);
2629 KCoreDirListerPrivate::JobData data;
2632 data.processedSize = 0;
2635 d->jobData.insert(job, data);
2636 d->complete =
false;
2639void KCoreDirListerPrivate::connectJob(
KIO::ListJob *job)
2642 slotInfoMessage(job, plain);
2646 slotPercent(job, _percent);
2650 slotTotalSize(job, _size);
2653 slotProcessedSize(job, _psize);
2655 q->connect(job, &
KJob::speed, q, [
this](
KJob *job, qulonglong _speed) {
2656 slotSpeed(job, _speed);
2667 QList<KFileItem> *allItems = s_kDirListerCache.localData().itemsForDir(dir);
2673 if (which == AllItems) {
2676 std::copy_if(allItems->
cbegin(), allItems->
cend(), std::back_inserter(result), [
this](
const KFileItem &item) {
2677 return d->isItemVisible(item) && d->matchesMimeFilter(item);
2683bool KCoreDirLister::delayedMimeTypes()
const
2685 return d->delayedMimeTypes;
2690 d->delayedMimeTypes = delayedMimeTypes;
2694void KCoreDirListerPrivate::redirect(
const QUrl &oldUrl,
const QUrl &newUrl,
bool keepItems)
2700 rootFileItem.setUrl(newUrl);
2705 const int idx = lstDirs.indexOf(oldUrl);
2707 qCWarning(KIO_CORE) <<
"Unexpected redirection from" << oldUrl <<
"to" << newUrl <<
"but this dirlister is currently listing/holding" << lstDirs;
2709 lstDirs[idx] = newUrl;
2712 if (lstDirs.count() == 1) {
2718 Q_EMIT q->clearDir(oldUrl);
2721 Q_EMIT q->redirection(oldUrl, newUrl);
2724void KCoreDirListerCacheDirectoryData::moveListersWithoutCachedItemsJob(
const QUrl &url)
2732 while (lister_it.hasNext()) {
2734 if (!kdl->d->cachedItemsJobForUrl(url)) {
2738 Q_ASSERT(!listersCurrentlyHolding.contains(kdl));
2739 if (!listersCurrentlyHolding.contains(kdl)) {
2740 listersCurrentlyHolding.append(kdl);
2744 qCDebug(KIO_CORE_DIRLISTER) <<
"Not moving" << kdl <<
"to listersCurrentlyHolding because it still has job" << kdl->d->m_cachedItemsJobs;
2751 if (s_kDirListerCache.hasLocalData()) {
2752 return s_kDirListerCache.localData().itemForUrl(
url);
2758bool KCoreDirLister::autoErrorHandlingEnabled()
const
2760 return d->m_autoErrorHandling;
2765 d->m_autoErrorHandling = enable;
2768KCoreDirListerCache::CacheHiddenFile *KCoreDirListerCache::cachedDotHiddenForDir(
const QString &dir)
2771 QFile dotHiddenFile(path);
2773 if (dotHiddenFile.exists()) {
2775 CacheHiddenFile *cachedDotHiddenFile = m_cacheHiddenFiles.object(path);
2777 if (cachedDotHiddenFile && mtime <= cachedDotHiddenFile->mtime) {
2780 return cachedDotHiddenFile;
2784 std::set<QString> filesToHide;
2786 while (!stream.atEnd()) {
2789 filesToHide.
insert(name);
2793 m_cacheHiddenFiles.
insert(path,
new CacheHiddenFile(mtime, std::move(filesToHide)));
2795 return m_cacheHiddenFiles.object(path);
2803#include "moc_kcoredirlister.cpp"
2804#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