]> cloud.milkyroute.net Git - dolphin.git/blobdiff - src/kitemviews/kfileitemmodel.cpp
Merge remote-tracking branch 'origin/KDE/4.11'
[dolphin.git] / src / kitemviews / kfileitemmodel.cpp
index 7ea5e8018265aabf6a0e00e13eee7e176128a7e5..eb7b1646135b822ea0b26cf7c61aad269ab77dac 100644 (file)
@@ -114,6 +114,7 @@ KFileItemModel::~KFileItemModel()
 {
     qDeleteAll(m_itemData);
     qDeleteAll(m_filteredItems.values());
+    qDeleteAll(m_pendingItemsToInsert);
 }
 
 void KFileItemModel::loadDirectory(const KUrl& url)
@@ -124,8 +125,10 @@ 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);
+    QHashIterator<KUrl, KUrl> expandedDirs(m_expandedDirs);
+    while (expandedDirs.hasNext()) {
+        expandedDirs.next();
+        m_dirLister->openUrl(expandedDirs.value(), KDirLister::Reload);
     }
 
     m_dirLister->openUrl(url, KDirLister::Reload);
@@ -189,8 +192,30 @@ bool KFileItemModel::setData(int index, const QHash<QByteArray, QVariant>& value
 
     emit itemsChanged(KItemRangeList() << KItemRange(index, 1), changedRoles);
 
-    if (changedRoles.contains(sortRole())) {
-        m_resortAllItemsTimer->start();
+    // Trigger a resorting if the item's correct position has changed. Note
+    // that this can happen even if the sort role has not changed at all
+    // because the file name can be used as a fallback.
+    if (changedRoles.contains(sortRole()) || changedRoles.contains(roleForType(NameRole))) {
+        // Compare the changed item with its neighbors to see
+        // if an expensive resorting is needed at all.
+        const ItemData* changedItem = m_itemData.at(index);
+        const ItemData* previousItem = (index == 0) ? 0 : m_itemData.at(index - 1);
+        const ItemData* nextItem = (index == m_itemData.count() - 1) ? 0 : m_itemData.at(index + 1);
+
+        if ((previousItem && lessThan(changedItem, previousItem))
+            || (nextItem && lessThan(nextItem, changedItem))) {
+            m_resortAllItemsTimer->start();
+        } else if (groupedSorting() && changedRoles.contains(sortRole())) {
+            // The position is still correct, but the groups might have changed
+            // if the changed item is either the first or the last item in a
+            // group.
+            // In principle, we could try to find out if the item really is the
+            // first or last one in its group and then update the groups
+            // (possibly with a delayed timer to make sure that we don't
+            // re-calculate the groups very often if items are updated one by
+            // one), but starting m_resortAllItemsTimer is easier.
+            m_resortAllItemsTimer->start();
+        }
     }
 
     return true;
@@ -249,7 +274,7 @@ QMimeData* KFileItemModel::createMimeData(const QSet<int>& indexes) const
         const int index = it.next();
         const KFileItem item = fileItem(index);
         if (!item.isNull()) {
-            urls << item.url();
+            urls << item.targetUrl();
 
             bool isLocal;
             mostLocalUrls << item.mostLocalUrl(isLocal);
@@ -432,11 +457,12 @@ 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();
     if (expanded) {
-        m_expandedDirs.insert(url);
+        m_expandedDirs.insert(targetUrl, url);
         m_dirLister->openUrl(url, KDirLister::Keep);
     } else {
-        m_expandedDirs.remove(url);
+        m_expandedDirs.remove(targetUrl);
         m_dirLister->stop(url);
 
         removeFilteredChildren(KFileItemList() << item);
@@ -478,7 +504,7 @@ int KFileItemModel::expandedParentsCount(int index) const
 
 QSet<KUrl> KFileItemModel::expandedDirectories() const
 {
-    return m_expandedDirs;
+    return m_expandedDirs.values().toSet();
 }
 
 void KFileItemModel::restoreExpandedDirectories(const QSet<KUrl>& urls)
@@ -685,7 +711,6 @@ void KFileItemModel::resortAllItems()
         oldUrls.append(itemData->item.url());
     }
 
-    m_groups.clear();
     m_items.clear();
 
     // Resort the items
@@ -694,20 +719,45 @@ void KFileItemModel::resortAllItems()
         m_items.insert(m_itemData.at(i)->item.url(), i);
     }
 
-    // Determine the indexes that have been moved
-    QList<int> movedToIndexes;
-    movedToIndexes.reserve(itemCount);
-    for (int i = 0; i < itemCount; i++) {
-        const int newIndex = m_items.value(oldUrls.at(i).url());
-        movedToIndexes.append(newIndex);
+    // Determine the first index that has been moved.
+    int firstMovedIndex = 0;
+    while (firstMovedIndex < itemCount
+           && firstMovedIndex == m_items.value(oldUrls.at(firstMovedIndex))) {
+        ++firstMovedIndex;
     }
 
-    // Don't check whether items have really been moved and always emit a
-    // itemsMoved() signal after resorting: In case of grouped items
-    // the groups might change even if the items themselves don't change their
-    // position. Let the receiver of the signal decide whether a check for moved
-    // items makes sense.
-    emit itemsMoved(KItemRange(0, itemCount), movedToIndexes);
+    const bool itemsHaveMoved = firstMovedIndex < itemCount;
+    if (itemsHaveMoved) {
+        m_groups.clear();
+
+        int lastMovedIndex = itemCount - 1;
+        while (lastMovedIndex > firstMovedIndex
+               && lastMovedIndex == m_items.value(oldUrls.at(lastMovedIndex))) {
+            --lastMovedIndex;
+        }
+
+        Q_ASSERT(firstMovedIndex <= lastMovedIndex);
+
+        // Create a list movedToIndexes, which has the property that
+        // movedToIndexes[i] is the new index of the item with the old index
+        // firstMovedIndex + i.
+        const int movedItemsCount = lastMovedIndex - firstMovedIndex + 1;
+        QList<int> movedToIndexes;
+        movedToIndexes.reserve(movedItemsCount);
+        for (int i = firstMovedIndex; i <= lastMovedIndex; ++i) {
+            const int newIndex = m_items.value(oldUrls.at(i));
+            movedToIndexes.append(newIndex);
+        }
+
+        emit itemsMoved(KItemRange(firstMovedIndex, movedItemsCount), movedToIndexes);
+    } else if (groupedSorting()) {
+        // The groups might have changed even if the order of the items has not.
+        const QList<QPair<int, QVariant> > oldGroups = m_groups;
+        m_groups.clear();
+        if (groups() != oldGroups) {
+            emit groupsChanged();
+        }
+    }
 
 #ifdef KFILEITEMMODEL_DEBUG
     kDebug() << "[TIME] Resorting of" << itemCount << "items:" << timer.elapsed();
@@ -755,14 +805,15 @@ void KFileItemModel::slotItemsAdded(const KUrl& directoryUrl, const KFileItemLis
 {
     Q_ASSERT(!items.isEmpty());
 
-    KUrl parentUrl = directoryUrl;
-    parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
+    KUrl parentUrl;
+    if (m_expandedDirs.contains(directoryUrl)) {
+        parentUrl = m_expandedDirs.value(directoryUrl);
+    } else {
+        parentUrl = directoryUrl;
+        parentUrl.adjustPath(KUrl::RemoveTrailingSlash);
+    }
 
     if (m_requestRole[ExpandedParentsCountRole]) {
-        // To be able to compare whether the new items may be inserted as children
-        // of a parent item the pending items must be added to the model first.
-        dispatchPendingItemsToInsert();
-
         KFileItem item = items.first();
 
         // If the expanding of items is enabled, the call
@@ -776,6 +827,12 @@ void KFileItemModel::slotItemsAdded(const KUrl& directoryUrl, const KFileItemLis
             return;
         }
 
+        if (directoryUrl != directory()) {
+            // To be able to compare whether the new items may be inserted as children
+            // of a parent item the pending items must be added to the model first.
+            dispatchPendingItemsToInsert();
+        }
+
         // KDirLister keeps the children of items that got expanded once even if
         // they got collapsed again with KFileItemModel::setExpanded(false). So it must be
         // checked whether the parent for new items is still expanded.
@@ -931,6 +988,8 @@ void KFileItemModel::slotClear()
 
     m_maximumUpdateIntervalTimer->stop();
     m_resortAllItemsTimer->stop();
+
+    qDeleteAll(m_pendingItemsToInsert);
     m_pendingItemsToInsert.clear();
 
     const int removedCount = m_itemData.count();
@@ -1262,25 +1321,20 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item,
     data.insert(sharedValue("url"), item.url());
 
     const bool isDir = item.isDir();
-    if (m_requestRole[IsDirRole]) {
-        data.insert(sharedValue("isDir"), isDir);
+    if (m_requestRole[IsDirRole] && isDir) {
+        data.insert(sharedValue("isDir"), true);
     }
 
-    if (m_requestRole[IsLinkRole]) {
-        const bool isLink = item.isLink();
-        data.insert(sharedValue("isLink"), isLink);
+    if (m_requestRole[IsLinkRole] && item.isLink()) {
+        data.insert(sharedValue("isLink"), true);
     }
 
     if (m_requestRole[NameRole]) {
         data.insert(sharedValue("text"), item.text());
     }
 
-    if (m_requestRole[SizeRole]) {
-        if (isDir) {
-            data.insert(sharedValue("size"), QVariant());
-        } else {
-            data.insert(sharedValue("size"), item.size());
-        }
+    if (m_requestRole[SizeRole] && !isDir) {
+        data.insert(sharedValue("size"), item.size());
     }
 
     if (m_requestRole[DateRole]) {
@@ -1334,17 +1388,15 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem& item,
         data.insert(sharedValue("path"), path);
     }
 
-    if (m_requestRole[IsExpandableRole]) {
-        data.insert(sharedValue("isExpandable"), item.isDir() && item.url() == item.targetUrl());
+    if (m_requestRole[IsExpandableRole] && isDir) {
+        data.insert(sharedValue("isExpandable"), true);
     }
 
     if (m_requestRole[ExpandedParentsCountRole]) {
-        int level = 0;
         if (parent) {
-            level = parent->values["expandedParentsCount"].toInt() + 1;
+            const int level = parent->values["expandedParentsCount"].toInt() + 1;
+            data.insert(sharedValue("expandedParentsCount"), level);
         }
-
-        data.insert(sharedValue("expandedParentsCount"), level);
     }
 
     if (item.isMimeTypeKnown()) {