From 2a7e505dbfef94f71ddf18a04b58cfdfea63f198 Mon Sep 17 00:00:00 2001 From: eelke Date: Sat, 29 Dec 2018 18:59:54 +0100 Subject: [PATCH 01/24] Made a step in removing knowledge of DatabaseWindow from QueryTab as an effort to move in the direction of a plugin system. DatabaseWindow now passes a Context to QueryTab and other pages that give those pages an API for passing information up the system without knowing anything about the sytem. --- pglab/CodeGenerator.cpp | 4 +- pglab/CodeGenerator.h | 6 +- pglab/CrudTab.cpp | 4 +- pglab/CrudTab.h | 6 +- pglab/DatabaseWindow.cpp | 82 +++++++++++++++--- pglab/DatabaseWindow.h | 19 +++-- pglab/IPluginContentWidgetContext.h | 44 ++++++++++ pglab/PlgPage.cpp | 16 ---- pglab/PluginContentWidget.cpp | 18 ++++ pglab/{PlgPage.h => PluginContentWidget.h} | 12 ++- pglab/QueryTab.cpp | 99 ++++++++++------------ pglab/QueryTab.h | 14 ++- pglab/pglab.pro | 9 +- 13 files changed, 220 insertions(+), 113 deletions(-) create mode 100644 pglab/IPluginContentWidgetContext.h delete mode 100644 pglab/PlgPage.cpp create mode 100644 pglab/PluginContentWidget.cpp rename pglab/{PlgPage.h => PluginContentWidget.h} (68%) diff --git a/pglab/CodeGenerator.cpp b/pglab/CodeGenerator.cpp index dfc5b7e..0d74aa6 100644 --- a/pglab/CodeGenerator.cpp +++ b/pglab/CodeGenerator.cpp @@ -5,8 +5,8 @@ #include "UserConfiguration.h" #include -CodeGenerator::CodeGenerator(QWidget *parent) : - PlgPage(parent), +CodeGenerator::CodeGenerator(IPluginContentWidgetContext *context, QWidget *parent) : + PluginContentWidget(context, parent), ui(new Ui::CodeGenerator) { ui->setupUi(this); diff --git a/pglab/CodeGenerator.h b/pglab/CodeGenerator.h index fb09c88..5dcc35f 100644 --- a/pglab/CodeGenerator.h +++ b/pglab/CodeGenerator.h @@ -2,7 +2,7 @@ #define CODEGENERATOR_H #include -#include "PlgPage.h" +#include "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 catalog, QString query, std::shared_ptr dbres); diff --git a/pglab/CrudTab.cpp b/pglab/CrudTab.cpp index 36ad56b..d831c7f 100644 --- a/pglab/CrudTab.cpp +++ b/pglab/CrudTab.cpp @@ -12,8 +12,8 @@ #include -CrudTab::CrudTab(DatabaseWindow *parent) - : PlgPage(parent) +CrudTab::CrudTab(IPluginContentWidgetContext *context, DatabaseWindow *parent) + : PluginContentWidget(context, parent) , ui(new Ui::CrudTab) , m_window(parent) { diff --git a/pglab/CrudTab.h b/pglab/CrudTab.h index fd15e3f..06ce2ac 100644 --- a/pglab/CrudTab.h +++ b/pglab/CrudTab.h @@ -3,7 +3,7 @@ #include "catalog/PgClass.h" #include -#include "PlgPage.h" +#include "PluginContentWidget.h" #include #include @@ -15,12 +15,12 @@ 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, DatabaseWindow *parent = 0); ~CrudTab() override; void setConfig(std::shared_ptr db, const PgClass &table); diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index e53eda8..d671f56 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -15,20 +15,61 @@ #include #include "QueryTab.h" #include "util.h" -#include "PlgPage.h" +#include "PluginContentWidget.h" #include "CodeGenerator.h" #include "MasterController.h" #include "CrudTab.h" #include "WorkManager.h" #include "ScopeGuard.h" #include "EditTableWidget.h" +#include "IPluginContentWidgetContext.h" namespace pg = Pgsql; +namespace DatabaseWindow_details { + + class DatabaseWindowContentContext: public IPluginContentWidgetContext { + public: + explicit DatabaseWindowContentContext(DatabaseWindow *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); + } + + std::shared_ptr getDatabase() override + { + return m_window->getDatabase(); + } + + void QueueTask(TSQueue::t_Callable c) override + { + m_window->QueueTask(c); + } + + void showStatusMessage(const QString &msg) override + { + m_window->statusBar()->showMessage(msg); + } + private: + DatabaseWindow *m_window; + }; + +} +using namespace DatabaseWindow_details; + DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) : ASyncWindow(parent) , ui(new Ui::MainWindow) + , m_context(new DatabaseWindowContentContext(this)) , m_masterController(master) { ui->setupUi(this); @@ -38,12 +79,13 @@ DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) DatabaseWindow::~DatabaseWindow() { loader.reset(); + delete m_context; delete ui; } QueryTab* DatabaseWindow::newSqlPage() { - QueryTab *qt = new QueryTab(this); + QueryTab *qt = new QueryTab(m_context); qt->setConfig(m_config, m_database->catalog()); addPage(qt, "Tab"); qt->newdoc(); @@ -59,14 +101,14 @@ void DatabaseWindow::newCreateTablePage() void DatabaseWindow::newCrudPage(const PgClass &table) { - CrudTab *ct = new CrudTab(this); + CrudTab *ct = new CrudTab(m_context, this); ct->setConfig(m_database, table); addPage(ct, table.objectName()); } void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr dbres) { - auto cgtab = new CodeGenerator(this); + auto cgtab = new CodeGenerator(m_context, this); cgtab->Init(m_database->catalog(), query, dbres); addPage(cgtab, "Codegen"); } @@ -195,13 +237,13 @@ void DatabaseWindow::on_actionClose_triggered() void DatabaseWindow::on_actionAbout_triggered() { QMessageBox::about(this, "pgLab 0.1", tr( - "Copyrights 2016-2017, Eelke Klein, All Rights Reserved.\n" + "Copyrights 2016-2018, 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 " @@ -259,7 +301,7 @@ void DatabaseWindow::on_actionNew_SQL_triggered() void DatabaseWindow::on_tabWidget_tabCloseRequested(int index) { QWidget *widget = ui->tabWidget->widget(index); - PlgPage *plg_page = dynamic_cast(widget); + PluginContentWidget *plg_page = dynamic_cast(widget); if (plg_page) { if (plg_page->canClose()) { removePage(plg_page); @@ -325,7 +367,7 @@ void DatabaseWindow::on_actionCopy_as_raw_Cpp_string_triggered() } } -void DatabaseWindow::addToolBarButtonsForPage(PlgPage *page) +void DatabaseWindow::addToolBarButtonsForPage(PluginContentWidget *page) { std::vector actions = page->getToolbarActions(); QList list; @@ -335,7 +377,7 @@ void DatabaseWindow::addToolBarButtonsForPage(PlgPage *page) ui->mainToolBar->addActions(list); } -void DatabaseWindow::removeToolBarButtonsForPage(PlgPage *page) +void DatabaseWindow::removeToolBarButtonsForPage(PluginContentWidget *page) { std::vector actions = page->getToolbarActions(); for (auto act : actions) { @@ -344,7 +386,7 @@ void DatabaseWindow::removeToolBarButtonsForPage(PlgPage *page) } -void DatabaseWindow::addPage(PlgPage* page, QString caption) +void DatabaseWindow::addPage(PluginContentWidget* page, QString caption) { ui->tabWidget->addTab(page, caption); ui->tabWidget->setCurrentWidget(page); @@ -352,7 +394,7 @@ void DatabaseWindow::addPage(PlgPage* page, QString caption) //addToolBarButtonsForPage(page); } -void DatabaseWindow::removePage(PlgPage *) +void DatabaseWindow::removePage(PluginContentWidget *) { } @@ -365,10 +407,10 @@ void DatabaseWindow::on_tabWidget_currentChanged(int index) } // add buttons of new page - PlgPage * page = nullptr; + PluginContentWidget * page = nullptr; if (index >= 0) { QWidget *widget = ui->tabWidget->widget(index); - page = dynamic_cast(widget); + page = dynamic_cast(widget); if (page) { addToolBarButtonsForPage(page); } @@ -384,3 +426,17 @@ void DatabaseWindow::on_actionGenerate_code_triggered() } } + +void DatabaseWindow::setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint) +{ + auto index = ui->tabWidget->indexOf(widget); + ui->tabWidget->setTabText(index, caption); + ui->tabWidget->setTabToolTip(index, hint); +} + +void DatabaseWindow::setTabIcon(QWidget *widget, const QString &iconname) +{ + auto index = ui->tabWidget->indexOf(widget); + auto n = ":/icons/16x16/" + iconname; + ui->tabWidget->setTabIcon(index, QIcon(n)); +} diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index 610e53f..99483ba 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -33,7 +33,11 @@ class MasterController; class QCloseEvent; class OpenDatabase; class PgClass; -class PlgPage; +class PluginContentWidget; + +namespace DatabaseWindow_details { + class DatabaseWindowContentContext; +} /** This is the class for windows that handle tasks for a specific database/catalog * @@ -51,15 +55,18 @@ public: void newCrudPage(const PgClass &table); void newCodeGenPage(QString query, std::shared_ptr dbres); + void setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint); + void setTabIcon(QWidget *widget, const QString &iconname); private: Ui::MainWindow *ui; + DatabaseWindow_details::DatabaseWindowContentContext *m_context; ConnectionConfig m_config; std::shared_ptr m_database; MasterController *m_masterController; - PlgPage *m_previousPage = nullptr; ///< tracks which pages buttons were previously being displayed + PluginContentWidget *m_previousPage = nullptr; ///< tracks which pages buttons were previously being displayed class QLoad : public QueuedBackgroundTask { public: @@ -99,12 +106,12 @@ private: void catalogLoaded(); /// Called when a newly created page is added to the QTabWidget - void addPage(PlgPage* page, QString caption); + void addPage(PluginContentWidget* page, QString caption); /// Called when a page is completely removed from the QTabWidget - void removePage(PlgPage *page); + void removePage(PluginContentWidget *page); - void addToolBarButtonsForPage(PlgPage *page); - void removeToolBarButtonsForPage(PlgPage *page); + void addToolBarButtonsForPage(PluginContentWidget *page); + void removeToolBarButtonsForPage(PluginContentWidget *page); //class PageData private slots: diff --git a/pglab/IPluginContentWidgetContext.h b/pglab/IPluginContentWidgetContext.h new file mode 100644 index 0000000..8624ab8 --- /dev/null +++ b/pglab/IPluginContentWidgetContext.h @@ -0,0 +1,44 @@ +#ifndef IPLUGINCONTENTWIDGETCONTEXT_H +#define IPLUGINCONTENTWIDGETCONTEXT_H + +#include +#include +#include "tsqueue.h" + +class OpenDatabase; +class PluginContentWidget; + +/** This class serves to isolate the plugin from the actual construct in which it is + * used. + * + * It provides functions for operating on the context without needing to many details. + */ +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//iconname + */ + virtual void setIcon(PluginContentWidget *content, const QString &iconname) = 0; + + /** Returns an OpenDatabase object the widget can use to access + * the database. + */ + virtual std::shared_ptr getDatabase() = 0; + + virtual void QueueTask(TSQueue::t_Callable c) = 0; + + virtual void showStatusMessage(const QString &msg) = 0; +}; + +#endif // IPLUGINCONTENTWIDGETCONTEXT_H diff --git a/pglab/PlgPage.cpp b/pglab/PlgPage.cpp deleted file mode 100644 index 9356af5..0000000 --- a/pglab/PlgPage.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "PlgPage.h" - -//PglPage::PglPage() -//{ - -//} - -std::vector PlgPage::getToolbarActions() -{ - return std::vector(); -} - -bool PlgPage::canClose() -{ - return true; -} diff --git a/pglab/PluginContentWidget.cpp b/pglab/PluginContentWidget.cpp new file mode 100644 index 0000000..303bc15 --- /dev/null +++ b/pglab/PluginContentWidget.cpp @@ -0,0 +1,18 @@ +#include "PluginContentWidget.h" + +PluginContentWidget::PluginContentWidget(IPluginContentWidgetContext *context, QWidget* parent) + : QWidget(parent) + , m_context(context) +{ + +} + +std::vector PluginContentWidget::getToolbarActions() +{ + return std::vector(); +} + +bool PluginContentWidget::canClose() +{ + return true; +} diff --git a/pglab/PlgPage.h b/pglab/PluginContentWidget.h similarity index 68% rename from pglab/PlgPage.h rename to pglab/PluginContentWidget.h index ecb31ff..9e8f1c5 100644 --- a/pglab/PlgPage.h +++ b/pglab/PluginContentWidget.h @@ -4,6 +4,8 @@ #include #include +class IPluginContentWidgetContext; + /// Provides a pluggable system for toolbar buttons and menu actions /// /// We will need several kind of actions @@ -15,13 +17,17 @@ /// 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 getToolbarActions(); virtual bool canClose(); + +protected: + IPluginContentWidgetContext *context() { return m_context; } +private: + IPluginContentWidgetContext *m_context; }; #endif // PGLPAGE_H diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index f7dad5e..81b564b 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -15,19 +15,18 @@ #include #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 "IPluginContentWidgetContext.h" -QueryTab::QueryTab(DatabaseWindow *win, QWidget *parent) : - PlgPage(parent), - ui(new Ui::QueryTab), - m_win(win), - m_dbConnection(*getGlobalAsioIoService()) +QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) + : PluginContentWidget(context_, parent) + , ui(new Ui::QueryTab) + , m_dbConnection(*getGlobalAsioIoService()) { ui->setupUi(this); @@ -37,7 +36,7 @@ QueryTab::QueryTab(DatabaseWindow *win, QWidget *parent) : ui->queryEdit->setFont(UserConfiguration::instance()->codeFont()); highlighter = new SqlSyntaxHighlighter(ui->queryEdit->document()); - auto open_database = m_win->getDatabase(); + auto open_database = context()-> getDatabase(); if (open_database) { auto cat = open_database->catalog(); highlighter->setTypes(*cat->types()); @@ -64,7 +63,7 @@ void QueryTab::setConfig(const ConnectionConfig &config, { m_config = config; m_catalog = cat; - m_win->QueueTask([this]() { startConnect(); }); + context()->QueueTask([this]() { startConnect(); }); } bool QueryTab::canClose() @@ -160,7 +159,7 @@ void QueryTab::execute() auto cb = [this](Expected> res, qint64 elapsedms) { - m_win->QueueTask([this, res, elapsedms]() { query_ready(res, elapsedms); }); + context()->QueueTask([this, res, elapsedms]() { query_ready(res, elapsedms); }); }; if (m_queryParamListController->empty()) @@ -203,7 +202,7 @@ void QueryTab::explain(bool analyze) explain = ExplainRoot::createFromJson(root); } } - m_win->QueueTask([this, explain]() { explain_ready(explain); }); + context()->QueueTask([this, explain]() { explain_ready(explain); }); }).detach(); } } @@ -226,7 +225,7 @@ void QueryTab::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() @@ -285,27 +284,23 @@ void QueryTab::queryTextChanged() void QueryTab::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); } @@ -394,9 +389,7 @@ void QueryTab::explain_ready(ExplainRoot::SPtr explain) ui->explainTreeView->setColumnWidth(6, 600); ui->tabWidget->setCurrentWidget(ui->explainTab); - auto w = dynamic_cast(this->window()); - if (w) - w->statusBar()->showMessage(tr("Explain ready.")); + context()->showStatusMessage(tr("Explain ready.")); } else { addLog("Explain no result"); @@ -423,26 +416,26 @@ std::string QueryTab::getCommandUtf8() const return getCommand().toUtf8().data(); } -QTabWidget *QueryTab::getTabWidget() -{ - QWidget * w = parentWidget(); - QWidget * p = w->parentWidget(); - QTabWidget *tw = dynamic_cast(p); - return tw; -} +//QTabWidget *QueryTab::getTabWidget() +//{ +// QWidget * w = parentWidget(); +// QWidget * p = w->parentWidget(); +// QTabWidget *tw = dynamic_cast(p); +// return tw; +//} -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 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 QueryTab::query_ready(Expected> exp_res, qint64 elapsedms) { @@ -609,7 +602,7 @@ void QueryTab::generateCode() } if (resultList.size() == 1) { std::shared_ptr dbres = resultList[0]->GetPgsqlResult(); - m_win->newCodeGenPage(command, dbres); + //context()->newCodeGenPage(command, dbres); } } diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index 136ad59..1b1d76a 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -8,7 +8,7 @@ #include "tuplesresultwidget.h" #include -#include "PlgPage.h" +#include "PluginContentWidget.h" #include namespace Ui { @@ -22,7 +22,6 @@ namespace Pgsql { class QTableView; class QTabWidget; -class DatabaseWindow; class SqlSyntaxHighlighter; class ExplainRoot; class QueryResultModel; @@ -32,11 +31,11 @@ class OpenDatabase; class QueryParamListController; class PgDatabaseCatalog; -class QueryTab : public PlgPage { +class QueryTab : public PluginContentWidget { Q_OBJECT public: - QueryTab(DatabaseWindow *win, QWidget *parent = nullptr); - ~QueryTab(); + QueryTab(IPluginContentWidgetContext *context, QWidget *parent = nullptr); + ~QueryTab() override; void setConfig(const ConnectionConfig &config, std::shared_ptrcat); @@ -69,7 +68,6 @@ private: using ResultTabContainer = std::vector; Ui::QueryTab *ui; - DatabaseWindow *m_win; SqlSyntaxHighlighter* highlighter; ConnectionConfig m_config; StopWatch m_stopwatch; @@ -101,8 +99,8 @@ private: void explain_ready(ExplainRoot::SPtr explain); void query_ready(Expected> 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); diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 994bbf8..7eec123 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -66,7 +66,6 @@ SOURCES += main.cpp\ Module.cpp \ EditorGutter.cpp \ CodeEditor.cpp \ - PlgPage.cpp \ PropertyProxyModel.cpp \ CodeGenerator.cpp \ UserConfiguration.cpp \ @@ -84,7 +83,8 @@ PropertyProxyModel.cpp \ SequenceModel.cpp \ SequencesPage.cpp \ DatabaseWindow.cpp \ - PgLabTableView.cpp + PgLabTableView.cpp \ + PluginContentWidget.cpp HEADERS += \ QueryResultModel.h \ @@ -126,7 +126,6 @@ HEADERS += \ Module.h \ EditorGutter.h \ CodeEditor.h \ - PlgPage.h \ AbstractCommand.h \ PropertyProxyModel.h \ CustomDataRole.h \ @@ -146,7 +145,9 @@ CustomDataRole.h \ SequenceModel.h \ SequencesPage.h \ DatabaseWindow.h \ - PgLabTableView.h + PgLabTableView.h \ + PluginContentWidget.h \ + IPluginContentWidgetContext.h FORMS += mainwindow.ui \ ConnectionManagerWindow.ui \ From a54a063c137148ab04bf87e75f86db1bbce83dba Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 30 Dec 2018 15:44:05 +0100 Subject: [PATCH 02/24] DatabaseWindow no longer has to pass the config to QueryTab, QueryTab can now init itself from the supplied context. --- pglab/DatabaseWindow.cpp | 3 +-- pglab/QueryTab.cpp | 15 ++++++--------- pglab/QueryTab.h | 5 +---- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index d671f56..81cf935 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -86,10 +86,9 @@ DatabaseWindow::~DatabaseWindow() QueryTab* DatabaseWindow::newSqlPage() { QueryTab *qt = new QueryTab(m_context); - qt->setConfig(m_config, m_database->catalog()); - addPage(qt, "Tab"); qt->newdoc(); qt->focusEditor(); + addPage(qt, "Tab"); return qt; } diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index 81b564b..ba0b6dc 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -30,13 +30,16 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) { ui->setupUi(this); + m_config = context()->getDatabase()->config(); + m_catalog = context()->getDatabase()->catalog(); + connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTab::connectionStateChanged); connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTab::receiveNotice); ui->queryEdit->setFont(UserConfiguration::instance()->codeFont()); highlighter = new SqlSyntaxHighlighter(ui->queryEdit->document()); - auto open_database = context()-> getDatabase(); + auto open_database = context()->getDatabase(); if (open_database) { auto cat = open_database->catalog(); highlighter->setTypes(*cat->types()); @@ -49,6 +52,8 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) &QueryParamListController::on_addParam); connect(ui->removeButton, &QPushButton::clicked, m_queryParamListController, &QueryParamListController::on_removeParam); + + context()->QueueTask([this]() { startConnect(); }); } QueryTab::~QueryTab() @@ -58,14 +63,6 @@ QueryTab::~QueryTab() delete ui; } -void QueryTab::setConfig(const ConnectionConfig &config, - std::shared_ptr cat) -{ - m_config = config; - m_catalog = cat; - context()->QueueTask([this]() { startConnect(); }); -} - bool QueryTab::canClose() { bool can_close; diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index 1b1d76a..41169f4 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -37,10 +37,7 @@ public: QueryTab(IPluginContentWidgetContext *context, QWidget *parent = nullptr); ~QueryTab() override; - void setConfig(const ConnectionConfig &config, std::shared_ptrcat); - void newdoc(); -// void open(); bool load(const QString &filename); bool save(); bool saveAs(); @@ -50,7 +47,7 @@ public: void explain(bool analyze); void cancel(); - bool canClose(); + bool canClose() override; void copyQueryAsCString(); void copyQueryAsRawCppString(); From 15bee330765d4b9e32b5f21b1da9d815469a6820 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 30 Dec 2018 15:46:15 +0100 Subject: [PATCH 03/24] Made step to remove ASyncWindow in favour of usage of Future and FutureWatcher. This should allow concurrency in the plugins to be independent from their container. Contains also some work on the system for registering plugins. --- core/ControllableTask.h | 3 +- core/RunControllableTask.h | 4 +- core/TaskControl.h | 3 +- core/TaskExecutor.h | 2 +- pglab/CodeGenerator.h | 2 +- pglab/CrudModel.cpp | 7 +- pglab/CrudModel.h | 5 +- pglab/CrudTab.h | 4 +- pglab/DatabaseWindow.cpp | 24 +++---- pglab/DatabaseWindow.h | 64 +++++++++++++------ pglab/QueryTab.cpp | 34 +++++++++- pglab/QueryTab.h | 13 +++- pglab/pglab.pro | 16 ++++- pglab/plugin_support/MenuLocation.cpp | 8 +++ pglab/plugin_support/MenuLocation.h | 17 +++++ pglab/plugin_support/MenuPath.cpp | 10 +++ pglab/plugin_support/MenuPath.h | 21 ++++++ .../PluginContentWidget.cpp | 0 .../PluginContentWidget.h | 0 pglab/plugin_support/PluginModule.cpp | 19 ++++++ pglab/plugin_support/PluginModule.h | 31 +++++++++ pglab/plugin_support/PluginRegister.cpp | 29 +++++++++ pglab/plugin_support/PluginRegister.h | 30 +++++++++ pglab/plugin_support/ToolbarLocation.cpp | 14 ++++ pglab/plugin_support/ToolbarLocation.h | 19 ++++++ 25 files changed, 327 insertions(+), 52 deletions(-) create mode 100644 pglab/plugin_support/MenuLocation.cpp create mode 100644 pglab/plugin_support/MenuLocation.h create mode 100644 pglab/plugin_support/MenuPath.cpp create mode 100644 pglab/plugin_support/MenuPath.h rename pglab/{ => plugin_support}/PluginContentWidget.cpp (100%) rename pglab/{ => plugin_support}/PluginContentWidget.h (100%) create mode 100644 pglab/plugin_support/PluginModule.cpp create mode 100644 pglab/plugin_support/PluginModule.h create mode 100644 pglab/plugin_support/PluginRegister.cpp create mode 100644 pglab/plugin_support/PluginRegister.h create mode 100644 pglab/plugin_support/ToolbarLocation.cpp create mode 100644 pglab/plugin_support/ToolbarLocation.h diff --git a/core/ControllableTask.h b/core/ControllableTask.h index 70a44fa..8fe5738 100644 --- a/core/ControllableTask.h +++ b/core/ControllableTask.h @@ -12,8 +12,9 @@ template class ControllableTask { public: + using Result = T; virtual ~ControllableTask() {} - virtual T run(TaskControl& control) = 0; + virtual Result run(TaskControl& control) = 0; }; #endif // CONTROLLABLETASK_H diff --git a/core/RunControllableTask.h b/core/RunControllableTask.h index c93e19c..6cca6ae 100644 --- a/core/RunControllableTask.h +++ b/core/RunControllableTask.h @@ -7,14 +7,16 @@ #include #include +#include #include "ControllableTask.h" +#include "TaskControl.h" template class RunControllableTask : public QFutureInterface , public QRunnable { public: RunControllableTask(ControllableTask* tsk) : task(tsk) { } - virtial ~RunControllableTask() { delete task; } + virtual ~RunControllableTask() { delete task; } QFuture start() { diff --git a/core/TaskControl.h b/core/TaskControl.h index 7984900..3120e51 100644 --- a/core/TaskControl.h +++ b/core/TaskControl.h @@ -7,8 +7,7 @@ #include -class TaskControl -{ +class TaskControl { public: TaskControl(QFutureInterfaceBase *f) : fu(f) { } bool shouldRun() const { return !fu->isCanceled(); } diff --git a/core/TaskExecutor.h b/core/TaskExecutor.h index d44cf46..9a73b30 100644 --- a/core/TaskExecutor.h +++ b/core/TaskExecutor.h @@ -6,7 +6,7 @@ */ #include "ControllableTask.h" #include "RunControllableTask.h" - +#include /** * @brief The TaskExecutor class * diff --git a/pglab/CodeGenerator.h b/pglab/CodeGenerator.h index 5dcc35f..63ac868 100644 --- a/pglab/CodeGenerator.h +++ b/pglab/CodeGenerator.h @@ -2,7 +2,7 @@ #define CODEGENERATOR_H #include -#include "PluginContentWidget.h" +#include "plugin_support/PluginContentWidget.h" #include "Pgsql_declare.h" namespace Ui { diff --git a/pglab/CrudModel.cpp b/pglab/CrudModel.cpp index 6089774..d4c5222 100644 --- a/pglab/CrudModel.cpp +++ b/pglab/CrudModel.cpp @@ -19,8 +19,8 @@ #include #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 +172,8 @@ void CrudModel::loadData() if (res.valid()) { auto dbres = res.get(); if (dbres && *dbres) { - m_asyncWindow->QueueTask([this, dbres]() { loadIntoModel(dbres); }); +/// \todo Use ControllableTask instead with QFUtureWatcher +// m_asyncWindow->QueueTask([this, dbres]() { loadIntoModel(dbres); }); } } else { diff --git a/pglab/CrudModel.h b/pglab/CrudModel.h index db21177..ac071e4 100644 --- a/pglab/CrudModel.h +++ b/pglab/CrudModel.h @@ -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 db, const PgClass &table); @@ -231,8 +230,6 @@ private: }; using RowMappingVector = std::vector; - - ASyncWindow * m_asyncWindow; std::shared_ptr m_database; std::optional m_table; std::optional m_primaryKey; diff --git a/pglab/CrudTab.h b/pglab/CrudTab.h index 06ce2ac..64ae374 100644 --- a/pglab/CrudTab.h +++ b/pglab/CrudTab.h @@ -3,7 +3,7 @@ #include "catalog/PgClass.h" #include -#include "PluginContentWidget.h" +#include "plugin_support/PluginContentWidget.h" #include #include @@ -20,7 +20,7 @@ class CrudTab : public PluginContentWidget Q_OBJECT public: - explicit CrudTab(IPluginContentWidgetContext *context, DatabaseWindow *parent = 0); + explicit CrudTab(IPluginContentWidgetContext *context, DatabaseWindow *parent = nullptr); ~CrudTab() override; void setConfig(std::shared_ptr db, const PgClass &table); diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 81cf935..9def9b1 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -15,7 +15,7 @@ #include #include "QueryTab.h" #include "util.h" -#include "PluginContentWidget.h" +#include "plugin_support/PluginContentWidget.h" #include "CodeGenerator.h" #include "MasterController.h" #include "CrudTab.h" @@ -23,6 +23,7 @@ #include "ScopeGuard.h" #include "EditTableWidget.h" #include "IPluginContentWidgetContext.h" +#include "TaskExecutor.h" namespace pg = Pgsql; @@ -49,9 +50,9 @@ namespace DatabaseWindow_details { return m_window->getDatabase(); } - void QueueTask(TSQueue::t_Callable c) override + void QueueTask(TSQueue::t_Callable ) override { - m_window->QueueTask(c); +// m_window->QueueTask(c); } void showStatusMessage(const QString &msg) override @@ -67,18 +68,20 @@ using namespace DatabaseWindow_details; DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) -: ASyncWindow(parent) + : QMainWindow(parent) , ui(new Ui::MainWindow) , m_context(new DatabaseWindowContentContext(this)) , m_masterController(master) { ui->setupUi(this); ui->tabWidget->setDocumentMode(true); + + connect(&loadWatcher, &QFutureWatcher::finished, + this, &DatabaseWindow::catalogLoaded); } DatabaseWindow::~DatabaseWindow() { - loader.reset(); delete m_context; delete ui; } @@ -128,10 +131,9 @@ void DatabaseWindow::setConfig(const ConnectionConfig &config) title += m_config.name().c_str(); setWindowTitle(title); - loader = std::make_shared(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())); @@ -143,8 +145,8 @@ void DatabaseWindow::setConfig(const ConnectionConfig &config) void DatabaseWindow::catalogLoaded() { try { - SCOPE_EXIT { loader.reset(); }; - m_database = loader->GetResult(); + //SCOPE_EXIT { loadFuture = {}; }; + m_database = loadWatcher.future().result(); auto tt = new TablesPage(this); tt->setCatalog(m_database->catalog()); diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index 99483ba..bb09bfa 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -5,20 +5,24 @@ #include "ConnectionConfig.h" #include "OpenDatabase.h" #include -#include "ASyncWindow.h" +//#include "ASyncWindow.h" #include #include #include #include #include #include "Pgsql_Connection.h" -#include "QueuedBackgroundTask.h" +//#include "QueuedBackgroundTask.h" +#include "ControllableTask.h" #include #include #include #include #include +#include +#include +#include namespace Ui { class MainWindow; @@ -42,7 +46,7 @@ namespace DatabaseWindow_details { /** This is the class for windows that handle tasks for a specific database/catalog * */ -class DatabaseWindow : public ASyncWindow { +class DatabaseWindow : public QMainWindow { Q_OBJECT public: explicit DatabaseWindow(MasterController *master, QWidget *parent); @@ -68,33 +72,50 @@ private: MasterController *m_masterController; PluginContentWidget *m_previousPage = nullptr; ///< tracks which pages buttons were previously being displayed - class QLoad : public QueuedBackgroundTask { +// class QLoad : public QueuedBackgroundTask { +// public: +// explicit QLoad(ConnectionConfig config, CompletionFunction on_completion) +// : QueuedBackgroundTask(on_completion) +// , m_config(config) +// {} + +// OpenDatabase::OpenDatabaseSPtr GetResult() +// { +// if (hasException()) rethrow(); +// return result; +// } +// protected: + +// OpenDatabase::OpenDatabaseSPtr result; +// virtual void doRun() +// { +// auto res = OpenDatabase::createOpenDatabase(m_config); +// result = res.get(); +// } +// private: + +// ConnectionConfig m_config; +// }; + +// std::shared_ptr loader; + + class LoadCatalog: public ControllableTask { 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 loader; - + QFutureWatcher loadWatcher; QueryTab *GetActiveQueryTab(); @@ -103,7 +124,6 @@ private: QueryTab *newSqlPage(); void newCreateTablePage(); - void catalogLoaded(); /// Called when a newly created page is added to the QTabWidget void addPage(PluginContentWidget* page, QString caption); @@ -115,6 +135,8 @@ private: //class PageData private slots: + void catalogLoaded(); + void on_actionLoad_SQL_triggered(); void on_actionSave_SQL_triggered(); void on_actionExport_data_triggered(); diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index ba0b6dc..e97e4e9 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -22,6 +22,7 @@ #include "GlobalIoService.h" #include "UserConfiguration.h" #include "IPluginContentWidgetContext.h" +#include "plugin_support/PluginRegister.h" QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) : PluginContentWidget(context_, parent) @@ -58,7 +59,8 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) QueryTab::~QueryTab() { - m_dbConnection.closeConnection(); +// m_dbConnection.blockSignals(true); +// m_dbConnection.closeConnection(); delete ui; } @@ -667,3 +669,33 @@ std::vector QueryTab::getToolbarActions() } return actions; } + + +void QueryToolModule::init() +{ + auto action_new = new QAction(QIcon(":/icons/new_query_tab.png"), tr("New"), this); + connect(action_new, &QAction::triggered, this, &QueryToolModule::new_triggered); + + registerAction(action_new, MenuLocation({"File/New"}), ToolbarLocation("File", "")); +} + +void QueryToolModule::new_triggered() +{ +} + + +namespace { + + + std::shared_ptr createModule() + { + auto module = std::make_shared("Query tool", "pglab.querytool"); + module->init(); + + PluginRegister::getInstance()->registerModule(module); + return std::move(module); + } + + std::weak_ptr register_variable = createModule(); + +} diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index 41169f4..bac8480 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -8,8 +8,9 @@ #include "tuplesresultwidget.h" #include -#include "PluginContentWidget.h" +#include "plugin_support/PluginContentWidget.h" #include +#include "plugin_support/PluginModule.h" namespace Ui { class QueryTab; @@ -110,4 +111,14 @@ private slots: void startConnect(); }; +class QueryToolModule: public PluginModule { + Q_OBJECT +public: + using PluginModule::PluginModule; + + void init(); +private slots: + void new_triggered(); +}; + #endif // QUERYTAB_H diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 7eec123..3824e8a 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -84,7 +84,12 @@ PropertyProxyModel.cpp \ SequencesPage.cpp \ DatabaseWindow.cpp \ PgLabTableView.cpp \ - PluginContentWidget.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 HEADERS += \ QueryResultModel.h \ @@ -146,8 +151,13 @@ CustomDataRole.h \ SequencesPage.h \ DatabaseWindow.h \ PgLabTableView.h \ - PluginContentWidget.h \ - IPluginContentWidgetContext.h + IPluginContentWidgetContext.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 FORMS += mainwindow.ui \ ConnectionManagerWindow.ui \ diff --git a/pglab/plugin_support/MenuLocation.cpp b/pglab/plugin_support/MenuLocation.cpp new file mode 100644 index 0000000..3b80754 --- /dev/null +++ b/pglab/plugin_support/MenuLocation.cpp @@ -0,0 +1,8 @@ +#include "MenuLocation.h" + +MenuLocation::MenuLocation() = default; + +MenuLocation::MenuLocation(MenuPath path, int position) + : m_path(std::move(path)) + , m_position(position) +{} diff --git a/pglab/plugin_support/MenuLocation.h b/pglab/plugin_support/MenuLocation.h new file mode 100644 index 0000000..ea49ac6 --- /dev/null +++ b/pglab/plugin_support/MenuLocation.h @@ -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 diff --git a/pglab/plugin_support/MenuPath.cpp b/pglab/plugin_support/MenuPath.cpp new file mode 100644 index 0000000..8951d29 --- /dev/null +++ b/pglab/plugin_support/MenuPath.cpp @@ -0,0 +1,10 @@ +#include "MenuPath.h" + +MenuPath::MenuPath() = default; + +MenuPath::MenuPath(QString menu_path) + : m_menuPath(std::move(menu_path)) +{ +} + + diff --git a/pglab/plugin_support/MenuPath.h b/pglab/plugin_support/MenuPath.h new file mode 100644 index 0000000..98f0b96 --- /dev/null +++ b/pglab/plugin_support/MenuPath.h @@ -0,0 +1,21 @@ +#ifndef MENUPATH_H +#define MENUPATH_H + +#include +#include + + +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 m_menuItemSeperators; +}; + + +#endif // MENUPATH_H diff --git a/pglab/PluginContentWidget.cpp b/pglab/plugin_support/PluginContentWidget.cpp similarity index 100% rename from pglab/PluginContentWidget.cpp rename to pglab/plugin_support/PluginContentWidget.cpp diff --git a/pglab/PluginContentWidget.h b/pglab/plugin_support/PluginContentWidget.h similarity index 100% rename from pglab/PluginContentWidget.h rename to pglab/plugin_support/PluginContentWidget.h diff --git a/pglab/plugin_support/PluginModule.cpp b/pglab/plugin_support/PluginModule.cpp new file mode 100644 index 0000000..1991dd1 --- /dev/null +++ b/pglab/plugin_support/PluginModule.cpp @@ -0,0 +1,19 @@ +#include "plugin_support/PluginModule.h" + +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::registerAction(QAction *action, MenuLocation menu_location, ToolbarLocation toolbar_location) +{ + +} + + diff --git a/pglab/plugin_support/PluginModule.h b/pglab/plugin_support/PluginModule.h new file mode 100644 index 0000000..6577550 --- /dev/null +++ b/pglab/plugin_support/PluginModule.h @@ -0,0 +1,31 @@ +#ifndef PLUGIN_SUPPORTPLUGINMODULE_H +#define PLUGIN_SUPPORTPLUGINMODULE_H + +#include "plugin_support/MenuLocation.h" +#include "plugin_support/ToolbarLocation.h" +#include + +class QAction; + + +class PluginModule: public QObject { + Q_OBJECT +public: + PluginModule(QString name, QString ident); + + 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); + void registerAction(QAction *action, MenuLocation menu_location, ToolbarLocation toolbar_location); +private: + /// Name shown to end users + QString m_name; + /// Unique identifier + QString m_ident; + QString m_displayCategory; +}; + + +#endif // PLUGIN_SUPPORTPLUGINMODULE_H diff --git a/pglab/plugin_support/PluginRegister.cpp b/pglab/plugin_support/PluginRegister.cpp new file mode 100644 index 0000000..57b9eca --- /dev/null +++ b/pglab/plugin_support/PluginRegister.cpp @@ -0,0 +1,29 @@ +#include "PluginRegister.h" +#include "plugin_support/PluginModule.h" +#include + + +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 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::registerModule(PluginModuleSPtr module) +{ + qDebug() << "Register called for " << module->identifier(); +} diff --git a/pglab/plugin_support/PluginRegister.h b/pglab/plugin_support/PluginRegister.h new file mode 100644 index 0000000..ff80136 --- /dev/null +++ b/pglab/plugin_support/PluginRegister.h @@ -0,0 +1,30 @@ +#ifndef PLUGINREGISTER_H +#define PLUGINREGISTER_H + +#include +#include +#include +#include + +class QAction; +class PluginModule; + +class PluginRegister { +public: + using PluginModuleSPtr = std::shared_ptr; + using ModuleMap = std::map; + + static PluginRegister* getInstance(); + + PluginRegister(); + void registerModule(PluginModuleSPtr module); + const ModuleMap& modules() const { return m_moduleMap; } +private: + + ModuleMap m_moduleMap; + + static PluginRegister* s_pluginRegister; +}; + + +#endif // PLUGINREGISTER_H diff --git a/pglab/plugin_support/ToolbarLocation.cpp b/pglab/plugin_support/ToolbarLocation.cpp new file mode 100644 index 0000000..61a57b3 --- /dev/null +++ b/pglab/plugin_support/ToolbarLocation.cpp @@ -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(); +} diff --git a/pglab/plugin_support/ToolbarLocation.h b/pglab/plugin_support/ToolbarLocation.h new file mode 100644 index 0000000..ce0cb3d --- /dev/null +++ b/pglab/plugin_support/ToolbarLocation.h @@ -0,0 +1,19 @@ +#ifndef TOOLBARLOCATION_H +#define TOOLBARLOCATION_H + +#include + +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 From 424fb5984df05a91cccbcae526d8059c1d940e74 Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 31 Dec 2018 09:33:34 +0100 Subject: [PATCH 04/24] Fixed loading of data in CrudModel. --- pglab/CrudModel.cpp | 6 +++--- pglab/CrudModel.h | 12 +----------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/pglab/CrudModel.cpp b/pglab/CrudModel.cpp index d4c5222..18eda02 100644 --- a/pglab/CrudModel.cpp +++ b/pglab/CrudModel.cpp @@ -172,8 +172,8 @@ void CrudModel::loadData() if (res.valid()) { auto dbres = res.get(); if (dbres && *dbres) { -/// \todo Use ControllableTask instead with QFUtureWatcher -// m_asyncWindow->QueueTask([this, dbres]() { loadIntoModel(dbres); }); + QMetaObject::invokeMethod(this, "loadIntoModel", Qt::QueuedConnection, + Q_ARG(std::shared_ptr, dbres)); } } else { @@ -197,7 +197,7 @@ void CrudModel::loadIntoModel(std::shared_ptr data) void CrudModel::initRowMapping() { - m_rowMapping.resize(m_rowCount); + m_rowMapping.resize(static_cast(m_rowCount)); for (int i = 0; i < m_rowCount; ++i) m_rowMapping[i] = RowMapping{ i }; } diff --git a/pglab/CrudModel.h b/pglab/CrudModel.h index ac071e4..19482bb 100644 --- a/pglab/CrudModel.h +++ b/pglab/CrudModel.h @@ -263,13 +263,6 @@ private: /// call on initial load to fill in the mappings void initRowMapping(); -// using RedirectVec = std::vector; -// /// In sync with the actual table, used to efficiently find the correct row in the result -// RedirectVec m_redirectVector; - - - void loadIntoModel(std::shared_ptr data); - Value getData(const QModelIndex &index) const; Oid getType(int column) const; @@ -317,11 +310,8 @@ private: int attNumToCol(int attnum) const { return attnum - 1; } private slots: + void loadIntoModel(std::shared_ptr data); void connectionStateChanged(ASyncDBConnection::State state); -// void queryResult(std::shared_ptr result); -// void queryError(); - -// void dataProcessingFutureFinished(); }; #endif // CRUDMODEL_H From cc4f309c0f0c611b4224238ad90bcc9557864703 Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 31 Dec 2018 09:40:25 +0100 Subject: [PATCH 05/24] Completed removal of ASyncWindow --- pglab/ASyncWindow.cpp | 25 ------------------------- pglab/ASyncWindow.h | 24 ------------------------ pglab/CrudModel.cpp | 1 - pglab/DatabaseWindow.h | 1 - pglab/ServerWindow.cpp | 2 +- pglab/ServerWindow.h | 4 ++-- pglab/pglab.pro | 2 -- 7 files changed, 3 insertions(+), 56 deletions(-) delete mode 100644 pglab/ASyncWindow.cpp delete mode 100644 pglab/ASyncWindow.h diff --git a/pglab/ASyncWindow.cpp b/pglab/ASyncWindow.cpp deleted file mode 100644 index ab15bf6..0000000 --- a/pglab/ASyncWindow.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "ASyncWindow.h" -#include - -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())); - } - } -} diff --git a/pglab/ASyncWindow.h b/pglab/ASyncWindow.h deleted file mode 100644 index 59f3f67..0000000 --- a/pglab/ASyncWindow.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ASYNCWINDOW_H -#define ASYNCWINDOW_H - -#include -#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 diff --git a/pglab/CrudModel.cpp b/pglab/CrudModel.cpp index 18eda02..f404c1b 100644 --- a/pglab/CrudModel.cpp +++ b/pglab/CrudModel.cpp @@ -1,5 +1,4 @@ #include "CrudModel.h" -#include "ASyncWindow.h" #include "OpenDatabase.h" #include "catalog/PgDatabaseCatalog.h" #include "catalog/PgAttribute.h" diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index bb09bfa..8999774 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -5,7 +5,6 @@ #include "ConnectionConfig.h" #include "OpenDatabase.h" #include -//#include "ASyncWindow.h" #include #include #include diff --git a/pglab/ServerWindow.cpp b/pglab/ServerWindow.cpp index c2c49da..31cb27e 100644 --- a/pglab/ServerWindow.cpp +++ b/pglab/ServerWindow.cpp @@ -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) { diff --git a/pglab/ServerWindow.h b/pglab/ServerWindow.h index 9d90e28..d9a9d39 100644 --- a/pglab/ServerWindow.h +++ b/pglab/ServerWindow.h @@ -1,8 +1,8 @@ #ifndef SERVERWINDOW_H #define SERVERWINDOW_H -#include "ASyncWindow.h" #include "ConnectionConfig.h" +#include #include 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 ); diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 3824e8a..a2dcd1e 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -42,7 +42,6 @@ SOURCES += main.cpp\ OpenDatabase.cpp \ SqlSyntaxHighlighter.cpp \ ServerWindow.cpp \ - ASyncWindow.cpp \ DatabasesTableModel.cpp \ RolesTableModel.cpp \ ConnectionList.cpp \ @@ -107,7 +106,6 @@ HEADERS += \ OpenDatabase.h \ SqlSyntaxHighlighter.h \ ServerWindow.h \ - ASyncWindow.h \ DatabasesTableModel.h \ RolesTableModel.h \ ConnectionList.h \ From 1da8ef74071231f12d5584c398aa640260438e2d Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 31 Dec 2018 09:51:52 +0100 Subject: [PATCH 06/24] Remove all knowledge of DatabaseWindow from CrudTab (unwanted dependency) --- pglab/CrudTab.cpp | 4 +--- pglab/CrudTab.h | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/pglab/CrudTab.cpp b/pglab/CrudTab.cpp index d831c7f..57c1c45 100644 --- a/pglab/CrudTab.cpp +++ b/pglab/CrudTab.cpp @@ -1,7 +1,6 @@ #include "CrudTab.h" #include "ui_CrudTab.h" #include "CrudModel.h" -#include "DatabaseWindow.h" #include "ResultTableModelUtil.h" #include "PgLabItemDelegate.h" #include "IntegerRange.h" @@ -12,10 +11,9 @@ #include -CrudTab::CrudTab(IPluginContentWidgetContext *context, DatabaseWindow *parent) +CrudTab::CrudTab(IPluginContentWidgetContext *context, QWidget *parent) : PluginContentWidget(context, parent) , ui(new Ui::CrudTab) - , m_window(parent) { ui->setupUi(this); diff --git a/pglab/CrudTab.h b/pglab/CrudTab.h index 64ae374..838492d 100644 --- a/pglab/CrudTab.h +++ b/pglab/CrudTab.h @@ -13,14 +13,13 @@ namespace Ui { class OpenDatabase; class CrudModel; -class DatabaseWindow; class CrudTab : public PluginContentWidget { Q_OBJECT public: - explicit CrudTab(IPluginContentWidgetContext *context, DatabaseWindow *parent = nullptr); + explicit CrudTab(IPluginContentWidgetContext *context, QWidget *parent = nullptr); ~CrudTab() override; void setConfig(std::shared_ptr db, const PgClass &table); @@ -31,8 +30,6 @@ public: private: Ui::CrudTab *ui; - DatabaseWindow *m_window; - std::shared_ptr m_db; std::optional m_table; @@ -40,7 +37,6 @@ private: std::vector actions; private slots: -// void tableView_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous); void on_actionRemove_rows_triggered(); void headerCustomContextMenu(const QPoint &pos); }; From f9967039375ee9d476583210974571cab1530df0 Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 31 Dec 2018 11:38:54 +0100 Subject: [PATCH 07/24] Corrected some usage of QueueTask that was already broken as QueueTask is defunct. --- core/ExplainTreeModelItem.cpp | 8 ++ core/ExplainTreeModelItem.h | 3 +- pglab/DatabaseWindow.cpp | 5 -- pglab/QueryTab.cpp | 163 +++++++++++++++++----------------- pglab/QueryTab.h | 5 +- pglab/pglab.pro | 2 - pglab/tsqueue.cpp | 27 ------ pglab/tsqueue.h | 26 ------ 8 files changed, 95 insertions(+), 144 deletions(-) delete mode 100644 pglab/tsqueue.cpp delete mode 100644 pglab/tsqueue.h diff --git a/core/ExplainTreeModelItem.cpp b/core/ExplainTreeModelItem.cpp index 5f71489..035c671 100644 --- a/core/ExplainTreeModelItem.cpp +++ b/core/ExplainTreeModelItem.cpp @@ -4,6 +4,14 @@ namespace { + class registerMetaTypes { + public: + registerMetaTypes() + { + qRegisterMetaType(); + } + } registerMetaTypes_instance; + ExplainTreeModelItemPtr createPlanItemFromJson(Json::Value &plan) { diff --git a/core/ExplainTreeModelItem.h b/core/ExplainTreeModelItem.h index f800874..f78bb73 100644 --- a/core/ExplainTreeModelItem.h +++ b/core/ExplainTreeModelItem.h @@ -1,9 +1,9 @@ #pragma once #include -//#include #include #include +#include namespace Json { @@ -161,3 +161,4 @@ public: }; +Q_DECLARE_METATYPE(ExplainRoot::SPtr); diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 9def9b1..dd813da 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -50,11 +50,6 @@ namespace DatabaseWindow_details { return m_window->getDatabase(); } - void QueueTask(TSQueue::t_Callable ) override - { -// m_window->QueueTask(c); - } - void showStatusMessage(const QString &msg) override { m_window->statusBar()->showMessage(msg); diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index e97e4e9..703c799 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -54,14 +54,11 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) connect(ui->removeButton, &QPushButton::clicked, m_queryParamListController, &QueryParamListController::on_removeParam); - context()->QueueTask([this]() { startConnect(); }); + startConnect(); } QueryTab::~QueryTab() { -// m_dbConnection.blockSignals(true); -// m_dbConnection.closeConnection(); - delete ui; } @@ -158,7 +155,16 @@ void QueryTab::execute() auto cb = [this](Expected> res, qint64 elapsedms) { - context()->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, dbresult), + Q_ARG(qint64, elapsedms)); + } + else { + /// \todo handle error + + } }; if (m_queryParamListController->empty()) @@ -201,7 +207,8 @@ void QueryTab::explain(bool analyze) explain = ExplainRoot::createFromJson(root); } } - context()->QueueTask([this, explain]() { explain_ready(explain); }); + QMetaObject::invokeMethod(this, "explain_ready", + Q_ARG(ExplainRoot::SPtr, explain)); }).detach(); } } @@ -436,86 +443,80 @@ std::string QueryTab::getCommandUtf8() const //} -void QueryTab::query_ready(Expected> exp_res, qint64 elapsedms) +void QueryTab::query_ready(std::shared_ptr dbres, 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()); + 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(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); + auto result_model = std::make_shared(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)); + } + 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->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 - } + 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::markError(const Pgsql::ErrorDetails &details) diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index bac8480..15fe669 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -94,8 +94,6 @@ private: QString getCommand() const; std::string getCommandUtf8() const; - void explain_ready(ExplainRoot::SPtr explain); - void query_ready(Expected> dbres, qint64 elapsedms); //QTabWidget *getTabWidget(); //void setTabCaption(const QString &caption, const QString &tooltip); @@ -104,6 +102,9 @@ private: private slots: + void explain_ready(ExplainRoot::SPtr explain); + void query_ready(std::shared_ptr, qint64 elapsedms); + void queryTextChanged(); void connectionStateChanged(ASyncDBConnection::State state); void receiveNotice(Pgsql::ErrorDetails notice); diff --git a/pglab/pglab.pro b/pglab/pglab.pro index a2dcd1e..4b399cc 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -28,7 +28,6 @@ win32:RC_ICONS += pglab.ico SOURCES += main.cpp\ QueryResultModel.cpp \ QueryExplainModel.cpp \ - tsqueue.cpp \ CreateDatabaseDialog.cpp \ ConnectionManagerWindow.cpp \ ConnectionListModel.cpp \ @@ -93,7 +92,6 @@ PropertyProxyModel.cpp \ HEADERS += \ QueryResultModel.h \ QueryExplainModel.h \ - tsqueue.h \ CreateDatabaseDialog.h \ ConnectionManagerWindow.h \ ConnectionListModel.h \ diff --git a/pglab/tsqueue.cpp b/pglab/tsqueue.cpp deleted file mode 100644 index ef3a0f9..0000000 --- a/pglab/tsqueue.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "tsqueue.h" - -TSQueue::TSQueue() -{} - -void TSQueue::add(t_Callable callable) -{ - std::lock_guard g(m); - futureQueue.push_back(std::move(callable)); -} - -bool TSQueue::empty() -{ - std::lock_guard g(m); - return futureQueue.empty(); -} - -TSQueue::t_Callable TSQueue::pop() -{ - std::lock_guard g(m); - auto f = std::move(futureQueue.front()); - futureQueue.pop_front(); - if (futureQueue.empty()) { - } - return f; -} - diff --git a/pglab/tsqueue.h b/pglab/tsqueue.h deleted file mode 100644 index 779624e..0000000 --- a/pglab/tsqueue.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef TSQUEUE_H -#define TSQUEUE_H - -//#include "Win32Event.h" -#include -#include -#include - -class TSQueue { -public: - using t_Callable = std::function; - - TSQueue(); - void add(t_Callable callable); - bool empty(); - t_Callable pop(); - -private: - using t_CallableQueue = std::deque; - - std::mutex m; - t_CallableQueue futureQueue; -}; - - -#endif // TSQUEUE_H From b0cd47ef46131fd81f01f7d5909a1d35e9ee3c1d Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 31 Dec 2018 15:20:55 +0100 Subject: [PATCH 08/24] Extended the plugin system to allow for dynamic runtime bindings between modules. As a test implementation, this allows the TablesPage to open a CrudTab for a table/view without the need for TablesPage, CrudTab and DatabaseWindow to know anything about each other. --- pglab/CrudTab.cpp | 44 +++++++++++++++++-- pglab/CrudTab.h | 16 ++++++- pglab/DatabaseWindow.cpp | 24 +++++----- pglab/DatabaseWindow.h | 6 +-- pglab/QueryTab.cpp | 15 ++----- pglab/QueryTab.h | 2 +- pglab/TablesPage.cpp | 11 ++--- pglab/TablesPage.h | 8 ++-- pglab/pglab.pro | 9 ++-- .../IPluginContentWidgetContext.h | 15 +++++-- pglab/plugin_support/ModuleActionParameters.h | 10 +++++ .../PluginContentWidgetContextBase.cpp | 27 ++++++++++++ .../PluginContentWidgetContextBase.h | 19 ++++++++ pglab/plugin_support/PluginModule.cpp | 14 ++++++ pglab/plugin_support/PluginModule.h | 32 ++++++++++++-- pglab/plugin_support/PluginRegister.cpp | 10 ++++- pglab/plugin_support/PluginRegister.h | 2 + 17 files changed, 209 insertions(+), 55 deletions(-) rename pglab/{ => plugin_support}/IPluginContentWidgetContext.h (76%) create mode 100644 pglab/plugin_support/ModuleActionParameters.h create mode 100644 pglab/plugin_support/PluginContentWidgetContextBase.cpp create mode 100644 pglab/plugin_support/PluginContentWidgetContextBase.h diff --git a/pglab/CrudTab.cpp b/pglab/CrudTab.cpp index 57c1c45..7865faf 100644 --- a/pglab/CrudTab.cpp +++ b/pglab/CrudTab.cpp @@ -4,11 +4,16 @@ #include "ResultTableModelUtil.h" #include "PgLabItemDelegate.h" #include "IntegerRange.h" +#include "OpenDatabase.h" +#include "catalog/PgClassContainer.h" +#include "catalog/PgDatabaseCatalog.h" #include #include #include #include #include +#include "plugin_support/PluginRegister.h" +#include "plugin_support/IPluginContentWidgetContext.h" CrudTab::CrudTab(IPluginContentWidgetContext *context, QWidget *parent) @@ -41,11 +46,11 @@ CrudTab::~CrudTab() delete ui; } -void CrudTab::setConfig(std::shared_ptr db, const PgClass &table) +void CrudTab::setConfig(Oid oid) //std::shared_ptr db, const PgClass &table) { - m_db = db; - m_table = table; - m_crudModel->setConfig(db, table); + m_db = context()->getDatabase();; + m_table = *m_db->catalog()->classes()->getByKey(oid); + m_crudModel->setConfig(m_db, *m_table); } void CrudTab::refresh() @@ -113,3 +118,34 @@ 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); + }); +} + +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(ct); // maybe CrudTab should do this + ct->setConfig(params.at("oid").toUInt()); + +} + +namespace { + + std::weak_ptr register_variable = createPluginModule + ("CRUD tool", "pglab.crudpage"); + +} diff --git a/pglab/CrudTab.h b/pglab/CrudTab.h index 838492d..76628ee 100644 --- a/pglab/CrudTab.h +++ b/pglab/CrudTab.h @@ -4,6 +4,7 @@ #include "catalog/PgClass.h" #include #include "plugin_support/PluginContentWidget.h" +#include "plugin_support/PluginModule.h" #include #include @@ -22,7 +23,7 @@ public: explicit CrudTab(IPluginContentWidgetContext *context, QWidget *parent = nullptr); ~CrudTab() override; - void setConfig(std::shared_ptr db, const PgClass &table); + void setConfig(Oid oid); void refresh(); @@ -41,4 +42,17 @@ private slots: 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 diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index dd813da..c5890c2 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -18,18 +18,17 @@ #include "plugin_support/PluginContentWidget.h" #include "CodeGenerator.h" #include "MasterController.h" -#include "CrudTab.h" #include "WorkManager.h" #include "ScopeGuard.h" #include "EditTableWidget.h" -#include "IPluginContentWidgetContext.h" +#include "plugin_support/PluginContentWidgetContextBase.h" #include "TaskExecutor.h" namespace pg = Pgsql; namespace DatabaseWindow_details { - class DatabaseWindowContentContext: public IPluginContentWidgetContext { + class DatabaseWindowContentContext: public PluginContentWidgetContextBase { public: explicit DatabaseWindowContentContext(DatabaseWindow *window) : m_window(window) @@ -54,6 +53,11 @@ namespace DatabaseWindow_details { { m_window->statusBar()->showMessage(msg); } + + void addContentWidget(PluginContentWidget *widget) override + { + m_window->addPage(widget, ""); + } private: DatabaseWindow *m_window; }; @@ -96,13 +100,6 @@ void DatabaseWindow::newCreateTablePage() ui->tabWidget->addTab(w, "Create table"); } -void DatabaseWindow::newCrudPage(const PgClass &table) -{ - CrudTab *ct = new CrudTab(m_context, this); - ct->setConfig(m_database, table); - addPage(ct, table.objectName()); -} - void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr dbres) { auto cgtab = new CodeGenerator(m_context, this); @@ -110,7 +107,6 @@ void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptrtabWidget->currentWidget(); @@ -143,16 +139,16 @@ void DatabaseWindow::catalogLoaded() //SCOPE_EXIT { loadFuture = {}; }; m_database = loadWatcher.future().result(); - auto tt = new TablesPage(this); + auto tt = new TablesPage(m_context, this); tt->setCatalog(m_database->catalog()); ui->tabWidget->addTab(tt, "Tables"); - auto pg_cat_tables = new TablesPage(this); + auto pg_cat_tables = new TablesPage(m_context, 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); + auto info_schema_tables = new TablesPage(m_context, this); info_schema_tables->setNamespaceFilter(TablesTableModel::InformationSchema); info_schema_tables->setCatalog(m_database->catalog()); ui->tabWidget->addTab(info_schema_tables, "information_schema"); diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index 8999774..8183dff 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -55,11 +55,13 @@ public: std::shared_ptr getDatabase() { return m_database; } - void newCrudPage(const PgClass &table); void newCodeGenPage(QString query, std::shared_ptr dbres); 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); private: Ui::MainWindow *ui; @@ -124,8 +126,6 @@ private: void newCreateTablePage(); - /// Called when a newly created page is added to the QTabWidget - void addPage(PluginContentWidget* page, QString caption); /// Called when a page is completely removed from the QTabWidget void removePage(PluginContentWidget *page); diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index 703c799..fd33353 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -21,7 +21,7 @@ #include "util.h" #include "GlobalIoService.h" #include "UserConfiguration.h" -#include "IPluginContentWidgetContext.h" +#include "plugin_support/IPluginContentWidgetContext.h" #include "plugin_support/PluginRegister.h" QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) @@ -687,16 +687,7 @@ void QueryToolModule::new_triggered() namespace { - - std::shared_ptr createModule() - { - auto module = std::make_shared("Query tool", "pglab.querytool"); - module->init(); - - PluginRegister::getInstance()->registerModule(module); - return std::move(module); - } - - std::weak_ptr register_variable = createModule(); + std::weak_ptr register_variable = createPluginModule + ("Query tool", "pglab.querytool"); } diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index 15fe669..70bcee4 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -9,8 +9,8 @@ #include #include "plugin_support/PluginContentWidget.h" -#include #include "plugin_support/PluginModule.h" +#include namespace Ui { class QueryTab; diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index 1151396..4afd76f 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -21,11 +21,11 @@ #include "SqlCodePreview.h" #include #include +#include "plugin_support/IPluginContentWidgetContext.h" -TablesPage::TablesPage(DatabaseWindow *parent) - : QWidget(parent) +TablesPage::TablesPage(IPluginContentWidgetContext *context_, QWidget *parent) + : PluginContentWidget(context_, parent) , ui(new Ui::TablesPage) - , m_window(parent) { ui->setupUi(this); @@ -239,9 +239,10 @@ void TablesPage::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 &table) diff --git a/pglab/TablesPage.h b/pglab/TablesPage.h index ecffd24..5079c45 100644 --- a/pglab/TablesPage.h +++ b/pglab/TablesPage.h @@ -6,6 +6,8 @@ #include #include #include "TablesTableModel.h" +#include "plugin_support/PluginContentWidget.h" +#include "plugin_support/PluginModule.h" namespace Ui { class TablesPage; @@ -18,25 +20,23 @@ class ConstraintModel; class PgDatabaseCatalog; class NamespaceFilterWidget; class IndexModel; -class DatabaseWindow; class PropertiesPage; class TriggerPage; class PgClass; class SqlCodePreview; -class TablesPage : public QWidget +class TablesPage : public PluginContentWidget { Q_OBJECT public: - explicit TablesPage(DatabaseWindow *parent = nullptr); + explicit TablesPage(IPluginContentWidgetContext *context, QWidget *parent = nullptr); ~TablesPage(); void setCatalog(std::shared_ptr cat); void setNamespaceFilter(TablesTableModel::NamespaceFilter filter); private: Ui::TablesPage *ui; - DatabaseWindow *m_window; // QWidget *m_columnsTab; ColumnPage *m_columnsPage; // QWidget *m_propertiesTab; diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 4b399cc..18d35e4 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -87,7 +87,8 @@ PropertyProxyModel.cpp \ plugin_support/MenuLocation.cpp \ plugin_support/ToolbarLocation.cpp \ plugin_support/PluginRegister.cpp \ - plugin_support/PluginContentWidget.cpp + plugin_support/PluginContentWidget.cpp \ + plugin_support/PluginContentWidgetContextBase.cpp HEADERS += \ QueryResultModel.h \ @@ -147,13 +148,15 @@ CustomDataRole.h \ SequencesPage.h \ DatabaseWindow.h \ PgLabTableView.h \ - IPluginContentWidgetContext.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/PluginContentWidget.h \ + plugin_support/ModuleActionParameters.h \ + plugin_support/IPluginContentWidgetContext.h \ + plugin_support/PluginContentWidgetContextBase.h FORMS += mainwindow.ui \ ConnectionManagerWindow.ui \ diff --git a/pglab/IPluginContentWidgetContext.h b/pglab/plugin_support/IPluginContentWidgetContext.h similarity index 76% rename from pglab/IPluginContentWidgetContext.h rename to pglab/plugin_support/IPluginContentWidgetContext.h index 8624ab8..9424ce4 100644 --- a/pglab/IPluginContentWidgetContext.h +++ b/pglab/plugin_support/IPluginContentWidgetContext.h @@ -3,7 +3,7 @@ #include #include -#include "tsqueue.h" +#include "plugin_support/ModuleActionParameters.h" class OpenDatabase; class PluginContentWidget; @@ -11,7 +11,8 @@ class PluginContentWidget; /** This class serves to isolate the plugin from the actual construct in which it is * used. * - * It provides functions for operating on the context without needing to many details. + * It provides interface for operating on the context without needing to many details. + * Actual default implementation is in PluginContentWidgetContextBase. */ class IPluginContentWidgetContext { public: @@ -36,9 +37,15 @@ public: */ virtual std::shared_ptr getDatabase() = 0; - virtual void QueueTask(TSQueue::t_Callable c) = 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(PluginContentWidget *widget) = 0; }; #endif // IPLUGINCONTENTWIDGETCONTEXT_H diff --git a/pglab/plugin_support/ModuleActionParameters.h b/pglab/plugin_support/ModuleActionParameters.h new file mode 100644 index 0000000..e3fb45c --- /dev/null +++ b/pglab/plugin_support/ModuleActionParameters.h @@ -0,0 +1,10 @@ +#ifndef MODULEACTIONPARAMETERS_H +#define MODULEACTIONPARAMETERS_H + +#include +#include +#include + +using ModuleActionParameters = std::map; + +#endif // MODULEACTIONPARAMETERS_H diff --git a/pglab/plugin_support/PluginContentWidgetContextBase.cpp b/pglab/plugin_support/PluginContentWidgetContextBase.cpp new file mode 100644 index 0000000..10587ff --- /dev/null +++ b/pglab/plugin_support/PluginContentWidgetContextBase.cpp @@ -0,0 +1,27 @@ +#include "PluginContentWidgetContextBase.h" +#include "PluginRegister.h" +#include "PluginModule.h" +#include + +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); +} diff --git a/pglab/plugin_support/PluginContentWidgetContextBase.h b/pglab/plugin_support/PluginContentWidgetContextBase.h new file mode 100644 index 0000000..d060ba3 --- /dev/null +++ b/pglab/plugin_support/PluginContentWidgetContextBase.h @@ -0,0 +1,19 @@ +#ifndef PLUGINCONTENTWIDGETCONTEXTBASE_H +#define PLUGINCONTENTWIDGETCONTEXTBASE_H + +#include "plugin_support/IPluginContentWidgetContext.h" + +/// 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; +}; + +#endif // PLUGINCONTENTWIDGETCONTEXTBASE_H diff --git a/pglab/plugin_support/PluginModule.cpp b/pglab/plugin_support/PluginModule.cpp index 1991dd1..a9e9ec7 100644 --- a/pglab/plugin_support/PluginModule.cpp +++ b/pglab/plugin_support/PluginModule.cpp @@ -16,4 +16,18 @@ void PluginModule::registerAction(QAction *action, MenuLocation menu_location, T } +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; +} diff --git a/pglab/plugin_support/PluginModule.h b/pglab/plugin_support/PluginModule.h index 6577550..68b147c 100644 --- a/pglab/plugin_support/PluginModule.h +++ b/pglab/plugin_support/PluginModule.h @@ -1,16 +1,23 @@ #ifndef PLUGIN_SUPPORTPLUGINMODULE_H #define PLUGIN_SUPPORTPLUGINMODULE_H -#include "plugin_support/MenuLocation.h" -#include "plugin_support/ToolbarLocation.h" +#include "MenuLocation.h" +#include "ToolbarLocation.h" +#include "ModuleActionParameters.h" +#include "PluginRegister.h" #include +#include +#include class QAction; - +class IPluginContentWidgetContext; class PluginModule: public QObject { Q_OBJECT public: + using ModuleAction = std::function; + using ModuleActionMap = std::map; + PluginModule(QString name, QString ident); const QString& name() const { return m_name; } @@ -19,13 +26,32 @@ public: void setDisplayCategory(QString category); void registerAction(QAction *action, MenuLocation menu_location, ToolbarLocation toolbar_location); + + 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; private: /// Name shown to end users QString m_name; /// Unique identifier QString m_ident; QString m_displayCategory; + + ModuleActionMap m_moduleActions; }; +template +std::shared_ptr createPluginModule(QString name, QString ident) +{ + auto module = std::make_shared(std::move(name), std::move(ident)); + module->init(); + + PluginRegister::getInstance()->registerModule(module); + return std::move(module); +} + + #endif // PLUGIN_SUPPORTPLUGINMODULE_H diff --git a/pglab/plugin_support/PluginRegister.cpp b/pglab/plugin_support/PluginRegister.cpp index 57b9eca..342a691 100644 --- a/pglab/plugin_support/PluginRegister.cpp +++ b/pglab/plugin_support/PluginRegister.cpp @@ -25,5 +25,13 @@ PluginRegister::PluginRegister() = default; void PluginRegister::registerModule(PluginModuleSPtr module) { - qDebug() << "Register called for " << 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(); } diff --git a/pglab/plugin_support/PluginRegister.h b/pglab/plugin_support/PluginRegister.h index ff80136..3bd43a7 100644 --- a/pglab/plugin_support/PluginRegister.h +++ b/pglab/plugin_support/PluginRegister.h @@ -19,6 +19,8 @@ public: PluginRegister(); void registerModule(PluginModuleSPtr module); const ModuleMap& modules() const { return m_moduleMap; } + + const PluginModule* findModule(const QString &module_ident) const; private: ModuleMap m_moduleMap; From 456180325e9a9c32d994e8bc75b6dd85f0cd867b Mon Sep 17 00:00:00 2001 From: eelke Date: Mon, 31 Dec 2018 15:43:22 +0100 Subject: [PATCH 09/24] Code cleanups --- core/WorkManager.cpp | 47 ---------------------- core/WorkManager.h | 22 ---------- core/core.pro | 2 - pglab/CrudModel.cpp | 1 - pglab/DatabaseWindow.cpp | 5 +-- pglab/DatabaseWindow.h | 5 +-- pglab/{MainWindow.ui => DatabaseWindow.ui} | 6 +-- pglab/TablesPage.cpp | 1 - pglab/TablesPage.h | 6 --- pglab/pglab.pro | 5 ++- 10 files changed, 10 insertions(+), 90 deletions(-) delete mode 100644 core/WorkManager.cpp delete mode 100644 core/WorkManager.h rename pglab/{MainWindow.ui => DatabaseWindow.ui} (98%) diff --git a/core/WorkManager.cpp b/core/WorkManager.cpp deleted file mode 100644 index 05cf95d..0000000 --- a/core/WorkManager.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "WorkManager.h" - -#include -#include -#include -#include -#include - - -class WorkManagerImpl: public WorkManager { -public: - void addRunnable(QRunnable *runnable) override; - void addWork(Work work) override; -}; - - - -std::shared_ptr WorkManager::getWorkManager() -{ - static std::shared_ptr wm = std::make_shared(); - 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))); -} diff --git a/core/WorkManager.h b/core/WorkManager.h deleted file mode 100644 index c90239d..0000000 --- a/core/WorkManager.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef WORKMANAGER_H -#define WORKMANAGER_H - -#include -#include - -class QRunnable; - -class WorkManager { -public: - - static std::shared_ptr getWorkManager(); - - using Work = std::function; - - virtual ~WorkManager() = default; - virtual void addRunnable(QRunnable *runnable) = 0; - virtual void addWork(Work work) = 0; - -}; - -#endif // WORKMANAGER_H diff --git a/core/core.pro b/core/core.pro index a4a7e22..2289bec 100644 --- a/core/core.pro +++ b/core/core.pro @@ -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 \ diff --git a/pglab/CrudModel.cpp b/pglab/CrudModel.cpp index f404c1b..3acc331 100644 --- a/pglab/CrudModel.cpp +++ b/pglab/CrudModel.cpp @@ -6,7 +6,6 @@ #include "catalog/PgConstraintContainer.h" #include "GlobalIoService.h" #include "SqlFormattingUtils.h" -#include "WorkManager.h" #include "Pgsql_oids.h" #include #include diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index c5890c2..b073b7e 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -1,5 +1,5 @@ #include "DatabaseWindow.h" -#include "ui_MainWindow.h" +#include "ui_DatabaseWindow.h" #include "TablesPage.h" #include "FunctionsPage.h" #include "SequencesPage.h" @@ -18,7 +18,6 @@ #include "plugin_support/PluginContentWidget.h" #include "CodeGenerator.h" #include "MasterController.h" -#include "WorkManager.h" #include "ScopeGuard.h" #include "EditTableWidget.h" #include "plugin_support/PluginContentWidgetContextBase.h" @@ -68,7 +67,7 @@ using namespace DatabaseWindow_details; DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) : QMainWindow(parent) - , ui(new Ui::MainWindow) + , ui(new Ui::DatabaseWindow) , m_context(new DatabaseWindowContentContext(this)) , m_masterController(master) { diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index 8183dff..3c30a82 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -11,7 +11,6 @@ #include #include #include "Pgsql_Connection.h" -//#include "QueuedBackgroundTask.h" #include "ControllableTask.h" #include #include @@ -24,7 +23,7 @@ #include namespace Ui { - class MainWindow; + class DatabaseWindow; } namespace Pgsql { @@ -64,7 +63,7 @@ public: void addPage(PluginContentWidget* page, QString caption); private: - Ui::MainWindow *ui; + Ui::DatabaseWindow *ui; DatabaseWindow_details::DatabaseWindowContentContext *m_context; ConnectionConfig m_config; diff --git a/pglab/MainWindow.ui b/pglab/DatabaseWindow.ui similarity index 98% rename from pglab/MainWindow.ui rename to pglab/DatabaseWindow.ui index 98fe391..81bbb23 100644 --- a/pglab/MainWindow.ui +++ b/pglab/DatabaseWindow.ui @@ -1,7 +1,7 @@ - MainWindow - + DatabaseWindow + 0 @@ -45,7 +45,7 @@ 0 0 993 - 25 + 20 diff --git a/pglab/TablesPage.cpp b/pglab/TablesPage.cpp index 4afd76f..1445c62 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/TablesPage.cpp @@ -10,7 +10,6 @@ #include "ConstraintModel.h" #include "IconColumnDelegate.h" #include "IndexModel.h" -#include "DatabaseWindow.h" #include "PgLabItemDelegate.h" #include "PropertiesPage.h" #include "ResultTableModelUtil.h" diff --git a/pglab/TablesPage.h b/pglab/TablesPage.h index 5079c45..e741605 100644 --- a/pglab/TablesPage.h +++ b/pglab/TablesPage.h @@ -37,11 +37,8 @@ public: void setNamespaceFilter(TablesTableModel::NamespaceFilter filter); private: Ui::TablesPage *ui; - // QWidget *m_columnsTab; ColumnPage *m_columnsPage; -// QWidget *m_propertiesTab; PropertiesPage *m_propertiesPage; -// QWidget *m_triggerTab; TriggerPage *m_triggerPage; SqlCodePreview *m_sqlCodePreview; std::shared_ptr 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 &table); void updateSqlTab(const std::optional &table); @@ -60,7 +55,6 @@ private slots: void tableListTable_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous); void tableListTable_layoutChanged(const QList &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); diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 18d35e4..d492635 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -158,7 +158,7 @@ CustomDataRole.h \ plugin_support/IPluginContentWidgetContext.h \ plugin_support/PluginContentWidgetContextBase.h -FORMS += mainwindow.ui \ +FORMS += \ ConnectionManagerWindow.ui \ CreateDatabaseDialog.ui \ TuplesResultWidget.ui \ @@ -170,7 +170,8 @@ FORMS += mainwindow.ui \ NamespaceFilterWidget.ui \ ApplicationWindow.ui \ CrudTab.ui \ - CodeGenerator.ui + CodeGenerator.ui \ + DatabaseWindow.ui RESOURCES += \ resources.qrc From a29671593e09dae181cb7ae0df59c96dc404d638 Mon Sep 17 00:00:00 2001 From: eelke Date: Tue, 1 Jan 2019 08:26:20 +0100 Subject: [PATCH 10/24] Simplified module registration --- pglab/CrudTab.cpp | 7 +------ pglab/QueryTab.cpp | 8 +------- pglab/plugin_support/MenuAction.cpp | 6 ++++++ pglab/plugin_support/MenuAction.h | 11 +++++++++++ pglab/plugin_support/PluginModule.h | 5 +++++ 5 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 pglab/plugin_support/MenuAction.cpp create mode 100644 pglab/plugin_support/MenuAction.h diff --git a/pglab/CrudTab.cpp b/pglab/CrudTab.cpp index 7865faf..0b03ef1 100644 --- a/pglab/CrudTab.cpp +++ b/pglab/CrudTab.cpp @@ -143,9 +143,4 @@ void CrudPageModule::moduleAction_open( } -namespace { - - std::weak_ptr register_variable = createPluginModule - ("CRUD tool", "pglab.crudpage"); - -} +REGISTER_PLUGIN_MODULE(CrudPageModule, "CRUD tool", "pglab.crudpage") diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index fd33353..a2db049 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -684,10 +684,4 @@ void QueryToolModule::new_triggered() { } - -namespace { - - std::weak_ptr register_variable = createPluginModule - ("Query tool", "pglab.querytool"); - -} +REGISTER_PLUGIN_MODULE(QueryToolModule, "Query tool", "pglab.querytool") diff --git a/pglab/plugin_support/MenuAction.cpp b/pglab/plugin_support/MenuAction.cpp new file mode 100644 index 0000000..87199e2 --- /dev/null +++ b/pglab/plugin_support/MenuAction.cpp @@ -0,0 +1,6 @@ +#include "MenuAction.h" + +MenuAction::MenuAction() +{ + +} diff --git a/pglab/plugin_support/MenuAction.h b/pglab/plugin_support/MenuAction.h new file mode 100644 index 0000000..95409c5 --- /dev/null +++ b/pglab/plugin_support/MenuAction.h @@ -0,0 +1,11 @@ +#ifndef MENUACTION_H +#define MENUACTION_H + + +class MenuAction +{ +public: + MenuAction(); +}; + +#endif // MENUACTION_H \ No newline at end of file diff --git a/pglab/plugin_support/PluginModule.h b/pglab/plugin_support/PluginModule.h index 68b147c..c5aa8a0 100644 --- a/pglab/plugin_support/PluginModule.h +++ b/pglab/plugin_support/PluginModule.h @@ -53,5 +53,10 @@ std::shared_ptr createPluginModule(QString name, QString ident) return std::move(module); } +#define REGISTER_PLUGIN_MODULE(module, name, ident) \ + namespace {\ + std::weak_ptr register_variable = createPluginModule\ + (#name, #ident);} + #endif // PLUGIN_SUPPORTPLUGINMODULE_H From eec75e28f910c3de3c83d1ac7ce65de42ae13d69 Mon Sep 17 00:00:00 2001 From: eelke Date: Tue, 1 Jan 2019 08:49:32 +0100 Subject: [PATCH 11/24] Remove unused ApplicationWindow --- pglab/ApplicationWindow.cpp | 14 ---- pglab/ApplicationWindow.h | 22 ------ pglab/ApplicationWindow.ui | 145 ------------------------------------ pglab/pglab.pro | 3 - 4 files changed, 184 deletions(-) delete mode 100644 pglab/ApplicationWindow.cpp delete mode 100644 pglab/ApplicationWindow.h delete mode 100644 pglab/ApplicationWindow.ui diff --git a/pglab/ApplicationWindow.cpp b/pglab/ApplicationWindow.cpp deleted file mode 100644 index dd1c511..0000000 --- a/pglab/ApplicationWindow.cpp +++ /dev/null @@ -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; -} diff --git a/pglab/ApplicationWindow.h b/pglab/ApplicationWindow.h deleted file mode 100644 index b65d4e4..0000000 --- a/pglab/ApplicationWindow.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef APPLICATIONWINDOW_H -#define APPLICATIONWINDOW_H - -#include - -namespace Ui { -class ApplicationWindow; -} - -class ApplicationWindow : public QMainWindow -{ - Q_OBJECT - -public: - explicit ApplicationWindow(QWidget *parent = 0); - ~ApplicationWindow(); - -private: - Ui::ApplicationWindow *ui; -}; - -#endif // APPLICATIONWINDOW_H diff --git a/pglab/ApplicationWindow.ui b/pglab/ApplicationWindow.ui deleted file mode 100644 index b6faa92..0000000 --- a/pglab/ApplicationWindow.ui +++ /dev/null @@ -1,145 +0,0 @@ - - - ApplicationWindow - - - - 0 - 0 - 314 - 672 - - - - MainWindow - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 1 - 1 - - - - false - - - - - - - ... - - - - - - - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - - - - - - 0 - 0 - 314 - 25 - - - - - - - - diff --git a/pglab/pglab.pro b/pglab/pglab.pro index d492635..652a3e8 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -54,7 +54,6 @@ SOURCES += main.cpp\ ColumnTableModel.cpp \ NamespaceFilterWidget.cpp \ NamespaceItemModel.cpp \ - ApplicationWindow.cpp \ ConstraintModel.cpp \ IconColumnDelegate.cpp \ IndexModel.cpp \ @@ -118,7 +117,6 @@ HEADERS += \ ColumnTableModel.h \ NamespaceFilterWidget.h \ NamespaceItemModel.h \ - ApplicationWindow.h \ ConstraintModel.h \ IconColumnDelegate.h \ IndexModel.h \ @@ -168,7 +166,6 @@ FORMS += \ ProcessStdioWidget.ui \ TablesPage.ui \ NamespaceFilterWidget.ui \ - ApplicationWindow.ui \ CrudTab.ui \ CodeGenerator.ui \ DatabaseWindow.ui From f130c426a1f2c3d92b18c084149437978f82ebc1 Mon Sep 17 00:00:00 2001 From: eelke Date: Tue, 1 Jan 2019 11:04:48 +0100 Subject: [PATCH 12/24] Fix error on pg96 because of wrong minimum version --- pglablib/catalog/PgTriggerContainer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pglablib/catalog/PgTriggerContainer.cpp b/pglablib/catalog/PgTriggerContainer.cpp index fb32a4f..d082d4d 100644 --- a/pglablib/catalog/PgTriggerContainer.cpp +++ b/pglablib/catalog/PgTriggerContainer.cpp @@ -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; From dc8a052544ce9afd3a09d98da5c4d25da245de55 Mon Sep 17 00:00:00 2001 From: eelke Date: Tue, 1 Jan 2019 11:15:16 +0100 Subject: [PATCH 13/24] Basic concept of MenuAction is working Module can register action Window adds this action to its menu Clicking the menu item for the action has the expected result But menu structure still needs work (everything is now put into one dropdown menu) --- pglab/DatabaseWindow.cpp | 51 +++++++++++++++++++- pglab/DatabaseWindow.h | 26 +++++++++-- pglab/QueryTab.cpp | 14 ++++-- pglab/QueryTab.h | 4 +- pglab/main.cpp | 3 ++ pglab/pglab.pro | 6 ++- pglab/plugin_support/MenuAction.cpp | 62 +++++++++++++++++++++++-- pglab/plugin_support/MenuAction.h | 48 +++++++++++++++++-- pglab/plugin_support/PluginModule.cpp | 9 +++- pglab/plugin_support/PluginModule.h | 14 ++++-- pglab/plugin_support/PluginRegister.cpp | 7 +++ pglab/plugin_support/PluginRegister.h | 4 +- 12 files changed, 220 insertions(+), 28 deletions(-) diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index b073b7e..d48b0f5 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -65,17 +65,64 @@ namespace DatabaseWindow_details { using namespace DatabaseWindow_details; -DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) +LMainWindow::LMainWindow(QWidget *parent) : QMainWindow(parent) +{ + m_fileMenu = new QMenu("File T", this); + + +} + +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::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-> + + +} + +DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) + : LMainWindow(parent) , ui(new Ui::DatabaseWindow) - , m_context(new DatabaseWindowContentContext(this)) , m_masterController(master) { ui->setupUi(this); ui->tabWidget->setDocumentMode(true); + m_context = new DatabaseWindowContentContext(this); + connect(&loadWatcher, &QFutureWatcher::finished, this, &DatabaseWindow::catalogLoaded); + + initModuleMenus(); } DatabaseWindow::~DatabaseWindow() diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index 3c30a82..2bd8bd1 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -30,6 +30,7 @@ namespace Pgsql { class Connection; } +class MenuAction; class QueryTab; class MasterController; class QCloseEvent; @@ -41,13 +42,33 @@ namespace DatabaseWindow_details { class DatabaseWindowContentContext; } +class LMainWindow : public QMainWindow { + Q_OBJECT +public: + + LMainWindow(QWidget *parent = nullptr); + + void initModuleMenus(); +protected: + + DatabaseWindow_details::DatabaseWindowContentContext *m_context; + + void addModuleMenuActions(); + +private: + QMenu *m_fileMenu = nullptr; + + void addMenuAction(const MenuAction &ma); +}; + + /** This is the class for windows that handle tasks for a specific database/catalog * */ -class DatabaseWindow : public QMainWindow { +class DatabaseWindow : public LMainWindow { Q_OBJECT public: - explicit DatabaseWindow(MasterController *master, QWidget *parent); + DatabaseWindow(MasterController *master, QWidget *parent); ~DatabaseWindow(); void setConfig(const ConnectionConfig &config); @@ -64,7 +85,6 @@ public: private: Ui::DatabaseWindow *ui; - DatabaseWindow_details::DatabaseWindowContentContext *m_context; ConnectionConfig m_config; std::shared_ptr m_database; diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index a2db049..5331d4d 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -674,14 +674,18 @@ std::vector QueryTab::getToolbarActions() void QueryToolModule::init() { - auto action_new = new QAction(QIcon(":/icons/new_query_tab.png"), tr("New"), this); - connect(action_new, &QAction::triggered, this, &QueryToolModule::new_triggered); - - registerAction(action_new, MenuLocation({"File/New"}), ToolbarLocation("File", "")); + MenuAction ma_new("New", [this] (IPluginContentWidgetContext* context) + { menuAction_new(context); }); + ma_new.setMenuLocation(MenuPath("File/New")); + ma_new.setIcon(QIcon(":/icons/new_query_tab.png")); + registerMenuAction(ma_new); } -void QueryToolModule::new_triggered() +void QueryToolModule::menuAction_new(IPluginContentWidgetContext* context) { + auto *ct = new QueryTab(context, nullptr); + context->addContentWidget(ct); + ct->newdoc(); } REGISTER_PLUGIN_MODULE(QueryToolModule, "Query tool", "pglab.querytool") diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index 70bcee4..abcd7ef 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -117,9 +117,9 @@ class QueryToolModule: public PluginModule { public: using PluginModule::PluginModule; - void init(); + void init() override; + void menuAction_new(IPluginContentWidgetContext* context); private slots: - void new_triggered(); }; #endif // QUERYTAB_H diff --git a/pglab/main.cpp b/pglab/main.cpp index 38482a6..a78a29c 100644 --- a/pglab/main.cpp +++ b/pglab/main.cpp @@ -5,6 +5,7 @@ #endif #include #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; { diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 652a3e8..dfffeff 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -87,7 +87,8 @@ PropertyProxyModel.cpp \ plugin_support/ToolbarLocation.cpp \ plugin_support/PluginRegister.cpp \ plugin_support/PluginContentWidget.cpp \ - plugin_support/PluginContentWidgetContextBase.cpp + plugin_support/PluginContentWidgetContextBase.cpp \ + plugin_support/MenuAction.cpp HEADERS += \ QueryResultModel.h \ @@ -154,7 +155,8 @@ CustomDataRole.h \ plugin_support/PluginContentWidget.h \ plugin_support/ModuleActionParameters.h \ plugin_support/IPluginContentWidgetContext.h \ - plugin_support/PluginContentWidgetContextBase.h + plugin_support/PluginContentWidgetContextBase.h \ + plugin_support/MenuAction.h FORMS += \ ConnectionManagerWindow.ui \ diff --git a/pglab/plugin_support/MenuAction.cpp b/pglab/plugin_support/MenuAction.cpp index 87199e2..a53a0c7 100644 --- a/pglab/plugin_support/MenuAction.cpp +++ b/pglab/plugin_support/MenuAction.cpp @@ -1,6 +1,62 @@ -#include "MenuAction.h" +#include "MenuAction.h" -MenuAction::MenuAction() +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); } diff --git a/pglab/plugin_support/MenuAction.h b/pglab/plugin_support/MenuAction.h index 95409c5..21ff9ee 100644 --- a/pglab/plugin_support/MenuAction.h +++ b/pglab/plugin_support/MenuAction.h @@ -1,11 +1,49 @@ -#ifndef MENUACTION_H +#ifndef MENUACTION_H #define MENUACTION_H +#include "MenuLocation.h" +#include "ToolbarLocation.h" -class MenuAction -{ +#include +#include +#include +#include + +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: - MenuAction(); + using Func = std::function; + + 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 \ No newline at end of file + +#endif // MENUACTION_H diff --git a/pglab/plugin_support/PluginModule.cpp b/pglab/plugin_support/PluginModule.cpp index a9e9ec7..045604a 100644 --- a/pglab/plugin_support/PluginModule.cpp +++ b/pglab/plugin_support/PluginModule.cpp @@ -1,4 +1,5 @@ #include "plugin_support/PluginModule.h" +#include PluginModule::PluginModule(QString name, QString ident) : m_name(std::move(name)) @@ -11,9 +12,15 @@ void PluginModule::setDisplayCategory(QString category) m_displayCategory = std::move(category); } -void PluginModule::registerAction(QAction *action, MenuLocation menu_location, ToolbarLocation toolbar_location) +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) diff --git a/pglab/plugin_support/PluginModule.h b/pglab/plugin_support/PluginModule.h index c5aa8a0..e069246 100644 --- a/pglab/plugin_support/PluginModule.h +++ b/pglab/plugin_support/PluginModule.h @@ -1,13 +1,13 @@ #ifndef PLUGIN_SUPPORTPLUGINMODULE_H #define PLUGIN_SUPPORTPLUGINMODULE_H -#include "MenuLocation.h" -#include "ToolbarLocation.h" #include "ModuleActionParameters.h" +#include "MenuAction.h" #include "PluginRegister.h" #include #include #include +#include class QAction; class IPluginContentWidgetContext; @@ -15,17 +15,23 @@ class IPluginContentWidgetContext; class PluginModule: public QObject { Q_OBJECT public: + using MenuActionList = std::vector; using ModuleAction = std::function; using ModuleActionMap = std::map; 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); - void registerAction(QAction *action, MenuLocation menu_location, ToolbarLocation toolbar_location); + + /// 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); @@ -39,6 +45,7 @@ private: QString m_ident; QString m_displayCategory; + MenuActionList m_menuActions; ModuleActionMap m_moduleActions; }; @@ -47,7 +54,6 @@ template std::shared_ptr createPluginModule(QString name, QString ident) { auto module = std::make_shared(std::move(name), std::move(ident)); - module->init(); PluginRegister::getInstance()->registerModule(module); return std::move(module); diff --git a/pglab/plugin_support/PluginRegister.cpp b/pglab/plugin_support/PluginRegister.cpp index 342a691..f80791c 100644 --- a/pglab/plugin_support/PluginRegister.cpp +++ b/pglab/plugin_support/PluginRegister.cpp @@ -23,6 +23,13 @@ PluginRegister* PluginRegister::getInstance() PluginRegister::PluginRegister() = default; +void PluginRegister::initModules() +{ + for (auto && mod : m_moduleMap) { + mod.second->init(); + } +} + void PluginRegister::registerModule(PluginModuleSPtr module) { m_moduleMap.emplace(module->identifier(), module); diff --git a/pglab/plugin_support/PluginRegister.h b/pglab/plugin_support/PluginRegister.h index 3bd43a7..cc8449a 100644 --- a/pglab/plugin_support/PluginRegister.h +++ b/pglab/plugin_support/PluginRegister.h @@ -18,7 +18,9 @@ public: PluginRegister(); void registerModule(PluginModuleSPtr module); - const ModuleMap& modules() const { return m_moduleMap; } + + void initModules(); + const ModuleMap& modules() const{ return m_moduleMap; } const PluginModule* findModule(const QString &module_ident) const; private: From d86d278350f071a1d8ba873d696a8c89e99b6cfb Mon Sep 17 00:00:00 2001 From: eelke Date: Tue, 1 Jan 2019 14:34:14 +0100 Subject: [PATCH 14/24] Remove designer DatabaseForm generating widgets from code. Large part of toolbar and menu missing these will be recreated through plugin system. --- pglab/DatabaseWindow.cpp | 107 +++++++++++------ pglab/DatabaseWindow.h | 11 +- pglab/DatabaseWindow.ui | 248 --------------------------------------- pglab/pglab.pro | 3 +- 4 files changed, 77 insertions(+), 292 deletions(-) delete mode 100644 pglab/DatabaseWindow.ui diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index d48b0f5..58c4517 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -1,27 +1,31 @@ #include "DatabaseWindow.h" -#include "ui_DatabaseWindow.h" +//#include "ui_DatabaseWindow.h" #include "TablesPage.h" #include "FunctionsPage.h" #include "SequencesPage.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "QueryTab.h" #include "util.h" #include "plugin_support/PluginContentWidget.h" +#include "plugin_support/PluginContentWidgetContextBase.h" #include "CodeGenerator.h" #include "MasterController.h" #include "ScopeGuard.h" #include "EditTableWidget.h" -#include "plugin_support/PluginContentWidgetContextBase.h" #include "TaskExecutor.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace pg = Pgsql; @@ -111,11 +115,32 @@ void LMainWindow::addMenuAction(const MenuAction &ma) DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) : LMainWindow(parent) - , ui(new Ui::DatabaseWindow) +// , ui(new Ui::DatabaseWindow) , m_masterController(master) { - ui->setupUi(this); - ui->tabWidget->setDocumentMode(true); +// ui->setupUi(this); +// ui->tabWidget->setDocumentMode(true); + +// auto centralWidget = new QWidget(this); +// auto verticalLayout_3 = new QVBoxLayout(centralWidget); +// verticalLayout_3->setSpacing(4); +// verticalLayout_3->setContentsMargins(4, 4, 4, 4); + + m_tabWidget = new QTabWidget(this); + m_tabWidget->setObjectName(QString::fromUtf8("tabWidget")); + m_tabWidget->setDocumentMode(true); +// verticalLayout_3->addWidget(m_tabWidget); + + setCentralWidget(m_tabWidget); + + auto menuBar = new QMenuBar(this); + setMenuBar(menuBar); + + m_mainToolBar = new QToolBar(this); + addToolBar(Qt::TopToolBarArea, m_mainToolBar); + + auto statusBar = new QStatusBar(this); + setStatusBar(statusBar); m_context = new DatabaseWindowContentContext(this); @@ -123,12 +148,14 @@ DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) this, &DatabaseWindow::catalogLoaded); initModuleMenus(); + + QMetaObject::connectSlotsByName(this); } DatabaseWindow::~DatabaseWindow() { delete m_context; - delete ui; +// delete ui; } QueryTab* DatabaseWindow::newSqlPage() @@ -143,7 +170,7 @@ QueryTab* DatabaseWindow::newSqlPage() void DatabaseWindow::newCreateTablePage() { auto w = new EditTableWidget(m_database, this); - ui->tabWidget->addTab(w, "Create table"); + m_tabWidget->addTab(w, "Create table"); } void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr dbres) @@ -155,7 +182,7 @@ void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptrtabWidget->currentWidget(); + QWidget *widget = m_tabWidget->currentWidget(); QueryTab *qt = dynamic_cast(widget); return qt; } @@ -187,25 +214,25 @@ void DatabaseWindow::catalogLoaded() auto tt = new TablesPage(m_context, this); tt->setCatalog(m_database->catalog()); - ui->tabWidget->addTab(tt, "Tables"); + m_tabWidget->addTab(tt, "Tables"); auto pg_cat_tables = new TablesPage(m_context, this); pg_cat_tables->setNamespaceFilter(TablesTableModel::PgCatalog); pg_cat_tables->setCatalog(m_database->catalog()); - ui->tabWidget->addTab(pg_cat_tables, "pg_catalog"); + m_tabWidget->addTab(pg_cat_tables, "pg_catalog"); auto info_schema_tables = new TablesPage(m_context, this); info_schema_tables->setNamespaceFilter(TablesTableModel::InformationSchema); info_schema_tables->setCatalog(m_database->catalog()); - ui->tabWidget->addTab(info_schema_tables, "information_schema"); + m_tabWidget->addTab(info_schema_tables, "information_schema"); 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(); @@ -269,7 +296,7 @@ void DatabaseWindow::on_actionExport_data_triggered() void DatabaseWindow::on_actionClose_triggered() { //close(); - on_tabWidget_tabCloseRequested(ui->tabWidget->currentIndex()); + on_tabWidget_tabCloseRequested(m_tabWidget->currentIndex()); } void DatabaseWindow::on_actionAbout_triggered() @@ -338,12 +365,13 @@ void DatabaseWindow::on_actionNew_SQL_triggered() void DatabaseWindow::on_tabWidget_tabCloseRequested(int index) { - QWidget *widget = ui->tabWidget->widget(index); + QWidget *widget = m_tabWidget->widget(index); PluginContentWidget *plg_page = dynamic_cast(widget); if (plg_page) { if (plg_page->canClose()) { removePage(plg_page); - ui->tabWidget->removeTab(index); + m_tabWidget->removeTab(index); + delete plg_page; } } else { @@ -351,11 +379,14 @@ void DatabaseWindow::on_tabWidget_tabCloseRequested(int index) // to PlgPage QueryTab *qt = dynamic_cast(widget); if (qt && qt->canClose()) { - ui->tabWidget->removeTab(index); + m_tabWidget->removeTab(index); + delete qt; } else if (index > 0) { - ui->tabWidget->removeTab(index); + m_tabWidget->removeTab(index); + delete widget; } + } } @@ -412,22 +443,22 @@ void DatabaseWindow::addToolBarButtonsForPage(PluginContentWidget *page) for (auto act : actions) { list.append(act); } - ui->mainToolBar->addActions(list); + m_mainToolBar->addActions(list); } void DatabaseWindow::removeToolBarButtonsForPage(PluginContentWidget *page) { std::vector actions = page->getToolbarActions(); for (auto act : actions) { - ui->mainToolBar->removeAction(act); + m_mainToolBar->removeAction(act); } } void DatabaseWindow::addPage(PluginContentWidget* page, QString caption) { - ui->tabWidget->addTab(page, caption); - ui->tabWidget->setCurrentWidget(page); + m_tabWidget->addTab(page, caption); + m_tabWidget->setCurrentWidget(page); //addToolBarButtonsForPage(page); } @@ -447,7 +478,7 @@ void DatabaseWindow::on_tabWidget_currentChanged(int index) // add buttons of new page PluginContentWidget * page = nullptr; if (index >= 0) { - QWidget *widget = ui->tabWidget->widget(index); + QWidget *widget = m_tabWidget->widget(index); page = dynamic_cast(widget); if (page) { addToolBarButtonsForPage(page); @@ -467,14 +498,14 @@ void DatabaseWindow::on_actionGenerate_code_triggered() void DatabaseWindow::setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint) { - auto index = ui->tabWidget->indexOf(widget); - ui->tabWidget->setTabText(index, caption); - ui->tabWidget->setTabToolTip(index, hint); + auto index = m_tabWidget->indexOf(widget); + m_tabWidget->setTabText(index, caption); + m_tabWidget->setTabToolTip(index, hint); } void DatabaseWindow::setTabIcon(QWidget *widget, const QString &iconname) { - auto index = ui->tabWidget->indexOf(widget); + auto index = m_tabWidget->indexOf(widget); auto n = ":/icons/16x16/" + iconname; - ui->tabWidget->setTabIcon(index, QIcon(n)); + m_tabWidget->setTabIcon(index, QIcon(n)); } diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index 2bd8bd1..c3301a5 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -22,9 +22,9 @@ #include #include -namespace Ui { - class DatabaseWindow; -} +//namespace Ui { +// class DatabaseWindow; +//} namespace Pgsql { class Connection; @@ -38,6 +38,8 @@ class OpenDatabase; class PgClass; class PluginContentWidget; +class QTabWidget; + namespace DatabaseWindow_details { class DatabaseWindowContentContext; } @@ -84,7 +86,8 @@ public: void addPage(PluginContentWidget* page, QString caption); private: - Ui::DatabaseWindow *ui; + QTabWidget *m_tabWidget = nullptr; + QToolBar *m_mainToolBar = nullptr; ConnectionConfig m_config; std::shared_ptr m_database; diff --git a/pglab/DatabaseWindow.ui b/pglab/DatabaseWindow.ui deleted file mode 100644 index 81bbb23..0000000 --- a/pglab/DatabaseWindow.ui +++ /dev/null @@ -1,248 +0,0 @@ - - - DatabaseWindow - - - - 0 - 0 - 993 - 804 - - - - pglab - database - - - - - 7 - - - 4 - - - 4 - - - 4 - - - 4 - - - - - -1 - - - - - - - - - 0 - 0 - 993 - 20 - - - - - Fi&le - - - - - - - - - - - - - Help - - - - - - &Query - - - - - - Wi&ndow - - - - - - Edit - - - - - - - - - - - - - - - TopToolBarArea - - - false - - - - - - - - - - - - - - - - - - :/icons/folder.png:/icons/folder.png - - - &Load SQL - - - Ctrl+O - - - - - - :/icons/script_save.png:/icons/script_save.png - - - &Save SQL - - - Ctrl+S - - - - - - :/icons/table_save.png:/icons/table_save.png - - - &Export data - - - - - - :/icons/page_white_delete.png - - - - &Close - - - Ctrl+F4 - - - - - - :/icons/about.png - :/icons/information.png:/icons/about.png - - - &About - - - - - Sa&ve SQL as - - - - - Save copy &of SQL as - - - - - - :/icons/new_query_tab.png - :/icons/page_white_add.png:/icons/new_query_tab.png - - - &New SQL - - - Ctrl+N - - - - - &Show connection manager - - - - - - :/icons/page_white_copy.png - - - - &Copy - - - Ctrl+C - - - - - - :/icons/token_shortland_character.png - - - - Copy as C-&string - - - Ctrl+Alt+C - - - - - - :/icons/token_shortland_character.png - - - - Copy as raw C++-string - - - - - Generate code - - - - - - - - - diff --git a/pglab/pglab.pro b/pglab/pglab.pro index dfffeff..fea3323 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -169,8 +169,7 @@ FORMS += \ TablesPage.ui \ NamespaceFilterWidget.ui \ CrudTab.ui \ - CodeGenerator.ui \ - DatabaseWindow.ui + CodeGenerator.ui RESOURCES += \ resources.qrc From 4c3a2df65c2597f630e51a372e44e83e9f98f979 Mon Sep 17 00:00:00 2001 From: eelke Date: Tue, 1 Jan 2019 14:35:22 +0100 Subject: [PATCH 15/24] Fix plugin macro that added quotes to things that were already strings causing identifiers to not match. + some debug logging --- pglab/plugin_support/PluginModule.h | 2 +- pglab/plugin_support/PluginRegister.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pglab/plugin_support/PluginModule.h b/pglab/plugin_support/PluginModule.h index e069246..b3ea1db 100644 --- a/pglab/plugin_support/PluginModule.h +++ b/pglab/plugin_support/PluginModule.h @@ -62,7 +62,7 @@ std::shared_ptr createPluginModule(QString name, QString ident) #define REGISTER_PLUGIN_MODULE(module, name, ident) \ namespace {\ std::weak_ptr register_variable = createPluginModule\ - (#name, #ident);} + (name, ident);} #endif // PLUGIN_SUPPORTPLUGINMODULE_H diff --git a/pglab/plugin_support/PluginRegister.cpp b/pglab/plugin_support/PluginRegister.cpp index f80791c..8b1dd99 100644 --- a/pglab/plugin_support/PluginRegister.cpp +++ b/pglab/plugin_support/PluginRegister.cpp @@ -32,6 +32,7 @@ void PluginRegister::initModules() void PluginRegister::registerModule(PluginModuleSPtr module) { + qDebug() << "registerModule " << module->identifier(); m_moduleMap.emplace(module->identifier(), module); } From a5f4e4c54fcbf07a3ba5d7a28ec1f5291a9b0bf2 Mon Sep 17 00:00:00 2001 From: eelke Date: Fri, 4 Jan 2019 18:29:22 +0100 Subject: [PATCH 16/24] Create standard close action --- pglab/DatabaseWindow.cpp | 18 ++++++++++++++++-- pglab/DatabaseWindow.h | 6 +++++- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 58c4517..edcd3fb 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -133,10 +133,13 @@ DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) setCentralWidget(m_tabWidget); + createActions(); + auto menuBar = new QMenuBar(this); setMenuBar(menuBar); m_mainToolBar = new QToolBar(this); + m_mainToolBar->addAction(m_closeAction); addToolBar(Qt::TopToolBarArea, m_mainToolBar); auto statusBar = new QStatusBar(this); @@ -158,6 +161,18 @@ DatabaseWindow::~DatabaseWindow() // delete ui; } +void DatabaseWindow::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, &DatabaseWindow::actionClose_triggered); + } + +} + QueryTab* DatabaseWindow::newSqlPage() { QueryTab *qt = new QueryTab(m_context); @@ -293,9 +308,8 @@ void DatabaseWindow::on_actionExport_data_triggered() } } -void DatabaseWindow::on_actionClose_triggered() +void DatabaseWindow::actionClose_triggered() { - //close(); on_tabWidget_tabCloseRequested(m_tabWidget->currentIndex()); } diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index c3301a5..aeb6a39 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -89,6 +89,9 @@ private: QTabWidget *m_tabWidget = nullptr; QToolBar *m_mainToolBar = nullptr; + // Standard actions + QAction *m_closeAction = nullptr; + ConnectionConfig m_config; std::shared_ptr m_database; @@ -140,6 +143,7 @@ private: QFutureWatcher loadWatcher; + void createActions(); QueryTab *GetActiveQueryTab(); void closeEvent(QCloseEvent *event); @@ -161,7 +165,7 @@ private slots: void on_actionLoad_SQL_triggered(); void on_actionSave_SQL_triggered(); void on_actionExport_data_triggered(); - void on_actionClose_triggered(); + void actionClose_triggered(); void on_actionAbout_triggered(); void on_actionSave_SQL_as_triggered(); void on_actionSave_copy_of_SQL_as_triggered(); From 4a78330153a4ac0174ffcdca09d9d87a633f6234 Mon Sep 17 00:00:00 2001 From: eelke Date: Fri, 4 Jan 2019 18:46:02 +0100 Subject: [PATCH 17/24] Proof of concept for binding signal to passed in slot name. --- pglab/QueryTab.cpp | 5 ++++- pglab/QueryTab.h | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index 5331d4d..580804d 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -650,7 +650,9 @@ std::vector QueryTab::getToolbarActions() // 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); + //connect(action, &QAction::triggered, this, &QueryTab::execute); + std::string slot_name = SLOT(execute()); + connect(action, SIGNAL(triggered()), this, slot_name.c_str()); actions.push_back(action); // Explain action = new QAction(QIcon(":/icons/lightbulb_off.png"), tr("Explain"), this); @@ -678,6 +680,7 @@ void QueryToolModule::init() { menuAction_new(context); }); ma_new.setMenuLocation(MenuPath("File/New")); ma_new.setIcon(QIcon(":/icons/new_query_tab.png")); + ma_new.setShortCut(QKeySequence(Qt::CTRL + Qt::Key_N)); registerMenuAction(ma_new); } diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index abcd7ef..c6ca87c 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -44,7 +44,6 @@ public: bool saveAs(); void saveCopyAs(); - void execute(); void explain(bool analyze); void cancel(); @@ -61,6 +60,8 @@ public: void focusEditor(); virtual std::vector getToolbarActions() override; +public slots: + void execute(); private: using ResultTabContainer = std::vector; From fd603a7434503b271a13d0dbebcd8481a06cca03 Mon Sep 17 00:00:00 2001 From: eelke Date: Sat, 5 Jan 2019 09:49:12 +0100 Subject: [PATCH 18/24] Moving things from the application specific DatabaseWindow to generic LMainWindow (Leon framework) To achieve flexibility the getDatabase call on the context which was application specific to has been replaced with a type based object registry. --- pglab/CrudTab.cpp | 2 +- pglab/DatabaseWindow.cpp | 144 +++++++++--------- pglab/DatabaseWindow.h | 34 +++-- pglab/QueryTab.cpp | 7 +- .../IPluginContentWidgetContext.h | 49 +++++- 5 files changed, 137 insertions(+), 99 deletions(-) diff --git a/pglab/CrudTab.cpp b/pglab/CrudTab.cpp index 0b03ef1..d1b46a0 100644 --- a/pglab/CrudTab.cpp +++ b/pglab/CrudTab.cpp @@ -48,7 +48,7 @@ CrudTab::~CrudTab() void CrudTab::setConfig(Oid oid) //std::shared_ptr db, const PgClass &table) { - m_db = context()->getDatabase();; + m_db = context()->getObject(); // getDatabase();; m_table = *m_db->catalog()->classes()->getByKey(oid); m_crudModel->setConfig(m_db, *m_table); } diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index edcd3fb..7f7656d 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -47,10 +47,10 @@ namespace DatabaseWindow_details { m_window->setTabIcon(content, iconname); } - std::shared_ptr getDatabase() override - { - return m_window->getDatabase(); - } +// std::shared_ptr getDatabase() override +// { +// return m_window->getDatabase(); +// } void showStatusMessage(const QString &msg) override { @@ -72,9 +72,30 @@ using namespace DatabaseWindow_details; LMainWindow::LMainWindow(QWidget *parent) : QMainWindow(parent) { + 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 T", this); + createActions(); + m_mainToolBar->addAction(m_closeAction); +// QMetaObject::connectSlotsByName(this); } void LMainWindow::initModuleMenus() @@ -95,6 +116,19 @@ void LMainWindow::addModuleMenuActions() } } +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, &DatabaseWindow::actionClose_triggered); + } + +} + + void LMainWindow::addMenuAction(const MenuAction &ma) { qDebug() << "add action " << ma.text(); @@ -109,69 +143,56 @@ void LMainWindow::addMenuAction(const MenuAction &ma) // 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)); +} + + + + DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) : LMainWindow(parent) -// , ui(new Ui::DatabaseWindow) + , m_masterController(master) { -// ui->setupUi(this); -// ui->tabWidget->setDocumentMode(true); - -// auto centralWidget = new QWidget(this); -// auto verticalLayout_3 = new QVBoxLayout(centralWidget); -// verticalLayout_3->setSpacing(4); -// verticalLayout_3->setContentsMargins(4, 4, 4, 4); - - m_tabWidget = new QTabWidget(this); - m_tabWidget->setObjectName(QString::fromUtf8("tabWidget")); - m_tabWidget->setDocumentMode(true); -// verticalLayout_3->addWidget(m_tabWidget); - - setCentralWidget(m_tabWidget); - - createActions(); - - auto menuBar = new QMenuBar(this); - setMenuBar(menuBar); - - m_mainToolBar = new QToolBar(this); - m_mainToolBar->addAction(m_closeAction); - addToolBar(Qt::TopToolBarArea, m_mainToolBar); - - auto statusBar = new QStatusBar(this); - setStatusBar(statusBar); - m_context = new DatabaseWindowContentContext(this); connect(&loadWatcher, &QFutureWatcher::finished, this, &DatabaseWindow::catalogLoaded); initModuleMenus(); - QMetaObject::connectSlotsByName(this); } DatabaseWindow::~DatabaseWindow() { delete m_context; -// delete ui; } -void DatabaseWindow::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, &DatabaseWindow::actionClose_triggered); - } - -} QueryTab* DatabaseWindow::newSqlPage() { @@ -226,6 +247,7 @@ void DatabaseWindow::catalogLoaded() try { //SCOPE_EXIT { loadFuture = {}; }; m_database = loadWatcher.future().result(); + m_context->registerObject(m_database); auto tt = new TablesPage(m_context, this); tt->setCatalog(m_database->catalog()); @@ -308,11 +330,6 @@ void DatabaseWindow::on_actionExport_data_triggered() } } -void DatabaseWindow::actionClose_triggered() -{ - on_tabWidget_tabCloseRequested(m_tabWidget->currentIndex()); -} - void DatabaseWindow::on_actionAbout_triggered() { QMessageBox::about(this, "pgLab 0.1", tr( @@ -468,15 +485,6 @@ void DatabaseWindow::removeToolBarButtonsForPage(PluginContentWidget *page) } } - -void DatabaseWindow::addPage(PluginContentWidget* page, QString caption) -{ - m_tabWidget->addTab(page, caption); - m_tabWidget->setCurrentWidget(page); - - //addToolBarButtonsForPage(page); -} - void DatabaseWindow::removePage(PluginContentWidget *) { @@ -509,17 +517,3 @@ void DatabaseWindow::on_actionGenerate_code_triggered() } } - -void DatabaseWindow::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 DatabaseWindow::setTabIcon(QWidget *widget, const QString &iconname) -{ - auto index = m_tabWidget->indexOf(widget); - auto n = ":/icons/16x16/" + iconname; - m_tabWidget->setTabIcon(index, QIcon(n)); -} diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index aeb6a39..f3e848c 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -51,16 +51,33 @@ public: LMainWindow(QWidget *parent = nullptr); 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); protected: + QTabWidget *m_tabWidget = nullptr; + QToolBar *m_mainToolBar = nullptr; + + // Standard menu's + QMenu *m_fileMenu = nullptr; + + // Standard actions + QAction *m_closeAction = nullptr; DatabaseWindow_details::DatabaseWindowContentContext *m_context; void addModuleMenuActions(); -private: - QMenu *m_fileMenu = nullptr; +private: + + void createActions(); void addMenuAction(const MenuAction &ma); + +private slots: + void actionClose_triggered(); }; @@ -79,19 +96,8 @@ public: void newCodeGenPage(QString query, std::shared_ptr dbres); - 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); private: - QTabWidget *m_tabWidget = nullptr; - QToolBar *m_mainToolBar = nullptr; - - // Standard actions - QAction *m_closeAction = nullptr; - ConnectionConfig m_config; std::shared_ptr m_database; @@ -143,7 +149,6 @@ private: QFutureWatcher loadWatcher; - void createActions(); QueryTab *GetActiveQueryTab(); void closeEvent(QCloseEvent *event); @@ -165,7 +170,6 @@ private slots: void on_actionLoad_SQL_triggered(); void on_actionSave_SQL_triggered(); void on_actionExport_data_triggered(); - void actionClose_triggered(); void on_actionAbout_triggered(); void on_actionSave_SQL_as_triggered(); void on_actionSave_copy_of_SQL_as_triggered(); diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index 580804d..d834ec8 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -31,8 +31,9 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) { ui->setupUi(this); - m_config = context()->getDatabase()->config(); - m_catalog = context()->getDatabase()->catalog(); + auto db = context()->getObject(); + m_config = db->config(); + m_catalog = db->catalog(); connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTab::connectionStateChanged); connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTab::receiveNotice); @@ -40,7 +41,7 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) ui->queryEdit->setFont(UserConfiguration::instance()->codeFont()); highlighter = new SqlSyntaxHighlighter(ui->queryEdit->document()); - auto open_database = context()->getDatabase(); + auto open_database = context()->getObject(); if (open_database) { auto cat = open_database->catalog(); highlighter->setTypes(*cat->types()); diff --git a/pglab/plugin_support/IPluginContentWidgetContext.h b/pglab/plugin_support/IPluginContentWidgetContext.h index 9424ce4..4d5e94b 100644 --- a/pglab/plugin_support/IPluginContentWidgetContext.h +++ b/pglab/plugin_support/IPluginContentWidgetContext.h @@ -2,7 +2,9 @@ #define IPLUGINCONTENTWIDGETCONTEXT_H #include +#include #include +#include #include "plugin_support/ModuleActionParameters.h" class OpenDatabase; @@ -13,6 +15,9 @@ class PluginContentWidget; * * 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: @@ -32,11 +37,6 @@ public: */ virtual void setIcon(PluginContentWidget *content, const QString &iconname) = 0; - /** Returns an OpenDatabase object the widget can use to access - * the database. - */ - virtual std::shared_ptr getDatabase() = 0; - virtual void showStatusMessage(const QString &msg) = 0; virtual void moduleAction( @@ -46,6 +46,45 @@ public: ) = 0; virtual void addContentWidget(PluginContentWidget *widget) = 0; + + template + bool addObjects(Args&&...args); + template + bool registerObject(std::shared_ptr object); + template + std::shared_ptr getObject() const; +private: + std::map > m_objectRegistry; + }; +template +bool IPluginContentWidgetContext::addObjects(Args&&...args) +{ + std::type_index key(typeid(T)); + if (!m_objectRegistry.count(key)) { + auto p = std::make_shared(std::forward(args)...); + m_objectRegistry[key] = p; + return true; + } + return false; +} + +template +bool IPluginContentWidgetContext::registerObject(std::shared_ptr object) +{ + return m_objectRegistry.emplace(std::type_index(typeid(T)), object).second; +} + +template +std::shared_ptr IPluginContentWidgetContext::getObject() const +{ + auto it = m_objectRegistry.find(typeid(T)); + if (it == m_objectRegistry.end()) { + return {}; + } + return std::static_pointer_cast(it->second); +} + + #endif // IPLUGINCONTENTWIDGETCONTEXT_H From d0c4dabe8bc8d3e386eb6d090df02b576023f162 Mon Sep 17 00:00:00 2001 From: eelke Date: Sat, 5 Jan 2019 11:12:47 +0100 Subject: [PATCH 19/24] DatabaseWindow has no knowledge more of the existence of QueryTab but user can still create and use them within that window. --- pglab/DatabaseWindow.cpp | 342 +----------------- pglab/DatabaseWindow.h | 100 +---- pglab/QueryTab.cpp | 47 ++- pglab/QueryTab.h | 1 + pglab/pglab.pro | 6 +- .../IPluginContentWidgetContext.h | 4 + pglab/plugin_support/LMainWindow.cpp | 220 +++++++++++ pglab/plugin_support/LMainWindow.h | 58 +++ 8 files changed, 327 insertions(+), 451 deletions(-) create mode 100644 pglab/plugin_support/LMainWindow.cpp create mode 100644 pglab/plugin_support/LMainWindow.h diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 7f7656d..8e8dda4 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -1,12 +1,9 @@ #include "DatabaseWindow.h" -//#include "ui_DatabaseWindow.h" +#include "plugin_support/IPluginContentWidgetContext.h" #include "TablesPage.h" #include "FunctionsPage.h" #include "SequencesPage.h" -#include "QueryTab.h" #include "util.h" -#include "plugin_support/PluginContentWidget.h" -#include "plugin_support/PluginContentWidgetContextBase.h" #include "CodeGenerator.h" #include "MasterController.h" #include "ScopeGuard.h" @@ -16,171 +13,22 @@ #include #include #include -#include #include #include #include #include -#include #include -#include #include #include namespace pg = Pgsql; -namespace DatabaseWindow_details { - - class DatabaseWindowContentContext: public PluginContentWidgetContextBase { - public: - explicit DatabaseWindowContentContext(DatabaseWindow *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); - } - -// std::shared_ptr getDatabase() override -// { -// return m_window->getDatabase(); -// } - - void showStatusMessage(const QString &msg) override - { - m_window->statusBar()->showMessage(msg); - } - - void addContentWidget(PluginContentWidget *widget) override - { - m_window->addPage(widget, ""); - } - private: - DatabaseWindow *m_window; - }; - -} -using namespace DatabaseWindow_details; - - -LMainWindow::LMainWindow(QWidget *parent) - : QMainWindow(parent) -{ - 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 T", this); - - createActions(); - m_mainToolBar->addAction(m_closeAction); - -// QMetaObject::connectSlotsByName(this); -} - -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, &DatabaseWindow::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)); -} - - - DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) : LMainWindow(parent) , m_masterController(master) { - m_context = new DatabaseWindowContentContext(this); - connect(&loadWatcher, &QFutureWatcher::finished, this, &DatabaseWindow::catalogLoaded); @@ -188,20 +36,7 @@ DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) QMetaObject::connectSlotsByName(this); } -DatabaseWindow::~DatabaseWindow() -{ - delete m_context; -} - - -QueryTab* DatabaseWindow::newSqlPage() -{ - QueryTab *qt = new QueryTab(m_context); - qt->newdoc(); - qt->focusEditor(); - addPage(qt, "Tab"); - return qt; -} +DatabaseWindow::~DatabaseWindow() = default; void DatabaseWindow::newCreateTablePage() { @@ -211,18 +46,11 @@ void DatabaseWindow::newCreateTablePage() void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr dbres) { - auto cgtab = new CodeGenerator(m_context, this); + auto cgtab = new CodeGenerator(context(), this); cgtab->Init(m_database->catalog(), query, dbres); addPage(cgtab, "Codegen"); } -QueryTab *DatabaseWindow::GetActiveQueryTab() -{ - QWidget *widget = m_tabWidget->currentWidget(); - QueryTab *qt = dynamic_cast(widget); - return qt; -} - void DatabaseWindow::setConfig(const ConnectionConfig &config) { m_config = config; @@ -247,18 +75,19 @@ void DatabaseWindow::catalogLoaded() try { //SCOPE_EXIT { loadFuture = {}; }; m_database = loadWatcher.future().result(); - m_context->registerObject(m_database); + auto ctx = context(); + ctx->registerObject(m_database); - auto tt = new TablesPage(m_context, this); + auto tt = new TablesPage(ctx, this); tt->setCatalog(m_database->catalog()); m_tabWidget->addTab(tt, "Tables"); - auto pg_cat_tables = new TablesPage(m_context, this); + auto pg_cat_tables = new TablesPage(ctx, this); pg_cat_tables->setNamespaceFilter(TablesTableModel::PgCatalog); pg_cat_tables->setCatalog(m_database->catalog()); m_tabWidget->addTab(pg_cat_tables, "pg_catalog"); - auto info_schema_tables = new TablesPage(m_context, this); + auto info_schema_tables = new TablesPage(ctx, this); info_schema_tables->setNamespaceFilter(TablesTableModel::InformationSchema); info_schema_tables->setCatalog(m_database->catalog()); m_tabWidget->addTab(info_schema_tables, "information_schema"); @@ -271,7 +100,6 @@ void DatabaseWindow::catalogLoaded() sequences_page->setCatalog(m_database->catalog()); m_tabWidget->addTab(sequences_page, "Sequences"); - newSqlPage(); newCreateTablePage(); } catch (std::runtime_error &ex) { QMessageBox::critical(this, "Error reading database", @@ -281,59 +109,11 @@ 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_actionAbout_triggered() { QMessageBox::about(this, "pgLab 0.1", tr( - "Copyrights 2016-2018, 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 " @@ -388,40 +168,6 @@ void DatabaseWindow::showEvent(QShowEvent *event) event->accept(); } -void DatabaseWindow::on_actionNew_SQL_triggered() -{ - newSqlPage(); -} - - -void DatabaseWindow::on_tabWidget_tabCloseRequested(int index) -{ - QWidget *widget = m_tabWidget->widget(index); - PluginContentWidget *plg_page = dynamic_cast(widget); - if (plg_page) { - if (plg_page->canClose()) { - removePage(plg_page); - m_tabWidget->removeTab(index); - delete plg_page; - } - } - else { - // old behaviour shouldn't be needed any more when all pages have been migrated - // to PlgPage - QueryTab *qt = dynamic_cast(widget); - if (qt && qt->canClose()) { - m_tabWidget->removeTab(index); - delete qt; - } - else if (index > 0) { - m_tabWidget->removeTab(index); - delete widget; - } - - } -} - - void DatabaseWindow::on_actionShow_connection_manager_triggered() { m_masterController->showConnectionManager(); @@ -447,73 +193,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(PluginContentWidget *page) -{ - std::vector actions = page->getToolbarActions(); - QList list; - for (auto act : actions) { - list.append(act); - } - m_mainToolBar->addActions(list); -} - -void DatabaseWindow::removeToolBarButtonsForPage(PluginContentWidget *page) -{ - std::vector actions = page->getToolbarActions(); - for (auto act : actions) { - m_mainToolBar->removeAction(act); - } -} - -void DatabaseWindow::removePage(PluginContentWidget *) -{ - -} - -void DatabaseWindow::on_tabWidget_currentChanged(int index) -{ - // remove buttons of old page - if (m_previousPage) { - removeToolBarButtonsForPage(m_previousPage); - } - - // add buttons of new page - PluginContentWidget * page = nullptr; - if (index >= 0) { - QWidget *widget = m_tabWidget->widget(index); - page = dynamic_cast(widget); - if (page) { - addToolBarButtonsForPage(page); - } - } - m_previousPage = page; -} - -void DatabaseWindow::on_actionGenerate_code_triggered() -{ - QueryTab *tab = GetActiveQueryTab(); - if (tab) { - tab->generateCode(); - } - -} diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index f3e848c..8366707 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -4,8 +4,7 @@ #include "ASyncDBConnection.h" #include "ConnectionConfig.h" #include "OpenDatabase.h" -#include -#include +#include "plugin_support/LMainWindow.h" #include #include #include @@ -18,68 +17,20 @@ #include #include -#include #include #include -//namespace Ui { -// class DatabaseWindow; -//} - namespace Pgsql { class Connection; } -class MenuAction; -class QueryTab; class MasterController; class QCloseEvent; class OpenDatabase; class PgClass; -class PluginContentWidget; class QTabWidget; -namespace DatabaseWindow_details { - class DatabaseWindowContentContext; -} - -class LMainWindow : public QMainWindow { - Q_OBJECT -public: - - LMainWindow(QWidget *parent = nullptr); - - 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); -protected: - QTabWidget *m_tabWidget = nullptr; - QToolBar *m_mainToolBar = nullptr; - - // Standard menu's - QMenu *m_fileMenu = nullptr; - - // Standard actions - QAction *m_closeAction = nullptr; - - DatabaseWindow_details::DatabaseWindowContentContext *m_context; - - void addModuleMenuActions(); - - -private: - - void createActions(); - void addMenuAction(const MenuAction &ma); - -private slots: - void actionClose_triggered(); -}; - /** This is the class for windows that handle tasks for a specific database/catalog * @@ -102,34 +53,6 @@ private: std::shared_ptr m_database; MasterController *m_masterController; - PluginContentWidget *m_previousPage = nullptr; ///< tracks which pages buttons were previously being displayed - -// class QLoad : public QueuedBackgroundTask { -// public: -// explicit QLoad(ConnectionConfig config, CompletionFunction on_completion) -// : QueuedBackgroundTask(on_completion) -// , m_config(config) -// {} - -// OpenDatabase::OpenDatabaseSPtr GetResult() -// { -// if (hasException()) rethrow(); -// return result; -// } -// protected: - -// OpenDatabase::OpenDatabaseSPtr result; -// virtual void doRun() -// { -// auto res = OpenDatabase::createOpenDatabase(m_config); -// result = res.get(); -// } -// private: - -// ConnectionConfig m_config; -// }; - -// std::shared_ptr loader; class LoadCatalog: public ControllableTask { public: @@ -149,38 +72,17 @@ private: QFutureWatcher loadWatcher; - QueryTab *GetActiveQueryTab(); - void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *event); - QueryTab *newSqlPage(); void newCreateTablePage(); - - /// Called when a page is completely removed from the QTabWidget - void removePage(PluginContentWidget *page); - - void addToolBarButtonsForPage(PluginContentWidget *page); - void removeToolBarButtonsForPage(PluginContentWidget *page); - //class PageData private slots: void catalogLoaded(); - void on_actionLoad_SQL_triggered(); - void on_actionSave_SQL_triggered(); - void on_actionExport_data_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 diff --git a/pglab/QueryTab.cpp b/pglab/QueryTab.cpp index d834ec8..5eaea0a 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTab.cpp @@ -627,23 +627,15 @@ std::vector QueryTab::getToolbarActions() { 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); + action = new QAction(QIcon(":/icons/script_save.png"), tr("Save SQL as"), this); + connect(action, &QAction::triggered, this, &QueryTab::saveAs); + actions.push_back(action); // Save copy as // Copy // Copy as C-string @@ -677,12 +669,21 @@ std::vector QueryTab::getToolbarActions() void QueryToolModule::init() { - MenuAction ma_new("New", [this] (IPluginContentWidgetContext* context) - { menuAction_new(context); }); - ma_new.setMenuLocation(MenuPath("File/New")); - ma_new.setIcon(QIcon(":/icons/new_query_tab.png")); - ma_new.setShortCut(QKeySequence(Qt::CTRL + Qt::Key_N)); - registerMenuAction(ma_new); + { + 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); + } } void QueryToolModule::menuAction_new(IPluginContentWidgetContext* context) @@ -692,4 +693,16 @@ void QueryToolModule::menuAction_new(IPluginContentWidgetContext* context) 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 QueryTab(context, nullptr); + context->addContentWidget(ct); + ct->load(file_name); + } +} + REGISTER_PLUGIN_MODULE(QueryToolModule, "Query tool", "pglab.querytool") diff --git a/pglab/QueryTab.h b/pglab/QueryTab.h index c6ca87c..65dca0c 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTab.h @@ -120,6 +120,7 @@ public: void init() override; void menuAction_new(IPluginContentWidgetContext* context); + void menuAction_open(IPluginContentWidgetContext* context); private slots: }; diff --git a/pglab/pglab.pro b/pglab/pglab.pro index fea3323..39ae9bd 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -88,7 +88,8 @@ PropertyProxyModel.cpp \ plugin_support/PluginRegister.cpp \ plugin_support/PluginContentWidget.cpp \ plugin_support/PluginContentWidgetContextBase.cpp \ - plugin_support/MenuAction.cpp + plugin_support/MenuAction.cpp \ + plugin_support/LMainWindow.cpp HEADERS += \ QueryResultModel.h \ @@ -156,7 +157,8 @@ CustomDataRole.h \ plugin_support/ModuleActionParameters.h \ plugin_support/IPluginContentWidgetContext.h \ plugin_support/PluginContentWidgetContextBase.h \ - plugin_support/MenuAction.h + plugin_support/MenuAction.h \ + plugin_support/LMainWindow.h FORMS += \ ConnectionManagerWindow.ui \ diff --git a/pglab/plugin_support/IPluginContentWidgetContext.h b/pglab/plugin_support/IPluginContentWidgetContext.h index 4d5e94b..1bef7cb 100644 --- a/pglab/plugin_support/IPluginContentWidgetContext.h +++ b/pglab/plugin_support/IPluginContentWidgetContext.h @@ -47,6 +47,10 @@ public: virtual void addContentWidget(PluginContentWidget *widget) = 0; + /** Return a widget you can use as a parent + */ + virtual QWidget* container() = 0; + template bool addObjects(Args&&...args); template diff --git a/pglab/plugin_support/LMainWindow.cpp b/pglab/plugin_support/LMainWindow.cpp new file mode 100644 index 0000000..7d4a6ad --- /dev/null +++ b/pglab/plugin_support/LMainWindow.cpp @@ -0,0 +1,220 @@ +#include "LMainWindow.h" +#include "PluginContentWidget.h" +#include "PluginContentWidgetContextBase.h" +#include "PluginModule.h" +#include "PluginRegister.h" + +#include +#include +#include +#include + +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(PluginContentWidget *widget) override + { + 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(widget); + if (plg_page) { + if (plg_page->canClose()) { + m_tabWidget->removeTab(index); + 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) { + removeToolBarButtonsForPage(m_previousPage); + } + + // add buttons of new page + PluginContentWidget * page = nullptr; + if (index >= 0) { + QWidget *widget = m_tabWidget->widget(index); + page = dynamic_cast(widget); + if (page) { + addToolBarButtonsForPage(page); + } + } + m_previousPage = page; +} + +void LMainWindow::addToolBarButtonsForPage(PluginContentWidget *page) +{ + std::vector actions = page->getToolbarActions(); + QList list; + for (auto act : actions) { + list.append(act); + } + m_mainToolBar->addActions(list); +} + +void LMainWindow::removeToolBarButtonsForPage(PluginContentWidget *page) +{ + std::vector actions = page->getToolbarActions(); + for (auto act : actions) { + m_mainToolBar->removeAction(act); + } +} diff --git a/pglab/plugin_support/LMainWindow.h b/pglab/plugin_support/LMainWindow.h new file mode 100644 index 0000000..c7fac6d --- /dev/null +++ b/pglab/plugin_support/LMainWindow.h @@ -0,0 +1,58 @@ +#ifndef LMAINWINDOW_H +#define LMAINWINDOW_H + +#include + +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 addToolBarButtonsForPage(PluginContentWidget *page); + void removeToolBarButtonsForPage(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 From f4f2474a818714a901b07230b68fc06e716fa2e9 Mon Sep 17 00:00:00 2001 From: eelke Date: Sat, 5 Jan 2019 19:58:23 +0100 Subject: [PATCH 20/24] Moved definition of widget instance actions to the module so other parts of the system can no about them. The plugin system will create the Action objects and bind them to the specified slots of the specific widget instances. --- pglab/CodeGenerator.cpp | 3 - pglab/CrudTab.cpp | 23 +-- pglab/CrudTab.h | 4 +- pglab/{QueryTab.cpp => QueryTool.cpp} | 169 +++++------------- pglab/{QueryTab.h => QueryTool.h} | 27 +-- pglab/QueryToolModule.cpp | 85 +++++++++ pglab/QueryToolModule.h | 18 ++ pglab/pglab.pro | 12 +- .../IPluginContentWidgetContext.h | 6 +- pglab/plugin_support/LMainWindow.cpp | 26 ++- pglab/plugin_support/LMainWindow.h | 4 +- pglab/plugin_support/LWidgetAction.cpp | 56 ++++++ pglab/plugin_support/LWidgetAction.h | 42 +++++ pglab/plugin_support/MenuAction.cpp | 8 +- pglab/plugin_support/MenuAction.h | 7 +- pglab/plugin_support/PluginContentWidget.cpp | 9 +- pglab/plugin_support/PluginContentWidget.h | 2 +- .../PluginContentWidgetContextBase.cpp | 78 +++++++- .../PluginContentWidgetContextBase.h | 31 ++++ pglab/plugin_support/PluginModule.cpp | 1 + pglab/plugin_support/PluginModule.h | 11 +- 21 files changed, 418 insertions(+), 204 deletions(-) rename pglab/{QueryTab.cpp => QueryTool.cpp} (77%) rename pglab/{QueryTab.h => QueryTool.h} (81%) create mode 100644 pglab/QueryToolModule.cpp create mode 100644 pglab/QueryToolModule.h create mode 100644 pglab/plugin_support/LWidgetAction.cpp create mode 100644 pglab/plugin_support/LWidgetAction.h diff --git a/pglab/CodeGenerator.cpp b/pglab/CodeGenerator.cpp index 0d74aa6..3c2841e 100644 --- a/pglab/CodeGenerator.cpp +++ b/pglab/CodeGenerator.cpp @@ -27,11 +27,8 @@ void CodeGenerator::Init(std::shared_ptr catalog, QString que m_query = std::move(query); m_dbres = std::move(dbres); generateCode(); - - } - void CodeGenerator::on_updateCodeButton_clicked() { generateCode(); diff --git a/pglab/CrudTab.cpp b/pglab/CrudTab.cpp index d1b46a0..b0b0cf0 100644 --- a/pglab/CrudTab.cpp +++ b/pglab/CrudTab.cpp @@ -93,19 +93,6 @@ void CrudTab::on_actionRemove_rows_triggered() } } -std::vector 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); @@ -128,6 +115,14 @@ void CrudPageModule::init() { 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( @@ -138,7 +133,7 @@ void CrudPageModule::moduleAction_open( // create new widget for specified table // hand widget to context for display CrudTab *ct = new CrudTab(context, nullptr); - context->addContentWidget(ct); // maybe CrudTab should do this + context->addContentWidget(this, ct); // maybe CrudTab should do this ct->setConfig(params.at("oid").toUInt()); } diff --git a/pglab/CrudTab.h b/pglab/CrudTab.h index 76628ee..d20e4af 100644 --- a/pglab/CrudTab.h +++ b/pglab/CrudTab.h @@ -24,10 +24,8 @@ public: ~CrudTab() override; void setConfig(Oid oid); - +public slots: void refresh(); - - virtual std::vector getToolbarActions() override; private: Ui::CrudTab *ui; diff --git a/pglab/QueryTab.cpp b/pglab/QueryTool.cpp similarity index 77% rename from pglab/QueryTab.cpp rename to pglab/QueryTool.cpp index 5eaea0a..b03dfdb 100644 --- a/pglab/QueryTab.cpp +++ b/pglab/QueryTool.cpp @@ -1,12 +1,10 @@ - -#include "QueryTab.h" +#include "QueryTool.h" #include "ui_QueryTab.h" #include "SqlSyntaxHighlighter.h" #include #include #include #include -#include #include #include #include @@ -22,9 +20,9 @@ #include "GlobalIoService.h" #include "UserConfiguration.h" #include "plugin_support/IPluginContentWidgetContext.h" -#include "plugin_support/PluginRegister.h" -QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) + +QueryTool::QueryTool(IPluginContentWidgetContext *context_, QWidget *parent) : PluginContentWidget(context_, parent) , ui(new Ui::QueryTab) , m_dbConnection(*getGlobalAsioIoService()) @@ -35,8 +33,8 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) m_config = db->config(); m_catalog = db->catalog(); - connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTab::connectionStateChanged); - connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTab::receiveNotice); + connect(&m_dbConnection, &ASyncDBConnection::onStateChanged, this, &QueryTool::connectionStateChanged); + connect(&m_dbConnection, &ASyncDBConnection::onNotice, this, &QueryTool::receiveNotice); ui->queryEdit->setFont(UserConfiguration::instance()->codeFont()); @@ -47,7 +45,7 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) 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, @@ -58,12 +56,12 @@ QueryTab::QueryTab(IPluginContentWidgetContext *context_, QWidget *parent) startConnect(); } -QueryTab::~QueryTab() +QueryTool::~QueryTool() { delete ui; } -bool QueryTab::canClose() +bool QueryTool::canClose() { bool can_close; if (m_queryTextChanged) { @@ -75,7 +73,7 @@ bool QueryTab::canClose() return can_close; } -void QueryTab::newdoc() +void QueryTool::newdoc() { ui->queryEdit->clear(); setFileName(tr("new")); @@ -83,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); @@ -109,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) { @@ -121,7 +119,7 @@ bool QueryTab::save() return result; } -bool QueryTab::saveAs() +bool QueryTool::saveAs() { bool result = false; QString filename = promptUserForSaveSqlFilename(); @@ -135,7 +133,7 @@ bool QueryTab::saveAs() return result; } -void QueryTab::saveCopyAs() +void QueryTool::saveCopyAs() { QString filename = promptUserForSaveSqlFilename(); if (!filename.isEmpty()) { @@ -143,7 +141,7 @@ void QueryTab::saveCopyAs() } } -void QueryTab::execute() +void QueryTool::execute() { if (m_dbConnection.state() == ASyncDBConnection::State::Connected) { addLog("Query clicked"); @@ -175,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(); @@ -221,13 +229,13 @@ 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); @@ -235,7 +243,7 @@ void QueryTab::setFileName(const QString &filename) context()->setCaption(this, fn, m_fileName); } -bool QueryTab::continueWithoutSavingWarning() +bool QueryTool::continueWithoutSavingWarning() { QMessageBox msgBox; msgBox.setIcon(QMessageBox::Warning); @@ -254,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); @@ -277,19 +285,19 @@ 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) { QString iconname; switch (state) { @@ -311,14 +319,14 @@ void QueryTab::connectionStateChanged(ASyncDBConnection::State state) } -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)); @@ -365,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) { @@ -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,7 +426,7 @@ QString QueryTab::getCommand() const return command; } -std::string QueryTab::getCommandUtf8() const +std::string QueryTool::getCommandUtf8() const { return getCommand().toUtf8().data(); } @@ -444,7 +452,7 @@ std::string QueryTab::getCommandUtf8() const //} -void QueryTab::query_ready(std::shared_ptr dbres, qint64 elapsedms) +void QueryTool::query_ready(std::shared_ptr dbres, qint64 elapsedms) { if (dbres) { addLog("query_ready with result"); @@ -520,7 +528,7 @@ void QueryTab::query_ready(std::shared_ptr dbres, qint64 elapsedm } } -void QueryTab::markError(const Pgsql::ErrorDetails &details) +void QueryTool::markError(const Pgsql::ErrorDetails &details) { if (details.statementPosition > 0) { QTextCursor cursor = ui->queryEdit->textCursor(); @@ -561,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(); @@ -586,7 +594,7 @@ void QueryTab::copyQueryAsCString() #include #include -void QueryTab::copyQueryAsRawCppString() +void QueryTool::copyQueryAsRawCppString() { QString command = getCommand(); //auto sql = getAllOrSelectedSql(); @@ -594,7 +602,7 @@ void QueryTab::copyQueryAsRawCppString() QApplication::clipboard()->setText(cs); } -void QueryTab::generateCode() +void QueryTool::generateCode() { QString command = getCommand(); @@ -607,7 +615,7 @@ void QueryTab::generateCode() } } -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); @@ -617,92 +625,7 @@ void QueryTab::exportData(const QString &file_name) } } -void QueryTab::focusEditor() +void QueryTool::focusEditor() { ui->queryEdit->setFocus(); } - - -std::vector QueryTab::getToolbarActions() -{ - if (actions.empty()) { - QAction *action; - // 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); - 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); - std::string slot_name = SLOT(execute()); - connect(action, SIGNAL(triggered()), this, slot_name.c_str()); - 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; -} - - -void QueryToolModule::init() -{ - { - 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); - } -} - -void QueryToolModule::menuAction_new(IPluginContentWidgetContext* context) -{ - auto *ct = new QueryTab(context, nullptr); - context->addContentWidget(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 QueryTab(context, nullptr); - context->addContentWidget(ct); - ct->load(file_name); - } -} - -REGISTER_PLUGIN_MODULE(QueryToolModule, "Query tool", "pglab.querytool") diff --git a/pglab/QueryTab.h b/pglab/QueryTool.h similarity index 81% rename from pglab/QueryTab.h rename to pglab/QueryTool.h index 65dca0c..8a30cb8 100644 --- a/pglab/QueryTab.h +++ b/pglab/QueryTool.h @@ -9,7 +9,6 @@ #include #include "plugin_support/PluginContentWidget.h" -#include "plugin_support/PluginModule.h" #include namespace Ui { @@ -32,20 +31,17 @@ class OpenDatabase; class QueryParamListController; class PgDatabaseCatalog; -class QueryTab : public PluginContentWidget { +class QueryTool : public PluginContentWidget { Q_OBJECT public: - QueryTab(IPluginContentWidgetContext *context, QWidget *parent = nullptr); - ~QueryTab() override; + QueryTool(IPluginContentWidgetContext *context, QWidget *parent = nullptr); + ~QueryTool() override; void newdoc(); bool load(const QString &filename); - bool save(); - bool saveAs(); void saveCopyAs(); void explain(bool analyze); - void cancel(); bool canClose() override; @@ -59,9 +55,13 @@ public: bool isNew() const { return m_new; } void focusEditor(); - virtual std::vector getToolbarActions() override; public slots: void execute(); + bool save(); + bool saveAs(); + void explain(); + void analyze(); + void cancel(); private: using ResultTabContainer = std::vector; @@ -70,7 +70,6 @@ private: SqlSyntaxHighlighter* highlighter; ConnectionConfig m_config; StopWatch m_stopwatch; - std::vector actions; QueryParamListController *m_queryParamListController = nullptr; @@ -113,15 +112,5 @@ private slots: void startConnect(); }; -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 // QUERYTAB_H diff --git a/pglab/QueryToolModule.cpp b/pglab/QueryToolModule.cpp new file mode 100644 index 0000000..6be8ec9 --- /dev/null +++ b/pglab/QueryToolModule.cpp @@ -0,0 +1,85 @@ +#include "QueryToolModule.h" +#include "QueryTool.h" +#include "plugin_support/IPluginContentWidgetContext.h" +#include "plugin_support/PluginRegister.h" + +#include +#include + +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(MenuPath("File/Save")); + wa.setIcon(QIcon(":/icons/script_save.png")); + wa.setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S)); + registerWidgetAction(wa); + } + { + LWidgetAction wa("Save SQL as", SLOT(saveAs())); + wa.setMenuLocation(MenuPath("File/Save")); + wa.setIcon(QIcon(":/icons/script_save.png")); + registerWidgetAction(wa); + } + { + LWidgetAction wa("Execute", SLOT(execute())); + wa.setMenuLocation(MenuPath("Query/1")); + wa.setIcon(QIcon(":/icons/script_go.png")); + registerWidgetAction(wa); + } + { + LWidgetAction wa("Explain", SLOT(explain())); + wa.setMenuLocation(MenuPath("Query/2")); + wa.setIcon(QIcon(":/icons/lightbulb_off.png")); + registerWidgetAction(wa); + } + { + LWidgetAction wa("Analyze", SLOT(analyze())); + wa.setMenuLocation(MenuPath("Query/1")); + wa.setIcon(QIcon(":/icons/lightbulb.png")); + registerWidgetAction(wa); + } + { + LWidgetAction wa("Cancel", SLOT(cancel())); + wa.setMenuLocation(MenuPath("Query/1")); + wa.setIcon(QIcon(":/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(QueryToolModule, "Query tool", "pglab.querytool") diff --git a/pglab/QueryToolModule.h b/pglab/QueryToolModule.h new file mode 100644 index 0000000..bc77101 --- /dev/null +++ b/pglab/QueryToolModule.h @@ -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 diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 39ae9bd..02a678d 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -32,7 +32,6 @@ SOURCES += main.cpp\ ConnectionManagerWindow.cpp \ ConnectionListModel.cpp \ BackupRestore.cpp \ - QueryTab.cpp \ stopwatch.cpp \ TuplesResultWidget.cpp \ BackupDialog.cpp \ @@ -89,7 +88,10 @@ PropertyProxyModel.cpp \ plugin_support/PluginContentWidget.cpp \ plugin_support/PluginContentWidgetContextBase.cpp \ plugin_support/MenuAction.cpp \ - plugin_support/LMainWindow.cpp + plugin_support/LMainWindow.cpp \ + plugin_support/LWidgetAction.cpp \ + QueryTool.cpp \ + QueryToolModule.cpp HEADERS += \ QueryResultModel.h \ @@ -97,7 +99,6 @@ HEADERS += \ CreateDatabaseDialog.h \ ConnectionManagerWindow.h \ ConnectionListModel.h \ - QueryTab.h \ stopwatch.h \ TuplesResultWidget.h \ BackupDialog.h \ @@ -158,7 +159,10 @@ CustomDataRole.h \ plugin_support/IPluginContentWidgetContext.h \ plugin_support/PluginContentWidgetContextBase.h \ plugin_support/MenuAction.h \ - plugin_support/LMainWindow.h + plugin_support/LMainWindow.h \ + plugin_support/LWidgetAction.h \ + QueryTool.h \ + QueryToolModule.h FORMS += \ ConnectionManagerWindow.ui \ diff --git a/pglab/plugin_support/IPluginContentWidgetContext.h b/pglab/plugin_support/IPluginContentWidgetContext.h index 1bef7cb..c976ce9 100644 --- a/pglab/plugin_support/IPluginContentWidgetContext.h +++ b/pglab/plugin_support/IPluginContentWidgetContext.h @@ -8,8 +8,10 @@ #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. * @@ -45,7 +47,8 @@ public: const ModuleActionParameters &action_params ) = 0; - virtual void addContentWidget(PluginContentWidget *widget) = 0; + virtual void addContentWidget(PluginModule *module, PluginContentWidget *widget) = 0; + virtual void removeContentWidget(PluginContentWidget *widget) = 0; /** Return a widget you can use as a parent */ @@ -57,6 +60,7 @@ public: bool registerObject(std::shared_ptr object); template std::shared_ptr getObject() const; + private: std::map > m_objectRegistry; diff --git a/pglab/plugin_support/LMainWindow.cpp b/pglab/plugin_support/LMainWindow.cpp index 7d4a6ad..f782878 100644 --- a/pglab/plugin_support/LMainWindow.cpp +++ b/pglab/plugin_support/LMainWindow.cpp @@ -32,8 +32,9 @@ namespace LMainWindow_details { m_window->statusBar()->showMessage(msg); } - void addContentWidget(PluginContentWidget *widget) override + void addContentWidget(PluginModule *module, PluginContentWidget *widget) override { + PluginContentWidgetContextBase::addContentWidget(module, widget); m_window->addPage(widget, ""); } @@ -126,7 +127,7 @@ void LMainWindow::addMenuAction(const MenuAction &ma) { ma.perform(m_context); }, - ma.shortCut()); + ma.shortcut()); // auto ac = new QAction(this); @@ -171,6 +172,7 @@ void LMainWindow::tabWidget_tabCloseRequested(int index) if (plg_page) { if (plg_page->canClose()) { m_tabWidget->removeTab(index); + m_context->removeContentWidget(plg_page); delete plg_page; } } @@ -186,7 +188,7 @@ void LMainWindow::tabWidget_currentChanged(int index) { // remove buttons of old page if (m_previousPage) { - removeToolBarButtonsForPage(m_previousPage); + removeModuleWidgetActionsForPage(m_previousPage); } // add buttons of new page @@ -195,26 +197,18 @@ void LMainWindow::tabWidget_currentChanged(int index) QWidget *widget = m_tabWidget->widget(index); page = dynamic_cast(widget); if (page) { - addToolBarButtonsForPage(page); + addModuleWidgetActionsForPage(page); } } m_previousPage = page; } -void LMainWindow::addToolBarButtonsForPage(PluginContentWidget *page) +void LMainWindow::addModuleWidgetActionsForPage(PluginContentWidget *page) { - std::vector actions = page->getToolbarActions(); - QList list; - for (auto act : actions) { - list.append(act); - } - m_mainToolBar->addActions(list); + m_context->addWidgetActionsToToolbar(page, m_mainToolBar); } -void LMainWindow::removeToolBarButtonsForPage(PluginContentWidget *page) +void LMainWindow::removeModuleWidgetActionsForPage(PluginContentWidget *page) { - std::vector actions = page->getToolbarActions(); - for (auto act : actions) { - m_mainToolBar->removeAction(act); - } + m_context->removeWidgetActionsFromToolbar(page, m_mainToolBar); } diff --git a/pglab/plugin_support/LMainWindow.h b/pglab/plugin_support/LMainWindow.h index c7fac6d..0e30c71 100644 --- a/pglab/plugin_support/LMainWindow.h +++ b/pglab/plugin_support/LMainWindow.h @@ -39,8 +39,8 @@ protected: void addModuleMenuActions(); - void addToolBarButtonsForPage(PluginContentWidget *page); - void removeToolBarButtonsForPage(PluginContentWidget *page); + 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 diff --git a/pglab/plugin_support/LWidgetAction.cpp b/pglab/plugin_support/LWidgetAction.cpp new file mode 100644 index 0000000..6196143 --- /dev/null +++ b/pglab/plugin_support/LWidgetAction.cpp @@ -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; +} diff --git a/pglab/plugin_support/LWidgetAction.h b/pglab/plugin_support/LWidgetAction.h new file mode 100644 index 0000000..263c21a --- /dev/null +++ b/pglab/plugin_support/LWidgetAction.h @@ -0,0 +1,42 @@ +#ifndef LWIDGETACTION_H +#define LWIDGETACTION_H + +#include "MenuLocation.h" +#include +#include +#include + + +/** 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 setMenuLocation(MenuLocation 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 diff --git a/pglab/plugin_support/MenuAction.cpp b/pglab/plugin_support/MenuAction.cpp index a53a0c7..205b898 100644 --- a/pglab/plugin_support/MenuAction.cpp +++ b/pglab/plugin_support/MenuAction.cpp @@ -25,9 +25,9 @@ void MenuAction::setMenuLocation(MenuLocation menu_location) m_menuLocation = std::move(menu_location); } -void MenuAction::setShortCut(QKeySequence shortcut) +void MenuAction::setShortcut(QKeySequence shortcut) { - m_shortCut = std::move(shortcut); + m_shortcut = std::move(shortcut); } void MenuAction::setText(QString text) @@ -40,9 +40,9 @@ void MenuAction::setToolTip(QString tooltip) m_toolTip = std::move(tooltip); } -const QKeySequence& MenuAction::shortCut() const +const QKeySequence& MenuAction::shortcut() const { - return m_shortCut; + return m_shortcut; } const QString& MenuAction::text() const diff --git a/pglab/plugin_support/MenuAction.h b/pglab/plugin_support/MenuAction.h index 21ff9ee..d987660 100644 --- a/pglab/plugin_support/MenuAction.h +++ b/pglab/plugin_support/MenuAction.h @@ -27,10 +27,10 @@ public: const MenuLocation& menuLocation() const; void setIcon(QIcon icon); void setMenuLocation(MenuLocation menu_location); - void setShortCut(QKeySequence shortcut); + void setShortcut(QKeySequence shortcut); void setText(QString text); void setToolTip(QString tooltip); - const QKeySequence& shortCut() const; + const QKeySequence& shortcut() const; const QString& text() const; const QString& toolTip() const; @@ -39,11 +39,10 @@ private: QString m_text; QString m_toolTip; QIcon m_icon; - QKeySequence m_shortCut; + QKeySequence m_shortcut; MenuLocation m_menuLocation; Func m_func; }; - #endif // MENUACTION_H diff --git a/pglab/plugin_support/PluginContentWidget.cpp b/pglab/plugin_support/PluginContentWidget.cpp index 303bc15..39ff62d 100644 --- a/pglab/plugin_support/PluginContentWidget.cpp +++ b/pglab/plugin_support/PluginContentWidget.cpp @@ -3,14 +3,7 @@ PluginContentWidget::PluginContentWidget(IPluginContentWidgetContext *context, QWidget* parent) : QWidget(parent) , m_context(context) -{ - -} - -std::vector PluginContentWidget::getToolbarActions() -{ - return std::vector(); -} +{} bool PluginContentWidget::canClose() { diff --git a/pglab/plugin_support/PluginContentWidget.h b/pglab/plugin_support/PluginContentWidget.h index 9e8f1c5..663c181 100644 --- a/pglab/plugin_support/PluginContentWidget.h +++ b/pglab/plugin_support/PluginContentWidget.h @@ -5,6 +5,7 @@ #include class IPluginContentWidgetContext; +class PluginModule; /// Provides a pluggable system for toolbar buttons and menu actions /// @@ -21,7 +22,6 @@ class PluginContentWidget: public QWidget{ public: PluginContentWidget(IPluginContentWidgetContext *context, QWidget* parent = nullptr); /// Returns the toolbar buttons for this page - virtual std::vector getToolbarActions(); virtual bool canClose(); protected: diff --git a/pglab/plugin_support/PluginContentWidgetContextBase.cpp b/pglab/plugin_support/PluginContentWidgetContextBase.cpp index 10587ff..1d6703a 100644 --- a/pglab/plugin_support/PluginContentWidgetContextBase.cpp +++ b/pglab/plugin_support/PluginContentWidgetContextBase.cpp @@ -1,7 +1,43 @@ #include "PluginContentWidgetContextBase.h" -#include "PluginRegister.h" +#include "PluginContentWidget.h" #include "PluginModule.h" +#include "PluginRegister.h" +#include "LWidgetAction.h" +#include #include +#include +#include + + + +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 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; @@ -25,3 +61,43 @@ void PluginContentWidgetContextBase::moduleAction( 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); + +} diff --git a/pglab/plugin_support/PluginContentWidgetContextBase.h b/pglab/plugin_support/PluginContentWidgetContextBase.h index d060ba3..55428c8 100644 --- a/pglab/plugin_support/PluginContentWidgetContextBase.h +++ b/pglab/plugin_support/PluginContentWidgetContextBase.h @@ -2,6 +2,26 @@ #define PLUGINCONTENTWIDGETCONTEXTBASE_H #include "plugin_support/IPluginContentWidgetContext.h" +#include + +class LWidgetAction; +class QToolBar; +class QAction; + +class LWidgetData { +public: + LWidgetData(PluginModule *module); + PluginModule* module() { return m_module; } + void init(PluginContentWidget *widget); + QList actions(); + +private: + PluginModule *m_module; + /// List of actions specifically created for this widget from the widgetAction list of the module. + QList m_widgetActions; + + QAction *createAction(const LWidgetAction &wa, PluginContentWidget *widget); +}; /// Provides base implementation of IPluginContentWidgetContext class PluginContentWidgetContextBase : public IPluginContentWidgetContext @@ -14,6 +34,17 @@ public: 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; + + WidgetLst m_widgetLst; }; #endif // PLUGINCONTENTWIDGETCONTEXTBASE_H diff --git a/pglab/plugin_support/PluginModule.cpp b/pglab/plugin_support/PluginModule.cpp index 045604a..c5a3ac1 100644 --- a/pglab/plugin_support/PluginModule.cpp +++ b/pglab/plugin_support/PluginModule.cpp @@ -38,3 +38,4 @@ const PluginModule::ModuleAction* PluginModule::findModuleAction(const QString & return nullptr; return &res->second; } + diff --git a/pglab/plugin_support/PluginModule.h b/pglab/plugin_support/PluginModule.h index b3ea1db..951347a 100644 --- a/pglab/plugin_support/PluginModule.h +++ b/pglab/plugin_support/PluginModule.h @@ -3,6 +3,7 @@ #include "ModuleActionParameters.h" #include "MenuAction.h" +#include "LWidgetAction.h" #include "PluginRegister.h" #include #include @@ -16,12 +17,13 @@ class PluginModule: public QObject { Q_OBJECT public: using MenuActionList = std::vector; + using LWidgetActionList = std::vector; using ModuleAction = std::function; using ModuleActionMap = std::map; PluginModule(QString name, QString ident); - virtual void init() {}; + virtual void init() {} const QString& name() const { return m_name; } const QString& identifier() const { return m_ident; } @@ -38,6 +40,12 @@ public: /// 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; @@ -47,6 +55,7 @@ private: MenuActionList m_menuActions; ModuleActionMap m_moduleActions; + LWidgetActionList m_widgetActions; }; From d6fce5c31f3e0489a91766f1e33a11334905be95 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 6 Jan 2019 08:17:17 +0100 Subject: [PATCH 21/24] Simplified LWidgetAction initialization --- pglab/QueryToolModule.cpp | 24 ++++++++++++------------ pglab/plugin_support/LWidgetAction.h | 2 ++ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/pglab/QueryToolModule.cpp b/pglab/QueryToolModule.cpp index 6be8ec9..55d7406 100644 --- a/pglab/QueryToolModule.cpp +++ b/pglab/QueryToolModule.cpp @@ -26,39 +26,39 @@ void QueryToolModule::init() } { LWidgetAction wa("Save SQL", SLOT(save())); - wa.setMenuLocation(MenuPath("File/Save")); - wa.setIcon(QIcon(":/icons/script_save.png")); + 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(MenuPath("File/Save")); - wa.setIcon(QIcon(":/icons/script_save.png")); + wa.setMenuLocation("File/Save"); + wa.setIcon(":/icons/script_save.png"); registerWidgetAction(wa); } { LWidgetAction wa("Execute", SLOT(execute())); - wa.setMenuLocation(MenuPath("Query/1")); - wa.setIcon(QIcon(":/icons/script_go.png")); + wa.setMenuLocation("Query/1"); + wa.setIcon(":/icons/script_go.png"); registerWidgetAction(wa); } { LWidgetAction wa("Explain", SLOT(explain())); - wa.setMenuLocation(MenuPath("Query/2")); - wa.setIcon(QIcon(":/icons/lightbulb_off.png")); + wa.setMenuLocation("Query/2"); + wa.setIcon(":/icons/lightbulb_off.png"); registerWidgetAction(wa); } { LWidgetAction wa("Analyze", SLOT(analyze())); - wa.setMenuLocation(MenuPath("Query/1")); - wa.setIcon(QIcon(":/icons/lightbulb.png")); + wa.setMenuLocation("Query/1"); + wa.setIcon(":/icons/lightbulb.png"); registerWidgetAction(wa); } { LWidgetAction wa("Cancel", SLOT(cancel())); - wa.setMenuLocation(MenuPath("Query/1")); - wa.setIcon(QIcon(":/icons/script_delete.png")); + wa.setMenuLocation("Query/1"); + wa.setIcon(":/icons/script_delete.png"); registerWidgetAction(wa); } } diff --git a/pglab/plugin_support/LWidgetAction.h b/pglab/plugin_support/LWidgetAction.h index 263c21a..3169061 100644 --- a/pglab/plugin_support/LWidgetAction.h +++ b/pglab/plugin_support/LWidgetAction.h @@ -20,7 +20,9 @@ public: 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); From d3c85722c7815bbacafead59847679b50798c6ce Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 6 Jan 2019 08:17:37 +0100 Subject: [PATCH 22/24] Remove unneeded headers and code. --- pglab/DatabaseWindow.cpp | 63 +++++----------------------------------- pglab/DatabaseWindow.h | 17 ++--------- 2 files changed, 10 insertions(+), 70 deletions(-) diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 8e8dda4..9381f95 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -1,25 +1,19 @@ #include "DatabaseWindow.h" #include "plugin_support/IPluginContentWidgetContext.h" -#include "TablesPage.h" -#include "FunctionsPage.h" -#include "SequencesPage.h" #include "util.h" -#include "CodeGenerator.h" #include "MasterController.h" -#include "ScopeGuard.h" -#include "EditTableWidget.h" #include "TaskExecutor.h" #include -#include -#include -#include #include #include -#include -#include -#include -#include -#include +#include + +// Pages that should become modules +#include "TablesPage.h" +#include "EditTableWidget.h" +#include "CodeGenerator.h" +#include "FunctionsPage.h" +#include "SequencesPage.h" namespace pg = Pgsql; @@ -73,7 +67,6 @@ void DatabaseWindow::setConfig(const ConnectionConfig &config) void DatabaseWindow::catalogLoaded() { try { - //SCOPE_EXIT { loadFuture = {}; }; m_database = loadWatcher.future().result(); auto ctx = context(); ctx->registerObject(m_database); @@ -128,46 +121,6 @@ void DatabaseWindow::on_actionAbout_triggered() } -void DatabaseWindow::closeEvent(QCloseEvent* /*event*/) -{ - // TODO collect which files need saving -// std::vector 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(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_actionShow_connection_manager_triggered() { m_masterController->showConnectionManager(); diff --git a/pglab/DatabaseWindow.h b/pglab/DatabaseWindow.h index 8366707..ee748bb 100644 --- a/pglab/DatabaseWindow.h +++ b/pglab/DatabaseWindow.h @@ -1,24 +1,13 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H -#include "ASyncDBConnection.h" +#include "plugin_support/LMainWindow.h" #include "ConnectionConfig.h" #include "OpenDatabase.h" -#include "plugin_support/LMainWindow.h" -#include -#include -#include -#include #include "Pgsql_Connection.h" #include "ControllableTask.h" -#include -#include -#include - -#include -#include -#include #include +#include namespace Pgsql { class Connection; @@ -72,8 +61,6 @@ private: QFutureWatcher loadWatcher; - void closeEvent(QCloseEvent *event); - void showEvent(QShowEvent *event); void newCreateTablePage(); private slots: From 3e4917428de88a1e4e2ae6efb18a164387417a31 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 6 Jan 2019 10:11:48 +0100 Subject: [PATCH 23/24] TablesPage is now CatalogInspector and is now a module. --- .../{TablesPage.cpp => CatalogInspector.cpp} | 89 ++++++++++++++----- pglab/{TablesPage.h => CatalogInspector.h} | 19 +++- pglab/CrudTab.cpp | 2 +- pglab/DatabaseWindow.cpp | 18 +--- pglab/QueryToolModule.cpp | 2 +- pglab/pglab.pro | 8 +- pglab/plugin_support/PluginModule.h | 8 +- 7 files changed, 101 insertions(+), 45 deletions(-) rename pglab/{TablesPage.cpp => CatalogInspector.cpp} (71%) rename pglab/{TablesPage.h => CatalogInspector.h} (81%) diff --git a/pglab/TablesPage.cpp b/pglab/CatalogInspector.cpp similarity index 71% rename from pglab/TablesPage.cpp rename to pglab/CatalogInspector.cpp index 1445c62..c8063e4 100644 --- a/pglab/TablesPage.cpp +++ b/pglab/CatalogInspector.cpp @@ -1,4 +1,4 @@ -#include "TablesPage.h" +#include "CatalogInspector.h" #include "ui_TablesPage.h" #include "catalog/PgAttribute.h" @@ -10,6 +10,7 @@ #include "ConstraintModel.h" #include "IconColumnDelegate.h" #include "IndexModel.h" +#include "OpenDatabase.h" #include "PgLabItemDelegate.h" #include "PropertiesPage.h" #include "ResultTableModelUtil.h" @@ -22,7 +23,7 @@ #include #include "plugin_support/IPluginContentWidgetContext.h" -TablesPage::TablesPage(IPluginContentWidgetContext *context_, QWidget *parent) +CatalogInspector::CatalogInspector(IPluginContentWidgetContext *context_, QWidget *parent) : PluginContentWidget(context_, parent) , ui(new Ui::TablesPage) { @@ -61,24 +62,24 @@ TablesPage::TablesPage(IPluginContentWidgetContext *context_, QWidget *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 &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 @@ -102,12 +103,15 @@ TablesPage::TablesPage(IPluginContentWidgetContext *context_, QWidget *parent) // Force focus on columns tab by default ui->twDetails->setCurrentIndex(0); + auto db = context_->getObject(); + + setCatalog(db->catalog()); retranslateUi(false); } -void TablesPage::retranslateUi(bool all) +void CatalogInspector::retranslateUi(bool all) { if (all) ui->retranslateUi(this); @@ -123,12 +127,12 @@ void TablesPage::retranslateUi(bool all) } -TablesPage::~TablesPage() +CatalogInspector::~CatalogInspector() { delete ui; } -void TablesPage::setCatalog(std::shared_ptr cat) +void CatalogInspector::setCatalog(std::shared_ptr cat) { m_catalog = cat; m_tablesModel->setCatalog(cat); @@ -142,13 +146,28 @@ void TablesPage::setCatalog(std::shared_ptr 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()) { @@ -161,7 +180,7 @@ void TablesPage::tableListTable_currentRowChanged(const QModelIndex ¤t, co } -void TablesPage::tableListTable_layoutChanged(const QList &, QAbstractItemModel::LayoutChangeHint ) +void CatalogInspector::tableListTable_layoutChanged(const QList &, QAbstractItemModel::LayoutChangeHint ) { auto&& index = ui->tableListTable->selectionModel()->currentIndex(); if (index.isValid()) { @@ -173,7 +192,7 @@ void TablesPage::tableListTable_layoutChanged(const QList } -void TablesPage::selectedTableChanged(const std::optional &table) +void CatalogInspector::selectedTableChanged(const std::optional &table) { m_columnsPage->setData(m_catalog, table); @@ -189,7 +208,7 @@ void TablesPage::selectedTableChanged(const std::optional &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 rijen; @@ -206,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 rijen; @@ -229,12 +248,12 @@ 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) { @@ -244,7 +263,7 @@ void TablesPage::on_tableListTable_doubleClicked(const QModelIndex &index) } } -void TablesPage::updateSqlTab(const std::optional &table) +void CatalogInspector::updateSqlTab(const std::optional &table) { if (!table.has_value()) { m_sqlCodePreview->clear(); @@ -286,3 +305,31 @@ void TablesPage::updateSqlTab(const std::optional &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") diff --git a/pglab/TablesPage.h b/pglab/CatalogInspector.h similarity index 81% rename from pglab/TablesPage.h rename to pglab/CatalogInspector.h index e741605..8301398 100644 --- a/pglab/TablesPage.h +++ b/pglab/CatalogInspector.h @@ -25,13 +25,13 @@ class TriggerPage; class PgClass; class SqlCodePreview; -class TablesPage : public PluginContentWidget +class CatalogInspector : public PluginContentWidget { Q_OBJECT public: - explicit TablesPage(IPluginContentWidgetContext *context, QWidget *parent = nullptr); - ~TablesPage(); + explicit CatalogInspector(IPluginContentWidgetContext *context, QWidget *parent = nullptr); + ~CatalogInspector(); void setCatalog(std::shared_ptr cat); void setNamespaceFilter(TablesTableModel::NamespaceFilter filter); @@ -62,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 diff --git a/pglab/CrudTab.cpp b/pglab/CrudTab.cpp index b0b0cf0..7b73a1e 100644 --- a/pglab/CrudTab.cpp +++ b/pglab/CrudTab.cpp @@ -138,4 +138,4 @@ void CrudPageModule::moduleAction_open( } -REGISTER_PLUGIN_MODULE(CrudPageModule, "CRUD tool", "pglab.crudpage") +REGISTER_PLUGIN_MODULE_CAT(CrudPageModule, "CRUD tool", "pglab.crudpage", "database") diff --git a/pglab/DatabaseWindow.cpp b/pglab/DatabaseWindow.cpp index 9381f95..4a06812 100644 --- a/pglab/DatabaseWindow.cpp +++ b/pglab/DatabaseWindow.cpp @@ -9,7 +9,6 @@ #include // Pages that should become modules -#include "TablesPage.h" #include "EditTableWidget.h" #include "CodeGenerator.h" #include "FunctionsPage.h" @@ -71,19 +70,10 @@ void DatabaseWindow::catalogLoaded() auto ctx = context(); ctx->registerObject(m_database); - auto tt = new TablesPage(ctx, this); - tt->setCatalog(m_database->catalog()); - m_tabWidget->addTab(tt, "Tables"); - - auto pg_cat_tables = new TablesPage(ctx, this); - pg_cat_tables->setNamespaceFilter(TablesTableModel::PgCatalog); - pg_cat_tables->setCatalog(m_database->catalog()); - m_tabWidget->addTab(pg_cat_tables, "pg_catalog"); - - auto info_schema_tables = new TablesPage(ctx, this); - info_schema_tables->setNamespaceFilter(TablesTableModel::InformationSchema); - info_schema_tables->setCatalog(m_database->catalog()); - m_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()); diff --git a/pglab/QueryToolModule.cpp b/pglab/QueryToolModule.cpp index 55d7406..cc36d80 100644 --- a/pglab/QueryToolModule.cpp +++ b/pglab/QueryToolModule.cpp @@ -82,4 +82,4 @@ void QueryToolModule::menuAction_open(IPluginContentWidgetContext* context) } } -REGISTER_PLUGIN_MODULE(QueryToolModule, "Query tool", "pglab.querytool") +REGISTER_PLUGIN_MODULE_CAT(QueryToolModule, "Query tool", "pglab.querytool", "database") diff --git a/pglab/pglab.pro b/pglab/pglab.pro index 02a678d..fe0a375 100644 --- a/pglab/pglab.pro +++ b/pglab/pglab.pro @@ -48,7 +48,6 @@ SOURCES += main.cpp\ ResultTableModelUtil.cpp \ BaseTableModel.cpp \ QueryParamListController.cpp \ - TablesPage.cpp \ TablesTableModel.cpp \ ColumnTableModel.cpp \ NamespaceFilterWidget.cpp \ @@ -91,7 +90,8 @@ PropertyProxyModel.cpp \ plugin_support/LMainWindow.cpp \ plugin_support/LWidgetAction.cpp \ QueryTool.cpp \ - QueryToolModule.cpp + QueryToolModule.cpp \ + CatalogInspector.cpp HEADERS += \ QueryResultModel.h \ @@ -115,7 +115,6 @@ HEADERS += \ ResultTableModelUtil.h \ BaseTableModel.h \ QueryParamListController.h \ - TablesPage.h \ TablesTableModel.h \ ColumnTableModel.h \ NamespaceFilterWidget.h \ @@ -162,7 +161,8 @@ CustomDataRole.h \ plugin_support/LMainWindow.h \ plugin_support/LWidgetAction.h \ QueryTool.h \ - QueryToolModule.h + QueryToolModule.h \ + CatalogInspector.h FORMS += \ ConnectionManagerWindow.ui \ diff --git a/pglab/plugin_support/PluginModule.h b/pglab/plugin_support/PluginModule.h index 951347a..9927b34 100644 --- a/pglab/plugin_support/PluginModule.h +++ b/pglab/plugin_support/PluginModule.h @@ -60,9 +60,10 @@ private: template -std::shared_ptr createPluginModule(QString name, QString ident) +std::shared_ptr createPluginModule(QString name, QString ident, QString category={}) { auto module = std::make_shared(std::move(name), std::move(ident)); + module->setDisplayCategory(category); PluginRegister::getInstance()->registerModule(module); return std::move(module); @@ -73,5 +74,10 @@ std::shared_ptr createPluginModule(QString name, QString ident) std::weak_ptr register_variable = createPluginModule\ (name, ident);} +#define REGISTER_PLUGIN_MODULE_CAT(module, name, ident, category) \ + namespace {\ + std::weak_ptr register_variable = createPluginModule\ + (name, ident, category);} + #endif // PLUGIN_SUPPORTPLUGINMODULE_H From e5dd27ff1a574613d80a1fe2abc377c7af3b450e Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 6 Jan 2019 16:34:50 +0100 Subject: [PATCH 24/24] Added several actions that were left out while switching to module. - save copy as - export - copy as c string - copy as raw cpp string --- pglab/QueryTool.cpp | 8 ++++++++ pglab/QueryTool.h | 10 +++++++--- pglab/QueryToolModule.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/pglab/QueryTool.cpp b/pglab/QueryTool.cpp index b03dfdb..3e0ef23 100644 --- a/pglab/QueryTool.cpp +++ b/pglab/QueryTool.cpp @@ -629,3 +629,11 @@ void QueryTool::focusEditor() { ui->queryEdit->setFocus(); } + +void QueryTool::exportData() +{ + 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); +} diff --git a/pglab/QueryTool.h b/pglab/QueryTool.h index 8a30cb8..a711eb2 100644 --- a/pglab/QueryTool.h +++ b/pglab/QueryTool.h @@ -39,14 +39,11 @@ public: void newdoc(); bool load(const QString &filename); - void saveCopyAs(); void explain(bool analyze); bool canClose() override; - void copyQueryAsCString(); - void copyQueryAsRawCppString(); void generateCode(); void exportData(const QString &filename); @@ -57,11 +54,18 @@ public: 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; diff --git a/pglab/QueryToolModule.cpp b/pglab/QueryToolModule.cpp index cc36d80..0cf0c4a 100644 --- a/pglab/QueryToolModule.cpp +++ b/pglab/QueryToolModule.cpp @@ -37,6 +37,30 @@ void QueryToolModule::init() 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");