Merge branch 'plugin-architecture'
This commit is contained in:
commit
bcf0cf1c6c
59 changed files with 1668 additions and 1348 deletions
|
|
@ -12,8 +12,9 @@ template <class T>
|
|||
class ControllableTask
|
||||
{
|
||||
public:
|
||||
using Result = T;
|
||||
virtual ~ControllableTask() {}
|
||||
virtual T run(TaskControl& control) = 0;
|
||||
virtual Result run(TaskControl& control) = 0;
|
||||
};
|
||||
|
||||
#endif // CONTROLLABLETASK_H
|
||||
|
|
|
|||
|
|
@ -4,6 +4,14 @@
|
|||
|
||||
namespace {
|
||||
|
||||
class registerMetaTypes {
|
||||
public:
|
||||
registerMetaTypes()
|
||||
{
|
||||
qRegisterMetaType<ExplainRoot::SPtr>();
|
||||
}
|
||||
} registerMetaTypes_instance;
|
||||
|
||||
ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan)
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <QList>
|
||||
//#include <QVariant>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <QMetaType>
|
||||
|
||||
namespace Json {
|
||||
|
||||
|
|
@ -161,3 +161,4 @@ public:
|
|||
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ExplainRoot::SPtr);
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@
|
|||
|
||||
#include <QFutureInterface>
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
#include "ControllableTask.h"
|
||||
#include "TaskControl.h"
|
||||
|
||||
template <typename T>
|
||||
class RunControllableTask : public QFutureInterface<T> , public QRunnable
|
||||
{
|
||||
public:
|
||||
RunControllableTask(ControllableTask<T>* tsk) : task(tsk) { }
|
||||
virtial ~RunControllableTask() { delete task; }
|
||||
virtual ~RunControllableTask() { delete task; }
|
||||
|
||||
QFuture<T> start()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -7,8 +7,7 @@
|
|||
|
||||
#include <QFutureInterfaceBase>
|
||||
|
||||
class TaskControl
|
||||
{
|
||||
class TaskControl {
|
||||
public:
|
||||
TaskControl(QFutureInterfaceBase *f) : fu(f) { }
|
||||
bool shouldRun() const { return !fu->isCanceled(); }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
*/
|
||||
#include "ControllableTask.h"
|
||||
#include "RunControllableTask.h"
|
||||
|
||||
#include <QFuture>
|
||||
/**
|
||||
* @brief The TaskExecutor class
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
#include "WorkManager.h"
|
||||
|
||||
#include <QRunnable>
|
||||
#include <QThreadPool>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
|
||||
class WorkManagerImpl: public WorkManager {
|
||||
public:
|
||||
void addRunnable(QRunnable *runnable) override;
|
||||
void addWork(Work work) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<WorkManager> WorkManager::getWorkManager()
|
||||
{
|
||||
static std::shared_ptr<WorkManager> wm = std::make_shared<WorkManagerImpl>();
|
||||
return wm;
|
||||
}
|
||||
|
||||
void WorkManagerImpl::addRunnable(QRunnable *runnable)
|
||||
{
|
||||
auto tp = QThreadPool::globalInstance();
|
||||
tp->start(runnable);
|
||||
}
|
||||
|
||||
class CallableTask : public QRunnable {
|
||||
public:
|
||||
CallableTask(WorkManager::Work &&w)
|
||||
: work(std::move(w))
|
||||
{}
|
||||
protected:
|
||||
void run() final
|
||||
{
|
||||
work();
|
||||
}
|
||||
private:
|
||||
WorkManager::Work work;
|
||||
};
|
||||
|
||||
void WorkManagerImpl::addWork(Work work)
|
||||
{
|
||||
addRunnable(new CallableTask(std::move(work)));
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#ifndef WORKMANAGER_H
|
||||
#define WORKMANAGER_H
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
class QRunnable;
|
||||
|
||||
class WorkManager {
|
||||
public:
|
||||
|
||||
static std::shared_ptr<WorkManager> getWorkManager();
|
||||
|
||||
using Work = std::function<void()>;
|
||||
|
||||
virtual ~WorkManager() = default;
|
||||
virtual void addRunnable(QRunnable *runnable) = 0;
|
||||
virtual void addWork(Work work) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif // WORKMANAGER_H
|
||||
|
|
@ -31,7 +31,6 @@ SOURCES += my_boost_assert_handler.cpp \
|
|||
QueuedBackgroundTask.cpp \
|
||||
ExplainTreeModelItem.cpp \
|
||||
jsoncpp.cpp \
|
||||
WorkManager.cpp \
|
||||
SqlParser.cpp \
|
||||
SqlAstNode.cpp \
|
||||
SqlAstSelectList.cpp \
|
||||
|
|
@ -48,7 +47,6 @@ HEADERS += PasswordManager.h \
|
|||
Expected.h \
|
||||
ExplainTreeModelItem.h \
|
||||
json/json.h \
|
||||
WorkManager.h \
|
||||
TaskControl.h \
|
||||
ControllableTask.h \
|
||||
RunControllableTask.h \
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
#include "ASyncWindow.h"
|
||||
#include <QTimer>
|
||||
|
||||
ASyncWindow::ASyncWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
{}
|
||||
|
||||
void ASyncWindow::QueueTask(TSQueue::t_Callable c)
|
||||
{
|
||||
m_taskQueue.add(std::move(c));
|
||||
// Theoretically this needs to be only called if the queue was empty because otherwise it already would
|
||||
// be busy emptying the queue. For now however I think it is safer to call it just to make sure.
|
||||
QMetaObject::invokeMethod(this, "processCallableQueue", Qt::QueuedConnection); // queues on main thread
|
||||
}
|
||||
|
||||
void ASyncWindow::processCallableQueue()
|
||||
{
|
||||
if (!m_taskQueue.empty()) {
|
||||
auto c = m_taskQueue.pop();
|
||||
c();
|
||||
if (!m_taskQueue.empty()) {
|
||||
QTimer::singleShot(0, this, SLOT(processCallableQueue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef ASYNCWINDOW_H
|
||||
#define ASYNCWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "tsqueue.h"
|
||||
|
||||
class ASyncWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ASyncWindow(QWidget *parent);
|
||||
/* Meant to be called from other threads to pass a code block
|
||||
* that has to be executed in the context of the thread of the window.
|
||||
*/
|
||||
void QueueTask(TSQueue::t_Callable c);
|
||||
private:
|
||||
TSQueue m_taskQueue;
|
||||
private slots:
|
||||
|
||||
void processCallableQueue();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // ASYNCWINDOW_H
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
#include "ApplicationWindow.h"
|
||||
#include "ui_ApplicationWindow.h"
|
||||
|
||||
ApplicationWindow::ApplicationWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::ApplicationWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
ApplicationWindow::~ApplicationWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#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
|
||||
|
|
@ -1,145 +0,0 @@
|
|||
<?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>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
#include "TablesPage.h"
|
||||
#include "CatalogInspector.h"
|
||||
#include "ui_TablesPage.h"
|
||||
|
||||
#include "catalog/PgAttribute.h"
|
||||
|
|
@ -10,7 +10,7 @@
|
|||
#include "ConstraintModel.h"
|
||||
#include "IconColumnDelegate.h"
|
||||
#include "IndexModel.h"
|
||||
#include "DatabaseWindow.h"
|
||||
#include "OpenDatabase.h"
|
||||
#include "PgLabItemDelegate.h"
|
||||
#include "PropertiesPage.h"
|
||||
#include "ResultTableModelUtil.h"
|
||||
|
|
@ -21,11 +21,11 @@
|
|||
#include "SqlCodePreview.h"
|
||||
#include <QStringBuilder>
|
||||
#include <unordered_set>
|
||||
#include "plugin_support/IPluginContentWidgetContext.h"
|
||||
|
||||
TablesPage::TablesPage(DatabaseWindow *parent)
|
||||
: QWidget(parent)
|
||||
CatalogInspector::CatalogInspector(IPluginContentWidgetContext *context_, QWidget *parent)
|
||||
: PluginContentWidget(context_, parent)
|
||||
, ui(new Ui::TablesPage)
|
||||
, m_window(parent)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
|
@ -62,24 +62,24 @@ TablesPage::TablesPage(DatabaseWindow *parent)
|
|||
// ---------------
|
||||
// Table selection
|
||||
connect(ui->tableListTable->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
||||
&TablesPage::tableListTable_currentRowChanged);
|
||||
&CatalogInspector::tableListTable_currentRowChanged);
|
||||
|
||||
connect(m_tablesModel, &QAbstractItemModel::layoutChanged,
|
||||
this, &TablesPage::tableListTable_layoutChanged);
|
||||
this, &CatalogInspector::tableListTable_layoutChanged);
|
||||
|
||||
//layoutChanged(const QList<QPersistentModelIndex> &parents = ..., QAbstractItemModel::LayoutChangeHint hint = ...)
|
||||
|
||||
connect(ui->constraintsTable->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
&TablesPage::constraintsTable_selectionChanged);
|
||||
&CatalogInspector::constraintsTable_selectionChanged);
|
||||
connect(ui->constraintsTable->model(), &QAbstractItemModel::modelReset, this,
|
||||
&TablesPage::constraintsTable_modelReset);
|
||||
&CatalogInspector::constraintsTable_modelReset);
|
||||
|
||||
// React to changes in de selected indexes, does not trigger when model is reset
|
||||
connect(ui->indexesTable->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
&TablesPage::indexesTable_selectionChanged);
|
||||
&CatalogInspector::indexesTable_selectionChanged);
|
||||
// Capture model reset independently
|
||||
connect(ui->indexesTable->model(), &QAbstractItemModel::modelReset, this,
|
||||
&TablesPage::indexesTable_modelReset);
|
||||
&CatalogInspector::indexesTable_modelReset);
|
||||
|
||||
// Non designer based code
|
||||
// - Columns page
|
||||
|
|
@ -103,12 +103,15 @@ TablesPage::TablesPage(DatabaseWindow *parent)
|
|||
|
||||
// Force focus on columns tab by default
|
||||
ui->twDetails->setCurrentIndex(0);
|
||||
auto db = context_->getObject<OpenDatabase>();
|
||||
|
||||
setCatalog(db->catalog());
|
||||
|
||||
retranslateUi(false);
|
||||
}
|
||||
|
||||
|
||||
void TablesPage::retranslateUi(bool all)
|
||||
void CatalogInspector::retranslateUi(bool all)
|
||||
{
|
||||
if (all)
|
||||
ui->retranslateUi(this);
|
||||
|
|
@ -124,12 +127,12 @@ void TablesPage::retranslateUi(bool all)
|
|||
|
||||
}
|
||||
|
||||
TablesPage::~TablesPage()
|
||||
CatalogInspector::~CatalogInspector()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
||||
void CatalogInspector::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
||||
{
|
||||
m_catalog = cat;
|
||||
m_tablesModel->setCatalog(cat);
|
||||
|
|
@ -143,13 +146,28 @@ void TablesPage::setCatalog(std::shared_ptr<PgDatabaseCatalog> cat)
|
|||
highlighter->setTypes(*cat->types());
|
||||
}
|
||||
|
||||
void TablesPage::setNamespaceFilter(TablesTableModel::NamespaceFilter filter)
|
||||
void CatalogInspector::setNamespaceFilter(TablesTableModel::NamespaceFilter filter)
|
||||
{
|
||||
m_tablesModel->setNamespaceFilter(filter);
|
||||
QString hint = "Catalog instpector";
|
||||
QString caption = "Inspector";
|
||||
switch (filter) {
|
||||
case TablesTableModel::PgCatalog:
|
||||
hint += " - pg_catalog";
|
||||
caption = "pg_catalog";
|
||||
break;
|
||||
case TablesTableModel::InformationSchema:
|
||||
hint += " - information_schema";
|
||||
caption = "information_schema";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context()->setCaption(this, caption, hint);
|
||||
}
|
||||
|
||||
|
||||
void TablesPage::tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
void CatalogInspector::tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (current.row() != previous.row()) {
|
||||
if (current.isValid()) {
|
||||
|
|
@ -162,7 +180,7 @@ void TablesPage::tableListTable_currentRowChanged(const QModelIndex ¤t, co
|
|||
}
|
||||
|
||||
|
||||
void TablesPage::tableListTable_layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint )
|
||||
void CatalogInspector::tableListTable_layoutChanged(const QList<QPersistentModelIndex> &, QAbstractItemModel::LayoutChangeHint )
|
||||
{
|
||||
auto&& index = ui->tableListTable->selectionModel()->currentIndex();
|
||||
if (index.isValid()) {
|
||||
|
|
@ -174,7 +192,7 @@ void TablesPage::tableListTable_layoutChanged(const QList<QPersistentModelIndex>
|
|||
}
|
||||
|
||||
|
||||
void TablesPage::selectedTableChanged(const std::optional<PgClass> &table)
|
||||
void CatalogInspector::selectedTableChanged(const std::optional<PgClass> &table)
|
||||
{
|
||||
m_columnsPage->setData(m_catalog, table);
|
||||
|
||||
|
|
@ -190,7 +208,7 @@ void TablesPage::selectedTableChanged(const std::optional<PgClass> &table)
|
|||
updateSqlTab(table);
|
||||
}
|
||||
|
||||
void TablesPage::constraintsTable_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
|
||||
void CatalogInspector::constraintsTable_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
|
||||
{
|
||||
const auto indexes = ui->constraintsTable->selectionModel()->selectedIndexes();
|
||||
std::unordered_set<int> rijen;
|
||||
|
|
@ -207,12 +225,12 @@ void TablesPage::constraintsTable_selectionChanged(const QItemSelection &/*selec
|
|||
ui->constraintSqlEdit->setPlainText(drops % "\n" % creates);
|
||||
}
|
||||
|
||||
void TablesPage::constraintsTable_modelReset()
|
||||
void CatalogInspector::constraintsTable_modelReset()
|
||||
{
|
||||
ui->constraintSqlEdit->clear();
|
||||
}
|
||||
|
||||
void TablesPage::indexesTable_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
|
||||
void CatalogInspector::indexesTable_selectionChanged(const QItemSelection &/*selected*/, const QItemSelection &/*deselected*/)
|
||||
{
|
||||
const auto indexes = ui->indexesTable->selectionModel()->selectedIndexes();
|
||||
std::unordered_set<int> rijen;
|
||||
|
|
@ -230,21 +248,22 @@ void TablesPage::indexesTable_selectionChanged(const QItemSelection &/*selected*
|
|||
|
||||
}
|
||||
|
||||
void TablesPage::indexesTable_modelReset()
|
||||
void CatalogInspector::indexesTable_modelReset()
|
||||
{
|
||||
ui->indexSqlEdit->clear();
|
||||
}
|
||||
|
||||
void TablesPage::on_tableListTable_doubleClicked(const QModelIndex &index)
|
||||
void CatalogInspector::on_tableListTable_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
PgClass table = m_tablesModel->getTable(index.row());
|
||||
if (table.oid() != InvalidOid) {
|
||||
m_window->newCrudPage(table);
|
||||
context()->moduleAction("pglab.crudpage", "open", {
|
||||
{ "oid", table.oid() }
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void TablesPage::updateSqlTab(const std::optional<PgClass> &table)
|
||||
void CatalogInspector::updateSqlTab(const std::optional<PgClass> &table)
|
||||
{
|
||||
if (!table.has_value()) {
|
||||
m_sqlCodePreview->clear();
|
||||
|
|
@ -286,3 +305,31 @@ void TablesPage::updateSqlTab(const std::optional<PgClass> &table)
|
|||
//
|
||||
m_sqlCodePreview->setPlainText(drop_sql % "\n\n" % create_sql);
|
||||
}
|
||||
|
||||
|
||||
void CatalogInspectorModule::init()
|
||||
{
|
||||
registerModuleAction("open",
|
||||
[this] (IPluginContentWidgetContext* context,
|
||||
const ModuleActionParameters ¶ms)
|
||||
{
|
||||
moduleAction_open(context, params);
|
||||
});
|
||||
}
|
||||
|
||||
void CatalogInspectorModule::moduleAction_open(
|
||||
IPluginContentWidgetContext* context,
|
||||
const ModuleActionParameters ¶ms
|
||||
)
|
||||
{
|
||||
auto ct = new CatalogInspector(context, nullptr);
|
||||
context->addContentWidget(this, ct);
|
||||
auto nsf = params.at("namespace-filter").toString();
|
||||
TablesTableModel::NamespaceFilter filter = TablesTableModel::User;
|
||||
if (nsf == "pg_catalog") filter = TablesTableModel::PgCatalog;
|
||||
else if (nsf == "information_schema") filter = TablesTableModel::InformationSchema;
|
||||
ct->setNamespaceFilter(filter);
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_MODULE_CAT(CatalogInspectorModule, "Catalog inspector tool",
|
||||
"pglab.catalog-inspector", "database")
|
||||
|
|
@ -6,6 +6,8 @@
|
|||
#include <optional>
|
||||
#include <QItemSelection>
|
||||
#include "TablesTableModel.h"
|
||||
#include "plugin_support/PluginContentWidget.h"
|
||||
#include "plugin_support/PluginModule.h"
|
||||
|
||||
namespace Ui {
|
||||
class TablesPage;
|
||||
|
|
@ -18,30 +20,25 @@ class ConstraintModel;
|
|||
class PgDatabaseCatalog;
|
||||
class NamespaceFilterWidget;
|
||||
class IndexModel;
|
||||
class DatabaseWindow;
|
||||
class PropertiesPage;
|
||||
class TriggerPage;
|
||||
class PgClass;
|
||||
class SqlCodePreview;
|
||||
|
||||
class TablesPage : public QWidget
|
||||
class CatalogInspector : public PluginContentWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TablesPage(DatabaseWindow *parent = nullptr);
|
||||
~TablesPage();
|
||||
explicit CatalogInspector(IPluginContentWidgetContext *context, QWidget *parent = nullptr);
|
||||
~CatalogInspector();
|
||||
|
||||
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat);
|
||||
void setNamespaceFilter(TablesTableModel::NamespaceFilter filter);
|
||||
private:
|
||||
Ui::TablesPage *ui;
|
||||
DatabaseWindow *m_window;
|
||||
// QWidget *m_columnsTab;
|
||||
ColumnPage *m_columnsPage;
|
||||
// QWidget *m_propertiesTab;
|
||||
PropertiesPage *m_propertiesPage;
|
||||
// QWidget *m_triggerTab;
|
||||
TriggerPage *m_triggerPage;
|
||||
SqlCodePreview *m_sqlCodePreview;
|
||||
std::shared_ptr<PgDatabaseCatalog> m_catalog;
|
||||
|
|
@ -49,10 +46,8 @@ private:
|
|||
ColumnTableModel* m_columnsModel = nullptr;
|
||||
ConstraintModel* m_constraintModel = nullptr;
|
||||
IndexModel* m_indexModel = nullptr;
|
||||
//NamespaceFilterWidget* m_namespaceFilterWidget;
|
||||
|
||||
void retranslateUi(bool all = true);
|
||||
// QWidget* addDetailTab(QWidget *contents, bool infront = false);
|
||||
|
||||
void selectedTableChanged(const std::optional<PgClass> &table);
|
||||
void updateSqlTab(const std::optional<PgClass> &table);
|
||||
|
|
@ -60,7 +55,6 @@ private slots:
|
|||
|
||||
void tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void tableListTable_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint);
|
||||
// void constraintsTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void constraintsTable_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void constraintsTable_modelReset();
|
||||
void indexesTable_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
|
|
@ -68,4 +62,17 @@ private slots:
|
|||
void on_tableListTable_doubleClicked(const QModelIndex &index);
|
||||
};
|
||||
|
||||
class CatalogInspectorModule: public PluginModule {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using PluginModule::PluginModule;
|
||||
|
||||
void init();
|
||||
private slots:
|
||||
|
||||
private:
|
||||
void moduleAction_open(IPluginContentWidgetContext* context, const ModuleActionParameters ¶ms);
|
||||
};
|
||||
|
||||
|
||||
#endif // TABLESPAGE_H
|
||||
|
|
@ -5,8 +5,8 @@
|
|||
#include "UserConfiguration.h"
|
||||
#include <QTextStream>
|
||||
|
||||
CodeGenerator::CodeGenerator(QWidget *parent) :
|
||||
PlgPage(parent),
|
||||
CodeGenerator::CodeGenerator(IPluginContentWidgetContext *context, QWidget *parent) :
|
||||
PluginContentWidget(context, parent),
|
||||
ui(new Ui::CodeGenerator)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
|
@ -27,11 +27,8 @@ void CodeGenerator::Init(std::shared_ptr<PgDatabaseCatalog> catalog, QString que
|
|||
m_query = std::move(query);
|
||||
m_dbres = std::move(dbres);
|
||||
generateCode();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::on_updateCodeButton_clicked()
|
||||
{
|
||||
generateCode();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define CODEGENERATOR_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "PlgPage.h"
|
||||
#include "plugin_support/PluginContentWidget.h"
|
||||
#include "Pgsql_declare.h"
|
||||
|
||||
namespace Ui {
|
||||
|
|
@ -11,12 +11,12 @@ class CodeGenerator;
|
|||
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class CodeGenerator : public PlgPage
|
||||
class CodeGenerator : public PluginContentWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CodeGenerator(QWidget *parent = nullptr);
|
||||
CodeGenerator(IPluginContentWidgetContext *context, QWidget *parent = nullptr);
|
||||
~CodeGenerator();
|
||||
|
||||
void Init(std::shared_ptr<PgDatabaseCatalog> catalog, QString query, std::shared_ptr<const Pgsql::Result> dbres);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "CrudModel.h"
|
||||
#include "ASyncWindow.h"
|
||||
#include "OpenDatabase.h"
|
||||
#include "catalog/PgDatabaseCatalog.h"
|
||||
#include "catalog/PgAttribute.h"
|
||||
|
|
@ -7,7 +6,6 @@
|
|||
#include "catalog/PgConstraintContainer.h"
|
||||
#include "GlobalIoService.h"
|
||||
#include "SqlFormattingUtils.h"
|
||||
#include "WorkManager.h"
|
||||
#include "Pgsql_oids.h"
|
||||
#include <QtConcurrent>
|
||||
#include <QFuture>
|
||||
|
|
@ -19,8 +17,8 @@
|
|||
#include <string>
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
CrudModel::CrudModel(ASyncWindow *async_window)
|
||||
: m_asyncWindow(async_window)
|
||||
CrudModel::CrudModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
, m_dbConn(*getGlobalAsioIoService())
|
||||
{
|
||||
qDebug("CrudModel created");
|
||||
|
|
@ -172,7 +170,8 @@ void CrudModel::loadData()
|
|||
if (res.valid()) {
|
||||
auto dbres = res.get();
|
||||
if (dbres && *dbres) {
|
||||
m_asyncWindow->QueueTask([this, dbres]() { loadIntoModel(dbres); });
|
||||
QMetaObject::invokeMethod(this, "loadIntoModel", Qt::QueuedConnection,
|
||||
Q_ARG(std::shared_ptr<Pgsql::Result>, dbres));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -196,7 +195,7 @@ void CrudModel::loadIntoModel(std::shared_ptr<Pgsql::Result> data)
|
|||
|
||||
void CrudModel::initRowMapping()
|
||||
{
|
||||
m_rowMapping.resize(m_rowCount);
|
||||
m_rowMapping.resize(static_cast<size_t>(m_rowCount));
|
||||
for (int i = 0; i < m_rowCount; ++i)
|
||||
m_rowMapping[i] = RowMapping{ i };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
class PgConstraint;
|
||||
class OpenDatabase;
|
||||
class ASyncWindow;
|
||||
|
||||
/**
|
||||
* @brief The CrudModel class
|
||||
|
|
@ -55,7 +54,7 @@ class ASyncWindow;
|
|||
class CrudModel: public QAbstractTableModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CrudModel(ASyncWindow *async_win);
|
||||
explicit CrudModel(QObject *parent = nullptr);
|
||||
~CrudModel() override;
|
||||
|
||||
void setConfig(std::shared_ptr<OpenDatabase> db, const PgClass &table);
|
||||
|
|
@ -231,8 +230,6 @@ private:
|
|||
};
|
||||
using RowMappingVector = std::vector<RowMapping>;
|
||||
|
||||
|
||||
ASyncWindow * m_asyncWindow;
|
||||
std::shared_ptr<OpenDatabase> m_database;
|
||||
std::optional<PgClass> m_table;
|
||||
std::optional<PgConstraint> m_primaryKey;
|
||||
|
|
@ -266,13 +263,6 @@ private:
|
|||
/// call on initial load to fill in the mappings
|
||||
void initRowMapping();
|
||||
|
||||
// using RedirectVec = std::vector<int>;
|
||||
// /// In sync with the actual table, used to efficiently find the correct row in the result
|
||||
// RedirectVec m_redirectVector;
|
||||
|
||||
|
||||
void loadIntoModel(std::shared_ptr<Pgsql::Result> data);
|
||||
|
||||
Value getData(const QModelIndex &index) const;
|
||||
Oid getType(int column) const;
|
||||
|
||||
|
|
@ -320,11 +310,8 @@ private:
|
|||
int attNumToCol(int attnum) const { return attnum - 1; }
|
||||
private slots:
|
||||
|
||||
void loadIntoModel(std::shared_ptr<Pgsql::Result> data);
|
||||
void connectionStateChanged(ASyncDBConnection::State state);
|
||||
// void queryResult(std::shared_ptr<Pgsql::Result> result);
|
||||
// void queryError();
|
||||
|
||||
// void dataProcessingFutureFinished();
|
||||
};
|
||||
|
||||
#endif // CRUDMODEL_H
|
||||
|
|
|
|||
|
|
@ -1,21 +1,24 @@
|
|||
#include "CrudTab.h"
|
||||
#include "ui_CrudTab.h"
|
||||
#include "CrudModel.h"
|
||||
#include "DatabaseWindow.h"
|
||||
#include "ResultTableModelUtil.h"
|
||||
#include "PgLabItemDelegate.h"
|
||||
#include "IntegerRange.h"
|
||||
#include "OpenDatabase.h"
|
||||
#include "catalog/PgClassContainer.h"
|
||||
#include "catalog/PgDatabaseCatalog.h"
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <iterator>
|
||||
#include <set>
|
||||
#include "plugin_support/PluginRegister.h"
|
||||
#include "plugin_support/IPluginContentWidgetContext.h"
|
||||
|
||||
|
||||
CrudTab::CrudTab(DatabaseWindow *parent)
|
||||
: PlgPage(parent)
|
||||
CrudTab::CrudTab(IPluginContentWidgetContext *context, QWidget *parent)
|
||||
: PluginContentWidget(context, parent)
|
||||
, ui(new Ui::CrudTab)
|
||||
, m_window(parent)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
|
|
@ -43,11 +46,11 @@ CrudTab::~CrudTab()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void CrudTab::setConfig(std::shared_ptr<OpenDatabase> db, const PgClass &table)
|
||||
void CrudTab::setConfig(Oid oid) //std::shared_ptr<OpenDatabase> db, const PgClass &table)
|
||||
{
|
||||
m_db = db;
|
||||
m_table = table;
|
||||
m_crudModel->setConfig(db, table);
|
||||
m_db = context()->getObject<OpenDatabase>(); // getDatabase();;
|
||||
m_table = *m_db->catalog()->classes()->getByKey(oid);
|
||||
m_crudModel->setConfig(m_db, *m_table);
|
||||
}
|
||||
|
||||
void CrudTab::refresh()
|
||||
|
|
@ -90,19 +93,6 @@ void CrudTab::on_actionRemove_rows_triggered()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<QAction*> CrudTab::getToolbarActions()
|
||||
{
|
||||
if (actions.empty()) {
|
||||
QAction *action = new QAction(QIcon(":/icons/script_go.png"), tr("Refresh"), this);
|
||||
action->setShortcut(QKeySequence(Qt::Key_F5));
|
||||
connect(action, &QAction::triggered, this, &CrudTab::refresh);
|
||||
actions.push_back(action);
|
||||
|
||||
actions.push_back(ui->actionRemove_rows);
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
void CrudTab::headerCustomContextMenu(const QPoint &pos)
|
||||
{
|
||||
auto menu = new QMenu(this);
|
||||
|
|
@ -115,3 +105,37 @@ void CrudTab::headerCustomContextMenu(const QPoint &pos)
|
|||
auto horizontal_header = ui->tableView->horizontalHeader();
|
||||
menu->popup(horizontal_header->mapToGlobal(pos));
|
||||
}
|
||||
|
||||
|
||||
void CrudPageModule::init()
|
||||
{
|
||||
registerModuleAction("open",
|
||||
[this] (IPluginContentWidgetContext* context,
|
||||
const ModuleActionParameters ¶ms)
|
||||
{
|
||||
moduleAction_open(context, params);
|
||||
});
|
||||
|
||||
{
|
||||
LWidgetAction wa("Refresh", SLOT(refresh()));
|
||||
wa.setMenuLocation(MenuPath("Window/1"));
|
||||
wa.setIcon(QIcon(":/icons/script_go.png"));
|
||||
wa.setShortcut(QKeySequence(Qt::Key_F5));
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
}
|
||||
|
||||
void CrudPageModule::moduleAction_open(
|
||||
IPluginContentWidgetContext* context,
|
||||
const ModuleActionParameters ¶ms
|
||||
)
|
||||
{
|
||||
// create new widget for specified table
|
||||
// hand widget to context for display
|
||||
CrudTab *ct = new CrudTab(context, nullptr);
|
||||
context->addContentWidget(this, ct); // maybe CrudTab should do this
|
||||
ct->setConfig(params.at("oid").toUInt());
|
||||
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_MODULE_CAT(CrudPageModule, "CRUD tool", "pglab.crudpage", "database")
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
#include "catalog/PgClass.h"
|
||||
#include <QWidget>
|
||||
#include "PlgPage.h"
|
||||
#include "plugin_support/PluginContentWidget.h"
|
||||
#include "plugin_support/PluginModule.h"
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
|
|
@ -13,26 +14,21 @@ namespace Ui {
|
|||
|
||||
class OpenDatabase;
|
||||
class CrudModel;
|
||||
class DatabaseWindow;
|
||||
|
||||
class CrudTab : public PlgPage
|
||||
class CrudTab : public PluginContentWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CrudTab(DatabaseWindow *parent = 0);
|
||||
explicit CrudTab(IPluginContentWidgetContext *context, QWidget *parent = nullptr);
|
||||
~CrudTab() override;
|
||||
|
||||
void setConfig(std::shared_ptr<OpenDatabase> db, const PgClass &table);
|
||||
|
||||
void setConfig(Oid oid);
|
||||
public slots:
|
||||
void refresh();
|
||||
|
||||
virtual std::vector<QAction*> getToolbarActions() override;
|
||||
private:
|
||||
Ui::CrudTab *ui;
|
||||
|
||||
DatabaseWindow *m_window;
|
||||
|
||||
std::shared_ptr<OpenDatabase> m_db;
|
||||
std::optional<PgClass> m_table;
|
||||
|
||||
|
|
@ -40,9 +36,21 @@ private:
|
|||
std::vector<QAction*> actions;
|
||||
|
||||
private slots:
|
||||
// void tableView_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void on_actionRemove_rows_triggered();
|
||||
void headerCustomContextMenu(const QPoint &pos);
|
||||
};
|
||||
|
||||
class CrudPageModule: public PluginModule {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using PluginModule::PluginModule;
|
||||
|
||||
void init();
|
||||
private slots:
|
||||
|
||||
private:
|
||||
void moduleAction_open(IPluginContentWidgetContext* context, const ModuleActionParameters ¶ms);
|
||||
};
|
||||
|
||||
|
||||
#endif // CRUDTAB_H
|
||||
|
|
|
|||
|
|
@ -1,84 +1,49 @@
|
|||
#include "DatabaseWindow.h"
|
||||
#include "ui_MainWindow.h"
|
||||
#include "TablesPage.h"
|
||||
#include "plugin_support/IPluginContentWidgetContext.h"
|
||||
#include "util.h"
|
||||
#include "MasterController.h"
|
||||
#include "TaskExecutor.h"
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QMetaMethod>
|
||||
#include <QTableView>
|
||||
|
||||
// Pages that should become modules
|
||||
#include "EditTableWidget.h"
|
||||
#include "CodeGenerator.h"
|
||||
#include "FunctionsPage.h"
|
||||
#include "SequencesPage.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QTextTable>
|
||||
#include <QElapsedTimer>
|
||||
#include <algorithm>
|
||||
#include <QCloseEvent>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaMethod>
|
||||
#include "QueryTab.h"
|
||||
#include "util.h"
|
||||
#include "PlgPage.h"
|
||||
#include "CodeGenerator.h"
|
||||
#include "MasterController.h"
|
||||
#include "CrudTab.h"
|
||||
#include "WorkManager.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include "EditTableWidget.h"
|
||||
|
||||
namespace pg = Pgsql;
|
||||
|
||||
|
||||
DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent)
|
||||
: ASyncWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
: LMainWindow(parent)
|
||||
|
||||
, m_masterController(master)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->tabWidget->setDocumentMode(true);
|
||||
connect(&loadWatcher, &QFutureWatcher<LoadCatalog::Result>::finished,
|
||||
this, &DatabaseWindow::catalogLoaded);
|
||||
|
||||
initModuleMenus();
|
||||
QMetaObject::connectSlotsByName(this);
|
||||
}
|
||||
|
||||
DatabaseWindow::~DatabaseWindow()
|
||||
{
|
||||
loader.reset();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
QueryTab* DatabaseWindow::newSqlPage()
|
||||
{
|
||||
QueryTab *qt = new QueryTab(this);
|
||||
qt->setConfig(m_config, m_database->catalog());
|
||||
addPage(qt, "Tab");
|
||||
qt->newdoc();
|
||||
qt->focusEditor();
|
||||
return qt;
|
||||
}
|
||||
DatabaseWindow::~DatabaseWindow() = default;
|
||||
|
||||
void DatabaseWindow::newCreateTablePage()
|
||||
{
|
||||
auto w = new EditTableWidget(m_database, this);
|
||||
ui->tabWidget->addTab(w, "Create table");
|
||||
}
|
||||
|
||||
void DatabaseWindow::newCrudPage(const PgClass &table)
|
||||
{
|
||||
CrudTab *ct = new CrudTab(this);
|
||||
ct->setConfig(m_database, table);
|
||||
addPage(ct, table.objectName());
|
||||
m_tabWidget->addTab(w, "Create table");
|
||||
}
|
||||
|
||||
void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr<const Pgsql::Result> dbres)
|
||||
{
|
||||
auto cgtab = new CodeGenerator(this);
|
||||
auto cgtab = new CodeGenerator(context(), this);
|
||||
cgtab->Init(m_database->catalog(), query, dbres);
|
||||
addPage(cgtab, "Codegen");
|
||||
}
|
||||
|
||||
|
||||
QueryTab *DatabaseWindow::GetActiveQueryTab()
|
||||
{
|
||||
QWidget *widget = ui->tabWidget->currentWidget();
|
||||
QueryTab *qt = dynamic_cast<QueryTab*>(widget);
|
||||
return qt;
|
||||
}
|
||||
|
||||
void DatabaseWindow::setConfig(const ConnectionConfig &config)
|
||||
{
|
||||
m_config = config;
|
||||
|
|
@ -87,10 +52,9 @@ void DatabaseWindow::setConfig(const ConnectionConfig &config)
|
|||
title += m_config.name().c_str();
|
||||
setWindowTitle(title);
|
||||
|
||||
loader = std::make_shared<QLoad>(m_config, [this](QRunnable *) {
|
||||
QueueTask([this] () { catalogLoaded(); });
|
||||
} );
|
||||
WorkManager::getWorkManager()->addRunnable(loader.get());
|
||||
auto f = TaskExecutor::run(new LoadCatalog(m_config));
|
||||
loadWatcher.setFuture(f);
|
||||
|
||||
} catch (std::runtime_error &ex) {
|
||||
QMessageBox::critical(this, "Error reading database",
|
||||
QString::fromUtf8(ex.what()));
|
||||
|
|
@ -102,32 +66,23 @@ void DatabaseWindow::setConfig(const ConnectionConfig &config)
|
|||
void DatabaseWindow::catalogLoaded()
|
||||
{
|
||||
try {
|
||||
SCOPE_EXIT { loader.reset(); };
|
||||
m_database = loader->GetResult();
|
||||
m_database = loadWatcher.future().result();
|
||||
auto ctx = context();
|
||||
ctx->registerObject(m_database);
|
||||
|
||||
auto tt = new TablesPage(this);
|
||||
tt->setCatalog(m_database->catalog());
|
||||
ui->tabWidget->addTab(tt, "Tables");
|
||||
|
||||
auto pg_cat_tables = new TablesPage(this);
|
||||
pg_cat_tables->setNamespaceFilter(TablesTableModel::PgCatalog);
|
||||
pg_cat_tables->setCatalog(m_database->catalog());
|
||||
ui->tabWidget->addTab(pg_cat_tables, "pg_catalog");
|
||||
|
||||
auto info_schema_tables = new TablesPage(this);
|
||||
info_schema_tables->setNamespaceFilter(TablesTableModel::InformationSchema);
|
||||
info_schema_tables->setCatalog(m_database->catalog());
|
||||
ui->tabWidget->addTab(info_schema_tables, "information_schema");
|
||||
for (auto f : { "user", "pg_catalog", "information_schema" })
|
||||
ctx->moduleAction("pglab.catalog-inspector", "open", {
|
||||
{ "namespace-filter", f }
|
||||
});
|
||||
|
||||
auto functions_page = new FunctionsPage(this);
|
||||
functions_page->setCatalog(m_database->catalog());
|
||||
ui->tabWidget->addTab(functions_page, "Functions");
|
||||
m_tabWidget->addTab(functions_page, "Functions");
|
||||
|
||||
auto sequences_page = new SequencesPage(this);
|
||||
sequences_page->setCatalog(m_database->catalog());
|
||||
ui->tabWidget->addTab(sequences_page, "Sequences");
|
||||
m_tabWidget->addTab(sequences_page, "Sequences");
|
||||
|
||||
newSqlPage();
|
||||
newCreateTablePage();
|
||||
} catch (std::runtime_error &ex) {
|
||||
QMessageBox::critical(this, "Error reading database",
|
||||
|
|
@ -137,71 +92,17 @@ void DatabaseWindow::catalogLoaded()
|
|||
}
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionLoad_SQL_triggered()
|
||||
{
|
||||
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
|
||||
QString file_name = QFileDialog::getOpenFileName(this,
|
||||
tr("Open sql query"), home_dir, tr("SQL files (*.sql *.txt)"));
|
||||
if ( ! file_name.isEmpty()) {
|
||||
QueryTab* qt = newSqlPage();
|
||||
qt->load(file_name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionSave_SQL_triggered()
|
||||
{
|
||||
QueryTab *tab = GetActiveQueryTab();
|
||||
if (tab) {
|
||||
tab->save();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionSave_SQL_as_triggered()
|
||||
{
|
||||
QueryTab *tab = GetActiveQueryTab();
|
||||
if (tab) {
|
||||
tab->saveAs();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionSave_copy_of_SQL_as_triggered()
|
||||
{
|
||||
QueryTab *tab = GetActiveQueryTab();
|
||||
if (tab) {
|
||||
tab->saveCopyAs();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionExport_data_triggered()
|
||||
{
|
||||
QueryTab *tab = GetActiveQueryTab();
|
||||
if (tab) {
|
||||
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
|
||||
QString file_name = QFileDialog::getSaveFileName(this,
|
||||
tr("Export data"), home_dir, tr("CSV file (*.csv)"));
|
||||
|
||||
tab->exportData(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionClose_triggered()
|
||||
{
|
||||
//close();
|
||||
on_tabWidget_tabCloseRequested(ui->tabWidget->currentIndex());
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionAbout_triggered()
|
||||
{
|
||||
QMessageBox::about(this, "pgLab 0.1", tr(
|
||||
"Copyrights 2016-2017, Eelke Klein, All Rights Reserved.\n"
|
||||
"Copyrights 2016-2019, Eelke Klein, All Rights Reserved.\n"
|
||||
"\n"
|
||||
"The program is provided AS IS with NO WARRANTY OF ANY KIND, "
|
||||
"INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS "
|
||||
"FOR A PARTICULAR PURPOSE.\n"
|
||||
"\n"
|
||||
"This program is dynamically linked with Qt 5.9 Copyright (C) 2017 "
|
||||
"This program is dynamically linked with Qt 5.12 Copyright (C) 2018 "
|
||||
"The Qt Company Ltd. https://www.qt.io/licensing/. \n"
|
||||
"\n"
|
||||
"Icons by fatcow http://www.fatcow.com/free-icons provided under Creative Commons "
|
||||
|
|
@ -210,76 +111,6 @@ void DatabaseWindow::on_actionAbout_triggered()
|
|||
|
||||
}
|
||||
|
||||
void DatabaseWindow::closeEvent(QCloseEvent* /*event*/)
|
||||
{
|
||||
// TODO collect which files need saving
|
||||
// std::vector<QString> files_to_save;
|
||||
// int n = ui->tabWidget->count();
|
||||
// for (int i = 0; i < n; ++i) {
|
||||
// QWidget *w = ui->tabWidget->widget(i);
|
||||
// QueryTab *qt = dynamic_cast<QueryTab*>(w);
|
||||
// if (qt) {
|
||||
// if (qt->isChanged()) {
|
||||
// files_to_save.push_back(qt->fileName());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// QString s;
|
||||
// for (const auto& e : files_to_save) {
|
||||
// s += e + "\n";
|
||||
// }
|
||||
|
||||
// QMessageBox msgBox;
|
||||
// msgBox.setIcon(QMessageBox::Warning);
|
||||
// msgBox.setText("The following documents need to be saved");
|
||||
// msgBox.setInformativeText(s);
|
||||
// msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
// msgBox.setDefaultButton(QMessageBox::Cancel);
|
||||
// //int ret =
|
||||
// msgBox.exec();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void DatabaseWindow::showEvent(QShowEvent *event)
|
||||
{
|
||||
if (!event->spontaneous()) {
|
||||
// m_queryTextChanged = false;
|
||||
}
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionNew_SQL_triggered()
|
||||
{
|
||||
newSqlPage();
|
||||
}
|
||||
|
||||
|
||||
void DatabaseWindow::on_tabWidget_tabCloseRequested(int index)
|
||||
{
|
||||
QWidget *widget = ui->tabWidget->widget(index);
|
||||
PlgPage *plg_page = dynamic_cast<PlgPage*>(widget);
|
||||
if (plg_page) {
|
||||
if (plg_page->canClose()) {
|
||||
removePage(plg_page);
|
||||
ui->tabWidget->removeTab(index);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// old behaviour shouldn't be needed any more when all pages have been migrated
|
||||
// to PlgPage
|
||||
QueryTab *qt = dynamic_cast<QueryTab*>(widget);
|
||||
if (qt && qt->canClose()) {
|
||||
ui->tabWidget->removeTab(index);
|
||||
}
|
||||
else if (index > 0) {
|
||||
ui->tabWidget->removeTab(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DatabaseWindow::on_actionShow_connection_manager_triggered()
|
||||
{
|
||||
m_masterController->showConnectionManager();
|
||||
|
|
@ -305,82 +136,3 @@ void DatabaseWindow::on_actionCopy_triggered()
|
|||
}
|
||||
|
||||
|
||||
void DatabaseWindow::on_actionCopy_as_C_string_triggered()
|
||||
{
|
||||
// Find which edit is active, copy the selected text or all text if no selection present
|
||||
// Put quote's around each line and add escapes.
|
||||
|
||||
QueryTab *tab = GetActiveQueryTab();
|
||||
if (tab) {
|
||||
tab->copyQueryAsCString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DatabaseWindow::on_actionCopy_as_raw_Cpp_string_triggered()
|
||||
{
|
||||
QueryTab *tab = GetActiveQueryTab();
|
||||
if (tab) {
|
||||
tab->copyQueryAsRawCppString();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWindow::addToolBarButtonsForPage(PlgPage *page)
|
||||
{
|
||||
std::vector<QAction*> actions = page->getToolbarActions();
|
||||
QList<QAction*> list;
|
||||
for (auto act : actions) {
|
||||
list.append(act);
|
||||
}
|
||||
ui->mainToolBar->addActions(list);
|
||||
}
|
||||
|
||||
void DatabaseWindow::removeToolBarButtonsForPage(PlgPage *page)
|
||||
{
|
||||
std::vector<QAction*> actions = page->getToolbarActions();
|
||||
for (auto act : actions) {
|
||||
ui->mainToolBar->removeAction(act);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DatabaseWindow::addPage(PlgPage* page, QString caption)
|
||||
{
|
||||
ui->tabWidget->addTab(page, caption);
|
||||
ui->tabWidget->setCurrentWidget(page);
|
||||
|
||||
//addToolBarButtonsForPage(page);
|
||||
}
|
||||
|
||||
void DatabaseWindow::removePage(PlgPage *)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_tabWidget_currentChanged(int index)
|
||||
{
|
||||
// remove buttons of old page
|
||||
if (m_previousPage) {
|
||||
removeToolBarButtonsForPage(m_previousPage);
|
||||
}
|
||||
|
||||
// add buttons of new page
|
||||
PlgPage * page = nullptr;
|
||||
if (index >= 0) {
|
||||
QWidget *widget = ui->tabWidget->widget(index);
|
||||
page = dynamic_cast<PlgPage*>(widget);
|
||||
if (page) {
|
||||
addToolBarButtonsForPage(page);
|
||||
}
|
||||
}
|
||||
m_previousPage = page;
|
||||
}
|
||||
|
||||
void DatabaseWindow::on_actionGenerate_code_triggered()
|
||||
{
|
||||
QueryTab *tab = GetActiveQueryTab();
|
||||
if (tab) {
|
||||
tab->generateCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,128 +1,75 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "ASyncDBConnection.h"
|
||||
#include "plugin_support/LMainWindow.h"
|
||||
#include "ConnectionConfig.h"
|
||||
#include "OpenDatabase.h"
|
||||
#include <QLabel>
|
||||
#include "ASyncWindow.h"
|
||||
#include <QLabel>
|
||||
#include <QRunnable>
|
||||
#include <QSocketNotifier>
|
||||
#include <memory>
|
||||
#include <future>
|
||||
#include "Pgsql_Connection.h"
|
||||
#include "QueuedBackgroundTask.h"
|
||||
#include <chrono>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
|
||||
#include <QMutex>
|
||||
#include <QWaitCondition>
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
#include "ControllableTask.h"
|
||||
#include <QFutureWatcher>
|
||||
#include <memory>
|
||||
|
||||
namespace Pgsql {
|
||||
class Connection;
|
||||
}
|
||||
|
||||
class QueryTab;
|
||||
class MasterController;
|
||||
class QCloseEvent;
|
||||
class OpenDatabase;
|
||||
class PgClass;
|
||||
class PlgPage;
|
||||
|
||||
class QTabWidget;
|
||||
|
||||
|
||||
/** This is the class for windows that handle tasks for a specific database/catalog
|
||||
*
|
||||
*/
|
||||
class DatabaseWindow : public ASyncWindow {
|
||||
class DatabaseWindow : public LMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DatabaseWindow(MasterController *master, QWidget *parent);
|
||||
DatabaseWindow(MasterController *master, QWidget *parent);
|
||||
~DatabaseWindow();
|
||||
|
||||
void setConfig(const ConnectionConfig &config);
|
||||
|
||||
std::shared_ptr<OpenDatabase> getDatabase() { return m_database; }
|
||||
|
||||
void newCrudPage(const PgClass &table);
|
||||
void newCodeGenPage(QString query, std::shared_ptr<const Pgsql::Result> dbres);
|
||||
|
||||
private:
|
||||
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
ConnectionConfig m_config;
|
||||
std::shared_ptr<OpenDatabase> m_database;
|
||||
|
||||
MasterController *m_masterController;
|
||||
PlgPage *m_previousPage = nullptr; ///< tracks which pages buttons were previously being displayed
|
||||
|
||||
class QLoad : public QueuedBackgroundTask {
|
||||
class LoadCatalog: public ControllableTask<OpenDatabase::OpenDatabaseSPtr> {
|
||||
public:
|
||||
explicit QLoad(ConnectionConfig config, CompletionFunction on_completion)
|
||||
: QueuedBackgroundTask(on_completion)
|
||||
, m_config(config)
|
||||
LoadCatalog(ConnectionConfig config)
|
||||
: m_config(config)
|
||||
{}
|
||||
|
||||
OpenDatabase::OpenDatabaseSPtr GetResult()
|
||||
{
|
||||
if (hasException()) rethrow();
|
||||
return result;
|
||||
}
|
||||
protected:
|
||||
|
||||
OpenDatabase::OpenDatabaseSPtr result;
|
||||
virtual void doRun()
|
||||
OpenDatabase::OpenDatabaseSPtr run(TaskControl& ) override
|
||||
{
|
||||
auto res = OpenDatabase::createOpenDatabase(m_config);
|
||||
result = res.get();
|
||||
return res.get();
|
||||
}
|
||||
private:
|
||||
|
||||
private:
|
||||
ConnectionConfig m_config;
|
||||
};
|
||||
|
||||
std::shared_ptr<QLoad> loader;
|
||||
QFutureWatcher<LoadCatalog::Result> loadWatcher;
|
||||
|
||||
|
||||
QueryTab *GetActiveQueryTab();
|
||||
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void showEvent(QShowEvent *event);
|
||||
QueryTab *newSqlPage();
|
||||
void newCreateTablePage();
|
||||
|
||||
private slots:
|
||||
|
||||
void catalogLoaded();
|
||||
|
||||
/// Called when a newly created page is added to the QTabWidget
|
||||
void addPage(PlgPage* page, QString caption);
|
||||
/// Called when a page is completely removed from the QTabWidget
|
||||
void removePage(PlgPage *page);
|
||||
|
||||
void addToolBarButtonsForPage(PlgPage *page);
|
||||
void removeToolBarButtonsForPage(PlgPage *page);
|
||||
//class PageData
|
||||
private slots:
|
||||
|
||||
void on_actionLoad_SQL_triggered();
|
||||
void on_actionSave_SQL_triggered();
|
||||
void on_actionExport_data_triggered();
|
||||
void on_actionClose_triggered();
|
||||
void on_actionAbout_triggered();
|
||||
void on_actionSave_SQL_as_triggered();
|
||||
void on_actionSave_copy_of_SQL_as_triggered();
|
||||
void on_actionNew_SQL_triggered();
|
||||
void on_tabWidget_tabCloseRequested(int index);
|
||||
void on_actionShow_connection_manager_triggered();
|
||||
void on_actionCopy_triggered();
|
||||
void on_actionCopy_as_C_string_triggered();
|
||||
void on_actionCopy_as_raw_Cpp_string_triggered();
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
void on_actionGenerate_code_triggered();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
|
|
@ -1,248 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>993</width>
|
||||
<height>804</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>pglab - database</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>7</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>993</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuTest">
|
||||
<property name="title">
|
||||
<string>Fi&le</string>
|
||||
</property>
|
||||
<addaction name="actionNew_SQL"/>
|
||||
<addaction name="actionLoad_SQL"/>
|
||||
<addaction name="actionSave_SQL"/>
|
||||
<addaction name="actionSave_SQL_as"/>
|
||||
<addaction name="actionSave_copy_of_SQL_as"/>
|
||||
<addaction name="actionExport_data"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionClose"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuQuery">
|
||||
<property name="title">
|
||||
<string>&Query</string>
|
||||
</property>
|
||||
<addaction name="separator"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>Wi&ndow</string>
|
||||
</property>
|
||||
<addaction name="actionShow_connection_manager"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<addaction name="actionCopy"/>
|
||||
<addaction name="actionCopy_as_C_string"/>
|
||||
<addaction name="actionCopy_as_raw_Cpp_string"/>
|
||||
<addaction name="actionGenerate_code"/>
|
||||
</widget>
|
||||
<addaction name="menuTest"/>
|
||||
<addaction name="menuEdit"/>
|
||||
<addaction name="menuQuery"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionNew_SQL"/>
|
||||
<addaction name="actionLoad_SQL"/>
|
||||
<addaction name="actionSave_SQL"/>
|
||||
<addaction name="actionExport_data"/>
|
||||
<addaction name="actionClose"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionCopy"/>
|
||||
<addaction name="actionCopy_as_C_string"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="actionLoad_SQL">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Load SQL</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_SQL">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/script_save.png</normaloff>:/icons/script_save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Save SQL</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_data">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/table_save.png</normaloff>:/icons/table_save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Export data</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClose">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/page_white_delete.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Close</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+F4</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/about.png</normaloff>
|
||||
<normalon>:/icons/information.png</normalon>:/icons/about.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_SQL_as">
|
||||
<property name="text">
|
||||
<string>Sa&ve SQL as</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_copy_of_SQL_as">
|
||||
<property name="text">
|
||||
<string>Save copy &of SQL as</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew_SQL">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/new_query_tab.png</normaloff>
|
||||
<normalon>:/icons/page_white_add.png</normalon>:/icons/new_query_tab.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&New SQL</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+N</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShow_connection_manager">
|
||||
<property name="text">
|
||||
<string>&Show connection manager</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/page_white_copy.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Copy</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+C</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy_as_C_string">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/token_shortland_character.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy as C-&string</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Alt+C</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCopy_as_raw_Cpp_string">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/token_shortland_character.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy as raw C++-string</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionGenerate_code">
|
||||
<property name="text">
|
||||
<string>Generate code</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#include "PlgPage.h"
|
||||
|
||||
//PglPage::PglPage()
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
std::vector<QAction*> PlgPage::getToolbarActions()
|
||||
{
|
||||
return std::vector<QAction*>();
|
||||
}
|
||||
|
||||
bool PlgPage::canClose()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,12 +1,10 @@
|
|||
|
||||
#include "QueryTab.h"
|
||||
#include "QueryTool.h"
|
||||
#include "ui_QueryTab.h"
|
||||
#include "SqlSyntaxHighlighter.h"
|
||||
#include <QStandardPaths>
|
||||
#include <QPushButton>
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
#include <QStatusBar>
|
||||
#include <QMessageBox>
|
||||
#include <QTabWidget>
|
||||
#include <QTextCodec>
|
||||
|
|
@ -15,59 +13,55 @@
|
|||
#include <QClipboard>
|
||||
#include "ExplainTreeModelItem.h"
|
||||
#include "json/json.h"
|
||||
#include "DatabaseWindow.h"
|
||||
#include "OpenDatabase.h"
|
||||
#include "catalog/PgDatabaseCatalog.h"
|
||||
#include "QueryParamListController.h"
|
||||
#include "util.h"
|
||||
#include "GlobalIoService.h"
|
||||
#include "UserConfiguration.h"
|
||||
#include "plugin_support/IPluginContentWidgetContext.h"
|
||||
|
||||
QueryTab::QueryTab(DatabaseWindow *win, QWidget *parent) :
|
||||
PlgPage(parent),
|
||||
ui(new Ui::QueryTab),
|
||||
m_win(win),
|
||||
m_dbConnection(*getGlobalAsioIoService())
|
||||
|
||||
QueryTool::QueryTool(IPluginContentWidgetContext *context_, QWidget *parent)
|
||||
: PluginContentWidget(context_, parent)
|
||||
, ui(new Ui::QueryTab)
|
||||
, m_dbConnection(*getGlobalAsioIoService())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTab::connectionStateChanged);
|
||||
connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTab::receiveNotice);
|
||||
auto db = context()->getObject<OpenDatabase>();
|
||||
m_config = db->config();
|
||||
m_catalog = db->catalog();
|
||||
|
||||
connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTool::connectionStateChanged);
|
||||
connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTool::receiveNotice);
|
||||
|
||||
ui->queryEdit->setFont(UserConfiguration::instance()->codeFont());
|
||||
|
||||
highlighter = new SqlSyntaxHighlighter(ui->queryEdit->document());
|
||||
auto open_database = m_win->getDatabase();
|
||||
auto open_database = context()->getObject<OpenDatabase>();
|
||||
if (open_database) {
|
||||
auto cat = open_database->catalog();
|
||||
highlighter->setTypes(*cat->types());
|
||||
}
|
||||
|
||||
connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTab::queryTextChanged);
|
||||
connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTool::queryTextChanged);
|
||||
|
||||
m_queryParamListController = new QueryParamListController(ui->paramTableView, open_database, this);
|
||||
connect(ui->addButton, &QPushButton::clicked, m_queryParamListController,
|
||||
&QueryParamListController::on_addParam);
|
||||
connect(ui->removeButton, &QPushButton::clicked, m_queryParamListController,
|
||||
&QueryParamListController::on_removeParam);
|
||||
|
||||
startConnect();
|
||||
}
|
||||
|
||||
QueryTab::~QueryTab()
|
||||
QueryTool::~QueryTool()
|
||||
{
|
||||
m_dbConnection.closeConnection();
|
||||
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void QueryTab::setConfig(const ConnectionConfig &config,
|
||||
std::shared_ptr<PgDatabaseCatalog> cat)
|
||||
{
|
||||
m_config = config;
|
||||
m_catalog = cat;
|
||||
m_win->QueueTask([this]() { startConnect(); });
|
||||
}
|
||||
|
||||
bool QueryTab::canClose()
|
||||
bool QueryTool::canClose()
|
||||
{
|
||||
bool can_close;
|
||||
if (m_queryTextChanged) {
|
||||
|
|
@ -79,7 +73,7 @@ bool QueryTab::canClose()
|
|||
return can_close;
|
||||
}
|
||||
|
||||
void QueryTab::newdoc()
|
||||
void QueryTool::newdoc()
|
||||
{
|
||||
ui->queryEdit->clear();
|
||||
setFileName(tr("new"));
|
||||
|
|
@ -87,7 +81,7 @@ void QueryTab::newdoc()
|
|||
m_new = true;
|
||||
}
|
||||
|
||||
bool QueryTab::load(const QString &filename)
|
||||
bool QueryTool::load(const QString &filename)
|
||||
{
|
||||
bool result = false;
|
||||
QFile file(filename);
|
||||
|
|
@ -113,7 +107,7 @@ bool QueryTab::load(const QString &filename)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool QueryTab::save()
|
||||
bool QueryTool::save()
|
||||
{
|
||||
bool result;
|
||||
if (m_fileName.isEmpty() || m_new) {
|
||||
|
|
@ -125,7 +119,7 @@ bool QueryTab::save()
|
|||
return result;
|
||||
}
|
||||
|
||||
bool QueryTab::saveAs()
|
||||
bool QueryTool::saveAs()
|
||||
{
|
||||
bool result = false;
|
||||
QString filename = promptUserForSaveSqlFilename();
|
||||
|
|
@ -139,7 +133,7 @@ bool QueryTab::saveAs()
|
|||
return result;
|
||||
}
|
||||
|
||||
void QueryTab::saveCopyAs()
|
||||
void QueryTool::saveCopyAs()
|
||||
{
|
||||
QString filename = promptUserForSaveSqlFilename();
|
||||
if (!filename.isEmpty()) {
|
||||
|
|
@ -147,7 +141,7 @@ void QueryTab::saveCopyAs()
|
|||
}
|
||||
}
|
||||
|
||||
void QueryTab::execute()
|
||||
void QueryTool::execute()
|
||||
{
|
||||
if (m_dbConnection.state() == ASyncDBConnection::State::Connected) {
|
||||
addLog("Query clicked");
|
||||
|
|
@ -160,7 +154,16 @@ void QueryTab::execute()
|
|||
|
||||
auto cb = [this](Expected<std::shared_ptr<Pgsql::Result>> res, qint64 elapsedms)
|
||||
{
|
||||
m_win->QueueTask([this, res, elapsedms]() { query_ready(res, elapsedms); });
|
||||
if (res.valid()) {
|
||||
auto && dbresult = res.get();
|
||||
QMetaObject::invokeMethod(this, "query_ready",
|
||||
Q_ARG(std::shared_ptr<Pgsql::Result>, dbresult),
|
||||
Q_ARG(qint64, elapsedms));
|
||||
}
|
||||
else {
|
||||
/// \todo handle error
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
if (m_queryParamListController->empty())
|
||||
|
|
@ -170,7 +173,17 @@ void QueryTab::execute()
|
|||
}
|
||||
}
|
||||
|
||||
void QueryTab::explain(bool analyze)
|
||||
void QueryTool::explain()
|
||||
{
|
||||
explain(false);
|
||||
}
|
||||
|
||||
void QueryTool::analyze()
|
||||
{
|
||||
explain(true);
|
||||
}
|
||||
|
||||
void QueryTool::explain(bool analyze)
|
||||
{
|
||||
ui->explainTreeView->setModel(nullptr);
|
||||
explainModel.reset();
|
||||
|
|
@ -203,7 +216,8 @@ void QueryTab::explain(bool analyze)
|
|||
explain = ExplainRoot::createFromJson(root);
|
||||
}
|
||||
}
|
||||
m_win->QueueTask([this, explain]() { explain_ready(explain); });
|
||||
QMetaObject::invokeMethod(this, "explain_ready",
|
||||
Q_ARG(ExplainRoot::SPtr, explain));
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
|
@ -215,21 +229,21 @@ void QueryTab::explain(bool analyze)
|
|||
m_dbConnection.send(cmd, m_queryParamListController->params(), cb);
|
||||
}
|
||||
|
||||
void QueryTab::cancel()
|
||||
void QueryTool::cancel()
|
||||
{
|
||||
m_dbConnection.cancel();
|
||||
}
|
||||
|
||||
|
||||
void QueryTab::setFileName(const QString &filename)
|
||||
void QueryTool::setFileName(const QString &filename)
|
||||
{
|
||||
m_fileName = filename;
|
||||
QFileInfo fileInfo(filename);
|
||||
QString fn(fileInfo.fileName());
|
||||
setTabCaption(fn, m_fileName);
|
||||
context()->setCaption(this, fn, m_fileName);
|
||||
}
|
||||
|
||||
bool QueryTab::continueWithoutSavingWarning()
|
||||
bool QueryTool::continueWithoutSavingWarning()
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
|
|
@ -248,7 +262,7 @@ bool QueryTab::continueWithoutSavingWarning()
|
|||
return ret != QMessageBox::Cancel;
|
||||
}
|
||||
|
||||
bool QueryTab::saveSqlTo(const QString &filename)
|
||||
bool QueryTool::saveSqlTo(const QString &filename)
|
||||
{
|
||||
bool result = false;
|
||||
QFileInfo fileinfo(filename);
|
||||
|
|
@ -271,52 +285,48 @@ bool QueryTab::saveSqlTo(const QString &filename)
|
|||
}
|
||||
|
||||
|
||||
QString QueryTab::promptUserForSaveSqlFilename()
|
||||
QString QueryTool::promptUserForSaveSqlFilename()
|
||||
{
|
||||
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
|
||||
return QFileDialog::getSaveFileName(this, tr("Save query"), home_dir, tr("SQL file (*.sql)"));
|
||||
}
|
||||
|
||||
void QueryTab::queryTextChanged()
|
||||
void QueryTool::queryTextChanged()
|
||||
{
|
||||
m_queryTextChanged = true;
|
||||
}
|
||||
|
||||
|
||||
void QueryTab::connectionStateChanged(ASyncDBConnection::State state)
|
||||
void QueryTool::connectionStateChanged(ASyncDBConnection::State state)
|
||||
{
|
||||
QTabWidget *tabwidget = getTabWidget();
|
||||
if (tabwidget) {
|
||||
int i = tabwidget->indexOf(this);
|
||||
QString iconname;
|
||||
switch (state) {
|
||||
case ASyncDBConnection::State::NotConnected:
|
||||
case ASyncDBConnection::State::Connecting:
|
||||
iconname = ":/icons/16x16/document_red.png";
|
||||
break;
|
||||
case ASyncDBConnection::State::Connected:
|
||||
iconname = ":/icons/16x16/document_green.png";
|
||||
break;
|
||||
case ASyncDBConnection::State::QuerySend:
|
||||
case ASyncDBConnection::State::CancelSend:
|
||||
iconname = ":/icons/16x16/document_yellow.png";
|
||||
break;
|
||||
case ASyncDBConnection::State::Terminating:
|
||||
break;
|
||||
}
|
||||
tabwidget->setTabIcon(i, QIcon(iconname));
|
||||
QString iconname;
|
||||
switch (state) {
|
||||
case ASyncDBConnection::State::NotConnected:
|
||||
case ASyncDBConnection::State::Connecting:
|
||||
iconname = "document_red.png";
|
||||
break;
|
||||
case ASyncDBConnection::State::Connected:
|
||||
iconname = "document_green.png";
|
||||
break;
|
||||
case ASyncDBConnection::State::QuerySend:
|
||||
case ASyncDBConnection::State::CancelSend:
|
||||
iconname = "document_yellow.png";
|
||||
break;
|
||||
case ASyncDBConnection::State::Terminating:
|
||||
break;
|
||||
}
|
||||
context()->setIcon(this, iconname);
|
||||
}
|
||||
|
||||
|
||||
void QueryTab::addLog(QString s)
|
||||
void QueryTool::addLog(QString s)
|
||||
{
|
||||
QTextCursor text_cursor = QTextCursor(ui->edtLog->document());
|
||||
text_cursor.movePosition(QTextCursor::End);
|
||||
text_cursor.insertText(s + "\r\n");
|
||||
}
|
||||
|
||||
void QueryTab::receiveNotice(Pgsql::ErrorDetails notice)
|
||||
void QueryTool::receiveNotice(Pgsql::ErrorDetails notice)
|
||||
{
|
||||
ui->messagesEdit->append(QString::fromStdString(notice.errorMessage));
|
||||
|
||||
|
|
@ -363,12 +373,12 @@ void QueryTab::receiveNotice(Pgsql::ErrorDetails notice)
|
|||
// statementPosition
|
||||
}
|
||||
|
||||
void QueryTab::startConnect()
|
||||
void QueryTool::startConnect()
|
||||
{
|
||||
m_dbConnection.setupConnection(m_config);
|
||||
}
|
||||
|
||||
void QueryTab::explain_ready(ExplainRoot::SPtr explain)
|
||||
void QueryTool::explain_ready(ExplainRoot::SPtr explain)
|
||||
{
|
||||
m_stopwatch.stop();
|
||||
if (explain) {
|
||||
|
|
@ -394,9 +404,7 @@ void QueryTab::explain_ready(ExplainRoot::SPtr explain)
|
|||
ui->explainTreeView->setColumnWidth(6, 600);
|
||||
ui->tabWidget->setCurrentWidget(ui->explainTab);
|
||||
|
||||
auto w = dynamic_cast<QMainWindow*>(this->window());
|
||||
if (w)
|
||||
w->statusBar()->showMessage(tr("Explain ready."));
|
||||
context()->showStatusMessage(tr("Explain ready."));
|
||||
}
|
||||
else {
|
||||
addLog("Explain no result");
|
||||
|
|
@ -405,7 +413,7 @@ void QueryTab::explain_ready(ExplainRoot::SPtr explain)
|
|||
}
|
||||
}
|
||||
|
||||
QString QueryTab::getCommand() const
|
||||
QString QueryTool::getCommand() const
|
||||
{
|
||||
QString command;
|
||||
QTextCursor cursor = ui->queryEdit->textCursor();
|
||||
|
|
@ -418,115 +426,109 @@ QString QueryTab::getCommand() const
|
|||
return command;
|
||||
}
|
||||
|
||||
std::string QueryTab::getCommandUtf8() const
|
||||
std::string QueryTool::getCommandUtf8() const
|
||||
{
|
||||
return getCommand().toUtf8().data();
|
||||
}
|
||||
|
||||
QTabWidget *QueryTab::getTabWidget()
|
||||
{
|
||||
QWidget * w = parentWidget();
|
||||
QWidget * p = w->parentWidget();
|
||||
QTabWidget *tw = dynamic_cast<QTabWidget*>(p);
|
||||
return tw;
|
||||
}
|
||||
//QTabWidget *QueryTab::getTabWidget()
|
||||
//{
|
||||
// QWidget * w = parentWidget();
|
||||
// QWidget * p = w->parentWidget();
|
||||
// QTabWidget *tw = dynamic_cast<QTabWidget*>(p);
|
||||
// return tw;
|
||||
//}
|
||||
|
||||
void QueryTab::setTabCaption(const QString &caption, const QString &tooltip)
|
||||
//void QueryTab::setTabCaption(const QString &caption, const QString &tooltip)
|
||||
//{
|
||||
// QTabWidget *tabwidget = getTabWidget();
|
||||
// if (tabwidget) {
|
||||
// int i = tabwidget->indexOf(this);
|
||||
// if (i >= 0) {
|
||||
// tabwidget->setTabText(i, caption);
|
||||
// tabwidget->setTabToolTip(i, tooltip);
|
||||
// }
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
void QueryTool::query_ready(std::shared_ptr<Pgsql::Result> dbres, qint64 elapsedms)
|
||||
{
|
||||
QTabWidget *tabwidget = getTabWidget();
|
||||
if (tabwidget) {
|
||||
int i = tabwidget->indexOf(this);
|
||||
if (i >= 0) {
|
||||
tabwidget->setTabText(i, caption);
|
||||
tabwidget->setTabToolTip(i, tooltip);
|
||||
if (dbres) {
|
||||
addLog("query_ready with result");
|
||||
auto st = dbres->resultStatus();
|
||||
if (st == PGRES_TUPLES_OK) {
|
||||
//int n_rows = dbres->getRows();
|
||||
//QString rowcount_str = QString("rows: %1").arg(dbres->getRows());
|
||||
|
||||
auto result_model = std::make_shared<QueryResultModel>(nullptr , dbres,
|
||||
m_catalog);
|
||||
TuplesResultWidget *trw = new TuplesResultWidget;
|
||||
trw->setResult(result_model, elapsedms);
|
||||
resultList.push_back(trw);
|
||||
ui->tabWidget->addTab(trw, "Data");
|
||||
if (resultList.size() == 1)
|
||||
ui->tabWidget->setCurrentWidget(trw);
|
||||
|
||||
}
|
||||
else {
|
||||
if (st == PGRES_COMMAND_OK) {
|
||||
int tuples_affected = dbres->tuplesAffected();
|
||||
QString msg;
|
||||
if (tuples_affected >= 0)
|
||||
msg = tr("Query returned succesfully: %1 rows affected, execution time %2")
|
||||
.arg(QString::number(tuples_affected))
|
||||
.arg(msfloatToHumanReadableString(elapsedms));
|
||||
else
|
||||
msg = tr("Query returned succesfully, execution time %1")
|
||||
.arg(msfloatToHumanReadableString(elapsedms));
|
||||
|
||||
ui->messagesEdit->append(msg);
|
||||
|
||||
ui->tabWidget->setCurrentWidget(ui->messageTab);
|
||||
}
|
||||
else {
|
||||
// if (st == PGRES_EMPTY_QUERY) {
|
||||
// statusBar()->showMessage(tr("Empty query."));
|
||||
// }
|
||||
// else if (st == PGRES_COPY_OUT) {
|
||||
// statusBar()->showMessage(tr("COPY OUT."));
|
||||
// }
|
||||
// else if (st == PGRES_COPY_IN) {
|
||||
// statusBar()->showMessage(tr("COPY IN."));
|
||||
// }
|
||||
// else if (st == PGRES_BAD_RESPONSE) {
|
||||
// statusBar()->showMessage(tr("BAD RESPONSE."));
|
||||
// }
|
||||
// else if (st == PGRES_NONFATAL_ERROR) {
|
||||
// statusBar()->showMessage(tr("NON FATAL ERROR."));
|
||||
// }
|
||||
// else if (st == PGRES_FATAL_ERROR) {
|
||||
// statusBar()->showMessage(tr("FATAL ERROR."));
|
||||
// }
|
||||
// else if (st == PGRES_COPY_BOTH) {
|
||||
// statusBar()->showMessage(tr("COPY BOTH shouldn't happen is for replication."));
|
||||
// }
|
||||
// else if (st == PGRES_SINGLE_TUPLE) {
|
||||
// statusBar()->showMessage(tr("SINGLE TUPLE result."));
|
||||
// }
|
||||
// else {
|
||||
// statusBar()->showMessage(tr("No tuples returned, possibly an error..."));
|
||||
// }
|
||||
ui->tabWidget->setCurrentWidget(ui->messageTab);
|
||||
auto details = dbres->diagDetails();
|
||||
markError(details);
|
||||
receiveNotice(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
m_stopwatch.stop();
|
||||
addLog("query_ready with NO result");
|
||||
}
|
||||
}
|
||||
|
||||
void QueryTab::query_ready(Expected<std::shared_ptr<Pgsql::Result>> exp_res, qint64 elapsedms)
|
||||
{
|
||||
if (exp_res.valid()) {
|
||||
auto dbres = exp_res.get();
|
||||
if (dbres) {
|
||||
addLog("query_ready with result");
|
||||
auto st = dbres->resultStatus();
|
||||
if (st == PGRES_TUPLES_OK) {
|
||||
//int n_rows = dbres->getRows();
|
||||
//QString rowcount_str = QString("rows: %1").arg(dbres->getRows());
|
||||
|
||||
auto result_model = std::make_shared<QueryResultModel>(nullptr , dbres,
|
||||
m_catalog);
|
||||
TuplesResultWidget *trw = new TuplesResultWidget;
|
||||
trw->setResult(result_model, elapsedms);
|
||||
resultList.push_back(trw);
|
||||
ui->tabWidget->addTab(trw, "Data");
|
||||
if (resultList.size() == 1)
|
||||
ui->tabWidget->setCurrentWidget(trw);
|
||||
|
||||
}
|
||||
else {
|
||||
if (st == PGRES_COMMAND_OK) {
|
||||
int tuples_affected = dbres->tuplesAffected();
|
||||
QString msg;
|
||||
if (tuples_affected >= 0)
|
||||
msg = tr("Query returned succesfully: %1 rows affected, execution time %2")
|
||||
.arg(QString::number(tuples_affected))
|
||||
.arg(msfloatToHumanReadableString(elapsedms));
|
||||
else
|
||||
msg = tr("Query returned succesfully, execution time %1")
|
||||
.arg(msfloatToHumanReadableString(elapsedms));
|
||||
|
||||
ui->messagesEdit->append(msg);
|
||||
|
||||
ui->tabWidget->setCurrentWidget(ui->messageTab);
|
||||
}
|
||||
else {
|
||||
// if (st == PGRES_EMPTY_QUERY) {
|
||||
// statusBar()->showMessage(tr("Empty query."));
|
||||
// }
|
||||
// else if (st == PGRES_COPY_OUT) {
|
||||
// statusBar()->showMessage(tr("COPY OUT."));
|
||||
// }
|
||||
// else if (st == PGRES_COPY_IN) {
|
||||
// statusBar()->showMessage(tr("COPY IN."));
|
||||
// }
|
||||
// else if (st == PGRES_BAD_RESPONSE) {
|
||||
// statusBar()->showMessage(tr("BAD RESPONSE."));
|
||||
// }
|
||||
// else if (st == PGRES_NONFATAL_ERROR) {
|
||||
// statusBar()->showMessage(tr("NON FATAL ERROR."));
|
||||
// }
|
||||
// else if (st == PGRES_FATAL_ERROR) {
|
||||
// statusBar()->showMessage(tr("FATAL ERROR."));
|
||||
// }
|
||||
// else if (st == PGRES_COPY_BOTH) {
|
||||
// statusBar()->showMessage(tr("COPY BOTH shouldn't happen is for replication."));
|
||||
// }
|
||||
// else if (st == PGRES_SINGLE_TUPLE) {
|
||||
// statusBar()->showMessage(tr("SINGLE TUPLE result."));
|
||||
// }
|
||||
// else {
|
||||
// statusBar()->showMessage(tr("No tuples returned, possibly an error..."));
|
||||
// }
|
||||
ui->tabWidget->setCurrentWidget(ui->messageTab);
|
||||
auto details = dbres->diagDetails();
|
||||
markError(details);
|
||||
receiveNotice(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_stopwatch.stop();
|
||||
addLog("query_ready with NO result");
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we have an error
|
||||
}
|
||||
}
|
||||
|
||||
void QueryTab::markError(const Pgsql::ErrorDetails &details)
|
||||
void QueryTool::markError(const Pgsql::ErrorDetails &details)
|
||||
{
|
||||
if (details.statementPosition > 0) {
|
||||
QTextCursor cursor = ui->queryEdit->textCursor();
|
||||
|
|
@ -567,14 +569,14 @@ void QueryTab::markError(const Pgsql::ErrorDetails &details)
|
|||
}
|
||||
}
|
||||
|
||||
void QueryTab::clearResult()
|
||||
void QueryTool::clearResult()
|
||||
{
|
||||
for (auto e : resultList)
|
||||
delete e;
|
||||
resultList.clear();
|
||||
}
|
||||
|
||||
void QueryTab::copyQueryAsCString()
|
||||
void QueryTool::copyQueryAsCString()
|
||||
{
|
||||
// QString command;
|
||||
// QTextCursor cursor = ui->queryEdit->textCursor();
|
||||
|
|
@ -592,7 +594,7 @@ void QueryTab::copyQueryAsCString()
|
|||
#include <codebuilder/CodeBuilder.h>
|
||||
#include <codebuilder/DefaultConfigs.h>
|
||||
|
||||
void QueryTab::copyQueryAsRawCppString()
|
||||
void QueryTool::copyQueryAsRawCppString()
|
||||
{
|
||||
QString command = getCommand();
|
||||
//auto sql = getAllOrSelectedSql();
|
||||
|
|
@ -600,7 +602,7 @@ void QueryTab::copyQueryAsRawCppString()
|
|||
QApplication::clipboard()->setText(cs);
|
||||
}
|
||||
|
||||
void QueryTab::generateCode()
|
||||
void QueryTool::generateCode()
|
||||
{
|
||||
QString command = getCommand();
|
||||
|
||||
|
|
@ -609,11 +611,11 @@ void QueryTab::generateCode()
|
|||
}
|
||||
if (resultList.size() == 1) {
|
||||
std::shared_ptr<const Pgsql::Result> dbres = resultList[0]->GetPgsqlResult();
|
||||
m_win->newCodeGenPage(command, dbres);
|
||||
//context()->newCodeGenPage(command, dbres);
|
||||
}
|
||||
}
|
||||
|
||||
void QueryTab::exportData(const QString &file_name)
|
||||
void QueryTool::exportData(const QString &file_name)
|
||||
{
|
||||
auto widget = ui->tabWidget->currentWidget();
|
||||
auto fi = std::find(resultList.begin(), resultList.end(), widget);
|
||||
|
|
@ -623,57 +625,15 @@ void QueryTab::exportData(const QString &file_name)
|
|||
}
|
||||
}
|
||||
|
||||
void QueryTab::focusEditor()
|
||||
void QueryTool::focusEditor()
|
||||
{
|
||||
ui->queryEdit->setFocus();
|
||||
}
|
||||
|
||||
|
||||
std::vector<QAction*> QueryTab::getToolbarActions()
|
||||
void QueryTool::exportData()
|
||||
{
|
||||
if (actions.empty()) {
|
||||
QAction *action;
|
||||
// New
|
||||
// action = new QAction(QIcon(":/icons/new_query_tab.png"), tr("New"), this);
|
||||
// action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
|
||||
// connect(action, &QAction::triggered, this, &QueryTab::);
|
||||
// actions.push_back(action);
|
||||
// Load
|
||||
|
||||
// Save
|
||||
action = new QAction(QIcon(":/icons/script_save.png"), tr("Save SQL"), this);
|
||||
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
|
||||
connect(action, &QAction::triggered, this, &QueryTab::save);
|
||||
actions.push_back(action);
|
||||
// Save as (menu only)
|
||||
// action = new QAction(QIcon(":/icons/script_save.png"), tr("Save SQL as"), this);
|
||||
// //action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
|
||||
// connect(action, &QAction::triggered, this, &QueryTab::saveAs);
|
||||
// actions.push_back(action);
|
||||
// Save copy as
|
||||
// Copy
|
||||
// Copy as C-string
|
||||
// Copy as raw cpp string
|
||||
// Execute SQL
|
||||
action = new QAction(QIcon(":/icons/script_go.png"), tr("Execute"), this);
|
||||
action->setShortcut(QKeySequence(Qt::Key_F5));
|
||||
connect(action, &QAction::triggered, this, &QueryTab::execute);
|
||||
actions.push_back(action);
|
||||
// Explain
|
||||
action = new QAction(QIcon(":/icons/lightbulb_off.png"), tr("Explain"), this);
|
||||
action->setShortcut(QKeySequence(Qt::Key_F7));
|
||||
connect(action, &QAction::triggered, this, [this] () { explain(false); });
|
||||
actions.push_back(action);
|
||||
// Explain Anaylze
|
||||
action = new QAction(QIcon(":/icons/lightbulb.png"), tr("Analyze"), this);
|
||||
action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F7));
|
||||
connect(action, &QAction::triggered, this, [this] () { explain(true); });
|
||||
actions.push_back(action);
|
||||
// Cancel
|
||||
action = new QAction(QIcon(":/icons/script_delete.png"), tr("Cancel"), this);
|
||||
action->setShortcut(QKeySequence(Qt::ALT + Qt::Key_Pause));
|
||||
connect(action, &QAction::triggered, this, &QueryTab::cancel);
|
||||
actions.push_back(action);
|
||||
}
|
||||
return actions;
|
||||
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
|
||||
QString file_name = QFileDialog::getSaveFileName(this,
|
||||
tr("Export data"), home_dir, tr("CSV file (*.csv)"));
|
||||
exportData(file_name);
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
#include "tuplesresultwidget.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include "PlgPage.h"
|
||||
#include "plugin_support/PluginContentWidget.h"
|
||||
#include <memory>
|
||||
|
||||
namespace Ui {
|
||||
|
|
@ -22,7 +22,6 @@ namespace Pgsql {
|
|||
class QTableView;
|
||||
|
||||
class QTabWidget;
|
||||
class DatabaseWindow;
|
||||
class SqlSyntaxHighlighter;
|
||||
class ExplainRoot;
|
||||
class QueryResultModel;
|
||||
|
|
@ -32,29 +31,19 @@ class OpenDatabase;
|
|||
class QueryParamListController;
|
||||
class PgDatabaseCatalog;
|
||||
|
||||
class QueryTab : public PlgPage {
|
||||
class QueryTool : public PluginContentWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
QueryTab(DatabaseWindow *win, QWidget *parent = nullptr);
|
||||
~QueryTab();
|
||||
|
||||
void setConfig(const ConnectionConfig &config, std::shared_ptr<PgDatabaseCatalog>cat);
|
||||
QueryTool(IPluginContentWidgetContext *context, QWidget *parent = nullptr);
|
||||
~QueryTool() override;
|
||||
|
||||
void newdoc();
|
||||
// void open();
|
||||
bool load(const QString &filename);
|
||||
bool save();
|
||||
bool saveAs();
|
||||
void saveCopyAs();
|
||||
|
||||
void execute();
|
||||
void explain(bool analyze);
|
||||
void cancel();
|
||||
|
||||
bool canClose();
|
||||
bool canClose() override;
|
||||
|
||||
void copyQueryAsCString();
|
||||
void copyQueryAsRawCppString();
|
||||
void generateCode();
|
||||
void exportData(const QString &filename);
|
||||
|
||||
|
|
@ -63,17 +52,28 @@ public:
|
|||
bool isNew() const { return m_new; }
|
||||
void focusEditor();
|
||||
|
||||
virtual std::vector<QAction*> getToolbarActions() override;
|
||||
public slots:
|
||||
void execute();
|
||||
/// Save the document under its current name, a file save dialog will be shown if this is a new document
|
||||
bool save();
|
||||
/// Saves the document under a new name and continue editing the document under this new name.
|
||||
bool saveAs();
|
||||
/// Save the document under a new name but continue editing the document under its old name.
|
||||
void saveCopyAs();
|
||||
void copyQueryAsCString();
|
||||
void copyQueryAsRawCppString();
|
||||
void explain();
|
||||
void analyze();
|
||||
void cancel();
|
||||
void exportData();
|
||||
private:
|
||||
|
||||
using ResultTabContainer = std::vector<TuplesResultWidget*>;
|
||||
|
||||
Ui::QueryTab *ui;
|
||||
DatabaseWindow *m_win;
|
||||
SqlSyntaxHighlighter* highlighter;
|
||||
ConnectionConfig m_config;
|
||||
StopWatch m_stopwatch;
|
||||
std::vector<QAction*> actions;
|
||||
|
||||
QueryParamListController *m_queryParamListController = nullptr;
|
||||
|
||||
|
|
@ -98,16 +98,17 @@ private:
|
|||
|
||||
QString getCommand() const;
|
||||
std::string getCommandUtf8() const;
|
||||
void explain_ready(ExplainRoot::SPtr explain);
|
||||
void query_ready(Expected<std::shared_ptr<Pgsql::Result>> dbres, qint64 elapsedms);
|
||||
|
||||
QTabWidget *getTabWidget();
|
||||
void setTabCaption(const QString &caption, const QString &tooltip);
|
||||
//QTabWidget *getTabWidget();
|
||||
//void setTabCaption(const QString &caption, const QString &tooltip);
|
||||
void clearResult();
|
||||
void markError(const Pgsql::ErrorDetails &details);
|
||||
|
||||
private slots:
|
||||
|
||||
void explain_ready(ExplainRoot::SPtr explain);
|
||||
void query_ready(std::shared_ptr<Pgsql::Result>, qint64 elapsedms);
|
||||
|
||||
void queryTextChanged();
|
||||
void connectionStateChanged(ASyncDBConnection::State state);
|
||||
void receiveNotice(Pgsql::ErrorDetails notice);
|
||||
|
|
@ -115,4 +116,5 @@ private slots:
|
|||
void startConnect();
|
||||
};
|
||||
|
||||
|
||||
#endif // QUERYTAB_H
|
||||
109
pglab/QueryToolModule.cpp
Normal file
109
pglab/QueryToolModule.cpp
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#include "QueryToolModule.h"
|
||||
#include "QueryTool.h"
|
||||
#include "plugin_support/IPluginContentWidgetContext.h"
|
||||
#include "plugin_support/PluginRegister.h"
|
||||
|
||||
#include <QStandardPaths>
|
||||
#include <QFileDialog>
|
||||
|
||||
void QueryToolModule::init()
|
||||
{
|
||||
std::string slot_name = SLOT(QueryTool::execute());
|
||||
{
|
||||
MenuAction ma("New SQL", [this] (IPluginContentWidgetContext* context)
|
||||
{ menuAction_new(context); });
|
||||
ma.setMenuLocation(MenuPath("File/New"));
|
||||
ma.setIcon(QIcon(":/icons/new_query_tab.png"));
|
||||
ma.setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
|
||||
registerMenuAction(ma);
|
||||
}
|
||||
{
|
||||
MenuAction ma("Open SQL", [this] (IPluginContentWidgetContext* context)
|
||||
{ menuAction_open(context); });
|
||||
ma.setMenuLocation(MenuPath("File/Open"));
|
||||
ma.setIcon(QIcon(":/icons/folder.png"));
|
||||
registerMenuAction(ma);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Save SQL", SLOT(save()));
|
||||
wa.setMenuLocation("File/Save");
|
||||
wa.setIcon(":/icons/script_save.png");
|
||||
wa.setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Save SQL as", SLOT(saveAs()));
|
||||
wa.setMenuLocation("File/Save");
|
||||
wa.setIcon(":/icons/script_save.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Save copy of SQL as", SLOT(saveCopyAs()));
|
||||
wa.setMenuLocation("File/Save");
|
||||
//wa.setIcon(":/icons/script_save.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("&Export data", SLOT(exportData()));
|
||||
wa.setMenuLocation("File/Export");
|
||||
wa.setIcon(":/icons/table_save.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Copy as C string", SLOT(copyQueryAsCString()));
|
||||
wa.setMenuLocation("Edit/Copy");
|
||||
wa.setIcon(":/icons/token_shortland_character.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Copy as raw C++ string", SLOT(copyQueryAsRawCppString()));
|
||||
wa.setMenuLocation("Edit/Copy");
|
||||
wa.setIcon(":/icons/token_shortland_character.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Execute", SLOT(execute()));
|
||||
wa.setMenuLocation("Query/1");
|
||||
wa.setIcon(":/icons/script_go.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Explain", SLOT(explain()));
|
||||
wa.setMenuLocation("Query/2");
|
||||
wa.setIcon(":/icons/lightbulb_off.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Analyze", SLOT(analyze()));
|
||||
wa.setMenuLocation("Query/1");
|
||||
wa.setIcon(":/icons/lightbulb.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
{
|
||||
LWidgetAction wa("Cancel", SLOT(cancel()));
|
||||
wa.setMenuLocation("Query/1");
|
||||
wa.setIcon(":/icons/script_delete.png");
|
||||
registerWidgetAction(wa);
|
||||
}
|
||||
}
|
||||
|
||||
void QueryToolModule::menuAction_new(IPluginContentWidgetContext* context)
|
||||
{
|
||||
auto *ct = new QueryTool(context, nullptr);
|
||||
context->addContentWidget(this, ct);
|
||||
ct->newdoc();
|
||||
}
|
||||
|
||||
void QueryToolModule::menuAction_open(IPluginContentWidgetContext* context)
|
||||
{
|
||||
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
|
||||
QString file_name = QFileDialog::getOpenFileName(context->container(),
|
||||
tr("Open sql query"), home_dir, tr("SQL files (*.sql *.txt)"));
|
||||
if ( ! file_name.isEmpty()) {
|
||||
auto *ct = new QueryTool(context, nullptr);
|
||||
context->addContentWidget(this, ct);
|
||||
ct->load(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_MODULE_CAT(QueryToolModule, "Query tool", "pglab.querytool", "database")
|
||||
18
pglab/QueryToolModule.h
Normal file
18
pglab/QueryToolModule.h
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef QUERYTOOLMODULE_H
|
||||
#define QUERYTOOLMODULE_H
|
||||
|
||||
#include "plugin_support/PluginModule.h"
|
||||
|
||||
class QueryToolModule: public PluginModule {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using PluginModule::PluginModule;
|
||||
|
||||
void init() override;
|
||||
void menuAction_new(IPluginContentWidgetContext* context);
|
||||
void menuAction_open(IPluginContentWidgetContext* context);
|
||||
private slots:
|
||||
};
|
||||
|
||||
|
||||
#endif // QUERYTOOLMODULE_H
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
#include "catalog/PgDatabaseCatalog.h"
|
||||
|
||||
ServerWindow::ServerWindow(MasterController *master, QWidget *parent)
|
||||
: ASyncWindow(parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::ServerWindow)
|
||||
, m_masterController(master)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef SERVERWINDOW_H
|
||||
#define SERVERWINDOW_H
|
||||
|
||||
#include "ASyncWindow.h"
|
||||
#include "ConnectionConfig.h"
|
||||
#include <QMainWindow>
|
||||
#include <memory>
|
||||
|
||||
namespace Ui {
|
||||
|
|
@ -14,7 +14,7 @@ class OpenDatabase;
|
|||
class DatabasesTableModel;
|
||||
class RolesTableModel;
|
||||
|
||||
class ServerWindow : public ASyncWindow {
|
||||
class ServerWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ServerWindow(MasterController *master, QWidget *parent );
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#endif
|
||||
#include <memory>
|
||||
#include "GlobalIoService.h"
|
||||
#include "plugin_support/PluginRegister.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
|
@ -29,6 +30,8 @@ int main(int argc, char *argv[])
|
|||
QCoreApplication::setOrganizationDomain("eelkeklein.nl");
|
||||
QCoreApplication::setApplicationName("pglab");
|
||||
|
||||
PluginRegister::getInstance()->initModules();
|
||||
|
||||
std::thread asio_service_thread;
|
||||
int result = -1;
|
||||
{
|
||||
|
|
|
|||
|
|
@ -28,12 +28,10 @@ win32:RC_ICONS += pglab.ico
|
|||
SOURCES += main.cpp\
|
||||
QueryResultModel.cpp \
|
||||
QueryExplainModel.cpp \
|
||||
tsqueue.cpp \
|
||||
CreateDatabaseDialog.cpp \
|
||||
ConnectionManagerWindow.cpp \
|
||||
ConnectionListModel.cpp \
|
||||
BackupRestore.cpp \
|
||||
QueryTab.cpp \
|
||||
stopwatch.cpp \
|
||||
TuplesResultWidget.cpp \
|
||||
BackupDialog.cpp \
|
||||
|
|
@ -42,7 +40,6 @@ SOURCES += main.cpp\
|
|||
OpenDatabase.cpp \
|
||||
SqlSyntaxHighlighter.cpp \
|
||||
ServerWindow.cpp \
|
||||
ASyncWindow.cpp \
|
||||
DatabasesTableModel.cpp \
|
||||
RolesTableModel.cpp \
|
||||
ConnectionList.cpp \
|
||||
|
|
@ -51,12 +48,10 @@ SOURCES += main.cpp\
|
|||
ResultTableModelUtil.cpp \
|
||||
BaseTableModel.cpp \
|
||||
QueryParamListController.cpp \
|
||||
TablesPage.cpp \
|
||||
TablesTableModel.cpp \
|
||||
ColumnTableModel.cpp \
|
||||
NamespaceFilterWidget.cpp \
|
||||
NamespaceItemModel.cpp \
|
||||
ApplicationWindow.cpp \
|
||||
ConstraintModel.cpp \
|
||||
IconColumnDelegate.cpp \
|
||||
IndexModel.cpp \
|
||||
|
|
@ -66,7 +61,6 @@ SOURCES += main.cpp\
|
|||
Module.cpp \
|
||||
EditorGutter.cpp \
|
||||
CodeEditor.cpp \
|
||||
PlgPage.cpp \
|
||||
PropertyProxyModel.cpp \
|
||||
CodeGenerator.cpp \
|
||||
UserConfiguration.cpp \
|
||||
|
|
@ -84,16 +78,27 @@ PropertyProxyModel.cpp \
|
|||
SequenceModel.cpp \
|
||||
SequencesPage.cpp \
|
||||
DatabaseWindow.cpp \
|
||||
PgLabTableView.cpp
|
||||
PgLabTableView.cpp \
|
||||
plugin_support/PluginModule.cpp \
|
||||
plugin_support/MenuPath.cpp \
|
||||
plugin_support/MenuLocation.cpp \
|
||||
plugin_support/ToolbarLocation.cpp \
|
||||
plugin_support/PluginRegister.cpp \
|
||||
plugin_support/PluginContentWidget.cpp \
|
||||
plugin_support/PluginContentWidgetContextBase.cpp \
|
||||
plugin_support/MenuAction.cpp \
|
||||
plugin_support/LMainWindow.cpp \
|
||||
plugin_support/LWidgetAction.cpp \
|
||||
QueryTool.cpp \
|
||||
QueryToolModule.cpp \
|
||||
CatalogInspector.cpp
|
||||
|
||||
HEADERS += \
|
||||
QueryResultModel.h \
|
||||
QueryExplainModel.h \
|
||||
tsqueue.h \
|
||||
CreateDatabaseDialog.h \
|
||||
ConnectionManagerWindow.h \
|
||||
ConnectionListModel.h \
|
||||
QueryTab.h \
|
||||
stopwatch.h \
|
||||
TuplesResultWidget.h \
|
||||
BackupDialog.h \
|
||||
|
|
@ -102,7 +107,6 @@ HEADERS += \
|
|||
OpenDatabase.h \
|
||||
SqlSyntaxHighlighter.h \
|
||||
ServerWindow.h \
|
||||
ASyncWindow.h \
|
||||
DatabasesTableModel.h \
|
||||
RolesTableModel.h \
|
||||
ConnectionList.h \
|
||||
|
|
@ -111,12 +115,10 @@ HEADERS += \
|
|||
ResultTableModelUtil.h \
|
||||
BaseTableModel.h \
|
||||
QueryParamListController.h \
|
||||
TablesPage.h \
|
||||
TablesTableModel.h \
|
||||
ColumnTableModel.h \
|
||||
NamespaceFilterWidget.h \
|
||||
NamespaceItemModel.h \
|
||||
ApplicationWindow.h \
|
||||
ConstraintModel.h \
|
||||
IconColumnDelegate.h \
|
||||
IndexModel.h \
|
||||
|
|
@ -126,7 +128,6 @@ HEADERS += \
|
|||
Module.h \
|
||||
EditorGutter.h \
|
||||
CodeEditor.h \
|
||||
PlgPage.h \
|
||||
AbstractCommand.h \
|
||||
PropertyProxyModel.h \
|
||||
CustomDataRole.h \
|
||||
|
|
@ -146,9 +147,24 @@ CustomDataRole.h \
|
|||
SequenceModel.h \
|
||||
SequencesPage.h \
|
||||
DatabaseWindow.h \
|
||||
PgLabTableView.h
|
||||
PgLabTableView.h \
|
||||
plugin_support/PluginModule.h \
|
||||
plugin_support/MenuPath.h \
|
||||
plugin_support/MenuLocation.h \
|
||||
plugin_support/ToolbarLocation.h \
|
||||
plugin_support/PluginRegister.h \
|
||||
plugin_support/PluginContentWidget.h \
|
||||
plugin_support/ModuleActionParameters.h \
|
||||
plugin_support/IPluginContentWidgetContext.h \
|
||||
plugin_support/PluginContentWidgetContextBase.h \
|
||||
plugin_support/MenuAction.h \
|
||||
plugin_support/LMainWindow.h \
|
||||
plugin_support/LWidgetAction.h \
|
||||
QueryTool.h \
|
||||
QueryToolModule.h \
|
||||
CatalogInspector.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
FORMS += \
|
||||
ConnectionManagerWindow.ui \
|
||||
CreateDatabaseDialog.ui \
|
||||
TuplesResultWidget.ui \
|
||||
|
|
@ -158,7 +174,6 @@ FORMS += mainwindow.ui \
|
|||
ProcessStdioWidget.ui \
|
||||
TablesPage.ui \
|
||||
NamespaceFilterWidget.ui \
|
||||
ApplicationWindow.ui \
|
||||
CrudTab.ui \
|
||||
CodeGenerator.ui
|
||||
|
||||
|
|
|
|||
98
pglab/plugin_support/IPluginContentWidgetContext.h
Normal file
98
pglab/plugin_support/IPluginContentWidgetContext.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
#ifndef IPLUGINCONTENTWIDGETCONTEXT_H
|
||||
#define IPLUGINCONTENTWIDGETCONTEXT_H
|
||||
|
||||
#include <QString>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <typeindex>
|
||||
#include "plugin_support/ModuleActionParameters.h"
|
||||
|
||||
class OpenDatabase;
|
||||
class PluginModule;
|
||||
class PluginContentWidget;
|
||||
|
||||
|
||||
/** This class serves to isolate the plugin from the actual construct in which it is
|
||||
* used.
|
||||
*
|
||||
* It provides interface for operating on the context without needing to many details.
|
||||
* Actual default implementation is in PluginContentWidgetContextBase.
|
||||
*
|
||||
* objectRegistry implementation is from Igor Tandetnik answer to the following question
|
||||
* https://stackoverflow.com/questions/35413745/using-shared-ptr-with-a-generic-registry-or-shared-object-storage-or-not
|
||||
*/
|
||||
class IPluginContentWidgetContext {
|
||||
public:
|
||||
|
||||
virtual ~IPluginContentWidgetContext() = default;
|
||||
/** Tells the context what to use as a caption for this content widget.
|
||||
*
|
||||
* Depending on the context the caption might not be visible or used as the caption
|
||||
* of a window or tab.
|
||||
*/
|
||||
virtual void setCaption(PluginContentWidget *content, const QString &caption, const QString &hint = {}) = 0;
|
||||
/** Tells the context what icon to use.
|
||||
*
|
||||
* In general the icon is used in a similar place as the caption.
|
||||
* \param iconname Assumed to be the name of an iconresource. The system will look for different
|
||||
* sizes under :/icons/<size>/iconname
|
||||
*/
|
||||
virtual void setIcon(PluginContentWidget *content, const QString &iconname) = 0;
|
||||
|
||||
virtual void showStatusMessage(const QString &msg) = 0;
|
||||
|
||||
virtual void moduleAction(
|
||||
const QString &module_identifier,
|
||||
QString module_action,
|
||||
const ModuleActionParameters &action_params
|
||||
) = 0;
|
||||
|
||||
virtual void addContentWidget(PluginModule *module, PluginContentWidget *widget) = 0;
|
||||
virtual void removeContentWidget(PluginContentWidget *widget) = 0;
|
||||
|
||||
/** Return a widget you can use as a parent
|
||||
*/
|
||||
virtual QWidget* container() = 0;
|
||||
|
||||
template<typename T, class...Args>
|
||||
bool addObjects(Args&&...args);
|
||||
template<typename T>
|
||||
bool registerObject(std::shared_ptr<T> object);
|
||||
template<typename T>
|
||||
std::shared_ptr<T> getObject() const;
|
||||
|
||||
private:
|
||||
std::map<std::type_index, std::shared_ptr<void> > m_objectRegistry;
|
||||
|
||||
};
|
||||
|
||||
template<typename T, class...Args>
|
||||
bool IPluginContentWidgetContext::addObjects(Args&&...args)
|
||||
{
|
||||
std::type_index key(typeid(T));
|
||||
if (!m_objectRegistry.count(key)) {
|
||||
auto p = std::make_shared<T>(std::forward<Args>(args)...);
|
||||
m_objectRegistry[key] = p;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool IPluginContentWidgetContext::registerObject(std::shared_ptr<T> object)
|
||||
{
|
||||
return m_objectRegistry.emplace(std::type_index(typeid(T)), object).second;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::shared_ptr<T> IPluginContentWidgetContext::getObject() const
|
||||
{
|
||||
auto it = m_objectRegistry.find(typeid(T));
|
||||
if (it == m_objectRegistry.end()) {
|
||||
return {};
|
||||
}
|
||||
return std::static_pointer_cast<T>(it->second);
|
||||
}
|
||||
|
||||
|
||||
#endif // IPLUGINCONTENTWIDGETCONTEXT_H
|
||||
214
pglab/plugin_support/LMainWindow.cpp
Normal file
214
pglab/plugin_support/LMainWindow.cpp
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
#include "LMainWindow.h"
|
||||
#include "PluginContentWidget.h"
|
||||
#include "PluginContentWidgetContextBase.h"
|
||||
#include "PluginModule.h"
|
||||
#include "PluginRegister.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMenuBar>
|
||||
#include <QStatusBar>
|
||||
#include <QToolBar>
|
||||
|
||||
namespace LMainWindow_details {
|
||||
|
||||
class LMainWindowContentContext: public PluginContentWidgetContextBase {
|
||||
public:
|
||||
explicit LMainWindowContentContext(LMainWindow *window)
|
||||
: m_window(window)
|
||||
{}
|
||||
|
||||
void setCaption(PluginContentWidget *content, const QString &caption, const QString &hint = {}) override
|
||||
{
|
||||
m_window->setTabCaptionForWidget(content, caption, hint);
|
||||
}
|
||||
|
||||
void setIcon(PluginContentWidget *content, const QString &iconname) override
|
||||
{
|
||||
m_window->setTabIcon(content, iconname);
|
||||
}
|
||||
|
||||
void showStatusMessage(const QString &msg) override
|
||||
{
|
||||
m_window->statusBar()->showMessage(msg);
|
||||
}
|
||||
|
||||
void addContentWidget(PluginModule *module, PluginContentWidget *widget) override
|
||||
{
|
||||
PluginContentWidgetContextBase::addContentWidget(module, widget);
|
||||
m_window->addPage(widget, "");
|
||||
}
|
||||
|
||||
QWidget* container() override
|
||||
{
|
||||
return m_window;
|
||||
}
|
||||
private:
|
||||
LMainWindow *m_window;
|
||||
};
|
||||
|
||||
}
|
||||
using namespace LMainWindow_details;
|
||||
|
||||
|
||||
LMainWindow::LMainWindow(QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
m_context = new LMainWindowContentContext(this);
|
||||
|
||||
m_tabWidget = new QTabWidget(this);
|
||||
m_tabWidget->setObjectName(QString::fromUtf8("tabWidget"));
|
||||
m_tabWidget->setDocumentMode(true);
|
||||
|
||||
setCentralWidget(m_tabWidget);
|
||||
|
||||
// menu
|
||||
auto menuBar = new QMenuBar(this);
|
||||
setMenuBar(menuBar);
|
||||
|
||||
// tooolbar
|
||||
m_mainToolBar = new QToolBar(this);
|
||||
addToolBar(Qt::TopToolBarArea, m_mainToolBar);
|
||||
|
||||
// statusbar
|
||||
auto statusBar = new QStatusBar(this);
|
||||
setStatusBar(statusBar);
|
||||
|
||||
m_fileMenu = new QMenu("File", this);
|
||||
|
||||
createActions();
|
||||
m_mainToolBar->addAction(m_closeAction);
|
||||
|
||||
connect(m_tabWidget, &QTabWidget::tabCloseRequested, this, &LMainWindow::tabWidget_tabCloseRequested);
|
||||
connect(m_tabWidget, &QTabWidget::currentChanged, this, &LMainWindow::tabWidget_currentChanged);
|
||||
}
|
||||
|
||||
LMainWindow::~LMainWindow()
|
||||
{
|
||||
delete m_context;
|
||||
}
|
||||
|
||||
void LMainWindow::initModuleMenus()
|
||||
{
|
||||
menuBar()->addMenu(m_fileMenu);
|
||||
addModuleMenuActions();
|
||||
}
|
||||
|
||||
void LMainWindow::addModuleMenuActions()
|
||||
{
|
||||
auto reg = PluginRegister::getInstance();
|
||||
auto mods = reg->modules();
|
||||
for (auto && mod : mods) {
|
||||
auto items = mod.second->menuActions();
|
||||
for (auto && item : items) {
|
||||
addMenuAction(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LMainWindow::createActions()
|
||||
{
|
||||
{
|
||||
auto action = m_closeAction = new QAction(this);
|
||||
QIcon icon;
|
||||
icon.addFile(QString::fromUtf8(":/icons/page_white_delete.png"), QSize(), QIcon::Normal, QIcon::On);
|
||||
action->setIcon(icon);
|
||||
connect(m_closeAction, &QAction::triggered, this, &LMainWindow::actionClose_triggered);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void LMainWindow::addMenuAction(const MenuAction &ma)
|
||||
{
|
||||
qDebug() << "add action " << ma.text();
|
||||
//auto ac =
|
||||
m_fileMenu->addAction(ma.icon(), ma.text(),
|
||||
[ma, this] ()
|
||||
{
|
||||
ma.perform(m_context);
|
||||
},
|
||||
ma.shortcut());
|
||||
|
||||
|
||||
// auto ac = new QAction(this);
|
||||
// ac->
|
||||
}
|
||||
|
||||
void LMainWindow::actionClose_triggered()
|
||||
{
|
||||
m_tabWidget->tabCloseRequested(m_tabWidget->currentIndex());
|
||||
}
|
||||
|
||||
|
||||
void LMainWindow::addPage(PluginContentWidget* page, QString caption)
|
||||
{
|
||||
m_tabWidget->addTab(page, caption);
|
||||
m_tabWidget->setCurrentWidget(page);
|
||||
}
|
||||
|
||||
void LMainWindow::setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint)
|
||||
{
|
||||
auto index = m_tabWidget->indexOf(widget);
|
||||
m_tabWidget->setTabText(index, caption);
|
||||
m_tabWidget->setTabToolTip(index, hint);
|
||||
}
|
||||
|
||||
void LMainWindow::setTabIcon(QWidget *widget, const QString &iconname)
|
||||
{
|
||||
auto index = m_tabWidget->indexOf(widget);
|
||||
auto n = ":/icons/16x16/" + iconname;
|
||||
m_tabWidget->setTabIcon(index, QIcon(n));
|
||||
}
|
||||
|
||||
IPluginContentWidgetContext* LMainWindow::context()
|
||||
{
|
||||
return m_context;
|
||||
}
|
||||
|
||||
void LMainWindow::tabWidget_tabCloseRequested(int index)
|
||||
{
|
||||
QWidget *widget = m_tabWidget->widget(index);
|
||||
PluginContentWidget *plg_page = dynamic_cast<PluginContentWidget*>(widget);
|
||||
if (plg_page) {
|
||||
if (plg_page->canClose()) {
|
||||
m_tabWidget->removeTab(index);
|
||||
m_context->removeContentWidget(plg_page);
|
||||
delete plg_page;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// old behaviour shouldn't be needed any more when all pages have been migrated
|
||||
// to PlgPage
|
||||
m_tabWidget->removeTab(index);
|
||||
delete widget;
|
||||
}
|
||||
}
|
||||
|
||||
void LMainWindow::tabWidget_currentChanged(int index)
|
||||
{
|
||||
// remove buttons of old page
|
||||
if (m_previousPage) {
|
||||
removeModuleWidgetActionsForPage(m_previousPage);
|
||||
}
|
||||
|
||||
// add buttons of new page
|
||||
PluginContentWidget * page = nullptr;
|
||||
if (index >= 0) {
|
||||
QWidget *widget = m_tabWidget->widget(index);
|
||||
page = dynamic_cast<PluginContentWidget*>(widget);
|
||||
if (page) {
|
||||
addModuleWidgetActionsForPage(page);
|
||||
}
|
||||
}
|
||||
m_previousPage = page;
|
||||
}
|
||||
|
||||
void LMainWindow::addModuleWidgetActionsForPage(PluginContentWidget *page)
|
||||
{
|
||||
m_context->addWidgetActionsToToolbar(page, m_mainToolBar);
|
||||
}
|
||||
|
||||
void LMainWindow::removeModuleWidgetActionsForPage(PluginContentWidget *page)
|
||||
{
|
||||
m_context->removeWidgetActionsFromToolbar(page, m_mainToolBar);
|
||||
}
|
||||
58
pglab/plugin_support/LMainWindow.h
Normal file
58
pglab/plugin_support/LMainWindow.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#ifndef LMAINWINDOW_H
|
||||
#define LMAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
class IPluginContentWidgetContext;
|
||||
class MenuAction;
|
||||
class PluginContentWidget;
|
||||
|
||||
namespace LMainWindow_details {
|
||||
class LMainWindowContentContext;
|
||||
}
|
||||
|
||||
class LMainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
LMainWindow(QWidget *parent = nullptr);
|
||||
~LMainWindow();
|
||||
|
||||
void initModuleMenus();
|
||||
void setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint);
|
||||
void setTabIcon(QWidget *widget, const QString &iconname);
|
||||
|
||||
/// Called when a newly created page is added to the QTabWidget
|
||||
void addPage(PluginContentWidget* page, QString caption);
|
||||
|
||||
IPluginContentWidgetContext* context();
|
||||
protected:
|
||||
QTabWidget *m_tabWidget = nullptr;
|
||||
QToolBar *m_mainToolBar = nullptr;
|
||||
|
||||
// Standard menu's
|
||||
QMenu *m_fileMenu = nullptr;
|
||||
|
||||
// Standard actions
|
||||
QAction *m_closeAction = nullptr;
|
||||
|
||||
|
||||
void addModuleMenuActions();
|
||||
|
||||
void addModuleWidgetActionsForPage(PluginContentWidget *page);
|
||||
void removeModuleWidgetActionsForPage(PluginContentWidget *page);
|
||||
private:
|
||||
LMainWindow_details::LMainWindowContentContext *m_context;
|
||||
PluginContentWidget *m_previousPage = nullptr; ///< tracks which pages buttons were previously being displayed
|
||||
|
||||
void createActions();
|
||||
void addMenuAction(const MenuAction &ma);
|
||||
|
||||
private slots:
|
||||
void actionClose_triggered();
|
||||
void tabWidget_tabCloseRequested(int index);
|
||||
void tabWidget_currentChanged(int index);
|
||||
};
|
||||
|
||||
|
||||
#endif // LMAINWINDOW_H
|
||||
56
pglab/plugin_support/LWidgetAction.cpp
Normal file
56
pglab/plugin_support/LWidgetAction.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "LWidgetAction.h"
|
||||
|
||||
LWidgetAction::LWidgetAction(QString text, const char * slotname)
|
||||
: m_text(std::move(text))
|
||||
, m_slotname(slotname)
|
||||
{}
|
||||
|
||||
const QIcon& LWidgetAction::icon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
const MenuLocation& LWidgetAction::menuLocation() const
|
||||
{
|
||||
return m_menuLocation;
|
||||
}
|
||||
|
||||
void LWidgetAction::setIcon(QIcon icon)
|
||||
{
|
||||
m_icon = std::move(icon);
|
||||
}
|
||||
|
||||
void LWidgetAction::setMenuLocation(MenuLocation menu_location)
|
||||
{
|
||||
m_menuLocation = std::move(menu_location);
|
||||
}
|
||||
|
||||
void LWidgetAction::setShortcut(QKeySequence shortcut)
|
||||
{
|
||||
m_shortCut = std::move(shortcut);
|
||||
}
|
||||
|
||||
void LWidgetAction::setText(QString text)
|
||||
{
|
||||
m_text = std::move(text);
|
||||
}
|
||||
|
||||
void LWidgetAction::setToolTip(QString tooltip)
|
||||
{
|
||||
m_toolTip = std::move(tooltip);
|
||||
}
|
||||
|
||||
const QKeySequence& LWidgetAction::shortcut() const
|
||||
{
|
||||
return m_shortCut;
|
||||
}
|
||||
|
||||
const QString& LWidgetAction::text() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
const QString& LWidgetAction::toolTip() const
|
||||
{
|
||||
return m_toolTip;
|
||||
}
|
||||
44
pglab/plugin_support/LWidgetAction.h
Normal file
44
pglab/plugin_support/LWidgetAction.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef LWIDGETACTION_H
|
||||
#define LWIDGETACTION_H
|
||||
|
||||
#include "MenuLocation.h"
|
||||
#include <QIcon>
|
||||
#include <QKeySequence>
|
||||
#include <QString>
|
||||
|
||||
|
||||
/** Action definition for a specific widget instance, it uses a slotname
|
||||
* so the action can be defined before the widget instance is created.
|
||||
* The plugin mechanism will take care of instantiating a connection to the named slot.
|
||||
*/
|
||||
class LWidgetAction {
|
||||
public:
|
||||
///
|
||||
/// \param slotname, use SLOT macro to pass name of the slot
|
||||
LWidgetAction(QString text, const char * slotname);
|
||||
|
||||
const QIcon& icon() const;
|
||||
const MenuLocation& menuLocation() const;
|
||||
void setIcon(QIcon icon);
|
||||
void setIcon(const char * icon) { setIcon(QIcon(icon)); }
|
||||
void setMenuLocation(MenuLocation menu_location);
|
||||
void setMenuLocation(const char * menu_location) { setMenuLocation(MenuPath(menu_location)); }
|
||||
void setShortcut(QKeySequence shortcut);
|
||||
void setText(QString text);
|
||||
void setToolTip(QString tooltip);
|
||||
const QKeySequence& shortcut() const;
|
||||
const char* slotName() const { return m_slotname; }
|
||||
const QString& text() const;
|
||||
const QString& toolTip() const;
|
||||
|
||||
private:
|
||||
QString m_text;
|
||||
QString m_toolTip;
|
||||
QIcon m_icon;
|
||||
QKeySequence m_shortCut;
|
||||
MenuLocation m_menuLocation;
|
||||
|
||||
const char * m_slotname;
|
||||
};
|
||||
|
||||
#endif // LWIDGETACTION_H
|
||||
62
pglab/plugin_support/MenuAction.cpp
Normal file
62
pglab/plugin_support/MenuAction.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include "MenuAction.h"
|
||||
|
||||
MenuAction::MenuAction(QString text, Func func)
|
||||
: m_text(std::move(text))
|
||||
, m_func(std::move(func))
|
||||
{}
|
||||
|
||||
const QIcon& MenuAction::icon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
const MenuLocation& MenuAction::menuLocation() const
|
||||
{
|
||||
return m_menuLocation;
|
||||
}
|
||||
|
||||
void MenuAction::setIcon(QIcon icon)
|
||||
{
|
||||
m_icon = std::move(icon);
|
||||
}
|
||||
|
||||
void MenuAction::setMenuLocation(MenuLocation menu_location)
|
||||
{
|
||||
m_menuLocation = std::move(menu_location);
|
||||
}
|
||||
|
||||
void MenuAction::setShortcut(QKeySequence shortcut)
|
||||
{
|
||||
m_shortcut = std::move(shortcut);
|
||||
}
|
||||
|
||||
void MenuAction::setText(QString text)
|
||||
{
|
||||
m_text = std::move(text);
|
||||
}
|
||||
|
||||
void MenuAction::setToolTip(QString tooltip)
|
||||
{
|
||||
m_toolTip = std::move(tooltip);
|
||||
}
|
||||
|
||||
const QKeySequence& MenuAction::shortcut() const
|
||||
{
|
||||
return m_shortcut;
|
||||
}
|
||||
|
||||
const QString& MenuAction::text() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
const QString& MenuAction::toolTip() const
|
||||
{
|
||||
return m_toolTip;
|
||||
}
|
||||
|
||||
void MenuAction::perform(IPluginContentWidgetContext *context) const
|
||||
{
|
||||
if (m_func)
|
||||
m_func(context);
|
||||
}
|
||||
48
pglab/plugin_support/MenuAction.h
Normal file
48
pglab/plugin_support/MenuAction.h
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#ifndef MENUACTION_H
|
||||
#define MENUACTION_H
|
||||
|
||||
#include "MenuLocation.h"
|
||||
#include "ToolbarLocation.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QKeySequence>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
|
||||
class QAction;
|
||||
class IPluginContentWidgetContext;
|
||||
|
||||
/** An action for in a menu or toolbar that does not pertain to a specific
|
||||
* widget. It often will create a widget for instance a New or Open action.
|
||||
* It does need a context.
|
||||
*
|
||||
*/
|
||||
class MenuAction {
|
||||
public:
|
||||
using Func = std::function<void(IPluginContentWidgetContext *context)>;
|
||||
|
||||
MenuAction(QString text, Func func);
|
||||
|
||||
const QIcon& icon() const;
|
||||
const MenuLocation& menuLocation() const;
|
||||
void setIcon(QIcon icon);
|
||||
void setMenuLocation(MenuLocation menu_location);
|
||||
void setShortcut(QKeySequence shortcut);
|
||||
void setText(QString text);
|
||||
void setToolTip(QString tooltip);
|
||||
const QKeySequence& shortcut() const;
|
||||
const QString& text() const;
|
||||
const QString& toolTip() const;
|
||||
|
||||
void perform(IPluginContentWidgetContext *context) const;
|
||||
private:
|
||||
QString m_text;
|
||||
QString m_toolTip;
|
||||
QIcon m_icon;
|
||||
QKeySequence m_shortcut;
|
||||
MenuLocation m_menuLocation;
|
||||
|
||||
Func m_func;
|
||||
};
|
||||
|
||||
#endif // MENUACTION_H
|
||||
8
pglab/plugin_support/MenuLocation.cpp
Normal file
8
pglab/plugin_support/MenuLocation.cpp
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#include "MenuLocation.h"
|
||||
|
||||
MenuLocation::MenuLocation() = default;
|
||||
|
||||
MenuLocation::MenuLocation(MenuPath path, int position)
|
||||
: m_path(std::move(path))
|
||||
, m_position(position)
|
||||
{}
|
||||
17
pglab/plugin_support/MenuLocation.h
Normal file
17
pglab/plugin_support/MenuLocation.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef MENULOCATION_H
|
||||
#define MENULOCATION_H
|
||||
|
||||
#include "plugin_support/MenuPath.h"
|
||||
|
||||
class MenuLocation {
|
||||
public:
|
||||
MenuLocation();
|
||||
MenuLocation(MenuPath path, int position = -1);
|
||||
|
||||
bool isEmpty() const;
|
||||
private:
|
||||
MenuPath m_path;
|
||||
int m_position = -1;
|
||||
};
|
||||
|
||||
#endif // MENULOCATION_H
|
||||
10
pglab/plugin_support/MenuPath.cpp
Normal file
10
pglab/plugin_support/MenuPath.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "MenuPath.h"
|
||||
|
||||
MenuPath::MenuPath() = default;
|
||||
|
||||
MenuPath::MenuPath(QString menu_path)
|
||||
: m_menuPath(std::move(menu_path))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
21
pglab/plugin_support/MenuPath.h
Normal file
21
pglab/plugin_support/MenuPath.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef MENUPATH_H
|
||||
#define MENUPATH_H
|
||||
|
||||
#include <QString>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
|
||||
|
||||
class MenuPath {
|
||||
public:
|
||||
MenuPath();
|
||||
MenuPath(QString menu_path);
|
||||
|
||||
private:
|
||||
QString m_menuPath;
|
||||
/// Contains the elements of the path, in general
|
||||
/// more then 3 levels is a bad idea but small_vector can grow when required.
|
||||
// boost::container::small_vector<int, 3> m_menuItemSeperators;
|
||||
};
|
||||
|
||||
|
||||
#endif // MENUPATH_H
|
||||
10
pglab/plugin_support/ModuleActionParameters.h
Normal file
10
pglab/plugin_support/ModuleActionParameters.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef MODULEACTIONPARAMETERS_H
|
||||
#define MODULEACTIONPARAMETERS_H
|
||||
|
||||
#include <map>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
using ModuleActionParameters = std::map<QString, QVariant>;
|
||||
|
||||
#endif // MODULEACTIONPARAMETERS_H
|
||||
11
pglab/plugin_support/PluginContentWidget.cpp
Normal file
11
pglab/plugin_support/PluginContentWidget.cpp
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "PluginContentWidget.h"
|
||||
|
||||
PluginContentWidget::PluginContentWidget(IPluginContentWidgetContext *context, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, m_context(context)
|
||||
{}
|
||||
|
||||
bool PluginContentWidget::canClose()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4,6 +4,9 @@
|
|||
#include <QWidget>
|
||||
#include <vector>
|
||||
|
||||
class IPluginContentWidgetContext;
|
||||
class PluginModule;
|
||||
|
||||
/// Provides a pluggable system for toolbar buttons and menu actions
|
||||
///
|
||||
/// We will need several kind of actions
|
||||
|
|
@ -15,13 +18,16 @@
|
|||
/// Can we use same groupings for toolbars and menu's
|
||||
/// How about additional toolbars?
|
||||
///
|
||||
class PlgPage: public QWidget{
|
||||
class PluginContentWidget: public QWidget{
|
||||
public:
|
||||
using QWidget::QWidget;
|
||||
|
||||
PluginContentWidget(IPluginContentWidgetContext *context, QWidget* parent = nullptr);
|
||||
/// Returns the toolbar buttons for this page
|
||||
virtual std::vector<QAction*> getToolbarActions();
|
||||
virtual bool canClose();
|
||||
|
||||
protected:
|
||||
IPluginContentWidgetContext *context() { return m_context; }
|
||||
private:
|
||||
IPluginContentWidgetContext *m_context;
|
||||
};
|
||||
|
||||
#endif // PGLPAGE_H
|
||||
103
pglab/plugin_support/PluginContentWidgetContextBase.cpp
Normal file
103
pglab/plugin_support/PluginContentWidgetContextBase.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
#include "PluginContentWidgetContextBase.h"
|
||||
#include "PluginContentWidget.h"
|
||||
#include "PluginModule.h"
|
||||
#include "PluginRegister.h"
|
||||
#include "LWidgetAction.h"
|
||||
#include <QAction>
|
||||
#include <QDebug>
|
||||
#include <QToolBar>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
LWidgetData::LWidgetData(PluginModule *module)
|
||||
: m_module(module)
|
||||
{}
|
||||
|
||||
void LWidgetData::init(PluginContentWidget *widget)
|
||||
{
|
||||
auto&& widget_actions = m_module->widgetActions();
|
||||
m_widgetActions.reserve(widget_actions.size());
|
||||
for (auto&& wa : widget_actions) {
|
||||
m_widgetActions.push_back(createAction(wa, widget));
|
||||
}
|
||||
}
|
||||
|
||||
QList<QAction *> LWidgetData::actions()
|
||||
{
|
||||
return m_widgetActions;
|
||||
}
|
||||
|
||||
QAction *LWidgetData::createAction(const LWidgetAction &wa, PluginContentWidget *widget)
|
||||
{
|
||||
auto ac = new QAction(wa.icon(), wa.text(), widget);
|
||||
ac->setShortcut(wa.shortcut());
|
||||
ac->setToolTip(wa.toolTip());
|
||||
QObject::connect(ac, SIGNAL(triggered()), widget, wa.slotName());
|
||||
return ac;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PluginContentWidgetContextBase::PluginContentWidgetContextBase() = default;
|
||||
|
||||
void PluginContentWidgetContextBase::moduleAction(
|
||||
const QString &module_identifier,
|
||||
QString module_action,
|
||||
const ModuleActionParameters &action_params
|
||||
)
|
||||
{
|
||||
auto reg = PluginRegister::getInstance();
|
||||
auto mod = reg->findModule(module_identifier);
|
||||
if (mod) {
|
||||
auto action = mod->findModuleAction(module_action);
|
||||
if (action) {
|
||||
qDebug() << QString("module %1 action %2 called ").arg(module_identifier, module_action);
|
||||
(*action)(this, action_params);
|
||||
}
|
||||
else
|
||||
qWarning() << QString("module %1 has no action %2").arg(module_identifier, module_action);
|
||||
}
|
||||
else
|
||||
qWarning() << QString("module not found %1").arg(module_identifier);
|
||||
}
|
||||
|
||||
void PluginContentWidgetContextBase::addContentWidget(PluginModule *module, PluginContentWidget *widget)
|
||||
{
|
||||
auto res = m_widgetLst.emplace(widget, module);
|
||||
if (!res.second)
|
||||
throw std::runtime_error("Unexpected conflicting key on insertiong PluginContentWidgetContextBase::addContentWidget");
|
||||
|
||||
res.first->second.init(widget);
|
||||
}
|
||||
|
||||
void PluginContentWidgetContextBase::removeContentWidget(PluginContentWidget *widget)
|
||||
{
|
||||
auto res = m_widgetLst.find(widget);
|
||||
if (res == m_widgetLst.end())
|
||||
return;
|
||||
|
||||
m_widgetLst.erase(res);
|
||||
}
|
||||
|
||||
void PluginContentWidgetContextBase::addWidgetActionsToToolbar(PluginContentWidget *widget, QToolBar *toolbar)
|
||||
{
|
||||
auto res = m_widgetLst.find(widget);
|
||||
if (res == m_widgetLst.end())
|
||||
return;
|
||||
|
||||
auto && actions = res->second.actions();
|
||||
toolbar->addActions(actions);
|
||||
}
|
||||
|
||||
void PluginContentWidgetContextBase::removeWidgetActionsFromToolbar(PluginContentWidget *widget, QToolBar *toolbar)
|
||||
{
|
||||
auto res = m_widgetLst.find(widget);
|
||||
if (res == m_widgetLst.end())
|
||||
return;
|
||||
|
||||
auto && actions = res->second.actions();
|
||||
for (auto && ac : actions)
|
||||
toolbar->removeAction(ac);
|
||||
|
||||
}
|
||||
50
pglab/plugin_support/PluginContentWidgetContextBase.h
Normal file
50
pglab/plugin_support/PluginContentWidgetContextBase.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#ifndef PLUGINCONTENTWIDGETCONTEXTBASE_H
|
||||
#define PLUGINCONTENTWIDGETCONTEXTBASE_H
|
||||
|
||||
#include "plugin_support/IPluginContentWidgetContext.h"
|
||||
#include <QList>
|
||||
|
||||
class LWidgetAction;
|
||||
class QToolBar;
|
||||
class QAction;
|
||||
|
||||
class LWidgetData {
|
||||
public:
|
||||
LWidgetData(PluginModule *module);
|
||||
PluginModule* module() { return m_module; }
|
||||
void init(PluginContentWidget *widget);
|
||||
QList<QAction *> actions();
|
||||
|
||||
private:
|
||||
PluginModule *m_module;
|
||||
/// List of actions specifically created for this widget from the widgetAction list of the module.
|
||||
QList<QAction *> m_widgetActions;
|
||||
|
||||
QAction *createAction(const LWidgetAction &wa, PluginContentWidget *widget);
|
||||
};
|
||||
|
||||
/// Provides base implementation of IPluginContentWidgetContext
|
||||
class PluginContentWidgetContextBase : public IPluginContentWidgetContext
|
||||
{
|
||||
public:
|
||||
PluginContentWidgetContextBase();
|
||||
|
||||
void moduleAction(
|
||||
const QString &module_identifier,
|
||||
QString module_action,
|
||||
const ModuleActionParameters &action_params
|
||||
) override;
|
||||
|
||||
void addContentWidget(PluginModule *module, PluginContentWidget *widget) override;
|
||||
void removeContentWidget(PluginContentWidget *widget) override;
|
||||
|
||||
void addWidgetActionsToToolbar(PluginContentWidget *widget, QToolBar *toolbar);
|
||||
void removeWidgetActionsFromToolbar(PluginContentWidget *widget, QToolBar *toolbar);
|
||||
private:
|
||||
|
||||
using WidgetLst = std::map<PluginContentWidget*, LWidgetData>;
|
||||
|
||||
WidgetLst m_widgetLst;
|
||||
};
|
||||
|
||||
#endif // PLUGINCONTENTWIDGETCONTEXTBASE_H
|
||||
41
pglab/plugin_support/PluginModule.cpp
Normal file
41
pglab/plugin_support/PluginModule.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#include "plugin_support/PluginModule.h"
|
||||
#include <QDebug>
|
||||
|
||||
PluginModule::PluginModule(QString name, QString ident)
|
||||
: m_name(std::move(name))
|
||||
, m_ident(std::move(ident))
|
||||
{
|
||||
}
|
||||
|
||||
void PluginModule::setDisplayCategory(QString category)
|
||||
{
|
||||
m_displayCategory = std::move(category);
|
||||
}
|
||||
|
||||
void PluginModule::registerMenuAction(MenuAction action)
|
||||
{
|
||||
qDebug() << "registerMenuAction " << action.text();
|
||||
m_menuActions.emplace_back(std::move(action));
|
||||
}
|
||||
|
||||
const PluginModule::MenuActionList& PluginModule::menuActions() const
|
||||
{
|
||||
return m_menuActions;
|
||||
}
|
||||
|
||||
void PluginModule::registerModuleAction(QString module_action, ModuleAction action)
|
||||
{
|
||||
m_moduleActions.emplace(
|
||||
std::move(module_action),
|
||||
std::move(action)
|
||||
);
|
||||
}
|
||||
|
||||
const PluginModule::ModuleAction* PluginModule::findModuleAction(const QString &module_action) const
|
||||
{
|
||||
auto res = m_moduleActions.find(module_action);
|
||||
if (res == m_moduleActions.end())
|
||||
return nullptr;
|
||||
return &res->second;
|
||||
}
|
||||
|
||||
83
pglab/plugin_support/PluginModule.h
Normal file
83
pglab/plugin_support/PluginModule.h
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
#ifndef PLUGIN_SUPPORTPLUGINMODULE_H
|
||||
#define PLUGIN_SUPPORTPLUGINMODULE_H
|
||||
|
||||
#include "ModuleActionParameters.h"
|
||||
#include "MenuAction.h"
|
||||
#include "LWidgetAction.h"
|
||||
#include "PluginRegister.h"
|
||||
#include <QObject>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class QAction;
|
||||
class IPluginContentWidgetContext;
|
||||
|
||||
class PluginModule: public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using MenuActionList = std::vector<MenuAction>;
|
||||
using LWidgetActionList = std::vector<LWidgetAction>;
|
||||
using ModuleAction = std::function<void(IPluginContentWidgetContext*, const ModuleActionParameters &)>;
|
||||
using ModuleActionMap = std::map<QString, ModuleAction>;
|
||||
|
||||
PluginModule(QString name, QString ident);
|
||||
|
||||
virtual void init() {}
|
||||
|
||||
const QString& name() const { return m_name; }
|
||||
const QString& identifier() const { return m_ident; }
|
||||
const QString& displayCategory() const { return m_displayCategory; }
|
||||
|
||||
void setDisplayCategory(QString category);
|
||||
|
||||
/// registers an action that should always be accessible from the menu
|
||||
void registerMenuAction(MenuAction action);
|
||||
const MenuActionList& menuActions() const;
|
||||
|
||||
void registerModuleAction(QString module_action, ModuleAction action);
|
||||
|
||||
/// Searches for and returns a pointer to the requested module action.
|
||||
/// When the action is not found nullptr is returned.
|
||||
const ModuleAction* findModuleAction(const QString &module_action) const;
|
||||
|
||||
void registerWidgetAction(const LWidgetAction &action)
|
||||
{
|
||||
m_widgetActions.push_back(action);
|
||||
}
|
||||
const LWidgetActionList& widgetActions() const { return m_widgetActions; }
|
||||
private:
|
||||
/// Name shown to end users
|
||||
QString m_name;
|
||||
/// Unique identifier
|
||||
QString m_ident;
|
||||
QString m_displayCategory;
|
||||
|
||||
MenuActionList m_menuActions;
|
||||
ModuleActionMap m_moduleActions;
|
||||
LWidgetActionList m_widgetActions;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
std::shared_ptr<PluginModule> createPluginModule(QString name, QString ident, QString category={})
|
||||
{
|
||||
auto module = std::make_shared<T>(std::move(name), std::move(ident));
|
||||
module->setDisplayCategory(category);
|
||||
|
||||
PluginRegister::getInstance()->registerModule(module);
|
||||
return std::move(module);
|
||||
}
|
||||
|
||||
#define REGISTER_PLUGIN_MODULE(module, name, ident) \
|
||||
namespace {\
|
||||
std::weak_ptr<PluginModule> register_variable = createPluginModule<module>\
|
||||
(name, ident);}
|
||||
|
||||
#define REGISTER_PLUGIN_MODULE_CAT(module, name, ident, category) \
|
||||
namespace {\
|
||||
std::weak_ptr<PluginModule> register_variable = createPluginModule<module>\
|
||||
(name, ident, category);}
|
||||
|
||||
|
||||
#endif // PLUGIN_SUPPORTPLUGINMODULE_H
|
||||
45
pglab/plugin_support/PluginRegister.cpp
Normal file
45
pglab/plugin_support/PluginRegister.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "PluginRegister.h"
|
||||
#include "plugin_support/PluginModule.h"
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
PluginRegister* PluginRegister::s_pluginRegister;
|
||||
|
||||
PluginRegister* PluginRegister::getInstance()
|
||||
{
|
||||
static std::mutex m;
|
||||
// check if set without locking first (in most cases it will be set and it will never be unset) so locking the mutex everytime
|
||||
// is a waist of time.
|
||||
if (!s_pluginRegister) {
|
||||
// not set then lock
|
||||
std::lock_guard<std::mutex> guard(m);
|
||||
// recheck in case someone else just set it
|
||||
if (!s_pluginRegister) {
|
||||
s_pluginRegister = new PluginRegister;
|
||||
}
|
||||
}
|
||||
return s_pluginRegister;
|
||||
}
|
||||
|
||||
PluginRegister::PluginRegister() = default;
|
||||
|
||||
void PluginRegister::initModules()
|
||||
{
|
||||
for (auto && mod : m_moduleMap) {
|
||||
mod.second->init();
|
||||
}
|
||||
}
|
||||
|
||||
void PluginRegister::registerModule(PluginModuleSPtr module)
|
||||
{
|
||||
qDebug() << "registerModule " << module->identifier();
|
||||
m_moduleMap.emplace(module->identifier(), module);
|
||||
}
|
||||
|
||||
const PluginModule* PluginRegister::findModule(const QString &module_ident) const
|
||||
{
|
||||
auto res = m_moduleMap.find(module_ident);
|
||||
if (res == m_moduleMap.end())
|
||||
return nullptr;
|
||||
return res->second.get();
|
||||
}
|
||||
34
pglab/plugin_support/PluginRegister.h
Normal file
34
pglab/plugin_support/PluginRegister.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef PLUGINREGISTER_H
|
||||
#define PLUGINREGISTER_H
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <QString>
|
||||
|
||||
class QAction;
|
||||
class PluginModule;
|
||||
|
||||
class PluginRegister {
|
||||
public:
|
||||
using PluginModuleSPtr = std::shared_ptr<PluginModule>;
|
||||
using ModuleMap = std::map<QString, PluginModuleSPtr>;
|
||||
|
||||
static PluginRegister* getInstance();
|
||||
|
||||
PluginRegister();
|
||||
void registerModule(PluginModuleSPtr module);
|
||||
|
||||
void initModules();
|
||||
const ModuleMap& modules() const{ return m_moduleMap; }
|
||||
|
||||
const PluginModule* findModule(const QString &module_ident) const;
|
||||
private:
|
||||
|
||||
ModuleMap m_moduleMap;
|
||||
|
||||
static PluginRegister* s_pluginRegister;
|
||||
};
|
||||
|
||||
|
||||
#endif // PLUGINREGISTER_H
|
||||
14
pglab/plugin_support/ToolbarLocation.cpp
Normal file
14
pglab/plugin_support/ToolbarLocation.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#include "ToolbarLocation.h"
|
||||
|
||||
ToolbarLocation::ToolbarLocation() = default;
|
||||
|
||||
ToolbarLocation::ToolbarLocation(QString toolbar, QString group, int position)
|
||||
: m_toolbar(std::move(toolbar))
|
||||
, m_group(std::move(group))
|
||||
, m_position(position)
|
||||
{}
|
||||
|
||||
bool ToolbarLocation::isEmpty() const
|
||||
{
|
||||
return m_toolbar.isEmpty();
|
||||
}
|
||||
19
pglab/plugin_support/ToolbarLocation.h
Normal file
19
pglab/plugin_support/ToolbarLocation.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef TOOLBARLOCATION_H
|
||||
#define TOOLBARLOCATION_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
class ToolbarLocation {
|
||||
public:
|
||||
ToolbarLocation();
|
||||
ToolbarLocation(QString toolbar, QString group, int position = -1);
|
||||
|
||||
bool isEmpty() const;
|
||||
private:
|
||||
QString m_toolbar;
|
||||
QString m_group;
|
||||
int m_position = -1;
|
||||
};
|
||||
|
||||
|
||||
#endif // TOOLBARLOCATION_H
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
#include "tsqueue.h"
|
||||
|
||||
TSQueue::TSQueue()
|
||||
{}
|
||||
|
||||
void TSQueue::add(t_Callable callable)
|
||||
{
|
||||
std::lock_guard<std::mutex> g(m);
|
||||
futureQueue.push_back(std::move(callable));
|
||||
}
|
||||
|
||||
bool TSQueue::empty()
|
||||
{
|
||||
std::lock_guard<std::mutex> g(m);
|
||||
return futureQueue.empty();
|
||||
}
|
||||
|
||||
TSQueue::t_Callable TSQueue::pop()
|
||||
{
|
||||
std::lock_guard<std::mutex> g(m);
|
||||
auto f = std::move(futureQueue.front());
|
||||
futureQueue.pop_front();
|
||||
if (futureQueue.empty()) {
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef TSQUEUE_H
|
||||
#define TSQUEUE_H
|
||||
|
||||
//#include "Win32Event.h"
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
class TSQueue {
|
||||
public:
|
||||
using t_Callable = std::function<void()>;
|
||||
|
||||
TSQueue();
|
||||
void add(t_Callable callable);
|
||||
bool empty();
|
||||
t_Callable pop();
|
||||
|
||||
private:
|
||||
using t_CallableQueue = std::deque<t_Callable>;
|
||||
|
||||
std::mutex m;
|
||||
t_CallableQueue futureQueue;
|
||||
};
|
||||
|
||||
|
||||
#endif // TSQUEUE_H
|
||||
|
|
@ -10,7 +10,7 @@ std::string PgTriggerContainer::getLoadQuery() const
|
|||
"SELECT oid, tgname, tgrelid, tgfoid, tgtype, tgenabled, tgisinternal, tgconstrrelid, \n"
|
||||
" tgconstrindid, tgconstraint, tgdeferrable, tginitdeferred, tgnargs, tgattr, \n"
|
||||
" tgargs, COALESCE(substring(pg_get_triggerdef(oid), 'WHEN (.*) EXECUTE PROCEDURE'), substring(pg_get_triggerdef(oid), 'WHEN (.*) \\$trigger')) AS whenclause";
|
||||
if (minimumVersion(90600)) {
|
||||
if (minimumVersion(100000)) {
|
||||
q += ", tgoldtable, tgnewtable";
|
||||
}
|
||||
q +=
|
||||
|
|
@ -38,7 +38,7 @@ PgTrigger PgTriggerContainer::loadElem(const Pgsql::Row &row)
|
|||
}
|
||||
}
|
||||
col >> v.whenclause;
|
||||
if (minimumVersion(90600)) {
|
||||
if (minimumVersion(100000)) {
|
||||
col >> v.oldtable >> v.newtable;
|
||||
}
|
||||
return v;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue