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

Plasma

  • plasma
  • widgets
videowidget.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2009 Marco Martin <notmart@gmail.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20#include "videowidget.h"
21
22#include "config-plasma.h"
23
24#include <QUrl>
25#include <QTimer>
26#include <QGraphicsLinearLayout>
27#include <QGraphicsSceneResizeEvent>
28
29#include <kicon.h>
30#include <kiconloader.h>
31
32#ifndef PLASMA_NO_KIO
33#include <kfiledialog.h>
34#else
35#include <QFileDialog>
36#endif
37
38#include <phonon/videowidget.h>
39#include <phonon/mediaobject.h>
40#include <phonon/mediasource.h>
41#include <phonon/audiooutput.h>
42
43#include <plasma/animations/animation.h>
44#include <plasma/widgets/iconwidget.h>
45#include <plasma/widgets/slider.h>
46#include <plasma/widgets/frame.h>
47
48namespace Plasma
49{
50
51class VideoWidgetPrivate
52{
53public:
54 VideoWidgetPrivate(VideoWidget *video)
55 : q(video),
56 ticking(false),
57 forceControlsVisible(false),
58 animation(0),
59 hideTimer(0),
60 shownControls(VideoWidget::NoControls),
61 controlsWidget(0),
62 previousButton(0),
63 playButton(0),
64 pauseButton(0),
65 stopButton(0),
66 playPauseButton(0),
67 nextButton(0),
68 progress(0),
69 volume(0),
70 openFileButton(0)
71 {
72 }
73
74 ~VideoWidgetPrivate()
75 {
76 }
77
78 void playPause();
79 void ticked(qint64 progress);
80 void totalTimeChanged(qint64 time);
81 void setPosition(int newProgress);
82 void setVolume(int value);
83 void volumeChanged(qreal value);
84 void showOpenFileDialog();
85 void openFile(const QString &path);
86 void stateChanged(Phonon::State newState, Phonon::State oldState);
87 void animateControlWidget(bool show);
88 void hideControlWidget();
89 void slidingCompleted();
90 bool spaceForControlsAvailable();
91
92
93 VideoWidget *q;
94
95 Phonon::VideoWidget *videoWidget;
96 Phonon::AudioOutput *audioOutput;
97 Phonon::MediaObject *media;
98
99 bool ticking;
100 bool forceControlsVisible;
101
102 //control widgets
103 Plasma::Animation *animation;
104 QTimer *hideTimer;
105 VideoWidget::Controls shownControls;
106 Plasma::Frame *controlsWidget;
107 IconWidget *previousButton;
108 IconWidget *playButton;
109 IconWidget *pauseButton;
110 IconWidget *stopButton;
111 IconWidget *playPauseButton;
112 IconWidget *nextButton;
113 Slider *progress;
114 Slider *volume;
115 IconWidget *openFileButton;
116};
117
118void VideoWidgetPrivate::playPause()
119{
120 if (media->state() == Phonon::PlayingState) {
121 media->pause();
122 } else {
123 media->play();
124 }
125}
126
127void VideoWidgetPrivate::ticked(qint64 newProgress)
128{
129 ticking = true;
130 progress->setValue(newProgress);
131 ticking = false;
132}
133
134void VideoWidgetPrivate::totalTimeChanged(qint64 time)
135{
136 ticking = true;
137 //FIXME: this will break for veeery long stuff, butPhonon::SeekSlider seems to have the same problem
138 progress->setRange(0, time);
139 ticking = false;
140}
141
142void VideoWidgetPrivate::setPosition(int progress)
143{
144 if (!ticking) {
145 media->seek(progress);
146 }
147}
148
149void VideoWidgetPrivate::setVolume(int value)
150{
151 audioOutput->setVolume(qreal(value)/100.0);
152}
153
154void VideoWidgetPrivate::volumeChanged(qreal value)
155{
156 volume->setValue(value*100);
157}
158
159void VideoWidgetPrivate::showOpenFileDialog()
160{
161#ifndef PLASMA_NO_KIO
162 openFile(KFileDialog::getOpenFileName());
163#else
164 openFile(QFileDialog::getOpenFileName());
165#endif
166}
167
168void VideoWidgetPrivate::openFile(const QString &path)
169{
170 media->setCurrentSource(Phonon::MediaSource(path));
171 media->play();
172}
173
174void VideoWidgetPrivate::stateChanged(Phonon::State newState, Phonon::State oldState)
175{
176 Q_UNUSED(oldState)
177
178 if (playPauseButton) {
179 if (newState == Phonon::PlayingState) {
180 playPauseButton->setIcon("media-playback-pause");
181 } else {
182 playPauseButton->setIcon("media-playback-start");
183 }
184 }
185}
186
187void VideoWidgetPrivate::animateControlWidget(bool show)
188{
189 if (!controlsWidget || controlsWidget->isVisible() == show) {
190 return;
191 }
192
193 const int distance = controlsWidget->size().height();
194 if (!controlsWidget->isVisible()) {
195 controlsWidget->setPos(0, -distance);
196 controlsWidget->show();
197 }
198
199 //clip only when animating
200 q->setFlags(q->flags()|QGraphicsItem::ItemClipsChildrenToShape);
201
202 if (!animation) {
203 animation = Plasma::Animator::create(Plasma::Animator::SlideAnimation, q);
204 animation->setTargetWidget(controlsWidget);
205 animation->setProperty("movementDirection", Animation::MoveDown);
206 q->connect(animation, SIGNAL(finished()), q, SLOT(slidingCompleted()));
207 }
208
209 animation->setProperty("distance", distance);
210 animation->setProperty("direction", show? QAbstractAnimation::Forward : QAbstractAnimation::Backward);
211 animation->start();
212}
213
214void VideoWidgetPrivate::hideControlWidget()
215{
216 animateControlWidget(false);
217}
218
219void VideoWidgetPrivate::slidingCompleted()
220{
221 if (!controlsWidget) {
222 return;
223 }
224
225 //usually don't clip
226 q->setFlags(q->flags()^QGraphicsItem::ItemClipsChildrenToShape);
227
228 if (controlsWidget->pos().y() < 0) {
229 controlsWidget->hide();
230 } else if (!forceControlsVisible) {
231 hideTimer->start(3000);
232 }
233}
234
235bool VideoWidgetPrivate::spaceForControlsAvailable()
236{
237 if (controlsWidget) {
238 QSize hint = controlsWidget->effectiveSizeHint(Qt::MinimumSize).toSize();
239 return (q->size().width() >= hint.width()) &&
240 (q->size().height() >= hint.height());
241 } else {
242 return true;
243 }
244}
245
246
247
248VideoWidget::VideoWidget(QGraphicsWidget *parent)
249 : QGraphicsProxyWidget(parent),
250 d(new VideoWidgetPrivate(this))
251{
252 d->videoWidget = new Phonon::VideoWidget;
253 d->audioOutput = new Phonon::AudioOutput(this);
254 d->media = new Phonon::MediaObject(this);
255 //it appears that the path has to be created BEFORE setting the proxy
256 Phonon::createPath(d->media, d->videoWidget);
257 Phonon::createPath(d->media, d->audioOutput);
258
259
260 setWidget(d->videoWidget);
261 d->videoWidget->setWindowIcon(QIcon());
262 setAcceptHoverEvents(true);
263
264 connect(d->media, SIGNAL(tick(qint64)), this, SIGNAL(tick(qint64)));
265 connect(d->media, SIGNAL(aboutToFinish()), this, SIGNAL(aboutToFinish()));
266}
267
268VideoWidget::~VideoWidget()
269{
270 delete d;
271}
272
273Phonon::MediaObject *VideoWidget::mediaObject() const
274{
275 return d->media;
276}
277
278Phonon::AudioOutput *VideoWidget::audioOutput() const
279{
280 return d->audioOutput;
281}
282
283void VideoWidget::setUrl(const QString &url)
284{
285 QString fileUrl;
286 if (url.startsWith('/')) {
287 fileUrl = "file://" % url;
288 } else {
289 fileUrl = url;
290 }
291
292 if (fileUrl == d->media->currentSource().url().toString()) {
293 return;
294 }
295
296 d->media->setCurrentSource(Phonon::MediaSource(fileUrl));
297}
298
299QString VideoWidget::url() const
300{
301 return d->media->currentSource().url().toString();
302}
303
304void VideoWidget::setUsedControls(const Controls controls)
305{
306 if (controls == d->shownControls) {
307 return;
308 }
309
310 d->shownControls = controls;
311
312 //kDebug()<<"Setting used controls"<<controls;
313
314 QGraphicsLinearLayout *controlsLayout = 0;
315 if (controls != NoControls && d->controlsWidget == 0) {
316 d->controlsWidget = new Plasma::Frame(this);
317 d->controlsWidget->setFrameShadow(Plasma::Frame::Raised);
318 controlsLayout = new QGraphicsLinearLayout(Qt::Horizontal, d->controlsWidget);
319 d->hideTimer = new QTimer(this);
320 connect(d->hideTimer, SIGNAL(timeout()), this, SLOT(hideControlWidget()));
321 //controls == NoControls
322 } else if (d->controlsWidget != 0) {
323 d->controlsWidget->deleteLater();
324 d->hideTimer->deleteLater();
325 d->controlsWidget = 0;
326
327 //disconnect all the stuff that wasn't automatically disconnected 'cause widget deaths
328 disconnect(d->media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(stateChanged(Phonon::State,Phonon::State)));
329 disconnect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64)));
330 disconnect(d->media, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
331 disconnect(d->audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
332 return;
333 }
334
335 Q_ASSERT(controlsLayout);
336
337 //empty the layout
338 while (controlsLayout->count() > 0) {
339 controlsLayout->removeAt(0);
340 }
341
342 if (controls&Previous) {
343 if (!d->previousButton) {
344 d->previousButton = new IconWidget(d->controlsWidget);
345 d->previousButton->setIcon("media-playback-start");
346 connect(d->playButton, SIGNAL(clicked()), this, SLOT(PreviousRequested()));
347 }
348 controlsLayout->addItem(d->previousButton);
349 } else {
350 d->previousButton->deleteLater();
351 d->previousButton = 0;
352 }
353
354 if (controls&Play) {
355 if (!d->playButton) {
356 d->playButton = new IconWidget(d->controlsWidget);
357 d->playButton->setIcon("media-playback-start");
358 connect(d->playButton, SIGNAL(clicked()), this, SLOT(play()));
359 }
360 controlsLayout->addItem(d->playButton);
361 } else {
362 d->playButton->deleteLater();
363 d->playButton = 0;
364 }
365
366 if (controls&Pause) {
367 if (!d->pauseButton) {
368 d->pauseButton = new IconWidget(d->controlsWidget);
369 d->pauseButton->setIcon("media-playback-pause");
370 connect(d->pauseButton, SIGNAL(clicked()), this, SLOT(pause()));
371 }
372 controlsLayout->addItem(d->pauseButton);
373 } else {
374 d->pauseButton->deleteLater();
375 d->pauseButton = 0;
376 }
377
378 if (controls&Stop) {
379 if (!d->stopButton) {
380 d->stopButton = new IconWidget(d->controlsWidget);
381 d->stopButton->setIcon("media-playback-stop");
382 connect(d->stopButton, SIGNAL(clicked()), this, SLOT(stop()));
383 }
384 controlsLayout->addItem(d->stopButton);
385 } else {
386 d->stopButton->deleteLater();
387 d->stopButton = 0;
388 }
389
390 if (controls&PlayPause) {
391 if (!d->playPauseButton) {
392 d->playPauseButton = new IconWidget(d->controlsWidget);
393 d->playPauseButton->setIcon("media-playback-start");
394 connect(d->playPauseButton, SIGNAL(clicked()), this, SLOT(playPause()));
395 }
396 controlsLayout->addItem(d->playPauseButton);
397 } else {
398 d->playPauseButton->deleteLater();
399 d->playPauseButton = 0;
400 }
401
402 if (controls&Next) {
403 if (!d->nextButton) {
404 d->nextButton = new IconWidget(d->nextButton);
405 d->nextButton->setIcon("media-playback-start");
406 connect(d->nextButton, SIGNAL(clicked()), this, SIGNAL(nextRequested()));
407 }
408 controlsLayout->addItem(d->nextButton);
409 } else {
410 d->nextButton->deleteLater();
411 d->nextButton = 0;
412 }
413
414 connect(d->media, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(stateChanged(Phonon::State,Phonon::State)));
415
416
417
418
419 if (controls&Progress) {
420 if (!d->progress) {
421 d->progress = new Slider(d->controlsWidget);
422 d->progress->setMinimum(0);
423 d->progress->setMaximum(100);
424 d->progress->setOrientation(Qt::Horizontal);
425 controlsLayout->setStretchFactor(d->progress, 4);
426 d->progress->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
427
428 connect(d->media, SIGNAL(tick(qint64)), this, SLOT(ticked(qint64)));
429 connect(d->media, SIGNAL(totalTimeChanged(qint64)), SLOT(totalTimeChanged(qint64)));
430 connect(d->progress, SIGNAL(valueChanged(int)), this, SLOT(setPosition(int)));
431 }
432 controlsLayout->addItem(d->progress);
433 } else {
434 d->progress->deleteLater();
435 d->progress = 0;
436 }
437
438
439 if (controls&Volume) {
440 if (!d->volume) {
441 d->volume = new Slider(d->controlsWidget);
442 d->volume->setMinimum(0);
443 d->volume->setMaximum(100);
444 d->volume->setValue(100);
445 d->volume->setOrientation(Qt::Horizontal);
446 d->volume->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
447
448 connect(d->volume, SIGNAL(valueChanged(int)), SLOT(setVolume(int)));
449 connect(d->audioOutput, SIGNAL(volumeChanged(qreal)), SLOT(volumeChanged(qreal)));
450 }
451 controlsLayout->addItem(d->volume);
452 } else {
453 d->volume->deleteLater();
454 d->volume = 0;
455 }
456
457
458 if (controls&OpenFile) {
459 if (!d->openFileButton) {
460 d->openFileButton = new IconWidget(d->controlsWidget);
461 d->openFileButton->setIcon(KIcon("document-open"));
462 connect(d->openFileButton, SIGNAL(clicked()), this, SLOT(showOpenFileDialog()));
463 }
464 controlsLayout->addItem(d->openFileButton);
465 } else {
466 d->openFileButton->deleteLater();
467 d->openFileButton = 0;
468 }
469
470 controlsLayout->activate();
471 d->controlsWidget->setPos(0,-d->controlsWidget->size().height());
472 d->controlsWidget->resize(size().width(), d->controlsWidget->size().height());
473 d->controlsWidget->hide();
474}
475
476VideoWidget::Controls VideoWidget::usedControls() const
477{
478 return d->shownControls;
479}
480
481void VideoWidget::play()
482{
483 if (d->media->state() == Phonon::PlayingState) {
484 return;
485 }
486
487 d->media->play();
488}
489
490void VideoWidget::pause()
491{
492 if (d->media->state() == Phonon::PausedState) {
493 return;
494 }
495
496 d->media->pause();
497}
498
499void VideoWidget::stop()
500{
501 if (d->media->state() == Phonon::StoppedState) {
502 return;
503 }
504
505 d->media->stop();
506}
507
508void VideoWidget::seek(qint64 time)
509{
510 if (d->media->currentTime() == time) {
511 return;
512 }
513
514 d->media->seek(time);
515}
516
517qint64 VideoWidget::currentTime() const
518{
519 return d->media->currentTime();
520}
521
522qint64 VideoWidget::totalTime() const
523{
524 return d->media->totalTime();
525}
526
527qint64 VideoWidget::remainingTime() const
528{
529 return d->media->remainingTime();
530}
531
532void VideoWidget::setControlsVisible(bool visible)
533{
534 if (d->controlsWidget) {
535 d->forceControlsVisible = visible;
536 d->animateControlWidget(visible);
537 }
538}
539
540bool VideoWidget::controlsVisible() const
541{
542 return d->controlsWidget != 0 && d->controlsWidget->isVisible();
543}
544
545void VideoWidget::setTickInterval(qint64 interval)
546{
547 d->media->setTickInterval(interval);
548}
549
550qint64 VideoWidget::tickInterval() const
551{
552 return d->media->tickInterval();
553}
554
555void VideoWidget::setStyleSheet(const QString &stylesheet)
556{
557 d->videoWidget->setStyleSheet(stylesheet);
558}
559
560QString VideoWidget::styleSheet()
561{
562 return d->videoWidget->styleSheet();
563}
564
565Phonon::VideoWidget *VideoWidget::nativeWidget() const
566{
567 return d->videoWidget;
568}
569
570
571void VideoWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
572{
573 QGraphicsProxyWidget::resizeEvent(event);
574
575 if (d->controlsWidget) {
576 QSize newControlsSize(event->newSize().width(), d->controlsWidget->size().height());
577 int newHeight = event->newSize().height();
578 qreal leftMargin, topMargin, rightMargin, bottomMargin;
579 d->controlsWidget->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
580
581 if (newHeight/5 >= KIconLoader::SizeEnormous) {
582 newControlsSize.setHeight(KIconLoader::SizeEnormous+topMargin+bottomMargin);
583 } else if (newHeight/5 >= KIconLoader::SizeHuge) {
584 newControlsSize.setHeight(KIconLoader::SizeHuge+topMargin+bottomMargin);
585 } else if (newHeight/5 >= KIconLoader::SizeLarge) {
586 newControlsSize.setHeight(KIconLoader::SizeLarge+topMargin+bottomMargin);
587 } else if (newHeight/5 >= KIconLoader::SizeMedium) {
588 newControlsSize.setHeight(KIconLoader::SizeMedium+topMargin+bottomMargin);
589 } else {
590 newControlsSize.setHeight(KIconLoader::SizeSmallMedium+topMargin+bottomMargin);
591 }
592 d->controlsWidget->resize(newControlsSize);
593
594 if (d->spaceForControlsAvailable()) {
595 d->animateControlWidget(false);
596 }
597 }
598}
599
600void VideoWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
601{
602 Q_UNUSED(event)
603
604 if (d->controlsWidget &&
605 !d->forceControlsVisible &&
606 d->spaceForControlsAvailable()) {
607 d->animateControlWidget(true);
608 }
609}
610
611void VideoWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
612{
613 Q_UNUSED(event)
614
615 if (d->controlsWidget && !d->forceControlsVisible) {
616 d->hideTimer->start(1000);
617 }
618}
619
620void VideoWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
621{
622 Q_UNUSED(event)
623
624 if (d->forceControlsVisible || !d->controlsWidget) {
625 return;
626 }
627
628 d->hideTimer->start(3000);
629
630 if (!d->controlsWidget->isVisible() &&
631 d->spaceForControlsAvailable()) {
632 d->animateControlWidget(true);
633 }
634}
635
636} // namespace Plasma
637
638#include <videowidget.moc>
639
animation.h
IconWidget
Provides a generic icon.
Plasma::Animation
Abstract representation of a single animation.
Definition: animation.h:47
Plasma::Animator::create
static Plasma::Animation * create(Animator::Animation type, QObject *parent=0)
Factory to build new animation objects.
Definition: animator.cpp:61
Plasma::Animator::SlideAnimation
@ SlideAnimation
Definition: animator.h:65
Plasma::Frame
A widget that provides a simple frame.
Definition: frame.h:44
Plasma::Frame::Raised
@ Raised
Definition: frame.h:55
Plasma::IconWidget
Definition: iconwidget.h:57
Plasma::Slider
Provides a plasma-themed QSlider.
Definition: slider.h:40
Plasma::VideoWidget::Previous
@ Previous
Definition: videowidget.h:69
Plasma::VideoWidget::PlayPause
@ PlayPause
Definition: videowidget.h:68
Plasma::VideoWidget::Play
@ Play
Definition: videowidget.h:65
Plasma::VideoWidget::Next
@ Next
Definition: videowidget.h:70
Plasma::VideoWidget::OpenFile
@ OpenFile
Definition: videowidget.h:73
Plasma::VideoWidget::Progress
@ Progress
Definition: videowidget.h:71
Plasma::VideoWidget::NoControls
@ NoControls
Definition: videowidget.h:64
Plasma::VideoWidget::Stop
@ Stop
Definition: videowidget.h:67
Plasma::VideoWidget::Pause
@ Pause
Definition: videowidget.h:66
Plasma::VideoWidget::Volume
@ Volume
Definition: videowidget.h:72
Plasma::VideoWidget::stop
void stop()
Stop the current file.
Definition: videowidget.cpp:499
Plasma::VideoWidget::tick
void tick(qint64 time)
Emitted regularly when the playing is progressing.
Plasma::VideoWidget::url
QString url
Definition: videowidget.h:52
Plasma::VideoWidget::pause
void pause()
Pause the current file.
Definition: videowidget.cpp:490
Plasma::VideoWidget::nextRequested
void nextRequested()
The user pressed the "next" button.
Plasma::VideoWidget::aboutToFinish
void aboutToFinish()
Emitted an instant before the playback is finished.
Plasma::VideoWidget::play
void play()
Play the current file.
Definition: videowidget.cpp:481
QGraphicsProxyWidget
QGraphicsWidget
frame.h
iconwidget.h
Plasma::AnimationScriptEngine::animation
QScriptValue animation(const QString &anim)
Definition: animationscriptengine.cpp:55
Plasma
Namespace for everything in libplasma.
Definition: abstractdialogmanager.cpp:25
slider.h
videowidget.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • 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
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal