Added list of constraints to the tables page.
Last column shows the full textual definition until I have decided on a better way to visualize the details.
This commit is contained in:
parent
22db22c6b1
commit
a99f059b70
27 changed files with 663 additions and 22 deletions
14
pglab/ApplicationWindow.cpp
Normal file
14
pglab/ApplicationWindow.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "ApplicationWindow.h"
|
||||||
|
#include "ui_ApplicationWindow.h"
|
||||||
|
|
||||||
|
ApplicationWindow::ApplicationWindow(QWidget *parent) :
|
||||||
|
QMainWindow(parent),
|
||||||
|
ui(new Ui::ApplicationWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ApplicationWindow::~ApplicationWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
22
pglab/ApplicationWindow.h
Normal file
22
pglab/ApplicationWindow.h
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef APPLICATIONWINDOW_H
|
||||||
|
#define APPLICATIONWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ApplicationWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApplicationWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ApplicationWindow(QWidget *parent = 0);
|
||||||
|
~ApplicationWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::ApplicationWindow *ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // APPLICATIONWINDOW_H
|
||||||
145
pglab/ApplicationWindow.ui
Normal file
145
pglab/ApplicationWindow.ui
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ApplicationWindow</class>
|
||||||
|
<widget class="QMainWindow" name="ApplicationWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>314</width>
|
||||||
|
<height>672</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="comboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||||
|
<horstretch>1</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frame">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="toolButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="frame_3">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>314</width>
|
||||||
|
<height>25</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
|
|
@ -83,7 +83,8 @@ QVariant ColumnTableModel::headerData(int section, Qt::Orientation orientation,
|
||||||
else if (role == Qt::ToolTipRole) {
|
else if (role == Qt::ToolTipRole) {
|
||||||
if (section >= colCount) {
|
if (section >= colCount) {
|
||||||
const auto &tbl_idx = m_indexes[section - colCount];
|
const auto &tbl_idx = m_indexes[section - colCount];
|
||||||
auto idx_cls = m_catalog->classes()->getByKey(tbl_idx.indexrelid);
|
//auto idx_cls = m_catalog->classes()->getByKey(tbl_idx.indexrelid);
|
||||||
|
auto idx_class_name = getClassDisplayString(*m_catalog, tbl_idx.indexrelid);
|
||||||
QString s;
|
QString s;
|
||||||
if (tbl_idx.isprimary)
|
if (tbl_idx.isprimary)
|
||||||
s = tr("Primary key");
|
s = tr("Primary key");
|
||||||
|
|
@ -91,7 +92,7 @@ QVariant ColumnTableModel::headerData(int section, Qt::Orientation orientation,
|
||||||
s = tr("Unique index");
|
s = tr("Unique index");
|
||||||
else
|
else
|
||||||
s = tr("Index");
|
s = tr("Index");
|
||||||
s += "\n" + idx_cls.name;
|
s += "\n" + idx_class_name;
|
||||||
v = s;
|
v = s;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>800</width>
|
<width>800</width>
|
||||||
<height>24</height>
|
<height>25</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QMenu" name="menuFile">
|
<widget class="QMenu" name="menuFile">
|
||||||
|
|
@ -217,6 +217,18 @@
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>toolBar</string>
|
<string>toolBar</string>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">QToolBar {
|
||||||
|
border-top: 1px solid rgb(192, 192, 192);
|
||||||
|
border-bottom: 1px solid rgb(192, 192, 192);
|
||||||
|
padding: 4px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QToolButton {
|
||||||
|
border: none;
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
<property name="movable">
|
<property name="movable">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
||||||
168
pglab/ConstraintModel.cpp
Normal file
168
pglab/ConstraintModel.cpp
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
#include "ConstraintModel.h"
|
||||||
|
#include "ScopeGuard.h"
|
||||||
|
#include "PgDatabaseCatalog.h"
|
||||||
|
#include "PgConstraintContainer.h"
|
||||||
|
#include "Pgsql_oids.h"
|
||||||
|
|
||||||
|
ConstraintModel::ConstraintModel(QObject *parent)
|
||||||
|
: BaseTableModel(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ConstraintModel::setData(std::shared_ptr<const PgDatabaseCatalog> cat, const PgClass &table)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
SCOPE_EXIT { endResetModel(); };
|
||||||
|
|
||||||
|
m_table = table;
|
||||||
|
m_catalog = cat;
|
||||||
|
m_constraints = cat->constraints()->getConstraintsForRelation(table.oid);
|
||||||
|
|
||||||
|
std::sort(m_constraints.begin(), m_constraints.end(),
|
||||||
|
[] (auto &l, auto &r) {
|
||||||
|
return l.type < r.type ||
|
||||||
|
(l.type == r.type && l.name < r.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
// // hide system columns
|
||||||
|
// auto si = table.hasoids
|
||||||
|
// ? std::remove_if(m_columns.begin(), m_columns.end(),
|
||||||
|
// [](PgAttribute &e) { return e.num <= 0 && e.name != "oid"; })
|
||||||
|
// : std::remove_if(m_columns.begin(), m_columns.end(),
|
||||||
|
// [](PgAttribute &e) { return e.num <= 0; });
|
||||||
|
// // move columns to end and remove them
|
||||||
|
// m_columns.erase(si, m_columns.end());
|
||||||
|
|
||||||
|
// // sort remaining columns by order in table
|
||||||
|
// std::sort(m_columns.begin(), m_columns.end(),
|
||||||
|
// [] (auto &l, auto &r) -> bool { return l.num < r.num; });
|
||||||
|
|
||||||
|
// m_indexes = m_catalog->indexes()->getIndexesForTable(table.oid);
|
||||||
|
// std::sort(m_indexes.begin(), m_indexes.end(),
|
||||||
|
// [] (const auto &l, const auto &r) -> bool
|
||||||
|
// {
|
||||||
|
// return l.isprimary > r.isprimary
|
||||||
|
// || (l.isprimary == r.isprimary && l.indexrelid < r.indexrelid);
|
||||||
|
// });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ConstraintModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
QVariant v;
|
||||||
|
if (orientation == Qt::Horizontal) {
|
||||||
|
if (role == Qt::DisplayRole) {
|
||||||
|
QString c;
|
||||||
|
switch (section) {
|
||||||
|
case TypeCol:
|
||||||
|
c = tr("Type");
|
||||||
|
break;
|
||||||
|
case NameCol:
|
||||||
|
c = tr("Name");
|
||||||
|
break;
|
||||||
|
case NsCol:
|
||||||
|
c = tr("Schema");
|
||||||
|
break;
|
||||||
|
case SupportingIndexCol:
|
||||||
|
c = tr("Supporting index");
|
||||||
|
break;
|
||||||
|
case DefinitionCol:
|
||||||
|
c = tr("Definition");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConstraintModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return m_constraints.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ConstraintModel::columnCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return colCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//QVariant ConstraintModel::data(const QModelIndex &index, int role) const
|
||||||
|
//{
|
||||||
|
// QVariant v;
|
||||||
|
// if (!index.isValid())
|
||||||
|
// return QVariant();
|
||||||
|
|
||||||
|
// // FIXME: Implement me!
|
||||||
|
// return v;
|
||||||
|
//}
|
||||||
|
|
||||||
|
Oid ConstraintModel::getType(int column) const
|
||||||
|
{
|
||||||
|
Oid oid = Pgsql::varchar_oid;
|
||||||
|
|
||||||
|
return oid;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString IconForConstraintType(ConstraintType ct)
|
||||||
|
{
|
||||||
|
QString s = ":/icons/constraints/";
|
||||||
|
switch (ct) {
|
||||||
|
case ConstraintType::Check:
|
||||||
|
s += "check.png";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ForeignKey:
|
||||||
|
s += "foreignkey.png";
|
||||||
|
break;
|
||||||
|
case ConstraintType::PrimaryKey:
|
||||||
|
s += "primarykey.png";
|
||||||
|
break;
|
||||||
|
case ConstraintType::Unique:
|
||||||
|
s += "unique.png";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ConstraintTrigger:
|
||||||
|
s = "CT";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ExclusionConstraint:
|
||||||
|
s = "XC";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "?";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QVariant ConstraintModel::getData(const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
QVariant v;
|
||||||
|
const int row = index.row();
|
||||||
|
const auto &t = m_constraints[row];
|
||||||
|
|
||||||
|
const int col = index.column();
|
||||||
|
QString s;
|
||||||
|
switch (col) {
|
||||||
|
case TypeCol:
|
||||||
|
s = IconForConstraintType(t.type);
|
||||||
|
break;
|
||||||
|
case NameCol:
|
||||||
|
s = t.name;
|
||||||
|
break;
|
||||||
|
case NsCol:
|
||||||
|
s = getNamespaceDisplayString(*m_catalog, t.connamespace);
|
||||||
|
break;
|
||||||
|
case SupportingIndexCol:
|
||||||
|
s = getIndexDisplayString(*m_catalog, t.indid);
|
||||||
|
break;
|
||||||
|
case DefinitionCol:
|
||||||
|
s = t.definition;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
v = s;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
51
pglab/ConstraintModel.h
Normal file
51
pglab/ConstraintModel.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef CONSTRAINTMODEL_H
|
||||||
|
#define CONSTRAINTMODEL_H
|
||||||
|
|
||||||
|
#include "BaseTableModel.h"
|
||||||
|
#include "PgClass.h"
|
||||||
|
#include "PgConstraint.h"
|
||||||
|
#include <QAbstractTableModel>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class PgDatabaseCatalog;
|
||||||
|
|
||||||
|
class ConstraintModel : public BaseTableModel {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum e_Columns : int {
|
||||||
|
TypeCol,
|
||||||
|
NameCol, ///
|
||||||
|
NsCol, ///
|
||||||
|
SupportingIndexCol,
|
||||||
|
DefinitionCol,
|
||||||
|
colCount };
|
||||||
|
|
||||||
|
explicit ConstraintModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
void setData(std::shared_ptr<const PgDatabaseCatalog> cat, const PgClass &table);
|
||||||
|
|
||||||
|
|
||||||
|
// Header:
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
// Basic functionality:
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
|
||||||
|
//QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual Oid getType(int column) const override;
|
||||||
|
virtual QVariant getData(const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<const PgDatabaseCatalog> m_catalog;
|
||||||
|
PgClass m_table;
|
||||||
|
|
||||||
|
using t_Constraints = std::vector<PgConstraint>;
|
||||||
|
t_Constraints m_constraints;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // CONSTRAINTMODEL_H
|
||||||
59
pglab/IconColumnDelegate.cpp
Normal file
59
pglab/IconColumnDelegate.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#include "IconColumnDelegate.h"
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
IconColumnDelegate::IconColumnDelegate(QWidget *parent)
|
||||||
|
: QStyledItemDelegate(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
IconColumnDelegate::~IconColumnDelegate()
|
||||||
|
{
|
||||||
|
clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IconColumnDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
if (index.data().canConvert<QString>()) {
|
||||||
|
QString icon_name = qvariant_cast<QString>(index.data());
|
||||||
|
|
||||||
|
|
||||||
|
QIcon* icon = IconColumnDelegate::getIcon(icon_name);
|
||||||
|
if (icon) {
|
||||||
|
if (option.state & QStyle::State_Selected)
|
||||||
|
painter->fillRect(option.rect, option.palette.highlight());
|
||||||
|
icon->paint(painter, option.rect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
QStyledItemDelegate::paint(painter, option, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize IconColumnDelegate::sizeHint(const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index) const
|
||||||
|
{
|
||||||
|
return QSize(16, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void IconColumnDelegate::clearCache()
|
||||||
|
{
|
||||||
|
for (auto &e : m_Icons)
|
||||||
|
delete e.
|
||||||
|
second;
|
||||||
|
m_Icons.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon* IconColumnDelegate::getIcon(const QString &name) const
|
||||||
|
{
|
||||||
|
auto fr = m_Icons.find(name);
|
||||||
|
if (fr == m_Icons.end()) {
|
||||||
|
// load and insert icon
|
||||||
|
QIcon *icon = new QIcon(name);
|
||||||
|
fr = m_Icons.emplace(name, icon).first;
|
||||||
|
}
|
||||||
|
return fr->second;
|
||||||
|
}
|
||||||
29
pglab/IconColumnDelegate.h
Normal file
29
pglab/IconColumnDelegate.h
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef ICONCOLUMNDELEGATE_H
|
||||||
|
#define ICONCOLUMNDELEGATE_H
|
||||||
|
|
||||||
|
#include <QStyledItemDelegate>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
/** This class asumes that the string values supplies for the column data
|
||||||
|
* can be Resolved by QIcon to an actual icon. Icons are cached and reused.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class IconColumnDelegate: public QStyledItemDelegate {
|
||||||
|
public:
|
||||||
|
IconColumnDelegate(QWidget *parent = nullptr);
|
||||||
|
~IconColumnDelegate();
|
||||||
|
|
||||||
|
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||||
|
QSize sizeHint(const QStyleOptionViewItem &option,
|
||||||
|
const QModelIndex &index) const override;
|
||||||
|
|
||||||
|
void clearCache();
|
||||||
|
private:
|
||||||
|
using t_IconCache = std::map<QString, QIcon*>;
|
||||||
|
|
||||||
|
mutable t_IconCache m_Icons;
|
||||||
|
|
||||||
|
QIcon* getIcon(const QString &name) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ICONCOLUMNDELEGATE_H
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
#include <QStatusBar>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
|
|
@ -399,7 +400,10 @@ void QueryTab::explain_ready(ExplainRoot::SPtr explain)
|
||||||
ui->explainTreeView->setColumnWidth(5, 80);
|
ui->explainTreeView->setColumnWidth(5, 80);
|
||||||
ui->explainTreeView->setColumnWidth(6, 600);
|
ui->explainTreeView->setColumnWidth(6, 600);
|
||||||
ui->tabWidget->setCurrentWidget(ui->explainTab);
|
ui->tabWidget->setCurrentWidget(ui->explainTab);
|
||||||
// statusBar()->showMessage(tr("Explain ready."));
|
|
||||||
|
auto w = dynamic_cast<QMainWindow*>(this->window());
|
||||||
|
if (w)
|
||||||
|
w->statusBar()->showMessage(tr("Explain ready."));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addLog("Explain no result");
|
addLog("Explain no result");
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@
|
||||||
#include "TablesTableModel.h"
|
#include "TablesTableModel.h"
|
||||||
#include "ResultTableModelUtil.h"
|
#include "ResultTableModelUtil.h"
|
||||||
#include "ColumnTableModel.h"
|
#include "ColumnTableModel.h"
|
||||||
|
#include "ConstraintModel.h"
|
||||||
#include "NamespaceFilterWidget.h"
|
#include "NamespaceFilterWidget.h"
|
||||||
|
#include "IconColumnDelegate.h"
|
||||||
|
|
||||||
TablesPage::TablesPage(QWidget *parent) :
|
TablesPage::TablesPage(QWidget *parent) :
|
||||||
QWidget(parent),
|
QWidget(parent),
|
||||||
|
|
@ -22,6 +24,13 @@ TablesPage::TablesPage(QWidget *parent) :
|
||||||
m_columnsModel = new ColumnTableModel(this);
|
m_columnsModel = new ColumnTableModel(this);
|
||||||
ui->columnsTable->setModel(m_columnsModel);
|
ui->columnsTable->setModel(m_columnsModel);
|
||||||
|
|
||||||
|
SetTableViewDefault(ui->constraintsTable);
|
||||||
|
m_constraintModel = new ConstraintModel(this);
|
||||||
|
auto delegate = new IconColumnDelegate(this);
|
||||||
|
|
||||||
|
ui->constraintsTable->setModel(m_constraintModel);
|
||||||
|
ui->constraintsTable->setItemDelegateForColumn(0, delegate);
|
||||||
|
|
||||||
m_namespaceFilterWidget = new NamespaceFilterWidget(this);
|
m_namespaceFilterWidget = new NamespaceFilterWidget(this);
|
||||||
ui->verticalLayoutTableView->addWidget(m_namespaceFilterWidget);
|
ui->verticalLayoutTableView->addWidget(m_namespaceFilterWidget);
|
||||||
|
|
||||||
|
|
@ -50,5 +59,8 @@ void TablesPage::on_tableListTable_currentRowChanged(const QModelIndex ¤t,
|
||||||
PgClass table = m_tablesModel->getTable(current.row());
|
PgClass table = m_tablesModel->getTable(current.row());
|
||||||
m_columnsModel->setData(m_catalog, table);
|
m_columnsModel->setData(m_catalog, table);
|
||||||
ui->columnsTable->resizeColumnsToContents();
|
ui->columnsTable->resizeColumnsToContents();
|
||||||
|
|
||||||
|
m_constraintModel->setData(m_catalog, table);
|
||||||
|
ui->constraintsTable->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ class TablesPage;
|
||||||
|
|
||||||
class TablesTableModel;
|
class TablesTableModel;
|
||||||
class ColumnTableModel;
|
class ColumnTableModel;
|
||||||
|
class ConstraintModel;
|
||||||
class PgDatabaseCatalog;
|
class PgDatabaseCatalog;
|
||||||
class NamespaceFilterWidget;
|
class NamespaceFilterWidget;
|
||||||
|
|
||||||
|
|
@ -27,6 +28,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;
|
||||||
|
ConstraintModel* m_constraintModel = nullptr;
|
||||||
NamespaceFilterWidget* m_namespaceFilterWidget;
|
NamespaceFilterWidget* m_namespaceFilterWidget;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QTabWidget" name="tabWidget">
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
<property name="currentIndex">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>2</number>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="columnsTab">
|
<widget class="QWidget" name="columnsTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
|
|
@ -50,6 +50,26 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="QWidget" name="tabConstraints">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Constraints</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="constraintsTable"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tabIndexes">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Indexes</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QTableView" name="indexesTable"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
<widget class="QWidget" name="propertiesTab">
|
<widget class="QWidget" name="propertiesTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Properties</string>
|
<string>Properties</string>
|
||||||
|
|
|
||||||
BIN
pglab/icons/constraints/check.png
Normal file
BIN
pglab/icons/constraints/check.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 406 B |
BIN
pglab/icons/constraints/foreignkey.png
Normal file
BIN
pglab/icons/constraints/foreignkey.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 299 B |
BIN
pglab/icons/constraints/primarykey.png
Normal file
BIN
pglab/icons/constraints/primarykey.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 443 B |
BIN
pglab/icons/constraints/unique.png
Normal file
BIN
pglab/icons/constraints/unique.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 422 B |
|
|
@ -62,7 +62,10 @@ SOURCES += main.cpp\
|
||||||
TablesTableModel.cpp \
|
TablesTableModel.cpp \
|
||||||
ColumnTableModel.cpp \
|
ColumnTableModel.cpp \
|
||||||
NamespaceFilterWidget.cpp \
|
NamespaceFilterWidget.cpp \
|
||||||
NamespaceItemModel.cpp
|
NamespaceItemModel.cpp \
|
||||||
|
ApplicationWindow.cpp \
|
||||||
|
ConstraintModel.cpp \
|
||||||
|
IconColumnDelegate.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
QueryResultModel.h \
|
QueryResultModel.h \
|
||||||
|
|
@ -96,7 +99,10 @@ HEADERS += \
|
||||||
TablesTableModel.h \
|
TablesTableModel.h \
|
||||||
ColumnTableModel.h \
|
ColumnTableModel.h \
|
||||||
NamespaceFilterWidget.h \
|
NamespaceFilterWidget.h \
|
||||||
NamespaceItemModel.h
|
NamespaceItemModel.h \
|
||||||
|
ApplicationWindow.h \
|
||||||
|
ConstraintModel.h \
|
||||||
|
IconColumnDelegate.h
|
||||||
|
|
||||||
FORMS += mainwindow.ui \
|
FORMS += mainwindow.ui \
|
||||||
ConnectionManagerWindow.ui \
|
ConnectionManagerWindow.ui \
|
||||||
|
|
@ -107,7 +113,8 @@ FORMS += mainwindow.ui \
|
||||||
ServerWindow.ui \
|
ServerWindow.ui \
|
||||||
ProcessStdioWidget.ui \
|
ProcessStdioWidget.ui \
|
||||||
TablesPage.ui \
|
TablesPage.ui \
|
||||||
NamespaceFilterWidget.ui
|
NamespaceFilterWidget.ui \
|
||||||
|
ApplicationWindow.ui
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources.qrc
|
resources.qrc
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,9 @@
|
||||||
<file>icons/delete_connection.png</file>
|
<file>icons/delete_connection.png</file>
|
||||||
<file>icons/open_query_window.png</file>
|
<file>icons/open_query_window.png</file>
|
||||||
<file>icons/manage_server.png</file>
|
<file>icons/manage_server.png</file>
|
||||||
|
<file>icons/constraints/check.png</file>
|
||||||
|
<file>icons/constraints/foreignkey.png</file>
|
||||||
|
<file>icons/constraints/primarykey.png</file>
|
||||||
|
<file>icons/constraints/unique.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ SUBDIRS += core \
|
||||||
pglablib \
|
pglablib \
|
||||||
pglab
|
pglab
|
||||||
|
|
||||||
|
pglab.depends = core ctk pgsql pglablib
|
||||||
|
pgsql.depends = core
|
||||||
|
pglablib.depends = core pgsql
|
||||||
|
|
||||||
|
|
||||||
CONFIG(debug, debug|release) {
|
CONFIG(debug, debug|release) {
|
||||||
SUBDIRS += tests
|
SUBDIRS += tests
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,64 @@ void operator<<(ConstraintType &s, const Pgsql::Value &v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ShortNameForConstraintType(ConstraintType ct)
|
||||||
|
{
|
||||||
|
QString s;
|
||||||
|
switch (ct) {
|
||||||
|
case ConstraintType::Check:
|
||||||
|
s = "C";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ForeignKey:
|
||||||
|
s = "FK";
|
||||||
|
break;
|
||||||
|
case ConstraintType::PrimaryKey:
|
||||||
|
s = "PK";
|
||||||
|
break;
|
||||||
|
case ConstraintType::Unique:
|
||||||
|
s = "U";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ConstraintTrigger:
|
||||||
|
s = "CT";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ExclusionConstraint:
|
||||||
|
s = "XC";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "?";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString LongNameForConstraintType(ConstraintType ct)
|
||||||
|
{
|
||||||
|
QString s;
|
||||||
|
switch (ct) {
|
||||||
|
case ConstraintType::Check:
|
||||||
|
s = "check";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ForeignKey:
|
||||||
|
s = "foreign key";
|
||||||
|
break;
|
||||||
|
case ConstraintType::PrimaryKey:
|
||||||
|
s = "primary key";
|
||||||
|
break;
|
||||||
|
case ConstraintType::Unique:
|
||||||
|
s = "unique";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ConstraintTrigger:
|
||||||
|
s = "constraint trigger";
|
||||||
|
break;
|
||||||
|
case ConstraintType::ExclusionConstraint:
|
||||||
|
s = "exclusion constraint";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = "?";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
void operator<<(ForeignKeyAction &s, const Pgsql::Value &v)
|
void operator<<(ForeignKeyAction &s, const Pgsql::Value &v)
|
||||||
{
|
{
|
||||||
const char *c = v.c_str();
|
const char *c = v.c_str();
|
||||||
|
|
@ -64,6 +122,7 @@ void operator<<(ForeignKeyMatch &s, const Pgsql::Value &v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PgConstraint::PgConstraint()
|
PgConstraint::PgConstraint()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,19 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
enum class ConstraintType {
|
enum class ConstraintType {
|
||||||
Check, // c
|
|
||||||
ForeignKey, // f
|
|
||||||
PrimaryKey, // p
|
PrimaryKey, // p
|
||||||
|
ForeignKey, // f
|
||||||
Unique, // u
|
Unique, // u
|
||||||
|
Check, // c
|
||||||
ConstraintTrigger, // t
|
ConstraintTrigger, // t
|
||||||
ExclusionConstraint, // x
|
ExclusionConstraint, // x
|
||||||
};
|
};
|
||||||
|
|
||||||
void operator<<(ConstraintType &s, const Pgsql::Value &v);
|
void operator<<(ConstraintType &s, const Pgsql::Value &v);
|
||||||
|
|
||||||
|
QString ShortNameForConstraintType(ConstraintType ct);
|
||||||
|
QString LongNameForConstraintType(ConstraintType ct);
|
||||||
|
|
||||||
|
|
||||||
enum class ForeignKeyAction {
|
enum class ForeignKeyAction {
|
||||||
NoAction, // a
|
NoAction, // a
|
||||||
|
|
|
||||||
|
|
@ -63,3 +63,12 @@ const PgConstraint* PgConstraintContainer::getFKeyForTableColumn(Oid relid, int1
|
||||||
// });
|
// });
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<PgConstraint> PgConstraintContainer::getConstraintsForRelation(Oid relid) const
|
||||||
|
{
|
||||||
|
std::vector<PgConstraint> result;
|
||||||
|
for (const auto &e : m_container)
|
||||||
|
if (e.relid == relid)
|
||||||
|
result.push_back(e);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ public:
|
||||||
virtual std::string getLoadQuery() const override;
|
virtual std::string getLoadQuery() const override;
|
||||||
//std::vector<PgConstraint> getIndexesForTable(Oid table_oid) const;
|
//std::vector<PgConstraint> getIndexesForTable(Oid table_oid) const;
|
||||||
const PgConstraint* getFKeyForTableColumn(Oid relid, int16_t attnum) const;
|
const PgConstraint* getFKeyForTableColumn(Oid relid, int16_t attnum) const;
|
||||||
|
|
||||||
|
std::vector<PgConstraint> getConstraintsForRelation(Oid relid) const;
|
||||||
protected:
|
protected:
|
||||||
virtual PgConstraint loadElem(const Pgsql::Row &row) override;
|
virtual PgConstraint loadElem(const Pgsql::Row &row) override;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,19 +38,31 @@ QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||||
|
|
||||||
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||||
{
|
{
|
||||||
//QString name;
|
QString result;
|
||||||
auto nss = cat.namespaces();
|
auto nss = cat.namespaces();
|
||||||
auto ns = nss->getByKey(oid);
|
auto ns = nss->getByKey(oid);
|
||||||
// if (auth_ids) {
|
result = ns.name; //QString("ns %1").arg(oid);
|
||||||
// const PgAuthId& auth_id = auth_ids->getByOid(oid);
|
return result;
|
||||||
// if (auth_id.valid()) {
|
}
|
||||||
// name = auth_id.name;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//return name;
|
|
||||||
// TODO load list and lookup name
|
|
||||||
return ns.name; //QString("ns %1").arg(oid);
|
|
||||||
|
|
||||||
|
QString getClassDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
auto l = cat.classes();
|
||||||
|
auto e = l->getByKey(oid);
|
||||||
|
result = e.name;
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
QString getIndexDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
// auto l = cat.indexes();
|
||||||
|
// auto e = l->getByKey(oid);
|
||||||
|
// if (e)
|
||||||
|
result = getClassDisplayString(cat, oid);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid)
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ QString getRoleDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||||
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
QString getNamespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||||
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
QString getTablespaceDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||||
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod = -1);
|
QString getTypeDisplayString(const PgDatabaseCatalog &cat, Oid oid, int32_t typmod = -1);
|
||||||
|
QString getIndexDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||||
|
QString getClassDisplayString(const PgDatabaseCatalog &cat, Oid oid);
|
||||||
|
|
||||||
|
|
||||||
#endif // PGSQLDATABASECATALOGUE_H
|
#endif // PGSQLDATABASECATALOGUE_H
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue