// 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 <tdelocale.h>
# include <tdemessagebox.h>
# include <tqtabwidget.h>
# include <tqheader.h>
# include <tqlabel.h>
# include <tqlayout.h>
# include "noatunlistview.h"
# include "pluginmodule.h"
# include <tqwhatsthis.h>
# 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 < 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 ( 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 < 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 ( 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 ( " <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 , TQ_SIGNAL ( stateChange ( PluginListItem * , bool ) ) , this , TQ_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 ( " <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 , TQ_SIGNAL ( stateChange ( PluginListItem * , bool ) ) , this , TQ_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 ( " <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 , TQ_SIGNAL ( stateChange ( PluginListItem * , bool ) ) , this , TQ_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 ( " <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 , TQ_SIGNAL ( stateChange ( PluginListItem * , bool ) ) , this , TQ_SLOT ( stateChange ( PluginListItem * , bool ) ) ) ;
tabControl - > addTab ( otherTab , i18n ( " O&ther Plugins " ) ) ;
}
void Plugins : : reopen ( )
{
playlistList - > clear ( ) ;
interfaceList - > clear ( ) ;
otherList - > clear ( ) ;
visList - > clear ( ) ;
TQValueList < NoatunLibraryInfo > available = napp - > libraryLoader ( ) - > available ( ) ;
TQValueList < NoatunLibraryInfo > loaded = napp - > libraryLoader ( ) - > loaded ( ) ;
for ( TQValueList < 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 ( 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 < NoatunLibraryInfo > 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 < NoatunLibraryInfo > : : 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 < PluginListItem * > ( cur ) ;
if ( item & & item - > info ( ) = = info )
return item ;
}
// visualizations
for ( TQListViewItem * 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 ( TQListViewItem * 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 ( TQListViewItem * 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);
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 < NoatunLibraryInfo > loaded = loader . loaded ( ) ;
for ( TQValueList < 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 ( TQShowEvent * 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> " ) , TQString ( ) , " Plugin warning " ) ;
}
CModule : : showEvent ( e ) ;
}
# include "pluginmodule.moc"