"Fossies" - the Fresh Open Source Software Archive

Member "kaffeine-2.0.18/src/mediawidget.cpp" (14 May 2019, 49751 Bytes) of package /linux/misc/kaffeine-2.0.18.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mediawidget.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.0.17_vs_2.0.18.

    1 /*
    2  * mediawidget.cpp
    3  *
    4  * Copyright (C) 2007-2011 Christoph Pfister <christophpfister@gmail.com>
    5  *
    6  * This program is free software; you can redistribute it and/or modify
    7  * it under the terms of the GNU General Public License as published by
    8  * the Free Software Foundation; either version 2 of the License, or
    9  * (at your option) any later version.
   10  *
   11  * This program is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  * GNU General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU General Public License along
   17  * with this program; if not, write to the Free Software Foundation, Inc.,
   18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   19  */
   20 
   21 #include "log.h"
   22 
   23 #include <KActionCollection>
   24 #include <KConfigGroup>
   25 #include <KSharedConfig>
   26 #include <KToolBar>
   27 #include <QAbstractItemView>
   28 #include <QBoxLayout>
   29 #include <QComboBox>
   30 #include <QContextMenuEvent>
   31 #include <QDialogButtonBox>
   32 #include <QDBusInterface>
   33 #include <QEvent>
   34 #include <QFileDialog>
   35 #include <QLabel>
   36 #include <QMenu>
   37 #include <QMimeData>
   38 #include <QPushButton>
   39 #include <QStringListModel>
   40 #include <QTimeEdit>
   41 #include <QTimer>
   42 #include <QWidgetAction>
   43 #include <QX11Info>
   44 #include <Solid/Block>
   45 #include <Solid/Device>
   46 #include <X11/extensions/scrnsaver.h>
   47 
   48 #include "backend-vlc/vlcmediawidget.h"
   49 #include "configuration.h"
   50 #include "mediawidget.h"
   51 #include "mediawidget_p.h"
   52 #include "osdwidget.h"
   53 
   54 MediaWidget::MediaWidget(QMenu *menu_, QToolBar *toolBar, KActionCollection *collection,
   55     QWidget *parent) : QWidget(parent), menu(menu_), displayMode(NormalMode),
   56     autoResizeFactor(0), blockBackendUpdates(false), muted(false),
   57     screenSaverSuspended(false), showElapsedTime(true)
   58 {
   59     dummySource.reset(new MediaSource());
   60     source = dummySource.data();
   61 
   62     QBoxLayout *layout = new QVBoxLayout(this);
   63     layout->setMargin(0);
   64 
   65     QPalette palette = QWidget::palette();
   66     palette.setColor(backgroundRole(), Qt::black);
   67     setPalette(palette);
   68     setAutoFillBackground(true);
   69 
   70     setAcceptDrops(true);
   71     setFocusPolicy(Qt::StrongFocus);
   72 
   73     backend = VlcMediaWidget::createVlcMediaWidget(this);
   74 
   75     if (backend == NULL) {
   76         backend = new DummyMediaWidget(this);
   77     }
   78 
   79     backend->connectToMediaWidget(this);
   80     layout->addWidget(backend);
   81     osdWidget = new OsdWidget(this);
   82 
   83     actionPrevious = new QWidgetAction(this);
   84     actionPrevious->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
   85     actionPrevious->setText(i18n("Previous"));
   86     actionPrevious->setShortcut(Qt::Key_PageUp);
   87     connect(actionPrevious, SIGNAL(triggered()), this, SLOT(previous()));
   88     toolBar->addAction(collection->addAction(QLatin1String("controls_previous"), actionPrevious));
   89     menu->addAction(actionPrevious);
   90 
   91     actionPlayPause = new QWidgetAction(this);
   92     actionPlayPause->setShortcut(Qt::Key_Space);
   93     textPlay = i18n("Play");
   94     textPause = i18n("Pause");
   95     iconPlay = QIcon::fromTheme(QLatin1String("media-playback-start"), QIcon(":media-playback-start"));
   96     iconPause = QIcon::fromTheme(QLatin1String("media-playback-pause"), QIcon(":media-playback-pause"));
   97     connect(actionPlayPause, SIGNAL(triggered(bool)), this, SLOT(pausedChanged(bool)));
   98     toolBar->addAction(collection->addAction(QLatin1String("controls_play_pause"), actionPlayPause));
   99     menu->addAction(actionPlayPause);
  100 
  101     actionStop = new QWidgetAction(this);
  102     actionStop->setIcon(QIcon::fromTheme(QLatin1String("media-playback-stop"), QIcon(":media-playback-stop")));
  103     actionStop->setText(i18n("Stop"));
  104     actionStop->setShortcut(Qt::Key_Backspace);
  105     connect(actionStop, SIGNAL(triggered()), this, SLOT(stop()));
  106     toolBar->addAction(collection->addAction(QLatin1String("controls_stop"), actionStop));
  107     menu->addAction(actionStop);
  108 
  109     actionNext = new QWidgetAction(this);
  110     actionNext->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
  111     actionNext->setText(i18n("Next"));
  112     actionNext->setShortcut(Qt::Key_PageDown);
  113     connect(actionNext, SIGNAL(triggered()), this, SLOT(next()));
  114     toolBar->addAction(collection->addAction(QLatin1String("controls_next"), actionNext));
  115     menu->addAction(actionNext);
  116     menu->addSeparator();
  117 
  118     fullScreenAction = new QWidgetAction(this);
  119     fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
  120     fullScreenAction->setText(i18nc("'Playback' menu", "Full Screen Mode"));
  121     fullScreenAction->setShortcut(Qt::Key_F);
  122     connect(fullScreenAction, SIGNAL(triggered()), this, SLOT(toggleFullScreen()));
  123     menu->addAction(collection->addAction(QLatin1String("view_fullscreen"), fullScreenAction));
  124 
  125     minimalModeAction = new QWidgetAction(this);
  126     minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
  127     minimalModeAction->setText(i18nc("'Playback' menu", "Minimal Mode"));
  128     minimalModeAction->setShortcut(Qt::Key_Period);
  129     connect(minimalModeAction, SIGNAL(triggered()), this, SLOT(toggleMinimalMode()));
  130     menu->addAction(collection->addAction(QLatin1String("view_minimal_mode"), minimalModeAction));
  131 
  132     audioStreamBox = new QComboBox(toolBar);
  133     connect(audioStreamBox, SIGNAL(currentIndexChanged(int)),
  134         this, SLOT(currentAudioStreamChanged(int)));
  135     toolBar->addWidget(audioStreamBox);
  136 
  137     audioStreamModel = new QStringListModel(toolBar);
  138     audioStreamBox->setModel(audioStreamModel);
  139 
  140     QMenu *subtitleMenu = new QMenu(i18nc("'Subtitle' menu", "Subtitle"), this);
  141     subtitleBox = new QComboBox(this);
  142     QWidgetAction *action = new QWidgetAction(this);
  143     action->setDefaultWidget(subtitleBox);
  144     textSubtitlesOff = i18nc("subtitle selection entry", "off");
  145     connect(subtitleBox, SIGNAL(currentIndexChanged(int)),
  146         this, SLOT(currentSubtitleChanged(int)));
  147     subtitleModel = new QStringListModel(toolBar);
  148     subtitleBox->setModel(subtitleModel);
  149     subtitleMenu->addAction(action);
  150     menu->addMenu(subtitleMenu);
  151     action = new QWidgetAction(this);
  152     action->setText(i18nc("'Subtitle' menu", "Add subtitle file"));
  153     action->setIcon(QIcon::fromTheme(QLatin1String("application-x-subrip"), QIcon(":application-x-subrip")));
  154     connect(action, &QWidgetAction::triggered, this, &MediaWidget::openSubtitle);
  155     subtitleMenu->addAction(action);
  156 
  157     menu->addMenu(subtitleMenu);
  158 
  159     QMenu *audioMenu = new QMenu(i18nc("'Playback' menu", "Audio"), this);
  160     action = new QWidgetAction(this);
  161     action->setIcon(QIcon::fromTheme(QLatin1String("audio-card"), QIcon(":audio-card")));
  162     action->setText(i18nc("'Audio' menu", "Audio Device"));
  163 
  164     audioDevMenu = new QMenu(i18nc("'Playback' menu", "Audio Device"), audioMenu);
  165     action = new QWidgetAction(this);
  166     connect(audioDevMenu, &QMenu::aboutToShow, this, &MediaWidget::getAudioDevices);
  167     audioMenu->addMenu(audioDevMenu);
  168 
  169     action = new QWidgetAction(this);
  170     action->setIcon(QIcon::fromTheme(QLatin1String("audio-volume-high"), QIcon(":audio-volume-high")));
  171     action->setText(i18nc("'Audio' menu", "Increase Volume"));
  172     action->setShortcut(Qt::Key_Plus);
  173     connect(action, SIGNAL(triggered()), this, SLOT(increaseVolume()));
  174     audioMenu->addAction(collection->addAction(QLatin1String("controls_increase_volume"), action));
  175 
  176     action = new QWidgetAction(this);
  177     action->setIcon(QIcon::fromTheme(QLatin1String("audio-volume-low"), QIcon(":audio-volume-low")));
  178     action->setText(i18nc("'Audio' menu", "Decrease Volume"));
  179     action->setShortcut(Qt::Key_Minus);
  180     connect(action, SIGNAL(triggered()), this, SLOT(decreaseVolume()));
  181     audioMenu->addAction(collection->addAction(QLatin1String("controls_decrease_volume"), action));
  182 
  183     muteAction = new QWidgetAction(this);
  184     muteAction->setText(i18nc("'Audio' menu", "Mute Volume"));
  185     mutedIcon = QIcon::fromTheme(QLatin1String("audio-volume-muted"), QIcon(":audio-volume-muted"));
  186     unmutedIcon = QIcon::fromTheme(QLatin1String("audio-volume-medium"), QIcon(":audio-volume-medium"));
  187     muteAction->setIcon(unmutedIcon);
  188     muteAction->setShortcut(Qt::Key_M);
  189     connect(muteAction, SIGNAL(triggered()), this, SLOT(mutedChanged()));
  190     toolBar->addAction(collection->addAction(QLatin1String("controls_mute_volume"), muteAction));
  191     audioMenu->addAction(muteAction);
  192     menu->addMenu(audioMenu);
  193 
  194     QMenu *videoMenu = new QMenu(i18nc("'Playback' menu", "Video"), this);
  195     menu->addMenu(videoMenu);
  196     menu->addSeparator();
  197 
  198     QMenu *deinterlaceMenu = new QMenu(i18nc("'Video' menu", "Deinterlace"), this);
  199     deinterlaceMenu->setIcon(QIcon::fromTheme(QLatin1String("format-justify-center"), QIcon(":format-justify-center")));
  200     QActionGroup *deinterlaceGroup = new QActionGroup(this);
  201     connect(deinterlaceMenu, SIGNAL(triggered(QAction*)),
  202         this, SLOT(deinterlacingChanged(QAction*)));
  203     videoMenu->addMenu(deinterlaceMenu);
  204 
  205     action = new QWidgetAction(deinterlaceGroup);
  206     action->setText(i18nc("'Deinterlace' menu", "disabled"));
  207     action->setCheckable(true);
  208     action->setShortcut(Qt::Key_D);
  209     action->setData(DeinterlaceDisabled);
  210     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_disabled"), action));
  211 
  212     action = new QWidgetAction(deinterlaceGroup);
  213     action->setText(i18nc("'Deinterlace' menu", "discard"));
  214     action->setCheckable(true);
  215     action->setData(DeinterlaceDiscard);
  216     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_discard"), action));
  217 
  218     action = new QWidgetAction(deinterlaceGroup);
  219     action->setText(i18nc("'Deinterlace' menu", "bob"));
  220     action->setCheckable(true);
  221     action->setData(DeinterlaceBob);
  222     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_bob"), action));
  223 
  224     action = new QWidgetAction(deinterlaceGroup);
  225     action->setText(i18nc("'Deinterlace' menu", "linear"));
  226     action->setCheckable(true);
  227     action->setData(DeinterlaceLinear);
  228     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_linear"), action));
  229 
  230     action = new QWidgetAction(deinterlaceGroup);
  231     action->setText(i18nc("'Deinterlace' menu", "yadif"));
  232     action->setCheckable(true);
  233     action->setData(DeinterlaceYadif);
  234     action->setShortcut(Qt::Key_I);
  235     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_yadif"), action));
  236 
  237     action = new QWidgetAction(deinterlaceGroup);
  238     action->setText(i18nc("'Deinterlace' menu", "yadif2x"));
  239     action->setCheckable(true);
  240     action->setData(DeinterlaceYadif2x);
  241     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_yadif2x"), action));
  242 
  243     action = new QWidgetAction(deinterlaceGroup);
  244     action->setText(i18nc("'Deinterlace' menu", "phosphor"));
  245     action->setCheckable(true);
  246     action->setData(DeinterlacePhosphor);
  247     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_phosphor"), action));
  248 
  249     action = new QWidgetAction(deinterlaceGroup);
  250     action->setText(i18nc("'Deinterlace' menu", "x"));
  251     action->setCheckable(true);
  252     action->setData(DeinterlaceX);
  253     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_x"), action));
  254 
  255     action = new QWidgetAction(deinterlaceGroup);
  256     action->setText(i18nc("'Deinterlace' menu", "mean"));
  257     action->setCheckable(true);
  258     action->setData(DeinterlaceMean);
  259     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_mean"), action));
  260 
  261     action = new QWidgetAction(deinterlaceGroup);
  262     action->setText(i18nc("'Deinterlace' menu", "blend"));
  263     action->setCheckable(true);
  264     action->setData(DeinterlaceBlend);
  265     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_blend"), action));
  266 
  267     action = new QWidgetAction(deinterlaceGroup);
  268     action->setText(i18nc("'Deinterlace' menu", "Inverse telecine"));
  269     action->setCheckable(true);
  270     action->setData(DeinterlaceIvtc);
  271     deinterlaceMenu->addAction(collection->addAction(QLatin1String("interlace_ivtc"), action));
  272 
  273     deinterlaceMode =
  274         KSharedConfig::openConfig()->group("MediaObject").readEntry("Deinterlace", 0);
  275 
  276     if (deinterlaceMode <= DeinterlaceIvtc) {
  277         for (int i = 0; i < deinterlaceGroup->actions().size(); i++) {
  278             if (deinterlaceGroup->actions().at(i)->data().toInt() == deinterlaceMode) {
  279                 deinterlaceGroup->actions().at(i)->setChecked(true);
  280                 break;
  281             }
  282         }
  283     } else {
  284         deinterlaceGroup->actions().at(0)->setChecked(true);
  285     }
  286     backend->setDeinterlacing(static_cast<DeinterlaceMode>(deinterlaceMode));
  287 
  288     QMenu *aspectMenu = new QMenu(i18nc("'Video' menu", "Aspect Ratio"), this);
  289     QActionGroup *aspectGroup = new QActionGroup(this);
  290     connect(aspectGroup, SIGNAL(triggered(QAction*)),
  291         this, SLOT(aspectRatioChanged(QAction*)));
  292     videoMenu->addMenu(aspectMenu);
  293 
  294     action = new QWidgetAction(aspectGroup);
  295     action->setText(i18nc("'Aspect Ratio' menu", "Automatic"));
  296     action->setCheckable(true);
  297     action->setData(AspectRatioAuto);
  298     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_auto"), action));
  299 
  300     action = new QWidgetAction(aspectGroup);
  301     action->setText(i18nc("'Aspect Ratio' menu", "1:1"));
  302     action->setCheckable(true);
  303     action->setData(AspectRatio1_1);
  304     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_1_1"), action));
  305 
  306     action = new QWidgetAction(aspectGroup);
  307     action->setText(i18nc("'Aspect Ratio' menu", "4:3"));
  308     action->setCheckable(true);
  309     action->setData(AspectRatio4_3);
  310     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_4_3"), action));
  311 
  312     action = new QWidgetAction(aspectGroup);
  313     action->setText(i18nc("'Aspect Ratio' menu", "5:4"));
  314     action->setCheckable(true);
  315     action->setData(AspectRatio5_4);
  316     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_5_4"), action));
  317 
  318     action = new QWidgetAction(aspectGroup);
  319     action->setText(i18nc("'Aspect Ratio' menu", "16:9"));
  320     action->setCheckable(true);
  321     action->setData(AspectRatio16_9);
  322     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_16_9"), action));
  323 
  324     action = new QWidgetAction(aspectGroup);
  325     action->setText(i18nc("'Aspect Ratio' menu", "16:10"));
  326     action->setCheckable(true);
  327     action->setData(AspectRatio16_10);
  328     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_16_10"), action));
  329 
  330     action = new QWidgetAction(aspectGroup);
  331     action->setText(i18nc("'Aspect Ratio' menu", "2.21:1"));
  332     action->setCheckable(true);
  333     action->setData(AspectRatio221_100);
  334     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_221_100"), action));
  335 
  336     action = new QWidgetAction(aspectGroup);
  337     action->setText(i18nc("'Aspect Ratio' menu", "2.35:1"));
  338     action->setCheckable(true);
  339     action->setData(AspectRatio235_100);
  340     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_235_100"), action));
  341 
  342     action = new QWidgetAction(aspectGroup);
  343     action->setText(i18nc("'Aspect Ratio' menu", "2.39:1"));
  344     action->setCheckable(true);
  345     action->setData(AspectRatio239_100);
  346     aspectMenu->addAction(collection->addAction(QLatin1String("controls_aspect_239_100"), action));
  347 
  348     QMenu *autoResizeMenu = new QMenu(i18n("Video size"), this);
  349     QActionGroup *autoResizeGroup = new QActionGroup(this);
  350     // we need an event even if you select the currently selected item
  351     autoResizeGroup->setExclusive(false);
  352     connect(autoResizeGroup, SIGNAL(triggered(QAction*)),
  353         this, SLOT(autoResizeTriggered(QAction*)));
  354 
  355     action = new QWidgetAction(autoResizeGroup);
  356     action->setText(i18nc("Video size", "Automatic"));
  357     action->setCheckable(true);
  358     action->setData(0);
  359     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_off"), action));
  360 
  361     action = new QWidgetAction(autoResizeGroup);
  362     action->setText(i18nc("Video size", "25%"));
  363     action->setCheckable(true);
  364     action->setData(25);
  365     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
  366 
  367     action = new QWidgetAction(autoResizeGroup);
  368     action->setText(i18nc("Video size", "50%"));
  369     action->setCheckable(true);
  370     action->setData(50);
  371     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
  372 
  373 
  374     action = new QWidgetAction(autoResizeGroup);
  375     action->setText(i18nc("Video size", "75%"));
  376     action->setCheckable(true);
  377     action->setData(75);
  378 
  379     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
  380     action = new QWidgetAction(autoResizeGroup);
  381     action->setText(i18nc("Video size", "Original Size"));
  382     action->setCheckable(true);
  383     action->setData(100);
  384     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_original"), action));
  385 
  386     action = new QWidgetAction(autoResizeGroup);
  387     action->setText(i18nc("Video size", "150%"));
  388     action->setCheckable(true);
  389     action->setData(150);
  390     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
  391 
  392     action = new QWidgetAction(autoResizeGroup);
  393     action->setText(i18nc("Video size", "200%"));
  394     action->setCheckable(true);
  395     action->setData(200);
  396     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
  397 
  398     action = new QWidgetAction(autoResizeGroup);
  399     action->setText(i18nc("Video size", "250%"));
  400     action->setCheckable(true);
  401     action->setData(250);
  402     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
  403 
  404     action = new QWidgetAction(autoResizeGroup);
  405     action->setText(i18nc("Video size", "300%"));
  406     action->setCheckable(true);
  407     action->setData(300);
  408     autoResizeMenu->addAction(collection->addAction(QLatin1String("controls_autoresize_double"), action));
  409 
  410     autoResizeFactor =
  411         KSharedConfig::openConfig()->group("MediaObject").readEntry("AutoResizeFactor", 0);
  412 
  413     if (autoResizeFactor <= 300) {
  414         for (int i = 0; i < autoResizeGroup->actions().size(); i++) {
  415             if (autoResizeGroup->actions().at(i)->data().toInt() == autoResizeFactor) {
  416                 autoResizeGroup->actions().at(i)->setChecked(true);
  417                 break;
  418             }
  419         }
  420     } else {
  421         autoResizeGroup->actions().at(0)->setChecked(true);
  422     }
  423     setVideoSize();
  424 
  425     videoMenu->addMenu(autoResizeMenu);
  426 
  427     action = new QWidgetAction(this);
  428     action->setText(i18n("Volume Slider"));
  429     volumeSlider = new QSlider(toolBar);
  430     volumeSlider->setFocusPolicy(Qt::NoFocus);
  431     volumeSlider->setOrientation(Qt::Horizontal);
  432     volumeSlider->setRange(0, 100);
  433     volumeSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
  434     volumeSlider->setToolTip(action->text());
  435     volumeSlider->setValue(KSharedConfig::openConfig()->group("MediaObject").readEntry("Volume", 100));
  436     connect(volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(volumeChanged(int)));
  437     backend->setVolume(volumeSlider->value());
  438     action->setDefaultWidget(volumeSlider);
  439     toolBar->addAction(collection->addAction(QLatin1String("controls_volume_slider"), action));
  440 
  441     jumpToPositionAction = new QWidgetAction(this);
  442     jumpToPositionAction->setIcon(QIcon::fromTheme(QLatin1String("go-jump"), QIcon(":go-jump")));
  443     jumpToPositionAction->setText(i18nc("@action:inmenu", "Jump to Position..."));
  444     jumpToPositionAction->setShortcut(Qt::CTRL + Qt::Key_J);
  445     connect(jumpToPositionAction, SIGNAL(triggered()), this, SLOT(jumpToPosition()));
  446     menu->addAction(collection->addAction(QLatin1String("controls_jump_to_position"), jumpToPositionAction));
  447 
  448     navigationMenu = new QMenu(i18nc("playback menu", "Skip"), this);
  449     menu->addMenu(navigationMenu);
  450     menu->addSeparator();
  451 
  452     int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
  453     int longSkipDuration = Configuration::instance()->getLongSkipDuration();
  454     connect(Configuration::instance(), SIGNAL(shortSkipDurationChanged(int)),
  455         this, SLOT(shortSkipDurationChanged(int)));
  456     connect(Configuration::instance(), SIGNAL(longSkipDurationChanged(int)),
  457         this, SLOT(longSkipDurationChanged(int)));
  458 
  459     longSkipBackwardAction = new QWidgetAction(this);
  460     longSkipBackwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
  461     // xgettext:no-c-format
  462     longSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward", longSkipDuration));
  463     longSkipBackwardAction->setShortcut(Qt::SHIFT + Qt::Key_Left);
  464     connect(longSkipBackwardAction, SIGNAL(triggered()), this, SLOT(longSkipBackward()));
  465     navigationMenu->addAction(
  466         collection->addAction(QLatin1String("controls_long_skip_backward"), longSkipBackwardAction));
  467 
  468     shortSkipBackwardAction = new QWidgetAction(this);
  469     shortSkipBackwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-backward"), QIcon(":media-skip-backward")));
  470     // xgettext:no-c-format
  471     shortSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward", shortSkipDuration));
  472     shortSkipBackwardAction->setShortcut(Qt::Key_Left);
  473     connect(shortSkipBackwardAction, SIGNAL(triggered()), this, SLOT(shortSkipBackward()));
  474     navigationMenu->addAction(
  475         collection->addAction(QLatin1String("controls_skip_backward"), shortSkipBackwardAction));
  476 
  477     shortSkipForwardAction = new QWidgetAction(this);
  478     shortSkipForwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
  479     // xgettext:no-c-format
  480     shortSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward", shortSkipDuration));
  481     shortSkipForwardAction->setShortcut(Qt::Key_Right);
  482     connect(shortSkipForwardAction, SIGNAL(triggered()), this, SLOT(shortSkipForward()));
  483     navigationMenu->addAction(
  484         collection->addAction(QLatin1String("controls_skip_forward"), shortSkipForwardAction));
  485 
  486     longSkipForwardAction = new QWidgetAction(this);
  487     longSkipForwardAction->setIcon(QIcon::fromTheme(QLatin1String("media-skip-forward"), QIcon(":media-skip-forward")));
  488     // xgettext:no-c-format
  489     longSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward", longSkipDuration));
  490     longSkipForwardAction->setShortcut(Qt::SHIFT + Qt::Key_Right);
  491     connect(longSkipForwardAction, SIGNAL(triggered()), this, SLOT(longSkipForward()));
  492     navigationMenu->addAction(
  493         collection->addAction(QLatin1String("controls_long_skip_forward"), longSkipForwardAction));
  494 
  495     toolBar->addAction(QIcon::fromTheme(QLatin1String("player-time"), QIcon(":player-time")), i18n("Seek Slider"))->setEnabled(false);
  496 
  497     action = new QWidgetAction(this);
  498     action->setText(i18n("Seek Slider"));
  499     seekSlider = new SeekSlider(toolBar);
  500     seekSlider->setFocusPolicy(Qt::NoFocus);
  501     seekSlider->setOrientation(Qt::Horizontal);
  502     seekSlider->setToolTip(action->text());
  503     connect(seekSlider, SIGNAL(valueChanged(int)), this, SLOT(seek(int)));
  504     action->setDefaultWidget(seekSlider);
  505     toolBar->addAction(collection->addAction(QLatin1String("controls_position_slider"), action));
  506 
  507     menuAction = new QWidgetAction(this);
  508     menuAction->setIcon(QIcon::fromTheme(QLatin1String("media-optical-video"), QIcon(":media-optical-video")));
  509     menuAction->setText(i18nc("dvd navigation", "DVD Menu"));
  510     connect(menuAction, SIGNAL(triggered()), this, SLOT(toggleMenu()));
  511     menu->addAction(collection->addAction(QLatin1String("controls_toggle_menu"), menuAction));
  512 
  513     titleMenu = new QMenu(i18nc("dvd navigation", "Title"), this);
  514     titleGroup = new QActionGroup(this);
  515     connect(titleGroup, SIGNAL(triggered(QAction*)),
  516         this, SLOT(currentTitleChanged(QAction*)));
  517     menu->addMenu(titleMenu);
  518 
  519     chapterMenu = new QMenu(i18nc("dvd navigation", "Chapter"), this);
  520     chapterGroup = new QActionGroup(this);
  521     connect(chapterGroup, SIGNAL(triggered(QAction*)),
  522         this, SLOT(currentChapterChanged(QAction*)));
  523     menu->addMenu(chapterMenu);
  524 
  525     angleMenu = new QMenu(i18nc("dvd navigation", "Angle"), this);
  526     angleGroup = new QActionGroup(this);
  527     connect(angleGroup, SIGNAL(triggered(QAction*)), this,
  528         SLOT(currentAngleChanged(QAction*)));
  529     menu->addMenu(angleMenu);
  530 
  531     action = new QWidgetAction(this);
  532     action->setText(i18n("Switch between elapsed and remaining time display"));
  533     timeButton = new QPushButton(toolBar);
  534     timeButton->setFocusPolicy(Qt::NoFocus);
  535     timeButton->setToolTip(action->text());
  536     connect(timeButton, SIGNAL(clicked(bool)), this, SLOT(timeButtonClicked()));
  537     action->setDefaultWidget(timeButton);
  538     toolBar->addAction(collection->addAction(QLatin1String("controls_time_button"), action));
  539 
  540     QTimer *timer = new QTimer(this);
  541     timer->start(50000);
  542     connect(timer, SIGNAL(timeout()), this, SLOT(checkScreenSaver()));
  543 
  544     // Set the play/pause icons accordingly
  545     playbackStatusChanged();
  546 }
  547 
  548 MediaWidget::~MediaWidget()
  549 {
  550     KSharedConfig::openConfig()->group("MediaObject").writeEntry("Volume", volumeSlider->value());
  551     KSharedConfig::openConfig()->group("MediaObject").writeEntry("Deinterlace", deinterlaceMode);
  552     KSharedConfig::openConfig()->group("MediaObject").writeEntry("AutoResizeFactor", autoResizeFactor);
  553 }
  554 
  555 QString MediaWidget::extensionFilter()
  556 {
  557     return i18n(
  558         "Supported Media Files ("
  559         // generated from kaffeine.desktop's mime types
  560         "*.3ga *.3gp *.3gpp *.669 *.ac3 *.aif *.aiff *.anim1 *.anim2 *.anim3 *.anim4 "
  561         "*.anim5 *.anim6 *.anim7 *.anim8 *.anim9 *.animj *.asf *.asx *.au *.avf *.avi "
  562         "*.bdm *.bdmv *.clpi *.cpi *.divx *.dv *.f4a *.f4b *.f4v *.flac *.flc *.fli *.flv "
  563         "*.it *.lrv *.m15 *.m2t *.m2ts *.m3u *.m3u8 *.m4a *.m4b *.m4v *.med *.mka *.mkv "
  564         "*.mng *.mod *.moov *.mov *.mp+ *.mp2 *.mp3 *.mp4 *.mpc *.mpe *.mpeg *.mpg *.mpga "
  565         "*.mpl *.mpls *.mpp *.mtm *.mts *.nsv *.oga *.ogg *.ogm *.ogv *.ogx *.opus *.pls "
  566         "*.qt *.qtl *.qtvr *.ra *.ram *.rax *.rm *.rmj *.rmm *.rms *.rmvb *.rmx *.rp *.rv "
  567         "*.rvx *.s3m *.shn *.snd *.spl *.stm *.swf *.ts *.tta *.ult *.uni *.vdr *.vlc "
  568         "*.vob *.voc *.wav *.wax *.webm *.wma *.wmv *.wmx *.wv *.wvp *.wvx *.xm *.xspf "
  569         // manual entries
  570         "*.kaffeine *.iso);;"
  571         "All Files (*)");
  572 }
  573 
  574 MediaWidget::DisplayMode MediaWidget::getDisplayMode() const
  575 {
  576     return displayMode;
  577 }
  578 
  579 void MediaWidget::setDisplayMode(DisplayMode displayMode_)
  580 {
  581     if (displayMode != displayMode_) {
  582         displayMode = displayMode_;
  583 
  584         switch (displayMode) {
  585         case NormalMode:
  586         case MinimalMode:
  587             fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
  588             fullScreenAction->setText(i18nc("'Playback' menu", "Full Screen Mode"));
  589             break;
  590         case FullScreenMode:
  591         case FullScreenReturnToMinimalMode:
  592             fullScreenAction->setIcon(QIcon::fromTheme(QLatin1String("view-restore"), QIcon(":view-restore")));
  593             fullScreenAction->setText(i18nc("'Playback' menu",
  594                 "Exit Full Screen Mode"));
  595             break;
  596         }
  597 
  598         switch (displayMode) {
  599         case NormalMode:
  600         case FullScreenMode:
  601         case FullScreenReturnToMinimalMode:
  602             minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-restore"), QIcon(":view-restore")));
  603             minimalModeAction->setText(i18nc("'Playback' menu", "Minimal Mode"));
  604             break;
  605         case MinimalMode:
  606             minimalModeAction->setIcon(QIcon::fromTheme(QLatin1String("view-fullscreen"), QIcon(":view-fullscreen")));
  607             minimalModeAction->setText(i18nc("'Playback' menu", "Exit Minimal Mode"));
  608             break;
  609         }
  610 
  611         emit displayModeChanged();
  612     }
  613 }
  614 
  615 void MediaWidget::play(MediaSource *source_)
  616 {
  617     if (source != source_) {
  618         source->playbackStatusChanged(Idle);
  619         source = source_;
  620 
  621         if (source == NULL) {
  622             source = dummySource.data();
  623         }
  624     }
  625 
  626     source->setMediaWidget(this);
  627     backend->play(*source);
  628 }
  629 
  630 void MediaWidget::mediaSourceDestroyed(MediaSource *mediaSource)
  631 {
  632     if (source == mediaSource) {
  633         source = dummySource.data();
  634     }
  635 }
  636 
  637 void MediaWidget::openSubtitle()
  638 {
  639     QString fname = QFileDialog::getOpenFileName(this,
  640             i18nc("@title:window", "Open subtitle"),".",
  641             i18n("Subtitles (*.cdg *.idx *.srt " \
  642                     "*.sub *.utf *.ass " \
  643                     "*.ssa *.aqt " \
  644                     "*.jss *.psb " \
  645                     "*.rt *.smi *.txt " \
  646                     "*.smil *.stl *.usf " \
  647                     "*.dks *.pjs *.mpl2 *.mks " \
  648                     "*.vtt *.ttml *.dfxp"));
  649 
  650     setSubtitle(QUrl::fromLocalFile(fname));
  651 }
  652 
  653 void MediaWidget::setSubtitle(QUrl url)
  654 {
  655     if (!url.isValid()) {
  656         return;
  657     }
  658 
  659     backend->setExternalSubtitle(url);
  660 }
  661 
  662 void MediaWidget::play(const QUrl &url, const QUrl &subtitleUrl)
  663 {
  664     // FIXME mem-leak
  665     play(new MediaSourceUrl(url, subtitleUrl));
  666 }
  667 
  668 void MediaWidget::playAudioCd(const QString &device)
  669 {
  670     QUrl devicePath;
  671 
  672     if (!device.isEmpty()) {
  673         devicePath = QUrl::fromLocalFile(device);
  674     } else {
  675         QList<Solid::Device> devices =
  676             Solid::Device::listFromQuery(QLatin1String("OpticalDisc.availableContent & 'Audio'"));
  677 
  678         if (!devices.isEmpty()) {
  679             Solid::Block *block = devices.first().as<Solid::Block>();
  680 
  681             if (block != NULL) {
  682                 devicePath = QUrl::fromLocalFile(block->device());
  683             }
  684         }
  685     }
  686 
  687     // FIXME mem-leak
  688     play(new MediaSourceAudioCd(devicePath));
  689 }
  690 
  691 void MediaWidget::playVideoCd(const QString &device)
  692 {
  693     QUrl devicePath;
  694 
  695     if (!device.isEmpty()) {
  696         devicePath = QUrl::fromLocalFile(device);
  697     } else {
  698         QList<Solid::Device> devices = Solid::Device::listFromQuery(
  699             QLatin1String("OpticalDisc.availableContent & 'VideoCd|SuperVideoCd'"));
  700 
  701         if (!devices.isEmpty()) {
  702             Solid::Block *block = devices.first().as<Solid::Block>();
  703 
  704             if (block != NULL) {
  705                 devicePath = QUrl::fromLocalFile(block->device());
  706             }
  707         }
  708     }
  709 
  710     // FIXME mem-leak
  711     play(new MediaSourceVideoCd(devicePath));
  712 }
  713 
  714 void MediaWidget::playDvd(const QString &device)
  715 {
  716     QUrl devicePath;
  717 
  718     if (!device.isEmpty()) {
  719         devicePath = QUrl::fromLocalFile(device);
  720     } else {
  721         QList<Solid::Device> devices =
  722             Solid::Device::listFromQuery(QLatin1String("OpticalDisc.availableContent & 'VideoDvd'"));
  723 
  724         if (!devices.isEmpty()) {
  725             Solid::Block *block = devices.first().as<Solid::Block>();
  726 
  727             if (block != NULL) {
  728                 devicePath = QUrl::fromLocalFile(block->device());
  729             }
  730         }
  731     }
  732 
  733     // FIXME mem-leak
  734     play(new MediaSourceDvd(devicePath));
  735 }
  736 
  737 OsdWidget *MediaWidget::getOsdWidget()
  738 {
  739     return osdWidget;
  740 }
  741 
  742 MediaWidget::PlaybackStatus MediaWidget::getPlaybackStatus() const
  743 {
  744     return backend->getPlaybackStatus();
  745 }
  746 
  747 int MediaWidget::getVolume() const
  748 {
  749     return volumeSlider->value();
  750 }
  751 
  752 int MediaWidget::getPosition() const
  753 {
  754     return backend->getCurrentTime();
  755 }
  756 
  757 void MediaWidget::play()
  758 {
  759     source->replay();
  760 }
  761 
  762 void MediaWidget::togglePause()
  763 {
  764     actionPlayPause->trigger();
  765 }
  766 
  767 void MediaWidget::setPosition(int position)
  768 {
  769     backend->seek(position);
  770 }
  771 
  772 void MediaWidget::setVolume(int volume)
  773 {
  774     // QSlider ensures that the value is within the range
  775     volumeSlider->setValue(volume);
  776 }
  777 
  778 void MediaWidget::setVolumeUnderMouse(int volume)
  779 {
  780     if (volume == 100 || !volume)
  781         osdWidget->showText(i18nc("osd", "Volume: %1%", volume), 1500);
  782     else
  783         setVolume(volume);
  784 }
  785 
  786 void MediaWidget::toggleMuted()
  787 {
  788     muteAction->trigger();
  789 }
  790 
  791 void MediaWidget::previous()
  792 {
  793     if (source->getType() == MediaSource::Url)
  794         emit playlistPrevious();
  795        source->previous();
  796 }
  797 
  798 void MediaWidget::next()
  799 {
  800     if (source->getType() == MediaSource::Url)
  801         emit playlistNext();
  802        source->next();
  803 }
  804 
  805 void MediaWidget::stop()
  806 {
  807     switch (backend->getPlaybackStatus()) {
  808     case Idle:
  809         break;
  810     case Playing:
  811     case Paused:
  812         osdWidget->showText(i18nc("osd", "Stopped"), 1500);
  813         break;
  814     }
  815 
  816     backend->stop();
  817     source->playbackStatusChanged(Idle);
  818 }
  819 
  820 void MediaWidget::setAudioCard()
  821 {
  822     QAction *action = qobject_cast<QAction *>(sender());
  823     backend->setAudioDevice(action->data().toString());
  824 }
  825 void MediaWidget::increaseVolume()
  826 {
  827     // QSlider ensures that the value is within the range
  828     volumeSlider->setValue(volumeSlider->value() + 5);
  829 }
  830 
  831 void MediaWidget::decreaseVolume()
  832 {
  833     // QSlider ensures that the value is within the range
  834     volumeSlider->setValue(volumeSlider->value() - 5);
  835 }
  836 
  837 void MediaWidget::checkScreenSaver()
  838 {
  839     bool suspendScreenSaver = false;
  840 
  841     switch (backend->getPlaybackStatus()) {
  842     case Idle:
  843     case Paused:
  844         break;
  845     case Playing:
  846         suspendScreenSaver = isVisible();
  847         break;
  848     }
  849 
  850     if (suspendScreenSaver) {
  851         // KDE - Inhibit doesn't inhibit "lock screen after inactivity"
  852         QDBusInterface(QLatin1String("org.freedesktop.ScreenSaver"), QLatin1String("/ScreenSaver"),
  853             QLatin1String("org.freedesktop.ScreenSaver")).call(QDBus::NoBlock,
  854             QLatin1String("SimulateUserActivity"));
  855 
  856         // GNOME - Inhibit doesn't inhibit power management functions
  857         QDBusInterface(QLatin1String("org.gnome.ScreenSaver"), QLatin1String("/"),
  858                    QLatin1String("org.gnome.ScreenSaver")).
  859             call(QDBus::NoBlock, QLatin1String("SimulateUserActivity"));
  860     }
  861 
  862     if (screenSaverSuspended != suspendScreenSaver) {
  863         // X11 - needed if none of the above applications is running
  864         screenSaverSuspended = suspendScreenSaver;
  865         XScreenSaverSuspend(QX11Info::display(), suspendScreenSaver);
  866     }
  867 }
  868 
  869 void MediaWidget::mutedChanged()
  870 {
  871     muted = !muted;
  872     backend->setMuted(muted);
  873 
  874     if (muted) {
  875         muteAction->setIcon(mutedIcon);
  876         osdWidget->showText(i18nc("osd", "Mute On"), 1500);
  877     } else {
  878         muteAction->setIcon(unmutedIcon);
  879         osdWidget->showText(i18nc("osd", "Mute Off"), 1500);
  880     }
  881 }
  882 
  883 void MediaWidget::volumeChanged(int volume)
  884 {
  885     backend->setVolume(volume);
  886     osdWidget->showText(i18nc("osd", "Volume: %1%", volume), 1500);
  887 }
  888 
  889 void MediaWidget::toggleFullScreen()
  890 {
  891     switch (displayMode) {
  892     case NormalMode:
  893         setDisplayMode(FullScreenMode);
  894         break;
  895     case FullScreenMode:
  896         setDisplayMode(NormalMode);
  897         break;
  898     case FullScreenReturnToMinimalMode:
  899         setDisplayMode(MinimalMode);
  900         break;
  901     case MinimalMode:
  902         setDisplayMode(FullScreenReturnToMinimalMode);
  903         break;
  904     }
  905 }
  906 
  907 void MediaWidget::toggleMinimalMode()
  908 {
  909     switch (displayMode) {
  910     case NormalMode:
  911     case FullScreenMode:
  912     case FullScreenReturnToMinimalMode:
  913         setDisplayMode(MinimalMode);
  914         break;
  915     case MinimalMode:
  916         setDisplayMode(NormalMode);
  917         break;
  918     }
  919 }
  920 
  921 void MediaWidget::seek(int position)
  922 {
  923     if (blockBackendUpdates) {
  924         return;
  925     }
  926 
  927     backend->seek(position);
  928 }
  929 
  930 void MediaWidget::deinterlacingChanged(QAction *action)
  931 {
  932     bool ok;
  933     const char *mode;
  934 
  935     deinterlaceMode = action->data().toInt(&ok);
  936 
  937     switch (deinterlaceMode) {
  938     case DeinterlaceDiscard:
  939         mode = "discard";
  940         break;
  941     case DeinterlaceBob:
  942         mode = "bob";
  943         break;
  944     case DeinterlaceLinear:
  945         mode = "linear";
  946         break;
  947     case DeinterlaceYadif:
  948         mode = "yadif";
  949         break;
  950     case DeinterlaceYadif2x:
  951         mode = "yadif2x";
  952         break;
  953     case DeinterlacePhosphor:
  954         mode = "phosphor";
  955         break;
  956     case DeinterlaceX:
  957         mode = "x";
  958         break;
  959     case DeinterlaceMean:
  960         mode = "mean";
  961         break;
  962     case DeinterlaceBlend:
  963         mode = "blend";
  964         break;
  965     case DeinterlaceIvtc:
  966         mode = "ivtc";
  967         break;
  968     case DeinterlaceDisabled:
  969     default:
  970         mode = "disabled";
  971     }
  972 
  973     backend->setDeinterlacing(static_cast<DeinterlaceMode>(deinterlaceMode));
  974 
  975     osdWidget->showText(i18nc("osd message", "Deinterlace %1", mode), 1500);
  976 }
  977 
  978 void MediaWidget::aspectRatioChanged(QAction *action)
  979 {
  980     bool ok;
  981     unsigned int aspectRatio_ = action->data().toInt(&ok);
  982 
  983     if (aspectRatio_ <= AspectRatio239_100) {
  984         backend->setAspectRatio(static_cast<AspectRatio>(aspectRatio_));
  985         setVideoSize();
  986 
  987         return;
  988     }
  989 
  990     qCWarning(logMediaWidget, "internal error");
  991 }
  992 
  993 
  994 void MediaWidget::setAspectRatio(MediaWidget::AspectRatio aspectRatio)
  995 {
  996     backend->setAspectRatio(aspectRatio);
  997 }
  998 
  999 
 1000 void MediaWidget::setVideoSize()
 1001 {
 1002     float scale = autoResizeFactor / 100.0;
 1003 
 1004     if (scale > 3.4 || scale < 0)
 1005         scale = 0;
 1006 
 1007     backend->resizeToVideo(scale);
 1008 }
 1009 
 1010 void MediaWidget::autoResizeTriggered(QAction *action)
 1011 {
 1012     foreach (QAction *autoResizeAction, action->actionGroup()->actions()) {
 1013         autoResizeAction->setChecked(autoResizeAction == action);
 1014     }
 1015 
 1016     bool ok = false;
 1017     autoResizeFactor = action->data().toInt(&ok);
 1018 
 1019     if (ok)
 1020         setVideoSize();
 1021     else
 1022         qCWarning(logMediaWidget, "internal error");
 1023 }
 1024 
 1025 void MediaWidget::pausedChanged(bool paused)
 1026 {
 1027     switch (backend->getPlaybackStatus()) {
 1028     case Idle:
 1029         source->replay();
 1030         break;
 1031     case Playing:
 1032     case Paused:
 1033         backend->setPaused(paused);
 1034         break;
 1035     }
 1036 }
 1037 
 1038 void MediaWidget::timeButtonClicked()
 1039 {
 1040     showElapsedTime = !showElapsedTime;
 1041     currentTotalTimeChanged();
 1042 }
 1043 
 1044 void MediaWidget::longSkipBackward()
 1045 {
 1046     int longSkipDuration = Configuration::instance()->getLongSkipDuration();
 1047     int currentTime = (backend->getCurrentTime() - 1000 * longSkipDuration);
 1048 
 1049     if (currentTime < 0) {
 1050         currentTime = 0;
 1051     }
 1052 
 1053     backend->seek(currentTime);
 1054 }
 1055 
 1056 void MediaWidget::shortSkipBackward()
 1057 {
 1058     int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
 1059     int currentTime = (backend->getCurrentTime() - 1000 * shortSkipDuration);
 1060 
 1061     if (currentTime < 0) {
 1062         currentTime = 0;
 1063     }
 1064 
 1065     backend->seek(currentTime);
 1066 }
 1067 
 1068 void MediaWidget::shortSkipForward()
 1069 {
 1070     int shortSkipDuration = Configuration::instance()->getShortSkipDuration();
 1071     backend->seek(backend->getCurrentTime() + 1000 * shortSkipDuration);
 1072 }
 1073 
 1074 void MediaWidget::longSkipForward()
 1075 {
 1076     int longSkipDuration = Configuration::instance()->getLongSkipDuration();
 1077     backend->seek(backend->getCurrentTime() + 1000 * longSkipDuration);
 1078 }
 1079 
 1080 void MediaWidget::jumpToPosition()
 1081 {
 1082     QDialog *dialog = new JumpToPositionDialog(this);
 1083     dialog->setAttribute(Qt::WA_DeleteOnClose, true);
 1084     dialog->setModal(true);
 1085     dialog->show();
 1086 }
 1087 
 1088 void MediaWidget::currentAudioStreamChanged(int currentAudioStream)
 1089 {
 1090     if (!blockBackendUpdates) {
 1091         if (source->overrideAudioStreams()) {
 1092             source->setCurrentAudioStream(currentAudioStream);
 1093             return;
 1094         }
 1095 
 1096         source->setCurrentAudioStream(currentAudioStream -
 1097             backend->getAudioStreams().size());
 1098 
 1099         if (currentAudioStream >= backend->getAudioStreams().size()) {
 1100             currentAudioStream = -1;
 1101         }
 1102 
 1103         if (backend->getCurrentAudioStream() != currentAudioStream) {
 1104             backend->setCurrentAudioStream(currentAudioStream);
 1105         }
 1106     }
 1107     audioStreamBox->view()->setMinimumWidth(audioStreamBox->view()->sizeHintForColumn(0));
 1108 
 1109 }
 1110 
 1111 void MediaWidget::currentSubtitleChanged(int currentSubtitle)
 1112 {
 1113     if (blockBackendUpdates)
 1114         return;
 1115 
 1116     if (source->overrideSubtitles()) {
 1117         source->setCurrentSubtitle(currentSubtitle - 1);
 1118         return;
 1119     }
 1120 
 1121     source->setCurrentSubtitle(currentSubtitle - 1 - backend->getSubtitles().size());
 1122 
 1123     backend->setCurrentSubtitle(currentSubtitle);
 1124 }
 1125 
 1126 void MediaWidget::toggleMenu()
 1127 {
 1128     backend->showDvdMenu();
 1129 }
 1130 
 1131 void MediaWidget::currentTitleChanged(QAction *action)
 1132 {
 1133     backend->setCurrentTitle(titleGroup->actions().indexOf(action) + 1);
 1134 }
 1135 
 1136 void MediaWidget::currentChapterChanged(QAction *action)
 1137 {
 1138     backend->setCurrentChapter(chapterGroup->actions().indexOf(action) + 1);
 1139 }
 1140 
 1141 void MediaWidget::currentAngleChanged(QAction *action)
 1142 {
 1143     backend->setCurrentAngle(angleGroup->actions().indexOf(action) + 1);
 1144 }
 1145 
 1146 void MediaWidget::shortSkipDurationChanged(int shortSkipDuration)
 1147 {
 1148         // xgettext:no-c-format
 1149     shortSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward",
 1150         shortSkipDuration));
 1151     // xgettext:no-c-format
 1152     shortSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward",
 1153         shortSkipDuration));
 1154 }
 1155 
 1156 void MediaWidget::longSkipDurationChanged(int longSkipDuration)
 1157 {
 1158         // xgettext:no-c-format
 1159     longSkipBackwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Backward",
 1160         longSkipDuration));
 1161     // xgettext:no-c-format
 1162     longSkipForwardAction->setText(i18nc("submenu of 'Skip'", "Skip %1s Forward",
 1163         longSkipDuration));
 1164 }
 1165 
 1166 void MediaWidget::getAudioDevices()
 1167 {
 1168     foreach(QAction *action, audioDevMenu->actions()) {
 1169         audioDevMenu->removeAction(action);
 1170     }
 1171 
 1172     foreach(const QString &device, backend->getAudioDevices()) {
 1173         QAction *action = new QWidgetAction(this);
 1174         action->setText(device);
 1175         action->setData(device);
 1176         connect(action, SIGNAL(triggered()), this, SLOT(setAudioCard()));
 1177         audioDevMenu->addAction(action);
 1178     }
 1179 }
 1180 
 1181 void MediaWidget::audioStreamsChanged()
 1182 {
 1183     QStringList items;
 1184     int currentIndex;
 1185 
 1186     if (source->overrideAudioStreams()) {
 1187         items = source->getAudioStreams();
 1188         currentIndex = source->getCurrentAudioStream();
 1189     } else {
 1190         items = backend->getAudioStreams();
 1191         currentIndex = backend->getCurrentAudioStream();
 1192     }
 1193 
 1194     blockBackendUpdates = true;
 1195 
 1196     if (audioStreamModel->stringList() != items) {
 1197         audioStreamModel->setStringList(items);
 1198     }
 1199 
 1200     audioStreamBox->setCurrentIndex(currentIndex);
 1201     audioStreamBox->setEnabled(items.size() > 1);
 1202     blockBackendUpdates = false;
 1203 }
 1204 
 1205 void MediaWidget::subtitlesChanged()
 1206 {
 1207     QStringList items(textSubtitlesOff);
 1208     int currentIndex = 0;
 1209 
 1210     if (source->overrideSubtitles()) {
 1211         items += source->getSubtitles();
 1212         currentIndex = (source->getCurrentSubtitle() + 1);
 1213 
 1214         // automatically choose appropriate subtitle
 1215         int selectedSubtitle = -1;
 1216 
 1217         if (currentIndex > 0) {
 1218             selectedSubtitle = (backend->getSubtitles().size() - 1);
 1219         }
 1220 
 1221         if (backend->getCurrentSubtitle() != selectedSubtitle) {
 1222             backend->setCurrentSubtitle(selectedSubtitle);
 1223         }
 1224     } else {
 1225         items += backend->getSubtitles();
 1226         items += source->getSubtitles();
 1227         currentIndex = (backend->getCurrentSubtitle());
 1228         int currentSourceIndex = source->getCurrentSubtitle();
 1229 
 1230         if (currentSourceIndex >= 0) {
 1231             currentIndex = (currentSourceIndex + backend->getSubtitles().size() + 1);
 1232         }
 1233     }
 1234 
 1235     blockBackendUpdates = true;
 1236 
 1237     if (subtitleModel->stringList() != items) {
 1238         subtitleModel->setStringList(items);
 1239     }
 1240 
 1241     if (currentIndex < 0)
 1242         currentIndex = 0;
 1243 
 1244     subtitleBox->setCurrentIndex(currentIndex);
 1245     subtitleBox->setEnabled(items.size() > 1);
 1246     blockBackendUpdates = false;
 1247 }
 1248 
 1249 void MediaWidget::currentTotalTimeChanged()
 1250 {
 1251     int currentTime = backend->getCurrentTime();
 1252     int totalTime = backend->getTotalTime();
 1253     source->trackLengthChanged(totalTime);
 1254 
 1255     if (source->getType() == MediaSource::Url)
 1256         emit playlistTrackLengthChanged(totalTime);
 1257 
 1258     // If the player backend doesn't implement currentTime and/or
 1259     // totalTime, the source can implement such logic
 1260     source->validateCurrentTotalTime(currentTime, totalTime);
 1261 
 1262     blockBackendUpdates = true;
 1263     seekSlider->setRange(0, totalTime);
 1264     seekSlider->setValue(currentTime);
 1265 
 1266     if (showElapsedTime) {
 1267         timeButton->setText(QLatin1Char(' ') + QTime(0, 0).addMSecs(currentTime).toString());
 1268     } else {
 1269         int remainingTime = (totalTime - currentTime);
 1270         timeButton->setText(QLatin1Char('-') + QTime(0, 0).addMSecs(remainingTime).toString());
 1271     }
 1272 
 1273     blockBackendUpdates = false;
 1274 }
 1275 
 1276 void MediaWidget::seekableChanged()
 1277 {
 1278     bool seekable = (backend->isSeekable() && !source->hideCurrentTotalTime());
 1279     seekSlider->setEnabled(seekable);
 1280     navigationMenu->setEnabled(seekable);
 1281     jumpToPositionAction->setEnabled(seekable);
 1282     timeButton->setEnabled(seekable);
 1283 }
 1284 
 1285 void MediaWidget::contextMenuEvent(QContextMenuEvent *event)
 1286 {
 1287     menu->popup(event->globalPos());
 1288 }
 1289 
 1290 void MediaWidget::mouseDoubleClickEvent(QMouseEvent *event)
 1291 {
 1292     Q_UNUSED(event)
 1293     emit toggleFullScreen();
 1294 }
 1295 
 1296 void MediaWidget::dragEnterEvent(QDragEnterEvent *event)
 1297 {
 1298     if (event->mimeData()->hasUrls()) {
 1299         event->acceptProposedAction();
 1300     }
 1301 }
 1302 
 1303 void MediaWidget::dropEvent(QDropEvent *event)
 1304 {
 1305     const QMimeData *mimeData = event->mimeData();
 1306 
 1307     if (mimeData->hasUrls()) {
 1308         emit playlistUrlsDropped(mimeData->urls());
 1309         event->acceptProposedAction();
 1310     }
 1311 }
 1312 
 1313 bool MediaWidget::event(QEvent *event)
 1314 {
 1315     switch (event->type()) {
 1316     case QEvent::ShortcutOverride:
 1317         {
 1318         QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
 1319         int key = keyEvent->key();
 1320 
 1321         if (backend->hasDvdMenu()) {
 1322             switch (key){
 1323             case Qt::Key_Return:
 1324             case Qt::Key_Up:
 1325             case Qt::Key_Down:
 1326             case Qt::Key_Left:
 1327             case Qt::Key_Right:
 1328                 backend->dvdNavigate(key);
 1329                 event->accept();
 1330                 return true;
 1331             }
 1332         }
 1333         break;
 1334         }
 1335     default:
 1336         break;
 1337     }
 1338 
 1339     return QWidget::event(event);
 1340 }
 1341 
 1342 void MediaWidget::keyPressEvent(QKeyEvent *event)
 1343 {
 1344     int key = event->key();
 1345 
 1346     if ((key >= Qt::Key_0) && (key <= Qt::Key_9)) {
 1347         event->accept();
 1348         emit osdKeyPressed(key);
 1349     } else {
 1350         QWidget::keyPressEvent(event);
 1351     }
 1352 }
 1353 
 1354 void MediaWidget::resizeEvent(QResizeEvent *event)
 1355 {
 1356     osdWidget->resize(event->size());
 1357     QWidget::resizeEvent(event);
 1358 }
 1359 
 1360 void MediaWidget::wheelEvent(QWheelEvent *event)
 1361 {
 1362     int y = event->delta();
 1363     int delta = (y < 0) ? -1 : 1;
 1364 
 1365     setVolumeUnderMouse(getVolume() + delta);
 1366 }
 1367 
 1368 void MediaWidget::playbackFinished()
 1369 {
 1370     if (source->getType() == MediaSource::Url)
 1371         emit playlistNext();
 1372 
 1373     source->playbackFinished();
 1374 }
 1375 
 1376 void MediaWidget::playbackStatusChanged()
 1377 {
 1378     source->playbackStatusChanged(backend->getPlaybackStatus());
 1379     bool playing = true;
 1380 
 1381     switch (backend->getPlaybackStatus()) {
 1382     case Idle:
 1383         actionPlayPause->setIcon(iconPlay);
 1384         actionPlayPause->setText(textPlay);
 1385         playing = false;
 1386         break;
 1387     case Playing:
 1388         actionPlayPause->setIcon(iconPause);
 1389         actionPlayPause->setText(textPause);
 1390         osdWidget->showText(i18nc("osd", "Playing"), 1500);
 1391         break;
 1392     case Paused:
 1393         actionPlayPause->setIcon(iconPlay);
 1394         actionPlayPause->setText(textPlay);
 1395         osdWidget->showText(i18nc("osd", "Paused"), 1500);
 1396         break;
 1397     }
 1398 
 1399     actionPlayPause->setCheckable(playing);
 1400     actionPrevious->setEnabled(playing);
 1401     actionStop->setEnabled(playing);
 1402     actionNext->setEnabled(playing);
 1403     timeButton->setEnabled(playing);
 1404 }
 1405 
 1406 void MediaWidget::metadataChanged()
 1407 {
 1408     QMap<MediaWidget::MetadataType, QString> metadata = backend->getMetadata();
 1409     source->metadataChanged(metadata);
 1410 
 1411     if (source->getType() == MediaSource::Url)
 1412         emit playlistTrackMetadataChanged(metadata);
 1413 
 1414     if (source->overrideCaption()) {
 1415         emit changeCaption(source->getDefaultCaption());
 1416         return;
 1417     }
 1418 
 1419     QString caption = metadata.value(Title);
 1420     QString artist = metadata.value(Artist);
 1421 
 1422     if (!caption.isEmpty() && !artist.isEmpty()) {
 1423         caption += QLatin1Char(' ');
 1424     }
 1425 
 1426     if (!artist.isEmpty()) {
 1427         caption += QLatin1Char('(');
 1428         caption += artist;
 1429         caption += QLatin1Char(')');
 1430     }
 1431 
 1432     if (caption.isEmpty()) {
 1433         caption = source->getDefaultCaption();
 1434     }
 1435 
 1436     QString osdText = caption;
 1437     if (backend->hasDvdMenu())
 1438         osdText += "\nUse keys to navigate at DVD menu";
 1439 
 1440     if (!caption.isEmpty()) {
 1441         osdWidget->showText(osdText, 2500);
 1442     }
 1443 
 1444     emit changeCaption(caption);
 1445 }
 1446 
 1447 void MediaWidget::dvdMenuChanged()
 1448 {
 1449     bool hasDvdMenu = backend->hasDvdMenu();
 1450 
 1451     menuAction->setEnabled(hasDvdMenu);
 1452 }
 1453 
 1454 void MediaWidget::titlesChanged()
 1455 {
 1456     int titleCount = backend->getTitleCount();
 1457     int currentTitle = backend->getCurrentTitle();
 1458 
 1459     if (titleCount > 1) {
 1460         QList<QAction *> actions = titleGroup->actions();
 1461 
 1462         if (actions.count() < titleCount) {
 1463             int i = actions.count();
 1464             actions.clear();
 1465 
 1466             for (; i < titleCount; ++i) {
 1467                 QAction *action = titleGroup->addAction(QString::number(i + 1));
 1468                 action->setCheckable(true);
 1469                 titleMenu->addAction(action);
 1470             }
 1471 
 1472             actions = titleGroup->actions();
 1473         }
 1474 
 1475         for (int i = 0; i < actions.size(); ++i) {
 1476             actions.at(i)->setVisible(i < titleCount);
 1477         }
 1478 
 1479         if ((currentTitle >= 1) && (currentTitle <= titleGroup->actions().count())) {
 1480             titleGroup->actions().at(currentTitle - 1)->setChecked(true);
 1481         } else if (titleGroup->checkedAction() != NULL) {
 1482             titleGroup->checkedAction()->setChecked(false);
 1483         }
 1484 
 1485         titleMenu->setEnabled(true);
 1486     } else {
 1487         titleMenu->setEnabled(false);
 1488     }
 1489 }
 1490 
 1491 void MediaWidget::chaptersChanged()
 1492 {
 1493     int chapterCount = backend->getChapterCount();
 1494     int currentChapter = backend->getCurrentChapter();
 1495 
 1496     if (chapterCount > 1) {
 1497         QList<QAction *> actions = chapterGroup->actions();
 1498 
 1499         if (actions.count() < chapterCount) {
 1500             int i = actions.count();
 1501             actions.clear();
 1502 
 1503             for (; i < chapterCount; ++i) {
 1504                 QAction *action = chapterGroup->addAction(QString::number(i + 1));
 1505                 action->setCheckable(true);
 1506                 chapterMenu->addAction(action);
 1507             }
 1508 
 1509             actions = chapterGroup->actions();
 1510         }
 1511 
 1512         for (int i = 0; i < actions.size(); ++i) {
 1513             actions.at(i)->setVisible(i < chapterCount);
 1514         }
 1515 
 1516         if ((currentChapter >= 1) && (currentChapter <= chapterGroup->actions().count())) {
 1517             chapterGroup->actions().at(currentChapter - 1)->setChecked(true);
 1518         } else if (chapterGroup->checkedAction() != NULL) {
 1519             chapterGroup->checkedAction()->setChecked(false);
 1520         }
 1521 
 1522         chapterMenu->setEnabled(true);
 1523     } else {
 1524         chapterMenu->setEnabled(false);
 1525     }
 1526 }
 1527 
 1528 void MediaWidget::anglesChanged()
 1529 {
 1530     int angleCount = backend->getAngleCount();
 1531     int currentAngle = backend->getCurrentAngle();
 1532 
 1533     if (angleCount > 1) {
 1534         QList<QAction *> actions = angleGroup->actions();
 1535 
 1536         if (actions.count() < angleCount) {
 1537             int i = actions.count();
 1538             actions.clear();
 1539 
 1540             for (; i < angleCount; ++i) {
 1541                 QAction *action = angleGroup->addAction(QString::number(i + 1));
 1542                 action->setCheckable(true);
 1543                 angleMenu->addAction(action);
 1544             }
 1545 
 1546             actions = angleGroup->actions();
 1547         }
 1548 
 1549         for (int i = 0; i < actions.size(); ++i) {
 1550             actions.at(i)->setVisible(i < angleCount);
 1551         }
 1552 
 1553         if ((currentAngle >= 1) && (currentAngle <= angleGroup->actions().count())) {
 1554             angleGroup->actions().at(currentAngle - 1)->setChecked(true);
 1555         } else if (angleGroup->checkedAction() != NULL) {
 1556             angleGroup->checkedAction()->setChecked(false);
 1557         }
 1558 
 1559         angleMenu->setEnabled(true);
 1560     } else {
 1561         angleMenu->setEnabled(false);
 1562     }
 1563 }
 1564 
 1565 void MediaWidget::videoSizeChanged()
 1566 {
 1567     setVideoSize();
 1568 }
 1569 
 1570 JumpToPositionDialog::JumpToPositionDialog(MediaWidget *mediaWidget_) : QDialog(mediaWidget_),
 1571     mediaWidget(mediaWidget_)
 1572 {
 1573     setWindowTitle(i18nc("@title:window", "Jump to Position"));
 1574 
 1575     QWidget *widget = new QWidget(this);
 1576     QBoxLayout *layout = new QVBoxLayout(widget);
 1577 
 1578     layout->addWidget(new QLabel(i18n("Enter a position:")));
 1579 
 1580     timeEdit = new QTimeEdit(this);
 1581     timeEdit->setDisplayFormat(QLatin1String("hh:mm:ss"));
 1582     timeEdit->setTime(QTime().addMSecs(mediaWidget->getPosition()));
 1583     layout->addWidget(timeEdit);
 1584 
 1585     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
 1586 
 1587     timeEdit->setFocus();
 1588 
 1589     QVBoxLayout *mainLayout = new QVBoxLayout;
 1590     setLayout(mainLayout);
 1591     mainLayout->addWidget(widget);
 1592     mainLayout->addWidget(buttonBox);
 1593     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
 1594 }
 1595 
 1596 JumpToPositionDialog::~JumpToPositionDialog()
 1597 {
 1598 }
 1599 
 1600 void JumpToPositionDialog::accept()
 1601 {
 1602     mediaWidget->setPosition(QTime(0, 0, 0).msecsTo(timeEdit->time()));
 1603     QDialog::accept();
 1604 }
 1605 
 1606 void SeekSlider::mousePressEvent(QMouseEvent *event)
 1607 {
 1608     int buttons = style()->styleHint(QStyle::SH_Slider_AbsoluteSetButtons);
 1609     Qt::MouseButton button = static_cast<Qt::MouseButton>(buttons & (~(buttons - 1)));
 1610     QMouseEvent modifiedEvent(event->type(), event->pos(), event->globalPos(), button,
 1611         event->buttons() ^ event->button() ^ button, event->modifiers());
 1612     QSlider::mousePressEvent(&modifiedEvent);
 1613 }
 1614 
 1615 void SeekSlider::wheelEvent(QWheelEvent *event)
 1616 {
 1617     int delta = (event->delta() < 0) ? -1 : 1;
 1618     int new_value = value() + delta * maximum() / 100;
 1619 
 1620     event->accept();
 1621     setValue(new_value);
 1622 }