/src/audiocontrols.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 704 lines · 527 code · 132 blank · 45 comment · 58 complexity · 79a7f607b3e2a2be7cbf3df46ebe5a3e 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-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  5. *
  6. * Tomahawk is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Tomahawk is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "AudioControls.h"
  20. #include "ui_AudioControls.h"
  21. #include "audio/AudioEngine.h"
  22. #include "playlist/PlaylistView.h"
  23. #include "database/Database.h"
  24. #include "widgets/ImageButton.h"
  25. #include "utils/TomahawkUtilsGui.h"
  26. #include "utils/Logger.h"
  27. #include "Album.h"
  28. #include "DropJob.h"
  29. #include "SocialWidget.h"
  30. #include "GlobalActionManager.h"
  31. #include "ViewManager.h"
  32. #include "Source.h"
  33. #include <QNetworkReply>
  34. #include <QDropEvent>
  35. #include <QMouseEvent>
  36. #include <QDesktopServices>
  37. const static int ALLOWED_MAX_DIVERSION = 300;
  38. using namespace Tomahawk;
  39. AudioControls::AudioControls( QWidget* parent )
  40. : QWidget( parent )
  41. , ui( new Ui::AudioControls )
  42. , m_repeatMode( PlaylistModes::NoRepeat )
  43. , m_shuffled( false )
  44. , m_lastSliderCheck( 0 )
  45. , m_parent( parent )
  46. {
  47. ui->setupUi( this );
  48. setAcceptDrops( true );
  49. QFont font( ui->artistTrackLabel->font() );
  50. font.setPointSize( TomahawkUtils::defaultFontSize() );
  51. ui->artistTrackLabel->setFont( font );
  52. ui->artistTrackLabel->setElideMode( Qt::ElideMiddle );
  53. ui->artistTrackLabel->setType( QueryLabel::ArtistAndTrack );
  54. ui->artistTrackLabel->setJumpLinkVisible( true );
  55. ui->albumLabel->setFont( font );
  56. ui->albumLabel->setType( QueryLabel::Album );
  57. ui->timeLabel->setFont( font );
  58. ui->timeLeftLabel->setFont( font );
  59. font.setPointSize( TomahawkUtils::defaultFontSize() - 2 );
  60. m_defaultSourceIcon = QPixmap( RESPATH "images/resolver-default.png" );
  61. ui->prevButton->setPixmap( RESPATH "images/back-rest.png" );
  62. ui->prevButton->setPixmap( RESPATH "images/back-pressed.png", QIcon::Off, QIcon::Active );
  63. ui->playPauseButton->setPixmap( RESPATH "images/play-rest.png" );
  64. ui->playPauseButton->setPixmap( RESPATH "images/play-pressed.png", QIcon::Off, QIcon::Active );
  65. ui->pauseButton->setPixmap( RESPATH "images/pause-rest.png" );
  66. ui->pauseButton->setPixmap( RESPATH "images/pause-pressed.png", QIcon::Off, QIcon::Active );
  67. ui->nextButton->setPixmap( RESPATH "images/skip-rest.png" );
  68. ui->nextButton->setPixmap( RESPATH "images/skip-pressed.png", QIcon::Off, QIcon::Active );
  69. ui->shuffleButton->setPixmap( RESPATH "images/shuffle-off-rest.png" );
  70. ui->shuffleButton->setPixmap( RESPATH "images/shuffle-off-pressed.png", QIcon::Off, QIcon::Active );
  71. ui->repeatButton->setPixmap( RESPATH "images/repeat-off-rest.png" );
  72. ui->repeatButton->setPixmap( RESPATH "images/repeat-off-pressed.png", QIcon::Off, QIcon::Active );
  73. ui->volumeLowButton->setPixmap( RESPATH "images/volume-icon-muted.png" );
  74. ui->volumeHighButton->setPixmap( RESPATH "images/volume-icon-full.png" );
  75. ui->socialButton->setPixmap( RESPATH "images/share.png" );
  76. ui->loveButton->setPixmap( RESPATH "images/not-loved.png" );
  77. ui->loveButton->setCheckable( true );
  78. ui->ownerButton->setPixmap( m_defaultSourceIcon );
  79. ui->socialButton->setFixedSize( QSize( 20, 20 ) );
  80. ui->loveButton->setFixedSize( QSize( 20, 20 ) );
  81. ui->ownerButton->setFixedSize( QSize( 34, 34 ) );
  82. ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" );
  83. ui->seekSlider->setEnabled( true );
  84. ui->seekSlider->setTimeLine( &m_sliderTimeLine );
  85. ui->volumeSlider->setRange( 0, 100 );
  86. ui->volumeSlider->setValue( AudioEngine::instance()->volume() );
  87. m_phononTickCheckTimer.setSingleShot( true );
  88. connect( &m_phononTickCheckTimer, SIGNAL( timeout() ), SLOT( phononTickCheckTimeout() ) );
  89. connect( &m_sliderTimeLine, SIGNAL( frameChanged( int ) ), ui->seekSlider, SLOT( setValue( int ) ) );
  90. connect( ui->seekSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( seek( int ) ) );
  91. connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( setVolume( int ) ) );
  92. connect( ui->prevButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( previous() ) );
  93. connect( ui->playPauseButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( play() ) );
  94. connect( ui->pauseButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( pause() ) );
  95. connect( ui->nextButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( next() ) );
  96. connect( ui->volumeLowButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( lowerVolume() ) );
  97. connect( ui->volumeHighButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( raiseVolume() ) );
  98. connect( ui->playPauseButton, SIGNAL( clicked() ), SIGNAL( playPressed() ) );
  99. connect( ui->pauseButton, SIGNAL( clicked() ), SIGNAL( pausePressed() ) );
  100. connect( ui->repeatButton, SIGNAL( clicked() ), SLOT( onRepeatClicked() ) );
  101. connect( ui->shuffleButton, SIGNAL( clicked() ), SLOT( onShuffleClicked() ) );
  102. connect( ui->artistTrackLabel, SIGNAL( clickedArtist() ), SLOT( onArtistClicked() ) );
  103. connect( ui->artistTrackLabel, SIGNAL( clickedTrack() ), SLOT( onTrackClicked() ) );
  104. connect( ui->albumLabel, SIGNAL( clickedAlbum() ), SLOT( onAlbumClicked() ) );
  105. connect( ui->socialButton, SIGNAL( clicked() ), SLOT( onSocialButtonClicked() ) );
  106. connect( ui->loveButton, SIGNAL( clicked( bool ) ), SLOT( onLoveButtonClicked( bool ) ) );
  107. connect( ui->ownerButton, SIGNAL( clicked() ), SLOT( onOwnerButtonClicked() ) );
  108. // <From AudioEngine>
  109. connect( AudioEngine::instance(), SIGNAL( loading( Tomahawk::result_ptr ) ), SLOT( onPlaybackLoading( Tomahawk::result_ptr ) ) );
  110. connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ) );
  111. connect( AudioEngine::instance(), SIGNAL( paused() ), SLOT( onPlaybackPaused() ) );
  112. connect( AudioEngine::instance(), SIGNAL( resumed() ), SLOT( onPlaybackResumed() ) );
  113. connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ) );
  114. connect( AudioEngine::instance(), SIGNAL( seeked( qint64 ) ), SLOT( onPlaybackSeeked( qint64 ) ) );
  115. connect( AudioEngine::instance(), SIGNAL( timerMilliSeconds( qint64 ) ), SLOT( onPlaybackTimer( qint64 ) ) );
  116. connect( AudioEngine::instance(), SIGNAL( volumeChanged( int ) ), SLOT( onVolumeChanged( int ) ) );
  117. ui->buttonAreaLayout->setSpacing( 0 );
  118. ui->stackedLayout->setSpacing( 0 );
  119. ui->stackedLayout->setContentsMargins( 0, 0, 0, 0 );
  120. ui->stackedLayout->setMargin( 0 );
  121. ui->playPauseButton->setContentsMargins( 0, 0, 0, 0 );
  122. ui->pauseButton->setContentsMargins( 0, 0, 0, 0 );
  123. ui->stackedLayout->setSizeConstraint( QLayout::SetFixedSize );
  124. onPlaybackStopped(); // initial state
  125. }
  126. AudioControls::~AudioControls()
  127. {
  128. delete ui;
  129. }
  130. void
  131. AudioControls::changeEvent( QEvent* e )
  132. {
  133. QWidget::changeEvent( e );
  134. switch ( e->type() )
  135. {
  136. case QEvent::LanguageChange:
  137. // ui->retranslateUi( this );
  138. break;
  139. default:
  140. break;
  141. }
  142. }
  143. void
  144. AudioControls::phononTickCheckTimeout()
  145. {
  146. onPlaybackTimer( m_lastSliderCheck );
  147. }
  148. void
  149. AudioControls::onVolumeChanged( int volume )
  150. {
  151. ui->volumeSlider->blockSignals( true );
  152. ui->volumeSlider->setValue( volume );
  153. ui->volumeSlider->blockSignals( false );
  154. }
  155. void
  156. AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
  157. {
  158. if ( result.isNull() )
  159. return;
  160. if ( m_currentTrack.isNull() || ( !m_currentTrack.isNull() && m_currentTrack.data()->id() != result.data()->id() ) )
  161. onPlaybackLoading( result );
  162. qint64 duration = AudioEngine::instance()->currentTrackTotalTime();
  163. if ( duration == -1 )
  164. duration = result.data()->duration() * 1000;
  165. ui->seekSlider->setRange( 0, duration );
  166. ui->seekSlider->setValue( 0 );
  167. ui->seekSlider->setEnabled( AudioEngine::instance()->canSeek() );
  168. m_sliderTimeLine.stop();
  169. m_sliderTimeLine.setDuration( duration );
  170. m_sliderTimeLine.setFrameRange( 0, duration );
  171. m_sliderTimeLine.setCurveShape( QTimeLine::LinearCurve );
  172. m_sliderTimeLine.setCurrentTime( 0 );
  173. m_seeked = false;
  174. ui->seekSlider->setVisible( true );
  175. int updateRate = (double)1000 / ( (double)ui->seekSlider->contentsRect().width() / (double)( duration / 1000 ) );
  176. m_sliderTimeLine.setUpdateInterval( qBound( 40, updateRate, 500 ) );
  177. m_lastSliderCheck = 0;
  178. m_phononTickCheckTimer.start( 500 );
  179. }
  180. void
  181. AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
  182. {
  183. if ( !m_currentTrack.isNull() )
  184. {
  185. disconnect( m_currentTrack->toQuery().data(), SIGNAL( updated() ), this, SLOT( onCoverUpdated() ) );
  186. disconnect( m_currentTrack->toQuery().data(), SIGNAL( socialActionsLoaded() ), this, SLOT( onSocialActionsLoaded() ) );
  187. }
  188. m_currentTrack = result;
  189. connect( m_currentTrack->toQuery().data(), SIGNAL( updated() ), SLOT( onCoverUpdated() ) );
  190. connect( m_currentTrack->toQuery().data(), SIGNAL( socialActionsLoaded() ), SLOT( onSocialActionsLoaded() ) );
  191. ui->artistTrackLabel->setResult( result );
  192. ui->albumLabel->setResult( result );
  193. const QString duration = TomahawkUtils::timeToString( result.data()->duration() );
  194. ui->timeLabel->setFixedWidth( ui->timeLabel->fontMetrics().width( QString( duration.length(), QChar( '0' ) ) ) );
  195. ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) );
  196. ui->timeLeftLabel->setFixedWidth( ui->timeLeftLabel->fontMetrics().width( QString( duration.length() + 1, QChar( '0' ) ) ) );
  197. ui->timeLeftLabel->setText( "-" + duration );
  198. m_lastTextSecondShown = 0;
  199. ui->stackedLayout->setCurrentWidget( ui->pauseButton );
  200. ui->loveButton->setEnabled( true );
  201. ui->loveButton->setVisible( true );
  202. ui->socialButton->setEnabled( true );
  203. ui->socialButton->setVisible( true );
  204. ui->ownerButton->setEnabled( true );
  205. ui->ownerButton->setVisible( true );
  206. ui->timeLabel->setToolTip( tr( "Time Elapsed" ) );
  207. ui->timeLeftLabel->setToolTip( tr( "Time Remaining" ) );
  208. ui->shuffleButton->setToolTip( tr( "Shuffle" ) );
  209. ui->repeatButton->setToolTip( tr( "Repeat" ) );
  210. ui->socialButton->setToolTip( tr( "Share" ) );
  211. ui->loveButton->setToolTip( tr( "Love" ) );
  212. ui->ownerButton->setToolTip( QString( tr( "Playing from %1" ) ).arg( result->friendlySource() ) );
  213. ui->prevButton->setEnabled( AudioEngine::instance()->canGoPrevious() );
  214. ui->nextButton->setEnabled( AudioEngine::instance()->canGoNext() );
  215. QPixmap sourceIcon = result->sourceIcon( Result::Plain, ui->ownerButton->size() );
  216. if ( !sourceIcon.isNull() )
  217. ui->ownerButton->setPixmap( sourceIcon );
  218. else
  219. {
  220. ui->ownerButton->clear();
  221. ui->ownerButton->setPixmap( m_defaultSourceIcon );
  222. }
  223. if ( QUrl( result->linkUrl() ).isValid() || !result->collection().isNull() )
  224. ui->ownerButton->setCursor( Qt::PointingHandCursor );
  225. else
  226. ui->ownerButton->setCursor( Qt::ArrowCursor );
  227. setCover();
  228. setSocialActions();
  229. }
  230. void
  231. AudioControls::onCoverUpdated()
  232. {
  233. Query* query = qobject_cast< Query* >( sender() );
  234. if ( !query || !m_currentTrack || query != m_currentTrack->toQuery().data() )
  235. return;
  236. setCover();
  237. }
  238. void
  239. AudioControls::setCover()
  240. {
  241. if ( !m_currentTrack->toQuery()->cover( ui->coverImage->size() ).isNull() )
  242. {
  243. QPixmap cover;
  244. cover = m_currentTrack->toQuery()->cover( ui->coverImage->size() );
  245. ui->coverImage->setPixmap( TomahawkUtils::createRoundedImage( cover, QSize( 0, 0 ) ), false );
  246. }
  247. else
  248. ui->coverImage->setPixmap( TomahawkUtils::defaultPixmap( TomahawkUtils::DefaultAlbumCover, TomahawkUtils::ScaledCover, ui->coverImage->size() ), true );
  249. }
  250. void
  251. AudioControls::onSocialActionsLoaded()
  252. {
  253. Query* query = qobject_cast< Query* >( sender() );
  254. if ( !query || !m_currentTrack || !query->equals( m_currentTrack->toQuery() ) )
  255. return;
  256. setSocialActions();
  257. }
  258. void
  259. AudioControls::setSocialActions()
  260. {
  261. if ( m_currentTrack->toQuery()->loved() )
  262. {
  263. ui->loveButton->setPixmap( RESPATH "images/loved.png" );
  264. ui->loveButton->setChecked( true );
  265. }
  266. else
  267. {
  268. ui->loveButton->setPixmap( RESPATH "images/not-loved.png" );
  269. ui->loveButton->setChecked( false );
  270. }
  271. }
  272. void
  273. AudioControls::onPlaybackPaused()
  274. {
  275. tDebug( LOGEXTRA ) << Q_FUNC_INFO;
  276. ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
  277. m_sliderTimeLine.setPaused( true );
  278. }
  279. void
  280. AudioControls::onPlaybackResumed()
  281. {
  282. tDebug( LOGEXTRA ) << Q_FUNC_INFO;
  283. ui->stackedLayout->setCurrentWidget( ui->pauseButton );
  284. }
  285. void
  286. AudioControls::onPlaybackSeeked( qint64 msec )
  287. {
  288. tDebug( LOGEXTRA ) << Q_FUNC_INFO;
  289. m_seeked = true;
  290. onPlaybackTimer( msec );
  291. }
  292. void
  293. AudioControls::onPlaybackStopped()
  294. {
  295. tDebug( LOGEXTRA ) << Q_FUNC_INFO;
  296. m_currentTrack.clear();
  297. ui->artistTrackLabel->setText( "" );
  298. ui->albumLabel->setText( "" );
  299. ui->timeLabel->setText( "" );
  300. ui->timeLeftLabel->setText( "" );
  301. ui->coverImage->setPixmap( QPixmap(), false );
  302. ui->seekSlider->setVisible( false );
  303. m_sliderTimeLine.stop();
  304. m_sliderTimeLine.setCurrentTime( 0 );
  305. m_phononTickCheckTimer.stop();
  306. ui->ownerButton->setPixmap( m_defaultSourceIcon );
  307. ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
  308. ui->loveButton->setEnabled( false );
  309. ui->loveButton->setVisible( false );
  310. ui->socialButton->setEnabled( false );
  311. ui->socialButton->setVisible( false );
  312. ui->ownerButton->setEnabled( false );
  313. ui->ownerButton->setVisible( false );
  314. ui->timeLabel->setToolTip( "" );
  315. ui->timeLeftLabel->setToolTip( "" );
  316. ui->shuffleButton->setToolTip( "" );
  317. ui->repeatButton->setToolTip( "" );
  318. ui->socialButton->setToolTip( "" );
  319. ui->loveButton->setToolTip( "" );
  320. ui->ownerButton->setToolTip( "" );
  321. ui->prevButton->setEnabled( AudioEngine::instance()->canGoPrevious() );
  322. ui->nextButton->setEnabled( AudioEngine::instance()->canGoNext() );
  323. }
  324. void
  325. AudioControls::onPlaybackTimer( qint64 msElapsed )
  326. {
  327. //tDebug() << Q_FUNC_INFO;
  328. m_phononTickCheckTimer.stop();
  329. if ( m_currentTrack.isNull() )
  330. {
  331. m_sliderTimeLine.stop();
  332. return;
  333. }
  334. const int seconds = msElapsed / 1000;
  335. if ( seconds != m_lastTextSecondShown )
  336. {
  337. ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
  338. ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
  339. m_lastTextSecondShown = seconds;
  340. }
  341. m_phononTickCheckTimer.start( 500 );
  342. if ( msElapsed == 0 )
  343. return;
  344. int currentTime = m_sliderTimeLine.currentTime();
  345. //tDebug( LOGEXTRA ) << Q_FUNC_INFO << "msElapsed =" << msElapsed << "and timer current time =" << m_sliderTimeLine.currentTime();
  346. // First condition checks for the common case where
  347. // 1) the track has been started
  348. // 2) we haven't seeked,
  349. // 3) the timeline is pretty close to the actual time elapsed, within ALLOWED_MAX_DIVERSIONmsec, so no adustment needed, and
  350. // 4) The audio engine is actually currently running
  351. if ( msElapsed > 0
  352. && !m_seeked
  353. && qAbs( msElapsed - currentTime ) <= ALLOWED_MAX_DIVERSION
  354. && AudioEngine::instance()->state() == AudioEngine::Playing )
  355. {
  356. if ( m_sliderTimeLine.state() != QTimeLine::Running )
  357. m_sliderTimeLine.resume();
  358. m_lastSliderCheck = msElapsed;
  359. return;
  360. }
  361. else
  362. {
  363. //tDebug() << Q_FUNC_INFO << "Fallthrough";
  364. // If we're in here we're offset, so we need to do some munging around
  365. ui->seekSlider->blockSignals( true );
  366. // First handle seeks
  367. if ( m_seeked )
  368. {
  369. //tDebug() << Q_FUNC_INFO << "Seeked";
  370. m_sliderTimeLine.setPaused( true );
  371. m_sliderTimeLine.setCurrentTime( msElapsed );
  372. m_seeked = false;
  373. if ( AudioEngine::instance()->state() == AudioEngine::Playing )
  374. m_sliderTimeLine.resume();
  375. }
  376. // Next handle falling behind by too much, or getting ahead by too much (greater than allowed amount, which would have been sorted above)
  377. // However, a Phonon bug means that after a seek we'll actually have AudioEngine's state be Playing, when it ain't, so have to detect that
  378. else if ( AudioEngine::instance()->state() == AudioEngine::Playing )
  379. {
  380. //tDebug() << Q_FUNC_INFO << "AudioEngine playing";
  381. m_sliderTimeLine.setPaused( true );
  382. m_sliderTimeLine.setCurrentTime( msElapsed );
  383. if ( msElapsed != m_lastSliderCheck )
  384. m_sliderTimeLine.resume();
  385. }
  386. // Finally, the case where the audioengine isn't playing; if the timeline is still running, pause it and catch up
  387. else if ( AudioEngine::instance()->state() != AudioEngine::Playing )
  388. {
  389. //tDebug() << Q_FUNC_INFO << "AudioEngine not playing";
  390. if ( msElapsed != currentTime || m_sliderTimeLine.state() == QTimeLine::Running)
  391. {
  392. m_sliderTimeLine.setPaused( true );
  393. m_sliderTimeLine.setCurrentTime( msElapsed );
  394. }
  395. }
  396. else
  397. {
  398. tDebug() << Q_FUNC_INFO << "What to do? How could we even get here?";
  399. }
  400. m_lastSliderCheck = msElapsed;
  401. ui->seekSlider->blockSignals( false );
  402. }
  403. }
  404. void
  405. AudioControls::onRepeatModeChanged( PlaylistModes::RepeatMode mode )
  406. {
  407. m_repeatMode = mode;
  408. switch ( m_repeatMode )
  409. {
  410. case PlaylistModes::NoRepeat:
  411. {
  412. // switch to RepeatOne
  413. ui->repeatButton->setPixmap( RESPATH "images/repeat-off-rest.png" );
  414. ui->repeatButton->setPixmap( RESPATH "images/repeat-off-pressed.png", QIcon::Off, QIcon::Active );
  415. }
  416. break;
  417. case PlaylistModes::RepeatOne:
  418. {
  419. // switch to RepeatAll
  420. ui->repeatButton->setPixmap( RESPATH "images/repeat-1-on-rest.png" );
  421. ui->repeatButton->setPixmap( RESPATH "images/repeat-1-on-pressed.png", QIcon::Off, QIcon::Active );
  422. }
  423. break;
  424. case PlaylistModes::RepeatAll:
  425. {
  426. // switch to NoRepeat
  427. ui->repeatButton->setPixmap( RESPATH "images/repeat-all-on-rest.png" );
  428. ui->repeatButton->setPixmap( RESPATH "images/repeat-all-on-pressed.png", QIcon::Off, QIcon::Active );
  429. }
  430. break;
  431. default:
  432. break;
  433. }
  434. }
  435. void
  436. AudioControls::onRepeatClicked()
  437. {
  438. switch ( m_repeatMode )
  439. {
  440. case PlaylistModes::NoRepeat:
  441. {
  442. // switch to RepeatOne
  443. ViewManager::instance()->setRepeatMode( PlaylistModes::RepeatOne );
  444. }
  445. break;
  446. case PlaylistModes::RepeatOne:
  447. {
  448. // switch to RepeatAll
  449. ViewManager::instance()->setRepeatMode( PlaylistModes::RepeatAll );
  450. }
  451. break;
  452. case PlaylistModes::RepeatAll:
  453. {
  454. // switch to NoRepeat
  455. ViewManager::instance()->setRepeatMode( PlaylistModes::NoRepeat );
  456. }
  457. break;
  458. default:
  459. break;
  460. }
  461. }
  462. void
  463. AudioControls::onShuffleModeChanged( bool enabled )
  464. {
  465. m_shuffled = enabled;
  466. if ( m_shuffled )
  467. {
  468. ui->shuffleButton->setPixmap( RESPATH "images/shuffle-on-rest.png" );
  469. ui->shuffleButton->setPixmap( RESPATH "images/shuffle-on-pressed.png", QIcon::Off, QIcon::Active );
  470. ui->repeatButton->setEnabled( false );
  471. }
  472. else
  473. {
  474. ui->shuffleButton->setPixmap( RESPATH "images/shuffle-off-rest.png" );
  475. ui->shuffleButton->setPixmap( RESPATH "images/shuffle-off-pressed.png", QIcon::Off, QIcon::Active );
  476. ui->repeatButton->setEnabled( true );
  477. }
  478. }
  479. void
  480. AudioControls::onShuffleClicked()
  481. {
  482. ViewManager::instance()->setShuffled( m_shuffled ^ true );
  483. }
  484. void
  485. AudioControls::onArtistClicked()
  486. {
  487. ViewManager::instance()->show( m_currentTrack->artist() );
  488. }
  489. void
  490. AudioControls::onAlbumClicked()
  491. {
  492. ViewManager::instance()->show( m_currentTrack->album() );
  493. }
  494. void
  495. AudioControls::onTrackClicked()
  496. {
  497. ViewManager::instance()->show( m_currentTrack->toQuery() );
  498. }
  499. void
  500. AudioControls::dragEnterEvent( QDragEnterEvent* e )
  501. {
  502. if ( DropJob::acceptsMimeData( e->mimeData() ) )
  503. e->acceptProposedAction();
  504. }
  505. void
  506. AudioControls::dragMoveEvent( QDragMoveEvent* /* e */ )
  507. {
  508. // if ( GlobalActionManager::instance()->acceptsMimeData( e->mimeData() ) )
  509. // e->acceptProposedAction();
  510. }
  511. void
  512. AudioControls::dropEvent( QDropEvent* e )
  513. {
  514. tDebug() << "AudioControls got drop:" << e->mimeData()->formats();
  515. if ( DropJob::acceptsMimeData( e->mimeData() ) )
  516. {
  517. DropJob *dj = new DropJob();
  518. dj->setDropAction( DropJob::Append );
  519. connect( dj, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( droppedTracks( QList<Tomahawk::query_ptr> ) ) );
  520. dj->tracksFromMimeData( e->mimeData() );
  521. e->accept();
  522. }
  523. }
  524. void
  525. AudioControls::droppedTracks( QList< query_ptr > tracks )
  526. {
  527. if ( !tracks.isEmpty() )
  528. {
  529. // queue and play the first no matter what
  530. GlobalActionManager::instance()->handlePlayTrack( tracks.first() );
  531. ViewManager::instance()->queue()->model()->appendQueries( tracks );
  532. }
  533. }
  534. void
  535. AudioControls::onSocialButtonClicked()
  536. {
  537. if ( !m_socialWidget.isNull() )
  538. m_socialWidget.data()->close();
  539. m_socialWidget = new SocialWidget( m_parent );
  540. QPoint socialWidgetPos = ui->socialButton->pos();
  541. socialWidgetPos.rx() += ui->socialButton->width() / 2;
  542. socialWidgetPos.ry() += 6;
  543. m_socialWidget.data()->setPosition( ui->metaDataArea->mapToGlobal( socialWidgetPos ) );
  544. m_socialWidget.data()->setQuery( m_currentTrack->toQuery() );
  545. m_socialWidget.data()->show();
  546. }
  547. void
  548. AudioControls::onLoveButtonClicked( bool checked )
  549. {
  550. if ( checked )
  551. {
  552. ui->loveButton->setPixmap( RESPATH "images/loved.png" );
  553. m_currentTrack->toQuery()->setLoved( true );
  554. }
  555. else
  556. {
  557. ui->loveButton->setPixmap( RESPATH "images/not-loved.png" );
  558. m_currentTrack->toQuery()->setLoved( false );
  559. }
  560. }
  561. void
  562. AudioControls::onOwnerButtonClicked()
  563. {
  564. if ( m_currentTrack->collection().isNull() )
  565. {
  566. QUrl url = QUrl( m_currentTrack->linkUrl() );
  567. if ( url.isValid() )
  568. QDesktopServices::openUrl( url );
  569. }
  570. else
  571. ViewManager::instance()->show( m_currentTrack->collection() );
  572. }