PluginManager.cpp 8.85 KB
Newer Older
Torsten Rahn's avatar
Torsten Rahn committed
1
//
2
// This file is part of the Marble Virtual Globe.
Torsten Rahn's avatar
Torsten Rahn committed
3
4
5
6
7
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
8
9
// Copyright 2008 Torsten Rahn <tackat@kde.org>
// Copyright 2009 Jens-Michael Hoffmann <jensmh@gmx.de>
Torsten Rahn's avatar
Torsten Rahn committed
10
11
12
13
14
15
16
//


// Own
#include "PluginManager.h"

// Qt
17
18
19
#include <QList>
#include <QPluginLoader>
#include <QTime>
Torsten Rahn's avatar
Torsten Rahn committed
20
21
22

// Local dir
#include "MarbleDirs.h"
23
#include "MarbleDebug.h"
24
#include "RenderPlugin.h"
25
#include "PositionProviderPlugin.h"
26
#include "AbstractFloatItem.h"
27
28
29
30
#include "ParseRunnerPlugin.h"
#include "ReverseGeocodingRunnerPlugin.h"
#include "RoutingRunnerPlugin.h"
#include "SearchRunnerPlugin.h"
Torsten Rahn's avatar
Torsten Rahn committed
31

32
33
namespace Marble
{
Torsten Rahn's avatar
Torsten Rahn committed
34
35
36
37

class PluginManagerPrivate
{
 public:
38
39
40
41
42
    PluginManagerPrivate()
            : m_pluginsLoaded(false)
    {
    }

43
44
    ~PluginManagerPrivate();

45
46
47
    void loadPlugins();

    bool m_pluginsLoaded;
Bernhard Beschow's avatar
Bernhard Beschow committed
48
49
    QList<const RenderPlugin *> m_renderPluginTemplates;
    QList<const PositionProviderPlugin *> m_positionProviderPluginTemplates;
50
51
52
53
    QList<const SearchRunnerPlugin *> m_searchRunnerPlugins;
    QList<const ReverseGeocodingRunnerPlugin *> m_reverseGeocodingRunnerPlugins;
    QList<RoutingRunnerPlugin *> m_routingRunnerPlugins;
    QList<const ParseRunnerPlugin *> m_parsingRunnerPlugins;
54

55
#ifdef Q_OS_ANDROID
56
57
    QStringList m_pluginPaths;
#endif
Torsten Rahn's avatar
Torsten Rahn committed
58
59
};

60
61
PluginManagerPrivate::~PluginManagerPrivate()
{
62
    // nothing to do
63
64
}

65
66
PluginManager::PluginManager( QObject *parent ) : QObject( parent ),
    d( new PluginManagerPrivate() )
Torsten Rahn's avatar
Torsten Rahn committed
67
{
68
    //Checking assets:/plugins for uninstalled plugins
69
#ifdef Q_OS_ANDROID
70
71
        installPluginsFromAssets();
#endif
Torsten Rahn's avatar
Torsten Rahn committed
72
73
74
75
}

PluginManager::~PluginManager()
{
Laurent Montel's avatar
Laurent Montel committed
76
    delete d;
Torsten Rahn's avatar
Torsten Rahn committed
77
78
}

79
QList<const RenderPlugin *> PluginManager::renderPlugins() const
80
{
Bernhard Beschow's avatar
Bernhard Beschow committed
81
    d->loadPlugins();
82
    return d->m_renderPluginTemplates;
83
}
84

Bernhard Beschow's avatar
Bernhard Beschow committed
85
void PluginManager::addRenderPlugin( const RenderPlugin *plugin )
86
87
88
89
90
91
{
    d->loadPlugins();
    d->m_renderPluginTemplates << plugin;
    emit renderPluginsChanged();
}

92
QList<const PositionProviderPlugin *> PluginManager::positionProviderPlugins() const
93
{
Bernhard Beschow's avatar
Bernhard Beschow committed
94
    d->loadPlugins();
95
    return d->m_positionProviderPluginTemplates;
96
97
}

Bernhard Beschow's avatar
Bernhard Beschow committed
98
void PluginManager::addPositionProviderPlugin( const PositionProviderPlugin *plugin )
99
100
101
102
103
104
{
    d->loadPlugins();
    d->m_positionProviderPluginTemplates << plugin;
    emit positionProviderPluginsChanged();
}

105
QList<const SearchRunnerPlugin *> PluginManager::searchRunnerPlugins() const
106
107
{
    d->loadPlugins();
108
109
110
    return d->m_searchRunnerPlugins;
}

Bernhard Beschow's avatar
Bernhard Beschow committed
111
void PluginManager::addSearchRunnerPlugin( const SearchRunnerPlugin *plugin )
112
113
114
115
116
117
{
    d->loadPlugins();
    d->m_searchRunnerPlugins << plugin;
    emit searchRunnerPluginsChanged();
}

118
119
120
121
122
123
QList<const ReverseGeocodingRunnerPlugin *> PluginManager::reverseGeocodingRunnerPlugins() const
{
    d->loadPlugins();
    return d->m_reverseGeocodingRunnerPlugins;
}

Bernhard Beschow's avatar
Bernhard Beschow committed
124
void PluginManager::addReverseGeocodingRunnerPlugin( const ReverseGeocodingRunnerPlugin *plugin )
125
126
127
128
129
130
{
    d->loadPlugins();
    d->m_reverseGeocodingRunnerPlugins << plugin;
    emit reverseGeocodingRunnerPluginsChanged();
}

131
132
133
134
135
136
QList<RoutingRunnerPlugin *> PluginManager::routingRunnerPlugins() const
{
    d->loadPlugins();
    return d->m_routingRunnerPlugins;
}

137
138
139
140
141
142
143
void PluginManager::addRoutingRunnerPlugin( RoutingRunnerPlugin *plugin )
{
    d->loadPlugins();
    d->m_routingRunnerPlugins << plugin;
    emit routingRunnerPluginsChanged();
}

144
145
146
147
QList<const ParseRunnerPlugin *> PluginManager::parsingRunnerPlugins() const
{
    d->loadPlugins();
    return d->m_parsingRunnerPlugins;
148
149
}

Bernhard Beschow's avatar
Bernhard Beschow committed
150
void PluginManager::addParseRunnerPlugin( const ParseRunnerPlugin *plugin )
151
152
153
154
155
156
{
    d->loadPlugins();
    d->m_parsingRunnerPlugins << plugin;
    emit parseRunnerPluginsChanged();
}

157
158
/** Append obj to the given plugins list if it inherits both T and U */
template<class T, class U>
159
bool appendPlugin( QObject * obj, QPluginLoader* &loader, QList<T*> &plugins )
Bernhard Beschow's avatar
Bernhard Beschow committed
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
{
    if ( qobject_cast<T*>( obj ) && qobject_cast<U*>( obj ) ) {
        Q_ASSERT( obj->metaObject()->superClass() ); // all our plugins have a super class
        mDebug() <<  obj->metaObject()->superClass()->className()
                << "plugin loaded from" << loader->fileName();
        T* plugin = qobject_cast<T*>( obj );
        Q_ASSERT( plugin ); // checked above
        plugins << plugin;
        return true;
    }

    return false;
}

/** Append obj to the given plugins list if it inherits both T and U */
template<class T, class U>
bool appendPlugin( QObject * obj, QPluginLoader* &loader, QList<const T*> &plugins )
177
178
179
180
{
    if ( qobject_cast<T*>( obj ) && qobject_cast<U*>( obj ) ) {
        Q_ASSERT( obj->metaObject()->superClass() ); // all our plugins have a super class
        mDebug() <<  obj->metaObject()->superClass()->className()
181
                << "plugin loaded from" << loader->fileName();
182
183
        T* plugin = qobject_cast<T*>( obj );
        Q_ASSERT( plugin ); // checked above
184
        plugins << plugin;
185
186
187
188
189
190
        return true;
    }

    return false;
}

191
void PluginManagerPrivate::loadPlugins()
Torsten Rahn's avatar
Torsten Rahn committed
192
{
193
194
195
196
197
198
199
    if (m_pluginsLoaded)
    {
        return;
    }

    QTime t;
    t.start();
Patrick Spendrin's avatar
Patrick Spendrin committed
200
    mDebug() << "Starting to load Plugins.";
Torsten Rahn's avatar
Torsten Rahn committed
201

202
    QStringList pluginFileNameList = MarbleDirs::pluginEntryList( "", QDir::Files );
203
204

    MarbleDirs::debug();
Torsten Rahn's avatar
Torsten Rahn committed
205

206
207
    Q_ASSERT( m_renderPluginTemplates.isEmpty() );
    Q_ASSERT( m_positionProviderPluginTemplates.isEmpty() );
208
209
210
211
    Q_ASSERT( m_searchRunnerPlugins.isEmpty() );
    Q_ASSERT( m_reverseGeocodingRunnerPlugins.isEmpty() );
    Q_ASSERT( m_routingRunnerPlugins.isEmpty() );
    Q_ASSERT( m_parsingRunnerPlugins.isEmpty() );
212

Laurent Montel's avatar
Laurent Montel committed
213
    foreach( const QString &fileName, pluginFileNameList ) {
Patrick Spendrin's avatar
Patrick Spendrin committed
214
        // mDebug() << fileName << " - " << MarbleDirs::pluginPath( fileName );
215
        QString const path = MarbleDirs::pluginPath( fileName );
216
#ifdef Q_OS_ANDROID
217
218
219
220
221
222
223
        QFileInfo targetFile( path );
        if ( !m_pluginPaths.contains( targetFile.canonicalFilePath() ) ) {
            // @todo Delete the file here?
            qDebug() << "Ignoring file " << path << " which is not among the currently installed plugins";
            continue;
        }
#endif
224
        QPluginLoader* loader = new QPluginLoader( path );
Torsten Rahn's avatar
Torsten Rahn committed
225

226
        QObject * obj = loader->instance();
227

Torsten Rahn's avatar
   
Torsten Rahn committed
228
        if ( obj ) {
229
            bool isPlugin = appendPlugin<RenderPlugin, RenderPluginInterface>
230
                       ( obj, loader, m_renderPluginTemplates );
231
            isPlugin = isPlugin || appendPlugin<PositionProviderPlugin, PositionProviderPluginInterface>
232
                       ( obj, loader, m_positionProviderPluginTemplates );
233
234
235
236
237
238
239
240
            isPlugin = isPlugin || appendPlugin<SearchRunnerPlugin, SearchRunnerPlugin>
                       ( obj, loader, m_searchRunnerPlugins ); // intentionally T==U
            isPlugin = isPlugin || appendPlugin<ReverseGeocodingRunnerPlugin, ReverseGeocodingRunnerPlugin>
                       ( obj, loader, m_reverseGeocodingRunnerPlugins ); // intentionally T==U
            isPlugin = isPlugin || appendPlugin<RoutingRunnerPlugin, RoutingRunnerPlugin>
                       ( obj, loader, m_routingRunnerPlugins ); // intentionally T==U
            isPlugin = isPlugin || appendPlugin<ParseRunnerPlugin, ParseRunnerPlugin>
                       ( obj, loader, m_parsingRunnerPlugins ); // intentionally T==U
241
            if ( !isPlugin ) {
Dennis Nienhüser's avatar
Dennis Nienhüser committed
242
                qWarning() << "Ignoring the following plugin since it couldn't be loaded:" << path;
243
                mDebug() << "Plugin failure:" << path << "is a plugin, but it does not implement the "
244
                        << "right interfaces or it was compiled against an old version of Marble. Ignoring it.";
245
                delete loader;
246
            }
247
        } else {
248
249
            qWarning() << "Ignoring to load the following file since it doesn't look like a valid Marble plugin:" << path << endl
                       << "Reason:" << loader->errorString();
Dennis Nienhüser's avatar
Dennis Nienhüser committed
250
            delete loader;
Torsten Rahn's avatar
Torsten Rahn committed
251
252
        }
    }
253
254

    m_pluginsLoaded = true;
255
256

    mDebug() << Q_FUNC_INFO << "Time elapsed:" << t.elapsed() << "ms";
Torsten Rahn's avatar
Torsten Rahn committed
257
258
}

259
#ifdef Q_OS_ANDROID
260
261
    void PluginManager::installPluginsFromAssets() const
    {
262
        d->m_pluginPaths.clear();
263
264
265
266
267
        QStringList copyList = MarbleDirs::pluginEntryList(QString());
        QDir pluginHome(MarbleDirs::localPath());
        pluginHome.mkpath(MarbleDirs::pluginLocalPath());
        pluginHome.setCurrent(MarbleDirs::pluginLocalPath());
        foreach (const QString & file, copyList) {
268
            QString const target = MarbleDirs::pluginLocalPath() + '/' + file;
269
            if (QFileInfo(MarbleDirs::pluginSystemPath() + '/' + file).isDir()) {
270
                pluginHome.mkpath(target);
271
            }
272
            else {
273
                QFile temporaryFile(MarbleDirs::pluginSystemPath() + '/' + file);
274
275
276
                temporaryFile.copy(target);
                QFileInfo targetFile(target);
                d->m_pluginPaths << targetFile.canonicalFilePath();
277
278
279
280
281
            }
        }
    }
#endif

282
}
283

284
#include "moc_PluginManager.cpp"