File indexing completed on 2024-04-28 04:48:39
0001 /* 0002 SPDX-FileCopyrightText: 2005 Max Howell <max.howell@methylblue.com> 0003 SPDX-FileCopyrightText: 2007 Christoph Pfister <christophpfister@gmail.com> 0004 SPDX-FileCopyrightText: 2007 Ian Monroe <ian@monroe.nu> 0005 0006 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0007 */ 0008 0009 #include <config.h> 0010 0011 #include "timeLabel.h" 0012 #include "videoWindow.h" 0013 0014 #include "actions.h" //::seek() FIXME unfortunate 0015 #include "theStream.h" 0016 0017 #include <QActionGroup> 0018 #include <QApplication> 0019 #include <QContextMenuEvent> 0020 #include <QDebug> 0021 #include <QIcon> 0022 #include <QLabel> 0023 #include <QMenu> 0024 #include <QMimeDatabase> 0025 #include <QPainter> 0026 #include <QTimer> 0027 #include <QVBoxLayout> 0028 0029 #include <KLocalizedString> 0030 #include <KSharedConfig> 0031 0032 #include <phonon/AudioOutput> 0033 #include <phonon/MediaController> 0034 #include <phonon/MediaObject> 0035 #include <phonon/SeekSlider> 0036 #include <phonon/VideoWidget> 0037 #include <phonon/VolumeFaderEffect> 0038 #include <phonon/VolumeSlider> 0039 #include <phonon/audiodataoutput.h> 0040 0041 #include <Solid/Block> 0042 #include <Solid/OpticalDisc> 0043 0044 #ifdef Q_OS_WIN 0045 #include <windows.h> 0046 #endif 0047 0048 #if defined(HAVE_UNISTD_H) 0049 #include <unistd.h> 0050 #endif 0051 0052 using Phonon::AudioOutput; 0053 using Phonon::MediaController; 0054 using Phonon::MediaObject; 0055 using Phonon::SeekSlider; 0056 using Phonon::VideoWidget; 0057 using Phonon::VolumeSlider; 0058 0059 namespace Dragon 0060 { 0061 0062 VideoWindow *VideoWindow::s_instance = nullptr; 0063 0064 VideoWindow::VideoWindow(QWidget *parent) 0065 : QWidget(parent) 0066 , m_cursorTimer(new QTimer(this)) 0067 , m_justLoaded(false) 0068 , m_subLanguages(new QActionGroup(this)) 0069 , m_audioLanguages(new QActionGroup(this)) 0070 , m_logo(new QLabel(this)) 0071 , m_initialOffset(0) 0072 , m_aDataOutput(nullptr) 0073 { 0074 m_isPreview = false; 0075 0076 s_instance = this; 0077 setObjectName(QLatin1String("VideoWindow")); 0078 0079 QVBoxLayout *box = new QVBoxLayout(this); 0080 box->setContentsMargins(0, 0, 0, 0); 0081 box->setSpacing(0); 0082 m_vWidget = new VideoWidget(this); 0083 m_vWidget->hide(); 0084 box->addWidget(m_vWidget); 0085 m_aOutput = new AudioOutput(Phonon::VideoCategory, this); 0086 m_media = new MediaObject(this); 0087 m_controller = new MediaController(m_media); 0088 m_controller->setAutoplayTitles(true); 0089 Phonon::createPath(m_media, m_vWidget); 0090 m_audioPath = Phonon::createPath(m_media, m_aOutput); 0091 m_media->setTickInterval(1000); 0092 connect(m_media, &Phonon::MediaObject::tick, this, &VideoWindow::tick); 0093 connect(m_media, &Phonon::MediaObject::currentSourceChanged, this, &VideoWindow::currentSourceChanged); 0094 connect(m_media, &Phonon::MediaObject::totalTimeChanged, this, &VideoWindow::totalTimeChanged); 0095 connect(m_media, &Phonon::MediaObject::seekableChanged, this, &VideoWindow::seekableChanged); 0096 connect(m_media, &Phonon::MediaObject::metaDataChanged, this, &VideoWindow::metaDataChanged); 0097 connect(m_aOutput, &Phonon::AudioOutput::mutedChanged, this, &VideoWindow::mutedChanged); 0098 connect(m_aOutput, &Phonon::AudioOutput::volumeChanged, this, &VideoWindow::volumeChanged); 0099 connect(m_media, &Phonon::MediaObject::hasVideoChanged, this, &VideoWindow::hasVideoChanged); 0100 connect(m_media, &Phonon::MediaObject::hasVideoChanged, m_vWidget, &QWidget::setVisible); // hide video widget if no video to show 0101 connect(m_media, &Phonon::MediaObject::hasVideoChanged, m_logo, &QWidget::setHidden); 0102 connect(m_media, &Phonon::MediaObject::finished, this, &VideoWindow::finished); 0103 connect(m_controller, &Phonon::MediaController::availableSubtitlesChanged, this, &VideoWindow::updateChannels); 0104 0105 { 0106 m_subLanguages->setExclusive(true); 0107 QAction *turnOff = new QAction(i18nc("@option:radio", "&DVD Subtitle Selection"), m_subLanguages); 0108 turnOff->setCheckable(true); 0109 turnOff->setProperty(TheStream::CHANNEL_PROPERTY, -1); 0110 connect(turnOff, &QAction::triggered, this, &VideoWindow::slotSetSubtitle); 0111 0112 QAction *separator = new QAction(m_subLanguages); 0113 separator->setSeparator(true); 0114 } 0115 { 0116 m_audioLanguages->setExclusive(true); 0117 QAction *autoLang = new QAction(i18nc("@option:radio audio language", "&Auto"), m_audioLanguages); 0118 autoLang->setProperty(TheStream::CHANNEL_PROPERTY, -1); 0119 autoLang->setCheckable(true); 0120 connect(autoLang, &QAction::triggered, this, &VideoWindow::slotSetAudio); 0121 0122 QAction *separator = new QAction(m_audioLanguages); 0123 separator->setSeparator(true); 0124 } 0125 0126 connect(m_media, &Phonon::MediaObject::stateChanged, this, &VideoWindow::stateChanged); 0127 connect(m_cursorTimer, &QTimer::timeout, this, &VideoWindow::hideCursor); 0128 m_cursorTimer->setSingleShot(true); 0129 { 0130 m_logo->setAutoFillBackground(true); 0131 QPalette pal; 0132 pal.setColor(QPalette::Window, Qt::white); 0133 m_logo->setPalette(pal); 0134 QLayout *layout = new QVBoxLayout(m_logo); 0135 layout->setAlignment(Qt::AlignCenter); 0136 m_logo->setLayout(layout); 0137 box->addWidget(m_logo); 0138 m_logo->show(); 0139 } 0140 { 0141 KConfigGroup config = KSharedConfig::openConfig()->group(QStringLiteral("General")); 0142 m_aOutput->setVolume(config.readEntry<double>("Volume", 1.0)); 0143 } 0144 } 0145 0146 VideoWindow::~VideoWindow() 0147 { 0148 eject(); 0149 KConfigGroup config = KSharedConfig::openConfig()->group(QStringLiteral("General")); 0150 config.writeEntry("Volume", static_cast<double>(m_aOutput->volume())); 0151 } 0152 0153 bool VideoWindow::init() 0154 { 0155 return m_media->state() != Phonon::ErrorState; 0156 } 0157 0158 bool VideoWindow::load(const QUrl &url) 0159 { 0160 QApplication::setOverrideCursor(Qt::WaitCursor); 0161 0162 eject(); 0163 0164 QMimeDatabase db; 0165 QMimeType mimeType = db.mimeTypeForUrl(url); 0166 qDebug() << "detected mimetype: " << mimeType.name(); 0167 if (mimeType.inherits(QLatin1String("application/x-cd-image")) || mimeType.inherits(QLatin1String("inode/directory"))) 0168 m_media->setCurrentSource(Phonon::MediaSource(Phonon::Dvd, url.path())); 0169 else 0170 m_media->setCurrentSource(url); 0171 m_justLoaded = true; 0172 0173 QApplication::restoreOverrideCursor(); 0174 0175 return true; 0176 } 0177 0178 bool VideoWindow::load(const QList<QUrl> &urls) 0179 { 0180 QApplication::setOverrideCursor(Qt::WaitCursor); 0181 0182 eject(); 0183 QList<QUrl> tmpUrls = urls; 0184 m_media->setCurrentSource(tmpUrls.takeFirst()); 0185 m_media->enqueue(tmpUrls); 0186 m_justLoaded = true; 0187 0188 QApplication::restoreOverrideCursor(); 0189 0190 return true; 0191 } 0192 0193 bool VideoWindow::play(qint64 offset) 0194 { 0195 QApplication::setOverrideCursor(Qt::WaitCursor); 0196 0197 m_justLoaded = false; 0198 m_initialOffset = offset; 0199 m_media->play(); 0200 0201 QApplication::restoreOverrideCursor(); 0202 0203 return true; 0204 } 0205 0206 bool VideoWindow::resume() 0207 { 0208 m_media->play(); 0209 return true; 0210 } 0211 0212 bool VideoWindow::playDvd() 0213 { 0214 eject(); 0215 m_media->setCurrentSource(Phonon::MediaSource(Phonon::Dvd)); 0216 m_media->play(); 0217 return true; 0218 } 0219 0220 bool VideoWindow::playDisc(const Solid::Device &device) 0221 { 0222 QString devicePath; 0223 { 0224 const Solid::Block *block = device.as<const Solid::Block>(); 0225 if (block) 0226 devicePath = block->device(); 0227 else { 0228 qDebug() << "device was not a block"; 0229 return false; 0230 } 0231 } 0232 const Solid::OpticalDisc *disc = device.as<const Solid::OpticalDisc>(); 0233 if (disc) { 0234 Phonon::DiscType phononType = Phonon::NoDisc; 0235 { 0236 Solid::OpticalDisc::ContentTypes solidType = disc->availableContent(); 0237 if (solidType & Solid::OpticalDisc::VideoDvd) 0238 phononType = Phonon::Dvd; 0239 if (solidType & (Solid::OpticalDisc::VideoCd | Solid::OpticalDisc::SuperVideoCd)) 0240 phononType = Phonon::Vcd; 0241 if (solidType & Solid::OpticalDisc::Audio) 0242 phononType = Phonon::Cd; 0243 0244 // No change -> cannot play the disc.... should not really happen as 0245 // mainWindow already preprocesses the type, so this would indicate 0246 // bogus handling in one of the classes -> assertation. 0247 Q_ASSERT(phononType != Phonon::NoDisc); 0248 if (phononType == Phonon::NoDisc) { 0249 qDebug() << "not a playable disc type: " << disc->availableContent() << " type"; 0250 return false; 0251 } 0252 } 0253 eject(); 0254 m_media->setCurrentSource(Phonon::MediaSource(phononType, devicePath)); 0255 qDebug() << "actually playing the disc at " << devicePath; 0256 m_media->play(); 0257 return true; 0258 } else { 0259 qDebug() << "device was not a disc"; 0260 return false; 0261 } 0262 } 0263 0264 bool VideoWindow::isPreview(const bool &v) 0265 { 0266 if (v) { 0267 m_isPreview = v; 0268 } 0269 return m_isPreview; 0270 } 0271 0272 void VideoWindow::relativeSeek(qint64 step) 0273 { 0274 qDebug() << "** relative seek"; 0275 const qint64 new_pos = currentTime() + step; 0276 if ((new_pos >= 0) && (new_pos < length())) { 0277 seek(new_pos); 0278 play(); 0279 } else if (new_pos < 0) { 0280 seek(0); 0281 play(); 0282 } 0283 } 0284 0285 void VideoWindow::stop() 0286 { 0287 qDebug() << "Stop called"; 0288 eject(); 0289 m_media->stop(); 0290 m_media->setCurrentSource(Phonon::MediaSource()); // set the current source to Phonon::MediaSource::Empty 0291 qDebug() << "Media source valid? " << TheStream::hasMedia(); 0292 m_vWidget->hide(); 0293 m_logo->show(); 0294 } 0295 0296 void VideoWindow::pause() 0297 { 0298 m_media->pause(); 0299 } 0300 0301 void VideoWindow::playPause() 0302 { 0303 if (m_media->state() == Phonon::PlayingState) 0304 pause(); 0305 else 0306 resume(); 0307 } 0308 0309 QString VideoWindow::urlOrDisc() const 0310 { 0311 Phonon::MediaSource source = m_media->currentSource(); 0312 switch (source.type()) { 0313 case Phonon::MediaSource::Invalid: 0314 case Phonon::MediaSource::Empty: 0315 return QLatin1String("Invalid"); // no i18n, used for DBus responses 0316 break; 0317 case Phonon::MediaSource::Url: 0318 case Phonon::MediaSource::LocalFile: 0319 return source.url().toString(); 0320 break; 0321 case Phonon::MediaSource::Disc: 0322 return source.deviceName(); 0323 break; 0324 case Phonon::MediaSource::Stream: 0325 return QLatin1String("Data Stream"); 0326 break; 0327 default: 0328 break; 0329 } 0330 return QLatin1String("Error"); 0331 } 0332 0333 Phonon::MediaSource::Type VideoWindow::mediaSourceType() const 0334 { 0335 return m_media->currentSource().type(); 0336 } 0337 0338 QMultiMap<QString, QString> VideoWindow::metaData() const 0339 { 0340 return m_media->metaData(); 0341 } 0342 0343 bool VideoWindow::isSeekable() const 0344 { 0345 return m_media->isSeekable(); 0346 } 0347 0348 Phonon::State VideoWindow::state() const 0349 { 0350 return m_media->state(); 0351 } 0352 0353 bool VideoWindow::isActiveState() const 0354 { 0355 return isActiveState(state()); 0356 } 0357 0358 bool VideoWindow::isActiveState(Phonon::State s) const 0359 { 0360 return (s == Phonon::PlayingState || s == Phonon::PausedState || s == Phonon::BufferingState); 0361 } 0362 0363 qreal VideoWindow::volume() const 0364 { 0365 return m_aOutput->volume(); 0366 } 0367 0368 void VideoWindow::setVolume(qreal vol) 0369 { 0370 m_aOutput->setVolume(vol); 0371 } 0372 0373 void VideoWindow::mute(bool muted) 0374 { 0375 m_aOutput->setMuted(muted); 0376 } 0377 0378 bool VideoWindow::isMuted() 0379 { 0380 return m_aOutput->isMuted(); 0381 } 0382 0383 void VideoWindow::seek(qint64 pos) 0384 { 0385 m_media->seek(pos); 0386 } 0387 0388 qint32 VideoWindow::tickInterval() const 0389 { 0390 return m_media->tickInterval(); 0391 } 0392 0393 void VideoWindow::showOSD(const QString & /*message*/) 0394 { 0395 return; 0396 } 0397 0398 void VideoWindow::resetZoom() 0399 { 0400 TheStream::profile().deleteEntry("Preferred Size"); 0401 window()->adjustSize(); 0402 } 0403 0404 qint64 VideoWindow::currentTime() const 0405 { 0406 return m_media->currentTime(); 0407 } 0408 0409 qint64 VideoWindow::length() const 0410 { 0411 return m_media->totalTime(); 0412 } 0413 0414 bool VideoWindow::setupAnalyzer(QObject *analyzer) 0415 { 0416 if (!m_aDataOutput) { 0417 m_aDataOutput = new Phonon::AudioDataOutput(this); 0418 m_audioDataPath = Phonon::createPath(m_media, m_aDataOutput); 0419 connect(m_aDataOutput, 0420 SIGNAL(dataReady(QMap<Phonon::AudioDataOutput::Channel, QVector<qint16>>)), 0421 analyzer, 0422 SLOT(drawFrame(QMap<Phonon::AudioDataOutput::Channel, QVector<qint16>>))); 0423 } 0424 0425 return m_audioDataPath.isValid(); 0426 } 0427 0428 bool VideoWindow::isDVD() const 0429 { 0430 return m_media->currentSource().discType() == Phonon::Dvd || m_media->currentSource().discType() == Phonon::BluRay; 0431 } 0432 0433 QWidget *VideoWindow::newPositionSlider() 0434 { 0435 SeekSlider *seekSlider = new SeekSlider(); 0436 seekSlider->setIconVisible(false); 0437 seekSlider->setMediaObject(m_media); 0438 seekSlider->setSingleStep(5000); 0439 return seekSlider; 0440 } 0441 0442 QWidget *VideoWindow::newVolumeSlider() 0443 { 0444 VolumeSlider *volumeSlider = new VolumeSlider(); 0445 volumeSlider->setObjectName(QLatin1String("volume")); 0446 volumeSlider->setAudioOutput(m_aOutput); 0447 volumeSlider->setMuteVisible(false); 0448 volumeSlider->setOrientation(Qt::Vertical); 0449 return volumeSlider; 0450 } 0451 0452 void VideoWindow::stateChanged(Phonon::State currentState, Phonon::State oldstate) // slot 0453 { 0454 qDebug() << "chapters: " << m_controller->availableChapters() << " titles: " << m_controller->availableTitles(); 0455 QStringList states; 0456 states << QLatin1String("Loading") << QLatin1String("Stopped") << QLatin1String("Playing") << QLatin1String("Buffering") << QLatin1String("Paused") 0457 << QLatin1String("Error"); 0458 qDebug() << "going from " << states.at(oldstate) << " to " << states.at(currentState); 0459 0460 if (currentState == Phonon::PlayingState && m_initialOffset > 0) { 0461 seek(m_initialOffset); 0462 m_initialOffset = 0; 0463 } 0464 0465 if (currentState == Phonon::PlayingState && m_media->hasVideo()) { 0466 m_logo->hide(); 0467 m_vWidget->show(); 0468 updateChannels(); 0469 } 0470 Q_EMIT stateUpdated(currentState, oldstate); 0471 } 0472 0473 void VideoWindow::settingChanged(int setting) 0474 { 0475 const QString name = sender()->objectName(); 0476 const double dSetting = static_cast<double>(setting) * 0.01; 0477 qDebug() << "setting " << name << " to " << dSetting; 0478 if (name == QLatin1String("brightnessSlider")) { 0479 m_vWidget->setBrightness(dSetting); 0480 } else if (name == QLatin1String("contrastSlider")) { 0481 m_vWidget->setContrast(dSetting); 0482 } else if (name == QLatin1String("hueSlider")) { 0483 m_vWidget->setHue(dSetting); 0484 } else if (name == QLatin1String("saturationSlider")) { 0485 m_vWidget->setSaturation(dSetting); 0486 } 0487 } 0488 0489 void VideoWindow::loadSettings() 0490 { 0491 if (TheStream::hasProfile()) { 0492 KConfigGroup profile = TheStream::profile(); 0493 m_vWidget->setBrightness(profile.readEntry<double>("Brightness", 0.0)); 0494 m_vWidget->setContrast(profile.readEntry<double>("Contrast", 0.0)); 0495 m_vWidget->setHue(profile.readEntry<double>("Hue", 0.0)); 0496 m_vWidget->setSaturation(profile.readEntry<double>("Saturation", 0.0)); 0497 setAudioChannel(profile.readEntry<int>("AudioChannel", -1)); 0498 setSubtitle(profile.readEntry<int>("Subtitle", -1)); 0499 } else { 0500 m_vWidget->setBrightness(0.0); 0501 m_vWidget->setContrast(0.0); 0502 m_vWidget->setHue(0.0); 0503 m_vWidget->setSaturation(0.0); 0504 } 0505 } 0506 0507 template<class ChannelDescription, class Func> 0508 void VideoWindow::updateActionGroup(QActionGroup *channelActions, const QList<ChannelDescription> &availableChannels, Func actionSlot) 0509 { 0510 { 0511 QList<QAction *> subActions = channelActions->actions(); 0512 while (2 < subActions.size()) 0513 delete subActions.takeLast(); 0514 } 0515 for (const ChannelDescription &channel : availableChannels) { 0516 QAction *lang = new QAction(channelActions); 0517 qDebug() << "the text is: \"" << channel.name() << "\" and index " << channel.index(); 0518 lang->setCheckable(true); 0519 lang->setText(channel.name()); 0520 lang->setProperty(TheStream::CHANNEL_PROPERTY, channel.index()); 0521 connect(lang, &QAction::triggered, this, actionSlot); 0522 } 0523 } 0524 0525 void VideoWindow::updateChannels() 0526 { 0527 qDebug() << "Updating channels, subtitle count:" << m_controller->availableSubtitles().count(); 0528 0529 updateActionGroup(m_subLanguages, m_controller->availableSubtitles(), &VideoWindow::slotSetSubtitle); 0530 Q_EMIT subChannelsChanged(m_subLanguages->actions()); 0531 updateActionGroup(m_audioLanguages, m_controller->availableAudioChannels(), &VideoWindow::slotSetAudio); 0532 Q_EMIT audioChannelsChanged(m_audioLanguages->actions()); 0533 } 0534 0535 void VideoWindow::hideCursor() 0536 { 0537 if (m_media->hasVideo() && m_vWidget->underMouse()) 0538 qApp->setOverrideCursor(Qt::BlankCursor); 0539 } 0540 0541 void VideoWindow::setSubtitle(int channel) 0542 { 0543 Phonon::SubtitleDescription desc = Phonon::SubtitleDescription::fromIndex(channel); 0544 qDebug() << "using index: " << channel << " returned desc has index: " << desc.index(); 0545 if (desc.isValid()) 0546 m_controller->setCurrentSubtitle(desc); 0547 } 0548 0549 void VideoWindow::slotSetSubtitle() 0550 { 0551 if (sender() && sender()->property(TheStream::CHANNEL_PROPERTY).canConvert<int>()) 0552 setSubtitle(sender()->property(TheStream::CHANNEL_PROPERTY).toInt()); 0553 } 0554 0555 void VideoWindow::setAudioChannel(int channel) 0556 { 0557 Phonon::AudioChannelDescription desc = Phonon::AudioChannelDescription::fromIndex(channel); 0558 qDebug() << "using index: " << channel << " returned desc has index: " << desc.index(); 0559 if (desc.isValid()) 0560 m_controller->setCurrentAudioChannel(desc); 0561 } 0562 0563 void VideoWindow::slotSetAudio() 0564 { 0565 if (sender() && sender()->property(TheStream::CHANNEL_PROPERTY).canConvert<int>()) 0566 setAudioChannel(sender()->property(TheStream::CHANNEL_PROPERTY).toInt()); 0567 } 0568 0569 void VideoWindow::toggleDVDMenu() 0570 { 0571 #if PHONON_VERSION >= PHONON_VERSION_CHECK(4, 5, 0) 0572 m_controller->setCurrentMenu(MediaController::RootMenu); 0573 #endif 0574 } 0575 0576 int VideoWindow::videoSetting(const QString &setting) 0577 { 0578 double dValue = 0.0; 0579 if (setting == QLatin1String("brightnessSlider")) { 0580 dValue = m_vWidget->brightness(); 0581 } else if (setting == QLatin1String("contrastSlider")) { 0582 dValue = m_vWidget->contrast(); 0583 } else if (setting == QLatin1String("hueSlider")) { 0584 dValue = m_vWidget->hue(); 0585 } else if (setting == QLatin1String("saturationSlider")) { 0586 dValue = m_vWidget->saturation(); 0587 } 0588 return static_cast<int>(dValue * 100.0); 0589 } 0590 0591 void VideoWindow::prevChapter() 0592 { 0593 if (TheStream::hasVideo()) 0594 m_controller->setCurrentChapter(m_controller->currentChapter() - 1); 0595 else 0596 m_controller->previousTitle(); 0597 } 0598 0599 void VideoWindow::nextChapter() 0600 { 0601 if (TheStream::hasVideo()) 0602 m_controller->setCurrentChapter(m_controller->currentChapter() + 1); 0603 else 0604 m_controller->nextTitle(); 0605 } 0606 0607 void VideoWindow::tenPercentBack() 0608 { 0609 const qint64 newTime = m_media->currentTime() - (m_media->totalTime() / 10); 0610 if (newTime > 0) 0611 m_media->seek(newTime); 0612 else 0613 m_media->seek(0); 0614 } 0615 0616 void VideoWindow::tenPercentForward() 0617 { 0618 const qint64 newTime = m_media->currentTime() + (m_media->totalTime() / 10); 0619 if (newTime < m_media->totalTime()) 0620 m_media->seek(newTime); 0621 } 0622 0623 void VideoWindow::tenSecondsBack() 0624 { 0625 relativeSeek(-10000); 0626 } 0627 0628 void VideoWindow::tenSecondsForward() 0629 { 0630 relativeSeek(10000); 0631 } 0632 0633 void VideoWindow::increaseVolume() 0634 { 0635 m_aOutput->setVolume(qMin(qreal(1.0), volume() + qreal(0.10))); 0636 } 0637 0638 void VideoWindow::decreaseVolume() 0639 { 0640 m_aOutput->setVolume(qMax(qreal(0.0), volume() - qreal(0.10))); 0641 } 0642 0643 bool VideoWindow::canGoPrev() const 0644 { 0645 return m_controller->currentTitle() > 1; 0646 } 0647 0648 bool VideoWindow::canGoNext() const 0649 { 0650 return m_controller->currentTitle() < m_controller->availableTitles(); 0651 } 0652 0653 /////////// 0654 /// Protected 0655 /////////// 0656 0657 bool VideoWindow::event(QEvent *event) 0658 { 0659 switch (event->type()) { 0660 case QEvent::Leave: 0661 m_cursorTimer->stop(); 0662 qApp->restoreOverrideCursor(); 0663 qDebug() << "stop cursorTimer"; 0664 break; 0665 case QEvent::FocusOut: 0666 // if the user summons some dialog via a shortcut or whatever we need to ensure 0667 // the mouse gets shown, because if it is modal, we won't get mouse events after 0668 // it is shown! This works because we are always the focus widget. 0669 // @see MainWindow::MainWindow where we setFocusProxy() 0670 case QEvent::Enter: 0671 case QEvent::MouseMove: 0672 case QEvent::MouseButtonPress: 0673 qApp->restoreOverrideCursor(); 0674 m_cursorTimer->start(CURSOR_HIDE_TIMEOUT); 0675 break; 0676 default: 0677 return QWidget::event(event); 0678 } 0679 return false; 0680 } 0681 0682 void VideoWindow::contextMenuEvent(QContextMenuEvent *event) 0683 { 0684 QMenu menu; 0685 if (mainWindow()) { 0686 qobject_cast<KHamburgerMenu *>(action("hamburger_menu"))->addToMenu(&menu); 0687 menu.addAction(action("play")); 0688 menu.addAction(action("fullscreen")); 0689 menu.addAction(action("reset_zoom")); 0690 if (isDVD()) { 0691 menu.addAction(action("toggle_dvd_menu")); 0692 } 0693 } 0694 menu.exec(event->globalPos()); 0695 } 0696 0697 void VideoWindow::mouseDoubleClickEvent(QMouseEvent *) 0698 { 0699 if (mainWindow()) // TODO: add full screen mode to kpart 0700 action("fullscreen")->toggle(); 0701 } 0702 0703 QSize VideoWindow::sizeHint() const // virtual 0704 { 0705 QSize s = TheStream::profile().readEntry<QSize>("Preferred Size", QSize()); 0706 0707 if (!s.isValid()) 0708 s = TheStream::defaultVideoSize(); 0709 0710 if (s.isValid() && !s.isNull()) 0711 return s; 0712 0713 return QWidget::sizeHint(); 0714 } 0715 0716 /////////// 0717 /// Private 0718 /////////// 0719 void VideoWindow::eject() 0720 { 0721 if (m_media->currentSource().type() == Phonon::MediaSource::Invalid) 0722 return; 0723 0724 if (m_media->currentSource().type() == Phonon::MediaSource::Empty) 0725 return; 0726 0727 KConfigGroup profile = TheStream::profile(); // the config profile for this video file 0728 0729 Phonon::State state = m_media->state(); 0730 if (((state == Phonon::PlayingState || state == Phonon::PausedState)) 0731 && (m_media->remainingTime() > 5000)) // if we are really close to the end, don't remember the position 0732 profile.writeEntry("Position", currentTime()); 0733 else 0734 profile.deleteEntry("Position"); 0735 0736 const QSize s = videoWindow()->size(); 0737 const QSize defaultSize = TheStream::defaultVideoSize(); 0738 if (defaultSize.isValid() && (s.width() == defaultSize.width() || s.height() == defaultSize.height())) 0739 profile.deleteEntry("Preferred Size"); 0740 else 0741 profile.writeEntry("Preferred Size", s); 0742 0743 profile.writeEntry("Contrast", m_vWidget->contrast()); 0744 profile.writeEntry("Brightness", m_vWidget->brightness()); 0745 profile.writeEntry("Hue", m_vWidget->hue()); 0746 profile.writeEntry("Saturation", m_vWidget->saturation()); 0747 profile.writeEntry("IsVideo", m_media->hasVideo()); 0748 { 0749 // this if clause - is to prevent a crash from bug 162721 (a Phonon bug), remove when fixed 0750 if (m_media->hasVideo()) { 0751 qDebug() << "trying to fetch subtitle information"; 0752 const int subtitle = TheStream::subtitleChannel(); 0753 const int audio = TheStream::audioChannel(); 0754 qDebug() << "fetched subtitle information"; 0755 0756 if (subtitle != -1) 0757 profile.writeEntry("Subtitle", subtitle); 0758 else 0759 profile.deleteEntry("Subtitle"); 0760 0761 if (audio != -1) 0762 profile.writeEntry("AudioChannel", audio); 0763 else 0764 profile.deleteEntry("AudioChannel"); 0765 } 0766 } 0767 profile.writeEntry("Date", QDate::currentDate()); 0768 profile.sync(); 0769 } 0770 0771 } // namespace Dragon 0772 0773 #include "moc_videoWindow.cpp"