diff options
Diffstat (limited to 'src/kitemviews/kfileitemmodel.cpp')
| -rw-r--r-- | src/kitemviews/kfileitemmodel.cpp | 141 |
1 files changed, 78 insertions, 63 deletions
diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 87006718a..fd773e1e9 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -21,7 +21,6 @@ #include "kfileitemmodel.h" -#include <KDirModel> #include <KGlobalSettings> #include <KLocale> #include <KStringHandler> @@ -76,7 +75,6 @@ KFileItemModel::KFileItemModel(QObject* parent) : connect(m_dirLister, SIGNAL(itemsDeleted(KFileItemList)), this, SLOT(slotItemsDeleted(KFileItemList))); connect(m_dirLister, SIGNAL(refreshItems(QList<QPair<KFileItem,KFileItem> >)), this, SLOT(slotRefreshItems(QList<QPair<KFileItem,KFileItem> >))); connect(m_dirLister, SIGNAL(clear()), this, SLOT(slotClear())); - connect(m_dirLister, SIGNAL(clear(KUrl)), this, SLOT(slotClear(KUrl))); connect(m_dirLister, SIGNAL(infoMessage(QString)), this, SIGNAL(infoMessage(QString))); connect(m_dirLister, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString))); connect(m_dirLister, SIGNAL(redirection(KUrl,KUrl)), this, SIGNAL(directoryRedirection(KUrl,KUrl))); @@ -247,9 +245,23 @@ QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const KUrl::List urls; KUrl::List mostLocalUrls; bool canUseMostLocalUrls = true; + const ItemData* lastAddedItem = 0; foreach (int index, indexes) { - const KFileItem item = fileItem(index); + const ItemData* itemData = m_itemData.at(index); + const ItemData* parent = itemData->parent; + + while (parent && parent != lastAddedItem) { + parent = parent->parent; + } + + if (parent && parent == lastAddedItem) { + // A parent of 'itemData' has been added already. + continue; + } + + lastAddedItem = itemData; + const KFileItem& item = itemData->item; if (!item.isNull()) { urls << item.targetUrl(); @@ -262,9 +274,7 @@ QMimeData* KFileItemModel::createMimeData(const KItemSet& indexes) const } const bool different = canUseMostLocalUrls && mostLocalUrls != urls; - urls = KDirModel::simplifiedUrlList(urls); // TODO: Check if we still need KDirModel for this in KDE 5.0 if (different) { - mostLocalUrls = KDirModel::simplifiedUrlList(mostLocalUrls); urls.populateMimeData(mostLocalUrls, data); } else { urls.populateMimeData(data); @@ -344,27 +354,50 @@ KFileItem KFileItemModel::fileItem(int index) const KFileItem KFileItemModel::fileItem(const KUrl& url) const { - const int index = m_items.value(url, -1); - if (index >= 0) { - return m_itemData.at(index)->item; + const int indexForUrl = index(url); + if (indexForUrl >= 0) { + return m_itemData.at(indexForUrl)->item; } return KFileItem(); } int KFileItemModel::index(const KFileItem& item) const { - if (item.isNull()) { - return -1; - } - - return m_items.value(item.url(), -1); + return index(item.url()); } int KFileItemModel::index(const KUrl& url) const { KUrl urlToFind = url; urlToFind.adjustPath(KUrl::RemoveTrailingSlash); - return m_items.value(urlToFind, -1); + + const int itemCount = m_itemData.count(); + int itemsInHash = m_items.count(); + + int index = m_items.value(urlToFind, -1); + while (index < 0 && itemsInHash < itemCount) { + // Not all URLs are stored yet in m_items. We grow m_items until either + // urlToFind is found, or all URLs have been stored in m_items. + // Note that we do not add the URLs to m_items one by one, but in + // larger blocks. After each block, we check if urlToFind is in + // m_items. We could in principle compare urlToFind with each URL while + // we are going through m_itemData, but comparing two QUrls will, + // unlike calling qHash for the URLs, trigger a parsing of the URLs + // which costs both CPU cycles and memory. + 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(); + m_items.insert(nextUrl, i); + } + + itemsInHash = currentBlockEnd; + index = m_items.value(urlToFind, -1); + } + + Q_ASSERT(index >= 0 || m_items.count() == m_itemData.count()); + + return index; } KFileItem KFileItemModel::rootItem() const @@ -662,7 +695,7 @@ QList<KFileItemModel::RoleInfo> KFileItemModel::rolesInformation() // menus tries to put the actions into sub menus otherwise. info.group = QString(); } - info.requiresNepomuk = map[i].requiresNepomuk; + info.requiresBaloo = map[i].requiresBaloo; info.requiresIndexer = map[i].requiresIndexer; rolesInfo.append(info); } @@ -725,6 +758,7 @@ void KFileItemModel::resortAllItems() } m_items.clear(); + m_items.reserve(itemCount); // Resort the items sort(m_itemData.begin(), m_itemData.end()); @@ -787,10 +821,10 @@ void KFileItemModel::slotCompleted() // 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) { - const int index = m_items.value(url, -1); - if (index >= 0) { + const int indexForUrl = index(url); + if (indexForUrl >= 0) { m_urlsToExpand.remove(url); - if (setExpanded(index, true)) { + if (setExpanded(indexForUrl, true)) { // The dir lister has been triggered. This slot will be called // again after the directory has been expanded. return; @@ -827,15 +861,12 @@ void KFileItemModel::slotItemsAdded(const KUrl& directoryUrl, const KFileItemLis } if (m_requestRole[ExpandedParentsCountRole]) { - KFileItem item = items.first(); - // If the expanding of items is enabled, the call // dirLister->openUrl(url, KDirLister::Keep) in KFileItemModel::setExpanded() // 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. - const int index = m_items.value(item.url(), -1); - if (index >= 0) { + if (index(items.first().url()) >= 0) { // The items are already part of the model. return; } @@ -849,7 +880,7 @@ void KFileItemModel::slotItemsAdded(const KUrl& directoryUrl, const KFileItemLis // 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. - const int parentIndex = m_items.value(parentUrl, -1); + const int parentIndex = index(parentUrl); if (parentIndex >= 0 && !m_itemData[parentIndex]->values.value("isExpanded").toBool()) { // The parent is not expanded. return; @@ -888,10 +919,9 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items) indexesToRemove.reserve(items.count()); foreach (const KFileItem& item, items) { - const KUrl url = item.url(); - const int index = m_items.value(url, -1); - if (index >= 0) { - indexesToRemove.append(index); + const int indexForItem = index(item); + if (indexForItem >= 0) { + indexesToRemove.append(indexForItem); } else { // Probably the item has been filtered. QHash<KFileItem, ItemData*>::iterator it = m_filteredItems.find(item); @@ -907,7 +937,7 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items) if (m_requestRole[ExpandedParentsCountRole] && !m_expandedDirs.isEmpty()) { // Assure that removing a parent item also results in removing all children QVector<int> indexesToRemoveWithChildren; - indexesToRemoveWithChildren.reserve(m_items.count()); + indexesToRemoveWithChildren.reserve(m_itemData.count()); const int itemCount = m_itemData.count(); foreach (int index, indexesToRemove) { @@ -947,14 +977,14 @@ void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& const QPair<KFileItem, KFileItem>& itemPair = it.next(); const KFileItem& oldItem = itemPair.first; const KFileItem& newItem = itemPair.second; - const int index = m_items.value(oldItem.url(), -1); - if (index >= 0) { - m_itemData[index]->item = newItem; + const int indexForItem = index(oldItem); + 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(index)->parent)); - QHash<QByteArray, QVariant>& values = m_itemData[index]->values; + QHashIterator<QByteArray, QVariant> it(retrieveData(newItem, m_itemData.at(indexForItem)->parent)); + QHash<QByteArray, QVariant>& values = m_itemData[indexForItem]->values; while (it.hasNext()) { it.next(); const QByteArray& role = it.key(); @@ -965,8 +995,8 @@ void KFileItemModel::slotRefreshItems(const QList<QPair<KFileItem, KFileItem> >& } m_items.remove(oldItem.url()); - m_items.insert(newItem.url(), index); - indexes.append(index); + m_items.insert(newItem.url(), indexForItem); + indexes.append(indexForItem); } else { // Check if 'oldItem' is one of the filtered items. QHash<KFileItem, ItemData*>::iterator it = m_filteredItems.find(oldItem); @@ -1023,11 +1053,6 @@ void KFileItemModel::slotClear() m_expandedDirs.clear(); } -void KFileItemModel::slotClear(const KUrl& url) -{ - Q_UNUSED(url); -} - void KFileItemModel::slotNaturalSortingChanged() { m_naturalSorting = KGlobalSettings::naturalSorting(); @@ -1088,7 +1113,7 @@ void KFileItemModel::insertItems(QList<ItemData*>& newItems) m_itemData.append(0); } - // We build the new list m_items in reverse order to minimize + // We build the new list m_itemData in reverse order to minimize // the number of moves and guarantee O(N) complexity. int targetIndex = totalItemCount - 1; int sourceIndexExistingItems = existingItemCount - 1; @@ -1126,11 +1151,9 @@ void KFileItemModel::insertItems(QList<ItemData*>& newItems) std::reverse(itemRanges.begin(), itemRanges.end()); } - // The indexes starting from the first inserted item must be adjusted. - m_items.reserve(totalItemCount); - for (int i = itemRanges.front().index; i < totalItemCount; ++i) { - m_items.insert(m_itemData.at(i)->item.url(), i); - } + // 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. + m_items.clear(); emit itemsInserted(itemRanges); @@ -1147,19 +1170,12 @@ void KFileItemModel::removeItems(const KItemRangeList& itemRanges, RemoveItemsBe m_groups.clear(); - // Step 1: Remove the items from the hash m_items, and free the ItemData. + // Step 1: Remove the items from m_itemData, and free the ItemData. int removedItemsCount = 0; foreach (const KItemRange& range, itemRanges) { removedItemsCount += range.count; for (int index = range.index; index < range.index + range.count; ++index) { - const KUrl url = m_itemData.at(index)->item.url(); - - // Prevent repeated expensive rehashing by using QHash::erase(), - // rather than QHash::remove(). - QHash<KUrl, int>::iterator it = m_items.find(url); - m_items.erase(it); - if (behavior == DeleteItemData) { delete m_itemData.at(index); } @@ -1188,12 +1204,9 @@ void KFileItemModel::removeItems(const KItemRangeList& itemRanges, RemoveItemsBe m_itemData.erase(m_itemData.end() - removedItemsCount, m_itemData.end()); - // Step 3: Adjust indexes in the hash m_items, starting from the - // index of the first removed item. - const int newItemDataCount = m_itemData.count(); - for (int i = itemRanges.front().index; i < newItemDataCount; ++i) { - m_items.insert(m_itemData.at(i)->item.url(), i); - } + // 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. + m_items.clear(); emit itemsRemoved(itemRanges); } @@ -1207,7 +1220,7 @@ QList<KFileItemModel::ItemData*> KFileItemModel::createItemDataList(const KUrl& determineMimeTypes(items, 200); } - const int parentIndex = m_items.value(parentUrl, -1); + const int parentIndex = index(parentUrl); ItemData* parentItem = parentIndex < 0 ? 0 : m_itemData.at(parentIndex); QList<ItemData*> itemDataList; @@ -2070,7 +2083,7 @@ void KFileItemModel::emitSortProgress(int resolvedCount) const KFileItemModel::RoleInfoMap* KFileItemModel::rolesInfoMap(int& count) { static const RoleInfoMap rolesInfoMap[] = { - // | role | roleType | role translation | group translation | requires Nepomuk | requires indexer + // | role | roleType | role translation | group translation | requires Baloo | requires indexer { 0, NoRole, 0, 0, 0, 0, false, false }, { "text", NameRole, I18N_NOOP2_NOSTRIP("@label", "Name"), 0, 0, false, false }, { "size", SizeRole, I18N_NOOP2_NOSTRIP("@label", "Size"), 0, 0, false, false }, @@ -2136,7 +2149,9 @@ QByteArray KFileItemModel::sharedValue(const QByteArray& value) bool KFileItemModel::isConsistent() const { - if (m_items.count() != m_itemData.count()) { + // m_items may contain less items than m_itemData because m_items + // is populated lazily, see KFileItemModel::index(const KUrl& url). + if (m_items.count() > m_itemData.count()) { return false; } |
