File indexing completed on 2024-05-12 05:02:03

0001 /*
0002    SPDX-FileCopyrightText: 2020 Olivier de Gaalon <olivier.jg@gmail.com>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "accountschannelsmodel.h"
0008 
0009 #include "accountmanager.h"
0010 #include "rocketchataccount.h"
0011 #include "rocketchataccountfilterproxymodel.h"
0012 #include "rocketchataccountmodel.h"
0013 #include "ruqola.h"
0014 
0015 AccountsChannelsModel::AccountsChannelsModel(QObject *parent)
0016     : QAbstractItemModel(parent)
0017 {
0018     auto accountManager = Ruqola::self()->accountManager();
0019     const auto src = accountManager->rocketChatAccountModel();
0020     const auto acctsProxy = accountManager->rocketChatAccountProxyModel();
0021 
0022     auto roomsModel = [src, acctsProxy](int i) {
0023         const auto acctIndex = acctsProxy->mapToSource(acctsProxy->index(i, 0)).row();
0024         return src->account(acctIndex)->roomModel();
0025     };
0026 
0027     auto mapRoomsModel = [roomsModel, acctsProxy, this](int roomsModelIndex) {
0028         auto rooms = roomsModel(roomsModelIndex);
0029         mapModelToIndex(rooms, [roomsModel, acctsProxy, rooms, this] {
0030             for (int i = 0, count = acctsProxy->rowCount(); i < count; ++i) {
0031                 if (roomsModel(i) == rooms) {
0032                     return index(i, 0);
0033                 }
0034             }
0035             return QModelIndex();
0036         });
0037     };
0038 
0039     connect(acctsProxy, &QAbstractItemModel::rowsInserted, this, [mapRoomsModel](const QModelIndex &, int first, int last) {
0040         for (int i = first; i <= last; ++i) {
0041             mapRoomsModel(i);
0042         }
0043     });
0044 
0045     connect(acctsProxy, &QAbstractItemModel::rowsAboutToBeRemoved, this, [roomsModel, this](const QModelIndex &, int first, int last) {
0046         for (int i = first; i <= last; ++i) {
0047             unproxyModel(roomsModel(i));
0048         }
0049     });
0050 
0051     connect(acctsProxy, &QAbstractItemModel::modelReset, this, [mapRoomsModel, acctsProxy, this]() {
0052         while (!mProxied.isEmpty()) {
0053             unproxyModel(mProxied.begin()->model);
0054         }
0055         for (int i = 0, count = acctsProxy->rowCount(); i < count; ++i) {
0056             mapRoomsModel(i);
0057         }
0058     });
0059 
0060     mapModelToIndex(acctsProxy, [] {
0061         return QModelIndex();
0062     });
0063     for (int i = 0, count = acctsProxy->rowCount(); i < count; ++i) {
0064         mapRoomsModel(i);
0065     }
0066 }
0067 
0068 AccountsChannelsModel::~AccountsChannelsModel() = default;
0069 
0070 QModelIndex AccountsChannelsModel::index(int row, int column, const QModelIndex &parent) const
0071 {
0072     if (auto model = rootModel(parent)) {
0073         return createIndex(row, column, model);
0074     }
0075     return {};
0076 }
0077 
0078 QModelIndex AccountsChannelsModel::parent(const QModelIndex &child) const
0079 {
0080     if (!child.isValid()) {
0081         return {};
0082     }
0083 
0084     if (auto model = static_cast<QAbstractItemModel *>(child.internalPointer())) {
0085         return modelRoot(model);
0086     }
0087 
0088     return {};
0089 }
0090 
0091 int AccountsChannelsModel::rowCount(const QModelIndex &parent) const
0092 {
0093     if (auto model = rootModel(parent)) {
0094         return model->rowCount();
0095     }
0096     return 0;
0097 }
0098 
0099 int AccountsChannelsModel::columnCount(const QModelIndex &) const
0100 {
0101     return 1;
0102 }
0103 
0104 QVariant AccountsChannelsModel::data(const QModelIndex &index, int role) const
0105 {
0106     if (!index.isValid()) {
0107         return {};
0108     }
0109 
0110     const auto model = static_cast<QAbstractItemModel *>(index.internalPointer());
0111     if (!model) {
0112         return {};
0113     }
0114 
0115     return model->index(index.row(), index.column()).data(role);
0116 }
0117 
0118 QModelIndex AccountsChannelsModel::modelRoot(QAbstractItemModel *model) const
0119 {
0120     const auto find = [model](const ProxyIndex &i) {
0121         return i.model == model;
0122     };
0123     const auto it = std::find_if(mProxied.begin(), mProxied.end(), find);
0124     return (it == mProxied.end()) ? QModelIndex() : it->root();
0125 }
0126 
0127 QAbstractItemModel *AccountsChannelsModel::rootModel(const QModelIndex &root) const
0128 {
0129     const auto find = [&root](const ProxyIndex &i) {
0130         return i.root() == root;
0131     };
0132     const auto it = std::find_if(mProxied.begin(), mProxied.end(), find);
0133     return (it == mProxied.end()) ? nullptr : it->model;
0134 }
0135 
0136 void AccountsChannelsModel::mapModelToIndex(QAbstractItemModel *model, const std::function<QModelIndex()> &root)
0137 {
0138     connect(model, &QAbstractItemModel::rowsAboutToBeInserted, this, [this, model](const QModelIndex &parent, int first, int last) {
0139         Q_ASSERT(!parent.isValid());
0140         beginInsertRows(modelRoot(model), first, last);
0141     });
0142     connect(model, &QAbstractItemModel::rowsInserted, this, &AccountsChannelsModel::endInsertRows);
0143 
0144     connect(model, &QAbstractItemModel::rowsAboutToBeRemoved, this, [this, model](const QModelIndex &parent, int first, int last) {
0145         Q_ASSERT(!parent.isValid());
0146         beginRemoveRows(modelRoot(model), first, last);
0147     });
0148     connect(model, &QAbstractItemModel::rowsRemoved, this, &AccountsChannelsModel::endRemoveRows);
0149 
0150     connect(model, &QAbstractItemModel::rowsAboutToBeMoved, this, [this, model](const QModelIndex &src, int sf, int sl, const QModelIndex &dst, int df) {
0151         Q_ASSERT(!src.isValid() && !dst.isValid());
0152         const auto idx = modelRoot(model);
0153         beginMoveRows(idx, sf, sl, idx, df);
0154     });
0155     connect(model, &QAbstractItemModel::rowsMoved, this, &AccountsChannelsModel::endMoveRows);
0156 
0157     connect(model, &QAbstractItemModel::modelAboutToBeReset, this, &AccountsChannelsModel::beginResetModel);
0158     connect(model, &QAbstractItemModel::modelReset, this, &AccountsChannelsModel::endResetModel);
0159 
0160     connect(model, &QAbstractItemModel::layoutAboutToBeChanged, this, &AccountsChannelsModel::layoutAboutToBeChanged);
0161     connect(model, &QAbstractItemModel::layoutChanged, this, &AccountsChannelsModel::layoutChanged);
0162 
0163     connect(model, &QAbstractItemModel::dataChanged, this, [this, model](const QModelIndex &tl, const QModelIndex &br) {
0164         const auto parent = modelRoot(model);
0165         Q_EMIT dataChanged(index(tl.row(), tl.column(), parent), index(br.row(), br.column(), parent));
0166     });
0167 
0168     mProxied.append({model, root});
0169 }
0170 
0171 void AccountsChannelsModel::unproxyModel(QAbstractItemModel *model)
0172 {
0173     const auto find = [model](const ProxyIndex &i) {
0174         return i.model == model;
0175     };
0176     const auto it = std::find_if(mProxied.begin(), mProxied.end(), find);
0177     if (it != mProxied.end()) {
0178         model->disconnect(this);
0179         mProxied.erase(it);
0180     }
0181 }