From d07a8258e909c24764dbde23a201c2b3d8014713 Mon Sep 17 00:00:00 2001 From: James Graham Date: Sun, 8 Dec 2024 13:10:00 +0000 Subject: [PATCH] Room Custom Filter Prep This is basically prep work for customisable sort orders. The room sort parameters are detached from the room sort model as multiple components will need to access the values. The sorting is then generified. Some defunct sorting parameters are also removed. --- src/CMakeLists.txt | 2 + src/enums/roomsortparameter.cpp | 85 +++++++++++++++++ src/enums/roomsortparameter.h | 122 +++++++++++++++++++++++++ src/models/roomlistmodel.cpp | 6 +- src/models/roomlistmodel.h | 1 - src/models/roomtreemodel.cpp | 14 +-- src/models/roomtreemodel.h | 3 - src/models/sortfilterroomtreemodel.cpp | 75 ++++++--------- src/models/sortfilterroomtreemodel.h | 4 +- 9 files changed, 242 insertions(+), 70 deletions(-) create mode 100644 src/enums/roomsortparameter.cpp create mode 100644 src/enums/roomsortparameter.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5a5ad2f2c..c59a261cb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -194,6 +194,8 @@ add_library(neochat STATIC models/threadmodel.h enums/messagetype.h messagecomponent.h + enums/roomsortparameter.cpp + enums/roomsortparameter.h ) set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES diff --git a/src/enums/roomsortparameter.cpp b/src/enums/roomsortparameter.cpp new file mode 100644 index 000000000..62bab0c2a --- /dev/null +++ b/src/enums/roomsortparameter.cpp @@ -0,0 +1,85 @@ +// SPDX-FileCopyrightText: 2024 James Graham +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + +#include "roomsortparameter.h" + +namespace +{ +template +int typeCompare(T left, T right) +{ + return left == right ? 0 : left > right ? 1 : -1; +} + +template<> +int typeCompare(QString left, QString right) +{ + return left.localeAwareCompare(right); +} +} + +int RoomSortParameter::compareParameter(Parameter parameter, NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + switch (parameter) { + case AlphabeticalAscending: + return compareParameter(leftRoom, rightRoom); + case AlphabeticalDescending: + return compareParameter(leftRoom, rightRoom); + case HasUnread: + return compareParameter(leftRoom, rightRoom); + case MostUnread: + return compareParameter(leftRoom, rightRoom); + case HasHighlight: + return compareParameter(leftRoom, rightRoom); + case MostHighlights: + return compareParameter(leftRoom, rightRoom); + case LastActive: + return compareParameter(leftRoom, rightRoom); + default: + return false; + } +} + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + return -typeCompare(leftRoom->displayName(), rightRoom->displayName()); +} + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + return typeCompare(leftRoom->displayName(), rightRoom->displayName()); +} + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + return typeCompare(leftRoom->contextAwareNotificationCount() > 0, rightRoom->contextAwareNotificationCount() > 0); +} + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + return typeCompare(leftRoom->contextAwareNotificationCount(), rightRoom->contextAwareNotificationCount()); +} + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + const auto leftHighlight = leftRoom->highlightCount() > 0 && leftRoom->contextAwareNotificationCount() > 0; + const auto rightHighlight = rightRoom->highlightCount() > 0 && rightRoom->contextAwareNotificationCount() > 0; + return typeCompare(leftHighlight, rightHighlight); +} + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + return typeCompare(int(leftRoom->highlightCount()), int(rightRoom->highlightCount())); +} + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom) +{ + return typeCompare(leftRoom->lastActiveTime(), rightRoom->lastActiveTime()); +} diff --git a/src/enums/roomsortparameter.h b/src/enums/roomsortparameter.h new file mode 100644 index 000000000..b44bc9a75 --- /dev/null +++ b/src/enums/roomsortparameter.h @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: 2024 James Graham +// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL + +#pragma once + +#include "neochatroom.h" +#include +#include + +#include + +/** + * @class RoomSortParameter + * + * A class with the Parameter enum for room sort parameters. + */ +class RoomSortParameter : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("") + +public: + /** + * @brief Defines the available sort parameters. + */ + enum Parameter { + AlphabeticalAscending, + AlphabeticalDescending, + HasUnread, + MostUnread, + HasHighlight, + MostHighlights, + LastActive, + }; + Q_ENUM(Parameter) + + /** + * @brief Translate the Parameter enum value to a human readable name string. + * + * @sa Parameter + */ + static QString parameterName(Parameter parameter) + { + switch (parameter) { + case Parameter::AlphabeticalAscending: + return i18nc("As in sorting alphabetically with A first and Z last", "Alphabetical Ascending"); + case Parameter::AlphabeticalDescending: + return i18nc("As in sorting alphabetically with Z first and A last", "Alphabetical Descending"); + case Parameter::HasUnread: + return i18nc("As in sorting rooms with unread message above those without", "Has Unread Messages"); + case Parameter::MostUnread: + return i18nc("As in sorting rooms with the most unread messages higher", "Most Unread Messages"); + case Parameter::HasHighlight: + return i18nc("As in sorting rooms with highlighted message above those without", "Has Highlighted Messages"); + case Parameter::MostHighlights: + return i18nc("As in sorting rooms with the most highlighted messages higher", "Most Highlighted Messages"); + case Parameter::LastActive: + return i18nc("As in sorting the chat room with the newest meassage first", "Last Active"); + default: + return {}; + } + }; + + /** + * @brief Translate the Parameter enum value to a human readable description string. + * + * @sa Parameter + */ + static QString parameterDescription(Parameter parameter) + { + switch (parameter) { + case Parameter::AlphabeticalAscending: + return i18nc("@info", "Room names closer to A alphabetically are higher"); + case Parameter::AlphabeticalDescending: + return i18nc("@info", "Room names closer to Z alphabetically are higher"); + case Parameter::HasUnread: + return i18nc("@info", "Rooms with unread messages are higher"); + case Parameter::MostUnread: + return i18nc("@info", "Rooms with the most unread message are higher"); + case Parameter::HasHighlight: + return i18nc("@info", "Rooms with highlighted messages are higher"); + case Parameter::MostHighlights: + return i18nc("@info", "Rooms with the most highlighted messages are higher"); + case Parameter::LastActive: + return i18nc("@info", "Rooms with the newer messages are higher"); + default: + return {}; + } + }; + + /** + * @brief Compare the given parameter of the two given rooms. + * + * @return 0 if they are equal, 1 if the left is greater and -1 if the right is greater. + * + * @sa Parameter + */ + static int compareParameter(Parameter parameter, NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); + +private: + template + static int compareParameter(NeoChatRoom *, NeoChatRoom *) + { + return false; + } +}; + +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); +template<> +int RoomSortParameter::compareParameter(NeoChatRoom *leftRoom, NeoChatRoom *rightRoom); diff --git a/src/models/roomlistmodel.cpp b/src/models/roomlistmodel.cpp index 6e4db5c33..e6b9ecab7 100644 --- a/src/models/roomlistmodel.cpp +++ b/src/models/roomlistmodel.cpp @@ -129,7 +129,7 @@ void RoomListModel::connectRoomSignals(NeoChatRoom *room) refresh(room); }); connect(room, &Room::addedMessages, this, [this, room] { - refresh(room, {SubtitleTextRole, LastActiveTimeRole}); + refresh(room, {SubtitleTextRole}); }); connect(room, &Room::pendingEventMerged, this, [this, room] { refresh(room, {SubtitleTextRole}); @@ -229,9 +229,6 @@ QVariant RoomListModel::data(const QModelIndex &index, int role) const if (role == HasHighlightNotificationsRole) { return room->highlightCount() > 0 && room->contextAwareNotificationCount() > 0; } - if (role == LastActiveTimeRole) { - return room->lastActiveTime(); - } if (role == JoinStateRole) { if (!room->successorId().isEmpty()) { return QStringLiteral("upgraded"); @@ -291,7 +288,6 @@ QHash RoomListModel::roleNames() const roles[CategoryRole] = "category"; roles[ContextNotificationCountRole] = "contextNotificationCount"; roles[HasHighlightNotificationsRole] = "hasHighlightNotifications"; - roles[LastActiveTimeRole] = "lastActiveTime"; roles[JoinStateRole] = "joinState"; roles[CurrentRoomRole] = "currentRoom"; roles[SubtitleTextRole] = "subtitleText"; diff --git a/src/models/roomlistmodel.h b/src/models/roomlistmodel.h index ff3cb181f..9fc2c03f6 100644 --- a/src/models/roomlistmodel.h +++ b/src/models/roomlistmodel.h @@ -43,7 +43,6 @@ public: CategoryRole, /**< The room category, e.g favourite. */ ContextNotificationCountRole, /**< The context aware notification count for the room. */ HasHighlightNotificationsRole, /**< Whether there are any highlight notifications. */ - LastActiveTimeRole, /**< The timestamp of the last event sent in the room. */ JoinStateRole, /**< The local user's join state in the room. */ CurrentRoomRole, /**< The room object for the room. */ SubtitleTextRole, /**< The text to show as the room subtitle. */ diff --git a/src/models/roomtreemodel.cpp b/src/models/roomtreemodel.cpp index 0742c7988..dc450a3f6 100644 --- a/src/models/roomtreemodel.cpp +++ b/src/models/roomtreemodel.cpp @@ -176,7 +176,7 @@ void RoomTreeModel::connectRoomSignals(NeoChatRoom *room) refreshRoomRoles(room); }); connect(room, &Room::addedMessages, this, [this, room] { - refreshRoomRoles(room, {SubtitleTextRole, LastActiveTimeRole}); + refreshRoomRoles(room, {SubtitleTextRole}); }); connect(room, &Room::pendingEventMerged, this, [this, room] { refreshRoomRoles(room, {SubtitleTextRole}); @@ -274,7 +274,6 @@ QHash RoomTreeModel::roleNames() const roles[CategoryRole] = "category"; roles[ContextNotificationCountRole] = "contextNotificationCount"; roles[HasHighlightNotificationsRole] = "hasHighlightNotifications"; - roles[LastActiveTimeRole] = "lastActiveTime"; roles[JoinStateRole] = "joinState"; roles[CurrentRoomRole] = "currentRoom"; roles[SubtitleTextRole] = "subtitleText"; @@ -284,8 +283,6 @@ QHash RoomTreeModel::roleNames() const roles[IsDirectChat] = "isDirectChat"; roles[DelegateTypeRole] = "delegateType"; roles[IconRole] = "icon"; - roles[AttentionRole] = "attention"; - roles[FavouriteRole] = "favourite"; roles[RoomTypeRole] = "roomType"; return roles; } @@ -341,9 +338,6 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const if (role == HasHighlightNotificationsRole) { return room->highlightCount() > 0 && room->contextAwareNotificationCount() > 0; } - if (role == LastActiveTimeRole) { - return room->lastActiveTime(); - } if (role == JoinStateRole) { if (!room->successorId().isEmpty()) { return QStringLiteral("upgraded"); @@ -380,12 +374,6 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const if (role == DelegateTypeRole) { return QStringLiteral("normal"); } - if (role == AttentionRole) { - return room->notificationCount() + room->highlightCount() > 0; - } - if (role == FavouriteRole) { - return room->isFavourite(); - } if (role == RoomTypeRole) { if (room->creation()) { return room->creation()->contentPart("type"_L1); diff --git a/src/models/roomtreemodel.h b/src/models/roomtreemodel.h index 326f97359..0644db11e 100644 --- a/src/models/roomtreemodel.h +++ b/src/models/roomtreemodel.h @@ -36,7 +36,6 @@ public: CategoryRole, /**< The room category, e.g favourite. */ ContextNotificationCountRole, /**< The context aware notification count for the room. */ HasHighlightNotificationsRole, /**< Whether there are any highlight notifications. */ - LastActiveTimeRole, /**< The timestamp of the last event sent in the room. */ JoinStateRole, /**< The local user's join state in the room. */ CurrentRoomRole, /**< The room object for the room. */ SubtitleTextRole, /**< The text to show as the room subtitle. */ @@ -48,8 +47,6 @@ public: IsDirectChat, /**< Whether this room is a direct chat. */ DelegateTypeRole, IconRole, - AttentionRole, /**< Whether there are any notifications. */ - FavouriteRole, /**< Whether the room is favourited. */ RoomTypeRole, /**< The room's type. */ }; Q_ENUM(EventRoles) diff --git a/src/models/sortfilterroomtreemodel.cpp b/src/models/sortfilterroomtreemodel.cpp index a2bd05873..258d9861f 100644 --- a/src/models/sortfilterroomtreemodel.cpp +++ b/src/models/sortfilterroomtreemodel.cpp @@ -6,6 +6,7 @@ #include "neochatconfig.h" #include "neochatconnection.h" +#include "neochatroom.h" #include "neochatroomtype.h" #include "roommanager.h" #include "roomtreemodel.h" @@ -44,67 +45,49 @@ SortFilterRoomTreeModel::SortFilterRoomTreeModel(RoomTreeModel *sourceModel, QOb void SortFilterRoomTreeModel::setRoomSortOrder(SortFilterRoomTreeModel::RoomSortOrder sortOrder) { m_sortOrder = sortOrder; - if (sortOrder == SortFilterRoomTreeModel::Alphabetical) { - setSortRole(RoomTreeModel::DisplayNameRole); - } else if (sortOrder == SortFilterRoomTreeModel::Activity) { - setSortRole(RoomTreeModel::LastActiveTimeRole); - } invalidate(); } -static const QVector alphabeticalSortPriorities{ +static const QVector alphabeticalSortPriorities{ // Does exactly what it says on the tin. - RoomTreeModel::DisplayNameRole, + RoomSortParameter::AlphabeticalAscending, }; -static const QVector activitySortPriorities{ - // Anything useful at the top, quiet rooms at the bottom - RoomTreeModel::AttentionRole, - // Organize by highlights, notifications, unread favorites, all other unread, in that order - RoomTreeModel::HasHighlightNotificationsRole, - RoomTreeModel::ContextNotificationCountRole, - RoomTreeModel::FavouriteRole, +static const QVector activitySortPriorities{ + RoomSortParameter::HasHighlight, + RoomSortParameter::MostHighlights, + RoomSortParameter::HasUnread, + RoomSortParameter::MostUnread, + RoomSortParameter::LastActive, }; -static const QVector lastMessageSortPriorities{ - // Sort by last activity time - RoomTreeModel::LastActiveTimeRole, - // Anything useful at the top, quiet rooms at the bottom - RoomTreeModel::AttentionRole, - // Organize by highlights, notifications, unread favorites, all other unread, in that order - RoomTreeModel::HasHighlightNotificationsRole, - RoomTreeModel::ContextNotificationCountRole, - RoomTreeModel::FavouriteRole, +static const QVector lastMessageSortPriorities{ + RoomSortParameter::LastActive, }; -bool SortFilterRoomTreeModel::roleCmp(const QVariant &sortLeft, const QVariant &sortRight) const -{ - switch (sortLeft.typeId()) { - case QMetaType::Bool: - return (sortLeft == sortRight) ? false : sortLeft.toBool(); - case QMetaType::QString: - return sortLeft.toString() < sortRight.toString(); - case QMetaType::Int: - return sortLeft.toInt() > sortRight.toInt(); - case QMetaType::QDateTime: - return sortLeft.toDateTime() > sortRight.toDateTime(); - default: - return false; - } -} - -bool SortFilterRoomTreeModel::prioritiesCmp(const QVector &priorities, +bool SortFilterRoomTreeModel::prioritiesCmp(const QVector &priorities, const QModelIndex &source_left, const QModelIndex &source_right) const { - for (RoomTreeModel::EventRoles sortRole : priorities) { - const auto sortLeft = sourceModel()->data(source_left, sortRole); - const auto sortRight = sourceModel()->data(source_right, sortRole); - if (sortLeft != sortRight) { - return roleCmp(sortLeft, sortRight); + const auto treeModel = dynamic_cast(sourceModel()); + if (treeModel == nullptr) { + return false; + } + + const auto leftRoom = dynamic_cast(treeModel->connection()->room(source_left.data(RoomTreeModel::RoomIdRole).toString())); + const auto rightRoom = dynamic_cast(treeModel->connection()->room(source_right.data(RoomTreeModel::RoomIdRole).toString())); + if (leftRoom == nullptr || rightRoom == nullptr) { + return false; + } + + for (auto sortRole : priorities) { + auto result = RoomSortParameter::compareParameter(sortRole, leftRoom, rightRoom); + + if (result != 0) { + return result > 0; } } - return QSortFilterProxyModel::lessThan(source_left, source_right); + return false; } bool SortFilterRoomTreeModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const diff --git a/src/models/sortfilterroomtreemodel.h b/src/models/sortfilterroomtreemodel.h index 3368d4af6..db17b7b9c 100644 --- a/src/models/sortfilterroomtreemodel.h +++ b/src/models/sortfilterroomtreemodel.h @@ -7,6 +7,7 @@ #include #include +#include "enums/roomsortparameter.h" #include "models/roomtreemodel.h" /** @@ -105,6 +106,5 @@ private: QString m_filterText; QString m_activeSpaceId; - bool roleCmp(const QVariant &left, const QVariant &right) const; - bool prioritiesCmp(const QVector &priorities, const QModelIndex &left, const QModelIndex &right) const; + bool prioritiesCmp(const QVector &priorities, const QModelIndex &left, const QModelIndex &right) const; };