diff options
Diffstat (limited to 'src/kitemviews')
| -rw-r--r-- | src/kitemviews/kfileitemlistview.cpp | 14 | ||||
| -rw-r--r-- | src/kitemviews/kfileitemlistview.h | 1 | ||||
| -rw-r--r-- | src/kitemviews/kfileitemmodel.cpp | 78 | ||||
| -rw-r--r-- | src/kitemviews/kfileitemmodel.h | 3 | ||||
| -rw-r--r-- | src/kitemviews/kfileitemmodelrolesupdater.cpp | 8 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.cpp | 18 | ||||
| -rw-r--r-- | src/kitemviews/kitemlistview.h | 1 | ||||
| -rw-r--r-- | src/kitemviews/kitemmodelbase.cpp | 41 | ||||
| -rw-r--r-- | src/kitemviews/kitemmodelbase.h | 9 |
9 files changed, 156 insertions, 17 deletions
diff --git a/src/kitemviews/kfileitemlistview.cpp b/src/kitemviews/kfileitemlistview.cpp index 3a02d537d..585a972a6 100644 --- a/src/kitemviews/kfileitemlistview.cpp +++ b/src/kitemviews/kfileitemlistview.cpp @@ -354,6 +354,15 @@ void KFileItemListView::slotSortRoleChanged(const QByteArray ¤t, const QBy KStandardItemListView::slotSortRoleChanged(current, previous); } +void KFileItemListView::slotGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous) +{ + if (!visibleRoles().contains(current)) { + applyRolesToModel(); + } + + KItemListView::slotGroupRoleChanged(current, previous); +} + void KFileItemListView::triggerVisibleIndexRangeUpdate() { if (!model()) { @@ -441,6 +450,11 @@ void KFileItemListView::applyRolesToModel() // Assure that the role that is used for sorting will be determined roles.insert(fileItemModel->sortRole()); + const QByteArray rawGroupRole = fileItemModel->rawGroupRole(); + if (!rawGroupRole.isEmpty()) { + roles.insert(rawGroupRole); + } + fileItemModel->setRoles(roles); m_modelRolesUpdater->setRoles(roles); } diff --git a/src/kitemviews/kfileitemlistview.h b/src/kitemviews/kfileitemlistview.h index eae00f1f0..203daca09 100644 --- a/src/kitemviews/kfileitemlistview.h +++ b/src/kitemviews/kfileitemlistview.h @@ -93,6 +93,7 @@ protected: protected Q_SLOTS: void slotItemsRemoved(const KItemRangeList &itemRanges) override; void slotSortRoleChanged(const QByteArray ¤t, const QByteArray &previous) override; + void slotGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous) override; private Q_SLOTS: void triggerVisibleIndexRangeUpdate(); diff --git a/src/kitemviews/kfileitemmodel.cpp b/src/kitemviews/kfileitemmodel.cpp index ba33254c0..f4b51ce72 100644 --- a/src/kitemviews/kfileitemmodel.cpp +++ b/src/kitemviews/kfileitemmodel.cpp @@ -639,7 +639,7 @@ QList<QPair<int, QVariant>> KFileItemModel::groups() const QElapsedTimer timer; timer.start(); #endif - switch (typeForRole(sortRole())) { + switch (typeForRole(groupRole())) { case NameRole: m_groups = nameRoleGroups(); break; @@ -673,7 +673,7 @@ QList<QPair<int, QVariant>> KFileItemModel::groups() const m_groups = ratingRoleGroups(); break; default: - m_groups = genericStringRoleGroups(sortRole()); + m_groups = genericStringRoleGroups(groupRole()); break; } @@ -1232,6 +1232,24 @@ void KFileItemModel::onGroupedSortingChanged(bool current) m_groups.clear(); } +void KFileItemModel::onGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous, bool resortItems) +{ + Q_UNUSED(previous) + const RoleType roleType = typeForRole(current); + + if (!m_requestRole[roleType]) { + QSet<QByteArray> newRoles = m_roles; + newRoles << current; + setRoles(newRoles); + } + + m_groups.clear(); + + if (resortItems) { + resortAllItems(); + } +} + void KFileItemModel::onSortRoleChanged(const QByteArray ¤t, const QByteArray &previous, bool resortItems) { Q_UNUSED(previous) @@ -1927,7 +1945,7 @@ void KFileItemModel::removeItems(const KItemRangeList &itemRanges, RemoveItemsBe QList<KFileItemModel::ItemData *> KFileItemModel::createItemDataList(const QUrl &parentUrl, const KFileItemList &items) const { - if (m_sortRole == TypeRole) { + if (m_sortRole == TypeRole || typeForRole(rawGroupRole()) == TypeRole) { // Try to resolve the MIME-types synchronously to prevent a reordering of // the items when sorting by type (per default MIME-types are resolved // asynchronously by KFileItemModelRolesUpdater). @@ -1991,6 +2009,17 @@ void KFileItemModel::prepareItemsForSorting(QList<ItemData *> &itemDataList) // DateRole). break; } + + if (typeForRole(rawGroupRole()) == TypeRole && m_sortRole != TypeRole) { + for (ItemData *itemData : std::as_const(itemDataList)) { + if (itemData->values.isEmpty()) { + const KFileItem &item = itemData->item; + if (item.isDir() || item.isMimeTypeKnown()) { + itemData->values = retrieveData(itemData->item, itemData->parent); + } + } + } + } } int KFileItemModel::expandedParentsCount(const ItemData *data) @@ -2046,7 +2075,8 @@ void KFileItemModel::emitItemsChangedAndTriggerResorting(const KItemRangeList &i // 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)) - || (changedRoles.contains("count") && sortRole() == "size")) { // "count" is used in the "size" sort role, so this might require a resorting. + || (changedRoles.contains("count") && sortRole() == "size") // "count" is used in the "size" sort role, so this might require a resorting. + || (groupedSorting() && !rawGroupRole().isEmpty() && changedRoles.contains(groupRole()))) { for (const KItemRange &range : itemRanges) { bool needsResorting = false; @@ -2077,7 +2107,7 @@ void KFileItemModel::emitItemsChangedAndTriggerResorting(const KItemRangeList &i } } - if (groupedSorting() && changedRoles.contains(sortRole())) { + if (groupedSorting() && (changedRoles.contains(sortRole()) || (!rawGroupRole().isEmpty() && changedRoles.contains(groupRole())))) { // 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. @@ -2307,6 +2337,20 @@ QHash<QByteArray, QVariant> KFileItemModel::retrieveData(const KFileItem &item, return data; } +QString KFileItemModel::groupKeyForItem(const ItemData *item, const QByteArray &role) const +{ + switch (typeForRole(role)) { + case ModificationTimeRole: + case CreationTimeRole: + case AccessTimeRole: + return QDateTime::fromSecsSinceEpoch(item->values.value(role).toLongLong()).date().toString(Qt::ISODate); + case DeletionTimeRole: + return item->values.value("deletiontime").toDateTime().date().toString(Qt::ISODate); + default: + return item->values.value(role).toString(); + } +} + bool KFileItemModel::lessThan(const ItemData *a, const ItemData *b, const QCollator &collator) const { int result = 0; @@ -2364,6 +2408,17 @@ bool KFileItemModel::lessThan(const ItemData *a, const ItemData *b, const QColla } } + if (groupedSorting() && !rawGroupRole().isEmpty() && groupRole() != sortRole()) { + const QByteArray gRole = groupRole(); + const QString groupValueA = groupKeyForItem(a, gRole); + const QString groupValueB = groupKeyForItem(b, gRole); + const int groupResult = stringCompare(groupValueA, groupValueB, collator); + if (groupResult != 0) { + // Groups are always in ascending order regardless of the sort order setting. + return groupResult < 0; + } + } + result = sortRoleCompare(a, b, collator); return (sortOrder() == Qt::AscendingOrder) ? result < 0 : result > 0; @@ -2375,15 +2430,16 @@ void KFileItemModel::sort(const QList<KFileItemModel::ItemData *>::iterator &beg return lessThan(a, b, m_collator); }; - if (m_sortRole == NameRole || isRoleValueNatural(m_sortRole)) { - // Sorting by string can be expensive, in particular if natural sorting is - // enabled. Use all CPU cores to speed up the sorting process. + const QByteArray rawRole = rawGroupRole(); + const bool groupKeyIsString = !rawRole.isEmpty() && groupRole() != sortRole() + && isRoleValueNatural(typeForRole(rawRole)); + // String-based sorts benefit from parallelism; non-string sorts use one thread + // to avoid non-reentrant comparison functions (bug 312679). + const bool primaryKeyIsString = m_sortRole == NameRole || isRoleValueNatural(m_sortRole) || groupKeyIsString; + if (primaryKeyIsString) { static const int numberOfThreads = QThread::idealThreadCount(); parallelMergeSort(begin, end, lambdaLessThan, numberOfThreads); } else { - // Sorting by other roles is quite fast. Use only one thread to prevent - // problems caused by non-reentrant comparison functions, see - // https://bugs.kde.org/show_bug.cgi?id=312679 mergeSort(begin, end, lambdaLessThan); } } diff --git a/src/kitemviews/kfileitemmodel.h b/src/kitemviews/kfileitemmodel.h index 2a6e710c3..0ac5d9261 100644 --- a/src/kitemviews/kfileitemmodel.h +++ b/src/kitemviews/kfileitemmodel.h @@ -293,6 +293,7 @@ protected: void onGroupedSortingChanged(bool current) override; void onSortRoleChanged(const QByteArray ¤t, const QByteArray &previous, bool resortItems = true) override; void onSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous) override; + void onGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous, bool resortItems = true) override; private Q_SLOTS: /** @@ -447,6 +448,8 @@ private: */ bool lessThan(const ItemData *a, const ItemData *b, const QCollator &collator) const; + QString groupKeyForItem(const ItemData *item, const QByteArray &role) const; + /** * Sorts the items between \a begin and \a end using the comparison * function lessThan(). diff --git a/src/kitemviews/kfileitemmodelrolesupdater.cpp b/src/kitemviews/kfileitemmodelrolesupdater.cpp index 38fa58436..33cf6341c 100644 --- a/src/kitemviews/kfileitemmodelrolesupdater.cpp +++ b/src/kitemviews/kfileitemmodelrolesupdater.cpp @@ -281,6 +281,14 @@ void KFileItemModelRolesUpdater::setPaused(bool paused) void KFileItemModelRolesUpdater::setRoles(const QSet<QByteArray> &roles) { if (m_roles != roles) { + const QSet<QByteArray> addedRoles = roles - m_roles; + for (const QByteArray &role : addedRoles) { + if (m_resolvableRoles.contains(role)) { + m_finishedItems.clear(); + break; + } + } + m_roles = roles; #if HAVE_BALOO diff --git a/src/kitemviews/kitemlistview.cpp b/src/kitemviews/kitemlistview.cpp index b87216d4b..d24c2426d 100644 --- a/src/kitemviews/kitemlistview.cpp +++ b/src/kitemviews/kitemlistview.cpp @@ -1477,8 +1477,8 @@ void KItemListView::slotItemsChanged(const KItemRangeList &itemRanges, const QSe } } - if (m_grouped && roles.contains(m_model->sortRole())) { - // The sort-role has been changed which might result + if (m_grouped && roles.contains(m_model->groupRole())) { + // The group-role data has been changed which might result // in modified group headers updateVisibleGroupHeaders(); doLayout(NoAnimation); @@ -1543,6 +1543,16 @@ void KItemListView::slotSortRoleChanged(const QByteArray ¤t, const QByteAr } } +void KItemListView::slotGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous) +{ + Q_UNUSED(current) + Q_UNUSED(previous) + if (m_grouped) { + updateVisibleGroupHeaders(); + doLayout(NoAnimation); + } +} + void KItemListView::slotCurrentChanged(int current, int previous) { // In SingleSelection mode (e.g., in the Places Panel), the current item is @@ -1826,6 +1836,7 @@ void KItemListView::setModel(KItemModelBase *model) disconnect(m_model, &KItemModelBase::groupedSortingChanged, this, &KItemListView::slotGroupedSortingChanged); disconnect(m_model, &KItemModelBase::sortOrderChanged, this, &KItemListView::slotSortOrderChanged); disconnect(m_model, &KItemModelBase::sortRoleChanged, this, &KItemListView::slotSortRoleChanged); + disconnect(m_model, &KItemModelBase::groupRoleChanged, this, &KItemListView::slotGroupRoleChanged); m_sizeHintResolver->itemsRemoved(KItemRangeList() << KItemRange(0, m_model->count())); } @@ -1843,6 +1854,7 @@ void KItemListView::setModel(KItemModelBase *model) connect(m_model, &KItemModelBase::groupedSortingChanged, this, &KItemListView::slotGroupedSortingChanged); connect(m_model, &KItemModelBase::sortOrderChanged, this, &KItemListView::slotSortOrderChanged); connect(m_model, &KItemModelBase::sortRoleChanged, this, &KItemListView::slotSortRoleChanged); + connect(m_model, &KItemModelBase::groupRoleChanged, this, &KItemListView::slotGroupRoleChanged); const int itemCount = m_model->count(); if (itemCount > 0) { @@ -2251,7 +2263,7 @@ void KItemListView::updateGroupHeaderForWidget(KItemListWidget *widget) const int groupIndex = groupIndexForItem(index); Q_ASSERT(groupIndex >= 0); groupHeader->setData(groups.at(groupIndex).second); - groupHeader->setRole(model()->sortRole()); + groupHeader->setRole(model()->groupRole()); groupHeader->setStyleOption(m_styleOption); groupHeader->setScrollOrientation(scrollOrientation()); groupHeader->setItemIndex(index); diff --git a/src/kitemviews/kitemlistview.h b/src/kitemviews/kitemlistview.h index 8dc83d528..20c34ceea 100644 --- a/src/kitemviews/kitemlistview.h +++ b/src/kitemviews/kitemlistview.h @@ -441,6 +441,7 @@ protected Q_SLOTS: virtual void slotGroupedSortingChanged(bool current); virtual void slotSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); virtual void slotSortRoleChanged(const QByteArray ¤t, const QByteArray &previous); + virtual void slotGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous); virtual void slotCurrentChanged(int current, int previous); virtual void slotSelectionChanged(const KItemSet ¤t, const KItemSet &previous); diff --git a/src/kitemviews/kitemmodelbase.cpp b/src/kitemviews/kitemmodelbase.cpp index 82e491220..a4f7b0890 100644 --- a/src/kitemviews/kitemmodelbase.cpp +++ b/src/kitemviews/kitemmodelbase.cpp @@ -50,13 +50,41 @@ bool KItemModelBase::groupedSorting() const void KItemModelBase::setSortRole(const QByteArray &role, bool resortItems) { if (role != m_sortRole) { - const QByteArray previous = m_sortRole; + const QByteArray previousSortRole = m_sortRole; m_sortRole = role; - onSortRoleChanged(role, previous, resortItems); - Q_EMIT sortRoleChanged(role, previous); + onSortRoleChanged(role, previousSortRole, resortItems); + Q_EMIT sortRoleChanged(role, previousSortRole); + + if (m_groupRole.isEmpty()) { + onGroupRoleChanged(role, previousSortRole, false); + Q_EMIT groupRoleChanged(role, previousSortRole); + } + } +} + +void KItemModelBase::setGroupRole(const QByteArray &role) +{ + if (role != m_groupRole) { + const QByteArray previousEffective = groupRole(); + m_groupRole = role; + const QByteArray currentEffective = groupRole(); + if (currentEffective != previousEffective) { + onGroupRoleChanged(currentEffective, previousEffective); + Q_EMIT groupRoleChanged(currentEffective, previousEffective); + } } } +QByteArray KItemModelBase::groupRole() const +{ + return m_groupRole.isEmpty() ? m_sortRole : m_groupRole; +} + +QByteArray KItemModelBase::rawGroupRole() const +{ + return m_groupRole; +} + QByteArray KItemModelBase::sortRole() const { return m_sortRole; @@ -149,6 +177,13 @@ void KItemModelBase::onSortRoleChanged(const QByteArray ¤t, const QByteArr Q_UNUSED(resortItems) } +void KItemModelBase::onGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous, bool resortItems) +{ + Q_UNUSED(current) + Q_UNUSED(previous) + Q_UNUSED(resortItems) +} + void KItemModelBase::onSortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous) { Q_UNUSED(current) diff --git a/src/kitemviews/kitemmodelbase.h b/src/kitemviews/kitemmodelbase.h index 42a9c54c9..68d1d5d8a 100644 --- a/src/kitemviews/kitemmodelbase.h +++ b/src/kitemviews/kitemmodelbase.h @@ -76,6 +76,10 @@ public: void setSortRole(const QByteArray &role, bool resortItems = true); QByteArray sortRole() const; + void setGroupRole(const QByteArray &role); + QByteArray groupRole() const; + QByteArray rawGroupRole() const; + /** * Sets the sort order to \a order. The method KItemModelBase::onSortOrderChanged() will be * called so that model-implementations can react on the sort order change. Afterwards the @@ -248,6 +252,8 @@ Q_SIGNALS: void sortRoleChanged(const QByteArray ¤t, const QByteArray &previous); void sortOrderChanged(Qt::SortOrder current, Qt::SortOrder previous); + void groupRoleChanged(const QByteArray ¤t, const QByteArray &previous); + protected: /** * Is invoked if the grouped sorting has been changed by KItemModelBase::setGroupedSorting(). Allows @@ -266,6 +272,8 @@ protected: */ virtual void onSortRoleChanged(const QByteArray ¤t, const QByteArray &previous, bool resortItems = true); + virtual void onGroupRoleChanged(const QByteArray ¤t, const QByteArray &previous, bool resortItems = true); + /** * Is invoked if the sort order has been changed by KItemModelBase::setSortOrder(). Allows * to react on the changed sort order before the signal sortOrderChanged() will be emitted. @@ -279,6 +287,7 @@ protected: private: bool m_groupedSorting; QByteArray m_sortRole; + QByteArray m_groupRole; Qt::SortOrder m_sortOrder; }; |
