1
/***************************************************************************
2
begin                : 2004/03/12
3
copyright            : (C) Mark Kretschmann
4
email                : markey@web.de
5
***************************************************************************/
6
7
/***************************************************************************
8
 *                                                                         *
9
 *   This program is free software; you can redistribute it and/or modify  *
10
 *   it under the terms of the GNU General Public License as published by  *
11
 *   the Free Software Foundation; either version 2 of the License, or     *
12
 *   (at your option) any later version.                                   *
13
 *                                                                         *
14
 ***************************************************************************/
15
16
#define DEBUG_PREFIX "PluginManager"
17
18
#include "PluginManager.h"
19
20
#include "Debug.h"
21
#include "plugin.h"
22
23
#include <KLibLoader>
24
#include <KLocale>
25
#include <KMessageBox>
26
27
#include <QFile>
28
29
using std::vector;
30
using Amarok::Plugin;
31
32
33
vector<PluginManager::StoreItem>
34
PluginManager::m_store;
35
36
37
/////////////////////////////////////////////////////////////////////////////////////
38
// PUBLIC INTERFACE
39
/////////////////////////////////////////////////////////////////////////////////////
40
41
KService::List
42
PluginManager::query( const QString& constraint )
43
{
44
    // Add versioning constraint
45
    QString
46
    str  = "[X-KDE-Amarok-framework-version] == ";
47
    str += QString::number( FrameworkVersion );
48
    if ( !constraint.trimmed().isEmpty() )
49
        str += " and " + constraint;
50
    str += " and ";
51
    str += "[X-KDE-Amarok-rank] > 0";
52
53
    debug() << "Plugin trader constraint: " << str;
54
55
    return KServiceTypeTrader::self()->query( "Amarok/Plugin", str );
56
}
57
58
59
Plugin*
60
PluginManager::createFromQuery( const QString &constraint )
61
{
62
    Debug::Block block( __PRETTY_FUNCTION__ );
63
64
    KService::List offers = query( constraint );
65
66
    if ( offers.isEmpty() ) {
67
        warning() << "No matching plugin found.\n";
68
        return 0;
69
    }
70
71
    // Select plugin with highest rank
72
    int rank = 0;
73
    uint current = 0;
74
    for ( int i = 0; i < offers.count(); i++ ) {
75
        if ( offers[i]->property( "X-KDE-Amarok-rank" ).toInt() > rank )
76
            current = i;
77
    }
78
79
    return createFromService( offers[current] );
80
}
81
82
83
Plugin*
84
PluginManager::createFromService( const KService::Ptr service )
85
{
86
    debug() << "Trying to load: " << service->library();
87
88
    //get the library loader instance
89
    KLibLoader *loader = KLibLoader::self();
90
    //try to load the specified library
91
    KLibrary *lib = loader->library( QFile::encodeName( service->library() ), QLibrary::ExportExternalSymbolsHint );
92
93
    if ( !lib ) {
94
        KMessageBox::error( 0, i18n( "<p>KLibLoader could not load the plugin:<br/><i>%1</i></p>"
95
                                     "<p>Error message:<br/><i>%2</i></p>",
96
                                     service->library(),
97
                                     loader->lastErrorMessage() ) );
98
        return 0;
99
    }
100
    //look up address of init function and cast it to pointer-to-function
101
    Plugin* (*create_plugin)() = ( Plugin* (*)() ) lib->resolveSymbol( "create_plugin" );
102
103
    if ( !create_plugin ) {
104
        warning() << "create_plugin == NULL\n";
105
        return 0;
106
    }
107
    //create plugin on the heap
108
    Plugin* plugin = create_plugin();
109
110
    //put plugin into store
111
    StoreItem item;
112
    item.plugin = plugin;
113
    item.library = lib;
114
    item.service = service;
115
    m_store.push_back( item );
116
117
    dump( service );
118
    return plugin;
119
}
120
121
122
void
123
PluginManager::unload( Plugin* plugin )
124
{
125
    DEBUG_FUNC_INFO
126
127
    vector<StoreItem>::iterator iter = lookupPlugin( plugin );
128
129
    if ( iter != m_store.end() ) {
130
        delete (*iter).plugin;
131
        debug() << "Unloading library: "<< (*iter).service->library();
132
        (*iter).library->unload();
133
134
        m_store.erase( iter );
135
    }
136
    else
137
        warning() << "Could not unload plugin (not found in store).\n";
138
}
139
140
141
KService::Ptr
142
PluginManager::getService( const Plugin* plugin )
143
{
144
    if ( !plugin ) {
145
        warning() << "pointer == NULL\n";
146
        return KService::Ptr(0);
147
    }
148
149
    //search plugin in store
150
    vector<StoreItem>::const_iterator iter = lookupPlugin( plugin );
151
152
    if ( iter == m_store.end() ) {
153
        warning() << "Plugin not found in store.\n";
154
	return KService::Ptr(0);
155
    }
156
157
    return (*iter).service;
158
}
159
160
161
void
162
PluginManager::showAbout( const QString &constraint )
163
{
164
    KService::List offers = query( constraint );
165
166
    if ( offers.isEmpty() )
167
        return;
168
169
    KService::Ptr s = offers.front();
170
171
    const QString body = "<tr><td>%1</td><td>%2</td></tr>";
172
173
    QString str  = "<html><body><table width=\"100%\" border=\"1\">";
174
175
    str += body.arg( i18nc( "Title, as in: the title of this item", "Name" ),                s->name() );
176
    str += body.arg( i18n( "Library" ),             s->library() );
177
    str += body.arg( i18n( "Authors" ),             s->property( "X-KDE-Amarok-authors" ).toStringList().join( "\n" ) );
178
    str += body.arg( i18nc( "Property, belonging to the author of this item", "Email" ),               s->property( "X-KDE-Amarok-email" ).toStringList().join( "\n" ) );
179
    str += body.arg( i18n( "Version" ),             s->property( "X-KDE-Amarok-version" ).toString() );
180
    str += body.arg( i18n( "Framework Version" ),   s->property( "X-KDE-Amarok-framework-version" ).toString() );
181
182
    str += "</table></body></html>";
183
184
    KMessageBox::information( 0, str, i18n( "Plugin Information" ) );
185
}
186
187
188
void
189
PluginManager::dump( const KService::Ptr service )
190
{
191
    #define ENDLI endl << Debug::indent()
192
193
    debug()
194
      << ENDLI
195
      << "PluginManager Service Info:" << ENDLI
196
      << "---------------------------" << ENDLI
197
      << "name                          :" << service->name() << ENDLI
198
      << "library                       :" << service->library() << ENDLI
199
      << "desktopEntryPath              :" << service->entryPath() << ENDLI
200
      << "X-KDE-Amarok-plugintype       :" << service->property( "X-KDE-Amarok-plugintype" ).toString() << ENDLI
201
      << "X-KDE-Amarok-name             :" << service->property( "X-KDE-Amarok-name" ).toString() << ENDLI
202
      << "X-KDE-Amarok-authors          :" << service->property( "X-KDE-Amarok-authors" ).toStringList() << ENDLI
203
      << "X-KDE-Amarok-rank             :" << service->property( "X-KDE-Amarok-rank" ).toString() << ENDLI
204
      << "X-KDE-Amarok-version          :" << service->property( "X-KDE-Amarok-version" ).toString() << ENDLI
205
      << "X-KDE-Amarok-framework-version:" << service->property( "X-KDE-Amarok-framework-version" ).toString()
206
      << endl
207
     ;
208
209
    #undef ENDLI
210
}
211
212
213
/////////////////////////////////////////////////////////////////////////////////////
214
// PRIVATE INTERFACE
215
/////////////////////////////////////////////////////////////////////////////////////
216
217
vector<PluginManager::StoreItem>::iterator
218
PluginManager::lookupPlugin( const Plugin* plugin )
219
{
220
    vector<StoreItem>::iterator iter;
221
222
    //search plugin pointer in store
223
    vector<StoreItem>::iterator iterEnd(m_store.end() );
224
    for ( iter = m_store.begin(); iter != iterEnd; ++iter ) {
225
        if ( (*iter).plugin == plugin )
226
            break;
227
    }
228
229
    return iter;
230
}