]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kfileitemmodel.cpp
Fix for crash which was introduced by commit
[dolphin.git] / src / kitemviews / kfileitemmodel.cpp
index 524b4f59a97ff6597e854b144870ecda77d80657..98249dbd982d39ee796bd3bb4e6554a58a8725b6 100644 (file)
@@ -25,7 +25,6 @@
 #include <KLocalizedString>
 #include <KStringHandler>
 #include <KDebug>
-#include <kstringhandler_deprecated.h> //TODO: port to QCollator
 
 #include "private/kfileitemmodelsortalgorithm.h"
 #include "private/kfileitemmodeldirlister.h"
@@ -47,7 +46,6 @@ KFileItemModel::KFileItemModel(QObject* parent) :
     m_sortRole(NameRole),
     m_sortingProgressPercent(-1),
     m_roles(),
-    m_caseSensitivity(Qt::CaseInsensitive),
     m_itemData(),
     m_items(),
     m_filter(),
@@ -60,6 +58,9 @@ KFileItemModel::KFileItemModel(QObject* parent) :
     m_expandedDirs(),
     m_urlsToExpand()
 {
+    m_collator.setCaseSensitivity(Qt::CaseInsensitive);
+    m_collator.setNumericMode(true);
+
     m_dirLister = new KFileItemModelDirLister(this);
     m_dirLister->setDelayedMimeTypes(true);
 
@@ -189,8 +190,9 @@ bool KFileItemModel::setData(int index, const QHash<QByteArray, QVariant>& value
 
     m_itemData[index]->values = currentValues;
     if (changedRoles.contains("text")) {
-        KUrl url = m_itemData[index]->item.url();
-        url.setFileName(currentValues["text"].toString());
+        QUrl url = m_itemData[index]->item.url();
+        url = url.adjusted(QUrl::RemoveFilename);
+        url.setPath(url.path() + currentValues["text"].toString());
         m_itemData[index]->item.setUrl(url);
     }
 
@@ -243,8 +245,8 @@ QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const
     // The following code has been taken from KDirModel::mimeData()
     // (kdelibs/kio/kio/kdirmodel.cpp)
     // Copyright (C) 2006 David Faure <faure@kde.org>
-    KUrl::List urls;
-    KUrl::List mostLocalUrls;
+    QList<QUrl> urls;
+    QList<QUrl> mostLocalUrls;
     bool canUseMostLocalUrls = true;
     const ItemData* lastAddedItem = 0;
 
@@ -276,9 +278,9 @@ QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const
 
     const bool different = canUseMostLocalUrls && mostLocalUrls != urls;
     if (different) {
-        urls.populateMimeData(mostLocalUrls, data);
+        data->setUrls(mostLocalUrls);
     } else {
-        urls.populateMimeData(data);
+        data->setUrls(urls);
     }
 
     return data;
@@ -369,8 +371,7 @@ int KFileItemModel::index(const KFileItem& item) const
 
 int KFileItemModel::index(const QUrl& url) const
 {
-    KUrl urlToFind = url;
-    urlToFind.adjustPath(KUrl::RemoveTrailingSlash);
+    const QUrl urlToFind = url.adjusted(QUrl::StripTrailingSlash);
 
     const int itemCount = m_itemData.count();
     int itemsInHash = m_items.count();
@@ -388,7 +389,7 @@ int KFileItemModel::index(const QUrl& url) const
         const int blockSize = 1000;
         const int currentBlockEnd = qMin(itemsInHash + blockSize, itemCount);
         for (int i = itemsInHash; i < currentBlockEnd; ++i) {
-            const KUrl nextUrl = m_itemData.at(i)->item.url();
+            const QUrl nextUrl = m_itemData.at(i)->item.url();
             m_items.insert(nextUrl, i);
         }
 
@@ -412,12 +413,12 @@ int KFileItemModel::index(const QUrl& url) const
             kWarning() << "m_itemData.count() ==" << m_itemData.count();
 
             // Check if there are multiple items with the same URL.
-            QMultiHash<KUrl, int> indexesForUrl;
+            QMultiHash<QUrl, int> indexesForUrl;
             for (int i = 0; i < m_itemData.count(); ++i) {
                 indexesForUrl.insert(m_itemData.at(i)->item.url(), i);
             }
 
-            foreach (const KUrl& url, indexesForUrl.uniqueKeys()) {
+            foreach (const QUrl& url, indexesForUrl.uniqueKeys()) {
                 if (indexesForUrl.count(url) > 1) {
                     kWarning() << "Multiple items found with the URL" << url;
                     foreach (int index, indexesForUrl.values(url)) {
@@ -511,15 +512,15 @@ bool KFileItemModel::setExpanded(int index, bool expanded)
     }
 
     const KFileItem item = m_itemData.at(index)->item;
-    const KUrl url = item.url();
-    const KUrl targetUrl = item.targetUrl();
+    const QUrl url = item.url();
+    const QUrl targetUrl = item.targetUrl();
     if (expanded) {
         m_expandedDirs.insert(targetUrl, url);
         m_dirLister->openUrl(url, KDirLister::Keep);
 
-        const KUrl::List previouslyExpandedChildren = m_itemData.at(index)->values.value("previouslyExpandedChildren").value<KUrl::List>();
-        foreach (const KUrl& url, previouslyExpandedChildren) {
-            m_urlsToExpand.insert(url);
+        const QVariantList previouslyExpandedChildren = m_itemData.at(index)->values.value("previouslyExpandedChildren").value<QVariantList>();
+        foreach (const QVariant& var, previouslyExpandedChildren) {
+            m_urlsToExpand.insert(var.toUrl());
         }
     } else {
         // Note that there might be (indirect) children of the folder which is to be collapsed in
@@ -541,14 +542,14 @@ bool KFileItemModel::setExpanded(int index, bool expanded)
         const int itemCount = m_itemData.count();
         const int firstChildIndex = index + 1;
 
-        KUrl::List expandedChildren;
+        QVariantList expandedChildren;
 
         int childIndex = firstChildIndex;
         while (childIndex < itemCount && expandedParentsCount(childIndex) > parentLevel) {
             ItemData* itemData = m_itemData.at(childIndex);
             if (itemData->values.value("isExpanded").toBool()) {
-                const KUrl targetUrl = itemData->item.targetUrl();
-                const KUrl url = itemData->item.url();
+                const QUrl targetUrl = itemData->item.targetUrl();
+                const QUrl url = itemData->item.url();
                 m_expandedDirs.remove(targetUrl);
                 m_dirLister->stop(url);     // TODO: try to unit-test this, see https://bugs.kde.org/show_bug.cgi?id=332102#c11
                 expandedChildren.append(targetUrl);
@@ -610,10 +611,10 @@ void KFileItemModel::expandParentDirectories(const QUrl &url)
     // expanded is added to m_urlsToExpand. KDirLister
     // does not care whether the parent-URL has already been
     // expanded.
-    KUrl urlToExpand = m_dirLister->url();
+    QUrl urlToExpand = m_dirLister->url();
     const QStringList subDirs = url.path().mid(pos).split(QDir::separator());
     for (int i = 0; i < subDirs.count() - 1; ++i) {
-        urlToExpand.addPath(subDirs.at(i));
+        urlToExpand.setPath(urlToExpand.path() + '/' + subDirs.at(i));
         m_urlsToExpand.insert(urlToExpand);
     }
 
@@ -801,7 +802,7 @@ void KFileItemModel::resortAllItems()
     // Remember the order of the current URLs so
     // that it can be determined which indexes have
     // been moved because of the resorting.
-    QList<KUrl> oldUrls;
+    QList<QUrl> oldUrls;
     oldUrls.reserve(itemCount);
     foreach (const ItemData* itemData, m_itemData) {
         oldUrls.append(itemData->item.url());
@@ -870,7 +871,7 @@ void KFileItemModel::slotCompleted()
         // Note that the parent folder must be expanded before any of its subfolders become visible.
         // Therefore, some URLs in m_restoredExpandedUrls might not be visible yet
         // -> we expand the first visible URL we find in m_restoredExpandedUrls.
-        foreach (const KUrl& url, m_urlsToExpand) {
+        foreach (const QUrl& url, m_urlsToExpand) {
             const int indexForUrl = index(url);
             if (indexForUrl >= 0) {
                 m_urlsToExpand.remove(url);
@@ -902,12 +903,11 @@ void KFileItemModel::slotItemsAdded(const QUrl &directoryUrl, const KFileItemLis
 {
     Q_ASSERT(!items.isEmpty());
 
-    KUrl parentUrl;
+    QUrl parentUrl;
     if (m_expandedDirs.contains(directoryUrl)) {
         parentUrl = m_expandedDirs.value(directoryUrl);
     } else {
-        parentUrl = directoryUrl;
-        parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
+        parentUrl = directoryUrl.adjusted(QUrl::StripTrailingSlash);
     }
 
     if (m_requestRole[ExpandedParentsCountRole]) {
@@ -916,7 +916,7 @@ void KFileItemModel::slotItemsAdded(const QUrl &directoryUrl, const KFileItemLis
         // might result in emitting the same items twice due to the Keep-parameter.
         // This case happens if an item gets expanded, collapsed and expanded again
         // before the items could be loaded for the first expansion.
-        if (index(KUrl(items.first().url())) >= 0) {
+        if (index(items.first().url()) >= 0) {
             // The items are already part of the model.
             return;
         }
@@ -1173,7 +1173,7 @@ void KFileItemModel::insertItems(QList<ItemData*>& newItems)
 
         while (sourceIndexNewItems >= 0) {
             ItemData* newItem = newItems.at(sourceIndexNewItems);
-            if (sourceIndexExistingItems >= 0 && lessThan(newItem, m_itemData.at(sourceIndexExistingItems))) {
+            if (sourceIndexExistingItems >= 0 && lessThan(newItem, m_itemData.at(sourceIndexExistingItems), m_collator)) {
                 // Move an existing item to its new position. If any new items
                 // are behind it, push the item range to itemRanges.
                 if (rangeCount > 0) {
@@ -1202,7 +1202,7 @@ void KFileItemModel::insertItems(QList<ItemData*>& newItems)
     }
 
     // The indexes in m_items are not correct anymore. Therefore, we clear m_items.
-    // It will be re-populated with the updated indices if index(const KUrl&) is called.
+    // It will be re-populated with the updated indices if index(const QUrl&) is called.
     m_items.clear();
 
     emit itemsInserted(itemRanges);
@@ -1255,13 +1255,13 @@ void KFileItemModel::removeItems(const KItemRangeList& itemRanges, RemoveItemsBe
     m_itemData.erase(m_itemData.end() - removedItemsCount, m_itemData.end());
 
     // The indexes in m_items are not correct anymore. Therefore, we clear m_items.
-    // It will be re-populated with the updated indices if index(const KUrl&) is called.
+    // It will be re-populated with the updated indices if index(const QUrl&) is called.
     m_items.clear();
 
     emit itemsRemoved(itemRanges);
 }
 
-QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const KUrl& parentUrl, const KFileItemList& items) const
+QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const QUrl& parentUrl, const KFileItemList& items) const
 {
     if (m_sortRole == TypeRole) {
         // Try to resolve the MIME-types synchronously to prevent a reordering of
@@ -1389,14 +1389,14 @@ void KFileItemModel::emitItemsChangedAndTriggerResorting(const KItemRangeList& i
             // (b)  the successor of the last item is "lessThan" the last item, or
             // (c)  the internal order of the items in the range is incorrect.
             if (first > 0
-                && lessThan(m_itemData.at(first), m_itemData.at(first - 1))) {
+                && lessThan(m_itemData.at(first), m_itemData.at(first - 1), m_collator)) {
                 needsResorting = true;
             } else if (last < count() - 1
-                && lessThan(m_itemData.at(last + 1), m_itemData.at(last))) {
+                && lessThan(m_itemData.at(last + 1), m_itemData.at(last), m_collator)) {
                 needsResorting = true;
             } else {
                 for (int index = first; index < last; ++index) {
-                    if (lessThan(m_itemData.at(index + 1), m_itemData.at(index))) {
+                    if (lessThan(m_itemData.at(index + 1), m_itemData.at(index), m_collator)) {
                         needsResorting = true;
                         break;
                     }
@@ -1583,7 +1583,7 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item,
     return data;
 }
 
-bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const
+bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b, const QCollator& collator) const
 {
     int result = 0;
 
@@ -1628,7 +1628,7 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const
         }
     }
 
-    result = sortRoleCompare(a, b);
+    result = sortRoleCompare(a, b, collator);
 
     return (sortOrder() == Qt::AscendingOrder) ? result < 0 : result > 0;
 }
@@ -1639,24 +1639,36 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const
 class KFileItemModelLessThan
 {
 public:
-    KFileItemModelLessThan(const KFileItemModel* model) :
-        m_model(model)
+    KFileItemModelLessThan(const KFileItemModel* model, const QCollator& collator) :
+        m_model(model),
+        m_collator(collator)
+    {
+    }
+
+    KFileItemModelLessThan(const KFileItemModelLessThan& other) :
+        m_model(other.m_model),
+        m_collator()
     {
+        m_collator.setCaseSensitivity(other.m_collator.caseSensitivity());
+        m_collator.setIgnorePunctuation(other.m_collator.ignorePunctuation());
+        m_collator.setLocale(other.m_collator.locale());
+        m_collator.setNumericMode(other.m_collator.numericMode());
     }
 
     bool operator()(const KFileItemModel::ItemData* a, const KFileItemModel::ItemData* b) const
     {
-        return m_model->lessThan(a, b);
+        return m_model->lessThan(a, b, m_collator);
     }
 
 private:
     const KFileItemModel* m_model;
+    QCollator m_collator;
 };
 
 void KFileItemModel::sort(QList<KFileItemModel::ItemData*>::iterator begin,
                           QList<KFileItemModel::ItemData*>::iterator end) const
 {
-    KFileItemModelLessThan lessThan(this);
+    KFileItemModelLessThan lessThan(this, m_collator);
 
     if (m_sortRole == NameRole) {
         // Sorting by name can be expensive, in particular if natural sorting is
@@ -1671,7 +1683,7 @@ void KFileItemModel::sort(QList<KFileItemModel::ItemData*>::iterator begin,
     }
 }
 
-int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
+int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b, const QCollator& collator) const
 {
     const KFileItem& itemA = a->item;
     const KFileItem& itemB = b->item;
@@ -1734,9 +1746,8 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
     case ImageSizeRole: {
         // Alway use a natural comparing to interpret the numbers of a string like
         // "1600 x 1200" for having a correct sorting.
-        result = KStringHandler::naturalCompare(a->values.value("imageSize").toString(),
-                                                b->values.value("imageSize").toString(),
-                                                Qt::CaseSensitive);
+        result = collator.compare(a->values.value("imageSize").toString(),
+                                  b->values.value("imageSize").toString());
         break;
     }
 
@@ -1755,14 +1766,13 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
     }
 
     // Fallback #1: Compare the text of the items
-    result = stringCompare(itemA.text(), itemB.text());
+    result = stringCompare(itemA.text(), itemB.text(), collator);
     if (result != 0) {
         return result;
     }
 
     // Fallback #2: KFileItem::text() may not be unique in case UDS_DISPLAY_NAME is used
-    result = stringCompare(itemA.name(m_caseSensitivity == Qt::CaseInsensitive),
-                           itemB.name(m_caseSensitivity == Qt::CaseInsensitive));
+    result = stringCompare(itemA.name(), itemB.name(), collator);
     if (result != 0) {
         return result;
     }
@@ -1773,26 +1783,21 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const
     return QString::compare(itemA.url().url(), itemB.url().url(), Qt::CaseSensitive);
 }
 
-int KFileItemModel::stringCompare(const QString& a, const QString& b) const
+int KFileItemModel::stringCompare(const QString& a, const QString& b, const QCollator& collator) const
 {
-    // Taken from KDirSortFilterProxyModel (kdelibs/kfile/kdirsortfilterproxymodel.*)
-    // Copyright (C) 2006 by Peter Penz <peter.penz@gmx.at>
-    // Copyright (C) 2006 by Dominic Battre <dominic@battre.de>
-    // Copyright (C) 2006 by Martin Pool <mbp@canonical.com>
+    if (m_naturalSorting) {
+        return collator.compare(a, b);
+    }
 
-    if (m_caseSensitivity == Qt::CaseInsensitive) {
-        const int result = m_naturalSorting ? KStringHandler::naturalCompare(a, b, Qt::CaseInsensitive)
-                                            : QString::compare(a, b, Qt::CaseInsensitive);
-        if (result != 0) {
-            // Only return the result, if the strings are not equal. If they are equal by a case insensitive
-            // comparison, still a deterministic sort order is required. A case sensitive
-            // comparison is done as fallback.
-            return result;
-        }
+    const int result = QString::compare(a, b, collator.caseSensitivity());
+    if (result != 0 || collator.caseSensitivity() == Qt::CaseSensitive) {
+        // Only return the result, if the strings are not equal. If they are equal by a case insensitive
+        // comparison, still a deterministic sort order is required. A case sensitive
+        // comparison is done as fallback.
+        return result;
     }
 
-    return m_naturalSorting ? KStringHandler::naturalCompare(a, b, Qt::CaseSensitive)
-                            : QString::compare(a, b, Qt::CaseSensitive);
+    return QString::compare(a, b, Qt::CaseSensitive);
 }
 
 bool KFileItemModel::useMaximumUpdateInterval() const
@@ -1800,11 +1805,6 @@ 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());
@@ -1838,6 +1838,10 @@ QList<QPair<int, QVariant> > KFileItemModel::nameRoleGroups() const
                     }
                 }
 
+                auto localeAwareLessThan = [this](const QChar& c1, const QChar& c2) -> bool {
+                    return m_collator.compare(c1, c2) < 0;
+                };
+
                 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()) {
@@ -2200,7 +2204,7 @@ QByteArray KFileItemModel::sharedValue(const QByteArray& value)
 bool KFileItemModel::isConsistent() const
 {
     // m_items may contain less items than m_itemData because m_items
-    // is populated lazily, see KFileItemModel::index(const KUrl& url).
+    // is populated lazily, see KFileItemModel::index(const QUrl& url).
     if (m_items.count() > m_itemData.count()) {
         return false;
     }
@@ -2220,7 +2224,7 @@ bool KFileItemModel::isConsistent() const
         }
 
         // Check if the items are sorted correctly.
-        if (i > 0 && !lessThan(m_itemData.at(i - 1), m_itemData.at(i))) {
+        if (i > 0 && !lessThan(m_itemData.at(i - 1), m_itemData.at(i), m_collator)) {
             qWarning() << "The order of items" << i - 1 << "and" << i << "is wrong:"
                 << fileItem(i - 1) << fileItem(i);
             return false;