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