Use TreeItem from qt tree model example in RoomTreeModel
This commit is contained in:
@@ -13,6 +13,152 @@
|
|||||||
|
|
||||||
using namespace Quotient;
|
using namespace Quotient;
|
||||||
|
|
||||||
|
TreeItem::TreeItem(TreeData treeData, TreeItem *parent)
|
||||||
|
: m_treeData(treeData)
|
||||||
|
, m_parentItem(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void TreeItem::appendChild(std::unique_ptr<TreeItem> &&child)
|
||||||
|
{
|
||||||
|
m_childItems.push_back(std::move(child));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TreeItem::insertChildren(int position, int count, TreeData treeData)
|
||||||
|
{
|
||||||
|
if (position < 0 || position > qsizetype(m_childItems.size()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int row = 0; row < count; ++row) {
|
||||||
|
m_childItems.insert(m_childItems.cbegin() + position, std::make_unique<TreeItem>(treeData, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TreeItem::removeChildren(int position, int count)
|
||||||
|
{
|
||||||
|
if (position < 0 || position + count > qsizetype(m_childItems.size())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int row = 0; row < count; ++row) {
|
||||||
|
m_childItems.erase(m_childItems.cbegin() + position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeItem *TreeItem::child(int row)
|
||||||
|
{
|
||||||
|
return row >= 0 && row < childCount() ? m_childItems.at(row).get() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TreeItem::childCount() const
|
||||||
|
{
|
||||||
|
return int(m_childItems.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
int TreeItem::row() const
|
||||||
|
{
|
||||||
|
if (m_parentItem == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto it = std::find_if(m_parentItem->m_childItems.cbegin(), m_parentItem->m_childItems.cend(), [this](const std::unique_ptr<TreeItem> &treeItem) {
|
||||||
|
return treeItem.get() == this;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (it != m_parentItem->m_childItems.cend())
|
||||||
|
return std::distance(m_parentItem->m_childItems.cbegin(), it);
|
||||||
|
Q_ASSERT(false); // should not happen
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant TreeItem::data(int role) const
|
||||||
|
{
|
||||||
|
if (!m_parentItem) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::holds_alternative<NeoChatRoomType::Types>(m_treeData)) {
|
||||||
|
const auto row = this->row();
|
||||||
|
switch (role) {
|
||||||
|
case RoomTreeModel::DisplayNameRole:
|
||||||
|
return NeoChatRoomType::typeName(row);
|
||||||
|
case RoomTreeModel::DelegateTypeRole:
|
||||||
|
if (row == NeoChatRoomType::Search) {
|
||||||
|
return QStringLiteral("search");
|
||||||
|
}
|
||||||
|
if (row == NeoChatRoomType::AddDirect) {
|
||||||
|
return QStringLiteral("addDirect");
|
||||||
|
}
|
||||||
|
return QStringLiteral("section");
|
||||||
|
case RoomTreeModel::IconRole:
|
||||||
|
return NeoChatRoomType::typeIconName(row);
|
||||||
|
case RoomTreeModel::CategoryRole:
|
||||||
|
return row;
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto room = std::get<NeoChatRoom *>(m_treeData);
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case RoomTreeModel::DisplayNameRole:
|
||||||
|
return room->displayName();
|
||||||
|
case RoomTreeModel::AvatarRole:
|
||||||
|
return room->avatarMediaId();
|
||||||
|
case RoomTreeModel::CanonicalAliasRole:
|
||||||
|
return room->canonicalAlias();
|
||||||
|
case RoomTreeModel::TopicRole:
|
||||||
|
return room->topic();
|
||||||
|
case RoomTreeModel::CategoryRole:
|
||||||
|
return NeoChatRoomType::typeForRoom(room);
|
||||||
|
case RoomTreeModel::NotificationCountRole:
|
||||||
|
return room->notificationCount();
|
||||||
|
case RoomTreeModel::HighlightCountRole:
|
||||||
|
return room->highlightCount();
|
||||||
|
case RoomTreeModel::LastActiveTimeRole:
|
||||||
|
return room->lastActiveTime();
|
||||||
|
case RoomTreeModel::JoinStateRole:
|
||||||
|
if (!room->successorId().isEmpty()) {
|
||||||
|
return QStringLiteral("upgraded");
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(room->joinState());
|
||||||
|
case RoomTreeModel::CurrentRoomRole:
|
||||||
|
return QVariant::fromValue(room);
|
||||||
|
case RoomTreeModel::SubtitleTextRole: {
|
||||||
|
if (room->lastEvent() == nullptr || room->lastEventIsSpoiler()) {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
EventHandler eventHandler(room, room->lastEvent());
|
||||||
|
return eventHandler.subtitleText();
|
||||||
|
}
|
||||||
|
case RoomTreeModel::AvatarImageRole:
|
||||||
|
return room->avatar(128);
|
||||||
|
case RoomTreeModel::RoomIdRole:
|
||||||
|
return room->id();
|
||||||
|
case RoomTreeModel::IsSpaceRole:
|
||||||
|
return room->isSpace();
|
||||||
|
case RoomTreeModel::IsChildSpaceRole:
|
||||||
|
return SpaceHierarchyCache::instance().isChild(room->id());
|
||||||
|
case RoomTreeModel::ReplacementIdRole:
|
||||||
|
return room->successorId();
|
||||||
|
case RoomTreeModel::IsDirectChat:
|
||||||
|
return room->isDirectChat();
|
||||||
|
case RoomTreeModel::DelegateTypeRole:
|
||||||
|
return QStringLiteral("normal");
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeItem *TreeItem::parentItem() const
|
||||||
|
{
|
||||||
|
return m_parentItem;
|
||||||
|
}
|
||||||
|
|
||||||
RoomTreeModel::RoomTreeModel(QObject *parent)
|
RoomTreeModel::RoomTreeModel(QObject *parent)
|
||||||
: QAbstractItemModel(parent)
|
: QAbstractItemModel(parent)
|
||||||
{
|
{
|
||||||
@@ -27,11 +173,22 @@ void RoomTreeModel::initializeCategories()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_rooms.clear();
|
m_rooms.clear();
|
||||||
|
|
||||||
|
m_rootItem.reset(new TreeItem(nullptr));
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
m_rooms[NeoChatRoomType::Types(i)] = {};
|
m_rootItem->appendChild(std::make_unique<TreeItem>(NeoChatRoomType::Types(i), m_rootItem.get()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TreeItem *RoomTreeModel::getItem(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (index.isValid()) {
|
||||||
|
if (auto *item = static_cast<TreeItem *>(index.internalPointer()))
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return m_rootItem.get();
|
||||||
|
}
|
||||||
|
|
||||||
void RoomTreeModel::setConnection(NeoChatConnection *connection)
|
void RoomTreeModel::setConnection(NeoChatConnection *connection)
|
||||||
{
|
{
|
||||||
if (m_connection == connection) {
|
if (m_connection == connection) {
|
||||||
@@ -77,15 +234,21 @@ void RoomTreeModel::newRoom(Room *r)
|
|||||||
void RoomTreeModel::leftRoom(Room *r)
|
void RoomTreeModel::leftRoom(Room *r)
|
||||||
{
|
{
|
||||||
const auto room = dynamic_cast<NeoChatRoom *>(r);
|
const auto room = dynamic_cast<NeoChatRoom *>(r);
|
||||||
const auto type = NeoChatRoomType::typeForRoom(room);
|
|
||||||
auto row = m_rooms[type].indexOf(room);
|
auto idx = indexForRoom(room);
|
||||||
if (row == -1) {
|
if (!idx.isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
beginRemoveRows(index(type, 0), row, row);
|
|
||||||
|
beginRemoveRows(idx.parent(), idx.row(), idx.row());
|
||||||
|
const bool success = parentItem->removeChildren(position, rows);
|
||||||
m_rooms[type][row]->disconnect(this);
|
m_rooms[type][row]->disconnect(this);
|
||||||
m_rooms[type].removeAt(row);
|
m_rooms[type].removeAt(row);
|
||||||
endRemoveRows();
|
endRemoveRows();
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
qWarning() << "Unable to remove room";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomTreeModel::moveRoom(Quotient::Room *room)
|
void RoomTreeModel::moveRoom(Quotient::Room *room)
|
||||||
@@ -151,14 +314,12 @@ void RoomTreeModel::connectRoomSignals(NeoChatRoom *room)
|
|||||||
|
|
||||||
void RoomTreeModel::refreshRoomRoles(NeoChatRoom *room, const QList<int> &roles)
|
void RoomTreeModel::refreshRoomRoles(NeoChatRoom *room, const QList<int> &roles)
|
||||||
{
|
{
|
||||||
const auto roomType = NeoChatRoomType::typeForRoom(room);
|
const auto idx = indexForRoom(room);
|
||||||
const auto it = std::find(m_rooms[roomType].begin(), m_rooms[roomType].end(), room);
|
if (!idx.isValid()) {
|
||||||
if (it == m_rooms[roomType].end()) {
|
|
||||||
qCritical() << "Room" << room->id() << "not found in the room list";
|
qCritical() << "Room" << room->id() << "not found in the room list";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto parentIndex = index(roomType, 0, {});
|
|
||||||
const auto idx = index(it - m_rooms[roomType].begin(), 0, parentIndex);
|
|
||||||
Q_EMIT dataChanged(idx, idx, roles);
|
Q_EMIT dataChanged(idx, idx, roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,32 +336,40 @@ int RoomTreeModel::columnCount(const QModelIndex &parent) const
|
|||||||
|
|
||||||
int RoomTreeModel::rowCount(const QModelIndex &parent) const
|
int RoomTreeModel::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (!parent.isValid()) {
|
if (parent.isValid() && parent.column() > 0) {
|
||||||
return m_rooms.keys().size();
|
return 0;
|
||||||
}
|
}
|
||||||
if (!parent.parent().isValid()) {
|
|
||||||
return m_rooms.values()[parent.row()].size();
|
const TreeItem *parentItem = getItem(parent);
|
||||||
}
|
return parentItem ? parentItem->childCount() : 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex RoomTreeModel::parent(const QModelIndex &index) const
|
QModelIndex RoomTreeModel::parent(const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
if (!index.internalPointer()) {
|
if (!index.isValid())
|
||||||
return {};
|
return {};
|
||||||
}
|
|
||||||
return this->index(NeoChatRoomType::typeForRoom(static_cast<NeoChatRoom *>(index.internalPointer())), 0, QModelIndex());
|
TreeItem *childItem = getItem(index);
|
||||||
|
TreeItem *parentItem = childItem ? childItem->parentItem() : nullptr;
|
||||||
|
|
||||||
|
return (parentItem != m_rootItem.get() && parentItem != nullptr) ? createIndex(parentItem->row(), 0, parentItem) : QModelIndex{};
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex RoomTreeModel::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex RoomTreeModel::index(int row, int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if (!parent.isValid()) {
|
if (parent.isValid() && parent.column() != 0) {
|
||||||
return createIndex(row, column, nullptr);
|
|
||||||
}
|
|
||||||
if (row >= rowCount(parent)) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return createIndex(row, column, m_rooms[NeoChatRoomType::Types(parent.row())][row]);
|
|
||||||
|
TreeItem *parentItem = getItem(parent);
|
||||||
|
if (!parentItem) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto *childItem = parentItem->child(row)) {
|
||||||
|
return createIndex(row, column, childItem);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHash<int, QByteArray> RoomTreeModel::roleNames() const
|
QHash<int, QByteArray> RoomTreeModel::roleNames() const
|
||||||
@@ -231,103 +400,9 @@ QHash<int, QByteArray> RoomTreeModel::roleNames() const
|
|||||||
// TODO room type changes
|
// TODO room type changes
|
||||||
QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
|
Q_ASSERT(checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid));
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!index.parent().isValid()) {
|
return getItem(index)->data(role);
|
||||||
if (role == DisplayNameRole) {
|
|
||||||
return NeoChatRoomType::typeName(index.row());
|
|
||||||
}
|
|
||||||
if (role == DelegateTypeRole) {
|
|
||||||
if (index.row() == NeoChatRoomType::Search) {
|
|
||||||
return QStringLiteral("search");
|
|
||||||
}
|
|
||||||
if (index.row() == NeoChatRoomType::AddDirect) {
|
|
||||||
return QStringLiteral("addDirect");
|
|
||||||
}
|
|
||||||
return QStringLiteral("section");
|
|
||||||
}
|
|
||||||
if (role == IconRole) {
|
|
||||||
return NeoChatRoomType::typeIconName(index.row());
|
|
||||||
}
|
|
||||||
if (role == CategoryRole) {
|
|
||||||
return index.row();
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const auto room = m_rooms.values()[index.parent().row()][index.row()].get();
|
|
||||||
Q_ASSERT(room);
|
|
||||||
|
|
||||||
if (role == DisplayNameRole) {
|
|
||||||
return room->displayName();
|
|
||||||
}
|
|
||||||
if (role == AvatarRole) {
|
|
||||||
return room->avatarMediaId();
|
|
||||||
}
|
|
||||||
if (role == CanonicalAliasRole) {
|
|
||||||
return room->canonicalAlias();
|
|
||||||
}
|
|
||||||
if (role == TopicRole) {
|
|
||||||
return room->topic();
|
|
||||||
}
|
|
||||||
if (role == CategoryRole) {
|
|
||||||
return NeoChatRoomType::typeForRoom(room);
|
|
||||||
}
|
|
||||||
if (role == ContextNotificationCountRole) {
|
|
||||||
return int(room->contextAwareNotificationCount());
|
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
return QVariant::fromValue(room->joinState());
|
|
||||||
}
|
|
||||||
if (role == CurrentRoomRole) {
|
|
||||||
return QVariant::fromValue(room);
|
|
||||||
}
|
|
||||||
if (role == SubtitleTextRole) {
|
|
||||||
if (room->lastEvent() == nullptr || room->lastEventIsSpoiler()) {
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
EventHandler eventHandler(room, room->lastEvent());
|
|
||||||
return eventHandler.subtitleText();
|
|
||||||
}
|
|
||||||
if (role == AvatarImageRole) {
|
|
||||||
return room->avatar(128);
|
|
||||||
}
|
|
||||||
if (role == RoomIdRole) {
|
|
||||||
return room->id();
|
|
||||||
}
|
|
||||||
if (role == IsSpaceRole) {
|
|
||||||
return room->isSpace();
|
|
||||||
}
|
|
||||||
if (role == IsChildSpaceRole) {
|
|
||||||
return SpaceHierarchyCache::instance().isChild(room->id());
|
|
||||||
}
|
|
||||||
if (role == ReplacementIdRole) {
|
|
||||||
return room->successorId();
|
|
||||||
}
|
|
||||||
if (role == IsDirectChat) {
|
|
||||||
return room->isDirectChat();
|
|
||||||
}
|
|
||||||
if (role == DelegateTypeRole) {
|
|
||||||
return QStringLiteral("normal");
|
|
||||||
}
|
|
||||||
if (role == AttentionRole) {
|
|
||||||
return room->notificationCount() + room->highlightCount() > 0;
|
|
||||||
}
|
|
||||||
if (role == FavouriteRole) {
|
|
||||||
return room->isFavourite();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex RoomTreeModel::indexForRoom(NeoChatRoom *room) const
|
QModelIndex RoomTreeModel::indexForRoom(NeoChatRoom *room) const
|
||||||
@@ -336,18 +411,18 @@ QModelIndex RoomTreeModel::indexForRoom(NeoChatRoom *room) const
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try and find by checking type.
|
const auto roomType = NeoChatRoomType::typeForRoom(room);
|
||||||
const auto type = NeoChatRoomType::typeForRoom(room);
|
const auto roomTypeItem = m_rootItem->child(roomType);
|
||||||
auto row = m_rooms[type].indexOf(room);
|
|
||||||
if (row >= 0) {
|
for (int i = 0, count = roomTypeItem->childCount(); i < count; i++) {
|
||||||
return index(row, 0, index(type, 0));
|
auto roomItem = roomTypeItem->child(i);
|
||||||
}
|
if (std::get<NeoChatRoom *>(roomItem->treeData()) == room) {
|
||||||
// Double check that the room isn't in the wrong category.
|
const auto parentIndex = index(roomType, 0, {});
|
||||||
for (const auto &key : m_rooms.keys()) {
|
const auto idx = index(i, 0, parentIndex);
|
||||||
if (m_rooms[key].contains(room)) {
|
return idx;
|
||||||
return index(m_rooms[key].indexOf(room), 0, index(key, 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,30 @@ class Room;
|
|||||||
class NeoChatConnection;
|
class NeoChatConnection;
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
|
||||||
|
class TreeItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TreeData = std::variant<NeoChatRoom *, NeoChatRoomType::Types>;
|
||||||
|
|
||||||
|
explicit TreeItem(TreeData data, TreeItem *parentItem = nullptr);
|
||||||
|
|
||||||
|
TreeItem *child(int row);
|
||||||
|
int childCount() const;
|
||||||
|
QVariant data(int role) const;
|
||||||
|
void appendChild(std::unique_ptr<TreeItem> &&child);
|
||||||
|
bool insertChildren(int position, int count, TreeData treeData);
|
||||||
|
TreeItem *parentItem() const;
|
||||||
|
bool removeChildren(int position, int count);
|
||||||
|
bool removeColumns(int position, int columns);
|
||||||
|
int row() const;
|
||||||
|
TreeData treeData() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::unique_ptr<TreeItem>> m_childItems;
|
||||||
|
TreeData m_treeData;
|
||||||
|
TreeItem *m_parentItem;
|
||||||
|
};
|
||||||
|
|
||||||
class RoomTreeModel : public QAbstractItemModel
|
class RoomTreeModel : public QAbstractItemModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -76,6 +100,8 @@ public:
|
|||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
TreeItem *getItem(const QModelIndex &index) const;
|
||||||
|
|
||||||
Q_INVOKABLE QModelIndex indexForRoom(NeoChatRoom *room) const;
|
Q_INVOKABLE QModelIndex indexForRoom(NeoChatRoom *room) const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
@@ -83,7 +109,6 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<NeoChatConnection> m_connection = nullptr;
|
QPointer<NeoChatConnection> m_connection = nullptr;
|
||||||
QMap<NeoChatRoomType::Types, QList<QPointer<NeoChatRoom>>> m_rooms;
|
|
||||||
|
|
||||||
void initializeCategories();
|
void initializeCategories();
|
||||||
void connectRoomSignals(NeoChatRoom *room);
|
void connectRoomSignals(NeoChatRoom *room);
|
||||||
@@ -93,4 +118,6 @@ private:
|
|||||||
void moveRoom(Quotient::Room *room);
|
void moveRoom(Quotient::Room *room);
|
||||||
|
|
||||||
void refreshRoomRoles(NeoChatRoom *room, const QList<int> &roles = {});
|
void refreshRoomRoles(NeoChatRoom *room, const QList<int> &roles = {});
|
||||||
|
|
||||||
|
std::unique_ptr<TreeItem> m_rootItem;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user