summaryrefslogtreecommitdiffstats
path: root/kradio3/src/pluginmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kradio3/src/pluginmanager.cpp')
-rw-r--r--kradio3/src/pluginmanager.cpp538
1 files changed, 538 insertions, 0 deletions
diff --git a/kradio3/src/pluginmanager.cpp b/kradio3/src/pluginmanager.cpp
new file mode 100644
index 0000000..adac66c
--- /dev/null
+++ b/kradio3/src/pluginmanager.cpp
@@ -0,0 +1,538 @@
+/***************************************************************************
+ pluginmanager.cpp - description
+ -------------------
+ begin : Mon Apr 28 2003
+ copyright : (C) 2003 by Martin Witte
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "include/plugins.h"
+#include "include/pluginmanager.h"
+#include "include/pluginmanager-configuration.h"
+#include "include/plugin_configuration_dialog.h"
+#include "include/kradioapp.h"
+
+#include <kiconloader.h>
+#include <kdialogbase.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kprogress.h>
+
+#include <qlayout.h>
+#include <qframe.h>
+#include <qmenudata.h>
+
+#include "include/debug-profiler.h"
+
+PluginManager::PluginManager(
+ const QString &name,
+ KRadioApp *app,
+ const QString &configDialogTitle,
+ const QString &aboutDialogTitle)
+ : m_Name(name),
+ m_Application(app),
+ m_showProgressBar(true),
+ m_configDialog (NULL),
+ m_pluginManagerConfiguration(NULL),
+ m_aboutDialog(NULL),
+ m_configDialogTitle(configDialogTitle),
+ m_aboutDialogTitle (aboutDialogTitle)
+{
+}
+
+
+PluginManager::~PluginManager()
+{
+ delete m_pluginManagerConfiguration;
+ m_pluginManagerConfiguration = NULL;
+
+ // config Dialog must be deleted first, so we can clear m_configPages
+ // without problems (this is the only place where our config dialog is deleted)
+ // Without clearing this list, those pages would be deleted, but
+ // we would try to delete them another time when the associated plugin is
+ // deleted, because m_configPages is out of date.
+ if (m_configDialog) {
+ m_configDialog->cancel();
+ delete m_configDialog;
+ }
+ m_configPages.clear();
+ m_configPageFrames.clear();
+ m_configDialog = NULL;
+
+ if (m_aboutDialog)
+ delete m_aboutDialog;
+ m_aboutPages.clear();
+ m_aboutPageFrames.clear();
+ m_aboutDialog = NULL;
+
+ while (PluginBase *p = m_plugins.getFirst()) {
+ deletePlugin(p);
+ }
+}
+
+
+void PluginManager::noticeLibrariesChanged()
+{
+ if (m_pluginManagerConfiguration)
+ m_pluginManagerConfiguration->noticePluginLibrariesChanged();
+}
+
+
+void PluginManager::unloadPlugins(const QString &class_name)
+{
+ PluginList plugins = m_plugins;
+ for (PluginIterator it(plugins); it.current(); ++it) {
+ PluginBase *p = it.current();
+ if (p->pluginClassName() == class_name) {
+ deletePlugin(p);
+ }
+ }
+}
+
+
+void PluginManager::addWidgetPluginMenuItems(QMenuData *menu, QMap<WidgetPluginBase *,int> &map) const
+{
+ map.clear();
+
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ WidgetPluginBase *b = dynamic_cast<WidgetPluginBase*>(it.current());
+ if (!b) continue;
+
+ int id = menu->insertItem("dummy", b->getWidget(), SLOT(toggleShown()));
+ map.insert(b, id);
+ updateWidgetPluginMenuItem(b, menu, map, b->isReallyVisible());
+ }
+}
+
+
+void PluginManager::updateWidgetPluginMenuItem(WidgetPluginBase *b, QMenuData *menu, QMap<WidgetPluginBase *,int> &map, bool shown) const
+{
+ if (!b || !map.contains(b))
+ return;
+
+ const QString &name = b->description();
+ QString text = (shown ? i18n("Hide %1") : i18n("Show %1")).arg(name);
+
+ menu->changeItem(map[b],
+ QIconSet(SmallIconSet(!shown ? "kradio_show" : "kradio_hide")),
+ text);
+}
+
+
+void PluginManager::noticeWidgetPluginShown(WidgetPluginBase *p, bool shown)
+{
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ it.current()->noticeWidgetPluginShown(p, shown);
+ }
+}
+
+
+PluginBase *PluginManager::getPluginByName(const QString &name) const
+{
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ if (it.current()->name() == name)
+ return it.current();
+ }
+ return NULL;
+}
+
+
+void PluginManager::insertPlugin(PluginBase *p)
+{
+ BlockProfiler profiler("PluginManager::insertPlugin");
+
+ if (p) {
+ BlockProfiler profiler_cfg("PluginManager::insertPlugin - about/config");
+
+ /*kdDebug() << QDateTime::currentDateTime().toString(Qt::ISODate)
+ << " Debug: Adding Plugin: " << p->name() << "\n";*/
+
+ if (!m_configDialog)
+ createConfigDialog(m_configDialogTitle);
+ if (!m_aboutDialog)
+ createAboutDialog(m_aboutDialogTitle);
+
+ m_plugins.append(p);
+ p->setManager(this);
+
+ addConfigurationPage (p, p->createConfigurationPage());
+ addAboutPage (p, p->createAboutPage());
+
+ profiler_cfg.stop();
+ BlockProfiler profiler_connect("PluginManager::insertPlugin - connect");
+
+ // connect plugins with each other
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ if (it.current() != p) {
+ /*kdDebug() << QDateTime::currentDateTime().toString(Qt::ISODate)
+ << " Debug: connecting with " << it.current()->name() << "\n";*/
+ p->connectI(it.current());
+ }
+ }
+
+ // perhaps some existing config pages will profit from new plugin
+ // example: timecontrol profits from radio plugin
+ for (QWidgetDictIterator it(m_configPages); it.current(); ++it) {
+ Interface *i = dynamic_cast<Interface *>(it.current());
+ if (i)
+ i->connectI(p);
+ }
+
+ profiler_connect.stop();
+ BlockProfiler profiler_widget("PluginManager::insertPlugin - notifywidgets");
+
+ WidgetPluginBase *w1 = dynamic_cast<WidgetPluginBase*>(p);
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ it.current()->noticePluginsChanged(m_plugins);
+ if (w1)
+ it.current()->noticeWidgetPluginShown(w1, w1->isReallyVisible());
+
+ WidgetPluginBase *w2 = dynamic_cast<WidgetPluginBase*>(it.current());
+ if (w2)
+ p->noticeWidgetPluginShown(w2, w2->isReallyVisible());
+ }
+
+ if (m_pluginManagerConfiguration)
+ m_pluginManagerConfiguration->noticePluginsChanged();
+
+ profiler_widget.stop();
+ }
+}
+
+
+void PluginManager::deletePlugin(PluginBase *p)
+{
+ if (p && m_plugins.contains(p)) {
+ removePlugin(p);
+ delete p;
+ }
+}
+
+
+void PluginManager::removePlugin(PluginBase *p)
+{
+ if (p && m_plugins.contains(p)) {
+
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ if (it.current() != p) {
+ // workaround for buggy compilers/libstdc++
+ if (p->destructorCalled()) {
+ p->PluginBase::disconnectI(it.current());
+ } else {
+ p->disconnectI(it.current());
+ }
+ }
+ }
+
+ // remove config page from config dialog, only chance is to delete it
+ // plugin will be notified automatically (mechanism implemented by
+ // PluginBase)
+ while (QFrame *f = m_configPageFrames.find(p)) {
+ m_configPageFrames.remove(p);
+ m_configPages.remove(p);
+ delete f;
+ }
+ while (QFrame *f = m_aboutPageFrames.find(p)) {
+ m_aboutPageFrames.remove(p);
+ m_aboutPages.remove(p);
+ delete f;
+ }
+
+ // remove bindings between me and plugin
+ m_plugins.remove(p);
+ p->unsetManager();
+
+ p->noticePluginsChanged(PluginList());
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ it.current()->noticePluginsChanged(m_plugins);
+ }
+
+ if (m_pluginManagerConfiguration)
+ m_pluginManagerConfiguration->noticePluginsChanged();
+ }
+}
+
+
+void PluginManager::addConfigurationPage (PluginBase *forWhom,
+ const ConfigPageInfo &info)
+{
+ if (!forWhom || !m_plugins.containsRef(forWhom) || !info.page)
+ return;
+ QFrame *f = addConfigurationPage(info);
+
+ // register this frame and config page
+ m_configPageFrames.insert(forWhom, f);
+ m_configPages.insert(forWhom, info.page);
+
+ // perhaps new config page profits from existing plugins
+ // example: timecontrol profits from radio plugin
+ Interface *i = dynamic_cast<Interface *>(info.page);
+ if (i) {
+ for (PluginIterator it(m_plugins); it.current(); ++it)
+ i->connectI(it.current());
+ }
+}
+
+
+QFrame *PluginManager::addConfigurationPage (const ConfigPageInfo &info)
+{
+ if (!m_configDialog)
+ createConfigDialog(i18n(m_configDialogTitle.ascii()));
+
+ // create empty config frame
+ QFrame *f = m_configDialog->addPage(
+ info.itemName,
+ info.pageHeader,
+ KGlobal::instance()->iconLoader()->loadIcon( info.iconName, KIcon::NoGroup, KIcon::SizeMedium )
+ );
+
+ // fill config frame with layout ...
+ QGridLayout *l = new QGridLayout(f);
+ l->setSpacing( 0 );
+ l->setMargin( 0 );
+
+ // ... and externally created config page
+ info.page->reparent (f, QPoint(0,0), true);
+ l->addWidget( info.page, 0, 0 );
+
+ // make sure, that config page receives ok, apply and cancel signals
+ QObject::connect(this, SIGNAL(sigConfigOK()), info.page, SLOT(slotOK()));
+ QObject::connect(m_configDialog, SIGNAL(cancelClicked()), info.page, SLOT(slotCancel()));
+
+ return f;
+}
+
+
+void PluginManager::createConfigDialog(const QString &title)
+{
+ if (m_configDialog) delete m_configDialog;
+ m_configDialog = NULL;
+
+ PluginConfigurationDialog *cfg = new PluginConfigurationDialog(
+ KDialogBase::IconList,
+ title,
+ KDialogBase::Apply|KDialogBase::Ok|KDialogBase::Cancel,
+ KDialogBase::Ok,
+ /*parent = */ NULL,
+ title.ascii(),
+ /*modal = */ false,
+ true);
+
+ m_configDialog = cfg;
+
+ QObject::connect(m_configDialog, SIGNAL(okClicked()), this, SLOT(slotConfigOK()));
+ QObject::connect(m_configDialog, SIGNAL(applyClicked()), this, SLOT(slotConfigOK()));
+
+ insertPlugin(cfg);
+
+ addConfigurationPage(createOwnConfigurationPage());
+
+ for (PluginIterator i(m_plugins); m_configDialog && i.current(); ++i) {
+ addConfigurationPage(i.current(),
+ i.current()->createConfigurationPage());
+ }
+}
+
+
+ConfigPageInfo PluginManager::createOwnConfigurationPage()
+{
+ m_pluginManagerConfiguration = new PluginManagerConfiguration(NULL, m_Application, this);
+ return ConfigPageInfo (m_pluginManagerConfiguration,
+ i18n("Plugins"),
+ i18n("Plugin Library Configuration"),
+ "kradio_plugins");
+}
+
+
+
+
+
+void PluginManager::addAboutPage (PluginBase *forWhom,
+ const AboutPageInfo &info)
+{
+ if (!m_aboutDialog)
+ createAboutDialog(i18n(m_aboutDialogTitle.ascii()));
+
+ if ( !forWhom || !m_plugins.containsRef(forWhom)
+ || !m_aboutDialog || !info.page)
+ return;
+
+
+ // create empty about frame
+ QFrame *f = m_aboutDialog->addPage(
+ info.itemName,
+ info.pageHeader,
+ KGlobal::instance()->iconLoader()->loadIcon( info.iconName, KIcon::NoGroup, KIcon::SizeMedium )
+ );
+
+ // register this frame and config page
+ m_aboutPageFrames.insert(forWhom, f);
+ m_aboutPages.insert(forWhom, info.page);
+
+ // fill config frame with layout ...
+ QGridLayout *l = new QGridLayout(f);
+ l->setSpacing( 0 );
+ l->setMargin( 0 );
+
+ // ... and externally created config page
+ info.page->reparent (f, QPoint(0,0), true);
+ l->addWidget( info.page, 0, 0 );
+}
+
+
+void PluginManager::createAboutDialog(const QString &title)
+{
+ if (m_aboutDialog) delete m_aboutDialog;
+ m_aboutDialog = NULL;
+
+ m_aboutDialog = new KDialogBase(KDialogBase::IconList,
+ title,
+ KDialogBase::Close,
+ KDialogBase::Close,
+ /*parent = */ NULL,
+ title.ascii(),
+ /*modal = */ false,
+ true);
+
+ for (PluginIterator i(m_plugins); m_aboutDialog && i.current(); ++i) {
+ addAboutPage(i.current(),
+ i.current()->createAboutPage());
+ }
+}
+
+
+void PluginManager::saveState (KConfig *c) const
+{
+ c->setGroup("PluginManager-" + m_Name);
+ c->writeEntry("show-progress-bar", m_showProgressBar);
+ int n = 0;
+ for (PluginIterator it(m_plugins); it.current(); ++it) {
+ QString class_name = it.current()->pluginClassName();
+ QString object_name = it.current()->name();
+ if (class_name.length() && object_name.length() &&
+ m_Application->getPluginClasses().contains(class_name))
+ {
+ ++n;
+ c->writeEntry("plugin_class_" + QString::number(n), class_name);
+ c->writeEntry("plugin_name_" + QString::number(n), object_name);
+ }
+ }
+ c->writeEntry("plugins", n);
+
+ for (PluginIterator i(m_plugins); i.current(); ++i) {
+ i.current()->saveState(c);
+ }
+}
+
+
+void PluginManager::restoreState (KConfig *c)
+{
+ BlockProfiler profile_all("PluginManager::restoreState");
+ c->setGroup("PluginManager-" + m_Name);
+ m_showProgressBar = c->readBoolEntry("show-progress-bar", true);
+ int n = c->readNumEntry("plugins", 0);
+
+ KProgressDialog *progress = NULL;
+ if (m_showProgressBar) {
+ progress = new KProgressDialog(NULL, NULL, i18n("Starting Plugins"));
+ progress->setMinimumWidth(400);
+ progress->setAllowCancel(false);
+ progress->show();
+ progress->progressBar()->setTotalSteps(2*n);
+ }
+
+ for (int i = 1; i <= n; ++i) {
+ c->setGroup("PluginManager-" + m_Name);
+ QString class_name = c->readEntry("plugin_class_" + QString::number(i));
+ QString object_name = c->readEntry("plugin_name_" + QString::number(i));
+
+ if (m_showProgressBar)
+ progress->QWidget::setCaption(i18n("Creating Plugin %1").arg(class_name));
+ if (class_name.length() && object_name.length())
+ m_Application->CreatePlugin(this, class_name, object_name);
+ if (m_showProgressBar)
+ progress->progressBar()->setProgress(i);
+ }
+
+ if (m_Application && n == 0) {
+ const QMap<QString, PluginClassInfo> &classes = m_Application->getPluginClasses();
+ QMapConstIterator<QString, PluginClassInfo> end = classes.end();
+ n = classes.count();
+ if (m_showProgressBar)
+ progress->progressBar()->setTotalSteps(2*n);
+ int idx = 1;
+ for (QMapConstIterator<QString, PluginClassInfo> it=classes.begin(); it != end; ++it, ++idx) {
+ const PluginClassInfo &cls = *it;
+ if (m_showProgressBar)
+ progress->QWidget::setCaption(i18n("Creating Plugin %1").arg(cls.class_name));
+ m_Application->CreatePlugin(this, cls.class_name, m_Name + "-" + cls.class_name);
+ if (m_showProgressBar)
+ progress->progressBar()->setProgress(idx);
+ }
+ m_configDialog->show();
+ }
+
+ BlockProfiler profile_plugins("PluginManager::restoreState - plugins");
+
+ int idx = n;
+ for (PluginIterator i(m_plugins); i.current(); ++i, ++idx) {
+ BlockProfiler profile_plugin("PluginManager::restoreState - " + i.current()->pluginClassName());
+ if (m_showProgressBar)
+ progress->QWidget::setCaption(i18n("Initializing Plugin %1").arg(i.current()->pluginClassName()));
+ i.current()->restoreState(c);
+ if (m_showProgressBar)
+ progress->progressBar()->setProgress(idx+1);
+ }
+ if (m_showProgressBar)
+ delete progress;
+}
+
+PluginConfigurationDialog *PluginManager::getConfigDialog()
+{
+ if (!m_configDialog)
+ createConfigDialog(m_configDialogTitle);
+ return m_configDialog;
+}
+
+KDialogBase *PluginManager::getAboutDialog()
+{
+ if (!m_aboutDialog)
+ createAboutDialog();
+ return m_aboutDialog;
+}
+
+
+
+void PluginManager::slotConfigOK()
+{
+ emit sigConfigOK();
+ if (m_Application)
+ m_Application->saveState(KGlobal::config());
+}
+
+
+void PluginManager::startPlugins()
+{
+ for (PluginIterator i(m_plugins); i.current(); ++i) {
+ i.current()->startPlugin();
+ }
+}
+
+void PluginManager::aboutToQuit()
+{
+ for (PluginIterator i(m_plugins); i.current(); ++i) {
+ i.current()->aboutToQuit();
+ }
+}
+
+
+#include "pluginmanager.moc"