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 }