]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kfileitemmodel.cpp
KFileItemModelRolesUpdater: only update the size for changed folders
[dolphin.git] / src / kitemviews / kfileitemmodel.cpp
index 231bfe077e2d12ce195f38d42f65fbc5b0a241b5..7ba78a436fa57bf74c8f7d7948e27b0deab421ec 100644 (file)
@@ -33,6 +33,9 @@
 #include <QTimer>
 #include <QWidget>
 
+#include <algorithm>
+#include <vector>
+
 // #define KFILEITEMMODEL_DEBUG
 
 KFileItemModel::KFileItemModel(QObject* parent) :
@@ -120,6 +123,11 @@ void KFileItemModel::loadDirectory(const KUrl& url)
 
 void KFileItemModel::refreshDirectory(const KUrl& url)
 {
+    // Refresh all expanded directories first (Bug 295300)
+    foreach (const KUrl& expandedUrl, m_expandedDirs) {
+        m_dirLister->openUrl(expandedUrl, KDirLister::Reload);
+    }
+
     m_dirLister->openUrl(url, KDirLister::Reload);
 }
 
@@ -438,6 +446,29 @@ bool KFileItemModel::setExpanded(int index, bool expanded)
             itemsToRemove.append(m_itemData.at(index)->item);
             ++index;
         }
+
+        QSet<KUrl> urlsToRemove;
+        urlsToRemove.reserve(itemsToRemove.count() + 1);
+        urlsToRemove.insert(url);
+        foreach (const KFileItem& item, itemsToRemove) {
+            KUrl url = item.url();
+            url.adjustPath(KUrl::RemoveTrailingSlash);
+            urlsToRemove.insert(url);
+        }
+
+        QSet<KFileItem>::iterator it = m_filteredItems.begin();
+        while (it != m_filteredItems.end()) {
+            const KUrl url = it->url();
+            KUrl parentUrl = url.upUrl();
+            parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
+
+            if (urlsToRemove.contains(parentUrl)) {
+                it = m_filteredItems.erase(it);
+            } else {
+                ++it;
+            }
+        }
+
         removeItems(itemsToRemove);
     }
 
@@ -795,6 +826,33 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items)
         foreach (const KFileItem& item, itemsToRemove) {
             m_filteredItems.remove(item);
         }
+
+        if (m_requestRole[ExpandedParentsCountRole] && m_expandedParentsCountRoot >= 0) {
+            // Remove all filtered children of deleted items. First, we put the
+            // deleted URLs into a set to provide fast lookup while iterating
+            // over m_filteredItems and prevent quadratic complexity if there
+            // are N removed items and N filtered items.
+            QSet<KUrl> urlsToRemove;
+            urlsToRemove.reserve(itemsToRemove.count());
+            foreach (const KFileItem& item, itemsToRemove) {
+                KUrl url = item.url();
+                url.adjustPath(KUrl::RemoveTrailingSlash);
+                urlsToRemove.insert(url);
+            }
+
+            QSet<KFileItem>::iterator it = m_filteredItems.begin();
+            while (it != m_filteredItems.end()) {
+                const KUrl url = it->url();
+                KUrl parentUrl = url.upUrl();
+                parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
+
+                if (urlsToRemove.contains(parentUrl)) {
+                    it = m_filteredItems.erase(it);
+                } else {
+                    ++it;
+                }
+            }
+        }
     }
 
     removeItems(itemsToRemove);
@@ -1499,7 +1557,7 @@ int KFileItemModel::expandedParentsCountCompare(const ItemData* a, const ItemDat
     if (index > maxIndex) {
         index = maxIndex;
     }
-    while ((pathA.at(index) != QLatin1Char('/') || pathB.at(index) != QLatin1Char('/')) && index > 0) {
+    while (index > 0 && (pathA.at(index) != QLatin1Char('/') || pathB.at(index) != QLatin1Char('/'))) {
         --index;
     }
 
@@ -1557,6 +1615,11 @@ bool KFileItemModel::useMaximumUpdateInterval() const
     return !m_dirLister->url().isLocalFile();
 }
 
+static bool localeAwareLessThan(const QChar& c1, const QChar& c2)
+{
+    return QString::localeAwareCompare(c1, c2) < 0;
+}
+
 QList<QPair<int, QVariant> > KFileItemModel::nameRoleGroups() const
 {
     Q_ASSERT(!m_itemData.isEmpty());
@@ -1566,7 +1629,6 @@ QList<QPair<int, QVariant> > KFileItemModel::nameRoleGroups() const
 
     QString groupValue;
     QChar firstChar;
-    bool isLetter = false;
     for (int i = 0; i <= maxIndex; ++i) {
         if (isChildItem(i)) {
             continue;
@@ -1582,31 +1644,31 @@ QList<QPair<int, QVariant> > KFileItemModel::nameRoleGroups() const
 
         if (firstChar != newFirstChar) {
             QString newGroupValue;
-            if (newFirstChar >= QLatin1Char('A') && newFirstChar <= QLatin1Char('Z')) {
-                // Apply group 'A' - 'Z'
-                newGroupValue = newFirstChar;
-                isLetter = true;
+            if (newFirstChar.isLetter()) {
+                // Try to find a matching group in the range 'A' to 'Z'.
+                static std::vector<QChar> lettersAtoZ;
+                if (lettersAtoZ.empty()) {
+                    for (char c = 'A'; c <= 'Z'; ++c) {
+                        lettersAtoZ.push_back(QLatin1Char(c));
+                    }
+                }
+
+                std::vector<QChar>::iterator it = std::lower_bound(lettersAtoZ.begin(), lettersAtoZ.end(), newFirstChar, localeAwareLessThan);
+                if (it != lettersAtoZ.end()) {
+                    if (localeAwareLessThan(newFirstChar, *it) && it != lettersAtoZ.begin()) {
+                        // newFirstChar belongs to the group preceding *it.
+                        // Example: for an umlaut 'A' in the German locale, *it would be 'B' now.
+                        --it;
+                    }
+                    newGroupValue = *it;
+                } else {
+                    newGroupValue = newFirstChar;
+                }
             } else if (newFirstChar >= QLatin1Char('0') && newFirstChar <= QLatin1Char('9')) {
                 // Apply group '0 - 9' for any name that starts with a digit
                 newGroupValue = i18nc("@title:group Groups that start with a digit", "0 - 9");
-                isLetter = false;
             } else {
-                if (isLetter) {
-                    // If the current group is 'A' - 'Z' check whether a locale character
-                    // fits into the existing group.
-                    // TODO: This does not work in the case if e.g. the group 'O' starts with
-                    // an umlaut 'O' -> provide unit-test to document this known issue
-                    const QChar prevChar(firstChar.unicode() - ushort(1));
-                    const QChar nextChar(firstChar.unicode() + ushort(1));
-                    const QString currChar(newFirstChar);
-                    const bool partOfCurrentGroup = currChar.localeAwareCompare(prevChar) > 0 &&
-                                                    currChar.localeAwareCompare(nextChar) < 0;
-                    if (partOfCurrentGroup) {
-                        continue;
-                    }
-                }
                 newGroupValue = i18nc("@title:group", "Others");
-                isLetter = false;
             }
 
             if (newGroupValue != groupValue) {