Index: libs/libmyth/settings.h
===================================================================
--- libs/libmyth/settings.h	(revision 10200)
+++ libs/libmyth/settings.h	(working copy)
@@ -468,7 +468,7 @@
     void deleteButtonPressed(int);
 
 protected slots:
-    void setValueByLabel(const QString& label);
+    void setValueByIndex(int index);
     void addSelection(const QString& label,
                       QString value=QString::null,
                       bool select=false) {
Index: libs/libmyth/settings.cpp
===================================================================
--- libs/libmyth/settings.cpp	(revision 10200)
+++ libs/libmyth/settings.cpp	(working copy)
@@ -1161,8 +1161,8 @@
             this, SIGNAL(deleteButtonPressed(int)));
     connect(this, SIGNAL(valueChanged(const QString&)),
             widget, SLOT(setCurrentItem(const QString&)));
-    connect(widget, SIGNAL(highlighted(const QString&)),
-            this, SLOT(setValueByLabel(const QString&)));
+    connect(widget, SIGNAL(highlighted(int)),
+            this, SLOT(setValueByIndex(int)));
 
     if (cg)
         connect(widget, SIGNAL(changeHelpText(QString)), cg,
@@ -1181,13 +1181,8 @@
        widget->setSelectionMode(selectionMode);
 }
 
-void ListBoxSetting::setValueByLabel(const QString& label) {
-    for(unsigned i = 0 ; i < labels.size() ; ++i)
-        if (labels[i] == label) {
-            setValue(values[i]);
-            return;
-        }
-    cerr << "BUG: ListBoxSetting::setValueByLabel called for unknown label " << label << endl;
+void ListBoxSetting::setValueByIndex(int index) {
+    setValue(values[index]);
 }
 
 void ImageSelectSetting::addImageSelection(const QString& label,
Index: libs/libmythtv/dvbdevtree_cfg.h
===================================================================
--- libs/libmythtv/dvbdevtree_cfg.h	(revision 0)
+++ libs/libmythtv/dvbdevtree_cfg.h	(revision 0)
@@ -0,0 +1,151 @@
+/*
+ * \file dvbdevtree_cfg.h
+ * \brief DVB-S Device Tree Configuration Classes.
+ * \author Copyright (C) 2006, Yeasah Pell
+ */
+
+#ifndef DVBDEVTREE_CFG_H
+#define DVBDEVTREE_CFG_H
+
+#include "dvbtypes.h"
+#include "dvbdevtree.h"
+#include "settings.h"
+
+class SwitchTypeSetting;
+class SwitchPortsSetting;
+
+class SwitchConfig : public ConfigurationWizard
+{
+    Q_OBJECT
+public:
+    SwitchConfig(DVBDevSwitch& switch_dev);
+
+public slots:
+    void update();
+
+private:
+    SwitchTypeSetting* m_type;
+    SwitchPortsSetting* m_ports;
+};
+
+class RotorPosMap : public ListBoxSetting
+{
+    Q_OBJECT
+public:
+    RotorPosMap(DVBDevRotor& rotor);
+
+    virtual void load();
+    virtual void save();
+
+public slots:
+    void edit();
+    void del();
+
+protected:
+    void PopulateList();
+    
+private:
+    DVBDevRotor& m_rotor;
+    DVBDevRotor::POSMAP m_posmap;
+};
+
+class RotorConfig : public ConfigurationWizard
+{
+    Q_OBJECT
+public:
+    RotorConfig(DVBDevRotor& rotor);
+
+public slots:
+    void type_changed(const QString& type);
+    void positions();
+
+private:
+    DVBDevRotor& m_rotor;
+    TransButtonSetting* m_pos;
+};
+
+class LnbTypeSetting;
+class LnbLOFSwitchSetting;
+class LnbLOFLowSetting;
+class LnbLOFHighSetting;
+
+class LnbConfig : public ConfigurationWizard
+{
+    Q_OBJECT
+public:
+    LnbConfig(DVBDevLnb& lnb);
+
+public slots:
+    void preset(const QString& value);
+    void update();
+
+private:
+    LnbTypeSetting* m_type;
+    LnbLOFSwitchSetting* m_lof_switch;
+    LnbLOFLowSetting* m_lof_lo;
+    LnbLOFHighSetting* m_lof_hi;
+};
+
+class DeviceTree : public ListBoxSetting
+{
+    Q_OBJECT
+public:
+    DeviceTree(DVBDevTree& tree);
+
+    virtual void load();
+    virtual void save();
+
+protected:
+    bool editNode(int node_id);
+    void newRootNode();
+    void newNode(int parent_id, unsigned int child_num);
+
+    bool chooseType(dvbdev_t& type);
+    void PopulateTree();
+    void PopulateTree(DVBDevDevice* node,
+                      DVBDevDevice* parent = NULL,
+                      unsigned int childnum = 0,
+                      unsigned int depth = 0);
+
+public slots:
+    void edit();
+    void del();
+    
+private:
+    DVBDevTree& m_tree;
+};
+
+class DTVDeviceTreeWizard : public VerticalConfigurationGroup,
+                            public ConfigurationDialog
+{
+    Q_OBJECT
+public:
+    DTVDeviceTreeWizard(DVBDevTree& tree);
+
+    virtual int exec();
+};
+
+bool DTVDeviceNeedsConfiguration(unsigned int input_id);
+    
+class DTVDeviceConfigWizard : public ConfigurationWizard
+{
+    Q_OBJECT
+public:
+    DTVDeviceConfigWizard(DVBDevSettings& settings, unsigned int card_id);
+    ~DTVDeviceConfigWizard();
+    
+public slots:
+    void SelectNodes();
+  
+protected:
+    void AddNodes(ConfigurationGroup& group, DVBDevDevice* node);
+    
+private:
+    DVBDevTree m_tree;
+    DVBDevSettings& m_settings;
+
+    typedef std::map<unsigned int, Setting*> DEVS;
+    DEVS m_devs;
+};
+
+#endif // DVBDVBTREE_CFG_H
Index: libs/libmythtv/dvbdevtree_cfg.cpp
===================================================================
--- libs/libmythtv/dvbdevtree_cfg.cpp	(revision 0)
+++ libs/libmythtv/dvbdevtree_cfg.cpp	(revision 0)
@@ -0,0 +1,1093 @@
+/*
+ * \file dvbdevtree_cfg.cpp
+ * \brief DVB-S Device Tree Configuration Classes.
+ * \author Copyright (C) 2006, Yeasah Pell
+ */
+
+#include "mythcontext.h"
+#include "mythdbcon.h"
+#include "settings.h"
+#include "dvbdevtree_cfg.h"
+#include "dvbdevtree.h"
+#include <set>
+#include <cmath>
+
+/* Lat/Long items relocated from videosource.cpp */
+
+static GlobalLineEdit *DiSEqCLatitude()
+{
+    GlobalLineEdit *gc = new GlobalLineEdit("latitude");
+    gc->setLabel("Latitude");
+    gc->setHelpText(
+        QObject::tr("The Cartesian latitude for your location.") + " " +
+        QObject::tr("Use negative numbers for southern "
+                    "and western coordinates."));
+    return gc;
+}
+
+static GlobalLineEdit *DiSEqCLongitude()
+{
+    GlobalLineEdit *gc = new GlobalLineEdit("longitude");
+    gc->setLabel("Longitude");
+    gc->setHelpText(
+        QObject::tr("The Cartesian longitude for your location.") + " " +
+        QObject::tr("Use negative numbers for southern "
+                    "and western coordinates."));
+    return gc;
+}
+
+//////////////////////////////////////// DeviceTypeSetting
+
+class DeviceTypeSetting : public ComboBoxSetting
+{
+public:
+    DeviceTypeSetting(DVBDevDevice& device) : m_device(device)
+    {
+        setLabel(QObject::tr("Device Type"));
+        addSelection("Switch", QString::number((uint)DVBDEV_SWITCH));
+        addSelection("Rotor",  QString::number((uint)DVBDEV_ROTOR));
+        addSelection("LNB", QString::number((uint)DVBDEV_LNB));
+    }
+
+    virtual void load()
+    {
+        setValue(getValueIndex(QString::number((uint)m_device.GetDeviceType())));
+    }
+
+    virtual void save()
+    {
+        m_device.SetDeviceType((dvbdev_t)getValue().toUInt());
+    }
+
+private:    
+    DVBDevDevice& m_device;
+};
+
+//////////////////////////////////////// DeviceDescrSetting
+
+class DeviceDescrSetting : public LineEditSetting
+{
+public:
+    DeviceDescrSetting(DVBDevDevice& device) : m_device(device)
+    {
+        setLabel(QObject::tr("Description"));
+        setHelpText(QObject::tr("Optional descriptive name for this "
+                                "device, to make it easier to configure "
+                                "settings later."));
+    }
+    
+    virtual void load()
+    {
+        setValue(m_device.GetDescription());
+    }
+
+    virtual void save()
+    {
+        m_device.SetDescription(getValue());
+    }
+
+private:
+    DVBDevDevice& m_device;
+};
+
+//////////////////////////////////////// SwitchTypeSetting
+
+class SwitchTypeSetting : public ComboBoxSetting
+{
+public:
+    SwitchTypeSetting(DVBDevSwitch& switch_dev) : m_switch(switch_dev)
+    {
+        setLabel(QObject::tr("Switch Type"));
+        setHelpText(QObject::tr("Select the type of switch from the list."));
+
+        addSelection("Tone", QString::number((uint)SWITCH_TONE));
+        addSelection("DiSEqC", QString::number((uint)SWITCH_DISEQC_COMMITTED));
+        addSelection("DiSEqC (Uncommitted)",  QString::number((uint)SWITCH_DISEQC_UNCOMMITTED));
+        addSelection("Legacy SW21", QString::number((uint)SWITCH_LEGACY_SW21));
+        addSelection("Legacy SW42", QString::number((uint)SWITCH_LEGACY_SW42));
+        addSelection("Legacy SW64", QString::number((uint)SWITCH_LEGACY_SW64));
+    }
+
+    virtual void load()
+    {
+        setValue(getValueIndex(QString::number((uint)m_switch.GetType())));
+    }
+
+    virtual void save()
+    {
+        m_switch.SetType((dvbdev_switch_t)getValue().toUInt());
+    }
+
+private:    
+    DVBDevSwitch& m_switch;
+};
+
+//////////////////////////////////////// SwitchPortsSetting
+
+class SwitchPortsSetting : public LineEditSetting
+{
+public:
+    SwitchPortsSetting(DVBDevSwitch& switch_dev) : m_switch(switch_dev)
+    {
+        setLabel(QObject::tr("Number of ports"));
+        setHelpText(QObject::tr("The number of ports this switch has."));
+    }
+
+    virtual void load()
+    {
+        setValue(QString::number(m_switch.GetNumPorts()));
+    }
+
+    virtual void save()
+    {
+        m_switch.SetNumPorts(getValue().toUInt());
+    }
+
+private:    
+    DVBDevSwitch& m_switch;
+};
+
+//////////////////////////////////////// SwitchConfig
+
+SwitchConfig::SwitchConfig(DVBDevSwitch& switch_dev)
+{
+    ConfigurationGroup* group = 
+        new VerticalConfigurationGroup(false, false);
+    group->setLabel(QObject::tr("Switch Configuration"));
+    
+    group->addChild(new DeviceDescrSetting(switch_dev));
+    m_type = new SwitchTypeSetting(switch_dev);
+    group->addChild(m_type);
+    m_ports = new SwitchPortsSetting(switch_dev);
+    group->addChild(m_ports);
+    
+    connect(m_type, SIGNAL(valueChanged(const QString&)), this, SLOT(update()));
+    
+    addChild(group);
+}
+
+void SwitchConfig::update()
+{
+    switch((dvbdev_switch_t)m_type->getValue().toUInt())
+    {
+    case SWITCH_TONE:
+    case SWITCH_LEGACY_SW21:
+    case SWITCH_LEGACY_SW42:
+        m_ports->setValue("2");
+        m_ports->setEnabled(false);
+        break;
+    case SWITCH_LEGACY_SW64:
+        m_ports->setValue("3");
+        m_ports->setEnabled(false);
+        break;
+    case SWITCH_DISEQC_COMMITTED:
+    case SWITCH_DISEQC_UNCOMMITTED:
+        m_ports->setEnabled(true);
+        break;
+    }
+}
+
+//////////////////////////////////////// RotorTypeSetting
+
+class RotorTypeSetting : public ComboBoxSetting
+{
+public:
+    RotorTypeSetting(DVBDevRotor& rotor) : m_rotor(rotor)
+    {
+        setLabel(QObject::tr("Rotor Type"));
+        setHelpText(QObject::tr("Select the type of rotor from the list."));
+        addSelection("DiSEqC 1.2", QString::number((uint)ROTOR_DISEQC_1_2));
+        addSelection("DiSEqC 1.3 (GotoX/USALS)", QString::number((uint)ROTOR_DISEQC_1_3));
+    }
+
+    virtual void load()
+    {
+        setValue(getValueIndex(QString::number((uint)m_rotor.GetType())));
+    }
+
+    virtual void save()
+    {
+        m_rotor.SetType((dvbdev_rotor_t)getValue().toUInt());
+    }
+
+private:    
+    DVBDevRotor& m_rotor;
+};
+
+//////////////////////////////////////// RotorLoSpeedSetting
+
+class RotorLoSpeedSetting : public LineEditSetting
+{
+public:
+    RotorLoSpeedSetting(DVBDevRotor& rotor) : m_rotor(rotor)
+    {
+        setLabel(QObject::tr("Rotor Low Speed (deg/sec)"));
+        setHelpText(QObject::tr("To allow the approximate monitoring of "
+                                "rotor movement, enter the rated angular "
+                                "speed of the rotor when powered at 13V."));
+    }
+
+    virtual void load()
+    {
+        setValue(QString::number(m_rotor.GetLoSpeed()));
+    }
+
+    virtual void save()
+    {
+        m_rotor.SetLoSpeed(getValue().toDouble());
+    }
+
+private:    
+    DVBDevRotor& m_rotor;
+};
+
+//////////////////////////////////////// RotorHiSpeedSetting
+
+class RotorHiSpeedSetting : public LineEditSetting
+{
+public:
+    RotorHiSpeedSetting(DVBDevRotor& rotor) : m_rotor(rotor)
+    {
+        setLabel(QObject::tr("Rotor High Speed (deg/sec)"));
+        setHelpText(QObject::tr("To allow the approximate monitoring of "
+                                "rotor movement, enter the rated angular "
+                                "speed of the rotor when powered at 18V."));
+    }
+    
+    virtual void load()
+    {
+        setValue(QString::number(m_rotor.GetHiSpeed()));
+    }
+    
+    virtual void save()
+    {
+        m_rotor.SetHiSpeed(getValue().toDouble());
+    }
+    
+private:    
+    DVBDevRotor& m_rotor;
+};
+
+//////////////////////////////////////// RotorPosMap
+
+static QString AngleToString(double angle)
+{
+    QString str;
+    if(angle >= 0.0)
+        str = QString::number(angle) + "E";
+    else if(angle < 0.0)
+        str = QString::number(-angle) + "W";
+    return str;
+}
+
+static double AngleToFloat(const QString& angle)
+{
+    double pos;
+    QChar postfix = angle.at(angle.length()-1);
+    if(postfix.isLetter())
+    {
+        pos = angle.left(angle.length()-1).toDouble();
+        if(postfix == 'W' || postfix == 'w')
+            pos = -pos;
+    }
+    else
+        pos = angle.toDouble();
+    
+    return pos;
+}
+
+RotorPosMap::RotorPosMap(DVBDevRotor& rotor) : m_rotor(rotor)
+{
+    connect(this, SIGNAL(editButtonPressed(int)), SLOT(edit()));
+    connect(this, SIGNAL(deleteButtonPressed(int)), SLOT(del()));
+    connect(this, SIGNAL(accepted(int)), SLOT(edit()));
+}
+
+void RotorPosMap::load()
+{
+    m_posmap = m_rotor.GetPosMap();
+    PopulateList();
+}
+
+void RotorPosMap::save()
+{
+    m_rotor.SetPosMap(m_posmap);
+}
+
+void RotorPosMap::edit()
+{
+    unsigned int id = getValue().toUInt();
+
+    QString angle;
+    if(MythPopupBox::showGetTextPopup(gContext->GetMainWindow(),
+                                      QString("Position Index %1").arg(id),
+                                      "Orbital Position",
+                                      angle))
+    {
+        m_posmap[id] = AngleToFloat(angle);
+        PopulateList();
+    }
+}
+
+void RotorPosMap::del()
+{
+    unsigned int id = getValue().toUInt();
+    m_posmap.erase(id);
+    PopulateList();
+}
+
+void RotorPosMap::PopulateList()
+{
+    int old_sel = getValueIndex(getValue());
+    clearSelections();
+    uint num_pos = 64;
+    for(uint pos = 1; pos < num_pos; pos++)
+    {
+        DVBDevRotor::POSMAP::const_iterator p = m_posmap.find(pos);
+        QString posval;
+        if(p == m_posmap.end())
+            posval = "None";
+        else
+            posval = AngleToString(p->second);
+
+        addSelection(QString("Position #%1 (%2)")
+                     .arg(pos)
+                     .arg(posval),
+                     QString::number(pos));
+    }
+    setCurrentItem(old_sel);
+}
+
+//////////////////////////////////////// RotorPosConfig
+
+class RotorPosConfig : public VerticalConfigurationGroup,
+                       public ConfigurationDialog
+{
+public:
+    RotorPosConfig(DVBDevRotor& rotor)
+    {
+        setLabel(QObject::tr("Rotor Position Map"));
+        setUseLabel(true);
+        addChild(new RotorPosMap(rotor));
+    }
+
+    virtual int exec()
+    {
+        while (ConfigurationDialog::exec() == QDialog::Accepted) {}
+        return QDialog::Rejected;
+    }
+};
+    
+//////////////////////////////////////// RotorConfig
+
+RotorConfig::RotorConfig(DVBDevRotor& rotor) : m_rotor(rotor)
+{
+    ConfigurationGroup* group = 
+        new VerticalConfigurationGroup(false, false);
+    group->setLabel(QObject::tr("Rotor Configuration"));
+    
+    group->addChild(new DeviceDescrSetting(rotor));
+    
+    ConfigurationGroup* tgroup = 
+        new HorizontalConfigurationGroup(false, false, true, true);
+
+    RotorTypeSetting* rtype = new RotorTypeSetting(rotor);
+    connect(rtype, SIGNAL(valueChanged(const QString&)),
+            SLOT(type_changed(const QString&)));
+    tgroup->addChild(rtype);
+    
+    m_pos = new TransButtonSetting();
+    m_pos->setLabel(QObject::tr("Positions"));
+    m_pos->setHelpText(QObject::tr("Rotor position setup."));
+    m_pos->setEnabled(rotor.GetType() == ROTOR_DISEQC_1_2);
+    connect(m_pos, SIGNAL(pressed()), SLOT(positions()));
+    tgroup->addChild(m_pos);
+
+    group->addChild(tgroup);
+    group->addChild(new RotorLoSpeedSetting(rotor));
+    group->addChild(new RotorHiSpeedSetting(rotor));
+    group->addChild(DiSEqCLatitude());
+    group->addChild(DiSEqCLongitude());
+    
+    addChild(group);
+}
+
+void RotorConfig::type_changed(const QString& type)
+{
+    dvbdev_rotor_t rtype = (dvbdev_rotor_t)type.toUInt();
+    m_pos->setEnabled(rtype == ROTOR_DISEQC_1_2);
+}
+
+void RotorConfig::positions()
+{
+    RotorPosConfig config(m_rotor);
+    config.exec();
+    config.save();
+}
+    
+//////////////////////////////////////// LnbPresetSetting
+
+struct lnb_preset
+{
+    const char* name;
+    dvbdev_lnb_t type;
+    unsigned int lof_sw;
+    unsigned int lof_lo;
+    unsigned int lof_hi;
+};
+
+static lnb_preset lnb_presets[] = 
+{
+    /* description, type, LOF switch, LOF low, LOF high */
+    { "Single (Europe)", LNB_VOLTAGE, 0, 9750000, 0 },
+    { "Universal (Europe)", LNB_VOLTAGE_TONE, 11700000, 9750000, 10600000 },
+    { "Circular (N. America)", LNB_VOLTAGE, 0, 11250000, 0 },
+    { "Linear (N. America)", LNB_VOLTAGE, 0, 10750000, 0 },
+    { "C Band", LNB_VOLTAGE, 0, 5150000, 0 },
+    { NULL, LNB_VOLTAGE, 0, 0, 0 }
+};
+
+unsigned int FindPreset(const DVBDevLnb& lnb)
+{
+    unsigned int i;
+    for(i=0; lnb_presets[i].name != NULL; i++)
+    {
+        if(lnb_presets[i].type == lnb.GetType() &&
+           lnb_presets[i].lof_sw == lnb.GetLOFSwitch() &&
+           lnb_presets[i].lof_lo == lnb.GetLOFLow() &&
+           lnb_presets[i].lof_hi == lnb.GetLOFHigh())
+            break;
+    }
+    return i;
+}
+
+class LnbPresetSetting : public ComboBoxSetting
+{
+public:
+    LnbPresetSetting(DVBDevLnb& lnb) : m_lnb(lnb)
+    {
+        setLabel(QObject::tr("LNB Preset"));
+        setHelpText(QObject::tr("Select the LNB preset from the list, or "
+                                "choose Custom and change the advanced "
+                                "settings below."));
+        
+        unsigned int i;
+        for(i=0; lnb_presets[i].name != NULL; i++)
+            addSelection(lnb_presets[i].name, QString::number(i));
+        addSelection(QObject::tr("Custom"), QString::number(i));
+    }
+
+    virtual void load()
+    {
+        setValue(FindPreset(m_lnb));
+    }
+
+    virtual void save()
+    {
+    }
+
+private:    
+    DVBDevLnb& m_lnb;
+};
+
+//////////////////////////////////////// LnbTypeSetting
+
+class LnbTypeSetting : public ComboBoxSetting
+{
+public:
+    LnbTypeSetting(DVBDevLnb& lnb) : m_lnb(lnb)
+    {
+        setLabel(QObject::tr("LNB Type"));
+        setHelpText(QObject::tr("Select the type of LNB from the list."));
+        addSelection("Legacy (Fixed)", QString::number((uint)LNB_FIXED));
+        addSelection("Standard (Voltage)", QString::number((uint)LNB_VOLTAGE));
+        addSelection("Universal (Voltage+Tone)", QString::number((uint)LNB_VOLTAGE_TONE));
+    }
+
+    virtual void load()
+    {
+        setValue(getValueIndex(QString::number((uint)m_lnb.GetType())));
+    }
+
+    virtual void save()
+    {
+        m_lnb.SetType((dvbdev_lnb_t)getValue().toUInt());
+    }
+
+private:    
+    DVBDevLnb& m_lnb;
+};
+
+//////////////////////////////////////// LnbLOFSwitchSetting
+
+class LnbLOFSwitchSetting : public LineEditSetting
+{
+public:
+    LnbLOFSwitchSetting(DVBDevLnb& lnb) : m_lnb(lnb)
+    {
+        setLabel(QObject::tr("LNB LOF Switch (MHz)"));
+        setHelpText(QObject::tr("This defines at what frequency "
+                                "the LNB will do a switch from high to low "
+                                "setting, and vice versa."));
+    }
+
+    virtual void load()
+    {
+        setValue(QString::number(m_lnb.GetLOFSwitch() / 1000));
+    }
+
+    virtual void save()
+    {
+        m_lnb.SetLOFSwitch(getValue().toUInt() * 1000);
+    }
+
+private:    
+    DVBDevLnb& m_lnb;
+};
+
+//////////////////////////////////////// LnbLOFLowSetting
+
+class LnbLOFLowSetting : public LineEditSetting
+{
+public:
+    LnbLOFLowSetting(DVBDevLnb& lnb) : m_lnb(lnb)
+    {
+        setLabel(QObject::tr("LNB LOF Low (MHz)"));
+        setHelpText(QObject::tr("This defines the offset the "
+                                "frequency coming from the LNB will be "
+                                "in low setting."));
+    }
+
+    virtual void load()
+    {
+        setValue(QString::number(m_lnb.GetLOFLow() / 1000));
+    }
+
+    virtual void save()
+    {
+        m_lnb.SetLOFLow(getValue().toUInt() * 1000);
+    }
+
+private:    
+    DVBDevLnb& m_lnb;
+};
+
+//////////////////////////////////////// LnbLOFHighSetting
+
+class LnbLOFHighSetting : public LineEditSetting
+{
+public:
+    LnbLOFHighSetting(DVBDevLnb& lnb) : m_lnb(lnb)
+    {
+        setLabel(QObject::tr("LNB LOF High (MHz)"));
+        setHelpText(QObject::tr("This defines the offset the "
+                                "frequency coming from the LNB will be "
+                                "in high setting."));
+    }
+
+    virtual void load()
+    {
+        setValue(QString::number(m_lnb.GetLOFHigh() / 1000));
+    }
+
+    virtual void save()
+    {
+        m_lnb.SetLOFHigh(getValue().toUInt() * 1000);
+    }
+    
+private:    
+    DVBDevLnb& m_lnb;
+};
+
+//////////////////////////////////////// LnbConfig
+
+LnbConfig::LnbConfig(DVBDevLnb& lnb)
+{
+    ConfigurationGroup* group = 
+        new VerticalConfigurationGroup(false, false);
+    group->setLabel(QObject::tr("LNB Configuration"));
+
+    group->addChild(new DeviceDescrSetting(lnb));
+    LnbPresetSetting* preset = new LnbPresetSetting(lnb);
+    group->addChild(preset);
+    m_type = new LnbTypeSetting(lnb);
+    group->addChild(m_type);
+    m_lof_switch = new LnbLOFSwitchSetting(lnb);
+    group->addChild(m_lof_switch);
+    m_lof_lo = new LnbLOFLowSetting(lnb);
+    group->addChild(m_lof_lo);
+    m_lof_hi = new LnbLOFHighSetting(lnb);
+    group->addChild(m_lof_hi);
+    connect(m_type, SIGNAL(valueChanged(const QString&)), this, SLOT(update()));
+    connect(preset, SIGNAL(valueChanged(const QString&)), this, SLOT(preset(const QString&)));
+    addChild(group);
+}
+    
+void LnbConfig::preset(const QString& value)
+{
+    unsigned int index = value.toUInt();
+    if(index >= (sizeof(lnb_presets) / sizeof(lnb_preset)))
+        return;
+    
+    lnb_preset& preset = lnb_presets[index];
+    if(preset.name == NULL)
+    {
+        m_type->setEnabled(true);
+        update();
+    }
+    else
+    {
+        m_type->setValue(m_type->getValueIndex(QString::number((uint)preset.type)));
+        m_lof_switch->setValue(QString::number(preset.lof_sw / 1000));
+        m_lof_lo->setValue(QString::number(preset.lof_lo / 1000));
+        m_lof_hi->setValue(QString::number(preset.lof_hi / 1000));
+        m_type->setEnabled(false);
+        m_lof_switch->setEnabled(false);
+        m_lof_hi->setEnabled(false);
+        m_lof_lo->setEnabled(false);
+    }
+}
+    
+void LnbConfig::update()
+{
+    if(m_type->isEnabled())
+    {
+        switch((dvbdev_switch_t)m_type->getValue().toUInt())
+        {
+        case LNB_FIXED:
+        case LNB_VOLTAGE:
+            m_lof_switch->setEnabled(false);
+            m_lof_hi->setEnabled(false);
+            m_lof_lo->setEnabled(true);
+            break;
+        case LNB_VOLTAGE_TONE:
+            m_lof_switch->setEnabled(true);
+            m_lof_hi->setEnabled(true);
+            m_lof_lo->setEnabled(true);
+            break;
+        }
+    }
+}
+
+//////////////////////////////////////// DeviceTree
+
+
+DeviceTree::DeviceTree(DVBDevTree& tree) : m_tree(tree)
+{
+    connect(this, SIGNAL(editButtonPressed(int)), SLOT(edit()));
+    connect(this, SIGNAL(deleteButtonPressed(int)), SLOT(del()));
+    connect(this, SIGNAL(accepted(int)), SLOT(edit()));
+}
+
+void DeviceTree::load()
+{
+    PopulateTree();
+}
+
+void DeviceTree::save()
+{
+}
+
+bool DeviceTree::editNode(int node_id)
+{
+    DVBDevDevice* dev = m_tree.FindDevice(node_id);
+    bool changed = false;
+    if(dev)
+    {
+        switch(dev->GetDeviceType())
+        {
+        case DVBDEV_SWITCH:
+        {
+            DVBDevSwitch* sw = dynamic_cast<DVBDevSwitch*>(dev);
+            if(sw)
+            {
+                SwitchConfig config(*sw);
+                changed = (config.exec() == MythDialog::Accepted);
+            }
+        }
+        break;
+        case DVBDEV_ROTOR:
+        {
+            DVBDevRotor* rotor = dynamic_cast<DVBDevRotor*>(dev);
+            if(rotor)
+            {
+                RotorConfig config(*rotor);
+                changed = (config.exec() == MythDialog::Accepted);
+            }
+        }
+        break;
+        case DVBDEV_LNB:
+        {
+            DVBDevLnb* lnb = dynamic_cast<DVBDevLnb*>(dev);
+            if(lnb)
+            {
+                LnbConfig config(*lnb);
+                changed = (config.exec() == MythDialog::Accepted);
+            }
+        }
+        break;
+        default:
+            break;
+        }
+    }
+
+    if(changed)
+        PopulateTree();
+    return changed;
+}
+
+bool DeviceTree::chooseType(dvbdev_t& type)
+{
+    MythPopupBox* popup = new MythPopupBox(gContext->GetMainWindow(), "");
+    popup->addLabel(tr("Select Type of Device"));
+
+    MythListBox* list = new MythListBox(popup);
+    list->setScrollBar(false);
+    list->setBottomScrollBar(false);
+    list->insertItem("Switch");
+    list->insertItem("Rotor");
+    list->insertItem("LNB");
+    list->setCurrentItem(0);
+
+    popup->addWidget(list);
+    connect(list, SIGNAL(accepted(int)), popup, SLOT(done(int)));
+    list->setFocus();
+
+    int res = popup->ExecPopup();
+    type = (dvbdev_t)list->currentItem();
+    delete popup;
+
+    return res >= 0;
+}
+
+void DeviceTree::newRootNode()
+{
+    dvbdev_t type;
+    if(chooseType(type))
+    {
+        DVBDevDevice* dev = DVBDevDevice::CreateByType(m_tree, type);
+        if(dev)
+        {
+            m_tree.SetRoot(dev);
+            if(!editNode(dev->DeviceID()))
+                m_tree.SetRoot(NULL);
+            PopulateTree();
+        }
+    }
+}
+
+void DeviceTree::newNode(int parent_id, unsigned int child_num)
+{
+    DVBDevDevice* parent = m_tree.FindDevice(parent_id);
+    if(parent)
+    {
+        dvbdev_t type;
+        if(chooseType(type))
+        {
+            DVBDevDevice* dev = DVBDevDevice::CreateByType(m_tree, type);
+            if(dev)
+            {
+                if(parent->SetChild(child_num, dev))
+                {
+                    if(!editNode(dev->DeviceID()))
+                        parent->SetChild(child_num, NULL);
+                    PopulateTree();
+                }
+                else
+                    delete dev;
+            }
+        }
+    }
+}
+
+void DeviceTree::edit()
+{
+    QString id = getValue();
+    if(id.find(':') == -1)
+        editNode(id.toInt());
+    else
+    {
+        QStringList vals = QStringList::split(':', id, true);
+        if(vals[0].isEmpty())
+            newRootNode();
+        else
+            newNode(vals[0].toInt(), vals[1].toUInt());
+    }
+    setFocus();
+}
+
+void DeviceTree::del()
+{
+    QString id = getValue();
+    if(id.find(':') == -1)
+    {
+        int node_id = id.toInt();
+        DVBDevDevice* dev = m_tree.FindDevice(node_id);
+        if(dev)
+        {
+            DVBDevDevice* parent = dev->GetParent();
+            if(parent)
+                parent->SetChild(dev->GetOrdinal(), NULL);
+            else
+                m_tree.SetRoot(NULL);
+            
+            PopulateTree();
+        }
+    }
+    setFocus();
+}
+
+void DeviceTree::PopulateTree()
+{
+    int old_sel = getValueIndex(getValue());
+    clearSelections();
+    PopulateTree(m_tree.Root());
+    setCurrentItem(old_sel);
+}
+    
+void DeviceTree::PopulateTree(DVBDevDevice* node,
+                              DVBDevDevice* parent,
+                              unsigned int childnum,
+                              unsigned int depth)
+{
+    QString indent;
+    indent.fill('\t', depth);
+    if(node)
+    {
+        QString id = QString::number(node->DeviceID());
+        addSelection(indent + node->GetDescription(), id);
+        unsigned int num_ch = node->NumChildren();
+        for(unsigned int ch = 0; ch < num_ch; ch++)
+            PopulateTree(node->GetChild(ch), node, ch, depth+1);
+    }
+    else
+    {
+        QString id;
+        if(parent)
+            id = QString::number(parent->DeviceID());
+        id += ":" + QString::number(childnum);
+        
+        addSelection(indent + "(Unconnected)", id);
+    }
+}
+
+//////////////////////////////////////// DTVDeviceTreeWizard
+
+DTVDeviceTreeWizard::DTVDeviceTreeWizard(DVBDevTree& tree)
+    : ConfigurationGroup(false, true, false, false),
+      VerticalConfigurationGroup(false, true, false, false)
+{
+    setLabel(QObject::tr("DVB-S Device Tree"));
+    setUseLabel(true);
+    addChild(new DeviceTree(tree));
+}
+
+int DTVDeviceTreeWizard::exec()
+{
+    while (ConfigurationDialog::exec() == QDialog::Accepted) {}
+    return QDialog::Rejected;
+}
+
+//////////////////////////////////////// SwitchSetting
+
+class SwitchSetting : public ComboBoxSetting
+{
+public:
+    SwitchSetting(DVBDevDevice& node, DVBDevSettings& settings)
+        : m_node(node), m_settings(settings)
+    {
+        setLabel(node.GetDescription());
+        setHelpText(QObject::tr("Choose a port to use for this switch."));
+
+        unsigned int num_children = node.NumChildren();
+        for(unsigned int ch = 0; ch < num_children; ch++)
+        {
+            QString val = QString("%1").arg(ch);
+            QString descr = QString("Port %1").arg(ch+1);
+            DVBDevDevice* child = node.GetChild(ch);
+            if(child)
+                descr += QString(" (%2)").arg(child->GetDescription());
+            addSelection(descr, val);
+        }
+    }
+
+    virtual void load()
+    {
+        double value = m_settings.GetValue(m_node.DeviceID());
+        setValue((unsigned int)value);
+    }
+
+    virtual void save()
+    {
+        m_settings.SetValue(m_node.DeviceID(), getValue().toDouble());
+    }
+
+private:
+    DVBDevDevice& m_node;
+    DVBDevSettings& m_settings;
+};
+
+//////////////////////////////////////// RotorSetting
+
+class RotorSetting : public ComboBoxSetting
+{
+public:
+    RotorSetting(DVBDevDevice& node, DVBDevSettings& settings)
+        : m_node(node), m_settings(settings)
+    {
+        setLabel(node.GetDescription());
+        setHelpText(QObject::tr("Choose a satellite position."));
+
+        DVBDevRotor* rotor = dynamic_cast<DVBDevRotor*>(&m_node);
+        if(rotor)
+            m_posmap = rotor->GetPosMap();
+    }
+
+    virtual void load()
+    {
+        clearSelections();
+        DVBDevRotor::POSMAP::iterator p;
+        for(p = m_posmap.begin(); p != m_posmap.end(); p++)
+            addSelection(AngleToString(p->second), QString::number(p->second));
+        double angle = m_settings.GetValue(m_node.DeviceID());
+        setValue(getValueIndex(QString::number(angle)));
+    }
+
+    virtual void save()
+    {
+        m_settings.SetValue(m_node.DeviceID(), getValue().toDouble());
+    }
+
+private:
+    DVBDevDevice& m_node;
+    DVBDevSettings& m_settings;
+    DVBDevRotor::POSMAP m_posmap;
+};
+
+//////////////////////////////////////// USALSRotorSetting
+
+class USALSRotorSetting : public LineEditSetting
+{
+public:
+    USALSRotorSetting(DVBDevDevice& node, DVBDevSettings& settings)
+        : m_node(node), m_settings(settings)
+    {
+        setLabel(node.GetDescription());
+        setHelpText(QObject::tr("The longitude of the satellite "
+                                "you are aiming at.  For western hemisphere "
+                                "use a 'W' suffix.  Value is in decimal."));
+    }
+
+    virtual void load()
+    {
+        setValue(AngleToString(m_settings.GetValue(m_node.DeviceID())));
+    }
+
+    virtual void save()
+    {
+        m_settings.SetValue(m_node.DeviceID(), AngleToFloat(getValue()));
+    }
+
+private:
+    DVBDevDevice& m_node;
+    DVBDevSettings& m_settings;
+};
+
+//////////////////////////////////////// DTVDeviceNeedsConfiguration
+
+bool DTVDeviceNeedsConfiguration(unsigned int card_id)
+{
+    bool needs_conf = false;
+    MSqlQuery query(MSqlQuery::InitCon());
+    query.prepare("SELECT dtv_dev_type"
+                  " FROM dtv_device_tree, capturecard"
+                  " WHERE capturecard.dtv_dev_id = dtv_device_tree.dtv_dev_id"
+                  " AND capturecard.cardid = :CARDID");
+    query.bindValue(":CARDID", card_id);
+    if(query.exec() && query.isActive() && query.next())
+        needs_conf = (query.value(0).toString() != "lnb");
+    return needs_conf;
+}
+
+//////////////////////////////////////// DTVDeviceConfigWizard
+
+DTVDeviceConfigWizard::DTVDeviceConfigWizard(DVBDevSettings& settings,
+                                             unsigned int card_id)
+    : m_settings(settings)
+{
+    ConfigurationGroup* group =
+        new VerticalConfigurationGroup(false, false);
+    group->setLabel(QObject::tr("DTV Device Configuration"));
+
+    // load
+    m_tree.Load(card_id);
+
+    // initial UI setup
+    AddNodes(*group, m_tree.Root());
+    SelectNodes();
+
+    addChild(group);
+}
+
+DTVDeviceConfigWizard::~DTVDeviceConfigWizard()
+{
+}
+
+void DTVDeviceConfigWizard::AddNodes(ConfigurationGroup& group,
+                                     DVBDevDevice* node)
+{
+    if(node)
+    {
+        Setting* setting = NULL;
+        switch(node->GetDeviceType())
+        {
+        case DVBDEV_SWITCH:
+            setting = new SwitchSetting(*node, m_settings);
+            connect(setting, SIGNAL(valueChanged(const QString&)),
+                    SLOT(SelectNodes()));
+            break;
+        case DVBDEV_ROTOR:
+        {
+            DVBDevRotor* rotor = dynamic_cast<DVBDevRotor*>(node);
+            if(rotor && rotor->GetType() == ROTOR_DISEQC_1_2)
+                setting = new RotorSetting(*node, m_settings);
+            else
+                setting = new USALSRotorSetting(*node, m_settings);
+            break;
+        }
+        default:
+            break;
+        }
+
+        if(setting)
+        {
+            // add this node
+            m_devs[node->DeviceID()] = setting;
+            group.addChild(setting);
+        }
+
+        // add children
+        unsigned int num_ch = node->NumChildren();
+        for(unsigned int ch = 0; ch < num_ch; ch++)
+            AddNodes(group, node->GetChild(ch));
+    }
+}
+
+void DTVDeviceConfigWizard::SelectNodes()
+{
+    save();
+
+    std::set<unsigned int> active;
+    DVBDevDevice* node = m_tree.Root();
+    while(node)
+    {
+        active.insert(node->DeviceID());
+        node = node->SelectedChild(m_settings);
+    }
+
+    for(DEVS::iterator i = m_devs.begin(); i != m_devs.end(); i++)
+    {
+        bool visible = active.find(i->first) != active.end();
+        i->second->setEnabled(visible);
+    }
+}
