Have a working model for showing the namespaces in a tree with checkboxes.

The namespaces are currently spit into user and system. Later we might
add recognizing namespaces introduced by specific modules/extensions.
This commit is contained in:
eelke 2017-12-29 08:39:08 +01:00
parent 4e1120647c
commit b5254ac723
9 changed files with 414 additions and 5 deletions

View file

@ -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<const PgNamespaceContainer> nsc)
{
m_namespaceItemModel->init(nsc);
ui->treeView->expandAll();
}
std::set<Oid> NamespaceFilterWidget::getCheckedNamespaces() const
{
return m_namespaceItemModel->getCheckedNamespaces();
}

View file

@ -0,0 +1,35 @@
#ifndef NAMESPACEFILTERWIDGET_H
#define NAMESPACEFILTERWIDGET_H
#include <QWidget>
#include <memory>
#include <set>
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<const PgNamespaceContainer> nsc);
std::set<Oid> getCheckedNamespaces() const;
//signals:
// void onFilterChange();
private:
Ui::NamespaceFilterWidget *ui;
NamespaceItemModel *m_namespaceItemModel = nullptr;
};
#endif // NAMESPACEFILTERWIDGET_H

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NamespaceFilterWidget</class>
<widget class="QWidget" name="NamespaceFilterWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>698</width>
<height>611</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget" native="true"/>
</item>
<item>
<widget class="QTreeView" name="treeView">
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View file

@ -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<const PgNamespaceContainer> ns)
{
beginResetModel();
SCOPE_EXIT { endResetModel(); };
auto system = std::make_shared<GroupNode>("System");
auto user = std::make_shared<GroupNode>("User");
groups = { system, user };
for (const auto e : *ns)
if (e.isSystemCatalog())
system->leaves.push_back(std::make_shared<LeafNode>(system, e));
else
user->leaves.push_back(std::make_shared<LeafNode>(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<GroupNode*>(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<Node*>(index.internalPointer());
LeafNode *ln = dynamic_cast<LeafNode*>(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<Node*>(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<Node*>(index.internalPointer());
LeafNode *leaf = dynamic_cast<LeafNode*>(n);
if (role == Qt::DisplayRole) {
if (leaf) {
v = leaf->ns.name;
}
else {
GroupNode *grp = dynamic_cast<GroupNode*>(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<Node*>(index.internalPointer());
LeafNode *leaf = dynamic_cast<LeafNode*>(n);
if (leaf) {
leaf->checked = value == Qt::Checked;
emit dataChanged(index, index);
emit dataChanged(index.parent(), index.parent());
}
else {
GroupNode *gn = dynamic_cast<GroupNode*>(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<Node*>(index.internalPointer());
// LeafNode *leaf = dynamic_cast<LeafNode*>(n);
// if (leaf) {
flags.setFlag(Qt::ItemIsUserCheckable);
// }
// else {
// flags.setFlag(Qt::ItemIsAutoTristate);
// }
return flags;
}
//std::set<Oid> NamespaceItemModel::getCheckedNamespaces() const
//{
// std::set<Oid> result;
// for (auto g : groups)
// for (auto l : g->leaves)
// if (l->checked)
// result.insert(l->ns.oid);
// return result;
//}

126
pglab/NamespaceItemModel.h Normal file
View file

@ -0,0 +1,126 @@
#ifndef NAMESPACEITEMMODEL_H
#define NAMESPACEITEMMODEL_H
#include <QAbstractItemModel>
#include "PgNamespace.h"
#include <vector>
class PgNamespaceContainer;
class NamespaceItemModel: public QAbstractItemModel {
public:
NamespaceItemModel(QObject *parent = 0);
void init(std::shared_ptr<const PgNamespaceContainer> 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<Oid> getCheckedNamespaces() const;
private:
// using NsVec = std::vector<PgNamespace>;
// class Group {
// public:
// QString name;
// NsVec namespaces;
// };
// using GrpVec = std::vector<Group>;
// //std::shared_ptr<const PgNamespaceContainer> 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<GroupNode> parent;
bool checked = false;
PgNamespace ns;
LeafNode(std::weak_ptr<GroupNode> 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<std::shared_ptr<LeafNode>>;
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<std::shared_ptr<GroupNode>>;
GroupVec groups;
};
#endif // NAMESPACEITEMMODEL_H

View file

@ -2,9 +2,11 @@
#include "ui_TablesPage.h" #include "ui_TablesPage.h"
#include "PgAttribute.h" #include "PgAttribute.h"
#include "PgDatabaseCatalog.h"
#include "TablesTableModel.h" #include "TablesTableModel.h"
#include "ResultTableModelUtil.h" #include "ResultTableModelUtil.h"
#include "ColumnTableModel.h" #include "ColumnTableModel.h"
#include "NamespaceFilterWidget.h"
TablesPage::TablesPage(QWidget *parent) : TablesPage::TablesPage(QWidget *parent) :
QWidget(parent), QWidget(parent),
@ -20,6 +22,10 @@ TablesPage::TablesPage(QWidget *parent) :
m_columnsModel = new ColumnTableModel(this); m_columnsModel = new ColumnTableModel(this);
ui->columnsTable->setModel(m_columnsModel); ui->columnsTable->setModel(m_columnsModel);
m_namespaceFilterWidget = new NamespaceFilterWidget(this);
ui->verticalLayoutTableView->addWidget(m_namespaceFilterWidget);
connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this, connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
&TablesPage::on_tableListTable_currentRowChanged); &TablesPage::on_tableListTable_currentRowChanged);
@ -35,6 +41,7 @@ void TablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
m_catalog = cat; m_catalog = cat;
m_tablesModel->setCatalog(cat); m_tablesModel->setCatalog(cat);
ui->tableListTable->resizeColumnsToContents(); ui->tableListTable->resizeColumnsToContents();
m_namespaceFilterWidget->init(cat->namespaces());
} }
void TablesPage::on_tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous) void TablesPage::on_tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)

View file

@ -11,6 +11,7 @@ class TablesPage;
class TablesTableModel; class TablesTableModel;
class ColumnTableModel; class ColumnTableModel;
class PgDatabaseCatalog; class PgDatabaseCatalog;
class NamespaceFilterWidget;
class TablesPage : public QWidget class TablesPage : public QWidget
{ {
@ -26,6 +27,7 @@ private:
std::shared_ptr<PgDatabaseCatalog> m_catalog; std::shared_ptr<PgDatabaseCatalog> m_catalog;
TablesTableModel* m_tablesModel = nullptr; TablesTableModel* m_tablesModel = nullptr;
ColumnTableModel* m_columnsModel = nullptr; ColumnTableModel* m_columnsModel = nullptr;
NamespaceFilterWidget* m_namespaceFilterWidget;
private slots: private slots:

View file

@ -19,8 +19,8 @@
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<widget class="QWidget" name=""> <widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayoutTableView">
<item> <item>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">

View file

@ -83,7 +83,9 @@ SOURCES += main.cpp\
PgIndex.cpp \ PgIndex.cpp \
PgIndexContainer.cpp \ PgIndexContainer.cpp \
PgConstraint.cpp \ PgConstraint.cpp \
PgConstraintContainer.cpp PgConstraintContainer.cpp \
NamespaceFilterWidget.cpp \
NamespaceItemModel.cpp
HEADERS += \ HEADERS += \
QueryResultModel.h \ QueryResultModel.h \
@ -138,7 +140,9 @@ HEADERS += \
PgIndex.h \ PgIndex.h \
PgIndexContainer.h \ PgIndexContainer.h \
PgConstraint.h \ PgConstraint.h \
PgConstraintContainer.h PgConstraintContainer.h \
NamespaceFilterWidget.h \
NamespaceItemModel.h
FORMS += mainwindow.ui \ FORMS += mainwindow.ui \
DatabaseWindow.ui \ DatabaseWindow.ui \
@ -150,7 +154,8 @@ FORMS += mainwindow.ui \
BackupDialog.ui \ BackupDialog.ui \
ServerWindow.ui \ ServerWindow.ui \
ProcessStdioWidget.ui \ ProcessStdioWidget.ui \
TablesPage.ui TablesPage.ui \
NamespaceFilterWidget.ui
RESOURCES += \ RESOURCES += \
resources.qrc resources.qrc