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