From 15bee330765d4b9e32b5f21b1da9d815469a6820 Mon Sep 17 00:00:00 2001 From: eelke Date: Sun, 30 Dec 2018 15:46:15 +0100 Subject: [PATCH] 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