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.
amarok/amarok/src/playlistwindow.cpp

1276 lines
48 KiB

/***************************************************************************
begin : Fre Nov 15 2002
copyright : (C) Mark Kretschmann <markey@web.de>
: (C) Max Howell <max.howell@methylblue.com>
: (C) G??bor Lehel <illissius@gmail.com>
***************************************************************************/
/***************************************************************************
* *
* 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 "config.h" //HAVE_LIBVISUAL definition
#include "actionclasses.h" //see toolbar construction
#include "amarok.h"
#include "amarokconfig.h"
#include "browserbar.h"
#include "clicklineedit.h" //m_lineEdit
#include "collectionbrowser.h"
#include "contextbrowser.h"
#include "debug.h"
#include "mediadevicemanager.h"
#include "editfilterdialog.h"
#include "enginecontroller.h" //for actions in ctor
#include "filebrowser.h"
#include "k3bexporter.h"
#include "lastfm.h" //check credentials when adding lastfm streams
#include "mediabrowser.h"
#include "dynamicmode.h"
#include "playlist.h"
#include "playlistbrowser.h"
#include "playlistwindow.h"
#include "scriptmanager.h"
#include "statistics.h"
#include "statusbar.h"
#include "threadmanager.h"
#include "magnatunebrowser/magnatunebrowser.h"
#include <tqevent.h> //eventFilter()
#include <tqfont.h>
#include <tqheader.h>
#include <tqlayout.h>
#include <tqlabel.h> //search filter label
#include <tqpainter.h> //dynamic title
#include <tqpen.h>
#include <tqsizepolicy.h> //qspaceritem in dynamic bar
#include <tqtimer.h> //search filter timer
#include <tqtooltip.h> //TQToolTip::add()
#include <tqvbox.h> //contains the playlist
#include <kaction.h> //m_actionCollection
#include <kapplication.h> //kapp
#include <kfiledialog.h> //savePlaylist(), openPlaylist()
#include <kglobal.h>
#include <khtml_part.h> //Welcome Tab
#include <kiconloader.h> //ClearFilter button
#include <kinputdialog.h> //slotAddStream()
#include <klocale.h>
#include <kmenubar.h>
#include <kmessagebox.h> //savePlaylist()
#include <kpopupmenu.h>
#include <kpushbutton.h>
#include <kstandarddirs.h> //Welcome Tab, locate welcome.html
#include <ktoolbar.h>
#include <ktoolbarbutton.h> //createGUI()
#include <kxmlguibuilder.h> //XMLGUI
#include <kxmlguifactory.h> //XMLGUI
#include <fixx11h.h>
//////////////////////////////////////////////////////////////////////////////////////////
/// CLASS Amarok::ToolBar
//////////////////////////////////////////////////////////////////////////////////////////
namespace Amarok
{
class ToolBar : public KToolBar
{
public:
ToolBar( TQWidget *parent, const char *name )
: KToolBar( parent, name )
{}
protected:
virtual void
contextMenuEvent( TQContextMenuEvent *e ) {
Amarok::Menu::instance()->popup( e->globalPos() );
}
virtual void
wheelEvent( TQWheelEvent *e ) {
EngineController::instance()->increaseVolume( e->delta() / Amarok::VOLUME_SENSITIVITY );
}
};
}
PlaylistWindow *PlaylistWindow::s_instance = 0;
PlaylistWindow::PlaylistWindow()
: TQWidget( 0, "PlaylistWindow", TQt::WGroupLeader )
, KXMLGUIClient()
, m_lastBrowser( 0 )
{
s_instance = this;
// Sets caption and icon correctly (needed e.g. for GNOME)
kapp->setTopWidget( this );
KActionCollection* const ac = actionCollection();
const EngineController* const ec = EngineController::instance();
ac->setAutoConnectShortcuts( false );
ac->setWidget( this );
new K3bExporter();
KStdAction::configureToolbars( TQT_TQOBJECT(kapp), TQT_SLOT( slotConfigToolBars() ), ac );
KStdAction::keyBindings( TQT_TQOBJECT(kapp), TQT_SLOT( slotConfigShortcuts() ), ac );
KStdAction::keyBindings( TQT_TQOBJECT(kapp), TQT_SLOT( slotConfigGlobalShortcuts() ), ac, "options_configure_globals" );
KStdAction::preferences( TQT_TQOBJECT(kapp), TQT_SLOT( slotConfigAmarok() ), ac );
ac->action("options_configure_globals")->setIcon( Amarok::icon( "configure" ) );
ac->action(KStdAction::name(KStdAction::KeyBindings))->setIcon( Amarok::icon( "configure" ) );
ac->action(KStdAction::name(KStdAction::ConfigureToolbars))->setIcon( Amarok::icon( "configure" ) );
ac->action(KStdAction::name(KStdAction::Preferences))->setIcon( Amarok::icon( "configure" ) );
KStdAction::quit( TQT_TQOBJECT(kapp), TQT_SLOT( quit() ), ac );
KStdAction::open( TQT_TQOBJECT(this), TQT_SLOT(slotAddLocation()), ac, "playlist_add" )->setText( i18n("&Add Media...") );
ac->action( "playlist_add" )->setIcon( Amarok::icon( "files" ) );
KStdAction::open( TQT_TQOBJECT(this), TQT_SLOT(slotAddStream()), ac, "stream_add" )->setText( i18n("&Add Stream...") );
ac->action( "stream_add" )->setIcon( Amarok::icon( "files" ) );
KStdAction::save( TQT_TQOBJECT(this), TQT_SLOT(savePlaylist()), ac, "playlist_save" )->setText( i18n("&Save Playlist As...") );
ac->action( "playlist_save" )->setIcon( Amarok::icon( "save" ) );
#ifndef TQ_WS_MAC
KStdAction::showMenubar( TQT_TQOBJECT(this), TQT_SLOT(slotToggleMenu()), ac );
#endif
//FIXME: after string freeze rename to "Burn Current Playlist"?
new KAction( i18n("Burn to CD"), Amarok::icon( "burn" ), 0, TQT_TQOBJECT(this), TQT_SLOT(slotBurnPlaylist()), ac, "playlist_burn" );
actionCollection()->action("playlist_burn")->setEnabled( K3bExporter::isAvailable() );
new KAction( i18n("Play Media..."), Amarok::icon( "files" ), 0, TQT_TQOBJECT(this), TQT_SLOT(slotPlayMedia()), ac, "playlist_playmedia" );
new KAction( i18n("Play Audio CD"), Amarok::icon( "album" ), 0, TQT_TQOBJECT(this), TQT_SLOT(playAudioCD()), ac, "play_audiocd" );
KAction *playPause = new KAction( i18n( "&Play/Pause" ), Amarok::icon( "play" ), Key_Space, ec, TQT_SLOT( playPause() ), ac, "play_pause" );
new KAction( i18n("Script Manager"), Amarok::icon( "scripts" ), 0, TQT_TQOBJECT(this), TQT_SLOT(showScriptSelector()), ac, "script_manager" );
new KAction( i18n("Queue Manager"), Amarok::icon( "queue" ), 0, TQT_TQOBJECT(this), TQT_SLOT(showQueueManager()), ac, "queue_manager" );
KAction *seekForward = new KAction( i18n( "&Seek Forward" ), Amarok::icon( "fastforward" ), Key_Right, ec, TQT_SLOT( seekForward() ), ac, "seek_forward" );
KAction *seekBackward = new KAction( i18n( "&Seek Backward" ), Amarok::icon( "rewind" ), Key_Left, ec, TQT_SLOT( seekBackward() ), ac, "seek_backward" );
new KAction( i18n("Statistics"), Amarok::icon( "info" ), 0, TQT_TQOBJECT(this), TQT_SLOT(showStatistics()), ac, "statistics" );
new KAction( i18n("Update Collection"), Amarok::icon( "refresh" ), 0, CollectionDB::instance(), TQT_SLOT( scanModifiedDirs() ), actionCollection(), "update_collection" );
m_lastfmTags << "Alternative" << "Ambient" << "Chill Out" << "Classical" << "Dance"
<< "Electronica" << "Favorites" << "Heavy Metal" << "Hip Hop" << "Indie Rock"
<< "Industrial" << "Japanese" << "Pop" << "Psytrance" << "Rap" << "Rock"
<< "Soundtrack" << "Techno" << "Trance";
KPopupMenu* playTagRadioMenu = new KPopupMenu( this );
int id = 0;
foreach( m_lastfmTags ) {
playTagRadioMenu->insertItem( *it, this, TQT_SLOT( playLastfmGlobaltag( int ) ), 0, id );
++id;
}
KPopupMenu* addTagRadioMenu = new KPopupMenu( this );
id = 0;
foreach( m_lastfmTags ) {
addTagRadioMenu->insertItem( *it, this, TQT_SLOT( addLastfmGlobaltag( int ) ), 0, id );
++id;
}
KActionMenu* playLastfm = new KActionMenu( i18n( "Play las&t.fm Stream" ), Amarok::icon( "audioscrobbler" ), ac, "lastfm_play" );
TQPopupMenu* playLastfmMenu = playLastfm->popupMenu();
playLastfmMenu->insertItem( i18n( "Personal Radio" ), this, TQT_SLOT( playLastfmPersonal() ) );
playLastfmMenu->insertItem( i18n( "Neighbor Radio" ), this, TQT_SLOT( playLastfmNeighbor() ) );
playLastfmMenu->insertItem( i18n( "Custom Station" ), this, TQT_SLOT( playLastfmCustom() ) );
playLastfmMenu->insertItem( i18n( "Global Tag Radio" ), playTagRadioMenu );
KActionMenu* addLastfm = new KActionMenu( i18n( "Add las&t.fm Stream" ), Amarok::icon( "audioscrobbler" ), ac, "lastfm_add" );
TQPopupMenu* addLastfmMenu = addLastfm->popupMenu();
addLastfmMenu->insertItem( i18n( "Personal Radio" ), this, TQT_SLOT( addLastfmPersonal() ) );
addLastfmMenu->insertItem( i18n( "Neighbor Radio" ), this, TQT_SLOT( addLastfmNeighbor() ) );
addLastfmMenu->insertItem( i18n( "Custom Station" ), this, TQT_SLOT( addLastfmCustom() ) );
addLastfmMenu->insertItem( i18n( "Global Tag Radio" ), addTagRadioMenu );
ac->action( "options_configure_globals" )->setText( i18n( "Configure &Global Shortcuts..." ) );
new KAction( i18n( "Previous Track" ), Amarok::icon( "back" ), 0, ec, TQT_SLOT( previous() ), ac, "prev" );
new KAction( i18n( "Play" ), Amarok::icon( "play" ), 0, ec, TQT_SLOT( play() ), ac, "play" );
new KAction( i18n( "Pause" ), Amarok::icon( "pause" ), 0, ec, TQT_SLOT( pause() ), ac, "pause" );
new KAction( i18n( "Next Track" ), Amarok::icon( "next" ), 0, ec, TQT_SLOT( next() ), ac, "next" );
KAction *toggleFocus = new KAction( i18n( "Toggle Focus" ), "reload", CTRL+Key_Tab, TQT_TQOBJECT(this), TQT_SLOT( slotToggleFocus() ), ac, "toggle_focus" );
{ // KAction idiocy -- shortcuts don't work until they've been plugged into a menu
KPopupMenu asdf;
playPause->plug( &asdf );
seekForward->plug( &asdf );
seekBackward->plug( &asdf );
toggleFocus->plug( &asdf );
playPause->unplug( &asdf );
seekForward->unplug( &asdf );
seekBackward->unplug( &asdf );
toggleFocus->unplug( &asdf );
}
new Amarok::MenuAction( ac );
new Amarok::StopAction( ac );
new Amarok::PlayPauseAction( ac );
new Amarok::AnalyzerAction( ac );
new Amarok::RepeatAction( ac );
new Amarok::RandomAction( ac );
new Amarok::FavorAction( ac );
new Amarok::VolumeAction( ac );
if( K3bExporter::isAvailable() )
new Amarok::BurnMenuAction( ac );
if( AmarokConfig::playlistWindowSize().isValid() ) {
// if first ever run, use sizeHint(), and let
// KWin place us otherwise use the stored values
resize( AmarokConfig::playlistWindowSize() );
move( AmarokConfig::playlistWindowPos() );
}
}
PlaylistWindow::~PlaylistWindow()
{
Amarok::config( "PlaylistWindow" )->writeEntry( "showMenuBar", m_menubar->isShown() );
AmarokConfig::setPlaylistWindowPos( pos() ); //TODO de XT?
AmarokConfig::setPlaylistWindowSize( size() ); //TODO de XT?
}
///////// public interface
/**
* This function will initialize the playlist window.
*/
void PlaylistWindow::init()
{
DEBUG_BLOCK
//this function is necessary because Amarok::actionCollection() returns our actionCollection
//via the App::m_pPlaylistWindow pointer since App::m_pPlaylistWindow is not defined until
//the above ctor returns it causes a crash unless we do the initialisation in 2 stages.
m_browsers = new BrowserBar( this );
//<Dynamic Mode Status Bar />
DynamicBar *dynamicBar = new DynamicBar( m_browsers->container());
TQFrame *playlist;
{ //<Search LineEdit>
KToolBar *bar = new KToolBar( m_browsers->container(), "NotMainToolBar" );
bar->setIconSize( 22, false ); //looks more sensible
bar->setFlat( true ); //removes the ugly frame
bar->setMovingEnabled( false ); //removes the ugly frame
playlist = new Playlist( m_browsers->container() );
actionCollection()->action( "playlist_clear")->plug( bar );
actionCollection()->action( "playlist_save")->plug( bar );
bar->addSeparator();
actionCollection()->action( "playlist_undo")->plug( bar );
actionCollection()->action( "playlist_redo")->plug( bar );
bar->boxLayout()->addStretch();
TQWidget *button = new KToolBarButton( "locationbar_erase", 1, bar );
TQLabel *filter_label = new TQLabel( i18n("S&earch:") + ' ', bar );
m_lineEdit = new ClickLineEdit( i18n( "Playlist Search" ), bar );
filter_label->setBuddy( m_lineEdit );
bar->setStretchableWidget( m_lineEdit );
KPushButton *filterButton = new KPushButton("...", bar, "filter");
filterButton->setSizePolicy( TQSizePolicy::Preferred, TQSizePolicy::Fixed );
m_lineEdit->setFrame( TQFrame::Sunken );
m_lineEdit->installEventFilter( this ); //we intercept keyEvents
connect( button, TQT_SIGNAL(clicked()), m_lineEdit, TQT_SLOT(clear()) );
connect( m_lineEdit, TQT_SIGNAL(textChanged( const TQString& )),
playlist, TQT_SLOT(setFilterSlot( const TQString& )) );
connect( filterButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotEditFilter() ) );
TQToolTip::add( button, i18n( "Clear search field" ) );
TQString filtertip = i18n( "Enter space-separated terms to search in the playlist.\n\n"
"Advanced, Google-esque syntax is also available;\n"
"see the handbook (The Playlist section of chapter 4) for details." );
TQToolTip::add( m_lineEdit, filtertip );
TQToolTip::add( filterButton, i18n( "Click to edit playlist filter" ) );
} //</Search LineEdit>
dynamicBar->init();
m_toolbar = new Amarok::ToolBar( m_browsers->container(), "mainToolBar" );
#ifndef TQ_WS_MAC
m_toolbar->setShown( AmarokConfig::showToolbar() );
#endif
TQWidget *statusbar = new Amarok::StatusBar( this );
KAction* repeatAction = Amarok::actionCollection()->action( "repeat" );
connect( repeatAction, TQT_SIGNAL( activated( int ) ), playlist, TQT_SLOT( slotRepeatTrackToggled( int ) ) );
m_menubar = new KMenuBar( this );
#ifndef TQ_WS_MAC
m_menubar->setShown( AmarokConfig::showMenuBar() );
#endif
//BEGIN Actions menu
KPopupMenu *actionsMenu = new KPopupMenu( m_menubar );
actionCollection()->action("playlist_playmedia")->plug( actionsMenu );
actionCollection()->action("lastfm_play")->plug( actionsMenu );
actionCollection()->action("play_audiocd")->plug( actionsMenu );
actionsMenu->insertSeparator();
actionCollection()->action("prev")->plug( actionsMenu );
actionCollection()->action("play_pause")->plug( actionsMenu );
actionCollection()->action("stop")->plug( actionsMenu );
actionCollection()->action("next")->plug( actionsMenu );
actionsMenu->insertSeparator();
actionCollection()->action(KStdAction::name(KStdAction::Quit))->plug( actionsMenu );
connect( actionsMenu, TQT_SIGNAL( aboutToShow() ), TQT_SLOT( actionsMenuAboutToShow() ) );
//END Actions menu
//BEGIN Playlist menu
KPopupMenu *playlistMenu = new KPopupMenu( m_menubar );
actionCollection()->action("playlist_add")->plug( playlistMenu );
actionCollection()->action("stream_add")->plug( playlistMenu );
actionCollection()->action("lastfm_add")->plug( playlistMenu );
actionCollection()->action("playlist_save")->plug( playlistMenu );
actionCollection()->action("playlist_burn")->plug( playlistMenu );
playlistMenu->insertSeparator();
actionCollection()->action("playlist_undo")->plug( playlistMenu );
actionCollection()->action("playlist_redo")->plug( playlistMenu );
playlistMenu->insertSeparator();
actionCollection()->action("playlist_clear")->plug( playlistMenu );
actionCollection()->action("playlist_shuffle")->plug( playlistMenu );
//this one has no real context with regard to the menu
//actionCollection()->action("playlist_copy")->plug( playlistMenu );
playlistMenu->insertSeparator();
actionCollection()->action("queue_selected")->plug( playlistMenu );
actionCollection()->action("playlist_remove_duplicates")->plug( playlistMenu );
actionCollection()->action("playlist_select_all")->plug( playlistMenu );
//END Playlist menu
//BEGIN Mode menu
KPopupMenu *modeMenu = new KPopupMenu( m_menubar );
actionCollection()->action("repeat")->plug( modeMenu );
KSelectAction *random = static_cast<KSelectAction*>( actionCollection()->action("random_mode") );
random->plug( modeMenu );
random->popupMenu()->insertSeparator();
actionCollection()->action("favor_tracks")->plug( random->popupMenu() );
//END Mode menu
//BEGIN Tools menu
m_toolsMenu = new KPopupMenu( m_menubar );
m_toolsMenu->insertItem( SmallIconSet( Amarok::icon( "covermanager" ) ), i18n("&Cover Manager"), Amarok::Menu::ID_SHOW_COVER_MANAGER );
actionCollection()->action("queue_manager")->plug( m_toolsMenu );
m_toolsMenu->insertItem( SmallIconSet( Amarok::icon( "visualizations" ) ), i18n("&Visualizations"), Amarok::Menu::ID_SHOW_VIS_SELECTOR );
m_toolsMenu->insertItem( SmallIconSet( Amarok::icon( "equalizer") ), i18n("&Equalizer"), TQT_TQOBJECT(kapp), TQT_SLOT( slotConfigEqualizer() ), 0, Amarok::Menu::ID_CONFIGURE_EQUALIZER );
actionCollection()->action("script_manager")->plug( m_toolsMenu );
actionCollection()->action("statistics")->plug( m_toolsMenu );
m_toolsMenu->insertSeparator();
actionCollection()->action("update_collection")->plug( m_toolsMenu );
m_toolsMenu->insertItem( SmallIconSet( Amarok::icon( "rescan" ) ), i18n("&Rescan Collection"), Amarok::Menu::ID_RESCAN_COLLECTION );
#if defined HAVE_LIBVISUAL
m_toolsMenu->setItemEnabled( Amarok::Menu::ID_SHOW_VIS_SELECTOR, true );
#else
m_toolsMenu->setItemEnabled( Amarok::Menu::ID_SHOW_VIS_SELECTOR, false );
#endif
connect( m_toolsMenu, TQT_SIGNAL( aboutToShow() ), TQT_SLOT( toolsMenuAboutToShow() ) );
connect( m_toolsMenu, TQT_SIGNAL( activated(int) ), TQT_SLOT( slotMenuActivated(int) ) );
//END Tools menu
//BEGIN Settings menu
m_settingsMenu = new KPopupMenu( m_menubar );
//TODO use KStdAction or KMainWindow
#ifndef TQ_WS_MAC
static_cast<KToggleAction *>(actionCollection()->action(KStdAction::name(KStdAction::ShowMenubar)))->setChecked( AmarokConfig::showMenuBar() );
actionCollection()->action(KStdAction::name(KStdAction::ShowMenubar))->plug( m_settingsMenu );
m_settingsMenu->insertItem( AmarokConfig::showToolbar() ? i18n( "Hide Toolbar" ) : i18n("Show Toolbar"), ID_SHOW_TOOLBAR );
m_settingsMenu->insertItem( AmarokConfig::showPlayerWindow() ? i18n("Hide Player &Window") : i18n("Show Player &Window"), ID_SHOW_PLAYERWINDOW );
m_settingsMenu->insertSeparator();
#endif
#ifdef TQ_WS_MAC
// plug it first, as this item will be moved to the applications first menu
actionCollection()->action(KStdAction::name(KStdAction::Preferences))->plug( m_settingsMenu );
#endif
actionCollection()->action("options_configure_globals")->plug( m_settingsMenu );
actionCollection()->action(KStdAction::name(KStdAction::KeyBindings))->plug( m_settingsMenu );
actionCollection()->action(KStdAction::name(KStdAction::ConfigureToolbars))->plug( m_settingsMenu );
actionCollection()->action(KStdAction::name(KStdAction::Preferences))->plug( m_settingsMenu );
connect( m_settingsMenu, TQT_SIGNAL( activated(int) ), TQT_SLOT( slotMenuActivated(int) ) );
//END Settings menu
m_menubar->insertItem( i18n( "E&ngage" ), actionsMenu );
m_menubar->insertItem( i18n( "&Playlist" ), playlistMenu );
m_menubar->insertItem( i18n( "&Mode" ), modeMenu );
m_menubar->insertItem( i18n( "&Tools" ), m_toolsMenu );
m_menubar->insertItem( i18n( "&Settings" ), m_settingsMenu );
m_menubar->insertItem( i18n( "&Help" ), Amarok::Menu::helpMenu() );
TQBoxLayout *layV = new TQVBoxLayout( this );
layV->addWidget( m_menubar );
layV->addWidget( m_browsers, 1 );
layV->addWidget( m_toolbar );
layV->addSpacing( 2 );
layV->addWidget( statusbar );
//The volume slider later becomes our FocusProxy, so all wheelEvents get redirected to it
m_toolbar->setFocusPolicy( TQ_WheelFocus );
m_toolbar->setFlat( true );
m_toolbar->setMovingEnabled( false );
playlist->setMargin( 2 );
playlist->installEventFilter( this ); //we intercept keyEvents
//<XMLGUI>
{
TQString xmlFile = Amarok::config()->readEntry( "XMLFile", "amarokui.rc" );
// this bug can bite you if you are a pre 1.2 user, we
// deleted amarokui_first.rc, but we must still support it
// NOTE 1.4.1 we remove amarokui_xmms.rc too, so we can only be this ui.rc
xmlFile = "amarokui.rc";
setXMLFile( xmlFile );
createGUI(); //NOTE we implement this
}
//</XMLGUI>
//<Browsers>
{
Debug::Block block( "Creating browsers. Please report long start times!" );
#define addBrowserMacro( Type, name, text, icon ) { \
Debug::Block block( name ); \
m_browsers->addBrowser( name, new Type( name ), text, icon ); }
#define addInstBrowserMacro( Type, name, text, icon ) { \
Debug::Block block( name ); \
m_browsers->addBrowser( name, Type::instance(), text, icon ); }
addBrowserMacro( ContextBrowser, "ContextBrowser", i18n("Context"), Amarok::icon( "info" ) )
addBrowserMacro( CollectionBrowser, "CollectionBrowser", i18n("Collection"), Amarok::icon( "collection" ) )
m_browsers->makeDropProxy( "CollectionBrowser", CollectionView::instance() );
addInstBrowserMacro( PlaylistBrowser, "PlaylistBrowser", i18n("Playlists"), Amarok::icon( "playlist" ) )
//DEBUG: Comment out the addBrowserMacro line and uncomment the m_browsers line (passing in a vfat device name) to see the "virtual root" functionality
addBrowserMacro( FileBrowser, "FileBrowser", i18n("Files"), Amarok::icon( "files" ) )
//Add Magnatune browser
addInstBrowserMacro( MagnatuneBrowser, "MagnatuneBrowser", i18n("Magnatune"), Amarok::icon( "magnatune" ) )
new MediaBrowser( "MediaBrowser" );
if( MediaBrowser::isAvailable() )
{
addInstBrowserMacro( MediaBrowser, "MediaBrowser", i18n("Devices"), Amarok::icon( "device" ) )
//to re-enable mediabrowser hiding, uncomment this:
//connect( MediaBrowser::instance(), TQT_SIGNAL( availabilityChanged( bool ) ),
// this, TQT_SLOT( mbAvailabilityChanged( bool ) ) );
m_browsers->makeDropProxy( "MediaBrowser", MediaBrowser::queue() );
}
#undef addBrowserMacro
#undef addInstBrowserMacro
}
//</Browsers>
connect( Playlist::instance()->qscrollview(), TQT_SIGNAL( dynamicModeChanged( const DynamicMode* ) ),
PlaylistBrowser::instance(), TQT_SLOT( loadDynamicItems() ) );
tqApp->installEventFilter( this ); // keyboards shortcuts for the browsers
connect( playlist, TQT_SIGNAL( itemCountChanged( int, int, int, int, int, int ) ),
statusbar, TQT_SLOT( slotItemCountChanged( int, int, int, int, int, int ) ) );
connect( playlist, TQT_SIGNAL( queueChanged( const PLItemList &, const PLItemList & ) ),
statusbar, TQT_SLOT( updateQueueLabel() ) );
connect( playlist, TQT_SIGNAL( aboutToClear() ), m_lineEdit, TQT_SLOT( clear() ) );
Amarok::MessageQueue::instance()->sendMessages();
}
void PlaylistWindow::slotSetFilter( const TQString &filter ) //SLOT
{
m_lineEdit->setText( filter );
}
void PlaylistWindow::slotEditFilter() //SLOT
{
EditFilterDialog *fd = new EditFilterDialog( this, true, m_lineEdit->text() );
connect( fd, TQT_SIGNAL(filterChanged(const TQString &)), TQT_SLOT(slotSetFilter(const TQString &)) );
if( fd->exec() )
m_lineEdit->setText( fd->filter() );
delete fd;
}
void PlaylistWindow::addBrowser( const TQString &name, TQWidget *browser, const TQString &text, const TQString &icon )
{
if( !m_browsers->browser( name ) )
m_browsers->addBrowser( name, browser, text, icon );
if( name == "MediaBrowser" )
{
m_browsers->makeDropProxy( "MediaBrowser", MediaBrowser::queue() );
}
}
/**
* Reload the amarokui.rc xml file.
* mainly just used by amarok::Menu
*/
void PlaylistWindow::recreateGUI()
{
reloadXML();
createGUI();
}
/**
* Create the amarok gui from the xml file.
*/
void PlaylistWindow::createGUI()
{
setUpdatesEnabled( false );
LastFm::Controller::instance(); // create love/ban/skip actions
m_toolbar->clear();
//KActions don't unplug themselves when the widget that is plugged is deleted!
//we need to unplug to detect if the menu is plugged in App::applySettings()
//TODO report to bugs.kde.org
//we unplug after clear as otherwise it crashes! dunno why..
KActionPtrList actions = actionCollection()->actions();
for( KActionPtrList::Iterator it = actions.begin(), end = actions.end(); it != end; ++it )
(*it)->unplug( m_toolbar );
KXMLGUIBuilder builder( this );
KXMLGUIFactory factory( &builder, TQT_TQOBJECT(this) );
//build Toolbar, plug actions
factory.addClient( this );
//TEXT ON RIGHT HACK
//KToolBarButtons have independent settings for their appearance.
//KToolBarButton::modeChange() causes that button to set its mode to that of its parent KToolBar
//KToolBar::setIconText() calls modeChange() for children, unless 2nd param is false
TQStringList list;
list << "toolbutton_playlist_add"
// << "toolbutton_playlist_clear"
// << "toolbutton_playlist_shuffle"
// << "toolbutton_playlist_show"
<< "toolbutton_burn_menu"
<< "toolbutton_amarok_menu";
m_toolbar->setIconText( KToolBar::IconTextRight, false ); //we want some buttons to have text on right
const TQStringList::ConstIterator end = list.constEnd();
const TQStringList::ConstIterator last = list.fromLast();
for( TQStringList::ConstIterator it = list.constBegin(); it != end; ++it )
{
KToolBarButton* const button = static_cast<KToolBarButton*>( TQT_TQWIDGET(m_toolbar->child( (*it).latin1() )) );
if ( it == last ) {
//if the user has no PlayerWindow, he MUST have the menu action plugged
//NOTE this is not saved to the local XMLFile, which is what the user will want
if ( !AmarokConfig::showPlayerWindow() && !AmarokConfig::showMenuBar() && !button )
actionCollection()->action( "amarok_menu" )->plug( m_toolbar );
}
if ( button ) {
button->modeChange();
button->setFocusPolicy( TQ_NoFocus );
}
}
m_toolbar->setIconText( KToolBar::IconOnly, false ); //default appearance
conserveMemory();
setUpdatesEnabled( true );
}
/**
* Apply the loaded settings on the playlist window.
* this function loads the custom fonts (if chosen) and than calls PlayList::instance()->applySettings();
*/
void PlaylistWindow::applySettings()
{
switch( AmarokConfig::useCustomFonts() )
{
case true:
Playlist::instance()->setFont( AmarokConfig::playlistWindowFont() );
ContextBrowser::instance()->setFont( AmarokConfig::contextBrowserFont() );
break;
case false:
Playlist::instance()->unsetFont();
ContextBrowser::instance()->unsetFont();
break;
}
}
/**
* @param o The object
* @param e The event
*
* Here we filter some events for the Playlist Search LineEdit and the Playlist. @n
* this makes life easier since we have more useful functions available from this class
*/
bool PlaylistWindow::eventFilter( TQObject *o, TQEvent *e )
{
Playlist* const pl = Playlist::instance();
typedef TQListViewItemIterator It;
switch( e->type() )
{
case 6/*TQEvent::KeyPress*/:
//there are a few keypresses that we intercept
#define e TQT_TQKEYEVENT(e)
if( e->key() == Key_F2 )
{
// currentItem is ALWAYS visible.
TQListViewItem *item = pl->currentItem();
// intercept F2 for inline tag renaming
// NOTE: tab will move to the next tag
// NOTE: if item is still null don't select first item in playlist, user wouldn't want that. It's silly.
// TODO: berkus has solved the "inability to cancel" issue with KListView, but it's not in kdelibs yet..
// item may still be null, but this is safe
// NOTE: column 0 cannot be edited currently, hence we pick column 1
pl->rename( item, 1 ); //TODO what if this column is hidden?
return true;
}
if( e->state() & ControlButton )
{
int n = -1;
switch( e->key() )
{
case Key_0: n = 0; break;
case Key_1: n = 1; break;
case Key_2: n = 2; break;
case Key_3: n = 3; break;
case Key_4: n = 4; break;
case Key_5: n = 5; break;
}
if( n == 0 )
{
m_browsers->closeCurrentBrowser();
return true;
}
else if( n > 0 && n <= m_browsers->visibleCount() )
{
m_browsers->showHideVisibleBrowser( n - 1 );
return true;
}
}
if( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(m_lineEdit) ) //the search lineedit
{
TQListViewItem *item;
switch( e->key() )
{
case Key_Up:
case Key_Down:
case Key_PageDown:
case Key_PageUp:
pl->setFocus();
TQApplication::sendEvent( pl, e );
return true;
case Key_Return:
case Key_Enter:
item = *It( pl, It::Visible );
m_lineEdit->clear();
pl->m_filtertimer->stop(); //HACK HACK HACK
if( e->state() & ControlButton )
{
PLItemList in, out;
if( e->state() & ShiftButton )
for( It it( pl, It::Visible ); PlaylistItem *x = static_cast<PlaylistItem*>( *it ); ++it )
{
pl->queue( x, true );
( pl->m_nextTracks.contains( x ) ? in : out ).append( x );
}
else
{
It it( pl, It::Visible );
pl->activate( *it );
++it;
for( int i = 0; PlaylistItem *x = static_cast<PlaylistItem*>( *it ); ++i, ++it )
{
in.append( x );
pl->m_nextTracks.insert( i, x );
}
}
if( !in.isEmpty() || !out.isEmpty() )
emit pl->queueChanged( in, out );
pl->setFilter( "" );
pl->ensureItemCentered( ( e->state() & ShiftButton ) ? item : pl->currentTrack() );
}
else
{
pl->setFilter( "" );
if( ( e->state() & ShiftButton ) && item )
{
pl->queue( item );
pl->ensureItemCentered( item );
}
else
{
pl->activate( item );
pl->showCurrentTrack();
}
}
return true;
case Key_Escape:
m_lineEdit->clear();
return true;
default:
return false;
}
}
//following are for Playlist::instance() only
//we don't handle these in the playlist because often we manipulate the lineEdit too
if( TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(pl) )
{
if( pl->currentItem() && ( e->key() == Key_Up && pl->currentItem()->itemAbove() == 0 && !(e->state() & TQt::ShiftButton) ) )
{
TQListViewItem *lastitem = *It( pl, It::Visible );
if ( !lastitem )
return false;
while( lastitem->itemBelow() )
lastitem = lastitem->itemBelow();
pl->currentItem()->setSelected( false );
pl->setCurrentItem( lastitem );
lastitem->setSelected( true );
pl->ensureItemVisible( lastitem );
return true;
}
if( pl->currentItem() && ( e->key() == Key_Down && pl->currentItem()->itemBelow() == 0 && !(e->state() & TQt::ShiftButton) ) )
{
pl->currentItem()->setSelected( false );
pl->setCurrentItem( *It( pl, It::Visible ) );
(*It( pl, It::Visible ))->setSelected( true );
pl->ensureItemVisible( *It( pl, It::Visible ) );
return true;
}
if( e->key() == Key_Delete )
{
pl->removeSelectedItems();
return true;
}
if( ( ( e->key() >= Key_0 && e->key() <= Key_Z ) || e->key() == Key_Backspace || e->key() == Key_Escape ) && ( !e->state() || e->state() == TQt::ShiftButton ) ) //only if shift or no modifier key is pressed and 0-Z or backspace or escape
{
m_lineEdit->setFocus();
TQApplication::sendEvent( m_lineEdit, e );
return true;
}
}
#undef e
break;
default:
break;
}
return TQWidget::eventFilter( o, e );
}
void PlaylistWindow::closeEvent( TQCloseEvent *e )
{
#ifdef TQ_WS_MAC
Q_UNUSED( e );
hide();
#else
Amarok::genericEventHandler( TQT_TQWIDGET(this), TQT_TQEVENT(e) );
#endif
}
void PlaylistWindow::showEvent( TQShowEvent* )
{
static bool firstTime = true;
if( firstTime )
Playlist::instance()->setFocus();
firstTime = false;
}
#include <tqdesktopwidget.h>
TQSize PlaylistWindow::sizeHint() const
{
return TQApplication::desktop()->screenGeometry( (TQWidget*)this ).size() / 1.5;
}
void PlaylistWindow::savePlaylist() const //SLOT
{
Playlist *pl = Playlist::instance();
PlaylistItem *item = pl->firstChild();
if( item && !item->isVisible() )
item = static_cast<PlaylistItem*>( item->itemBelow() );
TQString title = pl->playlistName();
if( item && title == i18n( "Untitled" ) )
{
TQString artist = item->artist();
TQString album = item->album();
bool useArtist = true, useAlbum = true;
item = static_cast<PlaylistItem*>( item->itemBelow() );
for( ; item; item = static_cast<PlaylistItem*>( item->itemBelow() ) )
{
if( artist != item->artist() )
useArtist = false;
if( album != item->album() )
useAlbum = false;
if( !useArtist && !useAlbum )