Work on plugin mechanism

Context actions have become normal actions in the pluginwidget so the widget knows abot them and
can easily do things like enable/disable.
This commit is contained in:
eelke 2019-02-08 10:10:11 +01:00
parent eca8841427
commit a704332342
24 changed files with 239 additions and 267 deletions

View file

@ -106,6 +106,22 @@ void CrudTab::headerCustomContextMenu(const QPoint &pos)
menu->popup(horizontal_header->mapToGlobal(pos));
}
void CrudTab::initActions()
{
{
auto ac = new QAction(QIcon(":/icons/script_go.png"), tr("Refresh"), this);
ac->setShortcut(QKeySequence(Qt::Key_F5));
connect(ac, &QAction::triggered, this, &CrudTab::refresh);
m_refreshAction = ac;
}
}
QList<QAction *> CrudTab::actions()
{
return { m_refreshAction };
}
void CrudPageModule::init()
{
@ -115,14 +131,6 @@ void CrudPageModule::init()
{
moduleAction_open(context, params);
});
{
LContextAction wa("Refresh", SLOT(refresh()));
wa.setMenuLocation(MenuPath("Window/1"));
wa.setIcon(QIcon(":/icons/script_go.png"));
wa.setShortcut(QKeySequence(Qt::Key_F5));
registerContextAction(wa);
}
}
void CrudPageModule::moduleAction_open(

View file

@ -33,7 +33,11 @@ private:
std::optional<PgClass> m_table;
CrudModel *m_crudModel = nullptr;
std::vector<QAction*> actions;
QAction *m_refreshAction = nullptr;
void initActions();
virtual QList<QAction *> actions() override;
private slots:
void on_actionRemove_rows_triggered();
@ -49,6 +53,7 @@ public:
private slots:
private:
void moduleAction_open(IPluginContentWidgetContext* context, const ModuleActionParameters &params);
};

View file

@ -36,7 +36,7 @@ QVariant QueryResultModel::data(const QModelIndex &index, int role) const
const int col = index.column();
const int rij = index.row();
const Oid oid = result->type(col);
if (role == Qt::DisplayRole) {
if (role == Qt::DisplayRole || role == Qt::EditRole) {
if (result->null(col, rij)) {
//v = nullptr;
}
@ -74,10 +74,11 @@ QVariant QueryResultModel::headerData(int section, Qt::Orientation orientation,
r = QString::number(section + 1);
}
}
Qt::ItemFlags f;
return r;
}
//Qt::ItemFlags QueryResultModel::flags(const QModelIndex &) const
//{
// return Qt::ItemIsUserCheckable;
//}
Qt::ItemFlags QueryResultModel::flags(const QModelIndex &) const
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
}

View file

@ -17,7 +17,7 @@ public:
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
std::shared_ptr<const Pgsql::Result> GetPgsqlResult() const { return result; }
protected:

View file

@ -45,6 +45,8 @@ QueryTool::QueryTool(IPluginContentWidgetContext *context_, QWidget *parent)
highlighter->setTypes(*cat->types());
}
initActions();
connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTool::queryTextChanged);
m_queryParamListController = new QueryParamListController(ui->paramTableView, open_database, this);
@ -173,16 +175,6 @@ void QueryTool::execute()
}
}
void QueryTool::explain()
{
explain(false);
}
void QueryTool::analyze()
{
explain(true);
}
void QueryTool::explain(bool analyze)
{
ui->explainTreeView->setModel(nullptr);
@ -615,7 +607,7 @@ void QueryTool::generateCode()
}
}
void QueryTool::exportData(const QString &file_name)
void QueryTool::exportDataToFilename(const QString &file_name)
{
auto widget = ui->tabWidget->currentWidget();
auto fi = std::find(resultList.begin(), resultList.end(), widget);
@ -635,5 +627,73 @@ 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);
exportDataToFilename(file_name);
}
void QueryTool::initActions()
{
{
auto ac = new QAction(QIcon(":/icons/script_save.png"), tr("Save SQL"), this);
ac->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
connect(ac, &QAction::triggered, this, &QueryTool::save);
m_saveSqlAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/script_save.png"), tr("Save SQL as"), this);
connect(ac, &QAction::triggered, this, &QueryTool::saveAs);
m_saveSqlAsAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/script_save.png"), tr("Save copy of SQL as"), this);
connect(ac, &QAction::triggered, this, &QueryTool::saveCopyAs);
m_saveCopyOfSqlAsAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/table_save.png"), tr("&Export data"), this);
connect(ac, &QAction::triggered, this, &QueryTool::exportData);
m_exportDataAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/token_shortland_character.png"), tr("Copy as C string"), this);
connect(ac, &QAction::triggered, this, &QueryTool::copyQueryAsCString);
m_copyQueryAsCStringAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/token_shortland_character.png"), tr("Copy as raw C++ string"), this);
connect(ac, &QAction::triggered, this, &QueryTool::copyQueryAsRawCppString);
m_copyQueryAsRawCppStringAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/script_go.png"), tr("Execute"), this);
connect(ac, &QAction::triggered, this, &QueryTool::execute);
ac->setShortcut(QKeySequence(Qt::Key_F5));
m_executeAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/lightbulb_off.png"), tr("Explain"), this);
connect(ac, &QAction::triggered, [this] { explain(false); });
ac->setShortcut(QKeySequence(Qt::Key_F7));
m_explainAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/lightbulb.png"), tr("Analyze"), this);
connect(ac, &QAction::triggered, [this] { explain(true); });
ac->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F7));
m_analyzeAction = ac;
}
{
auto ac = new QAction(QIcon(":/icons/script_delete.png"), tr("Cancel"), this);
connect(ac, &QAction::triggered, this, &QueryTool::cancel);
m_analyzeAction = ac;
}
}
QList<QAction *> QueryTool::actions()
{
return { m_saveSqlAction, m_saveSqlAsAction, m_saveCopyOfSqlAsAction,
m_exportDataAction,
m_copyQueryAsCStringAction, m_copyQueryAsRawCppStringAction,
m_executeAction, m_explainAction, m_analyzeAction };
}

View file

@ -45,13 +45,15 @@ public:
bool canClose() override;
void generateCode();
void exportData(const QString &filename);
void exportDataToFilename(const QString &filename);
QString fileName() const { return m_fileName; }
bool isChanged() const { return m_queryTextChanged; }
bool isNew() const { return m_new; }
void focusEditor();
QList<QAction *> actions();
public slots:
void execute();
/// Save the document under its current name, a file save dialog will be shown if this is a new document
@ -62,10 +64,9 @@ public slots:
void saveCopyAs();
void copyQueryAsCString();
void copyQueryAsRawCppString();
void explain();
void analyze();
void cancel();
void exportData();
private:
using ResultTabContainer = std::vector<TuplesResultWidget*>;
@ -75,6 +76,16 @@ private:
ConnectionConfig m_config;
StopWatch m_stopwatch;
QAction *m_saveSqlAction = nullptr;
QAction *m_saveSqlAsAction = nullptr;
QAction *m_saveCopyOfSqlAsAction = nullptr;
QAction *m_exportDataAction = nullptr;
QAction *m_copyQueryAsCStringAction = nullptr;
QAction *m_copyQueryAsRawCppStringAction = nullptr;
QAction *m_executeAction = nullptr;
QAction *m_explainAction = nullptr;
QAction *m_analyzeAction = nullptr;
QueryParamListController *m_queryParamListController = nullptr;
bool m_new = true;
@ -103,6 +114,7 @@ private:
//void setTabCaption(const QString &caption, const QString &tooltip);
void clearResult();
void markError(const Pgsql::ErrorDetails &details);
void initActions();
private slots:

View file

@ -11,7 +11,7 @@ void QueryToolModule::init()
std::string slot_name = SLOT(QueryTool::execute());
{
StaticAction ma("New SQL", [this] (IPluginContentWidgetContext* context)
{ menuAction_new(context); });
{ staticAction_new(context); });
ma.setMenuLocation(MenuPath("File/New"));
ma.setToolbarLocation(ToolbarLocation("main", "new"));
ma.setIcon(QIcon(":/icons/new_query_tab.png"));
@ -20,91 +20,22 @@ void QueryToolModule::init()
}
{
StaticAction ma("Open SQL", [this] (IPluginContentWidgetContext* context)
{ menuAction_open(context); });
{ staticAction_open(context); });
ma.setMenuLocation(MenuPath("File/Open"));
ma.setToolbarLocation(ToolbarLocation("main", "open"));
ma.setIcon(QIcon(":/icons/folder.png"));
registerStaticAction(ma);
}
{
LContextAction wa("Save SQL", SLOT(save()));
wa.setMenuLocation("File/Save");
wa.setToolbarLocation(ToolbarLocation("main", "save"));
wa.setIcon(":/icons/script_save.png");
wa.setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
registerContextAction(wa);
}
{
LContextAction wa("Save SQL as", SLOT(saveAs()));
wa.setMenuLocation("File/Save");
wa.setToolbarLocation(ToolbarLocation("main", "save"));
wa.setIcon(":/icons/script_save.png");
registerContextAction(wa);
}
{
LContextAction wa("Save copy of SQL as", SLOT(saveCopyAs()));
wa.setMenuLocation("File/Save");
wa.setToolbarLocation(ToolbarLocation("main", "save"));
//wa.setIcon(":/icons/script_save.png");
registerContextAction(wa);
}
{
LContextAction wa("&Export data", SLOT(exportData()));
wa.setMenuLocation("File/Export");
wa.setToolbarLocation(ToolbarLocation("main", "save"));
wa.setIcon(":/icons/table_save.png");
registerContextAction(wa);
}
{
LContextAction wa("Copy as C string", SLOT(copyQueryAsCString()));
wa.setMenuLocation("Edit/Copy");
wa.setToolbarLocation(ToolbarLocation("edit", "copy"));
wa.setIcon(":/icons/token_shortland_character.png");
registerContextAction(wa);
}
{
LContextAction wa("Copy as raw C++ string", SLOT(copyQueryAsRawCppString()));
wa.setMenuLocation("Edit/Copy");
wa.setIcon(":/icons/token_shortland_character.png");
registerContextAction(wa);
}
{
LContextAction wa("Execute", SLOT(execute()));
wa.setMenuLocation("Query/1");
wa.setIcon(":/icons/script_go.png");
wa.setShortcut(QKeySequence(Qt::Key_F5));
registerContextAction(wa);
}
{
LContextAction wa("Explain", SLOT(explain()));
wa.setMenuLocation("Query/2");
wa.setIcon(":/icons/lightbulb_off.png");
wa.setShortcut(QKeySequence(Qt::Key_F7));
registerContextAction(wa);
}
{
LContextAction wa("Analyze", SLOT(analyze()));
wa.setMenuLocation("Query/1");
wa.setIcon(":/icons/lightbulb.png");
wa.setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F7));
registerContextAction(wa);
}
{
LContextAction wa("Cancel", SLOT(cancel()));
wa.setMenuLocation("Query/1");
wa.setIcon(":/icons/script_delete.png");
registerContextAction(wa);
}
}
void QueryToolModule::menuAction_new(IPluginContentWidgetContext* context)
void QueryToolModule::staticAction_new(IPluginContentWidgetContext* context)
{
auto *ct = new QueryTool(context, nullptr);
context->addContentWidget(this, ct);
ct->newdoc();
}
void QueryToolModule::menuAction_open(IPluginContentWidgetContext* context)
void QueryToolModule::staticAction_open(IPluginContentWidgetContext* context)
{
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
QString file_name = QFileDialog::getOpenFileName(context->container(),

View file

@ -9,8 +9,8 @@ public:
using PluginModule::PluginModule;
void init() override;
void menuAction_new(IPluginContentWidgetContext* context);
void menuAction_open(IPluginContentWidgetContext* context);
void staticAction_new(IPluginContentWidgetContext* context);
void staticAction_open(IPluginContentWidgetContext* context);
private slots:
};

View file

@ -91,7 +91,7 @@ PropertyProxyModel.cpp \
QueryToolModule.cpp \
CatalogInspector.cpp \
plugin_support/StaticAction.cpp \
plugin_support/LContextAction.cpp
plugin_support/LMainMenu.cpp
HEADERS += \
QueryResultModel.h \
@ -162,7 +162,7 @@ CustomDataRole.h \
QueryToolModule.h \
CatalogInspector.h \
plugin_support/StaticAction.h \
plugin_support/LContextAction.h
plugin_support/LMainMenu.h
FORMS += \
ConnectionManagerWindow.ui \

View file

@ -1,61 +0,0 @@
#include "LContextAction.h"
LContextAction::LContextAction(QString text, const char * slotname)
: m_text(std::move(text))
, m_slotname(slotname)
{}
const QIcon& LContextAction::icon() const
{
return m_icon;
}
const MenuLocation& LContextAction::menuLocation() const
{
return m_menuLocation;
}
void LContextAction::setIcon(QIcon icon)
{
m_icon = std::move(icon);
}
void LContextAction::setMenuLocation(MenuLocation menu_location)
{
m_menuLocation = std::move(menu_location);
}
void LContextAction::setToolbarLocation(ToolbarLocation toolbar_location)
{
m_toolbarLocation = toolbar_location;
}
void LContextAction::setShortcut(QKeySequence shortcut)
{
m_shortCut = std::move(shortcut);
}
void LContextAction::setText(QString text)
{
m_text = std::move(text);
}
void LContextAction::setToolTip(QString tooltip)
{
m_toolTip = std::move(tooltip);
}
const QKeySequence& LContextAction::shortcut() const
{
return m_shortCut;
}
const QString& LContextAction::text() const
{
return m_text;
}
const QString& LContextAction::toolTip() const
{
return m_toolTip;
}

View file

@ -1,47 +0,0 @@
#ifndef LWIDGETACTION_H
#define LWIDGETACTION_H
#include "MenuLocation.h"
#include "ToolbarLocation.h"
#include <QIcon>
#include <QKeySequence>
#include <QString>
/** Action definition for a specific widget instance, it uses a slotname
* so the action can be defined before the widget instance is created.
* The plugin mechanism will take care of instantiating a connection to the named slot.
*/
class LContextAction {
public:
///
/// \param slotname, use SLOT macro to pass name of the slot
LContextAction(QString text, const char * slotname);
const QIcon& icon() const;
const MenuLocation& menuLocation() const;
void setIcon(QIcon icon);
void setIcon(const char * icon) { setIcon(QIcon(icon)); }
void setMenuLocation(MenuLocation menu_location);
void setMenuLocation(const char * menu_location) { setMenuLocation(MenuPath(menu_location)); }
void setToolbarLocation(ToolbarLocation toolbar_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;
ToolbarLocation m_toolbarLocation;
const char * m_slotname;
};
#endif // LWIDGETACTION_H

View file

@ -0,0 +1,6 @@
#include "LMainMenu.h"
LMainMenu::LMainMenu()
{
}

View file

@ -0,0 +1,56 @@
#ifndef LMAINMENU_H
#define LMAINMENU_H
#include <QString>
#include <vector>
class QAction;
class LMenuGroupItem {
public:
LMenuGroupItem(QAction *action, int position)
: m_menuAction(action)
, m_position(position)
{}
int position() const { return m_position; }
private:
QAction *m_menuAction;
int m_position;
};
// Menu's are divided into logical groups,
// these groups form only a single level they are NOT submenu's
class LMenuGroup {
public:
explicit LMenuGroup(QString group_id);
QString groupId() const;
private:
QString m_groupId;
};
class LMenu {
public:
QString menuId() const;
void addGroup(const LMenuGroup &group)
{
m_groups.push_back(group);
}
private:
using Groups = std::vector<LMenuGroup>;
QString m_caption;
Groups m_groups;
};
class LMainMenu: public LMenu {
public:
LMainMenu();
};
#endif // LMAINMENU_H

View file

@ -99,7 +99,7 @@ void LMainWindow::addModuleMenuActions()
auto reg = PluginRegister::getInstance();
auto mods = reg->modules();
for (auto && mod : mods) {
auto items = mod.second->menuActions();
auto items = mod.second->staticActions();
for (auto && item : items) {
addMenuAction(item);
}

View file

@ -2,9 +2,12 @@
#define MENULOCATION_H
#include "plugin_support/MenuPath.h"
#include <QString>
///
class MenuLocation {
public:
MenuLocation();
MenuLocation(MenuPath path, int position = -1);

View file

@ -2,9 +2,16 @@
MenuPath::MenuPath() = default;
//MenuPath::MenuPath(QString menu_path)
// : m_menuPath(std::move(menu_path))
//{
//}
MenuPath::MenuPath(QString menu_path)
: m_menuPath(std::move(menu_path))
{
auto parts = menu_path.splitRef('/');
for (auto&& elem : parts) {
m_elems.emplace_back(elem);
}
}

View file

@ -2,17 +2,46 @@
#define MENUPATH_H
#include <QString>
#include <boost/container/small_vector.hpp>
#include <QVector>
#include <vector>
/// For a menu path we use a string very similar to a file path. Width however the addition of semicolons
/// for specifying groups. So the following path
///
/// /File:Save
///
/// Specifies the File menu and the group Save within that menu while
///
/// /File/Export
///
/// Would specify the export sub menu of the file menu
///
class MenuPath {
public:
MenuPath();
MenuPath(QString menu_path);
private:
QString m_menuPath;
class Elem {
public:
QStringRef menu;
QStringRef group;
explicit Elem(QStringRef s)
{
auto p = s.split(':');
menu = p[0];
if (p.size() > 1) {
group = p[1];
}
}
};
std::vector<Elem> m_elems;
};
#endif // MENUPATH_H

View file

@ -24,8 +24,11 @@ public:
/// Returns the toolbar buttons for this page
virtual bool canClose();
virtual QList<QAction *> actions() { return QList<QAction*>(); }
protected:
IPluginContentWidgetContext *context() { return m_context; }
private:
IPluginContentWidgetContext *m_context;
};

View file

@ -2,7 +2,6 @@
#include "PluginContentWidget.h"
#include "PluginModule.h"
#include "PluginRegister.h"
#include "LContextAction.h"
#include <QAction>
#include <QDebug>
#include <QToolBar>
@ -16,28 +15,8 @@ LWidgetData::LWidgetData(PluginModule *module)
void LWidgetData::init(PluginContentWidget *widget)
{
auto&& widget_actions = m_module->contextActions();
m_widgetActions.reserve(widget_actions.size());
for (auto&& wa : widget_actions) {
m_widgetActions.push_back(createAction(wa, widget));
}
}
QList<QAction *> LWidgetData::actions()
{
return m_widgetActions;
}
QAction *LWidgetData::createAction(const LContextAction &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;
@ -82,21 +61,13 @@ void PluginContentWidgetContextBase::removeContentWidget(PluginContentWidget *wi
void PluginContentWidgetContextBase::addWidgetActionsToToolbar(PluginContentWidget *widget, QToolBar *toolbar)
{
auto res = m_widgetLst.find(widget);
if (res == m_widgetLst.end())
return;
auto && actions = res->second.actions();
auto && actions = widget->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();
auto && actions = widget->actions();
for (auto && ac : actions)
toolbar->removeAction(ac);

View file

@ -13,14 +13,9 @@ public:
LWidgetData(PluginModule *module);
PluginModule* module() { return m_module; }
void init(PluginContentWidget *widget);
QList<QAction *> actions();
private:
PluginModule *m_module;
/// List of actions specifically created for this widget from the widgetAction list of the module.
QList<QAction *> m_widgetActions;
QAction *createAction(const LContextAction &wa, PluginContentWidget *widget);
};
/// Provides base implementation of IPluginContentWidgetContext

View file

@ -3,7 +3,6 @@
#include "ModuleActionParameters.h"
#include "StaticAction.h"
#include "LContextAction.h"
#include "PluginRegister.h"
#include <QObject>
#include <functional>
@ -17,7 +16,6 @@ class PluginModule: public QObject {
Q_OBJECT
public:
using StaticActionList = std::vector<StaticAction>;
using ContextActionList = std::vector<LContextAction>;
using ModuleAction = std::function<void(IPluginContentWidgetContext*, const ModuleActionParameters &)>;
using ModuleActionMap = std::map<QString, ModuleAction>;
@ -43,11 +41,6 @@ public:
/// When the action is not found nullptr is returned.
const ModuleAction* findModuleAction(const QString &module_action) const;
void registerContextAction(const LContextAction &action)
{
m_widgetActions.push_back(action);
}
const ContextActionList& contextActions() const { return m_widgetActions; }
private:
/// Name shown to end users
QString m_name;
@ -57,7 +50,6 @@ private:
StaticActionList m_menuActions;
ModuleActionMap m_moduleActions;
ContextActionList m_widgetActions;
};

View file

@ -9,7 +9,6 @@
#include <QString>
#include <functional>
class QAction;
class IPluginContentWidgetContext;
/** An action for in a menu or toolbar that does not pertain to a specific

View file

@ -1,5 +1,6 @@
#include "tuplesresultwidget.h"
#include "ui_tuplesresultwidget.h"
#include "ResultTableModelUtil.h"
#include "util.h"
#include <QFile>
@ -14,6 +15,7 @@ TuplesResultWidget::TuplesResultWidget(QWidget *parent) :
ui->setupUi(this);
ui->lblRowCount->setText(QString());
SetTableViewDefault(ui->ResultView);
auto delegate = new PgLabItemDelegate(ui->ResultView);
ui->ResultView->setItemDelegate(delegate);
}

View file

@ -38,7 +38,7 @@
</font>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
<set>QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
@ -53,7 +53,7 @@
<bool>false</bool>
</property>
<attribute name="verticalHeaderDefaultSectionSize">
<number>20</number>
<number>21</number>
</attribute>
<attribute name="verticalHeaderMinimumSectionSize">
<number>16</number>