File indexing completed on 2024-04-14 04:48:44

0001 /*
0002     SPDX-FileCopyrightText: 2002 Koos Vriezen
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // include files for QT
0008 #include <QDataStream>
0009 #include <QRegExp>
0010 #include <QIcon>
0011 #include <QInputDialog>
0012 #include <QIODevice>
0013 #include <QCursor>
0014 #include <QPainter>
0015 #include <QCheckBox>
0016 #include <QPushButton>
0017 #include <QKeySequence>
0018 #include <QApplication>
0019 #include <QSlider>
0020 #include <QLayout>
0021 #include <QMenu>
0022 #include <QMimeData>
0023 #include <QWhatsThis>
0024 #include <QTimer>
0025 #include <QFile>
0026 #include <QMetaObject>
0027 #include <QDirIterator>
0028 #include <QDropEvent>
0029 #include <QLabel>
0030 #include <QDockWidget>
0031 #include <QMenuBar>
0032 #include <QStatusBar>
0033 #include <QStandardPaths>
0034 #include <QSystemTrayIcon>
0035 #include <QX11Info>
0036 
0037 // KF
0038 #include <KIconLoader>
0039 #include <KMessageBox>
0040 #include <KToolBar>
0041 #include <KLocalizedString>
0042 #include <KConfig>
0043 #include <KSharedConfig>
0044 #include <KStandardAction>
0045 #include <KActionCollection>
0046 #include <KLineEdit>
0047 #include <KShortcutsDialog>
0048 #include <KRecentFilesAction>
0049 #include <KToggleAction>
0050 
0051 // application specific includes
0052 #include "kmplayerapp_log.h"
0053 #include "kmplayerconfig.h"
0054 #include "kmplayer.h"
0055 #include "kmplayer_lists.h"
0056 #include "kmplayerview.h"
0057 #include "playmodel.h"
0058 #include "playlistview.h"
0059 #include "viewarea.h"
0060 #include "kmplayercontrolpanel.h"
0061 #include "kmplayerpartbase.h"
0062 #include "kmplayerprocess.h"
0063 #include "kmplayertvsource.h"
0064 //#include "kmplayerbroadcast.h"
0065 //#include "kmplayervdr.h"
0066 #include "kmplayerconfig.h"
0067 
0068 #include <KUrlRequester>
0069 #include <QFileDialog>
0070 
0071 extern const char * strMPlayerGroup;
0072 
0073 
0074 KMPlayerApp::KMPlayerApp (QWidget *)
0075     : KXmlGuiWindow (nullptr),
0076       m_systray (nullptr),
0077       m_player (new KMPlayer::PartBase (this, nullptr, KSharedConfig::openConfig ())),
0078       m_view (static_cast <KMPlayer::View*> (m_player->view())),
0079       //m_ffserverconfig (new KMPlayerFFServerConfig),
0080       //m_broadcastconfig (new KMPlayerBroadcastConfig (m_player, m_ffserverconfig)),
0081       edit_tree_id (-1),
0082       last_time_left (0),
0083       m_played_intro (false),
0084       m_played_exit (false),
0085       m_minimal_mode (false)
0086 {
0087     setCentralWidget (m_view);
0088     //connect (m_broadcastconfig, SIGNAL (broadcastStarted()), this, SLOT (broadcastStarted()));
0089     //connect (m_broadcastconfig, SIGNAL (broadcastStopped()), this, SLOT (broadcastStopped()));
0090     initStatusBar();
0091     m_player->init (actionCollection (), "/KMPlayerPart", false);
0092     m_view->initDock (m_view->viewArea ());
0093     //m_player->mediaManager ()->processInfos () ["xvideo"] =
0094     //    new XvProcessInfo (m_player->mediaManager ());
0095     ListsSource * lstsrc = new ListsSource (m_player);
0096     m_player->sources () ["listssource"] = lstsrc;
0097     m_player->sources () ["dvdsource"] = new ::KMPlayerDVDSource(this);
0098     m_player->sources () ["vcdsource"] = new KMPlayerVCDSource(this);
0099     m_player->sources () ["audiocdsource"] = new KMPlayerAudioCDSource(this);
0100     m_player->sources () ["pipesource"] = new KMPlayerPipeSource (this);
0101     m_player->sources () ["tvsource"] = new KMPlayerTVSource(this);
0102     //m_player->sources () ["vdrsource"] = new KMPlayerVDRSource (this);
0103     m_player->setSource (m_player->sources () ["urlsource"]);
0104     initActions();
0105     initView();
0106 
0107     //setAutoSaveSettings();
0108     playlist = new Playlist (this, lstsrc);
0109     playlist_id = m_player->playModel()->addTree (playlist, "listssource", "view-media-playlist", KMPlayer::PlayModel::AllowDrag | KMPlayer::PlayModel::AllowDrops | KMPlayer::PlayModel::TreeEdit | KMPlayer::PlayModel::Moveable | KMPlayer::PlayModel::Deleteable);
0110     readOptions();
0111 }
0112 
0113 KMPlayerApp::~KMPlayerApp () {
0114     //delete m_broadcastconfig;
0115     if (recents)
0116         recents->document ()->dispose ();
0117     if (playlist)
0118         playlist->document ()->dispose ();
0119 
0120     if (current_generator && current_generator->active ()) {
0121         current_generator->deactivate ();
0122         current_generator = nullptr;
0123     }
0124     while (generators.first ()) {
0125         generators.first ()->data->document ()->dispose ();
0126         generators.remove (generators.first ());
0127     }
0128 }
0129 
0130 
0131 void KMPlayerApp::initActions () {
0132     KActionCollection * ac = actionCollection ();
0133     fileNewWindow = ac->addAction ("new_window");
0134     fileNewWindow->setText( i18n( "New window" ) );
0135     //fileNewWindow->setIcon (QIcon::fromTheme("window-new"));
0136     connect (fileNewWindow, &QAction::triggered, this, &KMPlayerApp::slotFileNewWindow);
0137     fileOpen = KStandardAction::open (this, &KMPlayerApp::slotFileOpen, ac);
0138     fileOpenRecent = KStandardAction::openRecent(this, &KMPlayerApp::slotFileOpenRecent, ac);
0139     KStandardAction::saveAs (this, &KMPlayerApp::slotSaveAs, ac);
0140     fileClose = KStandardAction::close (this, &KMPlayerApp::slotFileClose, ac);
0141     fileQuit = KStandardAction::quit (this, &KMPlayerApp::slotFileQuit, ac);
0142     viewEditMode = ac->addAction ("edit_mode");
0143     viewEditMode->setCheckable (true);
0144     viewEditMode->setText (i18n ("&Edit mode"));
0145     connect (viewEditMode, &QAction::triggered, this, &KMPlayerApp::editMode);
0146     QAction *viewplaylist = ac->addAction ( "view_playlist");
0147     viewplaylist->setText (i18n ("Pla&y List"));
0148     //viewplaylist->setIcon (QIcon::fromTheme("media-playlist"));
0149     connect (viewplaylist, &QAction::triggered, m_player, &KMPlayer::PartBase::showPlayListWindow);
0150     KStandardAction::preferences (m_player, &KMPlayer::PartBase::showConfigDialog, ac);
0151     QAction *playmedia = ac->addAction ("play");
0152     playmedia->setText (i18n ("P&lay"));
0153     connect (playmedia, &QAction::triggered, m_player, &KMPlayer::PartBase::play);
0154     QAction *pausemedia = ac->addAction ("pause");
0155     pausemedia->setText (i18n ("&Pause"));
0156     connect (pausemedia, &QAction::triggered, m_player, &KMPlayer::PartBase::pause);
0157     QAction *stopmedia = ac->addAction ("stop");
0158     stopmedia->setText (i18n ("&Stop"));
0159     connect (stopmedia, &QAction::triggered, m_player, &KMPlayer::PartBase::stop);
0160     KStandardAction::keyBindings (this, &KMPlayerApp::slotConfigureKeys, ac);
0161     //KStandardAction::configureToolbars (this, &KMPlayerApp::slotConfigureToolbars, ac);
0162     viewFullscreen = ac->addAction ("view_fullscreen");
0163     viewFullscreen->setCheckable (true);
0164     viewFullscreen->setText (i18n("Fullscreen"));
0165     connect (viewFullscreen, &QAction::triggered, this, &KMPlayerApp::fullScreen);
0166     toggleView = ac->addAction ("view_video");
0167     toggleView->setText (i18n ("C&onsole"));
0168     toggleView->setIcon (QIcon::fromTheme("utilities-terminal"));
0169     connect (toggleView, &QAction::triggered,
0170             qobject_cast<KMPlayer::View*>(m_player->view ()), &KMPlayer::View::toggleVideoConsoleWindow);
0171     viewSyncEditMode = ac->addAction ("sync_edit_mode");
0172     viewSyncEditMode->setText (i18n ("Reload"));
0173     viewSyncEditMode->setIcon (QIcon::fromTheme("view-refresh"));
0174     connect (viewSyncEditMode, &QAction::triggered, this, &KMPlayerApp::syncEditMode);
0175     viewSyncEditMode->setEnabled (false);
0176     viewToolBar = KStandardAction::create (KStandardAction::ShowToolbar,
0177             this, &KMPlayerApp::slotViewToolBar, ac);
0178     viewStatusBar = KStandardAction::create (KStandardAction::ShowStatusbar,
0179             this, &KMPlayerApp::slotViewStatusBar, ac);
0180     viewMenuBar = KStandardAction::create (KStandardAction::ShowMenubar,
0181             this, &KMPlayerApp::slotViewMenuBar, ac);
0182     QAction *act = ac->addAction ("clear_history");
0183     act->setText (i18n ("Clear &History"));
0184     connect (act, &QAction::triggered, this, &KMPlayerApp::slotClearHistory);
0185 #if defined(KMPLAYER_WITH_NPP) && defined(KMPLAYER_WITH_CAIRO)
0186     act = ac->addAction ("generators");
0187     act->setText (i18n ("&Generators"));
0188     m_generatormenu = new QMenu (this);
0189     connect (m_generatormenu, &QMenu::aboutToShow,
0190              this, &KMPlayerApp::slotGeneratorMenu);
0191     act->setMenu (m_generatormenu);
0192 #endif
0193 
0194 
0195     /*fileNewWindow = new KAction(i18n("New &Window"), 0, 0, this, SLOT(slotFileNewWindow()), ac, "new_window");
0196     new KAction (i18n ("&Open DVD"), QString ("dvd_mount"), KShortcut (), this, SLOT(openDVD ()), ac, "opendvd");
0197     new KAction (i18n ("&Open VCD"), QString ("cdrom_mount"), KShortcut (), this, SLOT(openVCD ()), ac, "openvcd");
0198     new KAction (i18n ("&Open Audio CD"), QString ("cdrom_mount"), KShortcut (), this, SLOT(openAudioCD ()), ac, "openaudiocd");
0199     new KAction (i18n ("&Open Pipe..."), QString ("pipe"), KShortcut (), this, SLOT(openPipe ()), ac, "source_pipe");
0200     //KIconLoader::global ()->loadIconSet (QString ("video-television"), K3Icon::Small, 0,true)
0201     new KAction (i18n ("&Connect"), QString ("connect_established"), KShortcut (), this, SLOT (openVDR ()), ac, "vdr_connect");
0202     editVolumeInc = new KAction (i18n ("Increase Volume"), QString ("player_volume"), KShortcut (), m_player, SLOT (increaseVolume ()), ac, "edit_volume_up");
0203     editVolumeDec = new KAction (i18n ("Decrease Volume"), QString ("player_volume"), KShortcut (), m_player, SLOT(decreaseVolume ()), ac, "edit_volume_down");
0204     //new KAction (i18n ("V&ideo"), QString ("video"), KShortcut (), m_view, SLOT (toggleVideoConsoleWindow ()), ac, "view_video");
0205     new KAction (i18n ("Pla&y List"), QString ("player_playlist"), KShortcut (), m_player, SLOT (showPlayListWindow ()), ac, "view_playlist");
0206     new KAction (i18n ("Minimal mode"), QString ("empty"), KShortcut (), this, SLOT (slotMinimalMode ()), ac, "view_minimal");
0207     new KAction (i18n ("50%"), 0, 0, this, SLOT (zoom50 ()), ac, "view_zoom_50");
0208     new KAction (i18n ("100%"), QString ("viewmagfit"), KShortcut (), this, SLOT (zoom100 ()), ac, "view_zoom_100");
0209     new KAction (i18n ("150%"), 0, 0, this, SLOT (zoom150 ()), ac, "view_zoom_150");
0210     new KAction (i18n ("Show Popup Menu"), KShortcut (), m_view->controlPanel (), SLOT (showPopupMenu ()), ac, "view_show_popup_menu");
0211     new KAction (i18n ("Show Language Menu"), KShortcut (Qt::Key_L), m_view->controlPanel (), SLOT (showLanguageMenu ()), ac, "view_show_lang_menu");
0212     viewKeepRatio = new KToggleAction (i18n ("&Keep Width/Height Ratio"), 0, this, SLOT (keepSizeRatio ()), ac, "view_keep_ratio");
0213     fileNewWindow->setStatusText(i18n("Opens a new application window"));
0214     fileOpen->setStatusText(i18n("Opens an existing file"));
0215     fileOpenRecent->setStatusText(i18n("Opens a recently used file"));
0216     fileClose->setStatusText(i18n("Closes the actual source"));
0217     fileQuit->setStatusText(i18n("Quits the application"));*/
0218     viewStatusBar->setStatusTip (i18n ("Enables/disables the status bar"));
0219     viewMenuBar->setStatusTip (i18n ("Enables/disables the menu bar"));
0220     viewToolBar->setStatusTip (i18n ("Enables/disables the toolbar"));
0221 }
0222 
0223 void KMPlayerApp::initStatusBar () {
0224     QStatusBar *sb = statusBar();
0225     playtime_info = new QLabel("--:--");
0226     sb->addPermanentWidget(playtime_info);
0227     sb->showMessage(i18n ("Ready."));
0228 }
0229 
0230 void KMPlayerApp::initMenu () {
0231     createGUI ("kmplayerui.rc"); // first build the one from the kmplayerui.rc
0232 
0233     //QAction *bookmark_action = actionCollection ()->addAction ("bookmarks");
0234     QList<QAction *> acts = menuBar()->actions();
0235     if (acts.size () > 2) {
0236         QMenu *bookmark_menu = new QMenu(this);
0237         QAction *bookmark_action = menuBar()->insertMenu (acts.at(2), bookmark_menu);
0238         bookmark_action->setText (i18n( "&Bookmarks"));
0239         m_player->createBookmarkMenu (bookmark_menu, actionCollection ());
0240     }
0241 
0242 }
0243 
0244 void KMPlayerApp::initView () {
0245     KSharedConfigPtr config = KSharedConfig::openConfig ();
0246     //m_view->docArea ()->readDockConfig (config.data (), QString ("Window Layout"));
0247     m_player->connectPanel (m_view->controlPanel ());
0248     initMenu ();
0249     //new KAction (i18n ("Increase Volume"), editVolumeInc->shortcut (), m_player, SLOT (increaseVolume ()), m_view->viewArea ()->actionCollection (), "edit_volume_up");
0250     //new KAction (i18n ("Decrease Volume"), editVolumeDec->shortcut (), m_player, SLOT(decreaseVolume ()), m_view->viewArea ()->actionCollection (), "edit_volume_down");
0251     connect (m_player->settings (), &KMPlayer::Settings::configChanged,
0252              this, &KMPlayerApp::configChanged);
0253     connect (m_player, &KMPlayer::PartBase::loading,
0254              this, &KMPlayerApp::loadingProgress);
0255     connect (m_player, &KMPlayer::PartBase::positioned,
0256              this, &KMPlayerApp::positioned);
0257     connect (m_player, &KMPlayer::PartBase::statusUpdated,
0258              this, &KMPlayerApp::slotStatusMsg);
0259     connect (m_view, &KMPlayer::View::windowVideoConsoleToggled,
0260              this, &KMPlayerApp::windowVideoConsoleToggled);
0261     connect (m_player, &KMPlayer::PartBase::sourceChanged,
0262              this, &KMPlayerApp::slotSourceChanged);
0263     /*m_view->controlPanel ()->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom50,
0264             this, SLOT (zoom50 ()));
0265     m_view->controlPanel ()->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom100,
0266             this, SLOT (zoom100 ()));
0267     m_view->controlPanel ()->zoomMenu ()->connectItem (KMPlayer::ControlPanel::menu_zoom150,
0268             this, SLOT (zoom150 ()));
0269     connect (m_view->controlPanel()->broadcastButton (), SIGNAL (clicked ()),
0270             this, SLOT (broadcastClicked ()));*/
0271     m_auto_resize = m_player->settings ()->autoresize;
0272     if (m_auto_resize)
0273         connect (m_player, &KMPlayer::PartBase::sourceDimensionChanged,
0274                  this, &KMPlayerApp::zoom100);
0275     connect (m_view, &KMPlayer::View::fullScreenChanged,
0276             this, &KMPlayerApp::fullScreen);
0277     connect (m_view->playList (), &QTreeView::activated,
0278             this, &KMPlayerApp::playListItemActivated);
0279     connect (m_view->playList(), &KMPlayer::PlayListView::dropped,
0280             this, &KMPlayerApp::playListItemDropped);
0281     connect (m_view->playList(), &KMPlayer::PlayListView::prepareMenu,
0282              this, &KMPlayerApp::preparePlaylistMenu);
0283     m_dropmenu = new QMenu (m_view->playList ());
0284     dropAdd = m_dropmenu->addAction(QIcon::fromTheme("view-media-playlist"),
0285                 i18n ("&Add to list"), this, &KMPlayerApp::menuDropInList);
0286     dropAddGroup = m_dropmenu->addAction(QIcon::fromTheme("folder-grey"),
0287         i18n ("Add in new &Group"), this, &KMPlayerApp::menuDropInGroup);
0288     dropCopy = m_dropmenu->addAction(QIcon::fromTheme("edit-copy"),
0289             i18n ("&Copy here"), this, &KMPlayerApp::menuCopyDrop);
0290     dropDelete = m_dropmenu->addAction(QIcon::fromTheme("edit-delete"),
0291             i18n ("&Delete"), this, &KMPlayerApp::menuDeleteNode);
0292     /*QMenu * viewmenu = new QMenu;
0293     viewmenu->addAction(i18n ("Full Screen"), this, SLOT(fullScreen ()),
0294                           QKeySequence ("CTRL + Key_F"));
0295     menuBar ()->addAction(i18n ("&View"), viewmenu, -1, 2);*/
0296     //toolBar("mainToolBar")->hide();
0297     setAcceptDrops (true);
0298 }
0299 
0300 void KMPlayerApp::loadingProgress (int perc) {
0301     if (perc < 100)
0302         playtime_info->setText(QString ("%1%").arg (perc));
0303     else
0304         playtime_info->setText(QString ("--:--"));
0305 }
0306 
0307 void KMPlayerApp::positioned (int pos, int length) {
0308     int left = (length - pos) / 10;
0309     if (left != last_time_left) {
0310         last_time_left = left;
0311         QString text ("--:--");
0312         if (left > 0) {
0313             int h = left / 3600;
0314             int m = (left % 3600) / 60;
0315             int s = left % 60;
0316             if (h > 0)
0317                 text = QString::asprintf ("%d:%02d:%02d", h, m, s);
0318             else
0319                 text = QString::asprintf ("%02d:%02d", m, s);
0320         }
0321         playtime_info->setText(text);
0322     }
0323 }
0324 
0325 void KMPlayerApp::windowVideoConsoleToggled (bool show) {
0326     if (show) {
0327         toggleView->setText (i18n ("V&ideo"));
0328         toggleView->setIcon (QIcon::fromTheme("video-display"));
0329     } else {
0330         toggleView->setText (i18n ("C&onsole"));
0331         toggleView->setIcon (QIcon::fromTheme("utilities-terminal"));
0332     }
0333 }
0334 
0335 void KMPlayerApp::playerStarted () {
0336     KMPlayer::Source * source = m_player->source ();
0337     if (!strcmp (source->name (), "urlsource")) {
0338         const QUrl url = source->url ();
0339         QString surl = url.url ();
0340         QString nurl = url.isLocalFile()
0341             ? url.toLocalFile()
0342             : QUrl::fromPercentEncoding (surl.toUtf8 ());
0343         if (url.isEmpty () || surl.startsWith ("lists"))
0344             return;
0345         //if (url.isEmpty () && m_player->process ()->mrl ())
0346         //    url = KUrl (m_player->process ()->mrl ()->mrl ()->src);
0347         recentFiles ()->addUrl (url);
0348         recents->defer (); // make sure it's loaded
0349         recents->insertBefore (new Recent (recents, this, nurl),
0350                                recents->firstChild ());
0351         KMPlayer::Node *c = recents->firstChild ()->nextSibling ();
0352         int count = 1;
0353         KMPlayer::Node *more = nullptr;
0354         while (c) {
0355             if (c->id == id_node_recent_node &&
0356                     (c->mrl ()->src == surl || c->mrl ()->src == nurl)) {
0357                 KMPlayer::Node *tmp = c->nextSibling ();
0358                 recents->removeChild (c);
0359                 c = tmp;
0360             } else {
0361                 if (c->id == KMPlayer::id_node_group_node)
0362                     more = c;
0363                 c = c->nextSibling ();
0364                 count++;
0365             }
0366         }
0367         if (!more && count > 10) {
0368             more = new Group (recents, this, i18n ("More..."));
0369             recents->appendChild (more);
0370         }
0371         if (more) {
0372             if (count > 10) {
0373                 KMPlayer::NodePtr item = more->previousSibling ();
0374                 recents->removeChild (item);
0375                 more->insertBefore (item, more->firstChild ());
0376             }
0377             if (more->firstChild ())
0378                 c = more->firstChild ()->nextSibling ();
0379             count = 0;
0380             while (c) {
0381                 if (c->id == id_node_recent_node &&
0382                         (c->mrl ()->src == surl || c->mrl ()->src == nurl)) {
0383                     KMPlayer::Node *tmp = c->nextSibling ();
0384                     more->removeChild (c);
0385                     c = tmp;
0386                 } else {
0387                     c = c->nextSibling ();
0388                     count++;
0389                 }
0390             }
0391             if (count > 50)
0392                 more->removeChild (more->lastChild ());
0393         }
0394         m_player->playModel()->updateTree (recents_id, recents, nullptr, false, false);
0395     }
0396 }
0397 
0398 void KMPlayerApp::slotSourceChanged (KMPlayer::Source *olds, KMPlayer::Source * news) {
0399     if (olds) {
0400         disconnect (olds, &KMPlayer::Source::titleChanged,
0401                     this, QOverload<const QString&>::of(&KMPlayerApp::setCaption));
0402         disconnect (olds, &KMPlayer::Source::startPlaying,
0403                     this, &KMPlayerApp::playerStarted);
0404     }
0405     if (news) {
0406         setCaption (news->prettyName (), false);
0407         connect (news, &KMPlayer::Source::titleChanged,
0408                  this, QOverload<const QString&>::of(&KMPlayerApp::setCaption));
0409         connect (news, &KMPlayer::Source::startPlaying,
0410                  this, &KMPlayerApp::playerStarted);
0411         viewSyncEditMode->setEnabled (m_view->editMode () ||
0412                 !strcmp (m_player->source ()->name (), "urlsource"));
0413     }
0414 }
0415 
0416 void KMPlayerApp::openDVD () {
0417     slotStatusMsg(i18n("Opening DVD..."));
0418     m_player->setSource (m_player->sources () ["dvdsource"]);
0419 }
0420 
0421 void KMPlayerApp::openVCD () {
0422     slotStatusMsg(i18n("Opening VCD..."));
0423     m_player->setSource (m_player->sources () ["vcdsource"]);
0424 }
0425 
0426 void KMPlayerApp::openAudioCD () {
0427     slotStatusMsg(i18n("Opening Audio CD..."));
0428     m_player->setSource (m_player->sources () ["audiocdsource"]);
0429 }
0430 
0431 void KMPlayerApp::openPipe () {
0432     slotStatusMsg(i18n("Opening pipe..."));
0433     bool ok;
0434     QString cmd = QInputDialog::getText(m_player->view(), i18n("Read From Pipe"),
0435       i18n ("Enter a command that will output an audio/video stream\nto the stdout. This will be piped to a player's stdin.\n\nCommand:"), QLineEdit::Normal, m_player->sources() ["pipesource"]->pipeCmd(), &ok);
0436     if (!ok) {
0437         slotStatusMsg (i18n ("Ready."));
0438         return;
0439     }
0440     static_cast <KMPlayerPipeSource *> (m_player->sources () ["pipesource"])->setCommand (cmd);
0441     m_player->setSource (m_player->sources () ["pipesource"]);
0442 }
0443 
0444 void KMPlayerApp::openVDR () {
0445     /*slotStatusMsg(i18n("Opening VDR..."));
0446     if (!strcmp (m_player->source ()->name (), "vdrsource") && m_player->playing ())
0447         static_cast<KMPlayerVDRSource *>(m_player->source())->toggleConnected();
0448     else
0449         m_player->setSource (m_player->sources () ["vdrsource"]);*/
0450 }
0451 
0452 #ifdef KMPLAYER_WITH_CAIRO
0453 static const char *svg_bat =
0454     "<svg width='64' height='64'>"
0455     "<path style='fill:#000000;'"
0456     " d='M 32.120,14.655"
0457     " C 31.374,14.777 30.356,14.660 30.073,14.204"
0458     " C 29.358,12.759 29.294,12.087 28.475,10.922"
0459     " C 27.216,9.132 29.242,23.435 25.250,22.485"
0460     " C 22.700,22.632 22.131,22.902 20.038,22.518"
0461     " C 14.017,21.412 11.310,19.129 17.209,12.808"
0462     " C 0.858,20.547 -1.279,37.053 14.151,48.311"
0463     " C 8.665,41.481 16.731,35.528 20.131,44.676"
0464     " C 26.243,38.164 29.892,38.528 32.120,50.180"
0465     " C 34.405,38.488 38.054,38.124 44.167,44.635"
0466     " C 47.567,35.487 55.633,41.441 50.146,48.271"
0467     " C 65.577,37.013 63.439,20.507 47.089,12.768"
0468     " C 52.987,19.089 50.281,21.372 44.260,22.477"
0469     " C 42.166,22.862 41.597,22.592 39.047,22.445"
0470     " C 35.056,23.395 37.070,9.162 35.806,10.949"
0471     " C 34.970,12.130 35.321,12.669 34.242,14.147"
0472     " C 33.975,14.570 32.841,14.787 31.374,14.777 z'/>"
0473     "</svg>";
0474 
0475 static const char *svg_rat =
0476     "<svg width='64' height='64'>"
0477     "<path style='fill:#000000'"
0478     " d='M 37.966,10.702"
0479     " C 32.946,10.674 26.432,11.605 20.582,16.078"
0480     " C 19.781,16.691 20.028,14.288 19.307,14.084"
0481     " C 16.546,12.762 16.018,13.323 15.487,15.518"
0482     " C 15.440,15.712 14.021,15.893 13.561,15.455"
0483     " C 13.561,15.455 13.079,12.719 12.164,14.205"
0484     " C 11.787,14.818 11.688,13.574 10.500,15.472"
0485     " C 10.195,15.959 11.279,16.212 11.279,16.212"
0486     " C 11.279,16.212 7.825,19.421 7.869,20.140"
0487     " C 7.817,20.879 3.397,23.614 3.003,24.316"
0488     " C 2.285,25.598 5.593,27.321 9.036,26.688"
0489     " C 15.133,24.334 13.390,27.117 20.559,32.120"
0490     " C 20.559,32.120 20.490,33.826 20.491,34.474"
0491     " C 20.491,35.221 17.934,35.078 17.999,35.470"
0492     " C 18.077,35.949 17.590,35.794 17.702,36.316"
0493     " C 17.702,36.316 17.698,36.693 17.769,37.147"
0494     " C 17.685,37.334 19.341,36.803 19.472,37.475"
0495     " C 19.721,37.833 20.264,36.338 20.264,36.338"
0496     " C 20.544,35.759 21.054,35.192 21.890,36.278"
0497     " C 22.329,36.847 21.930,32.105 21.930,32.105"
0498     " C 21.930,32.105 27.859,33.031 27.478,34.460"
0499     " C 27.017,36.193 25.302,37.245 25.302,37.245"
0500     " C 23.675,37.429 23.683,37.998 23.440,38.876"
0501     " C 23.257,39.298 24.390,39.555 25.819,39.147"
0502     " C 26.419,38.871 26.508,39.644 26.726,39.392"
0503     " C 26.832,38.455 26.835,38.181 27.518,38.994"
0504     " C 27.263,36.857 29.360,35.554 29.435,35.442"
0505     " C 30.664,35.520 31.209,35.547 31.638,35.304"
0506     " C 32.010,34.551 33.203,34.079 35.435,33.716"
0507     " C 38.129,34.629 41.428,35.382 41.335,35.737"
0508     " C 41.206,36.225 36.891,35.726 37.019,37.589"
0509     " C 37.037,37.999 38.802,37.810 39.455,38.240"
0510     " C 39.756,38.296 41.215,37.707 42.661,36.513"
0511     " C 47.291,36.531 45.592,36.114 46.395,34.658"
0512     " C 46.623,34.246 54.256,35.533 55.788,33.790"
0513     " C 71.658,42.231 45.020,46.142 35.779,49.254"
0514     " C 31.072,50.987 13.462,51.472 12.112,52.822"
0515     " C 11.971,52.964 29.064,52.059 36.085,50.330"
0516     " C 79.669,41.497 56.851,34.139 56.427,30.933"
0517     " C 52.013,19.888 51.186,14.211 37.966,10.702 z'/>"
0518     "</svg>";
0519 
0520 struct IntroSource : public KMPlayer::Source {
0521     KMPlayerApp * m_app;
0522     IntroSource (KMPlayer::PartBase *p, KMPlayerApp * a)
0523         : KMPlayer::Source (i18n ("Intro"), p, "introsource"), m_app (a) {}
0524     bool hasLength () override { return false; }
0525     bool isSeekable () override { return false; }
0526     QString prettyName () override { return i18n ("Intro"); }
0527     void activate () override;
0528     void deactivate () override;
0529     void stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State os, KMPlayer::Node::State ns) override;
0530     bool deactivated;
0531     bool finished;
0532 };
0533 
0534 QString makeNumber (int i) {
0535     return QString (
0536             "<svg width='64' height='64'>"
0537             "<circle id='circle0' cx='32' cy='32' r='30' stroke='#B0B0B0'"
0538             "stroke-width='4' fill='#A0A0A0'/>"
0539             "<text x='15' y='50'"
0540             "font-family='Sans' font-size='55' fill='black'>%1</text>"
0541             "</svg>").arg (i);
0542 }
0543 
0544 void IntroSource::activate () {
0545     if (m_player->settings ()->autoresize)
0546         m_app->disconnect(m_player, &KMPlayer::PartBase::sourceDimensionChanged,
0547                           m_app, &KMPlayerApp::zoom100);
0548     m_document = new KMPlayer::SourceDocument (this, QString ());
0549     QString introfile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kmplayer/intro.xml");
0550     QFile file (introfile);
0551     if (file.exists () && file.open(QIODevice::ReadOnly)) {
0552         QTextStream ts (&file);
0553         KMPlayer::readXML (m_document, ts, QString (), false);
0554     } else {
0555         QString buf;
0556         QTextStream out(&buf, QIODevice::WriteOnly);
0557         out << "<smil><head><layout>"
0558             "<root-layout width='320' height='240' background-color='black'/>"
0559             "<region id='stage1' left='16' top='12' width='288' height='216'/>"
0560             "<region id='stage2' top='40' height='160'/>"
0561             "<region id='switch' top='30' width='20' height='20' right='20'/>"
0562             "<region id='reg' left='128' width='64' top='88' height='64' z-index='1'>"
0563             "<region id='icon' z-index='1'/>"
0564             "<region id='two' z-index='3'/>"
0565             "<region id='one' z-index='2'/>"
0566             "</region>"
0567             "<region id='spot' width='80' top='80' height='80'/>"
0568             "<region id='bat' left='208' width='64' top='48' height='64'/>"
0569             "<region id='rat' left='18' width='64' top='128' height='64'/>"
0570             "</layout>"
0571             "<transition id='clock1' dur='.3' type='clockWipe' direction='reverse'/>"
0572             "<transition id='fade1' dur='.1' type='fade'/>"
0573             "<transition id='fade2' dur='.2' type='fade'/>"
0574             "</head><body><excl><par>"
0575             "<brush region='stage1' dur='1' color='#303030'/>"
0576             "<img region='two' dur='.4' transIn='fade1' transOut='clock1'>" <<
0577             makeNumber (2) <<
0578             "</img><img region='switch' begin='0.08' dur='.1'>"
0579             "<svg width='20' height='20'>"
0580             "<path fill='white' d='M 2 2 L 18 2 L 9 12.7 z'/>"
0581             "</svg></img>"
0582             "<img region='one' begin='.1' dur='.8' transOut='clock1'>" <<
0583             makeNumber (1) <<
0584             "</img><img region='switch' begin='.7' dur='.1'>"
0585             "<svg width='20' height='20'>"
0586             "<circle fill='white' cx='9' cy='9' r='9'/>"
0587             "</svg></img>"
0588             "<brush region='stage2' begin='1.5' dur='.4' color='#101020'/>"
0589             "<img region='spot' begin='1' dur='.3' transIn='fade1' repeat='3'>"
0590             "<svg width='80' height='80'>"
0591             "<circle id='light' fill='red' cx='40' cy='40' r='40'/>"
0592             "</svg>"
0593             "</img>"
0594             "<img region='bat' begin='1' dur='.9'>" <<
0595             svg_bat <<
0596             "</img>"
0597             "<img region='rat' begin='1.2' dur='.7'>" <<
0598             svg_rat <<
0599             "</img>"
0600             "<animateMotion target='spot' begin='1' dur='.9' "
0601             "calcMode='discrete' values='200,40;10,120;120,80'/>"
0602             "<animate target='light' begin='1' dur='.9' calcMode='discrete'"
0603             "attribute='fill' values='#A04040;#40A040;#4040A0'/>"
0604             "<img region='icon' begin='1.5' dur='0.4' transIn='fade2' "
0605             "transOut='fade1' fit='meet' src='" <<
0606             KIconLoader::global()->iconPath (QString::fromLatin1 ("kmplayer"), -128) <<
0607             "'/></par><seq begin='stage1.activateEvent'/>"
0608             "</excl></body></smil>";
0609 
0610         QTextStream ts(&buf, QIODevice::ReadOnly);
0611         KMPlayer::readXML (m_document, ts, QString (), false);
0612     }
0613     //m_document->normalize ();
0614     m_current = m_document; //mrl->self ();
0615     if (m_document && m_document->firstChild ()) {
0616         KMPlayer::Mrl * mrl = m_document->firstChild ()->mrl ();
0617         if (mrl) {
0618             Source::setDimensions (m_document->firstChild (), mrl->size.width, mrl->size.height);
0619             m_player->updateTree ();
0620             m_current->activate ();
0621             Q_EMIT startPlaying ();
0622         }
0623     }
0624     deactivated = finished = false;
0625 }
0626 
0627 void IntroSource::stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State, KMPlayer::Node::State new_state) {
0628     if (new_state == KMPlayer::Node::state_deactivated &&
0629             m_document == node) {
0630         m_document->reset ();
0631         finished = true;
0632         if (m_player->view ())
0633             m_app->restoreFromConfig ();
0634         Q_EMIT stopPlaying ();
0635         if (!deactivated) // replace introsource with urlsource
0636             m_player->openUrl (QUrl ());
0637     }
0638 }
0639 
0640 void IntroSource::deactivate () {
0641     deactivated = true;
0642     if (m_player->settings ()->autoresize)
0643         m_app->connect(m_player, &KMPlayer::PartBase::sourceDimensionChanged,
0644                        m_app, &KMPlayerApp::zoom100);
0645     if (!finished && m_document) // user opens a source while introducing
0646         m_document->reset ();
0647 }
0648 #endif
0649 
0650 void KMPlayerApp::restoreFromConfig () {
0651     if (m_player->view ()) {
0652         m_view->dockArea ()->hide ();
0653         KConfigGroup dock_cfg (KSharedConfig::openConfig(), "Window Layout");
0654         m_view->dockArea ()->restoreState (dock_cfg.readEntry ("Layout", QByteArray ()));
0655         m_view->dockPlaylist ()->setVisible (dock_cfg.readEntry ("Show playlist", false));
0656         m_view->dockArea ()->show ();
0657         m_view->layout ()->activate ();
0658     }
0659 }
0660 
0661 void KMPlayerApp::openDocumentFile (const QUrl& url)
0662 {
0663     if (!m_played_intro) {
0664         m_played_intro = true;
0665         KMPlayer::Source * src = m_player->sources () ["urlsource"];
0666         if (url.isEmpty () && src->document () &&
0667                 src->document ()->hasChildNodes ()) {
0668             restoreFromConfig ();
0669             m_player->setSource (src);
0670             return;
0671 #ifdef KMPLAYER_WITH_CAIRO
0672         } else if (!m_player->settings ()->no_intro && url.isEmpty ()) {
0673             m_player->setSource (new IntroSource (m_player, this));
0674             return;
0675 #endif
0676         } else {
0677             m_played_exit = true; // no intro, so no exit as well
0678             restoreFromConfig ();
0679         }
0680     }
0681     slotStatusMsg(i18n("Opening file..."));
0682     m_player->openUrl (url);
0683     /*if (m_broadcastconfig->broadcasting () && url.url() == m_broadcastconfig->serverURL ()) {
0684         // speed up replay
0685         FFServerSetting & ffs = m_broadcastconfig->ffserversettings;
0686         KMPlayer::Source * source = m_player->source ();
0687         if (!ffs.width.isEmpty () && !ffs.height.isEmpty ()) {
0688             source->setWidth (ffs.width.toInt ());
0689             source->setHeight (ffs.height.toInt ());
0690         }
0691         source->setIdentified ();
0692     }*/
0693     slotStatusMsg (i18n ("Ready."));
0694 }
0695 
0696 void KMPlayerApp::addUrl (const QUrl& url) {
0697     KMPlayer::Source * src = m_player->sources () ["urlsource"];
0698     KMPlayer::NodePtr d = src->document ();
0699     if (d)
0700         d->appendChild (new KMPlayer::GenericURL (d,
0701                     url.isLocalFile() ? url.toLocalFile() : url.url()));
0702 }
0703 
0704 void KMPlayerApp::saveProperties (KConfigGroup &def_cfg) {
0705     def_cfg.writeEntry ("URL", m_player->source ()->url ().url ());
0706     def_cfg.writeEntry ("Visible", isVisible ());
0707 }
0708 
0709 void KMPlayerApp::readProperties (const KConfigGroup &def_cfg) {
0710     QUrl url (def_cfg.readEntry ("URL", QString ()));
0711     openDocumentFile (url);
0712     if (!def_cfg.readEntry ("Visible", true) && m_systray)
0713         hide ();
0714 }
0715 
0716 void KMPlayerApp::resizePlayer (int /*percentage*/) {
0717     /*KMPlayer::Source * source = m_player->source ();
0718     if (!source)
0719         return;
0720     int w, h;
0721     source->dimensions (w, h);
0722     if (w == 0 && h == 0) {
0723         w = 320;
0724         h = 240;
0725     } else
0726         h = m_view->viewer ()->heightForWidth (w);
0727     //qCDebug(LOG_KMPLAYER_APP) << "KMPlayerApp::resizePlayer (" << w << "," << h << ")";
0728     if (w > 0 && h > 0) {
0729         if (m_view->controlPanel ()->isVisible ())
0730             h += m_view->controlPanel ()->size ().height ();
0731         QSize s1 = size ();
0732         QSize s2 = m_view->viewArea ()->size ();
0733         w += s1.width () - s2.width ();
0734         h += s1.height () - s2.height ();
0735         w = int (1.0 * w * percentage/100.0);
0736         h = int (1.0 * h * percentage/100.0);
0737         QSize s = sizeForCentralWidgetSize (QSize (w, h));
0738         if (s.width () != width () || s.height () != height ()) {
0739             QSize oldsize = m_view->viewArea ()->size ();
0740             resize (s);
0741         }
0742     }*/
0743 }
0744 
0745 void KMPlayerApp::zoom50 () {
0746     resizePlayer (50);
0747 }
0748 
0749 void KMPlayerApp::zoom100 () {
0750     resizePlayer (100);
0751 }
0752 
0753 void KMPlayerApp::zoom150 () {
0754     resizePlayer (150);
0755 }
0756 
0757 void KMPlayerApp::editMode () {
0758     //m_view->dockArea ()->hide ();
0759     bool editmode = !m_view->editMode ();
0760     KMPlayer::PlayItem * pi = m_view->playList ()->selectedItem ();
0761     if (!pi || !pi->node)
0762         editmode = false;
0763     //m_view->dockArea ()->show ();
0764     viewEditMode->setChecked (editmode);
0765     KMPlayer::TopPlayItem * ri = (edit_tree_id > 0 && !editmode)
0766         ? m_view->playList ()->rootItem (edit_tree_id)
0767         : pi->rootItem ();
0768     if (editmode) {
0769         edit_tree_id = ri->id;
0770         m_view->setEditMode (ri, true);
0771         m_view->setInfoMessage (pi->node->innerXML ());
0772         viewSyncEditMode->setEnabled (true);
0773     } else {
0774         m_view->setEditMode (ri, false);
0775         edit_tree_id = -1;
0776         viewSyncEditMode->setEnabled (!strcmp (m_player->source()->name (), "urlsource"));
0777     }
0778 }
0779 
0780 void KMPlayerApp::syncEditMode () {
0781     if (edit_tree_id > -1) {
0782         KMPlayer::PlayItem *si = m_view->playList()->selectedItem();
0783         if (si && si->node) {
0784             si->node->clearChildren ();
0785             QString txt = m_view->infoPanel ()->toPlainText();
0786             QTextStream ts (&txt, QIODevice::ReadOnly);
0787             KMPlayer::readXML (si->node, ts, QString (), false);
0788             m_player->playModel()->updateTree (edit_tree_id, si->node->document(), si->node, true, false);
0789         }
0790     } else
0791         m_player->openUrl (m_player->source ()->url ());
0792 }
0793 
0794 void KMPlayerApp::showBroadcastConfig () {
0795     /*m_player->settings ()->addPage (m_broadcastconfig);
0796     m_player->settings ()->addPage (m_ffserverconfig);*/
0797 }
0798 
0799 void KMPlayerApp::hideBroadcastConfig () {
0800     /*m_player->settings ()->removePage (m_broadcastconfig);
0801     m_player->settings ()->removePage (m_ffserverconfig);*/
0802 }
0803 
0804 void KMPlayerApp::broadcastClicked () {
0805     /*if (m_broadcastconfig->broadcasting ())
0806         m_broadcastconfig->stopServer ();
0807     else {
0808         m_player->settings ()->show ("BroadcastPage");
0809         m_view->controlPanel()->broadcastButton ()->toggle ();
0810     }*/
0811 }
0812 
0813 void KMPlayerApp::broadcastStarted () {
0814     /*if (!m_view->controlPanel()->broadcastButton ()->isOn ())
0815         m_view->controlPanel()->broadcastButton ()->toggle ();*/
0816 }
0817 
0818 void KMPlayerApp::broadcastStopped () {
0819     /*if (m_view->controlPanel()->broadcastButton ()->isOn ())
0820         m_view->controlPanel()->broadcastButton ()->toggle ();
0821     if (m_player->source () != m_player->sources () ["tvsource"])
0822         m_view->controlPanel()->broadcastButton ()->hide ();
0823     setCursor (QCursor (Qt::ArrowCursor));*/
0824 }
0825 
0826 bool KMPlayerApp::broadcasting () const {
0827     //return m_broadcastconfig->broadcasting ();
0828     return false;
0829 }
0830 
0831 void KMPlayerApp::saveOptions()
0832 {
0833     KSharedConfigPtr config = KSharedConfig::openConfig ();
0834     KConfigGroup general (config, "General Options");
0835     if (m_player->settings ()->remembersize)
0836         general.writeEntry ("Geometry", size ());
0837     general.writeEntry ("Show Toolbar", viewToolBar->isChecked());
0838     general.writeEntry ("Show Statusbar", viewStatusBar->isChecked ());
0839     general.writeEntry ("Show Menubar", viewMenuBar->isChecked ());
0840     if (!m_player->sources () ["pipesource"]->pipeCmd ().isEmpty ()) {
0841         KConfigGroup (config, "Pipe Command").writeEntry (
0842                 "Command1", m_player->sources () ["pipesource"]->pipeCmd ());
0843     }
0844     m_view->setInfoMessage (QString ());
0845     KConfigGroup dock_cfg (KSharedConfig::openConfig(), "Window Layout");
0846     dock_cfg.writeEntry ("Layout", m_view->dockArea ()->saveState ());
0847     dock_cfg.writeEntry ("Show playlist", m_view->dockPlaylist ()->isVisible ());
0848     KConfigGroup toolbar_cfg (KSharedConfig::openConfig(), "Main Toolbar");
0849     toolBar("mainToolBar")->saveSettings (toolbar_cfg);
0850     Recents * rc = static_cast <Recents *> (recents.ptr ());
0851     if (rc && rc->resolved) {
0852         fileOpenRecent->saveEntries (KConfigGroup (config, "Recent Files"));
0853         rc->sync(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/recent.xml");
0854     }
0855     Playlist * pl = static_cast <Playlist *> (playlist.ptr ());
0856     if (pl && pl->resolved)
0857         pl->sync(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/playlist.xml");
0858 }
0859 
0860 
0861 void KMPlayerApp::readOptions() {
0862     KSharedConfigPtr config = KSharedConfig::openConfig ();
0863 
0864     KConfigGroup gen_cfg (config, "General Options");
0865 
0866     // bar status settings
0867     viewToolBar->setChecked (gen_cfg.readEntry("Show Toolbar", true));
0868     slotViewToolBar();
0869 
0870     bool bViewStatusbar = gen_cfg.readEntry("Show Statusbar", true);
0871     viewStatusBar->setChecked(bViewStatusbar);
0872     slotViewStatusBar();
0873 
0874     viewMenuBar->setChecked (gen_cfg.readEntry("Show Menubar", true));
0875     slotViewMenuBar();
0876 
0877     QSize size = gen_cfg.readEntry ("Geometry", QSize ());
0878     if (!size.isEmpty ())
0879         resize (size);
0880     else if (m_player->settings ()->remembersize)
0881         resize (QSize (640, 480));
0882 
0883     KConfigGroup toolbar_cfg (KSharedConfig::openConfig(), "Main Toolbar");
0884     toolBar("mainToolBar")->applySettings (toolbar_cfg);
0885     KConfigGroup pipe_cfg (config, "Pipe Command");
0886     static_cast <KMPlayerPipeSource *> (m_player->sources () ["pipesource"])->setCommand (
0887             pipe_cfg.readEntry ("Command1", QString ()));
0888     // initialize the recent file list
0889     if (!recents) {
0890         QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
0891         dir.mkpath(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer");
0892         fileOpenRecent->loadEntries (KConfigGroup (config, "Recent Files"));
0893         recents = new Recents (this);
0894         recents_id = m_player->playModel()->addTree (recents, "listssource", "view-history", KMPlayer::PlayModel::AllowDrag);
0895     }
0896     configChanged ();
0897 }
0898 
0899 #include <netwm.h>
0900 #undef Always
0901 #undef Never
0902 #undef Status
0903 #undef Unsorted
0904 #undef Bool
0905 
0906 void KMPlayerApp::minimalMode (bool by_user) {
0907     /*unsigned long props = NET::WMWindowType;
0908     NETWinInfo winfo (QX11Info::display (), winId (), QX11Info::appRootWindow(), props);
0909     if (m_minimal_mode) {
0910         winfo.setWindowType (NET::Normal);
0911         readOptions ();
0912         if (by_user)
0913             disconnect (m_view->controlPanel ()->button (KMPlayer::ControlPanel::button_playlist), SIGNAL (clicked ()), this, SLOT (slotMinimalMode ()));
0914         restoreFromConfig ();
0915     } else {
0916         saveOptions ();
0917         menuBar()->hide();
0918         toolBar("mainToolBar")->hide();
0919         statusBar()->hide();
0920         if (by_user)
0921             connect (m_view->controlPanel ()->button (KMPlayer::ControlPanel::button_playlist), SIGNAL (clicked ()), this, SLOT (slotMinimalMode ()));
0922         if (by_user)
0923             winfo.setWindowType (NET::Utility);
0924     }
0925     m_view->viewArea ()->minimalMode ();
0926     if (by_user) {
0927         QRect rect = m_view->viewArea ()->topWindowRect ();
0928         hide ();
0929         QTimer::singleShot (0, this, SLOT (zoom100 ()));
0930         show ();
0931         move (rect.x (), rect.y ());
0932     }
0933     m_minimal_mode = !m_minimal_mode;*/
0934 }
0935 
0936 void KMPlayerApp::slotMinimalMode () {
0937     minimalMode (true);
0938 }
0939 
0940 #ifdef KMPLAYER_WITH_CAIRO
0941 struct ExitSource : public KMPlayer::Source {
0942     ExitSource (KMPlayer::PartBase *p)
0943         : KMPlayer::Source (i18n ("Exit"), p, "exitsource") {}
0944     QString prettyName () override { return i18n ("Exit"); }
0945     bool hasLength () override { return false; }
0946     bool isSeekable () override { return false; }
0947     void activate () override;
0948     void deactivate () override {}
0949     void stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State os, KMPlayer::Node::State ns) override;
0950 };
0951 
0952 void ExitSource::activate () {
0953     m_document = new KMPlayer::SourceDocument (this, QString ());
0954     QString exitfile = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kmplayer/exit.xml");
0955     QFile file (exitfile);
0956     if (file.exists () && file.open (QIODevice::ReadOnly)) {
0957         QTextStream ts (&file);
0958         KMPlayer::readXML (m_document, ts, QString (), false);
0959     } else {
0960         QString smil = QString::fromLatin1 ("<smil><head><layout>"
0961           "<root-layout width='320' height='240' background-color='black'/>"
0962           "<region top='40' height='160' background-color='#101020'>"
0963           "<region id='image' left='128' top='28' width='64' bottom='28'/>"
0964           "</region></layout>"
0965           "<transition id='pw' dur='0.3' type='pushWipe' subtype='fromBottom'/>"
0966           "</head><body>"
0967           "<par>"
0968           //"<animate target='reg1' attribute='background-color' calcMode='discrete' values='#FFFFFF;#E4E4E4;#CCCCCC;#B4B4B4;#9E9E9E;#8A8A8A;#777777;#656565;#555555;#464646;#393939;#2D2D2D;#222222;#191919;#111111;#0B0B0B;#060606;#020202;#000000;#000000' dur='0.6'/>"
0969           "<img src='%2' id='img1' region='image' dur='0.4' fit='hidden' transOut='pw'/>"
0970           "</par>"
0971           "</body></smil>").arg (KIconLoader::global()->iconPath (QString::fromLatin1 ("kmplayer"), -64));
0972         QByteArray ba = smil.toUtf8 ();
0973         QTextStream ts (&ba, QIODevice::ReadOnly);
0974         KMPlayer::readXML (m_document, ts, QString (), false);
0975     }
0976     //m_document->normalize ();
0977     m_current = m_document;
0978     if (m_document && m_document->firstChild ()) {
0979         KMPlayer::Mrl * mrl = m_document->firstChild ()->mrl ();
0980         if (mrl) {
0981             setDimensions (m_document->firstChild (), mrl->size.width, mrl->size.height);
0982             m_player->updateTree ();
0983             m_current->activate ();
0984             Q_EMIT startPlaying ();
0985             return;
0986         }
0987     }
0988     qApp->quit ();
0989 }
0990 
0991 void ExitSource::stateElementChanged (KMPlayer::Node * node, KMPlayer::Node::State, KMPlayer::Node::State new_state) {
0992     if (new_state == KMPlayer::Node::state_deactivated &&
0993             m_document == node &&
0994             m_player->view ())
0995        m_player->view ()->topLevelWidget ()->close ();
0996 }
0997 #endif
0998 
0999 bool KMPlayerApp::queryClose () {
1000     // KMPlayerVDRSource has to wait for pending commands like mute and quit
1001     m_player->stop ();
1002     //static_cast <KMPlayerVDRSource *> (m_player->sources () ["vdrsource"])->waitForConnectionClose ();
1003     if (m_played_exit || m_player->settings ()->no_intro || qApp->isSavingSession()) {
1004         aboutToCloseWindow();
1005         return true;
1006     }
1007     if (m_auto_resize)
1008         disconnect(m_player, &KMPlayer::PartBase::sourceDimensionChanged,
1009                    this, &KMPlayerApp::zoom100);
1010     m_played_exit = true;
1011     if (!m_minimal_mode)
1012         minimalMode (false);
1013 #ifdef KMPLAYER_WITH_CAIRO
1014     m_player->setSource (new ExitSource (m_player));
1015     return false;
1016 #else
1017     aboutToCloseWindow();
1018     return true;
1019 #endif
1020 }
1021 
1022 void KMPlayerApp::aboutToCloseWindow()
1023 {
1024     if (!m_minimal_mode)
1025         saveOptions();
1026     disconnect (m_player->settings (), &KMPlayer::Settings::configChanged,
1027                 this, &KMPlayerApp::configChanged);
1028     m_player->settings ()->writeConfig ();
1029 }
1030 
1031 void KMPlayerApp::slotFileNewWindow()
1032 {
1033     slotStatusMsg(i18n("Opening a new application window..."));
1034 
1035     KMPlayerApp *new_window= new KMPlayerApp();
1036     new_window->show();
1037 
1038     slotStatusMsg(i18n("Ready."));
1039 }
1040 
1041 static bool findOpenLocation(QStandardPaths::StandardLocation type, QString* dir)
1042 {
1043     QStringList dirs = QStandardPaths::standardLocations(type);
1044     for (int i = 0; i < dirs.size(); ++i) {
1045         if (QDir(dirs[i]).exists()) {
1046             *dir = dirs[i];
1047             return true;
1048         }
1049     }
1050     return false;
1051 }
1052 
1053 void KMPlayerApp::slotFileOpen () {
1054     QString dir;
1055     if (!(findOpenLocation(QStandardPaths::MoviesLocation, &dir)
1056                 || findOpenLocation(QStandardPaths::MusicLocation, &dir)
1057                 || findOpenLocation(QStandardPaths::DesktopLocation, &dir)
1058                 || findOpenLocation(QStandardPaths::HomeLocation, &dir))) {
1059         dir = QString("/");
1060     }
1061     QList<QUrl> urls = QFileDialog::getOpenFileUrls(this, i18n("Open File"),
1062             QUrl::fromLocalFile(dir), QString());
1063     if (urls.size () == 1) {
1064         openDocumentFile (urls [0]);
1065     } else if (urls.size () > 1) {
1066         m_player->openUrl (QUrl ());
1067         for (int i = 0; i < urls.size (); i++)
1068             addUrl (urls [i]);
1069     }
1070 }
1071 
1072 void KMPlayerApp::slotFileOpenRecent(const QUrl& url)
1073 {
1074     slotStatusMsg(i18n("Opening file..."));
1075 
1076     openDocumentFile (url);
1077 
1078 }
1079 
1080 static bool findSaveLocation(QStandardPaths::StandardLocation type, QString* dir)
1081 {
1082     *dir = QStandardPaths::writableLocation(type);
1083     return !dir->isEmpty() && QDir(*dir).exists();
1084 }
1085 
1086 void KMPlayerApp::slotSaveAs () {
1087     QString dir;
1088     if (!(findSaveLocation(QStandardPaths::MoviesLocation, &dir)
1089                 || findSaveLocation(QStandardPaths::MusicLocation, &dir)
1090                 || findSaveLocation(QStandardPaths::DesktopLocation, &dir)
1091                 || findSaveLocation(QStandardPaths::HomeLocation, &dir))) {
1092         dir = QString("/tmp");
1093     }
1094     QString url = QFileDialog::getSaveFileName(this, i18n("Save File"), dir + QChar('/'));
1095     if (!url.isEmpty ()) {
1096         QFile file (url);
1097         if (!file.open (QIODevice::WriteOnly | QIODevice::Truncate)) {
1098             KMessageBox::error (this, i18n ("Error opening file %1.\n%2.",url,file.errorString ()), i18n("Error"));
1099             return;
1100         }
1101         if (m_player->source ()) {
1102             KMPlayer::NodePtr doc = m_player->source ()->document ();
1103             if (doc) {
1104                 QTextStream ts (&file);
1105                 ts.setCodec("UTF-8");
1106                 ts << QString ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1107                 if (doc->childNodes ().length () == 1)
1108                     ts << doc->innerXML ();
1109                 else
1110                     ts << doc->outerXML ();
1111             }
1112         }
1113         file.close ();
1114     }
1115 }
1116 
1117 void KMPlayerApp::slotClearHistory () {
1118     fileOpenRecent->clear ();
1119     int mi = fileOpenRecent->maxItems ();
1120     fileOpenRecent->setMaxItems (0);
1121     fileOpenRecent->setMaxItems (mi);
1122     m_player->settings ()->urllist.clear ();
1123     m_player->settings ()->sub_urllist.clear ();
1124     if (recents) { // small window this check fails and thus ClearHistory fails
1125         recents->defer (); // make sure it's loaded
1126         recents->clear ();
1127         m_player->playModel()->updateTree (recents_id, recents, nullptr, false, false);
1128     }
1129 }
1130 
1131 void KMPlayerApp::slotGeneratorMenu () {
1132     if (!generators.first ()) {
1133         const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kmplayer/generators", QStandardPaths::LocateDirectory);
1134         for (int i = 0; i < dirs.size(); ++i) {
1135             QDirIterator it(dirs[i], QStringList() << QStringLiteral("*.xml"));
1136             while (it.hasNext()) {
1137                 QString file = it.next();
1138                 Generator *gen = new Generator(this);
1139                 KMPlayer::NodePtr doc = gen;
1140                 gen->readFromFile(file);
1141                 KMPlayer::Node *n = gen->firstChild();
1142                 if (n && n->isElementNode()) {
1143                     QString name = static_cast<KMPlayer::Element*>(n)->getAttribute(
1144                             KMPlayer::Ids::attr_name);
1145                     if (name.isEmpty())
1146                         name = QFile(file).fileName();
1147                     generators.append(new KMPlayer::NodeStoreItem(doc));
1148                     m_generatormenu->addAction(name, this, &KMPlayerApp::slotGenerator);
1149                 } else {
1150                     gen->dispose();
1151                 }
1152             }
1153         }
1154     }
1155 }
1156 
1157 void KMPlayerApp::slotGenerator () {
1158     const QAction *act = qobject_cast <QAction *> (sender ());
1159     KMPlayer::NodeStoreItem *store = generators.first ();
1160     QObjectList chlds = m_generatormenu->children ();
1161 
1162     if (current_generator && current_generator->active ()) {
1163         current_generator->deactivate ();
1164         current_generator = nullptr;
1165     }
1166 
1167     for (int i = 0; store && i < chlds.size (); ++i) {
1168         const QAction *ca = qobject_cast <QAction *> (chlds[i]);
1169         if (ca && !ca->text ().isEmpty ()) {
1170             if (ca == act) {
1171                 current_generator = store->data;
1172                 break;
1173             }
1174             store = store->nextSibling ();
1175         }
1176     }
1177     if (current_generator)
1178         current_generator->activate ();
1179 }
1180 
1181 void KMPlayerApp::slotFileClose()
1182 {
1183     slotStatusMsg(i18n("Closing file..."));
1184 
1185     m_player->stop ();
1186 
1187     slotStatusMsg(i18n("Ready."));
1188 }
1189 
1190 void KMPlayerApp::slotFileQuit()
1191 {
1192     close();
1193 }
1194 
1195 void KMPlayerApp::slotPreferences () {
1196     m_player->showConfigDialog ();
1197 }
1198 
1199 void KMPlayerApp::slotConfigureKeys () {
1200   KShortcutsDialog::configure (actionCollection ());
1201 }
1202 
1203 void KMPlayerApp::slotConfigureToolbars () {
1204     //KEditToolbar dlg (actionCollection ());
1205     //if (dlg.exec ())
1206     //    initMenu (); // also add custom popups //createGUI ();
1207 }
1208 
1209 void KMPlayerApp::slotViewToolBar() {
1210     m_showToolbar = viewToolBar->isChecked();
1211     if(m_showToolbar)
1212         toolBar("mainToolBar")->show();
1213     else
1214         toolBar("mainToolBar")->hide();
1215 }
1216 
1217 void KMPlayerApp::slotViewStatusBar() {
1218     m_showStatusbar = viewStatusBar->isChecked();
1219     statusBar()->setVisible (m_showStatusbar);
1220 }
1221 
1222 void KMPlayerApp::slotViewMenuBar() {
1223     m_showMenubar = viewMenuBar->isChecked();
1224     if (m_showMenubar) {
1225         menuBar()->show();
1226         slotStatusMsg(i18n("Ready"));
1227     } else {
1228         menuBar()->hide();
1229         slotStatusMsg (i18n ("Show Menu Bar with %1",
1230                     viewMenuBar->shortcut ().toString ()));
1231         if (!m_showStatusbar) {
1232             statusBar()->show();
1233             QTimer::singleShot (3000, statusBar(), &QWidget::hide);
1234         }
1235     }
1236 }
1237 
1238 void KMPlayerApp::slotStatusMsg (const QString &text) {
1239     QStatusBar * sb = statusBar ();
1240     sb->showMessage(text);
1241 }
1242 
1243 void KMPlayerApp::fullScreen () {
1244     if (qobject_cast <QAction *> (sender ()))
1245         m_view->fullScreen();
1246     viewFullscreen->setChecked (m_view->isFullScreen ());
1247     if (m_view->isFullScreen())
1248         hide ();
1249     else {
1250         show ();
1251         setGeometry (m_view->viewArea ()->topWindowRect ());
1252     }
1253 }
1254 
1255 void KMPlayerApp::playListItemActivated (const QModelIndex& index) {
1256     KMPlayer::PlayItem * vi = static_cast <KMPlayer::PlayItem *> (index.internalPointer ());
1257     if (edit_tree_id > -1) {
1258         if (vi->rootItem ()->id != edit_tree_id)
1259             editMode ();
1260         m_view->setInfoMessage (edit_tree_id > -1 && vi->node
1261                 ? vi->node->innerXML () : QString ());
1262     }
1263     viewEditMode->setEnabled (vi->rootItem ()->itemFlags() & KMPlayer::PlayModel::TreeEdit);
1264 }
1265 
1266 void KMPlayerApp::playListItemDropped (QDropEvent *de, KMPlayer::PlayItem *item) {
1267     KMPlayer::TopPlayItem *ritem = item->rootItem();
1268     QUrl url;
1269 
1270     manip_node = nullptr;
1271     m_drop_list.clear ();
1272 
1273     if (de->mimeData()->hasFormat ("text/uri-list")) {
1274         m_drop_list = de->mimeData()->urls();
1275     } else if (de->mimeData ()->hasFormat ("application/x-qabstractitemmodeldatalist")) {
1276         KMPlayer::PlayItem* pli = m_view->playList()->selectedItem ();
1277         if (pli && pli->node) {
1278             manip_node = pli->node;
1279             if (pli->node->mrl ()) {
1280                 QUrl url = QUrl::fromUserInput(pli->node->mrl ()->src);
1281                 if (url.isValid ())
1282                     m_drop_list.push_back (url);
1283             }
1284         }
1285     }
1286     if (m_drop_list.isEmpty ()) {
1287         const QUrl url = QUrl::fromUserInput(de->mimeData ()->text ());
1288         if (url.isValid ())
1289             m_drop_list.push_back (url);
1290     }
1291     if (ritem->id == 0) {
1292         if (m_drop_list.size () > 0) {
1293             if (m_drop_list.size () == 1) {
1294                 url = m_drop_list[0];
1295             } else if (m_drop_list.size () > 1) {
1296                 m_player->sources () ["urlsource"]->setUrl (QString ());
1297                 for (int i = 0; i < m_drop_list.size (); i++)
1298                     addUrl (m_drop_list[i]);
1299             }
1300             openDocumentFile (url);
1301         }
1302     } else {
1303         m_drop_after = item;
1304         KMPlayer::NodePtr after_node = static_cast<KMPlayer::PlayItem*> (item)->node;
1305         if (after_node->id == KMPlayer::id_node_playlist_document ||
1306                 after_node->id == KMPlayer::id_node_group_node)
1307             after_node->defer (); // make sure it has loaded
1308         dropAdd->setText(!!manip_node ? i18n ("Move here") : i18n ("&Add to list"));
1309         dropDelete->setVisible(!!manip_node);
1310         dropCopy->setVisible(manip_node && manip_node->isPlayable ());
1311         if (manip_node || m_drop_list.size () > 0)
1312             m_dropmenu->exec (m_view->playList ()->mapToGlobal (de->pos ()));
1313     }
1314 }
1315 
1316 void KMPlayerApp::menuDropInList () {
1317     KMPlayer::NodePtr n = m_drop_after->node;
1318     KMPlayer::NodePtr pi;
1319     for (int i = m_drop_list.size (); n && (i > 0 || manip_node); i--) {
1320         if (manip_node && manip_node->parentNode ()) {
1321             pi = manip_node;
1322             manip_node = nullptr;
1323             pi->parentNode ()->removeChild (pi);
1324         } else
1325             pi = new PlaylistItem(playlist, this,false, m_drop_list[i-1].url());
1326         if (n == playlist
1327                 || (KMPlayer::id_node_playlist_item != n->id
1328                     && m_view->playList()->isExpanded (m_view->playList()->index(m_drop_after)))) {
1329             n->insertBefore (pi, n->firstChild ());
1330         } else if (n->parentNode ()) {
1331             n->parentNode ()->insertBefore (pi, n->nextSibling ());
1332         }
1333     }
1334     m_player->playModel()->updateTree (playlist_id, playlist, pi, true, false);
1335 }
1336 
1337 void KMPlayerApp::menuDropInGroup () {
1338     KMPlayer::NodePtr n = m_drop_after->node;
1339     if (!n)
1340         return;
1341     KMPlayer::NodePtr g = new PlaylistGroup (playlist, this, i18n("New group"));
1342     if (n == playlist
1343             || (KMPlayer::id_node_playlist_item != n->id
1344                 && m_view->playList()->isExpanded (m_view->playList()->index(m_drop_after)))) {
1345         n->insertBefore (g, n->firstChild ());
1346     } else {
1347         n->parentNode ()->insertBefore (g, n->nextSibling ());
1348     }
1349     KMPlayer::NodePtr pi;
1350     for (int i = 0; i < m_drop_list.size () || manip_node; ++i) {
1351         if (manip_node && manip_node->parentNode ()) {
1352             pi = manip_node;
1353             manip_node = nullptr;
1354             pi->parentNode ()->removeChild (pi);
1355         } else
1356             pi = new PlaylistItem (playlist,this, false, m_drop_list[i].url ());
1357         g->appendChild (pi);
1358     }
1359     m_player->playModel()->updateTree (playlist_id, playlist, pi, true, false);
1360 }
1361 
1362 void KMPlayerApp::menuCopyDrop () {
1363     KMPlayer::NodePtr n = m_drop_after->node;
1364     if (n && manip_node) {
1365         KMPlayer::NodePtr pi = new PlaylistItem (playlist, this, false, manip_node->mrl ()->src);
1366         if (n == playlist
1367                 || (KMPlayer::id_node_playlist_item != n->id
1368                     && m_view->playList()->isExpanded (m_view->playList()->index(m_drop_after)))) {
1369             n->insertBefore (pi, n->firstChild ());
1370         } else {
1371             n->parentNode ()->insertBefore (pi, n->nextSibling ());
1372         }
1373         m_player->playModel()->updateTree (playlist_id, playlist, pi, true, false);
1374     }
1375 }
1376 
1377 void KMPlayerApp::menuDeleteNode () {
1378     KMPlayer::Node *n = nullptr;
1379     if (manip_node && manip_node->parentNode ()) {
1380         n = manip_node->previousSibling() ? manip_node->previousSibling() : manip_node->parentNode ();
1381         manip_node->parentNode ()->removeChild (manip_node);
1382     }
1383     m_player->playModel()->updateTree (manip_tree_id, nullptr, n, true, false);
1384 }
1385 
1386 void KMPlayerApp::menuMoveUpNode () {
1387     KMPlayer::NodePtr n = manip_node.ptr ();
1388     if (n && n->parentNode () && n->previousSibling ()) {
1389         KMPlayer::Node *prev = n->previousSibling ();
1390         n->parentNode ()->removeChild (n);
1391         prev->parentNode ()->insertBefore (n, prev);
1392     }
1393     m_player->playModel()->updateTree (manip_tree_id, nullptr, n, true, false);
1394 }
1395 
1396 void KMPlayerApp::menuMoveDownNode () {
1397     KMPlayer::NodePtr n = manip_node.ptr ();
1398     if (n && n->parentNode () && n->nextSibling ()) {
1399         KMPlayer::Node *next = n->nextSibling ();
1400         n->parentNode ()->removeChild (n);
1401         next->parentNode ()->insertBefore (n, next->nextSibling ());
1402     }
1403     m_player->playModel()->updateTree (manip_tree_id, nullptr, n, true, false);
1404 }
1405 
1406 void KMPlayerApp::playListItemMoved () {
1407     KMPlayer::PlayItem *si = m_view->playList ()->selectedItem ();
1408     KMPlayer::TopPlayItem * ri = si->rootItem ();
1409     qCDebug(LOG_KMPLAYER_APP) << "playListItemMoved " << (ri->id == playlist_id) << !! si->node;
1410     if (ri->id == playlist_id && si->node) {
1411         KMPlayer::Node *p = si->node->parentNode ();
1412         if (p) {
1413             p->removeChild (si->node);
1414             m_player->playModel()->updateTree(playlist_id,playlist,nullptr,false,false);
1415         }
1416     }
1417 }
1418 
1419 void KMPlayerApp::preparePlaylistMenu (KMPlayer::PlayItem * item, QMenu * pm) {
1420     KMPlayer::TopPlayItem *ri = item->rootItem ();
1421     if (ri != item
1422             && item->node
1423             && ri->item_flags & (KMPlayer::PlayModel::Moveable | KMPlayer::PlayModel::Deleteable)) {
1424         manip_tree_id = ri->id;
1425         pm->addSeparator();
1426         manip_node = item->node;
1427         if (ri->item_flags & KMPlayer::PlayModel::Deleteable)
1428             pm->addAction(QIcon::fromTheme("edit-delete"), i18n("&Delete item"), this, &KMPlayerApp::menuDeleteNode);
1429         if (ri->item_flags & KMPlayer::PlayModel::Moveable) {
1430             if (manip_node->previousSibling ())
1431                 pm->addAction(QIcon::fromTheme("go-up"), i18n("&Move up"), this, &KMPlayerApp::menuMoveUpNode);
1432             if (manip_node->nextSibling ())
1433                 pm->addAction(QIcon::fromTheme("go-down"), i18n("Move &down"), this, &KMPlayerApp::menuMoveDownNode);
1434         }
1435     }
1436 }
1437 
1438 void KMPlayerApp::configChanged () {
1439     //viewKeepRatio->setChecked (m_player->settings ()->sizeratio);
1440     if (m_player->settings ()->docksystray && !m_systray) {
1441         m_systray = new QSystemTrayIcon (QIcon::fromTheme("kmplayer"), this);
1442         m_systray->show ();
1443     } else if (!m_player->settings ()->docksystray && m_systray) {
1444         delete m_systray;
1445         m_systray = nullptr;
1446     }
1447     if (m_player->settings ()->autoresize && !m_auto_resize)
1448         connect(m_player, &KMPlayer::PartBase::sourceDimensionChanged,
1449                 this, &KMPlayerApp::zoom100);
1450     else if (!m_player->settings ()->autoresize && m_auto_resize)
1451         disconnect(m_player, &KMPlayer::PartBase::sourceDimensionChanged,
1452                    this, &KMPlayerApp::zoom100);
1453     m_auto_resize = m_player->settings ()->autoresize;
1454 }
1455 
1456 void KMPlayerApp::keepSizeRatio () {
1457     m_view->setKeepSizeRatio (!m_view->keepSizeRatio ());
1458     m_player->settings ()->sizeratio = m_view->keepSizeRatio ();
1459     //viewKeepRatio->setChecked (m_view->keepSizeRatio ());
1460 }
1461 
1462 //-----------------------------------------------------------------------------
1463 
1464 KMPlayerPrefSourcePageDVD::KMPlayerPrefSourcePageDVD (QWidget * parent)
1465  : QFrame(parent) {
1466     QVBoxLayout *layout = new QVBoxLayout;
1467     autoPlayDVD = new QCheckBox (i18n ("Auto play after opening DVD"));
1468     autoPlayDVD->setWhatsThis(i18n("Start playing DVD right after opening DVD"));
1469     QLabel *dvdDevicePathLabel = new QLabel (i18n("DVD device:"));
1470     dvddevice = new KUrlRequester (QUrl::fromLocalFile("/dev/dvd"));
1471     dvddevice->setWhatsThis(i18n("Path to your DVD device, you must have read rights to this device"));
1472     layout->addWidget (autoPlayDVD);
1473     layout->addItem (new QSpacerItem (0, 10, QSizePolicy::Minimum, QSizePolicy::Minimum));
1474     layout->addWidget (dvdDevicePathLabel);
1475     layout->addWidget (dvddevice);
1476     layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
1477     setLayout(layout);
1478 }
1479 
1480 //-----------------------------------------------------------------------------
1481 
1482 class Disks : public KMPlayer::Document
1483 {
1484 public:
1485     Disks (KMPlayerApp * a);
1486     void message (KMPlayer::MessageType msg, void *data) override;
1487     KMPlayerApp * app;
1488 };
1489 
1490 class Disk : public KMPlayer::Mrl
1491 {
1492 public:
1493     Disk (KMPlayer::NodePtr & doc, KMPlayerApp *a, const QString &url, const QString &pn);
1494     void activate () override;
1495     KMPlayerApp * app;
1496 };
1497 
1498 Disks::Disks (KMPlayerApp * a)
1499                 : KMPlayer::Document ("disks://", nullptr), app (a) {
1500     id = id_node_disk_document;
1501     resolved = true;
1502     bookmarkable = false;
1503     title = i18n ("Optical Disks");
1504 }
1505 
1506 void Disks::message (KMPlayer::MessageType msg, void *data) {
1507     if (KMPlayer::MsgChildFinished == msg)
1508         finish ();
1509     else
1510         KMPlayer::Document::message (msg, data);
1511 }
1512 
1513 Disk::Disk (KMPlayer::NodePtr & doc, KMPlayerApp * a, const QString &url, const QString &pn)
1514   : KMPlayer::Mrl (doc, id_node_disk_node), app (a) {
1515     src = url;
1516     title = pn;
1517     bookmarkable = false;
1518 }
1519 
1520 void Disk::activate () {
1521     const char * sn;
1522     if (src.startsWith ("cdda"))
1523         sn = "audiocdsource";
1524     else if (src.startsWith ("vcd"))
1525         sn = "vcdsource";
1526     else
1527         sn = "dvdsource";
1528     app->player ()->setSource (app->player ()->sources () [sn]);
1529 }
1530 
1531 //-----------------------------------------------------------------------------
1532 
1533 KMPlayerDVDSource::KMPlayerDVDSource(KMPlayerApp* a)
1534     : KMPlayer::Source(i18n ("DVD"), a->player(), "dvdsource"), m_app(a), m_configpage(nullptr) {
1535     // FIXME: these menus are void currently
1536     setUrl ("dvd://");
1537     m_player->settings ()->addPage (this);
1538     disks = new Disks (a);
1539     disks->appendChild (new Disk (disks, a, "cdda://", i18n ("CDROM - Audio Compact Disk")));
1540     disks->appendChild (new Disk (disks, a, "vcd://", i18n ("VCD - Video Compact Disk")));
1541     disks->appendChild (new Disk (disks, a, "dvd://", i18n ("DVD - Digital Video Disk")));
1542     m_player->playModel()->addTree (disks, "listssource", "media-optical", 0);
1543 }
1544 
1545 KMPlayerDVDSource::~KMPlayerDVDSource () {
1546     disks->document ()->dispose ();
1547 }
1548 
1549 bool KMPlayerDVDSource::processOutput (const QString & str) {
1550     if (KMPlayer::Source::processOutput (str))
1551         return true;
1552     if (m_identified)
1553         return false;
1554     if (str.startsWith ("ID_DVD_TITLES=")) {
1555         int nt = str.mid (14).toInt ();
1556         for (int i = 0; i < nt; i++)
1557             m_document->appendChild (new KMPlayer::GenericMrl (m_document,
1558                         QString ("dvd://%1").arg (i+1),
1559                         i18n ("Track %1", QString::number (i+1))));
1560         return true;
1561     }
1562     return false;
1563 }
1564 
1565 void KMPlayerDVDSource::activate () {
1566     m_start_play = m_auto_play;
1567     setUrl ("dvd://");
1568     QTimer::singleShot (0, m_player, &KMPlayer::PartBase::play);
1569 }
1570 
1571 void KMPlayerDVDSource::setIdentified (bool b) {
1572     KMPlayer::Source::setIdentified (b);
1573     m_start_play = true;
1574     m_player->updateTree ();
1575     m_app->slotStatusMsg (i18n ("Ready."));
1576 }
1577 
1578 void KMPlayerDVDSource::deactivate () {
1579 }
1580 
1581 void KMPlayerDVDSource::setCurrent (KMPlayer::Mrl *cur) {
1582     KMPlayer::Source::setCurrent (cur);
1583     QString url ("dvd://");
1584     if (m_document)
1585         m_document->mrl ()->src = url;
1586     else
1587         setUrl (url);
1588     m_options = QString (m_identified ? "" : "-v ");
1589     if (m_player->settings ()->dvddevice.size () > 0)
1590         m_options += QString(" -dvd-device ") + m_player->settings()->dvddevice;
1591     if (!m_start_play)
1592         m_options += " -frames 0";
1593     m_recordcmd = m_options + QString (" -vf scale -zoom");
1594 }
1595 
1596 QString KMPlayerDVDSource::filterOptions () {
1597     KMPlayer::Settings * settings = m_player->settings ();
1598     if (!settings->disableppauto)
1599         return KMPlayer::Source::filterOptions ();
1600     return QString ("");
1601 }
1602 
1603 void KMPlayerDVDSource::play (KMPlayer::Mrl *mrl) {
1604     KMPlayer::Source::play (mrl);
1605 }
1606 
1607 QString KMPlayerDVDSource::prettyName () {
1608     return i18n ("DVD");
1609 }
1610 
1611 static const char * strPlayDVD = "Immediately Play DVD";
1612 
1613 void KMPlayerDVDSource::write (KSharedConfigPtr config) {
1614     KConfigGroup (config, strMPlayerGroup).writeEntry (strPlayDVD, m_auto_play);
1615 }
1616 
1617 void KMPlayerDVDSource::read (KSharedConfigPtr config) {
1618     m_auto_play = KConfigGroup (config, strMPlayerGroup).readEntry (strPlayDVD, true);
1619 }
1620 
1621 void KMPlayerDVDSource::sync (bool fromUI) {
1622     if (fromUI) {
1623         m_auto_play = m_configpage->autoPlayDVD->isChecked ();
1624         m_player->settings ()->dvddevice = m_configpage->dvddevice->lineEdit()->text ();
1625     } else {
1626         m_configpage->autoPlayDVD->setChecked (m_auto_play);
1627         m_configpage->dvddevice->lineEdit()->setText (m_player->settings ()->dvddevice);
1628     }
1629 }
1630 
1631 void KMPlayerDVDSource::prefLocation (QString & item, QString & icon, QString & tab) {
1632     item = i18n ("Source");
1633     icon = QString ("source");
1634     tab = i18n ("DVD");
1635 }
1636 
1637 QFrame * KMPlayerDVDSource::prefPage (QWidget * parent) {
1638     m_configpage = new KMPlayerPrefSourcePageDVD (parent);
1639     return m_configpage;
1640 }
1641 
1642 //-----------------------------------------------------------------------------
1643 
1644 KMPlayerPrefSourcePageVCD::KMPlayerPrefSourcePageVCD (QWidget * parent)
1645  : QFrame (parent) {
1646      QVBoxLayout *layout = new QVBoxLayout;
1647      autoPlayVCD = new QCheckBox (i18n ("Auto play after opening a VCD"));
1648      autoPlayVCD->setWhatsThis(i18n("Start playing VCD right after opening VCD"));
1649      QLabel *vcdDevicePathLabel = new QLabel (i18n ("VCD (CDROM) device:"));
1650      vcddevice= new KUrlRequester (QUrl::fromLocalFile ("/dev/cdrom"));
1651      vcddevice->setWhatsThis(i18n("Path to your CDROM/DVD device, you must have read rights to this device"));
1652      layout->addWidget (autoPlayVCD);
1653      layout->addItem (new QSpacerItem (0, 10, QSizePolicy::Minimum, QSizePolicy::Minimum));
1654      layout->addWidget (vcdDevicePathLabel);
1655      layout->addWidget (vcddevice);
1656      layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
1657      setLayout(layout);
1658 }
1659 
1660 //-----------------------------------------------------------------------------
1661 
1662 KMPlayerVCDSource::KMPlayerVCDSource(KMPlayerApp* a)
1663     : KMPlayer::Source(i18n("VCD"), a->player(), "vcdsource"), m_app(a), m_configpage(nullptr) {
1664     m_player->settings ()->addPage (this);
1665     setUrl ("vcd://");
1666 }
1667 
1668 KMPlayerVCDSource::~KMPlayerVCDSource () {
1669 }
1670 
1671 bool KMPlayerVCDSource::processOutput (const QString & str) {
1672     if (KMPlayer::Source::processOutput (str))
1673         return true;
1674     if (m_identified)
1675         return false;
1676     //qCDebug(LOG_KMPLAYER_APP) << "scanning " << cstr;
1677     QRegExp * patterns = static_cast <KMPlayer::MPlayerPreferencesPage *> (m_player->mediaManager ()->processInfos () ["mplayer"]->config_page)->m_patterns;
1678     QRegExp & trackRegExp = patterns [KMPlayer::MPlayerPreferencesPage::pat_vcdtrack];
1679     if (trackRegExp.indexIn(str) > -1) {
1680         m_document->state = KMPlayer::Element::state_deferred;
1681         m_document->appendChild (new KMPlayer::GenericMrl (m_document, QString ("vcd://") + trackRegExp.cap (1), i18n ("Track ") + trackRegExp.cap (1)));
1682         qCDebug(LOG_KMPLAYER_APP) << "track " << trackRegExp.cap (1);
1683         return true;
1684     }
1685     return false;
1686 }
1687 
1688 void KMPlayerVCDSource::activate () {
1689     m_player->stop ();
1690     init ();
1691     m_start_play = m_auto_play;
1692     setUrl ("vcd://");
1693     if (m_start_play)
1694         QTimer::singleShot (0, m_player, &KMPlayer::PartBase::play);
1695 }
1696 
1697 void KMPlayerVCDSource::deactivate () {
1698 }
1699 
1700 void KMPlayerVCDSource::setIdentified (bool b) {
1701     KMPlayer::Source::setIdentified (b);
1702     setCurrent (!m_current || !m_document->hasChildNodes ()
1703             ? m_document->mrl () : m_current->mrl ());
1704     m_player->updateTree ();
1705     if (m_current->state == KMPlayer::Element::state_deferred)
1706         m_current->undefer ();
1707     m_app->slotStatusMsg (i18n ("Ready."));
1708 }
1709 
1710 void KMPlayerVCDSource::setCurrent (KMPlayer::Mrl *cur) {
1711     KMPlayer::Source::setCurrent (cur);
1712     QString url ("vcd://");
1713     if (m_current && m_current != m_document)
1714         url += m_current->mrl ()->src;
1715     m_options.truncate (0);
1716     if (m_player->settings ()->vcddevice.size () > 0)
1717         m_options+=QString(" -cdrom-device ") + m_player->settings()->vcddevice;
1718     m_recordcmd = m_options;
1719 }
1720 
1721 QString KMPlayerVCDSource::prettyName () {
1722     return i18n ("VCD");
1723 }
1724 
1725 static const char * strPlayVCD = "Immediately Play VCD";
1726 
1727 void KMPlayerVCDSource::write (KSharedConfigPtr config) {
1728     KConfigGroup (config, strMPlayerGroup).writeEntry (strPlayVCD, m_auto_play);
1729 }
1730 
1731 void KMPlayerVCDSource::read (KSharedConfigPtr config) {
1732     m_auto_play = KConfigGroup (config, strMPlayerGroup).readEntry (strPlayVCD, true);
1733 }
1734 
1735 void KMPlayerVCDSource::sync (bool fromUI) {
1736     if (fromUI) {
1737         m_auto_play = m_configpage->autoPlayVCD->isChecked ();
1738         m_player->settings ()->vcddevice = m_configpage->vcddevice->lineEdit()->text ();
1739     } else {
1740         m_configpage->autoPlayVCD->setChecked (m_auto_play);
1741         m_configpage->vcddevice->lineEdit()->setText (m_player->settings ()->vcddevice);
1742     }
1743 }
1744 
1745 void KMPlayerVCDSource::prefLocation (QString & item, QString & icon, QString & tab) {
1746     item = i18n ("Source");
1747     icon = QString ("source");
1748     tab = i18n ("VCD");
1749 }
1750 
1751 QFrame * KMPlayerVCDSource::prefPage (QWidget * parent) {
1752     m_configpage = new KMPlayerPrefSourcePageVCD (parent);
1753     return m_configpage;
1754 }
1755 
1756 //-----------------------------------------------------------------------------
1757 
1758 KMPlayerAudioCDSource::KMPlayerAudioCDSource(KMPlayerApp* a)
1759     : KMPlayer::Source(i18n("Audio CD"), a->player(), "audiocdsource"), m_app(a) {
1760     setUrl ("cdda://");
1761 }
1762 
1763 KMPlayerAudioCDSource::~KMPlayerAudioCDSource () {
1764 }
1765 
1766 bool KMPlayerAudioCDSource::processOutput (const QString & str) {
1767     if (KMPlayer::Source::processOutput (str))
1768         return true;
1769     if (m_identified)
1770         return false;
1771     //qCDebug(LOG_KMPLAYER_APP) << "scanning " << str;
1772     QRegExp * patterns = static_cast <KMPlayer::MPlayerPreferencesPage *> (m_player->mediaManager ()->processInfos () ["mplayer"]->config_page)->m_patterns;
1773     QRegExp & trackRegExp = patterns [KMPlayer::MPlayerPreferencesPage::pat_cdromtracks];
1774     if (trackRegExp.indexIn(str) > -1) {
1775         //if (m_document->state != KMPlayer::Element::state_deferred)
1776         //    m_document->defer ();
1777         int nt = trackRegExp.cap (1).toInt ();
1778         qCDebug(LOG_KMPLAYER_APP) << "tracks " << trackRegExp.cap (1);
1779         for (int i = 0; i < nt; i++)
1780             m_document->appendChild (new KMPlayer::GenericMrl (m_document, QString ("cdda://%1").arg (i+1), i18n ("Track %1",QString::number(i+1))));
1781         return true;
1782     }
1783     return false;
1784 }
1785 
1786 void KMPlayerAudioCDSource::activate () {
1787     m_player->stop ();
1788     init ();
1789     //m_start_play = m_auto_play;
1790     setUrl ("cdda://");
1791     //if (m_start_play)
1792         QTimer::singleShot (0, m_player, &KMPlayer::PartBase::play);
1793 }
1794 
1795 void KMPlayerAudioCDSource::deactivate () {
1796 }
1797 
1798 void KMPlayerAudioCDSource::setIdentified (bool b) {
1799     KMPlayer::Source::setIdentified (b);
1800     setCurrent (!m_current || !m_document->hasChildNodes ()
1801             ? m_document->mrl () : m_current->mrl ());
1802     if (m_current == m_document && m_document->hasChildNodes ()) {
1803         //m_back_request = m_document->firstChild ();
1804         //m_player->process ()->stop ();
1805     }
1806     m_player->updateTree ();
1807     //if (m_current->state == KMPlayer::Element::state_deferred)
1808     //    m_current->undefer ();
1809     m_app->slotStatusMsg (i18n ("Ready."));
1810 }
1811 
1812 void KMPlayerAudioCDSource::setCurrent (KMPlayer::Mrl *cur) {
1813     KMPlayer::Source::setCurrent (cur);
1814     QString url ("cdda://");
1815     if (m_current && m_current != m_document)
1816         url += m_current->mrl ()->src;
1817     m_options = "-cdda speed=3";
1818     if (m_player->settings ()->vcddevice.size () > 0)
1819         m_options+=QString(" -cdrom-device ") + m_player->settings()->vcddevice;
1820     m_recordcmd = m_options;
1821 }
1822 
1823 QString KMPlayerAudioCDSource::prettyName () {
1824     return i18n ("Audio CD");
1825 }
1826 
1827 //-----------------------------------------------------------------------------
1828 
1829 KMPlayerPipeSource::KMPlayerPipeSource (KMPlayerApp * a)
1830  : KMPlayer::Source (i18n ("Pipe"), a->player (), "pipesource"), m_app (a) {
1831 }
1832 
1833 KMPlayerPipeSource::~KMPlayerPipeSource () {
1834 }
1835 
1836 bool KMPlayerPipeSource::hasLength () {
1837     return false;
1838 }
1839 
1840 bool KMPlayerPipeSource::isSeekable () {
1841     return false;
1842 }
1843 
1844 void KMPlayerPipeSource::activate () {
1845     // dangerous !! if (!m_url.protocol ().compare ("kmplayer"))
1846     //    m_pipecmd = QUrl::fromPercentEncoding(m_url.path ().toLatin1()).mid (1);
1847     setUrl ("stdin://");
1848     KMPlayer::GenericMrl * gen = new KMPlayer::GenericMrl (m_document, QString ("stdin://"), m_pipecmd);
1849     gen->bookmarkable = false;
1850     m_document->appendChild (gen);
1851     m_recordcmd = m_options = QString ("-"); // or m_url?
1852     m_identified = true;
1853     reset ();
1854     QTimer::singleShot (0, m_player, &KMPlayer::PartBase::play);
1855     m_app->slotStatusMsg (i18n ("Ready."));
1856 }
1857 
1858 void KMPlayerPipeSource::deactivate () {
1859 }
1860 
1861 QString KMPlayerPipeSource::prettyName () {
1862     return i18n ("Pipe - %1",m_pipecmd);
1863 }
1864 
1865 void KMPlayerPipeSource::setCommand (const QString & cmd) {
1866     m_pipecmd = cmd;
1867     if (m_document)
1868         m_document->mrl ()->title = cmd;
1869 }
1870 
1871 #include "moc_kmplayer.cpp"