File indexing completed on 2024-04-28 04:50:49

0001 /*
0002  * mediawidget.cpp
0003  *
0004  * Copyright (C) 2007-2011 Christoph Pfister <christophpfister@gmail.com>
0005  *
0006  * This program is free software; you can redistribute it and/or modify
0007  * it under the terms of the GNU General Public License as published by
0008  * the Free Software Foundation; either version 2 of the License, or
0009  * (at your option) any later version.
0010  *
0011  * This program is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014  * GNU General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU General Public License along
0017  * with this program; if not, write to the Free Software Foundation, Inc.,
0018  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
0019  */
0020 
0021 #include "log.h"
0022 
0023 #include <KActionCollection>
0024 #include <KConfigGroup>
0025 #include <KSharedConfig>
0026 #include <KToolBar>
0027 #include <QAbstractItemView>
0028 #include <QBoxLayout>
0029 #include <QComboBox>
0030 #include <QContextMenuEvent>
0031 #include <QDialogButtonBox>
0032 #include <QDBusInterface>
0033 #include <QEvent>
0034 #include <QFileDialog>
0035 #include <QLabel>
0036 #include <QMenu>
0037 #include <QMimeData>
0038 #include <QPushButton>
0039 #include <QStringListModel>
0040 #include <QTimeEdit>
0041 #include <QTimer>
0042 #include <QWidgetAction>
0043 #include <QX11Info>
0044 #include <Solid/Block>
0045 #include <Solid/Device>
0046 #include <KWindowSystem>
0047 
0048 #include "backend-vlc/vlcmediawidget.h"
0049 #include "configuration.h"
0050 #include "mediawidget.h"
0051 #include "mediawidget_p.h"
0052 #include "osdwidget.h"
0053 
0054 // Needs to be included before X11 headers, which deine some things like "Bool"
0055 #include "moc_mediawidget.cpp"
0056 
0057 #include <X11/extensions/scrnsaver.h>
0058 
0059 MediaWidget::MediaWidget(QMenu *menu_, QToolBar *toolBar, KActionCollection *collection,
0060     QWidget *parent) : QWidget(parent), menu(menu_), displayMode(NormalMode),
0061     autoResizeFactor(0), blockBackendUpdates(false), muted(false),
0062     screenSaverSuspended(false), showElapsedTime(true)
0063 {
0064     dummySource.reset(new MediaSource());
0065     source = dummySource.data();
0066 
0067     QBoxLayout *layout = new QVBoxLayout(this);
0068     layout->setMargin(0);
0069 
0070     QPalette palette = QWidget::palette();
0071     palette.setColor(backgroundRole(), Qt::black);
0072     setPalette(palette);
0073     setAutoFillBackground(true);
0074 
0075     setAcceptDrops(true);
0076     setFocusPolicy(Qt::StrongFocus);
0077 
0078     backend = VlcMediaWidget::createVlcMediaWidget(this);
0079 
0080     if (backend == NULL) {
0081         backend = new DummyMediaWidget(this);
0082     }
0083 
0084     backend->connectToMediaWidget(this);
0085     layout->addWidget(backend);
0086     osdWidget = new OsdWidget(this);
0087 
0088     actionPrevious = new QWidgetAction(this);
0089     actionPrevious->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
0090     actionPrevious->setText(i18n("Previous"));
0091     actionPrevious->setShortcut(Qt::Key_PageUp);
0092     connect(actionPrevious, SIGNAL(triggered()), this, SLOT(previous()));
0093     toolBar->addAction(collection->addAction(QLatin1String("controls_previous"), actionPrevious));
0094     menu->addAction(actionPrevious);
0095 
0096     actionPlayPause = new QWidgetAction(this);
0097     actionPlayPause->setShortcut(Qt::Key_Space);
0098     textPlay = i18n("Play");
0099     textPause = i18n("Pause");
0100     iconPlay = QIcon::fromTheme(QLatin1String("media-playback-start"), QIcon(":media-playback-start"));
0101     iconPause = QIcon::fromTheme(QLatin1String("media-playback-pause"), QIcon(":media-playback-pause"));
0102     connect(actionPlayPause, SIGNAL(triggered(bool)), this, SLOT(pausedChanged(bool)));
0103     toolBar->addAction(collection->addAction(QLatin1String("controls_play_pause"), actionPlayPause));
0104     menu->addAction(actionPlayPause);
0105 
0106     actionStop = new QWidgetAction(this);
0107     actionStop->setIcon(QIcon::fromTheme(QLatin1String("media-playback-stop"), QIcon(":media-playback-stop")));
0108     actionStop->setText(i18n("Stop"));
0109     actionStop->setShortcut(Qt::Key_Backspace);
0110     connect(actionStop, SIGNAL(triggered()), this, SLOT(stop()));
0111     toolBar->addAction(collection->addAction(QLatin1String("controls_stop"), actionStop));
0112     menu->addAction(actionStop);
0113 
0114     actionNext = new QWidgetAction(this);
0115     actionNext->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
0116     actionNext->setText(i18n("Next"));
0117     actionNext->setShortcut(Qt::Key_PageDown);
0118     connect(actionNext, SIGNAL(triggered()), this, SLOT(next()));
0119     toolBar->addAction(collection->addAction(QLatin1String("controls_next"), actionNext));
0120     menu->addAction(actionNext);
0121     menu->addSeparator();
0122 
0123     fullScreenAction = new QWidgetAction(this);
0124     fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
0125     fullScreenAction->setText(i18nc("'Playback' menu", "Full Screen Mode"));
0126     fullScreenAction->setShortcut(Qt::Key_F);
0127     connect(fullScreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
0128     menu->addAction(collection->addAction(QLatin1String("view_fullscreen"), fullScreenAction));
0129 
0130     minimalModeAction = new QWidgetAction(this);
0131     minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
0132     minimalModeAction->setText(i18nc("'Playback' menu", "Minimal Mode"));
0133     minimalModeAction->setShortcut(Qt::Key_Period);
0134     connect(minimalModeAction, SIGNAL(triggered()), this, SLOT(toggleMinimalMode()));
0135     menu->addAction(collection->addAction(QLatin1String("view_minimal_mode"), minimalModeAction));
0136 
0137     audioStreamBox = new QComboBox(toolBar);
0138     connect(audioStreamBox, SIGNAL(currentIndexChanged(int)),
0139         this, SLOT(currentAudioStreamChanged(int)));
0140     toolBar->addWidget(audioStreamBox);
0141 
0142     audioStreamModel = new QStringListModel(toolBar);
0143     audioStreamBox->setModel(audioStreamModel);
0144 
0145     QMenu *subtitleMenu = new QMenu(i18nc("'Subtitle' menu", "Subtitle"), this);
0146     subtitleBox = new QComboBox(this);
0147     QWidgetAction *action = new QWidgetAction(this);
0148     action->setDefaultWidget(subtitleBox);
0149     textSubtitlesOff = i18nc("subtitle selection entry", "off");
0150     connect(subtitleBox, SIGNAL(currentIndexChanged(int)),
0151         this, SLOT(currentSubtitleChanged(int)));
0152     subtitleModel = new QStringListModel(toolBar);
0153     subtitleBox->setModel(subtitleModel);
0154     subtitleMenu->addAction(action);
0155     menu->addMenu(subtitleMenu);
0156     action = new QWidgetAction(this);
0157     action->setText(i18nc("'Subtitle' menu", "Add subtitle file"));
0158     action->setIcon(QIcon::fromTheme(QLatin1String("application-x-subrip"), QIcon(":application-x-subrip")));
0159     connect(action, &QWidgetAction::triggered, this, &MediaWidget::openSubtitle);
0160     subtitleMenu->addAction(action);
0161 
0162     menu->addMenu(subtitleMenu);
0163 
0164     QMenu *audioMenu = new QMenu(i18nc("'Playback' menu", "Audio"), this);
0165     action = new QWidgetAction(this);
0166     action->setIcon(QIcon::fromTheme(QLatin1String("audio-card"), QIcon(":audio-card")));
0167     action->setText(i18nc("'Audio' menu", "Audio Device"));
0168 
0169     audioDevMenu = new QMenu(i18nc("'Playback' menu", "Audio Device"), audioMenu);
0170     action = new QWidgetAction(this);
0171     connect(audioDevMenu, &QMenu::aboutToShow, this, &MediaWidget::getAudioDevices);
0172     audioMenu->addMenu(audioDevMenu);
0173 
0174     action = new QWidgetAction(this);
0175     action->setIcon(QIcon::fromTheme(QLatin1String("audio-volume-high"), QIcon(":audio-volume-high")));
0176     action->setText(i18nc("'Audio' menu", "Increase Volume"));
0177     action->setShortcut(Qt::Key_Plus);
0178     connect(action, SIGNAL(triggered()), this, SLOT(increaseVolume()));
0179     audioMenu->addAction(collection->addAction(QLatin1String("controls_increase_volume"), action));
0180 
0181     action = new QWidgetAction(this);
0182     action->setIcon(QIcon::fromTheme(QLatin1String("audio-volume-low"), QIcon(":audio-volume-low")));
0183     action->setText(i18nc("'Audio' menu", "Decrease Volume"));
0184     action->setShortcut(Qt::Key_Minus);
0185     connect(action, SIGNAL(triggered()), this, SLOT(decreaseVolume()));
0186     audioMenu->addAction(collection->addAction(QLatin1String("controls_decrease_volume"), action));
0187 
0188     muteAction = new QWidgetAction(this);
0189     muteAction->setText(i18nc("'Audio' menu", "Mute Volume"));
0190     mutedIcon = QIcon::fromTheme(QLatin1String("audio-volume-muted"), QIcon(":audio-volume-muted"));
0191     unmutedIcon = QIcon::fromTheme(QLatin1String("audio-volume-medium"), QIcon(":audio-volume-medium"));
0192     muteAction->setIcon(unmutedIcon);
0193     muteAction->setShortcut(Qt::Key_M);
0194     connect(muteAction, SIGNAL(triggered()), this, SLOT(mutedChanged()));
0195     toolBar->addAction(collection->addAction(QLatin1String("controls_mute_volume"), muteAction));
0196     audioMenu->addAction(muteAction);
0197     menu->addMenu(audioMenu);
0198 
0199     QMenu *videoMenu = new QMenu(i18nc("'Playback' menu", "Video"), this);
0200     menu->addMenu(videoMenu);
0201     menu->addSeparator();
0202 
0203     QMenu *deinterlaceMenu = new QMenu(i18nc("'Video' menu", "Deinterlace"), this);
0204     deinterlaceMenu->setIcon(QIcon::fromTheme(QLatin1String("format-justify-center"), QIcon(":format-justify-center")));
0205     QActionGroup *deinterlaceGroup = new QActionGroup(this);
0206     connect(deinterlaceMenu, SIGNAL(triggered(QAction*)),
0207         this, SLOT(deinterlacingChanged(QAction*)));
0208     videoMenu->addMenu(deinterlaceMenu);
0209 
0210     action = new QWidgetAction(deinterlaceGroup);
0211     action->setText(i18nc("'Deinterlace' menu", "disabled"));
0212     action->setCheckable(true);
0213     action->setShortcut(Qt::Key_D);
0214     action->setData(DeinterlaceDisabled);
0215     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_disabled"), action));
0216 
0217     action = new QWidgetAction(deinterlaceGroup);
0218     action->setText(i18nc("'Deinterlace' menu", "discard"));
0219     action->setCheckable(true);
0220     action->setData(DeinterlaceDiscard);
0221     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_discard"), action));
0222 
0223     action = new QWidgetAction(deinterlaceGroup);
0224     action->setText(i18nc("'Deinterlace' menu", "bob"));
0225     action->setCheckable(true);
0226     action->setData(DeinterlaceBob);
0227     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_bob"), action));
0228 
0229     action = new QWidgetAction(deinterlaceGroup);
0230     action->setText(i18nc("'Deinterlace' menu", "linear"));
0231     action->setCheckable(true);
0232     action->setData(DeinterlaceLinear);
0233     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_linear"), action));
0234 
0235     action = new QWidgetAction(deinterlaceGroup);
0236     action->setText(i18nc("'Deinterlace' menu", "yadif"));
0237     action->setCheckable(true);
0238     action->setData(DeinterlaceYadif);
0239     action->setShortcut(Qt::Key_I);
0240     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_yadif"), action));
0241 
0242     action = new QWidgetAction(deinterlaceGroup);
0243     action->setText(i18nc("'Deinterlace' menu", "yadif2x"));
0244     action->setCheckable(true);
0245     action->setData(DeinterlaceYadif2x);
0246     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_yadif2x"), action));
0247 
0248     action = new QWidgetAction(deinterlaceGroup);
0249     action->setText(i18nc("'Deinterlace' menu", "phosphor"));
0250     action->setCheckable(true);
0251     action->setData(DeinterlacePhosphor);
0252     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_phosphor"), action));
0253 
0254     action = new QWidgetAction(deinterlaceGroup);
0255     action->setText(i18nc("'Deinterlace' menu", "x"));
0256     action->setCheckable(true);
0257     action->setData(DeinterlaceX);
0258     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_x"), action));
0259 
0260     action = new QWidgetAction(deinterlaceGroup);
0261     action->setText(i18nc("'Deinterlace' menu", "mean"));
0262     action->setCheckable(true);
0263     action->setData(DeinterlaceMean);
0264     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_mean"), action));
0265 
0266     action = new QWidgetAction(deinterlaceGroup);
0267     action->setText(i18nc("'Deinterlace' menu", "blend"));
0268     action->setCheckable(true);
0269     action->setData(DeinterlaceBlend);
0270     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_blend"), action));
0271 
0272     action = new QWidgetAction(deinterlaceGroup);
0273     action->setText(i18nc("'Deinterlace' menu", "Inverse telecine"));
0274     action->setCheckable(true);
0275     action->setData(DeinterlaceIvtc);
0276     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_ivtc"), action));
0277 
0278     deinterlaceMode =
0279         KSharedConfig::openConfig()->group("MediaObject").readEntry("Deinterlace", 0);
0280 
0281     if (deinterlaceMode <= DeinterlaceIvtc) {
0282         for (int i = 0; i < deinterlaceGroup->actions().size(); i++) {
0283             if (deinterlaceGroup->actions().at(i)->data().toInt() == deinterlaceMode) {
0284                 deinterlaceGroup->actions().at(i)->setChecked(true);
0285                 break;
0286             }
0287         }
0288     } else {
0289         deinterlaceGroup->actions().at(0)->setChecked(true);
0290     }
0291     backend->setDeinterlacing(static_cast<DeinterlaceMode>(deinterlaceMode));
0292 
0293     QMenu *aspectMenu = new QMenu(i18nc("'Video' menu", "Aspect Ratio"), this);
0294     QActionGroup *aspectGroup = new QActionGroup(this);
0295     connect(aspectGroup, SIGNAL(triggered(QAction*)),
0296         this, SLOT(aspectRatioChanged(QAction*)));
0297     videoMenu->addMenu(aspectMenu);
0298 
0299     action = new QWidgetAction(aspectGroup);
0300     action->setText(i18nc("'Aspect Ratio' menu", "Automatic"));
0301     action->setCheckable(true);
0302     action->setData(AspectRatioAuto);
0303     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_auto"), action));
0304 
0305     action = new QWidgetAction(aspectGroup);
0306     action->setText(i18nc("'Aspect Ratio' menu", "1:1"));
0307     action->setCheckable(true);
0308     action->setData(AspectRatio1_1);
0309     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_1_1"), action));
0310 
0311     action = new QWidgetAction(aspectGroup);
0312     action->setText(i18nc("'Aspect Ratio' menu", "4:3"));
0313     action->setCheckable(true);
0314     action->setData(AspectRatio4_3);
0315     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_4_3"), action));
0316 
0317     action = new QWidgetAction(aspectGroup);
0318     action->setText(i18nc("'Aspect Ratio' menu", "5:4"));
0319     action->setCheckable(true);
0320     action->setData(AspectRatio5_4);
0321     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_5_4"), action));
0322 
0323     action = new QWidgetAction(aspectGroup);
0324     action->setText(i18nc("'Aspect Ratio' menu", "16:9"));
0325     action->setCheckable(true);
0326     action->setData(AspectRatio16_9);
0327     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_16_9"), action));
0328 
0329     action = new QWidgetAction(aspectGroup);
0330     action->setText(i18nc("'Aspect Ratio' menu", "16:10"));
0331     action->setCheckable(true);
0332     action->setData(AspectRatio16_10);
0333     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_16_10"), action));
0334 
0335     action = new QWidgetAction(aspectGroup);
0336     action->setText(i18nc("'Aspect Ratio' menu", "2.21:1"));
0337     action->setCheckable(true);
0338     action->setData(AspectRatio221_100);
0339     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_221_100"), action));
0340 
0341     action = new QWidgetAction(aspectGroup);
0342     action->setText(i18nc("'Aspect Ratio' menu", "2.35:1"));
0343     action->setCheckable(true);
0344     action->setData(AspectRatio235_100);
0345     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_235_100"), action));
0346 
0347     action = new QWidgetAction(aspectGroup);
0348     action->setText(i18nc("'Aspect Ratio' menu", "2.39:1"));
0349     action->setCheckable(true);
0350     action->setData(AspectRatio239_100);
0351     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_239_100"), action));
0352 
0353     QMenu *autoResizeMenu = new QMenu(i18n("Video size"), this);
0354     QActionGroup *autoResizeGroup = new QActionGroup(this);
0355     // we need an event even if you select the currently selected item
0356     autoResizeGroup->setExclusive(false);
0357     connect(autoResizeGroup, SIGNAL(triggered(QAction*)),
0358         this, SLOT(autoResizeTriggered(QAction*)));
0359 
0360     action = new QWidgetAction(autoResizeGroup);
0361     action->setText(i18nc("Video size", "Automatic"));
0362     action->setCheckable(true);
0363     action->setData(0);
0364     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_off"), action));
0365 
0366     action = new QWidgetAction(autoResizeGroup);
0367     action->setText(i18nc("Video size", "25%"));
0368     action->setCheckable(true);
0369     action->setData(25);
0370     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
0371 
0372     action = new QWidgetAction(autoResizeGroup);
0373     action->setText(i18nc("Video size", "50%"));
0374     action->setCheckable(true);
0375     action->setData(50);
0376     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
0377 
0378 
0379     action = new QWidgetAction(autoResizeGroup);
0380     action->setText(i18nc("Video size", "75%"));
0381     action->setCheckable(true);
0382     action->setData(75);
0383 
0384     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
0385     action = new QWidgetAction(autoResizeGroup);
0386     action->setText(i18nc("Video size", "Original Size"));
0387     action->setCheckable(true);
0388     action->setData(100);
0389     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_original"), action));
0390 
0391     action = new QWidgetAction(autoResizeGroup);
0392     action->setText(i18nc("Video size", "150%"));
0393     action->setCheckable(true);
0394     action->setData(150);
0395     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
0396 
0397     action = new QWidgetAction(autoResizeGroup);
0398     action->setText(i18nc("Video size", "200%"));
0399     action->setCheckable(true);
0400     action->setData(200);
0401     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
0402 
0403     action = new QWidgetAction(autoResizeGroup);
0404     action->setText(i18nc("Video size", "250%"));
0405     action->setCheckable(true);
0406     action->setData(250);
0407     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
0408 
0409     action = new QWidgetAction(autoResizeGroup);
0410     action->setText(i18nc("Video size", "300%"));
0411     action->setCheckable(true);
0412     action->setData(300);
0413     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
0414 
0415     autoResizeFactor =
0416         KSharedConfig::openConfig()->group("MediaObject").readEntry("AutoResizeFactor", 0);
0417 
0418     if (autoResizeFactor <= 300) {
0419         for (int i = 0; i < autoResizeGroup->actions().size(); i++) {
0420             if (autoResizeGroup->actions().at(i)->data().toInt() == autoResizeFactor) {
0421                 autoResizeGroup->actions().at(i)->setChecked(true);
0422                 break;
0423             }
0424         }
0425     } else {
0426         autoResizeGroup->actions().at(0)->setChecked(true);
0427     }
0428     setVideoSize();
0429 
0430     videoMenu->addMenu(autoResizeMenu);
0431 
0432     action = new QWidgetAction(this);
0433     action->setText(i18n("Volume Slider"));
0434     volumeSlider = new QSlider(toolBar);
0435     volumeSlider->setFocusPolicy(Qt::NoFocus);
0436     volumeSlider->setOrientation(Qt::Horizontal);
0437     volumeSlider->setRange(0, 100);
0438     volumeSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
0439     volumeSlider->setToolTip(action->text());
0440     volumeSlider->setValue(KSharedConfig::openConfig()->group("MediaObject").readEntry("Volume", 100));
0441     connect(volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
0442     backend->setVolume(volumeSlider->value());
0443     action->setDefaultWidget(volumeSlider);
0444     toolBar->addAction(collection->addAction(QLatin1String("controls_volume_slider"), action));
0445 
0446     jumpToPositionAction = new QWidgetAction(this);
0447     jumpToPositionAction->setIcon(QIcon::fromTheme(QLatin1String("go-jump"), QIcon(":go-jump")));
0448     jumpToPositionAction->setText(i18nc("@action:inmenu", "Jump to Position..."));
0449     jumpToPositionAction->setShortcut(Qt::CTRL + Qt::Key_J);
0450     connect(jumpToPositionAction, SIGNAL(triggered()), this, SLOT(jumpToPosition()));
0451     menu->addAction(collection->addAction(QLatin1String("controls_jump_to_position"), jumpToPositionAction));
0452 
0453     navigationMenu = new QMenu(i18nc("playback menu", "Skip"), this);
0454     menu->addMenu(navigationMenu);
0455     menu->addSeparator();
0456 
0457     int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
0458     int longSkipDuration = Configuration::instance()->getLongSkipDuration();
0459     connect(Configuration::instance(), SIGNAL(shortSkipDurationChanged(int)),
0460         this, SLOT(shortSkipDurationChanged(int)));
0461     connect(Configuration::instance(), SIGNAL(longSkipDurationChanged(int)),
0462         this, SLOT(longSkipDurationChanged(int)));
0463 
0464     longSkipBackwardAction = new QWidgetAction(this);
0465     longSkipBackwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
0466     // xgettext:no-c-format
0467     longSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward", longSkipDuration));
0468     longSkipBackwardAction->setShortcut(Qt::SHIFT + Qt::Key_Left);
0469     connect(longSkipBackwardAction, SIGNAL(triggered()), this, SLOT(longSkipBackward()));
0470     navigationMenu->addAction(
0471         collection->addAction(QLatin1String("controls_long_skip_backward"), longSkipBackwardAction));
0472 
0473     shortSkipBackwardAction = new QWidgetAction(this);
0474     shortSkipBackwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
0475     // xgettext:no-c-format
0476     shortSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward", shortSkipDuration));
0477     shortSkipBackwardAction->setShortcut(Qt::Key_Left);
0478     connect(shortSkipBackwardAction, SIGNAL(triggered()), this, SLOT(shortSkipBackward()));
0479     navigationMenu->addAction(
0480         collection->addAction(QLatin1String("controls_skip_backward"), shortSkipBackwardAction));
0481 
0482     shortSkipForwardAction = new QWidgetAction(this);
0483     shortSkipForwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
0484     // xgettext:no-c-format
0485     shortSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward", shortSkipDuration));
0486     shortSkipForwardAction->setShortcut(Qt::Key_Right);
0487     connect(shortSkipForwardAction, SIGNAL(triggered()), this, SLOT(shortSkipForward()));
0488     navigationMenu->addAction(
0489         collection->addAction(QLatin1String("controls_skip_forward"), shortSkipForwardAction));
0490 
0491     longSkipForwardAction = new QWidgetAction(this);
0492     longSkipForwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
0493     // xgettext:no-c-format
0494     longSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward", longSkipDuration));
0495     longSkipForwardAction->setShortcut(Qt::SHIFT + Qt::Key_Right);
0496     connect(longSkipForwardAction, SIGNAL(triggered()), this, SLOT(longSkipForward()));
0497     navigationMenu->addAction(
0498         collection->addAction(QLatin1String("controls_long_skip_forward"), longSkipForwardAction));
0499 
0500     toolBar->addAction(QIcon::fromTheme(QLatin1String("player-time"), QIcon(":player-time")), i18n("Seek Slider"))->setEnabled(false);
0501 
0502     action = new QWidgetAction(this);
0503     action->setText(i18n("Seek Slider"));
0504     seekSlider = new SeekSlider(toolBar);
0505     seekSlider->setFocusPolicy(Qt::NoFocus);
0506     seekSlider->setOrientation(Qt::Horizontal);
0507     seekSlider->setToolTip(action->text());
0508     connect(seekSlider, SIGNAL(valueChanged(int)), this, SLOT(seek(int)));
0509     action->setDefaultWidget(seekSlider);
0510     toolBar->addAction(collection->addAction(QLatin1String("controls_position_slider"), action));
0511 
0512     menuAction = new QWidgetAction(this);
0513     menuAction->setIcon(QIcon::fromTheme(QLatin1String("media-optical-video"), QIcon(":media-optical-video")));
0514     menuAction->setText(i18nc("dvd navigation", "DVD Menu"));
0515     connect(menuAction, SIGNAL(triggered()), this, SLOT(toggleMenu()));
0516     menu->addAction(collection->addAction(QLatin1String("controls_toggle_menu"), menuAction));
0517 
0518     titleMenu = new QMenu(i18nc("dvd navigation", "Title"), this);
0519     titleGroup = new QActionGroup(this);
0520     connect(titleGroup, SIGNAL(triggered(QAction*)),
0521         this, SLOT(currentTitleChanged(QAction*)));
0522     menu->addMenu(titleMenu);
0523 
0524     chapterMenu = new QMenu(i18nc("dvd navigation", "Chapter"), this);
0525     chapterGroup = new QActionGroup(this);
0526     connect(chapterGroup, SIGNAL(triggered(QAction*)),
0527         this, SLOT(currentChapterChanged(QAction*)));
0528     menu->addMenu(chapterMenu);
0529 
0530     angleMenu = new QMenu(i18nc("dvd navigation", "Angle"), this);
0531     angleGroup = new QActionGroup(this);
0532     connect(angleGroup, SIGNAL(triggered(QAction*)), this,
0533         SLOT(currentAngleChanged(QAction*)));
0534     menu->addMenu(angleMenu);
0535 
0536     action = new QWidgetAction(this);
0537     action->setText(i18n("Switch between elapsed and remaining time display"));
0538     timeButton = new QPushButton(toolBar);
0539     timeButton->setFocusPolicy(Qt::NoFocus);
0540     timeButton->setToolTip(action->text());
0541     connect(timeButton, SIGNAL(clicked(bool)), this, SLOT(timeButtonClicked()));
0542     action->setDefaultWidget(timeButton);
0543     toolBar->addAction(collection->addAction(QLatin1String("controls_time_button"), action));
0544 
0545     QTimer *timer = new QTimer(this);
0546     timer->start(50000);
0547     connect(timer, SIGNAL(timeout()), this, SLOT(checkScreenSaver()));
0548 
0549     // Set the play/pause icons accordingly
0550     playbackStatusChanged();
0551 }
0552 
0553 MediaWidget::~MediaWidget()
0554 {
0555     // Ensure that the screen saver will be disabled
0556     checkScreenSaver(true);
0557 
0558     KSharedConfig::openConfig()->group("MediaObject").writeEntry("Volume", volumeSlider->value());
0559     KSharedConfig::openConfig()->group("MediaObject").writeEntry("Deinterlace", deinterlaceMode);
0560     KSharedConfig::openConfig()->group("MediaObject").writeEntry("AutoResizeFactor", autoResizeFactor);
0561 }
0562 
0563 QString MediaWidget::extensionFilter()
0564 {
0565     return i18n(
0566         "Supported Media Files ("
0567         // generated from kaffeine.desktop's mime types
0568         "*.3ga *.3gp *.3gpp *.669 *.ac3 *.aif *.aiff *.anim1 *.anim2 *.anim3 *.anim4 "
0569         "*.anim5 *.anim6 *.anim7 *.anim8 *.anim9 *.animj *.asf *.asx *.au *.avf *.avi "
0570         "*.bdm *.bdmv *.clpi *.cpi *.divx *.dv *.f4a *.f4b *.f4v *.flac *.flc *.fli *.flv "
0571         "*.it *.lrv *.m15 *.m2t *.m2ts *.m3u *.m3u8 *.m4a *.m4b *.m4v *.med *.mka *.mkv "
0572         "*.mng *.mod *.moov *.mov *.mp+ *.mp2 *.mp3 *.mp4 *.mpc *.mpe *.mpeg *.mpg *.mpga "
0573         "*.mpl *.mpls *.mpp *.mtm *.mts *.nsv *.oga *.ogg *.ogm *.ogv *.ogx *.opus *.pls "
0574         "*.qt *.qtl *.qtvr *.ra *.ram *.rax *.rm *.rmj *.rmm *.rms *.rmvb *.rmx *.rp *.rv "
0575         "*.rvx *.s3m *.shn *.snd *.spl *.stm *.swf *.ts *.tta *.ult *.uni *.vdr *.vlc "
0576         "*.vob *.voc *.wav *.wax *.webm *.wma *.wmv *.wmx *.wv *.wvp *.wvx *.xm *.xspf "
0577         // manual entries
0578         "*.kaffeine *.iso);;"
0579         "All Files (*)");
0580 }
0581 
0582 MediaWidget::DisplayMode MediaWidget::getDisplayMode() const
0583 {
0584     return displayMode;
0585 }
0586 
0587 void MediaWidget::setDisplayMode(DisplayMode displayMode_)
0588 {
0589     if (displayMode != displayMode_) {
0590         displayMode = displayMode_;
0591 
0592         switch (displayMode) {
0593         case NormalMode:
0594         case MinimalMode:
0595             fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
0596             fullScreenAction->setText(i18nc("'Playback' menu", "Full Screen Mode"));
0597             break;
0598         case FullScreenMode:
0599         case FullScreenReturnToMinimalMode:
0600             fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-restore"), QIcon(":view-restore")));
0601             fullScreenAction->setText(i18nc("'Playback' menu",
0602                 "Exit Full Screen Mode"));
0603             break;
0604         }
0605 
0606         switch (displayMode) {
0607         case NormalMode:
0608         case FullScreenMode:
0609         case FullScreenReturnToMinimalMode:
0610             minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-restore"), QIcon(":view-restore")));
0611             minimalModeAction->setText(i18nc("'Playback' menu", "Minimal Mode"));
0612             break;
0613         case MinimalMode:
0614             minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
0615             minimalModeAction->setText(i18nc("'Playback' menu", "Exit Minimal Mode"));
0616             break;
0617         }
0618 
0619         emit displayModeChanged();
0620     }
0621 }
0622 
0623 void MediaWidget::play(MediaSource *source_)
0624 {
0625     if (source != source_) {
0626         source->playbackStatusChanged(Idle);
0627         source = source_;
0628 
0629         if (source == NULL) {
0630             source = dummySource.data();
0631         }
0632     }
0633 
0634     source->setMediaWidget(this);
0635     backend->play(*source);
0636 }
0637 
0638 void MediaWidget::mediaSourceDestroyed(MediaSource *mediaSource)
0639 {
0640     if (source == mediaSource) {
0641         source = dummySource.data();
0642     }
0643 }
0644 
0645 void MediaWidget::openSubtitle()
0646 {
0647     QString fname = QFileDialog::getOpenFileName(this,
0648             i18nc("@title:window", "Open subtitle"),".",
0649             i18n("Subtitles (*.cdg *.idx *.srt " \
0650                     "*.sub *.utf *.ass " \
0651                     "*.ssa *.aqt " \
0652                     "*.jss *.psb " \
0653                     "*.rt *.smi *.txt " \
0654                     "*.smil *.stl *.usf " \
0655                     "*.dks *.pjs *.mpl2 *.mks " \
0656                     "*.vtt *.ttml *.dfxp"));
0657 
0658     setSubtitle(QUrl::fromLocalFile(fname));
0659 }
0660 
0661 void MediaWidget::setSubtitle(QUrl url)
0662 {
0663     if (!url.isValid()) {
0664         return;
0665     }
0666 
0667     backend->setExternalSubtitle(url);
0668 }
0669 
0670 void MediaWidget::play(const QUrl &url, const QUrl &subtitleUrl)
0671 {
0672     // FIXME mem-leak
0673     play(new MediaSourceUrl(url, subtitleUrl));
0674 }
0675 
0676 void MediaWidget::playAudioCd(const QString &device)
0677 {
0678     QUrl devicePath;
0679 
0680     if (!device.isEmpty()) {
0681         devicePath = QUrl::fromLocalFile(device);
0682     } else {
0683         QList<Solid::Device> devices =
0684             Solid::Device::listFromQuery(QLatin1String("OpticalDisc.availableContent & 'Audio'"));
0685 
0686         if (!devices.isEmpty()) {
0687             Solid::Block *block = devices.first().as<Solid::Block>();
0688 
0689             if (block != NULL) {
0690                 devicePath = QUrl::fromLocalFile(block->device());
0691             }
0692         }
0693     }
0694 
0695     // FIXME mem-leak
0696     play(new MediaSourceAudioCd(devicePath));
0697 }
0698 
0699 void MediaWidget::playVideoCd(const QString &device)
0700 {
0701     QUrl devicePath;
0702 
0703     if (!device.isEmpty()) {
0704         devicePath = QUrl::fromLocalFile(device);
0705     } else {
0706         QList<Solid::Device> devices = Solid::Device::listFromQuery(
0707             QLatin1String("OpticalDisc.availableContent & 'VideoCd|SuperVideoCd'"));
0708 
0709         if (!devices.isEmpty()) {
0710             Solid::Block *block = devices.first().as<Solid::Block>();
0711 
0712             if (block != NULL) {
0713                 devicePath = QUrl::fromLocalFile(block->device());
0714             }
0715         }
0716     }
0717 
0718     // FIXME mem-leak
0719     play(new MediaSourceVideoCd(devicePath));
0720 }
0721 
0722 void MediaWidget::playDvd(const QString &device)
0723 {
0724     QUrl devicePath;
0725 
0726     if (!device.isEmpty()) {
0727         devicePath = QUrl::fromLocalFile(device);
0728     } else {
0729         QList<Solid::Device> devices =
0730             Solid::Device::listFromQuery(QLatin1String("OpticalDisc.availableContent & 'VideoDvd'"));
0731 
0732         if (!devices.isEmpty()) {
0733             Solid::Block *block = devices.first().as<Solid::Block>();
0734 
0735             if (block != NULL) {
0736                 devicePath = QUrl::fromLocalFile(block->device());
0737             }
0738         }
0739     }
0740 
0741     // FIXME mem-leak
0742     play(new MediaSourceDvd(devicePath));
0743 }
0744 
0745 OsdWidget *MediaWidget::getOsdWidget()
0746 {
0747     return osdWidget;
0748 }
0749 
0750 MediaWidget::PlaybackStatus MediaWidget::getPlaybackStatus() const
0751 {
0752     return backend->getPlaybackStatus();
0753 }
0754 
0755 int MediaWidget::getVolume() const
0756 {
0757     return volumeSlider->value();
0758 }
0759 
0760 int MediaWidget::getPosition() const
0761 {
0762     return backend->getCurrentTime();
0763 }
0764 
0765 void MediaWidget::play()
0766 {
0767     source->replay();
0768 }
0769 
0770 void MediaWidget::togglePause()
0771 {
0772     actionPlayPause->trigger();
0773 }
0774 
0775 void MediaWidget::setPosition(int position)
0776 {
0777     backend->seek(position);
0778 }
0779 
0780 void MediaWidget::setVolume(int volume)
0781 {
0782     // QSlider ensures that the value is within the range
0783     volumeSlider->setValue(volume);
0784 }
0785 
0786 void MediaWidget::setVolumeUnderMouse(int volume)
0787 {
0788     if (volume == 100 || !volume)
0789         osdWidget->showText(i18nc("osd", "Volume: %1%", volume), 1500);
0790     else
0791         setVolume(volume);
0792 }
0793 
0794 void MediaWidget::toggleMuted()
0795 {
0796     muteAction->trigger();
0797 }
0798 
0799 void MediaWidget::previous()
0800 {
0801     if (source->getType() == MediaSource::Url)
0802         emit playlistPrevious();
0803        source->previous();
0804 }
0805 
0806 void MediaWidget::next()
0807 {
0808     if (source->getType() == MediaSource::Url)
0809         emit playlistNext();
0810        source->next();
0811 }
0812 
0813 void MediaWidget::stop()
0814 {
0815     switch (backend->getPlaybackStatus()) {
0816     case Idle:
0817         break;
0818     case Playing:
0819     case Paused:
0820         osdWidget->showText(i18nc("osd", "Stopped"), 1500);
0821         break;
0822     }
0823 
0824     backend->stop();
0825     source->playbackStatusChanged(Idle);
0826 }
0827 
0828 void MediaWidget::setAudioCard()
0829 {
0830     QAction *action = qobject_cast<QAction *>(sender());
0831     backend->setAudioDevice(action->data().toString());
0832 }
0833 void MediaWidget::increaseVolume()
0834 {
0835     // QSlider ensures that the value is within the range
0836     volumeSlider->setValue(volumeSlider->value() + 5);
0837 }
0838 
0839 void MediaWidget::decreaseVolume()
0840 {
0841     // QSlider ensures that the value is within the range
0842     volumeSlider->setValue(volumeSlider->value() - 5);
0843 }
0844 
0845 void MediaWidget::checkScreenSaver(bool noDisable)
0846 {
0847     bool suspendScreenSaver = false;
0848 
0849     if (!noDisable) {
0850         switch (backend->getPlaybackStatus()) {
0851         case Idle:
0852         case Paused:
0853             break;
0854         case Playing:
0855             suspendScreenSaver = isVisible();
0856             break;
0857         }
0858     }
0859 
0860     if (suspendScreenSaver) {
0861         // KDE - Inhibit doesn't inhibit "lock screen after inactivity"
0862         QDBusInterface(QLatin1String("org.freedesktop.ScreenSaver"), QLatin1String("/ScreenSaver"),
0863             QLatin1String("org.freedesktop.ScreenSaver")).call(QDBus::NoBlock,
0864             QLatin1String("SimulateUserActivity"));
0865 
0866         // GNOME - Inhibit doesn't inhibit power management functions
0867         QDBusInterface(QLatin1String("org.gnome.ScreenSaver"), QLatin1String("/"),
0868                    QLatin1String("org.gnome.ScreenSaver")).
0869             call(QDBus::NoBlock, QLatin1String("SimulateUserActivity"));
0870     }
0871 
0872     if (screenSaverSuspended != suspendScreenSaver) {
0873         // X11 - needed if none of the above applications is running
0874         if (KWindowSystem::isPlatformX11()) {
0875             screenSaverSuspended = suspendScreenSaver;
0876             XScreenSaverSuspend(QX11Info::display(), suspendScreenSaver);
0877         }
0878     }
0879 }
0880 
0881 void MediaWidget::mutedChanged()
0882 {
0883     muted = !muted;
0884     backend->setMuted(muted);
0885 
0886     if (muted) {
0887         muteAction->setIcon(mutedIcon);
0888         osdWidget->showText(i18nc("osd", "Mute On"), 1500);
0889     } else {
0890         muteAction->setIcon(unmutedIcon);
0891         osdWidget->showText(i18nc("osd", "Mute Off"), 1500);
0892     }
0893 }
0894 
0895 void MediaWidget::volumeChanged(int volume)
0896 {
0897     backend->setVolume(volume);
0898     osdWidget->showText(i18nc("osd", "Volume: %1%", volume), 1500);
0899 }
0900 
0901 void MediaWidget::toggleFullScreen()
0902 {
0903     switch (displayMode) {
0904     case NormalMode:
0905         setDisplayMode(FullScreenMode);
0906         break;
0907     case FullScreenMode:
0908         setDisplayMode(NormalMode);
0909         break;
0910     case FullScreenReturnToMinimalMode:
0911         setDisplayMode(MinimalMode);
0912         break;
0913     case MinimalMode:
0914         setDisplayMode(FullScreenReturnToMinimalMode);
0915         break;
0916     }
0917 }
0918 
0919 void MediaWidget::toggleMinimalMode()
0920 {
0921     switch (displayMode) {
0922     case NormalMode:
0923     case FullScreenMode:
0924     case FullScreenReturnToMinimalMode:
0925         setDisplayMode(MinimalMode);
0926         break;
0927     case MinimalMode:
0928         setDisplayMode(NormalMode);
0929         break;
0930     }
0931 }
0932 
0933 void MediaWidget::seek(int position)
0934 {
0935     if (blockBackendUpdates) {
0936         return;
0937     }
0938 
0939     backend->seek(position);
0940 }
0941 
0942 void MediaWidget::deinterlacingChanged(QAction *action)
0943 {
0944     bool ok;
0945     const char *mode;
0946 
0947     deinterlaceMode = action->data().toInt(&ok);
0948 
0949     switch (deinterlaceMode) {
0950     case DeinterlaceDiscard:
0951         mode = "discard";
0952         break;
0953     case DeinterlaceBob:
0954         mode = "bob";
0955         break;
0956     case DeinterlaceLinear:
0957         mode = "linear";
0958         break;
0959     case DeinterlaceYadif:
0960         mode = "yadif";
0961         break;
0962     case DeinterlaceYadif2x:
0963         mode = "yadif2x";
0964         break;
0965     case DeinterlacePhosphor:
0966         mode = "phosphor";
0967         break;
0968     case DeinterlaceX:
0969         mode = "x";
0970         break;
0971     case DeinterlaceMean:
0972         mode = "mean";
0973         break;
0974     case DeinterlaceBlend:
0975         mode = "blend";
0976         break;
0977     case DeinterlaceIvtc:
0978         mode = "ivtc";
0979         break;
0980     case DeinterlaceDisabled:
0981     default:
0982         mode = "disabled";
0983     }
0984 
0985     backend->setDeinterlacing(static_cast<DeinterlaceMode>(deinterlaceMode));
0986 
0987     osdWidget->showText(i18nc("osd message", "Deinterlace %1", mode), 1500);
0988 }
0989 
0990 void MediaWidget::aspectRatioChanged(QAction *action)
0991 {
0992     bool ok;
0993     unsigned int aspectRatio_ = action->data().toInt(&ok);
0994 
0995     if (aspectRatio_ <= AspectRatio239_100) {
0996         backend->setAspectRatio(static_cast<AspectRatio>(aspectRatio_));
0997         setVideoSize();
0998 
0999         return;
1000     }
1001 
1002     qCWarning(logMediaWidget, "internal error");
1003 }
1004 
1005 
1006 void MediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio)
1007 {
1008     backend->setAspectRatio(aspectRatio);
1009 }
1010 
1011 
1012 void MediaWidget::setVideoSize()
1013 {
1014     float scale = autoResizeFactor / 100.0;
1015 
1016     if (scale > 3.4 || scale < 0)
1017         scale = 0;
1018 
1019     backend->resizeToVideo(scale);
1020 }
1021 
1022 void MediaWidget::autoResizeTriggered(QAction *action)
1023 {
1024     foreach (QAction *autoResizeAction, action->actionGroup()->actions()) {
1025         autoResizeAction->setChecked(autoResizeAction == action);
1026     }
1027 
1028     bool ok = false;
1029     autoResizeFactor = action->data().toInt(&ok);
1030 
1031     if (ok)
1032         setVideoSize();
1033     else
1034         qCWarning(logMediaWidget, "internal error");
1035 }
1036 
1037 void MediaWidget::pausedChanged(bool paused)
1038 {
1039     switch (backend->getPlaybackStatus()) {
1040     case Idle:
1041         source->replay();
1042         break;
1043     case Playing:
1044     case Paused:
1045         backend->setPaused(paused);
1046         break;
1047     }
1048 }
1049 
1050 void MediaWidget::timeButtonClicked()
1051 {
1052     showElapsedTime = !showElapsedTime;
1053     currentTotalTimeChanged();
1054 }
1055 
1056 void MediaWidget::longSkipBackward()
1057 {
1058     int longSkipDuration = Configuration::instance()->getLongSkipDuration();
1059     int currentTime = (backend->getCurrentTime() - 1000 * longSkipDuration);
1060 
1061     if (currentTime < 0) {
1062         currentTime = 0;
1063     }
1064 
1065     backend->seek(currentTime);
1066 }
1067 
1068 void MediaWidget::shortSkipBackward()
1069 {
1070     int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
1071     int currentTime = (backend->getCurrentTime() - 1000 * shortSkipDuration);
1072 
1073     if (currentTime < 0) {
1074         currentTime = 0;
1075     }
1076 
1077     backend->seek(currentTime);
1078 }
1079 
1080 void MediaWidget::shortSkipForward()
1081 {
1082     int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
1083     backend->seek(backend->getCurrentTime() + 1000 * shortSkipDuration);
1084 }
1085 
1086 void MediaWidget::longSkipForward()
1087 {
1088     int longSkipDuration = Configuration::instance()->getLongSkipDuration();
1089     backend->seek(backend->getCurrentTime() + 1000 * longSkipDuration);
1090 }
1091 
1092 void MediaWidget::jumpToPosition()
1093 {
1094     QDialog *dialog = new JumpToPositionDialog(this);
1095     dialog->setAttribute(Qt::WA_DeleteOnClose, true);
1096     dialog->setModal(true);
1097     dialog->show();
1098 }
1099 
1100 void MediaWidget::currentAudioStreamChanged(int currentAudioStream)
1101 {
1102     if (!blockBackendUpdates) {
1103         if (source->overrideAudioStreams()) {
1104             source->setCurrentAudioStream(currentAudioStream);
1105             return;
1106         }
1107 
1108         source->setCurrentAudioStream(currentAudioStream -
1109             backend->getAudioStreams().size());
1110 
1111         if (currentAudioStream >= backend->getAudioStreams().size()) {
1112             currentAudioStream = -1;
1113         }
1114 
1115         if (backend->getCurrentAudioStream() != currentAudioStream) {
1116             backend->setCurrentAudioStream(currentAudioStream);
1117         }
1118     }
1119     audioStreamBox->view()->setMinimumWidth(audioStreamBox->view()->sizeHintForColumn(0));
1120 
1121 }
1122 
1123 void MediaWidget::currentSubtitleChanged(int currentSubtitle)
1124 {
1125     if (blockBackendUpdates)
1126         return;
1127 
1128     if (source->overrideSubtitles()) {
1129         source->setCurrentSubtitle(currentSubtitle - 1);
1130         return;
1131     }
1132 
1133     source->setCurrentSubtitle(currentSubtitle - 1 - backend->getSubtitles().size());
1134 
1135     backend->setCurrentSubtitle(currentSubtitle);
1136 }
1137 
1138 void MediaWidget::toggleMenu()
1139 {
1140     backend->showDvdMenu();
1141 }
1142 
1143 void MediaWidget::currentTitleChanged(QAction *action)
1144 {
1145     backend->setCurrentTitle(titleGroup->actions().indexOf(action) + 1);
1146 }
1147 
1148 void MediaWidget::currentChapterChanged(QAction *action)
1149 {
1150     backend->setCurrentChapter(chapterGroup->actions().indexOf(action) + 1);
1151 }
1152 
1153 void MediaWidget::currentAngleChanged(QAction *action)
1154 {
1155     backend->setCurrentAngle(angleGroup->actions().indexOf(action) + 1);
1156 }
1157 
1158 void MediaWidget::shortSkipDurationChanged(int shortSkipDuration)
1159 {
1160         // xgettext:no-c-format
1161     shortSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward",
1162         shortSkipDuration));
1163     // xgettext:no-c-format
1164     shortSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward",
1165         shortSkipDuration));
1166 }
1167 
1168 void MediaWidget::longSkipDurationChanged(int longSkipDuration)
1169 {
1170         // xgettext:no-c-format
1171     longSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward",
1172         longSkipDuration));
1173     // xgettext:no-c-format
1174     longSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward",
1175         longSkipDuration));
1176 }
1177 
1178 void MediaWidget::getAudioDevices()
1179 {
1180     foreach(QAction *action, audioDevMenu->actions()) {
1181         audioDevMenu->removeAction(action);
1182     }
1183 
1184     foreach(const QString &device, backend->getAudioDevices()) {
1185         QAction *action = new QWidgetAction(this);
1186         action->setText(device);
1187         action->setData(device);
1188         connect(action, SIGNAL(triggered()), this, SLOT(setAudioCard()));
1189         audioDevMenu->addAction(action);
1190     }
1191 }
1192 
1193 void MediaWidget::audioStreamsChanged()
1194 {
1195     QStringList items;
1196     int currentIndex;
1197 
1198     if (source->overrideAudioStreams()) {
1199         items = source->getAudioStreams();
1200         currentIndex = source->getCurrentAudioStream();
1201     } else {
1202         items = backend->getAudioStreams();
1203         currentIndex = backend->getCurrentAudioStream();
1204     }
1205 
1206     blockBackendUpdates = true;
1207 
1208     if (audioStreamModel->stringList() != items) {
1209         audioStreamModel->setStringList(items);
1210     }
1211 
1212     audioStreamBox->setCurrentIndex(currentIndex);
1213     audioStreamBox->setEnabled(items.size() > 1);
1214     blockBackendUpdates = false;
1215 }
1216 
1217 void MediaWidget::subtitlesChanged()
1218 {
1219     QStringList items(textSubtitlesOff);
1220     int currentIndex = 0;
1221 
1222     if (source->overrideSubtitles()) {
1223         items += source->getSubtitles();
1224         currentIndex = (source->getCurrentSubtitle() + 1);
1225 
1226         // automatically choose appropriate subtitle
1227         int selectedSubtitle = -1;
1228 
1229         if (currentIndex > 0) {
1230             selectedSubtitle = (backend->getSubtitles().size() - 1);
1231         }
1232 
1233         if (backend->getCurrentSubtitle() != selectedSubtitle) {
1234             backend->setCurrentSubtitle(selectedSubtitle);
1235         }
1236     } else {
1237         items += backend->getSubtitles();
1238         items += source->getSubtitles();
1239         currentIndex = (backend->getCurrentSubtitle());
1240         int currentSourceIndex = source->getCurrentSubtitle();
1241 
1242         if (currentSourceIndex >= 0) {
1243             currentIndex = (currentSourceIndex + backend->getSubtitles().size() + 1);
1244         }
1245     }
1246 
1247     blockBackendUpdates = true;
1248 
1249     if (subtitleModel->stringList() != items) {
1250         subtitleModel->setStringList(items);
1251     }
1252 
1253     if (currentIndex < 0)
1254         currentIndex = 0;
1255 
1256     subtitleBox->setCurrentIndex(currentIndex);
1257     subtitleBox->setEnabled(items.size() > 1);
1258     blockBackendUpdates = false;
1259 }
1260 
1261 void MediaWidget::currentTotalTimeChanged()
1262 {
1263     int currentTime = backend->getCurrentTime();
1264     int totalTime = backend->getTotalTime();
1265     source->trackLengthChanged(totalTime);
1266 
1267     if (source->getType() == MediaSource::Url)
1268         emit playlistTrackLengthChanged(totalTime);
1269 
1270     // If the player backend doesn't implement currentTime and/or
1271     // totalTime, the source can implement such logic
1272     source->validateCurrentTotalTime(currentTime, totalTime);
1273 
1274     blockBackendUpdates = true;
1275     seekSlider->setRange(0, totalTime);
1276     seekSlider->setValue(currentTime);
1277 
1278     if (showElapsedTime) {
1279         timeButton->setText(QLatin1Char(' ') + QTime(0, 0).addMSecs(currentTime).toString());
1280     } else {
1281         int remainingTime = (totalTime - currentTime);
1282         timeButton->setText(QLatin1Char('-') + QTime(0, 0).addMSecs(remainingTime).toString());
1283     }
1284 
1285     blockBackendUpdates = false;
1286 }
1287 
1288 void MediaWidget::seekableChanged()
1289 {
1290     bool seekable = (backend->isSeekable() && !source->hideCurrentTotalTime());
1291     seekSlider->setEnabled(seekable);
1292     navigationMenu->setEnabled(seekable);
1293     jumpToPositionAction->setEnabled(seekable);
1294     timeButton->setEnabled(seekable);
1295 }
1296 
1297 void MediaWidget::contextMenuEvent(QContextMenuEvent *event)
1298 {
1299     menu->popup(event->globalPos());
1300 }
1301 
1302 void MediaWidget::mouseDoubleClickEvent(QMouseEvent *event)
1303 {
1304     Q_UNUSED(event)
1305     emit toggleFullScreen();
1306 }
1307 
1308 void MediaWidget::dragEnterEvent(QDragEnterEvent *event)
1309 {
1310     if (event->mimeData()->hasUrls()) {
1311         event->acceptProposedAction();
1312     }
1313 }
1314 
1315 void MediaWidget::dropEvent(QDropEvent *event)
1316 {
1317     const QMimeData *mimeData = event->mimeData();
1318 
1319     if (mimeData->hasUrls()) {
1320         emit playlistUrlsDropped(mimeData->urls());
1321         event->acceptProposedAction();
1322     }
1323 }
1324 
1325 bool MediaWidget::event(QEvent *event)
1326 {
1327     switch (event->type()) {
1328     case QEvent::ShortcutOverride:
1329         {
1330         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
1331         int key = keyEvent->key();
1332 
1333         if (backend->hasDvdMenu()) {
1334             switch (key){
1335             case Qt::Key_Return:
1336             case Qt::Key_Up:
1337             case Qt::Key_Down:
1338             case Qt::Key_Left:
1339             case Qt::Key_Right:
1340                 backend->dvdNavigate(key);
1341                 event->accept();
1342                 return true;
1343             }
1344         }
1345         break;
1346         }
1347     default:
1348         break;
1349     }
1350 
1351     return QWidget::event(event);
1352 }
1353 
1354 void MediaWidget::keyPressEvent(QKeyEvent *event)
1355 {
1356     int key = event->key();
1357 
1358     if ((key >= Qt::Key_0) && (key <= Qt::Key_9)) {
1359         event->accept();
1360         emit osdKeyPressed(key);
1361     } else {
1362         QWidget::keyPressEvent(event);
1363     }
1364 }
1365 
1366 void MediaWidget::resizeEvent(QResizeEvent *event)
1367 {
1368     osdWidget->resize(event->size());
1369     QWidget::resizeEvent(event);
1370 }
1371 
1372 void MediaWidget::wheelEvent(QWheelEvent *event)
1373 {
1374     int y = event->angleDelta().y();
1375     int delta = (y < 0) ? -1 : 1;
1376 
1377     setVolumeUnderMouse(getVolume() + delta);
1378 }
1379 
1380 void MediaWidget::playbackFinished()
1381 {
1382     if (source->getType() == MediaSource::Url)
1383         emit playlistNext();
1384 
1385     source->playbackFinished();
1386 }
1387 
1388 void MediaWidget::playbackStatusChanged()
1389 {
1390     source->playbackStatusChanged(backend->getPlaybackStatus());
1391     bool playing = true;
1392 
1393     switch (backend->getPlaybackStatus()) {
1394     case Idle:
1395         actionPlayPause->setIcon(iconPlay);
1396         actionPlayPause->setText(textPlay);
1397         playing = false;
1398         break;
1399     case Playing:
1400         actionPlayPause->setIcon(iconPause);
1401         actionPlayPause->setText(textPause);
1402         osdWidget->showText(i18nc("osd", "Playing"), 1500);
1403         break;
1404     case Paused:
1405         actionPlayPause->setIcon(iconPlay);
1406         actionPlayPause->setText(textPlay);
1407         osdWidget->showText(i18nc("osd", "Paused"), 1500);
1408         break;
1409     }
1410 
1411     actionPlayPause->setCheckable(playing);
1412     actionPrevious->setEnabled(playing);
1413     actionStop->setEnabled(playing);
1414     actionNext->setEnabled(playing);
1415     timeButton->setEnabled(playing);
1416 }
1417 
1418 void MediaWidget::metadataChanged()
1419 {
1420     QMap<MediaWidget::MetadataType, QString> metadata = backend->getMetadata();
1421     source->metadataChanged(metadata);
1422 
1423     if (source->getType() == MediaSource::Url)
1424         emit playlistTrackMetadataChanged(metadata);
1425 
1426     if (source->overrideCaption()) {
1427         emit changeCaption(source->getDefaultCaption());
1428         return;
1429     }
1430 
1431     QString caption = metadata.value(Title);
1432     QString artist = metadata.value(Artist);
1433 
1434     if (!caption.isEmpty() && !artist.isEmpty()) {
1435         caption += QLatin1Char(' ');
1436     }
1437 
1438     if (!artist.isEmpty()) {
1439         caption += QLatin1Char('(');
1440         caption += artist;
1441         caption += QLatin1Char(')');
1442     }
1443 
1444     if (caption.isEmpty()) {
1445         caption = source->getDefaultCaption();
1446     }
1447 
1448     QString osdText = caption;
1449     if (backend->hasDvdMenu())
1450         osdText += "\nUse keys to navigate at DVD menu";
1451 
1452     if (!caption.isEmpty()) {
1453         osdWidget->showText(osdText, 2500);
1454     }
1455 
1456     emit changeCaption(caption);
1457 }
1458 
1459 void MediaWidget::dvdMenuChanged()
1460 {
1461     bool hasDvdMenu = backend->hasDvdMenu();
1462 
1463     menuAction->setEnabled(hasDvdMenu);
1464 }
1465 
1466 void MediaWidget::titlesChanged()
1467 {
1468     int titleCount = backend->getTitleCount();
1469     int currentTitle = backend->getCurrentTitle();
1470 
1471     if (titleCount > 1) {
1472         QList<QAction *> actions = titleGroup->actions();
1473 
1474         if (actions.count() < titleCount) {
1475             int i = actions.count();
1476             actions.clear();
1477 
1478             for (; i < titleCount; ++i) {
1479                 QAction *action = titleGroup->addAction(QString::number(i + 1));
1480                 action->setCheckable(true);
1481                 titleMenu->addAction(action);
1482             }
1483 
1484             actions = titleGroup->actions();
1485         }
1486 
1487         for (int i = 0; i < actions.size(); ++i) {
1488             actions.at(i)->setVisible(i < titleCount);
1489         }
1490 
1491         if ((currentTitle >= 1) && (currentTitle <= titleGroup->actions().count())) {
1492             titleGroup->actions().at(currentTitle - 1)->setChecked(true);
1493         } else if (titleGroup->checkedAction() != NULL) {
1494             titleGroup->checkedAction()->setChecked(false);
1495         }
1496 
1497         titleMenu->setEnabled(true);
1498     } else {
1499         titleMenu->setEnabled(false);
1500     }
1501 }
1502 
1503 void MediaWidget::chaptersChanged()
1504 {
1505     int chapterCount = backend->getChapterCount();
1506     int currentChapter = backend->getCurrentChapter();
1507 
1508     if (chapterCount > 1) {
1509         QList<QAction *> actions = chapterGroup->actions();
1510 
1511         if (actions.count() < chapterCount) {
1512             int i = actions.count();
1513             actions.clear();
1514 
1515             for (; i < chapterCount; ++i) {
1516                 QAction *action = chapterGroup->addAction(QString::number(i + 1));
1517                 action->setCheckable(true);
1518                 chapterMenu->addAction(action);
1519             }
1520 
1521             actions = chapterGroup->actions();
1522         }
1523 
1524         for (int i = 0; i < actions.size(); ++i) {
1525             actions.at(i)->setVisible(i < chapterCount);
1526         }
1527 
1528         if ((currentChapter >= 1) && (currentChapter <= chapterGroup->actions().count())) {
1529             chapterGroup->actions().at(currentChapter - 1)->setChecked(true);
1530         } else if (chapterGroup->checkedAction() != NULL) {
1531             chapterGroup->checkedAction()->setChecked(false);
1532         }
1533 
1534         chapterMenu->setEnabled(true);
1535     } else {
1536         chapterMenu->setEnabled(false);
1537     }
1538 }
1539 
1540 void MediaWidget::anglesChanged()
1541 {
1542     int angleCount = backend->getAngleCount();
1543     int currentAngle = backend->getCurrentAngle();
1544 
1545     if (angleCount > 1) {
1546         QList<QAction *> actions = angleGroup->actions();
1547 
1548         if (actions.count() < angleCount) {
1549             int i = actions.count();
1550             actions.clear();
1551 
1552             for (; i < angleCount; ++i) {
1553                 QAction *action = angleGroup->addAction(QString::number(i + 1));
1554                 action->setCheckable(true);
1555                 angleMenu->addAction(action);
1556             }
1557 
1558             actions = angleGroup->actions();
1559         }
1560 
1561         for (int i = 0; i < actions.size(); ++i) {
1562             actions.at(i)->setVisible(i < angleCount);
1563         }
1564 
1565         if ((currentAngle >= 1) && (currentAngle <= angleGroup->actions().count())) {
1566             angleGroup->actions().at(currentAngle - 1)->setChecked(true);
1567         } else if (angleGroup->checkedAction() != NULL) {
1568             angleGroup->checkedAction()->setChecked(false);
1569         }
1570 
1571         angleMenu->setEnabled(true);
1572     } else {
1573         angleMenu->setEnabled(false);
1574     }
1575 }
1576 
1577 void MediaWidget::videoSizeChanged()
1578 {
1579     setVideoSize();
1580 }
1581 
1582 JumpToPositionDialog::JumpToPositionDialog(MediaWidget *mediaWidget_) : QDialog(mediaWidget_),
1583     mediaWidget(mediaWidget_)
1584 {
1585     setWindowTitle(i18nc("@title:window", "Jump to Position"));
1586 
1587     QWidget *widget = new QWidget(this);
1588     QBoxLayout *layout = new QVBoxLayout(widget);
1589 
1590     layout->addWidget(new QLabel(i18n("Enter a position:")));
1591 
1592     timeEdit = new QTimeEdit(this);
1593     timeEdit->setDisplayFormat(QLatin1String("hh:mm:ss"));
1594     timeEdit->setTime(QTime().addMSecs(mediaWidget->getPosition()));
1595     layout->addWidget(timeEdit);
1596 
1597     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
1598 
1599     timeEdit->setFocus();
1600 
1601     QVBoxLayout *mainLayout = new QVBoxLayout;
1602     setLayout(mainLayout);
1603     mainLayout->addWidget(widget);
1604     mainLayout->addWidget(buttonBox);
1605     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
1606 }
1607 
1608 JumpToPositionDialog::~JumpToPositionDialog()
1609 {
1610 }
1611 
1612 void JumpToPositionDialog::accept()
1613 {
1614     mediaWidget->setPosition(QTime(0, 0, 0).msecsTo(timeEdit->time()));
1615     QDialog::accept();
1616 }
1617 
1618 void SeekSlider::mousePressEvent(QMouseEvent *event)
1619 {
1620     int buttons = style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons);
1621     Qt::MouseButton button = static_cast<Qt::MouseButton>(buttons & (~(buttons - 1)));
1622     QMouseEvent modifiedEvent(event->type(), event->pos(), event->globalPos(), button,
1623         event->buttons() ^ event->button() ^ button, event->modifiers());
1624     QSlider::mousePressEvent(&modifiedEvent);
1625 }
1626 
1627 void SeekSlider::wheelEvent(QWheelEvent *event)
1628 {
1629     int delta = (event->angleDelta().y() < 0) ? -1 : 1;
1630     int new_value = value() + delta * maximum() / 100;
1631 
1632     event->accept();
1633     setValue(new_value);
1634 }