// Copyright (c) 2000-2001 Charles Samuels // Copyright (c) 2000-2001 Neil Stevens // // 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 #include #include #include #include #include #include #include #include #include #include "noatunlistview.h" #include "pluginmodule.h" #include #include "common.h" PluginListItem::PluginListItem(const bool _exclusive, bool _checked, const NoatunLibraryInfo &_info, TQListView *_parent) : TQCheckListItem(_parent, _info.name, CheckBox) , mInfo(_info) , silentStateChange(false) , exclusive(_exclusive) { setChecked(_checked); if(_checked) static_cast(listView())->count++; } void PluginListItem::setChecked(bool b) { silentStateChange = true; setOn(b); silentStateChange = false; } void PluginListItem::stateChange(bool b) { if(!silentStateChange) static_cast(listView())->stateChanged(this, b); } void PluginListItem::paintCell(TQPainter *p, const TQColorGroup &cg, int a, int b, int c) { if(exclusive) myType = RadioButton; TQCheckListItem::paintCell(p, cg, a, b, c); if(exclusive) myType = CheckBox; } PluginListView::PluginListView(unsigned _min, unsigned _max, TQWidget *_parent, const char *_name) : TDEListView(_parent, _name) , hasMaximum(true) , max(_max) , min(_min <= _max ? _min : _max) , count(0) { } PluginListView::PluginListView(unsigned _min, TQWidget *_parent, const char *_name) : TDEListView(_parent, _name) , hasMaximum(false) , min(_min) , count(0) { } PluginListView::PluginListView(TQWidget *_parent, const char *_name) : TDEListView(_parent, _name) , hasMaximum(false) , min(0) , count(0) { } void PluginListView::clear() { count = 0; TDEListView::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 TQListViewItem *cur = firstChild(); PluginListItem *curItem = dynamic_cast(cur); while(cur == item || !curItem || !curItem->isOn()) { cur = cur->nextSibling(); curItem = dynamic_cast(cur); } curItem->setOn(false); } } else { if(count == min) { item->setChecked(true); } else { count--; emit stateChange(item, b); } } } Plugins::Plugins(TQObject *_parent) : CModule(i18n("Plugins"), i18n("Select Your Plugins"), "gear", _parent) , shown(false) { (new TQVBoxLayout(this))->setAutoAdd(true); TQTabWidget *tabControl = new TQTabWidget(this,"tabControl"); TQFrame *interfaceTab = new TQFrame(tabControl); (new TQVBoxLayout(interfaceTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true); (void)new TQLabel(i18n("Select one or more interfaces to use:"), 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, TQT_SIGNAL(stateChange(PluginListItem *, bool)), this, TQT_SLOT(stateChange(PluginListItem *, bool))); tabControl->addTab(interfaceTab, i18n("&Interfaces")); TQFrame *playlistTab = new TQFrame(tabControl); (new TQVBoxLayout(playlistTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true); (void)new TQLabel(i18n("Select one playlist to use:"), 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, TQT_SIGNAL(stateChange(PluginListItem *, bool)), this, TQT_SLOT(stateChange(PluginListItem *, bool))); tabControl->addTab(playlistTab, i18n("&Playlist")); TQFrame *visTab = new TQFrame(tabControl); (new TQVBoxLayout(visTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true); (void)new TQLabel(i18n("Select any visualizations to use:"), visTab); visList = new PluginListView(0, visTab); visList->addColumn(i18n("Name")); visList->addColumn(i18n("Description")); visList->addColumn(i18n("Author")); visList->addColumn(i18n("License")); connect(visList, TQT_SIGNAL(stateChange(PluginListItem *, bool)), this, TQT_SLOT(stateChange(PluginListItem *, bool))); tabControl->addTab(visTab, i18n("&Visualizations")); // Other plugins are not restricted TQFrame *otherTab = new TQFrame(tabControl); (new TQVBoxLayout(otherTab, KDialog::marginHint(), KDialog::spacingHint()))->setAutoAdd(true); (void)new TQLabel(i18n("Select any other plugins to use:"), otherTab); otherList = new PluginListView(0, otherTab); otherList->addColumn(i18n("Name")); otherList->addColumn(i18n("Description")); otherList->addColumn(i18n("Author")); otherList->addColumn(i18n("License")); connect(otherList, TQT_SIGNAL(stateChange(PluginListItem *, bool)), this, TQT_SLOT(stateChange(PluginListItem *, bool))); tabControl->addTab(otherTab, i18n("O&ther Plugins")); } void Plugins::reopen() { playlistList->clear(); interfaceList->clear(); otherList->clear(); visList->clear(); TQValueList available = napp->libraryLoader()->available(); TQValueList loaded = napp->libraryLoader()->loaded(); for(TQValueList::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(TQStringList::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 TQValueList loaded = napp->libraryLoader()->loaded(); // Add the ones marked for loading for(TQStringList::ConstIterator i = mAdded.begin(); i != mAdded.end(); ++i) loaded.append(loader.getInfo(*i)); // Subtract the ones marked for removal for(TQStringList::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(TQValueList::Iterator i = loaded.begin(); i != loaded.end(); ++i) { for(TQStringList::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(TQListViewItem *cur = otherList->firstChild(); cur != 0; cur = cur->itemBelow()) { PluginListItem *item = dynamic_cast(cur); if(item && item->info() == info) return item; } // visualizations for(TQListViewItem *cur = visList->firstChild(); cur != 0; cur = cur->itemBelow()) { PluginListItem *item = dynamic_cast(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(TQListViewItem *cur = interfaceList->firstChild(); cur != 0; cur = cur->itemBelow()) { PluginListItem *item = dynamic_cast(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(TQListViewItem *cur = playlistList->firstChild(); cur != 0; cur = cur->itemBelow()) { PluginListItem *item = dynamic_cast(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); TQString oldPlaylist, newPlaylist; // first load all non playlist things for (TQStringList::Iterator i = mAdded.begin(); i != mAdded.end(); ++i) { NoatunLibraryInfo info = loader.getInfo(*i); if(info.type != "playlist") loader.loadAll(TQStringList(*i)); else newPlaylist = (*i); } // Remove the plugins the user removed for (TQStringList::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(TQStringList(newPlaylist)); } // Round up the ones that weren't loaded right now, for saving in the configuration TQStringList specList(mAdded); TQValueList loaded = loader.loaded(); for(TQValueList::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(TQShowEvent *e) { if(!shown) { shown = true; KMessageBox::information(this, i18n("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."), TQString(), "Plugin warning"); } CModule::showEvent(e); } #include "pluginmodule.moc"