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

0001 /*
0002  * mainwindow.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 <KAboutData>
0024 #include <KActionCollection>
0025 #include <KConfigGroup>
0026 #include <KHelpMenu>
0027 #include <kio/deletejob.h>
0028 #include <KRecentFilesAction>
0029 #include <KSharedConfig>
0030 #include <KShortcutsDialog>
0031 #include <QApplication>
0032 #include <QCommandLineOption>
0033 #include <QDBusConnection>
0034 #include <QDesktopWidget>
0035 #include <QFileDialog>
0036 #include <QHoverEvent>
0037 #include <QInputDialog>
0038 #include <QLoggingCategory>
0039 #include <QMainWindow>
0040 #include <QMenu>
0041 #include <QMenuBar>
0042 #include <QSettings>
0043 #include <QStackedLayout>
0044 #include <QTabBar>
0045 #include <QToolBar>
0046 
0047 #include "configuration.h"
0048 #include "configurationdialog.h"
0049 #include "dbusobjects.h"
0050 #include "dvb/dvbtab.h"
0051 #include "mainwindow.h"
0052 #include "playlist/playlisttab.h"
0053 
0054 // log categories. Should match log.h
0055 
0056 Q_LOGGING_CATEGORY(logCam, "kaffeine.cam")
0057 Q_LOGGING_CATEGORY(logDev, "kaffeine.dev")
0058 Q_LOGGING_CATEGORY(logDvb, "kaffeine.dvb")
0059 Q_LOGGING_CATEGORY(logDvbSi, "kaffeine.dvbsi")
0060 Q_LOGGING_CATEGORY(logEpg, "kaffeine.epg")
0061 
0062 Q_LOGGING_CATEGORY(logConfig, "kaffeine.config")
0063 Q_LOGGING_CATEGORY(logMediaWidget, "kaffeine.mediawidget")
0064 Q_LOGGING_CATEGORY(logPlaylist, "kaffeine.playlist")
0065 Q_LOGGING_CATEGORY(logSql, "kaffeine.sql")
0066 Q_LOGGING_CATEGORY(logVlc, "kaffeine.vlc")
0067 
0068 #define FILTER_RULE "kaffeine.*.debug=true"
0069 
0070 #define CATEGORIES "cam, dev, dvb, dvbsi, epg, config, mediawidget, playlist, sql, vlc"
0071 
0072 class StackedLayout : public QStackedLayout
0073 {
0074 public:
0075     explicit StackedLayout(QWidget *parent) : QStackedLayout(parent) { }
0076     ~StackedLayout() { }
0077 
0078     QSize minimumSize() const override
0079     {
0080         QWidget *widget = currentWidget();
0081 
0082         if (widget != NULL) {
0083             return widget->minimumSizeHint();
0084         }
0085 
0086         return QSize();
0087     }
0088 };
0089 
0090 class StartTab : public TabBase
0091 {
0092 public:
0093     explicit StartTab(MainWindow *mainWindow);
0094     ~StartTab() { }
0095 
0096 private:
0097     void activate() override { }
0098 
0099     QAbstractButton *addShortcut(const QString &name, const QIcon &icon, QWidget *parent);
0100 };
0101 
0102 StartTab::StartTab(MainWindow *mainWindow)
0103 {
0104     setBackgroundRole(QPalette::Base);
0105     setAutoFillBackground(true);
0106 
0107     QGridLayout *gridLayout = new QGridLayout(this);
0108     gridLayout->setAlignment(Qt::AlignCenter);
0109     gridLayout->setMargin(10);
0110     gridLayout->setSpacing(15);
0111 
0112     QAbstractButton *button =
0113         addShortcut(i18n("&1 Play File"), QIcon::fromTheme(QLatin1String("video-x-generic"), QIcon(":video-x-generic")), this);
0114     button->setShortcut(Qt::Key_1);
0115     button->setWhatsThis(i18n("Open dialog to play a file"));
0116     connect(button, SIGNAL(clicked()), mainWindow, SLOT(open()));
0117     gridLayout->addWidget(button, 0, 0);
0118 
0119     button = addShortcut(i18n("&2 Play Audio CD"), QIcon::fromTheme(QLatin1String("media-optical-audio"), QIcon(":media-optical-audio")), this);
0120     button->setShortcut(Qt::Key_2);
0121     button->setWhatsThis(i18n("Start playing an audio CD. It assumes that the CD is already there at the CD drive"));
0122     connect(button, SIGNAL(clicked()), mainWindow, SLOT(openAudioCd()));
0123     gridLayout->addWidget(button, 0, 1);
0124 
0125     button = addShortcut(i18n("&3 Play Video CD"), QIcon::fromTheme(QLatin1String("media-optical"), QIcon(":media-optical-video")), this);
0126     button->setShortcut(Qt::Key_3);
0127     button->setWhatsThis(i18n("Start playing a Video CD. It assumes that the CD is already there at the CD drive"));
0128     connect(button, SIGNAL(clicked()), mainWindow, SLOT(openVideoCd()));
0129     gridLayout->addWidget(button, 0, 2);
0130 
0131     button = addShortcut(i18n("&4 Play DVD"), QIcon::fromTheme(QLatin1String("media-optical"), QIcon(":media-optical")), this);
0132     button->setShortcut(Qt::Key_4);
0133     button->setWhatsThis(i18n("Start playing a DVD. It assumes that the DVD is already there at the DVD drive"));
0134     connect(button, SIGNAL(clicked()), mainWindow, SLOT(openDvd()));
0135     gridLayout->addWidget(button, 1, 0);
0136 
0137 #if HAVE_DVB == 1
0138     button = addShortcut(i18n("&5 Digital TV"), QIcon::fromTheme(QLatin1String("video-television"), QIcon(":video-television")), this);
0139     button->setShortcut(Qt::Key_5);
0140     button->setWhatsThis("Open the Digital TV live view window. If the TV channels are already scanned, it will start playing the last channel");
0141     connect(button, SIGNAL(clicked()), mainWindow, SLOT(playDvb()));
0142     gridLayout->addWidget(button, 1, 1);
0143 #endif /* HAVE_DVB == 1 */
0144 }
0145 
0146 QAbstractButton *StartTab::addShortcut(const QString &name, const QIcon &icon, QWidget *parent)
0147 {
0148     // QPushButton has visual problems with big icons
0149     QToolButton *button = new QToolButton(parent);
0150     button->setText(name);
0151     button->setIcon(icon);
0152     button->setFocusPolicy(Qt::NoFocus);
0153     button->setIconSize(QSize(48, 48));
0154     button->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
0155     button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
0156     return button;
0157 }
0158 
0159 class PlayerTab : public TabBase
0160 {
0161 public:
0162     explicit PlayerTab(MediaWidget *mediaWidget_);
0163     ~PlayerTab() { }
0164 
0165     void activate() override
0166     {
0167         layout()->addWidget(mediaWidget);
0168         mediaWidget->setFocus();
0169     }
0170 
0171 private:
0172     MediaWidget *mediaWidget;
0173 };
0174 
0175 PlayerTab::PlayerTab(MediaWidget *mediaWidget_) : mediaWidget(mediaWidget_)
0176 {
0177     QHBoxLayout *layout = new QHBoxLayout(this);
0178     layout->setMargin(0);
0179 }
0180 
0181 void MainWindow::run()
0182 {
0183     // Allow the user to enable or disable debugging
0184     // We handle this before the other parameters, as it may affect some
0185     // early debug messages
0186     //
0187     // --debug enables all debugging categories. It is possible to enable
0188     // each category individually by calling Kaffeine with:
0189     //  QT_LOGGING_RULES="epg.debug=true" kaffeine
0190 
0191     if (parser->isSet("debug")) {
0192         QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
0193         QLoggingCategory::setFilterRules(QStringLiteral(FILTER_RULE));
0194     } else {
0195         QLoggingCategory::setFilterRules(QStringLiteral("kaffeine.*.debug=false"));
0196     }
0197 
0198     readSettings();
0199 
0200     setAttribute(Qt::WA_DeleteOnClose, true);
0201 
0202     // menu structure
0203 
0204     QMenuBar *menuBar = QMainWindow::menuBar();
0205     collection = new KActionCollection(this);
0206 
0207     QMenu *menu = new QMenu(i18n("&File"), this);
0208     menuBar->addMenu(menu);
0209 
0210     QAction *action = KStandardAction::open(this, SLOT(open()), collection);
0211     menu->addAction(collection->addAction(QLatin1String("file_open"), action));
0212 
0213     action = new QAction(QIcon::fromTheme(QLatin1String("text-html"), QIcon(":text-html")),
0214         i18nc("@action:inmenu", "Open URL..."), collection);
0215     action->setShortcut(Qt::CTRL | Qt::Key_U);
0216     connect(action, SIGNAL(triggered(bool)), this, SLOT(openUrl()));
0217     menu->addAction(collection->addAction(QLatin1String("file_open_url"), action));
0218 
0219     actionOpenRecent = KStandardAction::openRecent(this, SLOT(openUrl(QUrl)), collection);
0220     actionOpenRecent->loadEntries(KSharedConfig::openConfig()->group("Recent Files"));
0221     menu->addAction(collection->addAction(QLatin1String("file_open_recent"), actionOpenRecent));
0222 
0223     menu->addSeparator();
0224 
0225     action = new QAction(QIcon::fromTheme(QLatin1String("media-optical-audio"), QIcon(":media-optical-audio")), i18n("Play Audio CD"), collection);
0226     connect(action, SIGNAL(triggered(bool)), this, SLOT(openAudioCd()));
0227     menu->addAction(collection->addAction(QLatin1String("file_play_audiocd"), action));
0228 
0229     action = new QAction(QIcon::fromTheme(QLatin1String("media-optical"), QIcon(":media-optical-video")), i18n("Play Video CD"), collection);
0230     connect(action, SIGNAL(triggered(bool)), this, SLOT(openVideoCd()));
0231     menu->addAction(collection->addAction(QLatin1String("file_play_videocd"), action));
0232 
0233     action = new QAction(QIcon::fromTheme(QLatin1String("media-optical"), QIcon(":media-optical")), i18n("Play DVD"), collection);
0234     connect(action, SIGNAL(triggered(bool)), this, SLOT(openDvd()));
0235     menu->addAction(collection->addAction(QLatin1String("file_play_dvd"), action));
0236 
0237     action = new QAction(QIcon::fromTheme(QLatin1String("media-optical"), QIcon(":media-optical")), i18nc("@action:inmenu", "Play DVD Folder"),
0238         collection);
0239     connect(action, SIGNAL(triggered()), this, SLOT(playDvdFolder()));
0240     menu->addAction(collection->addAction(QLatin1String("file_play_dvd_folder"), action));
0241 
0242     menu->addSeparator();
0243 
0244     action = KStandardAction::quit(this, SLOT(close()), collection);
0245     menu->addAction(collection->addAction(QLatin1String("file_quit"), action));
0246 
0247     QMenu *playerMenu = new QMenu(i18n("&Playback"), this);
0248     menuBar->addMenu(playerMenu);
0249 
0250     QMenu *playlistMenu = new QMenu(i18nc("menu bar", "Play&list"), this);
0251     menuBar->addMenu(playlistMenu);
0252 
0253 #if HAVE_DVB == 1
0254     QMenu *dvbMenu = new QMenu(i18n("&Television"), this);
0255     menuBar->addMenu(dvbMenu);
0256 #endif /* HAVE_DVB == 1 */
0257 
0258     menu = new QMenu(i18n("&Settings"), this);
0259     menuBar->addMenu(menu);
0260 
0261     action = KStandardAction::keyBindings(this, SLOT(configureKeys()), collection);
0262     menu->addAction(collection->addAction(QLatin1String("settings_keys"), action));
0263 
0264     action = KStandardAction::preferences(this, SLOT(configureKaffeine()), collection);
0265     menu->addAction(collection->addAction(QLatin1String("settings_kaffeine"), action));
0266 
0267     menuBar->addSeparator();
0268     KHelpMenu *helpMenu = new KHelpMenu(this, *aboutData);
0269     menuBar->addMenu(helpMenu->menu());
0270 
0271     // navigation bar - keep in sync with TabIndex enum!
0272 
0273     navigationBar = new QToolBar(QLatin1String("navigation_bar"));
0274     this->addToolBar(Qt::LeftToolBarArea, navigationBar);
0275     connect(navigationBar, SIGNAL(orientationChanged(Qt::Orientation)),
0276         this, SLOT(navigationBarOrientationChanged(Qt::Orientation)));
0277 
0278     tabBar = new QTabBar(navigationBar);
0279     tabBar->addTab(QIcon::fromTheme(QLatin1String("start-here-kde"), QIcon(":start-here-kde")), i18n("Start"));
0280     tabBar->addTab(QIcon::fromTheme(QLatin1String("kaffeine"), QIcon(":kaffeine")), i18n("Playback"));
0281     tabBar->addTab(QIcon::fromTheme(QLatin1String("view-media-playlist"), QIcon(":view-media-playlist")), i18n("Playlist"));
0282 #if HAVE_DVB == 1
0283     tabBar->addTab(QIcon::fromTheme(QLatin1String("video-television"), QIcon(":video-television")), i18n("Television"));
0284 #endif /* HAVE_DVB == 1 */
0285     tabBar->setShape(QTabBar::RoundedWest);
0286     tabBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
0287     connect(tabBar, SIGNAL(currentChanged(int)), this, SLOT(activateTab(int)));
0288     navigationBar->addWidget(tabBar);
0289 
0290     // control bar
0291 
0292     controlBar = new QToolBar(QLatin1String("control_bar"), this);
0293     this->addToolBar(Qt::BottomToolBarArea, controlBar);
0294 
0295     controlBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
0296 
0297     autoHideControlBar = false;
0298     cursorHideTimer = new QTimer(this);
0299     cursorHideTimer->setInterval(1500);
0300     cursorHideTimer->setSingleShot(true);
0301     connect(cursorHideTimer, SIGNAL(timeout()), this, SLOT(hideCursor()));
0302 
0303     // main area
0304 
0305     QWidget *widget = new QWidget(this);
0306     stackedLayout = new StackedLayout(widget);
0307     setCentralWidget(widget);
0308 
0309     mediaWidget = new MediaWidget(playerMenu, controlBar, collection, widget);
0310     connect(mediaWidget, SIGNAL(displayModeChanged()), this, SLOT(displayModeChanged()));
0311     connect(mediaWidget, SIGNAL(changeCaption(QString)), this, SLOT(setWindowTitle(QString)));
0312 
0313     // tabs - keep in sync with TabIndex enum!
0314 
0315     TabBase *startTab = new StartTab(this);
0316     tabs.append(startTab);
0317     stackedLayout->addWidget(startTab);
0318 
0319     playerTab = new PlayerTab(mediaWidget);
0320     playerTab->activate();
0321     tabs.append(playerTab);
0322     stackedLayout->addWidget(playerTab);
0323 
0324     playlistTab = new PlaylistTab(playlistMenu, collection, mediaWidget);
0325     tabs.append(playlistTab);
0326     stackedLayout->addWidget(playlistTab);
0327 
0328 #if HAVE_DVB == 1
0329     dvbTab = new DvbTab(dvbMenu, collection, mediaWidget);
0330     connect(this, SIGNAL(mayCloseApplication(bool*,QWidget*)),
0331         dvbTab, SLOT(mayCloseApplication(bool*,QWidget*)));
0332     tabs.append(dvbTab);
0333     stackedLayout->addWidget(dvbTab);
0334 #endif /* HAVE_DVB == 1 */
0335 
0336     currentTabIndex = StartTabId;
0337 
0338     // actions also have to work if the menu bar is hidden (fullscreen)
0339     collection->addAssociatedWidget(this);
0340 
0341     // restore custom key bindings
0342     collection->readSettings();
0343 
0344     // Tray menu
0345     menu = new QMenu(i18n("Kaffeine"), this);
0346 
0347     action = new QAction(i18n("Play &File"), this);
0348     connect(action, SIGNAL(triggered(bool)), this, SLOT(open()));
0349     menu->addAction(action);
0350 
0351     action = new QAction(i18n("Play &Audio CD"), this);
0352     connect(action, SIGNAL(triggered(bool)), this, SLOT(openAudioCd()));
0353     menu->addAction(action);
0354 
0355     action = new QAction(i18n("Play &Video CD"), this);
0356     connect(action, SIGNAL(triggered(bool)), this, SLOT(openVideoCd()));
0357     menu->addAction(action);
0358 
0359     action = new QAction(i18n("Play &DVD"), this);
0360     connect(action, SIGNAL(triggered(bool)), this, SLOT(openDvd()));
0361     menu->addAction(action);
0362 
0363 #if HAVE_DVB == 1
0364     action = new QAction(i18n("&Watch Digital TV"), this);
0365     connect(action, SIGNAL(triggered(bool)), this, SLOT(playDvb()));
0366     menu->addAction(action);
0367 #endif
0368     action = new QAction(i18n("&Quit"), this);
0369     connect(action, SIGNAL(triggered(bool)), this, SLOT(close()));
0370     menu->addAction(action);
0371 
0372     // Tray Icon and its menu
0373     QMenu *trayMenu = new QMenu(this);
0374     trayIcon = new QSystemTrayIcon(this);
0375     trayIcon->setContextMenu(trayMenu);
0376     trayIcon->setIcon(QIcon::fromTheme(QLatin1String("kaffeine"), QIcon(":kaffeine")));
0377     trayIcon->setToolTip(i18n("Kaffeine"));
0378     trayIcon->setContextMenu(menu);
0379     connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayShowHide(QSystemTrayIcon::ActivationReason)) );
0380 
0381     // make sure that the bars are visible (fullscreen -> quit -> restore -> hidden)
0382     menuBar->show();
0383     navigationBar->show();
0384     controlBar->show();
0385     trayIcon->show();
0386 
0387     // workaround setAutoSaveSettings() which doesn't accept "IconOnly" as initial state
0388     controlBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
0389 
0390 #if QT_VERSION < 0x050a00
0391     // initialize random number generator
0392     qsrand(QTime(0, 0, 0).msecsTo(QTime::currentTime()));
0393 #endif
0394 
0395     // initialize dbus objects
0396     QDBusConnection::sessionBus().registerObject(QLatin1String("/"), new MprisRootObject(this),
0397         QDBusConnection::ExportAllContents);
0398     QDBusConnection::sessionBus().registerObject(QLatin1String("/Player"),
0399         new MprisPlayerObject(this, mediaWidget, playlistTab, this),
0400         QDBusConnection::ExportAllContents);
0401     QDBusConnection::sessionBus().registerObject(QLatin1String("/TrackList"),
0402         new MprisTrackListObject(playlistTab, this), QDBusConnection::ExportAllContents);
0403 #if HAVE_DVB == 1
0404     QDBusConnection::sessionBus().registerObject(QLatin1String("/Television"),
0405         new DBusTelevisionObject(dvbTab, this), QDBusConnection::ExportAllContents);
0406 #endif /* HAVE_DVB == 1 */
0407     QDBusConnection::sessionBus().registerService(QLatin1String("org.mpris.kaffeine"));
0408 
0409     parseArgs();
0410     show();
0411 }
0412 
0413 MainWindow::~MainWindow()
0414 {
0415     actionOpenRecent->saveEntries(KSharedConfig::openConfig()->group("Recent Files"));
0416 
0417     if (!temporaryUrls.isEmpty()) {
0418         KIO::del(temporaryUrls);
0419     }
0420 
0421     int value = 0;
0422 
0423     switch (mediaWidget->getDisplayMode()) {
0424     case MediaWidget::NormalMode: value = 0; break;
0425     case MediaWidget::MinimalMode: value = 1; break;
0426     case MediaWidget::FullScreenMode: value = 2; break;
0427     case MediaWidget::FullScreenReturnToMinimalMode: value = 2; break;
0428     }
0429 
0430     KSharedConfig::openConfig()->group("MainWindow").writeEntry("DisplayMode", value);
0431 }
0432 
0433 void MainWindow::close()
0434 {
0435     bool ok = true;
0436 
0437 #if HAVE_DVB == 1
0438     dvbTab->mayCloseApplication(&ok, mediaWidget);
0439 #endif /* HAVE_DVB == 1 */
0440 
0441     if (ok) {
0442         writeSettings();
0443         mediaWidget->stop();
0444         QMainWindow::close();
0445         Configuration::detach();
0446         QCoreApplication::exit(0);
0447     }
0448 }
0449 
0450 void MainWindow::readSettings()
0451 {
0452     QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
0453     const QByteArray geometry = settings.value("geometry", QByteArray()).toByteArray();
0454     if (geometry.isEmpty()) {
0455         const QRect availableGeometry = QApplication::desktop()->availableGeometry(this);
0456         resize(availableGeometry.width() / 3, availableGeometry.height() / 2);
0457         move((availableGeometry.width() - width()) / 2,
0458              (availableGeometry.height() - height()) / 2);
0459     } else {
0460         restoreGeometry(geometry);
0461     }
0462 }
0463 
0464 void MainWindow::writeSettings()
0465 {
0466     QSettings settings(QCoreApplication::organizationName(), QCoreApplication::applicationName());
0467     settings.setValue("geometry", saveGeometry());
0468 }
0469 
0470 MainWindow::MainWindow(KAboutData *aboutData, QCommandLineParser *parser)
0471 {
0472     this->aboutData = aboutData;
0473     this->parser = parser;
0474 
0475     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("d") << QLatin1String("debug"), i18n("Enable all debug messages. Please notice that Kaffeine also allows enabling debug messages per category, by using the environment var:\nQT_LOGGING_RULES=kaffeine.category.debug=true\nwhere 'category' can be:\n" CATEGORIES)));
0476     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("tempfile"), i18n("The files/URLs opened by the application will be deleted after use")));
0477     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("f") << QLatin1String("fullscreen"), i18n("Start in full screen mode")));
0478     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("m") << QLatin1String("minimal"), i18n("Start in minimal mode")));
0479     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("t") << QLatin1String("alwaysontop"), i18n("Start with always on top")));
0480     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("audiocd"), i18n("Play Audio CD")));
0481     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("videocd"), i18n("Play Video CD")));
0482     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("dvd"), i18n("Play DVD")));
0483     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("aspectratio"), "Force starting with an specific aspect ratio", QLatin1String("aspect ratio")));
0484 
0485 #if HAVE_DVB == 1
0486     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("dumpdvb"), i18nc("command line option", "Dump dvb data (debug option)")));
0487     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("channel"), i18nc("command line option", "Play TV channel"), QLatin1String("name / number")));
0488     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("tv"), i18nc("command line option", "(deprecated option)"), QLatin1String("channel")));
0489     parser->addOption(QCommandLineOption(QStringList() << QLatin1String("lastchannel"), i18nc("command line option", "Play last tuned TV channel")));
0490 #endif
0491     parser->addPositionalArgument(QLatin1String("[file]"), i18n("Files or URLs to play"));
0492 }
0493 
0494 void MainWindow::parseArgs(const QString workingDirectory)
0495 {
0496     /* Parse first arguments that aren't mutually exclusive */
0497 
0498     if (parser->isSet("alwaysontop")) {
0499         Qt::WindowFlags flags = this->windowFlags();
0500         flags |= Qt::WindowStaysOnTopHint;
0501         this->setWindowFlags(flags);
0502     }
0503 
0504     if (parser->isSet("fullscreen")) {
0505         mediaWidget->setDisplayMode(MediaWidget::FullScreenMode);
0506     } else if (parser->isSet("minimal")) {
0507         mediaWidget->setDisplayMode(MediaWidget::MinimalMode);
0508     } else {
0509         // set display mode
0510         switch (Configuration::instance()->getStartupDisplayMode()) {
0511         case Configuration::StartupNormalMode:
0512             // nothing to do
0513             break;
0514         case Configuration::StartupMinimalMode:
0515             mediaWidget->setDisplayMode(MediaWidget::MinimalMode);
0516             break;
0517         case Configuration::StartupFullScreenMode:
0518             mediaWidget->setDisplayMode(MediaWidget::FullScreenMode);
0519             break;
0520         case Configuration::StartupRememberLastSetting: {
0521             int value = KSharedConfig::openConfig()->group("MainWindow").readEntry("DisplayMode", 0);
0522 
0523             switch (value) {
0524             case 0:
0525                 // nothing to do
0526                 break;
0527             case 1:
0528                 mediaWidget->setDisplayMode(MediaWidget::MinimalMode);
0529                 break;
0530             case 2:
0531                 mediaWidget->setDisplayMode(MediaWidget::FullScreenMode);
0532                 break;
0533             }
0534 
0535             break;
0536         } /* case */
0537         } /* switch */
0538     }
0539 
0540     if (parser->isSet("aspectratio")) {
0541         MediaWidget::AspectRatio aspectRatio = MediaWidget::AspectRatioAuto;
0542         QString aspect;
0543 
0544         aspect = parser->value("aspectratio");
0545 
0546         if (aspect == "1:1")
0547             aspectRatio = MediaWidget::AspectRatio1_1;
0548         else if (aspect == "4:3")
0549             aspectRatio = MediaWidget::AspectRatio4_3;
0550         else if (aspect == "5:4")
0551             aspectRatio = MediaWidget::AspectRatio5_4;
0552         else if (aspect == "16:9")
0553             aspectRatio = MediaWidget::AspectRatio16_9;
0554         else if (aspect == "16:10")
0555             aspectRatio = MediaWidget::AspectRatio16_10;
0556         else if (aspect == "2.21:1")
0557             aspectRatio = MediaWidget::AspectRatio221_100;
0558         else if (aspect == "2.35:1")
0559             aspectRatio = MediaWidget::AspectRatio235_100;
0560         else if (aspect == "2.39:1")
0561             aspectRatio = MediaWidget::AspectRatio239_100;
0562 
0563         mediaWidget->setAspectRatio(aspectRatio);
0564     }
0565 
0566 
0567 #if HAVE_DVB == 1
0568     if (parser->isSet("dumpdvb")) {
0569         dvbTab->enableDvbDump();
0570     }
0571 #endif
0572 
0573     /*
0574      * Now, parse arguments that are mutually exclusive
0575      */
0576 
0577 #if HAVE_DVB == 1
0578     QString channel;
0579 
0580     channel = parser->value("channel");
0581 
0582     if (!channel.isEmpty()) {
0583         activateTab(DvbTabId);
0584         dvbTab->playChannel(channel);
0585 
0586         return;
0587     }
0588 
0589     channel = parser->value("tv");
0590     if (!channel.isEmpty()) {
0591         activateTab(DvbTabId);
0592         dvbTab->playChannel(channel);
0593 
0594         return;
0595     }
0596 
0597     if (parser->isSet("lastchannel")) {
0598         activateTab(DvbTabId);
0599         dvbTab->playLastChannel();
0600 
0601         return;
0602     }
0603 #endif /* HAVE_DVB == 1 */
0604 
0605     if (parser->isSet("audiocd")) {
0606         if (parser->positionalArguments().count() > 0) {
0607             openAudioCd(parser->positionalArguments().first());
0608         } else {
0609             openAudioCd();
0610         }
0611         return;
0612     }
0613 
0614     if (parser->isSet("videocd")) {
0615         if (parser->positionalArguments().count() > 0) {
0616             openVideoCd(parser->positionalArguments().first());
0617         } else {
0618             openVideoCd();
0619         }
0620         return;
0621     }
0622 
0623     if (parser->isSet("dvd")) {
0624         if (parser->positionalArguments().count() > 0) {
0625             openDvd(parser->positionalArguments().first());
0626         } else {
0627             openDvd();
0628         }
0629         return;
0630     }
0631 
0632     if (parser->positionalArguments().count() > 0) {
0633         QList<QUrl> urls;
0634 
0635         for (int i = 0; i < parser->positionalArguments().count(); ++i) {
0636             QUrl url = QUrl::fromUserInput(parser->positionalArguments().at(i), workingDirectory);
0637 
0638             if (url.isValid()) {
0639                 urls.append(url);
0640             }
0641         }
0642 
0643         if (parser->isSet("tempfile")) {
0644             temporaryUrls.append(urls);
0645         }
0646 
0647         if (urls.size() >= 2) {
0648             activateTab(PlaylistTabId);
0649             playlistTab->appendToVisiblePlaylist(urls, true);
0650         } else if (!urls.isEmpty()) {
0651             openUrl(urls.at(0));
0652         }
0653         return;
0654     }
0655 }
0656 
0657 void MainWindow::displayModeChanged()
0658 {
0659     MediaWidget::DisplayMode displayMode = mediaWidget->getDisplayMode();
0660 
0661     switch (displayMode) {
0662     case MediaWidget::FullScreenMode:
0663     case MediaWidget::FullScreenReturnToMinimalMode:
0664         setWindowState(windowState() | Qt::WindowFullScreen);
0665         break;
0666     case MediaWidget::MinimalMode:
0667     case MediaWidget::NormalMode:
0668         setWindowState(windowState() & (~Qt::WindowFullScreen));
0669         break;
0670     }
0671 
0672     switch (displayMode) {
0673     case MediaWidget::FullScreenMode:
0674     case MediaWidget::FullScreenReturnToMinimalMode:
0675     case MediaWidget::MinimalMode:
0676         menuBar()->hide();
0677         navigationBar->hide();
0678         controlBar->hide();
0679         autoHideControlBar = true;
0680         cursorHideTimer->start();
0681         break;
0682     case MediaWidget::NormalMode:
0683         menuBar()->show();
0684         navigationBar->show();
0685         controlBar->show();
0686         autoHideControlBar = false;
0687         cursorHideTimer->stop();
0688         unsetCursor();
0689         break;
0690     }
0691     tabs.at(currentTabIndex)->toggleDisplayMode(displayMode);
0692 }
0693 
0694 void MainWindow::trayShowHide(QSystemTrayIcon::ActivationReason reason)
0695 {
0696     if (reason != QSystemTrayIcon::DoubleClick)
0697         return;
0698 
0699     if (isVisible())
0700         hide();
0701     else {
0702         show();
0703         raise();
0704         setFocus();
0705     }
0706 }
0707 
0708 void MainWindow::open()
0709 {
0710     if (isMinimized())
0711         showNormal();
0712 
0713     QList<QUrl> urls = QFileDialog::getOpenFileUrls(this, i18nc("@title:window", "Open files"), QUrl(), MediaWidget::extensionFilter());
0714 
0715 //  trayIcon->showMessage("Open", "Opening file(s)");
0716     if (urls.size() >= 2) {
0717         activateTab(PlaylistTabId);
0718         playlistTab->appendToVisiblePlaylist(urls, true);
0719     } else if (!urls.isEmpty()) {
0720         openUrl(urls.at(0));
0721     }
0722 }
0723 
0724 void MainWindow::openUrl()
0725 {
0726     openUrl(QInputDialog::getText(this, i18nc("@title:window", "Open URL"), i18n("Enter a URL:")));
0727 }
0728 
0729 void MainWindow::openUrl(const QUrl &url)
0730 {
0731     if (!url.isValid()) {
0732         return;
0733     }
0734 
0735     // we need to copy "url" because addUrl() may invalidate it
0736     QUrl copy(url);
0737     actionOpenRecent->addUrl(copy); // moves the url to the top of the list
0738 
0739     if (currentTabIndex != PlaylistTabId) {
0740         activateTab(PlayerTabId);
0741     }
0742 
0743     playlistTab->appendToVisiblePlaylist(QList<QUrl>() << copy, true);
0744 }
0745 
0746 void MainWindow::openAudioCd(const QString &device)
0747 {
0748     if (isMinimized())
0749         showNormal();
0750 
0751     activateTab(PlayerTabId);
0752     mediaWidget->playAudioCd(device);
0753 }
0754 
0755 void MainWindow::openVideoCd(const QString &device)
0756 {
0757     if (isMinimized())
0758         showNormal();
0759 
0760     activateTab(PlayerTabId);
0761     mediaWidget->playVideoCd(device);
0762 }
0763 
0764 void MainWindow::openDvd(const QString &device)
0765 {
0766     if (isMinimized())
0767         showNormal();
0768 
0769     activateTab(PlayerTabId);
0770     mediaWidget->playDvd(device);
0771 }
0772 
0773 void MainWindow::playDvdFolder()
0774 {
0775     QString folder = QFileDialog::getExistingDirectory(this, QString());
0776 
0777     if (!folder.isEmpty()) {
0778         openDvd(folder);
0779     }
0780 }
0781 
0782 void MainWindow::playDvb()
0783 {
0784     if (isMinimized())
0785         showNormal();
0786 
0787     activateTab(DvbTabId);
0788     dvbTab->playLastChannel();
0789 }
0790 
0791 void MainWindow::configureKeys()
0792 {
0793     KShortcutsDialog::configure(collection);
0794 }
0795 
0796 void MainWindow::configureKaffeine()
0797 {
0798     QDialog *dialog = new ConfigurationDialog(this);
0799     dialog->setAttribute(Qt::WA_DeleteOnClose, true);
0800     dialog->setModal(true);
0801     dialog->show();
0802 }
0803 
0804 void MainWindow::navigationBarOrientationChanged(Qt::Orientation orientation)
0805 {
0806     if (orientation == Qt::Horizontal) {
0807         tabBar->setShape(QTabBar::RoundedNorth);
0808     } else {
0809         tabBar->setShape(QTabBar::RoundedWest);
0810     }
0811 }
0812 
0813 void MainWindow::activateTab(int tabIndex)
0814 {
0815     currentTabIndex = tabIndex;
0816     tabBar->setCurrentIndex(tabIndex);
0817 
0818     /*
0819      * Ensure that menus and timers will be properly shown,
0820      * according with the selected display mode.
0821      */
0822     stackedLayout->setCurrentIndex(currentTabIndex);
0823     tabs.at(currentTabIndex)->activate();
0824 
0825     emit displayModeChanged();
0826 }
0827 
0828 void MainWindow::hideCursor()
0829 {
0830     setCursor(Qt::BlankCursor);
0831 }
0832 
0833 void MainWindow::closeEvent(QCloseEvent *event)
0834 {
0835     bool ok = true;
0836     emit mayCloseApplication(&ok, this);
0837 
0838     if (!ok) {
0839         event->ignore();
0840     } else {
0841         MainWindow::close();
0842     }
0843 }
0844 
0845 bool MainWindow::event(QEvent *event)
0846 {
0847     bool retVal = QMainWindow::event(event); // this has to be done before calling setVisible()
0848 
0849     // FIXME we depend on QEvent::HoverMove (instead of QEvent::MouseMove)
0850     // but the latter depends on mouse tracking being enabled on this widget
0851     // and all its children (especially the video widget) ...
0852 
0853     switch (event->type()) {
0854     case QEvent::HoverMove: {
0855         int x = reinterpret_cast<QHoverEvent *> (event)->pos().x();
0856         int y = reinterpret_cast<QHoverEvent *> (event)->pos().y();
0857 
0858         if ((y < 0) || (y >= height()) ||
0859             (x < 0) || (x >= width())) {
0860             // QHoverEvent sometimes reports quite strange coordinates - ignore them
0861             return retVal;
0862         }
0863 
0864         if (autoHideControlBar) {
0865             cursorHideTimer->stop();
0866             unsetCursor();
0867 
0868             switch (toolBarArea(controlBar)) {
0869             case Qt::TopToolBarArea:
0870                 controlBar->setVisible(y < 60);
0871                 break;
0872             case Qt::BottomToolBarArea:
0873                 controlBar->setVisible(y >= (height() - 60));
0874                 menuBar()->setVisible(y < 60);
0875                 break;
0876             default:
0877                 break;
0878             }
0879 
0880             if (controlBar->isHidden() || menuBar()->isHidden()) {
0881                 cursorHideTimer->start();
0882             }
0883         }
0884 
0885         tabs.at(currentTabIndex)->mouse_move(x, y);
0886         break;
0887     }
0888     default:
0889         break;
0890     }
0891 
0892     return retVal;
0893 }
0894 
0895 void MainWindow::keyPressEvent(QKeyEvent *event)
0896 {
0897     if (event->key() == Qt::Key_Escape) {
0898         mediaWidget->setDisplayMode(MediaWidget::NormalMode);
0899     }
0900 
0901     QMainWindow::keyPressEvent(event);
0902 }
0903 
0904 void MainWindow::leaveEvent(QEvent *event)
0905 {
0906     if (autoHideControlBar) {
0907         menuBar()->setVisible(false);
0908         controlBar->setVisible(false);
0909         tabs.at(currentTabIndex)->mouse_move(-1, -1);
0910     }
0911 
0912     QMainWindow::leaveEvent(event);
0913 }
0914 
0915 #include "moc_mainwindow.cpp"