1
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
3
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
4
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
5
* Copyright 2010-2012, Jeff Mitchell <jeff@tomahawk-player.org>
6
* Copyright 2012, Teo Mrnjavac <teo@kde.org>
8
* Tomahawk is free software: you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation, either version 3 of the License, or
11
* (at your option) any later version.
13
* Tomahawk is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
22
#include "TomahawkWindow.h"
23
#include "ui_TomahawkWindow.h"
26
#include <QCloseEvent>
27
#include <QDesktopServices>
30
#include <QInputDialog>
32
#include <QPropertyAnimation>
34
#include <QMessageBox>
35
#include <QNetworkAccessManager>
36
#include <QNetworkReply>
39
#include <QToolButton>
41
#include "accounts/AccountManager.h"
42
#include "sourcetree/SourceTreeView.h"
43
#include "network/Servent.h"
44
#include "utils/TomahawkUtilsGui.h"
45
#include "utils/ProxyStyle.h"
46
#include "utils/WidgetDragFilter.h"
47
#include "widgets/AccountsToolButton.h"
48
#include "widgets/AnimatedSplitter.h"
49
#include "widgets/NewPlaylistWidget.h"
50
#include "widgets/SearchWidget.h"
51
#include "widgets/PlaylistTypeSelectorDialog.h"
52
#include "widgets/ContainedMenuButton.h"
53
#include "thirdparty/Qocoa/qsearchfield.h"
54
#include "playlist/dynamic/GeneratorInterface.h"
55
#include "playlist/PlaylistModel.h"
56
#include "playlist/PlaylistView.h"
57
#include "playlist/QueueView.h"
58
#include "jobview/JobStatusView.h"
59
#include "jobview/JobStatusModel.h"
60
#include "jobview/ErrorStatusMessage.h"
61
#include "jobview/JobStatusModel.h"
62
#include "sip/SipPlugin.h"
63
#include "filemetadata/ScanManager.h"
68
#include "ViewManager.h"
69
#include "ActionCollection.h"
70
#include "AudioControls.h"
71
#include "SettingsDialog.h"
72
#include "DiagnosticsDialog.h"
73
#include "TomahawkSettings.h"
74
#include "SourceList.h"
75
#include "TomahawkTrayIcon.h"
76
#include "TomahawkApp.h"
77
#include "LoadXSPFDialog.h"
78
#include "utils/ImageRegistry.h"
79
#include "utils/Logger.h"
83
#if defined( Q_WS_WIN )
84
#if defined ( WITH_QtSparkle )
85
#include <qtsparkle/Updater>
92
#define THBN_CLICKED 0x1800
96
using namespace Tomahawk;
97
using namespace Accounts;
100
TomahawkWindow::TomahawkWindow( QWidget* parent )
101
: QMainWindow( parent )
103
, m_buttonCreatedID( RegisterWindowMessage( L"TaskbarButtonCreated" ) )
104
#ifdef HAVE_THUMBBUTTON
108
, ui( new Ui::TomahawkWindow )
109
, m_searchWidget( 0 )
110
, m_audioControls( new AudioControls( this ) )
111
, m_trayIcon( new TomahawkTrayIcon( this ) )
112
, m_settingsDialog( 0 )
113
, m_audioRetryCounter( 0 )
115
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
117
ViewManager* vm = new ViewManager( this );
118
connect( vm, SIGNAL( showQueueRequested() ), SLOT( showQueue() ) );
119
connect( vm, SIGNAL( hideQueueRequested() ), SLOT( hideQueue() ) );
120
connect( APP, SIGNAL( tomahawkLoaded() ), vm, SLOT( setTomahawkLoaded() ) ); // Pass loaded signal into libtomahawk so components in there can connect to ViewManager
123
connect( AudioEngine::instance(), SIGNAL( stateChanged( AudioState, AudioState) ), SLOT( audioStateChanged( AudioState, AudioState) ) );
127
applyPlatformTweaks();
129
ui->centralWidget->setContentsMargins( 0, 0, 0, 0 );
130
TomahawkUtils::unmarginLayout( ui->centralWidget->layout() );
135
statusBar()->addPermanentWidget( m_audioControls, 1 );
141
if ( qApp->arguments().contains( "--debug" ) )
143
connect( ActionCollection::instance()->getAction( "crashNow" ), SIGNAL( triggered() ), SLOT( crashNow() ) );
149
vm->setQueue( m_queueView );
150
vm->showWelcomePage();
152
if ( TomahawkSettings::instance()->fullscreenEnabled() )
154
// Window must be fully constructed to toggle fullscreen mode. Queue it up.
155
QTimer::singleShot( 0, this, SLOT( toggleFullscreen() ) );
160
TomahawkWindow::~TomahawkWindow()
168
TomahawkWindow::loadSettings()
170
TomahawkSettings* s = TomahawkSettings::instance();
172
// Workaround for broken window geometry restoring on Qt Cocoa when setUnifiedTitleAndToolBarOnMac is true.
173
// See http://bugreports.qt.nokia.com/browse/QTBUG-3116 and
174
// http://lists.qt.nokia.com/pipermail/qt-interest/2009-August/011491.html
176
#ifdef QT_MAC_USE_COCOA
177
bool workaround = isVisible();
181
setWindowOpacity( 0 );
182
// let Qt update its frameStruts
187
if ( !s->mainWindowGeometry().isEmpty() )
188
restoreGeometry( s->mainWindowGeometry() );
189
if ( !s->mainWindowState().isEmpty() )
190
restoreState( s->mainWindowState() );
191
if ( !s->mainWindowSplitterState().isEmpty() )
192
ui->splitter->restoreState( s->mainWindowSplitterState() );
194
// Always set stretch factor. If user hasn't manually set splitter sizes,
195
// this will ensure a sane default on all startups. If the user has, the manual
196
// size will override the default stretching
197
ui->splitter->setStretchFactor( 0, 0 );
198
ui->splitter->setStretchFactor( 1, 1 );
200
#ifdef QT_MAC_USE_COCOA
203
// Make it visible again
204
setWindowOpacity( 1 );
209
bool mbVisible = s->menuBarVisible();
210
menuBar()->setVisible( mbVisible );
211
m_compactMenuAction->setVisible( !mbVisible );
212
ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( mbVisible ? tr( "Hide Menu Bar" ) : tr( "Show Menu Bar" ) );
218
TomahawkWindow::saveSettings()
220
TomahawkSettings* s = TomahawkSettings::instance();
221
s->setMainWindowGeometry( saveGeometry() );
222
s->setMainWindowState( saveState() );
223
s->setMainWindowSplitterState( ui->splitter->saveState() );
224
s->setMenuBarVisible( menuBar()->isVisible() );
229
TomahawkWindow::applyPlatformTweaks()
231
// HACK: QtCurve causes an infinite loop on startup. This is because
232
// setStyle calls setPalette, which calls ensureBaseStyle, which loads
233
// QtCurve. QtCurve calls setPalette, which creates an infinite loop.
234
// We could simply not use ProxyStyle under QtCurve, but that would
235
// make the whole UI look like crap.
236
// Instead, we tell ProxyStyle that it's running under QtCurve, so it
237
// can intercept QStyle::polish (which in the base implementation does
238
// nothing and in QtCurve does evil things), and avoid forwarding it
240
bool isQtCurve = false;
241
if ( QString( qApp->style()->metaObject()->className() ).toLower().contains( "qtcurve" ) )
243
qApp->setStyle( new ProxyStyle( isQtCurve ) );
246
setUnifiedTitleAndToolBarOnMac( true );
250
ui->hline1->setStyleSheet( "border: 1px solid gray;" );
251
ui->hline2->setStyleSheet( "border: 1px solid gray;" );
257
TomahawkWindow::setupToolBar()
259
m_toolbar = addToolBar( "TomahawkToolbar" );
260
m_toolbar->setObjectName( "TomahawkToolbar" );
261
m_toolbar->setMovable( false );
262
m_toolbar->setFloatable( false );
263
m_toolbar->setIconSize( QSize( 22, 22 ) );
264
m_toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly );
265
m_toolbar->setStyleSheet( "border-bottom: 0px" );
266
// If the toolbar is hidden accidentally it causes trouble on Unity because the user can't
267
// easily bring it back (TWK-1046). So we just prevent the user from hiding the toolbar.
268
// This should not affect Mac users.
269
m_toolbar->setContextMenuPolicy( Qt::PreventContextMenu );
272
m_toolbar->installEventFilter( new WidgetDragFilter( m_toolbar ) );
275
m_backAction = m_toolbar->addAction( ImageRegistry::instance()->icon( RESPATH "images/back.svg" ), tr( "Back" ), ViewManager::instance(), SLOT( historyBack() ) );
276
m_backAction->setToolTip( tr( "Go back one page" ) );
277
m_forwardAction = m_toolbar->addAction( ImageRegistry::instance()->icon( RESPATH "images/forward.svg" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) );
278
m_forwardAction->setToolTip( tr( "Go forward one page" ) );
280
m_toolbarLeftBalancer = new QWidget( this );
281
m_toolbarLeftBalancer->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
282
m_toolbarLeftBalancer->setFixedWidth( 0 );
283
m_toolbar->addWidget( m_toolbarLeftBalancer )->setProperty( "kind", QString( "spacer" ) );
285
QWidget* toolbarLeftSpacer = new QWidget( this );
286
toolbarLeftSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
287
m_toolbar->addWidget( toolbarLeftSpacer )->setProperty( "kind", QString( "spacer" ) );
289
m_searchWidget = new QSearchField( this );
290
m_searchWidget->setPlaceholderText( tr( "Search for any artist, album or song..." ) );
291
m_searchWidget->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
292
m_searchWidget->setFixedWidth( 340 );
293
connect( m_searchWidget, SIGNAL( returnPressed() ), this, SLOT( onFilterEdited() ) );
295
m_toolbar->addWidget( m_searchWidget )->setProperty( "kind", QString( "search" ) );
297
QWidget* rightSpacer = new QWidget( this );
298
rightSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
299
m_toolbar->addWidget( rightSpacer )->setProperty( "kind", QString( "spacer" ) );
301
m_toolbarRightBalancer = new QWidget( this );
302
m_toolbarRightBalancer->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
303
m_toolbarRightBalancer->setFixedWidth( 0 );
304
m_toolbar->addWidget( m_toolbarRightBalancer )->setProperty( "kind", QString( "spacer" ) );
306
m_accountsButton = new AccountsToolButton( m_toolbar );
307
m_toolbar->addWidget( m_accountsButton );
308
connect( m_accountsButton, SIGNAL( widthChanged() ),
309
this, SLOT( balanceToolbar() ) );
312
ContainedMenuButton* compactMenuButton = new ContainedMenuButton( m_toolbar );
313
compactMenuButton->setIcon( ImageRegistry::instance()->icon( RESPATH "images/configure.svg" ) );
314
compactMenuButton->setText( tr( "&Main Menu" ) );
315
compactMenuButton->setMenu( m_compactMainMenu );
316
compactMenuButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
317
m_compactMenuAction = m_toolbar->addWidget( compactMenuButton );
318
//HACK: adding the toggle action to the window, otherwise the shortcut keys
319
// won't be picked up when the menu is hidden.
320
// This must be done for all menu bar actions that have shortcut keys :(
321
// Does not apply to Mac which always shows the menu bar.
322
addAction( ActionCollection::instance()->getAction( "playPause" ) );
323
addAction( ActionCollection::instance()->getAction( "toggleMenuBar" ) );
324
addAction( ActionCollection::instance()->getAction( "quit" ) );
331
TomahawkWindow::balanceToolbar()
333
int leftActionsWidth = 0;
334
int rightActionsWidth = 0;
336
foreach ( QAction* action, m_toolbar->actions() )
338
if ( action->property( "kind" ) == QString( "spacer" ) ||
339
!action->isVisible() )
341
else if ( action->property( "kind" ) == QString( "search" ) )
347
QWidget* widget = m_toolbar->widgetForAction( action );
349
if ( !flip ) //we accumulate on the left
351
leftActionsWidth += widget->sizeHint().width()
352
+ m_toolbar->layout()->spacing();
354
else //then, on the right
356
rightActionsWidth += widget->sizeHint().width()
357
+ m_toolbar->layout()->spacing();
361
if ( leftActionsWidth > rightActionsWidth )
363
m_toolbarLeftBalancer->setFixedWidth( 0 );
364
m_toolbarRightBalancer->setFixedWidth( leftActionsWidth - rightActionsWidth );
368
m_toolbarLeftBalancer->setFixedWidth( rightActionsWidth - leftActionsWidth );
369
m_toolbarRightBalancer->setFixedWidth( 0 );
375
TomahawkWindow::setupSideBar()
377
// Delete fake designer widgets
378
delete ui->sidebarWidget;
379
delete ui->playlistWidget;
381
QWidget* sidebarWidget = new QWidget();
382
sidebarWidget->setLayout( new QVBoxLayout() );
384
m_sidebar = new AnimatedSplitter();
385
m_sidebar->setOrientation( Qt::Vertical );
386
m_sidebar->setChildrenCollapsible( false );
388
m_sourcetree = new SourceTreeView( this );
389
JobStatusView* jobsView = new JobStatusView( m_sidebar );
390
JobStatusModel* sourceModel = new JobStatusModel( jobsView );
391
m_jobsModel = new JobStatusSortModel( jobsView );
392
m_jobsModel->setJobModel( sourceModel );
393
jobsView->setModel( m_jobsModel );
395
m_queueView = new QueueView( m_sidebar );
396
AudioEngine::instance()->setQueue( m_queueView->queue()->proxyModel()->playlistInterface() );
398
m_sidebar->addWidget( m_sourcetree );
399
m_sidebar->addWidget( jobsView );
400
m_sidebar->addWidget( m_queueView );
402
// m_sidebar->setGreedyWidget( 1 );
403
m_sidebar->hide( 1, false );
404
m_sidebar->hide( 2, false );
405
m_sidebar->hide( 3, false );
407
sidebarWidget->layout()->addWidget( m_sidebar );
408
sidebarWidget->setContentsMargins( 0, 0, 0, 0 );
409
sidebarWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
410
sidebarWidget->layout()->setMargin( 0 );
413
sidebarWidget->layout()->setSpacing( 0 );
416
ui->splitter->addWidget( sidebarWidget );
417
ui->splitter->addWidget( ViewManager::instance()->widget() );
418
ui->splitter->setCollapsible( 1, false );
420
ActionCollection::instance()->getAction( "showOfflineSources" )
421
->setChecked( TomahawkSettings::instance()->showOfflineSources() );
426
TomahawkWindow::setupUpdateCheck()
428
#if defined( Q_OS_MAC ) && defined( HAVE_SPARKLE )
429
connect( ActionCollection::instance()->getAction( "checkForUpdates" ), SIGNAL( triggered( bool ) ),
430
SLOT( checkForUpdates() ) );
431
#elif defined( Q_WS_WIN ) && defined( WITH_QtSparkle )
434
if ( qApp->arguments().contains( "--debug" ) )
435
updaterUrl.setUrl( "http://download.tomahawk-player.org/sparklewin-debug" );
437
updaterUrl.setUrl( "http://download.tomahawk-player.org/sparklewin" );
439
qtsparkle::Updater* updater = new qtsparkle::Updater( updaterUrl, this );
440
Q_ASSERT( TomahawkUtils::nam() != 0 );
441
updater->SetNetworkAccessManager( TomahawkUtils::nam() );
442
updater->SetVersion( TomahawkUtils::appFriendlyVersion() );
444
connect( ActionCollection::instance()->getAction( "checkForUpdates" ), SIGNAL( triggered() ),
445
updater, SLOT( CheckNow() ) );
452
TomahawkWindow::setupWindowsButtons()
454
#ifdef HAVE_THUMBBUTTON
455
const GUID IID_ITaskbarList3 = { 0xea1afb91,0x9e28,0x4b86, { 0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf } };
458
THUMBBUTTONMASK dwMask = THUMBBUTTONMASK( THB_ICON | THB_TOOLTIP | THB_FLAGS );
459
m_thumbButtons[TP_PREVIOUS].dwMask = dwMask;
460
m_thumbButtons[TP_PREVIOUS].iId = TP_PREVIOUS;
461
m_thumbButtons[TP_PREVIOUS].hIcon = thumbIcon(TomahawkUtils::PrevButton);
462
m_thumbButtons[TP_PREVIOUS].dwFlags = THBF_ENABLED;
463
m_thumbButtons[TP_PREVIOUS].szTip[ tr( "Back" ).toWCharArray( m_thumbButtons[TP_PREVIOUS].szTip ) ] = 0;
465
m_thumbButtons[TP_PLAY_PAUSE].dwMask = dwMask;
466
m_thumbButtons[TP_PLAY_PAUSE].iId = TP_PLAY_PAUSE;
467
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PlayButton);
468
m_thumbButtons[TP_PLAY_PAUSE].dwFlags = THBF_ENABLED;
469
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
471
m_thumbButtons[TP_NEXT].dwMask = dwMask;
472
m_thumbButtons[TP_NEXT].iId = TP_NEXT;
473
m_thumbButtons[TP_NEXT].hIcon = thumbIcon(TomahawkUtils::NextButton);
474
m_thumbButtons[TP_NEXT].dwFlags = THBF_ENABLED;
475
m_thumbButtons[TP_NEXT].szTip[ tr( "Next" ).toWCharArray( m_thumbButtons[TP_NEXT].szTip ) ] = 0;
477
m_thumbButtons[3].dwMask = dwMask;
478
m_thumbButtons[3].iId = -1;
479
m_thumbButtons[3].hIcon = 0;
480
m_thumbButtons[3].dwFlags = THBF_NOBACKGROUND | THBF_DISABLED;
481
m_thumbButtons[3].szTip[0] = 0;
483
m_thumbButtons[TP_LOVE].dwMask = dwMask;
484
m_thumbButtons[TP_LOVE].iId = TP_LOVE;
485
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::NotLoved);
486
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
487
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
489
if ( S_OK == CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_taskbarList ) )
491
hr = m_taskbarList->HrInit();
492
if ( SUCCEEDED( hr ) )
494
hr = m_taskbarList->ThumbBarAddButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
498
m_taskbarList->Release();
503
return SUCCEEDED( hr );
504
#else // HAVE_THUMBBUTTON
511
TomahawkWindow::thumbIcon(TomahawkUtils::ImageType type)
513
static QMap<TomahawkUtils::ImageType,HICON> thumbIcons;
514
if (!thumbIcons.contains( type ) )
516
QPixmap pix ( TomahawkUtils::defaultPixmap(type , TomahawkUtils::Original, QSize( 20, 20 ) ) );
517
thumbIcons[type] = pix.toWinHICON();
519
return thumbIcons[type];
525
TomahawkWindow::setupSignals()
527
// <From AudioEngine>
528
connect( AudioEngine::instance(), SIGNAL( error( AudioEngine::AudioErrorCode ) ), SLOT( onAudioEngineError( AudioEngine::AudioErrorCode ) ) );
529
connect( AudioEngine::instance(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) );
530
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( audioStarted() ) );
531
connect( AudioEngine::instance(), SIGNAL( finished( Tomahawk::result_ptr ) ), SLOT( audioFinished() ) );
532
connect( AudioEngine::instance(), SIGNAL( resumed() ), SLOT( audioStarted() ) );
533
connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioPaused() ) );
534
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( audioStopped() ) );
537
ActionCollection *ac = ActionCollection::instance();
538
// connect( ui->actionAddPeerManually, SIGNAL( triggered() ), SLOT( addPeerManually() ) );
539
connect( ac->getAction( "preferences" ), SIGNAL( triggered() ), SLOT( showSettingsDialog() ) );
540
connect( ac->getAction( "diagnostics" ), SIGNAL( triggered() ), SLOT( showDiagnosticsDialog() ) );
541
connect( ac->getAction( "legalInfo" ), SIGNAL( triggered() ), SLOT( legalInfo() ) );
542
connect( ac->getAction( "openLogfile" ), SIGNAL( triggered() ), SLOT( openLogfile() ) );
543
connect( ac->getAction( "updateCollection" ), SIGNAL( triggered() ), SLOT( updateCollectionManually() ) );
544
connect( ac->getAction( "rescanCollection" ), SIGNAL( triggered() ), SLOT( rescanCollectionManually() ) );
545
connect( ac->getAction( "loadXSPF" ), SIGNAL( triggered() ), SLOT( loadSpiff() ) );
546
connect( ac->getAction( "aboutTomahawk" ), SIGNAL( triggered() ), SLOT( showAboutTomahawk() ) );
547
connect( ac->getAction( "quit" ), SIGNAL( triggered() ), qApp, SLOT( quit() ) );
548
connect( ac->getAction( "showOfflineSources" ), SIGNAL( triggered() ), SLOT( showOfflineSources() ) );
550
#if defined( Q_OS_MAC )
551
connect( ac->getAction( "minimize" ), SIGNAL( triggered() ), SLOT( minimize() ) );
552
connect( ac->getAction( "zoom" ), SIGNAL( triggered() ), SLOT( maximize() ) );
553
connect( ac->getAction( "fullscreen" ), SIGNAL( triggered() ), SLOT( toggleFullscreen() ) );
555
connect( ac->getAction( "toggleMenuBar" ), SIGNAL( triggered() ), SLOT( toggleMenuBar() ) );
559
connect( AccountManager::instance(), SIGNAL( authError( Tomahawk::Accounts::Account* ) ), SLOT( onAccountError() ) );
561
connect( ViewManager::instance(), SIGNAL( historyBackAvailable( bool ) ), SLOT( onHistoryBackAvailable( bool ) ) );
562
connect( ViewManager::instance(), SIGNAL( historyForwardAvailable( bool ) ), SLOT( onHistoryForwardAvailable( bool ) ) );
567
TomahawkWindow::setupMenuBar()
569
// Always create a menubar, but only create a compactMenu on Windows and X11
570
m_menuBar = ActionCollection::instance()->createMenuBar( this );
571
setMenuBar( m_menuBar );
573
m_compactMainMenu = ActionCollection::instance()->createCompactMenu( this );
579
TomahawkWindow::changeEvent( QEvent* e )
581
QMainWindow::changeEvent( e );
585
case QEvent::LanguageChange:
586
ui->retranslateUi( this );
596
TomahawkWindow::closeEvent( QCloseEvent* e )
599
if ( e->spontaneous() && QSystemTrayIcon::isSystemTrayAvailable() )
606
m_trayIcon->setShowHideWindow( false );
614
TomahawkWindow::showEvent( QShowEvent* e )
616
QMainWindow::showEvent( e );
618
#if defined( Q_OS_MAC )
619
ActionCollection::instance()->getAction( "minimize" )->setDisabled( false );
620
ActionCollection::instance()->getAction( "zoom" )->setDisabled( false );
626
TomahawkWindow::hideEvent( QHideEvent* e )
628
QMainWindow::hideEvent( e );
630
#if defined( Q_OS_MAC )
631
ActionCollection::instance()->getAction( "minimize" )->setDisabled( true );
632
ActionCollection::instance()->getAction( "zoom" )->setDisabled( true );
638
TomahawkWindow::keyPressEvent( QKeyEvent* e )
642
#if ! defined ( Q_OS_MAC )
643
#define KEY_PRESSED Q_FUNC_INFO << "Multimedia Key Pressed:"
646
case Qt::Key_MediaPlay:
647
tLog() << KEY_PRESSED << "Play";
648
AudioEngine::instance()->playPause();
650
case Qt::Key_MediaStop:
651
tLog() << KEY_PRESSED << "Stop";
652
AudioEngine::instance()->stop();
654
case Qt::Key_MediaPrevious:
655
tLog() << KEY_PRESSED << "Previous";
656
AudioEngine::instance()->previous();
658
case Qt::Key_MediaNext:
659
tLog() << KEY_PRESSED << "Next";
660
AudioEngine::instance()->next();
662
case Qt::Key_MediaPause:
663
tLog() << KEY_PRESSED << "Pause";
664
AudioEngine::instance()->pause();
666
case Qt::Key_MediaTogglePlayPause:
667
tLog() << KEY_PRESSED << "PlayPause";
668
AudioEngine::instance()->playPause();
670
case Qt::Key_MediaRecord:
681
QMainWindow::keyPressEvent( e );
687
TomahawkWindow::winEvent( MSG* msg, long* result )
689
#define TB_PRESSED Q_FUNC_INFO << "Taskbar Button Pressed:"
691
switch ( msg->message )
694
if ( HIWORD( msg->wParam ) == THBN_CLICKED )
696
switch ( TB_STATES( LOWORD( msg->wParam ) ) )
699
tLog() << TB_PRESSED << "Previous";
700
AudioEngine::instance()->previous();
703
tLog() << TB_PRESSED << "Play/Pause";
704
AudioEngine::instance()->playPause();
707
tLog() << TB_PRESSED << "Next";
708
AudioEngine::instance()->next();
711
tLog() << TB_PRESSED << "Love";
712
if ( !AudioEngine::instance()->currentTrack().isNull() )
714
AudioEngine::instance()->currentTrack()->toQuery()->setLoved( !AudioEngine::instance()->currentTrack()->toQuery()->loved() );
715
updateWindowsLoveButton();
724
if ( msg->message == m_buttonCreatedID )
725
return setupWindowsButtons();
734
TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
736
#ifdef HAVE_THUMBBUTTON
737
if ( m_taskbarList == 0 )
741
case AudioEngine::Playing:
743
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PauseButton);
744
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Pause" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
745
updateWindowsLoveButton();
750
case AudioEngine::Paused:
752
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PlayButton);
753
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
757
case AudioEngine::Stopped:
759
if ( !AudioEngine::instance()->currentTrack().isNull() )
761
disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
764
m_thumbButtons[TP_PLAY_PAUSE].hIcon = thumbIcon(TomahawkUtils::PlayButton);
765
m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
767
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::NotLoved);
768
m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
776
m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
778
Q_UNUSED( newState );
779
Q_UNUSED( oldState );
780
#endif // HAVE_THUMBBUTTON
785
TomahawkWindow::updateWindowsLoveButton()
787
#ifdef HAVE_THUMBBUTTON
788
if ( m_taskbarList == 0 )
790
if ( !AudioEngine::instance()->currentTrack().isNull() && AudioEngine::instance()->currentTrack()->toQuery()->loved() )
792
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::Loved);
793
m_thumbButtons[TP_LOVE].szTip[ tr( "Unlove" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
797
m_thumbButtons[TP_LOVE].hIcon = thumbIcon(TomahawkUtils::NotLoved);
798
m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
801
m_thumbButtons[TP_LOVE].dwFlags = THBF_ENABLED;
802
m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
803
#endif // HAVE_THUMBBUTTON
808
TomahawkWindow::onHistoryBackAvailable( bool avail )
810
m_backAction->setEnabled( avail );
815
TomahawkWindow::onHistoryForwardAvailable( bool avail )
817
m_forwardAction->setEnabled( avail );
822
TomahawkWindow::showSettingsDialog()
824
if ( !m_settingsDialog )
825
m_settingsDialog = new SettingsDialog;
827
m_settingsDialog->show();
832
TomahawkWindow::showDiagnosticsDialog()
834
DiagnosticsDialog win;
840
TomahawkWindow::legalInfo()
842
QDesktopServices::openUrl( QUrl( "http://www.tomahawk-player.org/legal.html" ) );
847
TomahawkWindow::openLogfile()
850
ShellExecuteW( 0, 0, (LPCWSTR)Logger::logFile().utf16(), 0, 0, SW_SHOWNORMAL );
852
QDesktopServices::openUrl( QUrl::fromLocalFile( Logger::logFile() ) );
858
TomahawkWindow::updateCollectionManually()
860
if ( TomahawkSettings::instance()->hasScannerPaths() )
861
ScanManager::instance()->runNormalScan();
866
TomahawkWindow::rescanCollectionManually()
868
if ( TomahawkSettings::instance()->hasScannerPaths() )
869
ScanManager::instance()->runFullRescan();
874
TomahawkWindow::addPeerManually()
876
TomahawkSettings* s = TomahawkSettings::instance();
878
QString addr = QInputDialog::getText( this, tr( "Connect To Peer" ),
879
tr( "Enter peer address:" ), QLineEdit::Normal,
880
s->value( "connip" ).toString(), &ok ); // FIXME
884
s->setValue( "connip", addr );
885
QString ports = QInputDialog::getText( this, tr( "Connect To Peer" ),
886
tr( "Enter peer port:" ), QLineEdit::Normal,
887
s->value( "connport", "50210" ).toString(), &ok );
891
s->setValue( "connport", ports );
892
int port = ports.toInt();
893
QString key = QInputDialog::getText( this, tr( "Connect To Peer" ),
894
tr( "Enter peer key:" ), QLineEdit::Normal,
899
qDebug() << "Attempting to connect to" << addr;
900
Servent::instance()->connectToPeer( addr, port, key );
905
TomahawkWindow::showOfflineSources()
907
m_sourcetree->showOfflineSources(
908
ActionCollection::instance()->getAction( "showOfflineSources" )->isChecked() );
909
TomahawkSettings::instance()->setShowOfflineSources(
910
ActionCollection::instance()->getAction( "showOfflineSources" )->isChecked() );
915
TomahawkWindow::fullScreenEntered()
917
TomahawkSettings::instance()->setFullscreenEnabled( true );
918
statusBar()->setSizeGripEnabled( false );
920
#if defined( Q_WS_MAC )
921
ActionCollection::instance()->getAction( "fullscreen" )->setText( tr( "Exit Full Screen" ) );
927
TomahawkWindow::fullScreenExited()
929
TomahawkSettings::instance()->setFullscreenEnabled( false );
930
statusBar()->setSizeGripEnabled( true );
932
#if defined( Q_WS_MAC )
933
ActionCollection::instance()->getAction( "fullscreen" )->setText( tr( "Enter Full Screen" ) );
939
TomahawkWindow::loadSpiff()
941
LoadXSPFDialog* diag = new LoadXSPFDialog( this, Qt::Sheet );
943
connect( diag, SIGNAL( finished( int ) ), this, SLOT( loadXspfFinished( int ) ) );
946
QWeakPointer< LoadXSPFDialog > safe( diag );
948
int ret = diag->exec();
949
if ( !safe.isNull() && ret == QDialog::Accepted )
951
QUrl url = QUrl::fromUserInput( safe.data()->xspfUrl() );
952
bool autoUpdate = safe.data()->autoUpdate();
954
XSPFLoader* loader = new XSPFLoader( true, autoUpdate );
955
connect( loader, SIGNAL( error( XSPFLoader::XSPFErrorCode ) ), SLOT( onXSPFError( XSPFLoader::XSPFErrorCode ) ) );
956
connect( loader, SIGNAL( ok( Tomahawk::playlist_ptr ) ), SLOT( onXSPFOk( Tomahawk::playlist_ptr ) ) );
964
TomahawkWindow::loadXspfFinished( int ret )
966
LoadXSPFDialog* d = qobject_cast< LoadXSPFDialog* >( sender() );
968
if ( ret == QDialog::Accepted )
970
QUrl url = QUrl::fromUserInput( d->xspfUrl() );
971
bool autoUpdate = d->autoUpdate();
973
XSPFLoader* loader = new XSPFLoader( true, autoUpdate );
974
connect( loader, SIGNAL( error( XSPFLoader::XSPFErrorCode ) ), SLOT( onXSPFError( XSPFLoader::XSPFErrorCode ) ) );
975
connect( loader, SIGNAL( ok( Tomahawk::playlist_ptr ) ), SLOT( onXSPFOk( Tomahawk::playlist_ptr ) ) );
983
TomahawkWindow::onXSPFOk( const Tomahawk::playlist_ptr& pl )
985
ViewManager::instance()->show( pl );
990
TomahawkWindow::onXSPFError( XSPFLoader::XSPFErrorCode error )
994
case XSPFLoader::ParseError:
995
QMessageBox::critical( this, tr( "XSPF Error" ), tr( "This is not a valid XSPF playlist." ) );
998
case XSPFLoader::InvalidTrackError:
999
QMessageBox::warning( this, tr( "Failed to save tracks" ), tr( "Some tracks in the playlist do not contain an artist and a title. They will be ignored." ), QMessageBox::Ok );
1002
//FIXME: This includes FetchError
1009
TomahawkWindow::onAudioEngineError( AudioEngine::AudioErrorCode /* error */ )
1013
msg = tr( "Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed." );
1015
msg = tr( "Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped." );
1017
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( msg, 15 ) );
1019
if ( m_audioRetryCounter < 3 )
1020
AudioEngine::instance()->play();
1021
m_audioRetryCounter++;
1026
TomahawkWindow::createAutomaticPlaylist( QString playlistName )
1028
if ( playlistName.isEmpty() )
1031
source_ptr author = SourceList::instance()->getLocal();
1032
QString id = uuid();
1033
QString info = ""; // FIXME
1034
QString creator = "someone"; // FIXME
1036
dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, Static, false );
1037
playlist->setMode( Static );
1038
playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls(), playlist->entries() );
1040
ViewManager::instance()->show( playlist );
1045
TomahawkWindow::createStation()
1047
QString title = tr( "Station" );
1049
QString playlistName = QInputDialog( this, Qt::Sheet ).getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, title, &ok );
1053
if ( playlistName.isEmpty() || playlistName == title )
1055
QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->stations();
1057
foreach ( const playlist_ptr& pl, pls )
1058
titles << pl->title();
1060
playlistName = title;
1062
while ( titles.contains( playlistName ) )
1064
playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
1068
source_ptr author = SourceList::instance()->getLocal();
1069
QString id = uuid();
1070
QString info = ""; // FIXME
1071
QString creator = "someone"; // FIXME
1073
dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, OnDemand, false );
1074
playlist->setMode( OnDemand );
1075
playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls() );
1077
ViewManager::instance()->show( playlist );
1082
TomahawkWindow::createPlaylist()
1084
PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet );
1087
playlistSelectorDlg->setModal( true );
1090
connect( playlistSelectorDlg, SIGNAL( finished( int ) ), SLOT( playlistCreateDialogFinished( int ) ) );
1091
playlistSelectorDlg->show();
1096
TomahawkWindow::playlistCreateDialogFinished( int ret )
1098
PlaylistTypeSelectorDlg* playlistSelectorDlg = qobject_cast< PlaylistTypeSelectorDlg* >( sender() );
1099
Q_ASSERT( playlistSelectorDlg );
1101
QString playlistName = playlistSelectorDlg->playlistName();
1103
if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret )
1105
if ( playlistName.isEmpty() )
1107
QList< playlist_ptr > pls = SourceList::instance()->getLocal()->collection()->playlists();
1109
foreach ( const playlist_ptr& pl, pls )
1110
titles << pl->title();
1112
QString title = tr( "Playlist" );
1113
playlistName = title;
1115
while ( titles.contains( playlistName ) )
1117
playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
1121
playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() );
1122
ViewManager::instance()->show( playlist );
1124
else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret )
1126
// create Auto Playlist
1127
if ( playlistName.isEmpty() )
1129
QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->autoPlaylists();
1131
foreach ( const dynplaylist_ptr& pl, pls )
1132
titles << pl->title();
1134
QString title = tr( "Automatic Playlist" );
1135
playlistName = title;
1137
while ( titles.contains( playlistName ) )
1139
playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
1143
createAutomaticPlaylist( playlistName );
1146
playlistSelectorDlg->deleteLater();
1151
TomahawkWindow::audioStarted()
1153
m_audioRetryCounter = 0;
1155
ActionCollection::instance()->getAction( "playPause" )->setIcon( ImageRegistry::instance()->icon( RESPATH "images/pause-rest.svg" ) );
1156
ActionCollection::instance()->getAction( "playPause" )->setText( tr( "Pause" ) );
1157
ActionCollection::instance()->getAction( "stop" )->setEnabled( true );
1160
connect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( updateWindowsLoveButton() ) );
1166
TomahawkWindow::audioFinished()
1169
disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
1175
TomahawkWindow::audioPaused()
1177
ActionCollection::instance()->getAction( "playPause" )->setIcon( ImageRegistry::instance()->icon( RESPATH "images/play-rest.svg" ) );
1178
ActionCollection::instance()->getAction( "playPause" )->setText( tr( "&Play" ) );
1183
TomahawkWindow::audioStopped()
1186
ActionCollection::instance()->getAction( "stop" )->setEnabled( false );
1188
m_currentTrack = result_ptr();
1189
setWindowTitle( m_windowTitle );
1194
TomahawkWindow::onPlaybackLoading( const Tomahawk::result_ptr& result )
1196
m_currentTrack = result;
1197
setWindowTitle( m_windowTitle );
1202
TomahawkWindow::onAccountError()
1205
// onAccountDisconnected();
1207
// TODO real error message from plugin kthxbbq
1208
QMessageBox::warning( this,
1209
tr( "Authentication Error" ),
1210
tr( "Error connecting to SIP: Authentication failed!" ),
1216
TomahawkWindow::setWindowTitle( const QString& title )
1218
m_windowTitle = title;
1220
if ( m_currentTrack.isNull() )
1221
QMainWindow::setWindowTitle( title );
1224
QString s = tr( "%1 by %2", "track, artist name" ).arg( m_currentTrack->track(), m_currentTrack->artist()->name() );
1225
QMainWindow::setWindowTitle( tr( "%1 - %2", "current track, some window title" ).arg( s, title ) );
1231
TomahawkWindow::showAboutTomahawk()
1236
head = tr( "<h2><b>Tomahawk %1<br/>(%2)</h2>" )
1237
.arg( TomahawkUtils::appFriendlyVersion() )
1238
.arg( qApp->applicationVersion() );
1240
head = tr( "<h2><b>Tomahawk %1</h2>" )
1241
.arg( TomahawkUtils::appFriendlyVersion() );
1244
const QString copyright( tr( "Copyright 2010 - 2013" ) );
1245
const QString thanksto( tr( "Thanks to:" ) );
1247
desc = QString( "%1<br/>Christian Muehlhaeuser <muesli@tomahawk-player.org><br/><br/>"
1248
"%2 Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindström, Syd Lawrence, Michael Zanetti, Teo Mrnjavac, Christopher Reichert, Harald Sitter" )
1252
QMessageBox::about( this, tr( "About Tomahawk" ), head + desc );
1257
TomahawkWindow::checkForUpdates()
1260
Tomahawk::checkForUpdates();
1266
TomahawkWindow::onSearch( const QString& search )
1268
if ( !search.trimmed().isEmpty() )
1269
ViewManager::instance()->show( new SearchWidget( search, this ) );
1274
TomahawkWindow::onFilterEdited()
1276
onSearch( m_searchWidget->text() );
1277
m_searchWidget->clear();
1282
TomahawkWindow::showQueue()
1284
if ( QThread::currentThread() != thread() )
1286
qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
1287
QMetaObject::invokeMethod( this, "showQueue", Qt::QueuedConnection );
1291
m_queueView->show();
1296
TomahawkWindow::hideQueue()
1298
if ( QThread::currentThread() != thread() )
1300
qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
1301
QMetaObject::invokeMethod( this, "hideQueue", Qt::QueuedConnection );
1305
m_queueView->hide();
1310
TomahawkWindow::minimize()
1312
if ( isMinimized() )
1324
TomahawkWindow::maximize()
1326
if ( isMaximized() )
1338
TomahawkWindow::toggleFullscreen()
1340
tDebug() << Q_FUNC_INFO;
1342
#if defined( Q_WS_MAC )
1343
Tomahawk::toggleFullscreen();
1349
TomahawkWindow::crashNow()
1351
TomahawkUtils::crash();
1356
TomahawkWindow::toggleMenuBar() //SLOT
1359
if ( menuBar()->isVisible() )
1361
menuBar()->setVisible( false );
1362
ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( tr( "Show Menu Bar" ) );
1363
m_compactMenuAction->setVisible( true );
1367
m_compactMenuAction->setVisible( false );
1368
ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( tr( "Hide Menu Bar" ) );
1369
menuBar()->setVisible( true );
1378
TomahawkWindow::audioControls()
1380
return m_audioControls;
1385
TomahawkWindow::sourceTreeView() const
1387
return m_sourcetree;