Move the various room models into RoomManager

Move the various room models into RoomManager. This means the same room models are always used and is a base from which further logic can be moved from QML to cpp.
This commit is contained in:
James Graham
2024-03-31 12:56:27 +00:00
parent 78ae14ab2f
commit 053ca6bed8
17 changed files with 155 additions and 95 deletions

View File

@@ -82,7 +82,7 @@ Q_SIGNALS:
void connectionChanged();
private:
QPointer<NeoChatConnection> m_connection = nullptr;
QPointer<NeoChatConnection> m_connection;
QMap<NeoChatRoomType::Types, QList<QPointer<NeoChatRoom>>> m_rooms;
void initializeCategories();

View File

@@ -5,17 +5,20 @@
#include "roomlistmodel.h"
SortFilterRoomListModel::SortFilterRoomListModel(QObject *parent)
SortFilterRoomListModel::SortFilterRoomListModel(RoomListModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{
Q_ASSERT(sourceModel);
setSourceModel(sourceModel);
sort(0);
invalidateFilter();
connect(this, &SortFilterRoomListModel::filterTextChanged, this, [this]() {
invalidateFilter();
});
connect(this, &SortFilterRoomListModel::sourceModelChanged, this, [this]() {
connect(sourceModel(), &QAbstractListModel::rowsInserted, this, &SortFilterRoomListModel::invalidateRowsFilter);
connect(sourceModel(), &QAbstractListModel::rowsRemoved, this, &SortFilterRoomListModel::invalidateRowsFilter);
connect(this->sourceModel(), &QAbstractListModel::rowsInserted, this, &SortFilterRoomListModel::invalidateRowsFilter);
connect(this->sourceModel(), &QAbstractListModel::rowsRemoved, this, &SortFilterRoomListModel::invalidateRowsFilter);
});
}

View File

@@ -6,6 +6,8 @@
#include <QQmlEngine>
#include <QSortFilterProxyModel>
#include "models/roomlistmodel.h"
/**
* @class SortFilterRoomListModel
*
@@ -36,7 +38,7 @@ class SortFilterRoomListModel : public QSortFilterProxyModel
Q_PROPERTY(QString filterText READ filterText READ filterText WRITE setFilterText NOTIFY filterTextChanged)
public:
explicit SortFilterRoomListModel(QObject *parent = nullptr);
explicit SortFilterRoomListModel(RoomListModel *sourceModel, QObject *parent = nullptr);
void setFilterText(const QString &text);
[[nodiscard]] QString filterText() const;

View File

@@ -10,9 +10,12 @@
#include "roomtreemodel.h"
#include "spacehierarchycache.h"
SortFilterRoomTreeModel::SortFilterRoomTreeModel(QObject *parent)
SortFilterRoomTreeModel::SortFilterRoomTreeModel(RoomTreeModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{
Q_ASSERT(sourceModel);
setSourceModel(sourceModel);
setRoomSortOrder(static_cast<RoomSortOrder>(NeoChatConfig::sortOrder()));
connect(NeoChatConfig::self(), &NeoChatConfig::SortOrderChanged, this, [this]() {
setRoomSortOrder(static_cast<RoomSortOrder>(NeoChatConfig::sortOrder()));
@@ -24,9 +27,9 @@ SortFilterRoomTreeModel::SortFilterRoomTreeModel(QObject *parent)
invalidateFilter();
connect(this, &SortFilterRoomTreeModel::filterTextChanged, this, &SortFilterRoomTreeModel::invalidateFilter);
connect(this, &SortFilterRoomTreeModel::sourceModelChanged, this, [this]() {
sourceModel()->disconnect(this);
connect(sourceModel(), &QAbstractItemModel::rowsInserted, this, &SortFilterRoomTreeModel::invalidateFilter);
connect(sourceModel(), &QAbstractItemModel::rowsRemoved, this, &SortFilterRoomTreeModel::invalidateFilter);
this->sourceModel()->disconnect(this);
connect(this->sourceModel(), &QAbstractItemModel::rowsInserted, this, &SortFilterRoomTreeModel::invalidateFilter);
connect(this->sourceModel(), &QAbstractItemModel::rowsRemoved, this, &SortFilterRoomTreeModel::invalidateFilter);
});
connect(NeoChatConfig::self(), &NeoChatConfig::CollapsedChanged, this, &SortFilterRoomTreeModel::invalidateFilter);

View File

@@ -62,7 +62,7 @@ public:
};
Q_ENUM(Mode)
explicit SortFilterRoomTreeModel(QObject *parent = nullptr);
explicit SortFilterRoomTreeModel(RoomTreeModel *sourceModel, QObject *parent = nullptr);
void setRoomSortOrder(RoomSortOrder sortOrder);

View File

@@ -5,22 +5,21 @@
#include "roomlistmodel.h"
SortFilterSpaceListModel::SortFilterSpaceListModel(QObject *parent)
SortFilterSpaceListModel::SortFilterSpaceListModel(RoomListModel *sourceModel, QObject *parent)
: QSortFilterProxyModel{parent}
{
setSortRole(RoomListModel::RoomIdRole);
sort(0);
invalidateFilter();
connect(this, &QAbstractProxyModel::sourceModelChanged, this, [this]() {
connect(sourceModel(), &QAbstractListModel::dataChanged, this, [this](const QModelIndex &, const QModelIndex &, QList<int> roles) {
if (roles.contains(RoomListModel::IsChildSpaceRole)) {
invalidate();
}
countChanged();
});
invalidate();
Q_ASSERT(sourceModel);
setSourceModel(sourceModel);
connect(this->sourceModel(), &QAbstractListModel::dataChanged, this, [this](const QModelIndex &, const QModelIndex &, QList<int> roles) {
if (roles.contains(RoomListModel::IsChildSpaceRole)) {
invalidate();
}
Q_EMIT countChanged();
});
setSortRole(RoomListModel::RoomIdRole);
sort(0);
}
bool SortFilterSpaceListModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const

View File

@@ -6,6 +6,8 @@
#include <QQmlEngine>
#include <QSortFilterProxyModel>
#include "models/roomlistmodel.h"
/**
* @class SortFilterSpaceListModel
*
@@ -25,7 +27,7 @@ class SortFilterSpaceListModel : public QSortFilterProxyModel
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
explicit SortFilterSpaceListModel(QObject *parent = nullptr);
explicit SortFilterSpaceListModel(RoomListModel *sourceModel, QObject *parent = nullptr);
Q_SIGNALS:
void countChanged();

View File

@@ -18,16 +18,11 @@ Kirigami.ScrollablePage {
required property NeoChatConnection connection
header: Kirigami.SearchField {
onTextChanged: sortModel.filterText = text
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
}
ListView {
model: SortFilterRoomListModel {
id: sortModel
sourceModel: RoomListModel {
connection: root.connection
}
}
model: RoomManager.sortFilterRoomListModel
delegate: RoomDelegate {
id: roomDelegate
onClicked: {

View File

@@ -25,13 +25,8 @@ QQC2.Popup {
root.open();
}
RoomListModel {
id: roomListModel
connection: root.connection
}
Component.onCompleted: {
chatDocumentHandler.completionModel.roomListModel = roomListModel;
chatDocumentHandler.completionModel.roomListModel = RoomManager.roomListModel;
}
function incrementIndex() {

View File

@@ -66,6 +66,7 @@ QQC2.Dialog {
root.close();
}
focusSequence: ""
onTextChanged: RoomManager.sortFilterRoomListModel.filterText = text
}
QQC2.ScrollView {
@@ -81,13 +82,7 @@ QQC2.Dialog {
highlightMoveDuration: 200
Keys.forwardTo: searchField
keyNavigationEnabled: true
model: SortFilterRoomListModel {
filterText: searchField.text
sourceModel: RoomListModel {
id: roomListModel
connection: root.connection
}
}
model: RoomManager.sortFilterRoomListModel
delegate: RoomDelegate {
connection: root.connection

View File

@@ -25,14 +25,11 @@ ColumnLayout {
text: i18n("Room")
textRole: "escapedDisplayName"
valueRole: "roomId"
displayText: roomListModel.data(roomListModel.index(currentIndex, 0), RoomListModel.DisplayNameRole)
model: RoomListModel {
id: roomListModel
connection: root.connection
}
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.DisplayNameRole)
model: RoomManager.roomListModel
currentIndex: 0
Component.onCompleted: currentIndex = roomListModel.rowForRoom(root.room)
onCurrentValueChanged: root.room = roomListModel.roomByAliasOrId(roomComboBox.currentValue)
Component.onCompleted: currentIndex = RoomManager.roomListModel.rowForRoom(root.room)
onCurrentValueChanged: root.room = RoomManager.roomListModel.roomByAliasOrId(roomComboBox.currentValue)
}
FormCard.FormTextDelegate {
text: i18n("Room Id: %1", root.room.id)

View File

@@ -29,10 +29,6 @@ Kirigami.Page {
required property NeoChatConnection connection
readonly property RoomTreeModel roomTreeModel: RoomTreeModel {
connection: root.connection
}
readonly property bool collapsed: Config.collapsed
onCurrentWidthChanged: pageStack.defaultColumnWidth = root.currentWidth
@@ -41,7 +37,7 @@ Kirigami.Page {
onCollapsedChanged: {
if (collapsed) {
sortFilterRoomTreeModel.filterText = "";
RoomManager.sortFilterRoomTreeModel.filterText = "";
}
}
@@ -107,8 +103,6 @@ Kirigami.Page {
Layout.fillHeight: true
connection: root.connection
onSpacesUpdated: sortFilterRoomTreeModel.invalidate()
}
Kirigami.Separator {
@@ -136,15 +130,7 @@ Kirigami.Page {
clip: true
reuseItems: false
model: SortFilterRoomTreeModel {
id: sortFilterRoomTreeModel
sourceModel: root.roomTreeModel
activeSpaceId: RoomManager.currentSpace
mode: RoomManager.currentSpace === "DM" ? SortFilterRoomTreeModel.DirectChats : SortFilterRoomTreeModel.Rooms
onRowsInserted: (index, first, last) => treeView.expandTo(index)
onDataChanged: treeView.expandRecursively()
}
model: RoomManager.sortFilterRoomTreeModel
selectionModel: ItemSelectionModel {}
@@ -217,7 +203,7 @@ Kirigami.Page {
anchors.horizontalCenterOffset: (spaceDrawer.width + 1) / 2
width: scrollView.width - Kirigami.Units.largeSpacing * 4
visible: treeView.rows == 0
text: if (sortFilterRoomTreeModel.filterText.length > 0) {
text: if (RoomManager.sortFilterRoomTreeModel.filterText.length > 0) {
return spaceDrawer.showDirectChats ? i18n("No friends found") : i18n("No rooms found");
} else {
return spaceDrawer.showDirectChats ? i18n("You haven't added any of your friends yet, click below to search for them.") : i18n("Join some rooms to get started");
@@ -226,12 +212,12 @@ Kirigami.Page {
Kirigami.Action {
id: exploreRoomAction
icon.name: sortFilterRoomTreeModel.filterText.length > 0 ? "search" : "list-add"
text: sortFilterRoomTreeModel.filterText.length > 0 ? i18n("Search in room directory") : i18n("Explore rooms")
icon.name: RoomManager.sortFilterRoomTreeModel.filterText.length > 0 ? "search" : "list-add"
text: RoomManager.sortFilterRoomTreeModel.filterText.length > 0 ? i18n("Search in room directory") : i18n("Explore rooms")
onTriggered: {
let dialog = pageStack.layers.push(Qt.createComponent('org.kde.neochat', 'ExploreRoomsPage.qml'), {
connection: root.connection,
keyword: sortFilterRoomTreeModel.filterText
keyword: RoomManager.sortFilterRoomTreeModel.filterText
}, {
title: i18nc("@title", "Explore Rooms")
});
@@ -243,8 +229,8 @@ Kirigami.Page {
Kirigami.Action {
id: userSearchAction
icon.name: sortFilterRoomTreeModel.filterText.length > 0 ? "search" : "list-add"
text: sortFilterRoomTreeModel.filterText.length > 0 ? i18n("Search in friend directory") : i18n("Find your friends")
icon.name: RoomManager.sortFilterRoomTreeModel.filterText.length > 0 ? "search" : "list-add"
text: RoomManager.sortFilterRoomTreeModel.filterText.length > 0 ? i18n("Search in friend directory") : i18n("Find your friends")
onTriggered: pageStack.pushDialogLayer(Qt.createComponent('org.kde.neochat', 'UserSearchPage.qml'), {
connection: root.connection
}, {
@@ -325,7 +311,7 @@ Kirigami.Page {
connection: root.connection
onTextChanged: newText => {
sortFilterRoomTreeModel.filterText = newText;
RoomManager.sortFilterRoomTreeModel.filterText = newText;
treeView.expandRecursively();
}
}
@@ -337,7 +323,7 @@ Kirigami.Page {
connection: root.connection
onTextChanged: newText => {
sortFilterRoomTreeModel.filterText = newText;
RoomManager.sortFilterRoomTreeModel.filterText = newText;
}
}
}

View File

@@ -21,8 +21,6 @@ QQC2.Control {
topPadding: 0
bottomPadding: 0
signal spacesUpdated
contentItem: Loader {
id: sidebarColumn
z: 0
@@ -169,12 +167,7 @@ QQC2.Control {
}
Repeater {
model: SortFilterSpaceListModel {
sourceModel: RoomListModel {
connection: root.connection
}
onLayoutChanged: root.spacesUpdated()
}
model: RoomManager.sortFilterSpaceListModel
delegate: AvatarTabButton {
id: spaceDelegate
@@ -194,7 +187,6 @@ QQC2.Control {
onSelected: {
RoomManager.resolveResource(spaceDelegate.roomId);
RoomManager.currentSpace = spaceDelegate.roomId;
root.selectionChanged();
}
checked: RoomManager.currentSpace === roomId
onContextMenuRequested: root.createContextMenu(currentRoom)

View File

@@ -29,6 +29,11 @@
RoomManager::RoomManager(QObject *parent)
: QObject(parent)
, m_config(KSharedConfig::openStateConfig())
, m_roomListModel(new RoomListModel(this))
, m_sortFilterRoomListModel(new SortFilterRoomListModel(m_roomListModel, this))
, m_sortFilterSpaceListModel(new SortFilterSpaceListModel(m_roomListModel, this))
, m_roomTreeModel(new RoomTreeModel(this))
, m_sortFilterRoomTreeModel(new SortFilterRoomTreeModel(m_roomTreeModel, this))
, m_timelineModel(new TimelineModel(this))
, m_messageFilterModel(new MessageFilterModel(this, m_timelineModel))
, m_mediaMessageFilterModel(new MediaMessageFilterModel(this, m_messageFilterModel))
@@ -44,6 +49,11 @@ RoomManager::RoomManager(QObject *parent)
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this](NeoChatConnection *connection) {
setConnection(connection);
});
connect(this, &RoomManager::connectionChanged, this, [this]() {
m_roomListModel->setConnection(m_connection);
m_roomTreeModel->setConnection(m_connection);
});
connect(m_sortFilterSpaceListModel, &SortFilterSpaceListModel::layoutChanged, m_sortFilterRoomTreeModel, &SortFilterRoomTreeModel::invalidate);
}
RoomManager::~RoomManager()
@@ -61,6 +71,31 @@ NeoChatRoom *RoomManager::currentRoom() const
return m_currentRoom;
}
RoomListModel *RoomManager::roomListModel() const
{
return m_roomListModel;
}
SortFilterRoomListModel *RoomManager::sortFilterRoomListModel() const
{
return m_sortFilterRoomListModel;
}
SortFilterSpaceListModel *RoomManager::sortFilterSpaceListModel() const
{
return m_sortFilterSpaceListModel;
}
RoomTreeModel *RoomManager::roomTreeModel() const
{
return m_roomTreeModel;
}
SortFilterRoomTreeModel *RoomManager::sortFilterRoomTreeModel() const
{
return m_sortFilterRoomTreeModel;
}
TimelineModel *RoomManager::timelineModel() const
{
return m_timelineModel;
@@ -327,6 +362,11 @@ void RoomManager::setConnection(NeoChatConnection *connection)
void RoomManager::setCurrentSpace(const QString &spaceId, bool setRoom)
{
m_currentSpaceId = spaceId;
// This need to happen before the signal so TreeView.expandRecursively() can work nicely.
m_sortFilterRoomTreeModel->setActiveSpaceId(m_currentSpaceId);
m_sortFilterRoomTreeModel->setMode(m_currentSpaceId == QLatin1String("DM") ? SortFilterRoomTreeModel::DirectChats : SortFilterRoomTreeModel::Rooms);
Q_EMIT currentSpaceChanged();
m_lastSpaceConfig.writeEntry(m_connection->userId(), spaceId);

View File

@@ -15,6 +15,11 @@
#include "eventhandler.h"
#include "models/mediamessagefiltermodel.h"
#include "models/messagefiltermodel.h"
#include "models/roomlistmodel.h"
#include "models/roomtreemodel.h"
#include "models/sortfilterroomlistmodel.h"
#include "models/sortfilterroomtreemodel.h"
#include "models/sortfilterspacelistmodel.h"
#include "models/timelinemodel.h"
class NeoChatRoom;
@@ -53,6 +58,39 @@ class RoomManager : public QObject, public UriResolverBase
*/
Q_PROPERTY(QString currentSpace READ currentSpace WRITE setCurrentSpace NOTIFY currentSpaceChanged)
/**
* @brief The RoomListModel that should be used for linear room visualisation.
*
* The connection the model uses to get the data will be updated by this class
* so there is no need to do this manually or replace the model when the connection
* changes.
*/
Q_PROPERTY(RoomListModel *roomListModel READ roomListModel CONSTANT)
/**
* @brief The SortFilterRoomListModel that should be used for room visualisation.
*/
Q_PROPERTY(SortFilterRoomListModel *sortFilterRoomListModel READ sortFilterRoomListModel CONSTANT)
/**
* @brief The SortFilterSpaceListModel that should be used for space visualisation.
*/
Q_PROPERTY(SortFilterSpaceListModel *sortFilterSpaceListModel READ sortFilterSpaceListModel CONSTANT)
/**
* @brief The RoomTreeModel that should be used for room visualisation.
*
* The connection the model uses to get the data will be updated by this class
* so there is no need to do this manually or replace the model when the connection
* changes.
*/
Q_PROPERTY(RoomTreeModel *roomTreeModel READ roomTreeModel CONSTANT)
/**
* @brief The SortFilterRoomTreeModel that should be used for room visualisation.
*/
Q_PROPERTY(SortFilterRoomTreeModel *sortFilterRoomTreeModel READ sortFilterRoomTreeModel CONSTANT)
/**
* @brief The TimelineModel that should be used for room message visualisation.
*
@@ -106,6 +144,12 @@ public:
NeoChatRoom *currentRoom() const;
RoomListModel *roomListModel() const;
SortFilterRoomListModel *sortFilterRoomListModel() const;
SortFilterSpaceListModel *sortFilterSpaceListModel() const;
RoomTreeModel *roomTreeModel() const;
SortFilterRoomTreeModel *sortFilterRoomTreeModel() const;
TimelineModel *timelineModel() const;
MessageFilterModel *messageFilterModel() const;
MediaMessageFilterModel *mediaMessageFilterModel() const;
@@ -293,6 +337,12 @@ private:
KConfigGroup m_directChatsConfig;
QPointer<ChatDocumentHandler> m_chatDocumentHandler;
RoomListModel *m_roomListModel;
SortFilterRoomListModel *m_sortFilterRoomListModel;
SortFilterSpaceListModel *m_sortFilterSpaceListModel;
RoomTreeModel *m_roomTreeModel;
SortFilterRoomTreeModel *m_sortFilterRoomTreeModel;
TimelineModel *m_timelineModel;
MessageFilterModel *m_messageFilterModel;
MediaMessageFilterModel *m_mediaMessageFilterModel;

View File

@@ -9,6 +9,7 @@
#include "neochatroom.h"
#include "roomlistmodel.h"
#include "roommanager.h"
#include "sortfilterroomlistmodel.h"
#include "windowcontroller.h"
RemoteImage Runner::serializeImage(const QImage &image)
@@ -28,9 +29,9 @@ RemoteImage Runner::serializeImage(const QImage &image)
Runner::Runner()
: QObject()
, m_sourceModel(new RoomListModel(this))
, m_model(new SortFilterRoomListModel(m_sourceModel, this))
{
m_sourceModel = new RoomListModel(this);
m_model.setSourceModel(m_sourceModel);
connect(&Controller::instance(), &Controller::activeConnectionChanged, this, [this]() {
m_sourceModel->setConnection(Controller::instance().activeConnection());
});
@@ -44,13 +45,13 @@ Runner::Runner()
void Runner::setRoomListModel(RoomListModel *roomListModel)
{
m_model.setSourceModel(roomListModel);
m_model->setSourceModel(roomListModel);
Q_EMIT roomListModelChanged();
}
RoomListModel *Runner::roomListModel() const
{
return dynamic_cast<RoomListModel *>(m_model.sourceModel());
return dynamic_cast<RoomListModel *>(m_model->sourceModel());
}
RemoteActions Runner::Actions()
@@ -60,22 +61,22 @@ RemoteActions Runner::Actions()
RemoteMatches Runner::Match(const QString &searchTerm)
{
m_model.setFilterText(searchTerm);
m_model->setFilterText(searchTerm);
RemoteMatches matches;
for (int i = 0; i < m_model.rowCount(); ++i) {
for (int i = 0; i < m_model->rowCount(); ++i) {
RemoteMatch match;
const QString name = m_model.data(m_model.index(i, 0), RoomListModel::DisplayNameRole).toString();
const QString name = m_model->data(m_model->index(i, 0), RoomListModel::DisplayNameRole).toString();
match.iconName = QStringLiteral("org.kde.neochat");
match.id = m_model.data(m_model.index(i, 0), RoomListModel::RoomIdRole).toString();
match.id = m_model->data(m_model->index(i, 0), RoomListModel::RoomIdRole).toString();
match.text = name;
match.relevance = 1;
const RemoteImage remoteImage = serializeImage(m_model.data(m_model.index(i, 0), RoomListModel::AvatarImageRole).value<QImage>());
const RemoteImage remoteImage = serializeImage(m_model->data(m_model->index(i, 0), RoomListModel::AvatarImageRole).value<QImage>());
match.properties.insert(QStringLiteral("icon-data"), QVariant::fromValue(remoteImage));
match.properties.insert(QStringLiteral("subtext"), m_model.data(m_model.index(i, 0), RoomListModel::TopicRole).toString());
match.properties.insert(QStringLiteral("subtext"), m_model->data(m_model->index(i, 0), RoomListModel::TopicRole).toString());
if (name.compare(searchTerm, Qt::CaseInsensitive) == 0) {
match.type = ExactMatch;

View File

@@ -203,7 +203,7 @@ Q_SIGNALS:
private:
RemoteImage serializeImage(const QImage &image);
SortFilterRoomListModel m_model;
RoomListModel *m_sourceModel;
QPointer<RoomListModel> m_sourceModel;
QPointer<SortFilterRoomListModel> m_model;
Runner();
};