Skip to content

Commit 55200a1

Browse files
committed
Add plug-in management dialog, delete plug-in map
1 parent 1d95057 commit 55200a1

File tree

8 files changed

+297
-88
lines changed

8 files changed

+297
-88
lines changed

examples/plugin_text/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
file(GLOB_RECURSE CPPS ./*.cpp)
22
file(GLOB_RECURSE HPPS ./*.hpp)
33

4+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/bin/Debug/nodes")
5+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/bin/Release/nodes")
6+
47
add_library(plugin_text SHARED ${CPPS} ${HPPS})
58

69
target_link_libraries(plugin_text QtNodes)

examples/plugin_text/PluginDefinition.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ Plugin::
88
Plugin()
99
{ _this_plugin = this; }
1010

11+
Plugin::
12+
~Plugin()
13+
{
14+
// TODO: Unregister all models here
15+
}
16+
1117
void
1218
Plugin::
1319
registerDataModels(std::shared_ptr<QtNodes::NodeDelegateModelRegistry> & reg)

examples/plugin_text/PluginDefinition.hpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,12 @@
55
#include <QtNodes/PluginInterface>
66

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

15-
using QtNodes::NodeDelegateModelRegistry;
16-
using QtNodes::PluginInterface;
17-
1814
#define PLUGIN_NAME "pluginText"
1915

2016
class DLL_EXPORT Plugin
@@ -27,6 +23,7 @@ class DLL_EXPORT Plugin
2723

2824
public:
2925
Plugin();
26+
~Plugin();
3027

3128
QString
3229
name() const override
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#include "PluginsManagerDlg.hpp"
2+
3+
#include <QTableView>
4+
#include <QPushButton>
5+
#include <QGridLayout>
6+
#include <QHeaderView>
7+
#include <QDir>
8+
#include <QFileDialog>
9+
#include <QDesktopServices>
10+
#include <QCoreApplication>
11+
12+
#include <QtNodes/NodeDelegateModelRegistry>
13+
#include <QtNodes/PluginInterface>
14+
15+
using QtNodes::NodeDelegateModelRegistry;
16+
using QtNodes::PluginInterface;
17+
18+
PluginsManagerDlg::
19+
PluginsManagerDlg(QWidget* parent)
20+
: QDialog(parent)
21+
{
22+
setMinimumSize(300, 250);
23+
24+
_pluginsFolder.setPath(QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + R"(./nodes)"));
25+
26+
QGridLayout *layout = new QGridLayout();
27+
setLayout(layout);
28+
29+
QTableView *pluginTable = new QTableView();
30+
pluginTable->setSelectionBehavior(QAbstractItemView::SelectRows);
31+
pluginTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
32+
pluginTable->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
33+
layout->addWidget(pluginTable, 0, 0, 1, 2);
34+
35+
_model = new QStandardItemModel(pluginTable);
36+
37+
_model->setColumnCount(2);
38+
_model->setHeaderData(0, Qt::Horizontal, "Name");
39+
_model->setHeaderData(1, Qt::Horizontal, "Version");
40+
pluginTable->setModel(_model);
41+
42+
loadPluginsFromFolder();
43+
44+
pluginTable->selectRow(0);
45+
46+
// add button
47+
QPushButton *addButton = new QPushButton("+");
48+
layout->addWidget(addButton, 1, 0);
49+
connect(addButton, &QPushButton::clicked, this,
50+
[this]()
51+
{
52+
// TODO: How to switch different suffixes according to different os
53+
QString fileName =
54+
QFileDialog::getOpenFileName(this,
55+
tr("Load Plugin"),
56+
QCoreApplication::applicationDirPath(),
57+
tr("*.dll;*.so;*.dylib"));
58+
59+
if (!QFileInfo::exists(fileName))
60+
return;
61+
62+
QFileInfo f(fileName);
63+
64+
QFileInfo newFile(
65+
QDir::cleanPath(_pluginsFolder.absolutePath() + QDir::separator() + f.fileName()));
66+
QString const newPath = newFile.absoluteFilePath();
67+
68+
if (f.absoluteFilePath() == newPath)
69+
return;
70+
71+
// Copy to the plug-in directory
72+
if (!QFile::copy(f.absoluteFilePath(), newPath))
73+
return;
74+
75+
PluginsManager* pluginsManager = PluginsManager::instance();
76+
auto plugin = pluginsManager->loadPluginFromPath(newPath);
77+
if (!plugin)
78+
{
79+
QFile::remove(newPath);
80+
return;
81+
}
82+
83+
QStandardItem *item = new QStandardItem(plugin->name());
84+
item->setData(newPath);
85+
_model->appendRow(item);
86+
87+
std::shared_ptr<NodeDelegateModelRegistry> reg = pluginsManager->registry();
88+
plugin->registerDataModels(reg);
89+
});
90+
91+
// delete button
92+
QPushButton *deleteButton = new QPushButton("-", this);
93+
layout->addWidget(deleteButton, 1, 1);
94+
connect(deleteButton,
95+
&QPushButton::clicked,
96+
this,
97+
[this, pluginTable]()
98+
{
99+
QItemSelectionModel *selectionModel = pluginTable->selectionModel();
100+
101+
int row = selectionModel->currentIndex().row();
102+
103+
while (selectionModel->selectedRows().count() > 0)
104+
{
105+
auto rowIdx = selectionModel->selectedRows().first();
106+
row = std::min(row, rowIdx.row());
107+
108+
QStandardItem *item = _model->itemFromIndex(rowIdx);
109+
110+
PluginsManager *pluginsManager = PluginsManager::instance();
111+
112+
// FIXME: Unload plugin successfully, but cannot delete the plugin file
113+
if (!pluginsManager->unloadPluginFromName(item->text()) ||
114+
!QFile::remove(item->data().toString()))
115+
{
116+
selectionModel->select(rowIdx, QItemSelectionModel::Deselect);
117+
continue;
118+
}
119+
120+
_model->removeRow(rowIdx.row());
121+
}
122+
123+
pluginTable->selectRow(row);
124+
});
125+
}
126+
127+
PluginsManagerDlg::
128+
~PluginsManagerDlg()
129+
{
130+
//
131+
}
132+
133+
void
134+
PluginsManagerDlg::
135+
openPluginsFolder()
136+
{
137+
// QDesktopServices::openUrl(QUrl::fromLocalFile(_pluginsFolderPath));
138+
QDesktopServices::openUrl(QUrl(_pluginsFolder.absolutePath()));
139+
}
140+
141+
QString
142+
PluginsManagerDlg::
143+
pluginsFolderPath() const
144+
{
145+
return _pluginsFolder.absolutePath();
146+
}
147+
148+
void
149+
PluginsManagerDlg::
150+
loadPluginsFromFolder()
151+
{
152+
PluginsManager* pluginsManager = PluginsManager::instance();
153+
std::shared_ptr<NodeDelegateModelRegistry> registry = pluginsManager->registry();
154+
pluginsManager->loadPlugins(_pluginsFolder.absolutePath());
155+
156+
for(auto l : pluginsManager->loaders())
157+
{
158+
PluginInterface* plugin = qobject_cast<PluginInterface*>(l.second->instance());
159+
if (!plugin)
160+
continue;
161+
162+
QStandardItem *item = new QStandardItem(plugin->name());
163+
item->setData(l.second->fileName());
164+
_model->appendRow(item);
165+
166+
plugin->registerDataModels(registry);
167+
}
168+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#pragma once
2+
3+
#include <QDir>
4+
#include <QDialog>
5+
#include <QStandardItemModel>
6+
7+
#include <QtNodes/PluginsManager>
8+
9+
using QtNodes::PluginsManager;
10+
11+
class PluginsManagerDlg : public QDialog
12+
{
13+
public:
14+
PluginsManagerDlg(QWidget* parent = nullptr);
15+
16+
virtual
17+
~PluginsManagerDlg();
18+
19+
public:
20+
void
21+
openPluginsFolder();
22+
23+
QString
24+
pluginsFolderPath() const;
25+
26+
private:
27+
void
28+
loadPluginsFromFolder();
29+
30+
private:
31+
QDir _pluginsFolder;
32+
33+
QStandardItemModel* _model = nullptr;
34+
};

examples/plugins_load/main.cpp

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <QtNodes/NodeDelegateModelRegistry>
1111
#include <QtNodes/PluginsManager>
1212

13+
#include "PluginsManagerDlg.hpp"
14+
1315
using QtNodes::DataFlowGraphicsScene;
1416
using QtNodes::DataFlowGraphModel;
1517
using QtNodes::GraphicsView;
@@ -37,50 +39,32 @@ main(int argc, char* argv[])
3739
{
3840
qSetMessagePattern(
3941
"[%{time yyyyMMdd h:mm:ss.zzz}] [%{time process}] "
40-
"[%{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-"
41-
"fatal}F%{endif}]: %{message}\t| (%{function}) [%{file}:%{line}]");
42+
"[%{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}"
43+
"%{if-fatal}F%{endif}]: %{message}\t| (%{function}) [%{file}:%{line}]");
4244

4345
QApplication app(argc, argv);
4446

4547
setStyle();
4648

47-
PluginsManager* pluginsManager = PluginsManager::instance();
48-
std::shared_ptr<NodeDelegateModelRegistry> registry = pluginsManager->registry();
49-
pluginsManager->loadPlugins(R"(./nodes)");
50-
for (auto plugin : pluginsManager->plugins())
51-
{
52-
plugin.second->registerDataModels(registry);
53-
}
54-
5549
QWidget mainWidget;
5650

51+
// Load plugins and register models
52+
PluginsManagerDlg pluginsManagerDlg(&mainWidget);
53+
5754
auto menuBar = new QMenuBar();
5855
QMenu* menu = menuBar->addMenu("Plugins");
59-
auto loadAction = menu->addAction("Load Plugin");
60-
auto unloadAction = menu->addAction("Unload Plugin");
61-
62-
QObject::connect(loadAction, &QAction::triggered,
63-
[&]()
64-
{
65-
// TODO: load plugins
66-
QString fileName =
67-
QFileDialog::getOpenFileName(nullptr,
68-
"Load Plugin",
69-
QDir::homePath());
70-
71-
if (!QFileInfo::exists(fileName))
72-
return;
73-
74-
auto plugin = pluginsManager->loadPluginFromPath(fileName);
75-
if (plugin)
76-
{
77-
plugin->registerDataModels(registry);
78-
}
79-
});
56+
auto pluginsManagerAction = menu->addAction("Plugins Manager");
57+
auto pluginsFloderAction = menu->addAction("Open Plugins Folder");
58+
59+
QObject::connect(pluginsManagerAction, &QAction::triggered,
60+
&pluginsManagerDlg, &PluginsManagerDlg::exec);
61+
62+
QObject::connect(pluginsFloderAction, &QAction::triggered,
63+
&pluginsManagerDlg, &PluginsManagerDlg::openPluginsFolder);
8064

8165
QVBoxLayout* l = new QVBoxLayout(&mainWidget);
8266

83-
DataFlowGraphModel dataFlowGraphModel(registry);
67+
DataFlowGraphModel dataFlowGraphModel(PluginsManager::instance()->registry());
8468

8569
l->addWidget(menuBar);
8670
auto scene = new DataFlowGraphicsScene(dataFlowGraphModel,

include/QtNodes/internal/PluginsManager.hpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,34 +43,36 @@ class NODE_EDITOR_PUBLIC PluginsManager
4343
PluginInterface*
4444
loadPluginFromPath(const QString &filePath);
4545

46+
std::vector<PluginInterface*>
47+
loadPluginFromPaths(const QStringList filePaths);
48+
4649
/**
4750
* @brief Unload the plugin from the full file path
4851
*
4952
* @param filePath "C:/plugin_text.dll"
50-
* @return int
53+
* @return bool
5154
*/
52-
int
55+
bool
5356
unloadPluginFromPath(const QString &filePath);
5457

5558
/**
5659
* @brief Uninstall a plugin by its name, not its file name
5760
*
5861
* @param pluginName "pluginText"
59-
* @return int
62+
* @return bool
6063
*/
61-
int
64+
bool
6265
unloadPluginFromName(const QString &pluginName);
6366

6467
inline
65-
std::unordered_map<QString, PluginInterface*>
66-
plugins()
67-
{ return _plugins; };
68+
std::unordered_map<QString, QPluginLoader*>
69+
loaders()
70+
{ return _loaders; };
6871

6972
private:
7073
static PluginsManager* _instance;
7174

72-
std::unordered_map<QString, PluginInterface*> _plugins;
73-
std::unordered_map<QString, QPluginLoader*> _loaders; ///< plugin path
75+
std::unordered_map<QString, QPluginLoader*> _loaders; // plugin name
7476

7577
std::shared_ptr<NodeDelegateModelRegistry> _register;
7678
};

0 commit comments

Comments
 (0)