X-Git-Url: https://cloud.milkyroute.net/gitweb/dolphin.git/blobdiff_plain/a55199684898960a25aa9afc730120660087cb5f..982ce7ae203de9142ca3e79e6fdeacd003fb0414:/src/kitemviews/kfileitemmodel.cpp diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index 95c960b3d..7a4323fea 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -44,13 +44,11 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) : m_filter(), m_filteredItems(), m_requestRole(), - m_minimumUpdateIntervalTimer(0), m_maximumUpdateIntervalTimer(0), m_resortAllItemsTimer(0), m_pendingItemsToInsert(), - m_pendingEmitLoadingCompleted(false), m_groups(), - m_rootExpansionLevel(UninitializedRootExpansionLevel), + m_expandedParentsCountRoot(UninitializedExpandedParentsCountRoot), m_expandedUrls(), m_urlsToExpand() { @@ -71,21 +69,13 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) : connect(dirLister, SIGNAL(clear()), this, SLOT(slotClear())); connect(dirLister, SIGNAL(clear(KUrl)), this, SLOT(slotClear(KUrl))); - // Although the layout engine of KItemListView is fast it is very inefficient to e.g. - // emit 50 itemsInserted()-signals each 100 ms. m_minimumUpdateIntervalTimer assures that updates - // are done in 1 second intervals for equal operations. - m_minimumUpdateIntervalTimer = new QTimer(this); - m_minimumUpdateIntervalTimer->setInterval(1000); - m_minimumUpdateIntervalTimer->setSingleShot(true); - connect(m_minimumUpdateIntervalTimer, SIGNAL(timeout()), this, SLOT(dispatchPendingItemsToInsert())); - // For slow KIO-slaves like used for searching it makes sense to show results periodically even // before the completed() or canceled() signal has been emitted. m_maximumUpdateIntervalTimer = new QTimer(this); m_maximumUpdateIntervalTimer->setInterval(2000); m_maximumUpdateIntervalTimer->setSingleShot(true); connect(m_maximumUpdateIntervalTimer, SIGNAL(timeout()), this, SLOT(dispatchPendingItemsToInsert())); - + // When changing the value of an item which represents the sort-role a resorting must be // triggered. Especially in combination with KFileItemModelRolesUpdater this might be done // for a lot of items within a quite small timeslot. To prevent expensive resortings the @@ -95,8 +85,6 @@ KFileItemModel::KFileItemModel(KDirLister* dirLister, QObject* parent) : m_resortAllItemsTimer->setSingleShot(true); connect(m_resortAllItemsTimer, SIGNAL(timeout()), this, SLOT(resortAllItems())); - Q_ASSERT(m_minimumUpdateIntervalTimer->interval() <= m_maximumUpdateIntervalTimer->interval()); - connect(KGlobalSettings::self(), SIGNAL(naturalSortingChanged()), this, SLOT(slotNaturalSortingChanged())); } @@ -151,7 +139,7 @@ bool KFileItemModel::setData(int index, const QHash& value if (changedRoles.contains(sortRole())) { m_resortAllItemsTimer->start(); } - + return true; } @@ -257,34 +245,21 @@ int KFileItemModel::indexForKeyboardSearch(const QString& text, int startFromInd bool KFileItemModel::supportsDropping(int index) const { const KFileItem item = fileItem(index); - return item.isNull() ? false : item.isDir(); + return !item.isNull() && (item.isDir() || item.isDesktopFile()); } QString KFileItemModel::roleDescription(const QByteArray& role) const { - QString descr; - - switch (roleIndex(role)) { - case NameRole: descr = i18nc("@item:intable", "Name"); break; - case SizeRole: descr = i18nc("@item:intable", "Size"); break; - case DateRole: descr = i18nc("@item:intable", "Date"); break; - case PermissionsRole: descr = i18nc("@item:intable", "Permissions"); break; - case OwnerRole: descr = i18nc("@item:intable", "Owner"); break; - case GroupRole: descr = i18nc("@item:intable", "Group"); break; - case TypeRole: descr = i18nc("@item:intable", "Type"); break; - case DestinationRole: descr = i18nc("@item:intable", "Destination"); break; - case PathRole: descr = i18nc("@item:intable", "Path"); break; - case CommentRole: descr = i18nc("@item:intable", "Comment"); break; - case TagsRole: descr = i18nc("@item:intable", "Tags"); break; - case RatingRole: descr = i18nc("@item:intable", "Rating"); break; - case NoRole: break; - case IsDirRole: break; - case IsExpandedRole: break; - case ExpansionLevelRole: break; - default: Q_ASSERT(false); break; + static QHash description; + if (description.isEmpty()) { + int count = 0; + const RoleInfoMap* map = rolesInfoMap(count); + for (int i = 0; i < count; ++i) { + description.insert(map[i].role, map[i].roleTranslation); + } } - return descr; + return description.value(role); } QList > KFileItemModel::groups() const @@ -294,23 +269,23 @@ QList > KFileItemModel::groups() const QElapsedTimer timer; timer.start(); #endif - switch (roleIndex(sortRole())) { - case NameRole: m_groups = nameRoleGroups(); break; - case SizeRole: m_groups = sizeRoleGroups(); break; - case DateRole: m_groups = dateRoleGroups(); break; - case PermissionsRole: m_groups = permissionRoleGroups(); break; - case OwnerRole: m_groups = genericStringRoleGroups("owner"); break; - case GroupRole: m_groups = genericStringRoleGroups("group"); break; - case TypeRole: m_groups = genericStringRoleGroups("type"); break; - case DestinationRole: m_groups = genericStringRoleGroups("destination"); break; - case PathRole: m_groups = genericStringRoleGroups("path"); break; - case CommentRole: m_groups = genericStringRoleGroups("comment"); break; - case TagsRole: m_groups = genericStringRoleGroups("tags"); break; - case RatingRole: m_groups = ratingRoleGroups(); break; - case NoRole: break; - case IsDirRole: break; - case IsExpandedRole: break; - case ExpansionLevelRole: break; + switch (typeForRole(sortRole())) { + case NameRole: m_groups = nameRoleGroups(); break; + case SizeRole: m_groups = sizeRoleGroups(); break; + case DateRole: m_groups = dateRoleGroups(); break; + case PermissionsRole: m_groups = permissionRoleGroups(); break; + case OwnerRole: m_groups = genericStringRoleGroups("owner"); break; + case GroupRole: m_groups = genericStringRoleGroups("group"); break; + case TypeRole: m_groups = genericStringRoleGroups("type"); break; + case DestinationRole: m_groups = genericStringRoleGroups("destination"); break; + case PathRole: m_groups = genericStringRoleGroups("path"); break; + case CommentRole: m_groups = genericStringRoleGroups("comment"); break; + case TagsRole: m_groups = genericStringRoleGroups("tags"); break; + case RatingRole: m_groups = ratingRoleGroups(); break; + case NoRole: break; + case IsDirRole: break; + case IsExpandedRole: break; + case ExpandedParentsCountRole: break; default: Q_ASSERT(false); break; } @@ -372,11 +347,14 @@ void KFileItemModel::clear() void KFileItemModel::setRoles(const QSet& roles) { + if (m_roles == roles) { + return; + } m_roles = roles; if (count() > 0) { - const bool supportedExpanding = m_requestRole[ExpansionLevelRole]; - const bool willSupportExpanding = roles.contains("expansionLevel"); + const bool supportedExpanding = m_requestRole[ExpandedParentsCountRole]; + const bool willSupportExpanding = roles.contains("expandedParentsCount"); if (supportedExpanding && !willSupportExpanding) { // No expanding is supported anymore. Take care to delete all items that have an expansion level // that is not 0 (and hence are part of an expanded item). @@ -390,7 +368,7 @@ void KFileItemModel::setRoles(const QSet& roles) QSetIterator it(roles); while (it.hasNext()) { const QByteArray& role = it.next(); - m_requestRole[roleIndex(role)] = true; + m_requestRole[typeForRole(role)] = true; } if (count() > 0) { @@ -439,9 +417,9 @@ bool KFileItemModel::setExpanded(int index, bool expanded) } KFileItemList itemsToRemove; - const int expansionLevel = data(index)["expansionLevel"].toInt(); + const int expandedParentsCount = data(index)["expandedParentsCount"].toInt(); ++index; - while (index < count() && data(index)["expansionLevel"].toInt() > expansionLevel) { + while (index < count() && data(index)["expandedParentsCount"].toInt() > expandedParentsCount) { itemsToRemove.append(m_itemData.at(index)->item); ++index; } @@ -468,6 +446,17 @@ bool KFileItemModel::isExpandable(int index) const return false; } +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 0; +} + QSet KFileItemModel::expandedUrls() const { return m_expandedUrls; @@ -478,7 +467,7 @@ void KFileItemModel::restoreExpandedUrls(const QSet& urls) m_urlsToExpand = urls; } -void KFileItemModel::setExpanded(const QSet& urls) +void KFileItemModel::expandParentItems(const KUrl& url) { const KDirLister* dirLister = m_dirLister.data(); if (!dirLister) { @@ -487,20 +476,15 @@ void KFileItemModel::setExpanded(const QSet& urls) const int pos = dirLister->url().path().length(); - // Assure that each sub-path of the URLs that should be - // expanded is added to m_urlsToExpand too. KDirLister + // Assure that each sub-path of the URL that should be + // expanded is added to m_urlsToExpand. KDirLister // does not care whether the parent-URL has already been // expanded. - QSetIterator it1(urls); - while (it1.hasNext()) { - const KUrl& url = it1.next(); - - KUrl urlToExpand = dirLister->url(); - const QStringList subDirs = url.path().mid(pos).split(QDir::separator()); - for (int i = 0; i < subDirs.count(); ++i) { - urlToExpand.addPath(subDirs.at(i)); - m_urlsToExpand.insert(urlToExpand); - } + KUrl urlToExpand = 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)); + m_urlsToExpand.insert(urlToExpand); } // KDirLister::open() must called at least once to trigger an initial @@ -562,6 +546,26 @@ QString KFileItemModel::nameFilter() const return m_filter.pattern(); } +QList KFileItemModel::rolesInformation() +{ + static QList rolesInfo; + if (rolesInfo.isEmpty()) { + int count = 0; + const RoleInfoMap* map = rolesInfoMap(count); + for (int i = 0; i < count; ++i) { + if (map[i].roleType != NoRole) { + RoleInfo info; + info.role = map[i].role; + info.translation = map[i].roleTranslation; + info.group = map[i].groupTranslation; + rolesInfo.append(info); + } + } + } + + return rolesInfo; +} + void KFileItemModel::onGroupedSortingChanged(bool current) { Q_UNUSED(current); @@ -571,7 +575,7 @@ void KFileItemModel::onGroupedSortingChanged(bool current) void KFileItemModel::onSortRoleChanged(const QByteArray& current, const QByteArray& previous) { Q_UNUSED(previous); - m_sortRole = roleIndex(current); + m_sortRole = typeForRole(current); #ifdef KFILEITEMMODEL_DEBUG if (!m_requestRole[m_sortRole]) { @@ -586,13 +590,13 @@ void KFileItemModel::onSortOrderChanged(Qt::SortOrder current, Qt::SortOrder pre { Q_UNUSED(current); Q_UNUSED(previous); - resortAllItems(); + resortAllItems(); } void KFileItemModel::resortAllItems() { m_resortAllItemsTimer->stop(); - + const int itemCount = count(); if (itemCount <= 0) { return; @@ -613,23 +617,23 @@ void KFileItemModel::resortAllItems() foreach (const ItemData* itemData, m_itemData) { oldUrls.append(itemData->item.url()); } - + m_groups.clear(); m_items.clear(); - + // Resort the items - sort(m_itemData.begin(), m_itemData.end()); + sort(m_itemData.begin(), m_itemData.end()); for (int i = 0; i < itemCount; ++i) { 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).url()); movedToIndexes.append(newIndex); - } + } // Don't check whether items have really been moved and always emit a // itemsMoved() signal after resorting: In case of grouped items @@ -637,22 +641,14 @@ void KFileItemModel::resortAllItems() // position. Let the receiver of the signal decide whether a check for moved // items makes sense. emit itemsMoved(KItemRange(0, itemCount), movedToIndexes); - + #ifdef KFILEITEMMODEL_DEBUG kDebug() << "[TIME] Resorting of" << itemCount << "items:" << timer.elapsed(); -#endif +#endif } void KFileItemModel::slotCompleted() { - if (m_urlsToExpand.isEmpty() && m_minimumUpdateIntervalTimer->isActive()) { - // dispatchPendingItems() will be called when the timer - // has been expired. - m_pendingEmitLoadingCompleted = true; - return; - } - - m_pendingEmitLoadingCompleted = false; dispatchPendingItemsToInsert(); if (!m_urlsToExpand.isEmpty()) { @@ -678,12 +674,10 @@ void KFileItemModel::slotCompleted() } emit loadingCompleted(); - m_minimumUpdateIntervalTimer->start(); } void KFileItemModel::slotCanceled() { - m_minimumUpdateIntervalTimer->stop(); m_maximumUpdateIntervalTimer->stop(); dispatchPendingItemsToInsert(); } @@ -692,7 +686,7 @@ void KFileItemModel::slotNewItems(const KFileItemList& items) { Q_ASSERT(!items.isEmpty()); - if (m_requestRole[ExpansionLevelRole] && m_rootExpansionLevel >= 0) { + if (m_requestRole[ExpandedParentsCountRole] && m_expandedParentsCountRoot >= 0) { // 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(); @@ -752,7 +746,7 @@ void KFileItemModel::slotItemsDeleted(const KFileItemList& items) dispatchPendingItemsToInsert(); KFileItemList itemsToRemove = items; - if (m_requestRole[ExpansionLevelRole] && m_rootExpansionLevel >= 0) { + if (m_requestRole[ExpandedParentsCountRole] && m_expandedParentsCountRoot >= 0) { // Assure that removing a parent item also results in removing all children foreach (const KFileItem& item, items) { itemsToRemove.append(childItems(item)); @@ -789,7 +783,15 @@ void KFileItemModel::slotRefreshItems(const QList >& const int index = m_items.value(oldItem.url(), -1); if (index >= 0) { m_itemData[index]->item = newItem; - m_itemData[index]->values = retrieveData(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 it(retrieveData(newItem)); + while (it.hasNext()) { + it.next(); + m_itemData[index]->values.insert(it.key(), it.value()); + } + m_items.remove(oldItem.url()); m_items.insert(newItem.url(), index); indexes.append(index); @@ -842,12 +844,11 @@ void KFileItemModel::slotClear() m_filteredItems.clear(); m_groups.clear(); - m_minimumUpdateIntervalTimer->stop(); m_maximumUpdateIntervalTimer->stop(); m_resortAllItemsTimer->stop(); m_pendingItemsToInsert.clear(); - m_rootExpansionLevel = UninitializedRootExpansionLevel; + m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot; const int removedCount = m_itemData.count(); if (removedCount > 0) { @@ -877,10 +878,6 @@ void KFileItemModel::dispatchPendingItemsToInsert() insertItems(m_pendingItemsToInsert); m_pendingItemsToInsert.clear(); } - - if (m_pendingEmitLoadingCompleted) { - emit loadingCompleted(); - } } void KFileItemModel::insertItems(const KFileItemList& items) @@ -932,7 +929,7 @@ void KFileItemModel::insertItems(const KFileItemList& items) // Insert item at the position targetIndex by transfering // the ownership of the item-data from sortedItems to m_itemData. // m_items will be inserted after the loop (see comment below) - m_itemData.insert(targetIndex, sortedItems.at(sourceIndex)); + m_itemData.insert(targetIndex, sortedItems.at(sourceIndex)); ++insertedCount; if (insertedAtIndex < 0) { @@ -990,7 +987,7 @@ void KFileItemModel::removeItems(const KFileItemList& items) int targetIndex = 0; foreach (const ItemData* itemData, sortedItems) { const KFileItem& itemToRemove = itemData->item; - + const int previousTargetIndex = targetIndex; while (targetIndex < m_itemData.count()) { if (m_itemData.at(targetIndex)->item.url() == itemToRemove.url()) { @@ -1036,7 +1033,7 @@ void KFileItemModel::removeItems(const KFileItemList& items) } if (count() <= 0) { - m_rootExpansionLevel = UninitializedRootExpansionLevel; + m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot; } itemRanges << KItemRange(removedAtIndex, removedCount); @@ -1054,8 +1051,8 @@ QList KFileItemModel::createItemDataList(const KFileI itemData->values = retrieveData(item); itemData->parent = 0; - const bool determineParent = m_requestRole[ExpansionLevelRole] - && itemData->values["expansionLevel"].toInt() > 0; + const bool determineParent = m_requestRole[ExpandedParentsCountRole] + && itemData->values["expandedParentsCount"].toInt() > 0; if (determineParent) { KUrl parentUrl = item.url().upUrl(); parentUrl.adjustPath(KUrl::RemoveTrailingSlash); @@ -1069,7 +1066,7 @@ QList KFileItemModel::createItemDataList(const KFileI itemDataList.append(itemData); } - + return itemDataList; } @@ -1080,17 +1077,17 @@ 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("expansionLevel").toInt() > 0) { + if (itemData->values.value("expandedParentsCount").toInt() > 0) { expandedItems.append(itemData->item); } } - // The m_rootExpansionLevel may not get reset before all items with - // a bigger expansionLevel have been removed. - Q_ASSERT(m_rootExpansionLevel >= 0); + // The m_expandedParentsCountRoot may not get reset before all items with + // a bigger count have been removed. + Q_ASSERT(m_expandedParentsCountRoot >= 0); removeItems(expandedItems); - m_rootExpansionLevel = UninitializedRootExpansionLevel; + m_expandedParentsCountRoot = UninitializedExpandedParentsCountRoot; m_expandedUrls.clear(); } @@ -1101,61 +1098,62 @@ void KFileItemModel::resetRoles() } } -KFileItemModel::Role KFileItemModel::roleIndex(const QByteArray& role) const -{ - static QHash rolesHash; - if (rolesHash.isEmpty()) { - rolesHash.insert("name", NameRole); - rolesHash.insert("size", SizeRole); - rolesHash.insert("date", DateRole); - rolesHash.insert("permissions", PermissionsRole); - rolesHash.insert("owner", OwnerRole); - rolesHash.insert("group", GroupRole); - rolesHash.insert("type", TypeRole); - rolesHash.insert("destination", DestinationRole); - rolesHash.insert("path", PathRole); - rolesHash.insert("comment", CommentRole); - rolesHash.insert("tags", TagsRole); - rolesHash.insert("rating", RatingRole); - rolesHash.insert("isDir", IsDirRole); - rolesHash.insert("isExpanded", IsExpandedRole); - rolesHash.insert("isExpandable", IsExpandableRole); - rolesHash.insert("expansionLevel", ExpansionLevelRole); - } - return rolesHash.value(role, NoRole); -} - -QByteArray KFileItemModel::roleByteArray(Role role) const -{ - static const char* const roles[RolesCount] = { - 0, // NoRole - "name", - "size", - "date", - "permissions", - "owner", - "group", - "type", - "destination", - "path", - "comment", - "tags", - "rating", - "isDir", - "isExpanded", - "isExpandable", - "expansionLevel" +KFileItemModel::RoleType KFileItemModel::typeForRole(const QByteArray& role) const +{ + static QHash roles; + if (roles.isEmpty()) { + // Insert user visible roles that can be accessed with + // KFileItemModel::roleInformation() + int count = 0; + const RoleInfoMap* map = rolesInfoMap(count); + for (int i = 0; i < count; ++i) { + roles.insert(map[i].role, map[i].roleType); + } + + // Insert internal roles (take care to synchronize the implementation + // with KFileItemModel::roleForType() in case if a change is done). + roles.insert("isDir", IsDirRole); + roles.insert("isExpanded", IsExpandedRole); + roles.insert("isExpandable", IsExpandableRole); + roles.insert("expandedParentsCount", ExpandedParentsCountRole); + + Q_ASSERT(roles.count() == RolesCount); + } + + return roles.value(role, NoRole); +} + +QByteArray KFileItemModel::roleForType(RoleType roleType) const +{ + static QHash roles; + if (roles.isEmpty()) { + // Insert user visible roles that can be accessed with + // KFileItemModel::roleInformation() + int count = 0; + const RoleInfoMap* map = rolesInfoMap(count); + for (int i = 0; i < count; ++i) { + roles.insert(map[i].roleType, map[i].role); + } + + // Insert internal roles (take care to synchronize the implementation + // with KFileItemModel::typeForRole() in case if a change is done). + roles.insert(IsDirRole, "isDir"); + roles.insert(IsExpandedRole, "isExpanded"); + roles.insert(IsExpandableRole, "isExpandable"); + roles.insert(ExpandedParentsCountRole, "expandedParentsCount"); + + Q_ASSERT(roles.count() == RolesCount); }; - return roles[role]; + + return roles.value(roleType); } QHash KFileItemModel::retrieveData(const KFileItem& item) const -{ +{ // It is important to insert only roles that are fast to retrieve. E.g. // KFileItem::iconName() can be very expensive if the MIME-type is unknown // and hence will be retrieved asynchronously by KFileItemModelRolesUpdater. QHash data; - data.insert("iconPixmap", QPixmap()); data.insert("url", item.url()); const bool isDir = item.isDir(); @@ -1224,28 +1222,28 @@ QHash KFileItemModel::retrieveData(const KFileItem& item) data.insert("isExpandable", item.isDir() && item.url() == item.targetUrl()); } - if (m_requestRole[ExpansionLevelRole]) { - if (m_rootExpansionLevel == UninitializedRootExpansionLevel && m_dirLister.data()) { + if (m_requestRole[ExpandedParentsCountRole]) { + if (m_expandedParentsCountRoot == UninitializedExpandedParentsCountRoot && m_dirLister.data()) { const KUrl rootUrl = m_dirLister.data()->url(); const QString protocol = rootUrl.protocol(); - const bool forceRootExpansionLevel = (protocol == QLatin1String("trash") || - protocol == QLatin1String("nepomuk") || - protocol == QLatin1String("remote") || - protocol.contains(QLatin1String("search"))); - if (forceRootExpansionLevel) { - m_rootExpansionLevel = ForceRootExpansionLevel; + const bool forceExpandedParentsCountRoot = (protocol == QLatin1String("trash") || + protocol == QLatin1String("nepomuk") || + protocol == QLatin1String("remote") || + protocol.contains(QLatin1String("search"))); + if (forceExpandedParentsCountRoot) { + m_expandedParentsCountRoot = ForceExpandedParentsCountRoot; } else { const QString rootDir = rootUrl.path(KUrl::AddTrailingSlash); - m_rootExpansionLevel = rootDir.count('/'); + m_expandedParentsCountRoot = rootDir.count('/'); } } - if (m_rootExpansionLevel == ForceRootExpansionLevel) { - data.insert("expansionLevel", -1); + if (m_expandedParentsCountRoot == ForceExpandedParentsCountRoot) { + data.insert("expandedParentsCount", -1); } else { const QString dir = item.url().directory(KUrl::AppendTrailingSlash); - const int level = dir.count('/') - m_rootExpansionLevel; - data.insert("expansionLevel", level); + const int level = dir.count('/') - m_expandedParentsCountRoot; + data.insert("expandedParentsCount", level); } } @@ -1264,8 +1262,8 @@ bool KFileItemModel::lessThan(const ItemData* a, const ItemData* b) const { int result = 0; - if (m_rootExpansionLevel >= 0) { - result = expansionLevelsCompare(a, b); + if (m_expandedParentsCountRoot >= 0) { + result = expandedParentsCountCompare(a, b); if (result != 0) { // The items have parents with different expansion levels return (sortOrder() == Qt::AscendingOrder) ? result < 0 : result > 0; @@ -1298,7 +1296,7 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const case NameRole: // The name role is handled as default fallback after the switch break; - + case SizeRole: { if (itemA.isDir()) { // See "if (m_sortFoldersFirst || m_sortRole == SizeRole)" in KFileItemModel::lessThan(): @@ -1313,12 +1311,20 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const } else if (valueB.isNull()) { result = +1; } else { - result = fileSizeCompare(valueA.value(), valueB.value()); + result = valueA.toInt() - valueB.toInt(); } } else { // See "if (m_sortFoldersFirst || m_sortRole == SizeRole)" in KFileItemModel::lessThan(): Q_ASSERT(!itemB.isDir()); - result = fileSizeCompare(itemA.size(), itemB.size()); + const KIO::filesize_t sizeA = itemA.size(); + const KIO::filesize_t sizeB = itemB.size(); + if (sizeA > sizeB) { + result = +1; + } else if (sizeA < sizeB) { + result = -1; + } else { + result = 0; + } } break; } @@ -1333,12 +1339,12 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const } break; } - + case RatingRole: { result = a->values.value("rating").toInt() - b->values.value("rating").toInt(); break; } - + case PermissionsRole: case OwnerRole: case GroupRole: @@ -1347,12 +1353,12 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const case PathRole: case CommentRole: case TagsRole: { - const QByteArray role = roleByteArray(m_sortRole); + const QByteArray role = roleForType(m_sortRole); result = QString::compare(a->values.value(role).toString(), b->values.value(role).toString()); break; } - + default: break; } @@ -1383,16 +1389,16 @@ int KFileItemModel::sortRoleCompare(const ItemData* a, const ItemData* b) const void KFileItemModel::sort(QList::iterator begin, QList::iterator end) -{ +{ // The implementation is based on qStableSortHelper() from qalgorithms.h // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). // In opposite to qStableSort() it allows to use a member-function for the comparison of elements. - + const int span = end - begin; if (span < 2) { return; } - + const QList::iterator middle = begin + span / 2; sort(begin, middle); sort(middle, end); @@ -1405,21 +1411,21 @@ void KFileItemModel::merge(QList::iterator begin, { // The implementation is based on qMerge() from qalgorithms.h // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - + const int len1 = pivot - begin; const int len2 = end - pivot; - + if (len1 == 0 || len2 == 0) { return; } - + if (len1 + len2 == 2) { if (lessThan(*(begin + 1), *(begin))) { qSwap(*begin, *(begin + 1)); } return; } - + QList::iterator firstCut; QList::iterator secondCut; int len2Half; @@ -1433,11 +1439,11 @@ void KFileItemModel::merge(QList::iterator begin, secondCut = pivot + len2Half; firstCut = upperBound(begin, pivot, *secondCut); } - + reverse(firstCut, pivot); reverse(pivot, secondCut); reverse(firstCut, secondCut); - + const QList::iterator newPivot = firstCut + len2Half; merge(begin, firstCut, newPivot); merge(newPivot, secondCut, end); @@ -1449,7 +1455,7 @@ QList::iterator KFileItemModel::lowerBound(QList::iterator middle; int n = int(end - begin); int half; @@ -1473,7 +1479,7 @@ QList::iterator KFileItemModel::upperBound(QList::iterator middle; int n = end - begin; int half; @@ -1496,11 +1502,11 @@ void KFileItemModel::reverse(QList::iterator begin, { // The implementation is based on qReverse() from qalgorithms.h // Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). - + --end; while (begin < end) { qSwap(*begin++, *end--); - } + } } int KFileItemModel::stringCompare(const QString& a, const QString& b) const @@ -1525,7 +1531,7 @@ int KFileItemModel::stringCompare(const QString& a, const QString& b) const : QString::compare(a, b, Qt::CaseSensitive); } -int KFileItemModel::expansionLevelsCompare(const ItemData* a, const ItemData* b) const +int KFileItemModel::expandedParentsCountCompare(const ItemData* a, const ItemData* b) const { const KUrl urlA = a->item.url(); const KUrl urlB = b->item.url(); @@ -1565,10 +1571,12 @@ int KFileItemModel::expansionLevelsCompare(const ItemData* a, const ItemData* b) bool isDirB = true; const QString subPathB = subPath(b->item, pathB, index, &isDirB); - if (isDirA && !isDirB) { - return (sortOrder() == Qt::AscendingOrder) ? -1 : +1; - } else if (!isDirA && isDirB) { - return (sortOrder() == Qt::AscendingOrder) ? +1 : -1; + if (m_sortFoldersFirst || m_sortRole == SizeRole) { + if (isDirA && !isDirB) { + return (sortOrder() == Qt::AscendingOrder) ? -1 : +1; + } else if (!isDirA && isDirB) { + return (sortOrder() == Qt::AscendingOrder) ? +1 : -1; + } } // Compare the items of the parents that represent the first @@ -1932,9 +1940,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("expansionLevel").toInt(); + const int parentLevel = m_itemData.at(index)->values.value("expandedParentsCount").toInt(); ++index; - while (index < m_itemData.count() && m_itemData.at(index)->values.value("expansionLevel").toInt() > parentLevel) { + while (index < m_itemData.count() && m_itemData.at(index)->values.value("expandedParentsCount").toInt() > parentLevel) { items.append(m_itemData.at(index)->item); ++index; } @@ -1943,15 +1951,36 @@ KFileItemList KFileItemModel::childItems(const KFileItem& item) const return items; } -int KFileItemModel::fileSizeCompare(KIO::filesize_t a, KIO::filesize_t b) -{ - if (a > b) { - return +1; - } else if (a < b) { - return -1; - } else { - return 0; - } +const KFileItemModel::RoleInfoMap* KFileItemModel::rolesInfoMap(int& count) +{ + static const RoleInfoMap rolesInfoMap[] = { + // role roleType role translation group translation + { 0, NoRole, 0, 0, 0, 0 }, + { "name", NameRole, I18N_NOOP2_NOSTRIP("@label", "Name"), 0, 0 }, + { "size", SizeRole, I18N_NOOP2_NOSTRIP("@label", "Size"), 0, 0 }, + { "date", DateRole, I18N_NOOP2_NOSTRIP("@label", "Date"), 0, 0 }, + { "type", TypeRole, I18N_NOOP2_NOSTRIP("@label", "Type"), 0, 0 }, + { "rating", RatingRole, I18N_NOOP2_NOSTRIP("@label", "Rating"), 0, 0 }, + { "tags", TagsRole, I18N_NOOP2_NOSTRIP("@label", "Tags"), 0, 0 }, + { "comment", CommentRole, I18N_NOOP2_NOSTRIP("@label", "Comment"), 0, 0 }, + { "wordCount", WordCountRole, I18N_NOOP2_NOSTRIP("@label", "Word Count"), I18N_NOOP2_NOSTRIP("@label", "Document") }, + { "lineCount", LineCountRole, I18N_NOOP2_NOSTRIP("@label", "Line Count"), I18N_NOOP2_NOSTRIP("@label", "Document") }, + { "imageSize", ImageSizeRole, I18N_NOOP2_NOSTRIP("@label", "Image Size"), I18N_NOOP2_NOSTRIP("@label", "Image") }, + { "orientation", OrientationRole, I18N_NOOP2_NOSTRIP("@label", "Orientation"), I18N_NOOP2_NOSTRIP("@label", "Image") }, + { "artist", ArtistRole, I18N_NOOP2_NOSTRIP("@label", "Artist"), I18N_NOOP2_NOSTRIP("@label", "Music") }, + { "album", AlbumRole, I18N_NOOP2_NOSTRIP("@label", "Album"), I18N_NOOP2_NOSTRIP("@label", "Music") }, + { "duration", DurationRole, I18N_NOOP2_NOSTRIP("@label", "Duration"), I18N_NOOP2_NOSTRIP("@label", "Music") }, + { "track", TrackRole, I18N_NOOP2_NOSTRIP("@label", "Track"), I18N_NOOP2_NOSTRIP("@label", "Music") }, + { "path", PathRole, I18N_NOOP2_NOSTRIP("@label", "Path"), I18N_NOOP2_NOSTRIP("@label", "Other") }, + { "destination", DestinationRole, I18N_NOOP2_NOSTRIP("@label", "Link Destination"), I18N_NOOP2_NOSTRIP("@label", "Other") }, + { "copiedFrom", CopiedFromRole, I18N_NOOP2_NOSTRIP("@label", "Copied From"), I18N_NOOP2_NOSTRIP("@label", "Other") }, + { "permissions", PermissionsRole, I18N_NOOP2_NOSTRIP("@label", "Permissions"), I18N_NOOP2_NOSTRIP("@label", "Other") }, + { "owner", OwnerRole, I18N_NOOP2_NOSTRIP("@label", "Owner"), I18N_NOOP2_NOSTRIP("@label", "Other") }, + { "group", GroupRole, I18N_NOOP2_NOSTRIP("@label", "Group"), I18N_NOOP2_NOSTRIP("@label", "Other") }, + }; + + count = sizeof(rolesInfoMap) / sizeof(RoleInfoMap); + return rolesInfoMap; } #include "kfileitemmodel.moc"