moved stuff around

Jean-Francois Dockes Jean-Francois Dockes 2016-10-05

added utils/smallut.cpp
added utils/smallut.h
changed GUI/prefs/prefs.cpp
changed GUI/prefs/sortprefs.h
changed notifications/notifications.cpp
changed upplay.pro
copied GUI/prefs/confgui.cpp -> utils/confgui.cpp
copied GUI/prefs/confgui.h -> utils/confgui.h
utils/smallut.cpp Diff Switch to side-by-side view
Loading...
utils/smallut.h Diff Switch to side-by-side view
Loading...
GUI/prefs/prefs.cpp Diff Switch to side-by-side view
Loading...
GUI/prefs/sortprefs.h Diff Switch to side-by-side view
Loading...
notifications/notifications.cpp Diff Switch to side-by-side view
Loading...
upplay.pro Diff Switch to side-by-side view
Loading...
GUI/prefs/confgui.cpp to utils/confgui.cpp
--- a/GUI/prefs/confgui.cpp
+++ b/utils/confgui.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005 J.F.Dockes 
+/* Copyright (C) 2005-2016 J.F.Dockes
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
  *   the Free Software Foundation; either version 2 of the License, or
@@ -47,15 +47,17 @@
 #include <qstringlist.h>
 #include <qcombobox.h>
 
+#include "smallut.h"
+
 using namespace std;
 
 namespace confgui {
 
-static const int spacing = 0;
+static const int spacing = 3;
 // left,top,right, bottom
 static QMargins margin(4,3,4,3);
 
-ConfTabsW::ConfTabsW(QWidget *parent, const QString& title, 
+ConfTabsW::ConfTabsW(QWidget *parent, const QString& title,
                      ConfLinkFact *fact)
     : QDialog(parent), m_makelink(fact)
 {
@@ -63,7 +65,7 @@
     tabWidget = new QTabWidget;
 
     buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
-				     | QDialogButtonBox::Cancel);
+                                     | QDialogButtonBox::Cancel);
 
     QVBoxLayout *mainLayout = new QVBoxLayout;
     mainLayout->setSpacing(spacing);
@@ -81,33 +83,33 @@
 void ConfTabsW::acceptChanges()
 {
     cerr << "ConfTabsW::acceptChanges()\n";
-    for (vector<ConfPanelW *>::iterator it = m_panels.begin(); 
-         it != m_panels.end(); it++) {
+    for (vector<ConfPanelW *>::iterator it = m_panels.begin();
+            it != m_panels.end(); it++) {
         (*it)->storeValues();
     }
-    for (vector<ConfPanelWIF *>::iterator it = m_widgets.begin(); 
-         it != m_widgets.end(); it++) {
+    for (vector<ConfPanelWIF *>::iterator it = m_widgets.begin();
+            it != m_widgets.end(); it++) {
         (*it)->storeValues();
     }
     emit sig_prefsChanged();
-    hide();
+    close();
 }
 
 void ConfTabsW::rejectChanges()
 {
     cerr << "ConfTabsW::rejectChanges()\n";
     reloadPanels();
-    hide();
+    close();
 }
 
 void ConfTabsW::reloadPanels()
 {
-    for (vector<ConfPanelW *>::iterator it = m_panels.begin(); 
-         it != m_panels.end(); it++) {
+    for (vector<ConfPanelW *>::iterator it = m_panels.begin();
+            it != m_panels.end(); it++) {
         (*it)->loadValues();
     }
-    for (vector<ConfPanelWIF *>::iterator it = m_widgets.begin(); 
-         it != m_widgets.end(); it++) {
+    for (vector<ConfPanelWIF *>::iterator it = m_widgets.begin();
+            it != m_widgets.end(); it++) {
         (*it)->loadValues();
     }
 }
@@ -130,43 +132,46 @@
     return tabWidget->addTab(qw, title);
 }
 
-ConfParamW *ConfTabsW::addParam(int tabindex,
-                             ParamType tp, const QString& varname,
-                             const QString& label, const QString& tooltip, 
-                             int ival, int maxval, 
-                             const QStringList* sl)
+ConfParamW *ConfTabsW::addParam(
+    int tabindex, ParamType tp, const QString& varname,
+    const QString& label, const QString& tooltip,
+    int ival, int maxval, const QStringList* sl)
 {
     ConfLink lnk = (*m_makelink)(varname);
 
     ConfPanelW *panel = (ConfPanelW*)tabWidget->widget(tabindex);
-    if (panel == 0) 
+    if (panel == 0) {
         return 0;
+    }
 
     ConfParamW *cp = 0;
     switch (tp) {
     case CFPT_BOOL:
-        cp = new ConfParamBoolW(this, lnk, label, tooltip);
+        cp = new ConfParamBoolW(varname, this, lnk, label, tooltip, ival);
         break;
-    case CFPT_INT: 
-	cp = new ConfParamIntW(this, lnk, label, tooltip, ival, maxval, 
-                               ival);
+    case CFPT_INT: {
+        size_t v = (size_t)sl;
+        int v1 = (v & 0xffffffff);
+        cp = new ConfParamIntW(varname, this, lnk, label, tooltip, ival,
+                               maxval, v1);
         break;
+    }
     case CFPT_STR:
-	cp = new ConfParamStrW(this, lnk, label, tooltip);
+        cp = new ConfParamStrW(varname, this, lnk, label, tooltip);
         break;
-    case CFPT_CSTR: 
-	cp = new ConfParamCStrW(this, lnk, label, tooltip, *sl);
+    case CFPT_CSTR:
+        cp = new ConfParamCStrW(varname, this, lnk, label, tooltip, *sl);
         break;
     case CFPT_FN:
-	cp = new ConfParamFNW(this, lnk, label, tooltip, ival);
+        cp = new ConfParamFNW(varname, this, lnk, label, tooltip, ival);
         break;
     case CFPT_STRL:
-	cp = new ConfParamSLW(this, lnk, label, tooltip);
-    case CFPT_DNL: 
-	cp = new ConfParamDNLW(this, lnk, label, tooltip);
+        cp = new ConfParamSLW(varname, this, lnk, label, tooltip);
+    case CFPT_DNL:
+        cp = new ConfParamDNLW(varname, this, lnk, label, tooltip);
         break;
     case CFPT_CSTRL:
-	cp = new ConfParamCSLW(this, lnk, label, tooltip, *sl);
+        cp = new ConfParamCSLW(varname, this, lnk, label, tooltip, *sl);
         break;
 
     }
@@ -175,6 +180,16 @@
     return cp;
 }
 
+ConfParamW *ConfTabsW::findParamW(const QString& varname)
+{
+    for (vector<ConfParamW *>::iterator it = m_params.begin();
+            it != m_params.end(); it++) {
+        if (!varname.compare((*it)->getVarName())) {
+            return *it;
+        }
+    }
+    return 0;
+}
 void ConfTabsW::endOfList(int tabindex)
 {
     ConfPanelW *panel = (ConfPanelW*)tabWidget->widget(tabindex);
@@ -186,7 +201,8 @@
 bool ConfTabsW::enableLink(ConfParamW* boolw, ConfParamW* otherw, bool revert)
 {
     if (std::find(m_params.begin(), m_params.end(), boolw) == m_params.end() ||
-        std::find(m_params.begin(), m_params.end(), otherw) == m_params.end()) {
+            std::find(m_params.begin(), m_params.end(), otherw) ==
+        m_params.end()) {
         cerr << "ConfTabsW::enableLink: param not found\n";
         return false;
     }
@@ -195,7 +211,7 @@
         cerr << "ConfTabsW::enableLink: not a boolw\n";
         return false;
     }
-    otherw->setEnabled(revert?!bw->m_cb->isChecked():bw->m_cb->isChecked());
+    otherw->setEnabled(revert ? !bw->m_cb->isChecked() : bw->m_cb->isChecked());
     if (revert) {
         connect(bw->m_cb, SIGNAL(toggled(bool)),
                 otherw, SLOT(setDisabled(bool)));
@@ -215,7 +231,7 @@
     m_vboxlayout->setContentsMargins(margin);
 }
 
-void ConfPanelW::addWidget(QWidget *w) 
+void ConfPanelW::addWidget(QWidget *w)
 {
     m_vboxlayout->addWidget(w);
     m_widgets.push_back(w);
@@ -228,8 +244,8 @@
 
 void ConfPanelW::storeValues()
 {
-    for (vector<QWidget *>::iterator it = m_widgets.begin(); 
-         it != m_widgets.end(); it++) {
+    for (vector<QWidget *>::iterator it = m_widgets.begin();
+            it != m_widgets.end(); it++) {
         ConfParamW *p = (ConfParamW*)*it;
         p->storeValue();
     }
@@ -237,192 +253,37 @@
 
 void ConfPanelW::loadValues()
 {
-    for (vector<QWidget *>::iterator it = m_widgets.begin(); 
-         it != m_widgets.end(); it++) {
+    for (vector<QWidget *>::iterator it = m_widgets.begin();
+            it != m_widgets.end(); it++) {
         ConfParamW *p = (ConfParamW*)*it;
         p->loadValue();
     }
 }
-
-static bool stringToBool(const string &s)
-{
-    if (s.empty())
-	return false;
-    if (isdigit(s[0])) {
-	int val = atoi(s.c_str());
-	return val ? true : false;
-    }
-    if (s.find_first_of("yYtT") == 0)
-	return true;
-    return false;
-}
-
-template <class T> bool stringToStrings(const string &s, T &tokens, 
-                                        const string& addseps)
-{
-    string current;
-    tokens.clear();
-    enum states {SPACE, TOKEN, INQUOTE, ESCAPE};
-    states state = SPACE;
-    for (unsigned int i = 0; i < s.length(); i++) {
-	switch (s[i]) {
-        case '"': 
-	    switch(state) {
-            case SPACE: 
-		state=INQUOTE; continue;
-            case TOKEN: 
-	        current += '"';
-		continue;
-            case INQUOTE: 
-                tokens.insert(tokens.end(), current);
-		current.clear();
-		state = SPACE;
-		continue;
-            case ESCAPE:
-	        current += '"';
-	        state = INQUOTE;
-                continue;
-	    }
-	    break;
-        case '\\': 
-	    switch(state) {
-            case SPACE: 
-            case TOKEN: 
-                current += '\\';
-                state=TOKEN; 
-                continue;
-            case INQUOTE: 
-                state = ESCAPE;
-                continue;
-            case ESCAPE:
-                current += '\\';
-                state = INQUOTE;
-                continue;
-	    }
-	    break;
-
-        case ' ': 
-        case '\t': 
-        case '\n': 
-        case '\r': 
-	    switch(state) {
-            case SPACE: 
-                continue;
-            case TOKEN: 
-		tokens.insert(tokens.end(), current);
-		current.clear();
-		state = SPACE;
-		continue;
-            case INQUOTE: 
-            case ESCAPE:
-                current += s[i];
-                continue;
-	    }
-	    break;
-
-        default:
-            if (!addseps.empty() && addseps.find(s[i]) != string::npos) {
-                switch(state) {
-                case ESCAPE:
-                    state = INQUOTE;
-                    break;
-                case INQUOTE: 
-                    break;
-                case SPACE: 
-                    tokens.insert(tokens.end(), string(1, s[i]));
-                    continue;
-                case TOKEN: 
-                    tokens.insert(tokens.end(), current);
-                    current.erase();
-                    tokens.insert(tokens.end(), string(1, s[i]));
-                    state = SPACE;
-                    continue;
-                }
-            } else switch(state) {
-                case ESCAPE:
-                    state = INQUOTE;
-                    break;
-                case SPACE: 
-                    state = TOKEN;
-                    break;
-                case TOKEN: 
-                case INQUOTE: 
-                    break;
-                }
-	    current += s[i];
-	}
-    }
-    switch(state) {
-    case SPACE: 
-	break;
-    case TOKEN: 
-	tokens.insert(tokens.end(), current);
-	break;
-    case INQUOTE: 
-    case ESCAPE:
-	return false;
-    }
-    return true;
-}
-
-template bool stringToStrings<vector<string> >(const string &, 
-					       vector<string> &, const string&);
-template <class T> void stringsToString(const T &tokens, string &s) 
-{
-    for (typename T::const_iterator it = tokens.begin();
-	 it != tokens.end(); it++) {
-	bool hasblanks = false;
-	if (it->find_first_of(" \t\n") != string::npos)
-	    hasblanks = true;
-	if (it != tokens.begin())
-	    s.append(1, ' ');
-	if (hasblanks)
-	    s.append(1, '"');
-	for (unsigned int i = 0; i < it->length(); i++) {
-	    char car = it->at(i);
-	    if (car == '"') {
-		s.append(1, '\\');
-		s.append(1, car);
-	    } else {
-		s.append(1, car);
-	    }
-	}
-	if (hasblanks)
-	    s.append(1, '"');
-    }
-}
-template void stringsToString<vector<string> >(const vector<string> &,string &);
-template <class T> string stringsToString(const T &tokens)
-{
-    string out;
-    stringsToString<T>(tokens, out);
-    return out;
-}
-template string stringsToString<vector<string> >(const vector<string> &);
-
 static QString myGetFileName(bool isdir, QString caption = QString(),
-			     bool filenosave = false);
+                             bool filenosave = false);
 
 static QString myGetFileName(bool isdir, QString caption, bool filenosave)
 {
     QFileDialog dialog(0, caption);
 
     if (isdir) {
-	dialog.setFileMode(QFileDialog::Directory);
-	dialog.setOptions(QFileDialog::ShowDirsOnly);
+        dialog.setFileMode(QFileDialog::Directory);
+        dialog.setOptions(QFileDialog::ShowDirsOnly);
     } else {
-	dialog.setFileMode(QFileDialog::AnyFile);
-	if (filenosave)
-	    dialog.setAcceptMode(QFileDialog::AcceptOpen);
-	else
-	    dialog.setAcceptMode(QFileDialog::AcceptSave);
+        dialog.setFileMode(QFileDialog::AnyFile);
+        if (filenosave) {
+            dialog.setAcceptMode(QFileDialog::AcceptOpen);
+        } else {
+            dialog.setAcceptMode(QFileDialog::AcceptSave);
+        }
     }
     dialog.setViewMode(QFileDialog::List);
-    QFlags<QDir::Filter> flags = QDir::NoDotAndDotDot | QDir::Hidden; 
-    if (isdir)
-	flags |= QDir::Dirs;
-    else 
-	flags |= QDir::Dirs | QDir::Files;
+    QFlags<QDir::Filter> flags = QDir::NoDotAndDotDot | QDir::Hidden;
+    if (isdir) {
+        flags |= QDir::Dirs;
+    } else {
+        flags |= QDir::Dirs | QDir::Files;
+    }
     dialog.setFilter(flags);
 
     if (dialog.exec() == QDialog::Accepted) {
@@ -433,10 +294,11 @@
 
 void ConfParamW::setValue(const QString& value)
 {
-    if (m_fsencoding)
+    if (m_fsencoding) {
         m_cflink->set(string((const char *)value.toLocal8Bit()));
-    else
+    } else {
         m_cflink->set(string((const char *)value.toUtf8()));
+    }
 }
 
 void ConfParamW::setValue(int value)
@@ -453,13 +315,13 @@
     m_cflink->set(string(buf));
 }
 
-extern void setSzPol(QWidget *w, QSizePolicy::Policy hpol, 
+extern void setSzPol(QWidget *w, QSizePolicy::Policy hpol,
                      QSizePolicy::Policy vpol,
                      int hstretch, int vstretch);
 
-void setSzPol(QWidget *w, QSizePolicy::Policy hpol, 
-		   QSizePolicy::Policy vpol,
-		   int hstretch, int vstretch)
+void setSzPol(QWidget *w, QSizePolicy::Policy hpol,
+              QSizePolicy::Policy vpol,
+              int hstretch, int vstretch)
 {
     QSizePolicy policy(hpol, vpol);
     policy.setHorizontalStretch(hstretch);
@@ -484,16 +346,15 @@
     return true;
 }
 
-ConfParamIntW::ConfParamIntW(QWidget *parent, ConfLink cflink, 
-			     const QString& lbltxt,
-			     const QString& tltptxt,
-			     int minvalue, 
-			     int maxvalue,
-                             int defaultvalue)
-    : ConfParamW(parent, cflink), m_defaultvalue(defaultvalue)
-{
-    if (!createCommon(lbltxt, tltptxt))
-	return;
+ConfParamIntW::ConfParamIntW(
+    const QString& varnm, QWidget *parent, ConfLink cflink,
+    const QString& lbltxt, const QString& tltptxt,
+    int minvalue, int maxvalue, int defaultvalue)
+    : ConfParamW(varnm, parent, cflink), m_defaultvalue(defaultvalue)
+{
+    if (!createCommon(lbltxt, tltptxt)) {
+        return;
+    }
 
     m_sb = new QSpinBox(this);
     m_sb->setMinimum(minvalue);
@@ -510,25 +371,29 @@
 
 void ConfParamIntW::storeValue()
 {
-    setValue(m_sb->value());
+    if (m_origvalue != m_sb->value()) {
+        setValue(m_sb->value());
+    }
 }
 
 void ConfParamIntW::loadValue()
 {
     string s;
-    if (m_cflink->get(s)) 
-        m_sb->setValue(atoi(s.c_str()));
-    else
-        m_sb->setValue(m_defaultvalue);
-}
-
-ConfParamStrW::ConfParamStrW(QWidget *parent, ConfLink cflink, 
-			     const QString& lbltxt,
-			     const QString& tltptxt)
-    : ConfParamW(parent, cflink)
-{
-    if (!createCommon(lbltxt, tltptxt))
-	return;
+    if (m_cflink->get(s)) {
+        m_sb->setValue(m_origvalue = atoi(s.c_str()));
+    } else {
+        m_sb->setValue(m_origvalue = m_defaultvalue);
+    }
+}
+
+ConfParamStrW::ConfParamStrW(
+    const QString& varnm, QWidget *parent, ConfLink cflink,
+    const QString& lbltxt, const QString& tltptxt)
+    : ConfParamW(varnm, parent, cflink)
+{
+    if (!createCommon(lbltxt, tltptxt)) {
+        return;
+    }
 
     m_le = new QLineEdit(this);
     setSzPol(m_le, QSizePolicy::Preferred, QSizePolicy::Fixed, 1, 0);
@@ -540,28 +405,30 @@
 
 void ConfParamStrW::storeValue()
 {
-    setValue(m_le->text());
+    if (m_origvalue.compare(m_le->text())) {
+        setValue(m_le->text());
+    }
 }
 
 void ConfParamStrW::loadValue()
 {
     string s;
     m_cflink->get(s);
-    if (m_fsencoding)
-        m_le->setText(QString::fromLocal8Bit(s.c_str()));
-    else
-        m_le->setText(QString::fromUtf8(s.c_str()));
-}
-
-ConfParamCStrW::ConfParamCStrW(QWidget *parent, ConfLink cflink, 
-			       const QString& lbltxt,
-			       const QString& tltptxt,
-			       const QStringList &sl
-			       )
-    : ConfParamW(parent, cflink)
-{
-    if (!createCommon(lbltxt, tltptxt))
-	return;
+    if (m_fsencoding) {
+        m_le->setText(m_origvalue = QString::fromLocal8Bit(s.c_str()));
+    } else {
+        m_le->setText(m_origvalue = QString::fromUtf8(s.c_str()));
+    }
+}
+
+ConfParamCStrW::ConfParamCStrW(
+    const QString& varnm, QWidget *parent, ConfLink cflink,
+    const QString& lbltxt, const QString& tltptxt, const QStringList& sl)
+    : ConfParamW(varnm, parent, cflink)
+{
+    if (!createCommon(lbltxt, tltptxt)) {
+        return;
+    }
     m_cmb = new QComboBox(this);
     m_cmb->setEditable(false);
     m_cmb->insertItems(0, sl);
@@ -573,9 +440,18 @@
     loadValue();
 }
 
+void ConfParamCStrW::setList(const QStringList& sl)
+{
+    m_cmb->clear();
+    m_cmb->insertItems(0, sl);
+    loadValue();
+}
+
 void ConfParamCStrW::storeValue()
 {
-    setValue(m_cmb->currentText());
+    if (m_origvalue.compare(m_cmb->currentText())) {
+        setValue(m_cmb->currentText());
+    }
 }
 
 void ConfParamCStrW::loadValue()
@@ -583,23 +459,25 @@
     string s;
     m_cflink->get(s);
     QString cs;
-    if (m_fsencoding)
+    if (m_fsencoding) {
         cs = QString::fromLocal8Bit(s.c_str());
-    else
+    } else {
         cs = QString::fromUtf8(s.c_str());
-        
+    }
+
     for (int i = 0; i < m_cmb->count(); i++) {
-	if (!cs.compare(m_cmb->itemText(i))) {
-	    m_cmb->setCurrentIndex(i);
-	    break;
-	}
-    }
-}
-
-ConfParamBoolW::ConfParamBoolW(QWidget *parent, ConfLink cflink, 
-			       const QString& lbltxt,
-			       const QString& tltptxt)
-    : ConfParamW(parent, cflink)
+        if (!cs.compare(m_cmb->itemText(i))) {
+            m_cmb->setCurrentIndex(i);
+            break;
+        }
+    }
+    m_origvalue = m_cmb->currentText();
+}
+
+ConfParamBoolW::ConfParamBoolW(
+    const QString& varnm, QWidget *parent, ConfLink cflink,
+    const QString& lbltxt, const QString& tltptxt, bool deflt)
+    : ConfParamW(varnm, parent, cflink), m_dflt(deflt)
 {
     // No createCommon because the checkbox has a label
     m_hl = new QHBoxLayout(this);
@@ -620,35 +498,40 @@
 
 void ConfParamBoolW::storeValue()
 {
-    setValue(m_cb->isChecked());
+    if (m_origvalue != m_cb->isChecked()) {
+        setValue(m_cb->isChecked());
+    }
 }
 
 void ConfParamBoolW::loadValue()
 {
     string s;
-    m_cflink->get(s);
-    m_cb->setChecked(stringToBool(s));
-}
-
-ConfParamFNW::ConfParamFNW(QWidget *parent, ConfLink cflink, 
-			   const QString& lbltxt,
-			   const QString& tltptxt,
-			   bool isdir
-			   )
-    : ConfParamW(parent, cflink), m_isdir(isdir)
-{
-    if (!createCommon(lbltxt, tltptxt))
-	return;
+    if (!m_cflink->get(s)) {
+        m_origvalue = m_dflt;
+    } else {
+        m_origvalue = stringToBool(s);
+    }
+    m_cb->setChecked(m_origvalue);
+}
+
+ConfParamFNW::ConfParamFNW(
+    const QString& varnm, QWidget *parent, ConfLink cflink,
+    const QString& lbltxt, const QString& tltptxt, bool isdir)
+    : ConfParamW(varnm, parent, cflink), m_isdir(isdir)
+{
+    if (!createCommon(lbltxt, tltptxt)) {
+        return;
+    }
 
     m_fsencoding = true;
 
     m_le = new QLineEdit(this);
-    m_le->setMinimumSize(QSize(150, 0 ));
+    m_le->setMinimumSize(QSize(150, 0));
     setSzPol(m_le, QSizePolicy::Preferred, QSizePolicy::Fixed, 1, 0);
     m_hl->addWidget(m_le);
 
     m_pb = new QPushButton(this);
-    
+
     QString text = tr("Choose");
     m_pb->setText(text);
     int width = m_pb->fontMetrics().boundingRect(text).width() + 15;
@@ -662,35 +545,39 @@
 
 void ConfParamFNW::storeValue()
 {
-    setValue(m_le->text());
+    if (m_origvalue.compare(m_le->text())) {
+        setValue(m_le->text());
+    }
 }
 
 void ConfParamFNW::loadValue()
 {
     string s;
     m_cflink->get(s);
-    m_le->setText(QString::fromLocal8Bit(s.c_str()));
+    m_le->setText(m_origvalue = QString::fromLocal8Bit(s.c_str()));
 }
 
 void ConfParamFNW::showBrowserDialog()
 {
     QString s = myGetFileName(m_isdir);
-    if (!s.isEmpty())
+    if (!s.isEmpty()) {
         m_le->setText(s);
-}
-
-class SmallerListWidget: public QListWidget 
-{
+    }
+}
+
+class SmallerListWidget: public QListWidget {
 public:
     SmallerListWidget(QWidget *parent)
-	: QListWidget(parent) {}
-    virtual QSize sizeHint() const {return QSize(150, 40);}
+        : QListWidget(parent) {}
+    virtual QSize sizeHint() const {
+        return QSize(150, 40);
+    }
 };
 
-ConfParamSLW::ConfParamSLW(QWidget *parent, ConfLink cflink, 
-			   const QString& lbltxt,
-			   const QString& tltptxt)
-    : ConfParamW(parent, cflink)
+ConfParamSLW::ConfParamSLW(
+    const QString& varnm, QWidget *parent, ConfLink cflink,
+    const QString& lbltxt, const QString& tltptxt)
+    : ConfParamW(varnm, parent, cflink)
 {
     // Can't use createCommon here cause we want the buttons below the label
     m_hl = new QHBoxLayout(this);
@@ -747,29 +634,33 @@
         // General parameters are encoded as utf-8. File names as
         // local8bit There is no hope for 8bit file names anyway
         // except for luck: the original encoding is unknown.
-	QString text = m_lb->item(i)->text();
-        if (m_fsencoding)
+        QString text = m_lb->item(i)->text();
+        if (m_fsencoding) {
             ls.push_back((const char *)(text.toLocal8Bit()));
-        else
+        } else {
             ls.push_back((const char *)(text.toUtf8()));
+        }
     }
     string s;
     stringsToString(ls, s);
-    m_cflink->set(s);
+    if (s.compare(m_origvalue)) {
+        m_cflink->set(s);
+    }
 }
 
 void ConfParamSLW::loadValue()
 {
-    string s;
-    m_cflink->get(s);
-    vector<string> ls; 
-    stringToStrings(s, ls);
+    m_origvalue.clear();
+    m_cflink->get(m_origvalue);
+    vector<string> ls;
+    stringToStrings(m_origvalue, ls);
     QStringList qls;
     for (vector<string>::const_iterator it = ls.begin(); it != ls.end(); it++) {
-        if (m_fsencoding)
+        if (m_fsencoding) {
             qls.push_back(QString::fromLocal8Bit(it->c_str()));
-        else
+        } else {
             qls.push_back(QString::fromUtf8(it->c_str()));
+        }
     }
     m_lb->clear();
     m_lb->insertItems(0, qls);
@@ -778,20 +669,20 @@
 void ConfParamSLW::showInputDialog()
 {
     bool ok;
-    QString s = QInputDialog::getText (this, 
-				       "", // title 
-				       "", // label, 
-				       QLineEdit::Normal, // EchoMode mode
-				       "", // const QString & text 
-				       &ok);
+    QString s = QInputDialog::getText(this,
+                                      "", // title
+                                      "", // label,
+                                      QLineEdit::Normal, // EchoMode mode
+                                      "", // const QString & text
+                                      &ok);
 
     if (ok && !s.isEmpty()) {
-	QList<QListWidgetItem *>items = 
-	    m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive);
-	if (items.empty()) {
-	    m_lb->insertItem(0, s);
-	    m_lb->sortItems();
-	}
+        QList<QListWidgetItem *>items =
+            m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive);
+        if (items.empty()) {
+            m_lb->insertItem(0, s);
+            m_lb->sortItems();
+        }
     }
 }
 
@@ -809,15 +700,15 @@
 
     vector<int> idxes;
     for (int i = 0; i < m_lb->count(); i++) {
-	if (m_lb->item(i)->isSelected()) {
-	    idxes.push_back(i);
-	}
-    }
-    for (vector<int>::reverse_iterator it = idxes.rbegin(); 
-	 it != idxes.rend(); it++) {
-	QListWidgetItem *item = m_lb->takeItem(*it);
-	emit entryDeleted(item->text());
-	delete item;
+        if (m_lb->item(i)->isSelected()) {
+            idxes.push_back(i);
+        }
+    }
+    for (vector<int>::reverse_iterator it = idxes.rbegin();
+            it != idxes.rend(); it++) {
+        QListWidgetItem *item = m_lb->takeItem(*it);
+        emit entryDeleted(item->text());
+        delete item;
     }
 }
 
@@ -826,17 +717,18 @@
 {
     QString s = myGetFileName(true);
     if (!s.isEmpty()) {
-	QList<QListWidgetItem *>items = 
-	    m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive);
-	if (items.empty()) {
-	    m_lb->insertItem(0, s);
-	    m_lb->sortItems();
-	    QList<QListWidgetItem *>items = 
-		m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive);
-	    if (m_lb->selectionMode() == QAbstractItemView::SingleSelection && 
-		!items.empty())
-		m_lb->setCurrentItem(*items.begin());
-	}
+        QList<QListWidgetItem *>items =
+            m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive);
+        if (items.empty()) {
+            m_lb->insertItem(0, s);
+            m_lb->sortItems();
+            QList<QListWidgetItem *>items =
+                m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive);
+            if (m_lb->selectionMode() == QAbstractItemView::SingleSelection &&
+                    !items.empty()) {
+                m_lb->setCurrentItem(*items.begin());
+            }
+        }
     }
 }
 
@@ -844,22 +736,234 @@
 void ConfParamCSLW::showInputDialog()
 {
     bool ok;
-    QString s = QInputDialog::getItem (this, // parent
-				       "", // title 
-				       "", // label, 
-				       m_sl, // items, 
-				       0, // current = 0
-				       false, // editable = true, 
-				       &ok);
+    QString s = QInputDialog::getItem(this,  // parent
+                                      "", // title
+                                      "", // label,
+                                      m_sl, // items,
+                                      0, // current = 0
+                                      false, // editable = true,
+                                      &ok);
 
     if (ok && !s.isEmpty()) {
-	QList<QListWidgetItem *>items = 
-	    m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive);
-	if (items.empty()) {
-	    m_lb->insertItem(0, s);
-	    m_lb->sortItems();
-	}
-    }
-}
+        QList<QListWidgetItem *>items =
+            m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive);
+        if (items.empty()) {
+            m_lb->insertItem(0, s);
+            m_lb->sortItems();
+        }
+    }
+}
+
+
+
+
+#ifdef ENABLE_XMLCONF
+
+#include "picoxml.h"
+
+static QString u8s2qs(const std::string us)
+{
+    return QString::fromUtf8(us.c_str());
+}
+
+static const string& mapfind(const string& nm, const map<string, string>& mp)
+{
+    static string strnull;
+    map<string, string>::const_iterator it;
+    it = mp.find(nm);
+    if (it == mp.end()) {
+        return strnull;
+    }
+    return it->second;
+}
+
+static string looksLikeAssign(const string& data)
+{
+    //LOGDEB("looksLikeAssign. data: [" << data << "]");
+    vector<string> toks;
+    stringToTokens(data, toks, "\n\r\t ");
+    if (toks.size() >= 2 && !toks[1].compare("=")) {
+        return toks[0];
+    }
+    return string();
+}
+
+ConfTabsW *xmlToConfGUI(const string& xml, string& toptext,
+                        ConfLinkFact* lnkf, QWidget *parent)
+{
+    //LOGDEB("xmlToConfGUI: [" << xml << "]");
+
+    class XMLToConfGUI : public PicoXMLParser {
+    public:
+        XMLToConfGUI(const string& x, ConfLinkFact *lnkf, QWidget *parent)
+            : PicoXMLParser(x), m_lnkfact(lnkf), m_parent(parent),
+              m_idx(0), m_hadTitle(false), m_hadGroup(false) {
+        }
+        virtual ~XMLToConfGUI() {}
+
+        virtual void startElement(const string& tagname,
+                                  const map<string, string>& attrs) {
+            if (!tagname.compare("var")) {
+                m_curvar = mapfind("name", attrs);
+                m_curvartp = mapfind("type", attrs);
+                m_curvarvals = mapfind("values", attrs);
+                //LOGDEB("Curvar: " << m_curvar);
+                if (m_curvar.empty() || m_curvartp.empty()) {
+                    throw std::runtime_error(
+                        "<var> with no name attribute or no type ! nm [" +
+                        m_curvar + "] tp [" + m_curvartp + "]");
+                } else {
+                    m_brief.clear();
+                    m_descr.clear();
+                }
+            } else if (!tagname.compare("filetitle") ||
+                       !tagname.compare("grouptitle")) {
+                m_other.clear();
+            }
+        }
+
+        virtual void endElement(const string& tagname) {
+            if (!tagname.compare("var")) {
+                if (!m_hadTitle) {
+                    m_w = new ConfTabsW(m_parent, "Teh title", m_lnkfact);
+                    m_hadTitle = true;
+                }
+                if (!m_hadGroup) {
+                    m_idx = m_w->addPanel("Group title");
+                    m_hadGroup = true;
+                }
+                ConfTabsW::ParamType paramtype;
+                if (!m_curvartp.compare("bool")) {
+                    paramtype = ConfTabsW::CFPT_BOOL;
+                } else if (!m_curvartp.compare("int")) {
+                    paramtype = ConfTabsW::CFPT_INT;
+                } else if (!m_curvartp.compare("string")) {
+                    paramtype = ConfTabsW::CFPT_STR;
+                } else if (!m_curvartp.compare("cstr")) {
+                    paramtype = ConfTabsW::CFPT_CSTR;
+                } else if (!m_curvartp.compare("cstrl")) {
+                    paramtype = ConfTabsW::CFPT_CSTRL;
+                } else if (!m_curvartp.compare("fn")) {
+                    paramtype = ConfTabsW::CFPT_FN;
+                } else if (!m_curvartp.compare("dfn")) {
+                    paramtype = ConfTabsW::CFPT_FN;
+                } else if (!m_curvartp.compare("strl")) {
+                    paramtype = ConfTabsW::CFPT_STRL;
+                } else if (!m_curvartp.compare("dnl")) {
+                    paramtype = ConfTabsW::CFPT_DNL;
+                } else {
+                    throw std::runtime_error("Bad type " + m_curvartp +
+                                             " for " + m_curvar);
+                }
+
+                switch (paramtype) {
+                case ConfTabsW::CFPT_BOOL: {
+                    int def = atoi(m_curvarvals.c_str());
+                    m_w->addParam(m_idx, paramtype, u8s2qs(m_curvar),
+                                  u8s2qs(m_brief), u8s2qs(m_descr), def);
+                    break;
+                }
+                case ConfTabsW::CFPT_INT: {
+                    vector<string> vals;
+                    stringToTokens(m_curvarvals, vals);
+                    int min = 0, max = 0, def = 0;
+                    if (vals.size() >= 3) {
+                        min = atoi(vals[0].c_str());
+                        max = atoi(vals[1].c_str());
+                        def = atoi(vals[2].c_str());
+                    }
+                    QStringList *sldef = 0;
+                    sldef = (QStringList*)(((char*)sldef) + def);
+                    m_w->addParam(m_idx, paramtype, u8s2qs(m_curvar),
+                                  u8s2qs(m_brief), u8s2qs(m_descr),
+                                  min, max, sldef);
+                    break;
+                }
+                case  ConfTabsW::CFPT_CSTR:
+                case ConfTabsW::CFPT_CSTRL: {
+                    vector<string> cstrl;
+                    stringToTokens(neutchars(m_curvarvals, "\n\r"), cstrl);
+                    QStringList qstrl;
+                    for (unsigned int i = 0; i < cstrl.size(); i++) {
+                        qstrl.push_back(u8s2qs(cstrl[i]));
+                    }
+                    m_w->addParam(m_idx, paramtype, u8s2qs(m_curvar),
+                                  u8s2qs(m_brief), u8s2qs(m_descr),
+                                  0, 0, &qstrl);
+                    break;
+                }
+                default:
+                    m_w->addParam(m_idx, paramtype, u8s2qs(m_curvar),
+                                  u8s2qs(m_brief), u8s2qs(m_descr));
+                }
+            } else if (!tagname.compare("filetitle")) {
+                m_w = new ConfTabsW(m_parent, u8s2qs(m_other), m_lnkfact);
+                m_hadTitle = true;
+                m_other.clear();
+            } else if (!tagname.compare("grouptitle")) {
+                if (!m_hadTitle) {
+                    m_w = new ConfTabsW(m_parent, "Teh title", m_lnkfact);
+                    m_hadTitle = true;
+                }
+                m_idx = m_w->addPanel(u8s2qs(m_other));
+                m_hadGroup = true;
+                m_other.clear();
+            } else if (!tagname.compare("descr")) {
+            } else if (!tagname.compare("brief")) {
+                m_brief = neutchars(m_brief, "\n\r");
+            }
+        }
+
+        virtual void characterData(const string& data) {
+            if (!tagStack().back().compare("brief")) {
+                m_brief += data;
+            } else if (!tagStack().back().compare("descr")) {
+                m_descr += data;
+            } else if (!tagStack().back().compare("filetitle") ||
+                       !tagStack().back().compare("grouptitle")) {
+                // We don't want \n in there
+                m_other += neutchars(data, "\n\r");
+                m_other += " ";
+            } else if (!tagStack().back().compare("confcomments")) {
+                string nvarname = looksLikeAssign(data);
+                if (!nvarname.empty() && nvarname.compare(m_curvar)) {
+                    cerr << "Var assigned [" << nvarname << "] mismatch "
+                         "with current variable [" << m_curvar << "]\n";
+                }
+                m_toptext += data;
+            }
+        }
+
+        ConfTabsW *m_w;
+
+        ConfLinkFact *m_lnkfact;
+        QWidget *m_parent;
+        int m_idx;
+        string m_curvar;
+        string m_curvartp;
+        string m_curvarvals;
+        string m_brief;
+        string m_descr;
+        string m_other;
+        string m_toptext;
+        bool m_hadTitle;
+        bool m_hadGroup;
+    };
+
+    XMLToConfGUI parser(xml, lnkf, parent);
+    try {
+        if (!parser.parse()) {
+            cerr << "Parse failed: " << parser.getReason() << endl;
+            return 0;
+        }
+    } catch (const std::runtime_error& e) {
+        cerr << e.what() << endl;
+        return 0;
+    }
+    toptext = parser.m_toptext;
+    return parser.m_w;
+}
+
+#endif /* ENABLE_XMLCONF */
 
 } // Namespace confgui
GUI/prefs/confgui.h to utils/confgui.h
--- a/GUI/prefs/confgui.h
+++ b/utils/confgui.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007 J.F.Dockes
+/* Copyright (C) 2007-2016 J.F.Dockes
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
  *   the Free Software Foundation; either version 2 of the License, or
@@ -17,23 +17,23 @@
 #ifndef _confgui_h_included_
 #define _confgui_h_included_
 /**
- * This file defines a number of simple classes (virtual base: ConfParamW) 
- * which let the user input configuration parameters. 
- *
- * Subclasses are defined for entering different kind of data, ie a string, 
+ * This file defines a number of simple classes (virtual base: ConfParamW)
+ * which let the user input configuration parameters.
+ *
+ * Subclasses are defined for entering different kind of data, ie a string,
  * a file name, an integer, etc.
  *
  * Each configuration gui object is linked to the configuration data through
  * a "link" object which knows the details of interacting with the actual
- * configuration data, like the parameter name, the actual config object, 
+ * configuration data, like the parameter name, the actual config object,
  * the method to call etc.
- * 
- * The link object is set when the input widget is created and cannot be 
+ *
+ * The link object is set when the input widget is created and cannot be
  * changed.
  *
  * The widgets are typically linked to a temporary configuration object, which
  * is then copied to the actual configuration if the data is accepted, or
- * destroyed and recreated as a copy if Cancel is pressed (you have to 
+ * destroyed and recreated as a copy if Cancel is pressed (you have to
  * delete/recreate the widgets in this case as the links are no longer valid).
  */
 
@@ -86,7 +86,7 @@
 };
 
 /** The top level widget has tabs, each tab/panel has multiple widgets
- * for setting parameter values 
+ * for setting parameter values
  */
 class ConfPanelW;
 class ConfParamW;
@@ -97,7 +97,8 @@
     ConfTabsW(QWidget *parent, const QString& title, ConfLinkFact *linkfact);
 
     enum ParamType {CFPT_BOOL, CFPT_INT, CFPT_STR, CFPT_CSTR, CFPT_FN,
-                    CFPT_STRL, CFPT_DNL, CFPT_CSTRL};
+                    CFPT_STRL, CFPT_DNL, CFPT_CSTRL
+                   };
 
     /** Add tab and return its identifier / index */
     int addPanel(const QString& title);
@@ -107,19 +108,20 @@
     int addForeignPanel(ConfPanelWIF* w, const QString& title);
 
     /** Add parameter setter to specified tab */
-    ConfParamW *addParam(int tabindex, ParamType tp, 
+    ConfParamW *addParam(int tabindex, ParamType tp,
                          const QString& varname, const QString& label,
-                         const QString& tooltip, int isdirorminval = 0, 
+                         const QString& tooltip, int isdirorminval = 0,
                          int maxval = 0, const QStringList* sl = 0);
     bool enableLink(ConfParamW* boolw, ConfParamW* otherw, bool revert = false);
     void endOfList(int tabindex);
-                                                
+    ConfParamW *findParamW(const QString& varname);
+                                                 
 public slots:
     void acceptChanges();
     void rejectChanges();
     void reloadPanels();
 
-signals: 
+signals:
     void sig_prefsChanged();
 
 private:
@@ -141,7 +143,7 @@
     Q_OBJECT
 public:
     ConfPanelW(QWidget *parent);
-    void addWidget (QWidget *w);
+    void addWidget(QWidget *w);
     void storeValues();
     void loadValues();
     void endOfList();
@@ -155,21 +157,24 @@
  */
 class ConfParamW : public QWidget {
     Q_OBJECT
-
-public:
-    ConfParamW(QWidget *parent, ConfLink cflink)
-        : QWidget(parent), m_cflink(cflink), m_fsencoding(false) {
+public:
+    ConfParamW(const QString& varnm, QWidget *parent, ConfLink cflink)
+        : QWidget(parent), m_varname(varnm),
+          m_cflink(cflink), m_fsencoding(false) {
     }
     virtual void loadValue() = 0;
     virtual void setFsEncoding(bool onoff) {
         m_fsencoding = onoff;
     }
-
+    const QString& getVarName() {
+        return m_varname;
+    }
 public slots:
     virtual void setEnabled(bool) = 0;
     virtual void storeValue() = 0;
 
 protected:
+    QString      m_varname;
     ConfLink     m_cflink;
     QHBoxLayout *m_hl;
     // File names are encoded as local8bit in the config files. Other
@@ -186,84 +191,96 @@
 /**  Boolean */
 class ConfParamBoolW : public ConfParamW {
     Q_OBJECT
-    public:
-    ConfParamBoolW(QWidget *parent, ConfLink cflink, 
+public:
+    ConfParamBoolW(const QString& varnm, QWidget *parent, ConfLink cflink,
                    const QString& lbltxt,
-                   const QString& tltptxt);
-    virtual void loadValue();
-    virtual void storeValue();
-public slots:
-    virtual void setEnabled(bool i) {
-        if(m_cb) 
+                   const QString& tltptxt, bool deflt = false);
+    virtual void loadValue();
+    virtual void storeValue();
+public slots:
+    virtual void setEnabled(bool i) {
+        if (m_cb) {
             ((QWidget*)m_cb)->setEnabled(i);
+        }
     }
 public:
     QCheckBox *m_cb;
+    bool m_dflt;
+    bool m_origvalue;
 };
 
 // Int
 class ConfParamIntW : public ConfParamW {
     Q_OBJECT
-    public:
+public:
     // The default value is only used if none exists in the sample
     // configuration file. Defaults are normally set in there.
-    ConfParamIntW(QWidget *parent, ConfLink cflink, 
+    ConfParamIntW(const QString& varnm, QWidget *parent, ConfLink cflink,
                   const QString& lbltxt,
                   const QString& tltptxt,
-                  int minvalue = INT_MIN, 
+                  int minvalue = INT_MIN,
                   int maxvalue = INT_MAX,
                   int defaultvalue = 0);
     virtual void loadValue();
     virtual void storeValue();
 public slots:
     virtual void setEnabled(bool i) {
-        if(m_sb) 
+        if (m_sb) {
             ((QWidget*)m_sb)->setEnabled(i);
+        }
     }
 protected:
     QSpinBox *m_sb;
     int       m_defaultvalue;
+    int       m_origvalue;
 };
 
 // Arbitrary string
 class ConfParamStrW : public ConfParamW {
     Q_OBJECT
-    public:
-    ConfParamStrW(QWidget *parent, ConfLink cflink, 
+public:
+    ConfParamStrW(const QString& varnm, QWidget *parent, ConfLink cflink,
                   const QString& lbltxt,
                   const QString& tltptxt);
     virtual void loadValue();
     virtual void storeValue();
 public slots:
     virtual void setEnabled(bool i) {
-        if (m_le) ((QWidget*)m_le)->setEnabled(i);
+        if (m_le) {
+            ((QWidget*)m_le)->setEnabled(i);
+        }
     }
 protected:
     QLineEdit *m_le;
+    QString m_origvalue;
 };
 
 // Constrained string: choose from list
 class ConfParamCStrW : public ConfParamW {
     Q_OBJECT
-    public:
-    ConfParamCStrW(QWidget *parent, ConfLink cflink, 
+public:
+    ConfParamCStrW(const QString& varnm, QWidget *parent, ConfLink cflink,
                    const QString& lbltxt,
                    const QString& tltptxt, const QStringList& sl);
     virtual void loadValue();
     virtual void storeValue();
-public slots:
-    virtual void setEnabled(bool i) {
-        if (m_cmb) ((QWidget*)m_cmb)->setEnabled(i);
+    virtual void setList(const QStringList& sl);
+public slots:
+    virtual void setEnabled(bool i) {
+        if (m_cmb) {
+            ((QWidget*)m_cmb)->setEnabled(i);
+        }
     }
 protected:
     QComboBox *m_cmb;
+    QString m_origvalue;
 };
 
 // File name
 class ConfParamFNW : public ConfParamW {
     Q_OBJECT
-    public:
-    ConfParamFNW(QWidget *parent, ConfLink cflink, 
+public:
+    ConfParamFNW(const QString& varnm, QWidget *parent, ConfLink cflink,
                  const QString& lbltxt,
                  const QString& tltptxt, bool isdir = false);
     virtual void loadValue();
@@ -272,30 +289,38 @@
     void showBrowserDialog();
 public slots:
     virtual void setEnabled(bool i) {
-        if(m_le) ((QWidget*)m_le)->setEnabled(i);
-        if(m_pb) ((QWidget*)m_pb)->setEnabled(i);
+        if (m_le) {
+            ((QWidget*)m_le)->setEnabled(i);
+        }
+        if (m_pb) {
+            ((QWidget*)m_pb)->setEnabled(i);
+        }
     }
 protected:
     QLineEdit *m_le;
     QPushButton *m_pb;
     bool       m_isdir;
+    QString m_origvalue;
 };
 
 // String list
 class ConfParamSLW : public ConfParamW {
     Q_OBJECT
-    public:
-    ConfParamSLW(QWidget *parent, ConfLink cflink, 
+public:
+    ConfParamSLW(const QString& varnm, QWidget *parent, ConfLink cflink,
                  const QString& lbltxt,
                  const QString& tltptxt);
     virtual void loadValue();
     virtual void storeValue();
-    QListWidget *getListBox() {return m_lb;}
-	
-public slots:
-    virtual void setEnabled(bool i) {
-        if (m_lb) 
+    QListWidget *getListBox() {
+        return m_lb;
+    }
+
+public slots:
+    virtual void setEnabled(bool i) {
+        if (m_lb) {
             ((QWidget*)m_lb)->setEnabled(i);
+        }
     }
 protected slots:
     virtual void showInputDialog();
@@ -305,16 +330,17 @@
 protected:
     QListWidget *m_lb;
     void listToConf();
+    std::string m_origvalue;
 };
 
 // Dir name list
 class ConfParamDNLW : public ConfParamSLW {
     Q_OBJECT
-    public:
-    ConfParamDNLW(QWidget *parent, ConfLink cflink, 
+public:
+    ConfParamDNLW(const QString& varnm, QWidget *parent, ConfLink cflink,
                   const QString& lbltxt,
                   const QString& tltptxt)
-        : ConfParamSLW(parent, cflink, lbltxt, tltptxt) {
+        : ConfParamSLW(varnm, parent, cflink, lbltxt, tltptxt) {
         m_fsencoding = true;
     }
 protected slots:
@@ -324,12 +350,12 @@
 // Constrained string list (chose from predefined)
 class ConfParamCSLW : public ConfParamSLW {
     Q_OBJECT
-    public:
-    ConfParamCSLW(QWidget *parent, ConfLink cflink, 
+public:
+    ConfParamCSLW(const QString& varnm, QWidget *parent, ConfLink cflink,
                   const QString& lbltxt,
                   const QString& tltptxt,
                   const QStringList& sl)
-        : ConfParamSLW(parent, cflink, lbltxt, tltptxt), m_sl(sl) {
+        : ConfParamSLW(varnm, parent, cflink, lbltxt, tltptxt), m_sl(sl) {
     }
 protected slots:
     virtual void showInputDialog();
@@ -337,10 +363,51 @@
     const QStringList m_sl;
 };
 
-// Expose some utilities in namespace confgui
-    template <class T> bool stringToStrings(const std::string &s, T &tokens, 
-                                            const std::string& addseps = "");
-    template <class T> void stringsToString(const T &tokens, std::string &s);
+#ifdef ENABLE_XMLCONF
+/**
+ * Interpret an XML string and create a configuration interface. XML sample:
+ *
+ * <confcomments>
+ *   <filetitle>Configuration file parameters for upmpdcli</filetitle>
+ *   <grouptitle>MPD parameters</grouptitle>
+ *   <var name="mpdhost" type="string">
+ *     <brief>Host MPD runs on.</brief>
+ *     <descr>Defaults to localhost. This can also be specified as -h</descr>
+ *   </var>
+ *   <var name="mpdport" type="int" values="0 65635 6600">
+ *     <brief>IP port used by MPD</brief>. 
+ *     <descr>Can also be specified as -p port. Defaults to the...</descr>
+ *   </var>
+ *   <var name="ownqueue" type="bool" values="1">
+ *     <brief>Set if we own the MPD queue.</brief>
+ *     <descr>If this is set (on by default), we own the MPD...</descr>
+ *   </var>
+ * </confcomments>
+ *
+ * <grouptitle> creates a panel in which the following <var> are set.
+ * The <var> attributes should be self-explanatory. "values"
+ * is used for different things depending on the var type
+ * (min/max, default, str list). Check the code about this. 
+ * type values: "bool" "int" "string" "cstr" "cstrl" "fn" "dfn" "strl" "dnl"
+ *
+ * The XML would typically exist as comments inside a reference configuration
+ * file (ConfSimple can extract such comments).
+ *
+ * This means that the reference configuration file can generate both
+ * the documentation and the GUI interface.
+ * 
+ * @param xml the input xml
+ * @param toptxt on output: the top level text. This will be evaluated
+ *   as a config for default values.
+ * @lnkf factory to create the objects which link the GUI to the
+ *   storage mechanism.
+ */
+extern ConfTabsW *xmlToConfGUI(const std::string& xml,
+                               std::string& toptxt,
+                               ConfLinkFact* lnkf,
+                               QWidget *parent);
+#endif
+
 }
 
 #endif /* _confgui_h_included_ */