X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/59723fca41a44e4d1ee753e93589027cbdf8d20d..926782d3be2502c6d3e87ef992aa371c081d72b4:/src/kitemviews/kfileitemmodel.cpp diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index c0dedff39..bd905bf07 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -190,11 +190,7 @@ bool KFileItemModel::setData(int index, const QHash& value m_itemData[index]->item.setUrl(url); } - emit itemsChanged(KItemRangeList() << KItemRange(index, 1), changedRoles); - - if (changedRoles.contains(sortRole())) { - m_resortAllItemsTimer->start(); - } + emitItemsChangedAndTriggerResorting(KItemRangeList() << KItemRange(index, 1), changedRoles); return true; } @@ -472,10 +468,7 @@ bool KFileItemModel::isExpandable(int index) const int KFileItemModel::expandedParentsCount(int index) const { if (index >= 0 && index < count()) { - const int parentsCount = m_itemData.at(index)->values.value("expandedParentsCount").toInt(); - if (parentsCount > 0) { - return parentsCount; - } + return expandedParentsCount(m_itemData.at(index)); } return 0; } @@ -689,7 +682,6 @@ void KFileItemModel::resortAllItems() oldUrls.append(itemData->item.url()); } - m_groups.clear(); m_items.clear(); // Resort the items @@ -698,20 +690,45 @@ void KFileItemModel::resortAllItems() m_items.insert(m_itemData.at(i)->item.url(), i); } - // Determine the indexes that have been moved - QList movedToIndexes; - movedToIndexes.reserve(itemCount); - for (int i = 0; i < itemCount; i++) { - const int newIndex = m_items.value(oldUrls.at(i)); - 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 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 > oldGroups = m_groups; + m_groups.clear(); + if (groups() != oldGroups) { + emit groupsChanged(); + } + } #ifdef KFILEITEMMODEL_DEBUG kDebug() << "[TIME] Resorting of" << itemCount << "items:" << timer.elapsed(); @@ -899,35 +916,8 @@ void KFileItemModel::slotRefreshItems(const QList >& // Extract the item-ranges out of the changed indexes qSort(indexes); - - KItemRangeList itemRangeList; - int previousIndex = indexes.at(0); - int rangeIndex = previousIndex; - int rangeCount = 1; - - const int maxIndex = indexes.count() - 1; - for (int i = 1; i <= maxIndex; ++i) { - const int currentIndex = indexes.at(i); - if (currentIndex == previousIndex + 1) { - ++rangeCount; - } else { - itemRangeList.append(KItemRange(rangeIndex, rangeCount)); - - rangeIndex = currentIndex; - rangeCount = 1; - } - previousIndex = currentIndex; - } - - if (rangeCount > 0) { - itemRangeList.append(KItemRange(rangeIndex, rangeCount)); - } - - emit itemsChanged(itemRangeList, changedRoles); - - if (changedRoles.contains(sortRole())) { - resortAllItems(); - } + const KItemRangeList itemRangeList = KItemRangeList::fromSortedContainer(indexes); + emitItemsChangedAndTriggerResorting(itemRangeList, changedRoles); } void KFileItemModel::slotClear() @@ -1064,36 +1054,6 @@ void KFileItemModel::insertItems(QList& newItems) #endif } -static KItemRangeList sortedIndexesToKItemRangeList(const QList& sortedNumbers) -{ - if (sortedNumbers.empty()) { - return KItemRangeList(); - } - - KItemRangeList result; - - QList::const_iterator it = sortedNumbers.begin(); - int index = *it; - int count = 1; - - ++it; - - QList::const_iterator end = sortedNumbers.end(); - while (it != end) { - if (*it == index + count) { - ++count; - } else { - result << KItemRange(index, count); - index = *it; - count = 1; - } - ++it; - } - - result << KItemRange(index, count); - return result; -} - void KFileItemModel::removeItems(const KFileItemList& items, RemoveItemsBehavior behavior) { #ifdef KFILEITEMMODEL_DEBUG @@ -1132,7 +1092,7 @@ void KFileItemModel::removeItems(const KFileItemList& items, RemoveItemsBehavior std::sort(indexesToRemove.begin(), indexesToRemove.end()); // Step 2: Remove the ItemData pointers from the list m_itemData. - const KItemRangeList itemRanges = sortedIndexesToKItemRangeList(indexesToRemove); + const KItemRangeList itemRanges = KItemRangeList::fromSortedContainer(indexesToRemove); int target = itemRanges.at(0).index; int source = itemRanges.at(0).index + itemRanges.at(0).count; int nextRange = 1; @@ -1188,6 +1148,23 @@ QList KFileItemModel::createItemDataList(const KUrl& return itemDataList; } +int KFileItemModel::expandedParentsCount(const ItemData* data) +{ + // The hash 'values' is only guaranteed to contain the key "expandedParentsCount" + // if the corresponding item is expanded, and it is not a top-level item. + const ItemData* parent = data->parent; + if (parent) { + if (parent->parent) { + Q_ASSERT(parent->values.contains("expandedParentsCount")); + return parent->values.value("expandedParentsCount").toInt() + 1; + } else { + return 1; + } + } else { + return 0; + } +} + void KFileItemModel::removeExpandedItems() { KFileItemList expandedItems; @@ -1195,16 +1172,78 @@ void KFileItemModel::removeExpandedItems() const int maxIndex = m_itemData.count() - 1; for (int i = 0; i <= maxIndex; ++i) { const ItemData* itemData = m_itemData.at(i); - if (itemData->values.value("expandedParentsCount").toInt() > 0) { + if (itemData->parent) { expandedItems.append(itemData->item); } } - // The m_expandedParentsCountRoot may not get reset before all items with - // a bigger count have been removed. removeItems(expandedItems, DeleteItemData); - m_expandedDirs.clear(); + + // Also remove all filtered items which have a parent. + QHash::iterator it = m_filteredItems.begin(); + const QHash::iterator end = m_filteredItems.end(); + + while (it != end) { + if (it.value()->parent) { + delete it.value(); + it = m_filteredItems.erase(it); + } else { + ++it; + } + } +} + +void KFileItemModel::emitItemsChangedAndTriggerResorting(const KItemRangeList& itemRanges, const QSet& changedRoles) +{ + emit itemsChanged(itemRanges, changedRoles); + + // Trigger a resorting if necessary. 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))) { + foreach (const KItemRange& range, itemRanges) { + bool needsResorting = false; + + const int first = range.index; + const int last = range.index + range.count - 1; + + // Resorting the model is necessary if + // (a) The first item in the range is "lessThan" its predecessor, + // (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))) { + needsResorting = true; + } else if (last < count() - 1 + && lessThan(m_itemData.at(last + 1), m_itemData.at(last))) { + needsResorting = true; + } else { + for (int index = first; index < last; ++index) { + if (lessThan(m_itemData.at(index + 1), m_itemData.at(index))) { + needsResorting = true; + break; + } + } + } + + if (needsResorting) { + m_resortAllItemsTimer->start(); + return; + } + } + } + + 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(); + } } void KFileItemModel::resetRoles() @@ -1348,7 +1387,7 @@ QHash KFileItemModel::retrieveData(const KFileItem& item, if (m_requestRole[ExpandedParentsCountRole]) { if (parent) { - const int level = parent->values["expandedParentsCount"].toInt() + 1; + const int level = expandedParentsCount(parent) + 1; data.insert(sharedValue("expandedParentsCount"), level); } } @@ -1359,6 +1398,9 @@ QHash KFileItemModel::retrieveData(const KFileItem& item, if (m_requestRole[TypeRole]) { data.insert(sharedValue("type"), item.mimeComment()); } + } else if (m_requestRole[TypeRole] && isDir) { + static const QString folderMimeType = item.mimeComment(); + data.insert(sharedValue("type"), folderMimeType); } return data; @@ -1369,8 +1411,8 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const int result = 0; if (a->parent != b->parent) { - const int expansionLevelA = a->values.value("expandedParentsCount").toInt(); - const int expansionLevelB = b->values.value("expandedParentsCount").toInt(); + const int expansionLevelA = expandedParentsCount(a); + const int expansionLevelB = expandedParentsCount(b); // If b has a higher expansion level than a, check if a is a parent // of b, and make sure that both expansion levels are equal otherwise. @@ -1390,7 +1432,7 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const a = a->parent; } - Q_ASSERT(a->values.value("expandedParentsCount").toInt() == b->values.value("expandedParentsCount").toInt()); + Q_ASSERT(expandedParentsCount(a) == expandedParentsCount(b)); // Compare the last parents of a and b which are different. while (a->parent != b->parent) { @@ -1889,9 +1931,9 @@ KFileItemList KFileItemModel::childItems(const KFileItem& item) const int index = m_items.value(item.url(), -1); if (index >= 0) { - const int parentLevel = m_itemData.at(index)->values.value("expandedParentsCount").toInt(); + const int parentLevel = expandedParentsCount(index); ++index; - while (index < m_itemData.count() && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > parentLevel) { + while (index < m_itemData.count() && expandedParentsCount(index) > parentLevel) { items.append(m_itemData.at(index)->item); ++index; } @@ -1965,7 +2007,15 @@ void KFileItemModel::determineMimeTypes(const KFileItemList& items, int timeout) QElapsedTimer timer; timer.start(); foreach (const KFileItem& item, items) { // krazy:exclude=foreach - item.determineMimeType(); + // Only determine mime types for files here. For directories, + // KFileItem::determineMimeType() reads the .directory file inside to + // load the icon, but this is not necessary at all if we just need the + // type. Some special code for setting the correct mime type for + // directories is in retrieveData(). + if (!item.isDir()) { + item.determineMimeType(); + } + if (timer.elapsed() > timeout) { // Don't block the user interface, let the remaining items // be resolved asynchronously. @@ -2018,7 +2068,7 @@ bool KFileItemModel::isConsistent() const const ItemData* data = m_itemData.at(i); const ItemData* parent = data->parent; if (parent) { - if (data->values.value("expandedParentsCount").toInt() != parent->values.value("expandedParentsCount").toInt() + 1) { + if (expandedParentsCount(data) != expandedParentsCount(parent) + 1) { qWarning() << "expandedParentsCount is inconsistent for parent" << parent->item << "and child" << data->item; return false; }