Fix double rooms issue.

This commit is contained in:
Black Hat 2018-07-14 15:35:27 +08:00
parent 7ae0bf9382
commit 247b80c1db
2 changed files with 89 additions and 18 deletions

View File

@ -11,38 +11,94 @@ RoomListModel::~RoomListModel() {}
void RoomListModel::setConnection(QMatrixClient::Connection* connection) { void RoomListModel::setConnection(QMatrixClient::Connection* connection) {
Q_ASSERT(connection); Q_ASSERT(connection);
using QMatrixClient::Connection;
using QMatrixClient::Room; using QMatrixClient::Room;
beginResetModel(); beginResetModel();
m_connection = connection; m_connection = connection;
connect(connection, &Connection::loggedOut, this, m_rooms.clear();
[=] { setConnection(connection); });
// connect(connection, &Connection::invitedRoom, this, connect(connection, &QMatrixClient::Connection::invitedRoom, this,
// &RoomListModel::updateRoom); &RoomListModel::updateRoom);
// connect(connection, &Connection::joinedRoom, this, connect(connection, &QMatrixClient::Connection::joinedRoom, this,
// &RoomListModel::updateRoom); &RoomListModel::updateRoom);
// connect(connection, &Connection::leftRoom, this, connect(connection, &QMatrixClient::Connection::leftRoom, this,
// &RoomListModel::updateRoom); &RoomListModel::updateRoom);
connect(connection, &Connection::aboutToDeleteRoom, this, connect(connection, &QMatrixClient::Connection::aboutToDeleteRoom, this,
&RoomListModel::deleteRoom); &RoomListModel::deleteRoom);
for (auto r : connection->roomMap()) addRoom(r); for (auto r : connection->roomMap()) doAddRoom(r);
endResetModel(); endResetModel();
} }
QMatrixClient::Room* RoomListModel::roomAt(int row) { return m_rooms.at(row); } QMatrixClient::Room* RoomListModel::roomAt(int row) { return m_rooms.at(row); }
void RoomListModel::addRoom(QMatrixClient::Room* room) { void RoomListModel::doAddRoom(QMatrixClient::Room* r) {
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count()); if (auto* room = r) {
connect(room, &QMatrixClient::Room::namesChanged, this, m_rooms.append(room);
&RoomListModel::namesChanged); connectRoomSignals(room);
m_rooms.append(room); } else {
endInsertRows(); qCritical() << "Attempt to add nullptr to the room list";
Q_ASSERT(false);
}
}
void RoomListModel::connectRoomSignals(QMatrixClient::Room* room) {
connect(room, &QMatrixClient::Room::displaynameChanged, this,
[=] { namesChanged(room); });
connect(room, &QMatrixClient::Room::unreadMessagesChanged, this,
[=] { unreadMessagesChanged(room); });
connect(room, &QMatrixClient::Room::notificationCountChanged, this,
[=] { unreadMessagesChanged(room); });
connect(room, &QMatrixClient::Room::joinStateChanged, this,
[=] { refresh(room); });
connect(room, &QMatrixClient::Room::avatarChanged, this,
[=] { refresh(room, {Qt::DecorationRole}); });
}
void RoomListModel::updateRoom(QMatrixClient::Room* room,
QMatrixClient::Room* prev) {
// There are two cases when this method is called:
// 1. (prev == nullptr) adding a new room to the room list
// 2. (prev != nullptr) accepting/rejecting an invitation or inviting to
// the previously left room (in both cases prev has the previous state).
if (prev == room) {
qCritical() << "RoomListModel::updateRoom: room tried to replace itself";
refresh(static_cast<QMatrixClient::Room*>(room));
return;
}
if (prev && room->id() != prev->id()) {
qCritical() << "RoomListModel::updateRoom: attempt to update room"
<< room->id() << "to" << prev->id();
// That doesn't look right but technically we still can do it.
}
// Ok, we're through with pre-checks, now for the real thing.
auto* newRoom = room;
const auto it = std::find_if(
m_rooms.begin(), m_rooms.end(),
[=](const QMatrixClient::Room* r) { return r == prev || r == newRoom; });
if (it != m_rooms.end()) {
qDebug() << "Room found in m_rooms.";
const int row = it - m_rooms.begin();
// There's no guarantee that prev != newRoom
if (*it == prev && *it != newRoom) {
prev->disconnect(this);
m_rooms.replace(row, newRoom);
connectRoomSignals(newRoom);
}
emit dataChanged(index(row), index(row));
} else {
qDebug() << "Room missing in m_rooms.";
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
doAddRoom(newRoom);
endInsertRows();
}
} }
void RoomListModel::deleteRoom(QMatrixClient::Room* room) { void RoomListModel::deleteRoom(QMatrixClient::Room* room) {
qDebug() << "Deleting room" << room->id();
const auto it = std::find(m_rooms.begin(), m_rooms.end(), room); const auto it = std::find(m_rooms.begin(), m_rooms.end(), room);
if (it == m_rooms.end()) return; // Already deleted, nothing to do if (it == m_rooms.end()) return; // Already deleted, nothing to do
qDebug() << "Erasing room" << room->id();
const int row = it - m_rooms.begin(); const int row = it - m_rooms.begin();
beginRemoveRows(QModelIndex(), row, row); beginRemoveRows(QModelIndex(), row, row);
m_rooms.erase(it); m_rooms.erase(it);
@ -91,6 +147,17 @@ void RoomListModel::namesChanged(QMatrixClient::Room* room) {
emit dataChanged(index(row), index(row)); emit dataChanged(index(row), index(row));
} }
void RoomListModel::refresh(QMatrixClient::Room* room,
const QVector<int>& roles) {
const auto it = std::find(m_rooms.begin(), m_rooms.end(), room);
if (it == m_rooms.end()) {
qCritical() << "Room" << room->id() << "not found in the room list";
return;
}
const auto idx = index(it - m_rooms.begin());
emit dataChanged(idx, idx, roles);
}
void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room) { void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room) {
int row = m_rooms.indexOf(room); int row = m_rooms.indexOf(room);
emit dataChanged(index(row), index(row)); emit dataChanged(index(row), index(row));

View File

@ -37,12 +37,16 @@ class RoomListModel : public QAbstractListModel {
private slots: private slots:
void namesChanged(QMatrixClient::Room* room); void namesChanged(QMatrixClient::Room* room);
void unreadMessagesChanged(QMatrixClient::Room* room); void unreadMessagesChanged(QMatrixClient::Room* room);
void addRoom(QMatrixClient::Room* room);
void doAddRoom(QMatrixClient::Room* room);
void updateRoom(QMatrixClient::Room* room, QMatrixClient::Room* prev);
void deleteRoom(QMatrixClient::Room* room); void deleteRoom(QMatrixClient::Room* room);
void refresh(QMatrixClient::Room* room, const QVector<int>& roles = {});
private: private:
QMatrixClient::Connection* m_connection = nullptr; QMatrixClient::Connection* m_connection = nullptr;
QList<QMatrixClient::Room*> m_rooms; QList<QMatrixClient::Room*> m_rooms;
void connectRoomSignals(QMatrixClient::Room* room);
signals: signals:
void connectionChanged(); void connectionChanged();