/src/tomahawkwindow.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 1346 lines · 1049 code · 237 blank · 60 comment · 77 complexity · 60eb4ffa9d58b54ca70a52ffa77b94b2 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  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>
  7. *
  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.
  12. *
  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.
  17. *
  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/>.
  20. */
  21. #include "TomahawkWindow.h"
  22. #include "ui_TomahawkWindow.h"
  23. #include "accounts/AccountManager.h"
  24. #include "sourcetree/SourceTreeView.h"
  25. #include "network/Servent.h"
  26. #include "utils/TomahawkUtilsGui.h"
  27. #include "utils/ProxyStyle.h"
  28. #include "utils/WidgetDragFilter.h"
  29. #include "widgets/AccountsToolButton.h"
  30. #include "widgets/AnimatedSplitter.h"
  31. #include "widgets/NewPlaylistWidget.h"
  32. #include "widgets/SearchWidget.h"
  33. #include "widgets/PlaylistTypeSelectorDialog.h"
  34. #include "thirdparty/Qocoa/qsearchfield.h"
  35. #include "playlist/dynamic/GeneratorInterface.h"
  36. #include "playlist/PlaylistModel.h"
  37. #include "playlist/PlaylistView.h"
  38. #include "playlist/QueueView.h"
  39. #include "jobview/JobStatusView.h"
  40. #include "jobview/JobStatusModel.h"
  41. #include "jobview/ErrorStatusMessage.h"
  42. #include "jobview/JobStatusModel.h"
  43. #include "sip/SipPlugin.h"
  44. #include "Playlist.h"
  45. #include "Query.h"
  46. #include "Artist.h"
  47. #include "ViewManager.h"
  48. #include "ActionCollection.h"
  49. #include "AudioControls.h"
  50. #include "SettingsDialog.h"
  51. #include "DiagnosticsDialog.h"
  52. #include "TomahawkSettings.h"
  53. #include "SourceList.h"
  54. #include "TomahawkTrayIcon.h"
  55. #include "libtomahawk/filemetadata/ScanManager.h"
  56. #include "TomahawkApp.h"
  57. #include "LoadXSPFDialog.h"
  58. #include "widgets/ContainedMenuButton.h"
  59. #include "utils/Logger.h"
  60. #include "config.h"
  61. #include <QAction>
  62. #include <QCloseEvent>
  63. #include <QDesktopServices>
  64. #include <QShowEvent>
  65. #include <QHideEvent>
  66. #include <QInputDialog>
  67. #include <QPixmap>
  68. #include <QPropertyAnimation>
  69. #include <QLineEdit>
  70. #include <QMessageBox>
  71. #include <QNetworkAccessManager>
  72. #include <QNetworkReply>
  73. #include <QTimer>
  74. #include <QToolBar>
  75. #include <QToolButton>
  76. #if defined( Q_WS_WIN )
  77. #if defined ( WITH_QtSparkle )
  78. #include <qtsparkle/Updater>
  79. #endif
  80. #ifndef THBN_CLICKED
  81. #define THBN_CLICKED 0x1800
  82. #endif
  83. #endif
  84. using namespace Tomahawk;
  85. using namespace Accounts;
  86. TomahawkWindow::TomahawkWindow( QWidget* parent )
  87. : QMainWindow( parent )
  88. #ifdef Q_OS_WIN
  89. , m_buttonCreatedID( RegisterWindowMessage( L"TaskbarButtonCreated" ) )
  90. #ifdef HAVE_THUMBBUTTON
  91. , m_taskbarList( 0 )
  92. #endif
  93. #endif
  94. , ui( new Ui::TomahawkWindow )
  95. , m_searchWidget( 0 )
  96. , m_audioControls( new AudioControls( this ) )
  97. , m_trayIcon( new TomahawkTrayIcon( this ) )
  98. , m_settingsDialog( 0 )
  99. , m_audioRetryCounter( 0 )
  100. {
  101. setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
  102. ViewManager* vm = new ViewManager( this );
  103. connect( vm, SIGNAL( showQueueRequested() ), SLOT( showQueue() ) );
  104. connect( vm, SIGNAL( hideQueueRequested() ), SLOT( hideQueue() ) );
  105. connect( APP, SIGNAL( tomahawkLoaded() ), vm, SLOT( setTomahawkLoaded() ) ); // Pass loaded signal into libtomahawk so components in there can connect to ViewManager
  106. #ifdef Q_OS_WIN
  107. connect( AudioEngine::instance(), SIGNAL( stateChanged( AudioState, AudioState) ), SLOT( audioStateChanged( AudioState, AudioState) ) );
  108. #endif
  109. ui->setupUi( this );
  110. applyPlatformTweaks();
  111. ui->centralWidget->setContentsMargins( 0, 0, 0, 0 );
  112. TomahawkUtils::unmarginLayout( ui->centralWidget->layout() );
  113. setupMenuBar();
  114. setupToolBar();
  115. setupSideBar();
  116. statusBar()->addPermanentWidget( m_audioControls, 1 );
  117. setupUpdateCheck();
  118. loadSettings();
  119. setupSignals();
  120. if ( qApp->arguments().contains( "--debug" ) )
  121. {
  122. connect( ActionCollection::instance()->getAction( "crashNow" ), SIGNAL( triggered() ),
  123. this, SLOT( crashNow() ) );
  124. }
  125. // set initial state
  126. audioStopped();
  127. vm->setQueue( m_queueView );
  128. vm->showWelcomePage();
  129. }
  130. TomahawkWindow::~TomahawkWindow()
  131. {
  132. saveSettings();
  133. delete ui;
  134. }
  135. void
  136. TomahawkWindow::loadSettings()
  137. {
  138. TomahawkSettings* s = TomahawkSettings::instance();
  139. // Workaround for broken window geometry restoring on Qt Cocoa when setUnifiedTitleAndToolBarOnMac is true.
  140. // See http://bugreports.qt.nokia.com/browse/QTBUG-3116 and
  141. // http://lists.qt.nokia.com/pipermail/qt-interest/2009-August/011491.html
  142. // for the 'fix'
  143. #ifdef QT_MAC_USE_COCOA
  144. bool workaround = isVisible();
  145. if ( workaround )
  146. {
  147. // make "invisible"
  148. setWindowOpacity( 0 );
  149. // let Qt update its frameStruts
  150. show();
  151. }
  152. #endif
  153. if ( !s->mainWindowGeometry().isEmpty() )
  154. restoreGeometry( s->mainWindowGeometry() );
  155. if ( !s->mainWindowState().isEmpty() )
  156. restoreState( s->mainWindowState() );
  157. if ( !s->mainWindowSplitterState().isEmpty() )
  158. ui->splitter->restoreState( s->mainWindowSplitterState() );
  159. // Always set stretch factor. If user hasn't manually set splitter sizes,
  160. // this will ensure a sane default on all startups. If the user has, the manual
  161. // size will override the default stretching
  162. ui->splitter->setStretchFactor( 0, 0 );
  163. ui->splitter->setStretchFactor( 1, 1 );
  164. #ifdef QT_MAC_USE_COCOA
  165. if ( workaround )
  166. {
  167. // Make it visible again
  168. setWindowOpacity( 1 );
  169. }
  170. #endif
  171. #ifndef Q_OS_MAC
  172. bool mbVisible = s->menuBarVisible();
  173. menuBar()->setVisible( mbVisible );
  174. m_compactMenuAction->setVisible( !mbVisible );
  175. ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( mbVisible ? tr( "Hide Menu Bar" ) : tr( "Show Menu Bar" ) );
  176. #endif
  177. }
  178. void
  179. TomahawkWindow::saveSettings()
  180. {
  181. TomahawkSettings* s = TomahawkSettings::instance();
  182. s->setMainWindowGeometry( saveGeometry() );
  183. s->setMainWindowState( saveState() );
  184. s->setMainWindowSplitterState( ui->splitter->saveState() );
  185. s->setMenuBarVisible( menuBar()->isVisible() );
  186. }
  187. void
  188. TomahawkWindow::applyPlatformTweaks()
  189. {
  190. // HACK: QtCurve causes an infinite loop on startup. This is because
  191. // setStyle calls setPalette, which calls ensureBaseStyle, which loads
  192. // QtCurve. QtCurve calls setPalette, which creates an infinite loop.
  193. // We could simply not use ProxyStyle under QtCurve, but that would
  194. // make the whole UI look like crap.
  195. // Instead, we tell ProxyStyle that it's running under QtCurve, so it
  196. // can intercept QStyle::polish (which in the base implementation does
  197. // nothing and in QtCurve does evil things), and avoid forwarding it
  198. // to QtCurve.
  199. bool isQtCurve = false;
  200. if( QString( qApp->style()->metaObject()->className() ).toLower().contains( "qtcurve" ) )
  201. isQtCurve = true;
  202. qApp->setStyle( new ProxyStyle( isQtCurve ) );
  203. #ifdef Q_OS_MAC
  204. setUnifiedTitleAndToolBarOnMac( true );
  205. delete ui->hline1;
  206. delete ui->hline2;
  207. #else
  208. ui->hline1->setStyleSheet( "border: 1px solid gray;" );
  209. ui->hline2->setStyleSheet( "border: 1px solid gray;" );
  210. #endif
  211. }
  212. void
  213. TomahawkWindow::setupToolBar()
  214. {
  215. m_toolbar = addToolBar( "TomahawkToolbar" );
  216. m_toolbar->setObjectName( "TomahawkToolbar" );
  217. m_toolbar->setMovable( false );
  218. m_toolbar->setFloatable( false );
  219. m_toolbar->setIconSize( QSize( 22, 22 ) );
  220. m_toolbar->setToolButtonStyle( Qt::ToolButtonIconOnly );
  221. m_toolbar->setStyleSheet( "border-bottom: 0px" );
  222. // If the toolbar is hidden accidentally it causes trouble on Unity because the user can't
  223. // easily bring it back (TWK-1046). So we just prevent the user from hiding the toolbar.
  224. // This should not affect Mac users.
  225. m_toolbar->setContextMenuPolicy( Qt::PreventContextMenu );
  226. #ifdef Q_OS_MAC
  227. m_toolbar->installEventFilter( new WidgetDragFilter( m_toolbar ) );
  228. #endif
  229. m_backAction = m_toolbar->addAction( QIcon( RESPATH "images/back.png" ), tr( "Back" ), ViewManager::instance(), SLOT( historyBack() ) );
  230. m_backAction->setToolTip( tr( "Go back one page" ) );
  231. m_forwardAction = m_toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) );
  232. m_forwardAction->setToolTip( tr( "Go forward one page" ) );
  233. m_toolbarLeftBalancer = new QWidget( this );
  234. m_toolbarLeftBalancer->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
  235. m_toolbarLeftBalancer->setFixedWidth( 0 );
  236. m_toolbar->addWidget( m_toolbarLeftBalancer )->setProperty( "kind", QString( "spacer" ) );
  237. QWidget* toolbarLeftSpacer = new QWidget( this );
  238. toolbarLeftSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
  239. m_toolbar->addWidget( toolbarLeftSpacer )->setProperty( "kind", QString( "spacer" ) );
  240. m_searchWidget = new QSearchField( this );
  241. m_searchWidget->setPlaceholderText( tr( "Global Search..." ) );
  242. m_searchWidget->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
  243. m_searchWidget->setFixedWidth( 340 );
  244. connect( m_searchWidget, SIGNAL( returnPressed() ), this, SLOT( onFilterEdited() ) );
  245. m_toolbar->addWidget( m_searchWidget )->setProperty( "kind", QString( "search" ) );
  246. QWidget* rightSpacer = new QWidget( this );
  247. rightSpacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
  248. m_toolbar->addWidget( rightSpacer )->setProperty( "kind", QString( "spacer" ) );
  249. m_toolbarRightBalancer = new QWidget( this );
  250. m_toolbarRightBalancer->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Preferred );
  251. m_toolbarRightBalancer->setFixedWidth( 0 );
  252. m_toolbar->addWidget( m_toolbarRightBalancer )->setProperty( "kind", QString( "spacer" ) );
  253. m_accountsButton = new AccountsToolButton( m_toolbar );
  254. m_toolbar->addWidget( m_accountsButton );
  255. connect( m_accountsButton, SIGNAL( widthChanged() ),
  256. this, SLOT( balanceToolbar() ) );
  257. #ifndef Q_OS_MAC
  258. ContainedMenuButton* compactMenuButton = new ContainedMenuButton( m_toolbar );
  259. compactMenuButton->setIcon( QIcon( RESPATH "images/configure.png" ) );
  260. compactMenuButton->setText( tr( "&Main Menu" ) );
  261. compactMenuButton->setMenu( m_compactMainMenu );
  262. compactMenuButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
  263. m_compactMenuAction = m_toolbar->addWidget( compactMenuButton );
  264. //HACK: adding the toggle action to the window, otherwise the shortcut keys
  265. // won't be picked up when the menu is hidden.
  266. // This must be done for all menu bar actions that have shortcut keys :(
  267. // Does not apply to Mac which always shows the menu bar.
  268. addAction( ActionCollection::instance()->getAction( "playPause" ) );
  269. addAction( ActionCollection::instance()->getAction( "toggleMenuBar" ) );
  270. addAction( ActionCollection::instance()->getAction( "quit" ) );
  271. #endif
  272. balanceToolbar();
  273. }
  274. void
  275. TomahawkWindow::balanceToolbar()
  276. {
  277. int leftActionsWidth = 0;
  278. int rightActionsWidth = 0;
  279. bool flip = false;
  280. foreach ( QAction* action, m_toolbar->actions() )
  281. {
  282. if ( action->property( "kind" ) == QString( "spacer" ) ||
  283. !action->isVisible() )
  284. continue;
  285. else if ( action->property( "kind" ) == QString( "search" ) )
  286. {
  287. flip = true;
  288. continue;
  289. }
  290. QWidget* widget = m_toolbar->widgetForAction( action );
  291. if ( !flip ) //we accumulate on the left
  292. {
  293. leftActionsWidth += widget->sizeHint().width()
  294. + m_toolbar->layout()->spacing();
  295. }
  296. else //then, on the right
  297. {
  298. rightActionsWidth += widget->sizeHint().width()
  299. + m_toolbar->layout()->spacing();
  300. }
  301. }
  302. if ( leftActionsWidth > rightActionsWidth )
  303. {
  304. m_toolbarLeftBalancer->setFixedWidth( 0 );
  305. m_toolbarRightBalancer->setFixedWidth( leftActionsWidth - rightActionsWidth );
  306. }
  307. else
  308. {
  309. m_toolbarLeftBalancer->setFixedWidth( rightActionsWidth - leftActionsWidth );
  310. m_toolbarRightBalancer->setFixedWidth( 0 );
  311. }
  312. }
  313. void
  314. TomahawkWindow::setupSideBar()
  315. {
  316. // Delete fake designer widgets
  317. delete ui->sidebarWidget;
  318. delete ui->playlistWidget;
  319. QWidget* sidebarWidget = new QWidget();
  320. sidebarWidget->setLayout( new QVBoxLayout() );
  321. m_sidebar = new AnimatedSplitter();
  322. m_sidebar->setOrientation( Qt::Vertical );
  323. m_sidebar->setChildrenCollapsible( false );
  324. m_sourcetree = new SourceTreeView( this );
  325. JobStatusView* jobsView = new JobStatusView( m_sidebar );
  326. JobStatusModel* sourceModel = new JobStatusModel( jobsView );
  327. m_jobsModel = new JobStatusSortModel( jobsView );
  328. m_jobsModel->setJobModel( sourceModel );
  329. jobsView->setModel( m_jobsModel );
  330. m_queueView = new QueueView( m_sidebar );
  331. AudioEngine::instance()->setQueue( m_queueView->queue()->proxyModel()->playlistInterface() );
  332. m_sidebar->addWidget( m_sourcetree );
  333. m_sidebar->addWidget( jobsView );
  334. m_sidebar->addWidget( m_queueView );
  335. // m_sidebar->setGreedyWidget( 1 );
  336. m_sidebar->hide( 1, false );
  337. m_sidebar->hide( 2, false );
  338. m_sidebar->hide( 3, false );
  339. sidebarWidget->layout()->addWidget( m_sidebar );
  340. sidebarWidget->setContentsMargins( 0, 0, 0, 0 );
  341. sidebarWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
  342. sidebarWidget->layout()->setMargin( 0 );
  343. #ifndef Q_OS_MAC
  344. sidebarWidget->layout()->setSpacing( 0 );
  345. #endif
  346. ui->splitter->addWidget( sidebarWidget );
  347. ui->splitter->addWidget( ViewManager::instance()->widget() );
  348. ui->splitter->setCollapsible( 1, false );
  349. ActionCollection::instance()->getAction( "showOfflineSources" )
  350. ->setChecked( TomahawkSettings::instance()->showOfflineSources() );
  351. }
  352. void
  353. TomahawkWindow::setupUpdateCheck()
  354. {
  355. #if defined( Q_OS_MAC ) && defined( HAVE_SPARKLE )
  356. connect( ActionCollection::instance()->getAction( "checkForUpdates" ), SIGNAL( triggered( bool ) ),
  357. SLOT( checkForUpdates() ) );
  358. #elif defined( Q_WS_WIN ) && defined( WITH_QtSparkle )
  359. QUrl updaterUrl;
  360. if ( qApp->arguments().contains( "--debug" ) )
  361. updaterUrl.setUrl( "http://download.tomahawk-player.org/sparklewin-debug" );
  362. else
  363. updaterUrl.setUrl( "http://download.tomahawk-player.org/sparklewin" );
  364. qtsparkle::Updater* updater = new qtsparkle::Updater( updaterUrl, this );
  365. Q_ASSERT( TomahawkUtils::nam() != 0 );
  366. updater->SetNetworkAccessManager( TomahawkUtils::nam() );
  367. updater->SetVersion( TomahawkUtils::appFriendlyVersion() );
  368. connect( ActionCollection::instance()->getAction( "checkForUpdates" ), SIGNAL( triggered() ),
  369. updater, SLOT( CheckNow() ) );
  370. #endif
  371. }
  372. #ifdef Q_OS_WIN
  373. bool
  374. TomahawkWindow::setupWindowsButtons()
  375. {
  376. #ifdef HAVE_THUMBBUTTON
  377. const GUID IID_ITaskbarList3 = { 0xea1afb91,0x9e28,0x4b86, { 0x90,0xe9,0x9e,0x9f,0x8a,0x5e,0xef,0xaf } };
  378. HRESULT hr = S_OK;
  379. QPixmap play( RESPATH "images/play-rest.png" );
  380. QPixmap back( RESPATH "images/back-rest.png" );
  381. QPixmap love( RESPATH "images/not-loved.png" );
  382. QTransform transform;
  383. transform.rotate( 180 );
  384. QPixmap next( back.transformed( transform ) );
  385. THUMBBUTTONMASK dwMask = THUMBBUTTONMASK( THB_ICON | THB_TOOLTIP | THB_FLAGS );
  386. m_thumbButtons[TP_PREVIOUS].dwMask = dwMask;
  387. m_thumbButtons[TP_PREVIOUS].iId = TP_PREVIOUS;
  388. m_thumbButtons[TP_PREVIOUS].hIcon = back.toWinHICON();
  389. m_thumbButtons[TP_PREVIOUS].dwFlags = THBF_ENABLED;
  390. m_thumbButtons[TP_PREVIOUS].szTip[ tr( "Back" ).toWCharArray( m_thumbButtons[TP_PREVIOUS].szTip ) ] = 0;
  391. m_thumbButtons[TP_PLAY_PAUSE].dwMask = dwMask;
  392. m_thumbButtons[TP_PLAY_PAUSE].iId = TP_PLAY_PAUSE;
  393. m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
  394. m_thumbButtons[TP_PLAY_PAUSE].dwFlags = THBF_ENABLED;
  395. m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
  396. m_thumbButtons[TP_NEXT].dwMask = dwMask;
  397. m_thumbButtons[TP_NEXT].iId = TP_NEXT;
  398. m_thumbButtons[TP_NEXT].hIcon = next.toWinHICON();
  399. m_thumbButtons[TP_NEXT].dwFlags = THBF_ENABLED;
  400. m_thumbButtons[TP_NEXT].szTip[ tr( "Next" ).toWCharArray( m_thumbButtons[TP_NEXT].szTip ) ] = 0;
  401. m_thumbButtons[3].dwMask = dwMask;
  402. m_thumbButtons[3].iId = -1;
  403. m_thumbButtons[3].hIcon = 0;
  404. m_thumbButtons[3].dwFlags = THBF_NOBACKGROUND | THBF_DISABLED;
  405. m_thumbButtons[3].szTip[0] = 0;
  406. m_thumbButtons[TP_LOVE].dwMask = dwMask;
  407. m_thumbButtons[TP_LOVE].iId = TP_LOVE;
  408. m_thumbButtons[TP_LOVE].hIcon = love.toWinHICON();
  409. m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
  410. m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
  411. if ( S_OK == CoCreateInstance( CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void **)&m_taskbarList ) )
  412. {
  413. hr = m_taskbarList->HrInit();
  414. if ( SUCCEEDED( hr ) )
  415. {
  416. hr = m_taskbarList->ThumbBarAddButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
  417. }
  418. else
  419. {
  420. m_taskbarList->Release();
  421. m_taskbarList = 0;
  422. }
  423. }
  424. return SUCCEEDED( hr );
  425. #else // HAVE_THUMBBUTTON
  426. return false;
  427. #endif
  428. }
  429. #endif
  430. void
  431. TomahawkWindow::setupSignals()
  432. {
  433. // <From PlaylistManager>
  434. connect( ViewManager::instance(), SIGNAL( repeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ),
  435. m_audioControls, SLOT( onRepeatModeChanged( Tomahawk::PlaylistModes::RepeatMode ) ) );
  436. connect( ViewManager::instance(), SIGNAL( shuffleModeChanged( bool ) ),
  437. m_audioControls, SLOT( onShuffleModeChanged( bool ) ) );
  438. // <From AudioEngine>
  439. connect( AudioEngine::instance(), SIGNAL( error( AudioEngine::AudioErrorCode ) ), SLOT( onAudioEngineError( AudioEngine::AudioErrorCode ) ) );
  440. connect( AudioEngine::instance(), SIGNAL( loading( const Tomahawk::result_ptr& ) ), SLOT( onPlaybackLoading( const Tomahawk::result_ptr& ) ) );
  441. connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( audioStarted() ) );
  442. connect( AudioEngine::instance(), SIGNAL( finished(Tomahawk::result_ptr) ), SLOT( audioFinished() ) );
  443. connect( AudioEngine::instance(), SIGNAL( resumed()), SLOT( audioStarted() ) );
  444. connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( audioPaused() ) );
  445. connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( audioStopped() ) );
  446. // <Menu Items>
  447. ActionCollection *ac = ActionCollection::instance();
  448. // connect( ui->actionAddPeerManually, SIGNAL( triggered() ), SLOT( addPeerManually() ) );
  449. connect( ac->getAction( "preferences" ), SIGNAL( triggered() ), SLOT( showSettingsDialog() ) );
  450. connect( ac->getAction( "diagnostics" ), SIGNAL( triggered() ), SLOT( showDiagnosticsDialog() ) );
  451. connect( ac->getAction( "legalInfo" ), SIGNAL( triggered() ), SLOT( legalInfo() ) );
  452. connect( ac->getAction( "updateCollection" ), SIGNAL( triggered() ), SLOT( updateCollectionManually() ) );
  453. connect( ac->getAction( "rescanCollection" ), SIGNAL( triggered() ), SLOT( rescanCollectionManually() ) );
  454. connect( ac->getAction( "loadXSPF" ), SIGNAL( triggered() ), SLOT( loadSpiff() ));
  455. connect( ac->getAction( "aboutTomahawk" ), SIGNAL( triggered() ), SLOT( showAboutTomahawk() ) );
  456. connect( ac->getAction( "quit" ), SIGNAL( triggered() ), qApp, SLOT( quit() ) );
  457. connect( ac->getAction( "showOfflineSources" ), SIGNAL( triggered() ), SLOT( showOfflineSources() ) );
  458. #if defined( Q_OS_MAC )
  459. connect( ac->getAction( "minimize" ), SIGNAL( triggered() ), SLOT( minimize() ) );
  460. connect( ac->getAction( "zoom" ), SIGNAL( triggered() ), SLOT( maximize() ) );
  461. #else
  462. connect( ac->getAction( "toggleMenuBar" ), SIGNAL( triggered() ), SLOT( toggleMenuBar() ) );
  463. #endif
  464. // <AccountHandler>
  465. connect( AccountManager::instance(), SIGNAL( authError( Tomahawk::Accounts::Account* ) ), SLOT( onAccountError() ) );
  466. connect( ViewManager::instance(), SIGNAL( historyBackAvailable( bool ) ), SLOT( onHistoryBackAvailable( bool ) ) );
  467. connect( ViewManager::instance(), SIGNAL( historyForwardAvailable( bool ) ), SLOT( onHistoryForwardAvailable( bool ) ) );
  468. }
  469. void
  470. TomahawkWindow::setupMenuBar()
  471. {
  472. // Always create a menubar, but only create a compactMenu on Windows and X11
  473. m_menuBar = ActionCollection::instance()->createMenuBar( this );
  474. setMenuBar( m_menuBar );
  475. #ifndef Q_OS_MAC
  476. m_compactMainMenu = ActionCollection::instance()->createCompactMenu( this );
  477. #endif
  478. }
  479. void
  480. TomahawkWindow::changeEvent( QEvent* e )
  481. {
  482. QMainWindow::changeEvent( e );
  483. switch ( e->type() )
  484. {
  485. case QEvent::LanguageChange:
  486. ui->retranslateUi( this );
  487. break;
  488. default:
  489. break;
  490. }
  491. }
  492. void
  493. TomahawkWindow::closeEvent( QCloseEvent* e )
  494. {
  495. #ifndef Q_OS_MAC
  496. if ( e->spontaneous() && QSystemTrayIcon::isSystemTrayAvailable() )
  497. {
  498. hide();
  499. e->ignore();
  500. return;
  501. }
  502. #else
  503. m_trayIcon->setShowHideWindow( false );
  504. #endif
  505. e->accept();
  506. }
  507. void
  508. TomahawkWindow::showEvent( QShowEvent* e )
  509. {
  510. QMainWindow::showEvent( e );
  511. #if defined( Q_OS_MAC )
  512. ActionCollection::instance()->getAction( "minimize" )->setDisabled( false );
  513. ActionCollection::instance()->getAction( "zoom" )->setDisabled( false );
  514. #endif
  515. }
  516. void
  517. TomahawkWindow::hideEvent( QHideEvent* e )
  518. {
  519. QMainWindow::hideEvent( e );
  520. #if defined( Q_OS_MAC )
  521. ActionCollection::instance()->getAction( "minimize" )->setDisabled( true );
  522. ActionCollection::instance()->getAction( "zoom" )->setDisabled( true );
  523. #endif
  524. }
  525. void
  526. TomahawkWindow::keyPressEvent( QKeyEvent* e )
  527. {
  528. bool accept = true;
  529. #if ! defined ( Q_OS_MAC )
  530. #define KEY_PRESSED Q_FUNC_INFO << "Multimedia Key Pressed:"
  531. switch( e->key() )
  532. {
  533. case Qt::Key_MediaPlay:
  534. tLog() << KEY_PRESSED << "Play";
  535. AudioEngine::instance()->playPause();
  536. break;
  537. case Qt::Key_MediaStop:
  538. tLog() << KEY_PRESSED << "Stop";
  539. AudioEngine::instance()->stop();
  540. break;
  541. case Qt::Key_MediaPrevious:
  542. tLog() << KEY_PRESSED << "Previous";
  543. AudioEngine::instance()->previous();
  544. break;
  545. case Qt::Key_MediaNext:
  546. tLog() << KEY_PRESSED << "Next";
  547. AudioEngine::instance()->next();
  548. break;
  549. case Qt::Key_MediaPause:
  550. tLog() << KEY_PRESSED << "Pause";
  551. AudioEngine::instance()->pause();
  552. break;
  553. case Qt::Key_MediaTogglePlayPause:
  554. tLog() << KEY_PRESSED << "PlayPause";
  555. AudioEngine::instance()->playPause();
  556. break;
  557. case Qt::Key_MediaRecord:
  558. default:
  559. accept = false;
  560. }
  561. #else
  562. accept = false;
  563. #endif
  564. if ( accept )
  565. e->accept();
  566. QMainWindow::keyPressEvent( e );
  567. }
  568. #ifdef Q_OS_WIN
  569. bool
  570. TomahawkWindow::winEvent( MSG* msg, long* result )
  571. {
  572. #define TB_PRESSED Q_FUNC_INFO << "Taskbar Button Pressed:"
  573. switch( msg->message )
  574. {
  575. case WM_COMMAND:
  576. if ( HIWORD( msg->wParam ) == THBN_CLICKED )
  577. {
  578. switch( TB_STATES(LOWORD( msg->wParam )) )
  579. {
  580. case TP_PREVIOUS:
  581. tLog() << TB_PRESSED << "Previous";
  582. AudioEngine::instance()->previous();
  583. break;
  584. case TP_PLAY_PAUSE:
  585. tLog() << TB_PRESSED << "Play/Pause";
  586. AudioEngine::instance()->playPause();
  587. break;
  588. case TP_NEXT:
  589. tLog() << TB_PRESSED << "Next";
  590. AudioEngine::instance()->next();
  591. break;
  592. case TP_LOVE:
  593. tLog() << TB_PRESSED << "Love";
  594. if ( !AudioEngine::instance()->currentTrack().isNull() )
  595. {
  596. AudioEngine::instance()->currentTrack()->toQuery()->setLoved( !AudioEngine::instance()->currentTrack()->toQuery()->loved() );
  597. updateWindowsLoveButton();
  598. }
  599. break;
  600. }
  601. return true;
  602. }
  603. break;
  604. }
  605. if ( msg->message == m_buttonCreatedID )
  606. return setupWindowsButtons();
  607. return false;
  608. }
  609. void
  610. TomahawkWindow::audioStateChanged( AudioState newState, AudioState oldState )
  611. {
  612. #ifdef HAVE_THUMBBUTTON
  613. if ( m_taskbarList == 0 )
  614. return;
  615. switch ( newState )
  616. {
  617. case AudioEngine::Playing:
  618. {
  619. QPixmap pause( RESPATH "images/pause-rest.png" );
  620. m_thumbButtons[TP_PLAY_PAUSE].hIcon = pause.toWinHICON();
  621. m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Pause" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
  622. updateWindowsLoveButton();
  623. }
  624. break;
  625. case AudioEngine::Paused:
  626. {
  627. QPixmap play( RESPATH "images/play-rest.png" );
  628. m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
  629. m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
  630. }
  631. break;
  632. case AudioEngine::Stopped:
  633. {
  634. if ( !AudioEngine::instance()->currentTrack().isNull() )
  635. {
  636. disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
  637. }
  638. QPixmap play( RESPATH "images/play-rest.png" );
  639. m_thumbButtons[TP_PLAY_PAUSE].hIcon = play.toWinHICON();
  640. m_thumbButtons[TP_PLAY_PAUSE].szTip[ tr( "Play" ).toWCharArray( m_thumbButtons[TP_PLAY_PAUSE].szTip ) ] = 0;
  641. QPixmap not_loved( RESPATH "images/not-loved.png" );
  642. m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
  643. m_thumbButtons[TP_LOVE].dwFlags = THBF_DISABLED;
  644. }
  645. break;
  646. default:
  647. return;
  648. }
  649. m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
  650. #endif // HAVE_THUMBBUTTON
  651. }
  652. void
  653. TomahawkWindow::updateWindowsLoveButton()
  654. {
  655. #ifdef HAVE_THUMBBUTTON
  656. if ( !AudioEngine::instance()->currentTrack().isNull() && AudioEngine::instance()->currentTrack()->toQuery()->loved() )
  657. {
  658. QPixmap loved( RESPATH "images/loved.png" );
  659. m_thumbButtons[TP_LOVE].hIcon = loved.toWinHICON();
  660. m_thumbButtons[TP_LOVE].szTip[ tr( "Unlove" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
  661. }
  662. else
  663. {
  664. QPixmap not_loved( RESPATH "images/not-loved.png" );
  665. m_thumbButtons[TP_LOVE].hIcon = not_loved.toWinHICON();
  666. m_thumbButtons[TP_LOVE].szTip[ tr( "Love" ).toWCharArray( m_thumbButtons[TP_LOVE].szTip ) ] = 0;
  667. }
  668. m_thumbButtons[TP_LOVE].dwFlags = THBF_ENABLED;
  669. m_taskbarList->ThumbBarUpdateButtons( winId(), ARRAYSIZE( m_thumbButtons ), m_thumbButtons );
  670. #endif // HAVE_THUMBBUTTON
  671. }
  672. #endif
  673. void
  674. TomahawkWindow::onHistoryBackAvailable( bool avail )
  675. {
  676. m_backAction->setEnabled( avail );
  677. }
  678. void
  679. TomahawkWindow::onHistoryForwardAvailable( bool avail )
  680. {
  681. m_forwardAction->setEnabled( avail );
  682. }
  683. void
  684. TomahawkWindow::showSettingsDialog()
  685. {
  686. if ( !m_settingsDialog )
  687. m_settingsDialog = new SettingsDialog;
  688. m_settingsDialog->show();
  689. }
  690. void
  691. TomahawkWindow::showDiagnosticsDialog()
  692. {
  693. DiagnosticsDialog win;
  694. win.exec();
  695. }
  696. void
  697. TomahawkWindow::legalInfo()
  698. {
  699. QDesktopServices::openUrl( QUrl( "http://www.tomahawk-player.org/legal.html" ) );
  700. }
  701. void
  702. TomahawkWindow::updateCollectionManually()
  703. {
  704. if ( TomahawkSettings::instance()->hasScannerPaths() )
  705. ScanManager::instance()->runNormalScan();
  706. }
  707. void
  708. TomahawkWindow::rescanCollectionManually()
  709. {
  710. if ( TomahawkSettings::instance()->hasScannerPaths() )
  711. ScanManager::instance()->runFullRescan();
  712. }
  713. void
  714. TomahawkWindow::addPeerManually()
  715. {
  716. TomahawkSettings* s = TomahawkSettings::instance();
  717. bool ok;
  718. QString addr = QInputDialog::getText( this, tr( "Connect To Peer" ),
  719. tr( "Enter peer address:" ), QLineEdit::Normal,
  720. s->value( "connip" ).toString(), &ok ); // FIXME
  721. if ( !ok )
  722. return;
  723. s->setValue( "connip", addr );
  724. QString ports = QInputDialog::getText( this, tr( "Connect To Peer" ),
  725. tr( "Enter peer port:" ), QLineEdit::Normal,
  726. s->value( "connport", "50210" ).toString(), &ok );
  727. if ( !ok )
  728. return;
  729. s->setValue( "connport", ports );
  730. int port = ports.toInt();
  731. QString key = QInputDialog::getText( this, tr( "Connect To Peer" ),
  732. tr( "Enter peer key:" ), QLineEdit::Normal,
  733. "whitelist", &ok );
  734. if ( !ok )
  735. return;
  736. qDebug() << "Attempting to connect to" << addr;
  737. Servent::instance()->connectToPeer( addr, port, key );
  738. }
  739. void
  740. TomahawkWindow::showOfflineSources()
  741. {
  742. m_sourcetree->showOfflineSources( ActionCollection::instance()
  743. ->getAction( "showOfflineSources" )->isChecked() );
  744. TomahawkSettings::instance()->setShowOfflineSources( ActionCollection::instance()
  745. ->getAction( "showOfflineSources" )->isChecked() );
  746. }
  747. void
  748. TomahawkWindow::fullScreenEntered()
  749. {
  750. statusBar()->setSizeGripEnabled( false );
  751. }
  752. void
  753. TomahawkWindow::fullScreenExited()
  754. {
  755. statusBar()->setSizeGripEnabled( true );
  756. }
  757. void
  758. TomahawkWindow::loadSpiff()
  759. {
  760. LoadXSPFDialog* diag = new LoadXSPFDialog( this, Qt::Sheet );
  761. #ifdef Q_OS_MAC
  762. connect( diag, SIGNAL( finished( int ) ), this, SLOT( loadXspfFinished( int ) ) );
  763. diag->show();
  764. #else
  765. QWeakPointer< LoadXSPFDialog > safe( diag );
  766. int ret = diag->exec();
  767. if ( !safe.isNull() && ret == QDialog::Accepted )
  768. {
  769. QUrl url = QUrl::fromUserInput( safe.data()->xspfUrl() );
  770. bool autoUpdate = safe.data()->autoUpdate();
  771. XSPFLoader* loader = new XSPFLoader( true, autoUpdate );
  772. connect( loader, SIGNAL( error( XSPFLoader::XSPFErrorCode ) ), SLOT( onXSPFError( XSPFLoader::XSPFErrorCode ) ) );
  773. connect( loader, SIGNAL( ok( Tomahawk::playlist_ptr ) ), SLOT( onXSPFOk( Tomahawk::playlist_ptr ) ) );
  774. loader->load( url );
  775. }
  776. #endif
  777. }
  778. void
  779. TomahawkWindow::loadXspfFinished( int ret )
  780. {
  781. LoadXSPFDialog* d = qobject_cast< LoadXSPFDialog* >( sender() );
  782. Q_ASSERT( d );
  783. if ( ret == QDialog::Accepted )
  784. {
  785. QUrl url = QUrl::fromUserInput( d->xspfUrl() );
  786. bool autoUpdate = d->autoUpdate();
  787. XSPFLoader* loader = new XSPFLoader( true, autoUpdate );
  788. connect( loader, SIGNAL( error( XSPFLoader::XSPFErrorCode ) ), SLOT( onXSPFError( XSPFLoader::XSPFErrorCode ) ) );
  789. connect( loader, SIGNAL( ok( Tomahawk::playlist_ptr ) ), SLOT( onXSPFOk( Tomahawk::playlist_ptr ) ) );
  790. loader->load( url );
  791. }
  792. d->deleteLater();
  793. }
  794. void
  795. TomahawkWindow::onXSPFOk( const Tomahawk::playlist_ptr& pl )
  796. {
  797. ViewManager::instance()->show( pl );
  798. }
  799. void
  800. TomahawkWindow::onXSPFError( XSPFLoader::XSPFErrorCode error )
  801. {
  802. switch ( error )
  803. {
  804. case XSPFLoader::ParseError:
  805. QMessageBox::critical( this, tr( "XSPF Error" ), tr( "This is not a valid XSPF playlist." ) );
  806. break;
  807. case XSPFLoader::InvalidTrackError:
  808. 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 );
  809. break;
  810. default:
  811. //FIXME: This includes FetchError
  812. break;
  813. }
  814. }
  815. void
  816. TomahawkWindow::onAudioEngineError( AudioEngine::AudioErrorCode /* error */ )
  817. {
  818. QString msg;
  819. #ifdef Q_WS_X11
  820. 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." );
  821. #else
  822. msg = tr( "Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped." );
  823. #endif
  824. JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( msg, 15 ) );
  825. if ( m_audioRetryCounter < 3 )
  826. AudioEngine::instance()->play();
  827. m_audioRetryCounter++;
  828. }
  829. void
  830. TomahawkWindow::createAutomaticPlaylist( QString playlistName )
  831. {
  832. if ( playlistName.isEmpty() )
  833. return;
  834. source_ptr author = SourceList::instance()->getLocal();
  835. QString id = uuid();
  836. QString info = ""; // FIXME
  837. QString creator = "someone"; // FIXME
  838. dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, Static, false );
  839. playlist->setMode( Static );
  840. playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls(), playlist->entries() );
  841. ViewManager::instance()->show( playlist );
  842. }
  843. void
  844. TomahawkWindow::createStation()
  845. {
  846. QString title = tr( "Station" );
  847. bool ok;
  848. QString playlistName = QInputDialog( this, Qt::Sheet ).getText( this, tr( "Create New Station" ), tr( "Name:" ), QLineEdit::Normal, title, &ok );
  849. if ( !ok )
  850. return;
  851. if ( playlistName.isEmpty() || playlistName == title )
  852. {
  853. QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->stations();
  854. QStringList titles;
  855. foreach ( const playlist_ptr& pl, pls )
  856. titles << pl->title();
  857. playlistName = title;
  858. int i = 2;
  859. while ( titles.contains( playlistName ) )
  860. {
  861. playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
  862. }
  863. }
  864. source_ptr author = SourceList::instance()->getLocal();
  865. QString id = uuid();
  866. QString info = ""; // FIXME
  867. QString creator = "someone"; // FIXME
  868. dynplaylist_ptr playlist = DynamicPlaylist::create( author, id, playlistName, info, creator, OnDemand, false );
  869. playlist->setMode( OnDemand );
  870. playlist->createNewRevision( uuid(), playlist->currentrevision(), playlist->type(), playlist->generator()->controls() );
  871. ViewManager::instance()->show( playlist );
  872. }
  873. void
  874. TomahawkWindow::createPlaylist()
  875. {
  876. PlaylistTypeSelectorDlg* playlistSelectorDlg = new PlaylistTypeSelectorDlg( TomahawkApp::instance()->mainWindow(), Qt::Sheet );
  877. #ifndef Q_OS_MAC
  878. playlistSelectorDlg->setModal( true );
  879. #endif
  880. connect( playlistSelectorDlg, SIGNAL( finished( int ) ), SLOT( playlistCreateDialogFinished( int ) ) );
  881. playlistSelectorDlg->show();
  882. }
  883. void
  884. TomahawkWindow::playlistCreateDialogFinished( int ret )
  885. {
  886. PlaylistTypeSelectorDlg* playlistSelectorDlg = qobject_cast< PlaylistTypeSelectorDlg* >( sender() );
  887. Q_ASSERT( playlistSelectorDlg );
  888. QString playlistName = playlistSelectorDlg->playlistName();
  889. if ( !playlistSelectorDlg->playlistTypeIsAuto() && ret )
  890. {
  891. if ( playlistName.isEmpty() )
  892. {
  893. QList< playlist_ptr > pls = SourceList::instance()->getLocal()->collection()->playlists();
  894. QStringList titles;
  895. foreach ( const playlist_ptr& pl, pls )
  896. titles << pl->title();
  897. QString title = tr( "Playlist" );
  898. playlistName = title;
  899. int i = 2;
  900. while ( titles.contains( playlistName ) )
  901. {
  902. playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
  903. }
  904. }
  905. playlist_ptr playlist = Tomahawk::Playlist::create( SourceList::instance()->getLocal(), uuid(), playlistName, "", "", false, QList< query_ptr>() );
  906. ViewManager::instance()->show( playlist );
  907. }
  908. else if ( playlistSelectorDlg->playlistTypeIsAuto() && ret )
  909. {
  910. // create Auto Playlist
  911. if ( playlistName.isEmpty() )
  912. {
  913. QList< dynplaylist_ptr > pls = SourceList::instance()->getLocal()->collection()->autoPlaylists();
  914. QStringList titles;
  915. foreach ( const dynplaylist_ptr& pl, pls )
  916. titles << pl->title();
  917. QString title = tr( "Automatic Playlist" );
  918. playlistName = title;
  919. int i = 2;
  920. while ( titles.contains( playlistName ) )
  921. {
  922. playlistName = QString( "%1 (%2)" ).arg( title ).arg( i++ );
  923. }
  924. }
  925. createAutomaticPlaylist( playlistName );
  926. }
  927. playlistSelectorDlg->deleteLater();
  928. }
  929. void
  930. TomahawkWindow::audioStarted()
  931. {
  932. m_audioRetryCounter = 0;
  933. ActionCollection::instance()->getAction( "playPause" )->setIcon( QIcon( RESPATH "images/pause-rest.png" ) );
  934. ActionCollection::instance()->getAction( "playPause" )->setText( tr( "Pause" ) );
  935. ActionCollection::instance()->getAction( "stop" )->setEnabled( true );
  936. #ifdef Q_OS_WIN
  937. connect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( updateWindowsLoveButton() ) );
  938. #endif
  939. }
  940. void
  941. TomahawkWindow::audioFinished()
  942. {
  943. #ifdef Q_OS_WIN
  944. disconnect( AudioEngine::instance()->currentTrack()->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( updateWindowsLoveButton() ) );
  945. #endif
  946. }
  947. void
  948. TomahawkWindow::audioPaused()
  949. {
  950. ActionCollection::instance()->getAction( "playPause" )->setIcon( QIcon( RESPATH "images/play-rest.png" ) );
  951. ActionCollection::instance()->getAction( "playPause" )->setText( tr( "&Play" ) );
  952. }
  953. void
  954. TomahawkWindow::audioStopped()
  955. {
  956. audioPaused();
  957. ActionCollection::instance()->getAction( "stop" )->setEnabled( false );
  958. m_currentTrack = result_ptr();
  959. setWindowTitle( m_windowTitle );
  960. }
  961. void
  962. TomahawkWindow::onPlaybackLoading( const Tomahawk::result_ptr& result )
  963. {
  964. m_currentTrack = result;
  965. setWindowTitle( m_windowTitle );
  966. }
  967. void
  968. TomahawkWindow::onAccountError()
  969. {
  970. // TODO fix.
  971. // onAccountDisconnected();
  972. // TODO real error message from plugin kthxbbq
  973. QMessageBox::warning( this,
  974. tr( "Authentication Error" ),
  975. tr( "Error connecting to SIP: Authentication failed!" ),
  976. QMessageBox::Ok );
  977. }
  978. void
  979. TomahawkWindow::setWindowTitle( const QString& title )
  980. {
  981. m_windowTitle = title;
  982. if ( m_currentTrack.isNull() )
  983. QMainWindow::setWindowTitle( title );
  984. else
  985. {
  986. QString s = tr( "%1 by %2", "track, artist name" ).arg( m_currentTrack->track(), m_currentTrack->artist()->name() );
  987. QMainWindow::setWindowTitle( tr( "%1 - %2", "current track, some window title" ).arg( s, title ) );
  988. }
  989. }
  990. void
  991. TomahawkWindow::showAboutTomahawk()
  992. {
  993. QString head, desc;
  994. #ifdef DEBUG_BUILD
  995. head = tr( "<h2><b>Tomahawk %1<br/>(%2)</h2>" )
  996. .arg( TomahawkUtils::appFriendlyVersion() )
  997. .arg( qApp->applicationVersion() );
  998. #else
  999. head = tr( "<h2><b>Tomahawk %1</h2>" )
  1000. .arg( TomahawkUtils::appFriendlyVersion() );
  1001. #endif
  1002. const QString copyright( tr( "Copyright 2010 - 2012" ) );
  1003. const QString thanksto( tr( "Thanks to:" ) );
  1004. desc = QString( "%1<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>"
  1005. "%2 Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Syd Lawrence, Michael Zanetti, Harald Sitter, Steve Robertson" )
  1006. .arg( copyright )
  1007. .arg( thanksto );
  1008. QMessageBox::about( this, tr( "About Tomahawk" ), head + desc );
  1009. }
  1010. void
  1011. TomahawkWindow::checkForUpdates()
  1012. {
  1013. #ifdef Q_OS_MAC
  1014. Tomahawk::checkForUpdates();
  1015. #endif
  1016. }
  1017. void
  1018. TomahawkWindow::onSearch( const QString& search )
  1019. {
  1020. if ( !search.trimmed().isEmpty() )
  1021. ViewManager::instance()->show( new SearchWidget( search, this ) );
  1022. }
  1023. void
  1024. TomahawkWindow::onFilterEdited()
  1025. {
  1026. onSearch( m_searchWidget->text() );
  1027. m_searchWidget->clear();
  1028. }
  1029. void
  1030. TomahawkWindow::showQueue()
  1031. {
  1032. if ( QThread::currentThread() != thread() )
  1033. {
  1034. qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
  1035. QMetaObject::invokeMethod( this, "showQueue", Qt::QueuedConnection );
  1036. return;
  1037. }
  1038. m_queueView->show();
  1039. }
  1040. void
  1041. TomahawkWindow::hideQueue()
  1042. {
  1043. if ( QThread::currentThread() != thread() )
  1044. {
  1045. qDebug() << "Reinvoking in correct thread:" << Q_FUNC_INFO;
  1046. QMetaObject::invokeMethod( this, "hideQueue", Qt::QueuedConnection );
  1047. return;
  1048. }
  1049. m_queueView->hide();
  1050. }
  1051. void
  1052. TomahawkWindow::minimize()
  1053. {
  1054. if ( isMinimized() )
  1055. {
  1056. showNormal();
  1057. }
  1058. else
  1059. {
  1060. showMinimized();
  1061. }
  1062. }
  1063. void
  1064. TomahawkWindow::maximize()
  1065. {
  1066. if ( isMaximized() )
  1067. {
  1068. showNormal();
  1069. }
  1070. else
  1071. {
  1072. showMaximized();
  1073. }
  1074. }
  1075. void
  1076. TomahawkWindow::crashNow()
  1077. {
  1078. TomahawkUtils::crash();
  1079. }
  1080. void
  1081. TomahawkWindow::toggleMenuBar() //SLOT
  1082. {
  1083. #ifndef Q_OS_MAC
  1084. if( menuBar()->isVisible() )
  1085. {
  1086. menuBar()->setVisible( false );
  1087. ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( tr( "Show Menu Bar" ) );
  1088. m_compactMenuAction->setVisible( true );
  1089. }
  1090. else
  1091. {
  1092. m_compactMenuAction->setVisible( false );
  1093. ActionCollection::instance()->getAction( "toggleMenuBar" )->setText( tr( "Hide Menu Bar" ) );
  1094. menuBar()->setVisible( true );
  1095. }
  1096. balanceToolbar();
  1097. saveSettings();
  1098. #endif
  1099. }
  1100. AudioControls*
  1101. TomahawkWindow::audioControls()
  1102. {
  1103. return m_audioControls;
  1104. }
  1105. SourceTreeView*
  1106. TomahawkWindow::sourceTreeView() const
  1107. {
  1108. return m_sourcetree;
  1109. }