File indexing completed on 2024-05-05 04:49:28
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Dan Meltzer <parallelgrapefruit@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "ProgressWidget.h" 0018 0019 #include "amarokconfig.h" 0020 #include "core/support/Debug.h" 0021 #include "EngineController.h" 0022 #include "SliderWidget.h" 0023 #include "TimeLabel.h" 0024 #include "amarokurls/AmarokUrl.h" 0025 #include "amarokurls/AmarokUrlHandler.h" 0026 #include "core/meta/Meta.h" 0027 #include "core/meta/support/MetaUtility.h" 0028 #include "core-impl/capabilities/timecode/TimecodeLoadCapability.h" 0029 0030 #include <KLocalizedString> 0031 0032 #include <QHBoxLayout> 0033 #include <QMouseEvent> 0034 0035 ProgressWidget::ProgressWidget( QWidget *parent ) 0036 : QWidget( parent ) 0037 { 0038 QHBoxLayout *box = new QHBoxLayout( this ); 0039 setLayout( box ); 0040 box->setMargin( 0 ); 0041 box->setSpacing( 4 ); 0042 0043 m_slider = new Amarok::TimeSlider( this ); 0044 m_slider->setToolTip( i18n( "Track Progress" ) ); 0045 m_slider->setMaximumSize( 600000, 20 ); 0046 0047 m_timeLabelLeft = new TimeLabel( this ); 0048 0049 m_timeLabelRight = new TimeLabel( this ); 0050 m_timeLabelRight->setAlignment( Qt::AlignRight ); 0051 0052 updateTimeLabelTooltips(); 0053 0054 m_timeLabelLeft->setShowTime( false ); 0055 m_timeLabelLeft->setAlignment( Qt::AlignRight ); 0056 m_timeLabelRight->setShowTime( false ); 0057 m_timeLabelRight->setAlignment( Qt::AlignLeft ); 0058 m_timeLabelLeft->show(); 0059 m_timeLabelRight->show(); 0060 0061 box->addSpacing( 3 ); 0062 box->addWidget( m_timeLabelLeft ); 0063 box->addWidget( m_slider ); 0064 box->addWidget( m_timeLabelRight ); 0065 0066 EngineController *engine = The::engineController(); 0067 0068 if( engine->isPaused() ) 0069 paused(); 0070 else if( engine->isPlaying() ) 0071 trackPlaying(); 0072 else 0073 stopped(); 0074 0075 connect( engine, &EngineController::stopped, 0076 this, &ProgressWidget::stopped ); 0077 connect( engine, &EngineController::paused, 0078 this, &ProgressWidget::paused ); 0079 connect( engine, &EngineController::trackPlaying, 0080 this, &ProgressWidget::trackPlaying ); 0081 connect( engine, &EngineController::trackLengthChanged, 0082 this, &ProgressWidget::trackLengthChanged ); 0083 connect( engine, &EngineController::trackPositionChanged, 0084 this, &ProgressWidget::trackPositionChanged ); 0085 0086 connect( m_slider, &Amarok::TimeSlider::sliderReleased, 0087 engine, &EngineController::seekTo ); 0088 0089 connect( m_slider, &Amarok::TimeSlider::valueChanged, 0090 this, &ProgressWidget::drawTimeDisplay ); 0091 0092 setBackgroundRole( QPalette::BrightText ); 0093 0094 connect ( The::amarokUrlHandler(), &AmarokUrlHandler::timecodesUpdated, 0095 this, &ProgressWidget::redrawBookmarks ); 0096 connect ( The::amarokUrlHandler(), &AmarokUrlHandler::timecodeAdded, 0097 this, &ProgressWidget::addBookmarkNoPopup ); 0098 } 0099 0100 void 0101 ProgressWidget::addBookmarkNoPopup( const QString &name, int milliSeconds ) 0102 { 0103 addBookmark( name, milliSeconds, false ); 0104 } 0105 0106 void 0107 ProgressWidget::addBookmark( const QString &name, int milliSeconds, bool showPopup ) 0108 { 0109 DEBUG_BLOCK 0110 if ( m_slider ) 0111 m_slider->drawTriangle( name, milliSeconds, showPopup ); 0112 } 0113 0114 void 0115 ProgressWidget::updateTimeLabelTooltips() 0116 { 0117 TimeLabel *elapsedLabel = AmarokConfig::leftTimeDisplayRemaining() ? m_timeLabelRight : m_timeLabelLeft; 0118 TimeLabel *remainingLabel = AmarokConfig::leftTimeDisplayRemaining() ? m_timeLabelLeft : m_timeLabelRight; 0119 0120 elapsedLabel->setToolTip( i18n( "The amount of time elapsed in current track" ) ); 0121 remainingLabel->setToolTip( i18n( "The amount of time remaining in current track" ) ); 0122 } 0123 0124 void 0125 ProgressWidget::drawTimeDisplay( int ms ) //SLOT 0126 { 0127 if ( !isVisible() ) 0128 return; 0129 0130 const qint64 trackLength = The::engineController()->trackLength(); 0131 0132 //sometimes the engine gives negative position and track length values for streams 0133 //which causes the time sliders to show 'interesting' values like -322:0-35:0-59 0134 int seconds = qMax(0, ms / 1000); 0135 int remainingSeconds = qMax(0, int((trackLength - ms) / 1000)); 0136 0137 QString sSeconds = Meta::secToPrettyTime( seconds ); 0138 QString sRemainingSeconds = '-' + Meta::secToPrettyTime( remainingSeconds ); 0139 0140 if( AmarokConfig::leftTimeDisplayRemaining() ) 0141 { 0142 m_timeLabelLeft->setText( sRemainingSeconds ); 0143 m_timeLabelLeft->setEnabled( remainingSeconds > 0 ); 0144 0145 m_timeLabelRight->setText( sSeconds ); 0146 m_timeLabelRight->setEnabled( seconds > 0 ); 0147 } 0148 else 0149 { 0150 m_timeLabelRight->setText( sRemainingSeconds ); 0151 m_timeLabelRight->setEnabled( remainingSeconds > 0 ); 0152 0153 m_timeLabelLeft->setText( sSeconds ); 0154 m_timeLabelLeft->setEnabled( seconds > 0 ); 0155 } 0156 } 0157 0158 void 0159 ProgressWidget::stopped() 0160 { 0161 m_slider->setEnabled( false ); 0162 m_slider->setMinimum( 0 ); //needed because setMaximum() calls with bogus values can change minValue 0163 m_slider->setMaximum( 0 ); 0164 m_timeLabelLeft->setEnabled( false ); 0165 m_timeLabelLeft->setEnabled( false ); 0166 m_timeLabelLeft->setShowTime( false ); 0167 m_timeLabelRight->setShowTime( false ); 0168 0169 m_currentUrlId.clear(); 0170 m_slider->clearTriangles(); 0171 } 0172 0173 void 0174 ProgressWidget::paused() 0175 { 0176 // I am wondering, is there a way that the track can get paused 0177 // directly? 0178 m_timeLabelLeft->setEnabled( true ); 0179 m_timeLabelRight->setEnabled( true ); 0180 } 0181 0182 void 0183 ProgressWidget::trackPlaying() 0184 { 0185 m_timeLabelLeft->setEnabled( true ); 0186 m_timeLabelLeft->setEnabled( true ); 0187 m_timeLabelLeft->setShowTime( true ); 0188 m_timeLabelRight->setShowTime( true ); 0189 0190 //in some cases (for streams mostly), we do not get an event for track length changes once 0191 //loading is done, causing maximum() to return 0 at when playback starts. In this case we need 0192 //to make sure that maximum is set correctly or the slider will not move. 0193 trackLengthChanged( The::engineController()->trackLength() ); 0194 } 0195 0196 void 0197 ProgressWidget::trackLengthChanged( qint64 milliseconds ) 0198 { 0199 m_slider->setMinimum( 0 ); 0200 m_slider->setMaximum( milliseconds ); 0201 0202 const int timeLength = Meta::msToPrettyTime( milliseconds ).length() + 1; // account for - in remaining time 0203 QFontMetrics tFm( m_timeLabelRight->font() ); 0204 const int labelSize = tFm.horizontalAdvance(QChar('0')) * timeLength; 0205 0206 //set the sizes of the labels to the max needed by the length of the track 0207 //this way the progressbar will not change size during playback of a track 0208 m_timeLabelRight->setFixedWidth( labelSize ); 0209 m_timeLabelLeft->setFixedWidth( labelSize ); 0210 0211 //get the urlid of the current track as the engine might stop and start several times 0212 //when skipping lst.fm tracks, so we need to know if we are still on the same track... 0213 if ( The::engineController()->currentTrack() ) 0214 m_currentUrlId = The::engineController()->currentTrack()->uidUrl(); 0215 0216 redrawBookmarks(); 0217 } 0218 0219 void 0220 ProgressWidget::trackPositionChanged( qint64 position ) 0221 { 0222 m_slider->setSliderValue( position ); 0223 0224 // update the enabled state. Phonon determines isSeekable sometimes too late. 0225 m_slider->setEnabled( (m_slider->maximum() > 0) && The::engineController()->isSeekable() ); 0226 if ( !m_slider->isEnabled() ) 0227 drawTimeDisplay( position ); 0228 } 0229 0230 0231 void 0232 ProgressWidget::redrawBookmarks( const QString *BookmarkName ) 0233 { 0234 DEBUG_BLOCK 0235 m_slider->clearTriangles(); 0236 if ( The::engineController()->currentTrack() ) 0237 { 0238 Meta::TrackPtr track = The::engineController()->currentTrack(); 0239 if ( track->has<Capabilities::TimecodeLoadCapability>() ) 0240 { 0241 Capabilities::TimecodeLoadCapability *tcl = track->create<Capabilities::TimecodeLoadCapability>(); 0242 BookmarkList list = tcl->loadTimecodes(); 0243 debug() << "found " << list.count() << " timecodes on this track"; 0244 foreach( AmarokUrlPtr url, list ) 0245 { 0246 if ( url->command() == "play" ) 0247 { 0248 0249 if ( url->args().keys().contains( "pos" ) ) 0250 { 0251 int pos = url->args().value( "pos" ).toDouble() * 1000; 0252 debug() << "showing timecode: " << url->name() << " at " << pos ; 0253 addBookmark( url->name(), pos, ( BookmarkName && BookmarkName == url->name() )); 0254 } 0255 } 0256 } 0257 delete tcl; 0258 } 0259 } 0260 } 0261 0262 void ProgressWidget::mousePressEvent(QMouseEvent* e) 0263 { 0264 QWidget* widgetUnderCursor = childAt(e->pos()); 0265 if( widgetUnderCursor == m_timeLabelLeft || 0266 widgetUnderCursor == m_timeLabelRight ) 0267 { 0268 // user clicked on one of the time labels, switch display 0269 AmarokConfig::setLeftTimeDisplayRemaining( !AmarokConfig::leftTimeDisplayRemaining() ); 0270 drawTimeDisplay( The::engineController()->trackPositionMs() ); 0271 updateTimeLabelTooltips(); 0272 } 0273 0274 QWidget::mousePressEvent(e); 0275 } 0276 0277 QSize ProgressWidget::sizeHint() const 0278 { 0279 //int height = fontMetrics().boundingRect( "123456789:-" ).height(); 0280 return QSize( width(), 12 ); 0281 } 0282