@@ -1,80 +1,89 | |||||
1 | /*------------------------------------------------------------------------------ |
|
1 | /*------------------------------------------------------------------------------ | |
2 | -- This file is a part of the QLop Software |
|
2 | -- This file is a part of the QLop Software | |
3 | -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS |
|
3 | -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS | |
4 | -- |
|
4 | -- | |
5 | -- This program is free software; you can redistribute it and/or modify |
|
5 | -- This program is free software; you can redistribute it and/or modify | |
6 | -- it under the terms of the GNU General Public License as published by |
|
6 | -- it under the terms of the GNU General Public License as published by | |
7 | -- the Free Software Foundation; either version 2 of the License, or |
|
7 | -- the Free Software Foundation; either version 2 of the License, or | |
8 | -- (at your option) any later version. |
|
8 | -- (at your option) any later version. | |
9 | -- |
|
9 | -- | |
10 | -- This program is distributed in the hope that it will be useful, |
|
10 | -- This program is distributed in the hope that it will be useful, | |
11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | -- GNU General Public License for more details. |
|
13 | -- GNU General Public License for more details. | |
14 | -- |
|
14 | -- | |
15 | -- You should have received a copy of the GNU General Public License |
|
15 | -- You should have received a copy of the GNU General Public License | |
16 | -- along with this program; if not, write to the Free Software |
|
16 | -- along with this program; if not, write to the Free Software | |
17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 | -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | -------------------------------------------------------------------------------*/ |
|
18 | -------------------------------------------------------------------------------*/ | |
19 | /*-- Author : Alexis Jeandet |
|
19 | /*-- Author : Alexis Jeandet | |
20 | -- Mail : alexis.jeandet@member.fsf.org |
|
20 | -- Mail : alexis.jeandet@member.fsf.org | |
21 | ----------------------------------------------------------------------------*/ |
|
21 | ----------------------------------------------------------------------------*/ | |
22 | #include "MainWindow.h" |
|
22 | #include "MainWindow.h" | |
23 | #include <QProcessEnvironment> |
|
23 | #include <QProcessEnvironment> | |
24 | #include <QThread> |
|
24 | #include <QThread> | |
25 | #include <SqpApplication.h> |
|
25 | #include <SqpApplication.h> | |
26 | #include <qglobal.h> |
|
26 | #include <qglobal.h> | |
27 |
|
27 | |||
|
28 | #include <QtPlugin> | |||
28 | #include <Plugin/PluginManager.h> |
|
29 | #include <Plugin/PluginManager.h> | |
29 | #include <QDir> |
|
30 | #include <QDir> | |
30 |
|
31 | |||
31 | #include <QLoggingCategory> |
|
32 | #include <QLoggingCategory> | |
32 |
|
33 | |||
33 | Q_LOGGING_CATEGORY(LOG_Main, "Main") |
|
34 | Q_LOGGING_CATEGORY(LOG_Main, "Main") | |
34 |
|
35 | |||
35 | namespace { |
|
36 | namespace { | |
36 |
|
37 | |||
37 | const auto PLUGIN_DIRECTORY_NAME = QStringLiteral("plugins"); |
|
38 | const auto PLUGIN_DIRECTORY_NAME = QStringLiteral("plugins"); | |
38 |
|
39 | |||
39 |
|
40 | |||
40 | } // namespace |
|
41 | } // namespace | |
41 |
|
42 | |||
42 | int main(int argc, char *argv[]) |
|
43 | int main(int argc, char *argv[]) | |
43 | { |
|
44 | { | |
|
45 | #ifdef QT_STATICPLUGIN | |||
|
46 | Q_IMPORT_PLUGIN(MockPlugin) | |||
|
47 | Q_IMPORT_PLUGIN(AmdaPlugin) | |||
|
48 | Q_INIT_RESOURCE(amdaresources); | |||
|
49 | #endif | |||
|
50 | Q_INIT_RESOURCE(sqpguiresources); | |||
|
51 | ||||
44 | SqpApplication a{argc, argv}; |
|
52 | SqpApplication a{argc, argv}; | |
45 | SqpApplication::setOrganizationName("LPP"); |
|
53 | SqpApplication::setOrganizationName("LPP"); | |
46 | SqpApplication::setOrganizationDomain("lpp.fr"); |
|
54 | SqpApplication::setOrganizationDomain("lpp.fr"); | |
47 | SqpApplication::setApplicationName("SciQLop"); |
|
55 | SqpApplication::setApplicationName("SciQLop"); | |
48 | MainWindow w; |
|
56 | MainWindow w; | |
49 | w.show(); |
|
57 | w.show(); | |
50 |
|
58 | |||
51 | // Loads plugins |
|
59 | // Loads plugins | |
52 | auto pluginDir = QDir{a.applicationDirPath()}; |
|
60 | auto pluginDir = QDir{a.applicationDirPath()}; | |
53 | auto pluginLookupPath = { |
|
61 | auto pluginLookupPath = { | |
54 | a.applicationDirPath(), |
|
62 | a.applicationDirPath(), | |
55 | a.applicationDirPath() + "/" + PLUGIN_DIRECTORY_NAME, |
|
63 | a.applicationDirPath() + "/" + PLUGIN_DIRECTORY_NAME, | |
56 | a.applicationDirPath() + "/../lib64/SciQlop", |
|
64 | a.applicationDirPath() + "/../lib64/SciQlop", | |
57 | a.applicationDirPath() + "/../lib64/sciqlop", |
|
65 | a.applicationDirPath() + "/../lib64/sciqlop", | |
58 | a.applicationDirPath() + "/../lib/SciQlop", |
|
66 | a.applicationDirPath() + "/../lib/SciQlop", | |
59 | a.applicationDirPath() + "/../lib/sciqlop", |
|
67 | a.applicationDirPath() + "/../lib/sciqlop", | |
60 | a.applicationDirPath() + "/../plugins", |
|
68 | a.applicationDirPath() + "/../plugins", | |
61 | }; |
|
69 | }; | |
62 |
|
70 | |||
63 | #if _WIN32 || _WIN64 |
|
71 | #if _WIN32 || _WIN64 | |
64 | pluginDir.mkdir(PLUGIN_DIRECTORY_NAME); |
|
72 | pluginDir.mkdir(PLUGIN_DIRECTORY_NAME); | |
65 | pluginDir.cd(PLUGIN_DIRECTORY_NAME); |
|
73 | pluginDir.cd(PLUGIN_DIRECTORY_NAME); | |
66 | #endif |
|
74 | #endif | |
67 |
|
75 | |||
68 | PluginManager pluginManager{}; |
|
76 | PluginManager pluginManager{}; | |
69 |
|
77 | |||
70 | for (auto &&path : pluginLookupPath) { |
|
78 | for (auto &&path : pluginLookupPath) { | |
71 | QDir directory{path}; |
|
79 | QDir directory{path}; | |
72 | if (directory.exists()) { |
|
80 | if (directory.exists()) { | |
73 | qCDebug(LOG_Main()) |
|
81 | qCDebug(LOG_Main()) | |
74 | << QObject::tr("Plugin directory: %1").arg(directory.absolutePath()); |
|
82 | << QObject::tr("Plugin directory: %1").arg(directory.absolutePath()); | |
75 | pluginManager.loadPlugins(directory); |
|
83 | pluginManager.loadPlugins(directory); | |
76 | } |
|
84 | } | |
77 | } |
|
85 | } | |
|
86 | pluginManager.loadStaticPlugins(); | |||
78 |
|
87 | |||
79 | return a.exec(); |
|
88 | return a.exec(); | |
80 | } |
|
89 | } |
@@ -1,36 +1,41 | |||||
1 | #ifndef SCIQLOP_PLUGINMANAGER_H |
|
1 | #ifndef SCIQLOP_PLUGINMANAGER_H | |
2 | #define SCIQLOP_PLUGINMANAGER_H |
|
2 | #define SCIQLOP_PLUGINMANAGER_H | |
3 |
|
3 | |||
4 | #include "CoreGlobal.h" |
|
4 | #include "CoreGlobal.h" | |
5 |
|
5 | |||
6 | #include <Common/spimpl.h> |
|
6 | #include <Common/spimpl.h> | |
7 |
|
7 | |||
8 | #include <QLoggingCategory> |
|
8 | #include <QLoggingCategory> | |
9 |
|
9 | |||
10 | class QDir; |
|
10 | class QDir; | |
11 |
|
11 | |||
12 | Q_DECLARE_LOGGING_CATEGORY(LOG_PluginManager) |
|
12 | Q_DECLARE_LOGGING_CATEGORY(LOG_PluginManager) | |
13 |
|
13 | |||
14 | /** |
|
14 | /** | |
15 | * @brief The PluginManager class aims to handle the plugins loaded dynamically into SciQLop. |
|
15 | * @brief The PluginManager class aims to handle the plugins loaded dynamically into SciQLop. | |
16 | */ |
|
16 | */ | |
17 | class SCIQLOP_CORE_EXPORT PluginManager { |
|
17 | class SCIQLOP_CORE_EXPORT PluginManager { | |
18 | public: |
|
18 | public: | |
19 | explicit PluginManager(); |
|
19 | explicit PluginManager(); | |
20 |
|
20 | |||
21 | /** |
|
21 | /** | |
22 | * Loads plugins into SciQlop. The loaded plugins are those located in the directory passed in |
|
22 | * Loads plugins into SciQlop. The loaded plugins are those located in the directory passed in | |
23 | * parameter |
|
23 | * parameter | |
24 | * @param pluginDir the directory containing the plugins |
|
24 | * @param pluginDir the directory containing the plugins | |
25 | */ |
|
25 | */ | |
26 | void loadPlugins(const QDir &pluginDir); |
|
26 | void loadPlugins(const QDir &pluginDir); | |
27 |
|
27 | |||
|
28 | /** | |||
|
29 | * Loads static plugins into SciQlop. SciQLOP supports statically linked plugins. | |||
|
30 | */ | |||
|
31 | void loadStaticPlugins(); | |||
|
32 | ||||
28 | /// @returns the number of plugins loaded |
|
33 | /// @returns the number of plugins loaded | |
29 | int nbPluginsLoaded() const noexcept; |
|
34 | int nbPluginsLoaded() const noexcept; | |
30 |
|
35 | |||
31 | private: |
|
36 | private: | |
32 |
|
|
37 | struct PluginManagerPrivate; | |
33 | spimpl::unique_impl_ptr<PluginManagerPrivate> impl; |
|
38 | spimpl::unique_impl_ptr<PluginManagerPrivate> impl; | |
34 | }; |
|
39 | }; | |
35 |
|
40 | |||
36 | #endif // SCIQLOP_PLUGINMANAGER_H |
|
41 | #endif // SCIQLOP_PLUGINMANAGER_H |
@@ -1,124 +1,138 | |||||
1 | #include <Plugin/PluginManager.h> |
|
1 | #include <Plugin/PluginManager.h> | |
2 |
|
2 | |||
3 | #include <Plugin/IPlugin.h> |
|
3 | #include <Plugin/IPlugin.h> | |
4 |
|
4 | |||
5 | #include <QDir> |
|
5 | #include <QDir> | |
6 | #include <QLibrary> |
|
6 | #include <QLibrary> | |
7 | #include <QPluginLoader> |
|
7 | #include <QPluginLoader> | |
8 |
|
8 | |||
9 | Q_LOGGING_CATEGORY(LOG_PluginManager, "PluginManager") |
|
9 | Q_LOGGING_CATEGORY(LOG_PluginManager, "PluginManager") | |
10 |
|
10 | |||
11 | namespace { |
|
11 | namespace { | |
12 |
|
12 | |||
13 | /// Key for retrieving metadata of the plugin |
|
13 | /// Key for retrieving metadata of the plugin | |
14 | const auto PLUGIN_METADATA_KEY = QStringLiteral("MetaData"); |
|
14 | const auto PLUGIN_METADATA_KEY = QStringLiteral("MetaData"); | |
15 |
|
15 | |||
16 | /// Key for retrieving the name of the plugin in its metadata |
|
16 | /// Key for retrieving the name of the plugin in its metadata | |
17 | const auto PLUGIN_NAME_KEY = QStringLiteral("name"); |
|
17 | const auto PLUGIN_NAME_KEY = QStringLiteral("name"); | |
18 |
|
18 | |||
19 | /// Helper to state the plugin loading operation |
|
19 | /// Helper to state the plugin loading operation | |
20 | struct LoadPluginState { |
|
20 | struct LoadPluginState { | |
21 | explicit LoadPluginState(const QString &pluginPath) |
|
21 | explicit LoadPluginState(const QString &pluginPath) | |
22 | : m_PluginPath{pluginPath}, m_Valid{true}, m_ErrorMessage{} |
|
22 | : m_PluginPath{pluginPath}, m_Valid{true}, m_ErrorMessage{} | |
23 | { |
|
23 | { | |
24 | } |
|
24 | } | |
25 |
|
25 | |||
26 | void log() const |
|
26 | void log() const | |
27 | { |
|
27 | { | |
28 | if (m_Valid) { |
|
28 | if (m_Valid) { | |
29 | qCDebug(LOG_PluginManager()) |
|
29 | qCDebug(LOG_PluginManager()) | |
30 | << QObject::tr("File '%1' has been loaded as a plugin").arg(m_PluginPath); |
|
30 | << QObject::tr("File '%1' has been loaded as a plugin").arg(m_PluginPath); | |
31 | } |
|
31 | } | |
32 | else { |
|
32 | else { | |
33 | qCWarning(LOG_PluginManager()) |
|
33 | qCWarning(LOG_PluginManager()) | |
34 | << QObject::tr("File '%1' can't be loaded as a plugin: %2") |
|
34 | << QObject::tr("File '%1' can't be loaded as a plugin: %2") | |
35 | .arg(m_PluginPath) |
|
35 | .arg(m_PluginPath) | |
36 | .arg(m_ErrorMessage); |
|
36 | .arg(m_ErrorMessage); | |
37 | } |
|
37 | } | |
38 | } |
|
38 | } | |
39 |
|
39 | |||
40 | void setError(const QString &errorMessage) |
|
40 | void setError(const QString &errorMessage) | |
41 | { |
|
41 | { | |
42 | m_Valid = false; |
|
42 | m_Valid = false; | |
43 | m_ErrorMessage = errorMessage; |
|
43 | m_ErrorMessage = errorMessage; | |
44 | } |
|
44 | } | |
45 |
|
45 | |||
46 | QString m_PluginPath; |
|
46 | QString m_PluginPath; | |
47 | bool m_Valid; |
|
47 | bool m_Valid; | |
48 | QString m_ErrorMessage; |
|
48 | QString m_ErrorMessage; | |
49 | }; |
|
49 | }; | |
50 |
|
50 | |||
51 | } // namespace |
|
51 | } // namespace | |
52 |
|
52 | |||
53 | struct PluginManager::PluginManagerPrivate { |
|
53 | struct PluginManager::PluginManagerPrivate { | |
54 | /** |
|
54 | /** | |
55 | * Loads a single plugin into SciQlop. The method has no effect if the plugin is malformed (e.g. |
|
55 | * Loads a single plugin into SciQlop. The method has no effect if the plugin is malformed (e.g. | |
56 | * wrong library type, missing metadata, etc.) |
|
56 | * wrong library type, missing metadata, etc.) | |
57 | * @param pluginPath the path to the plugin library. |
|
57 | * @param pluginPath the path to the plugin library. | |
58 | */ |
|
58 | */ | |
59 | void loadPlugin(const QString &pluginPath) |
|
59 | void loadPlugin(const QString &pluginPath) | |
60 | { |
|
60 | { | |
61 | qCDebug(LOG_PluginManager()) |
|
61 | qCDebug(LOG_PluginManager()) | |
62 | << QObject::tr("Attempting to load file '%1' as a plugin").arg(pluginPath); |
|
62 | << QObject::tr("Attempting to load file '%1' as a plugin").arg(pluginPath); | |
63 |
|
63 | |||
64 | LoadPluginState loadState{pluginPath}; |
|
64 | LoadPluginState loadState{pluginPath}; | |
65 |
|
65 | |||
66 | if (QLibrary::isLibrary(pluginPath)) { |
|
66 | if (QLibrary::isLibrary(pluginPath)) { | |
67 | QPluginLoader pluginLoader{pluginPath}; |
|
67 | QPluginLoader pluginLoader{pluginPath}; | |
68 |
|
68 | |||
69 | // Retrieving the plugin name to check if it can be loaded (i.e. no plugin with the same |
|
69 | // Retrieving the plugin name to check if it can be loaded (i.e. no plugin with the same | |
70 | // name has been registered yet) |
|
70 | // name has been registered yet) | |
71 | auto metadata = pluginLoader.metaData().value(PLUGIN_METADATA_KEY).toObject(); |
|
71 | auto metadata = pluginLoader.metaData().value(PLUGIN_METADATA_KEY).toObject(); | |
72 | auto pluginName = metadata.value(PLUGIN_NAME_KEY).toString(); |
|
72 | auto pluginName = metadata.value(PLUGIN_NAME_KEY).toString(); | |
73 |
|
73 | |||
74 | if (pluginName.isEmpty()) { |
|
74 | if (pluginName.isEmpty()) { | |
75 | loadState.setError(QObject::tr("empty file name")); |
|
75 | loadState.setError(QObject::tr("empty file name")); | |
76 | } |
|
76 | } | |
77 | else if (m_RegisteredPlugins.contains(pluginName)) { |
|
77 | else if (m_RegisteredPlugins.contains(pluginName)) { | |
78 | loadState.setError(QObject::tr("name '%1' already registered").arg(pluginName)); |
|
78 | loadState.setError(QObject::tr("name '%1' already registered").arg(pluginName)); | |
79 | } |
|
79 | } | |
80 | else { |
|
80 | else { | |
81 | if (auto pluginInstance = qobject_cast<IPlugin *>(pluginLoader.instance())) { |
|
81 | if (auto pluginInstance = qobject_cast<IPlugin *>(pluginLoader.instance())) { | |
82 | pluginInstance->initialize(); |
|
82 | pluginInstance->initialize(); | |
83 | m_RegisteredPlugins.insert(pluginName, pluginPath); |
|
83 | m_RegisteredPlugins.insert(pluginName, pluginPath); | |
84 | } |
|
84 | } | |
85 | else { |
|
85 | else { | |
86 | loadState.setError(QObject::tr("the file is not a Sciqlop plugin")); |
|
86 | loadState.setError(QObject::tr("the file is not a Sciqlop plugin")); | |
87 | } |
|
87 | } | |
88 | } |
|
88 | } | |
89 | } |
|
89 | } | |
90 | else { |
|
90 | else { | |
91 | loadState.setError(QObject::tr("the file is not a library")); |
|
91 | loadState.setError(QObject::tr("the file is not a library")); | |
92 | } |
|
92 | } | |
93 |
|
93 | |||
94 | // Log loading result |
|
94 | // Log loading result | |
95 | loadState.log(); |
|
95 | loadState.log(); | |
96 | } |
|
96 | } | |
97 |
|
97 | |||
|
98 | void loadStaticPlugins() | |||
|
99 | { | |||
|
100 | for (QObject *plugin : QPluginLoader::staticInstances()) | |||
|
101 | { | |||
|
102 | qobject_cast<IPlugin *>(plugin)->initialize(); | |||
|
103 | m_RegisteredPlugins.insert(plugin->metaObject()->className(), "StaticPlugin"); | |||
|
104 | } | |||
|
105 | } | |||
|
106 | ||||
98 | /// Registered plugins (key: plugin name, value: plugin path) |
|
107 | /// Registered plugins (key: plugin name, value: plugin path) | |
99 | QHash<QString, QString> m_RegisteredPlugins; |
|
108 | QHash<QString, QString> m_RegisteredPlugins; | |
100 | }; |
|
109 | }; | |
101 |
|
110 | |||
102 | PluginManager::PluginManager() : impl{spimpl::make_unique_impl<PluginManagerPrivate>()} |
|
111 | PluginManager::PluginManager() : impl{spimpl::make_unique_impl<PluginManagerPrivate>()} | |
103 | { |
|
112 | { | |
104 | } |
|
113 | } | |
105 |
|
114 | |||
106 | void PluginManager::loadPlugins(const QDir &pluginDir) |
|
115 | void PluginManager::loadPlugins(const QDir &pluginDir) | |
107 | { |
|
116 | { | |
108 | // Load plugins |
|
117 | // Load plugins | |
109 | auto pluginInfoList |
|
118 | auto pluginInfoList | |
110 | = pluginDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); |
|
119 | = pluginDir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name); | |
111 | for (auto entryInfo : qAsConst(pluginInfoList)) { |
|
120 | for (auto entryInfo : qAsConst(pluginInfoList)) { | |
112 | if (entryInfo.isDir()) { |
|
121 | if (entryInfo.isDir()) { | |
113 | this->loadPlugins(QDir{entryInfo.absoluteFilePath()}); |
|
122 | this->loadPlugins(QDir{entryInfo.absoluteFilePath()}); | |
114 | } |
|
123 | } | |
115 | else if (QLibrary::isLibrary(entryInfo.absoluteFilePath())) { |
|
124 | else if (QLibrary::isLibrary(entryInfo.absoluteFilePath())) { | |
116 | impl->loadPlugin(entryInfo.absoluteFilePath()); |
|
125 | impl->loadPlugin(entryInfo.absoluteFilePath()); | |
117 | } |
|
126 | } | |
118 | } |
|
127 | } | |
119 | } |
|
128 | } | |
120 |
|
129 | |||
|
130 | void PluginManager::loadStaticPlugins() | |||
|
131 | { | |||
|
132 | impl->loadStaticPlugins(); | |||
|
133 | } | |||
|
134 | ||||
121 | int PluginManager::nbPluginsLoaded() const noexcept |
|
135 | int PluginManager::nbPluginsLoaded() const noexcept | |
122 | { |
|
136 | { | |
123 | return impl->m_RegisteredPlugins.size(); |
|
137 | return impl->m_RegisteredPlugins.size(); | |
124 | } |
|
138 | } |
General Comments 0
You need to be logged in to leave comments.
Login now