Subversion Repositories Scribus

Rev

Rev 16577 | Rev 18438 | Go to most recent revision | 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"
3207 craig 8
#include "scplugin.h"
3850 fschmid 9
#include "loadsaveplugin.h"
2629 craig 10
 
10223 cbradney 11
#include <QDir>
10859 cbradney 12
#include <QEvent>
16546 jghali 13
#include <QMessageBox>
2629 craig 14
 
2688 craig 15
#include "scconfig.h"
2629 craig 16
 
1549 subik 17
#include "scribus.h"
5975 cbradney 18
#include "scribusdoc.h"
5243 cbradney 19
#include "scribuscore.h"
13576 cbradney 20
#include "ui/sctoolbar.h"
12566 cbradney 21
#include "selection.h"
14509 cbradney 22
#include "ui/scmwmenumanager.h"
1549 subik 23
#include "scraction.h"
13551 cbradney 24
#include "ui/splash.h"
2856 cbradney 25
#include "prefsmanager.h"
1552 subik 26
#include "prefsfile.h"
1693 craig 27
#include "scpaths.h"
5496 subik 28
#include "commonstrings.h"
17501 craig 29
#include "ui/storyeditor.h"
1549 subik 30
 
2629 craig 31
#ifdef HAVE_DLFCN_H
32
#include <dlfcn.h>
33
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
34
#include <windows.h>
35
#else
10223 cbradney 36
#include <QLibrary>
2629 craig 37
#endif
38
 
3205 craig 39
 
2187 cbradney 40
extern ScribusQApp *ScQApp;
1549 subik 41
 
3207 craig 42
PluginManager::PluginManager() :
43
        QObject(0),
44
        prefs(PrefsManager::instance()->prefsFile->getPluginContext("pluginmanager"))
1549 subik 45
{
46
}
47
 
48
PluginManager::~PluginManager()
49
{
50
}
51
 
2629 craig 52
void* PluginManager::loadDLL( QString plugin )
53
{
54
        void* lib = NULL;
55
#ifdef HAVE_DLFCN_H
16577 craig 56
        QString libpath = QDir::toNativeSeparators( plugin );
10553 fschmid 57
        lib = dlopen(libpath.toLocal8Bit().data(), RTLD_LAZY | RTLD_GLOBAL);
2629 craig 58
        if (!lib)
59
        {
4413 cbradney 60
                const char* error = dlerror();
2630 craig 61
                qDebug("%s: %s",
10493 fschmid 62
                                tr("Cannot find plugin", "plugin manager").toLocal8Bit().data(),
63
                                error ? error : tr("unknown error","plugin manager").toLocal8Bit().data());
2629 craig 64
        }
65
        dlerror();
66
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
16577 craig 67
        QString libpath = QDir::toNativeSeparators( plugin );
10304 jghali 68
        HINSTANCE hdll = LoadLibraryW( (const wchar_t*) libpath.utf16() );
2629 craig 69
        lib = (void*) hdll;
70
#else
71
        if( QFile::exists(plugin) )
72
                lib = (void*) new QLibrary( plugin );
73
        else
10752 craig 74
                qDebug("%s \"%s\"", tr("Cannot find plugin", "plugin manager").toLocal8Bit().data(), plugin.toLocal8Bit().data());
2629 craig 75
#endif
76
        return lib;
77
}
78
 
79
void* PluginManager::resolveSym( void* plugin, const char* sym )
80
{
81
        void* symAddr = NULL;
82
#ifdef HAVE_DLFCN_H
83
        const char* error;
84
        dlerror();
85
        symAddr = dlsym( plugin, sym );
86
        if ((error = dlerror()) != NULL)
87
        {
10493 fschmid 88
                qDebug("%s", tr("Cannot find symbol (%1)", "plugin manager").arg(error).toLocal8Bit().data());
2629 craig 89
                symAddr = NULL;
90
        }
91
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
92
        symAddr = (void* ) GetProcAddress( (HMODULE) plugin, sym);
93
        if ( symAddr == NULL)
10493 fschmid 94
                qDebug("%s", tr("Cannot find symbol (%1)", "plugin manager").arg(sym).toLocal8Bit().data());
2629 craig 95
#else
96
        QLibrary* qlib = (QLibrary*) plugin;
97
        if( plugin ) symAddr = qlib->resolve(sym);
98
        if ( symAddr == NULL)
10493 fschmid 99
                qDebug("%s", tr("Cannot find symbol (%1)", "plugin manager").arg(sym).toLocal8Bit().data());
2629 craig 100
#endif
101
        return symAddr;
102
}
103
 
104
void  PluginManager::unloadDLL( void* plugin )
105
{
106
#ifdef HAVE_DLFCN_H
107
        dlclose( plugin );
108
        dlerror();
109
#elif defined(DLL_USE_NATIVE_API) && defined(_WIN32)
110
        FreeLibrary( (HMODULE) plugin );
111
#else
112
        delete ( (QLibrary*) plugin );
113
#endif
114
}
115
 
1596 subik 116
void PluginManager::savePreferences()
117
{
118
        // write configuration
3207 craig 119
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
10516 cbradney 120
                prefs->set(it.value().pluginName, it.value().enableOnStartup);
1596 subik 121
}
122
 
8552 subik 123
QString PluginManager::getPluginName(QString fileName)
3207 craig 124
{
11162 cbradney 125
        // Must return plugin name. Note that this may be platform dependent;
3207 craig 126
        // it's likely to need some adjustment for platform naming schemes.
127
        // It currently handles:
128
        //    (lib)?pluginname(\.pluginext)?
129
        QFileInfo fi(fileName);
130
        QString baseName(fi.baseName());
131
        if (baseName.startsWith("lib"))
132
                baseName = baseName.remove(0,3);
133
        if (baseName.endsWith(platformDllExtension()))
15498 jghali 134
                baseName.chop(1 + platformDllExtension().length());
3207 craig 135
        // check name
136
        for (int i = 0; i < (int)baseName.length(); i++)
137
                if (! baseName[i].isLetterOrNumber() && baseName[i] != '_' )
138
                {
139
                        qDebug("Invalid character in plugin name for %s; skipping",
10493 fschmid 140
                                        fileName.toLocal8Bit().data());
8552 subik 141
                        return QString();
3207 craig 142
                }
10553 fschmid 143
        return baseName.toLatin1();
3207 craig 144
}
145
 
5496 subik 146
int PluginManager::initPlugin(const QString fileName)
147
{
148
        PluginData pda;
149
        pda.pluginFile = QString("%1/%2").arg(ScPaths::instance().pluginDir()).arg(fileName);
150
        pda.pluginName = getPluginName(pda.pluginFile);
151
        if (pda.pluginName.isNull())
152
                // Couldn't determine plugname from filename. We've already complained, so
153
                // move on to the next one.
154
                return 0;
155
        pda.plugin = 0;
156
        pda.pluginDLL = 0;
157
        pda.enabled = false;
12566 cbradney 158
        pda.enableOnStartup = prefs->getBool(pda.pluginName, false);
6260 fschmid 159
        ScCore->setSplashStatus( tr("Plugin: loading %1", "plugin manager").arg(pda.pluginName));
5496 subik 160
        if (loadPlugin(pda))
161
        {
13382 cbradney 162
                //HACK: Always enable our only persistent plugin, scripter
163
                if (pda.plugin->inherits("ScPersistentPlugin"))
164
                        pda.enableOnStartup=true;
5496 subik 165
                if (pda.enableOnStartup)
166
                        enablePlugin(pda);
167
                pluginMap.insert(pda.pluginName, pda);
168
                return 1;
169
        }
170
        return 0;
171
}
172
 
1549 subik 173
void PluginManager::initPlugs()
174
{
3207 craig 175
        Q_ASSERT(!pluginMap.count());
176
        QString libPattern = QString("*.%1*").arg(platformDllExtension());
5496 subik 177
        QMap<QString,int> allPlugs;
8561 subik 178
        int loaded = 0;
5496 subik 179
        uint changes = 1;
5710 subik 180
        QStringList failedPlugs; // output string for warn dialog
1693 craig 181
 
5047 subik 182
        /*! \note QDir::Reversed is there due the Mac plugin dependency.
183
        barcode depends on psimport. and load on that platform expect the
5496 subik 184
        psimp before barcode.You know, security by obscurity ;) PV */
1693 craig 185
        QDir dirList(ScPaths::instance().pluginDir(),
5047 subik 186
                                 libPattern, QDir::Name | QDir::Reversed,
10402 jghali 187
                                 (QDir::Filter) PluginManager::platformDllSearchFlags());
1693 craig 188
 
5496 subik 189
        if ((!dirList.exists()) || (dirList.count() == 0))
190
                return;
191
        for (uint dc = 0; dc < dirList.count(); ++dc)
1549 subik 192
        {
5496 subik 193
                int res = initPlugin(dirList[dc]);
194
                allPlugs[dirList[dc]] = res;
195
                if (res != 0)
196
                        ++loaded;
5710 subik 197
                else
198
                        failedPlugs.append(dirList[dc]);
5496 subik 199
        }
200
        /* Re-try the failed plugins again and again until it promote
201
        any progress (changes variable is changing ;)) */
7176 subik 202
        QMap<QString,int>::Iterator it;
5496 subik 203
        while (loaded < allPlugs.count() && changes!=0)
204
        {
205
                changes = 0;
206
                for (it = allPlugs.begin(); it != allPlugs.end(); ++it)
1549 subik 207
                {
10516 cbradney 208
                        if (it.value() != 0)
3207 craig 209
                                continue;
5496 subik 210
                        int res = initPlugin(it.key());
211
                        allPlugs[it.key()] = res;
212
                        if (res == 1)
1549 subik 213
                        {
5496 subik 214
                                ++loaded;
215
                                ++changes;
10553 fschmid 216
                                failedPlugs.removeAll(it.key());
1549 subik 217
                        }
218
                }
219
        }
5496 subik 220
        if (loaded != allPlugs.count())
5655 cbradney 221
        {
222
                if (ScCore->usingGUI())
223
                {
5710 subik 224
                        bool splashShown = ScCore->splashShowing();
225
                        QString failedStr("<ul>");
226
                        for (QStringList::Iterator it = failedPlugs.begin(); it != failedPlugs.end(); ++it)
227
                                failedStr += "<li>" + *it + "</li>";
228
                        failedStr += "</ul>";
5656 cbradney 229
                        if (splashShown)
230
                                ScCore->showSplash(false);
5781 cbradney 231
                        QMessageBox::warning(ScCore->primaryMainWindow(), CommonStrings::trWarning,
6367 subik 232
                                                                 "<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 233
                                                                                ).arg(allPlugs.count()-loaded).arg(allPlugs.count()).arg(failedStr)
5496 subik 234
                                                                         + "</qt>",
235
                                                         CommonStrings::tr_OK);
5656 cbradney 236
                        if (splashShown)
237
                                ScCore->showSplash(true);
5655 cbradney 238
                }
239
        }
1549 subik 240
}
241
 
11162 cbradney 242
// After a plugin has been initialized, this method calls its setup
3207 craig 243
// routines and connects it to the application.
244
void PluginManager::enablePlugin(PluginData & pda)
1549 subik 245
{
3207 craig 246
        Q_ASSERT(pda.enabled == false);
247
        QString failReason;
5243 cbradney 248
        bool isActionPlugin=false;
3207 craig 249
        if (pda.plugin->inherits("ScActionPlugin"))
1549 subik 250
        {
11580 subik 251
//              ScActionPlugin* plugin = dynamic_cast<ScActionPlugin*>(pda.plugin);
252
//              Q_ASSERT(plugin);
5243 cbradney 253
                isActionPlugin=true;
254
                /*
3207 craig 255
                pda.enabled = setupPluginActions(plugin);
256
                if (!pda.enabled)
257
                        failReason = tr("init failed", "plugin load error");
5243 cbradney 258
                */
1549 subik 259
        }
3207 craig 260
        else if (pda.plugin->inherits("ScPersistentPlugin"))
1549 subik 261
        {
3207 craig 262
                ScPersistentPlugin* plugin = dynamic_cast<ScPersistentPlugin*>(pda.plugin);
9810 avox 263
                assert(plugin);
3207 craig 264
                pda.enabled = plugin->initPlugin();
265
                if (!pda.enabled)
266
                        failReason = tr("init failed", "plugin load error");
1549 subik 267
        }
3850 fschmid 268
/* temporary hack to enable the import plugins */
269
        else if (pda.plugin->inherits("LoadSavePlugin"))
270
                pda.enabled = true;
1549 subik 271
        else
3207 craig 272
                failReason = tr("unknown plugin type", "plugin load error");
5243 cbradney 273
        if (pda.enabled || isActionPlugin)
274
                ScCore->setSplashStatus(
275
                                tr("Plugin: %1 loaded", "plugin manager")
276
                                .arg(pda.plugin->fullTrName()));
277
        else
278
                ScCore->setSplashStatus(
279
                                tr("Plugin: %1 failed to load: %2", "plugin manager")
280
                                .arg(pda.plugin->fullTrName()).arg(failReason));
281
}
282
 
283
bool PluginManager::setupPluginActions(ScribusMainWindow *mw)
284
{
285
        Q_CHECK_PTR(mw);
7176 subik 286
        ScActionPlugin* plugin = 0;
287
 
5243 cbradney 288
        mw->scrMenuMgr->addMenuSeparator("Extras");
289
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
1549 subik 290
        {
10516 cbradney 291
                if (it.value().plugin->inherits("ScActionPlugin"))
5243 cbradney 292
                {
293
                        //Add in ScrAction based plugin linkage
294
                        //Insert DLL Action into Dictionary with values from plugin interface
10516 cbradney 295
                        plugin = dynamic_cast<ScActionPlugin*>(it.value().plugin);
9810 avox 296
                        assert(plugin);
5243 cbradney 297
                        ScActionPlugin::ActionInfo ai(plugin->actionInfo());
9857 cbradney 298
                        ScrAction* action = new ScrAction(ScrAction::ActionDLL, ai.icon1, ai.icon2, ai.text, ai.keySequence, mw);
5243 cbradney 299
                        Q_CHECK_PTR(action);
15637 fschmid 300
                        action->setStatusTip(ai.helpText);
301
                        action->setToolTip(ai.helpText);
5243 cbradney 302
                        mw->scrActions.insert(ai.name, action);
7126 subik 303
 
5243 cbradney 304
                        // then enable and connect up the action
305
                        mw->scrActions[ai.name]->setEnabled(ai.enabledOnStartup);
306
                        // Connect action's activated signal with the plugin's run method
10728 cbradney 307
                        it.value().enabled = connect( mw->scrActions[ai.name], SIGNAL(triggeredData(ScribusDoc*)),
5781 cbradney 308
                                                        plugin, SLOT(run(ScribusDoc*)) );
5243 cbradney 309
                        //Get the menu manager to add the DLL's menu item to the right menu, after the chosen existing item
310
                        if ( ai.menuAfterName.isEmpty() )
11040 fschmid 311
                        {
312
                                if (!ai.menu.isEmpty())
11050 fschmid 313
                                {
314
                                        if ((!ai.subMenuName.isEmpty()) && (!ai.parentMenu.isEmpty()))
315
                                        {
316
                                                if (!mw->scrMenuMgr->menuExists(ai.menu))
317
                                                        mw->scrMenuMgr->createMenu(ai.menu, ai.subMenuName, ai.parentMenu);
318
                                        }
14509 cbradney 319
                                        mw->scrMenuMgr->addMenuItem(mw->scrActions[ai.name], ai.menu, true);
11050 fschmid 320
                                }
11040 fschmid 321
                        }
5243 cbradney 322
                        else
5781 cbradney 323
                        {
16016 fschmid 324
//                              QString actionName(ai.menu.toLower()+ai.menuAfterName);
325
                                QString actionName(ai.menuAfterName);
5781 cbradney 326
                                ScrAction* afterAction=0;
327
                                if (mw->scrActions.contains(actionName))
328
                                        afterAction=mw->scrActions[actionName];
11050 fschmid 329
                                if ((!ai.subMenuName.isEmpty()) && (!ai.parentMenu.isEmpty()))
330
                                {
331
                                        if (!mw->scrMenuMgr->menuExists(ai.menu))
332
                                                mw->scrMenuMgr->createMenu(ai.menu, ai.subMenuName, ai.parentMenu);
333
                                }
14509 cbradney 334
                                mw->scrMenuMgr->addMenuItemAfter(mw->scrActions[ai.name], ai.menu, true, afterAction);
5781 cbradney 335
                        }
11040 fschmid 336
                        if (!ai.toolbar.isEmpty())
337
                        {
338
                                QString tbName = QString("ToolBar-%1").arg(ai.toolbar);
339
                                if (mw->scrToolBars.contains(tbName))
340
                                        mw->scrToolBars[tbName]->addAction(mw->scrActions[ai.name]);
341
                                else
342
                                {
343
                                        ScToolBar *tb = new ScToolBar(ai.toolBarName, ai.toolbar, mw);
344
                                        tb->addAction(mw->scrActions[ai.name]);
345
                                        mw->addScToolBar(tb, tbName);
346
                                }
347
                        }
10516 cbradney 348
                        if (it.value().enabled)
11040 fschmid 349
                                ScCore->setSplashStatus( tr("Plugin: %1 initialized ok ", "plugin manager").arg(plugin->fullTrName()));
5243 cbradney 350
                        else
11040 fschmid 351
                                ScCore->setSplashStatus( tr("Plugin: %1 failed post initialization", "plugin manager").arg(plugin->fullTrName()));
5243 cbradney 352
                }
3207 craig 353
                else
5243 cbradney 354
                {
10516 cbradney 355
                        it.value().plugin->addToMainWindowMenu(mw);
5243 cbradney 356
                }
7126 subik 357
 
1549 subik 358
        }
5243 cbradney 359
        return true;
1549 subik 360
}
361
 
17501 craig 362
bool PluginManager::setupPluginActions(StoryEditor *sew)
363
{
364
        Q_CHECK_PTR(sew);
365
        ScActionPlugin* plugin = 0;
366
 
367
        //sew->seMenuMgr->addMenuSeparator("Extras");
368
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
369
        {
370
                if (it.value().plugin->inherits("ScActionPlugin"))
371
                {
372
                        //Add in ScrAction based plugin linkage
373
                        //Insert DLL Action into Dictionary with values from plugin interface
374
                        plugin = dynamic_cast<ScActionPlugin*>(it.value().plugin);
375
                        assert(plugin);
376
                        ScActionPlugin::ActionInfo ai(plugin->actionInfo());
377
                        if (ai.enabledForStoryEditor)
378
                        {
379
                                ScrAction* action = new ScrAction(ScrAction::ActionDLLSE, ai.icon1, ai.icon2, ai.text, ai.keySequence, sew);
380
                                Q_CHECK_PTR(action);
381
                                sew->seActions.insert(ai.name, action);
382
 
383
                                // then enable and connect up the action
384
                                sew->seActions[ai.name]->setEnabled(ai.enabledForStoryEditor);
385
 
386
                                // Connect action's activated signal with the plugin's run method
387
                                it.value().enabled = connect( sew->seActions[ai.name], SIGNAL(triggeredData(QWidget*, ScribusDoc*)),
388
                                                        plugin, SLOT(run(QWidget*, ScribusDoc*)) );
389
                                //Get the menu manager to add the DLL's menu item to the right menu, after the chosen existing item
390
                                if ( ai.menuAfterName.isEmpty() )
391
                                {
392
                                        if (!ai.seMenu.isEmpty())
393
                                        {
394
                                                if ((!ai.subMenuName.isEmpty()) && (!ai.parentMenu.isEmpty()))
395
                                                {
396
                                                        if (!sew->seMenuMgr->menuExists(ai.seMenu))
397
                                                                sew->seMenuMgr->createMenu(ai.seMenu, ai.subMenuName, ai.parentMenu);
398
                                                }
399
                                                sew->seMenuMgr->addMenuItem(sew->seActions[ai.name], ai.seMenu, true);
400
                                        }
401
                                }
402
                                else
403
                                {
404
                                        QString actionName(ai.seMenu.toLower()+ai.menuAfterName);
405
                                        ScrAction* afterAction=0;
406
                                        if (sew->seActions.contains(actionName))
407
                                                afterAction=sew->seActions[actionName];
408
                                        if ((!ai.subMenuName.isEmpty()) && (!ai.parentMenu.isEmpty()))
409
                                        {
410
                                                if (!sew->seMenuMgr->menuExists(ai.seMenu))
411
                                                        sew->seMenuMgr->createMenu(ai.seMenu, ai.subMenuName, ai.parentMenu);
412
                                        }
413
                                        sew->seMenuMgr->addMenuItemAfter(sew->seActions[ai.name], ai.seMenu, true, afterAction);
414
                                }
415
                        }
416
                }
417
        }
418
        return true;
419
}
420
 
421
 
12566 cbradney 422
void PluginManager::enableOnlyStartupPluginActions(ScribusMainWindow* mw)
423
{
424
        Q_CHECK_PTR(mw);
425
        ScActionPlugin* plugin = 0;
426
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
427
        {
428
                if (it.value().plugin->inherits("ScActionPlugin"))
429
                {
430
                        plugin = dynamic_cast<ScActionPlugin*>(it.value().plugin);
431
                        assert(plugin);
432
                        ScActionPlugin::ActionInfo ai(plugin->actionInfo());
433
                        if (mw->scrActions.contains(ai.name))
434
                                mw->scrActions[ai.name]->setEnabled(ai.enabledOnStartup);
435
                }
436
        }
437
}
438
 
439
void PluginManager::enablePluginActionsForSelection(ScribusMainWindow* mw)
440
{
441
        Q_CHECK_PTR(mw);
442
        ScribusDoc* doc=mw->doc;
443
        if (!doc)
444
                return;
445
 
12794 cbradney 446
        ScActionPlugin* ixplug = 0;
12566 cbradney 447
        ScrAction* pluginAction = 0;
448
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
449
        {
450
                if (it.value().plugin->inherits("ScActionPlugin"))
451
                {
452
                        ixplug = dynamic_cast<ScActionPlugin*>(it.value().plugin);
453
                        Q_ASSERT(ixplug);
12794 cbradney 454
                        if (ixplug)
12566 cbradney 455
                        {
12794 cbradney 456
                                ScActionPlugin::ActionInfo ai(ixplug->actionInfo());
457
                                pluginAction = mw->scrActions[ai.name];
458
                                if (pluginAction != 0)
459
                                {
460
                                        if (doc->m_Selection->count() != 0)
461
                                                pluginAction->setEnabled(ixplug->handleSelection(doc, doc->m_Selection->itemAt(0)->itemType()));
462
                                        else
463
                                                pluginAction->setEnabled(ixplug->handleSelection(doc));
464
                                }
12566 cbradney 465
                        }
466
                }
467
        }
468
}
469
 
8552 subik 470
bool PluginManager::DLLexists(QString name, bool includeDisabled) const
1549 subik 471
{
3207 craig 472
        // the plugin name must be known
473
        if (pluginMap.contains(name))
3850 fschmid 474
        {
3207 craig 475
                // the plugin must be loaded
476
                if (pluginMap[name].plugin)
3850 fschmid 477
                {
3383 craig 478
                        // and the plugin must be enabled unless we were told otherwise
3850 fschmid 479
                        if (pluginMap[name].enabled)
3207 craig 480
                                return true;
3850 fschmid 481
                        else
482
                                return includeDisabled;
483
                }
484
        }
3207 craig 485
        return false;
1549 subik 486
}
487
 
3207 craig 488
bool PluginManager::loadPlugin(PluginData & pda)
1549 subik 489
{
3207 craig 490
        typedef int (*getPluginAPIVersionPtr)();
491
        typedef ScPlugin* (*getPluginPtr)();
492
        getPluginAPIVersionPtr getPluginAPIVersion;
493
        getPluginPtr getPlugin;
1549 subik 494
 
3207 craig 495
        Q_ASSERT(pda.plugin == 0);
496
        Q_ASSERT(pda.pluginDLL == 0);
497
        Q_ASSERT(!pda.enabled);
498
        pda.plugin = 0;
1596 subik 499
 
3207 craig 500
        pda.pluginDLL = loadDLL(pda.pluginFile);
501
        if (!pda.pluginDLL)
1549 subik 502
                return false;
2629 craig 503
 
3207 craig 504
        getPluginAPIVersion = (getPluginAPIVersionPtr)
10553 fschmid 505
                resolveSym(pda.pluginDLL, QString(pda.pluginName + "_getPluginAPIVersion").toLocal8Bit().data());
3207 craig 506
        if (getPluginAPIVersion)
1549 subik 507
        {
3207 craig 508
                int gotVersion = (*getPluginAPIVersion)();
509
                if ( gotVersion != PLUGIN_API_VERSION )
1549 subik 510
                {
3207 craig 511
                        qDebug("API version mismatch when loading %s: Got %i, expected %i",
10493 fschmid 512
                                        pda.pluginFile.toLocal8Bit().data(), gotVersion, PLUGIN_API_VERSION);
1549 subik 513
                }
3207 craig 514
                else
1549 subik 515
                {
3207 craig 516
                        getPlugin = (getPluginPtr)
10553 fschmid 517
                                resolveSym(pda.pluginDLL, QString(pda.pluginName + "_getPlugin").toLocal8Bit().data());
3207 craig 518
                        if (getPlugin)
1596 subik 519
                        {
3207 craig 520
                                pda.plugin = (*getPlugin)();
521
                                if (!pda.plugin)
522
                                {
523
                                        qDebug("Unable to get ScPlugin when loading %s",
10493 fschmid 524
                                                        pda.pluginFile.toLocal8Bit().data());
3207 craig 525
                                }
526
                                else
527
                                        return true;
1596 subik 528
                        }
1549 subik 529
                }
530
        }
3207 craig 531
        unloadDLL(pda.pluginDLL);
532
        pda.pluginDLL = 0;
533
        Q_ASSERT(!pda.plugin);
534
        return false;
1549 subik 535
}
536
 
3207 craig 537
void PluginManager::cleanupPlugins()
1549 subik 538
{
3207 craig 539
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
10516 cbradney 540
                if (it.value().enabled == true)
541
                        finalizePlug(it.value());
1552 subik 542
}
543
 
3207 craig 544
void PluginManager::finalizePlug(PluginData & pda)
1552 subik 545
{
3207 craig 546
        typedef void (*freePluginPtr)(ScPlugin* plugin);
547
        if (pda.plugin)
1549 subik 548
        {
3207 craig 549
                if (pda.enabled)
550
                        disablePlugin(pda);
551
                Q_ASSERT(!pda.enabled);
552
                freePluginPtr freePlugin =
10553 fschmid 553
                        (freePluginPtr) resolveSym(pda.pluginDLL, QString(pda.pluginName + "_freePlugin").toLocal8Bit().data());
3207 craig 554
                if ( freePlugin )
555
                        (*freePlugin)( pda.plugin );
556
                pda.plugin = 0;
1549 subik 557
        }
3207 craig 558
        Q_ASSERT(!pda.enabled);
559
        if (pda.pluginDLL)
560
        {
561
                unloadDLL(pda.pluginDLL);
562
                pda.pluginDLL = 0;
563
        }
1549 subik 564
}
1552 subik 565
 
3207 craig 566
void PluginManager::disablePlugin(PluginData & pda)
1552 subik 567
{
3207 craig 568
        Q_ASSERT(pda.enabled);
569
        Q_ASSERT(pda.plugin);
570
        if (pda.plugin->inherits("ScActionPlugin"))
1552 subik 571
        {
3207 craig 572
                ScActionPlugin* plugin = dynamic_cast<ScActionPlugin*>(pda.plugin);
9810 avox 573
                assert(plugin);
3207 craig 574
                // FIXME: Correct way to delete action?
5781 cbradney 575
                delete ScCore->primaryMainWindow()->scrActions[plugin->actionInfo().name];
1552 subik 576
        }
3207 craig 577
        else if (pda.plugin->inherits("ScPersistentPlugin"))
578
        {
579
                ScPersistentPlugin* plugin = dynamic_cast<ScPersistentPlugin*>(pda.plugin);
9810 avox 580
                assert(plugin);
3207 craig 581
                plugin->cleanupPlugin();
582
        }
3850 fschmid 583
/* temporary hack to enable the import plugins */
584
        else if (pda.plugin->inherits("LoadSavePlugin"))
585
                pda.enabled = false;
3207 craig 586
        else
587
                Q_ASSERT(false); // We shouldn't ever have enabled an unknown plugin type.
588
        pda.enabled = false;
1552 subik 589
}
1665 craig 590
 
8552 subik 591
QString PluginManager::platformDllExtension()
1665 craig 592
{
593
#ifdef __hpux
594
        // HP/UX
595
        return "sl";
596
#elif defined(__APPLE__) && defined(__MACH__)
597
        // MacOS/X, Darwin
1731 craig 598
 
599
        // MacOS/X may actually use both 'so' and 'dylib'. .so is usually used
600
        // for plugins etc, dylib for system and app libraries We need to
601
        // support this distinction in the plugin manager, but for now it's
602
        // most appropriate to return the extension used by plugins -- CR
603
 
604
        //return "dylib";
605
        return "so";
2629 craig 606
#elif defined(_WIN32) || defined(_WIN64)
607
        return "dll";
1665 craig 608
#else
609
        // Generic *NIX
610
        return "so";
611
#endif
612
}
2187 cbradney 613
 
10402 jghali 614
int PluginManager::platformDllSearchFlags()
615
{
616
#if defined(_WIN32) || defined(_WIN64)
617
        return (QDir::Files | QDir::NoSymLinks);
618
#else
619
        return (QDir::Files | QDir::Executable | QDir::NoSymLinks);
620
#endif
621
}
622
 
10859 cbradney 623
void PluginManager::changeEvent(QEvent *e)
624
{
625
        if (e->type() == QEvent::LanguageChange)
626
        {
627
                languageChange();
628
        }
629
}
630
 
2187 cbradney 631
void PluginManager::languageChange()
632
{
7176 subik 633
        ScPlugin* plugin = 0;
634
        ScActionPlugin* ixplug = 0;
635
        ScrAction* pluginAction = 0;
3207 craig 636
        for (PluginMap::Iterator it = pluginMap.begin(); it != pluginMap.end(); ++it)
2187 cbradney 637
        {
10516 cbradney 638
                plugin = it.value().plugin;
3207 craig 639
                if (plugin)
640
                {
641
                        plugin->languageChange();
7176 subik 642
                        ixplug = dynamic_cast<ScActionPlugin*>(plugin);
3207 craig 643
                        if (ixplug)
644
                        {
645
                                ScActionPlugin::ActionInfo ai(ixplug->actionInfo());
7176 subik 646
                                pluginAction = ScCore->primaryMainWindow()->scrActions[ai.name];
3207 craig 647
                                if (pluginAction != 0)
10427 cbradney 648
                                        pluginAction->setText( ai.text );
12088 fschmid 649
                                if ((!ai.menu.isEmpty()) && (!ai.subMenuName.isEmpty()))
650
                                        ScCore->primaryMainWindow()->scrMenuMgr->setText(ai.menu, ai.subMenuName);
3207 craig 651
                        }
652
                }
2187 cbradney 653
        }
654
}
3207 craig 655
 
8552 subik 656
ScPlugin* PluginManager::getPlugin(const QString & pluginName, bool includeDisabled) const
3207 craig 657
{
658
        if (DLLexists(pluginName, includeDisabled))
659
                return pluginMap[pluginName].plugin;
660
        return 0;
661
}
662
 
663
PluginManager & PluginManager::instance()
664
{
5243 cbradney 665
        return (*ScCore->pluginManager);
3207 craig 666
}
667
 
8910 jghali 668
const QString PluginManager::getPluginPath(const QString & pluginName) const
3207 craig 669
{
670
        // It is not legal to call this function without a valid
671
        // plug in name.
672
        Q_ASSERT(pluginMap.contains(pluginName));
673
        return pluginMap[pluginName].pluginFile;
674
}
675
 
8552 subik 676
bool & PluginManager::enableOnStartup(const QString & pluginName)
3207 craig 677
{
678
        // It is not legal to call this function without a valid
679
        // plug in name.
680
        Q_ASSERT(pluginMap.contains(pluginName));
681
        return pluginMap[pluginName].enableOnStartup;
682
}
683
 
8552 subik 684
bool PluginManager::enabled(const QString & pluginName)
3246 craig 685
{
686
        // It is not legal to call this function without a valid
687
        // plug in name.
688
        Q_ASSERT(pluginMap.contains(pluginName));
689
        return pluginMap[pluginName].enabled;
690
}
691
 
8552 subik 692
QStringList PluginManager::pluginNames(
3383 craig 693
                bool includeDisabled, const char* inherits) const
3207 craig 694
{
3383 craig 695
        // Scan the plugin map for plugins...
8552 subik 696
        QStringList names;
3207 craig 697
        for (PluginMap::ConstIterator it = pluginMap.constBegin(); it != pluginMap.constEnd(); ++it)
10516 cbradney 698
                if (includeDisabled || it.value().enabled)
3383 craig 699
                        // Only including plugins that inherit a named parent (if
700
                        // specified), using the QMetaObject system.
10516 cbradney 701
                        if (!inherits || it.value().plugin->inherits(inherits))
702
                                names.append(it.value().pluginName);
3207 craig 703
        return names;
704
}