diff --git a/pglab/NamespaceFilterWidget.cpp b/pglab/NamespaceFilterWidget.cpp new file mode 100644 index 0000000..848d1e5 --- /dev/null +++ b/pglab/NamespaceFilterWidget.cpp @@ -0,0 +1,32 @@ +#include "NamespaceFilterWidget.h" +#include "ui_NamespaceFilterWidget.h" + +#include "NamespaceItemModel.h" + +NamespaceFilterWidget::NamespaceFilterWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::NamespaceFilterWidget) +{ + ui->setupUi(this); + + m_namespaceItemModel = new NamespaceItemModel(this); + ui->treeView->setModel(m_namespaceItemModel); + //ui->treeView->setModelColumn(0); +} + +NamespaceFilterWidget::~NamespaceFilterWidget() +{ + delete ui; +} + +void NamespaceFilterWidget::init(std::shared_ptr nsc) +{ + m_namespaceItemModel->init(nsc); + ui->treeView->expandAll(); +} + +std::set NamespaceFilterWidget::getCheckedNamespaces() const +{ + return m_namespaceItemModel->getCheckedNamespaces(); +} + diff --git a/pglab/NamespaceFilterWidget.h b/pglab/NamespaceFilterWidget.h new file mode 100644 index 0000000..bc73f22 --- /dev/null +++ b/pglab/NamespaceFilterWidget.h @@ -0,0 +1,35 @@ +#ifndef NAMESPACEFILTERWIDGET_H +#define NAMESPACEFILTERWIDGET_H + +#include +#include +#include + +namespace Ui { + class NamespaceFilterWidget; +} + +class NamespaceItemModel; +class PgNamespaceContainer; + +class NamespaceFilterWidget : public QWidget +{ + Q_OBJECT + +public: + explicit NamespaceFilterWidget(QWidget *parent = 0); + ~NamespaceFilterWidget(); + + void init(std::shared_ptr nsc); + + std::set getCheckedNamespaces() const; + +//signals: +// void onFilterChange(); + +private: + Ui::NamespaceFilterWidget *ui; + NamespaceItemModel *m_namespaceItemModel = nullptr; +}; + +#endif // NAMESPACEFILTERWIDGET_H diff --git a/pglab/NamespaceFilterWidget.ui b/pglab/NamespaceFilterWidget.ui new file mode 100644 index 0000000..bd221d7 --- /dev/null +++ b/pglab/NamespaceFilterWidget.ui @@ -0,0 +1,31 @@ + + + NamespaceFilterWidget + + + + 0 + 0 + 698 + 611 + + + + Form + + + + + + + + + false + + + + + + + + diff --git a/pglab/NamespaceItemModel.cpp b/pglab/NamespaceItemModel.cpp new file mode 100644 index 0000000..f57f5a8 --- /dev/null +++ b/pglab/NamespaceItemModel.cpp @@ -0,0 +1,171 @@ +#include "NamespaceItemModel.h" +#include "PgNamespace.h" +#include "PgNamespaceContainer.h" +#include "ScopeGuard.h" + +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 (const 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; +} + +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()); + LeafNode *ln = dynamic_cast(n); + if (ln) { // leftnode + 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 + 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 &parent) const +{ + return 1; +} + +QVariant NamespaceItemModel::data(const QModelIndex &index, int role) const +{ + QVariant v; + auto *n = static_cast(index.internalPointer()); + LeafNode *leaf = dynamic_cast(n); + if (role == Qt::DisplayRole) { + if (leaf) { + v = leaf->ns.name; + } + else { + GroupNode *grp = dynamic_cast(n); + if (grp) { + v = grp->name; + } + } + } + else if(role == Qt::CheckStateRole) { + //return checkedItems.contains(index) ? + // Qt::Checked : Qt::Unchecked; + if (n) + v = n->getCheckState(); + } + 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()); + LeafNode *leaf = dynamic_cast(n); + if (leaf) { + leaf->checked = value == Qt::Checked; + emit dataChanged(index, index); + emit dataChanged(index.parent(), index.parent()); + } + else { + GroupNode *gn = dynamic_cast(n); + if (gn) { + if (value == Qt::Checked) + for (auto l : gn->leaves) + l->checked = true; + if (value == Qt::Unchecked) + for (auto l : gn->leaves) + l->checked = false; + emit dataChanged(index, index); + emit dataChanged(this->index(0, 0, index), this->index(gn->leaves.size(), 0, index)); + } + + } +// if(value == Qt::Checked) +// checkedItems.insert(index); +// else +// checkedItems.remove(index); + + return true; +} + +Qt::ItemFlags NamespaceItemModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags = QAbstractItemModel::flags(index); + auto *n = static_cast(index.internalPointer()); +// LeafNode *leaf = dynamic_cast(n); +// if (leaf) { + flags.setFlag(Qt::ItemIsUserCheckable); +// } +// else { +// flags.setFlag(Qt::ItemIsAutoTristate); +// } + return flags; +} + +//std::set NamespaceItemModel::getCheckedNamespaces() const +//{ +// std::set result; +// for (auto g : groups) +// for (auto l : g->leaves) +// if (l->checked) +// result.insert(l->ns.oid); + +// return result; +//} diff --git a/pglab/NamespaceItemModel.h b/pglab/NamespaceItemModel.h new file mode 100644 index 0000000..81515dc --- /dev/null +++ b/pglab/NamespaceItemModel.h @@ -0,0 +1,126 @@ +#ifndef NAMESPACEITEMMODEL_H +#define NAMESPACEITEMMODEL_H + +#include +#include "PgNamespace.h" +#include + +class PgNamespaceContainer; + +class NamespaceItemModel: public QAbstractItemModel { +public: + NamespaceItemModel(QObject *parent = 0); + + void init(std::shared_ptr ns); + + virtual QModelIndex index(int row, int column, + const QModelIndex &parent = QModelIndex()) const override; + virtual QModelIndex parent(const QModelIndex &index) const override; + + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role) override; + virtual Qt::ItemFlags flags(const QModelIndex &index) const override; + + //std::set getCheckedNamespaces() const; + +private: +// using NsVec = std::vector; + +// class Group { +// public: +// QString name; +// NsVec namespaces; +// }; +// using GrpVec = std::vector; + +// //std::shared_ptr m_namespaces; +// GrpVec groups; + + + class Node { + public: + + virtual ~Node() {} + virtual int getRowCount() const = 0; + virtual Qt::CheckState getCheckState() 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) + {} + + virtual int getRowCount() const override + { + return 0; + } + + virtual Qt::CheckState getCheckState() const override + { + return checked ? Qt::Checked : Qt::Unchecked; + } + + bool operator < (const LeafNode &rhs) const + { + return ns.name < rhs.ns.name; + } + }; + + class GroupNode: public Node { + public: + using LeafVec = std::vector>; + + QString name; + LeafVec leaves; + + GroupNode(QString n) + : name(n) + {} + virtual int getRowCount() const override + { + return leaves.size(); + } + void sortLeaves() + { + std::sort(leaves.begin(), leaves.end(), + [] (auto l, auto r) -> bool { return *l < *r; }); + } + virtual 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; + } + }; + + using GroupVec = std::vector>; + + GroupVec groups; + +}; + +#endif // NAMESPACEITEMMODEL_H diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index 0f24a2f..7595664 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -2,9 +2,11 @@ #include "ui_TablesPage.h" #include "PgAttribute.h" +#include "PgDatabaseCatalog.h" #include "TablesTableModel.h" #include "ResultTableModelUtil.h" #include "ColumnTableModel.h" +#include "NamespaceFilterWidget.h" TablesPage::TablesPage(QWidget *parent) : QWidget(parent), @@ -20,6 +22,10 @@ TablesPage::TablesPage(QWidget *parent) : m_columnsModel = new ColumnTableModel(this); ui->columnsTable->setModel(m_columnsModel); + m_namespaceFilterWidget = new NamespaceFilterWidget(this); + ui->verticalLayoutTableView->addWidget(m_namespaceFilterWidget); + + connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &TablesPage::on_tableListTable_currentRowChanged); @@ -35,6 +41,7 @@ void TablesPage::setCatalog(std::shared_ptr cat) m_catalog = cat; m_tablesModel->setCatalog(cat); ui->tableListTable->resizeColumnsToContents(); + m_namespaceFilterWidget->init(cat->namespaces()); } void TablesPage::on_tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous) diff --git a/pglab/TablesPage.h b/pglab/TablesPage.h index 0cee048..c0ba1bf 100644 --- a/pglab/TablesPage.h +++ b/pglab/TablesPage.h @@ -11,6 +11,7 @@ class TablesPage; class TablesTableModel; class ColumnTableModel; class PgDatabaseCatalog; +class NamespaceFilterWidget; class TablesPage : public QWidget { @@ -26,6 +27,7 @@ private: std::shared_ptr m_catalog; TablesTableModel* m_tablesModel = nullptr; ColumnTableModel* m_columnsModel = nullptr; + NamespaceFilterWidget* m_namespaceFilterWidget; private slots: diff --git a/pglab/TablesPage.ui b/pglab/TablesPage.ui index fd081dc..df90551 100644 --- a/pglab/TablesPage.ui +++ b/pglab/TablesPage.ui @@ -19,8 +19,8 @@ Qt::Horizontal - - + + diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 9ac795a..4ec79d0 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -83,7 +83,9 @@ SOURCES += main.cpp\ PgIndex.cpp \ PgIndexContainer.cpp \ PgConstraint.cpp \ - PgConstraintContainer.cpp + PgConstraintContainer.cpp \ + NamespaceFilterWidget.cpp \ + NamespaceItemModel.cpp HEADERS += \ QueryResultModel.h \ @@ -138,7 +140,9 @@ HEADERS += \ PgIndex.h \ PgIndexContainer.h \ PgConstraint.h \ - PgConstraintContainer.h + PgConstraintContainer.h \ + NamespaceFilterWidget.h \ + NamespaceItemModel.h FORMS += mainwindow.ui \ DatabaseWindow.ui \ @@ -150,7 +154,8 @@ FORMS += mainwindow.ui \ BackupDialog.ui \ ServerWindow.ui \ ProcessStdioWidget.ui \ - TablesPage.ui + TablesPage.ui \ + NamespaceFilterWidget.ui RESOURCES += \ resources.qrc