00001
00002
00003
00004 #include <unistd.h>
00005 #include <fcntl.h>
00006 #include <sys/types.h>
00007 #include <sys/stat.h>
00008
00009
00010 #include <algorithm>
00011 using namespace std;
00012
00013
00014 #include <qapplication.h>
00015 #include <qstringlist.h>
00016 #include <qcursor.h>
00017 #include <qlayout.h>
00018 #include <qfile.h>
00019 #include <qmap.h>
00020 #include <qdir.h>
00021 #include <qprocess.h>
00022 #include <qdatetime.h>
00023
00024
00025 #include "mythconfig.h"
00026 #include "mythwidgets.h"
00027 #include "mythdialogs.h"
00028 #include "mythcontext.h"
00029 #include "mythdbcon.h"
00030 #include "videosource.h"
00031 #include "datadirect.h"
00032 #include "scanwizard.h"
00033 #include "cardutil.h"
00034 #include "sourceutil.h"
00035 #include "channelutil.h"
00036 #include "frequencies.h"
00037 #include "diseqcsettings.h"
00038 #include "firewiredevice.h"
00039 #include "compat.h"
00040
00041
00042 #ifdef USING_DVB
00043 #include "dvbtypes.h"
00044 #endif
00045
00046 #ifdef USING_V4L
00047 #include "videodev_myth.h"
00048 #endif
00049
00050 VideoSourceSelector::VideoSourceSelector(uint _initial_sourceid,
00051 const QString &_card_types,
00052 bool _must_have_mplexid) :
00053 ComboBoxSetting(this),
00054 initial_sourceid(_initial_sourceid),
00055 card_types(QDeepCopy<QString>(_card_types)),
00056 must_have_mplexid(_must_have_mplexid)
00057 {
00058 setLabel(tr("Video Source"));
00059 }
00060
00061 void VideoSourceSelector::load(void)
00062 {
00063 MSqlQuery query(MSqlQuery::InitCon());
00064
00065 QString querystr =
00066 "SELECT DISTINCT videosource.name, videosource.sourceid "
00067 "FROM cardinput, videosource, capturecard";
00068
00069 querystr += (must_have_mplexid) ? ", channel " : " ";
00070
00071 querystr +=
00072 "WHERE cardinput.sourceid = videosource.sourceid AND "
00073 " cardinput.cardid = capturecard.cardid AND "
00074 " capturecard.hostname = :HOSTNAME ";
00075
00076 if (!card_types.isEmpty())
00077 {
00078 querystr += QString(" AND capturecard.cardtype in %1 ")
00079 .arg(card_types);
00080 }
00081
00082 if (must_have_mplexid)
00083 {
00084 querystr +=
00085 " AND channel.sourceid = videosource.sourceid "
00086 " AND channel.mplexid != 32767 "
00087 " AND channel.mplexid != 0 ";
00088 }
00089
00090 query.prepare(querystr);
00091 query.bindValue(":HOSTNAME", gContext->GetHostName());
00092
00093 if (!query.exec() || !query.isActive() || query.size() <= 0)
00094 return;
00095
00096 uint sel = 0, cnt = 0;
00097 for (; query.next(); cnt++)
00098 {
00099 addSelection(query.value(0).toString(),
00100 query.value(1).toString());
00101
00102 sel = (query.value(1).toUInt() == initial_sourceid) ? cnt : sel;
00103 }
00104
00105 if (initial_sourceid)
00106 {
00107 if (cnt)
00108 setValue(sel);
00109 setEnabled(false);
00110 }
00111 }
00112
00113 class InstanceCount : public TransSpinBoxSetting
00114 {
00115 public:
00116 InstanceCount(const CaptureCard &parent) : TransSpinBoxSetting(1, 5, 1)
00117 {
00118 setLabel(QObject::tr("Max recordings"));
00119 setHelpText(
00120 QObject::tr(
00121 "Maximum number of simultaneous recordings this device "
00122 "should make. Some digital transmitters transmit multiple "
00123 "programs on a multiplex, if this is set to a value greater "
00124 "than one MythTV can sometimes take advantage of this."));
00125 uint cnt = parent.GetInstanceCount();
00126 cnt = (!cnt) ? (uint) 2 : ((cnt < 1) ? 1 : cnt);
00127 setValue(cnt);
00128 };
00129 };
00130
00131 class RecorderOptions : public ConfigurationWizard
00132 {
00133 public:
00134 RecorderOptions(CaptureCard& parent);
00135 uint GetInstanceCount(void) const { return (uint) count->intValue(); }
00136
00137 private:
00138 InstanceCount *count;
00139 };
00140
00141 QString VideoSourceDBStorage::whereClause(MSqlBindings& bindings)
00142 {
00143 QString sourceidTag(":WHERESOURCEID");
00144
00145 QString query("sourceid = " + sourceidTag);
00146
00147 bindings.insert(sourceidTag, parent.getSourceID());
00148
00149 return query;
00150 }
00151
00152 QString VideoSourceDBStorage::setClause(MSqlBindings& bindings)
00153 {
00154 QString sourceidTag(":SETSOURCEID");
00155 QString colTag(":SET" + getColumn().upper());
00156
00157 QString query("sourceid = " + sourceidTag + ", " +
00158 getColumn() + " = " + colTag);
00159
00160 bindings.insert(sourceidTag, parent.getSourceID());
00161 bindings.insert(colTag, setting->getValue());
00162
00163 return query;
00164 }
00165
00166 QString CaptureCardDBStorage::whereClause(MSqlBindings& bindings)
00167 {
00168 QString cardidTag(":WHERECARDID");
00169
00170 QString query("cardid = " + cardidTag);
00171
00172 bindings.insert(cardidTag, parent.getCardID());
00173
00174 return query;
00175 }
00176
00177 QString CaptureCardDBStorage::setClause(MSqlBindings& bindings)
00178 {
00179 QString cardidTag(":SETCARDID");
00180 QString colTag(":SET" + getColumn().upper());
00181
00182 QString query("cardid = " + cardidTag + ", " +
00183 getColumn() + " = " + colTag);
00184
00185 bindings.insert(cardidTag, parent.getCardID());
00186 bindings.insert(colTag, setting->getValue());
00187
00188 return query;
00189 }
00190
00191 class XMLTVGrabber : public ComboBoxSetting, public VideoSourceDBStorage
00192 {
00193 public:
00194 XMLTVGrabber(const VideoSource &parent) :
00195 ComboBoxSetting(this), VideoSourceDBStorage(this, parent, "xmltvgrabber")
00196 {
00197 setLabel(QObject::tr("Listings grabber"));
00198 };
00199 };
00200
00201 FreqTableSelector::FreqTableSelector(const VideoSource &parent) :
00202 ComboBoxSetting(this), VideoSourceDBStorage(this, parent, "freqtable")
00203 {
00204 setLabel(QObject::tr("Channel frequency table"));
00205 addSelection("default");
00206
00207 for (uint i = 0; chanlists[i].name; i++)
00208 addSelection(chanlists[i].name);
00209
00210 setHelpText(QObject::tr("Use default unless this source uses a "
00211 "different frequency table than the system wide table "
00212 "defined in the General settings."));
00213 }
00214
00215 TransFreqTableSelector::TransFreqTableSelector(uint _sourceid) :
00216 ComboBoxSetting(this), sourceid(_sourceid),
00217 loaded_freq_table(QString::null)
00218 {
00219 setLabel(QObject::tr("Channel frequency table"));
00220
00221 for (uint i = 0; chanlists[i].name; i++)
00222 addSelection(chanlists[i].name);
00223 }
00224
00225 void TransFreqTableSelector::load(void)
00226 {
00227 int idx = getValueIndex(gContext->GetSetting("FreqTable"));
00228 if (idx >= 0)
00229 setValue(idx);
00230
00231 if (!sourceid)
00232 return;
00233
00234 MSqlQuery query(MSqlQuery::InitCon());
00235 query.prepare(
00236 "SELECT freqtable "
00237 "FROM videosource "
00238 "WHERE sourceid = :SOURCEID");
00239 query.bindValue(":SOURCEID", sourceid);
00240
00241 if (!query.exec() || !query.isActive())
00242 {
00243 MythContext::DBError("TransFreqTableSelector::load", query);
00244 return;
00245 }
00246
00247 loaded_freq_table = QString::null;
00248
00249 if (query.next())
00250 {
00251 loaded_freq_table = query.value(0).toString();
00252 if (!loaded_freq_table.isEmpty() &&
00253 (loaded_freq_table.lower() != "default"))
00254 {
00255 int idx = getValueIndex(loaded_freq_table);
00256 if (idx >= 0)
00257 setValue(idx);
00258 }
00259 }
00260 }
00261
00262 void TransFreqTableSelector::save(void)
00263 {
00264 VERBOSE(VB_IMPORTANT, "TransFreqTableSelector::save(void)");
00265
00266 if ((loaded_freq_table == getValue()) ||
00267 ((loaded_freq_table.lower() == "default") &&
00268 (getValue() == gContext->GetSetting("FreqTable"))))
00269 {
00270 return;
00271 }
00272
00273 MSqlQuery query(MSqlQuery::InitCon());
00274 query.prepare(
00275 "UPDATE videosource "
00276 "SET freqtable = :FREQTABLE "
00277 "WHERE sourceid = :SOURCEID");
00278
00279 query.bindValue(":FREQTABLE", getValue());
00280 query.bindValue(":SOURCEID", sourceid);
00281
00282 if (!query.exec() || !query.isActive())
00283 {
00284 MythContext::DBError("TransFreqTableSelector::load", query);
00285 return;
00286 }
00287 }
00288
00289 void TransFreqTableSelector::SetSourceID(uint _sourceid)
00290 {
00291 sourceid = _sourceid;
00292 load();
00293 }
00294
00295 class UseEIT : public CheckBoxSetting, public VideoSourceDBStorage
00296 {
00297 public:
00298 UseEIT(const VideoSource &parent) :
00299 CheckBoxSetting(this), VideoSourceDBStorage(this, parent, "useeit")
00300 {
00301 setLabel(QObject::tr("Perform EIT Scan"));
00302 setHelpText(QObject::tr(
00303 "If this is enabled the data in this source will be "
00304 "updated with listing data provided by the channels "
00305 "themselves 'over-the-air'."));
00306 }
00307 };
00308
00309 class DataDirectUserID : public LineEditSetting, public VideoSourceDBStorage
00310 {
00311 public:
00312 DataDirectUserID(const VideoSource &parent) :
00313 LineEditSetting(this), VideoSourceDBStorage(this, parent, "userid")
00314 {
00315 setLabel(QObject::tr("User ID"));
00316 }
00317 };
00318
00319 class DataDirectPassword : public LineEditSetting, public VideoSourceDBStorage
00320 {
00321 public:
00322 DataDirectPassword(const VideoSource &parent) :
00323 LineEditSetting(this, true),
00324 VideoSourceDBStorage(this, parent, "password")
00325 {
00326 SetPasswordEcho(true);
00327 setLabel(QObject::tr("Password"));
00328 }
00329 };
00330
00331 void DataDirectLineupSelector::fillSelections(const QString &uid,
00332 const QString &pwd,
00333 int _source)
00334 {
00335 (void) uid;
00336 (void) pwd;
00337 #ifdef USING_BACKEND
00338 if (uid.isEmpty() || pwd.isEmpty())
00339 return;
00340
00341 qApp->processEvents();
00342
00343 DataDirectProcessor ddp(_source, uid, pwd);
00344 QString waitMsg = tr("Fetching lineups from %1...")
00345 .arg(ddp.GetListingsProviderName());
00346
00347 VERBOSE(VB_GENERAL, waitMsg);
00348 MythProgressDialog *pdlg = new MythProgressDialog(waitMsg, 2);
00349
00350 clearSelections();
00351
00352 pdlg->setProgress(1);
00353
00354 if (!ddp.GrabLineupsOnly())
00355 {
00356 VERBOSE(VB_IMPORTANT, "DDLS: fillSelections "
00357 "did not successfully load selections");
00358 return;
00359 }
00360 const DDLineupList lineups = ddp.GetLineups();
00361
00362 DDLineupList::const_iterator it;
00363 for (it = lineups.begin(); it != lineups.end(); ++it)
00364 addSelection((*it).displayname, (*it).lineupid);
00365
00366 pdlg->setProgress(2);
00367 pdlg->Close();
00368 pdlg->deleteLater();
00369 #else // USING_BACKEND
00370 VERBOSE(VB_IMPORTANT, "You must compile the backend "
00371 "to set up a DataDirect line-up");
00372 #endif // USING_BACKEND
00373 }
00374
00375 void DataDirect_config::load()
00376 {
00377 VerticalConfigurationGroup::load();
00378 bool is_sd_userid = userid->getValue().contains("@") > 0;
00379 bool match = ((is_sd_userid && (source == DD_SCHEDULES_DIRECT)) ||
00380 (!is_sd_userid && (source == DD_ZAP2IT)));
00381 if (((userid->getValue() != lastloadeduserid) ||
00382 (password->getValue() != lastloadedpassword)) && match)
00383 {
00384 lineupselector->fillSelections(userid->getValue(),
00385 password->getValue(),
00386 source);
00387 lastloadeduserid = userid->getValue();
00388 lastloadedpassword = password->getValue();
00389 }
00390 }
00391
00392 DataDirect_config::DataDirect_config(const VideoSource& _parent, int _source) :
00393 VerticalConfigurationGroup(false, false, false, false),
00394 parent(_parent)
00395 {
00396 source = _source;
00397
00398 HorizontalConfigurationGroup *up =
00399 new HorizontalConfigurationGroup(false, false, true, true);
00400
00401 up->addChild(userid = new DataDirectUserID(parent));
00402 addChild(up);
00403
00404 HorizontalConfigurationGroup *lp =
00405 new HorizontalConfigurationGroup(false, false, true, true);
00406
00407 lp->addChild(password = new DataDirectPassword(parent));
00408 lp->addChild(button = new DataDirectButton());
00409 addChild(lp);
00410
00411 addChild(lineupselector = new DataDirectLineupSelector(parent));
00412 addChild(new UseEIT(parent));
00413
00414 connect(button, SIGNAL(pressed()),
00415 this, SLOT(fillDataDirectLineupSelector()));
00416 }
00417
00418 void DataDirect_config::fillDataDirectLineupSelector(void)
00419 {
00420 lineupselector->fillSelections(
00421 userid->getValue(), password->getValue(), source);
00422 }
00423
00424 XMLTV_generic_config::XMLTV_generic_config(const VideoSource& _parent,
00425 QString _grabber) :
00426 VerticalConfigurationGroup(false, false, false, false),
00427 parent(_parent), grabber(_grabber)
00428 {
00429 TransLabelSetting *label = new TransLabelSetting();
00430 label->setLabel(grabber);
00431 label->setValue(
00432 QObject::tr("Configuration will run in the terminal window"));
00433 addChild(label);
00434 addChild(new UseEIT(parent));
00435 }
00436
00437 void XMLTV_generic_config::save()
00438 {
00439 VerticalConfigurationGroup::save();
00440 QString waitMsg(QObject::tr("Please wait while MythTV retrieves the "
00441 "list of available channels.\nYou "
00442 "might want to check the output as it\n"
00443 "runs by switching to the terminal from "
00444 "which you started\nthis program."));
00445 MythProgressDialog *pdlg = new MythProgressDialog(waitMsg, 2);
00446 VERBOSE(VB_GENERAL, QString("Please wait while MythTV retrieves the "
00447 "list of available channels"));
00448 pdlg->show();
00449
00450 QString command;
00451 QString filename = QString("%1/%2.xmltv")
00452 .arg(MythContext::GetConfDir()).arg(parent.getSourceName());
00453
00454 gContext->SaveSetting(QString("XMLTVConfig.%1").arg(parent.getSourceName()), filename);
00455
00456 command = QString("%1 --config-file '%2' --configure")
00457 .arg(grabber).arg(filename);
00458
00459 pdlg->setProgress(1);
00460
00461 int ret = system(command);
00462 if (ret != 0)
00463 {
00464 VERBOSE(VB_GENERAL, command);
00465 VERBOSE(VB_GENERAL, QString("exited with status %1").arg(ret));
00466
00467 MythPopupBox::showOkPopup(gContext->GetMainWindow(),
00468 QObject::tr("Failed to retrieve channel "
00469 "information."),
00470 QObject::tr("MythTV was unable to retrieve "
00471 "channel information for your "
00472 "provider.\nPlease check the "
00473 "terminal window for more "
00474 "information"));
00475 }
00476
00477 QString err_msg = QObject::tr(
00478 "You MUST run 'mythfilldatabase --manual the first time,\n "
00479 "instead of just 'mythfilldatabase'.\nYour grabber does not provide "
00480 "channel numbers, so you have to set them manually.");
00481
00482 if (is_grabber_external(grabber))
00483 {
00484 VERBOSE(VB_IMPORTANT, "\n" << err_msg);
00485 MythPopupBox::showOkPopup(
00486 gContext->GetMainWindow(), QObject::tr("Warning."), err_msg);
00487 }
00488
00489 pdlg->setProgress( 2 );
00490 pdlg->Close();
00491 pdlg->deleteLater();
00492 }
00493
00494 EITOnly_config::EITOnly_config(const VideoSource& _parent) :
00495 VerticalConfigurationGroup(false, false, true, true)
00496 {
00497 useeit = new UseEIT(_parent);
00498 useeit->setValue(true);
00499 useeit->setVisible(false);
00500 addChild(useeit);
00501
00502 TransLabelSetting *label;
00503 label=new TransLabelSetting();
00504 label->setValue(QObject::tr("Use only the transmitted guide data."));
00505 addChild(label);
00506 label=new TransLabelSetting();
00507 label->setValue(
00508 QObject::tr("This will usually only work with ATSC or DVB channels,"));
00509 addChild(label);
00510 label=new TransLabelSetting();
00511 label->setValue(
00512 QObject::tr("and generally provides data only for the next few days."));
00513 addChild(label);
00514 }
00515
00516 void EITOnly_config::save()
00517 {
00518
00519 useeit->setValue(true);
00520 useeit->save();
00521 }
00522
00523 NoGrabber_config::NoGrabber_config(const VideoSource& _parent) :
00524 VerticalConfigurationGroup(false, false, false, false)
00525 {
00526 useeit = new UseEIT(_parent);
00527 useeit->setValue(false);
00528 useeit->setVisible(false);
00529 addChild(useeit);
00530 }
00531
00532 void NoGrabber_config::save()
00533 {
00534 useeit->setValue(false);
00535 useeit->save();
00536 }
00537
00538 XMLTVConfig::XMLTVConfig(const VideoSource &parent) :
00539 TriggeredConfigurationGroup(false, true, false, false)
00540 {
00541 XMLTVGrabber* grabber = new XMLTVGrabber(parent);
00542 addChild(grabber);
00543 setTrigger(grabber);
00544
00545
00546 setSaveAll(false);
00547
00548 addTarget("schedulesdirect1",
00549 new DataDirect_config(parent, DD_SCHEDULES_DIRECT));
00550 grabber->addSelection("North America (SchedulesDirect.org) "
00551 "(Internal)", "schedulesdirect1");
00552
00553 addTarget("eitonly", new EITOnly_config(parent));
00554 grabber->addSelection("Transmitted guide only (EIT)", "eitonly");
00555
00556 QProcess find_grabber_proc( QString("tv_find_grabbers"), this );
00557 find_grabber_proc.addArgument("baseline");
00558 find_grabber_proc.addArgument("manualconfig");
00559 if ( find_grabber_proc.start() ) {
00560
00561 VERBOSE(VB_IMPORTANT, "Running tv_find_grabbers.");
00562 MythBusyDialog *find_grabbers_dialog = new MythBusyDialog(
00563 QObject::tr("Searching for installed XMLTV grabbers"));
00564 find_grabbers_dialog->start();
00565
00566 int i=0;
00567
00568
00569
00570
00571 while (find_grabber_proc.isRunning() && i < 250)
00572 {
00573 usleep(100000);
00574 ++i;
00575
00576 qApp->processEvents();
00577 }
00578
00579 if (find_grabber_proc.normalExit())
00580 {
00581 while (find_grabber_proc.canReadLineStdout())
00582 {
00583 QString grabber_list = find_grabber_proc.readLineStdout();
00584 QStringList grabber_split = QStringList::split("|",
00585 grabber_list);
00586 QString grabber_name = grabber_split[1] + " (xmltv)";
00587 QFileInfo grabber_file(grabber_split[0]);
00588 addTarget(grabber_file.fileName(),
00589 new XMLTV_generic_config(parent, grabber_file.fileName()));
00590 grabber->addSelection(grabber_name, grabber_file.fileName());
00591 }
00592 }
00593 else {
00594 VERBOSE(VB_IMPORTANT, "tv_find_grabbers exited early or we timed out waiting");
00595 }
00596
00597 find_grabbers_dialog->Close();
00598 find_grabbers_dialog->deleteLater();
00599 }
00600 else {
00601 VERBOSE(VB_IMPORTANT, "Failed to run tv_find_grabbers");
00602 }
00603
00604 addTarget("/bin/true", new NoGrabber_config(parent));
00605 grabber->addSelection("No grabber", "/bin/true");
00606 }
00607
00608 void XMLTVConfig::save(void)
00609 {
00610 TriggeredConfigurationGroup::save();
00611 MSqlQuery query(MSqlQuery::InitCon());
00612 query.prepare(
00613 "UPDATE videosource "
00614 "SET userid=NULL, password=NULL "
00615 "WHERE xmltvgrabber NOT IN ( 'datadirect', 'technovera', "
00616 " 'schedulesdirect1' )");
00617 query.exec();
00618 }
00619
00620 VideoSource::VideoSource()
00621 {
00622
00623 addChild(id = new ID());
00624
00625 ConfigurationGroup *group = new VerticalConfigurationGroup(false, false);
00626 group->setLabel(QObject::tr("Video source setup"));
00627 group->addChild(name = new Name(*this));
00628 group->addChild(new XMLTVConfig(*this));
00629 group->addChild(new FreqTableSelector(*this));
00630 addChild(group);
00631 }
00632
00633 bool VideoSourceEditor::cardTypesInclude(const int &sourceID,
00634 const QString &thecardtype)
00635 {
00636 MSqlQuery query(MSqlQuery::InitCon());
00637 query.prepare("SELECT count(cardtype)"
00638 " FROM cardinput,capturecard "
00639 " WHERE capturecard.cardid = cardinput.cardid "
00640 " AND cardinput.sourceid= :SOURCEID "
00641 " AND capturecard.cardtype= :CARDTYPE ;");
00642 query.bindValue(":SOURCEID", sourceID);
00643 query.bindValue(":CARDTYPE", thecardtype);
00644
00645 if (query.exec() && query.isActive() && query.size() > 0)
00646 {
00647 query.next();
00648 int count = query.value(0).toInt();
00649
00650 if (count > 0)
00651 return true;
00652 }
00653
00654 return false;
00655 }
00656
00657 void VideoSource::fillSelections(SelectSetting* setting)
00658 {
00659 MSqlQuery result(MSqlQuery::InitCon());
00660 result.prepare("SELECT name, sourceid FROM videosource;");
00661
00662 if (result.exec() && result.isActive() && result.size() > 0)
00663 {
00664 while (result.next())
00665 {
00666 setting->addSelection(result.value(0).toString(),
00667 result.value(1).toString());
00668 }
00669 }
00670 }
00671
00672 void VideoSource::loadByID(int sourceid)
00673 {
00674 id->setValue(sourceid);
00675 load();
00676 }
00677
00678 class VideoDevice : public PathSetting, public CaptureCardDBStorage
00679 {
00680 public:
00681 VideoDevice(const CaptureCard &parent,
00682 uint minor_min = 0,
00683 uint minor_max = UINT_MAX,
00684 QString card = QString::null,
00685 QString driver = QString::null) :
00686 PathSetting(this, true),
00687 CaptureCardDBStorage(this, parent, "videodevice")
00688 {
00689 setLabel(QObject::tr("Video device"));
00690
00691
00692 QDir dev("/dev/v4l", "video*", QDir::Name, QDir::System);
00693 fillSelectionsFromDir(dev, minor_min, minor_max,
00694 card, driver, false);
00695
00696
00697 dev.setPath("/dev");
00698 fillSelectionsFromDir(dev, minor_min, minor_max,
00699 card, driver, false);
00700
00701
00702 dev.setPath("/dev/dtv");
00703 fillSelectionsFromDir(dev, minor_min, minor_max,
00704 card, driver, false);
00705
00706
00707 dev.setPath("/dev");
00708 dev.setNameFilter("dtv*");
00709 fillSelectionsFromDir(dev, minor_min, minor_max,
00710 card, driver, false);
00711 };
00712
00713 uint fillSelectionsFromDir(const QDir& dir,
00714 uint minor_min, uint minor_max,
00715 QString card, QString driver,
00716 bool allow_duplicates)
00717 {
00718 uint cnt = 0;
00719 const QFileInfoList *il = dir.entryInfoList();
00720 if (!il)
00721 return cnt;
00722
00723 QFileInfoListIterator it( *il );
00724 QFileInfo *fi;
00725
00726 for (; (fi = it.current()) != 0; ++it)
00727 {
00728 struct stat st;
00729 QString filepath = fi->absFilePath();
00730 int err = lstat(filepath, &st);
00731
00732 if (0 != err)
00733 {
00734 VERBOSE(VB_IMPORTANT,
00735 QString("Could not stat file: %1").arg(filepath));
00736 continue;
00737 }
00738
00739
00740 if (!S_ISCHR(st.st_mode))
00741 continue;
00742
00743
00744 uint minor_num = minor(st.st_rdev);
00745 if (minor_min > minor_num || minor_max < minor_num)
00746 continue;
00747
00748
00749 if (!allow_duplicates && minor_list[minor_num])
00750 continue;
00751
00752
00753 int videofd = open(filepath.ascii(), O_RDWR);
00754 if (videofd >= 0)
00755 {
00756 QString cn, dn;
00757 if (CardUtil::GetV4LInfo(videofd, cn, dn) &&
00758 (driver.isEmpty() || (dn == driver)) &&
00759 (card.isEmpty() || (cn == card)))
00760 {
00761 addSelection(filepath);
00762 cnt++;
00763 }
00764 close(videofd);
00765 }
00766
00767
00768 minor_list[minor_num] = 1;
00769 }
00770
00771 return cnt;
00772 }
00773
00774 private:
00775 QMap<uint, uint> minor_list;
00776 };
00777
00778 class VBIDevice : public PathSetting, public CaptureCardDBStorage
00779 {
00780 public:
00781 VBIDevice(const CaptureCard &parent) :
00782 PathSetting(this, true),
00783 CaptureCardDBStorage(this, parent, "vbidevice")
00784 {
00785 setLabel(QObject::tr("VBI device"));
00786 setFilter(QString::null, QString::null);
00787 };
00788
00789 void setFilter(const QString &card, const QString &driver)
00790 {
00791 clearSelections();
00792 QDir dev("/dev/v4l", "vbi*", QDir::Name, QDir::System);
00793 if (!fillSelectionsFromDir(dev, card, driver))
00794 {
00795 dev.setPath("/dev");
00796 fillSelectionsFromDir(dev, card, driver);
00797 }
00798 }
00799
00800 uint fillSelectionsFromDir(const QDir &dir, const QString &card,
00801 const QString &driver)
00802 {
00803 uint cnt = 0;
00804 const QFileInfoList *il = dir.entryInfoList();
00805 if (!il)
00806 return cnt;
00807
00808 QFileInfoListIterator it(*il);
00809 QFileInfo *fi;
00810
00811 for (; (fi = it.current()) != 0; ++it)
00812 {
00813 QString device = fi->absFilePath();
00814 int vbifd = open(device.ascii(), O_RDWR);
00815 if (vbifd < 0)
00816 continue;
00817
00818 QString cn, dn;
00819 if (CardUtil::GetV4LInfo(vbifd, cn, dn) &&
00820 (driver.isEmpty() || (dn == driver)) &&
00821 (card.isEmpty() || (cn == card)))
00822 {
00823 addSelection(device);
00824 cnt++;
00825 }
00826
00827 close(vbifd);
00828 }
00829
00830 return cnt;
00831 }
00832 };
00833
00834 class AudioDevice : public PathSetting, public CaptureCardDBStorage
00835 {
00836 public:
00837 AudioDevice(const CaptureCard &parent) :
00838 PathSetting(this, true),
00839 CaptureCardDBStorage(this, parent, "audiodevice")
00840 {
00841 setLabel(QObject::tr("Audio device"));
00842 QDir dev("/dev", "dsp*", QDir::Name, QDir::System);
00843 fillSelectionsFromDir(dev);
00844 dev.setPath("/dev/sound");
00845 fillSelectionsFromDir(dev);
00846 addSelection(QObject::tr("(None)"), "/dev/null");
00847 };
00848 };
00849
00850 class SignalTimeout : public SpinBoxSetting, public CaptureCardDBStorage
00851 {
00852 public:
00853 SignalTimeout(const CaptureCard &parent, uint value, uint min_val) :
00854 SpinBoxSetting(this, min_val, 60000, 250),
00855 CaptureCardDBStorage(this, parent, "signal_timeout")
00856 {
00857 setLabel(QObject::tr("Signal Timeout (msec)"));
00858 setValue(value);
00859 setHelpText(QObject::tr(
00860 "Maximum time MythTV waits for any signal when "
00861 "scanning for channels."));
00862 };
00863 };
00864
00865 class ChannelTimeout : public SpinBoxSetting, public CaptureCardDBStorage
00866 {
00867 public:
00868 ChannelTimeout(const CaptureCard &parent, uint value, uint min_val) :
00869 SpinBoxSetting(this, min_val, 65000, 250),
00870 CaptureCardDBStorage(this, parent, "channel_timeout")
00871 {
00872 setLabel(QObject::tr("Tuning Timeout (msec)"));
00873 setValue(value);
00874 setHelpText(QObject::tr(
00875 "Maximum time MythTV waits for a channel lock "
00876 "when scanning for channels. Or, for issuing "
00877 "a warning in LiveTV mode."));
00878 };
00879 };
00880
00881 class AudioRateLimit : public ComboBoxSetting, public CaptureCardDBStorage
00882 {
00883 public:
00884 AudioRateLimit(const CaptureCard &parent) :
00885 ComboBoxSetting(this),
00886 CaptureCardDBStorage(this, parent, "audioratelimit")
00887 {
00888 setLabel(QObject::tr("Audio sampling rate limit"));
00889 addSelection(QObject::tr("(None)"), "0");
00890 addSelection("32000");
00891 addSelection("44100");
00892 addSelection("48000");
00893 };
00894 };
00895
00896 class SkipBtAudio : public CheckBoxSetting, public CaptureCardDBStorage
00897 {
00898 public:
00899 SkipBtAudio(const CaptureCard &parent) :
00900 CheckBoxSetting(this),
00901 CaptureCardDBStorage(this, parent, "skipbtaudio")
00902 {
00903 setLabel(QObject::tr("Do not adjust volume"));
00904 setHelpText(
00905 QObject::tr("Enable this option for budget BT878 based "
00906 "DVB-T cards such as the AverTV DVB-T which "
00907 "require the audio volume to be left alone."));
00908 };
00909 };
00910
00911 class DVBInput : public ComboBoxSetting, public CaptureCardDBStorage
00912 {
00913 public:
00914 DVBInput(const CaptureCard &parent) :
00915 ComboBoxSetting(this),
00916 CaptureCardDBStorage(this, parent, "defaultinput")
00917 {
00918 setLabel(QObject::tr("Default Input"));
00919 fillSelections(false);
00920 }
00921
00922 void fillSelections(bool diseqc)
00923 {
00924 clearSelections();
00925 addSelection((diseqc) ? "DVBInput #1" : "DVBInput");
00926 }
00927 };
00928
00929 class DVBCardNum : public ComboBoxSetting, public CaptureCardDBStorage
00930 {
00931 public:
00932 DVBCardNum(const CaptureCard &parent) :
00933 ComboBoxSetting(this),
00934 CaptureCardDBStorage(this, parent, "videodevice")
00935 {
00936 setLabel(QObject::tr("DVB Device Number"));
00937 setHelpText(
00938 QObject::tr("When you change this setting, the text below "
00939 "should change to the name and type of your card. "
00940 "If the card cannot be opened, an error message "
00941 "will be displayed."));
00942 fillSelections(-1);
00943 };
00944
00948 void fillSelections(int current)
00949 {
00950 clearSelections();
00951
00952
00953 vector<QString> sdevs = CardUtil::ProbeVideoDevices("DVB");
00954 vector<uint> devs;
00955 for (uint i = 0; i < sdevs.size(); i++)
00956 devs.push_back(sdevs[i].toUInt());
00957
00958
00959 if ((current >= 0) &&
00960 (find(devs.begin(), devs.end(), (uint)current) == devs.end()))
00961 {
00962 devs.push_back(current);
00963 stable_sort(devs.begin(), devs.end());
00964 }
00965
00966 vector<QString> db = CardUtil::GetVideoDevices("DVB");
00967
00968 QMap<uint,bool> in_use;
00969 QString sel = (current >= 0) ? QString::number(current) : "";
00970 for (uint i = 0; i < devs.size(); i++)
00971 {
00972 const QString dev = QString::number(devs[i]);
00973 in_use[devs[i]] = find(db.begin(), db.end(), dev) != db.end();
00974 if (sel.isEmpty() && !in_use[devs[i]])
00975 sel = dev;
00976 }
00977
00978 if (sel.isEmpty() && devs.size())
00979 sel = devs[0];
00980
00981 QString usestr = QString(" -- ");
00982 usestr += QObject::tr("Warning: already in use");
00983
00984 for (uint i = 0; i < devs.size(); i++)
00985 {
00986 const QString dev = QString::number(devs[i]);
00987 QString desc = dev + (in_use[devs[i]] ? usestr : "");
00988 desc = ((uint)current == devs[i]) ? dev : desc;
00989 addSelection(desc, dev, dev == sel);
00990 }
00991 }
00992
00993 virtual void load(void)
00994 {
00995 clearSelections();
00996 addSelection("-1");
00997
00998 CaptureCardDBStorage::load();
00999
01000 bool ok;
01001 int intval = getValue().toInt(&ok);
01002 intval = (ok) ? intval : -1;
01003
01004 fillSelections(intval);
01005 }
01006 };
01007
01008 class DVBCardType : public TransLabelSetting
01009 {
01010 public:
01011 DVBCardType()
01012 {
01013 setLabel(QObject::tr("Subtype"));
01014 };
01015 };
01016
01017 class DVBCardName : public TransLabelSetting
01018 {
01019 public:
01020 DVBCardName()
01021 {
01022 setLabel(QObject::tr("Frontend ID"));
01023 };
01024 };
01025
01026 class DVBNoSeqStart : public CheckBoxSetting, public CaptureCardDBStorage
01027 {
01028 public:
01029 DVBNoSeqStart(const CaptureCard &parent) :
01030 CheckBoxSetting(this),
01031 CaptureCardDBStorage(this, parent, "dvb_wait_for_seqstart")
01032 {
01033 setLabel(QObject::tr("Wait for SEQ start header."));
01034 setValue(true);
01035 setHelpText(
01036 QObject::tr("Make the dvb-recording drop packets from "
01037 "the card until a sequence start header is seen."));
01038 };
01039 };
01040
01041 class DVBOnDemand : public CheckBoxSetting, public CaptureCardDBStorage
01042 {
01043 public:
01044 DVBOnDemand(const CaptureCard &parent) :
01045 CheckBoxSetting(this),
01046 CaptureCardDBStorage(this, parent, "dvb_on_demand")
01047 {
01048 setLabel(QObject::tr("Open DVB card on demand"));
01049 setValue(true);
01050 setHelpText(
01051 QObject::tr("This option makes the backend dvb-recorder "
01052 "only open the card when it is actually in-use, leaving "
01053 "it free for other programs at other times."));
01054 };
01055 };
01056
01057 class DVBEITScan : public CheckBoxSetting, public CaptureCardDBStorage
01058 {
01059 public:
01060 DVBEITScan(const CaptureCard &parent) :
01061 CheckBoxSetting(this),
01062 CaptureCardDBStorage(this, parent, "dvb_eitscan")
01063 {
01064 setLabel(QObject::tr("Use DVB Card for active EIT scan"));
01065 setValue(true);
01066 setHelpText(
01067 QObject::tr("This option activates the active scan for "
01068 "program data (EIT). With this option enabled "
01069 "the DVB card is constantly in-use."));
01070 };
01071 };
01072
01073 class DVBTuningDelay : public SpinBoxSetting, public CaptureCardDBStorage
01074 {
01075 public:
01076 DVBTuningDelay(const CaptureCard &parent) :
01077 SpinBoxSetting(this, 0, 2000, 25),
01078 CaptureCardDBStorage(this, parent, "dvb_tuning_delay")
01079 {
01080 setLabel(QObject::tr("DVB Tuning Delay (msec)"));
01081 setHelpText(
01082 QObject::tr("Some Linux DVB drivers, in particular for the "
01083 "Hauppauge Nova-T, require that we slow down "
01084 "the tuning process."));
01085 };
01086 };
01087
01088 class FirewireGUID : public ComboBoxSetting, public CaptureCardDBStorage
01089 {
01090 public:
01091 FirewireGUID(const CaptureCard &parent) :
01092 ComboBoxSetting(this),
01093 CaptureCardDBStorage(this, parent, "videodevice")
01094 {
01095 setLabel(QObject::tr("GUID"));
01096 #ifdef USING_FIREWIRE
01097 vector<AVCInfo> list = FirewireDevice::GetSTBList();
01098 for (uint i = 0; i < list.size(); i++)
01099 {
01100 QString guid = list[i].GetGUIDString();
01101 guid_to_avcinfo[guid] = list[i];
01102 addSelection(guid);
01103 }
01104 #endif // USING_FIREWIRE
01105 }
01106
01107 AVCInfo GetAVCInfo(const QString &guid) const
01108 { return guid_to_avcinfo[guid]; }
01109
01110 private:
01111 QMap<QString,AVCInfo> guid_to_avcinfo;
01112 };
01113
01114 FirewireModel::FirewireModel(const CaptureCard &parent,
01115 const FirewireGUID *_guid) :
01116 ComboBoxSetting(this),
01117 CaptureCardDBStorage(this, parent, "firewire_model"),
01118 guid(_guid)
01119 {
01120 setLabel(QObject::tr("Cable box model"));
01121 addSelection(QObject::tr("Generic"), "GENERIC");
01122 addSelection("DCH-3200");
01123 addSelection("DCT-3412");
01124 addSelection("DCT-3416");
01125 addSelection("DCT-6200");
01126 addSelection("DCT-6212");
01127 addSelection("DCT-6216");
01128 addSelection("SA3250HD");
01129 addSelection("SA4200HD");
01130 addSelection("SA4250HDC");
01131 QString help = QObject::tr(
01132 "Choose the model that most closely resembles your set top box. "
01133 "Depending on firmware revision SA4200HD may work better for a "
01134 "SA3250HD box.");
01135 setHelpText(help);
01136 }
01137
01138 void FirewireModel::SetGUID(const QString &_guid)
01139 {
01140 (void) _guid;
01141
01142 #ifdef USING_FIREWIRE
01143 AVCInfo info = guid->GetAVCInfo(_guid);
01144 QString model = FirewireDevice::GetModelName(info.vendorid, info.modelid);
01145 setValue(max(getValueIndex(model), 0));
01146 #endif // USING_FIREWIRE
01147 }
01148
01149 void FirewireDesc::SetGUID(const QString &_guid)
01150 {
01151 (void) _guid;
01152
01153 setLabel(tr("Description"));
01154
01155 #ifdef USING_FIREWIRE
01156 QString name = guid->GetAVCInfo(_guid).product_name;
01157 name.replace("Scientific-Atlanta", "SA");
01158 name.replace(", Inc.", "");
01159 name.replace("Explorer(R)", "");
01160 name = name.simplifyWhiteSpace();
01161 setValue((name.isEmpty()) ? "" : name);
01162 #endif // USING_FIREWIRE
01163 }
01164
01165 class FirewireConnection : public ComboBoxSetting, public CaptureCardDBStorage
01166 {
01167 public:
01168 FirewireConnection(const CaptureCard &parent) :
01169 ComboBoxSetting(this),
01170 CaptureCardDBStorage(this, parent, "firewire_connection")
01171 {
01172 setLabel(QObject::tr("Connection Type"));
01173 addSelection(QObject::tr("Point to Point"),"0");
01174 addSelection(QObject::tr("Broadcast"),"1");
01175 }
01176 };
01177
01178 class FirewireSpeed : public ComboBoxSetting, public CaptureCardDBStorage
01179 {
01180 public:
01181 FirewireSpeed(const CaptureCard &parent) :
01182 ComboBoxSetting(this),
01183 CaptureCardDBStorage(this, parent, "firewire_speed")
01184 {
01185 setLabel(QObject::tr("Speed"));
01186 addSelection(QObject::tr("100Mbps"),"0");
01187 addSelection(QObject::tr("200Mbps"),"1");
01188 addSelection(QObject::tr("400Mbps"),"2");
01189 addSelection(QObject::tr("800Mbps"),"3");
01190 }
01191 };
01192
01193 class FirewireConfigurationGroup : public VerticalConfigurationGroup
01194 {
01195 public:
01196 FirewireConfigurationGroup(CaptureCard& a_parent) :
01197 VerticalConfigurationGroup(false, true, false, false),
01198 parent(a_parent),
01199 dev(new FirewireGUID(parent)),
01200 desc(new FirewireDesc(dev)),
01201 model(new FirewireModel(parent, dev))
01202 {
01203 addChild(dev);
01204 addChild(desc);
01205 addChild(model);
01206
01207 #ifdef USING_LINUX_FIREWIRE
01208 addChild(new FirewireConnection(parent));
01209 addChild(new FirewireSpeed(parent));
01210 #endif // USING_LINUX_FIREWIRE
01211
01212 addChild(new SignalTimeout(parent, 2000, 1000));
01213 addChild(new ChannelTimeout(parent, 9000, 1750));
01214 addChild(new SingleCardInput(parent));
01215
01216 model->SetGUID(dev->getValue());
01217 desc->SetGUID(dev->getValue());
01218 connect(dev, SIGNAL(valueChanged(const QString&)),
01219 model, SLOT( SetGUID( const QString&)));
01220 connect(dev, SIGNAL(valueChanged(const QString&)),
01221 desc, SLOT( SetGUID( const QString&)));
01222 };
01223
01224 private:
01225 CaptureCard &parent;
01226 FirewireGUID *dev;
01227 FirewireDesc *desc;
01228 FirewireModel *model;
01229 };
01230
01231 class DBOX2Port : public LineEditSetting, public CaptureCardDBStorage
01232 {
01233 public:
01234 DBOX2Port(const CaptureCard &parent) :
01235 LineEditSetting(this),
01236 CaptureCardDBStorage(this, parent, "dbox2_port")
01237 {
01238 setValue("31338");
01239 setLabel(QObject::tr("DBOX2 Streaming Port"));
01240 setHelpText(QObject::tr("DBOX2 streaming port on your DBOX2."));
01241 }
01242 };
01243
01244 class DBOX2HttpPort : public LineEditSetting, public CaptureCardDBStorage
01245 {
01246 public:
01247 DBOX2HttpPort(const CaptureCard &parent) :
01248 LineEditSetting(this),
01249 CaptureCardDBStorage(this, parent, "dbox2_httpport")
01250 {
01251 setValue("80");
01252 setLabel(QObject::tr("DBOX2 HTTP Port"));
01253 setHelpText(QObject::tr("DBOX2 http port on your DBOX2."));
01254 }
01255 };
01256
01257 class DBOX2Host : public LineEditSetting, public CaptureCardDBStorage
01258 {
01259 public:
01260 DBOX2Host(const CaptureCard &parent) :
01261 LineEditSetting(this),
01262 CaptureCardDBStorage(this, parent, "dbox2_host")
01263 {
01264 setValue("dbox");
01265 setLabel(QObject::tr("DBOX2 Host IP"));
01266 setHelpText(QObject::tr("DBOX2 Host IP is the remote device."));
01267 }
01268 };
01269
01270 class DBOX2ConfigurationGroup : public VerticalConfigurationGroup
01271 {
01272 public:
01273 DBOX2ConfigurationGroup(CaptureCard& a_parent):
01274 VerticalConfigurationGroup(false, true, false, false),
01275 parent(a_parent)
01276 {
01277 addChild(new DBOX2Port(parent));
01278 addChild(new DBOX2HttpPort(parent));
01279 addChild(new DBOX2Host(parent));
01280 addChild(new SingleCardInput(parent));
01281 };
01282 private:
01283 CaptureCard &parent;
01284 };
01285
01286 class HDHomeRunDeviceID : public LineEditSetting, public CaptureCardDBStorage
01287 {
01288 public:
01289 HDHomeRunDeviceID(const CaptureCard &parent) :
01290 LineEditSetting(this),
01291 CaptureCardDBStorage(this, parent, "videodevice")
01292 {
01293 setValue("FFFFFFFF");
01294 setLabel(QObject::tr("Device ID"));
01295 setHelpText(QObject::tr("IP address or Device ID from the bottom of "
01296 "the HDHomeRun. You may use "
01297 "'FFFFFFFF' if there is only one unit "
01298 "on your your network."));
01299 }
01300 };
01301
01302 class IPTVHost : public LineEditSetting, public CaptureCardDBStorage
01303 {
01304 public:
01305 IPTVHost(const CaptureCard &parent) :
01306 LineEditSetting(this),
01307 CaptureCardDBStorage(this, parent, "videodevice")
01308 {
01309 setValue("http://mafreebox.freebox.fr/freeboxtv/playlist.m3u");
01310 setLabel(QObject::tr("M3U URL"));
01311 setHelpText(QObject::tr("URL of M3U containing IPTV channel URLs."));
01312 }
01313 };
01314
01315 class IPTVConfigurationGroup : public VerticalConfigurationGroup
01316 {
01317 public:
01318 IPTVConfigurationGroup(CaptureCard& a_parent):
01319 VerticalConfigurationGroup(false, true, false, false),
01320 parent(a_parent)
01321 {
01322 setUseLabel(false);
01323 addChild(new IPTVHost(parent));
01324 addChild(new ChannelTimeout(parent, 3000, 1750));
01325 addChild(new SingleCardInput(parent));
01326 };
01327
01328 private:
01329 CaptureCard &parent;
01330 };
01331
01332 class HDHomeRunTunerIndex : public ComboBoxSetting, public CaptureCardDBStorage
01333 {
01334 public:
01335 HDHomeRunTunerIndex(const CaptureCard &parent) :
01336 ComboBoxSetting(this),
01337 CaptureCardDBStorage(this, parent, "dbox2_port")
01338 {
01339 setLabel(QObject::tr("Tuner"));
01340 addSelection("0");
01341 addSelection("1");
01342 }
01343 };
01344
01345 class HDHomeRunConfigurationGroup : public VerticalConfigurationGroup
01346 {
01347 public:
01348 HDHomeRunConfigurationGroup(CaptureCard& a_parent) :
01349 VerticalConfigurationGroup(false, true, false, false),
01350 parent(a_parent)
01351 {
01352 setUseLabel(false);
01353 addChild(new HDHomeRunDeviceID(parent));
01354 addChild(new HDHomeRunTunerIndex(parent));
01355 addChild(new SignalTimeout(parent, 1000, 250));
01356 addChild(new ChannelTimeout(parent, 3000, 1750));
01357 addChild(new SingleCardInput(parent));
01358 };
01359
01360 private:
01361 CaptureCard &parent;
01362 };
01363
01364 V4LConfigurationGroup::V4LConfigurationGroup(CaptureCard& a_parent) :
01365 VerticalConfigurationGroup(false, true, false, false),
01366 parent(a_parent),
01367 cardinfo(new TransLabelSetting()), vbidev(new VBIDevice(parent)),
01368 input(new TunerCardInput(parent))
01369 {
01370 VideoDevice *device = new VideoDevice(parent);
01371 HorizontalConfigurationGroup *audgrp =
01372 new HorizontalConfigurationGroup(false, false, true, true);
01373
01374 cardinfo->setLabel(tr("Probed info"));
01375 audgrp->addChild(new AudioRateLimit(parent));
01376 audgrp->addChild(new SkipBtAudio(parent));
01377
01378 addChild(device);
01379 addChild(cardinfo);
01380 addChild(vbidev);
01381 addChild(new AudioDevice(parent));
01382 addChild(audgrp);
01383 addChild(input);
01384
01385 connect(device, SIGNAL(valueChanged(const QString&)),
01386 this, SLOT( probeCard( const QString&)));
01387
01388 probeCard(device->getValue());
01389 };
01390
01391 void V4LConfigurationGroup::probeCard(const QString &device)
01392 {
01393 QString cn = tr("Failed to open"), ci = cn, dn = QString::null;
01394
01395 int videofd = open(device.ascii(), O_RDWR);
01396 if (videofd >= 0)
01397 {
01398 if (!CardUtil::GetV4LInfo(videofd, cn, dn))
01399 ci = cn = tr("Failed to probe");
01400 else if (!dn.isEmpty())
01401 ci = cn + " [" + dn + "]";
01402 close(videofd);
01403 }
01404
01405 cardinfo->setValue(ci);
01406 vbidev->setFilter(cn, dn);
01407 input->fillSelections(device);
01408 }
01409
01410
01411 MPEGConfigurationGroup::MPEGConfigurationGroup(CaptureCard &a_parent) :
01412 VerticalConfigurationGroup(false, true, false, false),
01413 parent(a_parent), cardinfo(new TransLabelSetting()),
01414 input(new TunerCardInput(parent))
01415 {
01416 VideoDevice *device =
01417 new VideoDevice(parent, 0, 15, QString::null, "ivtv");
01418
01419 cardinfo->setLabel(tr("Probed info"));
01420
01421 addChild(device);
01422 addChild(cardinfo);
01423 addChild(input);
01424
01425 connect(device, SIGNAL(valueChanged(const QString&)),
01426 this, SLOT( probeCard( const QString&)));
01427
01428 probeCard(device->getValue());
01429 }
01430
01431 void MPEGConfigurationGroup::probeCard(const QString &device)
01432 {
01433 QString cn = tr("Failed to open"), ci = cn, dn = QString::null;
01434
01435 int videofd = open(device.ascii(), O_RDWR);
01436 if (videofd >= 0)
01437 {
01438 if (!CardUtil::GetV4LInfo(videofd, cn, dn))
01439 ci = cn = tr("Failed to probe");
01440 else if (!dn.isEmpty())
01441 ci = cn + " [" + dn + "]";
01442 close(videofd);
01443 }
01444
01445 cardinfo->setValue(ci);
01446 input->fillSelections(device);
01447 }
01448
01449 CaptureCardGroup::CaptureCardGroup(CaptureCard &parent) :
01450 TriggeredConfigurationGroup(true, true, false, false)
01451 {
01452 setLabel(QObject::tr("Capture Card Setup"));
01453
01454 CardType* cardtype = new CardType(parent);
01455 addChild(cardtype);
01456
01457 setTrigger(cardtype);
01458 setSaveAll(false);
01459
01460 #ifdef USING_V4L
01461 addTarget("V4L", new V4LConfigurationGroup(parent));
01462 # ifdef USING_IVTV
01463 addTarget("MPEG", new MPEGConfigurationGroup(parent));
01464 # endif // USING_IVTV
01465 #endif // USING_V4L
01466
01467 #ifdef USING_DVB
01468 addTarget("DVB", new DVBConfigurationGroup(parent));
01469 #endif // USING_DVB
01470
01471 #ifdef USING_FIREWIRE
01472 addTarget("FIREWIRE", new FirewireConfigurationGroup(parent));
01473 #endif // USING_FIREWIRE
01474
01475 #ifdef USING_DBOX2
01476 addTarget("DBOX2", new DBOX2ConfigurationGroup(parent));
01477 #endif // USING_DBOX2
01478
01479 #ifdef USING_HDHOMERUN
01480 addTarget("HDHOMERUN", new HDHomeRunConfigurationGroup(parent));
01481 #endif // USING_HDHOMERUN
01482
01483 #ifdef USING_IPTV
01484 addTarget("FREEBOX", new IPTVConfigurationGroup(parent));
01485 #endif // USING_IPTV
01486 }
01487
01488 void CaptureCardGroup::triggerChanged(const QString& value)
01489 {
01490 QString own = (value == "MJPEG" || value == "GO7007") ? "V4L" : value;
01491 TriggeredConfigurationGroup::triggerChanged(own);
01492 }
01493
01494 CaptureCard::CaptureCard(bool use_card_group)
01495 : id(new ID), instance_count(0)
01496 {
01497 addChild(id);
01498 if (use_card_group)
01499 addChild(new CaptureCardGroup(*this));
01500 addChild(new Hostname(*this));
01501 }
01502
01503 void CaptureCard::fillSelections(SelectSetting *setting)
01504 {
01505 MSqlQuery query(MSqlQuery::InitCon());
01506 QString qstr =
01507 "SELECT cardid, videodevice, cardtype "
01508 "FROM capturecard "
01509 "WHERE hostname = :HOSTNAME "
01510 "ORDER BY cardid";
01511
01512 query.prepare(qstr);
01513 query.bindValue(":HOSTNAME", gContext->GetHostName());
01514
01515 if (!query.exec())
01516 {
01517 MythContext::DBError("CaptureCard::fillSelections", query);
01518 return;
01519 }
01520
01521 QMap<QString, uint> device_refs;
01522 while (query.next())
01523 {
01524 uint cardid = query.value(0).toUInt();
01525 QString videodevice = query.value(1).toString();
01526 QString cardtype = query.value(2).toString();
01527
01528 if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice]))
01529 continue;
01530
01531 QString label = CardUtil::GetDeviceLabel(
01532 cardid, cardtype, videodevice);
01533
01534 setting->addSelection(label, QString::number(cardid));
01535 }
01536 }
01537
01538 void CaptureCard::loadByID(int cardid)
01539 {
01540 id->setValue(cardid);
01541 load();
01542
01543
01544 uint new_cnt = 0;
01545 if (cardid > 0)
01546 {
01547 QString type = CardUtil::GetRawCardType(cardid);
01548 if (CardUtil::IsTunerSharingCapable(type))
01549 {
01550 QString dev = CardUtil::GetVideoDevice(cardid);
01551 vector<uint> cardids = CardUtil::GetCardIDs(dev, type);
01552 new_cnt = cardids.size();
01553 }
01554 }
01555 instance_count = new_cnt;
01556 }
01557
01558 void CaptureCard::save(void)
01559 {
01560 uint init_cardid = getCardID();
01561
01562 QString init_dev = QString::null;
01563 if (init_cardid)
01564 init_dev = CardUtil::GetVideoDevice(init_cardid);
01565
01567
01568 ConfigurationWizard::save();
01569
01571
01572 uint cardid = getCardID();
01573 QString type = CardUtil::GetRawCardType(cardid);
01574 if (!CardUtil::IsTunerSharingCapable(type))
01575 return;
01576
01577 if (!init_cardid)
01578 {
01579 QString dev = CardUtil::GetVideoDevice(cardid);
01580 vector<uint> cardids = CardUtil::GetCardIDs(dev, type);
01581 if (cardids.size() > 1)
01582 {
01583 VERBOSE(VB_IMPORTANT,
01584 "A card using this video device already exists!");
01585 CardUtil::DeleteCard(cardid);
01586 }
01587 return;
01588 }
01589
01590 vector<uint> cardids = CardUtil::GetCardIDs(init_dev, type);
01591
01592 if (!instance_count)
01593 instance_count = max((size_t)0, cardids.size()) + 1;
01594 uint cloneCount = instance_count - 1;
01595
01596
01597 for (uint i = cardids.size() - 1; (i > cloneCount) && cardids.size(); i--)
01598 {
01599 CardUtil::DeleteCard(cardids.back());
01600 cardids.pop_back();
01601 }
01602
01603
01604 if (cloneCount && !CardUtil::CreateInputGroupIfNeeded(cardid))
01605 return;
01606
01607
01608 for (uint i = 0; i < cardids.size(); i++)
01609 {
01610 if (cardids[i] != init_cardid)
01611 CardUtil::CloneCard(init_cardid, cardids[i]);
01612 }
01613
01614
01615 for (uint i = cardids.size(); i < cloneCount + 1; i++)
01616 {
01617 CardUtil::CloneCard(init_cardid, 0);
01618 }
01619 }
01620
01621 CardType::CardType(const CaptureCard &parent) :
01622 ComboBoxSetting(this),
01623 CaptureCardDBStorage(this, parent, "cardtype")
01624 {
01625 setLabel(QObject::tr("Card type"));
01626 setHelpText(QObject::tr("Change the cardtype to the appropriate type for "
01627 "the capture card you are configuring."));
01628 fillSelections(this);
01629 }
01630
01631 void CardType::fillSelections(SelectSetting* setting)
01632 {
01633 #ifdef USING_V4L
01634 setting->addSelection(
01635 QObject::tr("Analog V4L capture card"), "V4L");
01636 setting->addSelection(
01637 QObject::tr("MJPEG capture card (Matrox G200, DC10)"), "MJPEG");
01638 # ifdef USING_IVTV
01639 setting->addSelection(
01640 QObject::tr("IVTV MPEG-2 encoder card"), "MPEG");
01641 # endif // USING_IVTV
01642 #endif // USING_V4L
01643
01644 #ifdef USING_DVB
01645 setting->addSelection(
01646 QObject::tr("DVB DTV capture card (v3.x)"), "DVB");
01647 #endif // USING_DVB
01648
01649 #ifdef USING_FIREWIRE
01650 setting->addSelection(
01651 QObject::tr("FireWire cable box"), "FIREWIRE");
01652 #endif // USING_FIREWIRE
01653
01654 #ifdef USING_V4L
01655 setting->addSelection(
01656 QObject::tr("USB MPEG-4 encoder box (Plextor ConvertX, etc)"),
01657 "GO7007");
01658 #endif // USING_V4L
01659
01660 #ifdef USING_DBOX2
01661 setting->addSelection(
01662 QObject::tr("DBox2 TCP/IP cable box"), "DBOX2");
01663 #endif // USING_DBOX2
01664
01665 #ifdef USING_HDHOMERUN
01666 setting->addSelection(
01667 QObject::tr("HDHomeRun DTV tuner box"), "HDHOMERUN");
01668 #endif // USING_HDHOMERUN
01669
01670 #ifdef USING_IPTV
01671 setting->addSelection(QObject::tr("Network Recorder"), "FREEBOX");
01672 #endif // USING_IPTV
01673 }
01674
01675 class CardID : public SelectLabelSetting, public CardInputDBStorage
01676 {
01677 public:
01678 CardID(const CardInput &parent) :
01679 SelectLabelSetting(this), CardInputDBStorage(this, parent, "cardid")
01680 {
01681 setLabel(QObject::tr("Capture device"));
01682 };
01683
01684 virtual void load() {
01685 fillSelections();
01686 CardInputDBStorage::load();
01687 };
01688
01689 void fillSelections() {
01690 CaptureCard::fillSelections(this);
01691 };
01692 };
01693
01694 class InputDisplayName : public LineEditSetting, public CardInputDBStorage
01695 {
01696 public:
01697 InputDisplayName(const CardInput &parent) :
01698 LineEditSetting(this),
01699 CardInputDBStorage(this, parent, "displayname")
01700 {
01701 setLabel(QObject::tr("Display Name (optional)"));
01702 setHelpText(QObject::tr(
01703 "This name is displayed on screen when live TV begins "
01704 "and when changing the selected input or card. If you "
01705 "use this, make sure the information is unique for "
01706 "each input."));
01707 };
01708 };
01709
01710 class SourceID : public ComboBoxSetting, public CardInputDBStorage
01711 {
01712 public:
01713 SourceID(const CardInput &parent) :
01714 ComboBoxSetting(this), CardInputDBStorage(this, parent, "sourceid")
01715 {
01716 setLabel(QObject::tr("Video source"));
01717 addSelection(QObject::tr("(None)"), "0");
01718 };
01719
01720 virtual void load() {
01721 fillSelections();
01722 CardInputDBStorage::load();
01723 };
01724
01725 void fillSelections() {
01726 clearSelections();
01727 addSelection(QObject::tr("(None)"), "0");
01728 VideoSource::fillSelections(this);
01729 };
01730 };
01731
01732 class InputName : public LabelSetting, public CardInputDBStorage
01733 {
01734 public:
01735 InputName(const CardInput &parent) :
01736 LabelSetting(this), CardInputDBStorage(this, parent, "inputname")
01737 {
01738 setLabel(QObject::tr("Input"));
01739 };
01740 };
01741
01742 class InputGroup : public TransComboBoxSetting
01743 {
01744 public:
01745 InputGroup(const CardInput &parent, uint group_num) :
01746 TransComboBoxSetting(false), cardinput(parent),
01747 groupnum(group_num), groupid(0)
01748 {
01749 setLabel(QObject::tr("Input Group") +
01750 QString(" %1").arg(groupnum + 1));
01751 setHelpText(QObject::tr(
01752 "Leave as 'Generic' unless this input is shared with "
01753 "another device. Only one of the inputs in an input "
01754 "group will be allowed to record at any given time."));
01755 }
01756
01757 virtual void load(void);
01758
01759 virtual void save(void)
01760 {
01761 uint inputid = cardinput.getInputID();
01762 uint new_groupid = getValue().toUInt();
01763
01764 if (groupid)
01765 CardUtil::UnlinkInputGroup(inputid, groupid);
01766
01767 if (new_groupid)
01768 {
01769 if (CardUtil::UnlinkInputGroup(inputid, new_groupid))
01770 CardUtil::LinkInputGroup(inputid, new_groupid);
01771 }
01772 }
01773
01774 private:
01775 const CardInput &cardinput;
01776 uint groupnum;
01777 uint groupid;
01778 };
01779
01780 void InputGroup::load(void)
01781 {
01782 #if 0
01783 VERBOSE(VB_IMPORTANT,
01784 QString("InputGroup::load() %1 %2")
01785 .arg(groupnum).arg(cardinput.getInputID()));
01786 #endif
01787
01788 uint inputid = cardinput.getInputID();
01789 QMap<uint, uint> grpcnt;
01790 vector<QString> names;
01791 vector<uint> grpid;
01792 vector<uint> selected_groupids;
01793
01794 names.push_back(QObject::tr("Generic"));
01795 grpid.push_back(0);
01796 grpcnt[0]++;
01797
01798 MSqlQuery query(MSqlQuery::InitCon());
01799 query.prepare(
01800 "SELECT cardinputid, inputgroupid, inputgroupname "
01801 "FROM inputgroup "
01802 "ORDER BY inputgroupid, cardinputid, inputgroupname");
01803
01804 if (!query.exec())
01805 {
01806 MythContext::DBError("InputGroup::load()", query);
01807 }
01808 else
01809 {
01810 while (query.next())
01811 {
01812 uint groupid = query.value(1).toUInt();
01813 if (inputid && (query.value(0).toUInt() == inputid))
01814 selected_groupids.push_back(groupid);
01815
01816 grpcnt[groupid]++;
01817
01818 if (grpcnt[groupid] == 1)
01819 {
01820 names.push_back(
01821 QString::fromUtf8(query.value(2).toString()));
01822 grpid.push_back(groupid);
01823 }
01824 }
01825 }
01826
01827
01828 groupid = 0;
01829 if (groupnum < selected_groupids.size())
01830 groupid = selected_groupids[groupnum];
01831
01832 #if 0
01833 VERBOSE(VB_IMPORTANT, QString("Group num: %1 id: %2")
01834 .arg(groupnum).arg(groupid));
01835 for (uint i = 0; i < selected_groupids.size(); i++)
01836 cout<<selected_groupids[i]<<" ";
01837 cout<<endl;
01838 #endif
01839
01840
01841 clearSelections();
01842 uint index = 0;
01843 for (uint i = 0; i < names.size(); i++)
01844 {
01845 bool sel = (groupid == grpid[i]);
01846 index = (sel) ? i : index;
01847
01848 #if 0
01849 VERBOSE(VB_IMPORTANT, QString("grpid %1, name '%2', i %3, s %4")
01850 .arg(grpid[i]).arg(names[i])
01851 .arg(index).arg(sel ? "T" : "F"));
01852 #endif
01853
01854 addSelection(names[i], QString::number(grpid[i]), sel);
01855 }
01856
01857
01858
01859 if (names.size())
01860 setValue(index);
01861 }
01862
01863 class FreeToAir : public CheckBoxSetting, public CardInputDBStorage
01864 {
01865 public:
01866 FreeToAir(const CardInput &parent) :
01867 CheckBoxSetting(this),
01868 CardInputDBStorage(this, parent, "freetoaironly")
01869 {
01870 setValue(true);
01871 setLabel(QObject::tr("Unencrypted channels only"));
01872 setHelpText(QObject::tr(
01873 "If set, only unencrypted channels will be tuned to "
01874 "by MythTV or not be ignored by the MythTV channel "
01875 "scanner."));
01876 };
01877 };
01878
01879 class RadioServices : public CheckBoxSetting, public CardInputDBStorage
01880 {
01881 public:
01882 RadioServices(const CardInput &parent) :
01883 CheckBoxSetting(this),
01884 CardInputDBStorage(this, parent, "radioservices")
01885 {
01886 setValue(true);
01887 setLabel(QObject::tr("Allow audio only channels"));
01888 setHelpText(QObject::tr(
01889 "If set, audio only channels will not be ignored "
01890 "by the MythTV channel scanner."));
01891 };
01892 };
01893
01894 class QuickTune : public ComboBoxSetting, public CardInputDBStorage
01895 {
01896 public:
01897 QuickTune(const CardInput &parent) :
01898 ComboBoxSetting(this), CardInputDBStorage(this, parent, "quicktune")
01899 {
01900 setLabel(QObject::tr("Use quick tuning"));
01901 addSelection(QObject::tr("Never"), "0", true);
01902 addSelection(QObject::tr("Live TV only"), "1", true);
01903 addSelection(QObject::tr("Always"), "2", false);
01904 setHelpText(QObject::tr(
01905 "If enabled MythTV will tune using only the "
01906 "MPEG program number. The program numbers "
01907 "change more often than DVB or ATSC tuning "
01908 "parameters, so this is slightly less reliable. "
01909 "This will also inhibit EIT gathering during "
01910 "Live TV and recording."));
01911 };
01912 };
01913
01914 class ExternalChannelCommand :
01915 public LineEditSetting, public CardInputDBStorage
01916 {
01917 public:
01918 ExternalChannelCommand(const CardInput &parent) :
01919 LineEditSetting(this),
01920 CardInputDBStorage(this, parent, "externalcommand")
01921 {
01922 setLabel(QObject::tr("External channel change command"));
01923 setValue("");
01924 setHelpText(QObject::tr("If specified, this command will be run to "
01925 "change the channel for inputs which have an external "
01926 "tuner device such as a cable box. The first argument "
01927 "will be the channel number."));
01928 };
01929 };
01930
01931 class PresetTuner : public LineEditSetting, public CardInputDBStorage
01932 {
01933 public:
01934 PresetTuner(const CardInput &parent) :
01935 LineEditSetting(this),
01936 CardInputDBStorage(this, parent, "tunechan")
01937 {
01938 setLabel(QObject::tr("Preset tuner to channel"));
01939 setValue("");
01940 setHelpText(QObject::tr("Leave this blank unless you have an external "
01941 "tuner that is connected to the tuner input of your card. "
01942 "If so, you will need to specify the preset channel for "
01943 "the signal (normally 3 or 4)."));
01944 };
01945 };
01946
01947 void StartingChannel::SetSourceID(const QString &sourceid)
01948 {
01949
01950 clearSelections();
01951 if (sourceid.isEmpty() || !sourceid.toUInt())
01952 return;
01953
01954
01955 QString startChan = QString::null;
01956 MSqlQuery query(MSqlQuery::InitCon());
01957 query.prepare(
01958 "SELECT startchan "
01959 "FROM cardinput "
01960 "WHERE cardinputid = :INPUTID");
01961 query.bindValue(":INPUTID", getInputID());
01962
01963 if (!query.exec() || !query.isActive())
01964 MythContext::DBError("SetSourceID -- get start chan", query);
01965 else if (query.next())
01966 startChan = query.value(0).toString();
01967
01968 DBChanList channels = ChannelUtil::GetChannels(sourceid.toUInt(), false);
01969
01970 if (channels.empty())
01971 {
01972 addSelection(tr("Please add channels to this source"),
01973 startChan.isEmpty() ? "" : startChan);
01974 return;
01975 }
01976
01977
01978
01979 QString order = gContext->GetSetting("ChannelOrdering", "channum");
01980 ChannelUtil::SortChannels(channels, order);
01981 for (uint i = 0; i < channels.size(); i++)
01982 {
01983 const QString channum = channels[i].channum;
01984 addSelection(channum, channum, channum == startChan);
01985 }
01986 }
01987
01988 class InputPriority : public SpinBoxSetting, public CardInputDBStorage
01989 {
01990 public:
01991 InputPriority(const CardInput &parent) :
01992 SpinBoxSetting(this, -99, 99, 1),
01993 CardInputDBStorage(this, parent, "recpriority")
01994 {
01995 setLabel(QObject::tr("Input priority"));
01996 setValue(0);
01997 setHelpText(QObject::tr("If the input priority is not equal for "
01998 "all inputs, the scheduler may choose to record a show "
01999 "at a later time so that it can record on an input with "
02000 "a higher value."));
02001 };
02002 };
02003
02004 class DishNetEIT : public CheckBoxSetting, public CardInputDBStorage
02005 {
02006 public:
02007 DishNetEIT(const CardInput &parent) :
02008 CheckBoxSetting(this),
02009 CardInputDBStorage(this, parent, "dishnet_eit")
02010 {
02011 setLabel(QObject::tr("Use DishNet Long-term EIT Data"));
02012 setValue(false);
02013 setHelpText(
02014 QObject::tr(
02015 "If you point your satellite dish toward DishNet's birds, "
02016 "you may wish to enable this feature. For best results, "
02017 "enable general EIT collection as well."));
02018 };
02019 };
02020
02021 CardInput::CardInput(bool isDTVcard, bool isDVBcard,
02022 bool isNewInput, int _cardid) :
02023 id(new ID()),
02024 cardid(new CardID(*this)),
02025 inputname(new InputName(*this)),
02026 sourceid(new SourceID(*this)),
02027 startchan(new StartingChannel(*this)),
02028 scan(new TransButtonSetting()),
02029 srcfetch(new TransButtonSetting()),
02030 externalInputSettings(new DiSEqCDevSettings()),
02031 inputgrp0(new InputGroup(*this, 0)),
02032 inputgrp1(new InputGroup(*this, 1))
02033 {
02034 addChild(id);
02035
02036 if (CardUtil::IsInNeedOfExternalInputConf(_cardid))
02037 {
02038 addChild(new DTVDeviceConfigGroup(*externalInputSettings,
02039 _cardid, isNewInput));
02040 }
02041
02042 ConfigurationGroup *basic =
02043 new VerticalConfigurationGroup(false, false, true, true);
02044
02045 basic->setLabel(QObject::tr("Connect source to input"));
02046
02047 basic->addChild(cardid);
02048 basic->addChild(inputname);
02049 basic->addChild(new InputDisplayName(*this));
02050 basic->addChild(sourceid);
02051
02052 if (!isDTVcard)
02053 {
02054 basic->addChild(new ExternalChannelCommand(*this));
02055 basic->addChild(new PresetTuner(*this));
02056 }
02057
02058 if (isDTVcard)
02059 {
02060
02061 ConfigurationGroup *chgroup =
02062 new VerticalConfigurationGroup(false, false, true, true);
02063 chgroup->addChild(new QuickTune(*this));
02064 chgroup->addChild(new FreeToAir(*this));
02065 basic->addChild(chgroup);
02066 }
02067
02068 if (isDVBcard)
02069 {
02070 ConfigurationGroup *chgroup =
02071 new HorizontalConfigurationGroup(false, false, true, true);
02072 chgroup->addChild(new RadioServices(*this));
02073 chgroup->addChild(new DishNetEIT(*this));
02074 basic->addChild(chgroup);
02075 }
02076
02077 scan->setLabel(tr("Scan for channels"));
02078 scan->setHelpText(
02079 tr("Use channel scanner to find channels for this input."));
02080
02081 srcfetch->setLabel(tr("Fetch channels from listings source"));
02082 srcfetch->setHelpText(
02083 tr("This uses the listings data source to "
02084 "provide the channels for this input.") + " " +
02085 tr("This can take a long time to run."));
02086
02087 ConfigurationGroup *sgrp =
02088 new HorizontalConfigurationGroup(false, false, true, true);
02089 sgrp->addChild(scan);
02090 sgrp->addChild(srcfetch);
02091 basic->addChild(sgrp);
02092
02093 basic->addChild(startchan);
02094
02095 addChild(basic);
02096
02097 ConfigurationGroup *interact =
02098 new VerticalConfigurationGroup(false, false, true, true);
02099
02100 interact->setLabel(QObject::tr("Interactions between inputs"));
02101 interact->addChild(new InputPriority(*this));
02102
02103 TransButtonSetting *ingrpbtn = new TransButtonSetting("newgroup");
02104 ingrpbtn->setLabel(QObject::tr("Create a New Input Group"));
02105 ingrpbtn->setHelpText(
02106 QObject::tr("Input groups are only needed when two or more cards "
02107 "share the same resource such as a firewire card and "
02108 "an analog card input controlling the same set top box."));
02109 interact->addChild(ingrpbtn);
02110 interact->addChild(inputgrp0);
02111 interact->addChild(inputgrp1);
02112
02113 addChild(interact);
02114
02115 setName("CardInput");
02116 SetSourceID("-1");
02117
02118 connect(scan, SIGNAL(pressed()), SLOT(channelScanner()));
02119 connect(srcfetch, SIGNAL(pressed()), SLOT(sourceFetch()));
02120 connect(sourceid, SIGNAL(valueChanged(const QString&)),
02121 startchan,SLOT( SetSourceID (const QString&)));
02122 connect(sourceid, SIGNAL(valueChanged(const QString&)),
02123 this, SLOT( SetSourceID (const QString&)));
02124 connect(ingrpbtn, SIGNAL(pressed(QString)),
02125 this, SLOT( CreateNewInputGroup()));
02126 }
02127
02128 CardInput::~CardInput()
02129 {
02130 if (externalInputSettings)
02131 {
02132 delete externalInputSettings;
02133 externalInputSettings = NULL;
02134 }
02135 }
02136
02137 void CardInput::SetSourceID(const QString &sourceid)
02138 {
02139 bool enable = (sourceid.toInt() > 0);
02140 scan->setEnabled(enable);
02141 srcfetch->setEnabled(enable);
02142 }
02143
02144 QString CardInput::getSourceName(void) const
02145 {
02146 return sourceid->getSelectionLabel();
02147 }
02148
02149 void CardInput::CreateNewInputGroup(void)
02150 {
02151 QString new_name = QString::null;
02152 QString tmp_name = QString::null;
02153
02154 inputgrp0->save();
02155 inputgrp1->save();
02156
02157 while (true)
02158 {
02159 tmp_name = "";
02160 bool ok = MythPopupBox::showGetTextPopup(
02161 gContext->GetMainWindow(), tr("Create Input Group"),
02162 tr("Enter new group name"), tmp_name);
02163
02164 new_name = QDeepCopy<QString>(tmp_name);
02165
02166 if (!ok)
02167 return;
02168
02169 if (new_name.isEmpty())
02170 {
02171 MythPopupBox::showOkPopup(
02172 gContext->GetMainWindow(), tr("Error"),
02173 tr("Sorry, this Input Group name can not be blank."));
02174 continue;
02175 }
02176
02177 MSqlQuery query(MSqlQuery::InitCon());
02178 query.prepare(
02179 "SELECT inputgroupname "
02180 "FROM inputgroup "
02181 "WHERE inputgroupname = :GROUPNAME");
02182 query.bindValue(":GROUPNAME", new_name.utf8());
02183
02184 if (!query.exec())
02185 {
02186 MythContext::DBError("CreateNewInputGroup 1", query);
02187 return;
02188 }
02189
02190 if (query.next())
02191 {
02192 MythPopupBox::showOkPopup(
02193 gContext->GetMainWindow(), tr("Error"),
02194 tr("Sorry, this Input Group name is already in use."));
02195 continue;
02196 }
02197
02198 break;
02199 }
02200
02201 uint inputgroupid = CardUtil::CreateInputGroup(new_name);
02202
02203 inputgrp0->load();
02204 inputgrp1->load();
02205
02206 if (!inputgrp0->getValue().toUInt())
02207 {
02208 inputgrp0->setValue(
02209 inputgrp0->getValueIndex(QString::number(inputgroupid)));
02210 }
02211 else
02212 {
02213 inputgrp1->setValue(
02214 inputgrp1->getValueIndex(QString::number(inputgroupid)));
02215 }
02216 }
02217
02218 void CardInput::channelScanner(void)
02219 {
02220 uint srcid = sourceid->getValue().toUInt();
02221 uint crdid = cardid->getValue().toUInt();
02222 QString in = inputname->getValue();
02223
02224 #ifdef USING_BACKEND
02225 uint num_channels_before = SourceUtil::GetChannelCount(srcid);
02226
02227 save();
02228
02229 QString cardtype = CardUtil::GetRawCardType(crdid);
02230 if (CardUtil::IsUnscanable(cardtype))
02231 {
02232 VERBOSE(VB_IMPORTANT, QString("Sorry, %1 cards do not "
02233 "yet support scanning.").arg(cardtype));
02234 return;
02235 }
02236
02237 ScanWizard *scanwizard = new ScanWizard(srcid, crdid, in);
02238 scanwizard->exec(false, true);
02239 scanwizard->deleteLater();
02240
02241 if (SourceUtil::GetChannelCount(srcid))
02242 startchan->SetSourceID(QString::number(srcid));
02243 if (num_channels_before)
02244 {
02245 startchan->load();
02246 startchan->save();
02247 }
02248 #else
02249 VERBOSE(VB_IMPORTANT, "You must compile the backend "
02250 "to be able to scan for channels");
02251 #endif
02252
02253 }
02254
02255 void CardInput::sourceFetch(void)
02256 {
02257 uint srcid = sourceid->getValue().toUInt();
02258 uint crdid = cardid->getValue().toUInt();
02259
02260 uint num_channels_before = SourceUtil::GetChannelCount(srcid);
02261
02262 if (crdid && srcid)
02263 {
02264 save();
02265
02266 QString cardtype = CardUtil::GetRawCardType(crdid);
02267
02268 if (!CardUtil::IsUnscanable(cardtype) &&
02269 !CardUtil::IsEncoder(cardtype) &&
02270 !num_channels_before)
02271 {
02272 VERBOSE(VB_IMPORTANT, "Skipping channel fetch, you need to "
02273 "scan for channels first.");
02274 return;
02275 }
02276
02277 SourceUtil::UpdateChannelsFromListings(srcid, cardtype);
02278 }
02279
02280 if (SourceUtil::GetChannelCount(srcid))
02281 startchan->SetSourceID(QString::number(srcid));
02282 if (num_channels_before)
02283 {
02284 startchan->load();
02285 startchan->save();
02286 }
02287 }
02288
02289 QString CardInputDBStorage::whereClause(MSqlBindings& bindings)
02290 {
02291 QString cardinputidTag(":WHERECARDINPUTID");
02292
02293 QString query("cardinputid = " + cardinputidTag);
02294
02295 bindings.insert(cardinputidTag, parent.getInputID());
02296
02297 return query;
02298 }
02299
02300 QString CardInputDBStorage::setClause(MSqlBindings& bindings)
02301 {
02302 QString cardinputidTag(":SETCARDINPUTID");
02303 QString colTag(":SET" + getColumn().upper());
02304
02305 QString query("cardinputid = " + cardinputidTag + ", " +
02306 getColumn() + " = " + colTag);
02307
02308 bindings.insert(cardinputidTag, parent.getInputID());
02309 bindings.insert(colTag, setting->getValue());
02310
02311 return query;
02312 }
02313
02314 void CardInput::loadByID(int inputid)
02315 {
02316 id->setValue(inputid);
02317 externalInputSettings->Load(inputid);
02318 ConfigurationWizard::load();
02319 }
02320
02321 void CardInput::loadByInput(int _cardid, QString _inputname)
02322 {
02323 MSqlQuery query(MSqlQuery::InitCon());
02324 query.prepare("SELECT cardinputid FROM cardinput "
02325 "WHERE cardid = :CARDID AND inputname = :INPUTNAME");
02326 query.bindValue(":CARDID", _cardid);
02327 query.bindValue(":INPUTNAME", _inputname);
02328
02329 if (query.exec() && query.isActive() && query.next())
02330 {
02331 loadByID(query.value(0).toInt());
02332 }
02333 else
02334 {
02335 load();
02336 cardid->setValue(QString::number(_cardid));
02337 inputname->setValue(_inputname);
02338 }
02339 }
02340
02341 void CardInput::save(void)
02342 {
02343
02344 if (sourceid->getValue() == "0")
02345 {
02346
02347 MSqlQuery query(MSqlQuery::InitCon());
02348 query.prepare("DELETE FROM cardinput WHERE cardinputid = :INPUTID");
02349 query.bindValue(":INPUTID", getInputID());
02350 query.exec();
02351 }
02352 else
02353 {
02354 ConfigurationWizard::save();
02355 externalInputSettings->Store(getInputID());
02356 }
02357
02358
02359 uint src_cardid = cardid->getValue().toUInt();
02360 QString type = CardUtil::GetRawCardType(src_cardid);
02361 if (CardUtil::IsTunerSharingCapable(type))
02362 {
02363 vector<uint> clones = CardUtil::GetCloneCardIDs(src_cardid);
02364 if (clones.size() && CardUtil::CreateInputGroupIfNeeded(src_cardid))
02365 {
02366 for (uint i = 0; i < clones.size(); i++)
02367 CardUtil::CloneCard(src_cardid, clones[i]);
02368 }
02369 }
02370
02371
02372 CardUtil::DeleteOrphanInputs();
02373
02374 CardUtil::UnlinkInputGroup(0,0);
02375 }
02376
02377 int CardInputDBStorage::getInputID(void) const
02378 {
02379 return parent.getInputID();
02380 }
02381
02382 int CaptureCardDBStorage::getCardID(void) const
02383 {
02384 return parent.getCardID();
02385 }
02386
02387 CaptureCardEditor::CaptureCardEditor() : listbox(new ListBoxSetting(this))
02388 {
02389 listbox->setLabel(tr("Capture cards"));
02390 addChild(listbox);
02391 }
02392
02393 DialogCode CaptureCardEditor::exec(void)
02394 {
02395 while (ConfigurationDialog::exec() == kDialogCodeAccepted)
02396 edit();
02397
02398 return kDialogCodeRejected;
02399 }
02400
02401 void CaptureCardEditor::load(void)
02402 {
02403 listbox->clearSelections();
02404 listbox->addSelection(QObject::tr("(New capture card)"), "0");
02405 listbox->addSelection(QObject::tr("(Delete all capture cards on %1)")
02406 .arg(gContext->GetHostName()), "-1");
02407 listbox->addSelection(QObject::tr("(Delete all capture cards)"), "-2");
02408 CaptureCard::fillSelections(listbox);
02409 }
02410
02411 MythDialog* CaptureCardEditor::dialogWidget(MythMainWindow* parent,
02412 const char* widgetName)
02413 {
02414 dialog = ConfigurationDialog::dialogWidget(parent, widgetName);
02415 connect(dialog, SIGNAL(menuButtonPressed()), this, SLOT(menu()));
02416 connect(dialog, SIGNAL(editButtonPressed()), this, SLOT(edit()));
02417 connect(dialog, SIGNAL(deleteButtonPressed()), this, SLOT(del()));
02418 return dialog;
02419 }
02420
02421 void CaptureCardEditor::menu(void)
02422 {
02423 if (!listbox->getValue().toInt())
02424 {
02425 CaptureCard cc;
02426 cc.exec();
02427 }
02428 else
02429 {
02430 DialogCode val = MythPopupBox::Show2ButtonPopup(
02431 gContext->GetMainWindow(),
02432 "",
02433 tr("Capture Card Menu"),
02434 tr("Edit.."),
02435 tr("Delete.."),
02436 kDialogCodeButton0);
02437
02438 if (kDialogCodeButton0 == val)
02439 edit();
02440 else if (kDialogCodeButton1 == val)
02441 del();
02442 }
02443 }
02444
02445 void CaptureCardEditor::edit(void)
02446 {
02447 const int cardid = listbox->getValue().toInt();
02448 if (-1 == cardid)
02449 {
02450 DialogCode val = MythPopupBox::Show2ButtonPopup(
02451 gContext->GetMainWindow(), "",
02452 tr("Are you sure you want to delete "
02453 "ALL capture cards on %1?").arg(gContext->GetHostName()),
02454 tr("Yes, delete capture cards"),
02455 tr("No, don't"), kDialogCodeButton1);
02456
02457 if (kDialogCodeButton0 == val)
02458 {
02459 MSqlQuery cards(MSqlQuery::InitCon());
02460
02461 cards.prepare(
02462 "SELECT cardid "
02463 "FROM capturecard "
02464 "WHERE hostname = :HOSTNAME");
02465 cards.bindValue(":HOSTNAME", gContext->GetHostName());
02466
02467 if (!cards.exec() || !cards.isActive())
02468 {
02469 MythPopupBox::showOkPopup(
02470 gContext->GetMainWindow(),
02471 tr("Error getting list of cards for this host"),
02472 tr("Unable to delete capturecards for %1")
02473 .arg(gContext->GetHostName()));
02474
02475 MythContext::DBError("Selecting cardids for deletion", cards);
02476 return;
02477 }
02478
02479 while (cards.next())
02480 CardUtil::DeleteCard(cards.value(0).toUInt());
02481 }
02482 }
02483 else if (-2 == cardid)
02484 {
02485 DialogCode val = MythPopupBox::Show2ButtonPopup(
02486 gContext->GetMainWindow(), "",
02487 tr("Are you sure you want to delete "
02488 "ALL capture cards?"),
02489 tr("Yes, delete capture cards"),
02490 tr("No, don't"), kDialogCodeButton1);
02491
02492 if (kDialogCodeButton0 == val)
02493 {
02494 CardUtil::DeleteAllCards();
02495 load();
02496 }
02497 }
02498 else
02499 {
02500 CaptureCard cc;
02501 if (cardid)
02502 cc.loadByID(cardid);
02503 cc.exec();
02504 }
02505 }
02506
02507 void CaptureCardEditor::del(void)
02508 {
02509 DialogCode val = MythPopupBox::Show2ButtonPopup(
02510 gContext->GetMainWindow(), "",
02511 tr("Are you sure you want to delete this capture card?"),
02512 tr("Yes, delete capture card"),
02513 tr("No, don't"), kDialogCodeButton1);
02514
02515 if (kDialogCodeButton0 == val)
02516 {
02517 CardUtil::DeleteCard(listbox->getValue().toUInt());
02518 load();
02519 }
02520 }
02521
02522 VideoSourceEditor::VideoSourceEditor() : listbox(new ListBoxSetting(this))
02523 {
02524 listbox->setLabel(tr("Video sources"));
02525 addChild(listbox);
02526 }
02527
02528 MythDialog* VideoSourceEditor::dialogWidget(MythMainWindow* parent,
02529 const char* widgetName)
02530 {
02531 dialog = ConfigurationDialog::dialogWidget(parent, widgetName);
02532 connect(dialog, SIGNAL(menuButtonPressed()), this, SLOT(menu()));
02533 connect(dialog, SIGNAL(editButtonPressed()), this, SLOT(edit()));
02534 connect(dialog, SIGNAL(deleteButtonPressed()), this, SLOT(del()));
02535 return dialog;
02536 }
02537
02538 DialogCode VideoSourceEditor::exec(void)
02539 {
02540 while (ConfigurationDialog::exec() == kDialogCodeAccepted)
02541 edit();
02542
02543 return kDialogCodeRejected;
02544 }
02545
02546 void VideoSourceEditor::load(void)
02547 {
02548 listbox->clearSelections();
02549 listbox->addSelection(QObject::tr("(New video source)"), "0");
02550 listbox->addSelection(QObject::tr("(Delete all video sources)"), "-1");
02551 VideoSource::fillSelections(listbox);
02552 }
02553
02554 void VideoSourceEditor::menu(void)
02555 {
02556 if (!listbox->getValue().toInt())
02557 {
02558 VideoSource vs;
02559 vs.exec();
02560 }
02561 else
02562 {
02563 DialogCode val = MythPopupBox::Show2ButtonPopup(
02564 gContext->GetMainWindow(),
02565 "",
02566 tr("Video Source Menu"),
02567 tr("Edit.."),
02568 tr("Delete.."),
02569 kDialogCodeButton0);
02570
02571 if (kDialogCodeButton0 == val)
02572 edit();
02573 else if (kDialogCodeButton1 == val)
02574 del();
02575 }
02576 }
02577
02578 void VideoSourceEditor::edit(void)
02579 {
02580 const int sourceid = listbox->getValue().toInt();
02581 if (-1 == sourceid)
02582 {
02583 DialogCode val = MythPopupBox::Show2ButtonPopup(
02584 gContext->GetMainWindow(), "",
02585 tr("Are you sure you want to delete "
02586 "ALL video sources?"),
02587 tr("Yes, delete video sources"),
02588 tr("No, don't"), kDialogCodeButton1);
02589
02590 if (kDialogCodeButton0 == val)
02591 {
02592 SourceUtil::DeleteAllSources();
02593 load();
02594 }
02595 }
02596 else
02597 {
02598 VideoSource vs;
02599 if (sourceid)
02600 vs.loadByID(sourceid);
02601 vs.exec();
02602 }
02603 }
02604
02605 void VideoSourceEditor::del()
02606 {
02607 DialogCode val = MythPopupBox::Show2ButtonPopup(
02608 gContext->GetMainWindow(), "",
02609 tr("Are you sure you want to delete "
02610 "this video source?"),
02611 tr("Yes, delete video source"),
02612 tr("No, don't"),
02613 kDialogCodeButton1);
02614
02615 if (kDialogCodeButton0 == val)
02616 {
02617 SourceUtil::DeleteSource(listbox->getValue().toUInt());
02618 load();
02619 }
02620 }
02621
02622 CardInputEditor::CardInputEditor() : listbox(new ListBoxSetting(this))
02623 {
02624 listbox->setLabel(tr("Input connections"));
02625 addChild(listbox);
02626 }
02627
02628 DialogCode CardInputEditor::exec(void)
02629 {
02630 while (ConfigurationDialog::exec() == kDialogCodeAccepted)
02631 cardinputs[listbox->getValue().toInt()]->exec();
02632
02633 return kDialogCodeRejected;
02634 }
02635
02636 void CardInputEditor::load()
02637 {
02638 cardinputs.clear();
02639 listbox->clearSelections();
02640
02641
02642
02643
02644
02645 MSqlQuery query(MSqlQuery::InitCon());
02646 query.prepare(
02647 "SELECT cardid, videodevice, cardtype "
02648 "FROM capturecard "
02649 "WHERE hostname = :HOSTNAME "
02650 "ORDER BY cardid");
02651 query.bindValue(":HOSTNAME", gContext->GetHostName());
02652
02653 if (!query.exec())
02654 {
02655 MythContext::DBError("CardInputEditor::load", query);
02656 return;
02657 }
02658
02659 uint j = 0;
02660 QMap<QString, uint> device_refs;
02661 while (query.next())
02662 {
02663 uint cardid = query.value(0).toUInt();
02664 QString videodevice = query.value(1).toString();
02665 QString cardtype = query.value(2).toString();
02666
02667 if ((cardtype.lower() == "dvb") && (1 != ++device_refs[videodevice]))
02668 continue;
02669
02670 QStringList inputLabels;
02671 vector<CardInput*> cardInputs;
02672
02673 CardUtil::GetCardInputs(cardid, videodevice, cardtype,
02674 inputLabels, cardInputs);
02675
02676 for (uint i = 0; i < inputLabels.size(); i++, j++)
02677 {
02678 cardinputs.push_back(cardInputs[i]);
02679 listbox->addSelection(inputLabels[i], QString::number(j));
02680 }
02681 }
02682 }
02683
02684 #ifdef USING_DVB
02685 static QString remove_chaff(const QString &name)
02686 {
02687
02688 QString short_name = name;
02689 if (short_name.left(14) == "LG Electronics")
02690 short_name = short_name.right(short_name.length() - 15);
02691 if (short_name.left(4) == "Oren")
02692 short_name = short_name.right(short_name.length() - 5);
02693 if (short_name.left(8) == "Nextwave")
02694 short_name = short_name.right(short_name.length() - 9);
02695 if (short_name.right(8).lower() == "frontend")
02696 short_name = short_name.left(short_name.length() - 9);
02697 if (short_name.right(7) == "VSB/QAM")
02698 short_name = short_name.left(short_name.length() - 8);
02699 if (short_name.right(3) == "VSB")
02700 short_name = short_name.left(short_name.length() - 4);
02701 if (short_name.right(5) == "DVB-T")
02702 short_name = short_name.left(short_name.length() - 6);
02703
02704
02705
02706
02707
02708 short_name = short_name.simplifyWhiteSpace();
02709 if (short_name.left(7).lower() == "or51211")
02710 short_name = "pcHDTV HD-2000";
02711 else if (short_name.left(7).lower() == "or51132")
02712 short_name = "pcHDTV HD-3000";
02713 else if (short_name.left(7).lower() == "bcm3510")
02714 short_name = "Air2PC v1";
02715 else if (short_name.left(7).lower() == "nxt2002")
02716 short_name = "Air2PC v2";
02717 else if (short_name.left(7).lower() == "nxt200x")
02718 short_name = "Air2PC v2";
02719 else if (short_name.left(8).lower() == "lgdt3302")
02720 short_name = "DViCO HDTV3";
02721 else if (short_name.left(8).lower() == "lgdt3303")
02722 short_name = "DViCO v2 or Air2PC v3 or pcHDTV HD-5500";
02723
02724 return short_name;
02725 }
02726 #endif // USING_DVB
02727
02728 void DVBConfigurationGroup::probeCard(const QString &videodevice)
02729 {
02730 (void) videodevice;
02731
02732 #ifdef USING_DVB
02733 uint dvbdev = videodevice.toUInt();
02734 QString frontend_name = CardUtil::ProbeDVBFrontendName(dvbdev);
02735 QString subtype = CardUtil::ProbeDVBType(dvbdev);
02736
02737 QString err_open = tr("Could not open card #%1").arg(dvbdev);
02738 QString err_other = tr("Could not get card info for card #%1").arg(dvbdev);
02739
02740 switch (CardUtil::toCardType(subtype))
02741 {
02742 case CardUtil::ERROR_OPEN:
02743 cardname->setValue(err_open);
02744 cardtype->setValue(strerror(errno));
02745 break;
02746 case CardUtil::ERROR_UNKNOWN:
02747 cardname->setValue(err_other);
02748 cardtype->setValue("Unknown error");
02749 break;
02750 case CardUtil::ERROR_PROBE:
02751 cardname->setValue(err_other);
02752 cardtype->setValue(strerror(errno));
02753 break;
02754 case CardUtil::QPSK:
02755 cardtype->setValue("DVB-S");
02756 cardname->setValue(frontend_name);
02757 signal_timeout->setValue(60000);
02758 channel_timeout->setValue(62500);
02759 break;
02760 case CardUtil::QAM:
02761 cardtype->setValue("DVB-C");
02762 cardname->setValue(frontend_name);
02763 signal_timeout->setValue(1000);
02764 channel_timeout->setValue(3000);
02765 break;
02766 case CardUtil::OFDM:
02767 {
02768 cardtype->setValue("DVB-T");
02769 cardname->setValue(frontend_name);
02770 signal_timeout->setValue(500);
02771 channel_timeout->setValue(3000);
02772 if (frontend_name.lower().find("usb") >= 0)
02773 {
02774 signal_timeout->setValue(40000);
02775 channel_timeout->setValue(42500);
02776 }
02777
02778
02779 if ((frontend_name == "DiBcom 3000P/M-C DVB-T") ||
02780 (frontend_name ==
02781 "TerraTec/qanu USB2.0 Highspeed DVB-T Receiver"))
02782 {
02783 tuning_delay->setValue(200);
02784 }
02785
02786 #if 0 // frontends on hybrid DVB-T/Analog cards
02787 QString short_name = remove_chaff(frontend_name);
02788 buttonAnalog->setVisible(
02789 short_name.left(15).lower() == "zarlink zl10353" ||
02790 short_name.lower() == "wintv hvr 900 m/r: 65008/a1c0" ||
02791 short_name.left(17).lower() == "philips tda10046h");
02792 #endif
02793 }
02794 break;
02795 case CardUtil::ATSC:
02796 {
02797 QString short_name = remove_chaff(frontend_name);
02798 cardtype->setValue("ATSC");
02799 cardname->setValue(short_name);
02800 signal_timeout->setValue(500);
02801 channel_timeout->setValue(3000);
02802
02803
02804
02805 if (frontend_name = "Nextwave NXT200X VSB/QAM frontend")
02806 {
02807 signal_timeout->setValue(3000);
02808 channel_timeout->setValue(5500);
02809 }
02810
02811 #if 0 // frontends on hybrid DVB-T/Analog cards
02812 if (frontend_name.lower().find("usb") < 0)
02813 {
02814 buttonAnalog->setVisible(
02815 short_name.left(6).lower() == "pchdtv" ||
02816 short_name.left(5).lower() == "dvico" ||
02817 short_name.left(8).lower() == "nextwave");
02818 }
02819 #endif
02820 }
02821 break;
02822 default:
02823 break;
02824 }
02825 #else
02826 cardtype->setValue(QString("Recompile with DVB-Support!"));
02827 #endif
02828 }
02829
02830 TunerCardInput::TunerCardInput(const CaptureCard &parent,
02831 QString dev, QString type) :
02832 ComboBoxSetting(this), CaptureCardDBStorage(this, parent, "defaultinput"),
02833 last_device(dev), last_cardtype(type), last_diseqct(-1)
02834 {
02835 setLabel(QObject::tr("Default input"));
02836 int cardid = parent.getCardID();
02837 if (cardid <= 0)
02838 return;
02839
02840 last_cardtype = CardUtil::GetRawCardType(cardid);
02841 last_device = CardUtil::GetVideoDevice(cardid);
02842 }
02843
02844 void TunerCardInput::fillSelections(const QString& device)
02845 {
02846 clearSelections();
02847
02848 if (device.isEmpty())
02849 return;
02850
02851 last_device = device;
02852 QStringList inputs =
02853 CardUtil::probeInputs(device, last_cardtype);
02854
02855 for (QStringList::iterator i = inputs.begin(); i != inputs.end(); ++i)
02856 addSelection(*i);
02857 }
02858
02859 DVBConfigurationGroup::DVBConfigurationGroup(CaptureCard& a_parent) :
02860 VerticalConfigurationGroup(false, true, false, false),
02861 parent(a_parent),
02862 diseqc_tree(new DiSEqCDevTree())
02863 {
02864 cardnum = new DVBCardNum(parent);
02865 cardname = new DVBCardName();
02866 cardtype = new DVBCardType();
02867
02868 signal_timeout = new SignalTimeout(parent, 500, 250);
02869 channel_timeout = new ChannelTimeout(parent, 3000, 1750);
02870
02871 addChild(cardnum);
02872
02873 HorizontalConfigurationGroup *hg0 =
02874 new HorizontalConfigurationGroup(false, false, true, true);
02875 hg0->addChild(cardname);
02876 hg0->addChild(cardtype);
02877 addChild(hg0);
02878
02879 addChild(signal_timeout);
02880 addChild(channel_timeout);
02881
02882 addChild(new DVBAudioDevice(parent));
02883 addChild(new DVBVbiDevice(parent));
02884
02885 TransButtonSetting *buttonDiSEqC = new TransButtonSetting();
02886 buttonDiSEqC->setLabel(tr("DiSEqC"));
02887 buttonDiSEqC->setHelpText(tr("Input and satellite settings."));
02888
02889 TransButtonSetting *buttonRecOpt = new TransButtonSetting();
02890 buttonRecOpt->setLabel(tr("Recording Options"));
02891
02892 HorizontalConfigurationGroup *advcfg =
02893 new HorizontalConfigurationGroup(false, false, true, true);
02894 advcfg->addChild(buttonDiSEqC);
02895 advcfg->addChild(buttonRecOpt);
02896 addChild(advcfg);
02897
02898 defaultinput = new DVBInput(parent);
02899 addChild(defaultinput);
02900 defaultinput->setVisible(false);
02901
02902 tuning_delay = new DVBTuningDelay(parent);
02903 addChild(tuning_delay);
02904 tuning_delay->setVisible(false);
02905
02906 connect(cardnum, SIGNAL(valueChanged(const QString&)),
02907 this, SLOT( probeCard (const QString&)));
02908 connect(buttonDiSEqC, SIGNAL(pressed()),
02909 this, SLOT( DiSEqCPanel()));
02910 connect(buttonRecOpt, SIGNAL(pressed()),
02911 &parent, SLOT( recorderOptionsPanel()));
02912 }
02913
02914 DVBConfigurationGroup::~DVBConfigurationGroup()
02915 {
02916 if (diseqc_tree)
02917 {
02918 delete diseqc_tree;
02919 diseqc_tree = NULL;
02920 }
02921 }
02922
02923 void DVBConfigurationGroup::DiSEqCPanel()
02924 {
02925 parent.reload();
02926
02927 DTVDeviceTreeWizard diseqcWiz(*diseqc_tree);
02928 diseqcWiz.exec();
02929 defaultinput->fillSelections(diseqc_tree->IsInNeedOfConf());
02930 }
02931
02932 void DVBConfigurationGroup::load()
02933 {
02934 VerticalConfigurationGroup::load();
02935 diseqc_tree->Load(parent.getCardID());
02936 defaultinput->fillSelections(diseqc_tree->IsInNeedOfConf());
02937 }
02938
02939 void DVBConfigurationGroup::save()
02940 {
02941 VerticalConfigurationGroup::save();
02942 diseqc_tree->Store(parent.getCardID());
02943 DiSEqCDev trees;
02944 trees.InvalidateTrees();
02945 }
02946
02947 void CaptureCard::reload(void)
02948 {
02949 if (getCardID() == 0)
02950 {
02951 save();
02952 load();
02953 }
02954 }
02955
02956 void CaptureCard::recorderOptionsPanel()
02957 {
02958 reload();
02959
02960 RecorderOptions acw(*this);
02961 acw.exec();
02962 instance_count = acw.GetInstanceCount();
02963 }
02964
02965 RecorderOptions::RecorderOptions(CaptureCard &parent)
02966 : count(new InstanceCount(parent))
02967 {
02968 VerticalConfigurationGroup* rec = new VerticalConfigurationGroup(false);
02969 rec->setLabel(QObject::tr("Recorder Options"));
02970 rec->setUseLabel(false);
02971
02972 rec->addChild(count);
02973 rec->addChild(new DVBNoSeqStart(parent));
02974 rec->addChild(new DVBOnDemand(parent));
02975 rec->addChild(new DVBEITScan(parent));
02976 rec->addChild(new DVBTuningDelay(parent));
02977
02978 addChild(rec);
02979 }