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.
This commit is contained in:
eelke 2018-12-31 15:20:55 +01:00
parent f996703937
commit b0cd47ef46
17 changed files with 209 additions and 55 deletions

View file

@ -0,0 +1,51 @@
#ifndef IPLUGINCONTENTWIDGETCONTEXT_H
#define IPLUGINCONTENTWIDGETCONTEXT_H
#include <QString>
#include <memory>
#include "plugin_support/ModuleActionParameters.h"
class OpenDatabase;
class PluginContentWidget;
/** This class serves to isolate the plugin from the actual construct in which it is
* used.
*
* It provides interface for operating on the context without needing to many details.
* Actual default implementation is in PluginContentWidgetContextBase.
*/
class IPluginContentWidgetContext {
public:
virtual ~IPluginContentWidgetContext() = default;
/** Tells the context what to use as a caption for this content widget.
*
* Depending on the context the caption might not be visible or used as the caption
* of a window or tab.
*/
virtual void setCaption(PluginContentWidget *content, const QString &caption, const QString &hint = {}) = 0;
/** Tells the context what icon to use.
*
* In general the icon is used in a similar place as the caption.
* \param iconname Assumed to be the name of an iconresource. The system will look for different
* sizes under :/icons/<size>/iconname
*/
virtual void setIcon(PluginContentWidget *content, const QString &iconname) = 0;
/** Returns an OpenDatabase object the widget can use to access
* the database.
*/
virtual std::shared_ptr<OpenDatabase> getDatabase() = 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

View file

@ -0,0 +1,10 @@
#ifndef MODULEACTIONPARAMETERS_H
#define MODULEACTIONPARAMETERS_H
#include <map>
#include <QString>
#include <QVariant>
using ModuleActionParameters = std::map<QString, QVariant>;
#endif // MODULEACTIONPARAMETERS_H

View file

@ -0,0 +1,27 @@
#include "PluginContentWidgetContextBase.h"
#include "PluginRegister.h"
#include "PluginModule.h"
#include <QDebug>
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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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 <QObject>
#include <functional>
#include <map>
class QAction;
class IPluginContentWidgetContext;
class PluginModule: public QObject {
Q_OBJECT
public:
using ModuleAction = std::function<void(IPluginContentWidgetContext*, const ModuleActionParameters &)>;
using ModuleActionMap = std::map<QString, ModuleAction>;
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 <typename T>
std::shared_ptr<PluginModule> createPluginModule(QString name, QString ident)
{
auto module = std::make_shared<T>(std::move(name), std::move(ident));
module->init();
PluginRegister::getInstance()->registerModule(module);
return std::move(module);
}
#endif // PLUGIN_SUPPORTPLUGINMODULE_H

View file

@ -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();
}

View file

@ -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;