Changeset View
Changeset View
Standalone View
Standalone View
src/panels/information/phononwidget.cpp
Show All 16 Lines | 1 | /* This file is part of the KDE project | |||
---|---|---|---|---|---|
17 | 02110-1301, USA. | 17 | 02110-1301, USA. | ||
18 | 18 | | |||
19 | */ | 19 | */ | ||
20 | 20 | | |||
21 | #include "phononwidget.h" | 21 | #include "phononwidget.h" | ||
22 | 22 | | |||
23 | #include <KIconLoader> | 23 | #include <KIconLoader> | ||
24 | #include <KLocalizedString> | 24 | #include <KLocalizedString> | ||
25 | #include <Phonon/AudioOutput> | 25 | #include <QMediaPlayer> | ||
26 | #include <Phonon/MediaObject> | 26 | #include <QMediaPlaylist> | ||
27 | #include <Phonon/SeekSlider> | 27 | #include <QVideoWidget> | ||
28 | #include <Phonon/VideoWidget> | 28 | #include <QSlider> | ||
29 | 29 | | |||
30 | #include <QShowEvent> | 30 | #include <QShowEvent> | ||
31 | #include <QToolButton> | 31 | #include <QToolButton> | ||
32 | #include <QVBoxLayout> | 32 | #include <QVBoxLayout> | ||
33 | #include <QStyleOptionSlider> | ||||
33 | 34 | | |||
34 | class EmbeddedVideoPlayer : public Phonon::VideoWidget | 35 | class EmbeddedVideoPlayer : public QVideoWidget | ||
35 | { | 36 | { | ||
36 | Q_OBJECT | 37 | Q_OBJECT | ||
37 | 38 | | |||
38 | public: | 39 | public: | ||
39 | EmbeddedVideoPlayer(QWidget *parent = nullptr) : | 40 | EmbeddedVideoPlayer(QWidget *parent = nullptr) : | ||
40 | Phonon::VideoWidget(parent) | 41 | QVideoWidget(parent) | ||
41 | { | 42 | { | ||
42 | } | 43 | } | ||
43 | 44 | | |||
44 | void setSizeHint(const QSize& size) | 45 | void setSizeHint(const QSize& size) | ||
45 | { | 46 | { | ||
46 | m_sizeHint = size; | 47 | m_sizeHint = size; | ||
47 | updateGeometry(); | 48 | updateGeometry(); | ||
48 | } | 49 | } | ||
49 | 50 | | |||
50 | QSize sizeHint() const override | 51 | QSize sizeHint() const override | ||
51 | { | 52 | { | ||
52 | return m_sizeHint.isValid() ? m_sizeHint : Phonon::VideoWidget::sizeHint(); | 53 | return m_sizeHint.isValid() ? m_sizeHint : QVideoWidget::sizeHint(); | ||
53 | } | 54 | } | ||
54 | 55 | | |||
55 | private: | 56 | private: | ||
56 | QSize m_sizeHint; | 57 | QSize m_sizeHint; | ||
57 | }; | 58 | }; | ||
58 | 59 | | |||
60 | class SeekSlider : public QSlider | ||||
61 | { | ||||
62 | Q_OBJECT | ||||
63 | | ||||
64 | public: | ||||
65 | SeekSlider(Qt::Orientation orientation, QWidget *parent = nullptr): QSlider(orientation, parent) | ||||
66 | {} | ||||
67 | | ||||
68 | protected: | ||||
69 | // Function copied from qslider.cpp | ||||
70 | inline int pick(const QPoint &pt) const | ||||
71 | { | ||||
72 | return orientation() == Qt::Horizontal ? pt.x() : pt.y(); | ||||
73 | } | ||||
74 | | ||||
75 | // Function copied from qslider.cpp and modified to make it compile | ||||
76 | int pixelPosToRangeValue(int pos) const | ||||
77 | { | ||||
78 | QStyleOptionSlider opt; | ||||
79 | initStyleOption(&opt); | ||||
80 | QRect gr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); | ||||
81 | QRect sr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); | ||||
82 | int sliderMin, sliderMax, sliderLength; | ||||
83 | | ||||
84 | if (orientation() == Qt::Horizontal) { | ||||
85 | sliderLength = sr.width(); | ||||
86 | sliderMin = gr.x(); | ||||
87 | sliderMax = gr.right() - sliderLength + 1; | ||||
88 | } else { | ||||
89 | sliderLength = sr.height(); | ||||
90 | sliderMin = gr.y(); | ||||
91 | sliderMax = gr.bottom() - sliderLength + 1; | ||||
92 | } | ||||
93 | return QStyle::sliderValueFromPosition(minimum(), maximum(), pos - sliderMin, | ||||
94 | sliderMax - sliderMin, opt.upsideDown); | ||||
95 | } | ||||
96 | | ||||
97 | // Based on code from qslider.cpp | ||||
98 | void mousePressEvent ( QMouseEvent * event ) override | ||||
99 | { | ||||
100 | if (event->button() == Qt::LeftButton) { | ||||
101 | QStyleOptionSlider opt; | ||||
102 | initStyleOption(&opt); | ||||
103 | const QRect sliderRect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); | ||||
104 | const QPoint center = sliderRect.center() - sliderRect.topLeft(); | ||||
105 | // to take half of the slider off for the setSliderPosition call we use the center - topLeft | ||||
106 | | ||||
107 | if (!sliderRect.contains(event->pos())) { | ||||
108 | event->accept(); | ||||
109 | | ||||
110 | int position = pixelPosToRangeValue(pick(event->pos() - center)); | ||||
111 | setSliderPosition(position); | ||||
112 | triggerAction(SliderMove); | ||||
113 | setRepeatAction(SliderNoAction); | ||||
114 | | ||||
115 | emit sliderMoved(position); | ||||
116 | } else { | ||||
117 | QSlider::mousePressEvent(event); | ||||
118 | } | ||||
119 | } else { | ||||
120 | QSlider::mousePressEvent(event); | ||||
121 | } | ||||
122 | } | ||||
123 | }; | ||||
124 | | ||||
59 | PhononWidget::PhononWidget(QWidget *parent) | 125 | PhononWidget::PhononWidget(QWidget *parent) | ||
60 | : QWidget(parent), | 126 | : QWidget(parent), | ||
61 | m_url(), | 127 | m_url(), | ||
62 | m_playButton(nullptr), | 128 | m_playButton(nullptr), | ||
63 | m_stopButton(nullptr), | 129 | m_stopButton(nullptr), | ||
64 | m_topLayout(nullptr), | 130 | m_topLayout(nullptr), | ||
65 | m_media(nullptr), | 131 | m_player(nullptr), | ||
66 | m_seekSlider(nullptr), | 132 | m_seekSlider(nullptr), | ||
67 | m_audioOutput(nullptr), | 133 | m_videoWidget(nullptr), | ||
68 | m_videoPlayer(nullptr) | 134 | m_playlist(nullptr) | ||
69 | { | 135 | { | ||
70 | } | 136 | } | ||
71 | 137 | | |||
72 | void PhononWidget::setUrl(const QUrl &url, MediaKind kind) | 138 | void PhononWidget::setUrl(const QUrl &url, MediaKind kind) | ||
73 | { | 139 | { | ||
74 | if (m_url != url) { | 140 | if (m_url != url) { | ||
75 | m_url = url; | 141 | m_url = url; | ||
76 | m_isVideo = kind == MediaKind::Video; | 142 | m_isVideo = kind == MediaKind::Video; | ||
143 | m_seekSlider->setValue(0); | ||||
144 | m_seekSlider->setSliderPosition(0); | ||||
77 | } | 145 | } | ||
78 | if (m_autoPlay) { | 146 | if (m_autoPlay) { | ||
79 | play(); | 147 | play(); | ||
80 | } else { | 148 | } else { | ||
81 | stop(); | 149 | stop(); | ||
82 | } | 150 | } | ||
83 | } | 151 | } | ||
84 | 152 | | |||
85 | void PhononWidget::setAutoPlay(bool autoPlay) | 153 | void PhononWidget::setAutoPlay(bool autoPlay) | ||
86 | { | 154 | { | ||
87 | m_autoPlay = autoPlay; | 155 | m_autoPlay = autoPlay; | ||
88 | if (!m_url.isEmpty() && (m_media == nullptr || m_media->state() != Phonon::State::PlayingState) && m_autoPlay && isVisible()) { | 156 | if (!m_url.isEmpty() && (m_player == nullptr || m_player->state() != QMediaPlayer::PlayingState) && m_autoPlay && isVisible()) { | ||
89 | play(); | 157 | play(); | ||
90 | } | 158 | } | ||
91 | } | 159 | } | ||
92 | 160 | | |||
93 | QUrl PhononWidget::url() const | 161 | QUrl PhononWidget::url() const | ||
94 | { | 162 | { | ||
95 | return m_url; | 163 | return m_url; | ||
96 | } | 164 | } | ||
Show All 23 Lines | 186 | if (!m_topLayout) { | |||
120 | m_topLayout->setContentsMargins(0, 0, 0, 0); | 188 | m_topLayout->setContentsMargins(0, 0, 0, 0); | ||
121 | 189 | | |||
122 | QHBoxLayout *controlsLayout = new QHBoxLayout(); | 190 | QHBoxLayout *controlsLayout = new QHBoxLayout(); | ||
123 | controlsLayout->setContentsMargins(0, 0, 0, 0); | 191 | controlsLayout->setContentsMargins(0, 0, 0, 0); | ||
124 | controlsLayout->setSpacing(0); | 192 | controlsLayout->setSpacing(0); | ||
125 | 193 | | |||
126 | m_playButton = new QToolButton(this); | 194 | m_playButton = new QToolButton(this); | ||
127 | m_stopButton = new QToolButton(this); | 195 | m_stopButton = new QToolButton(this); | ||
128 | m_seekSlider = new Phonon::SeekSlider(this); | 196 | m_seekSlider = new SeekSlider(Qt::Orientation::Horizontal, this); | ||
129 | 197 | | |||
130 | controlsLayout->addWidget(m_playButton); | 198 | controlsLayout->addWidget(m_playButton); | ||
131 | controlsLayout->addWidget(m_stopButton); | 199 | controlsLayout->addWidget(m_stopButton); | ||
132 | controlsLayout->addWidget(m_seekSlider); | 200 | controlsLayout->addWidget(m_seekSlider); | ||
133 | 201 | | |||
134 | m_topLayout->addLayout(controlsLayout); | 202 | m_topLayout->addLayout(controlsLayout); | ||
135 | 203 | | |||
136 | const int smallIconSize = IconSize(KIconLoader::Small); | 204 | const int smallIconSize = IconSize(KIconLoader::Small); | ||
137 | const QSize buttonSize(smallIconSize, smallIconSize); | 205 | const QSize buttonSize(smallIconSize, smallIconSize); | ||
138 | 206 | | |||
139 | m_playButton->setToolTip(i18n("play")); | 207 | m_playButton->setToolTip(i18n("play")); | ||
140 | m_playButton->setIconSize(buttonSize); | 208 | m_playButton->setIconSize(buttonSize); | ||
141 | m_playButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); | 209 | m_playButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); | ||
142 | m_playButton->setAutoRaise(true); | 210 | m_playButton->setAutoRaise(true); | ||
143 | connect(m_playButton, &QToolButton::clicked, this, &PhononWidget::play); | 211 | connect(m_playButton, &QToolButton::clicked, this, &PhononWidget::play); | ||
144 | 212 | | |||
145 | m_stopButton->setToolTip(i18n("stop")); | 213 | m_stopButton->setToolTip(i18n("stop")); | ||
146 | m_stopButton->setIconSize(buttonSize); | 214 | m_stopButton->setIconSize(buttonSize); | ||
147 | m_stopButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); | 215 | m_stopButton->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-stop"))); | ||
148 | m_stopButton->setAutoRaise(true); | 216 | m_stopButton->setAutoRaise(true); | ||
149 | m_stopButton->hide(); | 217 | m_stopButton->hide(); | ||
150 | connect(m_stopButton, &QToolButton::clicked, this, &PhononWidget::stop); | 218 | connect(m_stopButton, &QToolButton::clicked, this, &PhononWidget::stop); | ||
151 | 219 | | |||
152 | m_seekSlider->setIconVisible(false); | | |||
153 | | ||||
154 | // Creating an audio player or video player instance might take up to | 220 | // Creating an audio player or video player instance might take up to | ||
155 | // 2 seconds when doing it the first time. To prevent that the user | 221 | // 2 seconds when doing it the first time. To prevent that the user | ||
156 | // interface gets noticeable blocked, the creation is delayed until | 222 | // interface gets noticeable blocked, the creation is delayed until | ||
157 | // the play button has been pressed (see PhononWidget::play()). | 223 | // the play button has been pressed (see PhononWidget::play()). | ||
158 | } | 224 | } | ||
159 | } | 225 | } | ||
160 | 226 | | |||
161 | void PhononWidget::hideEvent(QHideEvent *event) | 227 | void PhononWidget::hideEvent(QHideEvent *event) | ||
162 | { | 228 | { | ||
163 | QWidget::hideEvent(event); | 229 | QWidget::hideEvent(event); | ||
164 | if (!event->spontaneous()) { | 230 | if (!event->spontaneous()) { | ||
165 | stop(); | 231 | stop(); | ||
166 | } | 232 | } | ||
167 | } | 233 | } | ||
168 | 234 | | |||
169 | void PhononWidget::stateChanged(Phonon::State newstate) | 235 | void PhononWidget::stateChanged(QMediaPlayer::State newstate) | ||
170 | { | 236 | { | ||
171 | setUpdatesEnabled(false); | 237 | setUpdatesEnabled(false); | ||
172 | switch (newstate) { | 238 | switch (newstate) { | ||
173 | case Phonon::PlayingState: | 239 | case QMediaPlayer::State::PlayingState: | ||
174 | case Phonon::BufferingState: | 240 | case QMediaPlayer::State::PausedState: | ||
175 | m_stopButton->show(); | 241 | m_stopButton->show(); | ||
176 | m_playButton->hide(); | 242 | m_playButton->hide(); | ||
177 | break; | 243 | break; | ||
178 | default: | 244 | default: | ||
179 | m_stopButton->hide(); | 245 | m_stopButton->hide(); | ||
180 | m_playButton->show(); | 246 | m_playButton->show(); | ||
181 | break; | 247 | break; | ||
182 | } | 248 | } | ||
183 | setUpdatesEnabled(true); | 249 | setUpdatesEnabled(true); | ||
184 | } | 250 | } | ||
185 | 251 | | |||
186 | void PhononWidget::play() | 252 | void PhononWidget::play() | ||
187 | { | 253 | { | ||
188 | if (!m_media) { | 254 | if (!m_playlist) { | ||
189 | m_media = new Phonon::MediaObject(this); | 255 | m_playlist = new QMediaPlaylist; | ||
190 | connect(m_media, &Phonon::MediaObject::stateChanged, | 256 | | ||
191 | this, &PhononWidget::stateChanged); | 257 | m_player = new QMediaPlayer; | ||
192 | connect(m_media, &Phonon::MediaObject::finished, | 258 | m_player->setPlaylist(m_playlist); | ||
193 | this, &PhononWidget::finished); | | |||
194 | m_seekSlider->setMediaObject(m_media); | | |||
195 | } | | |||
196 | 259 | | |||
197 | if (!m_videoPlayer) { | 260 | m_videoWidget = new EmbeddedVideoPlayer(this); | ||
198 | m_videoPlayer = new EmbeddedVideoPlayer(this); | 261 | m_player->setVideoOutput(m_videoWidget); | ||
199 | m_videoPlayer->installEventFilter(this); | 262 | m_topLayout->insertWidget(0, m_videoWidget); | ||
200 | m_topLayout->insertWidget(0, m_videoPlayer); | | |||
201 | Phonon::createPath(m_media, m_videoPlayer); | | |||
202 | applyVideoSize(); | 263 | applyVideoSize(); | ||
203 | } | | |||
204 | 264 | | |||
205 | if (!m_audioOutput) { | 265 | connect(m_seekSlider, &QAbstractSlider::sliderMoved, | ||
206 | m_audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); | 266 | this, &PhononWidget::setPosition); | ||
207 | Phonon::createPath(m_media, m_audioOutput); | 267 | | ||
268 | connect(m_player, &QMediaPlayer::stateChanged, this, &PhononWidget::stateChanged); | ||||
269 | connect(m_player, &QMediaPlayer::positionChanged, this, &PhononWidget::positionChanged); | ||||
270 | connect(m_player, &QMediaPlayer::durationChanged, this, &PhononWidget::durationChanged); | ||||
208 | } | 271 | } | ||
209 | 272 | | |||
210 | if (m_isVideo) { | 273 | if (m_isVideo) { | ||
211 | emit hasVideoChanged(true); | 274 | emit hasVideoChanged(true); | ||
212 | } | 275 | } | ||
213 | 276 | | |||
214 | if (m_url != m_media->currentSource().url()) { | 277 | if (m_url != m_playlist->currentMedia().canonicalUrl()) { | ||
215 | m_media->setCurrentSource(m_url); | 278 | m_playlist->addMedia(m_url); | ||
279 | m_playlist->next(); | ||||
216 | } | 280 | } | ||
217 | m_media->play(); | 281 | m_player->play(); | ||
218 | 282 | | |||
219 | m_videoPlayer->setVisible(m_isVideo); | 283 | m_videoWidget->setVisible(m_isVideo); | ||
220 | } | 284 | } | ||
221 | 285 | | |||
222 | void PhononWidget::finished() | 286 | void PhononWidget::finished() | ||
223 | { | 287 | { | ||
224 | if (m_isVideo) { | 288 | if (m_isVideo) { | ||
225 | m_videoPlayer->hide(); | 289 | m_videoWidget->hide(); | ||
226 | emit hasVideoChanged(false); | 290 | emit hasVideoChanged(false); | ||
227 | } | 291 | } | ||
228 | } | 292 | } | ||
229 | 293 | | |||
230 | void PhononWidget::stop() | 294 | void PhononWidget::stop() | ||
231 | { | 295 | { | ||
232 | if (m_media) { | 296 | if (m_player) { | ||
233 | m_media->stop(); | 297 | m_playlist->clear(); | ||
234 | m_videoPlayer->hide(); | 298 | m_player->stop(); | ||
299 | m_videoWidget->hide(); | ||||
235 | emit hasVideoChanged(false); | 300 | emit hasVideoChanged(false); | ||
236 | } | 301 | } | ||
237 | } | 302 | } | ||
238 | 303 | | |||
239 | void PhononWidget::applyVideoSize() | 304 | void PhononWidget::applyVideoSize() | ||
240 | { | 305 | { | ||
241 | if ((m_videoPlayer) && m_videoSize.isValid()) { | 306 | if ((m_videoWidget) && m_videoSize.isValid()) { | ||
242 | m_videoPlayer->setSizeHint(m_videoSize); | 307 | m_videoWidget->setSizeHint(m_videoSize); | ||
308 | } | ||||
309 | } | ||||
310 | | ||||
311 | void PhononWidget::setPosition(qint64 position) | ||||
312 | { | ||||
313 | if (!m_player || m_player->state() == QMediaPlayer::StoppedState) { | ||||
314 | play(); | ||||
315 | } else { | ||||
316 | m_player->setPosition(position); | ||||
243 | } | 317 | } | ||
244 | } | 318 | } | ||
245 | 319 | | |||
320 | void PhononWidget::positionChanged(qint64 position) | ||||
321 | { | ||||
322 | if (m_player && m_player->state() != QMediaPlayer::StoppedState) { | ||||
323 | m_seekSlider->setValue(static_cast<int>(position)); | ||||
324 | } | ||||
325 | } | ||||
326 | | ||||
327 | void PhononWidget::durationChanged(qint64 duration) | ||||
328 | { | ||||
329 | m_seekSlider->setRange(0, static_cast<int>(duration)); | ||||
330 | } | ||||
331 | | ||||
332 | | ||||
246 | #include "phononwidget.moc" | 333 | #include "phononwidget.moc" |