Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion qml/windowed/AppListView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ FocusScope {
}
}

section.property: CategorizedSortProxyModel.sortRoleName // "transliterated" // "category"
section.property: CategorizedSortProxyModel.sectionRoleName // "transliterated" // "category"
section.criteria: section.property === "transliterated" ? ViewSection.FirstCharacter : ViewSection.FullString
section.delegate: sectionHeading
section.labelPositioning: ViewSection.InlineLabels // | ViewSection.CurrentLabelAtStart
Expand Down
26 changes: 17 additions & 9 deletions src/models/categorizedsortproxymodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void CategorizedSortProxyModel::setCategoryType(CategoryType categoryType)
CategoryType oldCategoryType = this->categoryType();

// Temporarily disable dynamic sort to prevent setSortRole from triggering
// a redundant sort. We trigger a single sort below via setDynamicSortFilter,
// a redundant sort. We trigger a single sort below via sort(0),
// which uses layoutAboutToBeChanged/layoutChanged instead of modelReset,
// preserving delegates.
const bool wasDynamic = dynamicSortFilter();
Expand All @@ -42,14 +42,22 @@ void CategorizedSortProxyModel::setCategoryType(CategoryType categoryType)
config->setValue("categoryType", categoryType);
}

// Re-enable dynamic sort filter to trigger a single d->sort() internally,
// then restore the original setting. d->sort() emits
// layoutAboutToBeChanged/layoutChanged (not modelReset), so the view moves
// existing delegates instead of destroying and recreating them.
setDynamicSortFilter(true);
if (!wasDynamic) {
setDynamicSortFilter(false);
}
// Use sort(0) instead of setDynamicSortFilter(true) because the latter
// calls d->sort() without setting proxy_sort_column, leaving it at -1
// (the Qt 6 default). When source_sort_column is -1,
// QSortFilterProxyModelPrivate::sort_source_rows falls through to
// std::less{} (a no-op), so no sorting actually occurs.
// sort(0) properly sets proxy_sort_column = 0 and calls
// update_source_sort_column(), then d->sort() emits
// layoutAboutToBeChanged/layoutChanged so the view moves existing
// delegates instead of destroying and recreating them.
sort(0);
setDynamicSortFilter(wasDynamic);

// Must update sectionRoleName after the sort so that the QML ListView
// evaluates section structure with the correct (already sorted) item order.
m_sectionRoleName = sortRoleName();
emit sectionRoleNameChanged();

qCInfo(logModels) << "Category type changed to:" << categoryType;
emit categoryTypeChanged();
Expand Down
6 changes: 5 additions & 1 deletion src/models/categorizedsortproxymodel.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2023 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

Expand All @@ -13,6 +13,7 @@ class CategorizedSortProxyModel : public QSortFilterProxyModel

Q_PROPERTY(CategoryType categoryType READ categoryType WRITE setCategoryType NOTIFY categoryTypeChanged)
Q_PROPERTY(QString sortRoleName READ sortRoleName NOTIFY categoryTypeChanged)
Q_PROPERTY(QString sectionRoleName READ sectionRoleName NOTIFY sectionRoleNameChanged)

QML_NAMED_ELEMENT(CategorizedSortProxyModel)
QML_SINGLETON
Expand Down Expand Up @@ -42,17 +43,20 @@ class CategorizedSortProxyModel : public QSortFilterProxyModel
enum CategoryType categoryType() const;

QString sortRoleName() const;
QString sectionRoleName() const { return m_sectionRoleName; }

Q_INVOKABLE QList<QString> alphabetarySections() const;
Q_INVOKABLE QList<int> DDECategorySections() const;

signals:
void categoryTypeChanged();
void sectionRoleNameChanged();

protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;

private:
bool isFreeSort;
QString m_sectionRoleName;
explicit CategorizedSortProxyModel(QObject *parent = nullptr);
};
Loading