Marble

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

KDE's Doxygen guidelines are available online.