diff --git a/src/core/kcoredirlister.cpp b/src/core/kcoredirlister.cpp --- a/src/core/kcoredirlister.cpp +++ b/src/core/kcoredirlister.cpp @@ -335,7 +335,7 @@ if (!itemU) { qCWarning(KIO_CORE) << "Can't find item for directory" << _url << "anymore"; } else { - const NonMovableFileItemList items = itemU->lstItems; + const QList items = itemU->lstItems; const KFileItem rootItem = itemU->rootItem; _reload = _reload || !itemU->complete; @@ -608,8 +608,8 @@ // Look for a manually-mounted directory inside // If there's one, we can't keep a watch either, FAM would prevent unmounting the CDROM // I hope this isn't too slow - NonMovableFileItemList::const_iterator kit = item->lstItems.constBegin(); - NonMovableFileItemList::const_iterator kend = item->lstItems.constEnd(); + auto kit = item->lstItems.constBegin(); + const auto kend = item->lstItems.constEnd(); for (; kit != kend && !containsManuallyMounted; ++kit) if ((*kit).isDir() && manually_mounted((*kit).url().toLocalFile(), possibleMountPoints)) { containsManuallyMounted = true; @@ -648,7 +648,7 @@ const QUrl dir = _dir.adjusted(QUrl::StripTrailingSlash); if (!checkUpdate(dir)) { - if (dir.isLocalFile() && findByUrl(nullptr, dir)) { + if (dir.isLocalFile() && !(findByUrl(nullptr, dir).isNull())) { pendingUpdates.insert(dir.toLocalFile()); if (!pendingUpdateTimer.isActive()) { pendingUpdateTimer.start(500); @@ -753,12 +753,7 @@ KFileItem KCoreDirListerCache::itemForUrl(const QUrl &url) const { - KFileItem *item = findByUrl(nullptr, url); - if (item) { - return *item; - } else { - return KFileItem(); - } + return findByUrl(nullptr, url); } KCoreDirListerCache::DirItem *KCoreDirListerCache::dirItemForUrl(const QUrl &dir) const @@ -771,7 +766,7 @@ return item; } -NonMovableFileItemList *KCoreDirListerCache::itemsForDir(const QUrl &dir) const +QList *KCoreDirListerCache::itemsForDir(const QUrl &dir) const { DirItem *item = dirItemForUrl(dir); return item ? &item->lstItems : nullptr; @@ -785,16 +780,20 @@ it != lister->d->lstDirs.constEnd(); ++it) { DirItem *dirItem = itemsInUse.value(*it); Q_ASSERT(dirItem); - const KFileItem item = dirItem->lstItems.findByName(_name); - if (!item.isNull()) { - return item; + + auto lit = dirItem->lstItems.constBegin(); + const auto litend = dirItem->lstItems.constEnd(); + for (; lit != litend; ++lit) { + if ((*lit).name() == _name) { + return *lit; + } } } return KFileItem(); } -KFileItem *KCoreDirListerCache::findByUrl(const KCoreDirLister *lister, const QUrl &_u) const +KFileItem KCoreDirListerCache::findByUrl(const KCoreDirLister *lister, const QUrl &_u) const { QUrl url(_u); url = url.adjusted(QUrl::StripTrailingSlash); @@ -804,12 +803,10 @@ if (dirItem) { // If lister is set, check that it contains this dir if (!lister || lister->d->lstDirs.contains(parentDir)) { - NonMovableFileItemList::iterator it = dirItem->lstItems.begin(); - const NonMovableFileItemList::iterator end = dirItem->lstItems.end(); - for (; it != end; ++it) { - if ((*it).url() == url) { - return &*it; - } + // Binary search + auto it = std::lower_bound(dirItem->lstItems.begin(), dirItem->lstItems.end(), url); + if (it != dirItem->lstItems.end() && it->url() == url) { + return *it; } } } @@ -821,11 +818,11 @@ if (dirItem && !dirItem->rootItem.isNull() && dirItem->rootItem.url() == url) { // If lister is set, check that it contains this dir if (!lister || lister->d->lstDirs.contains(url)) { - return &dirItem->rootItem; + return dirItem->rootItem; } } - return nullptr; + return KFileItem(); } void KCoreDirListerCache::slotFilesAdded(const QString &dir /*url*/) // from KDirNotify signals @@ -872,7 +869,7 @@ if (!dirItem) { continue; } - for (NonMovableFileItemList::iterator fit = dirItem->lstItems.begin(), fend = dirItem->lstItems.end(); fit != fend; ++fit) { + for (auto fit = dirItem->lstItems.begin(), fend = dirItem->lstItems.end(); fit != fend; ++fit) { if ((*fit).url() == url) { const KFileItem fileitem = *fit; removedItemsByDir[parentDir].append(fileitem); @@ -909,8 +906,8 @@ QStringList::const_iterator it = fileList.begin(); for (; it != fileList.end(); ++it) { QUrl url(*it); - KFileItem *fileitem = findByUrl(nullptr, url); - if (!fileitem) { + const KFileItem &fileitem = findByUrl(nullptr, url); + if (fileitem.isNull()) { qCDebug(KIO_CORE_DIRLISTER) << "item not found for" << url; continue; } @@ -947,58 +944,61 @@ #endif QUrl oldurl = src.adjusted(QUrl::StripTrailingSlash); - KFileItem *fileitem = findByUrl(nullptr, oldurl); - if (!fileitem) { + KFileItem fileitem = findByUrl(nullptr, oldurl); + if (fileitem.isNull()) { qCDebug(KIO_CORE_DIRLISTER) << "Item not found:" << oldurl; return; } - const KFileItem oldItem = *fileitem; + const KFileItem oldItem = fileitem; // Dest already exists? Was overwritten then (testcase: #151851) // We better emit it as deleted -before- doing the renaming, otherwise // the "update" mechanism will emit the old one as deleted and // kdirmodel will delete the new (renamed) one! - KFileItem *existingDestItem = findByUrl(nullptr, dst); - if (existingDestItem) { + const KFileItem &existingDestItem = findByUrl(nullptr, dst); + if (!existingDestItem.isNull()) { qCDebug(KIO_CORE_DIRLISTER) << dst << "already existed, let's delete it"; slotFilesRemoved(QList() << dst); } // If the item had a UDS_URL as well as UDS_NAME set, the user probably wants // to be updating the name only (since they can't see the URL). // Check to see if a URL exists, and if so, if only the file part has changed, // only update the name and not the underlying URL. - bool nameOnly = !fileitem->entry().stringValue(KIO::UDSEntry::UDS_URL).isEmpty(); + bool nameOnly = !fileitem.entry().stringValue(KIO::UDSEntry::UDS_URL).isEmpty(); nameOnly = nameOnly && src.adjusted(QUrl::RemoveFilename) == dst.adjusted(QUrl::RemoveFilename); - if (!nameOnly && fileitem->isDir()) { + if (!nameOnly && fileitem.isDir()) { renameDir(oldurl, dst); // #172945 - if the fileitem was the root item of a DirItem that was just removed from the cache, // then it's a dangling pointer now... fileitem = findByUrl(nullptr, oldurl); - if (!fileitem) { //deleted from cache altogether, #188807 + if (fileitem.isNull()) { //deleted from cache altogether, #188807 return; } } // Now update the KFileItem representing that file or dir (not exclusive with the above!) if (!oldItem.isLocalFile() && !oldItem.localPath().isEmpty() && dstPath.isEmpty()) { // it uses UDS_LOCAL_PATH and we don't know the new path? needs an update then slotFilesChanged(QStringList() << src.toString()); } else { + const QUrl &itemOldUrl = fileitem.url(); if (nameOnly) { - fileitem->setName(dst.fileName()); + fileitem.setName(dst.fileName()); } else { - fileitem->setUrl(dst); + fileitem.setUrl(dst); } if (!dstPath.isEmpty()) { - fileitem->setLocalPath(dstPath); + fileitem.setLocalPath(dstPath); } - fileitem->refreshMimeType(); - fileitem->determineMimeType(); - QSet listers = emitRefreshItem(oldItem, *fileitem); + fileitem.refreshMimeType(); + fileitem.determineMimeType(); + reinsert(fileitem, itemOldUrl); + + QSet listers = emitRefreshItem(oldItem, fileitem); Q_FOREACH (KCoreDirLister *kdl, listers) { kdl->d->emitItems(); } @@ -1127,10 +1127,10 @@ void KCoreDirListerCache::handleFileDirty(const QUrl &url) { // A file: do we know about it already? - KFileItem *existingItem = findByUrl(nullptr, url); + const KFileItem &existingItem = findByUrl(nullptr, url); const QUrl dir = url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash); QString filePath = url.toLocalFile(); - if (!existingItem) { + if (existingItem.isNull()) { // No - update the parent dir then handleDirDirty(dir); } @@ -1252,7 +1252,8 @@ } qCDebug(KIO_CORE_DIRLISTER)<< "Adding item: " << item.url(); - dir->lstItems.append(item); + // Add the items sorted by url, needed by findByUrl + dir->insert(item); foreach (KCoreDirLister *kdl, dirData.listersCurrentlyListing) { kdl->d->addNewItem(url, item); @@ -1575,17 +1576,18 @@ dir)); // Rename all items under that dir - for (NonMovableFileItemList::iterator kit = dir->lstItems.begin(), kend = dir->lstItems.end(); - kit != kend; ++kit) { + for (auto kit = dir->lstItems.begin(), kend = dir->lstItems.end(); kit != kend; ++kit) { const KFileItem oldItem = *kit; + KFileItem newItem = oldItem; - const QUrl oldItemUrl = (*kit).url().adjusted(QUrl::StripTrailingSlash); + const QUrl &oldItemUrl = oldItem.url(); QUrl newItemUrl(oldItemUrl); newItemUrl.setPath(concatPaths(newDirUrl.path(), oldItemUrl.fileName())); qCDebug(KIO_CORE_DIRLISTER) << "renaming" << oldItemUrl << "to" << newItemUrl; - (*kit).setUrl(newItemUrl); + newItem.setUrl(newItemUrl); + reinsert(newItem, oldItemUrl); - listers |= emitRefreshItem(oldItem, *kit); + listers |= emitRefreshItem(oldItem, newItem); } } } @@ -1746,13 +1748,13 @@ delayedMimeTypes &= kdl->d->delayedMimeTypes; } - typedef QHash FileItemHash; // fileName -> KFileItem* + typedef QHash FileItemHash; // fileName -> KFileItem FileItemHash fileItems; // Fill the hash from the old list of items. We'll remove entries as we see them // in the new listing, and the resulting hash entries will be the deleted items. - for (NonMovableFileItemList::iterator kit = dir->lstItems.begin(), kend = dir->lstItems.end(); kit != kend; ++kit) { - fileItems.insert((*kit).name(), &*kit); + for (auto kit = dir->lstItems.begin(), kend = dir->lstItems.end(); kit != kend; ++kit) { + fileItems.insert((*kit).name(), *kit); } QSet filesToHide; @@ -1805,31 +1807,29 @@ // Find this item FileItemHash::iterator fiit = fileItems.find(item.name()); if (fiit != fileItems.end()) { - KFileItem* tmp = fiit.value(); - QSet::iterator pru_it = pendingRemoteUpdates.find(tmp); + const KFileItem tmp = fiit.value(); + QSet::iterator pru_it = pendingRemoteUpdates.find(tmp); const bool inPendingRemoteUpdates = (pru_it != pendingRemoteUpdates.end()); // check if something changed for this file, using KFileItem::cmp() - if (!tmp->cmp(item) || inPendingRemoteUpdates) { + if (!tmp.cmp(item) || inPendingRemoteUpdates) { if (inPendingRemoteUpdates) { pendingRemoteUpdates.erase(pru_it); } - qCDebug(KIO_CORE_DIRLISTER) << "file changed:" << tmp->name(); + qCDebug(KIO_CORE_DIRLISTER) << "file changed:" << tmp.name(); - const KFileItem oldItem = *tmp; - *tmp = item; + reinsert(item, tmp.url()); foreach (KCoreDirLister *kdl, listers) { - kdl->d->addRefreshItem(jobUrl, oldItem, *tmp); + kdl->d->addRefreshItem(jobUrl, tmp, item); } } // Seen, remove fileItems.erase(fiit); } else { // this is a new file qCDebug(KIO_CORE_DIRLISTER) << "new file:" << name; - - dir->lstItems.append(item); + dir->insert(item); foreach (KCoreDirLister *kdl, listers) { kdl->d->addNewItem(jobUrl, item); @@ -1897,19 +1897,19 @@ job->kill(); } -void KCoreDirListerCache::deleteUnmarkedItems(const QList &listers, NonMovableFileItemList &lstItems, const QHash &itemsToDelete) +void KCoreDirListerCache::deleteUnmarkedItems(const QList &listers, QList &lstItems, const QHash &itemsToDelete) { // Make list of deleted items (for emitting) KFileItemList deletedItems; - QHashIterator kit(itemsToDelete); + QHashIterator kit(itemsToDelete); while (kit.hasNext()) { - const KFileItem& item = *kit.next().value(); + const KFileItem item = kit.next().value(); deletedItems.append(item); - qCDebug(KIO_CORE_DIRLISTER) << "deleted:" << item.name() << &item; + qCDebug(KIO_CORE_DIRLISTER) << "deleted:" << item.name() << item; } // Delete all remaining items - QMutableListIterator it(lstItems); + QMutableListIterator it(lstItems); while (it.hasNext()) { if (itemsToDelete.contains(it.next().name())) { it.remove(); @@ -2007,13 +2007,15 @@ foreach (const QString &file, pendingUpdates) { // always a local path qCDebug(KIO_CORE_DIRLISTER) << file; QUrl u = QUrl::fromLocalFile(file); - KFileItem *item = findByUrl(nullptr, u); // search all items - if (item) { + KFileItem item = findByUrl(nullptr, u); // search all items + if (!item.isNull()) { // we need to refresh the item, because e.g. the permissions can have changed. - KFileItem oldItem = *item; - item->refresh(); - if (!oldItem.cmp(*item)) { - listers |= emitRefreshItem(oldItem, *item); + KFileItem oldItem = item; + item.refresh(); + + if (!oldItem.cmp(item)) { + reinsert(item, oldItem.url()); + listers |= emitRefreshItem(oldItem, item); } } } @@ -2215,7 +2217,7 @@ // Fill hash with all items that are currently visible QSet oldVisibleItems; Q_FOREACH (const QUrl &dir, lstDirs) { - NonMovableFileItemList *itemList = kDirListerCache()->itemsForDir(dir); + QList *itemList = kDirListerCache()->itemsForDir(dir); if (!itemList) { continue; } @@ -2232,13 +2234,13 @@ Q_FOREACH (const QUrl &dir, lstDirs) { KFileItemList deletedItems; - NonMovableFileItemList *itemList = kDirListerCache()->itemsForDir(dir); + QList *itemList = kDirListerCache()->itemsForDir(dir); if (!itemList) { continue; } - NonMovableFileItemList::iterator kit = itemList->begin(); - const NonMovableFileItemList::iterator kend = itemList->end(); + auto kit = itemList->begin(); + const auto kend = itemList->end(); for (; kit != kend; ++kit) { KFileItem &item = *kit; const QString text = item.text(); @@ -2278,12 +2280,7 @@ KFileItem KCoreDirLister::findByUrl(const QUrl &_url) const { - KFileItem *item = kDirListerCache()->findByUrl(this, _url); - if (item) { - return *item; - } else { - return KFileItem(); - } + return kDirListerCache()->findByUrl(this, _url); } KFileItem KCoreDirLister::findByName(const QString &_name) const @@ -2462,29 +2459,21 @@ qCDebug(KIO_CORE_DIRLISTER) << "in" << directoryUrl << "item:" << item.url(); if (m_parent->matchesMimeFilter(item)) { - if (!lstNewItems) { - lstNewItems = new NewItemsHash; - } - Q_ASSERT(!item.isNull()); - (*lstNewItems)[directoryUrl].append(item); // items not filtered + (lstNewItems)[directoryUrl].append(item); // items not filtered } else { - if (!lstMimeFilteredItems) { - lstMimeFilteredItems = new KFileItemList; - } - Q_ASSERT(!item.isNull()); - lstMimeFilteredItems->append(item); // only filtered by mime + lstMimeFilteredItems.append(item); // only filtered by mime } } -void KCoreDirLister::Private::addNewItems(const QUrl &directoryUrl, const NonMovableFileItemList &items) +void KCoreDirLister::Private::addNewItems(const QUrl &directoryUrl, const QList &items) { // TODO: make this faster - test if we have a filter at all first // DF: was this profiled? The matchesFoo() functions should be fast, w/o filters... // Of course if there is no filter and we can do a range-insertion instead of a loop, that might be good. - NonMovableFileItemList::const_iterator kit = items.begin(); - const NonMovableFileItemList::const_iterator kend = items.end(); + auto kit = items.cbegin(); + const auto kend = items.end(); for (; kit != kend; ++kit) { addNewItem(directoryUrl, *kit); } @@ -2496,70 +2485,46 @@ !m_parent->matchesMimeFilter(oldItem); if (isItemVisible(item) && m_parent->matchesMimeFilter(item)) { if (refreshItemWasFiltered) { - if (!lstNewItems) { - lstNewItems = new NewItemsHash; - } - Q_ASSERT(!item.isNull()); - (*lstNewItems)[directoryUrl].append(item); + (lstNewItems)[directoryUrl].append(item); } else { - if (!lstRefreshItems) { - lstRefreshItems = new QList >; - } - Q_ASSERT(!item.isNull()); - lstRefreshItems->append(qMakePair(oldItem, item)); + lstRefreshItems.append(qMakePair(oldItem, item)); } } else if (!refreshItemWasFiltered) { - if (!lstRemoveItems) { - lstRemoveItems = new KFileItemList; - } - // notify the user that the mimetype of a file changed that doesn't match // a filter or does match an exclude filter // This also happens when renaming foo to .foo and dot files are hidden (#174721) Q_ASSERT(!oldItem.isNull()); - lstRemoveItems->append(oldItem); + lstRemoveItems.append(oldItem); } } void KCoreDirLister::Private::emitItems() { - NewItemsHash *tmpNew = lstNewItems; - lstNewItems = nullptr; - - KFileItemList *tmpMime = lstMimeFilteredItems; - lstMimeFilteredItems = nullptr; - - QList > *tmpRefresh = lstRefreshItems; - lstRefreshItems = nullptr; - - KFileItemList *tmpRemove = lstRemoveItems; - lstRemoveItems = nullptr; - - if (tmpNew) { - QHashIterator it(*tmpNew); + if (!lstNewItems.empty()) { + QHashIterator it(lstNewItems); while (it.hasNext()) { it.next(); emit m_parent->itemsAdded(it.key(), it.value()); emit m_parent->newItems(it.value()); // compat } - delete tmpNew; + lstNewItems.clear(); } - if (tmpMime) { - emit m_parent->itemsFilteredByMime(*tmpMime); - delete tmpMime; + if (!lstMimeFilteredItems.empty()) { + emit m_parent->itemsFilteredByMime(lstMimeFilteredItems); + lstMimeFilteredItems.clear(); } - if (tmpRefresh) { - emit m_parent->refreshItems(*tmpRefresh); - delete tmpRefresh; + if (!lstRefreshItems.empty()) { + emit m_parent->refreshItems(lstRefreshItems); + lstRefreshItems.clear(); } - if (tmpRemove) { - emit m_parent->itemsDeleted(*tmpRemove); - delete tmpRemove; + if (!lstRemoveItems.empty()) { + emit m_parent->itemsDeleted(lstRemoveItems); + lstRemoveItems.clear(); } } @@ -2713,25 +2678,30 @@ KFileItemList KCoreDirLister::itemsForDir(const QUrl &dir, WhichItems which) const { - NonMovableFileItemList *allItems = kDirListerCache()->itemsForDir(dir); + QList *allItems = kDirListerCache()->itemsForDir(dir); + KFileItemList result; if (!allItems) { - return KFileItemList(); + return result; } if (which == AllItems) { - return allItems->toKFileItemList(); + result.reserve(allItems->count()); + + foreach (const KFileItem &item, *allItems) { + result.append(item); + } + } else { // only items passing the filters - KFileItemList result; - NonMovableFileItemList::const_iterator kit = allItems->constBegin(); - const NonMovableFileItemList::const_iterator kend = allItems->constEnd(); + auto kit = allItems->constBegin(); + const auto kend = allItems->constEnd(); for (; kit != kend; ++kit) { const KFileItem &item = *kit; if (d->isItemVisible(item) && matchesMimeFilter(item)) { result.append(item); } } - return result; } + return result; } bool KCoreDirLister::delayedMimeTypes() const diff --git a/src/core/kcoredirlister_p.h b/src/core/kcoredirlister_p.h --- a/src/core/kcoredirlister_p.h +++ b/src/core/kcoredirlister_p.h @@ -34,61 +34,6 @@ #include #include -/** - * KCoreDirListerCache stores pointers to KFileItems internally and expects that - * these pointers remain valid, even if the number of items in the list 'lstItems' - * in KCoreDirLister::DirItem changes. Since such changes in a QList - * may change the internal memory layout of the QList, pointers to KFileItems in a - * QList might become invalid. - * - * Therefore, we make 'lstItems' a QList, where - * NonMovableFileItem is a class that inherits KFileItem, but is not declared as a - * Q_MOVABLE_TYPE. This forces QList to never move these items in memory, which is - * achieved by allocating space for each individual item, and store pointers to - * these items in the contiguous region in memory. - * - * TODO: Try to get rid of the raw KFileItem pointers in KCoreDirListerCache, and - * replace all occurrences of NonMovableFileItem(List) with KFileItem(List). - */ -class NonMovableFileItem : public KFileItem -{ -public: - NonMovableFileItem(const KFileItem &item) : - KFileItem(item) - {} -}; - -class NonMovableFileItemList : public QList -{ -public: - NonMovableFileItemList() - {} - - KFileItem findByName(const QString &fileName) const - { - const_iterator it = begin(); - const const_iterator itend = end(); - for (; it != itend; ++it) { - if ((*it).name() == fileName) { - return *it; - } - } - return KFileItem(); - } - - KFileItemList toKFileItemList() const - { - KFileItemList result; - result.reserve(count()); - - foreach (const NonMovableFileItem &item, *this) { - result.append(item); - } - - return result; - } -}; - class KCoreDirLister; namespace KIO { @@ -112,11 +57,6 @@ rootFileItem = KFileItem(); - lstNewItems = nullptr; - lstRefreshItems = nullptr; - lstMimeFilteredItems = nullptr; - lstRemoveItems = nullptr; - hasPendingChanges = false; } @@ -132,7 +72,7 @@ void jobDone(KIO::ListJob *); uint numJobs(); void addNewItem(const QUrl &directoryUrl, const KFileItem &item); - void addNewItems(const QUrl &directoryUrl, const NonMovableFileItemList &items); + void addNewItems(const QUrl &directoryUrl, const QList &items); void addRefreshItem(const QUrl &directoryUrl, const KFileItem &oldItem, const KFileItem &item); void emitItems(); void emitItemsDeleted(const KFileItemList &items); @@ -192,9 +132,9 @@ KFileItem rootFileItem; typedef QHash NewItemsHash; - NewItemsHash *lstNewItems; - QList > *lstRefreshItems; - KFileItemList *lstMimeFilteredItems, *lstRemoveItems; + NewItemsHash lstNewItems; + QList > lstRefreshItems; + KFileItemList lstMimeFilteredItems, lstRemoveItems; QList m_cachedItemsJobs; @@ -237,7 +177,7 @@ void updateDirectory(const QUrl &dir); KFileItem itemForUrl(const QUrl &url) const; - NonMovableFileItemList *itemsForDir(const QUrl &dir) const; + QList *itemsForDir(const QUrl &dir) const; bool listDir(KCoreDirLister *lister, const QUrl &_url, bool _keep, bool _reload); @@ -255,7 +195,7 @@ // findByUrl returns a pointer so that it's possible to modify the item. // See itemForUrl for the version that returns a readonly kfileitem. // @param lister can be 0. If set, it is checked that the url is held by the lister - KFileItem *findByUrl(const KCoreDirLister *lister, const QUrl &url) const; + KFileItem findByUrl(const KCoreDirLister *lister, const QUrl &url) const; // Called by CachedItemsJob: // Emits the cached items, for this lister and this url @@ -332,7 +272,7 @@ // when there were items deleted from the filesystem all the listers holding // the parent directory need to be notified, the items have to be deleted // and removed from the cache including all the children. - void deleteUnmarkedItems(const QList&, NonMovableFileItemList &lstItems, const QHash &itemsToDelete); + void deleteUnmarkedItems(const QList&, QList &lstItems, const QHash &itemsToDelete); // Helper method called when we know that a list of items was deleted void itemsDeleted(const QList &listers, const KFileItemList &deletedItems); @@ -353,6 +293,23 @@ */ QSet emitRefreshItem(const KFileItem &oldItem, const KFileItem &fileitem); + /** + * Remove the item from the sorted list matching @p oldUrl, + * that is in the wrong place in the sorted list and insert @p item in the right place. + * @param oldUrl the previous url of the @p item + * @param item the modified item to be inserted + */ + void reinsert(const KFileItem &item, const QUrl &oldUrl) + { + const QUrl parentDir = oldUrl.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash); + DirItem *dirItem = dirItemForUrl(parentDir); + if (dirItem) { + auto it = std::lower_bound(dirItem->lstItems.begin(), dirItem->lstItems.end(), oldUrl); + dirItem->lstItems.erase(it); + dirItem->insert(item); + } + } + /** * When KDirWatch tells us that something changed in "dir", we need to * also notify the dirlisters that are listing a symlink to "dir" (#213799) @@ -457,6 +414,13 @@ } } + // Insert the item in the sorted list + void insert(const KFileItem &item) + { + auto it = std::lower_bound(lstItems.begin(), lstItems.end(), item.url()); + lstItems.insert(it, item); + } + // number of KCoreDirListers using autoUpdate for this dir short autoUpdates; @@ -476,7 +440,7 @@ // Remember that this is optional. FTP sites don't return '.' in // the list, so they give no root item KFileItem rootItem; - NonMovableFileItemList lstItems; + QList lstItems; }; // definition of the cache of ".hidden" files @@ -517,7 +481,7 @@ // changes yet, we need to wait for the "update" directory listing. // The cmp() call can't differ mimetypes since they are determined on demand, // this is why we need to remember those files here. - QSet pendingRemoteUpdates; + QSet pendingRemoteUpdates; // the KDirNotify signals OrgKdeKDirNotifyInterface *kdirnotify; diff --git a/src/core/kfileitem.h b/src/core/kfileitem.h --- a/src/core/kfileitem.h +++ b/src/core/kfileitem.h @@ -486,6 +486,18 @@ */ bool operator!=(const KFileItem &other) const; + /** + * Returns true if other's URL is lexically greater than this url; otherwise returns false + * @since 5.47 + */ + bool operator<(const KFileItem &other) const; + + /** + * Returns true if url other is lexically greater than this url; otherwise returns false + * @since 5.47 + */ + bool operator<(const QUrl &other) const; + /** * Converts this KFileItem to a QVariant, this allows to use KFileItem * in QVariant() constructor diff --git a/src/core/kfileitem.cpp b/src/core/kfileitem.cpp --- a/src/core/kfileitem.cpp +++ b/src/core/kfileitem.cpp @@ -1236,6 +1236,22 @@ return !operator==(other); } +bool KFileItem::operator<(const KFileItem &other) const +{ + if (!d || !other.d) { + return false; + } + return d->m_url < other.d->m_url; +} + +bool KFileItem::operator<(const QUrl &other) const +{ + if (!d) { + return true; + } + return d->m_url < other; +} + KFileItem::operator QVariant() const { return qVariantFromValue(*this); diff --git a/src/widgets/kdirmodel.cpp b/src/widgets/kdirmodel.cpp --- a/src/widgets/kdirmodel.cpp +++ b/src/widgets/kdirmodel.cpp @@ -608,7 +608,8 @@ if (node != m_rootNode) { // we never set an item in the rootnode, we use m_dirLister->rootItem instead. bool hasNewNode = false; // A file became directory (well, it was overwritten) - if (fit->first.isDir() != fit->second.isDir()) { + // This fact can be notified twice, update only the first time. + if (fit->first.isDir() != fit->second.isDir() && !node->item().isDir()) { //qDebug() << "DIR/FILE STATUS CHANGE"; const int r = node->rowNumber(); removeFromNodeHash(node, oldUrl);