From 8216a67d58af0fd709bb3bfb8d0b6073b11cdfed Mon Sep 17 00:00:00 2001 From: =?utf8?q?M=C3=A9ven=20Car?= Date: Sun, 23 Jun 2019 17:36:38 +0200 Subject: [PATCH] InformationPanel: Port from Phonon to QtMultimedia --- .kde-ci.yml | 1 - CMakeLists.txt | 9 +- src/CMakeLists.txt | 10 +- .../information/informationpanelcontent.cpp | 50 ++- .../information/informationpanelcontent.h | 4 +- src/panels/information/mediawidget.cpp | 368 ++++++++++++++++++ .../{phononwidget.h => mediawidget.h} | 39 +- src/panels/information/phononwidget.cpp | 265 ------------- 8 files changed, 424 insertions(+), 322 deletions(-) create mode 100644 src/panels/information/mediawidget.cpp rename src/panels/information/{phononwidget.h => mediawidget.h} (70%) delete mode 100644 src/panels/information/phononwidget.cpp diff --git a/.kde-ci.yml b/.kde-ci.yml index 60ce73499..66f1007b9 100644 --- a/.kde-ci.yml +++ b/.kde-ci.yml @@ -26,7 +26,6 @@ Dependencies: 'frameworks/kcodecs': '@latest-kf6' 'frameworks/kuserfeedback': '@latest-kf6' 'frameworks/kcolorscheme': '@latest-kf6' - 'libraries/phonon': '@latest-kf6' - 'on': ['Linux/Qt6', 'Linux/Qt6Next', 'FreeBSD/Qt6'] 'require': diff --git a/CMakeLists.txt b/CMakeLists.txt index 2a074067e..e3b966eb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,8 +103,6 @@ find_package(KF6 ${KF6_MIN_VERSION} OPTIONAL_COMPONENTS DocTools ) -find_package(Phonon4Qt6 CONFIG REQUIRED) - find_package(PackageKitQt6) set_package_properties(PackageKitQt6 PROPERTIES DESCRIPTION "Software Manager integration" @@ -138,7 +136,12 @@ set_package_properties(KF6BalooWidgets PROPERTIES DESCRIPTION "Baloos Widgets" if (KF6Baloo_FOUND AND KF6BalooWidgets_FOUND) message(STATUS "Baloo packages are found") set(HAVE_BALOO TRUE) -else() + + find_package(Qt6 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS + Multimedia + MultimediaWidgets + ) +else () message(WARNING "Baloo packages not found. They are needed for the metadata features of Dolphin (including the information panel).") endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bf1ed0101..6e982fce8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -425,12 +425,12 @@ if(HAVE_BALOO) panels/information/informationpanel.cpp panels/information/informationpanelcontent.cpp panels/information/pixmapviewer.cpp - panels/information/phononwidget.cpp + panels/information/mediawidget.cpp settings/interface/panelsettingspage.cpp panels/information/informationpanel.h panels/information/informationpanelcontent.h panels/information/pixmapviewer.h - panels/information/phononwidget.h + panels/information/mediawidget.h settings/interface/panelsettingspage.h ) @@ -438,6 +438,10 @@ if(HAVE_BALOO) panels/information/dolphin_informationpanelsettings.kcfgc ) + target_link_libraries(dolphinstatic + Qt::Multimedia + Qt::MultimediaWidgets + ) endif() if(HAVE_KUSERFEEDBACK) @@ -477,7 +481,6 @@ target_sources(dolphinstatic PRIVATE ${dolphin_dbus_SRCS} ) -target_include_directories(dolphinstatic SYSTEM PRIVATE ${PHONON_INCLUDES}) target_link_libraries(dolphinstatic dolphinprivate KF6::CoreAddons @@ -486,7 +489,6 @@ target_link_libraries(dolphinstatic KF6::DBusAddons KF6::Notifications KF6::BookmarksWidgets - Phonon::phonon4qt6 ) if(HAVE_PACKAGEKIT) diff --git a/src/panels/information/informationpanelcontent.cpp b/src/panels/information/informationpanelcontent.cpp index 14a470b11..1ab57c0e7 100644 --- a/src/panels/information/informationpanelcontent.cpp +++ b/src/panels/information/informationpanelcontent.cpp @@ -24,9 +24,6 @@ #include -#include -#include - #include #include #include @@ -40,7 +37,7 @@ #include #include "dolphin_informationpanelsettings.h" -#include "phononwidget.h" +#include "mediawidget.h" #include "pixmapviewer.h" const int PLAY_ARROW_SIZE = 24; @@ -52,7 +49,7 @@ InformationPanelContent::InformationPanelContent(QWidget *parent) , m_previewJob(nullptr) , m_outdatedPreviewTimer(nullptr) , m_preview(nullptr) - , m_phononWidget(nullptr) + , m_mediaWidget(nullptr) , m_nameLabel(nullptr) , m_metaDataWidget(nullptr) , m_metaDataArea(nullptr) @@ -77,11 +74,11 @@ InformationPanelContent::InformationPanelContent(QWidget *parent) m_preview->setMinimumWidth(minPreviewWidth); m_preview->setMinimumHeight(KIconLoader::SizeEnormous); - m_phononWidget = new PhononWidget(parent); - m_phononWidget->hide(); - m_phononWidget->setMinimumWidth(minPreviewWidth); - m_phononWidget->setAutoPlay(InformationPanelSettings::previewsAutoPlay()); - connect(m_phononWidget, &PhononWidget::hasVideoChanged, this, &InformationPanelContent::slotHasVideoChanged); + m_mediaWidget = new MediaWidget(parent); + m_mediaWidget->hide(); + m_mediaWidget->setMinimumWidth(minPreviewWidth); + m_mediaWidget->setAutoPlay(InformationPanelSettings::previewsAutoPlay()); + connect(m_mediaWidget, &MediaWidget::hasVideoChanged, this, &InformationPanelContent::slotHasVideoChanged); // name m_nameLabel = new QLabel(parent); @@ -132,7 +129,7 @@ InformationPanelContent::InformationPanelContent(QWidget *parent) viewport->installEventFilter(this); layout->addWidget(m_preview); - layout->addWidget(m_phononWidget); + layout->addWidget(m_mediaWidget); layout->addWidget(m_nameLabel); layout->addWidget(new KSeparator()); layout->addWidget(m_configureLabel); @@ -203,7 +200,7 @@ void InformationPanelContent::refreshPreview() const bool isSearchUrl = itemUrl.scheme().contains(QLatin1String("search")) && m_item.localPath().isEmpty(); if (isSearchUrl) { m_preview->show(); - m_phononWidget->hide(); + m_mediaWidget->hide(); // in the case of a search-URL the URL is not readable for humans // (at least not useful to show in the Information Panel) @@ -219,16 +216,17 @@ void InformationPanelContent::refreshPreview() if (usePhonon) { // change the cursor of the preview m_preview->setCursor(Qt::PointingHandCursor); - m_preview->installEventFilter(m_phononWidget); - m_phononWidget->show(); + m_preview->installEventFilter(m_mediaWidget); + + m_mediaWidget->show(); // if the video is playing, has been paused or stopped // we don't need to update the preview/phonon widget states // unless the previewed file has changed, // or the setting previewshown has changed - if ((m_phononWidget->state() != Phonon::State::PlayingState && m_phononWidget->state() != Phonon::State::PausedState - && m_phononWidget->state() != Phonon::State::StoppedState) - || m_item.targetUrl() != m_phononWidget->url() || (!m_preview->isVisible() && !m_phononWidget->isVisible())) { + if ((m_mediaWidget->state() != QMediaPlayer::PlayingState && m_mediaWidget->state() != QMediaPlayer::PausedState + && m_mediaWidget->state() != QMediaPlayer::StoppedState) + || m_item.targetUrl() != m_mediaWidget->url() || (!m_preview->isVisible() && !m_mediaWidget->isVisible())) { if (InformationPanelSettings::previewsAutoPlay() && m_isVideo) { // hides the preview now to avoid flickering when the autoplay video starts m_preview->hide(); @@ -237,7 +235,7 @@ void InformationPanelContent::refreshPreview() m_preview->show(); } - m_phononWidget->setUrl(m_item.targetUrl(), m_isVideo ? PhononWidget::MediaKind::Video : PhononWidget::MediaKind::Audio); + m_mediaWidget->setUrl(m_item.targetUrl(), m_isVideo ? MediaWidget::MediaKind::Video : MediaWidget::MediaKind::Audio); adjustWidgetSizes(parentWidget()->width()); } } else { @@ -245,16 +243,16 @@ void InformationPanelContent::refreshPreview() m_preview->setAnimatedImageFileName(itemUrl.toLocalFile()); } // When we don't need it, hide the phonon widget first to avoid flickering - m_phononWidget->hide(); + m_mediaWidget->hide(); m_preview->show(); - m_preview->removeEventFilter(m_phononWidget); - m_phononWidget->clearUrl(); + m_preview->removeEventFilter(m_mediaWidget); + m_mediaWidget->clearUrl(); } } } else { m_preview->stopAnimatedImage(); m_preview->hide(); - m_phononWidget->hide(); + m_mediaWidget->hide(); } } @@ -287,7 +285,7 @@ void InformationPanelContent::showItems(const KFileItemList &items) m_metaDataWidget->setItems(items); - m_phononWidget->hide(); + m_mediaWidget->hide(); m_item = KFileItem(); } @@ -451,7 +449,7 @@ void InformationPanelContent::slotHasVideoChanged(bool hasVideo) void InformationPanelContent::setPreviewAutoPlay(bool autoPlay) { - m_phononWidget->setAutoPlay(autoPlay); + m_mediaWidget->setAutoPlay(autoPlay); } void InformationPanelContent::setNameLabelText(const QString &text) @@ -502,9 +500,9 @@ void InformationPanelContent::adjustWidgetSizes(int width) // try to increase the preview as large as possible m_preview->setSizeHint(QSize(maxWidth, maxWidth)); - if (m_phononWidget->isVisible()) { + if (m_mediaWidget->isVisible()) { // assure that the size of the video player is the same as the preview size - m_phononWidget->setVideoSize(QSize(maxWidth, maxWidth)); + m_mediaWidget->setVideoSize(QSize(maxWidth, maxWidth)); } } diff --git a/src/panels/information/informationpanelcontent.h b/src/panels/information/informationpanelcontent.h index 0ea05d990..333b26608 100644 --- a/src/panels/information/informationpanelcontent.h +++ b/src/panels/information/informationpanelcontent.h @@ -15,7 +15,7 @@ #include class KFileItemList; -class PhononWidget; +class MediaWidget; class PixmapViewer; class QPixmap; class QDialogButtonBox; @@ -145,7 +145,7 @@ private: QTimer *m_outdatedPreviewTimer; PixmapViewer *m_preview; - PhononWidget *m_phononWidget; + MediaWidget *m_mediaWidget; QLabel *m_nameLabel; Baloo::FileMetaDataWidget *m_metaDataWidget; QScrollArea *m_metaDataArea; diff --git a/src/panels/information/mediawidget.cpp b/src/panels/information/mediawidget.cpp new file mode 100644 index 000000000..345cb0201 --- /dev/null +++ b/src/panels/information/mediawidget.cpp @@ -0,0 +1,368 @@ +/* + SPDX-FileCopyrightText: 2007 Matthias Kretz + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "mediawidget.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +class EmbeddedVideoPlayer : public QVideoWidget +{ + Q_OBJECT + +public: + EmbeddedVideoPlayer(QWidget *parent = nullptr) + : QVideoWidget(parent) + { + } + + void setSizeHint(const QSize &size) + { + m_sizeHint = size; + updateGeometry(); + } + + QSize sizeHint() const override + { + return m_sizeHint.isValid() ? m_sizeHint : QVideoWidget::sizeHint(); + } + +private: + QSize m_sizeHint; +}; + +class SeekSlider : public QSlider +{ + Q_OBJECT + +public: + SeekSlider(Qt::Orientation orientation, QWidget *parent = nullptr) + : QSlider(orientation, parent) + { + } + +protected: + // Function copied from qslider.cpp + inline int pick(const QPoint &pt) const + { + return orientation() == Qt::Horizontal ? pt.x() : pt.y(); + } + + // Function copied from qslider.cpp and modified to make it compile + int pixelPosToRangeValue(int pos) const + { + QStyleOptionSlider opt; + initStyleOption(&opt); + QRect gr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); + QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + int sliderMin, sliderMax, sliderLength; + + if (orientation() == Qt::Horizontal) { + sliderLength = sr.width(); + sliderMin = gr.x(); + sliderMax = gr.right() - sliderLength + 1; + } else { + sliderLength = sr.height(); + sliderMin = gr.y(); + sliderMax = gr.bottom() - sliderLength + 1; + } + return QStyle::sliderValueFromPosition(minimum(), maximum(), pos - sliderMin, sliderMax - sliderMin, opt.upsideDown); + } + + // Based on code from qslider.cpp + void mousePressEvent(QMouseEvent *event) override + { + if (event->button() == Qt::LeftButton) { + QStyleOptionSlider opt; + initStyleOption(&opt); + const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + const QPoint center = sliderRect.center() - sliderRect.topLeft(); + // to take half of the slider off for the setSliderPosition call we use the center - topLeft + + if (!sliderRect.contains(event->pos())) { + event->accept(); + + int position = pixelPosToRangeValue(pick(event->pos() - center)); + setSliderPosition(position); + triggerAction(SliderMove); + setRepeatAction(SliderNoAction); + + Q_EMIT sliderMoved(position); + } else { + QSlider::mousePressEvent(event); + } + } else { + QSlider::mousePressEvent(event); + } + } +}; + +MediaWidget::MediaWidget(QWidget *parent) + : QWidget(parent) + , m_url() + , m_playButton(nullptr) + , m_pauseButton(nullptr) + , m_topLayout(nullptr) + , m_player(nullptr) + , m_seekSlider(nullptr) + , m_videoWidget(nullptr) +{ +} + +void MediaWidget::setUrl(const QUrl &url, MediaKind kind) +{ + if (m_url != url) { + m_url = url; + m_isVideo = kind == MediaKind::Video; + m_seekSlider->setValue(0); + } + if (m_autoPlay) { + play(); + } else { + stop(); + } +} + +void MediaWidget::setAutoPlay(bool autoPlay) +{ + m_autoPlay = autoPlay; + if (!m_url.isEmpty() && (m_player == nullptr || m_player->playbackState() != QMediaPlayer::PlayingState) && m_autoPlay && isVisible()) { + play(); + } +} + +QUrl MediaWidget::url() const +{ + return m_url; +} + +void MediaWidget::clearUrl() +{ + m_url.clear(); +} + +void MediaWidget::togglePlayback() +{ + if (m_player && m_player->playbackState() == QMediaPlayer::PlayingState) { + m_player->pause(); + } else { + play(); + } +} + +bool MediaWidget::eventFilter(QObject *object, QEvent *event) +{ + Q_UNUSED(object) + if (event->type() == QEvent::MouseButtonPress) { + const QMouseEvent *mouseEvent = static_cast(event); + if (mouseEvent->button() == Qt::LeftButton) { + // toggle playback + togglePlayback(); + return true; + } + } + return false; +} + +void MediaWidget::setVideoSize(const QSize &size) +{ + if (m_videoSize != size) { + m_videoSize = size; + applyVideoSize(); + } +} + +QSize MediaWidget::videoSize() const +{ + return m_videoSize; +} + +void MediaWidget::showEvent(QShowEvent *event) +{ + if (event->spontaneous()) { + QWidget::showEvent(event); + return; + } + + if (!m_topLayout) { + m_topLayout = new QVBoxLayout(this); + m_topLayout->setContentsMargins(0, 0, 0, 0); + + QHBoxLayout *controlsLayout = new QHBoxLayout(); + controlsLayout->setContentsMargins(0, 0, 0, 0); + controlsLayout->setSpacing(0); + + m_playButton = new QToolButton(this); + m_pauseButton = new QToolButton(this); + m_seekSlider = new SeekSlider(Qt::Orientation::Horizontal, this); + connect(m_seekSlider, &QAbstractSlider::sliderMoved, this, &MediaWidget::setPosition); + + controlsLayout->addWidget(m_playButton); + controlsLayout->addWidget(m_pauseButton); + controlsLayout->addWidget(m_seekSlider); + + m_topLayout->addLayout(controlsLayout); + + const int smallIconSize = style()->pixelMetric(QStyle::PM_SmallIconSize); + const QSize buttonSize(smallIconSize, smallIconSize); + + m_playButton->setToolTip(i18n("play")); + m_playButton->setIconSize(buttonSize); + m_playButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); + m_playButton->setAutoRaise(true); + connect(m_playButton, &QToolButton::clicked, this, &MediaWidget::play); + + m_pauseButton->setToolTip(i18n("pause")); + m_pauseButton->setIconSize(buttonSize); + m_pauseButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause"))); + m_pauseButton->setAutoRaise(true); + m_pauseButton->hide(); + connect(m_pauseButton, &QToolButton::clicked, this, &MediaWidget::togglePlayback); + + // Creating an audio player or video player instance might take up to + // 2 seconds when doing it the first time. To prevent that the user + // interface gets noticeable blocked, the creation is delayed until + // the play button has been pressed (see PhononWidget::play()). + } +} + +void MediaWidget::hideEvent(QHideEvent *event) +{ + QWidget::hideEvent(event); + if (!event->spontaneous()) { + stop(); + } +} + +void MediaWidget::onStateChanged(QMediaPlayer::PlaybackState newState) +{ + setUpdatesEnabled(false); + switch (newState) { + case QMediaPlayer::PlaybackState::PlayingState: + m_playButton->hide(); + m_pauseButton->show(); + break; + default: + m_pauseButton->hide(); + m_playButton->show(); + break; + } + setUpdatesEnabled(true); +} + +void MediaWidget::initPlayer() +{ + if (!m_player) { + m_player = new QMediaPlayer; + m_player->setAudioOutput(new QAudioOutput); + + m_videoWidget = new EmbeddedVideoPlayer(this); + m_videoWidget->setCursor(Qt::PointingHandCursor); + + m_videoWidget->installEventFilter(this); + m_player->setVideoOutput(m_videoWidget); + m_topLayout->insertWidget(0, m_videoWidget); + + applyVideoSize(); + + connect(m_player, &QMediaPlayer::playbackStateChanged, this, &MediaWidget::onStateChanged); + connect(m_player, &QMediaPlayer::positionChanged, this, &MediaWidget::onPositionChanged); + connect(m_player, &QMediaPlayer::durationChanged, this, &MediaWidget::onDurationChanged); + } + + if (m_url != m_player->source()) { + m_player->setSource(m_url); + m_seekSlider->setSliderPosition(0); + } + + Q_EMIT hasVideoChanged(m_isVideo); + + m_videoWidget->setVisible(m_isVideo); +} + +void MediaWidget::play() +{ + initPlayer(); + + m_player->play(); +} + +void MediaWidget::finished() +{ + if (m_isVideo) { + m_videoWidget->hide(); + Q_EMIT hasVideoChanged(false); + } +} + +QMediaPlayer::PlaybackState MediaWidget::state() const +{ + return m_player == nullptr ? QMediaPlayer::PlaybackState::StoppedState : m_player->playbackState(); +} + +void MediaWidget::stop() +{ + if (m_player) { + m_player->stop(); + m_videoWidget->hide(); + Q_EMIT hasVideoChanged(false); + } +} + +void MediaWidget::applyVideoSize() +{ + if ((m_videoWidget) && m_videoSize.isValid()) { + m_videoWidget->setSizeHint(m_videoSize); + } +} + +void MediaWidget::setPosition(qint64 position) +{ + if (!m_player || m_player->playbackState() == QMediaPlayer::StoppedState) { + initPlayer(); + + auto prevDuration = m_seekSlider->maximum(); + + connect( + m_player, + &QMediaPlayer::mediaStatusChanged, + this, + [prevDuration, position, this](QMediaPlayer::MediaStatus status) { + if (status == QMediaPlayer::BufferedMedia) { + m_player->setPosition(float(position) / prevDuration * m_player->duration()); + m_player->pause(); + } + }, + Qt::SingleShotConnection); + + m_player->play(); + } else { + m_player->setPosition(position); + } +} + +void MediaWidget::onPositionChanged(qint64 position) +{ + m_seekSlider->setValue(static_cast(position)); +} + +void MediaWidget::onDurationChanged(qint64 duration) +{ + m_seekSlider->setMaximum(static_cast(duration)); +} + +#include "mediawidget.moc" +#include "moc_mediawidget.cpp" diff --git a/src/panels/information/phononwidget.h b/src/panels/information/mediawidget.h similarity index 70% rename from src/panels/information/phononwidget.h rename to src/panels/information/mediawidget.h index a0a913b4f..bd04266e6 100644 --- a/src/panels/information/phononwidget.h +++ b/src/panels/information/mediawidget.h @@ -4,34 +4,30 @@ SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef PHONONWIDGET_H -#define PHONONWIDGET_H - -#include +#ifndef MEDIAWIDGET_H +#define MEDIAWIDGET_H #include +#include #include #include -namespace Phonon -{ -class AudioOutput; -class MediaObject; +#include + +class QMediaPlayer; class SeekSlider; -class VideoPlayer; -} // namespace Phonon class EmbeddedVideoPlayer; class QToolButton; class QVBoxLayout; -class PhononWidget : public QWidget +class MediaWidget : public QWidget { Q_OBJECT public: enum MediaKind { Video, Audio }; - explicit PhononWidget(QWidget *parent = nullptr); + explicit MediaWidget(QWidget *parent = nullptr); void setUrl(const QUrl &url, MediaKind kind); QUrl url() const; @@ -39,7 +35,7 @@ public: void setVideoSize(const QSize &size); QSize videoSize() const; - Phonon::State state() const; + QMediaPlayer::PlaybackState state() const; void setAutoPlay(bool autoPlay); bool eventFilter(QObject *object, QEvent *event) override; @@ -63,15 +59,17 @@ protected: void hideEvent(QHideEvent *event) override; private Q_SLOTS: - void stateChanged(Phonon::State newstate); void stop(); void finished(); + void setPosition(qint64 position); + void onStateChanged(QMediaPlayer::PlaybackState newState); + void onPositionChanged(qint64 position); + void onDurationChanged(qint64 position); private: void applyVideoSize(); - -private: void togglePlayback(); + void initPlayer(); QUrl m_url; QSize m_videoSize; @@ -80,12 +78,11 @@ private: QToolButton *m_pauseButton; QVBoxLayout *m_topLayout; - Phonon::MediaObject *m_media; - Phonon::SeekSlider *m_seekSlider; - Phonon::AudioOutput *m_audioOutput; - EmbeddedVideoPlayer *m_videoPlayer; + QMediaPlayer *m_player; + QSlider *m_seekSlider; + EmbeddedVideoPlayer *m_videoWidget; bool m_autoPlay; bool m_isVideo; }; -#endif // PHONONWIDGET_H +#endif // MEDIAWIDGET_H diff --git a/src/panels/information/phononwidget.cpp b/src/panels/information/phononwidget.cpp deleted file mode 100644 index 3365998f4..000000000 --- a/src/panels/information/phononwidget.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - SPDX-FileCopyrightText: 2007 Matthias Kretz - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "phononwidget.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -class EmbeddedVideoPlayer : public Phonon::VideoWidget -{ - Q_OBJECT - -public: - EmbeddedVideoPlayer(QWidget *parent = nullptr) - : Phonon::VideoWidget(parent) - { - } - - void setSizeHint(const QSize &size) - { - m_sizeHint = size; - updateGeometry(); - } - - QSize sizeHint() const override - { - return m_sizeHint.isValid() ? m_sizeHint : Phonon::VideoWidget::sizeHint(); - } - -private: - QSize m_sizeHint; -}; - -PhononWidget::PhononWidget(QWidget *parent) - : QWidget(parent) - , m_url() - , m_playButton(nullptr) - , m_pauseButton(nullptr) - , m_topLayout(nullptr) - , m_media(nullptr) - , m_seekSlider(nullptr) - , m_audioOutput(nullptr) - , m_videoPlayer(nullptr) -{ -} - -void PhononWidget::setUrl(const QUrl &url, MediaKind kind) -{ - if (m_url != url) { - m_url = url; - m_isVideo = kind == MediaKind::Video; - } - if (m_autoPlay) { - play(); - } else { - stop(); - } -} - -void PhononWidget::setAutoPlay(bool autoPlay) -{ - m_autoPlay = autoPlay; - if (!m_url.isEmpty() && (m_media == nullptr || m_media->state() != Phonon::State::PlayingState) && m_autoPlay && isVisible()) { - play(); - } -} - -QUrl PhononWidget::url() const -{ - return m_url; -} - -void PhononWidget::clearUrl() -{ - m_url.clear(); -} - -void PhononWidget::togglePlayback() -{ - if (m_media && m_media->state() == Phonon::State::PlayingState) { - m_media->pause(); - } else { - play(); - } -} - -bool PhononWidget::eventFilter(QObject *object, QEvent *event) -{ - Q_UNUSED(object) - if (event->type() == QEvent::MouseButtonPress) { - const QMouseEvent *mouseEvent = static_cast(event); - if (mouseEvent->button() == Qt::LeftButton) { - // toggle playback - togglePlayback(); - return true; - } - } - return false; -} - -void PhononWidget::setVideoSize(const QSize &size) -{ - if (m_videoSize != size) { - m_videoSize = size; - applyVideoSize(); - } -} - -QSize PhononWidget::videoSize() const -{ - return m_videoSize; -} - -void PhononWidget::showEvent(QShowEvent *event) -{ - if (event->spontaneous()) { - QWidget::showEvent(event); - return; - } - - if (!m_topLayout) { - m_topLayout = new QVBoxLayout(this); - m_topLayout->setContentsMargins(0, 0, 0, 0); - - QHBoxLayout *controlsLayout = new QHBoxLayout(); - controlsLayout->setContentsMargins(0, 0, 0, 0); - controlsLayout->setSpacing(0); - - m_playButton = new QToolButton(this); - m_pauseButton = new QToolButton(this); - m_seekSlider = new Phonon::SeekSlider(this); - - controlsLayout->addWidget(m_playButton); - controlsLayout->addWidget(m_pauseButton); - controlsLayout->addWidget(m_seekSlider); - - m_topLayout->addLayout(controlsLayout); - - const int smallIconSize = style()->pixelMetric(QStyle::PM_SmallIconSize); - const QSize buttonSize(smallIconSize, smallIconSize); - - m_playButton->setToolTip(i18n("play")); - m_playButton->setIconSize(buttonSize); - m_playButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); - m_playButton->setAutoRaise(true); - connect(m_playButton, &QToolButton::clicked, this, &PhononWidget::play); - - m_pauseButton->setToolTip(i18n("pause")); - m_pauseButton->setIconSize(buttonSize); - m_pauseButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause"))); - m_pauseButton->setAutoRaise(true); - m_pauseButton->hide(); - connect(m_pauseButton, &QToolButton::clicked, this, &PhononWidget::togglePlayback); - - m_seekSlider->setIconVisible(false); - - // Creating an audio player or video player instance might take up to - // 2 seconds when doing it the first time. To prevent that the user - // interface gets noticeable blocked, the creation is delayed until - // the play button has been pressed (see PhononWidget::play()). - } -} - -void PhononWidget::hideEvent(QHideEvent *event) -{ - QWidget::hideEvent(event); - if (!event->spontaneous()) { - stop(); - } -} - -void PhononWidget::stateChanged(Phonon::State newstate) -{ - setUpdatesEnabled(false); - switch (newstate) { - case Phonon::PlayingState: - case Phonon::BufferingState: - m_playButton->hide(); - m_pauseButton->show(); - break; - default: - m_pauseButton->hide(); - m_playButton->show(); - break; - } - setUpdatesEnabled(true); -} - -void PhononWidget::play() -{ - if (!m_media) { - m_media = new Phonon::MediaObject(this); - connect(m_media, &Phonon::MediaObject::stateChanged, this, &PhononWidget::stateChanged); - connect(m_media, &Phonon::MediaObject::finished, this, &PhononWidget::finished); - m_seekSlider->setMediaObject(m_media); - } - - if (!m_videoPlayer) { - m_videoPlayer = new EmbeddedVideoPlayer(this); - m_videoPlayer->setCursor(Qt::PointingHandCursor); - m_videoPlayer->installEventFilter(this); - m_topLayout->insertWidget(0, m_videoPlayer); - Phonon::createPath(m_media, m_videoPlayer); - applyVideoSize(); - } - - if (!m_audioOutput) { - m_audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); - Phonon::createPath(m_media, m_audioOutput); - } - - if (m_isVideo) { - Q_EMIT hasVideoChanged(true); - } - - if (m_url != m_media->currentSource().url()) { - m_media->setCurrentSource(m_url); - } - m_media->play(); - - m_videoPlayer->setVisible(m_isVideo); -} - -void PhononWidget::finished() -{ - if (m_isVideo) { - m_videoPlayer->hide(); - Q_EMIT hasVideoChanged(false); - } -} - -Phonon::State PhononWidget::state() const -{ - return m_media == nullptr ? Phonon::State::StoppedState : m_media->state(); -} - -void PhononWidget::stop() -{ - if (m_media) { - m_media->stop(); - m_videoPlayer->hide(); - Q_EMIT hasVideoChanged(false); - } -} - -void PhononWidget::applyVideoSize() -{ - if ((m_videoPlayer) && m_videoSize.isValid()) { - m_videoPlayer->setSizeHint(m_videoSize); - } -} - -#include "moc_phononwidget.cpp" -#include "phononwidget.moc" -- 2.47.3