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