PluginManager.hpp
1 #pragma once
2 #include <score/application/ApplicationContext.hpp>
3 #include <score/application/GUIApplicationContext.hpp>
4 #include <score/plugins/InterfaceList.hpp>
5 #include <score/plugins/PluginInstances.hpp>
6 #include <score/plugins/qt_interfaces/CommandFactory_QtInterface.hpp>
7 #include <score/plugins/qt_interfaces/FactoryFamily_QtInterface.hpp>
8 #include <score/plugins/qt_interfaces/FactoryInterface_QtInterface.hpp>
9 #include <score/plugins/qt_interfaces/GUIApplicationPlugin_QtInterface.hpp>
10 #include <score/plugins/qt_interfaces/PluginRequirements_QtInterface.hpp>
11 #include <score/tools/std/Optional.hpp>
12 
13 #include <core/plugin/PluginDependencyGraph.hpp>
14 
15 #include <QString>
16 #include <QStringList>
17 
18 #include <score_lib_base_export.h>
19 
20 #include <vector>
21 namespace score
22 {
23 struct ApplicationContext;
24 class GUIApplicationRegistrar;
25 class Plugin_QtInterface;
26 struct Addon;
27 
32 namespace PluginLoader
33 {
34 
35 enum class PluginLoadingError
36 {
37  NoError,
38  Blacklisted,
39  NotAPlugin,
40  AlreadyLoaded,
41  UnknownError
42 };
43 
44 QStringList addonsDir();
45 QStringList pluginsDir();
46 
47 SCORE_LIB_BASE_EXPORT void loadPluginsInAllFolders(
48  std::vector<score::Addon>& availablePlugins, QStringList additional = {});
49 
50 SCORE_LIB_BASE_EXPORT void
51 loadAddonsInAllFolders(std::vector<score::Addon>& availablePlugins);
52 
53 std::pair<score::Plugin_QtInterface*, PluginLoadingError>
54 loadPlugin(const QString& fileName, const std::vector<score::Addon>& availablePlugins);
55 
56 std::optional<score::Addon> makeAddon(
57  const QString& addon_path, const QJsonObject& json_addon,
58  const std::vector<score::Addon>& availablePlugins);
59 
60 template <typename Registrar_T>
61 void registerPluginsImpl(
62  const std::vector<score::Addon>& availablePlugins, Registrar_T& registrar,
63  const score::GUIApplicationContext& context)
64 {
65  // Load what the plug-ins have to offer.
66  for(const score::Addon& addon : availablePlugins)
67  {
68  auto commands_plugin = dynamic_cast<CommandFactory_QtInterface*>(addon.plugin);
69  if(commands_plugin)
70  {
71  auto [key, cmds] = commands_plugin->make_commands();
72  registrar.registerCommands(key, std::move(cmds));
73  }
74 
75  auto factories_plugin = dynamic_cast<FactoryInterface_QtInterface*>(addon.plugin);
76  if(factories_plugin)
77  {
78  for(auto& factory_family : registrar.components().factories)
79  {
80  const score::ApplicationContext& base_ctx = context;
81  // Register core factories
82  for(auto&& new_factory :
83  factories_plugin->factories(base_ctx, factory_family.first))
84  {
85  factory_family.second->insert(std::unique_ptr<InterfaceBase>(new_factory));
86  }
87 
88  // Register GUI factories
89  for(auto&& new_factory :
90  factories_plugin->guiFactories(context, factory_family.first))
91  {
92  factory_family.second->insert(std::unique_ptr<InterfaceBase>(new_factory));
93  }
94  }
95  }
96  }
97 }
98 
99 template <typename Registrar_T>
100 void registerPlugins(
101  const std::vector<score::Addon>& availablePlugins, Registrar_T& registrar,
102  const score::GUIApplicationContext& context)
103 {
104  for(const score::Addon& addon : availablePlugins)
105  {
106  auto ctrl_plugin = dynamic_cast<ApplicationPlugin_QtInterface*>(addon.plugin);
107  if(ctrl_plugin)
108  {
109  if(auto plug = ctrl_plugin->make_applicationPlugin(context))
110  registrar.registerApplicationPlugin(plug);
111  if(auto plug = ctrl_plugin->make_guiApplicationPlugin(context))
112  registrar.registerGUIApplicationPlugin(plug);
113  }
114  }
115  registerPluginsImpl(availablePlugins, registrar, context);
116 }
117 
125 template <typename Registrar_T, typename Context_T>
126 void loadPlugins(Registrar_T& registrar, const Context_T& context)
127 {
128  // Here, the plug-ins that are effectively loaded.
129  std::vector<score::Addon> availablePlugins;
130 
131  // Load static plug-ins
132  for(auto score_plug : score::staticPlugins())
133  {
134  score::Addon addon;
135  addon.plugin = score_plug;
136  addon.key = score_plug->key();
137  addon.corePlugin = true;
138  availablePlugins.push_back(std::move(addon));
139  }
140 
141  loadPluginsInAllFolders(availablePlugins);
142  loadAddonsInAllFolders(availablePlugins);
143 
144  // First bring in the plugin objects
145  registrar.registerAddons(availablePlugins);
146 
147  // Here, it is important not to collapse all the for-loops
148  // because for instance a ApplicationPlugin from plugin B might require the
149  // factory
150  // from plugin A to be loaded prior.
151  // Load all the factories.
152  for(const score::Addon& addon : availablePlugins)
153  {
154  auto facfam_interface = dynamic_cast<FactoryList_QtInterface*>(addon.plugin);
155 
156  if(facfam_interface)
157  {
158  for(auto&& elt : facfam_interface->factoryFamilies())
159  {
160  registrar.registerFactory(std::move(elt));
161  }
162  }
163  }
164 
165  // Load all the application context plugins.
166  // We have to order them according to their dependencies
167  PluginDependencyGraph graph{availablePlugins};
168  const auto& add = graph.sortedAddons();
169  if(!add.empty())
170  {
171  registerPlugins(add, registrar, context);
172  }
173 }
174 }
175 }
Classes and functions used at the plug-in loading step.
Definition: PluginManager.hpp:26
Base toolkit upon which the software is built.
Definition: Application.cpp:90
The Addon struct.
Definition: Addon.hpp:16
Used to access all the application-wide state and structures.
Definition: ApplicationContext.hpp:24
Specializes ApplicationContext with the QMainWindow.
Definition: GUIApplicationContext.hpp:15