From 68a1a8e7c964c1630a6efc1f83dddf94d4e95300 Mon Sep 17 00:00:00 2001 From: eelke Date: Sat, 25 Aug 2018 18:14:08 +0200 Subject: [PATCH 1/9] Addded HorizontalProxyModel which is used to effictively rotate a table 90 degrees. --- pglab/HorizontalProxyModel.cpp | 56 ++++++++++++++++++++++++++++++++++ pglab/HorizontalProxyModel.h | 18 +++++++++++ pglab/pglab.pro | 6 ++-- 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 pglab/HorizontalProxyModel.cpp create mode 100644 pglab/HorizontalProxyModel.h diff --git a/pglab/HorizontalProxyModel.cpp b/pglab/HorizontalProxyModel.cpp new file mode 100644 index 0000000..e11c41b --- /dev/null +++ b/pglab/HorizontalProxyModel.cpp @@ -0,0 +1,56 @@ +#include "HorizontalProxyModel.h" +/* + * Code borrowed from: https://stackoverflow.com/questions/21653253/how-to-change-orientation-of-qt-tableview + */ + + +HorizontalProxyModel::HorizontalProxyModel(QObject *parent) + : QAbstractProxyModel(parent) +{ +} + +QModelIndex HorizontalProxyModel::mapToSource(const QModelIndex &proxyIndex) const +{ + if (sourceModel()) { + return sourceModel()->index(proxyIndex.column(), proxyIndex.row()); + } + else { + return QModelIndex(); + } +} + +QModelIndex HorizontalProxyModel::mapFromSource(const QModelIndex &sourceIndex) const +{ + return index(sourceIndex.column(), sourceIndex.row()); +} + +QModelIndex HorizontalProxyModel::index(int row, int column, const QModelIndex &) const +{ + return createIndex(row, column, nullptr); +} + +QModelIndex HorizontalProxyModel::parent(const QModelIndex &) const +{ + return QModelIndex(); +} + +int HorizontalProxyModel::rowCount(const QModelIndex &) const +{ + return sourceModel() ? sourceModel()->columnCount() : 0; +} + +int HorizontalProxyModel::columnCount(const QModelIndex &) const +{ + return sourceModel() ? sourceModel()->rowCount() : 0; +} + +QVariant HorizontalProxyModel::headerData( + int section, Qt::Orientation orientation, int role) const +{ + if (!sourceModel()) { + return QVariant(); + } + Qt::Orientation new_orientation = orientation == Qt::Horizontal ? + Qt::Vertical : Qt::Horizontal; + return sourceModel()->headerData(section, new_orientation, role); +} diff --git a/pglab/HorizontalProxyModel.h b/pglab/HorizontalProxyModel.h new file mode 100644 index 0000000..2e073c9 --- /dev/null +++ b/pglab/HorizontalProxyModel.h @@ -0,0 +1,18 @@ +#ifndef HORIZONTALPROXYMODEL_H +#define HORIZONTALPROXYMODEL_H + +#include + +class HorizontalProxyModel : public QAbstractProxyModel { +public: + HorizontalProxyModel(QObject * parent = nullptr); + QModelIndex mapToSource(const QModelIndex &proxyIndex) const; + QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; +}; + +#endif // HORIZONTALPROXYMODEL_H diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 3058c10..52a6b07 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -73,7 +73,8 @@ SOURCES += main.cpp\ Module.cpp \ EditorGutter.cpp \ CodeEditor.cpp \ - PlgPage.cpp + PlgPage.cpp \ + HorizontalProxyModel.cpp HEADERS += \ QueryResultModel.h \ @@ -119,7 +120,8 @@ HEADERS += \ EditorGutter.h \ CodeEditor.h \ PlgPage.h \ - AbstractCommand.h + AbstractCommand.h \ + HorizontalProxyModel.h FORMS += mainwindow.ui \ ConnectionManagerWindow.ui \ -- 2.47.2 From 49f009bdf9674c876e9e2143f3fafbff911f6412 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 26 Aug 2018 07:08:44 +0200 Subject: [PATCH 2/9] Fix two warnings + some documentation in comment --- pglab/PgLabItemDelegate.cpp | 4 ++-- pglab/PgLabItemDelegate.h | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pglab/PgLabItemDelegate.cpp b/pglab/PgLabItemDelegate.cpp index 0806003..73ea803 100644 --- a/pglab/PgLabItemDelegate.cpp +++ b/pglab/PgLabItemDelegate.cpp @@ -83,7 +83,7 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option, Oid oid = InvalidOid; value = index.data(Qt::UserRole); // get OID if (value.isValid()) - oid = value.toInt(); //getType(index.column()); + oid = value.toUInt(); //getType(index.column()); value = index.data(Qt::DisplayRole); @@ -112,7 +112,7 @@ void PgLabItemDelegate::initStyleOption(QStyleOptionViewItem *option, // option->backgroundBrush = qvariant_cast(index.data(Qt::BackgroundRole)); // disable style animations for checkboxes etc. within itemviews (QTBUG-30146) - option->styleObject = 0; + option->styleObject = nullptr; } void PgLabItemDelegate::paint(QPainter *painter, diff --git a/pglab/PgLabItemDelegate.h b/pglab/PgLabItemDelegate.h index a1322cc..d11701b 100644 --- a/pglab/PgLabItemDelegate.h +++ b/pglab/PgLabItemDelegate.h @@ -3,6 +3,12 @@ #include +/** Delegate for rendering SQL data types in tableviews + * + * This delegate removes the need for the model to provide formatting information + * which in many cases solely based on the datatype so this delegate can determine + * on its own what the correct formatting is. + */ class PgLabItemDelegate : public QStyledItemDelegate { public: -- 2.47.2 From 3080523b0d6b58fbd588fa4e887e4c9ce4eea8c2 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 26 Aug 2018 07:11:46 +0200 Subject: [PATCH 3/9] First step in using HorizontalProxyModel to show selected row in properties table. HorizontalProxyModel now inherits from QIdentityProxyModel which provides a more complete base implementation (maybe to much?) for now it seems to do what we want, forward relevant signals which the abstract base didn't. Issues: Properties table needs formatting and shows all rows as columns instead of values of a single row. --- pglab/HorizontalProxyModel.cpp | 2 +- pglab/HorizontalProxyModel.h | 4 ++-- pglab/TablesPage.cpp | 6 +++++- pglab/TablesPage.ui | 11 ++++++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/pglab/HorizontalProxyModel.cpp b/pglab/HorizontalProxyModel.cpp index e11c41b..f50f6f1 100644 --- a/pglab/HorizontalProxyModel.cpp +++ b/pglab/HorizontalProxyModel.cpp @@ -5,7 +5,7 @@ HorizontalProxyModel::HorizontalProxyModel(QObject *parent) - : QAbstractProxyModel(parent) + : QIdentityProxyModel(parent) { } diff --git a/pglab/HorizontalProxyModel.h b/pglab/HorizontalProxyModel.h index 2e073c9..5646a03 100644 --- a/pglab/HorizontalProxyModel.h +++ b/pglab/HorizontalProxyModel.h @@ -1,9 +1,9 @@ #ifndef HORIZONTALPROXYMODEL_H #define HORIZONTALPROXYMODEL_H -#include +#include -class HorizontalProxyModel : public QAbstractProxyModel { +class HorizontalProxyModel : public QIdentityProxyModel { public: HorizontalProxyModel(QObject * parent = nullptr); QModelIndex mapToSource(const QModelIndex &proxyIndex) const; diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index 1ba5897..fe99126 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -7,7 +7,7 @@ #include "ResultTableModelUtil.h" #include "ColumnTableModel.h" #include "ConstraintModel.h" -//#include "NamespaceFilterWidget.h" +#include "HorizontalProxyModel.h" #include "IconColumnDelegate.h" #include "IndexModel.h" #include "SqlFormattingUtils.h" @@ -53,6 +53,10 @@ TablesPage::TablesPage(MainWindow *parent) ui->indexesTable->setItemDelegate(new PgLabItemDelegate(ui->indexesTable)); ui->indexesTable->setItemDelegateForColumn(0, delegate); + HorizontalProxyModel* proxy_model = new HorizontalProxyModel(this); + proxy_model->setSourceModel(m_tablesModel); + ui->tablePropertiesTable->setModel(proxy_model); + //m_namespaceFilterWidget = new NamespaceFilterWidget(this); //ui->verticalLayoutTableView->addWidget(m_namespaceFilterWidget); diff --git a/pglab/TablesPage.ui b/pglab/TablesPage.ui index 4481693..0df84f6 100644 --- a/pglab/TablesPage.ui +++ b/pglab/TablesPage.ui @@ -1,4 +1,4 @@ - + TablesPage @@ -13,7 +13,7 @@ Form - + @@ -38,7 +38,7 @@ - 0 + 3 @@ -90,6 +90,11 @@ Properties + + + + + -- 2.47.2 From c6faafec59a3aa65fcd2127b839cbcdd714422e3 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 26 Aug 2018 07:14:25 +0200 Subject: [PATCH 4/9] Renamed HorizontalProxyModel to PropertyProxyModel as the original name didn't reflect what we are going to morph it into. --- ...alProxyModel.cpp => PropertyProxyModel.cpp} | 18 +++++++++--------- ...zontalProxyModel.h => PropertyProxyModel.h} | 4 ++-- pglab/TablesPage.cpp | 4 ++-- pglab/pglab.pro | 4 ++-- 4 files changed, 15 insertions(+), 15 deletions(-) rename pglab/{HorizontalProxyModel.cpp => PropertyProxyModel.cpp} (58%) rename pglab/{HorizontalProxyModel.h => PropertyProxyModel.h} (84%) diff --git a/pglab/HorizontalProxyModel.cpp b/pglab/PropertyProxyModel.cpp similarity index 58% rename from pglab/HorizontalProxyModel.cpp rename to pglab/PropertyProxyModel.cpp index f50f6f1..df4598c 100644 --- a/pglab/HorizontalProxyModel.cpp +++ b/pglab/PropertyProxyModel.cpp @@ -1,15 +1,15 @@ -#include "HorizontalProxyModel.h" +#include "PropertyProxyModel.h" /* * Code borrowed from: https://stackoverflow.com/questions/21653253/how-to-change-orientation-of-qt-tableview */ -HorizontalProxyModel::HorizontalProxyModel(QObject *parent) +PropertyProxyModel::PropertyProxyModel(QObject *parent) : QIdentityProxyModel(parent) { } -QModelIndex HorizontalProxyModel::mapToSource(const QModelIndex &proxyIndex) const +QModelIndex PropertyProxyModel::mapToSource(const QModelIndex &proxyIndex) const { if (sourceModel()) { return sourceModel()->index(proxyIndex.column(), proxyIndex.row()); @@ -19,32 +19,32 @@ QModelIndex HorizontalProxyModel::mapToSource(const QModelIndex &proxyIndex) con } } -QModelIndex HorizontalProxyModel::mapFromSource(const QModelIndex &sourceIndex) const +QModelIndex PropertyProxyModel::mapFromSource(const QModelIndex &sourceIndex) const { return index(sourceIndex.column(), sourceIndex.row()); } -QModelIndex HorizontalProxyModel::index(int row, int column, const QModelIndex &) const +QModelIndex PropertyProxyModel::index(int row, int column, const QModelIndex &) const { return createIndex(row, column, nullptr); } -QModelIndex HorizontalProxyModel::parent(const QModelIndex &) const +QModelIndex PropertyProxyModel::parent(const QModelIndex &) const { return QModelIndex(); } -int HorizontalProxyModel::rowCount(const QModelIndex &) const +int PropertyProxyModel::rowCount(const QModelIndex &) const { return sourceModel() ? sourceModel()->columnCount() : 0; } -int HorizontalProxyModel::columnCount(const QModelIndex &) const +int PropertyProxyModel::columnCount(const QModelIndex &) const { return sourceModel() ? sourceModel()->rowCount() : 0; } -QVariant HorizontalProxyModel::headerData( +QVariant PropertyProxyModel::headerData( int section, Qt::Orientation orientation, int role) const { if (!sourceModel()) { diff --git a/pglab/HorizontalProxyModel.h b/pglab/PropertyProxyModel.h similarity index 84% rename from pglab/HorizontalProxyModel.h rename to pglab/PropertyProxyModel.h index 5646a03..8587e50 100644 --- a/pglab/HorizontalProxyModel.h +++ b/pglab/PropertyProxyModel.h @@ -3,9 +3,9 @@ #include -class HorizontalProxyModel : public QIdentityProxyModel { +class PropertyProxyModel : public QIdentityProxyModel { public: - HorizontalProxyModel(QObject * parent = nullptr); + PropertyProxyModel(QObject * parent = nullptr); QModelIndex mapToSource(const QModelIndex &proxyIndex) const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index fe99126..1e31cf3 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -7,7 +7,7 @@ #include "ResultTableModelUtil.h" #include "ColumnTableModel.h" #include "ConstraintModel.h" -#include "HorizontalProxyModel.h" +#include "PropertyProxyModel.h" #include "IconColumnDelegate.h" #include "IndexModel.h" #include "SqlFormattingUtils.h" @@ -53,7 +53,7 @@ TablesPage::TablesPage(MainWindow *parent) ui->indexesTable->setItemDelegate(new PgLabItemDelegate(ui->indexesTable)); ui->indexesTable->setItemDelegateForColumn(0, delegate); - HorizontalProxyModel* proxy_model = new HorizontalProxyModel(this); + PropertyProxyModel* proxy_model = new PropertyProxyModel(this); proxy_model->setSourceModel(m_tablesModel); ui->tablePropertiesTable->setModel(proxy_model); diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 52a6b07..c2d13f3 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -74,7 +74,7 @@ SOURCES += main.cpp\ EditorGutter.cpp \ CodeEditor.cpp \ PlgPage.cpp \ - HorizontalProxyModel.cpp + PropertyProxyModel.cpp HEADERS += \ QueryResultModel.h \ @@ -121,7 +121,7 @@ HEADERS += \ CodeEditor.h \ PlgPage.h \ AbstractCommand.h \ - HorizontalProxyModel.h + PropertyProxyModel.h FORMS += mainwindow.ui \ ConnectionManagerWindow.ui \ -- 2.47.2 From ad4c6fd442d3c9cf662c47e5376b47041adc0d29 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 26 Aug 2018 07:59:15 +0200 Subject: [PATCH 5/9] The PropertyProxyModel now properly maps the second column to the active row of the source. It has a slot to receive the activeRow. Used this in the TablesPage to let the property tab follow the currentIndex in the list of tables. --- pglab/PropertyProxyModel.cpp | 70 ++++++++++++++++++++++++++++++------ pglab/PropertyProxyModel.h | 28 ++++++++++----- pglab/TablesPage.cpp | 16 +++++++-- 3 files changed, 92 insertions(+), 22 deletions(-) diff --git a/pglab/PropertyProxyModel.cpp b/pglab/PropertyProxyModel.cpp index df4598c..38d0233 100644 --- a/pglab/PropertyProxyModel.cpp +++ b/pglab/PropertyProxyModel.cpp @@ -1,6 +1,11 @@ #include "PropertyProxyModel.h" /* * Code borrowed from: https://stackoverflow.com/questions/21653253/how-to-change-orientation-of-qt-tableview + * + * Originally it was called Horizontal_proxy_model however some adjustments were made to it. + * Instead of the column headers becoming row headers we now convert them to the first column. + * The second column show the values of a single row from the source model. Which is determined + * by the setActiveRow call. */ @@ -12,16 +17,23 @@ PropertyProxyModel::PropertyProxyModel(QObject *parent) QModelIndex PropertyProxyModel::mapToSource(const QModelIndex &proxyIndex) const { if (sourceModel()) { - return sourceModel()->index(proxyIndex.column(), proxyIndex.row()); - } - else { - return QModelIndex(); + if (activeRow >= 0) { + if (proxyIndex.column() == valueColumn) { + return sourceModel()->index(activeRow, proxyIndex.row()); + } + } } + return QModelIndex(); } QModelIndex PropertyProxyModel::mapFromSource(const QModelIndex &sourceIndex) const { - return index(sourceIndex.column(), sourceIndex.row()); + if (activeRow >= 0) { + if (sourceIndex.row() == activeRow) { + return index(sourceIndex.column(), valueColumn); + } + } + return QModelIndex(); } QModelIndex PropertyProxyModel::index(int row, int column, const QModelIndex &) const @@ -41,16 +53,52 @@ int PropertyProxyModel::rowCount(const QModelIndex &) const int PropertyProxyModel::columnCount(const QModelIndex &) const { - return sourceModel() ? sourceModel()->rowCount() : 0; + return 2; } QVariant PropertyProxyModel::headerData( int section, Qt::Orientation orientation, int role) const { - if (!sourceModel()) { - return QVariant(); +// if (!sourceModel()) { +// return QVariant(); +// } +// Qt::Orientation new_orientation = orientation == Qt::Horizontal ? +// Qt::Vertical : Qt::Horizontal; +// return sourceModel()->headerData(section, new_orientation, role); + if (orientation == Qt::Horizontal) { + if (role == Qt::DisplayRole) { + switch (section) { + case 0: + return tr("Property"); + case 1: + return tr("Value"); + } + } } - Qt::Orientation new_orientation = orientation == Qt::Horizontal ? - Qt::Vertical : Qt::Horizontal; - return sourceModel()->headerData(section, new_orientation, role); + return QVariant(); +} + +QVariant PropertyProxyModel::data(const QModelIndex &proxyIndex, int role) const +{ + auto sm = sourceModel(); + if (sm) { + switch (proxyIndex.column()) { + case 0: + // return source header data + return sm->headerData(proxyIndex.row(), Qt::Horizontal, role); + case 1: + // return value if activeRow is set + if (activeRow >= 0) { + return QIdentityProxyModel::data(proxyIndex, role); + } + } + } + //return d->model->data(mapToSource(proxyIndex), role); + return QVariant(); +} + +void PropertyProxyModel::setActiveRow(int row) +{ + activeRow = row; + emit dataChanged(index(0, valueColumn), index(rowCount(QModelIndex()), valueColumn), QVector() << Qt::DisplayRole); } diff --git a/pglab/PropertyProxyModel.h b/pglab/PropertyProxyModel.h index 8587e50..789dd72 100644 --- a/pglab/PropertyProxyModel.h +++ b/pglab/PropertyProxyModel.h @@ -4,15 +4,27 @@ #include class PropertyProxyModel : public QIdentityProxyModel { + Q_OBJECT public: - PropertyProxyModel(QObject * parent = nullptr); - QModelIndex mapToSource(const QModelIndex &proxyIndex) const; - QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; - QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; - QModelIndex parent(const QModelIndex &child) const; - int rowCount(const QModelIndex &parent) const; - int columnCount(const QModelIndex &parent) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; + PropertyProxyModel(QObject * parent = nullptr); + QModelIndex mapToSource(const QModelIndex &proxyIndex) const; + QModelIndex mapFromSource(const QModelIndex &sourceIndex) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &child) const; + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &proxyIndex, int role) const; + +public Q_SLOTS: + void setActiveRow(int row); + +private: + enum Columns { + propertyColumn = 0, + valueColumn + }; + int activeRow = -1; }; #endif // HORIZONTALPROXYMODEL_H diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index 1e31cf3..9031612 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -53,9 +53,19 @@ TablesPage::TablesPage(MainWindow *parent) ui->indexesTable->setItemDelegate(new PgLabItemDelegate(ui->indexesTable)); ui->indexesTable->setItemDelegateForColumn(0, delegate); - PropertyProxyModel* proxy_model = new PropertyProxyModel(this); - proxy_model->setSourceModel(m_tablesModel); - ui->tablePropertiesTable->setModel(proxy_model); + PropertyProxyModel* property_model = new PropertyProxyModel(this); + property_model->setSourceModel(m_tablesModel); + ui->tablePropertiesTable->setModel(property_model); + + connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentChanged, + [property_model](const QModelIndex ¤t, const QModelIndex &) { + int row = -1; + if (current.isValid()) + row = current.row(); + + property_model->setActiveRow(row); + }); + //m_namespaceFilterWidget = new NamespaceFilterWidget(this); //ui->verticalLayoutTableView->addWidget(m_namespaceFilterWidget); -- 2.47.2 From a4054ed7890e459c9d7f6cf598acc661883d5532 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 26 Aug 2018 15:18:32 +0200 Subject: [PATCH 6/9] Introduced global enum to keep track of custom roles we want to use in our datamodels. --- pglab/CustomDataRole.h | 10 ++++++++++ pglab/IndexModel.cpp | 3 ++- pglab/TablesPage.cpp | 1 + pglab/pglab.pro | 3 ++- 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 pglab/CustomDataRole.h diff --git a/pglab/CustomDataRole.h b/pglab/CustomDataRole.h new file mode 100644 index 0000000..dccd92e --- /dev/null +++ b/pglab/CustomDataRole.h @@ -0,0 +1,10 @@ +#ifndef CUSTOMDATAROLE_H +#define CUSTOMDATAROLE_H + +#include + +enum CustomDataRole { + CustomDataTypeRole = Qt::UserRole, +}; + +#endif // CUSTOMDATAROLE_H diff --git a/pglab/IndexModel.cpp b/pglab/IndexModel.cpp index 93adc16..4e41fa3 100644 --- a/pglab/IndexModel.cpp +++ b/pglab/IndexModel.cpp @@ -3,6 +3,7 @@ #include "PgIndexContainer.h" #include "Pgsql_oids.h" #include "ScopeGuard.h" +#include "CustomDataRole.h" void IndexModel::setData(std::shared_ptr cat, const PgClass &table) { @@ -96,7 +97,7 @@ QVariant IndexModel::data(const QModelIndex &index, int role) const QVariant v; if (role == Qt::DisplayRole) v = getData(index); - else if (role == Qt::UserRole) + else if (role == CustomDataTypeRole) v = getType(index.column()); return v; } diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index 9031612..fd0703a 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -55,6 +55,7 @@ TablesPage::TablesPage(MainWindow *parent) PropertyProxyModel* property_model = new PropertyProxyModel(this); property_model->setSourceModel(m_tablesModel); + SetTableViewDefault(ui->tablePropertiesTable); ui->tablePropertiesTable->setModel(property_model); connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentChanged, diff --git a/pglab/pglab.pro b/pglab/pglab.pro index c2d13f3..aac271b 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -121,7 +121,8 @@ HEADERS += \ CodeEditor.h \ PlgPage.h \ AbstractCommand.h \ - PropertyProxyModel.h + PropertyProxyModel.h \ + CustomDataRole.h FORMS += mainwindow.ui \ ConnectionManagerWindow.ui \ -- 2.47.2 From 7630723b69e0743729005626feef941c3a754b4c Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 27 Aug 2018 21:12:27 +0200 Subject: [PATCH 7/9] Switched TablesTableModel to rely on the PgLabDelegate for formatting instead of the old model base class. --- pglab/TablesPage.cpp | 12 ++++++++---- pglab/TablesTableModel.cpp | 35 ++++++++++++----------------------- pglab/TablesTableModel.h | 8 +++----- 3 files changed, 23 insertions(+), 32 deletions(-) diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index fd0703a..5c15fac 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -24,9 +24,13 @@ TablesPage::TablesPage(MainWindow *parent) { ui->setupUi(this); + auto pglab_delegate = new PgLabItemDelegate(this); + auto icon_delegate = new IconColumnDelegate(this); + SetTableViewDefault(ui->tableListTable); m_tablesModel = new TablesTableModel(this); ui->tableListTable->setModel(m_tablesModel); + ui->tableListTable->setItemDelegate(pglab_delegate); ui->tableListTable->setSortingEnabled(true); ui->tableListTable->sortByColumn(0, Qt::AscendingOrder); @@ -36,9 +40,8 @@ TablesPage::TablesPage(MainWindow *parent) SetTableViewDefault(ui->constraintsTable); m_constraintModel = new ConstraintModel(this); - auto delegate = new IconColumnDelegate(this); ui->constraintsTable->setModel(m_constraintModel); - ui->constraintsTable->setItemDelegateForColumn(0, delegate); + ui->constraintsTable->setItemDelegateForColumn(0, icon_delegate); QFont font; font.setFamily("Source Code Pro"); @@ -50,13 +53,14 @@ TablesPage::TablesPage(MainWindow *parent) SetTableViewDefault(ui->indexesTable); m_indexModel = new IndexModel(this); ui->indexesTable->setModel(m_indexModel); - ui->indexesTable->setItemDelegate(new PgLabItemDelegate(ui->indexesTable)); - ui->indexesTable->setItemDelegateForColumn(0, delegate); + ui->indexesTable->setItemDelegate(pglab_delegate); + ui->indexesTable->setItemDelegateForColumn(0, icon_delegate); PropertyProxyModel* property_model = new PropertyProxyModel(this); property_model->setSourceModel(m_tablesModel); SetTableViewDefault(ui->tablePropertiesTable); ui->tablePropertiesTable->setModel(property_model); + ui->tablePropertiesTable->setItemDelegate(pglab_delegate); connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentChanged, [property_model](const QModelIndex ¤t, const QModelIndex &) { diff --git a/pglab/TablesTableModel.cpp b/pglab/TablesTableModel.cpp index 41e42ec..cf38f0a 100644 --- a/pglab/TablesTableModel.cpp +++ b/pglab/TablesTableModel.cpp @@ -5,13 +5,12 @@ #include "PgNamespace.h" #include "PgNamespaceContainer.h" #include "Pgsql_declare.h" +#include "CustomDataRole.h" #include TablesTableModel::TablesTableModel(QObject *parent) - : BaseTableModel(parent) -{ - -} + : QAbstractTableModel(parent) +{} void TablesTableModel::setCatalog(std::shared_ptr cat) { @@ -166,11 +165,11 @@ QVariant TablesTableModel::getData(const QModelIndex &index) const v = getTablespaceDisplayString(*m_catalog, t.tablespace); break; case OptionsCol: - v = t.options; + //v = t.options; break; -// case AclCol: -// v = t.acl; -// break; + // case AclCol: + // v = t.acl; + // break; } return v; @@ -195,19 +194,9 @@ QString TablesTableModel::formatTableName(const PgClass &cls) const QVariant TablesTableModel::data(const QModelIndex &index, int role) const { - - if (role == Qt::ForegroundRole) { - - const auto &t = m_tables[index.row()]; - auto ns = m_catalog->namespaces()->getByKey(t.relnamespace); - if (ns.isSystemCatalog()) { - switch (index.column()) { - case NameCol: - case NamespaceCol: - return QBrush(Qt::blue); - break; - } - } - } - return BaseTableModel::data(index, role); + if (role == Qt::DisplayRole) + return getData(index); + else if (role == CustomDataTypeRole) + return getType(index.column()); + return QVariant(); } diff --git a/pglab/TablesTableModel.h b/pglab/TablesTableModel.h index 2c9b16e..1277c82 100644 --- a/pglab/TablesTableModel.h +++ b/pglab/TablesTableModel.h @@ -9,8 +9,7 @@ class PgClass; class PgDatabaseCatalog; -class TablesTableModel: public BaseTableModel -{ +class TablesTableModel: public QAbstractTableModel { public: enum e_Columns : int { NameCol, ///< either table, ns.table or table (ns) depending on settings/filters @@ -38,9 +37,6 @@ public: virtual QVariant data(const QModelIndex &index, int role) const override; PgClass getTable(int row) const; Oid getTableOid(int row) const; -protected: - virtual Oid getType(int column) const override; - virtual QVariant getData(const QModelIndex &index) const override; private: using t_Tables = std::vector; @@ -48,6 +44,8 @@ private: std::shared_ptr m_catalog; t_Tables m_tables; + Oid getType(int column) const; + QVariant getData(const QModelIndex &index) const; QString formatTableName(const PgClass &cls) const; void doSort(int so); }; -- 2.47.2 From 0cef5097717e910665d1184dbcc45a5a22eacdd9 Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 27 Aug 2018 21:14:57 +0200 Subject: [PATCH 8/9] Correct tablespace names are now shown in the list of tables. Slightly more complex then you may expect because the tablespace specified by the tables tends to be oid 0 which means the default tablespace is used. However this does not mean pg_default, it means the tablespace as defined as standard in the database definition. So we need to know what the current dbname is retrieve it's details from the catalog and retrieve that tablespace to know what to show for an oid of 0. --- pglablib/PgClass.h | 4 ++-- pglablib/PgClassContainer.cpp | 7 +++++-- pglablib/PgDatabaseCatalog.cpp | 21 ++++++++++++++++++--- pglablib/PgDatabaseCatalog.h | 6 ++++++ pglablib/PgDatabaseContainer.h | 1 - pglablib/PgTablespace.cpp | 4 ++++ pglablib/PgTablespace.h | 24 ++++++++++++++++++++++++ pglablib/PgTablespaceContainer.cpp | 25 +++++++++++++++++++++++++ pglablib/PgTablespaceContainer.h | 24 ++++++++++++++++++++++++ pglablib/pglablib.pro | 8 ++++++-- pgsql/Pgsql_Connection.cpp | 5 +++++ pgsql/Pgsql_Connection.h | 2 ++ pgsql/Pgsql_oids.h | 7 +++++++ 13 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 pglablib/PgTablespace.cpp create mode 100644 pglablib/PgTablespace.h create mode 100644 pglablib/PgTablespaceContainer.cpp create mode 100644 pglablib/PgTablespaceContainer.h diff --git a/pglablib/PgClass.h b/pglablib/PgClass.h index 82f86b0..6ee7984 100644 --- a/pglablib/PgClass.h +++ b/pglablib/PgClass.h @@ -51,8 +51,8 @@ public: bool ispopulated; int frozenxid; int minmxid; - QString acl; - QString options; + std::vector acl; + std::vector options; bool operator==(Oid _oid) const { return oid == _oid; } bool operator==(const QString &n) const { return name == n; } diff --git a/pglablib/PgClassContainer.cpp b/pglablib/PgClassContainer.cpp index 2accb33..701dc68 100644 --- a/pglablib/PgClassContainer.cpp +++ b/pglablib/PgClassContainer.cpp @@ -3,6 +3,7 @@ #include "Pgsql_Col.h" #include "PgDatabaseCatalog.h" #include "PgNamespaceContainer.h" +#include std::string PgClassContainer::getLoadQuery() const { @@ -21,8 +22,10 @@ PgClass PgClassContainer::loadElem(const Pgsql::Row &row) col >> v.oid >> v.name >> v.relnamespace >> v.type >> v.oftype >> v.owner >> v.am >> v.filenode >> v.tablespace >> v.pages_est >> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence - >> v.kind >> v.hasoids >> v.ispopulated >> v.frozenxid >> v.minmxid - >> v.acl >> v.options; + >> v.kind >> v.hasoids >> v.ispopulated >> v.frozenxid >> v.minmxid; + + col.getAsArray(std::back_inserter(v.acl), Pgsql::NullHandling::Ignore); + col.getAsArray(std::back_inserter(v.options), Pgsql::NullHandling::Ignore); auto cat = m_catalogue.lock(); auto ns = cat->namespaces()->getByKey(v.relnamespace); diff --git a/pglablib/PgDatabaseCatalog.cpp b/pglablib/PgDatabaseCatalog.cpp index e2eff8b..007fa2b 100644 --- a/pglablib/PgDatabaseCatalog.cpp +++ b/pglablib/PgDatabaseCatalog.cpp @@ -9,6 +9,7 @@ #include "PgDatabaseContainer.h" #include "PgIndexContainer.h" #include "PgNamespaceContainer.h" +#include "PgTablespaceContainer.h" #include "PgTypeContainer.h" #include "Pgsql_Connection.h" #include "Pgsql_oids.h" @@ -36,7 +37,6 @@ QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid) { QString name = getRoleNameFromOid(cat, oid); return name; -// return QString("%1 (%2)").arg(name).arg(oid); } QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid) @@ -71,7 +71,12 @@ QString getIndexDisplayString(const PgDatabaseCatalog &cat, Oid oid) QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid) { // TODO load list and lookup name - return QString("ts %1").arg(oid); + if (oid == 0) { + auto dbname = cat.getDBName(); + oid = cat.databases()->getByName(dbname).tablespace; + } + auto ts = cat.tablespaces()->getByKey(oid); + return ts.name; } QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod) @@ -129,11 +134,14 @@ void PgDatabaseCatalog::loadAll(Pgsql::Connection &conn, std::function progress_callback) { loadInfo(conn); - const int count = 10; + const int count = 11; int n = 0; if (progress_callback && !progress_callback(++n, count)) return; load2(m_namespaces, conn); + if (progress_callback && !progress_callback(++n, count)) + return; + load2(m_tablespaces, conn); if (progress_callback && !progress_callback(++n, count)) return; load2(m_classes, conn); // needs namespaces @@ -172,6 +180,8 @@ void PgDatabaseCatalog::loadInfo(Pgsql::Connection &conn) if (r && r.resultStatus() == PGRES_TUPLES_OK) if (r.rows() == 1) m_serverVersionString = r.get(0, 0).asQString(); + + m_dbName = conn.getDBName(); } void load(Pgsql::Connection &conn, IPgContainter &pg_cont) @@ -245,6 +255,11 @@ std::shared_ptr PgDatabaseCatalog::namespaces() cons return m_namespaces; } +std::shared_ptr PgDatabaseCatalog::tablespaces() const +{ + return m_tablespaces; +} + std::shared_ptr PgDatabaseCatalog::types() const { return m_types; diff --git a/pglablib/PgDatabaseCatalog.h b/pglablib/PgDatabaseCatalog.h index 1389322..ca1869c 100644 --- a/pglablib/PgDatabaseCatalog.h +++ b/pglablib/PgDatabaseCatalog.h @@ -21,6 +21,7 @@ class PgDatabaseContainer; class PgIndexContainer; class PgNamespaceContainer; class PgAmContainer; +class PgTablespaceContainer; class PgTypeContainer; class PgDatabaseCatalog: public std::enable_shared_from_this { @@ -37,6 +38,7 @@ public: const QString& serverVersionString() const; int serverVersion() const; + const QString& getDBName() const { return m_dbName; } std::shared_ptr attributes() const; std::shared_ptr authIds() const; @@ -46,10 +48,13 @@ public: std::shared_ptr indexes() const; std::shared_ptr ams() const; std::shared_ptr namespaces() const; + std::shared_ptr tablespaces() const; std::shared_ptr types() const; + private: QString m_serverVersionString; int m_serverVersion; + QString m_dbName; std::shared_ptr m_attributes; std::shared_ptr m_authIds; @@ -59,6 +64,7 @@ private: std::shared_ptr m_indexes; std::shared_ptr m_ams; std::shared_ptr m_namespaces; + std::shared_ptr m_tablespaces; std::shared_ptr m_types; template diff --git a/pglablib/PgDatabaseContainer.h b/pglablib/PgDatabaseContainer.h index 2cf856a..e7bcf1f 100644 --- a/pglablib/PgDatabaseContainer.h +++ b/pglablib/PgDatabaseContainer.h @@ -18,7 +18,6 @@ public: virtual std::string getLoadQuery() const override; virtual void load(const Pgsql::Result &res) override; - private: }; diff --git a/pglablib/PgTablespace.cpp b/pglablib/PgTablespace.cpp new file mode 100644 index 0000000..48709aa --- /dev/null +++ b/pglablib/PgTablespace.cpp @@ -0,0 +1,4 @@ +#include "PgTablespace.h" + +PgTablespace::PgTablespace() +{} diff --git a/pglablib/PgTablespace.h b/pglablib/PgTablespace.h new file mode 100644 index 0000000..cf50c64 --- /dev/null +++ b/pglablib/PgTablespace.h @@ -0,0 +1,24 @@ +#ifndef PGTABLESPACE_H +#define PGTABLESPACE_H + +#include +#include +#include + +class PgTablespace { +public: + Oid oid = InvalidOid; + QString name; + Oid owner = InvalidOid; + std::vector acl; + std::vector options; + + PgTablespace(); + + bool operator==(Oid _oid) const { return oid == _oid; } + //bool operator==(const QString &n) const { return name == n; } + bool operator<(Oid _oid) const { return oid < _oid; } + bool operator<(const PgTablespace &rhs) const { return oid < rhs.oid; } +}; + +#endif // PGTABLESPACE_H diff --git a/pglablib/PgTablespaceContainer.cpp b/pglablib/PgTablespaceContainer.cpp new file mode 100644 index 0000000..092056e --- /dev/null +++ b/pglablib/PgTablespaceContainer.cpp @@ -0,0 +1,25 @@ +#include "PgTablespaceContainer.h" +#include "Pgsql_Connection.h" +#include "Pgsql_Col.h" +#include "Pgsql_declare.h" +#include "PgDatabaseCatalog.h" +#include + +std::string PgTablespaceContainer::getLoadQuery() const +{ + return +R"__SQL__( +SELECT oid, spcname, spcowner, spcacl, spcoptions +FROM pg_tablespace +)__SQL__"; +} + +PgTablespace PgTablespaceContainer::loadElem(const Pgsql::Row &row) +{ + Pgsql::Col col(row); + PgTablespace v; + col >> v.oid >> v.name >> v.owner; + col.getAsArray(std::back_inserter(v.acl), Pgsql::NullHandling::Ignore); + col.getAsArray(std::back_inserter(v.options), Pgsql::NullHandling::Ignore); + return v; +} diff --git a/pglablib/PgTablespaceContainer.h b/pglablib/PgTablespaceContainer.h new file mode 100644 index 0000000..5f427f4 --- /dev/null +++ b/pglablib/PgTablespaceContainer.h @@ -0,0 +1,24 @@ +#ifndef PGTABLESPACECONTAINER_H +#define PGTABLESPACECONTAINER_H + +#include "PgContainer.h" +#include "PgTablespace.h" + +namespace Pgsql { + + class Result; + +} + + +class PgTablespaceContainer: public PgContainer { +public: + using PgContainer::PgContainer; + + virtual std::string getLoadQuery() const override; +protected: + PgTablespace loadElem(const Pgsql::Row &row) override; +private: +}; + +#endif // PGTABLESPACECONTAINER_H diff --git a/pglablib/pglablib.pro b/pglablib/pglablib.pro index 3e33c70..8c4047c 100644 --- a/pglablib/pglablib.pro +++ b/pglablib/pglablib.pro @@ -55,7 +55,9 @@ SOURCES += \ QueryGenerator.cpp \ PgAm.cpp \ PgAmContainer.cpp \ - PgObject.cpp + PgObject.cpp \ + PgTablespace.cpp \ + PgTablespaceContainer.cpp HEADERS += \ Pglablib.h \ @@ -88,7 +90,9 @@ HEADERS += \ QueryGenerator.h \ PgAm.h \ PgAmContainer.h \ - PgObject.h + PgObject.h \ + PgTablespace.h \ + PgTablespaceContainer.h unix { target.path = /usr/lib diff --git a/pgsql/Pgsql_Connection.cpp b/pgsql/Pgsql_Connection.cpp index 728e18d..db22689 100644 --- a/pgsql/Pgsql_Connection.cpp +++ b/pgsql/Pgsql_Connection.cpp @@ -263,3 +263,8 @@ void Connection::notifyReceiveFunc(void *arg, const PGresult *result) Connection *c = reinterpret_cast(arg); c->notifyReceiver(result); } + +QString Connection::getDBName() const +{ + return QString::fromUtf8(PQdb(conn)); +} diff --git a/pgsql/Pgsql_Connection.h b/pgsql/Pgsql_Connection.h index c9fd189..bbe34de 100644 --- a/pgsql/Pgsql_Connection.h +++ b/pgsql/Pgsql_Connection.h @@ -124,6 +124,8 @@ namespace Pgsql { QString escapeLiteral(const QString &literal); std::string escapeIdentifier(const std::string_view &ident); QString escapeIdentifier(const QString &ident); + + QString getDBName() const; private: PGconn *conn = nullptr; std::function notifyReceiver; diff --git a/pgsql/Pgsql_oids.h b/pgsql/Pgsql_oids.h index 295ef5c..4be5687 100644 --- a/pgsql/Pgsql_oids.h +++ b/pgsql/Pgsql_oids.h @@ -177,6 +177,13 @@ namespace Pgsql { static Oid elem() { return timestamptz_oid; } static Oid array() { return timestamptz_array_oid; } }; + + template <> + class OidFor { + public: + static Oid elem() { return text_oid; } + static Oid array() { return text_array_oid; } + }; // template <> // class OidFor<> { // public: -- 2.47.2 From e8f81557bb32f8dffe188532e279dfbd262919ec Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 2 Sep 2018 12:28:56 +0200 Subject: [PATCH 9/9] Simplify connecting QItemSelection::currentRowChanged to PropertyProxyModel::activeRow --- pglab/PropertyProxyModel.cpp | 4 ++-- pglab/PropertyProxyModel.h | 7 ++++++- pglab/TablesPage.cpp | 10 ++-------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pglab/PropertyProxyModel.cpp b/pglab/PropertyProxyModel.cpp index 38d0233..1448a3d 100644 --- a/pglab/PropertyProxyModel.cpp +++ b/pglab/PropertyProxyModel.cpp @@ -97,8 +97,8 @@ QVariant PropertyProxyModel::data(const QModelIndex &proxyIndex, int role) const return QVariant(); } -void PropertyProxyModel::setActiveRow(int row) +void PropertyProxyModel::setActiveRow(const QModelIndex &row) { - activeRow = row; + activeRow = row.isValid() ? row.row() : -1; emit dataChanged(index(0, valueColumn), index(rowCount(QModelIndex()), valueColumn), QVector() << Qt::DisplayRole); } diff --git a/pglab/PropertyProxyModel.h b/pglab/PropertyProxyModel.h index 789dd72..4d3ea9b 100644 --- a/pglab/PropertyProxyModel.h +++ b/pglab/PropertyProxyModel.h @@ -17,7 +17,12 @@ public: QVariant data(const QModelIndex &proxyIndex, int role) const; public Q_SLOTS: - void setActiveRow(int row); + /** Updates the model (and view) to show the values for row + * + * The column part of the index is not used QModelIndex is used to make is eacy to connect to + * QItemSelectionModel::currentRowChanged + */ + void setActiveRow(const QModelIndex &row); private: enum Columns { diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index 5c15fac..9f33e57 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -62,14 +62,8 @@ TablesPage::TablesPage(MainWindow *parent) ui->tablePropertiesTable->setModel(property_model); ui->tablePropertiesTable->setItemDelegate(pglab_delegate); - connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentChanged, - [property_model](const QModelIndex ¤t, const QModelIndex &) { - int row = -1; - if (current.isValid()) - row = current.row(); - - property_model->setActiveRow(row); - }); + connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentRowChanged, + property_model, &PropertyProxyModel::setActiveRow); //m_namespaceFilterWidget = new NamespaceFilterWidget(this); -- 2.47.2