Skip to content

Commit

Permalink
Support for filtering specified suffixes
Browse files Browse the repository at this point in the history
  • Loading branch information
zmoth committed Feb 17, 2023
1 parent 4a74b36 commit 65a9f44
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 24 deletions.
10 changes: 5 additions & 5 deletions examples/plugin_text/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
foreach(OUTPUT_TYPES ${CMAKE_CONFIGURATION_TYPES})
string(TOUPPER ${OUTPUT_TYPES} OUTPUT_CONFIG)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}/plugins)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}/plugins)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}/plugins)
# message(STATUS "CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} : ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}")
string(TOUPPER ${OUTPUT_TYPES} OUTPUT_CONFIG)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}/plugins/text)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}/plugins/text)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}/plugins/text)
# message(STATUS "CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG} : ${CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUT_CONFIG}}")
endforeach(OUTPUT_TYPES CMAKE_CONFIGURATION_TYPES)

file(GLOB_RECURSE CPPS ./*.cpp)
Expand Down
9 changes: 5 additions & 4 deletions examples/plugins_load/PluginsManagerDlg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ PluginsManagerDlg::PluginsManagerDlg(QWidget *parent)
{
setMinimumSize(300, 250);

_pluginsFolder.setPath(QDir::cleanPath(QCoreApplication::applicationDirPath()
+ QDir::separator() + R"(./plugins)"));
_pluginsFolder.setPath(
QDir::cleanPath(QCoreApplication::applicationDirPath() + QDir::separator() + "plugins"));

QGridLayout *layout = new QGridLayout();
setLayout(layout);
Expand All @@ -47,7 +47,6 @@ PluginsManagerDlg::PluginsManagerDlg(QWidget *parent)
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"),
Expand Down Expand Up @@ -135,7 +134,9 @@ void PluginsManagerDlg::loadPluginsFromFolder()
{
PluginsManager *pluginsManager = PluginsManager::instance();
std::shared_ptr<NodeDelegateModelRegistry> registry = pluginsManager->registry();
pluginsManager->loadPlugins(_pluginsFolder.absolutePath());
pluginsManager->loadPlugins(_pluginsFolder.absolutePath(),
QStringList() << "*.node"
<< "*.data");

for (auto l : pluginsManager->loaders()) {
PluginInterface *plugin = qobject_cast<PluginInterface *>(l.second->instance());
Expand Down
6 changes: 4 additions & 2 deletions include/QtNodes/internal/PluginsManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ class NODE_EDITOR_PUBLIC PluginsManager

std::shared_ptr<NodeDelegateModelRegistry> registry();

void loadPlugins(const QString &folderPath = "./plugins");
void loadPlugins(const QString &folderPath = "./plugins",
const QStringList &nameFilters = QStringList());

void unloadPlugins();

Expand All @@ -35,7 +36,8 @@ class NODE_EDITOR_PUBLIC PluginsManager
*/
PluginInterface *loadPluginFromPath(const QString &filePath);

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

/**
* @brief Unload the plugin from the full file path
Expand Down
95 changes: 82 additions & 13 deletions src/PluginsManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@
#include <utility>
#include <QDebug>
#include <QDir>
#include <QDirIterator>
#include <QPluginLoader>

#if defined(Q_OS_WIN)
#include <Windows.h>
#endif

namespace QtNodes {

PluginsManager *PluginsManager::_instance = nullptr;
Expand Down Expand Up @@ -40,7 +45,28 @@ std::shared_ptr<NodeDelegateModelRegistry> PluginsManager::registry()
return _register;
}

void PluginsManager::loadPlugins(const QString &folderPath)
/**
* @brief Recursively loads all plugins with the specified suffix according to the folder path.
* If no suffix is specified then the choice is up to the OS. For example, Windows OS selects `*.dll`
*
* ```
* │ plugins_load
* │ QtNodes.dll
* │
* └─plugins
* │
* └─text
* plugin_text.node
* text_dependent.dll
* ```
* @TODO: Currently only tested and passed under windows, is there a solution for Qt for all three platforms?
* 1. `plugins_Load` can successfully load `plugin_text.node`
* 2. After changing the folder name `text` it still loads successfully
*
* @param folderPath
* @param nameFilters
*/
void PluginsManager::loadPlugins(const QString &folderPath, const QStringList &nameFilters)
{
QDir pluginsDir;
if (!pluginsDir.exists(folderPath)) {
Expand All @@ -49,14 +75,40 @@ void PluginsManager::loadPlugins(const QString &folderPath)
}
pluginsDir.cd(folderPath);

QFileInfoList pluginsInfo = pluginsDir.entryInfoList(QDir::Dirs | QDir::Files
| QDir::NoDotAndDotDot | QDir::Hidden);
auto IsLibrary = [](const QFileInfo f, const QStringList &nameFilters) {
if (!f.isFile())
return false;

if (nameFilters.isEmpty())
return QLibrary::isLibrary(f.absoluteFilePath());

for (QFileInfo fileInfo : pluginsInfo) {
if (fileInfo.isFile()) {
loadPluginFromPath(fileInfo.absoluteFilePath());
} else {
loadPlugins(fileInfo.absoluteFilePath());
for (auto s : nameFilters) {
if (s.endsWith(f.suffix(), Qt::CaseInsensitive))
return true;
}
return false;
};

QDirIterator it(pluginsDir.path(),
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden);
while (it.hasNext()) {
it.next();
QFileInfo f = it.fileInfo();
if (f.isDir()) {
loadPlugins(it.filePath(), nameFilters);
} else if (f.isFile() && IsLibrary(f, nameFilters)) {
#if defined(Q_OS_WIN)
#ifdef UNICODE
SetDllDirectory(folderPath.toStdWString().c_str());
#else
SetDllDirectory(folderPath.toStdString().c_str());
#endif // !UNICODE
#endif
loadPluginFromPath(it.filePath());

#if defined(Q_OS_WIN)
SetDllDirectory(NULL);
#endif
}
}
}
Expand All @@ -72,12 +124,11 @@ void PluginsManager::unloadPlugins()

PluginInterface *PluginsManager::loadPluginFromPath(const QString &filePath)
{
// if (!QLibrary::isLibrary(filePath))
// return nullptr;
qInfo() << " >> " << filePath;

QPluginLoader *loader = new QPluginLoader(filePath);

qDebug() << loader->metaData();
// qDebug() << loader->metaData();

if (loader->isLoaded()) {
PluginInterface *plugin = qobject_cast<PluginInterface *>(loader->instance());
Expand Down Expand Up @@ -105,12 +156,30 @@ PluginInterface *PluginsManager::loadPluginFromPath(const QString &filePath)
return nullptr;
}

std::vector<PluginInterface *> PluginsManager::loadPluginFromPaths(const QStringList filePaths)
std::vector<PluginInterface *> PluginsManager::loadPluginFromPaths(const QStringList filePaths,
const QStringList &nameFilters)
{
std::vector<PluginInterface *> vecPlugins;
vecPlugins.clear();

auto IsLibrary = [](const QFileInfo f, const QStringList &nameFilters) {
if (!f.isFile())
return false;

if (nameFilters.isEmpty())
return QLibrary::isLibrary(f.absoluteFilePath());

for (auto nf : nameFilters) {
if (nf.endsWith(f.suffix(), Qt::CaseInsensitive))
return true;
}
return false;
};

for (auto path : filePaths) {
vecPlugins.push_back(loadPluginFromPath(path));
QFileInfo f(path);
if (IsLibrary(f, nameFilters))
vecPlugins.push_back(loadPluginFromPath(path));
}
return vecPlugins;
}
Expand Down

0 comments on commit 65a9f44

Please sign in to comment.