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;
2197 return d->settings.quickFilterMode;
2206 d->prepareForSettingsChange();
2210bool KCoreDirLister::requestMimeTypeWhileListing()
const
2212 return d->requestMimeTypeWhileListing;
2217 if (d->requestMimeTypeWhileListing == request) {
2221 d->requestMimeTypeWhileListing = request;
2222 if (d->requestMimeTypeWhileListing) {
2226 s_kDirListerCache.localData().forgetDirs(
this);
2245void KCoreDirListerPrivate::emitChanges()
2247 if (!hasPendingChanges) {
2253 hasPendingChanges =
false;
2255 const KCoreDirListerPrivate::FilterSettings newSettings = settings;
2256 settings = oldSettings;
2259 std::set<QString> oldVisibleItems;
2260 for (
const QUrl &dir : std::as_const(lstDirs)) {
2261 const QList<KFileItem> *itemList = s_kDirListerCache.localData().itemsForDir(dir);
2266 for (
const KFileItem &item : *itemList) {
2267 if (isItemVisible(item) && matchesMimeFilter(item)) {
2268 oldVisibleItems.insert(item.name());
2273 settings = newSettings;
2276 for (
const QUrl &dir : dirs) {
2279 const QList<KFileItem> *itemList = s_kDirListerCache.localData().itemsForDir(dir);
2284 for (
const auto &item : *itemList) {
2285 const QString text = item.text();
2289 const bool wasVisible = oldVisibleItems.find(item.name()) != oldVisibleItems.
cend();
2290 const bool mimeFiltered = matchesMimeFilter(item);
2291 const bool nowVisible = isItemVisible(item) && mimeFiltered;
2292 if (nowVisible && !wasVisible) {
2293 addNewItem(dir, item);
2294 }
else if (!nowVisible && wasVisible) {
2295 if (!mimeFiltered) {
2296 lstMimeFilteredItems.append(item);
2298 deletedItems.
append(item);
2301 if (!deletedItems.
isEmpty()) {
2302 Q_EMIT q->itemsDeleted(deletedItems);
2306 oldSettings = settings;
2311 s_kDirListerCache.localData().updateDirectory(dirUrl);
2321 return d->rootFileItem;
2326 return s_kDirListerCache.localData().findByUrl(
this,
url);
2331 return s_kDirListerCache.localData().findByName(
this, name);
2338 if (d->nameFilter == nameFilter) {
2342 d->prepareForSettingsChange();
2344 d->settings.lstFilters.clear();
2345 d->nameFilter = nameFilter;
2355 return d->nameFilter;
2360 if (d->settings.mimeFilter == mimeFilter) {
2364 d->prepareForSettingsChange();
2366 d->settings.mimeFilter.clear();
2368 d->settings.mimeFilter = mimeFilter;
2374 if (d->settings.mimeExcludeFilter == mimeExcludeFilter) {
2378 d->prepareForSettingsChange();
2379 d->settings.mimeExcludeFilter = mimeExcludeFilter;
2384 d->prepareForSettingsChange();
2385 d->settings.mimeFilter.
clear();
2386 d->settings.mimeExcludeFilter.clear();
2391 return d->settings.mimeFilter;
2396bool KCoreDirListerPrivate::matchesFilter(
const KFileItem &item)
const
2398 Q_ASSERT(!item.
isNull());
2404 if (!settings.isShowingDotFiles && item.isHidden()) {
2409 if (!settings.quickFilterMode && item.isDir()) {
2413 if (settings.lstFilters.isEmpty()) {
2417 return std::any_of(settings.lstFilters.cbegin(), settings.lstFilters.cend(), [&item](
const QRegularExpression &filter) {
2418 return filter.match(item.text()).hasMatch();
2422bool KCoreDirListerPrivate::matchesMimeFilter(
const KFileItem &item)
const
2424 Q_ASSERT(!item.
isNull());
2426 if (settings.mimeFilter.isEmpty() && settings.mimeExcludeFilter.isEmpty()) {
2429 return doMimeFilter(item.mimetype(), settings.mimeFilter) && doMimeExcludeFilter(item.mimetype(), settings.mimeExcludeFilter);
2432bool KCoreDirListerPrivate::doMimeFilter(
const QString &mime,
const QStringList &filters)
const
2444 qCDebug(KIO_CORE_DIRLISTER) <<
"doMimeFilter: investigating:" << mimeptr.
name();
2445 return std::any_of(filters.
cbegin(), filters.
cend(), [&mimeptr](
const QString &filter) {
2446 return mimeptr.inherits(filter);
2450bool KCoreDirListerPrivate::doMimeExcludeFilter(
const QString &mime,
const QStringList &filters)
const
2452 return !std::any_of(filters.
cbegin(), filters.
cend(), [&mime](
const QString &filter) {
2453 return mime == filter;
2459void KCoreDirListerPrivate::addNewItem(
const QUrl &directoryUrl,
const KFileItem &item)
2461 if (!isItemVisible(item)) {
2465 qCDebug(KIO_CORE_DIRLISTER) <<
"in" << directoryUrl <<
"item:" << item.url();
2467 if (matchesMimeFilter(item)) {
2468 Q_ASSERT(!item.
isNull());
2469 lstNewItems[directoryUrl].append(item);
2471 Q_ASSERT(!item.
isNull());
2472 lstMimeFilteredItems.append(item);
2476void KCoreDirListerPrivate::addNewItems(
const QUrl &directoryUrl,
const QList<KFileItem> &items)
2481 for (
const auto &item : items) {
2482 addNewItem(directoryUrl, item);
2486void KCoreDirListerPrivate::addRefreshItem(
const QUrl &directoryUrl,
const KFileItem &oldItem,
const KFileItem &item)
2489 if (directoryUrl == item.url()) {
2490 lstRefreshItems.append({oldItem, item});
2494 const bool refreshItemWasFiltered = !isItemVisible(oldItem) || !matchesMimeFilter(oldItem);
2495 if (item.
exists() && isItemVisible(item) && matchesMimeFilter(item)) {
2496 if (refreshItemWasFiltered) {
2497 Q_ASSERT(!item.
isNull());
2498 lstNewItems[directoryUrl].append(item);
2500 Q_ASSERT(!item.
isNull());
2501 lstRefreshItems.append(qMakePair(oldItem, item));
2503 }
else if (!refreshItemWasFiltered) {
2507 Q_ASSERT(!oldItem.
isNull());
2508 lstRemoveItems.append(oldItem);
2512void KCoreDirListerPrivate::emitItems()
2514 if (!lstNewItems.empty()) {
2515 for (
auto it = lstNewItems.cbegin(); it != lstNewItems.cend(); ++it) {
2516 const auto &val = it.value();
2517 Q_EMIT q->itemsAdded(it.key(), val);
2518 Q_EMIT q->newItems(val);
2520 lstNewItems.clear();
2523 if (!lstMimeFilteredItems.empty()) {
2524 Q_EMIT q->itemsFilteredByMime(lstMimeFilteredItems);
2525 lstMimeFilteredItems.clear();
2528 if (!lstRefreshItems.empty()) {
2529 Q_EMIT q->refreshItems(lstRefreshItems);
2530 lstRefreshItems.clear();
2533 if (!lstRemoveItems.empty()) {
2534 Q_EMIT q->itemsDeleted(lstRemoveItems);
2535 lstRemoveItems.clear();
2539bool KCoreDirListerPrivate::isItemVisible(
const KFileItem &item)
const
2544 return (!settings.dirOnlyMode || item.isDir()) && matchesFilter(item);
2547void KCoreDirListerPrivate::emitItemsDeleted(
const KFileItemList &itemsList)
2550 std::copy_if(itemsList.
cbegin(), itemsList.
cend(), std::back_inserter(items), [
this](
const KFileItem &item) {
2551 return isItemVisible(item) || matchesMimeFilter(item);
2554 Q_EMIT q->itemsDeleted(items);
2565void KCoreDirListerPrivate::slotInfoMessage(
KJob *,
const QString &message)
2567 Q_EMIT q->infoMessage(message);
2570void KCoreDirListerPrivate::slotPercent(
KJob *job,
unsigned long pcnt)
2572 jobData[
static_cast<KIO::ListJob *
>(job)].percent = pcnt;
2578 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2579 const JobData &data = dataIt.value();
2580 result += data.percent * data.totalSize;
2581 size += data.totalSize;
2589 Q_EMIT q->percent(result);
2592void KCoreDirListerPrivate::slotTotalSize(
KJob *job, qulonglong size)
2594 jobData[
static_cast<KIO::ListJob *
>(job)].totalSize = size;
2597 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2598 result += dataIt.value().totalSize;
2601 Q_EMIT q->totalSize(result);
2604void KCoreDirListerPrivate::slotProcessedSize(
KJob *job, qulonglong size)
2606 jobData[
static_cast<KIO::ListJob *
>(job)].processedSize = size;
2609 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2610 result += dataIt.value().processedSize;
2613 Q_EMIT q->processedSize(result);
2616void KCoreDirListerPrivate::slotSpeed(
KJob *job,
unsigned long spd)
2621 for (
auto dataIt = jobData.cbegin(); dataIt != jobData.cend(); ++dataIt) {
2622 result += dataIt.value().speed;
2625 Q_EMIT q->speed(result);
2628uint KCoreDirListerPrivate::numJobs()
2632 qCDebug(KIO_CORE_DIRLISTER) << q <<
"numJobs:" << jobData.count();
2633 for (
auto it = jobData.cbegin(); it != jobData.cend(); ++it) {
2634 qCDebug(KIO_CORE_DIRLISTER) << (
void *)it.key();
2635 qCDebug(KIO_CORE_DIRLISTER) << it.key();
2639 return jobData.count();
2644 jobData.remove(job);
2649 KCoreDirListerPrivate::JobData data;
2652 data.processedSize = 0;
2655 d->jobData.insert(job, data);
2656 d->complete =
false;
2659void KCoreDirListerPrivate::connectJob(
KIO::ListJob *job)
2662 slotInfoMessage(job, plain);
2666 slotPercent(job, _percent);
2670 slotTotalSize(job, _size);
2673 slotProcessedSize(job, _psize);
2675 q->connect(job, &
KJob::speed, q, [
this](
KJob *job, qulonglong _speed) {
2676 slotSpeed(job, _speed);
2687 QList<KFileItem> *allItems = s_kDirListerCache.localData().itemsForDir(dir);
2693 if (which == AllItems) {
2696 std::copy_if(allItems->
cbegin(), allItems->
cend(), std::back_inserter(result), [
this](
const KFileItem &item) {
2697 return d->isItemVisible(item) && d->matchesMimeFilter(item);
2703bool KCoreDirLister::delayedMimeTypes()
const
2705 return d->delayedMimeTypes;
2710 d->delayedMimeTypes = delayedMimeTypes;
2714void KCoreDirListerPrivate::redirect(
const QUrl &oldUrl,
const QUrl &newUrl,
bool keepItems)
2720 rootFileItem.setUrl(newUrl);
2725 const int idx = lstDirs.
indexOf(oldUrl);
2727 qCWarning(KIO_CORE) <<
"Unexpected redirection from" << oldUrl <<
"to" << newUrl <<
"but this dirlister is currently listing/holding" << lstDirs;
2729 lstDirs[idx] = newUrl;
2732 if (lstDirs.count() == 1) {
2738 Q_EMIT q->clearDir(oldUrl);
2741 Q_EMIT q->redirection(oldUrl, newUrl);
2744void KCoreDirListerCacheDirectoryData::moveListersWithoutCachedItemsJob(
const QUrl &url)
2751 auto listers = listersByStatus(ListerStatus::Listing);
2753 while (lister_it.hasNext()) {
2755 if (!lister->d->cachedItemsJobForUrl(url)) {
2758 insertOrModifyLister(lister, ListerStatus::Holding);
2761 qCDebug(KIO_CORE_DIRLISTER) <<
"Not moving" << lister <<
"to listersCurrentlyHolding because it still has job" << lister->d->m_cachedItemsJobs;
2768 if (s_kDirListerCache.hasLocalData()) {
2769 return s_kDirListerCache.localData().itemForUrl(
url);
2775bool KCoreDirLister::autoErrorHandlingEnabled()
const
2777 return d->m_autoErrorHandling;
2782 d->m_autoErrorHandling = enable;
2785KCoreDirListerCache::CacheHiddenFile *KCoreDirListerCache::cachedDotHiddenForDir(
const QString &dir)
2788 QFile dotHiddenFile(path);
2790 if (dotHiddenFile.exists()) {
2792 CacheHiddenFile *cachedDotHiddenFile = m_cacheHiddenFiles.object(path);
2794 if (cachedDotHiddenFile && mtime <= cachedDotHiddenFile->mtime) {
2797 return cachedDotHiddenFile;
2801 std::set<QString> filesToHide;
2803 while (!stream.atEnd()) {
2806 filesToHide.insert(name);
2810 m_cacheHiddenFiles.insert(path,
new CacheHiddenFile(mtime, std::move(filesToHide)));
2812 return m_cacheHiddenFiles.object(path);
2823 for (
const auto &[lister, listerStatus] : m_listerContainer) {
2824 if (listerStatus ==
status) {
2833 for (
const auto &lister : listers) {
2834 insertOrModifyLister(lister,
status);
2838void KCoreDirListerCacheDirectoryData::insertOrModifyLister(
KCoreDirLister *lister, ListerStatus
status)
2845 m_listerContainer.insert_or_assign(lister,
status);
2848void KCoreDirListerCacheDirectoryData::removeLister(
KCoreDirLister *lister)
2855 const auto it = m_listerContainer.find(lister);
2856 if (it != m_listerContainer.end()) {
2857 m_listerContainer.erase(it);
2864 for (
const auto &[lister, listerStatus] : m_listerContainer) {
2870int KCoreDirListerCacheDirectoryData::totaListerCount()
2872 return m_listerContainer.
size();
2875int KCoreDirListerCacheDirectoryData::listerCountByStatus(ListerStatus
status)
2878 for (
const auto &[lister, listerStatus] : m_listerContainer) {
2879 if (listerStatus ==
status) {
2888 const auto it = m_listerContainer.find(lister);
2889 if (it != m_listerContainer.end()) {
2890 const auto listerStatus = it->second;
2891 return listerStatus ==
status;
2896#include "moc_kcoredirlister.cpp"
2897#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.
void setQuickFilterMode(bool quickFilterMode)
Call this to set the quick filtering mode on, which will filter through all the items based by their ...
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.
bool quickFilterMode() const
Returns true if quickfiltering is enabled.
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