PageRenderTime 377ms CodeModel.GetById 110ms app.highlight 187ms RepoModel.GetById 44ms app.codeStats 1ms

/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
 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}