Skip to content

Commit

Permalink
Add plug-in management dialog, delete plug-in map
Browse files Browse the repository at this point in the history
  • Loading branch information
zmoth committed Jan 4, 2023
1 parent 8e9775b commit c60e4d4
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 75 deletions.
3 changes: 3 additions & 0 deletions examples/plugin_text/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
file(GLOB_RECURSE CPPS ./*.cpp)
file(GLOB_RECURSE HPPS ./*.hpp)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin/Debug/nodes")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin/Release/nodes")

add_library(plugin_text SHARED ${CPPS} ${HPPS})

target_link_libraries(plugin_text QtNodes)
Expand Down
6 changes: 6 additions & 0 deletions examples/plugin_text/PluginDefinition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ Plugin::
Plugin()
{ _this_plugin = this; }

Plugin::
~Plugin()
{
// TODO: Unregister all models here
}

void
Plugin::
registerDataModels(std::shared_ptr<QtNodes::NodeDelegateModelRegistry> & reg)
Expand Down
7 changes: 2 additions & 5 deletions examples/plugin_text/PluginDefinition.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,12 @@
#include <QtNodes/PluginInterface>

// This needs to be the same as the name of your project file ${PROJECT_NAME}
// 这里需要和您的工程文件名一致 ${PROJECT_NAME}
#if defined(plugin_text_EXPORTS)
#ifdef plugin_text_EXPORTS
#define DLL_EXPORT Q_DECL_EXPORT
#else
#define DLL_EXPORT Q_DECL_IMPORT
#endif

using QtNodes::NodeDelegateModelRegistry;
using QtNodes::PluginInterface;

#define PLUGIN_NAME "pluginText"

class DLL_EXPORT Plugin
Expand All @@ -27,6 +23,7 @@ class DLL_EXPORT Plugin

public:
Plugin();
~Plugin();

QString
name() const override
Expand Down
149 changes: 149 additions & 0 deletions examples/plugins_load/PluginsManagerDlg.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
#include "PluginsManagerDlg.hpp"

#include <QTableView>
#include <QPushButton>
#include <QGridLayout>
#include <QHeaderView>
#include <QDir>
#include <QFileDialog>
#include <QDesktopServices>

#include <QtNodes/NodeDelegateModelRegistry>
#include <QtNodes/PluginInterface>

using QtNodes::NodeDelegateModelRegistry;
using QtNodes::PluginInterface;

PluginsManagerDlg::
PluginsManagerDlg(QWidget* parent)
: QDialog(parent)
, _pluginsFolderPath(R"(./nodes)")
{
QGridLayout *layout = new QGridLayout();
setLayout(layout);

QTableView *pluginTable = new QTableView();
pluginTable->setSelectionBehavior(QAbstractItemView::SelectRows);
pluginTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
pluginTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
layout->addWidget(pluginTable, 0, 0, 1, 2);

_model = new QStandardItemModel(pluginTable);

_model->setColumnCount(2);
_model->setHeaderData(0, Qt::Horizontal, "name");
_model->setHeaderData(1, Qt::Horizontal, "version");
pluginTable->setModel(_model);

loadPluginsFromFolder();

// add button
QPushButton *addButton = new QPushButton("+");
layout->addWidget(addButton, 1, 0);
connect(addButton, &QPushButton::clicked, this,
[this]()
{
// TODO: How to switch different suffixes according to different os
QString fileName =
QFileDialog::getOpenFileName(this,
tr("Load Plugin"),
QDir::currentPath(),
tr("*.dll;*.so;*.dylib"));

if (!QFileInfo::exists(fileName))
return;

// Copy to the plug-in directory
QFileInfo f(fileName);
QString newPath = _pluginsFolderPath + "/" + f.fileName();
QFile::copy(fileName, newPath);

PluginsManager* pluginsManager = PluginsManager::instance();
auto plugin = pluginsManager->loadPluginFromPath(newPath);
if (plugin == nullptr)
{
QFile::remove(newPath);
return;
}

QStandardItem *item = new QStandardItem(plugin->name());
item->setCheckable(true);
item->setCheckState(Qt::Unchecked);
_model->appendRow(item);

item->setData(newPath);

std::shared_ptr<NodeDelegateModelRegistry> reg = pluginsManager->registry();
plugin->registerDataModels(reg);
});

// // delete button
// QPushButton *deleteButton = new QPushButton("-", this);
// layout->addWidget(deleteButton, 1, 1);
// connect(deleteButton, &QPushButton::clicked, this,
// [this]()
// {
// for (int i = 0; i < _model->rowCount(); ++i)
// {
// QStandardItem* item = _model->item(i);
// if(item->checkState() == Qt::Checked)
// {
// PluginsManager* pluginsManager = PluginsManager::instance();

// if (pluginsManager->unloadPluginFromName(item->text()))
// {
// qDebug() << item->data().toString();
// if (QFile::remove(item->data().toString()))
// {
// _model->removeRow(i);
// }
// }
// }
// }
// });
}

PluginsManagerDlg::
~PluginsManagerDlg()
{
//
}

void
PluginsManagerDlg::
openPluginsFolder()
{
QDesktopServices::openUrl(QUrl::fromLocalFile(_pluginsFolderPath));
}

QString
PluginsManagerDlg::
pluginsFolderPath() const
{
return _pluginsFolderPath;
}

void
PluginsManagerDlg::
loadPluginsFromFolder()
{
PluginsManager* pluginsManager = PluginsManager::instance();
std::shared_ptr<NodeDelegateModelRegistry> registry = pluginsManager->registry();
pluginsManager->loadPlugins(_pluginsFolderPath);

for(auto l : pluginsManager->loaders())
{
PluginInterface* plugin = qobject_cast<PluginInterface*>(l.second->instance());
if (plugin == nullptr)
continue;

QStandardItem *item = new QStandardItem(plugin->name());
item->setCheckable(true);
item->setCheckState(Qt::Unchecked);
_model->appendRow(item);

item->setData(l.second->fileName());

plugin->registerDataModels(registry);
}
}
33 changes: 33 additions & 0 deletions examples/plugins_load/PluginsManagerDlg.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#pragma once

#include <QDialog>
#include <QStandardItemModel>

#include <QtNodes/PluginsManager>

using QtNodes::PluginsManager;

class PluginsManagerDlg : public QDialog
{
public:
PluginsManagerDlg(QWidget* parent = nullptr);

virtual
~PluginsManagerDlg();

public:
void
openPluginsFolder();

QString
pluginsFolderPath() const;

private:
void
loadPluginsFromFolder();

private:
QString _pluginsFolderPath;

QStandardItemModel* _model = nullptr;
};
48 changes: 16 additions & 32 deletions examples/plugins_load/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <QtNodes/NodeDelegateModelRegistry>
#include <QtNodes/PluginsManager>

#include "PluginsManagerDlg.hpp"

using QtNodes::DataFlowGraphicsScene;
using QtNodes::DataFlowGraphModel;
using QtNodes::GraphicsView;
Expand Down Expand Up @@ -37,50 +39,32 @@ main(int argc, char* argv[])
{
qSetMessagePattern(
"[%{time yyyyMMdd h:mm:ss.zzz}] [%{time process}] "
"[%{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-"
"fatal}F%{endif}]: %{message}\t| (%{function}) [%{file}:%{line}]");
"[%{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}"
"%{if-fatal}F%{endif}]: %{message}\t| (%{function}) [%{file}:%{line}]");

QApplication app(argc, argv);

setStyle();

PluginsManager* pluginsManager = PluginsManager::instance();
std::shared_ptr<NodeDelegateModelRegistry> registry = pluginsManager->registry();
pluginsManager->loadPlugins(R"(./nodes)");
for (auto plugin : pluginsManager->plugins())
{
plugin.second->registerDataModels(registry);
}

QWidget mainWidget;

// Load plugins and register models
PluginsManagerDlg pluginsManagerDlg(&mainWidget);

auto menuBar = new QMenuBar();
QMenu* menu = menuBar->addMenu("Plugins");
auto loadAction = menu->addAction("Load Plugin");
auto unloadAction = menu->addAction("Unload Plugin");

QObject::connect(loadAction, &QAction::triggered,
[&]()
{
// TODO: load plugins
QString fileName =
QFileDialog::getOpenFileName(nullptr,
"Load Plugin",
QDir::homePath());

if (!QFileInfo::exists(fileName))
return;

auto plugin = pluginsManager->loadPluginFromPath(fileName);
if (plugin)
{
plugin->registerDataModels(registry);
}
});
auto pluginsManagerAction = menu->addAction("Plugins Manager");
auto pluginsFloderAction = menu->addAction("Open Plugins Folder");

QObject::connect(pluginsManagerAction, &QAction::triggered,
&pluginsManagerDlg, &PluginsManagerDlg::exec);

QObject::connect(pluginsFloderAction, &QAction::triggered,
&pluginsManagerDlg, &PluginsManagerDlg::openPluginsFolder);

QVBoxLayout* l = new QVBoxLayout(&mainWidget);

DataFlowGraphModel dataFlowGraphModel(registry);
DataFlowGraphModel dataFlowGraphModel(PluginsManager::instance()->registry());

l->addWidget(menuBar);
auto scene = new DataFlowGraphicsScene(dataFlowGraphModel,
Expand Down
20 changes: 11 additions & 9 deletions include/QtNodes/internal/PluginsManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,34 +43,36 @@ class NODE_EDITOR_PUBLIC PluginsManager
PluginInterface*
loadPluginFromPath(const QString &filePath);

std::vector<PluginInterface*>
loadPluginFromPaths(const QStringList filePaths);

/**
* @brief Unload the plugin from the full file path
*
* @param filePath "C:/plugin_text.dll"
* @return int
* @return bool
*/
int
bool
unloadPluginFromPath(const QString &filePath);

/**
* @brief Uninstall a plugin by its name, not its file name
*
* @param pluginName "pluginText"
* @return int
* @return bool
*/
int
bool
unloadPluginFromName(const QString &pluginName);

inline
std::unordered_map<QString, PluginInterface*>
plugins()
{ return _plugins; };
std::unordered_map<QString, QPluginLoader*>
loaders()
{ return _loaders; };

private:
static PluginsManager* _instance;

std::unordered_map<QString, PluginInterface*> _plugins;
std::unordered_map<QString, QPluginLoader*> _loaders; ///< plugin path
std::unordered_map<QString, QPluginLoader*> _loaders; // plugin name

std::shared_ptr<NodeDelegateModelRegistry> _register;
};
Expand Down
Loading

0 comments on commit c60e4d4

Please sign in to comment.