You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/noatun/library/pluginmodule.cpp

407 lines
12 KiB

// 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"