Plasma
videowidget.cpp
Go to the documentation of this file.
00001 /* 00002 * Copyright 2009 Marco Martin <notmart@gmail.com> 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU Library General Public License as 00006 * published by the Free Software Foundation; either version 2, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details 00013 * 00014 * You should have received a copy of the GNU Library General Public 00015 * License along with this program; if not, write to the 00016 * Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "videowidget.h" 00021 00022 #include "config-plasma.h" 00023 00024 #include <QUrl> 00025 #include <QTimer> 00026 #include <QGraphicsLinearLayout> 00027 #include <QGraphicsSceneResizeEvent> 00028 00029 #include <kicon.h> 00030 #include <kiconloader.h> 00031 00032 #ifndef PLASMA_NO_KIO 00033 #include <kfiledialog.h> 00034 #else 00035 #include <QFileDialog> 00036 #endif 00037 00038 #include <phonon/videowidget.h> 00039 #include <phonon/mediaobject.h> 00040 #include <phonon/mediasource.h> 00041 #include <phonon/audiooutput.h> 00042 00043 #include <plasma/animations/animation.h> 00044 #include <plasma/widgets/iconwidget.h> 00045 #include <plasma/widgets/slider.h> 00046 #include <plasma/widgets/frame.h> 00047 00048 namespace Plasma 00049 { 00050 00051 class VideoWidgetPrivate 00052 { 00053 public: 00054 VideoWidgetPrivate(VideoWidget *video) 00055 : q(video), 00056 ticking(false), 00057 forceControlsVisible(false), 00058 animation(0), 00059 hideTimer(0), 00060 shownControls(VideoWidget::NoControls), 00061 controlsWidget(0), 00062 previousButton(0), 00063 playButton(0), 00064 pauseButton(0), 00065 stopButton(0), 00066 playPauseButton(0), 00067 nextButton(0), 00068 progress(0), 00069 volume(0), 00070 openFileButton(0) 00071 { 00072 } 00073 00074 ~VideoWidgetPrivate() 00075 { 00076 } 00077 00078 void playPause(); 00079 void ticked(qint64 progress); 00080 void totalTimeChanged(qint64 time); 00081 void setPosition(int newProgress); 00082 void setVolume(int value); 00083 void volumeChanged(qreal value); 00084 void showOpenFileDialog(); 00085 void openFile(const QString &path); 00086 void stateChanged(Phonon::State newState, Phonon::State oldState); 00087 void animateControlWidget(bool show); 00088 void hideControlWidget(); 00089 void slidingCompleted(); 00090 bool spaceForControlsAvailable(); 00091 00092 00093 VideoWidget *q; 00094 00095 Phonon::VideoWidget *videoWidget; 00096 Phonon::AudioOutput *audioOutput; 00097 Phonon::MediaObject *media; 00098 00099 bool ticking; 00100 bool forceControlsVisible; 00101 00102 //control widgets 00103 Plasma::Animation *animation; 00104 QTimer *hideTimer; 00105 VideoWidget::Controls shownControls; 00106 Plasma::Frame *controlsWidget; 00107 IconWidget *previousButton; 00108 IconWidget *playButton; 00109 IconWidget *pauseButton; 00110 IconWidget *stopButton; 00111 IconWidget *playPauseButton; 00112 IconWidget *nextButton; 00113 Slider *progress; 00114 Slider *volume; 00115 IconWidget *openFileButton; 00116 }; 00117 00118 void VideoWidgetPrivate::playPause() 00119 { 00120 if (media->state() == Phonon::PlayingState) { 00121 media->pause(); 00122 } else { 00123 media->play(); 00124 } 00125 } 00126 00127 void VideoWidgetPrivate::ticked(qint64 newProgress) 00128 { 00129 ticking = true; 00130 progress->setValue(newProgress); 00131 ticking = false; 00132 } 00133 00134 void VideoWidgetPrivate::totalTimeChanged(qint64 time) 00135 { 00136 ticking = true; 00137 //FIXME: this will break for veeery long stuff, butPhonon::SeekSlider seems to have the same problem 00138 progress->setRange(0, time); 00139 ticking = false; 00140 } 00141 00142 void VideoWidgetPrivate::setPosition(int progress) 00143 { 00144 if (!ticking) { 00145 media->seek(progress); 00146 } 00147 } 00148 00149 void VideoWidgetPrivate::setVolume(int value) 00150 { 00151 audioOutput->setVolume(qreal(value)/100.0); 00152 } 00153 00154 void VideoWidgetPrivate::volumeChanged(qreal value) 00155 { 00156 volume->setValue(value*100); 00157 } 00158 00159 void VideoWidgetPrivate::showOpenFileDialog() 00160 { 00161 #ifndef PLASMA_NO_KIO 00162 openFile(KFileDialog::getOpenFileName()); 00163 #else 00164 openFile(QFileDialog::getOpenFileName()); 00165 #endif 00166 } 00167 00168 void VideoWidgetPrivate::openFile(const QString &path) 00169 { 00170 media->setCurrentSource(Phonon::MediaSource(path)); 00171 media->play(); 00172 } 00173 00174 void VideoWidgetPrivate::stateChanged(Phonon::State newState, Phonon::State oldState) 00175 { 00176 Q_UNUSED(oldState) 00177 00178 if (playPauseButton) { 00179 if (newState == Phonon::PlayingState) { 00180 playPauseButton->setIcon("media-playback-pause"); 00181 } else { 00182 playPauseButton->setIcon("media-playback-start"); 00183 } 00184 } 00185 } 00186 00187 void VideoWidgetPrivate::animateControlWidget(bool show) 00188 { 00189 if (!controlsWidget || controlsWidget->isVisible() == show) { 00190 return; 00191 } 00192 00193 const int distance = controlsWidget->size().height(); 00194 if (!controlsWidget->isVisible()) { 00195 controlsWidget->setPos(0, -distance); 00196 controlsWidget->show(); 00197 } 00198 00199 //clip only when animating 00200 q->setFlags(q->flags()|QGraphicsItem::ItemClipsChildrenToShape); 00201 00202 if (!animation) { 00203 animation = Plasma::Animator::create(Plasma::Animator::SlideAnimation, q); 00204 animation->setTargetWidget(controlsWidget); 00205 animation->setProperty("movementDirection", Animation::MoveDown); 00206 q->connect(animation, SIGNAL(finished()), q, SLOT(slidingCompleted())); 00207 } 00208 00209 animation->setProperty("distance", distance); 00210 animation->setProperty("direction", show? QAbstractAnimation::Forward : QAbstractAnimation::Backward); 00211 animation->start(); 00212 } 00213 00214 void VideoWidgetPrivate::hideControlWidget() 00215 { 00216 animateControlWidget(false); 00217 } 00218 00219 void VideoWidgetPrivate::slidingCompleted() 00220 { 00221 if (!controlsWidget) { 00222 return; 00223 } 00224 00225 //usually don't clip 00226 q->setFlags(q->flags()^QGraphicsItem::ItemClipsChildrenToShape); 00227 00228 if (controlsWidget->pos().y() < 0) { 00229 controlsWidget->hide(); 00230 } else if (!forceControlsVisible) { 00231 hideTimer->start(3000); 00232 } 00233 } 00234 00235 bool VideoWidgetPrivate::spaceForControlsAvailable() 00236 { 00237 if (controlsWidget) { 00238 QSize hint = controlsWidget->effectiveSizeHint(Qt::MinimumSize).toSize(); 00239 return (q->size().width() >= hint.width()) && 00240 (q->size().height() >= hint.height()); 00241 } else { 00242 return true; 00243 } 00244 } 00245 00246 00247 00248 VideoWidget::VideoWidget(QGraphicsWidget *parent) 00249 : QGraphicsProxyWidget(parent), 00250 d(new VideoWidgetPrivate(this)) 00251 { 00252 d->videoWidget = new Phonon::VideoWidget; 00253 d->audioOutput = new Phonon::AudioOutput(this); 00254 d->media = new Phonon::MediaObject(this); 00255 //it appears that the path has to be created BEFORE setting the proxy 00256 Phonon::createPath(d->media, d->videoWidget); 00257 Phonon::createPath(d->media, d->audioOutput); 00258 00259 00260 setWidget(d->videoWidget); 00261 d->videoWidget->setWindowIcon(QIcon()); 00262 setAcceptHoverEvents(true); 00263 00264 connect(d->media, SIGNAL(tick(qint64)), this, SIGNAL(tick(qint64))); 00265 connect(d->media, SIGNAL(aboutToFinish()), this, SIGNAL(aboutToFinish())); 00266 } 00267 00268 VideoWidget::~VideoWidget() 00269 { 00270 delete d; 00271 } 00272 00273 Phonon::MediaObject *VideoWidget::mediaObject() const 00274 { 00275 return d->media; 00276 } 00277 00278 Phonon::AudioOutput *VideoWidget::audioOutput() const 00279 { 00280 return d->audioOutput; 00281 } 00282 00283 void VideoWidget::setUrl(const QString &url) 00284 { 00285 d->media->setCurrentSource(Phonon::MediaSource(url)); 00286 } 00287 00288 QString VideoWidget::url() const 00289 { 00290 return d->media->currentSource().url().toString(); 00291 } 00292 00293 void VideoWidget::setUsedControls(const Controls controls) 00294 { 00295 d->shownControls = controls; 00296 00297 //kDebug()<<"Setting used controls"<<controls; 00298 00299 QGraphicsLinearLayout *controlsLayout = 0; 00300 if (controls != NoControls && d->controlsWidget == 0) { 00301 d->controlsWidget = new Plasma::Frame(this); 00302 d->controlsWidget->setFrameShadow(Plasma::Frame::Raised); 00303 controlsLayout = new QGraphicsLinearLayout(Qt::Horizontal, d->controlsWidget); 00304 d->hideTimer = new QTimer(this); 00305 connect(d->hideTimer, SIGNAL(timeout()), this, SLOT(hideControlWidget())); 00306 //controls == NoControls 00307 } else if (d->controlsWidget != 0) { 00308 d->controlsWidget->deleteLater(); 00309 d->hideTimer->deleteLater(); 00310 d->controlsWidget = 0; 00311 00312 //disconnect all the stuff that wasn't automatically disconnected 'cause widget deaths 00313 disconnect(d->media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State))); 00314 disconnect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64))); 00315 disconnect(d->media, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64))); 00316 disconnect(d->audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal))); 00317 return; 00318 } 00319 00320 Q_ASSERT(controlsLayout); 00321 00322 //empty the layout 00323 while (controlsLayout->count() > 0) { 00324 controlsLayout->removeAt(0); 00325 } 00326 00327 if (controls&Previous) { 00328 if (!d->previousButton) { 00329 d->previousButton = new IconWidget(d->controlsWidget); 00330 d->previousButton->setIcon("media-playback-start"); 00331 connect(d->playButton, SIGNAL(clicked()), this, SLOT(PreviousRequested())); 00332 } 00333 controlsLayout->addItem(d->previousButton); 00334 } else { 00335 d->previousButton->deleteLater(); 00336 d->previousButton = 0; 00337 } 00338 00339 if (controls&Play) { 00340 if (!d->playButton) { 00341 d->playButton = new IconWidget(d->controlsWidget); 00342 d->playButton->setIcon("media-playback-start"); 00343 connect(d->playButton, SIGNAL(clicked()), this, SLOT(play())); 00344 } 00345 controlsLayout->addItem(d->playButton); 00346 } else { 00347 d->playButton->deleteLater(); 00348 d->playButton = 0; 00349 } 00350 00351 if (controls&Pause) { 00352 if (!d->pauseButton) { 00353 d->pauseButton = new IconWidget(d->controlsWidget); 00354 d->pauseButton->setIcon("media-playback-pause"); 00355 connect(d->pauseButton, SIGNAL(clicked()), this, SLOT(pause())); 00356 } 00357 controlsLayout->addItem(d->pauseButton); 00358 } else { 00359 d->pauseButton->deleteLater(); 00360 d->pauseButton = 0; 00361 } 00362 00363 if (controls&Stop) { 00364 if (!d->stopButton) { 00365 d->stopButton = new IconWidget(d->controlsWidget); 00366 d->stopButton->setIcon("media-playback-stop"); 00367 connect(d->stopButton, SIGNAL(clicked()), this, SLOT(stop())); 00368 } 00369 controlsLayout->addItem(d->stopButton); 00370 } else { 00371 d->stopButton->deleteLater(); 00372 d->stopButton = 0; 00373 } 00374 00375 if (controls&PlayPause) { 00376 if (!d->playPauseButton) { 00377 d->playPauseButton = new IconWidget(d->controlsWidget); 00378 d->playPauseButton->setIcon("media-playback-start"); 00379 connect(d->playPauseButton, SIGNAL(clicked()), this, SLOT(playPause())); 00380 } 00381 controlsLayout->addItem(d->playPauseButton); 00382 } else { 00383 d->playPauseButton->deleteLater(); 00384 d->playPauseButton = 0; 00385 } 00386 00387 if (controls&Next) { 00388 if (!d->nextButton) { 00389 d->nextButton = new IconWidget(d->nextButton); 00390 d->nextButton->setIcon("media-playback-start"); 00391 connect(d->nextButton, SIGNAL(clicked()), this, SIGNAL(nextRequested())); 00392 } 00393 controlsLayout->addItem(d->nextButton); 00394 } else { 00395 d->nextButton->deleteLater(); 00396 d->nextButton = 0; 00397 } 00398 00399 connect(d->media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State))); 00400 00401 00402 00403 00404 if (controls&Progress) { 00405 if (!d->progress) { 00406 d->progress = new Slider(d->controlsWidget); 00407 d->progress->setMinimum(0); 00408 d->progress->setMaximum(100); 00409 d->progress->setOrientation(Qt::Horizontal); 00410 controlsLayout->setStretchFactor(d->progress, 4); 00411 d->progress->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); 00412 00413 connect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64))); 00414 connect(d->media, SIGNAL(totalTimeChanged(qint64)), SLOT(totalTimeChanged(qint64))); 00415 connect(d->progress, SIGNAL(valueChanged(int)), this, SLOT(setPosition(int))); 00416 } 00417 controlsLayout->addItem(d->progress); 00418 } else { 00419 d->progress->deleteLater(); 00420 d->progress = 0; 00421 } 00422 00423 00424 if (controls&Volume) { 00425 if (!d->volume) { 00426 d->volume = new Slider(d->controlsWidget); 00427 d->volume->setMinimum(0); 00428 d->volume->setMaximum(100); 00429 d->volume->setValue(100); 00430 d->volume->setOrientation(Qt::Horizontal); 00431 d->volume->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); 00432 00433 connect(d->volume, SIGNAL(valueChanged(int)), SLOT(setVolume(int))); 00434 connect(d->audioOutput, SIGNAL(volumeChanged(qreal)), SLOT(volumeChanged(qreal))); 00435 } 00436 controlsLayout->addItem(d->volume); 00437 } else { 00438 d->volume->deleteLater(); 00439 d->volume = 0; 00440 } 00441 00442 00443 if (controls&OpenFile) { 00444 if (!d->openFileButton) { 00445 d->openFileButton = new IconWidget(d->controlsWidget); 00446 d->openFileButton->setIcon(KIcon("document-open")); 00447 connect(d->openFileButton, SIGNAL(clicked()), this, SLOT(showOpenFileDialog())); 00448 } 00449 controlsLayout->addItem(d->openFileButton); 00450 } else { 00451 d->openFileButton->deleteLater(); 00452 d->openFileButton = 0; 00453 } 00454 00455 controlsLayout->activate(); 00456 d->controlsWidget->setPos(0,-d->controlsWidget->size().height()); 00457 d->controlsWidget->resize(size().width(), d->controlsWidget->size().height()); 00458 d->controlsWidget->hide(); 00459 } 00460 00461 VideoWidget::Controls VideoWidget::usedControls() const 00462 { 00463 return d->shownControls; 00464 } 00465 00466 void VideoWidget::play() 00467 { 00468 d->media->play(); 00469 } 00470 00471 void VideoWidget::pause() 00472 { 00473 d->media->pause(); 00474 } 00475 00476 void VideoWidget::stop() 00477 { 00478 d->media->stop(); 00479 } 00480 00481 void VideoWidget::seek(qint64 time) 00482 { 00483 d->media->seek(time); 00484 } 00485 00486 qint64 VideoWidget::currentTime() const 00487 { 00488 return d->media->currentTime(); 00489 } 00490 00491 qint64 VideoWidget::totalTime() const 00492 { 00493 return d->media->totalTime(); 00494 } 00495 00496 qint64 VideoWidget::remainingTime() const 00497 { 00498 return d->media->remainingTime(); 00499 } 00500 00501 void VideoWidget::setControlsVisible(bool visible) 00502 { 00503 if (d->controlsWidget) { 00504 d->forceControlsVisible = visible; 00505 d->animateControlWidget(visible); 00506 } 00507 } 00508 00509 bool VideoWidget::controlsVisible() const 00510 { 00511 return d->controlsWidget != 0 && d->controlsWidget->isVisible(); 00512 } 00513 00514 void VideoWidget::setStyleSheet(const QString &stylesheet) 00515 { 00516 d->videoWidget->setStyleSheet(stylesheet); 00517 } 00518 00519 QString VideoWidget::styleSheet() 00520 { 00521 return d->videoWidget->styleSheet(); 00522 } 00523 00524 Phonon::VideoWidget *VideoWidget::nativeWidget() const 00525 { 00526 return d->videoWidget; 00527 } 00528 00529 00530 void VideoWidget::resizeEvent(QGraphicsSceneResizeEvent *event) 00531 { 00532 QGraphicsProxyWidget::resizeEvent(event); 00533 00534 if (d->controlsWidget) { 00535 QSize newControlsSize(event->newSize().width(), d->controlsWidget->size().height()); 00536 int newHeight = event->newSize().height(); 00537 qreal leftMargin, topMargin, rightMargin, bottomMargin; 00538 d->controlsWidget->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin); 00539 00540 if (newHeight/5 >= KIconLoader::SizeEnormous) { 00541 newControlsSize.setHeight(KIconLoader::SizeEnormous+topMargin+bottomMargin); 00542 } else if (newHeight/5 >= KIconLoader::SizeHuge) { 00543 newControlsSize.setHeight(KIconLoader::SizeHuge+topMargin+bottomMargin); 00544 } else if (newHeight/5 >= KIconLoader::SizeLarge) { 00545 newControlsSize.setHeight(KIconLoader::SizeLarge+topMargin+bottomMargin); 00546 } else if (newHeight/5 >= KIconLoader::SizeMedium) { 00547 newControlsSize.setHeight(KIconLoader::SizeMedium+topMargin+bottomMargin); 00548 } else { 00549 newControlsSize.setHeight(KIconLoader::SizeSmallMedium+topMargin+bottomMargin); 00550 } 00551 d->controlsWidget->resize(newControlsSize); 00552 00553 if (d->spaceForControlsAvailable()) { 00554 d->animateControlWidget(false); 00555 } 00556 } 00557 } 00558 00559 void VideoWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event) 00560 { 00561 Q_UNUSED(event) 00562 00563 if (d->controlsWidget && 00564 !d->forceControlsVisible && 00565 d->spaceForControlsAvailable()) { 00566 d->animateControlWidget(true); 00567 } 00568 } 00569 00570 void VideoWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) 00571 { 00572 Q_UNUSED(event) 00573 00574 if (d->controlsWidget && !d->forceControlsVisible) { 00575 d->hideTimer->start(1000); 00576 } 00577 } 00578 00579 void VideoWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event) 00580 { 00581 Q_UNUSED(event) 00582 00583 if (d->forceControlsVisible || !d->controlsWidget) { 00584 return; 00585 } 00586 00587 d->hideTimer->start(3000); 00588 00589 if (!d->controlsWidget->isVisible() && 00590 d->spaceForControlsAvailable()) { 00591 d->animateControlWidget(true); 00592 } 00593 } 00594 00595 } // namespace Plasma 00596 00597 #include <videowidget.moc> 00598
KDE 4.6 API Reference