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);
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);
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.listerCountByStatus(ListerStatus::Listing) == 0) {
154 dirData.insertOrModifyLister(lister, ListerStatus::Listing);
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.listersByStatus(ListerStatus::Listing);
214 qCDebug(KIO_CORE_DIRLISTER) <<
"Entry currently being listed:" << _url <<
"by" << dirData.listersByStatus(ListerStatus::Listing);
221 Q_ASSERT(!dirData.contains(lister, ListerStatus::Listing));
222 dirData.insertOrModifyLister(lister, ListerStatus::Listing);
225 if (lister->d->autoUpdate) {
226 itemU->incAutoUpdate();
233 lister->d->connectJob(job);
239 qCDebug(KIO_CORE_DIRLISTER) <<
"Listing" << itemU->lstItems.count() <<
"cached items soon";
240 auto *cachedItemsJob =
new KCoreDirListerPrivate::CachedItemsJob(lister, _url, _reload);
244 cachedItemsJob->setEmitCompleted(
false);
255KCoreDirListerPrivate::CachedItemsJob *KCoreDirListerPrivate::cachedItemsJobForUrl(
const QUrl &url)
const
257 for (CachedItemsJob *job : m_cachedItemsJobs) {
258 if (job->
url() == url) {
265KCoreDirListerPrivate::CachedItemsJob::CachedItemsJob(
KCoreDirLister *lister,
const QUrl &url,
bool reload)
270 , m_emitCompleted(true)
272 qCDebug(KIO_CORE_DIRLISTER) <<
"Creating CachedItemsJob" <<
this <<
"for lister" << lister << url;
273 if (lister->d->cachedItemsJobForUrl(url)) {
274 qCWarning(KIO_CORE) <<
"Lister" << lister <<
"has a cached items job already for" << url;
276 lister->d->m_cachedItemsJobs.append(
this);
282void KCoreDirListerPrivate::CachedItemsJob::done()
287 s_kDirListerCache.localData().emitItemsFromCache(
this, m_lister, m_url, m_reload, m_emitCompleted);
291bool KCoreDirListerPrivate::CachedItemsJob::doKill()
293 qCDebug(KIO_CORE_DIRLISTER) <<
this;
294 s_kDirListerCache.localData().forgetCachedItemsJob(
this, m_lister, m_url);
295 if (!property(
"_kdlc_silent").toBool()) {
296 Q_EMIT m_lister->listingDirCanceled(m_url);
298 Q_EMIT m_lister->canceled();
304void KCoreDirListerCache::emitItemsFromCache(KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob,
310 lister->d->complete =
false;
312 DirItem *itemU = s_kDirListerCache.localData().itemsInUse.value(_url);
314 qCWarning(KIO_CORE) <<
"Can't find item for directory" << _url <<
"anymore";
317 const KFileItem rootItem = itemU->rootItem;
318 _reload = _reload || !itemU->complete;
320 if (lister->d->rootFileItem.isNull() && !rootItem.
isNull() && lister->d->url == _url) {
321 lister->d->rootFileItem = rootItem;
324 qCDebug(KIO_CORE_DIRLISTER) <<
"emitting" << items.
count() <<
"for lister" << lister;
325 lister->d->addNewItems(_url, items);
326 lister->d->emitItems();
330 forgetCachedItemsJob(cachedItemsJob, lister, _url);
336 if (_emitCompleted) {
337 lister->d->complete =
true;
343 updateDirectory(_url);
348void KCoreDirListerCache::forgetCachedItemsJob(KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob,
KCoreDirLister *lister,
const QUrl &_url)
353 lister->d->m_cachedItemsJobs.removeAll(cachedItemsJob);
355 KCoreDirListerCacheDirectoryData &dirData = directoryData[_url];
356 Q_ASSERT(dirData.contains(lister, ListerStatus::Listing));
360 Q_ASSERT(!dirData.contains(lister, ListerStatus::Holding));
361 qCDebug(KIO_CORE_DIRLISTER) <<
"Moving from listing to holding, because no more job" << lister << _url;
362 dirData.insertOrModifyLister(lister, ListerStatus::Holding);
364 qCDebug(KIO_CORE_DIRLISTER) <<
"Still having a listjob" << listJob <<
", so not moving to currently-holding.";
368void KCoreDirListerCache::stop(
KCoreDirLister *lister,
bool silent)
370 qCDebug(KIO_CORE_DIRLISTER) <<
"lister:" << lister <<
"silent=" << silent;
373 for (
const QUrl &url : urls) {
374 stopListingUrl(lister, url, silent);
378void KCoreDirListerCache::stopListingUrl(
KCoreDirLister *lister,
const QUrl &_u,
bool silent)
383 KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob = lister->d->cachedItemsJobForUrl(url);
384 if (cachedItemsJob) {
386 cachedItemsJob->setProperty(
"_kdlc_silent",
true);
388 cachedItemsJob->kill();
392 qCDebug(KIO_CORE_DIRLISTER) << lister <<
" url=" << url;
394 const auto dirit = directoryData.find(url);
395 if (dirit == directoryData.end()) {
398 KCoreDirListerCacheDirectoryData &dirData = dirit.value();
399 auto listersCurrentlyListing = dirData.listersByStatus(ListerStatus::Listing);
400 if (listersCurrentlyListing.contains(lister)) {
401 qCDebug(KIO_CORE_DIRLISTER) <<
" found lister" << lister <<
"in list - for" << url;
402 if (listersCurrentlyListing.count() == 1) {
404 stopListJob(url, silent);
407 dirData.removeLister(lister);
417void KCoreDirListerCache::stopListJob(
const QUrl &url,
bool silent)
430 qCDebug(KIO_CORE_DIRLISTER) <<
"Killing list job" << job <<
"for" << url;
434 job->
kill(KJob::EmitResult);
438void KCoreDirListerCache::setAutoUpdate(
KCoreDirLister *lister,
bool enable)
442 for (
const QUrl &url : std::as_const(lister->d->lstDirs)) {
443 DirItem *dirItem = itemsInUse.value(url);
446 dirItem->incAutoUpdate();
448 dirItem->decAutoUpdate();
455 qCDebug(KIO_CORE_DIRLISTER) << lister;
457 Q_EMIT lister->
clear();
462 const QList<QUrl> lstDirsCopy = lister->d->lstDirs;
463 lister->d->lstDirs.clear();
465 qCDebug(KIO_CORE_DIRLISTER) <<
"Iterating over dirs" << lstDirsCopy;
467 for (
const QUrl &dir : lstDirsCopy) {
468 forgetDirs(lister, dir,
false, possibleMountPoints);
474 KMountPoint::Ptr mp = possibleMountPoints.
findByPath(path);
476 if (possibleMountPoints.
isEmpty()) {
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.removeLister(lister);
501 lister->d->jobDone(job);
504 DirItem *item = itemsInUse.value(url);
506 bool insertIntoCache =
false;
508 if (dirData.totaListerCount() == 0) {
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) {
543 const bool isLocal = item->url.isLocalFile();
544 bool isManuallyMounted =
false;
545 bool containsManuallyMounted =
false;
547 isManuallyMounted = manually_mounted(item->url.toLocalFile(), possibleMountPoints);
548 if (!isManuallyMounted) {
552 auto kit = item->lstItems.constBegin();
553 const auto kend = item->lstItems.constEnd();
554 for (; kit != kend && !containsManuallyMounted; ++kit) {
555 if ((*kit).isDir() && manually_mounted((*kit).url().toLocalFile(), possibleMountPoints)) {
556 containsManuallyMounted =
true;
562 if (isManuallyMounted || containsManuallyMounted) {
563 qCDebug(KIO_CORE_DIRLISTER) <<
"Not adding a watch on " << item->url <<
" because it "
564 << (isManuallyMounted ?
"is manually mounted" :
"contains a manually mounted subdir");
565 item->complete =
false;
567 item->incAutoUpdate();
568 item->watchedWhileInCache =
true;
576 if (item && lister->d->autoUpdate) {
577 item->decAutoUpdate();
581 if (item && insertIntoCache) {
582 qCDebug(KIO_CORE_DIRLISTER) << lister <<
"item moved into cache:" << url;
583 itemsCached.insert(url, item);
587void KCoreDirListerCache::updateDirectory(
const QUrl &_dir)
589 qCDebug(KIO_CORE_DIRLISTER) << _dir;
592 if (!checkUpdate(dir)) {
594 if (checkUpdate(parentDir)) {
607 KCoreDirListerCacheDirectoryData &dirData = directoryData[
dir];
611 qCDebug(KIO_CORE_DIRLISTER) <<
dir <<
"listers=" << listers <<
"holders=" << holders;
624 KCoreDirListerPrivate::CachedItemsJob *cachedItemsJob = lister->d->cachedItemsJobForUrl(dir);
625 if (cachedItemsJob) {
626 cachedItemsJob->setEmitCompleted(
false);
627 cachedItemsJob->done();
628 delete cachedItemsJob;
633 qCDebug(KIO_CORE_DIRLISTER) <<
"Killed=" << killed;
638 if (!(listers.isEmpty() || killed)) {
639 qCWarning(KIO_CORE) <<
"The unexpected happened.";
640 qCWarning(KIO_CORE) <<
"listers for" <<
dir <<
"=" << listers;
641 qCWarning(KIO_CORE) <<
"job=" << job;
643 qCDebug(KIO_CORE_DIRLISTER) <<
"lister" << lister <<
"m_cachedItemsJobs=" << lister->d->m_cachedItemsJobs;
649 Q_ASSERT(listers.isEmpty() || killed);
654 const bool requestFromListers = std::any_of(listers.cbegin(), listers.cend(), [](
KCoreDirLister *lister) {
655 return lister->requestMimeTypeWhileListing();
657 const bool requestFromholders = std::any_of(holders.cbegin(), holders.cend(), [](
KCoreDirLister *lister) {
658 return lister->requestMimeTypeWhileListing();
661 if (requestFromListers || requestFromholders) {
668 qCDebug(KIO_CORE_DIRLISTER) <<
"update started in" <<
dir;
674 if (!holders.isEmpty()) {
677 holder->jobStarted(job);
678 Q_EMIT holder->started(dir);
682 holder->jobStarted(job);
688bool KCoreDirListerCache::checkUpdate(
const QUrl &_dir)
690 if (!itemsInUse.contains(_dir)) {
691 DirItem *item = itemsCached[_dir];
692 if (item && item->complete) {
693 item->complete =
false;
694 item->watchedWhileInCache =
false;
695 item->decAutoUpdate();
696 qCDebug(KIO_CORE_DIRLISTER) <<
"directory " << _dir <<
" not in use, marked dirty.";
699 qCDebug(KIO_CORE_DIRLISTER) <<
"aborted, directory " << _dir <<
" not in cache.";
706KFileItem KCoreDirListerCache::itemForUrl(
const QUrl &url)
const
708 return findByUrl(
nullptr, url);
711KCoreDirListerCache::DirItem *KCoreDirListerCache::dirItemForUrl(
const QUrl &dir)
const
714 DirItem *item = itemsInUse.value(url);
716 item = itemsCached[url];
723 DirItem *item = dirItemForUrl(dir);
724 return item ? &item->lstItems :
nullptr;
731 auto isMatch = [&_name](
const KFileItem &item) {
732 return _name == item.name();
735 for (
const auto &dirUrl : std::as_const(lister->d->lstDirs)) {
736 DirItem *dirItem = itemsInUse.value(dirUrl);
739 auto it = std::find_if(dirItem->lstItems.cbegin(), dirItem->lstItems.cend(), isMatch);
740 if (it != dirItem->lstItems.cend()) {
754 DirItem *dirItem = dirItemForUrl(parentDir);
757 if (!lister || lister->d->lstDirs.contains(parentDir)) {
759 auto it = std::lower_bound(dirItem->lstItems.begin(), dirItem->lstItems.end(), url);
760 if (it != dirItem->lstItems.end() && it->url() == url) {
769 dirItem = dirItemForUrl(url);
770 if (dirItem && !dirItem->rootItem.isNull() && dirItem->rootItem.url() == url) {
772 if (!lister || lister->d->lstDirs.contains(url)) {
773 return dirItem->rootItem;
780void KCoreDirListerCache::slotFilesAdded(
const QString &dir )
783 itemsAddedInDirectory(urlDir);
786void KCoreDirListerCache::itemsAddedInDirectory(
const QUrl &urlDir)
788 qCDebug(KIO_CORE_DIRLISTER) << urlDir;
789 const QList<QUrl> urls = directoriesForCanonicalPath(urlDir);
790 for (
const QUrl &u : urls) {
795void KCoreDirListerCache::slotFilesRemoved(
const QStringList &fileList)
800void KCoreDirListerCache::slotFilesRemoved(
const QList<QUrl> &fileList)
802 qCDebug(KIO_CORE_DIRLISTER) << fileList.
count();
807 for (
const QUrl &url : fileList) {
808 const QList<QUrl> dirUrls = directoriesForCanonicalPath(url);
809 for (
const QUrl &dir : dirUrls) {
810 DirItem *dirItem = dirItemForUrl(dir);
812 deletedSubdirs.
append(dir);
813 if (!dirItem->rootItem.isNull()) {
814 removedItemsByDir[url].append(dirItem->rootItem);
820 const QList<QUrl> parentDirUrls = directoriesForCanonicalPath(parentDir);
821 for (
const QUrl &dir : parentDirUrls) {
822 DirItem *dirItem = dirItemForUrl(dir);
827 const auto dirItemIt = std::find_if(dirItem->lstItems.cbegin(), dirItem->lstItems.cend(), [&url](
const KFileItem &fitem) {
828 return fitem.name() == url.fileName();
830 if (dirItemIt != dirItem->lstItems.cend()) {
832 removedItemsByDir[
dir].append(fileitem);
834 if (fileitem.
isNull() || fileitem.isDir()) {
835 deletedSubdirs.
append(url);
837 dirItem->lstItems.
erase(dirItemIt);
842 for (
auto rit = removedItemsByDir.
constBegin(), cend = removedItemsByDir.
constEnd(); rit != cend; ++rit) {
845 auto dit = directoryData.constFind(rit.key());
846 if (dit != directoryData.constEnd()) {
847 itemsDeleted((*dit).listersByStatus(ListerStatus::Holding), rit.value());
851 for (
const QUrl &url : std::as_const(deletedSubdirs)) {
858void KCoreDirListerCache::slotFilesChanged(
const QStringList &fileList)
860 qCDebug(KIO_CORE_DIRLISTER) << fileList;
862 for (
const QString &fileUrl : fileList) {
863 const QUrl url(fileUrl);
864 const KFileItem &fileitem = findByUrl(
nullptr, url);
866 qCDebug(KIO_CORE_DIRLISTER) <<
"item not found for" << url;
872 pendingRemoteUpdates.insert(fileitem);
882 for (
const QUrl &dirUrl : std::as_const(dirsToUpdate)) {
883 updateDirectory(dirUrl);
888 processPendingUpdates();
891void KCoreDirListerCache::slotFileRenamed(
const QString &_src,
const QString &_dst,
const QString &dstPath)
895 qCDebug(KIO_CORE_DIRLISTER) << src <<
"->" << dst;
901 KFileItem fileitem = findByUrl(
nullptr, oldurl);
903 qCDebug(KIO_CORE_DIRLISTER) <<
"Item not found:" << oldurl;
913 const KFileItem &existingDestItem = findByUrl(
nullptr, dst);
914 if (!existingDestItem.
isNull()) {
915 qCDebug(KIO_CORE_DIRLISTER) << dst <<
"already existed, let's delete it";
926 if (!nameOnly && fileitem.isDir()) {
927 renameDir(oldurl, dst);
930 fileitem = findByUrl(
nullptr, oldurl);
937 if (!oldItem.isLocalFile() && !oldItem.localPath().
isEmpty()
941 const QUrl &itemOldUrl = fileitem.url();
943 fileitem.
setName(dst.fileName());
953 fileitem.determineMimeType();
954 reinsert(fileitem, itemOldUrl);
956 const std::set<KCoreDirLister *> listers = emitRefreshItem(oldItem, fileitem);
958 lister->d->emitItems();
967std::set<KCoreDirLister *> KCoreDirListerCache::emitRefreshItem(
const KFileItem &oldItem,
const KFileItem &fileitem)
969 qCDebug(KIO_CORE_DIRLISTER) <<
"old:" << oldItem.name() << oldItem.url() <<
"new:" << fileitem.name() << fileitem.url();
972 DirectoryDataHash::iterator dit = directoryData.find(parentDir);
973 std::set<KCoreDirLister *> listers;
974 if (dit != directoryData.end()) {
975 for (
auto *lister : (*dit).allListers()) {
976 listers.insert(lister);
979 if (oldItem.isDir()) {
981 dit = directoryData.find(oldItem.url());
982 if (dit != directoryData.end()) {
983 for (
auto *lister : (*dit).allListers()) {
984 listers.insert(lister);
991 QUrl directoryUrl(oldItem.url());
992 if (oldItem.isDir() && lister->d->rootFileItem == oldItem) {
993 const KFileItem oldRootItem = lister->d->rootFileItem;
994 lister->d->rootFileItem = fileitem;
995 lister->d->addRefreshItem(directoryUrl, oldRootItem, fileitem);
998 lister->d->addRefreshItem(directoryUrl, oldItem, fileitem);
1004QList<QUrl> KCoreDirListerCache::directoriesForCanonicalPath(
const QUrl &dir)
const
1008 if (urlList.
size() > 1) {
1009 std::sort(urlList.
begin(), urlList.
end());
1010 auto end_unique = std::unique(urlList.
begin(), urlList.
end());
1011 urlList.
erase(end_unique, urlList.
end());
1017 if (dirs.count() > 1) {
1018 qCDebug(KIO_CORE_DIRLISTER) <<
dir <<
"known as" << dirs;
1027void KCoreDirListerCache::slotFileDirty(
const QString &path)
1029 qCDebug(KIO_CORE_DIRLISTER) <<
path;
1036 isDir = item.isDir();
1039 if (!info.exists()) {
1042 isDir = info.isDir();
1046 const QList<QUrl> urls = directoriesForCanonicalPath(url);
1047 for (
const QUrl &dir : urls) {
1048 handleDirDirty(dir);
1053 for (
const QUrl &dir : urls) {
1055 aliasUrl.setPath(Utils::concatPaths(aliasUrl.path(), url.
fileName()));
1056 handleFileDirty(aliasUrl);
1061void KCoreDirListerCache::handleDirDirty(
const QUrl &url)
1067 const QString dirPath = Utils::slashAppended(dir);
1069 for (
auto pendingIt = pendingUpdates.cbegin(); pendingIt != pendingUpdates.cend(); ) {
1070 const QString updPath = *pendingIt;
1071 qCDebug(KIO_CORE_DIRLISTER) <<
"had pending update" << updPath;
1073 qCDebug(KIO_CORE_DIRLISTER) <<
"forgetting about individual update to" << updPath;
1074 pendingIt = pendingUpdates.
erase(pendingIt);
1080 if (checkUpdate(url)) {
1081 const auto [it, isInserted] = pendingDirectoryUpdates.insert(dir);
1082 if (isInserted && !pendingUpdateTimer.isActive()) {
1083 pendingUpdateTimer.start(200);
1089void KCoreDirListerCache::handleFileDirty(
const QUrl &url)
1092 const KFileItem &existingItem = findByUrl(
nullptr, url);
1094 if (existingItem.
isNull()) {
1096 handleDirDirty(dir);
1100 if (checkUpdate(dir)) {
1102 const auto [it, isInserted] = pendingUpdates.
insert(filePath);
1103 if (isInserted && !pendingUpdateTimer.isActive()) {
1104 pendingUpdateTimer.start(200);
1109void KCoreDirListerCache::slotFileCreated(
const QString &path)
1111 qCDebug(KIO_CORE_DIRLISTER) <<
path;
1118void KCoreDirListerCache::slotFileDeleted(
const QString &path)
1120 qCDebug(KIO_CORE_DIRLISTER) <<
path;
1125 for (
const QUrl &url : urls) {
1127 urlInfo.setPath(Utils::concatPaths(urlInfo.path(), fileName));
1128 fileUrls << urlInfo.toString();
1130 slotFilesRemoved(fileUrls);
1138 qCDebug(KIO_CORE_DIRLISTER) <<
"new entries for " << url;
1140 DirItem *
dir = itemsInUse.value(url);
1142 qCWarning(KIO_CORE) <<
"Internal error: job is listing" << url <<
"but itemsInUse only knows about" << itemsInUse.keys();
1147 DirectoryDataHash::iterator dit = directoryData.find(url);
1148 if (dit == directoryData.end()) {
1149 qCWarning(KIO_CORE) <<
"Internal error: job is listing" << url <<
"but directoryData doesn't know about that url, only about:" << directoryData.keys();
1150 Q_ASSERT(dit != directoryData.end());
1153 KCoreDirListerCacheDirectoryData &dirData = *dit;
1156 qCWarning(KIO_CORE) <<
"Internal error: job is listing" << url <<
"but directoryData says no listers are currently listing " << url;
1165 bool delayedMimeTypes =
true;
1167 delayedMimeTypes &= lister->d->delayedMimeTypes;
1170 CacheHiddenFile *cachedHidden =
nullptr;
1171 bool dotHiddenChecked =
false;
1173 for (
const auto &entry : entries) {
1189 dir->rootItem = itemForUrl(url);
1191 dir->rootItem =
KFileItem(entry, url, delayedMimeTypes,
true);
1195 if (lister->d->rootFileItem.isNull() && lister->d->url == url) {
1196 lister->d->rootFileItem =
dir->rootItem;
1200 KFileItem item(entry, url, delayedMimeTypes,
true);
1203 if (!dotHiddenChecked) {
1204 const QString localPath = item.localPath();
1207 cachedHidden = cachedDotHiddenForDir(rootItemPath);
1209 dotHiddenChecked =
true;
1213 if (cachedHidden && cachedHidden->listedFiles.find(name) != cachedHidden->listedFiles.cend()) {
1217 qCDebug(KIO_CORE_DIRLISTER) <<
"Adding item: " << item.url();
1223 std::sort(newItems.
begin(), newItems.
end());
1226 dir->insertSortedItems(newItems);
1229 lister->d->addNewItems(url, newItems);
1233 lister->d->emitItems();
1237void KCoreDirListerCache::slotResult(
KJob *j)
1245 runningListJobs.remove(job);
1247 QUrl jobUrl(joburl(job));
1250 qCDebug(KIO_CORE_DIRLISTER) <<
"finished listing" << jobUrl;
1252 const auto dit = directoryData.find(jobUrl);
1253 if (dit == directoryData.end()) {
1254 qCWarning(KIO_CORE) <<
"Nothing found in directoryData for URL" << jobUrl;
1258 Q_ASSERT(dit != directoryData.end());
1261 KCoreDirListerCacheDirectoryData &dirData = *dit;
1262 if (dirData.listerCountByStatus(ListerStatus::Listing) == 0) {
1263 qCWarning(KIO_CORE) <<
"OOOOPS, nothing in directoryData.listersCurrentlyListing for" << jobUrl;
1268 Q_ASSERT(dirData.listerCountByStatus(ListerStatus::Listing) != 0);
1275 Q_ASSERT(dirData.listerCountByStatus(ListerStatus::Holding) == 0);
1276 dirData.moveListersWithoutCachedItemsJob(jobUrl);
1279 bool errorShown =
false;
1281 lister->d->jobDone(job);
1282 if (job->
error() != KJob::KilledJobError) {
1284 if (lister->d->m_autoErrorHandling && !errorShown) {
1296 if (lister->d->numJobs() == 0) {
1297 lister->d->complete =
true;
1304 DirItem *
dir = itemsInUse.value(jobUrl);
1306 dir->complete =
true;
1309 lister->d->jobDone(job);
1311 if (lister->d->numJobs() == 0) {
1312 lister->d->complete =
true;
1320 processPendingUpdates();
1323 updateDirectory(jobUrl);
1331void KCoreDirListerCache::slotRedirection(
KIO::Job *j,
const QUrl &url)
1343 if (oldUrl == newUrl) {
1344 qCDebug(KIO_CORE_DIRLISTER) <<
"New redirection url same as old, giving up.";
1346 }
else if (newUrl.isEmpty()) {
1347 qCDebug(KIO_CORE_DIRLISTER) <<
"New redirection url is empty, giving up.";
1351 qCDebug(KIO_CORE_DIRLISTER) << oldUrl <<
"->" << newUrl;
1364 DirItem *
dir = itemsInUse.take(oldUrl);
1367 DirectoryDataHash::iterator dit = directoryData.find(oldUrl);
1368 Q_ASSERT(dit != directoryData.end());
1369 KCoreDirListerCacheDirectoryData oldDirData = *dit;
1370 directoryData.erase(dit);
1371 Q_ASSERT(oldDirData.listerCountByStatus(ListerStatus::Listing) != 0);
1376 lister->d->redirect(oldUrl, newUrl,
false );
1383 holder->jobStarted(job);
1386 Q_EMIT holder->started(oldUrl);
1388 holder->d->redirect(oldUrl, newUrl,
false );
1393 DirItem *newDir = itemsInUse.
value(newUrl);
1395 qCDebug(KIO_CORE_DIRLISTER) << newUrl <<
"already in use";
1406 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1410 qCDebug(KIO_CORE_DIRLISTER) <<
"and it is currently listed";
1415 lister->d->jobDone(oldJob);
1418 lister->d->connectJob(job);
1423 curListers.
append(lister);
1426 curListers = listers;
1436 qCDebug(KIO_CORE_DIRLISTER) <<
"and it is currently held.";
1439 holder->jobStarted(job);
1440 Q_EMIT holder->started(newUrl);
1445 curHolders.
append(holder);
1448 curHolders = holders;
1454 if (lister->d->rootFileItem.isNull() && lister->d->url == newUrl) {
1455 lister->d->rootFileItem = newDir->rootItem;
1458 lister->d->addNewItems(newUrl, newDir->lstItems);
1459 lister->d->emitItems();
1461 }
else if ((newDir = itemsCached.take(newUrl))) {
1462 qCDebug(KIO_CORE_DIRLISTER) << newUrl <<
"is unused, but already in the cache.";
1465 itemsInUse.
insert(newUrl, newDir);
1466 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1467 newDirData.insertOrModifyListers(listers, ListerStatus::Listing);
1468 newDirData.insertOrModifyListers(holders, ListerStatus::Holding);
1472 if (lister->d->rootFileItem.isNull() && lister->d->url == newUrl) {
1473 lister->d->rootFileItem = newDir->rootItem;
1476 lister->d->addNewItems(newUrl, newDir->lstItems);
1477 lister->d->emitItems();
1480 qCDebug(KIO_CORE_DIRLISTER) << newUrl <<
"has not been listed yet.";
1484 dir->redirect(newUrl);
1485 itemsInUse.
insert(newUrl, dir);
1486 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1487 newDirData.insertOrModifyListers(listers, ListerStatus::Listing);
1488 newDirData.insertOrModifyListers(holders, ListerStatus::Holding);
1490 if (holders.isEmpty()) {
1511struct KCoreDirListerCache::ItemInUseChange {
1512 ItemInUseChange(
const QUrl &old,
const QUrl &newU, DirItem *di)
1523void KCoreDirListerCache::renameDir(
const QUrl &oldUrl,
const QUrl &newUrl)
1525 qCDebug(KIO_CORE_DIRLISTER) << oldUrl <<
"->" << newUrl;
1527 std::vector<ItemInUseChange> itemsToChange;
1528 std::set<KCoreDirLister *> listers;
1531 for (
auto itu = itemsInUse.begin(), ituend = itemsInUse.end(); itu != ituend; ++itu) {
1532 DirItem *
dir = itu.value();
1533 const QUrl &oldDirUrl = itu.key();
1534 qCDebug(KIO_CORE_DIRLISTER) <<
"itemInUse:" << oldDirUrl;
1536 if (oldDirUrl == oldUrl || oldUrl.
isParentOf(oldDirUrl)) {
1540 QUrl newDirUrl(newUrl);
1542 newDirUrl.setPath(Utils::concatPaths(newDirUrl.path(), relPath));
1544 qCDebug(KIO_CORE_DIRLISTER) <<
"new url=" << newDirUrl;
1547 dir->redirect(newDirUrl);
1556 const QUrl &oldItemUrl = oldItem.url();
1557 QUrl newItemUrl(oldItemUrl);
1558 newItemUrl.setPath(Utils::concatPaths(newDirUrl.path(), oldItemUrl.
fileName()));
1559 qCDebug(KIO_CORE_DIRLISTER) <<
"renaming" << oldItemUrl <<
"to" << newItemUrl;
1560 newItem.
setUrl(newItemUrl);
1562 listers.merge(emitRefreshItem(oldItem, newItem));
1570 lister->d->emitItems();
1575 for (
const ItemInUseChange &i : itemsToChange) {
1576 itemsInUse.remove(i.oldUrl);
1577 itemsInUse.insert(i.newUrl, i.dirItem);
1580 for (
const ItemInUseChange &i : itemsToChange) {
1581 emitRedirections(
QUrl(i.oldUrl),
QUrl(i.newUrl));
1585 removeDirFromCache(oldUrl);
1590void KCoreDirListerCache::emitRedirections(
const QUrl &_oldUrl,
const QUrl &_newUrl)
1592 qCDebug(KIO_CORE_DIRLISTER) << _oldUrl <<
"->" << _newUrl;
1602 DirectoryDataHash::iterator dit = directoryData.find(oldUrl);
1603 if (dit == directoryData.end()) {
1609 KCoreDirListerCacheDirectoryData &newDirData = directoryData[newUrl];
1614 lister->d->jobDone(job);
1618 newDirData.insertOrModifyListers(listers, ListerStatus::Listing);
1623 holder->d->jobDone(job);
1626 newDirData.insertOrModifyListers(holders, ListerStatus::Holding);
1628 directoryData.
erase(dit);
1630 if (!listers.isEmpty()) {
1631 updateDirectory(newUrl);
1635 Q_EMIT lister->
started(newUrl);
1641 holder->d->redirect(oldUrl, newUrl,
true );
1645void KCoreDirListerCache::removeDirFromCache(
const QUrl &dir)
1647 qCDebug(KIO_CORE_DIRLISTER) <<
dir;
1648 const QList<QUrl> cachedDirs = itemsCached.keys();
1649 for (
const QUrl &cachedDir : cachedDirs) {
1650 if (dir == cachedDir ||
dir.isParentOf(cachedDir)) {
1651 itemsCached.remove(cachedDir);
1658 runningListJobs[
static_cast<KIO::ListJob *
>(job)] += list;
1661void KCoreDirListerCache::slotUpdateResult(
KJob *j)
1666 QUrl jobUrl(joburl(job));
1669 qCDebug(KIO_CORE_DIRLISTER) <<
"finished update" << jobUrl;
1671 KCoreDirListerCacheDirectoryData &dirData = directoryData[jobUrl];
1674 dirData.moveListersWithoutCachedItemsJob(jobUrl);
1682 lister->d->jobDone(job);
1690 if (lister->d->numJobs() == 0) {
1691 lister->d->complete =
true;
1698 runningListJobs.remove(job);
1702 processPendingUpdates();
1706 DirItem *
dir = itemsInUse.value(jobUrl,
nullptr);
1708 qCWarning(KIO_CORE) <<
"Internal error: itemsInUse did not contain" << jobUrl;
1714 dir->complete =
true;
1718 bool delayedMimeTypes =
true;
1720 delayedMimeTypes &= lister->d->delayedMimeTypes;
1724 FileItemHash fileItems;
1728 for (
const KFileItem &item : std::as_const(
dir->lstItems)) {
1729 fileItems.insert(item.name(), item);
1732 CacheHiddenFile *cachedHidden =
nullptr;
1733 bool dotHiddenChecked =
false;
1736 for (
const auto &entry : buf) {
1738 KFileItem item(entry, jobUrl, delayedMimeTypes,
true);
1753 dir->rootItem = item;
1756 if (lister->d->rootFileItem.isNull() && lister->d->url == jobUrl) {
1757 lister->d->rootFileItem =
dir->rootItem;
1764 if (!dotHiddenChecked) {
1765 const QString localPath = item.localPath();
1768 cachedHidden = cachedDotHiddenForDir(rootItemPath);
1770 dotHiddenChecked =
true;
1775 if (cachedHidden && cachedHidden->listedFiles.find(name) != cachedHidden->listedFiles.cend()) {
1780 FileItemHash::iterator fiit = fileItems.find(item.name());
1781 if (fiit != fileItems.end()) {
1784 bool inPendingUpdates =
false;
1785 bool inPendingRemoteUpdates =
false;
1787 std::set<QString>::iterator pu_it;
1788 std::set<KFileItem>::iterator pru_it;
1790 pu_it = pendingUpdates.find(tmp.url().
toLocalFile());
1791 inPendingUpdates = pu_it != pendingUpdates.end();
1793 pru_it = pendingRemoteUpdates.find(tmp);
1794 inPendingRemoteUpdates = pru_it != pendingRemoteUpdates.end();
1798 if (inPendingRemoteUpdates || inPendingUpdates || !tmp.
cmp(item)) {
1799 if (inPendingRemoteUpdates) {
1800 pendingRemoteUpdates.erase(pru_it);
1802 if (inPendingUpdates) {
1803 pendingUpdates.erase(pu_it);
1806 qCDebug(KIO_CORE_DIRLISTER) <<
"file changed:" << tmp.name();
1808 reinsert(item, tmp.url());
1810 lister->d->addRefreshItem(jobUrl, tmp, item);
1814 fileItems.erase(fiit);
1816 qCDebug(KIO_CORE_DIRLISTER) <<
"new file:" <<
name;
1822 std::sort(newItems.
begin(), newItems.
end());
1825 dir->insertSortedItems(newItems);
1828 lister->d->addNewItems(jobUrl, newItems);
1831 runningListJobs.
remove(job);
1833 if (!fileItems.isEmpty()) {
1834 deleteUnmarkedItems(listers,
dir->lstItems, fileItems);
1838 lister->d->emitItems();
1840 lister->d->jobDone(job);
1842 if (lister->d->numJobs() == 0) {
1843 lister->d->complete =
true;
1850 processPendingUpdates();
1853 updateDirectory(jobUrl);
1861 for (
auto it = runningListJobs.cbegin(); it != runningListJobs.cend(); ++it) {
1865 if (jobUrl == url && job != not_job) {
1883 runningListJobs.remove(job);
1895 for (
auto kit = itemsToDelete.
cbegin(), endIt = itemsToDelete.
cend(); kit != endIt; ++kit) {
1897 deletedItems.
append(item);
1898 qCDebug(KIO_CORE_DIRLISTER) <<
"deleted:" << item.name() << item;
1902 auto it = std::remove_if(lstItems.
begin(), lstItems.
end(), [&itemsToDelete](
const KFileItem &item) {
1903 return itemsToDelete.contains(item.name());
1905 lstItems.
erase(it, lstItems.
end());
1907 itemsDeleted(listers, deletedItems);
1913 lister->d->emitItemsDeleted(deletedItems);
1916 for (
const KFileItem &item : deletedItems) {
1918 deleteDir(item.url());
1923void KCoreDirListerCache::deleteDir(
const QUrl &_dirUrl)
1925 qCDebug(KIO_CORE_DIRLISTER) << _dirUrl;
1935 auto itu = itemsInUse.
cbegin();
1936 const auto ituend = itemsInUse.cend();
1937 for (; itu != ituend; ++itu) {
1938 const QUrl &deletedUrl = itu.key();
1939 if (dirUrl == deletedUrl || dirUrl.
isParentOf(deletedUrl)) {
1940 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(lister, deletedUrl);
1961 if (holder->d->url == deletedUrl) {
1963 if (!holder->d->rootFileItem.isNull()) {
1964 Q_EMIT holder->itemsDeleted(
KFileItemList{holder->d->rootFileItem});
1969 const bool treeview = holder->d->lstDirs.count() > 1;
1971 Q_EMIT holder->clear();
1972 holder->d->lstDirs.clear();
1974 holder->d->lstDirs.removeAll(deletedUrl);
1977 forgetDirs(holder, deletedUrl, treeview, possibleMountPoints);
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 lister->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.";
2091 for (
KCoreDirLister *listit : std::as_const(listersWithoutJob)) {
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);
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)
2731 auto listers = listersByStatus(ListerStatus::Listing);
2733 while (lister_it.hasNext()) {
2735 if (!lister->d->cachedItemsJobForUrl(url)) {
2738 insertOrModifyLister(lister, ListerStatus::Holding);
2741 qCDebug(KIO_CORE_DIRLISTER) <<
"Not moving" << lister <<
"to listersCurrentlyHolding because it still has job" << lister->d->m_cachedItemsJobs;
2748 if (s_kDirListerCache.hasLocalData()) {
2749 return s_kDirListerCache.localData().itemForUrl(
url);
2755bool KCoreDirLister::autoErrorHandlingEnabled()
const
2757 return d->m_autoErrorHandling;
2762 d->m_autoErrorHandling = enable;
2765KCoreDirListerCache::CacheHiddenFile *KCoreDirListerCache::cachedDotHiddenForDir(
const QString &dir)
2768 QFile dotHiddenFile(path);
2770 if (dotHiddenFile.exists()) {
2772 CacheHiddenFile *cachedDotHiddenFile = m_cacheHiddenFiles.object(path);
2774 if (cachedDotHiddenFile && mtime <= cachedDotHiddenFile->mtime) {
2777 return cachedDotHiddenFile;
2781 std::set<QString> filesToHide;
2783 while (!stream.atEnd()) {
2786 filesToHide.insert(name);
2790 m_cacheHiddenFiles.insert(path,
new CacheHiddenFile(mtime, std::move(filesToHide)));
2792 return m_cacheHiddenFiles.object(path);
2803 for (
const auto &[lister, listerStatus] : m_listerContainer) {
2804 if (listerStatus ==
status) {
2813 for (
const auto &lister : listers) {
2814 insertOrModifyLister(lister,
status);
2818void KCoreDirListerCacheDirectoryData::insertOrModifyLister(
KCoreDirLister *lister, ListerStatus
status)
2825 m_listerContainer.insert_or_assign(lister,
status);
2828void KCoreDirListerCacheDirectoryData::removeLister(
KCoreDirLister *lister)
2835 const auto it = m_listerContainer.find(lister);
2836 if (it != m_listerContainer.end()) {
2837 m_listerContainer.erase(it);
2844 for (
const auto &[lister, listerStatus] : m_listerContainer) {
2850int KCoreDirListerCacheDirectoryData::totaListerCount()
2852 return m_listerContainer.
size();
2855int KCoreDirListerCacheDirectoryData::listerCountByStatus(ListerStatus
status)
2858 for (
const auto &[lister, listerStatus] : m_listerContainer) {
2859 if (listerStatus ==
status) {
2868 const auto it = m_listerContainer.find(lister);
2869 if (it != m_listerContainer.end()) {
2870 const auto listerStatus = it->second;
2871 return listerStatus ==
status;
2876#include "moc_kcoredirlister.cpp"
2877#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.
QFlags< OpenUrlFlag > OpenUrlFlags
Stores a combination of OpenUrlFlag values.
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 jobError(KIO::Job *job)
Emitted if listing a directory fails with an error.
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().
QStringList mountOptions() const
Options used to mount the filesystem.
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 CaptureState status()
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.
QList< UDSEntry > UDSEntryList
A directory listing is a list of UDSEntry instances.
@ 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.
QString name(StandardAction id)
const QList< QKeySequence > & reload()
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
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)
qsizetype indexOf(const AT &value, qsizetype from) const const
bool isEmpty() const const
void prepend(parameter_type value)
void reserve(qsizetype size)
qsizetype size() const const
T value(qsizetype i) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
iterator erase(const_iterator first, const_iterator last)
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)
QObject * parent() const const
QVariant property(const char *name) const const
bool setProperty(const char *name, QVariant &&value)
QString wildcardToRegularExpression(QStringView pattern, WildcardConversionOptions options)
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
QString url(FormattingOptions options) const const
bool toBool() const const