#include "NamespaceItemModel.h" #include "catalog/PgNamespace.h" #include "catalog/PgNamespaceContainer.h" #include "ScopeGuard.h" namespace NamespaceItemModel_impl { class Node { public: virtual ~Node() = default; virtual int getRowCount() const = 0; virtual Qt::CheckState getCheckState() const = 0; virtual void setChecked(NamespaceItemModel *model, const QModelIndex &index, bool checked) = 0; virtual QVariant data(const QModelIndex &index, int role) const = 0; virtual int columnCount() const = 0; }; class GroupNode; class LeafNode: public Node { public: std::weak_ptr parent; bool checked = false; PgNamespace ns; LeafNode(std::weak_ptr p, const PgNamespace &nspace) : parent(p) , ns(nspace) {} int getRowCount() const override { return 0; } Qt::CheckState getCheckState() const override { return checked ? Qt::Checked : Qt::Unchecked; } void setChecked(NamespaceItemModel *model, const QModelIndex &index, bool chk) override { checked = chk; emit model->dataChanged(index, index); emit model->dataChanged(index.parent(), index.parent()); } QVariant data(const QModelIndex &index, int role) const override { QVariant v; if (role == Qt::DisplayRole) { switch (index.column()) { case NamespaceItemModel::ColNamespaceName: return ns.objectName(); case NamespaceItemModel::ColOwner: return ns.ownerName(); case NamespaceItemModel::ColAcl: return ns.aclString(); } } else if (role == Qt::CheckStateRole) { if (index.column() == 0) return getCheckState(); } return {}; } int columnCount() const override { return NamespaceItemModel::ColCount; } bool operator < (const LeafNode &rhs) const { return ns.objectName() < rhs.ns.objectName(); } }; class GroupNode: public Node { public: using LeafVec = QVector>; QString name; LeafVec leaves; GroupNode(QString n) : name(n) {} int getRowCount() const override { return leaves.size(); } void sortLeaves() { std::sort(leaves.begin(), leaves.end(), [] (auto l, auto r) -> bool { return *l < *r; }); } Qt::CheckState getCheckState() const override { bool some_checked = false; bool some_unchecked = false; for (auto&& l : leaves) { if (l->checked) some_checked = true; else some_unchecked = true; } Qt::CheckState result; if (some_checked && some_unchecked) result = Qt::PartiallyChecked; else if (some_checked) result = Qt::Checked; else result = Qt::Unchecked; return result; } void setChecked(NamespaceItemModel *model, const QModelIndex &index, bool chk) override { if (chk) for (auto&& l : leaves) l->checked = true; if (!chk) for (auto&& l : leaves) l->checked = false; emit model->dataChanged(index, index); emit model->dataChanged(model->index(0, 0, index), model->index(leaves.size(), 0, index)); } QVariant data(const QModelIndex &index, int role) const override { QVariant v; if (role == Qt::DisplayRole) { switch (index.column()) { case NamespaceItemModel::ColNamespaceName: return name; } } else if(role == Qt::CheckStateRole) { if (index.column() == 0) return getCheckState(); } return {}; } int columnCount() const override { return 1; } }; } // end of NamespaceItemModel_impl using namespace NamespaceItemModel_impl; NamespaceItemModel::NamespaceItemModel(QObject *parent) : QAbstractItemModel(parent) { } void NamespaceItemModel::init(std::shared_ptr ns) { beginResetModel(); SCOPE_EXIT { endResetModel(); }; auto system = std::make_shared("System"); auto user = std::make_shared("User"); groups = { system, user }; for (auto&& e : *ns) if (e.isSystemCatalog()) system->leaves.push_back(std::make_shared(system, e)); else user->leaves.push_back(std::make_shared(user, e)); system->sortLeaves(); user->sortLeaves(); for (auto&& e : user->leaves) e->checked = true; } void NamespaceItemModel::setEnableCheckboxes(bool enable) { if (m_enableCheckboxes != enable) { beginResetModel(); SCOPE_EXIT { endResetModel(); }; m_enableCheckboxes = enable; } } bool NamespaceItemModel::isEnableCheckboxes() const { return m_enableCheckboxes; } QModelIndex NamespaceItemModel::index(int row, int column, const QModelIndex &parent) const { QModelIndex result; if (hasIndex(row, column, parent)) { // We only have two levels, the groups and the namespaces if (parent.isValid()) { // namespace level auto grp = static_cast(parent.internalPointer()); result = createIndex(row, column, grp->leaves[row].get()); } else { // toplevel (groups) const auto grp = groups[row]; result = createIndex(row, column, grp.get()); } } return result; } QModelIndex NamespaceItemModel::parent(const QModelIndex &index) const { QModelIndex result; if (index.isValid()) { auto n = static_cast(index.internalPointer()); auto ln = dynamic_cast(n); if (ln) { // leafnode auto grp = ln->parent.lock(); // Get the parent group // auto fr = std::find(groups.begin(), groups.end(), grp); // find it in the list // int row = fr - groups.begin(); // calculate index ie row int row = groups.indexOf(grp); result = createIndex(row, 0, grp.get()); // return index } } return result; } int NamespaceItemModel::rowCount(const QModelIndex &parent) const { int count = 0; if (parent.isValid() && parent.column() <= 0) { auto node = static_cast(parent.internalPointer()); count = node->getRowCount(); } else { count = groups.size(); } return count; } int NamespaceItemModel::columnCount(const QModelIndex &/*index*/) const { // if (index.isValid()) { // auto *n = static_cast(index.internalPointer()); // return n->columnCount(); // } return ColCount; } QVariant NamespaceItemModel::data(const QModelIndex &index, int role) const { QVariant v; auto *n = static_cast(index.internalPointer()); v = n->data(index, role); return v; } bool NamespaceItemModel::setData(const QModelIndex &index, const QVariant &value, int role) { if(!index.isValid() || role != Qt::CheckStateRole) return false; auto *n = static_cast(index.internalPointer()); if (index.column() == 0) n->setChecked(this, index, value == Qt::Checked); return true; } Qt::ItemFlags NamespaceItemModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = QAbstractItemModel::flags(index); if (index.column() == 0 && m_enableCheckboxes) flags.setFlag(Qt::ItemIsUserCheckable); return flags; } QVariant NamespaceItemModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { if (role == Qt::DisplayRole) { switch (section) { case ColNamespaceName: return tr("Name"); case ColOwner: return tr("Owner"); case ColAcl: return tr("ACL"); } } } return {}; }