1 /****************************************************************************************
2 * Copyright (c) 2002-2013 Mark Kretschmann <kretschmann@kde.org> *
3 * Copyright (c) 2002 Max Howell <max.howell@methylblue.com> *
4 * Copyright (c) 2002 Gabor Lehel <illissius@gmail.com> *
5 * Copyright (c) 2002 Nikolaj Hald Nielsen <nhn@kde.org> *
6 * Copyright (c) 2009 Artur Szymiec <artur.szymiec@gmail.com> *
7 * Copyright (c) 2010 Téo Mrnjavac <teo@kde.org> *
8 * *
9 * This program is free software; you can redistribute it and/or modify it under *
10 * the terms of the GNU General Public License as published by the Free Software *
11 * Foundation; either version 2 of the License, or (at your option) any later *
12 * version. *
13 * *
14 * This program is distributed in the hope that it will be useful, but WITHOUT ANY *
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
16 * PARTICULAR PURPOSE. See the GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License along with *
19 * this program. If not, see <http://www.gnu.org/licenses/>. *
20 ****************************************************************************************/
21
22 #define DEBUG_PREFIX "MainWindow"
23
24 #include "MainWindow.h"
25
26 #include "App.h"
27 #include "ActionClasses.h"
28 #include "EngineController.h" //for actions in ctor
29 #include "KNotificationBackend.h"
30 #include "PaletteHandler.h"
31 #include "PluginManager.h"
32 #include "SvgHandler.h"
33 #include "amarokconfig.h"
34 #include "aboutdialog/ExtendedAboutDialog.h"
35 #include "aboutdialog/OcsData.h"
36 #include "amarokurls/AmarokUrlHandler.h"
37 #include "amarokurls/BookmarkManager.h"
38 #include "browsers/BrowserDock.h"
39 #include "browsers/collectionbrowser/CollectionWidget.h"
40 #include "browsers/filebrowser/FileBrowser.h"
41 #include "browsers/playlistbrowser/PlaylistBrowser.h"
42 #include "browsers/playlistbrowser/PodcastCategory.h"
43 #include "browsers/servicebrowser/ServiceBrowser.h"
44 #include "context/ContextDock.h"
45 #include "core/meta/Statistics.h"
46 #include "core/support/Amarok.h"
47 #include "core/support/Components.h"
48 #include "core/support/Debug.h"
49 #include "core-impl/collections/support/CollectionManager.h"
50 #include "covermanager/CoverManager.h" // for actions
51 #include "dialogs/DiagnosticDialog.h"
52 #include "dialogs/EqualizerDialog.h"
53 #include "moodbar/MoodbarManager.h"
54 #include "network/NetworkAccessManagerProxy.h"
55 #ifdef DEBUG_BUILD_TYPE
56 #include "network/NetworkAccessViewer.h"
57 #endif // DEBUG_BUILD_TYPE
58 #include "playlist/PlaylistActions.h"
59 #include "playlist/PlaylistController.h"
60 #include "playlist/PlaylistDock.h"
61 #include "playlist/PlaylistModelStack.h"
62 #include "playlist/ProgressiveSearchWidget.h"
63 #include "playlist/layouts/LayoutConfigAction.h"
64 #include "playlistmanager/PlaylistManager.h"
65 #include "playlistmanager/file/PlaylistFileProvider.h"
66 #include "services/scriptable/ScriptableService.h"
67 #include "statsyncing/Controller.h"
68 #include "toolbar/MainToolbar.h"
69 #include "toolbar/SlimToolbar.h"
70 #include "widgets/Osd.h"
71
72 #include <QAction> //m_actionCollection
73 #include <QApplication> //qApp
74 #include <QCheckBox>
75 #include <QClipboard>
76 #include <QDesktopServices>
77 #include <QDesktopWidget>
78 #include <QDockWidget>
79 #include <QFileDialog> //openPlaylist()
80 #include <QInputDialog> //slotAddStream()
81 #include <QList>
82 #include <QMenu>
83 #include <QMenuBar>
84 #include <QStandardPaths>
85 #include <QStyle>
86 #include <QVBoxLayout>
87
88 #include <KActionCollection>
89 #include <KBugReport>
90 #include <KFileWidget>
91 #include <KFormat>
92 #include <KGlobalAccel>
93 #include <KLocalizedString>
94 #include <KMessageBox>
95 #include <KStandardAction>
96 #include <KWindowSystem>
97
98 #include <iostream>
99
100 #ifdef Q_WS_X11
101 #include <fixx11h.h>
102 #include <KConfigGroup>
103 #endif
104
105 #ifdef Q_WS_MAC
106 #include "mac/GrowlInterface.h"
107 #ifdef HAVE_NOTIFICATION_CENTER
108 #include "mac/MacSystemNotify.h"
109 #endif
110 #endif
111
112 #define AMAROK_CAPTION I18N_NOOP( "Amarok" )
113
114 extern OcsData ocsData;
115
116 namespace The {
mainWindow()117 MainWindow* mainWindow() { return pApp->mainWindow(); }
118 }
119
MainWindow()120 MainWindow::MainWindow()
121 : KMainWindow( nullptr )
122 , m_showMenuBar( nullptr )
123 , m_lastBrowser( 0 )
124 , m_waitingForCd( false )
125 {
126 DEBUG_BLOCK
127
128 setObjectName( "MainWindow" );
129
130 #ifdef Q_WS_MAC
131 (void)new GrowlInterface( qApp->applicationName() );
132 #ifdef HAVE_NOTIFICATION_CENTER
133 (void)new OSXNotify( qApp->applicationName() );
134 #endif
135 #endif
136
137 PERF_LOG( "Instantiate Collection Manager" )
138 CollectionManager::instance();
139 PERF_LOG( "Started Collection Manager instance" )
140
141 /* The PluginManager needs to be loaded before the playlist model
142 * (which gets started by "statusBar::connectPlaylist" below so that it can handle any
143 * tracks in the saved playlist that are associated with services. Eg, if
144 * the playlist has a Magnatune track in it when Amarok is closed, then the
145 * Magnatune service needs to be initialized before the playlist is loaded
146 * here. */
147 PERF_LOG( "Instantiate Plugin Manager" )
148 The::pluginManager();
149 PERF_LOG( "Started Plugin Manager instance" )
150
151 createActions();
152 PERF_LOG( "Created actions" )
153
154 The::paletteHandler()->setPalette( palette() );
155 setPlainCaption( i18n( AMAROK_CAPTION ) );
156
157 init(); // We could as well move the code from init() here, but meh.. getting a tad long
158
159 //restore active category ( as well as filters and levels and whatnot.. )
160 const QString path = Amarok::config().readEntry( "Browser Path", QString() );
161 if( !path.isEmpty() )
162 m_browserDock->list()->navigate( path );
163
164 setAutoSaveSettings();
165
166 m_showMenuBar->setChecked(!menuBar()->isHidden()); // workaround for bug #171080
167
168 EngineController *engine = The::engineController();
169 connect( engine, &EngineController::stopped, this, &MainWindow::slotStopped );
170 connect( engine, &EngineController::paused, this, &MainWindow::slotPaused );
171 connect( engine, &EngineController::trackPlaying, this, &MainWindow::slotNewTrackPlaying );
172 connect( engine, &EngineController::trackMetadataChanged, this, &MainWindow::slotMetadataChanged );
173 }
174
~MainWindow()175 MainWindow::~MainWindow()
176 {
177 DEBUG_BLOCK
178
179 //save currently active category
180 Amarok::config().writeEntry( "Browser Path", m_browserDock->list()->path() );
181
182 #ifdef DEBUG_BUILD_TYPE
183 delete m_networkViewer.data();
184 #endif // DEBUG_BUILD_TYPE
185 delete The::svgHandler();
186 delete The::paletteHandler();
187 }
188
189
190 ///////// public interface
191
192 /**
193 * This function will initialize the main window.
194 */
195 void
init()196 MainWindow::init()
197 {
198 layout()->setContentsMargins( 0, 0, 0, 0 );
199 layout()->setSpacing( 0 );
200
201 //create main toolbar
202 m_mainToolbar = new MainToolbar( this );
203 m_mainToolbar.data()->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea );
204 m_mainToolbar.data()->setMovable ( true );
205 addToolBar( Qt::TopToolBarArea, m_mainToolbar.data() );
206
207 //create slim toolbar
208 m_slimToolbar = new SlimToolbar( this );
209 m_slimToolbar.data()->setAllowedAreas( Qt::TopToolBarArea | Qt::BottomToolBarArea );
210 m_slimToolbar.data()->setMovable ( true );
211 addToolBar( Qt::TopToolBarArea, m_slimToolbar.data() );
212 m_slimToolbar->hide();
213
214 //BEGIN Creating Widgets
215 PERF_LOG( "Create sidebar" )
216 m_browserDock = new BrowserDock( this );
217 m_browserDock->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored );
218
219 m_browserDock->installEventFilter( this );
220 PERF_LOG( "Sidebar created" )
221
222 PERF_LOG( "Create Playlist" )
223 m_playlistDock = new Playlist::Dock( this );
224 m_playlistDock->installEventFilter( this );
225 //HACK, need to connect after because of order in MainWindow()
226 connect( Amarok::actionCollection()->action( "playlist_edit_queue" ),
227 &QAction::triggered, m_playlistDock.data(), &Playlist::Dock::slotEditQueue );
228 PERF_LOG( "Playlist created" )
229
230 PERF_LOG( "Creating ContextWidget" )
231 m_contextDock = new ContextDock( this );
232 m_contextDock->installEventFilter( this );
233 PERF_LOG( "ContextScene created" )
234 //END Creating Widgets
235
236 createMenus();
237
238 setDockOptions( QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks
239 | QMainWindow::AnimatedDocks | QMainWindow::VerticalTabs );
240
241 addDockWidget( Qt::LeftDockWidgetArea, m_browserDock.data() );
242 addDockWidget( Qt::LeftDockWidgetArea, m_contextDock.data(), Qt::Horizontal );
243 addDockWidget( Qt::LeftDockWidgetArea, m_playlistDock.data(), Qt::Horizontal );
244
245 setLayoutLocked( AmarokConfig::lockLayout() );
246
247 //<Browsers>
248 {
249 Debug::Block block( "Creating browsers. Please report long start times!" );
250
251 //TODO: parent these browsers?
252 PERF_LOG( "Creating CollectionWidget" )
253 m_collectionBrowser = new CollectionWidget( "collections", 0 );
254 //TODO: rename "Music Collections
255 m_collectionBrowser->setPrettyName( i18n( "Local Music" ) );
256 m_collectionBrowser->setIcon( QIcon::fromTheme( "drive-harddisk" ) );
257 m_collectionBrowser->setShortDescription( i18n( "Local sources of content" ) );
258 m_browserDock->list()->addCategory( m_collectionBrowser );
259 PERF_LOG( "Created CollectionWidget" )
260
261 PERF_LOG( "Creating ServiceBrowser" )
262 ServiceBrowser *serviceBrowser = ServiceBrowser::instance();
263 serviceBrowser->setParent( 0 );
264 serviceBrowser->setPrettyName( i18n( "Internet" ) );
265 serviceBrowser->setIcon( QIcon::fromTheme( "internet-services" ) );
266 serviceBrowser->setShortDescription( i18n( "Online sources of content" ) );
267 m_browserDock->list()->addCategory( serviceBrowser );
268 PERF_LOG( "Created ServiceBrowser" )
269
270 PERF_LOG( "Creating PlaylistBrowser" )
271 m_playlistBrowser = new PlaylistBrowserNS::PlaylistBrowser( "playlists", 0 );
272 m_playlistBrowser->setPrettyName( i18n("Playlists") );
273 m_playlistBrowser->setIcon( QIcon::fromTheme( "view-media-playlist-amarok" ) );
274 m_playlistBrowser->setShortDescription( i18n( "Various types of playlists" ) );
275 m_browserDock->list()->addCategory( m_playlistBrowser );
276 PERF_LOG( "CreatedPlaylsitBrowser" )
277
278 PERF_LOG( "Creating FileBrowser" )
279 FileBrowser *fileBrowser = new FileBrowser( "files", 0 );
280 fileBrowser->setPrettyName( i18n("Files") );
281 fileBrowser->setIcon( QIcon::fromTheme( "folder-amarok" ) );
282
283 fileBrowser->setShortDescription( i18n( "Browse local hard drive for content" ) );
284 m_browserDock->list()->addCategory( fileBrowser );
285 PERF_LOG( "Created FileBrowser" )
286
287 serviceBrowser->setScriptableServiceManager( The::scriptableServiceManager() );
288 PERF_LOG( "ScriptableServiceManager done" )
289
290 PERF_LOG( "Creating Podcast Category" )
291 m_browserDock->list()->addCategory( The::podcastCategory() );
292 PERF_LOG( "Created Podcast Category" )
293
294 // If Amarok is started for the first time, set initial dock widget sizes
295 if( !Amarok::config( "MainWindow" ).hasKey( "State" ) )
296 QTimer::singleShot( 0, this, &MainWindow::setDefaultDockSizes );
297
298 PERF_LOG( "finished MainWindow::init" )
299 }
300 The::amarokUrlHandler(); //Instantiate
301 The::coverFetcher(); //Instantiate
302
303 // we must filter ourself to get mouseevents on the "splitter" - what is us, but filtered by the layouter
304 installEventFilter( this );
305 }
306
307 QMenu*
createPopupMenu()308 MainWindow::createPopupMenu()
309 {
310 QMenu* menu = new QMenu( this );
311
312 // Show/hide menu bar
313 if (!menuBar()->isVisible())
314 menu->addAction( m_showMenuBar );
315
316 menu->addSeparator();
317
318 addViewMenuItems(menu);
319
320 return menu;
321 }
322
323 void
addViewMenuItems(QMenu * menu)324 MainWindow::addViewMenuItems(QMenu* menu)
325 {
326 menu->setTitle( i18nc("@item:inmenu", "&View" ) );
327
328 // Layout locking:
329 QAction* lockAction = new QAction( i18n( "Lock Layout" ), this );
330 lockAction->setCheckable( true );
331 lockAction->setChecked( AmarokConfig::lockLayout() );
332 connect( lockAction, &QAction::toggled, this, &MainWindow::setLayoutLocked );
333 menu->addAction( lockAction );
334
335 menu->addSeparator();
336
337 // Dock widgets:
338 QList<QDockWidget *> dockwidgets = findChildren<QDockWidget *>();
339
340 foreach( QDockWidget* dockWidget, dockwidgets )
341 {
342 if( dockWidget->parentWidget() == this )
343 menu->addAction( dockWidget->toggleViewAction() );
344 }
345
346 menu->addSeparator();
347
348 // Toolbars:
349 QList<QToolBar *> toolbars = findChildren<QToolBar *>();
350 QActionGroup* toolBarGroup = new QActionGroup( this );
351 toolBarGroup->setExclusive( true );
352
353 foreach( QToolBar* toolBar, toolbars )
354 {
355 if( toolBar->parentWidget() == this )
356 {
357 QAction* action = toolBar->toggleViewAction();
358 connect( action, &QAction::toggled, toolBar, &QToolBar::setVisible );
359 toolBarGroup->addAction( action );
360 menu->addAction( action );
361 }
362 }
363
364 menu->addSeparator();
365
366 QAction *resetAction = new QAction( i18n( "Reset Layout" ), this );
367 connect( resetAction, &QAction::triggered, this, &MainWindow::resetLayout );
368 menu->addAction( resetAction );
369 }
370
371 void
showBrowser(const QString & name)372 MainWindow::showBrowser( const QString &name )
373 {
374 Q_UNUSED( name );
375 // showBrowser( index ); // FIXME
376 }
377
378 void
showDock(AmarokDockId dockId)379 MainWindow::showDock( AmarokDockId dockId )
380 {
381 QString name;
382 switch( dockId )
383 {
384 case AmarokDockNavigation:
385 name = m_browserDock->windowTitle();
386 break;
387 case AmarokDockContext:
388 name = m_contextDock->windowTitle();
389 break;
390 case AmarokDockPlaylist:
391 name = m_playlistDock->windowTitle();
392 break;
393 }
394
395 QList < QTabBar * > tabList = findChildren < QTabBar * > ();
396
397 foreach( QTabBar *bar, tabList )
398 {
399 for( int i = 0; i < bar->count(); i++ )
400 {
401 if( bar->tabText( i ) == name )
402 {
403 bar->setCurrentIndex( i );
404 break;
405 }
406 }
407 }
408 }
409
410 void
closeEvent(QCloseEvent * e)411 MainWindow::closeEvent( QCloseEvent *e )
412 {
413 #ifdef Q_WS_MAC
414 Q_UNUSED( e );
415 hide();
416 #else
417
418 //KDE policy states we should hide to tray and not quit() when the
419 //close window button is pushed for the main widget
420 if( AmarokConfig::showTrayIcon() && e->spontaneous() && !qApp->isSavingSession() )
421 {
422 KMessageBox::information( this,
423 i18n( "<qt>Closing the main window will keep Amarok running in the System Tray. "
424 "Use <B>Quit</B> from the menu, or the Amarok tray icon to exit the application.</qt>" ),
425 i18n( "Docking in System Tray" ), "hideOnCloseInfo" );
426
427 hide();
428 e->ignore();
429 return;
430 }
431
432 e->accept();
433 pApp->quit();
434 #endif
435 }
436
437 void
exportPlaylist()438 MainWindow::exportPlaylist() //SLOT
439 {
440 DEBUG_BLOCK
441
442 QFileDialog fileDialog;
443 fileDialog.restoreState( Amarok::config( "playlist-export-dialog" ).readEntry( "state", QByteArray() ) );
444
445 // FIXME: Make checkbox visible in dialog
446 QCheckBox *saveRelativeCheck = new QCheckBox( i18n("Use relative path for &saving"), &fileDialog );
447 saveRelativeCheck->setChecked( AmarokConfig::relativePlaylist() );
448
449 QStringList supportedMimeTypes;
450
451 supportedMimeTypes << "video/x-ms-asf"; //ASX
452 supportedMimeTypes << "audio/x-mpegurl"; //M3U
453 supportedMimeTypes << "audio/x-scpls"; //PLS
454 supportedMimeTypes << "application/xspf+xml"; //XSPF
455
456 fileDialog.setMimeTypeFilters( supportedMimeTypes );
457 fileDialog.setAcceptMode( QFileDialog::AcceptSave );
458 fileDialog.setFileMode( QFileDialog::AnyFile );
459 fileDialog.setWindowTitle( i18n("Save As") );
460 fileDialog.setObjectName( "PlaylistExport" );
461
462 int result = fileDialog.exec();
463 QString playlistPath = fileDialog.selectedFiles().value( 0 );
464 if( result == QDialog::Accepted && !playlistPath.isEmpty() )
465 The::playlist()->exportPlaylist( playlistPath, saveRelativeCheck->isChecked() );
466
467 Amarok::config( "playlist-export-dialog" ).writeEntry( "state", fileDialog.saveState() );
468 }
469
470 void
slotShowActiveTrack() const471 MainWindow::slotShowActiveTrack() const
472 {
473 m_playlistDock->showActiveTrack();
474 }
475
476 void
slotEditTrackInfo() const477 MainWindow::slotEditTrackInfo() const
478 {
479 m_playlistDock->editTrackInfo();
480 }
481
482 void
slotShowCoverManager()483 MainWindow::slotShowCoverManager() //SLOT
484 {
485 CoverManager::showOnce( QString(), this );
486 }
487
488 void
slotShowDiagnosticsDialog()489 MainWindow::slotShowDiagnosticsDialog()
490 {
491 DiagnosticDialog *dialog = new DiagnosticDialog( KAboutData::applicationData(), this );
492 dialog->show();
493 }
494
slotShowBookmarkManager()495 void MainWindow::slotShowBookmarkManager()
496 {
497 BookmarkManager::showOnce( this );
498 }
499
slotShowEqualizer()500 void MainWindow::slotShowEqualizer()
501 {
502 EqualizerDialog::showOnce( this );
503 }
504
505 void
slotPlayMedia()506 MainWindow::slotPlayMedia() //SLOT
507 {
508 // Request location and immediately start playback
509 slotAddLocation( true );
510 }
511
512 void
slotAddLocation(bool directPlay)513 MainWindow::slotAddLocation( bool directPlay ) //SLOT
514 {
515 static QUrl lastDirectory;
516
517 // open a file selector to add media to the playlist
518 QList<QUrl> files;
519 QFileDialog dlg;
520 dlg.setDirectory( QStandardPaths::writableLocation(QStandardPaths::MusicLocation) );
521
522 if( !lastDirectory.isEmpty() )
523 dlg.setDirectoryUrl( lastDirectory );
524
525 dlg.setWindowTitle( directPlay ? i18n("Play Media (Files or URLs)") : i18n("Add Media (Files or URLs)") );
526 dlg.setFileMode( QFileDialog::ExistingFiles );
527 dlg.setObjectName( "PlayMedia" );
528 int accepted = dlg.exec();
529 files = dlg.selectedUrls();
530
531 lastDirectory = dlg.directoryUrl();
532
533 if( accepted != QDialog::Accepted || files.isEmpty() )
534 return;
535
536 Playlist::AddOptions options = directPlay ? Playlist::OnPlayMediaAction
537 : Playlist::OnAppendToPlaylistAction;
538 The::playlistController()->insertOptioned( files, options );
539 }
540
541 void
slotAddStream()542 MainWindow::slotAddStream() //SLOT
543 {
544 bool ok;
545 QString url = QInputDialog::getText( this, i18n( "Add Stream" ), i18n( "Enter Stream URL:" ),
546 QLineEdit::Normal, QString(), &ok );
547 if( !ok )
548 return;
549
550 The::playlistController()->insertOptioned( QUrl( url ),
551 Playlist::OnAppendToPlaylistAction | Playlist::RemotePlaylistsAreStreams );
552 }
553
554 void
slotFocusPlaylistSearch()555 MainWindow::slotFocusPlaylistSearch()
556 {
557 showDock( AmarokDockPlaylist ); // ensure that the dock is visible if tabbed
558 m_playlistDock->searchWidget()->focusInputLine();
559 }
560
561 void
slotFocusCollectionSearch()562 MainWindow::slotFocusCollectionSearch()
563 {
564 // ensure collection browser is activated within navigation dock:
565 browserDock()->list()->navigate( QStringLiteral("collections") );
566 showDock( AmarokDockNavigation ); // ensure that the dock is visible if tabbed
567 m_collectionBrowser->focusInputLine();
568 }
569
570 #ifdef DEBUG_BUILD_TYPE
571 void
showNetworkRequestViewer()572 MainWindow::showNetworkRequestViewer() //SLOT
573 {
574 if( !m_networkViewer )
575 {
576 m_networkViewer = new NetworkAccessViewer( this );
577 The::networkAccessManager()->setNetworkAccessViewer( m_networkViewer.data() );
578
579 }
580 The::networkAccessManager()->networkAccessViewer()->show();
581 }
582 #endif // DEBUG_BUILD_TYPE
583
584 /**
585 * "Toggle Main Window" global shortcut connects to this slot
586 */
587 void
showHide()588 MainWindow::showHide() //SLOT
589 {
590 const KWindowInfo info( winId(), 0, 0 );
591 const int currentDesktop = KWindowSystem::currentDesktop();
592
593 if( !isVisible() )
594 {
595 setVisible( true );
596 }
597 else
598 {
599 if( !isMinimized() )
600 {
601 if( !isActiveWindow() ) // not minimised and without focus
602 {
603 KWindowSystem::setOnDesktop( winId(), currentDesktop );
604 KWindowSystem::activateWindow( winId() );
605 }
606 else // Amarok has focus
607 {
608 setVisible( false );
609 }
610 }
611 else // Amarok is minimised
612 {
613 setWindowState( windowState() & ~Qt::WindowMinimized );
614 KWindowSystem::setOnDesktop( winId(), currentDesktop );
615 KWindowSystem::activateWindow( winId() );
616 }
617 }
618 }
619
620 void
showNotificationPopup()621 MainWindow::showNotificationPopup() // slot
622 {
623 if( Amarok::KNotificationBackend::instance()->isEnabled()
624 && !Amarok::OSD::instance()->isEnabled() )
625 Amarok::KNotificationBackend::instance()->showCurrentTrack();
626 else
627 Amarok::OSD::instance()->forceToggleOSD();
628 }
629
630 void
slotFullScreen()631 MainWindow::slotFullScreen() // slot
632 {
633 setWindowState( windowState() ^ Qt::WindowFullScreen );
634 }
635
636 void
slotLoveTrack()637 MainWindow::slotLoveTrack()
638 {
639 Q_EMIT loveTrack( The::engineController()->currentTrack() );
640 }
641
642 void
slotBanTrack()643 MainWindow::slotBanTrack()
644 {
645 Q_EMIT banTrack( The::engineController()->currentTrack() );
646 }
647
648 void
slotShufflePlaylist()649 MainWindow::slotShufflePlaylist()
650 {
651 m_playlistDock->sortWidget()->trimToLevel();
652 The::playlistActions()->shuffle();
653 }
654
655 void
slotSeekForwardShort()656 MainWindow::slotSeekForwardShort()
657 {
658 EngineController* ec = The::engineController();
659 ec->seekBy( AmarokConfig::seekShort() * 1000 );
660 }
661
662 void
slotSeekForwardMedium()663 MainWindow::slotSeekForwardMedium()
664 {
665 EngineController* ec = The::engineController();
666 ec->seekBy( AmarokConfig::seekMedium() * 1000 );
667 }
668
669 void
slotSeekForwardLong()670 MainWindow::slotSeekForwardLong()
671 {
672 EngineController* ec = The::engineController();
673 ec->seekBy( AmarokConfig::seekLong() * 1000 );
674 }
675
676 void
slotSeekBackwardShort()677 MainWindow::slotSeekBackwardShort()
678 {
679 EngineController* ec = The::engineController();
680 ec->seekBy( AmarokConfig::seekShort() * -1000 );
681 }
682
683 void
slotSeekBackwardMedium()684 MainWindow::slotSeekBackwardMedium()
685 {
686 EngineController* ec = The::engineController();
687 ec->seekBy( AmarokConfig::seekMedium() * -1000 );
688 }
689
690 void
slotSeekBackwardLong()691 MainWindow::slotSeekBackwardLong()
692 {
693 EngineController* ec = The::engineController();
694 ec->seekBy( AmarokConfig::seekLong() * -1000 );
695 }
696
slotPutCurrentTrackToClipboard()697 void MainWindow::slotPutCurrentTrackToClipboard()
698 {
699 Meta::TrackPtr currentTrack = The::engineController()->currentTrack();
700 if ( currentTrack )
701 {
702 QString text;
703 Meta::ArtistPtr artist = currentTrack->artist();
704 if( artist )
705 text = artist->prettyName() + " - ";
706 text += currentTrack->prettyName();
707
708 QClipboard *clipboard = QApplication::clipboard();
709 clipboard->setText( text );
710 }
711 }
712
713 void
activate()714 MainWindow::activate()
715 {
716 #ifdef Q_WS_X11
717 const KWindowInfo info = KWindowSystem::windowInfo( winId(), 0, 0 );
718
719 if( KWindowSystem::activeWindow() != winId() )
720 setVisible( true );
721 else if( !info.isMinimized() )
722 setVisible( true );
723 if( !isHidden() )
724 KWindowSystem::activateWindow( winId() );
725 #else
726 setVisible( true );
727 #endif
728 }
729
730 void
createActions()731 MainWindow::createActions()
732 {
733 KActionCollection* const ac = Amarok::actionCollection();
734 const EngineController* const ec = The::engineController();
735 const Playlist::Actions* const pa = The::playlistActions();
736 const Playlist::Controller* const pc = The::playlistController();
737
738 KStandardAction::keyBindings( pApp, &App::slotConfigShortcuts, ac );
739 KStandardAction::preferences( pApp, &App::slotConfigAmarokWithEmptyPage, ac );
740
741 m_showMenuBar = KStandardAction::showMenubar(this, &MainWindow::slotShowMenuBar, ac);
742 ac->action( KStandardAction::name( KStandardAction::KeyBindings ) )->setIcon( QIcon::fromTheme( QStringLiteral("configure-shortcuts-amarok") ) );
743 ac->action( KStandardAction::name( KStandardAction::Preferences ) )->setIcon( QIcon::fromTheme( QStringLiteral("configure-amarok") ) );
744 ac->action( KStandardAction::name( KStandardAction::Preferences ) )->setMenuRole(QAction::PreferencesRole); // Define OS X Prefs menu here, removes need for ifdef later
745
746 KStandardAction::quit( pApp, &App::quit, ac );
747
748 QAction *action = new QAction( QIcon::fromTheme( QStringLiteral("document-open") ), i18n("&Add Media..."), this );
749 ac->addAction( "playlist_add", action );
750 connect( action, &QAction::triggered, this, &MainWindow::slotAddLocation );
751 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_A ) );
752
753 action = new QAction( QIcon::fromTheme( QStringLiteral("edit-clear-list") ), i18nc( "clear playlist", "&Clear Playlist" ), this );
754 connect( action, &QAction::triggered, pc, &Playlist::Controller::clear );
755 ac->addAction( "playlist_clear", action );
756
757 action = new QAction( QIcon::fromTheme( QStringLiteral("format-list-ordered") ),
758 i18nc( "edit play queue of playlist", "Edit &Queue" ), this );
759 //Qt::META+Qt::Key_Q is taken by Plasma as a global
760 action->setShortcut( QKeySequence( Qt::META + Qt::Key_U ) );
761 ac->addAction( "playlist_edit_queue", action );
762
763 action = new QAction( i18nc( "Remove duplicate and dead (unplayable) tracks from the playlist", "Re&move Duplicates" ), this );
764 connect( action, &QAction::triggered, pc, &Playlist::Controller::removeDeadAndDuplicates );
765 ac->addAction( "playlist_remove_dead_and_duplicates", action );
766
767 action = new Playlist::LayoutConfigAction( this );
768 ac->addAction( "playlist_layout", action );
769
770 action = new QAction( QIcon::fromTheme( QStringLiteral("document-open-remote") ), i18n("&Add Stream..."), this );
771 connect( action, &QAction::triggered, this, &MainWindow::slotAddStream );
772 ac->addAction( "stream_add", action );
773
774 action = new QAction( QIcon::fromTheme( QStringLiteral("document-export-amarok") ), i18n("&Export Playlist As..."), this );
775 connect( action, &QAction::triggered, this, &MainWindow::exportPlaylist );
776 ac->addAction( "playlist_export", action );
777
778 action = new QAction( QIcon::fromTheme( QStringLiteral("bookmark-new") ), i18n( "Bookmark Media Sources View" ), this );
779 ac->addAction( "bookmark_browser", action );
780 connect( action, &QAction::triggered, The::amarokUrlHandler(), &AmarokUrlHandler::bookmarkCurrentBrowserView );
781
782 action = new QAction( QIcon::fromTheme( QStringLiteral("bookmarks-organize") ), i18n( "Bookmark Manager" ), this );
783 ac->addAction( "bookmark_manager", action );
784 connect( action, &QAction::triggered, this, &MainWindow::slotShowBookmarkManager );
785
786 action = new QAction( QIcon::fromTheme( QStringLiteral("view-media-equalizer") ), i18n( "Equalizer" ), this );
787 ac->addAction( "equalizer_dialog", action );
788 connect( action, &QAction::triggered, this, &MainWindow::slotShowEqualizer );
789
790 action = new QAction( QIcon::fromTheme( QStringLiteral("bookmark-new") ), i18n( "Bookmark Playlist Setup" ), this );
791 ac->addAction( "bookmark_playlistview", action );
792 connect( action, &QAction::triggered, The::amarokUrlHandler(), &AmarokUrlHandler::bookmarkCurrentPlaylistView );
793
794 action = new QAction( QIcon::fromTheme( QStringLiteral("bookmark-new") ), i18n( "Bookmark Context Applets" ), this );
795 ac->addAction( "bookmark_contextview", action );
796 connect( action, &QAction::triggered, The::amarokUrlHandler(), &AmarokUrlHandler::bookmarkCurrentContextView );
797
798 action = new QAction( QIcon::fromTheme( QStringLiteral("media-album-cover-manager-amarok") ), i18n( "Cover Manager" ), this );
799 connect( action, &QAction::triggered, this, &MainWindow::slotShowCoverManager );
800 ac->addAction( "cover_manager", action );
801
802 action = new QAction( QIcon::fromTheme(QStringLiteral("document-open")), i18n("Play Media..."), this );
803 ac->addAction( "playlist_playmedia", action );
804 action->setShortcut( Qt::CTRL + Qt::Key_O );
805 connect( action, &QAction::triggered, this, &MainWindow::slotPlayMedia );
806
807 action = new QAction( QIcon::fromTheme(QStringLiteral("media-track-edit-amarok")), i18n("Edit Details of Currently Selected Track"), this );
808 ac->addAction( "trackdetails_edit", action );
809 action->setShortcut( Qt::CTRL + Qt::Key_E );
810 connect( action, &QAction::triggered, this, &MainWindow::slotEditTrackInfo );
811
812 action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-forward-amarok") ),
813 i18n( "Seek Forward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekShort() * 1000 ) ), this );
814 ac->addAction( "seek_forward_short", action );
815 action->setShortcut( Qt::CTRL + Qt::Key_Right );
816 connect( action, &QAction::triggered, this, &MainWindow::slotSeekForwardShort );
817
818 action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-forward-amarok") ),
819 i18n( "Seek Forward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekMedium() * 1000 ) ), this );
820 ac->addAction( "seek_forward_medium", action );
821 action->setShortcut( Qt::Key_Right );
822 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::SHIFT + Qt::Key_Plus ) );
823 connect( action, &QAction::triggered, this, &MainWindow::slotSeekForwardMedium );
824
825 action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-forward-amarok") ),
826 i18n( "Seek Forward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekLong() * 1000 ) ), this );
827 ac->addAction( "seek_forward_long", action );
828 action->setShortcut( Qt::SHIFT + Qt::Key_Right );
829 connect( action, &QAction::triggered, this, &MainWindow::slotSeekForwardLong );
830
831
832 action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-backward-amarok") ),
833 i18n( "Seek Backward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekShort() * 1000 ) ), this );
834 ac->addAction( "seek_backward_short", action );
835 action->setShortcut( Qt::CTRL + Qt::Key_Left );
836 connect( action, &QAction::triggered, this, &MainWindow::slotSeekBackwardShort );
837
838 action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-backward-amarok") ),
839 i18n( "Seek Backward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekMedium() * 1000 ) ), this );
840 ac->addAction( "seek_backward_medium", action );
841 action->setShortcut( Qt::Key_Left );
842 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::SHIFT + Qt::Key_Minus ) );
843 connect( action, &QAction::triggered, this, &MainWindow::slotSeekBackwardMedium );
844
845 action = new QAction( QIcon::fromTheme( QStringLiteral("media-seek-backward-amarok") ),
846 i18n( "Seek Backward by %1 seconds", KFormat().formatDecimalDuration( AmarokConfig::seekLong() * 1000 ) ), this );
847 ac->addAction( "seek_backward_long", action );
848 action->setShortcut( Qt::SHIFT + Qt::Key_Left );
849 connect( action, &QAction::triggered, this, &MainWindow::slotSeekBackwardLong );
850
851 PERF_LOG( "MainWindow::createActions 6" )
852 action = new QAction( QIcon::fromTheme(QStringLiteral("view-refresh")), i18n( "Update Collection" ), this );
853 connect ( action, &QAction::triggered, CollectionManager::instance(), &CollectionManager::checkCollectionChanges );
854 ac->addAction( "update_collection", action );
855
856 action = new QAction( QIcon::fromTheme( QStringLiteral("amarok_playcount") ), i18n( "Synchronize Statistics..." ), this );
857 ac->addAction( "synchronize_statistics", action );
858 connect( action, &QAction::triggered, Amarok::Components::statSyncingController(),
859 &StatSyncing::Controller::synchronize );
860 Amarok::Components::statSyncingController();
861 action = new QAction( this );
862 ac->addAction( "prev", action );
863 action->setIcon( QIcon::fromTheme(QStringLiteral("media-skip-backward-amarok")) );
864 action->setText( i18n( "Previous Track" ) );
865 KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
866 connect( action, &QAction::triggered, pa, &Playlist::Actions::back );
867
868 action = new QAction( this );
869 ac->addAction( "replay", action );
870 action->setIcon( QIcon::fromTheme(QStringLiteral("media-playback-start")) );
871 action->setText( i18n( "Restart current track" ) );
872 KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
873 connect( action, &QAction::triggered, ec, &EngineController::replay );
874
875 action = new QAction( this );
876 ac->addAction( "shuffle_playlist", action );
877 action->setIcon( QIcon::fromTheme(QStringLiteral("media-playlist-shuffle")) );
878 action->setText( i18n( "Shuffle Playlist" ) );
879 action->setShortcut( Qt::CTRL + Qt::Key_H );
880 connect( action, &QAction::triggered, this, &MainWindow::slotShufflePlaylist );
881
882 action = new QAction( this );
883 ac->addAction( QStringLiteral("repopulate"), action );
884 action->setText( i18n( "Repopulate Playlist" ) );
885 action->setIcon( QIcon::fromTheme("view-refresh-amarok") );
886 connect( action, &QAction::triggered, pa, &Playlist::Actions::repopulateDynamicPlaylist );
887
888 action = new QAction( this );
889 ac->addAction( QStringLiteral("disable_dynamic"), action );
890 action->setText( i18n( "Disable Dynamic Playlist" ) );
891 action->setIcon( QIcon::fromTheme("edit-delete-amarok") );
892 //this is connected inside the dynamic playlist category
893
894 action = new QAction( QIcon::fromTheme(QStringLiteral("media-skip-forward-amarok")), i18n( "Next Track" ), this );
895 ac->addAction( "next", action );
896 KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
897 connect( action, &QAction::triggered, pa, &Playlist::Actions::next );
898
899 action = new QAction( i18n( "Increase Volume" ), this );
900 ac->addAction( "increaseVolume", action );
901 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_Plus ) );
902 action->setShortcut( Qt::Key_Plus );
903 connect( action, &QAction::triggered, ec, &EngineController::regularIncreaseVolume );
904
905 action = new QAction( i18n( "Decrease Volume" ), this );
906 ac->addAction( "decreaseVolume", action );
907 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_Minus ) );
908 action->setShortcut( Qt::Key_Minus );
909 connect( action, &QAction::triggered, ec, &EngineController::regularDecreaseVolume );
910
911 action = new QAction( i18n( "Toggle Main Window" ), this );
912 ac->addAction( "toggleMainWindow", action );
913 KGlobalAccel::setGlobalShortcut(action, QKeySequence() );
914 connect( action, &QAction::triggered, this, &MainWindow::showHide );
915
916 action = new QAction( i18n( "Toggle Full Screen" ), this );
917 ac->addAction( "toggleFullScreen", action );
918 action->setShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_F ) );
919 connect( action, &QAction::triggered, this, &MainWindow::slotFullScreen );
920
921 action = new QAction( i18n( "Search playlist" ), this );
922 ac->addAction( "searchPlaylist", action );
923 action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_J ) );
924 connect( action, &QAction::triggered, this, &MainWindow::slotFocusPlaylistSearch );
925
926 action = new QAction( i18n( "Search collection" ), this );
927 ac->addAction( "searchCollection", action );
928 action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_F ) );
929 connect( action, &QAction::triggered, this, &MainWindow::slotFocusCollectionSearch );
930
931 action = new QAction( QIcon::fromTheme( "music-amarok" ), i18n("Show active track"), this );
932 ac->addAction( "show_active_track", action );
933 connect( action, &QAction::triggered, this, &MainWindow::slotShowActiveTrack );
934
935 action = new QAction( i18n( "Show Notification Popup" ), this );
936 ac->addAction( "showNotificationPopup", action );
937 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_O ) );
938 connect( action, &QAction::triggered, this, &MainWindow::showNotificationPopup );
939
940 action = new QAction( i18n( "Mute Volume" ), this );
941 ac->addAction( "mute", action );
942 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_M ) );
943 connect( action, &QAction::triggered, ec, &EngineController::toggleMute );
944
945 action = new QAction( i18n( "Last.fm: Love Current Track" ), this );
946 ac->addAction( "loveTrack", action );
947 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_L ) );
948 connect( action, &QAction::triggered, this, &MainWindow::slotLoveTrack );
949
950 action = new QAction( i18n( "Last.fm: Ban Current Track" ), this );
951 ac->addAction( "banTrack", action );
952 //KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_B ) );
953 connect( action, &QAction::triggered, this, &MainWindow::slotBanTrack );
954
955 action = new QAction( i18n( "Last.fm: Skip Current Track" ), this );
956 ac->addAction( "skipTrack", action );
957 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_S ) );
958 connect( action, &QAction::triggered, this, &MainWindow::skipTrack );
959
960 action = new QAction( QIcon::fromTheme( "media-track-queue-amarok" ), i18n( "Queue Track" ), this );
961 ac->addAction( "queueTrack", action );
962 action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_D ) );
963 connect( action, &QAction::triggered, this, &MainWindow::switchQueueStateShortcut );
964
965 action = new QAction( i18n( "Put Artist - Title of the current track to the clipboard" ), this );
966 ac->addAction("artistTitleClipboard", action);
967 action->setShortcut( QKeySequence( Qt::CTRL + Qt::Key_C ) );
968 connect( action, &QAction::triggered, this, &MainWindow::slotPutCurrentTrackToClipboard );
969
970 action = new QAction( i18n( "Rate Current Track: 1" ), this );
971 ac->addAction( "rate1", action );
972 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_1 ) );
973 connect( action, &QAction::triggered, this, &MainWindow::setRating1 );
974
975 action = new QAction( i18n( "Rate Current Track: 2" ), this );
976 ac->addAction( "rate2", action );
977 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_2 ) );
978 connect( action, &QAction::triggered, this, &MainWindow::setRating2 );
979
980 action = new QAction( i18n( "Rate Current Track: 3" ), this );
981 ac->addAction( "rate3", action );
982 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_3 ) );
983 connect( action, &QAction::triggered, this, &MainWindow::setRating3 );
984
985 action = new QAction( i18n( "Rate Current Track: 4" ), this );
986 ac->addAction( "rate4", action );
987 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_4 ) );
988 connect( action, &QAction::triggered, this, &MainWindow::setRating4 );
989
990 action = new QAction( i18n( "Rate Current Track: 5" ), this );
991 ac->addAction( "rate5", action );
992 KGlobalAccel::setGlobalShortcut(action, QKeySequence( Qt::META + Qt::Key_5 ) );
993 connect( action, &QAction::triggered, this, &MainWindow::setRating5 );
994
995 #ifdef DEBUG_BUILD_TYPE
996 action = new QAction( i18n( "Network Request Viewer" ), this );
997 ac->addAction( "network_request_viewer", action );
998 action->setIcon( QIcon::fromTheme( "utilities-system-monitor" ) );
999 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
setRating(int n)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
createMenus()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
slotShowMenuBar()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
showAbout()1182 MainWindow::showAbout()
1183 {
1184 ExtendedAboutDialog dialog( KAboutData::applicationData(), &ocsData );
1185 dialog.exec();
1186 }
1187
1188 void
showReportBug()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
changeEvent(QEvent * event)1198 MainWindow::changeEvent( QEvent *event )
1199 {
1200 if( event->type() == QEvent::PaletteChange )
1201 The::paletteHandler()->setPalette( palette() );
1202 }
1203
1204 void
slotStopped()1205 MainWindow::slotStopped()
1206 {
1207 setPlainCaption( i18n( AMAROK_CAPTION ) );
1208 }
1209
1210 void
slotPaused()1211 MainWindow::slotPaused()
1212 {
1213 setPlainCaption( i18n( "Paused :: %1", i18n( AMAROK_CAPTION ) ) );
1214 }
1215
1216 void
slotNewTrackPlaying()1217 MainWindow::slotNewTrackPlaying()
1218 {
1219 slotMetadataChanged( The::engineController()->currentTrack() );
1220 }
1221
1222 void
slotMetadataChanged(Meta::TrackPtr track)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 *
collectionBrowser()1230 MainWindow::collectionBrowser()
1231 {
1232 return m_collectionBrowser;
1233 }
1234
1235 QString
activeBrowserName()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
setLayoutLocked(bool locked)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
resetLayout()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
setDefaultDockSizes()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, 0, 0 );
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
playAudioCd()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
isWaitingForCd() const1371 MainWindow::isWaitingForCd() const
1372 {
1373 DEBUG_BLOCK
1374 debug() << "waiting?: " << m_waitingForCd;
1375 return m_waitingForCd;
1376 }
1377
1378 bool
isOnCurrentDesktop() const1379 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
1389