File indexing completed on 2024-04-21 04:47:51

0001  /****************************************************************************************
0002  * Copyright (c) 2002-2013 Mark Kretschmann <kretschmann@kde.org>                       *
0003  * Copyright (c) 2002 Max Howell <max.howell@methylblue.com>                            *
0004  * Copyright (c) 2002 Gabor Lehel <illissius@gmail.com>                                 *
0005  * Copyright (c) 2002 Nikolaj Hald Nielsen <nhn@kde.org>                                *
0006  * Copyright (c) 2009 Artur Szymiec <artur.szymiec@gmail.com>                           *
0007  * Copyright (c) 2010 Téo Mrnjavac <teo@kde.org>                                        *
0008  *                                                                                      *
0009  * This program is free software; you can redistribute it and/or modify it under        *
0010  * the terms of the GNU General Public License as published by the Free Software        *
0011  * Foundation; either version 2 of the License, or (at your option) any later           *
0012  * version.                                                                             *
0013  *                                                                                      *
0014  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0015  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0016  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0017  *                                                                                      *
0018  * You should have received a copy of the GNU General Public License along with         *
0019  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0020  ****************************************************************************************/
0021 
0022 #define DEBUG_PREFIX "MainWindow"
0023 
0024 #include "MainWindow.h"
0025 
0026 #include "App.h"
0027 #include "ActionClasses.h"
0028 #include "EngineController.h" //for actions in ctor
0029 #include "KNotificationBackend.h"
0030 #include "PaletteHandler.h"
0031 #include "PluginManager.h"
0032 #include "SvgHandler.h"
0033 #include "amarokconfig.h"
0034 #include "aboutdialog/ExtendedAboutDialog.h"
0035 #include "aboutdialog/OcsData.h"
0036 #include "amarokurls/AmarokUrlHandler.h"
0037 #include "amarokurls/BookmarkManager.h"
0038 #include "browsers/BrowserDock.h"
0039 #include "browsers/collectionbrowser/CollectionWidget.h"
0040 #include "browsers/filebrowser/FileBrowser.h"
0041 #include "browsers/playlistbrowser/PlaylistBrowser.h"
0042 #include "browsers/playlistbrowser/PodcastCategory.h"
0043 #include "browsers/servicebrowser/ServiceBrowser.h"
0044 #include "context/ContextDock.h"
0045 #include "core/meta/Statistics.h"
0046 #include "core/support/Amarok.h"
0047 #include "core/support/Components.h"
0048 #include "core/support/Debug.h"
0049 #include "core-impl/collections/support/CollectionManager.h"
0050 #include "covermanager/CoverManager.h" // for actions
0051 #include "dialogs/DiagnosticDialog.h"
0052 #include "dialogs/EqualizerDialog.h"
0053 #include "moodbar/MoodbarManager.h"
0054 #include "network/NetworkAccessManagerProxy.h"
0055 #ifdef DEBUG_BUILD_TYPE
0056 #include "network/NetworkAccessViewer.h"
0057 #endif // DEBUG_BUILD_TYPE
0058 #include "playlist/PlaylistActions.h"
0059 #include "playlist/PlaylistController.h"
0060 #include "playlist/PlaylistDock.h"
0061 #include "playlist/PlaylistModelStack.h"
0062 #include "playlist/ProgressiveSearchWidget.h"
0063 #include "playlist/layouts/LayoutConfigAction.h"
0064 #include "playlistmanager/PlaylistManager.h"
0065 #include "playlistmanager/file/PlaylistFileProvider.h"
0066 #include "services/scriptable/ScriptableService.h"
0067 #include "statsyncing/Controller.h"
0068 #include "toolbar/MainToolbar.h"
0069 #include "toolbar/SlimToolbar.h"
0070 #include "widgets/Osd.h"
0071 
0072 #include <QAction>          //m_actionCollection
0073 #include <QApplication>     //qApp
0074 #include <QCheckBox>
0075 #include <QClipboard>
0076 #include <QDesktopServices>
0077 #include <QDesktopWidget>
0078 #include <QDockWidget>
0079 #include <QFileDialog>      //openPlaylist()
0080 #include <QInputDialog>     //slotAddStream()
0081 #include <QList>
0082 #include <QMenu>
0083 #include <QMenuBar>
0084 #include <QStandardPaths>
0085 #include <QStyle>
0086 #include <QVBoxLayout>
0087 
0088 #include <KActionCollection>
0089 #include <KBugReport>
0090 #include <KFileWidget>
0091 #include <KFormat>
0092 #include <KGlobalAccel>
0093 #include <KLocalizedString>
0094 #include <KMessageBox>
0095 #include <KStandardAction>
0096 #include <KWindowSystem>
0097 
0098 #include <iostream>
0099 
0100 #ifdef Q_WS_X11
0101 #include <fixx11h.h>
0102 #include <KConfigGroup>
0103 #endif
0104 
0105 #ifdef Q_WS_MAC
0106 #include "mac/GrowlInterface.h"
0107 #ifdef HAVE_NOTIFICATION_CENTER
0108 #include "mac/MacSystemNotify.h"
0109 #endif
0110 #endif
0111 
0112 #define AMAROK_CAPTION I18N_NOOP( "Amarok" )
0113 
0114 extern OcsData ocsData;
0115 
0116 namespace The {
0117     MainWindow* mainWindow() { return pApp->mainWindow(); }
0118 }
0119 
0120 MainWindow::MainWindow()
0121     : KMainWindow( nullptr )
0122     , m_showMenuBar( nullptr )
0123     , m_lastBrowser( 0 )
0124     , m_waitingForCd( false )
0125 {
0126     DEBUG_BLOCK
0127 
0128     setObjectName( "MainWindow" );
0129 
0130 #ifdef Q_WS_MAC
0131     (void)new GrowlInterface( qApp->applicationName() );
0132 #ifdef HAVE_NOTIFICATION_CENTER
0133     (void)new OSXNotify( qApp->applicationName() );
0134 #endif
0135 #endif
0136 
0137     PERF_LOG( "Instantiate Collection Manager" )
0138     CollectionManager::instance();
0139     PERF_LOG( "Started Collection Manager instance" )
0140 
0141     /* The PluginManager needs to be loaded before the playlist model
0142     * (which gets started by "statusBar::connectPlaylist" below so that it can handle any
0143     * tracks in the saved playlist that are associated with services. Eg, if
0144     * the playlist has a Magnatune track in it when Amarok is closed, then the
0145     * Magnatune service needs to be initialized before the playlist is loaded
0146     * here. */
0147     PERF_LOG( "Instantiate Plugin Manager" )
0148     The::pluginManager();
0149     PERF_LOG( "Started Plugin Manager instance" )
0150 
0151     createActions();
0152     PERF_LOG( "Created actions" )
0153 
0154     The::paletteHandler()->setPalette( palette() );
0155     setPlainCaption( i18n( AMAROK_CAPTION ) );
0156 
0157     init();  // We could as well move the code from init() here, but meh.. getting a tad long
0158 
0159     //restore active category ( as well as filters and levels and whatnot.. )
0160     const QString path = Amarok::config().readEntry( "Browser Path", QString() );
0161     if( !path.isEmpty() )
0162         m_browserDock->list()->navigate( path );
0163 
0164     setAutoSaveSettings();
0165 
0166     m_showMenuBar->setChecked(!menuBar()->isHidden());  // workaround for bug #171080
0167 
0168     EngineController *engine = The::engineController();
0169     connect( engine, &EngineController::stopped, this, &MainWindow::slotStopped );
0170     connect( engine, &EngineController::paused, this, &MainWindow::slotPaused );
0171     connect( engine, &EngineController::trackPlaying, this, &MainWindow::slotNewTrackPlaying );
0172     connect( engine, &EngineController::trackMetadataChanged, this, &MainWindow::slotMetadataChanged );
0173 }
0174 
0175 MainWindow::~MainWindow()
0176 {
0177     DEBUG_BLOCK
0178 
0179     //save currently active category
0180     Amarok::config().writeEntry( "Browser Path", m_browserDock->list()->path() );
0181 
0182 #ifdef DEBUG_BUILD_TYPE
0183     delete m_networkViewer.data();
0184 #endif // DEBUG_BUILD_TYPE
0185     delete The::svgHandler();
0186     delete The::paletteHandler();
0187 }
0188 
0189 
0190 ///////// public interface
0191 
0192 /**
0193  * This function will initialize the main window.
0194  */
0195 void
0196 MainWindow::init()
0197 {
0198     layout()->setContentsMargins( 0, 0, 0, 0 );
0199     layout()->setSpacing( 0 );
0200 
0201     //create main toolbar
0202     m_mainToolbar = new MainToolbar( this );
0203     m_mainToolbar.data()->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea );
0204     m_mainToolbar.data()->setMovable ( true );
0205     addToolBar( Qt::TopToolBarArea, m_mainToolbar.data() );
0206 
0207     //create slim toolbar
0208     m_slimToolbar = new SlimToolbar( this );
0209     m_slimToolbar.data()->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea );
0210     m_slimToolbar.data()->setMovable ( true );
0211     addToolBar( Qt::TopToolBarArea, m_slimToolbar.data() );
0212     m_slimToolbar->hide();
0213 
0214     //BEGIN Creating Widgets
0215     PERF_LOG( "Create sidebar" )
0216     m_browserDock = new BrowserDock( this );
0217     m_browserDock->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored );
0218 
0219     m_browserDock->installEventFilter( this );
0220     PERF_LOG( "Sidebar created" )
0221 
0222     PERF_LOG( "Create Playlist" )
0223     m_playlistDock = new Playlist::Dock( this );
0224     m_playlistDock->installEventFilter( this );
0225     //HACK, need to connect after because of order in MainWindow()
0226     connect( Amarok::actionCollection()->action( "playlist_edit_queue" ),
0227              &QAction::triggered, m_playlistDock.data(), &Playlist::Dock::slotEditQueue );
0228     PERF_LOG( "Playlist created" )
0229 
0230     PERF_LOG( "Creating ContextWidget" )
0231     m_contextDock = new ContextDock( this );
0232     m_contextDock->installEventFilter( this );
0233     PERF_LOG( "ContextScene created" )
0234     //END Creating Widgets
0235 
0236     createMenus();
0237 
0238     setDockOptions( QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks
0239                     | QMainWindow::AnimatedDocks | QMainWindow::VerticalTabs );
0240 
0241     addDockWidget( Qt::LeftDockWidgetArea, m_browserDock.data() );
0242     addDockWidget( Qt::LeftDockWidgetArea, m_contextDock.data(), Qt::Horizontal );
0243     addDockWidget( Qt::LeftDockWidgetArea, m_playlistDock.data(), Qt::Horizontal );
0244 
0245     setLayoutLocked( AmarokConfig::lockLayout() );
0246 
0247     //<Browsers>
0248     {
0249         Debug::Block block( "Creating browsers. Please report long start times!" );
0250 
0251         //TODO: parent these browsers?
0252         PERF_LOG( "Creating CollectionWidget" )
0253         m_collectionBrowser = new CollectionWidget( "collections", nullptr );
0254         //TODO: rename "Music Collections
0255         m_collectionBrowser->setPrettyName( i18n( "Local Music" ) );
0256         m_collectionBrowser->setIcon( QIcon::fromTheme( "drive-harddisk" ) );
0257         m_collectionBrowser->setShortDescription( i18n( "Local sources of content" ) );
0258         m_browserDock->list()->addCategory( m_collectionBrowser );
0259         PERF_LOG( "Created CollectionWidget" )
0260 
0261         PERF_LOG( "Creating ServiceBrowser" )
0262         ServiceBrowser *serviceBrowser = ServiceBrowser::instance();
0263         serviceBrowser->setParent( nullptr );
0264         serviceBrowser->setPrettyName( i18n( "Internet" ) );
0265         serviceBrowser->setIcon( QIcon::fromTheme( "internet-services" ) );
0266         serviceBrowser->setShortDescription( i18n( "Online sources of content" ) );
0267         m_browserDock->list()->addCategory( serviceBrowser );
0268         PERF_LOG( "Created ServiceBrowser" )
0269 
0270         PERF_LOG( "Creating PlaylistBrowser" )
0271         m_playlistBrowser = new PlaylistBrowserNS::PlaylistBrowser( "playlists", nullptr );
0272         m_playlistBrowser->setPrettyName( i18n("Playlists") );
0273         m_playlistBrowser->setIcon( QIcon::fromTheme( "view-media-playlist-amarok" ) );
0274         m_playlistBrowser->setShortDescription( i18n( "Various types of playlists" ) );
0275         m_browserDock->list()->addCategory( m_playlistBrowser );
0276         PERF_LOG( "CreatedPlaylsitBrowser" )
0277 
0278         PERF_LOG( "Creating FileBrowser" )
0279         FileBrowser *fileBrowser = new FileBrowser( "files", nullptr );
0280         fileBrowser->setPrettyName( i18n("Files") );
0281         fileBrowser->setIcon( QIcon::fromTheme( "folder-amarok" ) );
0282 
0283         fileBrowser->setShortDescription( i18n( "Browse local hard drive for content" ) );
0284         m_browserDock->list()->addCategory( fileBrowser );
0285         PERF_LOG( "Created FileBrowser" )
0286 
0287         serviceBrowser->setScriptableServiceManager( The::scriptableServiceManager() );
0288         PERF_LOG( "ScriptableServiceManager done" )
0289 
0290         PERF_LOG( "Creating Podcast Category" )
0291         m_browserDock->list()->addCategory( The::podcastCategory() );
0292         PERF_LOG( "Created Podcast Category" )
0293 
0294     // If Amarok is started for the first time, set initial dock widget sizes
0295         if( !Amarok::config( "MainWindow" ).hasKey( "State" ) )
0296             QTimer::singleShot( 0, this, &MainWindow::setDefaultDockSizes );
0297 
0298         PERF_LOG( "finished MainWindow::init" )
0299     }
0300     The::amarokUrlHandler(); //Instantiate
0301     The::coverFetcher(); //Instantiate
0302 
0303     // we must filter ourself to get mouseevents on the "splitter" - what is us, but filtered by the layouter
0304     installEventFilter( this );
0305 }
0306 
0307 QMenu*
0308 MainWindow::createPopupMenu()
0309 {
0310     QMenu* menu = new QMenu( this );
0311 
0312     // Show/hide menu bar
0313     if (!menuBar()->isVisible())
0314         menu->addAction( m_showMenuBar );
0315 
0316     menu->addSeparator();
0317 
0318     addViewMenuItems(menu);
0319 
0320     return menu;
0321 }
0322 
0323 void
0324 MainWindow::addViewMenuItems(QMenu* menu)
0325 {
0326     menu->setTitle( i18nc("@item:inmenu", "&View" ) );
0327 
0328     // Layout locking:
0329     QAction* lockAction = new QAction( i18n( "Lock Layout" ), this );
0330     lockAction->setCheckable( true );
0331     lockAction->setChecked( AmarokConfig::lockLayout() );
0332     connect( lockAction, &QAction::toggled, this, &MainWindow::setLayoutLocked );
0333     menu->addAction( lockAction );
0334 
0335     menu->addSeparator();
0336 
0337     // Dock widgets:
0338     QList<QDockWidget *> dockwidgets = findChildren<QDockWidget *>();
0339 
0340     foreach( QDockWidget* dockWidget, dockwidgets )
0341     {
0342         if( dockWidget->parentWidget() == this )
0343             menu->addAction( dockWidget->toggleViewAction() );
0344     }
0345 
0346     menu->addSeparator();
0347 
0348     // Toolbars:
0349     QList<QToolBar *> toolbars = findChildren<QToolBar *>();
0350     QActionGroup* toolBarGroup = new QActionGroup( this );
0351     toolBarGroup->setExclusive( true );
0352 
0353     foreach( QToolBar* toolBar, toolbars )
0354     {
0355         if( toolBar->parentWidget() == this )
0356         {
0357             QAction* action = toolBar->toggleViewAction();
0358             connect( action, &QAction::toggled, toolBar, &QToolBar::setVisible );
0359             toolBarGroup->addAction( action );
0360             menu->addAction( action );
0361         }
0362     }
0363 
0364     menu->addSeparator();
0365 
0366     QAction *resetAction = new QAction( i18n( "Reset Layout" ), this );
0367     connect( resetAction, &QAction::triggered, this, &MainWindow::resetLayout );
0368     menu->addAction( resetAction );
0369 }
0370 
0371 void
0372 MainWindow::showBrowser( const QString &name )
0373 {
0374     Q_UNUSED( name );
0375     // showBrowser( index ); // FIXME
0376 }
0377 
0378 void
0379 MainWindow::showDock( AmarokDockId dockId )
0380 {
0381     QString name;
0382     switch( dockId )
0383     {
0384         case AmarokDockNavigation:
0385             name = m_browserDock->windowTitle();
0386             break;
0387         case AmarokDockContext:
0388             name = m_contextDock->windowTitle();
0389             break;
0390         case AmarokDockPlaylist:
0391             name = m_playlistDock->windowTitle();
0392             break;
0393     }
0394 
0395     QList < QTabBar * > tabList = findChildren < QTabBar * > ();
0396 
0397     foreach( QTabBar *bar, tabList )
0398     {
0399         for( int i = 0; i < bar->count(); i++ )
0400         {
0401             if( bar->tabText( i ) == name )
0402             {
0403                 bar->setCurrentIndex( i );
0404                 break;
0405             }
0406         }
0407     }
0408 }
0409 
0410 void
0411 MainWindow::closeEvent( QCloseEvent *e )
0412 {
0413 #ifdef Q_WS_MAC
0414     Q_UNUSED( e );
0415     hide();
0416 #else
0417 
0418     //KDE policy states we should hide to tray and not quit() when the
0419     //close window button is pushed for the main widget
0420     if( AmarokConfig::showTrayIcon() && e->spontaneous() && !qApp->isSavingSession() )
0421     {
0422         KMessageBox::information( this,
0423                 i18n( "<qt>Closing the main window will keep Amarok running in the System Tray. "
0424                       "Use <B>Quit</B> from the menu, or the Amarok tray icon to exit the application.</qt>" ),
0425                 i18n( "Docking in System Tray" ), "hideOnCloseInfo" );
0426 
0427         hide();
0428         e->ignore();
0429         return;
0430     }
0431 
0432     e->accept();
0433     pApp->quit();
0434 #endif
0435 }
0436 
0437 void
0438 MainWindow::exportPlaylist() //SLOT
0439 {
0440     DEBUG_BLOCK
0441 
0442     QFileDialog fileDialog;
0443     fileDialog.restoreState( Amarok::config( "playlist-export-dialog" ).readEntry( "state", QByteArray() ) );
0444 
0445     // FIXME: Make checkbox visible in dialog
0446     QCheckBox *saveRelativeCheck = new QCheckBox( i18n("Use relative path for &saving"), &fileDialog );
0447     saveRelativeCheck->setChecked( AmarokConfig::relativePlaylist() );
0448 
0449     QStringList supportedMimeTypes;
0450 
0451     supportedMimeTypes << "video/x-ms-asf"; //ASX
0452     supportedMimeTypes << "audio/x-mpegurl"; //M3U
0453     supportedMimeTypes << "audio/x-scpls"; //PLS
0454     supportedMimeTypes << "application/xspf+xml"; //XSPF
0455 
0456     fileDialog.setMimeTypeFilters( supportedMimeTypes );
0457     fileDialog.setAcceptMode( QFileDialog::AcceptSave );
0458     fileDialog.setFileMode( QFileDialog::AnyFile );
0459     fileDialog.setWindowTitle( i18n("Save As") );
0460     fileDialog.setObjectName( "PlaylistExport" );
0461 
0462     int result = fileDialog.exec();
0463     QString playlistPath = fileDialog.selectedFiles().value( 0 );
0464     if( result == QDialog::Accepted && !playlistPath.isEmpty() )
0465         The::playlist()->exportPlaylist( playlistPath, saveRelativeCheck->isChecked() );
0466 
0467     Amarok::config( "playlist-export-dialog" ).writeEntry( "state", fileDialog.saveState() );
0468 }
0469 
0470 void
0471 MainWindow::slotShowActiveTrack() const
0472 {
0473     m_playlistDock->showActiveTrack();
0474 }
0475 
0476 void
0477 MainWindow::slotEditTrackInfo() const
0478 {
0479     m_playlistDock->editTrackInfo();
0480 }
0481 
0482 void
0483 MainWindow::slotShowCoverManager() //SLOT
0484 {
0485     CoverManager::showOnce( QString(), this );
0486 }
0487 
0488 void
0489 MainWindow::slotShowDiagnosticsDialog()
0490 {
0491     DiagnosticDialog *dialog = new DiagnosticDialog( KAboutData::applicationData(), this );
0492     dialog->show();
0493 }
0494 
0495 void MainWindow::slotShowBookmarkManager()
0496 {
0497     BookmarkManager::showOnce( this );
0498 }
0499 
0500 void MainWindow::slotShowEqualizer()
0501 {
0502     EqualizerDialog::showOnce( this );
0503 }
0504 
0505 void
0506 MainWindow::slotPlayMedia() //SLOT
0507 {
0508     // Request location and immediately start playback
0509     slotAddLocation( true );
0510 }
0511 
0512 void
0513 MainWindow::slotAddLocation( bool directPlay ) //SLOT
0514 {
0515     static QUrl lastDirectory;
0516 
0517     // open a file selector to add media to the playlist
0518     QList<QUrl> files;
0519     QFileDialog dlg;
0520     dlg.setDirectory( QStandardPaths::writableLocation(QStandardPaths::MusicLocation) );
0521 
0522     if( !lastDirectory.isEmpty() )
0523         dlg.setDirectoryUrl( lastDirectory );
0524 
0525     dlg.setWindowTitle( directPlay ? i18n("Play Media (Files or URLs)") : i18n("Add Media (Files or URLs)") );
0526     dlg.setFileMode( QFileDialog::ExistingFiles );
0527     dlg.setObjectName( "PlayMedia" );
0528     int accepted = dlg.exec();
0529     files = dlg.selectedUrls();
0530 
0531     lastDirectory = dlg.directoryUrl();
0532 
0533     if( accepted != QDialog::Accepted || files.isEmpty() )
0534         return;
0535 
0536     Playlist::AddOptions options = directPlay ? Playlist::OnPlayMediaAction
0537                                               : Playlist::OnAppendToPlaylistAction;
0538     The::playlistController()->insertOptioned( files, options );
0539 }
0540 
0541 void
0542 MainWindow::slotAddStream() //SLOT
0543 {
0544     bool ok;
0545     QString url = QInputDialog::getText( this, i18n( "Add Stream" ), i18n( "Enter Stream URL:" ),
0546                                          QLineEdit::Normal, QString(), &ok );
0547     if( !ok )
0548         return;
0549 
0550     The::playlistController()->insertOptioned( QUrl( url ),
0551             Playlist::OnAppendToPlaylistAction | Playlist::RemotePlaylistsAreStreams );
0552 }
0553 
0554 void
0555 MainWindow::slotFocusPlaylistSearch()
0556 {
0557     showDock( AmarokDockPlaylist );  // ensure that the dock is visible if tabbed
0558     m_playlistDock->searchWidget()->focusInputLine();
0559 }
0560 
0561 void
0562 MainWindow::slotFocusCollectionSearch()
0563 {
0564     // ensure collection browser is activated within navigation dock:
0565     browserDock()->list()->navigate( QStringLiteral("collections") );
0566     showDock( AmarokDockNavigation );  // ensure that the dock is visible if tabbed
0567     m_collectionBrowser->focusInputLine();
0568 }
0569 
0570 #ifdef DEBUG_BUILD_TYPE
0571 void
0572 MainWindow::showNetworkRequestViewer() //SLOT
0573 {
0574     if( !m_networkViewer )
0575     {
0576         m_networkViewer = new NetworkAccessViewer( this );
0577         The::networkAccessManager()->setNetworkAccessViewer( m_networkViewer.data() );
0578 
0579     }
0580     The::networkAccessManager()->networkAccessViewer()->show();
0581 }
0582 #endif // DEBUG_BUILD_TYPE
0583 
0584 /**
0585  * "Toggle Main Window" global shortcut connects to this slot
0586  */
0587 void
0588 MainWindow::showHide() //SLOT
0589 {
0590     const KWindowInfo info( winId(), {}, {} );
0591     const int currentDesktop = KWindowSystem::currentDesktop();
0592 
0593     if( !isVisible() )
0594     {
0595         setVisible( true );
0596     }
0597     else
0598     {
0599         if( !isMinimized() )
0600         {
0601             if( !isActiveWindow() ) // not minimised and without focus
0602             {
0603                 KWindowSystem::setOnDesktop( winId(), currentDesktop );
0604                 KWindowSystem::activateWindow( winId() );
0605             }
0606             else // Amarok has focus
0607             {
0608                 setVisible( false );
0609             }
0610         }
0611         else // Amarok is minimised
0612         {
0613             setWindowState( windowState() & ~Qt::WindowMinimized );
0614             KWindowSystem::setOnDesktop( winId(), currentDesktop );
0615             KWindowSystem::activateWindow( winId() );
0616         }
0617     }
0618 }
0619 
0620 void
0621 MainWindow::showNotificationPopup() // slot
0622 {
0623     if( Amarok::KNotificationBackend::instance()->isEnabled()
0624             && !Amarok::OSD::instance()->isEnabled() )
0625         Amarok::KNotificationBackend::instance()->showCurrentTrack();
0626     else
0627         Amarok::OSD::instance()->forceToggleOSD();
0628 }
0629 
0630 void
0631 MainWindow::slotFullScreen() // slot
0632 {
0633     setWindowState( windowState() ^ Qt::WindowFullScreen );
0634 }
0635 
0636 void
0637 MainWindow::slotLoveTrack()
0638 {
0639     Q_EMIT loveTrack( The::engineController()->currentTrack() );
0640 }
0641 
0642 void
0643 MainWindow::slotBanTrack()
0644 {
0645     Q_EMIT banTrack( The::engineController()->currentTrack() );
0646 }
0647 
0648 void
0649 MainWindow::slotShufflePlaylist()
0650 {
0651     m_playlistDock->sortWidget()->trimToLevel();
0652     The::playlistActions()->shuffle();
0653 }
0654 
0655 void
0656 MainWindow::slotSeekForwardShort()
0657 {
0658     EngineController* ec = The::engineController();
0659     ec->seekBy( AmarokConfig::seekShort() * 1000 );
0660 }
0661 
0662 void
0663 MainWindow::slotSeekForwardMedium()
0664 {
0665     EngineController* ec = The::engineController();
0666     ec->seekBy( AmarokConfig::seekMedium() * 1000 );
0667 }
0668 
0669 void
0670 MainWindow::slotSeekForwardLong()
0671 {
0672     EngineController* ec = The::engineController();
0673     ec->seekBy( AmarokConfig::seekLong() * 1000 );
0674 }
0675 
0676 void
0677 MainWindow::slotSeekBackwardShort()
0678 {
0679     EngineController* ec = The::engineController();
0680     ec->seekBy( AmarokConfig::seekShort() * -1000 );
0681 }
0682 
0683 void
0684 MainWindow::slotSeekBackwardMedium()
0685 {
0686     EngineController* ec = The::engineController();
0687     ec->seekBy( AmarokConfig::seekMedium() * -1000 );
0688 }
0689 
0690 void
0691 MainWindow::slotSeekBackwardLong()
0692 {
0693     EngineController* ec = The::engineController();
0694     ec->seekBy( AmarokConfig::seekLong() * -1000 );
0695 }
0696 
0697 void MainWindow::slotPutCurrentTrackToClipboard()
0698 {
0699     Meta::TrackPtr currentTrack = The::engineController()->currentTrack();
0700     if ( currentTrack )
0701     {
0702         QString text;
0703         Meta::ArtistPtr artist = currentTrack->artist();
0704         if( artist )
0705             text = artist->prettyName() + " - ";
0706         text += currentTrack->prettyName();
0707 
0708         QClipboard *clipboard = QApplication::clipboard();
0709         clipboard->setText( text );
0710     }
0711 }
0712 
0713 void
0714 MainWindow::activate()
0715 {
0716 #ifdef Q_WS_X11
0717     const KWindowInfo info = KWindowSystem::windowInfo( winId(), 0, 0 );
0718 
0719     if( KWindowSystem::activeWindow() != winId() )
0720         setVisible( true );
0721     else if( !info.isMinimized() )
0722         setVisible( true );
0723     if( !isHidden() )
0724         KWindowSystem::activateWindow( winId() );
0725 #else
0726     setVisible( true );
0727 #endif
0728 }
0729 
0730 void
0731 MainWindow::createActions()
0732 {
0733     KActionCollection* const ac = Amarok::actionCollection();
0734     const EngineController* const ec = The::engineController();
0735     const Playlist::Actions* const pa = The::playlistActions();
0736     const Playlist::Controller* const pc = The::playlistController();
0737 
0738     KStandardAction::keyBindings( pApp, &App::slotConfigShortcuts, ac );
0739     KStandardAction::preferences( pApp, &App::slotConfigAmarokWithEmptyPage, ac );
0740 
0741     m_showMenuBar = KStandardAction::showMenubar(this, &MainWindow::slotShowMenuBar, ac);
0742     ac->action( KStandardAction::name( KStandardAction::KeyBindings ) )->setIcon( QIcon::fromTheme( QStringLiteral("configure-shortcuts-amarok") ) );
0743     ac->action( KStandardAction::name( KStandardAction::Preferences ) )->setIcon( QIcon::fromTheme( QStringLiteral("configure-amarok") ) );
0744     ac->action( KStandardAction::name( KStandardAction::Preferences ) )->setMenuRole(QAction::PreferencesRole); // Define OS X Prefs menu here, removes need for ifdef later
0745 
0746     KStandardAction::quit( pApp, &App::quit, ac );
0747 
0748     QAction *action = new QAction( QIcon::fromTheme( QStringLiteral("document-open") ), i18n("&Add Media..."), this );
0749     ac->addAction( "playlist_add", action );
0750     connect( action, &QAction::triggered, this, &MainWindow::slotAddLocation );
0751     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_A ) );
0752 
0753     action = new QAction( QIcon::fromTheme( QStringLiteral("edit-clear-list") ), i18nc( "clear playlist", "&Clear Playlist" ), this );
0754     connect( action, &QAction::triggered, pc, &Playlist::Controller::clear );
0755     ac->addAction( "playlist_clear", action );
0756 
0757     action = new QAction( QIcon::fromTheme( QStringLiteral("format-list-ordered") ),
0758                           i18nc( "edit play queue of playlist", "Edit &Queue" ), this );
0759     //Qt::META+Qt::Key_Q is taken by Plasma as a global
0760     action->setShortcut( QKeySequence( Qt::META + Qt::Key_U ) );
0761     ac->addAction( "playlist_edit_queue", action );
0762 
0763     action = new QAction( i18nc( "Remove duplicate and dead (unplayable) tracks from the playlist", "Re&move Duplicates" ), this );
0764     connect( action, &QAction::triggered, pc, &Playlist::Controller::removeDeadAndDuplicates );
0765     ac->addAction( "playlist_remove_dead_and_duplicates", action );
0766 
0767     action = new Playlist::LayoutConfigAction( this );
0768     ac->addAction( "playlist_layout", action );
0769 
0770     action = new QAction( QIcon::fromTheme( QStringLiteral("document-open-remote") ), i18n("&Add Stream..."), this );
0771     connect( action, &QAction::triggered, this, &MainWindow::slotAddStream );
0772     ac->addAction( "stream_add", action );
0773 
0774     action = new QAction( QIcon::fromTheme( QStringLiteral("document-export-amarok") ), i18n("&Export Playlist As..."), this );
0775     connect( action, &QAction::triggered, this, &MainWindow::exportPlaylist );
0776     ac->addAction( "playlist_export", action );
0777 
0778     action = new QAction( QIcon::fromTheme( QStringLiteral("bookmark-new") ), i18n( "Bookmark Media Sources View" ), this );
0779     ac->addAction( "bookmark_browser", action );
0780     connect( action, &QAction::triggered, The::amarokUrlHandler(), &AmarokUrlHandler::bookmarkCurrentBrowserView );
0781 
0782     action = new QAction( QIcon::fromTheme( QStringLiteral("bookmarks-organize") ), i18n( "Bookmark Manager" ), this );
0783     ac->addAction( "bookmark_manager", action );
0784     connect( action, &QAction::triggered, this, &MainWindow::slotShowBookmarkManager );
0785 
0786     action = new QAction( QIcon::fromTheme( QStringLiteral("view-media-equalizer") ), i18n( "Equalizer" ), this );
0787     ac->addAction( "equalizer_dialog", action );
0788     connect( action, &QAction::triggered, this, &MainWindow::slotShowEqualizer );
0789 
0790     action = new QAction( QIcon::fromTheme( QStringLiteral("bookmark-new") ), i18n( "Bookmark Playlist Setup" ), this );
0791     ac->addAction( "bookmark_playlistview", action );
0792     connect( action, &QAction::triggered, The::amarokUrlHandler(), &AmarokUrlHandler::bookmarkCurrentPlaylistView );
0793 
0794     action = new QAction( QIcon::fromTheme( QStringLiteral("bookmark-new") ), i18n( "Bookmark Context Applets" ), this );
0795     ac->addAction( "bookmark_contextview", action );
0796     connect( action, &QAction::triggered, The::amarokUrlHandler(), &AmarokUrlHandler::bookmarkCurrentContextView );
0797 
0798     action = new QAction( QIcon::fromTheme( QStringLiteral("media-album-cover-manager-amarok") ), i18n( "Cover Manager" ), this );
0799     connect( action, &QAction::triggered, this, &MainWindow::slotShowCoverManager );
0800     ac->addAction( "cover_manager", action );
0801 
0802     action = new QAction( QIcon::fromTheme(QStringLiteral("document-open")), i18n("Play Media..."), this );
0803     ac->addAction( "playlist_playmedia", action );
0804     action->setShortcut( Qt::CTRL + Qt::Key_O );
0805     connect( action, &QAction::triggered, this, &MainWindow::slotPlayMedia );
0806 
0807     action = new QAction( QIcon::fromTheme(QStringLiteral("media-track-edit-amarok")), i18n("Edit Details of Currently Selected Track"), this );
0808     ac->addAction( "trackdetails_edit", action );
0809     action->setShortcut( Qt::CTRL + Qt::Key_E );
0810     connect( action, &QAction::triggered, this, &MainWindow::slotEditTrackInfo );
0811 
0812     action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-forward-amarok") ),
0813                           i18n( "Seek Forward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekShort() * 1000 ) ), this );
0814     ac->addAction( "seek_forward_short", action );
0815     action->setShortcut( Qt::CTRL + Qt::Key_Right );
0816     connect( action, &QAction::triggered, this, &MainWindow::slotSeekForwardShort );
0817 
0818     action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-forward-amarok") ),
0819                           i18n( "Seek Forward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekMedium() * 1000 ) ), this );
0820     ac->addAction( "seek_forward_medium", action );
0821     action->setShortcut( Qt::Key_Right );
0822     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::SHIFT + Qt::Key_Plus ) );
0823     connect( action, &QAction::triggered, this, &MainWindow::slotSeekForwardMedium );
0824 
0825     action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-forward-amarok") ),
0826                           i18n( "Seek Forward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekLong() * 1000 ) ), this );
0827     ac->addAction( "seek_forward_long", action );
0828     action->setShortcut( Qt::SHIFT + Qt::Key_Right );
0829     connect( action, &QAction::triggered, this, &MainWindow::slotSeekForwardLong );
0830 
0831 
0832     action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-backward-amarok") ),
0833                           i18n( "Seek Backward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekShort() * 1000 ) ), this );
0834     ac->addAction( "seek_backward_short", action );
0835     action->setShortcut( Qt::CTRL + Qt::Key_Left );
0836     connect( action, &QAction::triggered, this, &MainWindow::slotSeekBackwardShort );
0837 
0838     action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-backward-amarok") ),
0839                           i18n( "Seek Backward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekMedium() * 1000 ) ), this );
0840     ac->addAction( "seek_backward_medium", action );
0841     action->setShortcut( Qt::Key_Left );
0842     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::SHIFT + Qt::Key_Minus ) );
0843     connect( action, &QAction::triggered, this, &MainWindow::slotSeekBackwardMedium );
0844 
0845     action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-backward-amarok") ),
0846                           i18n( "Seek Backward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekLong() * 1000 ) ), this );
0847     ac->addAction( "seek_backward_long", action );
0848     action->setShortcut( Qt::SHIFT + Qt::Key_Left );
0849     connect( action, &QAction::triggered, this, &MainWindow::slotSeekBackwardLong );
0850 
0851     PERF_LOG( "MainWindow::createActions 6" )
0852     action = new QAction( QIcon::fromTheme(QStringLiteral("view-refresh")), i18n( "Update Collection" ), this );
0853     connect ( action, &QAction::triggered, CollectionManager::instance(), &CollectionManager::checkCollectionChanges );
0854     ac->addAction( "update_collection", action );
0855 
0856     action =  new QAction( QIcon::fromTheme( QStringLiteral("amarok_playcount") ), i18n( "Synchronize Statistics..." ), this );
0857     ac->addAction( "synchronize_statistics", action );
0858     connect( action, &QAction::triggered, Amarok::Components::statSyncingController(),
0859              &StatSyncing::Controller::synchronize );
0860     Amarok::Components::statSyncingController();
0861     action = new QAction( this );
0862     ac->addAction( "prev", action );
0863     action->setIcon( QIcon::fromTheme(QStringLiteral("media-skip-backward-amarok")) );
0864     action->setText( i18n( "Previous Track" ) );
0865     KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
0866     connect( action, &QAction::triggered, pa, &Playlist::Actions::back );
0867 
0868     action = new QAction( this );
0869     ac->addAction( "replay", action );
0870     action->setIcon( QIcon::fromTheme(QStringLiteral("media-playback-start")) );
0871     action->setText( i18n( "Restart current track" ) );
0872     KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
0873     connect( action, &QAction::triggered, ec, &EngineController::replay );
0874 
0875     action = new QAction( this );
0876     ac->addAction( "shuffle_playlist", action );
0877     action->setIcon( QIcon::fromTheme(QStringLiteral("media-playlist-shuffle")) );
0878     action->setText( i18n( "Shuffle Playlist" ) );
0879     action->setShortcut( Qt::CTRL + Qt::Key_H );
0880     connect( action, &QAction::triggered, this, &MainWindow::slotShufflePlaylist );
0881 
0882     action = new QAction( this );
0883     ac->addAction( QStringLiteral("repopulate"), action );
0884     action->setText( i18n( "Repopulate Playlist" ) );
0885     action->setIcon( QIcon::fromTheme("view-refresh-amarok") );
0886     connect( action, &QAction::triggered, pa, &Playlist::Actions::repopulateDynamicPlaylist );
0887 
0888     action = new QAction( this );
0889     ac->addAction( QStringLiteral("disable_dynamic"), action );
0890     action->setText( i18n( "Disable Dynamic Playlist" ) );
0891     action->setIcon( QIcon::fromTheme("edit-delete-amarok") );
0892     //this is connected inside the dynamic playlist category
0893 
0894     action = new QAction( QIcon::fromTheme(QStringLiteral("media-skip-forward-amarok")), i18n( "Next Track" ), this );
0895     ac->addAction( "next", action );
0896     KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
0897     connect( action, &QAction::triggered, pa, &Playlist::Actions::next );
0898 
0899     action = new QAction( i18n( "Increase Volume" ), this );
0900     ac->addAction( "increaseVolume", action );
0901     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_Plus ) );
0902     action->setShortcut( Qt::Key_Plus );
0903     connect( action, &QAction::triggered, ec, &EngineController::regularIncreaseVolume );
0904 
0905     action = new QAction( i18n( "Decrease Volume" ), this );
0906     ac->addAction( "decreaseVolume", action );
0907     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_Minus ) );
0908     action->setShortcut( Qt::Key_Minus );
0909     connect( action, &QAction::triggered, ec, &EngineController::regularDecreaseVolume );
0910 
0911     action = new QAction( i18n( "Toggle Main Window" ), this );
0912     ac->addAction( "toggleMainWindow", action );
0913     KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
0914     connect( action, &QAction::triggered, this, &MainWindow::showHide );
0915 
0916     action = new QAction( i18n( "Toggle Full Screen" ), this );
0917     ac->addAction( "toggleFullScreen", action );
0918     action->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_F ) );
0919     connect( action, &QAction::triggered, this, &MainWindow::slotFullScreen );
0920 
0921     action = new QAction( i18n( "Search playlist" ), this );
0922     ac->addAction( "searchPlaylist", action );
0923     action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_J ) );
0924     connect( action, &QAction::triggered, this, &MainWindow::slotFocusPlaylistSearch );
0925 
0926     action = new QAction( i18n( "Search collection" ), this );
0927     ac->addAction( "searchCollection", action );
0928     action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_F ) );
0929     connect( action, &QAction::triggered, this, &MainWindow::slotFocusCollectionSearch );
0930 
0931     action = new QAction( QIcon::fromTheme( "music-amarok" ), i18n("Show active track"), this );
0932     ac->addAction( "show_active_track", action );
0933     connect( action, &QAction::triggered, this, &MainWindow::slotShowActiveTrack );
0934 
0935     action = new QAction( i18n( "Show Notification Popup" ), this );
0936     ac->addAction( "showNotificationPopup", action );
0937     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_O ) );
0938     connect( action, &QAction::triggered, this, &MainWindow::showNotificationPopup );
0939 
0940     action = new QAction( i18n( "Mute Volume" ), this );
0941     ac->addAction( "mute", action );
0942     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_M ) );
0943     connect( action, &QAction::triggered, ec, &EngineController::toggleMute );
0944 
0945     action = new QAction( i18n( "Last.fm: Love Current Track" ), this );
0946     ac->addAction( "loveTrack", action );
0947     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_L ) );
0948     connect( action, &QAction::triggered, this, &MainWindow::slotLoveTrack );
0949 
0950     action = new QAction( i18n( "Last.fm: Ban Current Track" ), this );
0951     ac->addAction( "banTrack", action );
0952     //KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_B ) );
0953     connect( action, &QAction::triggered, this, &MainWindow::slotBanTrack );
0954 
0955     action = new QAction( i18n( "Last.fm: Skip Current Track" ), this );
0956     ac->addAction( "skipTrack", action );
0957     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_S ) );
0958     connect( action, &QAction::triggered, this, &MainWindow::skipTrack );
0959 
0960     action = new QAction( QIcon::fromTheme( "media-track-queue-amarok" ), i18n( "Queue Track" ), this );
0961     ac->addAction( "queueTrack", action );
0962     action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_D ) );
0963     connect( action, &QAction::triggered, this, &MainWindow::switchQueueStateShortcut );
0964 
0965     action = new QAction( i18n( "Put Artist - Title of the current track to the clipboard" ), this  );
0966     ac->addAction("artistTitleClipboard", action);
0967     action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_C ) );
0968     connect( action, &QAction::triggered, this, &MainWindow::slotPutCurrentTrackToClipboard );
0969 
0970     action = new QAction( i18n( "Rate Current Track: 1" ), this );
0971     ac->addAction( "rate1", action );
0972     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_1 ) );
0973     connect( action, &QAction::triggered, this, &MainWindow::setRating1 );
0974 
0975     action = new QAction( i18n( "Rate Current Track: 2" ), this );
0976     ac->addAction( "rate2", action );
0977     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_2 ) );
0978     connect( action, &QAction::triggered, this, &MainWindow::setRating2 );
0979 
0980     action = new QAction( i18n( "Rate Current Track: 3" ), this );
0981     ac->addAction( "rate3", action );
0982     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_3 ) );
0983     connect( action, &QAction::triggered, this, &MainWindow::setRating3 );
0984 
0985     action = new QAction( i18n( "Rate Current Track: 4" ), this );
0986     ac->addAction( "rate4", action );
0987     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_4 ) );
0988     connect( action, &QAction::triggered, this, &MainWindow::setRating4 );
0989 
0990     action = new QAction( i18n( "Rate Current Track: 5" ), this );
0991     ac->addAction( "rate5", action );
0992     KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_5 ) );
0993     connect( action, &QAction::triggered, this, &MainWindow::setRating5 );
0994 
0995 #ifdef DEBUG_BUILD_TYPE
0996     action = new QAction( i18n( "Network Request Viewer" ), this );
0997     ac->addAction( "network_request_viewer", action );
0998     action->setIcon( QIcon::fromTheme( "utilities-system-monitor" ) );
0999     connect( action, &QAction::triggered, this, &MainWindow::showNetworkRequestViewer );
1000 #endif // DEBUG_BUILD_TYPE
1001 
1002     action = KStandardAction::redo( pc, &Playlist::Controller::redo, this);
1003     ac->addAction( "playlist_redo", action );
1004     action->setEnabled( false );
1005     action->setIcon( QIcon::fromTheme( "edit-redo" ) );
1006     connect( pc, &Playlist::Controller::canRedoChanged, action, &QAction::setEnabled );
1007 
1008     action = KStandardAction::undo( pc, &Playlist::Controller::undo, this);
1009     ac->addAction( "playlist_undo", action );
1010     action->setEnabled( false );
1011     action->setIcon( QIcon::fromTheme( "edit-undo" ) );
1012     connect( pc, &Playlist::Controller::canUndoChanged, action, &QAction::setEnabled );
1013 
1014     action = new QAction( QIcon::fromTheme( "amarok" ), i18n( "&About Amarok" ), this );
1015     ac->addAction( "extendedAbout", action );
1016     connect( action, &QAction::triggered, this, &MainWindow::showAbout );
1017 
1018     action = new QAction ( QIcon::fromTheme( "info-amarok" ), i18n( "&Diagnostics" ), this );
1019     ac->addAction( "diagnosticDialog", action );
1020     connect( action, &QAction::triggered, this, &MainWindow::slotShowDiagnosticsDialog );
1021 
1022     action = new QAction( QIcon::fromTheme( "tools-report-bug" ), i18n("&Report Bug..."), this );
1023     ac->addAction( "reportBug", action );
1024     connect( action, &QAction::triggered, this, &MainWindow::showReportBug );
1025 
1026     PERF_LOG( "MainWindow::createActions 8" )
1027     new Amarok::MenuAction( ac, this );
1028     new Amarok::StopAction( ac, this );
1029     new Amarok::StopPlayingAfterCurrentTrackAction( ac, this );
1030     new Amarok::PlayPauseAction( ac, this );
1031     new Amarok::ReplayGainModeAction( ac, this );
1032 
1033     ac->addAssociatedWidget( this );
1034     foreach( QAction* action, ac->actions() )
1035         action->setShortcutContext( Qt::WindowShortcut );
1036 }
1037 
1038 void
1039 MainWindow::setRating( int n )
1040 {
1041     n *= 2;
1042 
1043     Meta::TrackPtr track = The::engineController()->currentTrack();
1044     if( track )
1045     {
1046         Meta::StatisticsPtr statistics = track->statistics();
1047         // if we're setting an identical rating then we really must
1048         // want to set the half-star below rating
1049         if( statistics->rating() == n )
1050             n -= 1;
1051 
1052         statistics->setRating( n );
1053         Amarok::OSD::instance()->OSDWidget::ratingChanged( statistics->rating() );
1054     }
1055 }
1056 
1057 void
1058 MainWindow::createMenus()
1059 {
1060     m_menubar = menuBar();
1061 
1062     //BEGIN Actions menu
1063     QMenu *actionsMenu = new QMenu( m_menubar );
1064 #ifdef Q_WS_MAC
1065     // Add these functions to the dock icon menu in OS X
1066     //extern void qt_mac_set_dock_menu(QMenu *);
1067     //qt_mac_set_dock_menu(actionsMenu);
1068     // Change to avoid duplicate menu titles in OS X
1069     actionsMenu->setTitle( i18n("&Music") );
1070 #else
1071     actionsMenu->setTitle( i18n("&Amarok") );
1072 #endif
1073     actionsMenu->addAction( Amarok::actionCollection()->action("playlist_playmedia") );
1074     actionsMenu->addSeparator();
1075     actionsMenu->addAction( Amarok::actionCollection()->action("prev") );
1076     actionsMenu->addAction( Amarok::actionCollection()->action("play_pause") );
1077     actionsMenu->addAction( Amarok::actionCollection()->action("stop") );
1078     actionsMenu->addAction( Amarok::actionCollection()->action("stop_after_current") );
1079     actionsMenu->addAction( Amarok::actionCollection()->action("next") );
1080 
1081 
1082 #ifndef Q_WS_MAC    // Avoid duplicate "Quit" in OS X dock menu
1083     actionsMenu->addSeparator();
1084     actionsMenu->addAction( Amarok::actionCollection()->action( KStandardAction::name( KStandardAction::Quit ) ) );
1085 #endif
1086     //END Actions menu
1087 
1088     //BEGIN View menu
1089     QMenu* viewMenu = new QMenu(this);
1090     addViewMenuItems(viewMenu);
1091     //END View menu
1092 
1093     //BEGIN Playlist menu
1094     QMenu *playlistMenu = new QMenu( m_menubar.data() );
1095     playlistMenu->setTitle( i18n("&Playlist") );
1096     playlistMenu->addAction( Amarok::actionCollection()->action("playlist_add") );
1097     playlistMenu->addAction( Amarok::actionCollection()->action("stream_add") );
1098     //playlistMenu->addAction( Amarok::actionCollection()->action("playlist_save") ); //FIXME: See FIXME in PlaylistDock.cpp
1099     playlistMenu->addAction( Amarok::actionCollection()->action( "playlist_export" ) );
1100     playlistMenu->addSeparator();
1101     playlistMenu->addAction( Amarok::actionCollection()->action("playlist_undo") );
1102     playlistMenu->addAction( Amarok::actionCollection()->action("playlist_redo") );
1103     playlistMenu->addSeparator();
1104     playlistMenu->addAction( Amarok::actionCollection()->action("playlist_clear") );
1105     playlistMenu->addAction( Amarok::actionCollection()->action("playlist_remove_dead_and_duplicates") );
1106     playlistMenu->addAction( Amarok::actionCollection()->action("playlist_layout") );
1107     playlistMenu->addAction( Amarok::actionCollection()->action("playlist_edit_queue") );
1108     //END Playlist menu
1109 
1110     //BEGIN Tools menu
1111     m_toolsMenu = new QMenu( m_menubar.data() );
1112     m_toolsMenu->setTitle( i18n("&Tools") );
1113 
1114     m_toolsMenu->addAction( Amarok::actionCollection()->action("bookmark_manager") );
1115     m_toolsMenu->addAction( Amarok::actionCollection()->action("cover_manager") );
1116     m_toolsMenu->addAction( Amarok::actionCollection()->action("equalizer_dialog") );
1117 #ifdef DEBUG_BUILD_TYPE
1118     m_toolsMenu->addAction( Amarok::actionCollection()->action("network_request_viewer") );
1119 #endif // DEBUG_BUILD_TYPE
1120     m_toolsMenu->addSeparator();
1121     m_toolsMenu->addAction( Amarok::actionCollection()->action("update_collection") );
1122     m_toolsMenu->addAction( Amarok::actionCollection()->action("synchronize_statistics") );
1123     //END Tools menu
1124 
1125     //BEGIN Settings menu
1126     m_settingsMenu = new QMenu( m_menubar.data() );
1127     m_settingsMenu->setTitle( i18n("&Settings") );
1128 
1129     m_settingsMenu->addAction( Amarok::actionCollection()->action( KStandardAction::name( KStandardAction::ShowMenubar ) ) );
1130 
1131     //TODO use KStandardAction or KXmlGuiWindow
1132 
1133     // the phonon-coreaudio  backend has major issues with either the VolumeFaderEffect itself
1134     // or with it in the pipeline. track playback stops every ~3-4 tracks, and on tracks >5min it
1135     // stops at about 5:40. while we get this resolved upstream, don't make playing amarok such on osx.
1136     // so we disable replaygain on osx
1137 
1138 #ifndef Q_WS_MAC
1139     m_settingsMenu->addAction( Amarok::actionCollection()->action("replay_gain_mode") );
1140     m_settingsMenu->addSeparator();
1141 #endif
1142 
1143     m_settingsMenu->addAction( Amarok::actionCollection()->action( KStandardAction::name( KStandardAction::KeyBindings ) ) );
1144     m_settingsMenu->addAction( Amarok::actionCollection()->action( KStandardAction::name( KStandardAction::Preferences ) ) );
1145     //END Settings menu
1146 
1147     m_menubar->addMenu( actionsMenu );
1148     m_menubar->addMenu( viewMenu );
1149     m_menubar->addMenu( playlistMenu );
1150     m_menubar->addMenu( m_toolsMenu.data() );
1151     m_menubar->addMenu( m_settingsMenu.data() );
1152 
1153     QMenu *helpMenu = Amarok::Menu::helpMenu();
1154     helpMenu->insertAction( helpMenu->actions().last(),
1155                             Amarok::actionCollection()->action( "extendedAbout" ) );
1156     helpMenu->insertAction( helpMenu->actions().last(),
1157                             Amarok::actionCollection()->action( "diagnosticDialog" ) );
1158 
1159     m_menubar->addSeparator();
1160     m_menubar->addMenu( helpMenu );
1161 }
1162 
1163 void
1164 MainWindow::slotShowMenuBar()
1165 {
1166     if (!m_showMenuBar->isChecked())
1167     {
1168         //User have chosen to hide a menu. Lets warn him
1169         if (KMessageBox::warningContinueCancel(this,
1170             i18n("You have chosen to hide the menu bar.\n\nPlease remember that you can always use the shortcut \"%1\" to bring it back.", m_showMenuBar->shortcut().toString() ),
1171             i18n("Hide Menu"), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), "showMenubar") != KMessageBox::Continue)
1172         {
1173             //Cancel menu hiding. Revert menu item to checked state.
1174             m_showMenuBar->setChecked(true);
1175             return;
1176         }
1177     }
1178     menuBar()->setVisible(m_showMenuBar->isChecked());
1179 }
1180 
1181 void
1182 MainWindow::showAbout()
1183 {
1184     ExtendedAboutDialog dialog( KAboutData::applicationData(), &ocsData );
1185     dialog.exec();
1186 }
1187 
1188 void
1189 MainWindow::showReportBug()
1190 {
1191     KBugReport * rbDialog = new KBugReport( KAboutData::applicationData() ,this  );
1192     rbDialog->setObjectName( "KBugReport" );
1193     rbDialog->exec();
1194     delete rbDialog;
1195 }
1196 
1197 void
1198 MainWindow::changeEvent( QEvent *event )
1199 {
1200     if( event->type() == QEvent::PaletteChange )
1201         The::paletteHandler()->setPalette( palette() );
1202 }
1203 
1204 void
1205 MainWindow::slotStopped()
1206 {
1207     setPlainCaption( i18n( AMAROK_CAPTION ) );
1208 }
1209 
1210 void
1211 MainWindow::slotPaused()
1212 {
1213     setPlainCaption( i18n( "Paused  ::  %1", i18n( AMAROK_CAPTION ) ) );
1214 }
1215 
1216 void
1217 MainWindow::slotNewTrackPlaying()
1218 {
1219     slotMetadataChanged( The::engineController()->currentTrack() );
1220 }
1221 
1222 void
1223 MainWindow::slotMetadataChanged( Meta::TrackPtr track )
1224 {
1225     if( track )
1226         setPlainCaption( i18n( "%1 - %2  ::  %3", track->artist() ? track->artist()->prettyName() : i18n( "Unknown" ), track->prettyName(), i18n( AMAROK_CAPTION ) ) );
1227 }
1228 
1229 CollectionWidget *
1230 MainWindow::collectionBrowser()
1231 {
1232     return m_collectionBrowser;
1233 }
1234 
1235 QString
1236 MainWindow::activeBrowserName()
1237 {
1238     if(m_browserDock->list()->activeCategory() )
1239         return m_browserDock->list()->activeCategory()->name();
1240     else
1241         return QString();
1242 }
1243 
1244 void
1245 MainWindow::setLayoutLocked( bool locked )
1246 {
1247     DEBUG_BLOCK
1248 
1249     if( m_browserDock )
1250         m_browserDock.data()->setMovable( !locked );
1251 
1252     if( m_contextDock )
1253         m_contextDock.data()->setMovable( !locked );
1254 
1255     if( m_playlistDock )
1256         m_playlistDock.data()->setMovable( !locked );
1257 
1258     if( m_slimToolbar )
1259     {
1260         m_slimToolbar.data()->setFloatable( !locked );
1261         m_slimToolbar.data()->setMovable( !locked );
1262     }
1263 
1264     if( m_mainToolbar )
1265     {
1266         m_mainToolbar.data()->setFloatable( !locked );
1267         m_mainToolbar.data()->setMovable( !locked );
1268     }
1269 
1270     AmarokConfig::setLockLayout( locked );
1271     AmarokConfig::self()->save();
1272 }
1273 
1274 void
1275 MainWindow::resetLayout()
1276 {
1277     // Store current state, so that we can undo the operation
1278     const QByteArray state = saveState();
1279 
1280     // Remove all dock widgets, then add them again. This resets their state completely.
1281     removeDockWidget( m_browserDock.data() );
1282     removeDockWidget( m_contextDock.data() );
1283     removeDockWidget( m_playlistDock.data() );
1284 
1285     addDockWidget( Qt::LeftDockWidgetArea, m_browserDock.data() );
1286     addDockWidget( Qt::LeftDockWidgetArea, m_contextDock.data(), Qt::Horizontal );
1287     addDockWidget( Qt::LeftDockWidgetArea, m_playlistDock.data(), Qt::Horizontal );
1288 
1289     m_browserDock->setFloating( false );
1290     m_contextDock->setFloating( false );
1291     m_playlistDock->setFloating( false );
1292 
1293     m_browserDock->show();
1294     m_contextDock->show();
1295     m_playlistDock->show();
1296 
1297     // Now set Amarok's default dockwidget sizes
1298     setDefaultDockSizes();
1299 
1300     if( KMessageBox::warningContinueCancel( this, i18n( "Apply this layout change?" ), i18n( "Reset Layout" ) ) == KMessageBox::Cancel )
1301         restoreState( state );
1302 }
1303 
1304 void
1305 MainWindow::setDefaultDockSizes() // SLOT
1306 {
1307     int totalWidgetWidth = contentsRect().width();
1308 
1309     //get the width of the splitter handles, we need to subtract these...
1310     const int splitterHandleWidth = style()->pixelMetric( QStyle::PM_DockWidgetSeparatorExtent, nullptr, nullptr );
1311 
1312     totalWidgetWidth -= ( splitterHandleWidth * 2 );
1313 
1314     const int widgetWidth = totalWidgetWidth / 3;
1315     const int leftover = totalWidgetWidth - 3 * widgetWidth;
1316 
1317     //We need to set fixed widths initially, just until the main window has been properly laid out. As soon as this has
1318     //happened, we will unlock these sizes again so that the elements can be resized by the user.
1319     const int mins[3] = { m_browserDock->minimumWidth(), m_contextDock->minimumWidth(), m_playlistDock->minimumWidth() };
1320     const int maxs[3] = { m_browserDock->maximumWidth(), m_contextDock->maximumWidth(), m_playlistDock->maximumWidth() };
1321 
1322     m_browserDock->setFixedWidth( widgetWidth * 0.65 );
1323     m_contextDock->setFixedWidth( widgetWidth * 1.7 + leftover );
1324     m_playlistDock->setFixedWidth( widgetWidth * 0.65 );
1325 
1326     // Important: We need to activate the layout we have just set
1327     layout()->activate();
1328 
1329     m_browserDock->setMinimumWidth( mins[0] ); m_browserDock->setMaximumWidth( maxs[0] );
1330     m_contextDock->setMinimumWidth( mins[1] ); m_contextDock->setMaximumWidth( maxs[1] );
1331     m_playlistDock->setMinimumWidth( mins[2] ); m_playlistDock->setMaximumWidth( maxs[2] );
1332 }
1333 
1334 bool
1335 MainWindow::playAudioCd()
1336 {
1337     DEBUG_BLOCK
1338     //drop whatever we are doing and play auidocd
1339 
1340     QList<Collections::Collection*> collections = CollectionManager::instance()->viewableCollections();
1341 
1342     // Search a non-empty MemoryCollection with the id: AudioCd
1343     foreach( Collections::Collection *collection, collections )
1344     {
1345         if( collection->collectionId() == "AudioCd" )
1346         {
1347 
1348             debug() << "got audiocd collection";
1349 
1350             Collections::MemoryCollection * cdColl = dynamic_cast<Collections::MemoryCollection *>( collection );
1351 
1352             if( !cdColl || cdColl->trackMap().isEmpty() )
1353             {
1354                 debug() << "cd collection not ready yet (track count = 0 )";
1355                 m_waitingForCd = true;
1356                 return false;
1357             }
1358 
1359             The::playlistController()->insertOptioned( cdColl->trackMap().values(), Playlist::OnPlayMediaAction );
1360             m_waitingForCd = false;
1361             return true;
1362         }
1363     }
1364 
1365     debug() << "waiting for cd...";
1366     m_waitingForCd = true;
1367     return false;
1368 }
1369 
1370 bool
1371 MainWindow::isWaitingForCd() const
1372 {
1373     DEBUG_BLOCK
1374     debug() << "waiting?: " << m_waitingForCd;
1375     return m_waitingForCd;
1376 }
1377 
1378 bool
1379 MainWindow::isOnCurrentDesktop() const
1380 {
1381 #ifdef Q_WS_X11
1382     return KWindowSystem::windowInfo( winId(), NET::WMDesktop ).desktop() == KWindowSystem::currentDesktop();
1383 #else
1384     return true;
1385 #endif
1386 }
1387 
1388