File indexing completed on 2024-04-21 15:38:22

0001 /* This file is part of the KMPlayer application
0002    Copyright (C) 2003 Koos Vriezen <koos.vriezen@xs4all.nl>
0003 
0004    This program is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This program is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012     General Public License for more details.
0013 
0014    You should have received a copy of the GNU General Public License
0015    along with this program; see the file COPYING.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include <qlayout.h>
0021 #include <qlabel.h>
0022 #include <qtimer.h>
0023 #include <qpushbutton.h>
0024 #include <qcheckbox.h>
0025 #include <QTableWidget>
0026 #include <qstringlist.h>
0027 #include <qcombobox.h>
0028 #include <qlineedit.h>
0029 #include <qgroupbox.h>
0030 #include <qwhatsthis.h>
0031 #include <qtabwidget.h>
0032 #include <qmessagebox.h>
0033 #include <QHeaderView>
0034 #include <QMenu>
0035 #include <QStandardPaths>
0036 #include <qfontmetrics.h>
0037 
0038 #include <klocalizedstring.h>
0039 #include <kdebug.h>
0040 #include <kmessagebox.h>
0041 #include <klineedit.h>
0042 #include <kurlrequester.h>
0043 #include <kcombobox.h>
0044 #include <kconfig.h>
0045 #include <kconfiggroup.h>
0046 
0047 #include "kmplayerpartbase.h"
0048 #include "kmplayerprocess.h"
0049 #include "kmplayerconfig.h"
0050 #include "kmplayertvsource.h"
0051 #include "playmodel.h"
0052 #include "playlistview.h"
0053 #include "viewarea.h"
0054 #include "kmplayer.h"
0055 #include "kmplayercontrolpanel.h"
0056 
0057 static const char * strTV = "TV";
0058 static const char * strTVDriver = "Driver";
0059 
0060 
0061 KDE_NO_CDTOR_EXPORT TVDevicePage::TVDevicePage (QWidget *parent, KMPlayer::NodePtr dev)
0062 : QFrame (parent), device_doc (dev) {
0063     setObjectName("PageTVDevice");
0064     TVDevice * device = KMPlayer::convertNode <TVDevice> (device_doc);
0065     QLabel* deviceLabel = new QLabel(i18n("Video device:") + device->src);
0066     QLabel* audioLabel = new QLabel(i18n("Audio device:"));
0067     audiodevice = new KUrlRequester (KUrl (device->getAttribute ("audio")));
0068     QLabel* nameLabel = new QLabel(i18n("Name:"));
0069     name = new QLineEdit(device->title);
0070     QLabel *sizewidthLabel = new QLabel(i18n("Width:"));
0071     sizewidth = new QLineEdit(device->getAttribute(KMPlayer::Ids::attr_width));
0072     QLabel* sizeheightLabel = new QLabel (i18n ("Height:"));
0073     sizeheight = new QLineEdit(device->getAttribute(KMPlayer::Ids::attr_height));
0074     noplayback = new QCheckBox(i18n("Do not immediately play"));
0075     noplayback->setChecked (!device->getAttribute ("playback").toInt ());
0076     noplayback->setWhatsThis(i18n("Only start playing after clicking the play button"));
0077     inputsTab = new QTabWidget;
0078     for (KMPlayer::Node *ip = device->firstChild (); ip; ip = ip->nextSibling ()) {
0079         if (ip->id != id_node_tv_input)
0080             continue;
0081         TVInput * input = KMPlayer::convertNode <TVInput> (ip);
0082         QWidget* widget = new QWidget;
0083         QHBoxLayout* tablayout = new QHBoxLayout;
0084         if (!input->getAttribute ("tuner").isEmpty ()) {
0085             QHBoxLayout* horzlayout = new QHBoxLayout;
0086             QVBoxLayout* vertlayout = new QVBoxLayout;
0087             horzlayout->addWidget(new QLabel(i18n("Norm:")));
0088             QComboBox* norms = new QComboBox;
0089             norms->setObjectName("PageTVNorm");
0090             norms->addItem(QString("NTSC"));
0091             norms->addItem(QString("PAL"));
0092             norms->addItem(QString("SECAM"));
0093             norms->setCurrentIndex(norms->findText(input->getAttribute ("norm")));
0094             horzlayout->addWidget (norms);
0095             vertlayout->addLayout (horzlayout);
0096             vertlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
0097             QTableWidget* table = new QTableWidget(90, 2);
0098             table->setObjectName("PageTVChannels");
0099             table->setContentsMargins(0, 0, 0, 0);
0100             QFontMetrics metrics (table->font ());
0101             QStringList labels = QStringList() << i18n("Channel") << i18n("Frequency (MHz)");
0102             table->setHorizontalHeaderLabels(labels);
0103             int index = 0;
0104             int first_column_width = QFontMetrics(table->horizontalHeader()->font()).boundingRect(labels[0]).width() + 20;
0105             for (KMPlayer::Node *c=input->firstChild();c;c=c->nextSibling()) {
0106                 if (c->id != id_node_tv_channel)
0107                     continue;
0108                 int strwid = metrics.boundingRect (c->mrl ()->title).width ();
0109                 if (strwid > first_column_width)
0110                     first_column_width = strwid + 4;
0111                 table->setItem(index, 0, new QTableWidgetItem(c->mrl()->title));
0112                 table->setItem(index++, 1, new QTableWidgetItem(KMPlayer::convertNode<TVChannel>(c)->getAttribute("frequency")));
0113             }
0114             table->setColumnWidth (0, first_column_width);
0115             table->horizontalHeader()->setStretchLastSection(true);
0116             tablayout->addWidget (table);
0117             tablayout->addLayout (vertlayout);
0118         }
0119         widget->setLayout(tablayout);
0120         inputsTab->addTab (widget, input->mrl ()->title);
0121     }
0122     QPushButton* delButton = new QPushButton(i18n("Delete"));
0123     connect (delButton, SIGNAL (clicked ()), this, SLOT (slotDelete ()));
0124     QGridLayout* gridlayout = new QGridLayout;
0125     gridlayout->addWidget (audioLabel, 0, 0);
0126     gridlayout->addWidget (audiodevice, 0, 0, 1, 3);
0127     gridlayout->addWidget (nameLabel, 1, 0);
0128     gridlayout->addWidget (name, 1, 1, 1, 3);
0129     gridlayout->addWidget (sizewidthLabel, 2, 0);
0130     gridlayout->addWidget (sizewidth, 2, 1);
0131     gridlayout->addWidget (sizeheightLabel, 2, 2);
0132     gridlayout->addWidget (sizeheight, 2, 3);
0133     QVBoxLayout* layout = new QVBoxLayout;
0134     layout->addWidget(deviceLabel);
0135     layout->addLayout(gridlayout);
0136     layout->addWidget (inputsTab);
0137     layout->addSpacing (5);
0138     layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum));
0139     QHBoxLayout *buttonlayout = new QHBoxLayout ();
0140     buttonlayout->addWidget (noplayback);
0141     buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum));
0142     buttonlayout->addWidget (delButton);
0143     layout->addLayout (buttonlayout);
0144     setLayout(layout);
0145 }
0146 
0147 KDE_NO_EXPORT void TVDevicePage::slotDelete () {
0148     if (KMessageBox::warningYesNo (this, i18n ("You are about to remove this device from the Source menu.\nContinue?"), i18n ("Confirm")) == KMessageBox::Yes)
0149         emit deleted (this);
0150 }
0151 
0152 //-----------------------------------------------------------------------------
0153 
0154 KDE_NO_CDTOR_EXPORT KMPlayerPrefSourcePageTV::KMPlayerPrefSourcePageTV (QWidget *parent, KMPlayerTVSource * tvsource)
0155 : QFrame (parent), m_tvsource (tvsource) {
0156     notebook = new QTabWidget;
0157     notebook->setTabPosition (QTabWidget::South);
0158     QWidget * general = new QWidget (notebook);
0159     QLabel* driverLabel = new QLabel(i18n("Driver:"));
0160     driver = new QLineEdit;
0161     driver->setWhatsThis(i18n("dummy, v4l or bsdbt848"));
0162     QLabel *deviceLabel = new QLabel(i18n("Device:"));
0163     device = new KUrlRequester(KUrl("/dev/video"));
0164     device->setWhatsThis(i18n("Path to your video device, eg. /dev/video0"));
0165     scan = new QPushButton(i18n("Scan..."));
0166     QGridLayout *gridlayout = new QGridLayout;
0167     gridlayout->addWidget (driverLabel, 0, 0);
0168     gridlayout->addWidget (driver, 0, 1);
0169     gridlayout->addWidget (deviceLabel, 1, 0);
0170     gridlayout->addWidget (device, 1, 1);
0171     QHBoxLayout *buttonlayout = new QHBoxLayout;
0172     buttonlayout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum));
0173     buttonlayout->addWidget (scan);
0174     QVBoxLayout *layout = new QVBoxLayout;
0175     layout->addLayout(gridlayout);
0176     layout->addLayout (buttonlayout);
0177     layout->addItem (new QSpacerItem (0, 0, QSizePolicy::Minimum, QSizePolicy::Expanding));
0178     general->setLayout(layout);
0179     notebook->addTab(general, i18n("General"));
0180     QVBoxLayout* mainlayout = new QVBoxLayout;
0181     mainlayout->addWidget(notebook);
0182     setLayout(mainlayout);
0183 }
0184 
0185 KDE_NO_EXPORT void KMPlayerPrefSourcePageTV::showEvent (QShowEvent *) {
0186     m_tvsource->readXML ();
0187 }
0188 
0189 //-----------------------------------------------------------------------------
0190 
0191 KDE_NO_CDTOR_EXPORT TVNode::TVNode (KMPlayer::NodePtr &d, const QString & s, const char * t, short id, const QString & n) : KMPlayer::GenericMrl (d, s, n, t) {
0192     this->id = id;
0193     editable = true;
0194 }
0195 
0196 KDE_NO_EXPORT void TVNode::setNodeName (const QString & nn) {
0197     title = nn;
0198     setAttribute (KMPlayer::Ids::attr_name, nn);
0199 }
0200 
0201 //-----------------------------------------------------------------------------
0202 
0203 KDE_NO_CDTOR_EXPORT TVChannel::TVChannel (KMPlayer::NodePtr & d, const QString & n, double freq) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel, n) {
0204     setAttribute (KMPlayer::Ids::attr_name, n);
0205     setAttribute ("frequency", QString::number (freq, 'f', 2));
0206 }
0207 
0208 KDE_NO_CDTOR_EXPORT TVChannel::TVChannel (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "channel", id_node_tv_channel) {
0209 }
0210 
0211 KDE_NO_EXPORT void TVChannel::closed () {
0212     title = getAttribute (KMPlayer::Ids::attr_name);
0213     Mrl::closed ();
0214 }
0215 
0216 //-----------------------------------------------------------------------------
0217 
0218 TVInput::TVInput (KMPlayer::NodePtr & d, const QString & n, int id)
0219  : TVNode (d, QString ("tv://"), "input", id_node_tv_input, n) {
0220     setAttribute (KMPlayer::Ids::attr_name, n);
0221     setAttribute (KMPlayer::Ids::attr_id, QString::number (id));
0222 }
0223 
0224 KDE_NO_CDTOR_EXPORT TVInput::TVInput (KMPlayer::NodePtr & d) : TVNode (d, QString ("tv://"), "input", id_node_tv_input) {
0225 }
0226 
0227 KDE_NO_EXPORT KMPlayer::Node *TVInput::childFromTag (const QString & tag) {
0228     // kDebug () << nodeName () << " childFromTag " << tag;
0229     if (tag == QString::fromLatin1 ("channel")) {
0230         return new TVChannel (m_doc);
0231     } else
0232         return 0L;
0233 }
0234 
0235 KDE_NO_EXPORT void TVInput::closed () {
0236     //title = getAttribute (KMPlayer::Ids::attr_name);
0237     Mrl::closed ();
0238 }
0239 
0240 KDE_NO_EXPORT void TVInput::setNodeName (const QString & name) {
0241     Node *p = parentNode ();
0242     QString nm (name);
0243     if (p && p->id == id_node_tv_device) {
0244         int pos = name.indexOf (QString (" - ") + p->mrl ()->title);
0245         if (pos > -1)
0246             nm.truncate (pos);
0247     }
0248     title = nm + QString (" - ") + title;
0249     TVNode::setNodeName (nm);
0250 }
0251 
0252 //-----------------------------------------------------------------------------
0253 
0254 KDE_NO_CDTOR_EXPORT TVDevice::TVDevice (KMPlayer::NodePtr & doc, const QString & d) : TVNode (doc, d, "device", id_node_tv_device), zombie (false) {
0255     setAttribute ("path", d);
0256 }
0257 
0258 KDE_NO_CDTOR_EXPORT TVDevice::TVDevice (KMPlayer::NodePtr & doc)
0259     : TVNode (doc, i18n ("tv device"), "device", id_node_tv_device), zombie (false) {
0260 }
0261 
0262 KDE_NO_CDTOR_EXPORT TVDevice::~TVDevice () {
0263     if (device_page)
0264         device_page->deleteLater ();
0265 }
0266 
0267 KDE_NO_EXPORT KMPlayer::Node *TVDevice::childFromTag (const QString & tag) {
0268     // kDebug () << nodeName () << " childFromTag " << tag;
0269     if (tag == QString::fromLatin1 ("input"))
0270         return new TVInput (m_doc);
0271     return 0L;
0272 }
0273 
0274 KDE_NO_EXPORT void TVDevice::closed () {
0275     updateNodeName ();
0276     Mrl::closed ();
0277 }
0278 
0279 KDE_NO_EXPORT void TVDevice::message (KMPlayer::MessageType msg, void *data) {
0280     if (KMPlayer::MsgChildFinished == msg)
0281         finish ();
0282     else
0283         TVNode::message (msg, data);
0284 }
0285 
0286 void *TVDevice::role (KMPlayer::RoleType msg, void *content)
0287 {
0288     if (KMPlayer::RolePlaylist == msg)
0289         return NULL;
0290     return TVNode::role (msg, content);
0291 }
0292 
0293 KDE_NO_EXPORT void TVDevice::setNodeName (const QString & name) {
0294     TVNode::setNodeName (name);
0295     updateNodeName ();
0296 }
0297 
0298 KDE_NO_EXPORT void TVDevice::updateNodeName () {
0299     title = getAttribute (KMPlayer::Ids::attr_name);
0300     src = getAttribute ("path");
0301     for (KMPlayer::Node *c = firstChild (); c; c = c->nextSibling ())
0302         if (c->id == id_node_tv_input) {
0303             TVInput * i = static_cast <TVInput *> (c);
0304             i->title = i->getAttribute (KMPlayer::Ids::attr_name) +
0305                 QString (" - ") + title;
0306         }
0307 }
0308 
0309 KDE_NO_EXPORT void TVDevice::updateDevicePage () {
0310     if (!device_page)
0311         return;
0312     title = device_page->name->text ();
0313     setAttribute (KMPlayer::Ids::attr_name, title);
0314     setAttribute ("audio", device_page->audiodevice->lineEdit()->text ());
0315     setAttribute ("playback", device_page->noplayback->isChecked() ? "0" : "1");
0316     setAttribute (KMPlayer::Ids::attr_width, device_page->sizewidth->text ());
0317     setAttribute (KMPlayer::Ids::attr_height, device_page->sizeheight->text ());
0318     int i = 0;
0319     for (KMPlayer::Node *ip = firstChild(); ip; ip=ip->nextSibling(),++i) {
0320         if (ip->id != id_node_tv_input)
0321             continue;
0322         TVInput * input = KMPlayer::convertNode <TVInput> (ip);
0323         bool ok;
0324         if (input->getAttribute ("tuner").toInt (&ok) && ok) {
0325             QWidget* widget = device_page->inputsTab->widget(i);
0326             QTableWidget* table = static_cast<QTableWidget*>(widget->findChild<QTableWidget*>("PageTVChannels"));
0327             if (table) {
0328                 input->clearChildren ();
0329                 for (int j = 0; j<table->rowCount() && table->item (j, 1); ++j) {
0330                     input->appendChild (new TVChannel (m_doc, table->item (j, 0)->text (), table->item (j, 1)->text ().toDouble ()));
0331                 }
0332             }
0333             QComboBox* norms = static_cast<QComboBox*>(widget->findChild<QComboBox*>("PageTVNorm"));
0334             if (norms) {
0335                 input->setAttribute ("norm", norms->currentText ());
0336             }
0337         }
0338     }
0339 }
0340 
0341 //-----------------------------------------------------------------------------
0342 
0343 KDE_NO_CDTOR_EXPORT
0344 TVDocument::TVDocument (KMPlayerTVSource * source)
0345     : FileDocument (id_node_tv_document, "tv://", source), m_source (source) {
0346     title = i18n ("Television");
0347     bookmarkable = false;
0348 }
0349 
0350 KDE_NO_EXPORT KMPlayer::Node *TVDocument::childFromTag (const QString & tag) {
0351     // kDebug () << nodeName () << " childFromTag " << tag;
0352     if (tag == QString::fromLatin1 ("device"))
0353         return new TVDevice (m_doc);
0354     return FileDocument::childFromTag (tag);
0355 }
0356 
0357 KDE_NO_EXPORT void TVDocument::message (KMPlayer::MessageType msg, void *data) {
0358     if (KMPlayer::MsgChildFinished == msg)
0359         finish ();
0360     else
0361         FileDocument::message (msg, data);
0362 }
0363 
0364 KDE_NO_EXPORT void TVDocument::defer () {
0365     if (!resolved) {
0366         resolved = true;
0367         readFromFile(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml");
0368     }
0369 }
0370 
0371 //-----------------------------------------------------------------------------
0372 
0373 KDE_NO_CDTOR_EXPORT KMPlayerTVSource::KMPlayerTVSource(KMPlayerApp* a)
0374     : KMPlayer::Source (i18n ("TV"), a->player(), "tvsource"), m_app(a), m_configpage(0L), scanner(0L), config_read(false) {
0375     m_url = "tv://";
0376     m_document = new TVDocument (this);
0377     m_player->settings ()->addPage (this);
0378     tree_id = m_player->playModel()->addTree (m_document, "tvsource", "video-television", KMPlayer::PlayModel::TreeEdit | KMPlayer::PlayModel::Moveable | KMPlayer::PlayModel::Deleteable);
0379 }
0380 
0381 KDE_NO_CDTOR_EXPORT KMPlayerTVSource::~KMPlayerTVSource () {
0382     static_cast <TVDocument *> (m_document.ptr ())->sync
0383         (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml");
0384 }
0385 
0386 KDE_NO_EXPORT void KMPlayerTVSource::activate () {
0387     m_identified = true;
0388     //if (m_player->settings ()->showbroadcastbutton)
0389     //    m_app->view()->controlPanel()->broadcastButton ()->show ();
0390     if (m_cur_tvdevice && !m_current) {
0391         for (KMPlayer::Node *i = m_cur_tvdevice->firstChild(); i && !m_current; i=i->nextSibling())
0392             if (i->id == id_node_tv_input) {
0393                 TVInput * input = KMPlayer::convertNode <TVInput> (i);
0394                 bool ok;
0395                 m_cur_tvinput = i;
0396                 if (input->getAttribute ("tuner").toInt (&ok) && ok) {
0397                     for (KMPlayer::Node *c = i->firstChild (); c; c = c->nextSibling ())
0398                         if (c->id == id_node_tv_channel) {
0399                             setCurrent (c->mrl ());
0400                             break;
0401                         }
0402                 } else
0403                     m_current = i;
0404             }
0405     } else if (!m_cur_tvdevice)
0406         KMPlayer::Source::reset ();
0407     if (m_cur_tvdevice) {
0408         QString playback = static_cast <KMPlayer::Element *> (m_cur_tvdevice.ptr ())->getAttribute (QString::fromLatin1 ("playback"));
0409         if (playback.isEmpty () || playback.toInt ())
0410             QTimer::singleShot (0, m_player, SLOT (play ()));
0411     }
0412 }
0413 /* TODO: playback by
0414  * ffmpeg -vd /dev/video0 -r 25 -s 768x576 -f rawvideo - |mplayer -nocache -ao arts -rawvideo on:w=768:h=576:fps=25 -quiet -
0415  */
0416 
0417 KDE_NO_EXPORT void KMPlayerTVSource::deactivate () {
0418     //if (m_player->view () && !m_app->view ()->controlPanel()->broadcastButton ()->isOn ())
0419     //    m_app->view ()->controlPanel()->broadcastButton ()->hide ();
0420     reset ();
0421 }
0422 
0423 void KMPlayerTVSource::play (KMPlayer::Mrl *mrl) {
0424     if (mrl && mrl->id == id_node_tv_document) {
0425         readXML ();
0426     } else {
0427         m_current = mrl;
0428         for (KMPlayer::Node *e = mrl; e; e = e->parentNode ()) {
0429             if (e->id == id_node_tv_device) {
0430                 m_cur_tvdevice = e;
0431                 break;
0432             } else if (e->id == id_node_tv_input)
0433                 m_cur_tvinput = e;
0434         }
0435         if (m_player->source () != this)
0436             m_player->setSource (this);
0437         else
0438             KMPlayer::Source::play (mrl);
0439         /*else if (m_player->process ()->playing ()) {
0440             //m_back_request = m_current;
0441             m_player->process ()->stop ();
0442         } else {
0443             buildArguments ();
0444             if (m_app->broadcasting ())
0445                 QTimer::singleShot (0, m_app->broadcastConfig (), SLOT (startFeed ()));
0446             else
0447                 KMPlayer::Source::play (mrl);
0448         }*/
0449     }
0450 }
0451 
0452 KDE_NO_EXPORT KMPlayer::NodePtr KMPlayerTVSource::root () {
0453     return m_cur_tvinput;
0454 }
0455 
0456 KDE_NO_EXPORT void KMPlayerTVSource::setCurrent (KMPlayer::Mrl *mrl) {
0457     TVChannel * channel = 0L;
0458     TVInput * input = 0L;
0459     m_current = mrl;
0460     KMPlayer::NodePtr elm = m_current;
0461     if (elm && elm->id == id_node_tv_channel) {
0462         channel = KMPlayer::convertNode <TVChannel> (elm);
0463         elm = elm->parentNode ();
0464     }
0465     if (elm && elm->id == id_node_tv_input)
0466         input = KMPlayer::convertNode <TVInput> (elm);
0467     if (!(channel || (input && input->getAttribute ("tuner").isEmpty ())))
0468         return;
0469     m_cur_tvinput = input;
0470     m_cur_tvdevice = input->parentNode ();
0471     m_player->playModel()->updateTree(0, m_cur_tvinput, m_current, true, false);
0472     if (m_cur_tvdevice->id != id_node_tv_device) {
0473         return;
0474     }
0475     TVDevice * tvdevice = KMPlayer::convertNode <TVDevice> (m_cur_tvdevice);
0476     m_identified = true;
0477     m_audiodevice = tvdevice->getAttribute ("audio");
0478     m_videodevice = tvdevice->src;
0479     m_videonorm = input->getAttribute ("norm");
0480     m_tuner = input->getAttribute (KMPlayer::Ids::attr_name);
0481     QString xvport = tvdevice->getAttribute ("xvport");
0482     if (!xvport.isEmpty ())
0483         m_xvport = xvport.toInt ();
0484     QString xvenc = input->getAttribute ("xvenc");
0485     if (!xvenc.isEmpty ())
0486         m_xvencoding = xvenc.toInt ();
0487     QString command;
0488     command.sprintf ("device=%s:input=%s",
0489             tvdevice->src.toAscii ().data (),
0490             input->getAttribute (KMPlayer::Ids::attr_id).toAscii ().data ());
0491     if (channel) {
0492         QString freq = channel->getAttribute ("frequency");
0493         m_frequency = (int)(1000 * freq.toDouble ());
0494         command += QString (":freq=%1").arg (freq);
0495     } else
0496         m_frequency = 0;
0497     if (!m_videonorm.isEmpty ())
0498         command += QString (":norm=%1").arg (m_videonorm);
0499     m_app->setCaption (i18n ("TV: ") + (channel ? channel->mrl ()->title : input->mrl ()->title), false);
0500     setDimensions (m_cur_tvdevice,
0501             tvdevice->getAttribute (KMPlayer::Ids::attr_width).toInt (),
0502             tvdevice->getAttribute (KMPlayer::Ids::attr_height).toInt ());
0503     m_options.sprintf ("-tv noaudio:driver=%s:%s:width=%d:height=%d -slave -nocache -quiet", tvdriver.toAscii ().data (), command.toAscii ().data (), width (), height ());
0504     m_recordcmd.sprintf ("-tv %s:driver=%s:%s:width=%d:height=%d", m_audiodevice.isEmpty () ? "noaudio" : QString(QLatin1String ("forceaudio:adevice=") + m_audiodevice).toAscii ().data(), tvdriver.toAscii ().data (), command.toAscii ().data (), width (), height ());
0505 }
0506 
0507 KDE_NO_EXPORT void KMPlayerTVSource::menuClicked (int id) {
0508     KMPlayer::Node *elm = m_document->firstChild ();
0509     for (; id > 0; --id,  elm = elm->nextSibling ())
0510         ;
0511     m_cur_tvdevice = elm;
0512     m_cur_tvinput = elm->firstChild (); // FIXME
0513     m_current = 0L;
0514     m_player->setSource (this);
0515 }
0516 
0517 KDE_NO_EXPORT QString KMPlayerTVSource::filterOptions () {
0518     if (! m_player->settings ()->disableppauto)
0519         return KMPlayer::Source::filterOptions ();
0520     return QString ("-vf pp=lb");
0521 }
0522 
0523 KDE_NO_EXPORT bool KMPlayerTVSource::hasLength () {
0524     return false;
0525 }
0526 
0527 KDE_NO_EXPORT bool KMPlayerTVSource::isSeekable () {
0528     return true;
0529 }
0530 
0531 KDE_NO_EXPORT QString KMPlayerTVSource::prettyName () {
0532     QString name (i18n ("TV"));
0533     //if (m_tvsource)
0534     //    name += ' ' + m_tvsource->title;
0535     return name;
0536 }
0537 
0538 KDE_NO_EXPORT void KMPlayerTVSource::write (KSharedConfigPtr m_config) {
0539     if (!config_read) return;
0540     KConfigGroup (m_config, strTV).writeEntry (strTVDriver, tvdriver);
0541     static_cast <TVDocument *> (m_document.ptr ())->writeToFile
0542         (QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kmplayer/tv.xml");
0543     kDebug () << "KMPlayerTVSource::write XML";
0544 }
0545 
0546 KDE_NO_EXPORT void KMPlayerTVSource::readXML () {
0547     if (config_read) return;
0548     config_read = true;
0549     kDebug () << "KMPlayerTVSource::readXML";
0550     m_document->defer ();
0551     m_player->playModel()->updateTree (tree_id, m_document, 0, false, false);
0552     sync (false);
0553 }
0554 
0555 KDE_NO_EXPORT void KMPlayerTVSource::read (KSharedConfigPtr m_config) {
0556     tvdriver = KConfigGroup (m_config, strTV).readEntry (
0557             strTVDriver, QString ("v4l2"));
0558 }
0559 
0560 KDE_NO_EXPORT void KMPlayerTVSource::sync (bool fromUI) {
0561     if (!m_configpage) return;
0562     if (m_document && m_document->hasChildNodes ())
0563         m_app->showBroadcastConfig ();
0564     else
0565         m_app->hideBroadcastConfig ();
0566     if (fromUI) {
0567         tvdriver = m_configpage->driver->text ();
0568         for (KMPlayer::Node *d=m_document->firstChild();d; d=d->nextSibling())
0569             if (d->id == id_node_tv_device)
0570                 static_cast <TVDevice *> (d)->updateDevicePage ();
0571         m_player->playModel()->updateTree(tree_id, m_document, 0, false, false);
0572     } else {
0573         m_configpage->driver->setText (tvdriver);
0574         for (KMPlayer::Node *dp = m_document->firstChild (); dp; dp = dp->nextSibling ())
0575             if (dp->id == id_node_tv_device)
0576                 addTVDevicePage (KMPlayer::convertNode <TVDevice> (dp));
0577     }
0578 }
0579 
0580 KDE_NO_EXPORT void KMPlayerTVSource::prefLocation (QString & item, QString & icon, QString & tab) {
0581     item = i18n ("Source");
0582     icon = QString ("source");
0583     tab = i18n ("TV");
0584 }
0585 
0586 KDE_NO_EXPORT QFrame * KMPlayerTVSource::prefPage (QWidget * parent) {
0587     if (!m_configpage) {
0588         m_configpage = new KMPlayerPrefSourcePageTV (parent, this);
0589         scanner = new TVDeviceScannerSource (this);
0590         connect (m_configpage->scan, SIGNAL(clicked()), this, SLOT(slotScan()));
0591     }
0592     return m_configpage;
0593 }
0594 
0595 static bool hasTVDevice (KMPlayer::NodePtr doc, const QString & devstr) {
0596     for (KMPlayer::Node *e = doc->firstChild (); e; e = e->nextSibling ())
0597         if (e->id == id_node_tv_device &&
0598                 static_cast <TVDevice *> (e)->src == devstr)
0599             return true;
0600     return false;
0601 }
0602 
0603 KDE_NO_EXPORT void KMPlayerTVSource::slotScan () {
0604     QString devstr = m_configpage->device->lineEdit()->text ();
0605     if (!hasTVDevice(m_document, devstr)) {
0606         scanner->scan (devstr, m_configpage->driver->text());
0607         connect (scanner, SIGNAL (scanFinished (TVDevice *)),
0608                 this, SLOT (slotScanFinished (TVDevice *)));
0609     } else
0610         KMessageBox::error (m_configpage, i18n ("Device already present."),
0611                 i18n ("Error"));
0612 }
0613 
0614 KDE_NO_EXPORT void KMPlayerTVSource::slotScanFinished (TVDevice * tvdevice) {
0615     disconnect (scanner, SIGNAL (scanFinished (TVDevice *)),
0616                 this, SLOT (slotScanFinished (TVDevice *)));
0617     if (tvdevice) {
0618         tvdevice->zombie = false;
0619         addTVDevicePage (tvdevice, true);
0620         m_player->playModel()->updateTree(tree_id, m_document, 0, false, false);
0621     } else
0622         KMessageBox::error(m_configpage,i18n("No device found."),i18n("Error"));
0623 }
0624 
0625 KDE_NO_EXPORT void KMPlayerTVSource::addTVDevicePage(TVDevice *dev, bool show) {
0626     if (dev->device_page)
0627         dev->device_page->deleteLater ();
0628     dev->device_page = new TVDevicePage (m_configpage->notebook, dev);
0629     m_configpage->notebook->addTab(dev->device_page, dev->title);
0630     connect (dev->device_page, SIGNAL (deleted (TVDevicePage *)),
0631              this, SLOT (slotDeviceDeleted (TVDevicePage *)));
0632     if (show)
0633         m_configpage->notebook->setCurrentIndex(m_configpage->notebook->count()-1);
0634 }
0635 
0636 KDE_NO_EXPORT void KMPlayerTVSource::slotDeviceDeleted (TVDevicePage *devpage) {
0637     m_document->removeChild (devpage->device_doc);
0638     m_configpage->notebook->setCurrentIndex(0);
0639     m_player->playModel()->updateTree (tree_id, m_document, 0, false, false);
0640 }
0641 
0642 //-----------------------------------------------------------------------------
0643 
0644 KDE_NO_CDTOR_EXPORT TVDeviceScannerSource::TVDeviceScannerSource (KMPlayerTVSource * src)
0645  : KMPlayer::Source (i18n ("TVScanner"), src->player (), "tvscanner"),
0646    m_tvsource (src),
0647    m_tvdevice (0L),
0648    m_process (NULL),
0649    m_viewer (NULL) {
0650 }
0651 
0652 KDE_NO_EXPORT void TVDeviceScannerSource::init () {
0653 }
0654 
0655 KDE_NO_EXPORT bool TVDeviceScannerSource::processOutput (const QString & line) {
0656     if (m_nameRegExp.indexIn(line) > -1) {
0657         m_tvdevice->title = m_nameRegExp.cap (1);
0658         m_tvdevice->setAttribute(KMPlayer::Ids::attr_name,m_tvdevice->title);
0659         kDebug() << "Name " << m_tvdevice->title;
0660     } else if (m_sizesRegExp.indexIn(line) > -1) {
0661         m_tvdevice->setAttribute (KMPlayer::Ids::attr_width,
0662                 m_sizesRegExp.cap(1));
0663         m_tvdevice->setAttribute (KMPlayer::Ids::attr_height,
0664                 m_sizesRegExp.cap(2));
0665         m_tvdevice->setAttribute ("minwidth", m_sizesRegExp.cap (1));
0666         m_tvdevice->setAttribute ("minheight", m_sizesRegExp.cap (2));
0667         m_tvdevice->setAttribute ("maxwidth", m_sizesRegExp.cap (3));
0668         m_tvdevice->setAttribute ("maxheight", m_sizesRegExp.cap (4));
0669     } else if (m_inputRegExp.indexIn(line) > -1) {
0670         KMPlayer::NodePtr doc = m_tvsource->document ();
0671         TVInput * input = new TVInput (doc, m_inputRegExp.cap(2).trimmed(),
0672                                        m_inputRegExp.cap (1).toInt ());
0673         if (m_inputRegExp.cap (3).toInt () == 1)
0674             input->setAttribute ("tuner", "1");
0675         m_tvdevice->appendChild (input);
0676         kDebug() << "Input " << input->mrl ()->title;
0677     } else if (m_inputRegExpV4l2.indexIn(line) > -1) {
0678         KMPlayer::NodePtr doc = m_tvsource->document ();
0679         QStringList sl = m_inputRegExpV4l2.cap(1).split (QChar (';'));
0680         const QStringList::iterator e = sl.end ();
0681         for (QStringList::iterator i = sl.begin (); i != e; ++i) {
0682             int pos = (*i).indexOf (QChar ('='));
0683             if (pos > 0) {
0684                 int id = (*i).left (pos).trimmed ().toInt ();
0685                 TVInput *input = new TVInput(doc,(*i).mid(pos+1).trimmed(), id);
0686                 if (!id && m_caps.indexOf ("tuner") > -1)
0687                     input->setAttribute ("tuner", "1");
0688                 m_tvdevice->appendChild (input);
0689             }
0690         }
0691     } else {
0692         int pos = line.indexOf ("Capabilites:");
0693         if (pos > 0)
0694             m_caps = line.mid (pos + 12);
0695         return false;
0696     }
0697     return true;
0698 }
0699 
0700 KDE_NO_EXPORT QString TVDeviceScannerSource::filterOptions () {
0701     return QString ("");
0702 }
0703 
0704 KDE_NO_EXPORT bool TVDeviceScannerSource::hasLength () {
0705     return false;
0706 }
0707 
0708 KDE_NO_EXPORT bool TVDeviceScannerSource::isSeekable () {
0709     return false;
0710 }
0711 
0712 KDE_NO_EXPORT bool TVDeviceScannerSource::scan (const QString & dev, const QString & dri) {
0713     if (m_tvdevice)
0714         return false;
0715     setUrl ("tv://");
0716     KMPlayer::NodePtr doc = m_tvsource->document ();
0717     m_tvdevice = new TVDevice (doc, dev);
0718     m_tvsource->document ()->appendChild (m_tvdevice);
0719     m_tvdevice->zombie = true; // not for real yet
0720     m_driver = dri;
0721     m_old_source = m_tvsource->player ()->source ();
0722     m_tvsource->player ()->setSource (this);
0723     m_identified = true;
0724     play (m_tvdevice);
0725     return true;
0726 }
0727 
0728 KDE_NO_EXPORT void TVDeviceScannerSource::activate () {
0729     m_nameRegExp.setPattern ("Selected device:\\s*([^\\s].*)");
0730     m_sizesRegExp.setPattern ("Supported sizes:\\s*([0-9]+)x([0-9]+) => ([0-9]+)x([0-9]+)");
0731     m_inputRegExp.setPattern ("\\s*([0-9]+):\\s*([^:]+):[^\\(]*\\(tuner:([01]),\\s*norm:([^\\)]+)\\)");
0732     m_inputRegExpV4l2.setPattern ("inputs:((?:\\s*[0-9]+\\s*=\\s*[^;]+;)+)");
0733 }
0734 
0735 KDE_NO_EXPORT void TVDeviceScannerSource::deactivate () {
0736     kDebug () << "TVDeviceScannerSource::deactivate";
0737     if (m_tvdevice) {
0738         if (m_tvdevice->parentNode ())
0739             m_tvdevice->parentNode ()->removeChild (m_tvdevice);
0740         m_tvdevice = 0L;
0741         delete m_process;
0742         emit scanFinished (m_tvdevice);
0743     }
0744 }
0745 
0746 KDE_NO_EXPORT void TVDeviceScannerSource::play (KMPlayer::Mrl *) {
0747     if (!m_tvdevice)
0748         return;
0749     m_options.sprintf ("tv:// -tv driver=%s:device=%s -identify -frames 0", m_driver.toAscii ().data (), m_tvdevice->src.toAscii ().data ());
0750     m_tvsource->player ()->stop ();
0751     KMPlayer::Node *n = new KMPlayer::SourceDocument (this, QString ());
0752     setDocument (n, n);
0753     m_process = m_player->mediaManager()->processInfos()["mplayer"]->create (m_player, this);
0754     m_viewer = m_player->viewWidget ()->viewArea ()->createVideoWidget ();
0755     m_process->ready ();
0756 }
0757 
0758 KDE_NO_EXPORT void TVDeviceScannerSource::scanningFinished () {
0759     TVDevice * dev = 0L;
0760     delete m_process;
0761     kDebug () << "scanning done " << m_tvdevice->hasChildNodes ();
0762     if (!m_tvdevice->hasChildNodes ()) {
0763         m_tvsource->document ()->removeChild (m_tvdevice);
0764     } else {
0765         dev = m_tvdevice;
0766         if (width () > 0 && height () > 0) {
0767             m_tvdevice->setAttribute (KMPlayer::Ids::attr_width,
0768                     QString::number (width ()));
0769             m_tvdevice->setAttribute (KMPlayer::Ids::attr_height,
0770                     QString::number (height ()));
0771         }
0772     }
0773     m_tvdevice = 0L;
0774     m_player->setSource (m_old_source);
0775     emit scanFinished (dev);
0776 }
0777 
0778 void TVDeviceScannerSource::stateChange (KMPlayer::IProcess *,
0779                    KMPlayer::IProcess::State os, KMPlayer::IProcess::State ns) {
0780     if (KMPlayer::IProcess::Ready == ns) {
0781         if (os > KMPlayer::IProcess::Ready)
0782             QTimer::singleShot (0, this, SLOT (scanningFinished()));
0783         else if (m_process && os < KMPlayer::IProcess::Ready)
0784             m_process->play ();
0785     }
0786 }
0787 
0788 void TVDeviceScannerSource::processDestroyed (KMPlayer::IProcess *) {
0789     m_process = NULL;
0790     KMPlayer::View *view = m_player->viewWidget ();
0791     if (view)
0792         view->viewArea ()->destroyVideoWidget (m_viewer);
0793     m_viewer = NULL;
0794 }
0795 
0796 KMPlayer::IViewer *TVDeviceScannerSource::viewer () {
0797     return m_viewer;
0798 }
0799 
0800 KMPlayer::Mrl *TVDeviceScannerSource::getMrl () {
0801     return document ()->mrl ();
0802 }
0803 
0804 
0805 #include "kmplayertvsource.moc"