Subversion Repositories Scribus

Rev

Rev 7255 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4430 cbradney 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
1549 subik 7
#include "pluginmanager.h"
1551 fschmid 8
#include "pluginmanager.moc"
3207 craig 9
#include "scplugin.h"
3850 fschmid 10
#include "loadsaveplugin.h"
2629 craig 11
 
1549 subik 12
#include <qdir.h>
2629 craig 13
 
2688 craig 14
#include "scconfig.h"
2629 craig 15
 
1549 subik 16
#include "scribus.h"
5975 cbradney 17
#include "scribusdoc.h"
5243 cbradney 18
#include "scribuscore.h"
1549 subik 19
#include "menumanager.h"
20
#include "scraction.h"
21
#include "splash.h"
8220 fschmid 22
//#include "mpalette.h"
23
//#include "tree.h"
2856 cbradney 24
#include "prefsmanager.h"
1552 subik 25
#include "prefsfile.h"
1693 craig 26
#include "scpaths.h"
5496 subik 27
#include "commonstrings.h"
1549 subik 28
 
2629 craig 29
#ifdef HAVE_DLFCN_H
30
#include <dlfcn.h>
31
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
32
#include <windows.h>
33
#else
34
#include <qlibrary.h>
35
#endif
36
 
3205 craig 37
 
2187 cbradney 38
extern ScribusQApp *ScQApp;
1549 subik 39
 
3207 craig 40
PluginManager::PluginManager() :
41
        QObject(0),
42
        prefs(PrefsManager::instance()->prefsFile->getPluginContext("pluginmanager"))
1549 subik 43
{
44
}
45
 
46
PluginManager::~PluginManager()
47
{
48
}
49
 
2629 craig 50
void* PluginManager::loadDLL( QString plugin )
51
{
52
        void* lib = NULL;
53
#ifdef HAVE_DLFCN_H
54
        QString libpath = QDir::convertSeparators( plugin );
55
        lib = dlopen(libpath, RTLD_LAZY | RTLD_GLOBAL);
56
        if (!lib)
57
        {
4413 cbradney 58
                const char* error = dlerror();
2630 craig 59
                qDebug("%s: %s",
2641 craig 60
                                tr("Cannot find plugin", "plugin manager").local8Bit().data(),
61
                                error ? error : tr("unknown error","plugin manager").local8Bit().data());
2629 craig 62
        }
63
        dlerror();
64
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
65
        QString libpath = QDir::convertSeparators( plugin );
66
        HINSTANCE hdll = LoadLibrary( (const char*) libpath );
67
        lib = (void*) hdll;
68
#else
69
        if( QFile::exists(plugin) )
70
                lib = (void*) new QLibrary( plugin );
71
        else
2641 craig 72
                qDebug("%s \"%s\"", tr("Cannot find plugin", "plugin manager").local8Bit().data(), plugin.local8Bit().data());
2629 craig 73
#endif
74
        return lib;
75
}
76
 
77
void* PluginManager::resolveSym( void* plugin, const char* sym )
78
{
79
        void* symAddr = NULL;
80
#ifdef HAVE_DLFCN_H
81
        const char* error;
82
        dlerror();
83
        symAddr = dlsym( plugin, sym );
84
        if ((error = dlerror()) != NULL)
85
        {
2641 craig 86
                qDebug("%s", tr("Cannot find symbol (%1)", "plugin manager").arg(error).local8Bit().data());
2629 craig 87
                symAddr = NULL;
88
        }
89
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
90
        symAddr = (void* ) GetProcAddress( (HMODULE) plugin, sym);
91
        if ( symAddr == NULL)
2641 craig 92
                qDebug("%s", tr("Cannot find symbol (%1)", "plugin manager").arg(sym).local8Bit().data());
2629 craig 93
#else
94
        QLibrary* qlib = (QLibrary*) plugin;
95
        if( plugin ) symAddr = qlib->resolve(sym);
96
        if ( symAddr == NULL)
2641 craig 97
                qDebug("%s", tr("Cannot find symbol (%1)", "plugin manager").arg(sym).local8Bit().data());
2629 craig 98
#endif
99
        return symAddr;
100
}
101
 
102
void  PluginManager::unloadDLL( void* plugin )
103
{
104
#ifdef HAVE_DLFCN_H
105
        dlclose( plugin );
106
        dlerror();
107
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
108
        FreeLibrary( (HMODULE) plugin );
109
#else
110
        delete ( (QLibrary*) plugin );
111
#endif
112
}
113
 
1596 subik 114
void PluginManager::savePreferences()
115
{
116
        // write configuration
3207 craig 117
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
118
                prefs->set(it.data().pluginName, it.data().enableOnStartup);
1596 subik 119
}
120
 
3207 craig 121
QCString PluginManager::getPluginName(QString fileName)
122
{
123
        // Must return plug-in name. Note that this may be platform dependent;
124
        // it's likely to need some adjustment for platform naming schemes.
125
        // It currently handles:
126
        //    (lib)?pluginname(\.pluginext)?
127
        QFileInfo fi(fileName);
128
        QString baseName(fi.baseName());
129
        if (baseName.startsWith("lib"))
130
                baseName = baseName.remove(0,3);
131
        if (baseName.endsWith(platformDllExtension()))
132
                baseName = baseName.left(baseName.length() - 1 - platformDllExtension().length());
133
        // check name
134
        for (int i = 0; i < (int)baseName.length(); i++)
135
                if (! baseName[i].isLetterOrNumber() && baseName[i] != '_' )
136
                {
137
                        qDebug("Invalid character in plugin name for %s; skipping",
138
                                        fileName.local8Bit().data());
139
                        return QCString();
140
                }
141
        return baseName.latin1();
142
}
143
 
5496 subik 144
int PluginManager::initPlugin(const QString fileName)
145
{
146
        PluginData pda;
147
        pda.pluginFile = QString("%1/%2").arg(ScPaths::instance().pluginDir()).arg(fileName);
148
        pda.pluginName = getPluginName(pda.pluginFile);
149
        if (pda.pluginName.isNull())
150
                // Couldn't determine plugname from filename. We've already complained, so
151
                // move on to the next one.
152
                return 0;
153
        pda.plugin = 0;
154
        pda.pluginDLL = 0;
155
        pda.enabled = false;
156
        pda.enableOnStartup = prefs->getBool(pda.pluginName, true);
6260 fschmid 157
        ScCore->setSplashStatus( tr("Plugin: loading %1", "plugin manager").arg(pda.pluginName));
5496 subik 158
        if (loadPlugin(pda))
159
        {
160
                if (pda.enableOnStartup)
161
                        enablePlugin(pda);
162
                pluginMap.insert(pda.pluginName, pda);
163
                return 1;
164
        }
165
        return 0;
166
}
167
 
1549 subik 168
void PluginManager::initPlugs()
169
{
3207 craig 170
        Q_ASSERT(!pluginMap.count());
171
        QString libPattern = QString("*.%1*").arg(platformDllExtension());
5496 subik 172
        QMap<QString,int> allPlugs;
173
        uint loaded = 0;
174
        uint changes = 1;
5710 subik 175
        QStringList failedPlugs; // output string for warn dialog
1693 craig 176
 
5047 subik 177
        /*! \note QDir::Reversed is there due the Mac plugin dependency.
178
        barcode depends on psimport. and load on that platform expect the
5496 subik 179
        psimp before barcode.You know, security by obscurity ;) PV */
1693 craig 180
        QDir dirList(ScPaths::instance().pluginDir(),
5047 subik 181
                                 libPattern, QDir::Name | QDir::Reversed,
1693 craig 182
                                 QDir::Files | QDir::Executable | QDir::NoSymLinks);
183
 
5496 subik 184
        if ((!dirList.exists()) || (dirList.count() == 0))
185
                return;
186
        for (uint dc = 0; dc < dirList.count(); ++dc)
1549 subik 187
        {
5496 subik 188
                int res = initPlugin(dirList[dc]);
189
                allPlugs[dirList[dc]] = res;
190
                if (res != 0)
191
                        ++loaded;
5710 subik 192
                else
193
                        failedPlugs.append(dirList[dc]);
5496 subik 194
        }
195
        /* Re-try the failed plugins again and again until it promote
196
        any progress (changes variable is changing ;)) */
7176 subik 197
        QMap<QString,int>::Iterator it;
5496 subik 198
        while (loaded < allPlugs.count() && changes!=0)
199
        {
200
                changes = 0;
201
                for (it = allPlugs.begin(); it != allPlugs.end(); ++it)
1549 subik 202
                {
5496 subik 203
                        if (it.data() != 0)
3207 craig 204
                                continue;
5496 subik 205
                        int res = initPlugin(it.key());
206
                        allPlugs[it.key()] = res;
207
                        if (res == 1)
1549 subik 208
                        {
5496 subik 209
                                ++loaded;
210
                                ++changes;
5710 subik 211
                                failedPlugs.remove(it.key());
1549 subik 212
                        }
213
                }
214
        }
5496 subik 215
        if (loaded != allPlugs.count())
5655 cbradney 216
        {
217
                if (ScCore->usingGUI())
218
                {
5710 subik 219
                        bool splashShown = ScCore->splashShowing();
220
                        QString failedStr("<ul>");
221
                        for (QStringList::Iterator it = failedPlugs.begin(); it != failedPlugs.end(); ++it)
222
                                failedStr += "<li>" + *it + "</li>";
223
                        failedStr += "</ul>";
5656 cbradney 224
                        if (splashShown)
225
                                ScCore->showSplash(false);
5781 cbradney 226
                        QMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning,
6367 subik 227
                                                                 "<qt>" + tr("There is a problem loading %1 of %2 plugins. %3 This is probably caused by some kind of dependency issue or old plugins existing in your install directory. If you clean out your install directory and reinstall and this still occurs, please report it on bugs.scribus.net."
5710 subik 228
                                                                                ).arg(allPlugs.count()-loaded).arg(allPlugs.count()).arg(failedStr)
5496 subik 229
                                                                         + "</qt>",
230
                                                         CommonStrings::tr_OK);
5656 cbradney 231
                        if (splashShown)
232
                                ScCore->showSplash(true);
5655 cbradney 233
                }
234
        }
1549 subik 235
}
236
 
3207 craig 237
// After a plug-in has been initialized, this method calls its setup
238
// routines and connects it to the application.
239
void PluginManager::enablePlugin(PluginData & pda)
1549 subik 240
{
3207 craig 241
        Q_ASSERT(pda.enabled == false);
242
        QString failReason;
5243 cbradney 243
        bool isActionPlugin=false;
3207 craig 244
        if (pda.plugin->inherits("ScActionPlugin"))
1549 subik 245
        {
3207 craig 246
                ScActionPlugin* plugin = dynamic_cast<ScActionPlugin*>(pda.plugin);
247
                Q_ASSERT(plugin);
5243 cbradney 248
                isActionPlugin=true;
249
                /*
3207 craig 250
                pda.enabled = setupPluginActions(plugin);
251
                if (!pda.enabled)
252
                        failReason = tr("init failed", "plugin load error");
5243 cbradney 253
                */
1549 subik 254
        }
3207 craig 255
        else if (pda.plugin->inherits("ScPersistentPlugin"))
1549 subik 256
        {
3207 craig 257
                ScPersistentPlugin* plugin = dynamic_cast<ScPersistentPlugin*>(pda.plugin);
258
                Q_ASSERT(plugin);
259
                pda.enabled = plugin->initPlugin();
260
                if (!pda.enabled)
261
                        failReason = tr("init failed", "plugin load error");
1549 subik 262
        }
3850 fschmid 263
/* temporary hack to enable the import plugins */
264
        else if (pda.plugin->inherits("LoadSavePlugin"))
265
                pda.enabled = true;
1549 subik 266
        else
3207 craig 267
                failReason = tr("unknown plugin type", "plugin load error");
5243 cbradney 268
        if (pda.enabled || isActionPlugin)
269
                ScCore->setSplashStatus(
270
                                tr("Plugin: %1 loaded", "plugin manager")
271
                                .arg(pda.plugin->fullTrName()));
272
        else
273
                ScCore->setSplashStatus(
274
                                tr("Plugin: %1 failed to load: %2", "plugin manager")
275
                                .arg(pda.plugin->fullTrName()).arg(failReason));
276
}
277
 
278
bool PluginManager::setupPluginActions(ScribusMainWindow *mw)
279
{
280
        Q_CHECK_PTR(mw);
7176 subik 281
        ScActionPlugin* plugin = 0;
282
 
5243 cbradney 283
        mw->scrMenuMgr->addMenuSeparator("Extras");
284
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
1549 subik 285
        {
5243 cbradney 286
                if (it.data().plugin->inherits("ScActionPlugin"))
287
                {
288
                        //Add in ScrAction based plugin linkage
289
                        //Insert DLL Action into Dictionary with values from plugin interface
7176 subik 290
                        plugin = dynamic_cast<ScActionPlugin*>(it.data().plugin);
5243 cbradney 291
                        Q_ASSERT(plugin);
292
                        ScActionPlugin::ActionInfo ai(plugin->actionInfo());
5781 cbradney 293
                        ScrAction* action = new ScrAction(ScrAction::ActionDLL, ai.iconSet, ai.text, ai.keySequence, mw, ai.name);
5243 cbradney 294
                        Q_CHECK_PTR(action);
295
                        mw->scrActions.insert(ai.name, action);
7126 subik 296
 
5243 cbradney 297
                        // then enable and connect up the action
298
                        mw->scrActions[ai.name]->setEnabled(ai.enabledOnStartup);
299
                        // Connect action's activated signal with the plugin's run method
5781 cbradney 300
                        it.data().enabled = connect( mw->scrActions[ai.name], SIGNAL(activatedData(ScribusDoc*)),
301
                                                        plugin, SLOT(run(ScribusDoc*)) );
5243 cbradney 302
                        //Get the menu manager to add the DLL's menu item to the right menu, after the chosen existing item
303
                        if ( ai.menuAfterName.isEmpty() )
304
                                mw->scrMenuMgr->addMenuItem(mw->scrActions[ai.name], ai.menu);
305
                        else
5781 cbradney 306
                        {
307
                                QString actionName(ai.menu.lower()+ai.menuAfterName);
308
                                ScrAction* afterAction=0;
309
                                if (mw->scrActions.contains(actionName))
310
                                        afterAction=mw->scrActions[actionName];
311
                                mw->scrMenuMgr->addMenuItemAfter(mw->scrActions[ai.name], ai.menu, afterAction);
312
                        }
5243 cbradney 313
                        if (it.data().enabled)
6260 fschmid 314
                                ScCore->setSplashStatus( tr("Plugin: %1 initialized ok ", "plugin manager")
5243 cbradney 315
                                                .arg(plugin->fullTrName()));
316
                        else
6260 fschmid 317
                                ScCore->setSplashStatus( tr("Plugin: %1 failed post initialization", "plugin manager")
5243 cbradney 318
                                                .arg(plugin->fullTrName()));
319
                }
3207 craig 320
                else
5243 cbradney 321
                {
322
                        it.data().plugin->addToMainWindowMenu(mw);
323
                }
7126 subik 324
 
1549 subik 325
        }
5243 cbradney 326
        return true;
1549 subik 327
}
328
 
3207 craig 329
bool PluginManager::DLLexists(QCString name, bool includeDisabled) const
1549 subik 330
{
3207 craig 331
        // the plugin name must be known
332
        if (pluginMap.contains(name))
3850 fschmid 333
        {
3207 craig 334
                // the plugin must be loaded
335
                if (pluginMap[name].plugin)
3850 fschmid 336
                {
3383 craig 337
                        // and the plugin must be enabled unless we were told otherwise
3850 fschmid 338
                        if (pluginMap[name].enabled)
3207 craig 339
                                return true;
3850 fschmid 340
                        else
341
                                return includeDisabled;
342
                }
343
        }
3207 craig 344
        return false;
1549 subik 345
}
346
 
3207 craig 347
bool PluginManager::loadPlugin(PluginData & pda)
1549 subik 348
{
3207 craig 349
        typedef int (*getPluginAPIVersionPtr)();
350
        typedef ScPlugin* (*getPluginPtr)();
351
        getPluginAPIVersionPtr getPluginAPIVersion;
352
        getPluginPtr getPlugin;
1549 subik 353
 
3207 craig 354
        Q_ASSERT(pda.plugin == 0);
355
        Q_ASSERT(pda.pluginDLL == 0);
356
        Q_ASSERT(!pda.enabled);
357
        pda.plugin = 0;
1596 subik 358
 
3207 craig 359
        pda.pluginDLL = loadDLL(pda.pluginFile);
360
        if (!pda.pluginDLL)
1549 subik 361
                return false;
2629 craig 362
 
3207 craig 363
        getPluginAPIVersion = (getPluginAPIVersionPtr)
364
                resolveSym(pda.pluginDLL, pda.pluginName + "_getPluginAPIVersion");
365
        if (getPluginAPIVersion)
1549 subik 366
        {
3207 craig 367
                int gotVersion = (*getPluginAPIVersion)();
368
                if ( gotVersion != PLUGIN_API_VERSION )
1549 subik 369
                {
3207 craig 370
                        qDebug("API version mismatch when loading %s: Got %i, expected %i",
371
                                        pda.pluginFile.local8Bit().data(), gotVersion, PLUGIN_API_VERSION);
1549 subik 372
                }
3207 craig 373
                else
1549 subik 374
                {
3207 craig 375
                        getPlugin = (getPluginPtr)
376
                                resolveSym(pda.pluginDLL, pda.pluginName + "_getPlugin");
377
                        if (getPlugin)
1596 subik 378
                        {
3207 craig 379
                                pda.plugin = (*getPlugin)();
380
                                if (!pda.plugin)
381
                                {
382
                                        qDebug("Unable to get ScPlugin when loading %s",
383
                                                        pda.pluginFile.local8Bit().data());
384
                                }
385
                                else
386
                                        return true;
1596 subik 387
                        }
1549 subik 388
                }
389
        }
3207 craig 390
        unloadDLL(pda.pluginDLL);
391
        pda.pluginDLL = 0;
392
        Q_ASSERT(!pda.plugin);
393
        return false;
1549 subik 394
}
395
 
3207 craig 396
void PluginManager::cleanupPlugins()
1549 subik 397
{
3207 craig 398
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
399
                if (it.data().enabled == true)
400
                        finalizePlug(it.data());
1552 subik 401
}
402
 
3207 craig 403
void PluginManager::finalizePlug(PluginData & pda)
1552 subik 404
{
3207 craig 405
        typedef void (*freePluginPtr)(ScPlugin* plugin);
406
        if (pda.plugin)
1549 subik 407
        {
3207 craig 408
                if (pda.enabled)
409
                        disablePlugin(pda);
410
                Q_ASSERT(!pda.enabled);
411
                freePluginPtr freePlugin =
412
                        (freePluginPtr) resolveSym(pda.pluginDLL, pda.pluginName + "_freePlugin");
413
                if ( freePlugin )
414
                        (*freePlugin)( pda.plugin );
415
                pda.plugin = 0;
1549 subik 416
        }
3207 craig 417
        Q_ASSERT(!pda.enabled);
418
        if (pda.pluginDLL)
419
        {
420
                unloadDLL(pda.pluginDLL);
421
                pda.pluginDLL = 0;
422
        }
1549 subik 423
}
1552 subik 424
 
3207 craig 425
void PluginManager::disablePlugin(PluginData & pda)
1552 subik 426
{
3207 craig 427
        Q_ASSERT(pda.enabled);
428
        Q_ASSERT(pda.plugin);
429
        if (pda.plugin->inherits("ScActionPlugin"))
1552 subik 430
        {
3207 craig 431
                ScActionPlugin* plugin = dynamic_cast<ScActionPlugin*>(pda.plugin);
432
                Q_ASSERT(plugin);
433
                // FIXME: Correct way to delete action?
5781 cbradney 434
                delete ScCore->primaryMainWindow()->scrActions[plugin->actionInfo().name];
1552 subik 435
        }
3207 craig 436
        else if (pda.plugin->inherits("ScPersistentPlugin"))
437
        {
438
                ScPersistentPlugin* plugin = dynamic_cast<ScPersistentPlugin*>(pda.plugin);
439
                Q_ASSERT(plugin);
440
                plugin->cleanupPlugin();
441
        }
3850 fschmid 442
/* temporary hack to enable the import plugins */
443
        else if (pda.plugin->inherits("LoadSavePlugin"))
444
                pda.enabled = false;
3207 craig 445
        else
446
                Q_ASSERT(false); // We shouldn't ever have enabled an unknown plugin type.
447
        pda.enabled = false;
1552 subik 448
}
1665 craig 449
 
450
QCString PluginManager::platformDllExtension()
451
{
452
#ifdef __hpux
453
        // HP/UX
454
        return "sl";
455
#elif defined(__APPLE__) && defined(__MACH__)
456
        // MacOS/X, Darwin
1731 craig 457
 
458
        // MacOS/X may actually use both 'so' and 'dylib'. .so is usually used
459
        // for plugins etc, dylib for system and app libraries We need to
460
        // support this distinction in the plugin manager, but for now it's
461
        // most appropriate to return the extension used by plugins -- CR
462
 
463
        //return "dylib";
464
        return "so";
2629 craig 465
#elif defined(_WIN32) || defined(_WIN64)
466
        return "dll";
1665 craig 467
#else
468
        // Generic *NIX
469
        return "so";
470
#endif
471
}
2187 cbradney 472
 
473
void PluginManager::languageChange()
474
{
7176 subik 475
        ScPlugin* plugin = 0;
476
        ScActionPlugin* ixplug = 0;
477
        ScrAction* pluginAction = 0;
3207 craig 478
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
2187 cbradney 479
        {
7176 subik 480
                plugin = it.data().plugin;
3207 craig 481
                if (plugin)
482
                {
483
                        plugin->languageChange();
7176 subik 484
                        ixplug = dynamic_cast<ScActionPlugin*>(plugin);
3207 craig 485
                        if (ixplug)
486
                        {
487
                                ScActionPlugin::ActionInfo ai(ixplug->actionInfo());
7176 subik 488
                                pluginAction = ScCore->primaryMainWindow()->scrActions[ai.name];
3207 craig 489
                                if (pluginAction != 0)
490
                                        pluginAction->setMenuText( ai.text );
491
                        }
492
                }
2187 cbradney 493
        }
494
}
3207 craig 495
 
3246 craig 496
ScPlugin* PluginManager::getPlugin(const QCString & pluginName, bool includeDisabled) const
3207 craig 497
{
498
        if (DLLexists(pluginName, includeDisabled))
499
                return pluginMap[pluginName].plugin;
500
        return 0;
501
}
502
 
503
PluginManager & PluginManager::instance()
504
{
5243 cbradney 505
        return (*ScCore->pluginManager);
3207 craig 506
}
507
 
508
const QString & PluginManager::getPluginPath(const QCString pluginName) const
509
{
510
        // It is not legal to call this function without a valid
511
        // plug in name.
512
        Q_ASSERT(pluginMap.contains(pluginName));
513
        return pluginMap[pluginName].pluginFile;
514
}
515
 
516
bool & PluginManager::enableOnStartup(const QCString pluginName)
517
{
518
        // It is not legal to call this function without a valid
519
        // plug in name.
520
        Q_ASSERT(pluginMap.contains(pluginName));
521
        return pluginMap[pluginName].enableOnStartup;
522
}
523
 
3246 craig 524
bool PluginManager::enabled(const QCString pluginName)
525
{
526
        // It is not legal to call this function without a valid
527
        // plug in name.
528
        Q_ASSERT(pluginMap.contains(pluginName));
529
        return pluginMap[pluginName].enabled;
530
}
531
 
3383 craig 532
QValueList<QCString> PluginManager::pluginNames(
533
                bool includeDisabled, const char* inherits) const
3207 craig 534
{
3383 craig 535
        // Scan the plugin map for plugins...
3207 craig 536
        QValueList<QCString> names;
537
        for (PluginMap::ConstIterator it = pluginMap.constBegin(); it != pluginMap.constEnd(); ++it)
3383 craig 538
                if (includeDisabled || it.data().enabled)
539
                        // Only including plugins that inherit a named parent (if
540
                        // specified), using the QMetaObject system.
541
                        if (!inherits || it.data().plugin->inherits(inherits))
542
                                names.append(it.data().pluginName);
3207 craig 543
        return names;
544
}