• Skip to content
  • Skip to link menu
KDE 4.7 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

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     QString fileUrl;
00286     if (url.startsWith('/')) {
00287         fileUrl = "file://" % url;
00288     } else {
00289         fileUrl = url;
00290     }
00291 
00292     if (fileUrl == d->media->currentSource().url().toString()) {
00293         return;
00294     }
00295 
00296     d->media->setCurrentSource(Phonon::MediaSource(fileUrl));
00297 }
00298 
00299 QString VideoWidget::url() const
00300 {
00301     return d->media->currentSource().url().toString();
00302 }
00303 
00304 void VideoWidget::setUsedControls(const Controls controls)
00305 {
00306     if (controls == d->shownControls) {
00307         return;
00308     }
00309 
00310     d->shownControls = controls;
00311 
00312     //kDebug()<<"Setting used controls"<<controls;
00313 
00314     QGraphicsLinearLayout *controlsLayout = 0;
00315     if (controls != NoControls && d->controlsWidget == 0) {
00316         d->controlsWidget = new Plasma::Frame(this);
00317         d->controlsWidget->setFrameShadow(Plasma::Frame::Raised);
00318         controlsLayout = new QGraphicsLinearLayout(Qt::Horizontal, d->controlsWidget);
00319         d->hideTimer = new QTimer(this);
00320         connect(d->hideTimer, SIGNAL(timeout()), this, SLOT(hideControlWidget()));
00321     //controls == NoControls
00322     } else if (d->controlsWidget != 0) {
00323         d->controlsWidget->deleteLater();
00324         d->hideTimer->deleteLater();
00325         d->controlsWidget = 0;
00326 
00327         //disconnect all the stuff that wasn't automatically disconnected 'cause widget deaths
00328         disconnect(d->media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State)));
00329         disconnect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64)));
00330         disconnect(d->media, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
00331         disconnect(d->audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
00332         return;
00333     }
00334 
00335     Q_ASSERT(controlsLayout);
00336 
00337     //empty the layout
00338     while (controlsLayout->count() > 0) {
00339         controlsLayout->removeAt(0);
00340     }
00341 
00342     if (controls&Previous) {
00343         if (!d->previousButton) {
00344             d->previousButton = new IconWidget(d->controlsWidget);
00345             d->previousButton->setIcon("media-playback-start");
00346             connect(d->playButton, SIGNAL(clicked()), this, SLOT(PreviousRequested()));
00347         }
00348         controlsLayout->addItem(d->previousButton);
00349     } else {
00350         d->previousButton->deleteLater();
00351         d->previousButton = 0;
00352     }
00353 
00354     if (controls&Play) {
00355         if (!d->playButton) {
00356             d->playButton = new IconWidget(d->controlsWidget);
00357             d->playButton->setIcon("media-playback-start");
00358             connect(d->playButton, SIGNAL(clicked()), this, SLOT(play()));
00359         }
00360         controlsLayout->addItem(d->playButton);
00361     } else {
00362         d->playButton->deleteLater();
00363         d->playButton = 0;
00364     }
00365 
00366     if (controls&Pause) {
00367         if (!d->pauseButton) {
00368             d->pauseButton = new IconWidget(d->controlsWidget);
00369             d->pauseButton->setIcon("media-playback-pause");
00370             connect(d->pauseButton, SIGNAL(clicked()), this, SLOT(pause()));
00371         }
00372         controlsLayout->addItem(d->pauseButton);
00373     } else {
00374         d->pauseButton->deleteLater();
00375         d->pauseButton = 0;
00376     }
00377 
00378     if (controls&Stop) {
00379         if (!d->stopButton) {
00380             d->stopButton = new IconWidget(d->controlsWidget);
00381             d->stopButton->setIcon("media-playback-stop");
00382             connect(d->stopButton, SIGNAL(clicked()), this, SLOT(stop()));
00383         }
00384         controlsLayout->addItem(d->stopButton);
00385     } else {
00386         d->stopButton->deleteLater();
00387         d->stopButton = 0;
00388     }
00389 
00390     if (controls&PlayPause) {
00391         if (!d->playPauseButton) {
00392             d->playPauseButton = new IconWidget(d->controlsWidget);
00393             d->playPauseButton->setIcon("media-playback-start");
00394             connect(d->playPauseButton, SIGNAL(clicked()), this, SLOT(playPause()));
00395         }
00396         controlsLayout->addItem(d->playPauseButton);
00397     } else {
00398         d->playPauseButton->deleteLater();
00399         d->playPauseButton = 0;
00400     }
00401 
00402     if (controls&Next) {
00403         if (!d->nextButton) {
00404             d->nextButton = new IconWidget(d->nextButton);
00405             d->nextButton->setIcon("media-playback-start");
00406             connect(d->nextButton, SIGNAL(clicked()), this, SIGNAL(nextRequested()));
00407         }
00408         controlsLayout->addItem(d->nextButton);
00409     } else {
00410         d->nextButton->deleteLater();
00411         d->nextButton = 0;
00412     }
00413 
00414     connect(d->media, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State)));
00415 
00416 
00417 
00418 
00419     if (controls&Progress) {
00420         if (!d->progress) {
00421             d->progress = new Slider(d->controlsWidget);
00422             d->progress->setMinimum(0);
00423             d->progress->setMaximum(100);
00424             d->progress->setOrientation(Qt::Horizontal);
00425             controlsLayout->setStretchFactor(d->progress, 4);
00426             d->progress->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
00427 
00428             connect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64)));
00429             connect(d->media, SIGNAL(totalTimeChanged(qint64)), SLOT(totalTimeChanged(qint64)));
00430             connect(d->progress, SIGNAL(valueChanged(int)), this, SLOT(setPosition(int)));
00431         }
00432         controlsLayout->addItem(d->progress);
00433     } else {
00434         d->progress->deleteLater();
00435         d->progress = 0;
00436     }
00437 
00438 
00439     if (controls&Volume) {
00440         if (!d->volume) {
00441             d->volume = new Slider(d->controlsWidget);
00442             d->volume->setMinimum(0);
00443             d->volume->setMaximum(100);
00444             d->volume->setValue(100);
00445             d->volume->setOrientation(Qt::Horizontal);
00446             d->volume->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
00447 
00448             connect(d->volume, SIGNAL(valueChanged(int)), SLOT(setVolume(int)));
00449             connect(d->audioOutput, SIGNAL(volumeChanged(qreal)), SLOT(volumeChanged(qreal)));
00450         }
00451         controlsLayout->addItem(d->volume);
00452     } else {
00453         d->volume->deleteLater();
00454         d->volume = 0;
00455     }
00456 
00457 
00458     if (controls&OpenFile) {
00459         if (!d->openFileButton) {
00460             d->openFileButton = new IconWidget(d->controlsWidget);
00461             d->openFileButton->setIcon(KIcon("document-open"));
00462             connect(d->openFileButton, SIGNAL(clicked()), this, SLOT(showOpenFileDialog()));
00463         }
00464         controlsLayout->addItem(d->openFileButton);
00465     } else {
00466         d->openFileButton->deleteLater();
00467         d->openFileButton = 0;
00468     }
00469 
00470     controlsLayout->activate();
00471     d->controlsWidget->setPos(0,-d->controlsWidget->size().height());
00472     d->controlsWidget->resize(size().width(), d->controlsWidget->size().height());
00473     d->controlsWidget->hide();
00474 }
00475 
00476 VideoWidget::Controls VideoWidget::usedControls() const
00477 {
00478     return d->shownControls;
00479 }
00480 
00481 void VideoWidget::play()
00482 {
00483     if (d->media->state() == Phonon::PlayingState) {
00484         return;
00485     }
00486 
00487     d->media->play();
00488 }
00489 
00490 void VideoWidget::pause()
00491 {
00492     if (d->media->state() == Phonon::PausedState) {
00493         return;
00494     }
00495 
00496     d->media->pause();
00497 }
00498 
00499 void VideoWidget::stop()
00500 {
00501     if (d->media->state() == Phonon::StoppedState) {
00502         return;
00503     }
00504 
00505     d->media->stop();
00506 }
00507 
00508 void VideoWidget::seek(qint64 time)
00509 {
00510     if (d->media->currentTime() == time) {
00511         return;
00512     }
00513 
00514     d->media->seek(time);
00515 }
00516 
00517 qint64 VideoWidget::currentTime() const
00518 {
00519     return d->media->currentTime();
00520 }
00521 
00522 qint64 VideoWidget::totalTime() const
00523 {
00524     return d->media->totalTime();
00525 }
00526 
00527 qint64 VideoWidget::remainingTime() const
00528 {
00529     return d->media->remainingTime();
00530 }
00531 
00532 void VideoWidget::setControlsVisible(bool visible)
00533 {
00534     if (d->controlsWidget) {
00535         d->forceControlsVisible = visible;
00536         d->animateControlWidget(visible);
00537     }
00538 }
00539 
00540 bool VideoWidget::controlsVisible() const
00541 {
00542     return d->controlsWidget != 0 && d->controlsWidget->isVisible();
00543 }
00544 
00545 void VideoWidget::setTickInterval(qint64 interval)
00546 {
00547     d->media->setTickInterval(interval);
00548 }
00549 
00550 qint64 VideoWidget::tickInterval() const
00551 {
00552     return d->media->tickInterval();
00553 }
00554 
00555 void VideoWidget::setStyleSheet(const QString &stylesheet)
00556 {
00557     d->videoWidget->setStyleSheet(stylesheet);
00558 }
00559 
00560 QString VideoWidget::styleSheet()
00561 {
00562     return d->videoWidget->styleSheet();
00563 }
00564 
00565 Phonon::VideoWidget *VideoWidget::nativeWidget() const
00566 {
00567     return d->videoWidget;
00568 }
00569 
00570 
00571 void VideoWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
00572 {
00573     QGraphicsProxyWidget::resizeEvent(event);
00574 
00575     if (d->controlsWidget) {
00576         QSize newControlsSize(event->newSize().width(), d->controlsWidget->size().height());
00577         int newHeight = event->newSize().height();
00578         qreal leftMargin, topMargin, rightMargin, bottomMargin;
00579         d->controlsWidget->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
00580 
00581         if (newHeight/5 >= KIconLoader::SizeEnormous) {
00582             newControlsSize.setHeight(KIconLoader::SizeEnormous+topMargin+bottomMargin);
00583         } else if (newHeight/5 >= KIconLoader::SizeHuge) {
00584             newControlsSize.setHeight(KIconLoader::SizeHuge+topMargin+bottomMargin);
00585         } else if (newHeight/5 >= KIconLoader::SizeLarge) {
00586             newControlsSize.setHeight(KIconLoader::SizeLarge+topMargin+bottomMargin);
00587         } else if (newHeight/5 >= KIconLoader::SizeMedium) {
00588             newControlsSize.setHeight(KIconLoader::SizeMedium+topMargin+bottomMargin);
00589         } else {
00590             newControlsSize.setHeight(KIconLoader::SizeSmallMedium+topMargin+bottomMargin);
00591         }
00592         d->controlsWidget->resize(newControlsSize);
00593 
00594         if (d->spaceForControlsAvailable()) {
00595             d->animateControlWidget(false);
00596         }
00597     }
00598 }
00599 
00600 void VideoWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
00601 {
00602     Q_UNUSED(event)
00603 
00604     if (d->controlsWidget &&
00605         !d->forceControlsVisible &&
00606         d->spaceForControlsAvailable()) {
00607         d->animateControlWidget(true);
00608     }
00609 }
00610 
00611 void VideoWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
00612 {
00613     Q_UNUSED(event)
00614 
00615     if (d->controlsWidget && !d->forceControlsVisible) {
00616         d->hideTimer->start(1000);
00617     }
00618 }
00619 
00620 void VideoWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
00621 {
00622     Q_UNUSED(event)
00623 
00624     if (d->forceControlsVisible || !d->controlsWidget) {
00625         return;
00626     }
00627 
00628     d->hideTimer->start(3000);
00629 
00630     if (!d->controlsWidget->isVisible() &&
00631         d->spaceForControlsAvailable()) {
00632         d->animateControlWidget(true);
00633     }
00634 }
00635 
00636 } // namespace Plasma
00637 
00638 #include <videowidget.moc>
00639 

Plasma

Skip menu "Plasma"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.5
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal