]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kfileitemmodel.cpp
Merge branch 'release/21.08'
[dolphin.git] / src / kitemviews / kfileitemmodel.cpp
index 9a2d159f9171310b0864f33349b96d54d07ec082..776466d68c3c03ab20d94b63f29de756d20ec684 100644 (file)
@@ -34,7 +34,6 @@ KFileItemModel::KFileItemModel(QObject* parent) :
     KItemModelBase("text", parent),
     m_dirLister(nullptr),
     m_sortDirsFirst(true),
-    m_sortHiddenLast(false),
     m_sortRole(NameRole),
     m_sortingProgressPercent(-1),
     m_roles(),
@@ -208,19 +207,6 @@ bool KFileItemModel::sortDirectoriesFirst() const
     return m_sortDirsFirst;
 }
 
-void KFileItemModel::setSortHiddenLast(bool hiddenLast)
-{
-    if (hiddenLast != m_sortHiddenLast) {
-        m_sortHiddenLast = hiddenLast;
-        resortAllItems();
-    }
-}
-
-bool KFileItemModel::sortHiddenLast() const
-{
-    return m_sortHiddenLast;
-}
-
 void KFileItemModel::setShowHiddenFiles(bool show)
 {
     m_dirLister->setShowingDotFiles(show);
@@ -1098,32 +1084,46 @@ void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >&
     QSet<QByteArray> changedRoles;
     KFileItemList changedFiles;
 
+    // Contains the indexes of the currently visible items
+    // that should get hidden and hence moved to m_filteredItems.
+    QVector<int> newFilteredIndexes;
+
+    // Contains currently hidden items that should
+    // get visible and hence removed from m_filteredItems
+    QList<ItemData*> newVisibleItems;
+
     QListIterator<QPair<KFileItem, KFileItem> > it(items);
     while (it.hasNext()) {
         const QPair<KFileItem, KFileItem>& itemPair = it.next();
         const KFileItem& oldItem = itemPair.first;
         const KFileItem& newItem = itemPair.second;
         const int indexForItem = index(oldItem);
+        const bool newItemMatchesFilter = m_filter.matches(newItem);
         if (indexForItem >= 0) {
             m_itemData[indexForItem]->item = newItem;
 
             // Keep old values as long as possible if they could not retrieved synchronously yet.
             // The update of the values will be done asynchronously by KFileItemModelRolesUpdater.
-            QHashIterator<QByteArray, QVariant> it(retrieveData(newItem, m_itemData.at(indexForItem)->parent));
-            QHash<QByteArray, QVariant>& values = m_itemData[indexForItem]->values;
+            ItemData * const itemData = m_itemData.at(indexForItem);
+            QHashIterator<QByteArray, QVariant> it(retrieveData(newItem, itemData->parent));
             while (it.hasNext()) {
                 it.next();
                 const QByteArray& role = it.key();
-                if (values.value(role) != it.value()) {
-                    values.insert(role, it.value());
+                if (itemData->values.value(role) != it.value()) {
+                    itemData->values.insert(role, it.value());
                     changedRoles.insert(role);
                 }
             }
 
             m_items.remove(oldItem.url());
-            m_items.insert(newItem.url(), indexForItem);
-            changedFiles.append(newItem);
-            indexes.append(indexForItem);
+            if (newItemMatchesFilter) {
+                m_items.insert(newItem.url(), indexForItem);
+                changedFiles.append(newItem);
+                indexes.append(indexForItem);
+            } else {
+                newFilteredIndexes.append(indexForItem);
+                m_filteredItems.insert(newItem, itemData);
+            }
         } else {
             // Check if 'oldItem' is one of the filtered items.
             QHash<KFileItem, ItemData*>::iterator it = m_filteredItems.find(oldItem);
@@ -1136,11 +1136,22 @@ void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >&
                 itemData->values.clear();
 
                 m_filteredItems.erase(it);
-                m_filteredItems.insert(newItem, itemData);
+                if (newItemMatchesFilter) {
+                    newVisibleItems.append(itemData);
+                } else {
+                    m_filteredItems.insert(newItem, itemData);
+                }
             }
         }
     }
 
+    // Hide items, previously visible that should get hidden
+    const KItemRangeList removedRanges = KItemRangeList::fromSortedContainer(newFilteredIndexes);
+    removeItems(removedRanges, KeepItemData);
+
+    // Show previously hidden items that should get visible
+    insertItems(newVisibleItems);
+
     // If the changed items have been created recently, they might not be in m_items yet.
     // In that case, the list 'indexes' might be empty.
     if (indexes.isEmpty()) {
@@ -1742,17 +1753,6 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b, const QColla
         }
     }
 
-    // Show hidden files and folders last
-    if (m_sortHiddenLast) {
-        const bool isHiddenA = a->item.isHidden();
-        const bool isHiddenB = b->item.isHidden();
-        if (isHiddenA && !isHiddenB) {
-            return false;
-        } else if (!isHiddenA && isHiddenB) {
-            return true;
-        }
-    }
-
     if (m_sortDirsFirst || (DetailsModeSettings::directorySizeCount() && m_sortRole == SizeRole)) {
         const bool isDirA = a->item.isDir();
         const bool isDirB = b->item.isDir();
@@ -1791,6 +1791,11 @@ void KFileItemModel::sort(const QList<KFileItemModel::ItemData*>::iterator &begi
 
 int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const QCollator& collator) const
 {
+    // This function must never return 0, because that would break stable
+    // sorting, which leads to all kinds of bugs.
+    // See: https://bugs.kde.org/show_bug.cgi?id=433247
+    // If two items have equal sort values, let the fallbacks at the bottom of
+    // the function handle it.
     const KFileItem& itemA = a->item;
     const KFileItem& itemB = b->item;
 
@@ -1808,29 +1813,21 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
             auto valueA = a->values.value("count");
             auto valueB = b->values.value("count");
             if (valueA.isNull()) {
-                if (valueB.isNull()) {
-                    result = 0;
-                    break;
-                } else {
-                    result = -1;
-                    break;
+                if (!valueB.isNull()) {
+                    return -1;
                 }
             } else if (valueB.isNull()) {
-                result = +1;
-                break;
+                return +1;
             } else {
                 if (valueA.toLongLong() < valueB.toLongLong()) {
-                    result = -1;
-                    break;
+                    return -1;
                 } else if (valueA.toLongLong() > valueB.toLongLong()) {
-                    result = +1;
-                    break;
-                } else {
-                    result = 0;
-                    break;
+                    return +1;
                 }
             }
+            break;
         }
+
         KIO::filesize_t sizeA = 0;
         if (itemA.isDir()) {
             sizeA = a->values.value("size").toULongLong();
@@ -1843,12 +1840,10 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
         } else {
             sizeB = itemB.size();
         }
-        if (sizeA > sizeB) {
-            result = +1;
-        } else if (sizeA < sizeB) {
-            result = -1;
-        } else {
-            result = 0;
+        if (sizeA < sizeB) {
+            return -1;
+        } else if (sizeA > sizeB) {
+            return +1;
         }
         break;
     }
@@ -1857,9 +1852,9 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
         const long long dateTimeA = itemA.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
         const long long dateTimeB = itemB.entry().numberValue(KIO::UDSEntry::UDS_MODIFICATION_TIME, -1);
         if (dateTimeA < dateTimeB) {
-            result = -1;
+            return -1;
         } else if (dateTimeA > dateTimeB) {
-            result = +1;
+            return +1;
         }
         break;
     }
@@ -1868,9 +1863,9 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
         const long long dateTimeA = itemA.entry().numberValue(KIO::UDSEntry::UDS_CREATION_TIME, -1);
         const long long dateTimeB = itemB.entry().numberValue(KIO::UDSEntry::UDS_CREATION_TIME, -1);
         if (dateTimeA < dateTimeB) {
-            result = -1;
+            return -1;
         } else if (dateTimeA > dateTimeB) {
-            result = +1;
+            return +1;
         }
         break;
     }
@@ -1879,9 +1874,9 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
         const QDateTime dateTimeA = a->values.value("deletiontime").toDateTime();
         const QDateTime dateTimeB = b->values.value("deletiontime").toDateTime();
         if (dateTimeA < dateTimeB) {
-            result = -1;
+            return -1;
         } else if (dateTimeA > dateTimeB) {
-            result = +1;
+            return +1;
         }
         break;
     }
@@ -1902,9 +1897,9 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const
         const QString roleValueA = a->values.value(role).toString();
         const QString roleValueB = b->values.value(role).toString();
         if (!roleValueA.isEmpty() && roleValueB.isEmpty()) {
-            result = -1;
+            return -1;
         } else if (roleValueA.isEmpty() && !roleValueB.isEmpty()) {
-            result = +1;
+            return +1;
         } else if (isRoleValueNatural(m_sortRole)) {
             result = stringCompare(roleValueA, roleValueB, collator);
         } else {