summaryrefslogtreecommitdiffstats
path: root/noatun/library/pluginmodule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'noatun/library/pluginmodule.cpp')
-rw-r--r--noatun/library/pluginmodule.cpp406
1 files changed, 406 insertions, 0 deletions
diff --git a/noatun/library/pluginmodule.cpp b/noatun/library/pluginmodule.cpp
new file mode 100644
index 00000000..aec76e44
--- /dev/null
+++ b/noatun/library/pluginmodule.cpp
@@ -0,0 +1,406 @@
+// Copyright (c) 2000-2001 Charles Samuels <charles@kde.org>
+// Copyright (c) 2000-2001 Neil Stevens <multivac@fcmail.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIAB\ILITY, WHETHER IN
+// AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#include <noatun/app.h>
+
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qtabwidget.h>
+#include <qheader.h>
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include "noatunlistview.h"
+#include "pluginmodule.h"
+
+#include <qwhatsthis.h>
+
+#include "common.h"
+
+PluginListItem::PluginListItem(const bool _exclusive, bool _checked, const NoatunLibraryInfo &_info, QListView *_parent)
+ : QCheckListItem(_parent, _info.name, CheckBox)
+ , mInfo(_info)
+ , silentStateChange(false)
+ , exclusive(_exclusive)
+{
+ setChecked(_checked);
+ if(_checked) static_cast<PluginListView *>(listView())->count++;
+}
+
+
+void PluginListItem::setChecked(bool b)
+{
+ silentStateChange = true;
+ setOn(b);
+ silentStateChange = false;
+}
+
+void PluginListItem::stateChange(bool b)
+{
+ if(!silentStateChange)
+ static_cast<PluginListView *>(listView())->stateChanged(this, b);
+}
+
+void PluginListItem::paintCell(QPainter *p, const QColorGroup &cg, int a, int b, int c)
+{
+ if(exclusive) myType = RadioButton;
+ QCheckListItem::paintCell(p, cg, a, b, c);
+ if(exclusive) myType = CheckBox;
+}
+
+PluginListView::PluginListView(unsigned _min, unsigned _max, QWidget *_parent, const char *_name)
+ : KListView(_parent, _name)
+ , hasMaximum(true)
+ , max(_max)
+ , min(_min <= _max ? _min : _max)
+ , count(0)
+{
+}
+
+PluginListView::PluginListView(unsigned _min, QWidget *_parent, const char *_name)
+ : KListView(_parent, _name)
+ , hasMaximum(false)
+ , min(_min)
+ , count(0)
+{
+}
+
+PluginListView::PluginListView(QWidget *_parent, const char *_name)
+ : KListView(_parent, _name)
+ , hasMaximum(false)
+ , min(0)
+ , count(0)
+{
+}
+
+void PluginListView::clear()
+{
+ count = 0;
+ KListView::clear();
+}
+
+void PluginListView::stateChanged(PluginListItem *item, bool b)
+{
+ if(b)
+ {
+ count++;
+ emit stateChange(item, b);
+
+ if(hasMaximum && count > max)
+ {
+ // Find a different one and turn it off
+
+ QListViewItem *cur = firstChild();
+ PluginListItem *curItem = dynamic_cast<PluginListItem *>(cur);
+
+ while(cur == item || !curItem || !curItem->isOn())
+ {
+ cur = cur->nextSibling();
+ curItem = dynamic_cast<PluginListItem *>(cur);
+ }
+
+ curItem->setOn(false);
+ }
+ }
+ else
+ {
+ if(count == min)
+ {
+ item->setChecked(true);
+ }
+ else
+ {
+ count--;
+ emit stateChange(item, b);
+ }
+ }
+}
+
+Plugins::Plugins(QObject *_parent)
+ : CModule(i18n("Plugins"), i18n("Select Your Plugins"), "gear", _parent)
+ , shown(false)
+{
+ (new QVBoxLayout(this))->setAutoAdd(true);
+ QTabWidget *tabControl = new QTabWidget(this,"tabControl");
+
+ QFrame *interfaceTab = new QFrame(tabControl);
+ (new QVBoxLayout(interfaceTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true);
+ (void)new QLabel(i18n("<b>Select one or more interfaces to use:</b>"), interfaceTab);
+ // At least one interface is required
+ interfaceList = new PluginListView(1, interfaceTab);
+ interfaceList->addColumn(i18n("Name"));
+ interfaceList->addColumn(i18n("Description"));
+ interfaceList->addColumn(i18n("Author"));
+ interfaceList->addColumn(i18n("License"));
+ connect(interfaceList, SIGNAL(stateChange(PluginListItem *, bool)), this, SLOT(stateChange(PluginListItem *, bool)));
+ tabControl->addTab(interfaceTab, i18n("&Interfaces"));
+
+ QFrame *playlistTab = new QFrame(tabControl);
+ (new QVBoxLayout(playlistTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true);
+ (void)new QLabel(i18n("<b>Select one playlist to use:</b>"), playlistTab);
+ // Exactly one playlist is required
+ playlistList = new PluginListView(1, 1, playlistTab);
+ playlistList->addColumn(i18n("Name"));
+ playlistList->addColumn(i18n("Description"));
+ playlistList->addColumn(i18n("Author"));
+ playlistList->addColumn(i18n("License"));
+ connect(playlistList, SIGNAL(stateChange(PluginListItem *, bool)), this, SLOT(stateChange(PluginListItem *, bool)));
+ tabControl->addTab(playlistTab, i18n("&Playlist"));
+
+ QFrame *visTab = new QFrame(tabControl);
+ (new QVBoxLayout(visTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true);
+ (void)new QLabel(i18n("<b>Select any visualizations to use:</b>"), visTab);
+ visList = new PluginListView(0, visTab);
+ visList->addColumn(i18n("Name"));
+ visList->addColumn(i18n("Description"));
+ visList->addColumn(i18n("Author"));
+ visList->addColumn(i18n("License"));
+ connect(visList, SIGNAL(stateChange(PluginListItem *, bool)), this, SLOT(stateChange(PluginListItem *, bool)));
+ tabControl->addTab(visTab, i18n("&Visualizations"));
+
+ // Other plugins are not restricted
+ QFrame *otherTab = new QFrame(tabControl);
+ (new QVBoxLayout(otherTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true);
+ (void)new QLabel(i18n("<b>Select any other plugins to use:</b>"), otherTab);
+ otherList = new PluginListView(0, otherTab);
+ otherList->addColumn(i18n("Name"));
+ otherList->addColumn(i18n("Description"));
+ otherList->addColumn(i18n("Author"));
+ otherList->addColumn(i18n("License"));
+ connect(otherList, SIGNAL(stateChange(PluginListItem *, bool)), this, SLOT(stateChange(PluginListItem *, bool)));
+ tabControl->addTab(otherTab, i18n("O&ther Plugins"));
+}
+
+void Plugins::reopen()
+{
+ playlistList->clear();
+ interfaceList->clear();
+ otherList->clear();
+ visList->clear();
+
+ QValueList<NoatunLibraryInfo> available = napp->libraryLoader()->available();
+ QValueList<NoatunLibraryInfo> loaded = napp->libraryLoader()->loaded();
+
+ for(QValueList<NoatunLibraryInfo>::Iterator i = available.begin(); i != available.end(); ++i)
+ {
+ PluginListView *parent;
+ bool exclusive = false;
+
+ if((*i).type == "userinterface")
+ {
+ parent = interfaceList;
+ }
+ else if((*i).type == "playlist")
+ {
+ parent = playlistList;
+ exclusive = true;
+ }
+ else if((*i).type == "sm" || (*i).type=="hidden")
+ {
+ parent = 0;
+ }
+ else if ((*i).type == "visualization")
+ {
+ parent = visList;
+ }
+ else
+ {
+ parent = otherList;
+ }
+
+ if(parent)
+ {
+ PluginListItem *item = new PluginListItem(exclusive, loaded.contains(*i), *i, parent);
+ item->setText(0, (*i).name);
+ item->setText(1, (*i).comment);
+ item->setText(2, (*i).author);
+ item->setText(3, (*i).license);
+ }
+ }
+}
+
+void Plugins::stateChange(PluginListItem *item, bool b)
+{
+ if(b)
+ addPlugin(item->info());
+ else
+ removePlugin(item->info());
+}
+
+void Plugins::addPlugin(const NoatunLibraryInfo &info)
+{
+ // Load any that this one depends upon
+ for(QStringList::ConstIterator i = info.require.begin(); i != info.require.end(); ++i)
+ {
+ NoatunLibraryInfo requiredInfo = napp->libraryLoader()->getInfo(*i);
+ PluginListItem *item = findItem(requiredInfo);
+ if(item) item->setOn(true);
+ }
+
+ if(mDeleted.contains(info.specfile))
+ mDeleted.remove(info.specfile);
+ else if(!mAdded.contains(info.specfile))
+ mAdded.append(info.specfile);
+}
+
+void Plugins::removePlugin(const NoatunLibraryInfo &info)
+{
+ LibraryLoader &loader = *(napp->libraryLoader());
+
+ // Here are the ones loaded
+ QValueList<NoatunLibraryInfo> loaded = napp->libraryLoader()->loaded();
+
+ // Add the ones marked for loading
+ for(QStringList::ConstIterator i = mAdded.begin(); i != mAdded.end(); ++i)
+ loaded.append(loader.getInfo(*i));
+
+ // Subtract the ones marked for removal
+ for(QStringList::ConstIterator i = mDeleted.begin(); i != mDeleted.end(); ++i)
+ loaded.remove(loader.getInfo(*i));
+
+ // If any depend on this plugin, mark them for removal (or remove them from mAdded)
+ for(QValueList<NoatunLibraryInfo>::Iterator i = loaded.begin(); i != loaded.end(); ++i)
+ {
+ for(QStringList::ConstIterator j = (*i).require.begin(); j != (*i).require.end(); ++j)
+ {
+ if(*j == info.specfile)
+ {
+ PluginListItem *item = findItem(*i);
+ if(item) item->setOn(false);
+ }
+ }
+ }
+
+ if (mAdded.contains(info.specfile))
+ mAdded.remove(info.specfile);
+ else if(!mDeleted.contains(info.specfile))
+ mDeleted.append(info.specfile);
+}
+
+PluginListItem *Plugins::findItem(const NoatunLibraryInfo &info) const
+{
+ for(QListViewItem *cur = otherList->firstChild(); cur != 0; cur = cur->itemBelow())
+ {
+ PluginListItem *item = dynamic_cast<PluginListItem *>(cur);
+ if(item && item->info() == info)
+ return item;
+ }
+
+ // visualizations
+ for(QListViewItem *cur = visList->firstChild(); cur != 0; cur = cur->itemBelow())
+ {
+ PluginListItem *item = dynamic_cast<PluginListItem *>(cur);
+ if(item && item->info() == info)
+ return item;
+ }
+
+ // If our only interface has a dependency removed, that's a double dose of trouble
+ // We may as well have this here for completeness, though
+ for(QListViewItem *cur = interfaceList->firstChild(); cur != 0; cur = cur->itemBelow())
+ {
+ PluginListItem *item = dynamic_cast<PluginListItem *>(cur);
+ if(item && item->info() == info)
+ return item;
+ }
+
+ // If a playlist is added or removed due to a dependency, we're doom-diddly-oomed
+ // We may as well have this here for completeness, though
+ for(QListViewItem *cur = playlistList->firstChild(); cur != 0; cur = cur->itemBelow())
+ {
+ PluginListItem *item = dynamic_cast<PluginListItem *>(cur);
+ if(item && item->info() == info)
+ return item;
+ }
+
+ return 0;
+}
+
+void Plugins::save()
+{
+ LibraryLoader &loader = *(napp->libraryLoader());
+
+ // Load the plugins the user added
+ //loader.loadAll(mAdded);
+
+ QString oldPlaylist, newPlaylist;
+
+ // first load all non playlist things
+ for (QStringList::Iterator i = mAdded.begin(); i != mAdded.end(); ++i)
+ {
+ NoatunLibraryInfo info = loader.getInfo(*i);
+ if(info.type != "playlist")
+ loader.loadAll(QStringList(*i));
+ else
+ newPlaylist = (*i);
+ }
+
+ // Remove the plugins the user removed
+ for (QStringList::Iterator i = mDeleted.begin(); i != mDeleted.end(); ++i)
+ {
+ NoatunLibraryInfo info = loader.getInfo(*i);
+ if(info.type != "playlist")
+ loader.remove(*i);
+ else
+ oldPlaylist = *i;
+ }
+
+ // Loading normal plugins works the other way round!
+ // If you unload a playlist it sets the global playlist pointer to NULL,
+ // that also means you cannot first load the new and then unload the old one.
+ if(!newPlaylist.isEmpty() && !oldPlaylist.isEmpty())
+ {
+ kdDebug(66666) << k_funcinfo << "Unloading " << oldPlaylist << endl;
+ loader.remove(oldPlaylist);
+ kdDebug(66666) << k_funcinfo << "Loading " << oldPlaylist << endl;
+ loader.loadAll(QStringList(newPlaylist));
+ }
+
+
+ // Round up the ones that weren't loaded right now, for saving in the configuration
+ QStringList specList(mAdded);
+
+ QValueList<NoatunLibraryInfo> loaded = loader.loaded();
+ for(QValueList<NoatunLibraryInfo>::Iterator i = loaded.begin(); i != loaded.end(); ++i)
+ {
+ if(!specList.contains((*i).specfile) && loader.isLoaded((*i).specfile))
+ specList += (*i).specfile;
+ }
+
+ // Now we actually save
+ loader.setModules(specList);
+
+ mDeleted.clear();
+ mAdded.clear();
+}
+
+void Plugins::showEvent(QShowEvent *e)
+{
+ if(!shown)
+ {
+ shown = true;
+ KMessageBox::information(this, i18n("<qt>Changing your playlist plugin will stop playback. Different playlists may use different methods of storing information, so after changing playlists you may have to recreate your playlist.</qt>"), QString::null, "Plugin warning");
+ }
+ CModule::showEvent(e);
+}
+
+#include "pluginmodule.moc"