| 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 |
} |