diff --git a/examples/plugin_text/CMakeLists.txt b/examples/plugin_text/CMakeLists.txt index 480ed7b6..8443dd25 100644 --- a/examples/plugin_text/CMakeLists.txt +++ b/examples/plugin_text/CMakeLists.txt @@ -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) diff --git a/examples/plugins_load/PluginsManagerDlg.cpp b/examples/plugins_load/PluginsManagerDlg.cpp index 5ad1bb63..116d7888 100644 --- a/examples/plugins_load/PluginsManagerDlg.cpp +++ b/examples/plugins_load/PluginsManagerDlg.cpp @@ -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); @@ -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"), @@ -135,7 +134,9 @@ void PluginsManagerDlg::loadPluginsFromFolder() { PluginsManager *pluginsManager = PluginsManager::instance(); std::shared_ptr registry = pluginsManager->registry(); - pluginsManager->loadPlugins(_pluginsFolder.absolutePath()); + pluginsManager->loadPlugins(_pluginsFolder.absolutePath(), + QStringList() << "*.node" + << "*.data"); for (auto l : pluginsManager->loaders()) { PluginInterface *plugin = qobject_cast(l.second->instance()); diff --git a/include/QtNodes/internal/PluginsManager.hpp b/include/QtNodes/internal/PluginsManager.hpp index 8327019b..93342a37 100644 --- a/include/QtNodes/internal/PluginsManager.hpp +++ b/include/QtNodes/internal/PluginsManager.hpp @@ -23,7 +23,8 @@ class NODE_EDITOR_PUBLIC PluginsManager std::shared_ptr registry(); - void loadPlugins(const QString &folderPath = "./plugins"); + void loadPlugins(const QString &folderPath = "./plugins", + const QStringList &nameFilters = QStringList()); void unloadPlugins(); @@ -35,7 +36,8 @@ class NODE_EDITOR_PUBLIC PluginsManager */ PluginInterface *loadPluginFromPath(const QString &filePath); - std::vector loadPluginFromPaths(const QStringList filePaths); + std::vector loadPluginFromPaths(const QStringList filePaths, + const QStringList &nameFilters); /** * @brief Unload the plugin from the full file path diff --git a/src/PluginsManager.cpp b/src/PluginsManager.cpp index f92a4f82..7d7665b4 100644 --- a/src/PluginsManager.cpp +++ b/src/PluginsManager.cpp @@ -6,8 +6,13 @@ #include #include #include +#include #include +#if defined(Q_OS_WIN) +#include +#endif + namespace QtNodes { PluginsManager *PluginsManager::_instance = nullptr; @@ -40,7 +45,28 @@ std::shared_ptr 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)) { @@ -49,14 +75,36 @@ 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) + SetDllDirectory(folderPath.toStdWString().c_str()); +#endif + loadPluginFromPath(it.filePath()); + +#if defined(Q_OS_WIN) + SetDllDirectory(NULL); +#endif } } } @@ -72,12 +120,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(loader->instance()); @@ -105,12 +152,30 @@ PluginInterface *PluginsManager::loadPluginFromPath(const QString &filePath) return nullptr; } -std::vector PluginsManager::loadPluginFromPaths(const QStringList filePaths) +std::vector PluginsManager::loadPluginFromPaths(const QStringList filePaths, + const QStringList &nameFilters) { std::vector 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; }