Marble

PluginManager.cpp
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 //
3 // SPDX-FileCopyrightText: 2008 Torsten Rahn <[email protected]>
4 // SPDX-FileCopyrightText: 2009 Jens-Michael Hoffmann <[email protected]>
5 //
6 
7 
8 // Own
9 #include "PluginManager.h"
10 
11 // Qt
12 #include <QPluginLoader>
13 #include <QElapsedTimer>
14 #include <QMessageBox>
15 
16 // Local dir
17 #include "MarbleDirs.h"
18 #include "MarbleDebug.h"
19 #include "RenderPlugin.h"
20 #include "PositionProviderPlugin.h"
21 #include "ParseRunnerPlugin.h"
22 #include "ReverseGeocodingRunnerPlugin.h"
23 #include "RoutingRunnerPlugin.h"
24 #include "SearchRunnerPlugin.h"
25 #include <config-marble.h>
26 
27 namespace Marble
28 {
29 
30 class PluginManagerPrivate
31 {
32  public:
33  PluginManagerPrivate(PluginManager* parent)
34  : m_pluginsLoaded(false),
35  m_parent(parent)
36  {
37  }
38 
39  ~PluginManagerPrivate();
40 
41  void loadPlugins();
42  bool addPlugin(QObject *obj, const QPluginLoader *loader);
43 
44  bool m_pluginsLoaded;
45  QList<const RenderPlugin *> m_renderPluginTemplates;
46  QList<const PositionProviderPlugin *> m_positionProviderPluginTemplates;
47  QList<const SearchRunnerPlugin *> m_searchRunnerPlugins;
48  QList<const ReverseGeocodingRunnerPlugin *> m_reverseGeocodingRunnerPlugins;
49  QList<RoutingRunnerPlugin *> m_routingRunnerPlugins;
50  QList<const ParseRunnerPlugin *> m_parsingRunnerPlugins;
51  PluginManager* m_parent;
52  static QStringList m_blacklist;
53  static QStringList m_whitelist;
54 
55 #ifdef Q_OS_ANDROID
56  QStringList m_pluginPaths;
57 #endif
58 };
59 
60 QStringList PluginManagerPrivate::m_blacklist;
61 QStringList PluginManagerPrivate::m_whitelist;
62 
63 PluginManagerPrivate::~PluginManagerPrivate()
64 {
65  // nothing to do
66 }
67 
68 PluginManager::PluginManager( QObject *parent ) : QObject( parent ),
69  d( new PluginManagerPrivate(this) )
70 {
71  //Checking assets:/plugins for uninstalled plugins
72 #ifdef Q_OS_ANDROID
73  installPluginsFromAssets();
74 #endif
75 }
76 
77 PluginManager::~PluginManager()
78 {
79  delete d;
80 }
81 
83 {
84  d->loadPlugins();
85  return d->m_renderPluginTemplates;
86 }
87 
89 {
90  d->loadPlugins();
91  d->m_renderPluginTemplates << plugin;
92  emit renderPluginsChanged();
93 }
94 
96 {
97  d->loadPlugins();
98  return d->m_positionProviderPluginTemplates;
99 }
100 
102 {
103  d->loadPlugins();
104  d->m_positionProviderPluginTemplates << plugin;
105  emit positionProviderPluginsChanged();
106 }
107 
109 {
110  d->loadPlugins();
111  return d->m_searchRunnerPlugins;
112 }
113 
115 {
116  d->loadPlugins();
117  d->m_searchRunnerPlugins << plugin;
118  emit searchRunnerPluginsChanged();
119 }
120 
122 {
123  d->loadPlugins();
124  return d->m_reverseGeocodingRunnerPlugins;
125 }
126 
128 {
129  d->loadPlugins();
130  d->m_reverseGeocodingRunnerPlugins << plugin;
131  emit reverseGeocodingRunnerPluginsChanged();
132 }
133 
135 {
136  d->loadPlugins();
137  return d->m_routingRunnerPlugins;
138 }
139 
141 {
142  d->loadPlugins();
143  d->m_routingRunnerPlugins << plugin;
144  emit routingRunnerPluginsChanged();
145 }
146 
148 {
149  d->loadPlugins();
150  return d->m_parsingRunnerPlugins;
151 }
152 
154 {
155  d->loadPlugins();
156  d->m_parsingRunnerPlugins << plugin;
157  emit parseRunnerPluginsChanged();
158 }
159 
161 {
162  PluginManagerPrivate::m_blacklist << MARBLE_SHARED_LIBRARY_PREFIX + filename;
163 }
164 
166 {
167  PluginManagerPrivate::m_whitelist << MARBLE_SHARED_LIBRARY_PREFIX + filename;
168 }
169 
170 /** Append obj to the given plugins list if it inherits both T and U */
171 template<class Iface, class Plugin>
172 bool appendPlugin( QObject * obj, const QPluginLoader *loader, QList<Plugin> &plugins )
173 {
174  if ( qobject_cast<Iface*>( obj ) && qobject_cast<Plugin>( obj ) ) {
175  Q_ASSERT( obj->metaObject()->superClass() ); // all our plugins have a super class
176  mDebug() << obj->metaObject()->superClass()->className()
177  << "plugin loaded from" << (loader ? loader->fileName() : "<static>");
178  auto plugin = qobject_cast<Plugin>( obj );
179  Q_ASSERT( plugin ); // checked above
180  plugins << plugin;
181  return true;
182  }
183 
184  return false;
185 }
186 
187 bool PluginManagerPrivate::addPlugin(QObject *obj, const QPluginLoader *loader)
188 {
189  bool isPlugin = appendPlugin<RenderPluginInterface>
190  ( obj, loader, m_renderPluginTemplates );
191  isPlugin = isPlugin || appendPlugin<PositionProviderPluginInterface>
192  ( obj, loader, m_positionProviderPluginTemplates );
193  isPlugin = isPlugin || appendPlugin<SearchRunnerPlugin>
194  ( obj, loader, m_searchRunnerPlugins );
195  isPlugin = isPlugin || appendPlugin<ReverseGeocodingRunnerPlugin>
196  ( obj, loader, m_reverseGeocodingRunnerPlugins );
197  isPlugin = isPlugin || appendPlugin<RoutingRunnerPlugin>
198  ( obj, loader, m_routingRunnerPlugins );
199  isPlugin = isPlugin || appendPlugin<ParseRunnerPlugin>
200  ( obj, loader, m_parsingRunnerPlugins );
201  if ( !isPlugin ) {
202  qWarning() << "Ignoring the following plugin since it couldn't be loaded:" << (loader ? loader->fileName() : "<static>");
203  mDebug() << "Plugin failure:" << (loader ? loader->fileName() : "<static>") << "is a plugin, but it does not implement the "
204  << "right interfaces or it was compiled against an old version of Marble. Ignoring it.";
205  }
206  return isPlugin;
207 }
208 
209 void PluginManagerPrivate::loadPlugins()
210 {
211  if (m_pluginsLoaded)
212  {
213  return;
214  }
215 
216  QElapsedTimer t;
217  t.start();
218  mDebug() << "Starting to load Plugins.";
219 
220  QStringList pluginFileNameList = MarbleDirs::pluginEntryList( "", QDir::Files );
221 
222  MarbleDirs::debug();
223 
224  Q_ASSERT( m_renderPluginTemplates.isEmpty() );
225  Q_ASSERT( m_positionProviderPluginTemplates.isEmpty() );
226  Q_ASSERT( m_searchRunnerPlugins.isEmpty() );
227  Q_ASSERT( m_reverseGeocodingRunnerPlugins.isEmpty() );
228  Q_ASSERT( m_routingRunnerPlugins.isEmpty() );
229  Q_ASSERT( m_parsingRunnerPlugins.isEmpty() );
230 
231  bool foundPlugin = false;
232  for( const QString &fileName: pluginFileNameList ) {
233  QString const baseName = QFileInfo(fileName).baseName();
234  QString const libBaseName = MARBLE_SHARED_LIBRARY_PREFIX + QFileInfo(fileName).baseName();
235  if (!m_whitelist.isEmpty() && !m_whitelist.contains(baseName) && !m_whitelist.contains(libBaseName)) {
236  mDebug() << "Ignoring non-whitelisted plugin " << fileName;
237  continue;
238  }
239  if (m_blacklist.contains(baseName) || m_blacklist.contains(libBaseName)) {
240  mDebug() << "Ignoring blacklisted plugin " << fileName;
241  continue;
242  }
243 
244  // mDebug() << fileName << " - " << MarbleDirs::pluginPath( fileName );
245  QString const path = MarbleDirs::pluginPath( fileName );
246 #ifdef Q_OS_ANDROID
247  QFileInfo targetFile( path );
248  if ( !m_pluginPaths.contains( targetFile.canonicalFilePath() ) ) {
249  // @todo Delete the file here?
250  qDebug() << "Ignoring file " << path << " which is not among the currently installed plugins";
251  continue;
252  }
253 #endif
254  QPluginLoader* loader = new QPluginLoader( path, m_parent );
255 
256  QObject * obj = loader->instance();
257 
258  if ( obj ) {
259  bool isPlugin = addPlugin(obj, loader);
260  if (!isPlugin) {
261  delete loader;
262  } else {
263  foundPlugin = true;
264  }
265  } else {
266  qWarning() << "Ignoring to load the following file since it doesn't look like a valid Marble plugin:" << path << endl
267  << "Reason:" << loader->errorString();
268  delete loader;
269  }
270  }
271 
272  const auto staticPlugins = QPluginLoader::staticInstances();
273  for (auto obj : staticPlugins) {
274  if (addPlugin(obj, nullptr)) {
275  foundPlugin = true;
276  }
277  }
278 
279  if ( !foundPlugin ) {
280 #ifdef Q_OS_WIN
281  QString pluginPaths = "Plugin Path: " + MarbleDirs::marblePluginPath();
282  if ( MarbleDirs::marblePluginPath().isEmpty() )
283  pluginPaths = "";
284  pluginPaths += "System Path: " + MarbleDirs::pluginSystemPath() + "\nLocal Path: " + MarbleDirs::pluginLocalPath();
285 
286  QMessageBox::warning( nullptr,
287  "No plugins loaded",
288  "No plugins were loaded, please check if the plugins were installed in one of the following paths:\n" + pluginPaths
289  + "\n\nAlso check if the plugin is compiled against the right version of Marble. " +
290  "Analyzing the debug messages inside a debugger might give more insight." );
291 #else
292  qWarning() << "No plugins loaded. Please check if the plugins were installed in the correct path,"
293  << "or if any errors occurred while loading plugins.";
294 #endif
295  }
296 
297  m_pluginsLoaded = true;
298 
299  mDebug() << Q_FUNC_INFO << "Time elapsed:" << t.elapsed() << "ms";
300 }
301 
302 #ifdef Q_OS_ANDROID
303  void PluginManager::installPluginsFromAssets() const
304  {
305  d->m_pluginPaths.clear();
306  QStringList copyList = MarbleDirs::pluginEntryList(QString());
307  QDir pluginHome(MarbleDirs::localPath());
308  pluginHome.mkpath(MarbleDirs::pluginLocalPath());
309  pluginHome.setCurrent(MarbleDirs::pluginLocalPath());
310 
311  QStringList pluginNameFilter = QStringList() << "lib*.so";
312  QStringList const existingPlugins = QDir(MarbleDirs::pluginLocalPath()).entryList(pluginNameFilter, QDir::Files);
313  for(const QString &existingPlugin: existingPlugins) {
314  QFile::remove(existingPlugin);
315  }
316 
317  for (const QString & file: copyList) {
318  QString const target = MarbleDirs::pluginLocalPath() + QLatin1Char('/') + file;
319  if (QFileInfo(MarbleDirs::pluginSystemPath() + QLatin1Char('/') + file).isDir()) {
320  pluginHome.mkpath(target);
321  }
322  else {
323  QFile temporaryFile(MarbleDirs::pluginSystemPath() + QLatin1Char('/') + file);
324  temporaryFile.copy(target);
325  QFileInfo targetFile(target);
326  d->m_pluginPaths << targetFile.canonicalFilePath();
327  }
328  }
329  }
330 #endif
331 
332 }
333 
334 #include "moc_PluginManager.cpp"
QList< const PositionProviderPlugin * > positionProviderPlugins() const
Returns all available PositionProviderPlugins.
The abstract class that creates a renderable item.
Definition: RenderPlugin.h:38
QTextStream & endl(QTextStream &stream)
QList< const RenderPlugin * > renderPlugins() const
Returns all available RenderPlugins.
void addRoutingRunnerPlugin(RoutingRunnerPlugin *plugin)
Add a RoutingRunnerPlugin manually to the list of known plugins.
bool remove()
QList< const SearchRunnerPlugin * > searchRunnerPlugins() const
Returns all search runner plugins.
void addPositionProviderPlugin(const PositionProviderPlugin *plugin)
Add a PositionProviderPlugin manually to the list of known plugins.
The abstract class that provides position information.
QList< const ParseRunnerPlugin * > parsingRunnerPlugins() const
Returns all parse runner plugins.
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
void addParseRunnerPlugin(const ParseRunnerPlugin *plugin)
Add a ParseRunnerPlugin manually to the list of known plugins.
bool appendPlugin(QObject *obj, const QPluginLoader *loader, QList< Plugin > &plugins)
Append obj to the given plugins list if it inherits both T and U.
QList< RoutingRunnerPlugin * > routingRunnerPlugins() const
Returns all routing runner plugins.
A plugin for Marble to execute a parsing task.
QObjectList staticInstances()
QCA_EXPORT QStringList pluginPaths()
QString baseName() const const
const QMetaObject * superClass() const const
static void blacklistPlugin(const QString &filename)
blacklistPlugin Prevent that a plugin is loaded from the given filename
Binds a QML item to a specific geodetic location in screen coordinates.
qint64 elapsed() const const
virtual const QMetaObject * metaObject() const const
A plugin for Marble to execute a placemark search.
const char * className() const const
A plugin for Marble to execute a routing task.
void addSearchRunnerPlugin(const SearchRunnerPlugin *plugin)
Add a SearchRunnerPlugin manually to the list of known plugins.
QString path(const QString &relativePath)
void addRenderPlugin(const RenderPlugin *plugin)
Add a RenderPlugin manually to the list of known plugins.
QList< const ReverseGeocodingRunnerPlugin * > reverseGeocodingRunnerPlugins() const
Returns all reverse geocoding runner plugins.
QObject * instance()
void addReverseGeocodingRunnerPlugin(const ReverseGeocodingRunnerPlugin *plugin)
Add a ReverseGeocodingRunnerPlugin manually to the list of known plugins.
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
A plugin for Marble to execute a reverse geocoding task.
static void whitelistPlugin(const QString &filename)
whitelistPlugin Add a plugin to the whitelist of plugins.
QDebug mDebug()
a function to replace qDebug() in Marble library code
Definition: MarbleDebug.cpp:31
QString errorString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Sun Oct 1 2023 04:09:38 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.