File indexing completed on 2024-05-12 17:18:50

0001 /*
0002   SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
0003 
0004   SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "phononwidget.h"
0008 
0009 #include <KLocalizedString>
0010 #include <phonon/AudioOutput>
0011 #include <phonon/MediaObject>
0012 #include <phonon/SeekSlider>
0013 #include <phonon/VideoWidget>
0014 
0015 #include <QShowEvent>
0016 #include <QStyle>
0017 #include <QToolButton>
0018 #include <QVBoxLayout>
0019 
0020 class EmbeddedVideoPlayer : public Phonon::VideoWidget
0021 {
0022     Q_OBJECT
0023 
0024 public:
0025     EmbeddedVideoPlayer(QWidget *parent = nullptr)
0026         : Phonon::VideoWidget(parent)
0027     {
0028     }
0029 
0030     void setSizeHint(const QSize &size)
0031     {
0032         m_sizeHint = size;
0033         updateGeometry();
0034     }
0035 
0036     QSize sizeHint() const override
0037     {
0038         return m_sizeHint.isValid() ? m_sizeHint : Phonon::VideoWidget::sizeHint();
0039     }
0040 
0041 private:
0042     QSize m_sizeHint;
0043 };
0044 
0045 PhononWidget::PhononWidget(QWidget *parent)
0046     : QWidget(parent)
0047     , m_url()
0048     , m_playButton(nullptr)
0049     , m_pauseButton(nullptr)
0050     , m_topLayout(nullptr)
0051     , m_media(nullptr)
0052     , m_seekSlider(nullptr)
0053     , m_audioOutput(nullptr)
0054     , m_videoPlayer(nullptr)
0055 {
0056 }
0057 
0058 void PhononWidget::setUrl(const QUrl &url, MediaKind kind)
0059 {
0060     if (m_url != url) {
0061         m_url = url;
0062         m_isVideo = kind == MediaKind::Video;
0063     }
0064     if (m_autoPlay) {
0065         play();
0066     } else {
0067         stop();
0068     }
0069 }
0070 
0071 void PhononWidget::setAutoPlay(bool autoPlay)
0072 {
0073     m_autoPlay = autoPlay;
0074     if (!m_url.isEmpty() && (m_media == nullptr || m_media->state() != Phonon::State::PlayingState) && m_autoPlay && isVisible()) {
0075         play();
0076     }
0077 }
0078 
0079 QUrl PhononWidget::url() const
0080 {
0081     return m_url;
0082 }
0083 
0084 void PhononWidget::clearUrl()
0085 {
0086     m_url.clear();
0087 }
0088 
0089 void PhononWidget::togglePlayback()
0090 {
0091     if (m_media && m_media->state() == Phonon::State::PlayingState) {
0092         m_media->pause();
0093     } else {
0094         play();
0095     }
0096 }
0097 
0098 bool PhononWidget::eventFilter(QObject *object, QEvent *event)
0099 {
0100     Q_UNUSED(object)
0101     if (event->type() == QEvent::MouseButtonPress) {
0102         const QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
0103         if (mouseEvent->button() == Qt::LeftButton) {
0104             // toggle playback
0105             togglePlayback();
0106             return true;
0107         }
0108     }
0109     return false;
0110 }
0111 
0112 void PhononWidget::setVideoSize(const QSize &size)
0113 {
0114     if (m_videoSize != size) {
0115         m_videoSize = size;
0116         applyVideoSize();
0117     }
0118 }
0119 
0120 QSize PhononWidget::videoSize() const
0121 {
0122     return m_videoSize;
0123 }
0124 
0125 void PhononWidget::showEvent(QShowEvent *event)
0126 {
0127     if (event->spontaneous()) {
0128         QWidget::showEvent(event);
0129         return;
0130     }
0131 
0132     if (!m_topLayout) {
0133         m_topLayout = new QVBoxLayout(this);
0134         m_topLayout->setContentsMargins(0, 0, 0, 0);
0135 
0136         QHBoxLayout *controlsLayout = new QHBoxLayout();
0137         controlsLayout->setContentsMargins(0, 0, 0, 0);
0138         controlsLayout->setSpacing(0);
0139 
0140         m_playButton = new QToolButton(this);
0141         m_pauseButton = new QToolButton(this);
0142         m_seekSlider = new Phonon::SeekSlider(this);
0143 
0144         controlsLayout->addWidget(m_playButton);
0145         controlsLayout->addWidget(m_pauseButton);
0146         controlsLayout->addWidget(m_seekSlider);
0147 
0148         m_topLayout->addLayout(controlsLayout);
0149 
0150         const int smallIconSize = style()->pixelMetric(QStyle::PM_SmallIconSize);
0151         const QSize buttonSize(smallIconSize, smallIconSize);
0152 
0153         m_playButton->setToolTip(i18n("play"));
0154         m_playButton->setIconSize(buttonSize);
0155         m_playButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start")));
0156         m_playButton->setAutoRaise(true);
0157         connect(m_playButton, &QToolButton::clicked, this, &PhononWidget::play);
0158 
0159         m_pauseButton->setToolTip(i18n("pause"));
0160         m_pauseButton->setIconSize(buttonSize);
0161         m_pauseButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-pause")));
0162         m_pauseButton->setAutoRaise(true);
0163         m_pauseButton->hide();
0164         connect(m_pauseButton, &QToolButton::clicked, this, &PhononWidget::togglePlayback);
0165 
0166         m_seekSlider->setIconVisible(false);
0167 
0168         // Creating an audio player or video player instance might take up to
0169         // 2 seconds when doing it the first time. To prevent that the user
0170         // interface gets noticeable blocked, the creation is delayed until
0171         // the play button has been pressed (see PhononWidget::play()).
0172     }
0173 }
0174 
0175 void PhononWidget::hideEvent(QHideEvent *event)
0176 {
0177     QWidget::hideEvent(event);
0178     if (!event->spontaneous()) {
0179         stop();
0180     }
0181 }
0182 
0183 void PhononWidget::stateChanged(Phonon::State newstate)
0184 {
0185     setUpdatesEnabled(false);
0186     switch (newstate) {
0187     case Phonon::PlayingState:
0188     case Phonon::BufferingState:
0189         m_playButton->hide();
0190         m_pauseButton->show();
0191         break;
0192     default:
0193         m_pauseButton->hide();
0194         m_playButton->show();
0195         break;
0196     }
0197     setUpdatesEnabled(true);
0198 }
0199 
0200 void PhononWidget::play()
0201 {
0202     if (!m_media) {
0203         m_media = new Phonon::MediaObject(this);
0204         connect(m_media, &Phonon::MediaObject::stateChanged, this, &PhononWidget::stateChanged);
0205         connect(m_media, &Phonon::MediaObject::finished, this, &PhononWidget::finished);
0206         m_seekSlider->setMediaObject(m_media);
0207     }
0208 
0209     if (!m_videoPlayer) {
0210         m_videoPlayer = new EmbeddedVideoPlayer(this);
0211         m_videoPlayer->setCursor(Qt::PointingHandCursor);
0212         m_videoPlayer->installEventFilter(this);
0213         m_topLayout->insertWidget(0, m_videoPlayer);
0214         Phonon::createPath(m_media, m_videoPlayer);
0215         applyVideoSize();
0216     }
0217 
0218     if (!m_audioOutput) {
0219         m_audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
0220         Phonon::createPath(m_media, m_audioOutput);
0221     }
0222 
0223     if (m_isVideo) {
0224         Q_EMIT hasVideoChanged(true);
0225     }
0226 
0227     if (m_url != m_media->currentSource().url()) {
0228         m_media->setCurrentSource(m_url);
0229     }
0230     m_media->play();
0231 
0232     m_videoPlayer->setVisible(m_isVideo);
0233 }
0234 
0235 void PhononWidget::finished()
0236 {
0237     if (m_isVideo) {
0238         m_videoPlayer->hide();
0239         Q_EMIT hasVideoChanged(false);
0240     }
0241 }
0242 
0243 Phonon::State PhononWidget::state() const
0244 {
0245     return m_media == nullptr ? Phonon::State::StoppedState : m_media->state();
0246 }
0247 
0248 void PhononWidget::stop()
0249 {
0250     if (m_media) {
0251         m_media->stop();
0252         m_videoPlayer->hide();
0253         Q_EMIT hasVideoChanged(false);
0254     }
0255 }
0256 
0257 void PhononWidget::applyVideoSize()
0258 {
0259     if ((m_videoPlayer) && m_videoSize.isValid()) {
0260         m_videoPlayer->setSizeHint(m_videoSize);
0261     }
0262 }
0263 
0264 #include "moc_phononwidget.cpp"
0265 #include "phononwidget.moc"