|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the demonstration applications of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ***************************************************************************/ |
|
41 |
|
42 #include <QtGui> |
|
43 |
|
44 #define SLIDER_RANGE 8 |
|
45 |
|
46 #include "mediaplayer.h" |
|
47 #include "ui_settings.h" |
|
48 |
|
49 |
|
50 MediaVideoWidget::MediaVideoWidget(MediaPlayer *player, QWidget *parent) : |
|
51 Phonon::VideoWidget(parent), m_player(player), m_action(this) |
|
52 { |
|
53 m_action.setCheckable(true); |
|
54 m_action.setChecked(false); |
|
55 m_action.setShortcut(QKeySequence( Qt::AltModifier + Qt::Key_Return)); |
|
56 m_action.setShortcutContext(Qt::WindowShortcut); |
|
57 connect(&m_action, SIGNAL(toggled(bool)), SLOT(setFullScreen(bool))); |
|
58 addAction(&m_action); |
|
59 setAcceptDrops(true); |
|
60 } |
|
61 |
|
62 void MediaVideoWidget::setFullScreen(bool enabled) |
|
63 { |
|
64 Phonon::VideoWidget::setFullScreen(enabled); |
|
65 emit fullScreenChanged(enabled); |
|
66 } |
|
67 |
|
68 void MediaVideoWidget::mouseDoubleClickEvent(QMouseEvent *e) |
|
69 { |
|
70 Phonon::VideoWidget::mouseDoubleClickEvent(e); |
|
71 setFullScreen(!isFullScreen()); |
|
72 } |
|
73 |
|
74 void MediaVideoWidget::keyPressEvent(QKeyEvent *e) |
|
75 { |
|
76 if(!e->modifiers()) { |
|
77 // On non-QWERTY Symbian key-based devices, there is no space key. |
|
78 // The zero key typically is marked with a space character. |
|
79 if (e->key() == Qt::Key_Space || e->key() == Qt::Key_0) { |
|
80 m_player->playPause(); |
|
81 e->accept(); |
|
82 return; |
|
83 } |
|
84 |
|
85 // On Symbian devices, there is no key which maps to Qt::Key_Escape |
|
86 // On devices which lack a backspace key (i.e. non-QWERTY devices), |
|
87 // the 'C' key maps to Qt::Key_Backspace |
|
88 else if (e->key() == Qt::Key_Escape || e->key() == Qt::Key_Backspace) { |
|
89 setFullScreen(false); |
|
90 e->accept(); |
|
91 return; |
|
92 } |
|
93 } |
|
94 Phonon::VideoWidget::keyPressEvent(e); |
|
95 } |
|
96 |
|
97 bool MediaVideoWidget::event(QEvent *e) |
|
98 { |
|
99 switch(e->type()) |
|
100 { |
|
101 case QEvent::Close: |
|
102 //we just ignore the cose events on the video widget |
|
103 //this prevents ALT+F4 from having an effect in fullscreen mode |
|
104 e->ignore(); |
|
105 return true; |
|
106 case QEvent::MouseMove: |
|
107 #ifndef QT_NO_CURSOR |
|
108 unsetCursor(); |
|
109 #endif |
|
110 //fall through |
|
111 case QEvent::WindowStateChange: |
|
112 { |
|
113 //we just update the state of the checkbox, in case it wasn't already |
|
114 m_action.setChecked(windowState() & Qt::WindowFullScreen); |
|
115 const Qt::WindowFlags flags = m_player->windowFlags(); |
|
116 if (windowState() & Qt::WindowFullScreen) { |
|
117 m_timer.start(1000, this); |
|
118 } else { |
|
119 m_timer.stop(); |
|
120 #ifndef QT_NO_CURSOR |
|
121 unsetCursor(); |
|
122 #endif |
|
123 } |
|
124 } |
|
125 break; |
|
126 default: |
|
127 break; |
|
128 } |
|
129 |
|
130 return Phonon::VideoWidget::event(e); |
|
131 } |
|
132 |
|
133 void MediaVideoWidget::timerEvent(QTimerEvent *e) |
|
134 { |
|
135 if (e->timerId() == m_timer.timerId()) { |
|
136 //let's store the cursor shape |
|
137 #ifndef QT_NO_CURSOR |
|
138 setCursor(Qt::BlankCursor); |
|
139 #endif |
|
140 } |
|
141 Phonon::VideoWidget::timerEvent(e); |
|
142 } |
|
143 |
|
144 void MediaVideoWidget::dropEvent(QDropEvent *e) |
|
145 { |
|
146 m_player->handleDrop(e); |
|
147 } |
|
148 |
|
149 void MediaVideoWidget::dragEnterEvent(QDragEnterEvent *e) { |
|
150 if (e->mimeData()->hasUrls()) |
|
151 e->acceptProposedAction(); |
|
152 } |
|
153 |
|
154 |
|
155 MediaPlayer::MediaPlayer(const QString &filePath, |
|
156 const bool hasSmallScreen) : |
|
157 playButton(0), nextEffect(0), settingsDialog(0), ui(0), |
|
158 m_AudioOutput(Phonon::VideoCategory), |
|
159 m_videoWidget(new MediaVideoWidget(this)), |
|
160 m_hasSmallScreen(hasSmallScreen) |
|
161 { |
|
162 setWindowTitle(tr("Media Player")); |
|
163 setContextMenuPolicy(Qt::CustomContextMenu); |
|
164 m_videoWidget->setContextMenuPolicy(Qt::CustomContextMenu); |
|
165 |
|
166 QSize buttonSize(34, 28); |
|
167 |
|
168 QPushButton *openButton = new QPushButton(this); |
|
169 |
|
170 openButton->setIcon(style()->standardIcon(QStyle::SP_DialogOpenButton)); |
|
171 QPalette bpal; |
|
172 QColor arrowcolor = bpal.buttonText().color(); |
|
173 if (arrowcolor == Qt::black) |
|
174 arrowcolor = QColor(80, 80, 80); |
|
175 bpal.setBrush(QPalette::ButtonText, arrowcolor); |
|
176 openButton->setPalette(bpal); |
|
177 |
|
178 rewindButton = new QPushButton(this); |
|
179 rewindButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipBackward)); |
|
180 |
|
181 forwardButton = new QPushButton(this); |
|
182 forwardButton->setIcon(style()->standardIcon(QStyle::SP_MediaSkipForward)); |
|
183 forwardButton->setEnabled(false); |
|
184 |
|
185 playButton = new QPushButton(this); |
|
186 playIcon = style()->standardIcon(QStyle::SP_MediaPlay); |
|
187 pauseIcon = style()->standardIcon(QStyle::SP_MediaPause); |
|
188 playButton->setIcon(playIcon); |
|
189 |
|
190 slider = new Phonon::SeekSlider(this); |
|
191 slider->setMediaObject(&m_MediaObject); |
|
192 volume = new Phonon::VolumeSlider(&m_AudioOutput); |
|
193 |
|
194 QVBoxLayout *vLayout = new QVBoxLayout(this); |
|
195 vLayout->setContentsMargins(8, 8, 8, 8); |
|
196 |
|
197 QHBoxLayout *layout = new QHBoxLayout(); |
|
198 |
|
199 info = new QLabel(this); |
|
200 info->setMinimumHeight(70); |
|
201 info->setAcceptDrops(false); |
|
202 info->setMargin(2); |
|
203 info->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken); |
|
204 info->setLineWidth(2); |
|
205 info->setAutoFillBackground(true); |
|
206 |
|
207 QPalette palette; |
|
208 palette.setBrush(QPalette::WindowText, Qt::white); |
|
209 #ifndef Q_WS_MAC |
|
210 openButton->setMinimumSize(54, buttonSize.height()); |
|
211 rewindButton->setMinimumSize(buttonSize); |
|
212 forwardButton->setMinimumSize(buttonSize); |
|
213 playButton->setMinimumSize(buttonSize); |
|
214 #endif |
|
215 info->setStyleSheet("border-image:url(:/images/screen.png) ; border-width:3px"); |
|
216 info->setPalette(palette); |
|
217 info->setText(tr("<center>No media</center>")); |
|
218 |
|
219 volume->setFixedWidth(120); |
|
220 |
|
221 layout->addWidget(openButton); |
|
222 layout->addWidget(rewindButton); |
|
223 layout->addWidget(playButton); |
|
224 layout->addWidget(forwardButton); |
|
225 |
|
226 layout->addStretch(); |
|
227 layout->addWidget(volume); |
|
228 |
|
229 vLayout->addWidget(info); |
|
230 initVideoWindow(); |
|
231 vLayout->addWidget(&m_videoWindow); |
|
232 QVBoxLayout *buttonPanelLayout = new QVBoxLayout(); |
|
233 m_videoWindow.hide(); |
|
234 buttonPanelLayout->addLayout(layout); |
|
235 |
|
236 timeLabel = new QLabel(this); |
|
237 progressLabel = new QLabel(this); |
|
238 QWidget *sliderPanel = new QWidget(this); |
|
239 QHBoxLayout *sliderLayout = new QHBoxLayout(); |
|
240 sliderLayout->addWidget(slider); |
|
241 sliderLayout->addWidget(timeLabel); |
|
242 sliderLayout->addWidget(progressLabel); |
|
243 sliderLayout->setContentsMargins(0, 0, 0, 0); |
|
244 sliderPanel->setLayout(sliderLayout); |
|
245 |
|
246 buttonPanelLayout->addWidget(sliderPanel); |
|
247 buttonPanelLayout->setContentsMargins(0, 0, 0, 0); |
|
248 #ifdef Q_OS_MAC |
|
249 layout->setSpacing(4); |
|
250 buttonPanelLayout->setSpacing(0); |
|
251 info->setMinimumHeight(100); |
|
252 info->setFont(QFont("verdana", 15)); |
|
253 // QStyle *flatButtonStyle = new QWindowsStyle; |
|
254 openButton->setFocusPolicy(Qt::NoFocus); |
|
255 // openButton->setStyle(flatButtonStyle); |
|
256 // playButton->setStyle(flatButtonStyle); |
|
257 // rewindButton->setStyle(flatButtonStyle); |
|
258 // forwardButton->setStyle(flatButtonStyle); |
|
259 #endif |
|
260 QWidget *buttonPanelWidget = new QWidget(this); |
|
261 buttonPanelWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); |
|
262 buttonPanelWidget->setLayout(buttonPanelLayout); |
|
263 vLayout->addWidget(buttonPanelWidget); |
|
264 |
|
265 QHBoxLayout *labelLayout = new QHBoxLayout(); |
|
266 |
|
267 vLayout->addLayout(labelLayout); |
|
268 setLayout(vLayout); |
|
269 |
|
270 // Create menu bar: |
|
271 fileMenu = new QMenu(this); |
|
272 QAction *openFileAction = fileMenu->addAction(tr("Open &File...")); |
|
273 QAction *openUrlAction = fileMenu->addAction(tr("Open &Location...")); |
|
274 QAction *const openLinkAction = fileMenu->addAction(tr("Open &RAM File...")); |
|
275 |
|
276 connect(openLinkAction, SIGNAL(triggered(bool)), this, SLOT(openRamFile())); |
|
277 |
|
278 fileMenu->addSeparator(); |
|
279 QMenu *aspectMenu = fileMenu->addMenu(tr("&Aspect ratio")); |
|
280 QActionGroup *aspectGroup = new QActionGroup(aspectMenu); |
|
281 connect(aspectGroup, SIGNAL(triggered(QAction*)), this, SLOT(aspectChanged(QAction*))); |
|
282 aspectGroup->setExclusive(true); |
|
283 QAction *aspectActionAuto = aspectMenu->addAction(tr("Auto")); |
|
284 aspectActionAuto->setCheckable(true); |
|
285 aspectActionAuto->setChecked(true); |
|
286 aspectGroup->addAction(aspectActionAuto); |
|
287 QAction *aspectActionScale = aspectMenu->addAction(tr("Scale")); |
|
288 aspectActionScale->setCheckable(true); |
|
289 aspectGroup->addAction(aspectActionScale); |
|
290 QAction *aspectAction16_9 = aspectMenu->addAction(tr("16/9")); |
|
291 aspectAction16_9->setCheckable(true); |
|
292 aspectGroup->addAction(aspectAction16_9); |
|
293 QAction *aspectAction4_3 = aspectMenu->addAction(tr("4/3")); |
|
294 aspectAction4_3->setCheckable(true); |
|
295 aspectGroup->addAction(aspectAction4_3); |
|
296 |
|
297 QMenu *scaleMenu = fileMenu->addMenu(tr("&Scale mode")); |
|
298 QActionGroup *scaleGroup = new QActionGroup(scaleMenu); |
|
299 connect(scaleGroup, SIGNAL(triggered(QAction*)), this, SLOT(scaleChanged(QAction*))); |
|
300 scaleGroup->setExclusive(true); |
|
301 QAction *scaleActionFit = scaleMenu->addAction(tr("Fit in view")); |
|
302 scaleActionFit->setCheckable(true); |
|
303 scaleActionFit->setChecked(true); |
|
304 scaleGroup->addAction(scaleActionFit); |
|
305 QAction *scaleActionCrop = scaleMenu->addAction(tr("Scale and crop")); |
|
306 scaleActionCrop->setCheckable(true); |
|
307 scaleGroup->addAction(scaleActionCrop); |
|
308 |
|
309 m_fullScreenAction = fileMenu->addAction(tr("Full screen video")); |
|
310 m_fullScreenAction->setCheckable(true); |
|
311 m_fullScreenAction->setEnabled(false); // enabled by hasVideoChanged |
|
312 bool b = connect(m_fullScreenAction, SIGNAL(toggled(bool)), m_videoWidget, SLOT(setFullScreen(bool))); |
|
313 Q_ASSERT(b); |
|
314 b = connect(m_videoWidget, SIGNAL(fullScreenChanged(bool)), m_fullScreenAction, SLOT(setChecked(bool))); |
|
315 Q_ASSERT(b); |
|
316 |
|
317 fileMenu->addSeparator(); |
|
318 QAction *settingsAction = fileMenu->addAction(tr("&Settings...")); |
|
319 |
|
320 // Setup signal connections: |
|
321 connect(rewindButton, SIGNAL(clicked()), this, SLOT(rewind())); |
|
322 //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); |
|
323 openButton->setMenu(fileMenu); |
|
324 |
|
325 connect(playButton, SIGNAL(clicked()), this, SLOT(playPause())); |
|
326 connect(forwardButton, SIGNAL(clicked()), this, SLOT(forward())); |
|
327 //connect(openButton, SIGNAL(clicked()), this, SLOT(openFile())); |
|
328 connect(settingsAction, SIGNAL(triggered(bool)), this, SLOT(showSettingsDialog())); |
|
329 connect(openUrlAction, SIGNAL(triggered(bool)), this, SLOT(openUrl())); |
|
330 connect(openFileAction, SIGNAL(triggered(bool)), this, SLOT(openFile())); |
|
331 |
|
332 connect(m_videoWidget, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); |
|
333 connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); |
|
334 connect(&m_MediaObject, SIGNAL(metaDataChanged()), this, SLOT(updateInfo())); |
|
335 connect(&m_MediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(updateTime())); |
|
336 connect(&m_MediaObject, SIGNAL(tick(qint64)), this, SLOT(updateTime())); |
|
337 connect(&m_MediaObject, SIGNAL(finished()), this, SLOT(finished())); |
|
338 connect(&m_MediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)), this, SLOT(stateChanged(Phonon::State,Phonon::State))); |
|
339 connect(&m_MediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int))); |
|
340 connect(&m_MediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool))); |
|
341 |
|
342 rewindButton->setEnabled(false); |
|
343 playButton->setEnabled(false); |
|
344 setAcceptDrops(true); |
|
345 |
|
346 m_audioOutputPath = Phonon::createPath(&m_MediaObject, &m_AudioOutput); |
|
347 Phonon::createPath(&m_MediaObject, m_videoWidget); |
|
348 |
|
349 if (!filePath.isEmpty()) |
|
350 setFile(filePath); |
|
351 resize(minimumSizeHint()); |
|
352 } |
|
353 |
|
354 void MediaPlayer::stateChanged(Phonon::State newstate, Phonon::State oldstate) |
|
355 { |
|
356 Q_UNUSED(oldstate); |
|
357 |
|
358 if (oldstate == Phonon::LoadingState) { |
|
359 QRect videoHintRect = QRect(QPoint(0, 0), m_videoWindow.sizeHint()); |
|
360 QRect newVideoRect = QApplication::desktop()->screenGeometry().intersected(videoHintRect); |
|
361 if (!m_hasSmallScreen) { |
|
362 if (m_MediaObject.hasVideo()) { |
|
363 // Flush event que so that sizeHint takes the |
|
364 // recently shown/hidden m_videoWindow into account: |
|
365 qApp->processEvents(); |
|
366 resize(sizeHint()); |
|
367 } else |
|
368 resize(minimumSize()); |
|
369 } |
|
370 } |
|
371 |
|
372 switch (newstate) { |
|
373 case Phonon::ErrorState: |
|
374 if (m_MediaObject.errorType() == Phonon::FatalError) { |
|
375 playButton->setEnabled(false); |
|
376 rewindButton->setEnabled(false); |
|
377 } else { |
|
378 m_MediaObject.pause(); |
|
379 } |
|
380 QMessageBox::warning(this, "Phonon Mediaplayer", m_MediaObject.errorString(), QMessageBox::Close); |
|
381 break; |
|
382 |
|
383 case Phonon::StoppedState: |
|
384 m_videoWidget->setFullScreen(false); |
|
385 // Fall through |
|
386 case Phonon::PausedState: |
|
387 playButton->setIcon(playIcon); |
|
388 if (m_MediaObject.currentSource().type() != Phonon::MediaSource::Invalid){ |
|
389 playButton->setEnabled(true); |
|
390 rewindButton->setEnabled(true); |
|
391 } else { |
|
392 playButton->setEnabled(false); |
|
393 rewindButton->setEnabled(false); |
|
394 } |
|
395 break; |
|
396 case Phonon::PlayingState: |
|
397 playButton->setEnabled(true); |
|
398 playButton->setIcon(pauseIcon); |
|
399 if (m_MediaObject.hasVideo()) |
|
400 m_videoWindow.show(); |
|
401 // Fall through |
|
402 case Phonon::BufferingState: |
|
403 rewindButton->setEnabled(true); |
|
404 break; |
|
405 case Phonon::LoadingState: |
|
406 rewindButton->setEnabled(false); |
|
407 break; |
|
408 } |
|
409 |
|
410 } |
|
411 |
|
412 void MediaPlayer::initSettingsDialog() |
|
413 { |
|
414 settingsDialog = new QDialog(this); |
|
415 ui = new Ui_settings(); |
|
416 ui->setupUi(settingsDialog); |
|
417 |
|
418 connect(ui->brightnessSlider, SIGNAL(valueChanged(int)), this, SLOT(setBrightness(int))); |
|
419 connect(ui->hueSlider, SIGNAL(valueChanged(int)), this, SLOT(setHue(int))); |
|
420 connect(ui->saturationSlider, SIGNAL(valueChanged(int)), this, SLOT(setSaturation(int))); |
|
421 connect(ui->contrastSlider , SIGNAL(valueChanged(int)), this, SLOT(setContrast(int))); |
|
422 connect(ui->aspectCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setAspect(int))); |
|
423 connect(ui->scalemodeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(setScale(int))); |
|
424 |
|
425 ui->brightnessSlider->setValue(int(m_videoWidget->brightness() * SLIDER_RANGE)); |
|
426 ui->hueSlider->setValue(int(m_videoWidget->hue() * SLIDER_RANGE)); |
|
427 ui->saturationSlider->setValue(int(m_videoWidget->saturation() * SLIDER_RANGE)); |
|
428 ui->contrastSlider->setValue(int(m_videoWidget->contrast() * SLIDER_RANGE)); |
|
429 ui->aspectCombo->setCurrentIndex(m_videoWidget->aspectRatio()); |
|
430 ui->scalemodeCombo->setCurrentIndex(m_videoWidget->scaleMode()); |
|
431 connect(ui->effectButton, SIGNAL(clicked()), this, SLOT(configureEffect())); |
|
432 |
|
433 #ifdef Q_WS_X11 |
|
434 //Cross fading is not currently implemented in the GStreamer backend |
|
435 ui->crossFadeSlider->setVisible(false); |
|
436 ui->crossFadeLabel->setVisible(false); |
|
437 ui->crossFadeLabel1->setVisible(false); |
|
438 ui->crossFadeLabel2->setVisible(false); |
|
439 ui->crossFadeLabel3->setVisible(false); |
|
440 #endif |
|
441 ui->crossFadeSlider->setValue((int)(2 * m_MediaObject.transitionTime() / 1000.0f)); |
|
442 |
|
443 // Insert audio devices: |
|
444 QList<Phonon::AudioOutputDevice> devices = Phonon::BackendCapabilities::availableAudioOutputDevices(); |
|
445 for (int i=0; i<devices.size(); i++){ |
|
446 QString itemText = devices[i].name(); |
|
447 if (!devices[i].description().isEmpty()) { |
|
448 itemText += QString::fromLatin1(" (%1)").arg(devices[i].description()); |
|
449 } |
|
450 ui->deviceCombo->addItem(itemText); |
|
451 if (devices[i] == m_AudioOutput.outputDevice()) |
|
452 ui->deviceCombo->setCurrentIndex(i); |
|
453 } |
|
454 |
|
455 // Insert audio effects: |
|
456 ui->audioEffectsCombo->addItem(tr("<no effect>")); |
|
457 QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects(); |
|
458 Phonon::Effect *currEffect = currEffects.size() ? currEffects[0] : 0; |
|
459 QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); |
|
460 for (int i=0; i<availableEffects.size(); i++){ |
|
461 ui->audioEffectsCombo->addItem(availableEffects[i].name()); |
|
462 if (currEffect && availableEffects[i] == currEffect->description()) |
|
463 ui->audioEffectsCombo->setCurrentIndex(i+1); |
|
464 } |
|
465 connect(ui->audioEffectsCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(effectChanged())); |
|
466 |
|
467 } |
|
468 |
|
469 void MediaPlayer::effectChanged() |
|
470 { |
|
471 int currentIndex = ui->audioEffectsCombo->currentIndex(); |
|
472 if (currentIndex) { |
|
473 QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); |
|
474 Phonon::EffectDescription chosenEffect = availableEffects[currentIndex - 1]; |
|
475 |
|
476 QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects(); |
|
477 Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0; |
|
478 |
|
479 // Deleting the running effect will stop playback, it is deleted when removed from path |
|
480 if (nextEffect && !(currentEffect && (currentEffect->description().name() == nextEffect->description().name()))) |
|
481 delete nextEffect; |
|
482 |
|
483 nextEffect = new Phonon::Effect(chosenEffect); |
|
484 } |
|
485 ui->effectButton->setEnabled(currentIndex); |
|
486 } |
|
487 |
|
488 void MediaPlayer::showSettingsDialog() |
|
489 { |
|
490 const bool hasPausedForDialog = playPauseForDialog(); |
|
491 |
|
492 if (!settingsDialog) |
|
493 initSettingsDialog(); |
|
494 |
|
495 float oldBrightness = m_videoWidget->brightness(); |
|
496 float oldHue = m_videoWidget->hue(); |
|
497 float oldSaturation = m_videoWidget->saturation(); |
|
498 float oldContrast = m_videoWidget->contrast(); |
|
499 Phonon::VideoWidget::AspectRatio oldAspect = m_videoWidget->aspectRatio(); |
|
500 Phonon::VideoWidget::ScaleMode oldScale = m_videoWidget->scaleMode(); |
|
501 int currentEffect = ui->audioEffectsCombo->currentIndex(); |
|
502 settingsDialog->exec(); |
|
503 |
|
504 if (settingsDialog->result() == QDialog::Accepted){ |
|
505 m_MediaObject.setTransitionTime((int)(1000 * float(ui->crossFadeSlider->value()) / 2.0f)); |
|
506 QList<Phonon::AudioOutputDevice> devices = Phonon::BackendCapabilities::availableAudioOutputDevices(); |
|
507 m_AudioOutput.setOutputDevice(devices[ui->deviceCombo->currentIndex()]); |
|
508 QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects(); |
|
509 QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); |
|
510 |
|
511 if (ui->audioEffectsCombo->currentIndex() > 0){ |
|
512 Phonon::Effect *currentEffect = currEffects.size() ? currEffects[0] : 0; |
|
513 if (!currentEffect || currentEffect->description() != nextEffect->description()){ |
|
514 foreach(Phonon::Effect *effect, currEffects) { |
|
515 m_audioOutputPath.removeEffect(effect); |
|
516 delete effect; |
|
517 } |
|
518 m_audioOutputPath.insertEffect(nextEffect); |
|
519 } |
|
520 } else { |
|
521 foreach(Phonon::Effect *effect, currEffects) { |
|
522 m_audioOutputPath.removeEffect(effect); |
|
523 delete effect; |
|
524 nextEffect = 0; |
|
525 } |
|
526 } |
|
527 } else { |
|
528 // Restore previous settings |
|
529 m_videoWidget->setBrightness(oldBrightness); |
|
530 m_videoWidget->setSaturation(oldSaturation); |
|
531 m_videoWidget->setHue(oldHue); |
|
532 m_videoWidget->setContrast(oldContrast); |
|
533 m_videoWidget->setAspectRatio(oldAspect); |
|
534 m_videoWidget->setScaleMode(oldScale); |
|
535 ui->audioEffectsCombo->setCurrentIndex(currentEffect); |
|
536 } |
|
537 |
|
538 if (hasPausedForDialog) |
|
539 m_MediaObject.play(); |
|
540 } |
|
541 |
|
542 void MediaPlayer::initVideoWindow() |
|
543 { |
|
544 QVBoxLayout *videoLayout = new QVBoxLayout(); |
|
545 videoLayout->addWidget(m_videoWidget); |
|
546 videoLayout->setContentsMargins(0, 0, 0, 0); |
|
547 m_videoWindow.setLayout(videoLayout); |
|
548 m_videoWindow.setMinimumSize(100, 100); |
|
549 } |
|
550 |
|
551 |
|
552 void MediaPlayer::configureEffect() |
|
553 { |
|
554 if (!nextEffect) |
|
555 return; |
|
556 |
|
557 |
|
558 QList<Phonon::Effect *> currEffects = m_audioOutputPath.effects(); |
|
559 const QList<Phonon::EffectDescription> availableEffects = Phonon::BackendCapabilities::availableAudioEffects(); |
|
560 if (ui->audioEffectsCombo->currentIndex() > 0) { |
|
561 Phonon::EffectDescription chosenEffect = availableEffects[ui->audioEffectsCombo->currentIndex() - 1]; |
|
562 |
|
563 QDialog effectDialog; |
|
564 effectDialog.setWindowTitle(tr("Configure effect")); |
|
565 QVBoxLayout *topLayout = new QVBoxLayout(&effectDialog); |
|
566 |
|
567 QLabel *description = new QLabel("<b>Description:</b><br>" + chosenEffect.description(), &effectDialog); |
|
568 description->setWordWrap(true); |
|
569 topLayout->addWidget(description); |
|
570 |
|
571 QScrollArea *scrollArea = new QScrollArea(&effectDialog); |
|
572 topLayout->addWidget(scrollArea); |
|
573 |
|
574 QVariantList savedParamValues; |
|
575 foreach(Phonon::EffectParameter param, nextEffect->parameters()) { |
|
576 savedParamValues << nextEffect->parameterValue(param); |
|
577 } |
|
578 |
|
579 QWidget *scrollWidget = new Phonon::EffectWidget(nextEffect); |
|
580 scrollWidget->setMinimumWidth(320); |
|
581 scrollWidget->setContentsMargins(10, 10, 10,10); |
|
582 scrollArea->setWidget(scrollWidget); |
|
583 |
|
584 QDialogButtonBox *bbox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, &effectDialog); |
|
585 connect(bbox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), &effectDialog, SLOT(accept())); |
|
586 connect(bbox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), &effectDialog, SLOT(reject())); |
|
587 topLayout->addWidget(bbox); |
|
588 |
|
589 effectDialog.exec(); |
|
590 |
|
591 if (effectDialog.result() != QDialog::Accepted) { |
|
592 //we need to restore the paramaters values |
|
593 int currentIndex = 0; |
|
594 foreach(Phonon::EffectParameter param, nextEffect->parameters()) { |
|
595 nextEffect->setParameterValue(param, savedParamValues.at(currentIndex++)); |
|
596 } |
|
597 |
|
598 } |
|
599 } |
|
600 } |
|
601 |
|
602 void MediaPlayer::handleDrop(QDropEvent *e) |
|
603 { |
|
604 QList<QUrl> urls = e->mimeData()->urls(); |
|
605 if (e->proposedAction() == Qt::MoveAction){ |
|
606 // Just add to the queue: |
|
607 for (int i=0; i<urls.size(); i++) |
|
608 m_MediaObject.enqueue(Phonon::MediaSource(urls[i].toLocalFile())); |
|
609 } else { |
|
610 // Create new queue: |
|
611 m_MediaObject.clearQueue(); |
|
612 if (urls.size() > 0) { |
|
613 QString fileName = urls[0].toLocalFile(); |
|
614 QDir dir(fileName); |
|
615 if (dir.exists()) { |
|
616 dir.setFilter(QDir::Files); |
|
617 QStringList entries = dir.entryList(); |
|
618 if (entries.size() > 0) { |
|
619 setFile(fileName + QDir::separator() + entries[0]); |
|
620 for (int i=1; i< entries.size(); ++i) |
|
621 m_MediaObject.enqueue(fileName + QDir::separator() + entries[i]); |
|
622 } |
|
623 } else { |
|
624 setFile(fileName); |
|
625 for (int i=1; i<urls.size(); i++) |
|
626 m_MediaObject.enqueue(Phonon::MediaSource(urls[i].toLocalFile())); |
|
627 } |
|
628 } |
|
629 } |
|
630 forwardButton->setEnabled(m_MediaObject.queue().size() > 0); |
|
631 m_MediaObject.play(); |
|
632 } |
|
633 |
|
634 void MediaPlayer::dropEvent(QDropEvent *e) |
|
635 { |
|
636 if (e->mimeData()->hasUrls() && e->proposedAction() != Qt::LinkAction) { |
|
637 e->acceptProposedAction(); |
|
638 handleDrop(e); |
|
639 } else { |
|
640 e->ignore(); |
|
641 } |
|
642 } |
|
643 |
|
644 void MediaPlayer::dragEnterEvent(QDragEnterEvent *e) |
|
645 { |
|
646 dragMoveEvent(e); |
|
647 } |
|
648 |
|
649 void MediaPlayer::dragMoveEvent(QDragMoveEvent *e) |
|
650 { |
|
651 if (e->mimeData()->hasUrls()) { |
|
652 if (e->proposedAction() == Qt::CopyAction || e->proposedAction() == Qt::MoveAction){ |
|
653 e->acceptProposedAction(); |
|
654 } |
|
655 } |
|
656 } |
|
657 |
|
658 void MediaPlayer::playPause() |
|
659 { |
|
660 if (m_MediaObject.state() == Phonon::PlayingState) |
|
661 m_MediaObject.pause(); |
|
662 else { |
|
663 if (m_MediaObject.currentTime() == m_MediaObject.totalTime()) |
|
664 m_MediaObject.seek(0); |
|
665 m_MediaObject.play(); |
|
666 } |
|
667 } |
|
668 |
|
669 void MediaPlayer::setFile(const QString &fileName) |
|
670 { |
|
671 setWindowTitle(fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1)); |
|
672 m_MediaObject.setCurrentSource(Phonon::MediaSource(fileName)); |
|
673 m_MediaObject.play(); |
|
674 } |
|
675 |
|
676 void MediaPlayer::setLocation(const QString& location) |
|
677 { |
|
678 setWindowTitle(location.right(location.length() - location.lastIndexOf('/') - 1)); |
|
679 m_MediaObject.setCurrentSource(Phonon::MediaSource(QUrl::fromEncoded(location.toUtf8()))); |
|
680 m_MediaObject.play(); |
|
681 } |
|
682 |
|
683 bool MediaPlayer::playPauseForDialog() |
|
684 { |
|
685 // If we're running on a small screen, we want to pause the video when |
|
686 // popping up dialogs. We neither want to tamper with the state if the |
|
687 // user has paused. |
|
688 if (m_hasSmallScreen && m_MediaObject.hasVideo()) { |
|
689 if (Phonon::PlayingState == m_MediaObject.state()) { |
|
690 m_MediaObject.pause(); |
|
691 return true; |
|
692 } |
|
693 } |
|
694 return false; |
|
695 } |
|
696 |
|
697 void MediaPlayer::openFile() |
|
698 { |
|
699 const bool hasPausedForDialog = playPauseForDialog(); |
|
700 |
|
701 QStringList fileNames = QFileDialog::getOpenFileNames(this, QString(), |
|
702 QDesktopServices::storageLocation(QDesktopServices::MusicLocation)); |
|
703 |
|
704 if (hasPausedForDialog) |
|
705 m_MediaObject.play(); |
|
706 |
|
707 m_MediaObject.clearQueue(); |
|
708 if (fileNames.size() > 0) { |
|
709 QString fileName = fileNames[0]; |
|
710 setFile(fileName); |
|
711 for (int i=1; i<fileNames.size(); i++) |
|
712 m_MediaObject.enqueue(Phonon::MediaSource(fileNames[i])); |
|
713 } |
|
714 forwardButton->setEnabled(m_MediaObject.queue().size() > 0); |
|
715 } |
|
716 |
|
717 void MediaPlayer::bufferStatus(int percent) |
|
718 { |
|
719 if (percent == 0 || percent == 100) |
|
720 progressLabel->setText(QString()); |
|
721 else { |
|
722 QString str = QString::fromLatin1("(%1%)").arg(percent); |
|
723 progressLabel->setText(str); |
|
724 } |
|
725 } |
|
726 |
|
727 void MediaPlayer::setSaturation(int val) |
|
728 { |
|
729 m_videoWidget->setSaturation(val / qreal(SLIDER_RANGE)); |
|
730 } |
|
731 |
|
732 void MediaPlayer::setHue(int val) |
|
733 { |
|
734 m_videoWidget->setHue(val / qreal(SLIDER_RANGE)); |
|
735 } |
|
736 |
|
737 void MediaPlayer::setAspect(int val) |
|
738 { |
|
739 m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio(val)); |
|
740 } |
|
741 |
|
742 void MediaPlayer::setScale(int val) |
|
743 { |
|
744 m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleMode(val)); |
|
745 } |
|
746 |
|
747 void MediaPlayer::setBrightness(int val) |
|
748 { |
|
749 m_videoWidget->setBrightness(val / qreal(SLIDER_RANGE)); |
|
750 } |
|
751 |
|
752 void MediaPlayer::setContrast(int val) |
|
753 { |
|
754 m_videoWidget->setContrast(val / qreal(SLIDER_RANGE)); |
|
755 } |
|
756 |
|
757 void MediaPlayer::updateInfo() |
|
758 { |
|
759 int maxLength = 30; |
|
760 QString font = "<font color=#ffeeaa>"; |
|
761 QString fontmono = "<font family=\"monospace,courier new\" color=#ffeeaa>"; |
|
762 |
|
763 QMap <QString, QString> metaData = m_MediaObject.metaData(); |
|
764 QString trackArtist = metaData.value("ARTIST"); |
|
765 if (trackArtist.length() > maxLength) |
|
766 trackArtist = trackArtist.left(maxLength) + "..."; |
|
767 |
|
768 QString trackTitle = metaData.value("TITLE"); |
|
769 int trackBitrate = metaData.value("BITRATE").toInt(); |
|
770 |
|
771 QString fileName; |
|
772 if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) { |
|
773 fileName = m_MediaObject.currentSource().url().toString(); |
|
774 } else { |
|
775 fileName = m_MediaObject.currentSource().fileName(); |
|
776 fileName = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1); |
|
777 if (fileName.length() > maxLength) |
|
778 fileName = fileName.left(maxLength) + "..."; |
|
779 } |
|
780 |
|
781 QString title; |
|
782 if (!trackTitle.isEmpty()) { |
|
783 if (trackTitle.length() > maxLength) |
|
784 trackTitle = trackTitle.left(maxLength) + "..."; |
|
785 title = "Title: " + font + trackTitle + "<br></font>"; |
|
786 } else if (!fileName.isEmpty()) { |
|
787 if (fileName.length() > maxLength) |
|
788 fileName = fileName.left(maxLength) + "..."; |
|
789 title = font + fileName + "</font>"; |
|
790 if (m_MediaObject.currentSource().type() == Phonon::MediaSource::Url) { |
|
791 title.prepend("Url: "); |
|
792 } else { |
|
793 title.prepend("File: "); |
|
794 } |
|
795 } |
|
796 |
|
797 QString artist; |
|
798 if (!trackArtist.isEmpty()) |
|
799 artist = "Artist: " + font + trackArtist + "</font>"; |
|
800 |
|
801 QString bitrate; |
|
802 if (trackBitrate != 0) |
|
803 bitrate = "<br>Bitrate: " + font + QString::number(trackBitrate/1000) + "kbit</font>"; |
|
804 |
|
805 info->setText(title + artist + bitrate); |
|
806 } |
|
807 |
|
808 void MediaPlayer::updateTime() |
|
809 { |
|
810 long len = m_MediaObject.totalTime(); |
|
811 long pos = m_MediaObject.currentTime(); |
|
812 QString timeString; |
|
813 if (pos || len) |
|
814 { |
|
815 int sec = pos/1000; |
|
816 int min = sec/60; |
|
817 int hour = min/60; |
|
818 int msec = pos; |
|
819 |
|
820 QTime playTime(hour%60, min%60, sec%60, msec%1000); |
|
821 sec = len / 1000; |
|
822 min = sec / 60; |
|
823 hour = min / 60; |
|
824 msec = len; |
|
825 |
|
826 QTime stopTime(hour%60, min%60, sec%60, msec%1000); |
|
827 QString timeFormat = "m:ss"; |
|
828 if (hour > 0) |
|
829 timeFormat = "h:mm:ss"; |
|
830 timeString = playTime.toString(timeFormat); |
|
831 if (len) |
|
832 timeString += " / " + stopTime.toString(timeFormat); |
|
833 } |
|
834 timeLabel->setText(timeString); |
|
835 } |
|
836 |
|
837 void MediaPlayer::rewind() |
|
838 { |
|
839 m_MediaObject.seek(0); |
|
840 } |
|
841 |
|
842 void MediaPlayer::forward() |
|
843 { |
|
844 QList<Phonon::MediaSource> queue = m_MediaObject.queue(); |
|
845 if (queue.size() > 0) { |
|
846 m_MediaObject.setCurrentSource(queue[0]); |
|
847 forwardButton->setEnabled(queue.size() > 1); |
|
848 m_MediaObject.play(); |
|
849 } |
|
850 } |
|
851 |
|
852 void MediaPlayer::openUrl() |
|
853 { |
|
854 QSettings settings; |
|
855 settings.beginGroup(QLatin1String("BrowserMainWindow")); |
|
856 QString sourceURL = settings.value("location").toString(); |
|
857 bool ok = false; |
|
858 sourceURL = QInputDialog::getText(this, tr("Open Location"), tr("Please enter a valid address here:"), QLineEdit::Normal, sourceURL, &ok); |
|
859 if (ok && !sourceURL.isEmpty()) { |
|
860 setLocation(sourceURL); |
|
861 settings.setValue("location", sourceURL); |
|
862 } |
|
863 } |
|
864 |
|
865 /*! |
|
866 \since 4.6 |
|
867 */ |
|
868 void MediaPlayer::openRamFile() |
|
869 { |
|
870 QSettings settings; |
|
871 settings.beginGroup(QLatin1String("BrowserMainWindow")); |
|
872 |
|
873 const QStringList fileNameList(QFileDialog::getOpenFileNames(this, |
|
874 QString(), |
|
875 settings.value("openRamFile").toString(), |
|
876 QLatin1String("RAM files (*.ram)"))); |
|
877 |
|
878 if (fileNameList.isEmpty()) |
|
879 return; |
|
880 |
|
881 QFile linkFile; |
|
882 QList<QUrl> list; |
|
883 QByteArray sourceURL; |
|
884 for (int i = 0; i < fileNameList.count(); i++ ) { |
|
885 linkFile.setFileName(fileNameList[i]); |
|
886 if (linkFile.open(QIODevice::ReadOnly | QIODevice::Text)) { |
|
887 while (!linkFile.atEnd()) { |
|
888 sourceURL = linkFile.readLine().trimmed(); |
|
889 if (!sourceURL.isEmpty()) { |
|
890 const QUrl url(QUrl::fromEncoded(sourceURL)); |
|
891 if (url.isValid()) |
|
892 list.append(url); |
|
893 } |
|
894 } |
|
895 linkFile.close(); |
|
896 } |
|
897 } |
|
898 |
|
899 if (!list.isEmpty()) { |
|
900 m_MediaObject.clearQueue(); |
|
901 setLocation(list[0].toString()); |
|
902 for (int i = 1; i < list.count(); i++) |
|
903 m_MediaObject.enqueue(Phonon::MediaSource(list[i])); |
|
904 m_MediaObject.play(); |
|
905 } |
|
906 |
|
907 forwardButton->setEnabled(!m_MediaObject.queue().isEmpty()); |
|
908 settings.setValue("openRamFile", fileNameList[0]); |
|
909 } |
|
910 |
|
911 void MediaPlayer::finished() |
|
912 { |
|
913 } |
|
914 |
|
915 void MediaPlayer::showContextMenu(const QPoint &p) |
|
916 { |
|
917 fileMenu->popup(m_videoWidget->isFullScreen() ? p : mapToGlobal(p)); |
|
918 } |
|
919 |
|
920 void MediaPlayer::scaleChanged(QAction *act) |
|
921 { |
|
922 if (act->text() == tr("Scale and crop")) |
|
923 m_videoWidget->setScaleMode(Phonon::VideoWidget::ScaleAndCrop); |
|
924 else |
|
925 m_videoWidget->setScaleMode(Phonon::VideoWidget::FitInView); |
|
926 } |
|
927 |
|
928 void MediaPlayer::aspectChanged(QAction *act) |
|
929 { |
|
930 if (act->text() == tr("16/9")) |
|
931 m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio16_9); |
|
932 else if (act->text() == tr("Scale")) |
|
933 m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioWidget); |
|
934 else if (act->text() == tr("4/3")) |
|
935 m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio4_3); |
|
936 else |
|
937 m_videoWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioAuto); |
|
938 } |
|
939 |
|
940 void MediaPlayer::hasVideoChanged(bool bHasVideo) |
|
941 { |
|
942 info->setVisible(!bHasVideo); |
|
943 m_videoWindow.setVisible(bHasVideo); |
|
944 m_fullScreenAction->setEnabled(bHasVideo); |
|
945 } |