mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 19:02:48 +00:00
402 lines
12 KiB
C++
402 lines
12 KiB
C++
/* This file is part of the KDE libraries
|
|
Copyright (C) 2016-2019 Ivailo Monev <xakepa10@gmail.com>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License version 2, as published by the Free Software Foundation.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include <QFileDialog>
|
|
#include <QInputDialog>
|
|
#include <QMessageBox>
|
|
#include <QTimer>
|
|
|
|
#include "kdebug.h"
|
|
#include "klocale.h"
|
|
#include "kicon.h"
|
|
#include "kmainwindow.h"
|
|
#include "kstatusbar.h"
|
|
#include "kmediaplayer.h"
|
|
#include "kmediawidget.h"
|
|
#include "ui_kmediawidget.h"
|
|
|
|
class KMediaWidgetPrivate
|
|
{
|
|
public:
|
|
KMediaPlayer *m_player;
|
|
bool m_dragdrop;
|
|
bool m_fullscreen;
|
|
bool m_hiddencontrols;
|
|
QWidget *m_parent;
|
|
QMainWindow *m_parenthack;
|
|
QSize m_parentsizehack;
|
|
int m_timerid;
|
|
QString m_path;
|
|
bool m_replay;
|
|
bool m_visible;
|
|
Ui_KMediaWidgetPrivate *m_ui;
|
|
};
|
|
|
|
KMediaWidget::KMediaWidget(QWidget *parent, KMediaOptions options)
|
|
: QWidget(parent), d(new KMediaWidgetPrivate)
|
|
{
|
|
d->m_ui = new Ui_KMediaWidgetPrivate();
|
|
d->m_ui->setupUi(this);
|
|
d->m_player = new KMediaPlayer(d->m_ui->w_player);
|
|
d->m_dragdrop = (options & DragDrop) != options;
|
|
d->m_fullscreen = (options & FullscreenVideo) != options;
|
|
d->m_hiddencontrols = (options & HiddenControls) != options;
|
|
d->m_parent = parent;
|
|
|
|
d->m_ui->w_play->setIcon(KIcon("media-playback-start"));
|
|
d->m_ui->w_play->setText(i18n("Play"));
|
|
d->m_ui->w_play->setEnabled(false);
|
|
d->m_ui->w_position->setEnabled(false);
|
|
d->m_ui->w_volume->setValue(d->m_player->volume());
|
|
d->m_ui->w_fullscreen->setIcon(KIcon("view-fullscreen"));
|
|
|
|
connect(d->m_ui->w_play, SIGNAL(clicked()), this, SLOT(setPlay()));
|
|
// connect(d->m_ui->w_position, SIGNAL(sliderMoved(int)), this, SLOT(setPosition(int)));
|
|
connect(d->m_ui->w_position, SIGNAL(sliderReleased()), this, SLOT(_setPosition()));
|
|
connect(d->m_ui->w_volume, SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
|
|
connect(d->m_ui->w_fullscreen, SIGNAL(clicked()), SLOT(setFullscreen()));
|
|
|
|
connect(d->m_player, SIGNAL(paused(bool)), this, SLOT(_updatePlay(bool)));
|
|
connect(d->m_player, SIGNAL(loaded()), this, SLOT(_updateLoaded()));
|
|
connect(d->m_player, SIGNAL(seekable(bool)), this, SLOT(_updateSeekable(bool)));
|
|
connect(d->m_player, SIGNAL(position(double)), this, SLOT(_updatePosition(double)));
|
|
connect(d->m_player, SIGNAL(finished()), this, SLOT(_updateFinished()));
|
|
connect(d->m_player, SIGNAL(error(QString)), this, SLOT(_updateError(QString)));
|
|
|
|
if (d->m_dragdrop) {
|
|
setAcceptDrops(true);
|
|
d->m_player->setAcceptDrops(true);
|
|
}
|
|
|
|
if (!d->m_fullscreen) {
|
|
d->m_ui->w_fullscreen->setVisible(false);
|
|
}
|
|
|
|
if (d->m_hiddencontrols) {
|
|
d->m_visible = true;
|
|
setMouseTracking(false);
|
|
}
|
|
}
|
|
|
|
KMediaWidget::~KMediaWidget()
|
|
{
|
|
if (d->m_timerid >= 0) {
|
|
killTimer(d->m_timerid);
|
|
}
|
|
d->m_player->stop();
|
|
d->m_player->deleteLater();
|
|
delete d->m_ui;
|
|
delete d;
|
|
}
|
|
|
|
void KMediaWidget::open(const QString &path)
|
|
{
|
|
// m_path should be updated from _updateLoaded() but that may be too late
|
|
d->m_path = path;
|
|
d->m_replay = false;
|
|
|
|
d->m_ui->w_play->setEnabled(true);
|
|
d->m_ui->w_position->setEnabled(true);
|
|
|
|
d->m_player->load(path);
|
|
|
|
d->m_ui->w_position->setEnabled(d->m_player->isSeekable());
|
|
|
|
if (d->m_hiddencontrols) {
|
|
resetControlsTimer();
|
|
setMouseTracking(true);
|
|
}
|
|
}
|
|
|
|
KMediaPlayer* KMediaWidget::player() const
|
|
{
|
|
return d->m_player;
|
|
}
|
|
|
|
void KMediaWidget::setPlay(const int value)
|
|
{
|
|
// TODO: can the position be stored and restored reliably as well?
|
|
if (d->m_replay && !d->m_path.isEmpty()) {
|
|
open(d->m_path);
|
|
return;
|
|
}
|
|
|
|
bool pause;
|
|
if (value == -1) {
|
|
pause = d->m_player->isPlaying();
|
|
} else {
|
|
pause = bool(value);
|
|
}
|
|
if (pause) {
|
|
d->m_player->pause();
|
|
} else {
|
|
d->m_player->play();
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::setPosition(const int value)
|
|
{
|
|
d->m_player->seek(value);
|
|
}
|
|
|
|
void KMediaWidget::setVolume(const int value)
|
|
{
|
|
d->m_player->setVolume(value);
|
|
}
|
|
|
|
void KMediaWidget::setFullscreen(const int value)
|
|
{
|
|
bool fullscreen;
|
|
if (value == -1) {
|
|
fullscreen = !d->m_player->isFullscreen();
|
|
} else {
|
|
fullscreen = bool(value);
|
|
}
|
|
/*
|
|
Making a QWidget go fullscreen requires quite some magic for X11
|
|
because showFullScreen() requires the parent of the widget to be a
|
|
window (QMainWindow) thus the hack bellow. Asking the parent widget to
|
|
go fullscreen is required to preserve the media controls visible and
|
|
interactive. Note that setting the MPV property is just for consistency
|
|
and possible clients quering it, it does nothing when MPV is embed (as
|
|
of the time of writing this).
|
|
*/
|
|
if (!d->m_parent && (parentWidget() == window()) && !d->m_parenthack) {
|
|
kDebug() << i18n("using parent widget from parentWidget()");
|
|
d->m_parent = parentWidget();
|
|
d->m_parentsizehack = QSize(-1, -1);
|
|
d->m_parenthack = NULL;
|
|
} else if (!d->m_parent && parentWidget()) {
|
|
kWarning() << i18n("creating a parent, detaching widget, starting voodoo dance..");
|
|
d->m_parent = parentWidget();
|
|
d->m_parentsizehack = d->m_parent->size();
|
|
d->m_parenthack = new QMainWindow(d->m_parent);
|
|
}
|
|
|
|
if (fullscreen) {
|
|
if (d->m_parenthack && d->m_parentsizehack.isValid() && d->m_parent) {
|
|
kDebug() << i18n("using parent hack widget");
|
|
d->m_parenthack->setCentralWidget(this);
|
|
d->m_parenthack->showFullScreen();
|
|
} else if (d->m_parent) {
|
|
kDebug() << i18n("using parent widget");
|
|
d->m_parent->showFullScreen();
|
|
} else {
|
|
kWarning() << i18n("cannot set fullscreen state");
|
|
}
|
|
d->m_player->setFullscreen(true);
|
|
} else {
|
|
if (d->m_parenthack && d->m_parentsizehack.isValid() && d->m_parent) {
|
|
kDebug() << i18n("restoring parent from hack widget");
|
|
setParent(d->m_parent);
|
|
resize(d->m_parentsizehack);
|
|
show();
|
|
delete d->m_parenthack;
|
|
d->m_parenthack = NULL;
|
|
d->m_parent = NULL;
|
|
} else if (d->m_parent) {
|
|
kDebug() << i18n("restoring from parent widget");
|
|
d->m_parent->showNormal();
|
|
} else {
|
|
kWarning() << i18n("cannot restore to non-fullscreen state");
|
|
}
|
|
d->m_player->setFullscreen(false);
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::resetControlsTimer()
|
|
{
|
|
if (d->m_timerid >= 0) {
|
|
killTimer(d->m_timerid);
|
|
}
|
|
// do not hide the controls if path is not loaded
|
|
if (!d->m_player->path().isEmpty()) {
|
|
d->m_timerid = startTimer(3000);
|
|
}
|
|
}
|
|
|
|
QSize KMediaWidget::sizeHint() const
|
|
{
|
|
return d->m_ui->w_player->sizeHint();
|
|
}
|
|
|
|
QSize KMediaWidget::minimumSizeHint() const
|
|
{
|
|
if (d->m_fullscreen) {
|
|
return QSize(300, 233);
|
|
}
|
|
return QSize(180, 140);
|
|
}
|
|
|
|
void KMediaWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
|
{
|
|
if (d->m_fullscreen) {
|
|
setFullscreen();
|
|
}
|
|
event->ignore();
|
|
}
|
|
|
|
void KMediaWidget::mouseMoveEvent(QMouseEvent *event)
|
|
{
|
|
if (d->m_hiddencontrols) {
|
|
resetControlsTimer();
|
|
_updateControls(true);
|
|
}
|
|
event->ignore();
|
|
}
|
|
|
|
void KMediaWidget::timerEvent(QTimerEvent *event)
|
|
{
|
|
if (event->timerId() == d->m_timerid
|
|
&& !d->m_ui->w_play->isDown()
|
|
&& !d->m_ui->w_position->isSliderDown()
|
|
&& !d->m_ui->w_volume->isSliderDown()
|
|
&& !d->m_ui->w_fullscreen->isDown()) {
|
|
_updateControls(false);
|
|
event->accept();
|
|
} else {
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::dragEnterEvent(QDragEnterEvent *event)
|
|
{
|
|
if (event->mimeData()->hasUrls()) {
|
|
event->acceptProposedAction();
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::dropEvent(QDropEvent *event)
|
|
{
|
|
const QList<QUrl> urls = event->mimeData()->urls();
|
|
QStringList invalid;
|
|
foreach (const QUrl url, urls) {
|
|
QString urlstring = url.toString();
|
|
if (!d->m_player->isPathSupported(urlstring)) {
|
|
kDebug() << i18n("ignoring unsupported:\n%1", urlstring);
|
|
invalid.append(urlstring);
|
|
continue;
|
|
}
|
|
open(urlstring);
|
|
}
|
|
if (!invalid.isEmpty()) {
|
|
QMessageBox::warning(this, i18n("Invalid paths"),
|
|
i18n("Some paths are invalid:\n%1", invalid.join("\n")));
|
|
} else {
|
|
event->acceptProposedAction();
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::_updateControls(const bool visible)
|
|
{
|
|
if (d->m_hiddencontrols && visible != d->m_visible) {
|
|
d->m_ui->w_frame->setVisible(visible);
|
|
emit controlsHidden(visible);
|
|
d->m_visible = visible;
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::_updatePlay(const bool paused)
|
|
{
|
|
if (paused) {
|
|
d->m_ui->w_play->setIcon(KIcon("media-playback-start"));
|
|
d->m_ui->w_play->setText(i18n("Play"));
|
|
} else {
|
|
d->m_ui->w_play->setIcon(KIcon("media-playback-pause"));
|
|
d->m_ui->w_play->setText(i18n("Pause"));
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::_updateSeekable(const bool seekable)
|
|
{
|
|
d->m_ui->w_position->setEnabled(seekable);
|
|
d->m_ui->w_position->setMaximum(d->m_player->totalTime());
|
|
}
|
|
|
|
void KMediaWidget::_setPosition()
|
|
{
|
|
d->m_player->seek(d->m_ui->w_position->value());
|
|
}
|
|
|
|
void KMediaWidget::_updatePosition(const double seconds)
|
|
{
|
|
// do not update the slider while it's dragged by the user
|
|
if (!d->m_ui->w_position->isSliderDown()) {
|
|
d->m_ui->w_position->setValue(seconds);
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::_updateLoaded()
|
|
{
|
|
d->m_path = d->m_player->path();
|
|
const QString title = d->m_player->title();
|
|
if (!title.isEmpty()) {
|
|
_updateStatus(title);
|
|
}
|
|
_updatePlay(!d->m_player->isPlaying());
|
|
}
|
|
|
|
void KMediaWidget::_updateStatus(const QString string)
|
|
{
|
|
if (d->m_fullscreen) {
|
|
QWidget *windowwidget = window();
|
|
KMainWindow *kmainwindow = qobject_cast<KMainWindow*>(windowwidget);
|
|
if (kmainwindow) {
|
|
kmainwindow->setCaption(string);
|
|
KStatusBar *statusbar = kmainwindow->statusBar();
|
|
if (statusbar) {
|
|
if (d->m_player->isPlaying()) {
|
|
statusbar->showMessage(i18n("Now playing: %1", string));
|
|
} else {
|
|
statusbar->showMessage(string);
|
|
}
|
|
}
|
|
} else if (windowwidget) {
|
|
windowwidget->setWindowTitle(string);
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMediaWidget::_updateFinished()
|
|
{
|
|
d->m_replay = true;
|
|
|
|
if (d->m_hiddencontrols) {
|
|
// show the controls until the next open
|
|
_updateControls(true);
|
|
setMouseTracking(false);
|
|
}
|
|
_updatePlay(true);
|
|
}
|
|
|
|
void KMediaWidget::_updateError(const QString error)
|
|
{
|
|
if (d->m_fullscreen) {
|
|
_updateStatus(error);
|
|
} else {
|
|
// since there are not many ways to indicate an error when
|
|
// there are no extended controls use the play button to do so
|
|
d->m_ui->w_play->setIcon(KIcon("dialog-error"));
|
|
d->m_ui->w_play->setText(i18n("Error"));
|
|
}
|
|
|
|
d->m_ui->w_position->setEnabled(false);
|
|
}
|
|
|
|
|
|
#include "moc_kmediawidget.cpp"
|