From 9e51ed8613f04b2f93696beb000b4dc3a8c97253 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Sun, 22 Sep 2019 09:23:17 +0200 Subject: [PATCH] Converted the index preferences to use the shared confgui code --- src/qtgui/confgui/confgui.cpp | 837 +++++++++++++++++++++++------ src/qtgui/confgui/confgui.h | 600 ++++++++++++++------- src/qtgui/confgui/confguiindex.cpp | 648 ++++++++++------------ src/qtgui/confgui/confguiindex.h | 81 ++- src/qtgui/rclm_wins.cpp | 17 +- src/qtgui/rclmain_w.h | 9 +- 6 files changed, 1380 insertions(+), 812 deletions(-) diff --git a/src/qtgui/confgui/confgui.cpp b/src/qtgui/confgui/confgui.cpp index e8227dd3..f2e7798f 100644 --- a/src/qtgui/confgui/confgui.cpp +++ b/src/qtgui/confgui/confgui.cpp @@ -1,29 +1,38 @@ -/* 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 + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "confgui.h" + #include #include +#include +#include +#include #include #include #include +#include +#include #include #include - +#include +#include +#include #include #include #include @@ -38,31 +47,273 @@ #include #include -#include "confgui.h" #include "smallut.h" -#include "log.h" -#include "rcldb.h" -#include "guiutils.h" -#include -#include -using std::list; -using std::vector; +#ifdef ENABLE_XMLCONF +#include "picoxml.h" +#endif + +using namespace std; namespace confgui { -static const int spacing = 2; -static const int margin = 2; +static const int spacing = 3; +// left,top,right, bottom +static QMargins margin(4,3,4,3); + +ConfTabsW::ConfTabsW(QWidget *parent, const QString& title, + ConfLinkFact *fact) + : QDialog(parent), m_makelink(fact) +{ + setWindowTitle(title); + tabWidget = new QTabWidget; + + buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok + | QDialogButtonBox::Cancel); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->setSpacing(spacing); + mainLayout->setContentsMargins(margin); + mainLayout->addWidget(tabWidget); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + resize(QSize(500, 400).expandedTo(minimumSizeHint())); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(acceptChanges())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(rejectChanges())); +} + +void ConfTabsW::hideButtons() +{ + if (buttonBox) + buttonBox->hide(); +} + +void ConfTabsW::acceptChanges() +{ + cerr << "ConfTabsW::acceptChanges()\n"; + for (auto& entry : m_panels) { + entry->storeValues(); + } + for (auto& entry : m_widgets) { + entry->storeValues(); + } + emit sig_prefsChanged(); + if (!buttonBox->isHidden()) + close(); +} + +void ConfTabsW::rejectChanges() +{ + cerr << "ConfTabsW::rejectChanges()\n"; + reloadPanels(); + if (!buttonBox->isHidden()) + close(); +} + +void ConfTabsW::reloadPanels() +{ + for (auto& entry : m_panels) { + entry->loadValues(); + } + for (auto& entry : m_widgets) { + entry->loadValues(); + } +} + +int ConfTabsW::addPanel(const QString& title) +{ + ConfPanelW *w = new ConfPanelW(this); + m_panels.push_back(w); + return tabWidget->addTab(w, title); +} + +int ConfTabsW::addForeignPanel(ConfPanelWIF* w, const QString& title) +{ + m_widgets.push_back(w); + QWidget *qw = dynamic_cast(w); + if (qw == 0) { + qDebug() << "Can't cast panel to QWidget"; + abort(); + } + return tabWidget->addTab(qw, title); +} + +void ConfTabsW::setCurrentIndex(int idx) +{ + if (tabWidget) { + tabWidget->setCurrentIndex(idx); + } +} + +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) { + return 0; + } + + ConfParamW *cp = 0; + switch (tp) { + case CFPT_BOOL: + cp = new ConfParamBoolW(varname, this, lnk, label, tooltip, ival); + break; + 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(varname, this, lnk, label, tooltip); + break; + case CFPT_CSTR: + cp = new ConfParamCStrW(varname, this, lnk, label, tooltip, *sl); + break; + case CFPT_FN: + cp = new ConfParamFNW(varname, this, lnk, label, tooltip, ival); + break; + case CFPT_STRL: + cp = new ConfParamSLW(varname, this, lnk, label, tooltip); + break; + case CFPT_DNL: + cp = new ConfParamDNLW(varname, this, lnk, label, tooltip); + break; + case CFPT_CSTRL: + cp = new ConfParamCSLW(varname, this, lnk, label, tooltip, *sl); + break; + } + panel->addWidget(cp); + m_params.push_back(cp); + return cp; +} + +ConfParamW *ConfTabsW::findParamW(const QString& varname) +{ + for (vector::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); + if (panel == 0) + return; + panel->endOfList(); +} + +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()) { + cerr << "ConfTabsW::enableLink: param not found\n"; + return false; + } + ConfParamBoolW *bw = dynamic_cast(boolw); + if (bw == 0) { + cerr << "ConfTabsW::enableLink: not a boolw\n"; + return false; + } + otherw->setEnabled(revert ? !bw->m_cb->isChecked() : bw->m_cb->isChecked()); + if (revert) { + connect(bw->m_cb, SIGNAL(toggled(bool)), + otherw, SLOT(setDisabled(bool))); + } else { + connect(bw->m_cb, SIGNAL(toggled(bool)), + otherw, SLOT(setEnabled(bool))); + } + return true; +} + +ConfPanelW::ConfPanelW(QWidget *parent) + : QWidget(parent) +{ + m_vboxlayout = new QVBoxLayout(this); + m_vboxlayout->setSpacing(spacing); + m_vboxlayout->setAlignment(Qt::AlignTop); + m_vboxlayout->setContentsMargins(margin); +} + +void ConfPanelW::addWidget(QWidget *w) +{ + m_vboxlayout->addWidget(w); + m_widgets.push_back(w); +} + +void ConfPanelW::endOfList() +{ + m_vboxlayout->addStretch(2); +} + +void ConfPanelW::storeValues() +{ + for (vector::iterator it = m_widgets.begin(); + it != m_widgets.end(); it++) { + ConfParamW *p = (ConfParamW*)*it; + p->storeValue(); + } +} + +void ConfPanelW::loadValues() +{ + for (vector::iterator it = m_widgets.begin(); + it != m_widgets.end(); it++) { + ConfParamW *p = (ConfParamW*)*it; + p->loadValue(); + } +} +static QString myGetFileName(bool isdir, QString caption = QString(), + 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); + } else { + dialog.setFileMode(QFileDialog::AnyFile); + if (filenosave) { + dialog.setAcceptMode(QFileDialog::AcceptOpen); + } else { + dialog.setAcceptMode(QFileDialog::AcceptSave); + } + } + dialog.setViewMode(QFileDialog::List); + QFlags flags = QDir::NoDotAndDotDot | QDir::Hidden; + if (isdir) { + flags |= QDir::Dirs; + } else { + flags |= QDir::Dirs | QDir::Files; + } + dialog.setFilter(flags); + + if (dialog.exec() == QDialog::Accepted) { + return dialog.selectedFiles().value(0); + } + return QString(); +} void ConfParamW::setValue(const QString& value) { -#ifndef _WIN32 - // On Windows all paths are unicode. - if (m_fsencoding) + if (m_fsencoding) { m_cflink->set(string((const char *)value.toLocal8Bit())); - else -#endif + } else { m_cflink->set(string((const char *)value.toUtf8())); + } } void ConfParamW::setValue(int value) @@ -71,6 +322,7 @@ void ConfParamW::setValue(int value) sprintf(buf, "%d", value); m_cflink->set(string(buf)); } + void ConfParamW::setValue(bool value) { char buf[30]; @@ -78,7 +330,11 @@ void ConfParamW::setValue(bool value) m_cflink->set(string(buf)); } -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) { @@ -93,6 +349,7 @@ bool ConfParamW::createCommon(const QString& lbltxt, const QString& tltptxt) { m_hl = new QHBoxLayout(this); m_hl->setSpacing(spacing); + m_hl->setContentsMargins(margin); QLabel *tl = new QLabel(this); setSzPol(tl, QSizePolicy::Preferred, QSizePolicy::Fixed, 0, 0); @@ -104,16 +361,15 @@ bool ConfParamW::createCommon(const QString& lbltxt, const QString& tltptxt) 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) +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)) + if (!createCommon(lbltxt, tltptxt)) { return; + } m_sb = new QSpinBox(this); m_sb->setMinimum(minvalue); @@ -126,26 +382,33 @@ ConfParamIntW::ConfParamIntW(QWidget *parent, ConfLink cflink, m_hl->addWidget(fr); loadValue(); - QObject::connect(m_sb, SIGNAL(valueChanged(int)), - this, SLOT(setValue(int))); +} + +void ConfParamIntW::storeValue() +{ + 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); + if (m_cflink->get(s)) { + m_sb->setValue(m_origvalue = atoi(s.c_str())); + } else { + m_sb->setValue(m_origvalue = m_defaultvalue); + } } -ConfParamStrW::ConfParamStrW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt) - : ConfParamW(parent, cflink) +ConfParamStrW::ConfParamStrW( + const QString& varnm, QWidget *parent, ConfLink cflink, + const QString& lbltxt, const QString& tltptxt) + : ConfParamW(varnm, parent, cflink) { - if (!createCommon(lbltxt, tltptxt)) + if (!createCommon(lbltxt, tltptxt)) { return; + } m_le = new QLineEdit(this); setSzPol(m_le, QSizePolicy::Preferred, QSizePolicy::Fixed, 1, 0); @@ -153,32 +416,34 @@ ConfParamStrW::ConfParamStrW(QWidget *parent, ConfLink cflink, m_hl->addWidget(m_le); loadValue(); - QObject::connect(m_le, SIGNAL(textChanged(const QString&)), - this, SLOT(setValue(const QString&))); +} + +void ConfParamStrW::storeValue() +{ + if (m_origvalue.compare(m_le->text())) { + setValue(m_le->text()); + } } void ConfParamStrW::loadValue() { string s; m_cflink->get(s); -#ifndef _WIN32 - // On Windows all paths are unicode. - if (m_fsencoding) - m_le->setText(QString::fromLocal8Bit(s.c_str())); - else -#endif - m_le->setText(QString::fromUtf8(s.c_str())); + 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(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt, - const QStringList &sl - ) - : ConfParamW(parent, cflink) +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)) + if (!createCommon(lbltxt, tltptxt)) { return; + } m_cmb = new QComboBox(this); m_cmb->setEditable(false); m_cmb->insertItems(0, sl); @@ -188,8 +453,20 @@ ConfParamCStrW::ConfParamCStrW(QWidget *parent, ConfLink cflink, m_hl->addWidget(m_cmb); loadValue(); - QObject::connect(m_cmb, SIGNAL(activated(const QString&)), - this, SLOT(setValue(const QString&))); +} + +void ConfParamCStrW::setList(const QStringList& sl) +{ + m_cmb->clear(); + m_cmb->insertItems(0, sl); + loadValue(); +} + +void ConfParamCStrW::storeValue() +{ + if (m_origvalue.compare(m_cmb->currentText())) { + setValue(m_cmb->currentText()); + } } void ConfParamCStrW::loadValue() @@ -197,30 +474,30 @@ void ConfParamCStrW::loadValue() string s; m_cflink->get(s); QString cs; -#ifndef _WIN32 - // On Windows all paths are unicode. - if (m_fsencoding) + if (m_fsencoding) { cs = QString::fromLocal8Bit(s.c_str()); - else -#endif + } 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; } } + m_origvalue = cs; } -ConfParamBoolW::ConfParamBoolW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt) - : ConfParamW(parent, cflink) +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); m_hl->setSpacing(spacing); + m_hl->setContentsMargins(margin); m_cb = new QCheckBox(lbltxt, this); setSzPol(m_cb, QSizePolicy::Fixed, QSizePolicy::Fixed, 0, 0); @@ -232,38 +509,44 @@ ConfParamBoolW::ConfParamBoolW(QWidget *parent, ConfLink cflink, m_hl->addWidget(fr); loadValue(); - QObject::connect(m_cb, SIGNAL(toggled(bool)), this, SLOT(setValue(bool))); +} + +void ConfParamBoolW::storeValue() +{ + if (m_origvalue != m_cb->isChecked()) { + setValue(m_cb->isChecked()); + } } void ConfParamBoolW::loadValue() { string s; - m_cflink->get(s); - m_cb->setChecked(stringToBool(s)); + if (!m_cflink->get(s)) { + m_origvalue = m_dflt; + } else { + m_origvalue = stringToBool(s); + } + m_cb->setChecked(m_origvalue); } -ConfParamFNW::ConfParamFNW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt, - bool isdir, - QString dirloc, - QString dfltnm - ) - : ConfParamW(parent, cflink), m_isdir(isdir), m_dirloc(dirloc), - m_dfltnm(dfltnm) +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)) + 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; @@ -273,48 +556,55 @@ ConfParamFNW::ConfParamFNW(QWidget *parent, ConfLink cflink, loadValue(); QObject::connect(m_pb, SIGNAL(clicked()), this, SLOT(showBrowserDialog())); - QObject::connect(m_le, SIGNAL(textChanged(const QString&)), - this, SLOT(setValue(const QString&))); +} + +void ConfParamFNW::storeValue() +{ + if (m_origvalue.compare(m_le->text())) { + setValue(m_le->text()); + } } void ConfParamFNW::loadValue() { string s; m_cflink->get(s); -#ifndef _WIN32 - // On Windows all paths are unicode. - m_le->setText(QString::fromLocal8Bit(s.c_str())); -#else - m_le->setText(QString::fromUtf8(s.c_str())); -#endif + m_le->setText(m_origvalue = QString::fromLocal8Bit(s.c_str())); } void ConfParamFNW::showBrowserDialog() { - QString s = myGetFileName(m_isdir, "", false, m_dirloc, m_dfltnm); - if (!s.isEmpty()) + QString s = myGetFileName(m_isdir); + 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);} + 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); m_hl->setSpacing(spacing); + m_hl->setContentsMargins(margin); QVBoxLayout *vl1 = new QVBoxLayout(); + vl1->setSpacing(spacing); + vl1->setContentsMargins(margin); QHBoxLayout *hl1 = new QHBoxLayout(); + hl1->setSpacing(spacing); + hl1->setContentsMargins(margin); QLabel *tl = new QLabel(this); setSzPol(tl, QSizePolicy::Preferred, QSizePolicy::Fixed, 0, 0); @@ -352,21 +642,40 @@ ConfParamSLW::ConfParamSLW(QWidget *parent, ConfLink cflink, QObject::connect(pbD, SIGNAL(clicked()), this, SLOT(deleteSelected())); } +void ConfParamSLW::storeValue() +{ + vector ls; + for (int i = 0; i < m_lb->count(); i++) { + // 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) { + ls.push_back((const char *)(text.toLocal8Bit())); + } else { + ls.push_back((const char *)(text.toUtf8())); + } + } + string s; + stringsToString(ls, s); + if (s.compare(m_origvalue)) { + m_cflink->set(s); + } +} + void ConfParamSLW::loadValue() { - string s; - m_cflink->get(s); - list ls; - stringToStrings(s, ls); + m_origvalue.clear(); + m_cflink->get(m_origvalue); + vector ls; + stringToStrings(m_origvalue, ls); QStringList qls; - for (list::const_iterator it = ls.begin(); it != ls.end(); it++) { - // On Windows all paths are unicode. -#ifndef _WIN32 - if (m_fsencoding) + for (vector::const_iterator it = ls.begin(); it != ls.end(); it++) { + if (m_fsencoding) { qls.push_back(QString::fromLocal8Bit(it->c_str())); - else -#endif + } else { qls.push_back(QString::fromUtf8(it->c_str())); + } } m_lb->clear(); m_lb->insertItems(0, qls); @@ -375,55 +684,23 @@ void ConfParamSLW::loadValue() 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()) { - QListitems = - m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive); + QListitems = + m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive); if (items.empty()) { m_lb->insertItem(0, s); m_lb->sortItems(); - listToConf(); } } } -void ConfParamSLW::listToConf() -{ - list ls; - LOGDEB2("ConfParamSLW::listToConf. m_fsencoding " << m_fsencoding << "\n"); - for (int i = 0; i < m_lb->count(); i++) { - // 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. - // As a special Windows hack, if fsencoding is set, we convert - // backslashes to slashes. This is an awful hack because - // fsencoding does not necessarily imply that the values are - // paths, and it will come back to haunt us one day. - QString text = m_lb->item(i)->text(); - if (m_fsencoding) { - // On Windows all paths are unicode. -#ifdef _WIN32 - string pth((const char *)(text.toUtf8())); - path_slashize(pth); - ls.push_back(pth); -#else - ls.push_back((const char *)(text.toLocal8Bit())); -#endif - } else { - ls.push_back((const char *)(text.toUtf8())); - } - } - string s; - stringsToString(ls, s); - m_cflink->set(s); -} - void ConfParamSLW::deleteSelected() { // We used to repeatedly go through the list and delete the first @@ -442,15 +719,12 @@ void ConfParamSLW::deleteSelected() idxes.push_back(i); } } - for (vector::reverse_iterator it = idxes.rbegin(); - it != idxes.rend(); it++) { - LOGDEB0("deleteSelected: " << *it << " was selected\n"); + for (vector::reverse_iterator it = idxes.rbegin(); + it != idxes.rend(); it++) { QListWidgetItem *item = m_lb->takeItem(*it); emit entryDeleted(item->text()); delete item; } - - listToConf(); } // "Add entry" dialog for a file name list @@ -458,17 +732,17 @@ void ConfParamDNLW::showInputDialog() { QString s = myGetFileName(true); if (!s.isEmpty()) { - QListitems = - m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive); + QListitems = + m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive); if (items.empty()) { m_lb->insertItem(0, s); m_lb->sortItems(); - QListitems = - m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive); - if (m_lb->selectionMode() == QAbstractItemView::SingleSelection && - !items.empty()) + QListitems = + m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive); + if (m_lb->selectionMode() == QAbstractItemView::SingleSelection && + !items.empty()) { m_lb->setCurrentItem(*items.begin()); - listToConf(); + } } } } @@ -477,23 +751,238 @@ void ConfParamDNLW::showInputDialog() 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()) { - QListitems = - m_lb->findItems(s, Qt::MatchFixedString|Qt::MatchCaseSensitive); + QListitems = + m_lb->findItems(s, Qt::MatchFixedString | Qt::MatchCaseSensitive); if (items.empty()) { m_lb->insertItem(0, s); m_lb->sortItems(); - listToConf(); } } } + + +#ifdef ENABLE_XMLCONF + +static QString u8s2qs(const std::string us) +{ + return QString::fromUtf8(us.c_str()); +} + +static const string& mapfind(const string& nm, const map& mp) +{ + static string strnull; + map::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 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& 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( + " 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); + } + rtrimstring(m_brief, " ."); + 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 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 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; + } + // Get rid of "parameters" in the title, it's not interesting + // and this makes our tab headers smaller. + string ps{"parameters"}; + string::size_type pos = m_other.find(ps); + if (pos != string::npos) { + m_other = m_other.replace(pos, ps.size(), ""); + } + 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 diff --git a/src/qtgui/confgui/confgui.h b/src/qtgui/confgui/confgui.h index 8f258b84..6ad97c4f 100644 --- a/src/qtgui/confgui/confgui.h +++ b/src/qtgui/confgui/confgui.h @@ -1,263 +1,449 @@ -/* Copyright (C) 2007 J.F.Dockes +/* Copyright (C) 2007-2018 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 + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License + * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _confgui_h_included_ #define _confgui_h_included_ -#include "autoconfig.h" - /** - * This file defines a number of simple classes (virtual base: ConfParamW) - * which let the user input configuration parameters. + * 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, + * 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). + * + * The set() methods of the link objects are only called if the + * current value() differs from the value obtained by get() when the + * object was initialized. This can be used to avoid cluttering the + * output with values which are unmodified from the defaults. + * + * The file also defines a multi-tabbed dialog container for the + * parameter objects, with simple interface methods to create/add + * panels and elements. */ #include #include -#include -#include -#include - #include +#include +#include +#include +#include +#include + +class QCheckBox; +class QComboBox; +class QDialogButtonBox; class QHBoxLayout; class QLineEdit; class QListWidget; -class QSpinBox; -class QComboBox; -class QCheckBox; class QPushButton; +class QSpinBox; +class QTabWidget; +class QVBoxLayout; namespace confgui { - // A class to isolate the gui widget from the config storage mechanism - class ConfLinkRep { - public: - virtual ~ConfLinkRep() {} - virtual bool set(const std::string& val) = 0; - virtual bool get(std::string& val) = 0; - }; - typedef std::shared_ptr ConfLink; +/** Interface between the GUI widget and the config storage mechanism: */ +class ConfLinkRep { +public: + virtual ~ConfLinkRep() {} + virtual bool set(const std::string& val) = 0; + virtual bool get(std::string& val) = 0; +}; +typedef std::shared_ptr ConfLink; - // Useful to store/manage data which has no direct representation in - // the config, ie list of subkey directories - class ConfLinkNullRep : public ConfLinkRep { - public: - virtual ~ConfLinkNullRep() {} - virtual bool set(const std::string&) - { - return true; - } - virtual bool get(std::string& val) {val = ""; return true;} +// May be used to store/manage data which has no direct representation +// in the config +class ConfLinkNullRep : public ConfLinkRep { +public: + virtual ~ConfLinkNullRep() {} + virtual bool set(const std::string&) { + return true; + } + virtual bool get(std::string& val) {val = ""; return true;} +}; + +/** Link maker class */ +class ConfLinkFact { +public: + virtual ~ConfLinkFact() {} + virtual ConfLink operator()(const QString& nm) = 0; +}; + +class ConfPanelWIF { +public: + virtual ~ConfPanelWIF() {} + virtual void storeValues() = 0; + virtual void loadValues() = 0; +}; + +class ConfPanelW; +class ConfParamW; + +/** The top level widget has tabs, each tab/panel has multiple widgets + * for setting parameter values */ +class ConfTabsW : public QDialog { + Q_OBJECT; + +public: + 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 }; - // A widget to let the user change one configuration - // parameter. Subclassed for specific parameter types. Basically - // has a label and some kind of entry widget - class ConfParamW : public QWidget { - Q_OBJECT - public: - ConfParamW(QWidget *parent, ConfLink cflink) - : QWidget(parent), m_cflink(cflink), m_fsencoding(false) - { - } - virtual void loadValue() = 0; - virtual void setFsEncoding(bool onoff) {m_fsencoding = onoff;} - protected: - ConfLink m_cflink; - QHBoxLayout *m_hl; - // File names are encoded as local8bit in the config files. Other - // are encoded as utf-8 - bool m_fsencoding; - virtual bool createCommon(const QString& lbltxt, - const QString& tltptxt); - public slots: - virtual void setEnabled(bool) = 0; - protected slots: - void setValue(const QString& newvalue); - void setValue(int newvalue); - void setValue(bool newvalue); - }; + /** Add tab and return its identifier / index */ + int addPanel(const QString& title); - // Widgets for setting the different types of configuration parameters: + /** Add foreign tab where we only know to call loadvalues/storevalues. + * The object has to derive from QWidget */ + int addForeignPanel(ConfPanelWIF* w, const QString& title); - // Int - class ConfParamIntW : public ConfParamW { - Q_OBJECT - 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, - const QString& lbltxt, - const QString& tltptxt, - int minvalue = INT_MIN, - int maxvalue = INT_MAX, - int defaultvalue = 0); - virtual void loadValue(); - public slots: - virtual void setEnabled(bool i) {if(m_sb) ((QWidget*)m_sb)->setEnabled(i);} - protected: - QSpinBox *m_sb; - int m_defaultvalue; - }; + /** Add parameter setter to specified tab */ + ConfParamW *addParam(int tabindex, ParamType tp, + const QString& varname, const QString& label, + 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); - // Arbitrary string - class ConfParamStrW : public ConfParamW { - Q_OBJECT - public: - ConfParamStrW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt); - virtual void loadValue(); - public slots: - virtual void setEnabled(bool i) {if(m_le) ((QWidget*)m_le)->setEnabled(i);} - protected: - QLineEdit *m_le; - }; + /** Find param widget associated with given variable name */ + ConfParamW *findParamW(const QString& varname); - // Constrained string: choose from list - class ConfParamCStrW : public ConfParamW { - Q_OBJECT - public: - ConfParamCStrW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt, const QStringList& sl); - virtual void loadValue(); - public slots: - virtual void setEnabled(bool i) {if(m_cmb) ((QWidget*)m_cmb)->setEnabled(i);} - protected: - QComboBox *m_cmb; - }; + void hideButtons(); + +public slots: + void acceptChanges(); + void rejectChanges(); + void reloadPanels(); + void setCurrentIndex(int); + +signals: + /** This is emitted when acceptChanges() is called, after the + * values have been stored */ + void sig_prefsChanged(); - // Boolean - class ConfParamBoolW : public ConfParamW { - Q_OBJECT - public: - ConfParamBoolW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt); - virtual void loadValue(); - public slots: - virtual void setEnabled(bool i) { - if(m_cb) { - ((QWidget*)m_cb)->setEnabled(i); - } +private: + ConfLinkFact *m_makelink{nullptr}; + std::vector m_panels; + // "Foreign" panels + std::vector m_widgets; + // All params + std::vector m_params; + QTabWidget *tabWidget{nullptr}; + QDialogButtonBox *buttonBox{nullptr}; +}; + +///////////////////////////////////////////////// +// The rest of the class definitions are only useful if you need to +// access a specific element for customisation (use findParamW() and a +// dynamic cast). + +/** A panel/tab contains multiple controls for parameters */ +class ConfPanelW : public QWidget { + Q_OBJECT +public: + ConfPanelW(QWidget *parent); + void addWidget(QWidget *w); + void storeValues(); + void loadValues(); + void endOfList(); +private: + QVBoxLayout *m_vboxlayout; + std::vector m_widgets; +}; + +/** Config panel element: manages one configuration + * parameter. Subclassed for specific parameter types. + */ +class ConfParamW : public QWidget { + Q_OBJECT +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 + // are encoded as utf-8 + bool m_fsencoding; + virtual bool createCommon(const QString& lbltxt, const QString& tltptxt); + void setValue(const QString& newvalue); + void setValue(int newvalue); + void setValue(bool newvalue); +}; + +//////// Widgets for setting the different types of configuration parameters: + +/** Boolean */ +class ConfParamBoolW : public ConfParamW { + Q_OBJECT +public: + ConfParamBoolW(const QString& varnm, QWidget *parent, ConfLink cflink, + const QString& lbltxt, + 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; - }; + } +public: + QCheckBox *m_cb; + bool m_dflt; + bool m_origvalue; +}; - // File name - class ConfParamFNW : public ConfParamW { - Q_OBJECT - public: - ConfParamFNW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt, bool isdir = false, - QString dirloc = QString(), - QString dfltnm = QString() - ); - virtual void loadValue(); - protected slots: - 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); +// Int +class ConfParamIntW : public ConfParamW { + Q_OBJECT +public: + // The default value is only used if none exists in the sample + // configuration file. Defaults are normally set in there. + ConfParamIntW(const QString& varnm, QWidget *parent, ConfLink cflink, + const QString& lbltxt, + const QString& tltptxt, + 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) { + ((QWidget*)m_sb)->setEnabled(i); } - protected: - QLineEdit *m_le; - QPushButton *m_pb; - bool m_isdir; - QString m_dirloc; - QString m_dfltnm; - }; + } +protected: + QSpinBox *m_sb; + int m_defaultvalue; + int m_origvalue; +}; - // String list - class ConfParamSLW : public ConfParamW { - Q_OBJECT - public: - ConfParamSLW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt); - virtual void loadValue(); - 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(); - void deleteSelected(); - signals: - void entryDeleted(QString); - protected: - QListWidget *m_lb; - void listToConf(); - }; +// Arbitrary string +class ConfParamStrW : public ConfParamW { + Q_OBJECT +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); + } + } +protected: + QLineEdit *m_le; + QString m_origvalue; +}; - // Dir name list - class ConfParamDNLW : public ConfParamSLW { - Q_OBJECT - public: - ConfParamDNLW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt) - : ConfParamSLW(parent, cflink, lbltxt, tltptxt) - { - m_fsencoding = true; - } - protected slots: - virtual void showInputDialog(); - }; +// Constrained string: choose from list +class ConfParamCStrW : public ConfParamW { + Q_OBJECT +public: + ConfParamCStrW(const QString& varnm, QWidget *parent, ConfLink cflink, + const QString& lbltxt, + const QString& tltptxt, const QStringList& sl); + virtual void loadValue(); + virtual void storeValue(); + 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; +}; - // Constrained string list (chose from predefined) - class ConfParamCSLW : public ConfParamSLW { - Q_OBJECT - public: - ConfParamCSLW(QWidget *parent, ConfLink cflink, - const QString& lbltxt, - const QString& tltptxt, - const QStringList& sl) - : ConfParamSLW(parent, cflink, lbltxt, tltptxt), m_sl(sl) - { - } - protected slots: - virtual void showInputDialog(); - protected: - const QStringList m_sl; - }; +// File name +class ConfParamFNW : public ConfParamW { + Q_OBJECT +public: + ConfParamFNW(const QString& varnm, QWidget *parent, ConfLink cflink, + const QString& lbltxt, + const QString& tltptxt, bool isdir = false); + virtual void loadValue(); + virtual void storeValue(); +protected slots: + 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); + } + } +protected: + QLineEdit *m_le; + QPushButton *m_pb; + bool m_isdir; + QString m_origvalue; +}; + +// String list +class ConfParamSLW : public ConfParamW { + Q_OBJECT +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) { + ((QWidget*)m_lb)->setEnabled(i); + } + } +protected slots: + virtual void showInputDialog(); + void deleteSelected(); +signals: + void entryDeleted(QString); +protected: + QListWidget *m_lb; + void listToConf(); + std::string m_origvalue; +}; + +// Dir name list +class ConfParamDNLW : public ConfParamSLW { + Q_OBJECT +public: + ConfParamDNLW(const QString& varnm, QWidget *parent, ConfLink cflink, + const QString& lbltxt, + const QString& tltptxt) + : ConfParamSLW(varnm, parent, cflink, lbltxt, tltptxt) { + m_fsencoding = true; + } +protected slots: + virtual void showInputDialog(); +}; + +// Constrained string list (chose from predefined) +class ConfParamCSLW : public ConfParamSLW { + Q_OBJECT +public: + ConfParamCSLW(const QString& varnm, QWidget *parent, ConfLink cflink, + const QString& lbltxt, + const QString& tltptxt, + const QStringList& sl) + : ConfParamSLW(varnm, parent, cflink, lbltxt, tltptxt), m_sl(sl) { + } +protected slots: + virtual void showInputDialog(); +protected: + const QStringList m_sl; +}; + +extern void setSzPol(QWidget *w, QSizePolicy::Policy hpol, + QSizePolicy::Policy vpol, + int hstretch, int vstretch); + +#ifdef ENABLE_XMLCONF +/** + * Interpret an XML string and create a configuration interface. XML sample: + * + * + * Configuration file parameters for upmpdcli + * MPD parameters + * + * Host MPD runs on. + * Defaults to localhost. This can also be specified as -h + * + * mpdhost = default-host + * + * IP port used by MPD. + * Can also be specified as -p port. Defaults to the... + * + * mpdport = defport + * + * Set if we own the MPD queue. + * If this is set (on by default), we own the MPD... + * + * ownqueue = + * + * + * creates a panel in which the following are set. + * The 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[output] toptxt the top level XML text (text not inside , + * normally commented variable assignments). 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 - extern void setSzPol(QWidget *w, QSizePolicy::Policy hpol, - QSizePolicy::Policy vpol, - int hstretch, int vstretch); } #endif /* _confgui_h_included_ */ diff --git a/src/qtgui/confgui/confguiindex.cpp b/src/qtgui/confgui/confguiindex.cpp index 3a3dddad..8051b588 100644 --- a/src/qtgui/confgui/confguiindex.cpp +++ b/src/qtgui/confgui/confguiindex.cpp @@ -28,15 +28,14 @@ #include #include -#include +#include #include #include #include -using std::list; +using std::vector; using std::set; using std::string; -#include "confgui.h" #include "recoll.h" #include "confguiindex.h" #include "smallut.h" @@ -45,95 +44,90 @@ using std::string; #include "execmd.h" #include "rclconfig.h" -namespace confgui { static const int spacing = 3; static const int margin = 3; -/** - * A Gui-to-Data link class for ConfTree - * Has a subkey pointer member which makes it easy to change the - * current subkey for a number at a time. - */ +using namespace confgui; + +/* Link class for ConfTree. Has a subkey pointer member which makes it easy + * to change the current subkey for multiple instances. */ class ConfLinkRclRep : public ConfLinkRep { public: - ConfLinkRclRep(ConfNull *conf, const string& nm, - string *sk = 0) + ConfLinkRclRep(ConfNull **conf, const string& nm, string *sk = 0) : m_conf(conf), m_nm(nm), m_sk(sk) /* KEEP THE POINTER, shared data */ - { } + {} virtual ~ConfLinkRclRep() {} virtual bool set(const string& val) { - if (!m_conf) + if (!m_conf || !*m_conf) return false; - LOGDEB1("Setting [" << m_nm << "] value to [" << val << "]\n"); - bool ret = m_conf->set(m_nm, val, getSk()); + bool ret = (*m_conf)->set(m_nm, val, getSk()); if (!ret) LOGERR("Value set failed\n" ); return ret; } virtual bool get(string& val) { - if (!m_conf) + if (!m_conf || !*m_conf) return false; - bool ret = m_conf->get(m_nm, val, getSk()); + bool ret = (*m_conf)->get(m_nm, val, getSk()); LOGDEB1("ConfLinkRcl::get: [" << m_nm << "] sk [" << - getSk() << "] -> [" << (ret ? val : "no value") << "]\n" ); + getSk() << "] -> [" << (ret ? val : "no value") << "]\n"); return ret; } private: string getSk() { return m_sk ? *m_sk : string(); } - ConfNull *m_conf; + ConfNull **m_conf; const string m_nm; const string *m_sk; }; -typedef std::function()> RclConfVecValueGetter; - /* Special link for skippedNames and noContentSuffixes which are computed as set differences */ +typedef std::function()> RclConfVecValueGetter; class ConfLinkPlusMinus : public ConfLinkRep { public: - ConfLinkPlusMinus(RclConfig *rclconf, ConfNull *conf, + ConfLinkPlusMinus(RclConfig *rclconf, ConfNull **conf, const string& basename, RclConfVecValueGetter getter, string *sk = 0) : m_rclconf(rclconf), m_conf(conf), m_basename(basename), m_getter(getter), - m_sk(sk) /* KEEP THE POINTER, shared data */ - { - } + m_sk(sk) /* KEEP THE POINTER, shared data */ { + } virtual ~ConfLinkPlusMinus() {} virtual bool set(const string& snval) { - if (!m_conf || !m_rclconf) + if (!m_conf || !*m_conf || !m_rclconf) return false; string sbase; - m_conf->get(m_basename, sbase, getSk()); + (*m_conf)->get(m_basename, sbase, getSk()); std::set nval; stringToStrings(snval, nval); string splus, sminus; RclConfig::setPlusMinus(sbase, nval, splus, sminus); LOGDEB1("ConfLinkPlusMinus: base [" << sbase << "] nvalue [" << snval << "] splus [" << splus << "] sminus [" << sminus << "]\n"); - if (!m_conf->set(m_basename + "-", sminus, getSk())) { + if (!(*m_conf)->set(m_basename + "-", sminus, getSk())) { return false; } - if (!m_conf->set(m_basename + "+", splus, getSk())) { + if (!(*m_conf)->set(m_basename + "+", splus, getSk())) { return false; } return true; } virtual bool get(string& val) { - if (!m_conf || !m_rclconf) + LOGDEB("ConfLinPlusMinus::get [" << m_basename << "]\n"); + if (!m_conf || !*m_conf || !m_rclconf) return false; m_rclconf->setKeyDir(getSk()); vector vval = m_getter(); val = stringsToString(vval); - LOGDEB1("ConfLinkPlusMinus: "< " << val < " << val << "\n"); return true; } @@ -143,34 +137,58 @@ private: } RclConfig *m_rclconf; - ConfNull *m_conf; + ConfNull **m_conf; string m_basename; RclConfVecValueGetter m_getter; const string *m_sk; }; -ConfIndexW::ConfIndexW(QWidget *parent, RclConfig *config) - : QDialog(parent), m_rclconf(config) +class MyConfLinkFactRCL : public ConfLinkFact { +public: + MyConfLinkFactRCL() {} + MyConfLinkFactRCL(ConfNull **conf, string *sk = 0) + : m_conf(conf), m_sk(sk) /* KEEP THE POINTER, shared data */ + {} + virtual ConfLink operator()(const QString& nm) { + ConfLinkRep *lnk = new ConfLinkRclRep(m_conf, qs2utf8s(nm), m_sk); + return ConfLink(lnk); + } + ConfNull **m_conf{nullptr}; + string *m_sk{nullptr}; +}; + +string sknull; +static MyConfLinkFactRCL conflinkfactory; + +void ConfIndexW::showPrefs(bool modal) { - QString title(tr("Recoll - Index Settings: ")); - title += QString::fromLocal8Bit(config->getConfDir().c_str()); - setWindowTitle(title); - tabWidget = new QTabWidget; - reloadPanels(); + delete m_conf; + if (((m_conf = m_rclconf->cloneMainConfig()) == 0)) { + return; + } + m_conf->holdWrites(true); - buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok - | QDialogButtonBox::Cancel); + if (nullptr == m_w) { + QString title = u8s2qs("Recoll - Index Settings: "); + title += QString::fromLocal8Bit(m_rclconf->getConfDir().c_str()); + conflinkfactory = MyConfLinkFactRCL(&m_conf, &sknull); + if (nullptr == (m_w = new ConfTabsW(this, title, &conflinkfactory))) { + return; + } + connect(m_w, SIGNAL(sig_prefsChanged()), this, SLOT(acceptChanges())); + initPanels(); + } else { + m_w->hide(); + } - QVBoxLayout *mainLayout = new QVBoxLayout; - mainLayout->addWidget(tabWidget); - mainLayout->addWidget(buttonBox); - setLayout(mainLayout); - - resize(QSize(600, 450).expandedTo(minimumSizeHint())); - - connect(buttonBox, SIGNAL(accepted()), this, SLOT(acceptChanges())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(rejectChanges())); + m_w->reloadPanels(); + if (modal) { + m_w->exec(); + m_w->setModal(false); + } else { + m_w->show(); + } } void ConfIndexW::acceptChanges() @@ -180,7 +198,6 @@ void ConfIndexW::acceptChanges() LOGERR("ConfIndexW::acceptChanges: no config\n" ); return; } - // Let the changes to disk if (!m_conf->holdWrites(false)) { QMessageBox::critical(0, "Recoll", tr("Can't write configuration file")); @@ -189,292 +206,190 @@ void ConfIndexW::acceptChanges() delete m_conf; m_conf = 0; m_rclconf->updateMainConfig(); - - hide(); } -void ConfIndexW::rejectChanges() +void ConfIndexW::initPanels() { - LOGDEB("ConfIndexW::rejectChanges()\n" ); - // Discard local changes. - delete m_conf; - m_conf = 0; - hide(); -} + int idx = m_w->addPanel(tr("Global parameters")); + setupTopPanel(idx); -void ConfIndexW::reloadPanels() -{ - if ((m_conf = m_rclconf->cloneMainConfig()) == 0) - return; - m_conf->holdWrites(true); - tabWidget->clear(); - m_widgets.clear(); - - QWidget *w = new ConfTopPanelW(this, m_conf); - m_widgets.push_back(w); - tabWidget->addTab(w, QObject::tr("Global parameters")); - - w = new ConfSubPanelW(this, m_conf, m_rclconf); - m_widgets.push_back(w); - tabWidget->addTab(w, QObject::tr("Local parameters")); + idx = m_w->addForeignPanel( + new ConfSubPanelW(m_w, &m_conf, m_rclconf), + tr("Local parameters")); #ifndef _WIN32 - w = new ConfBeaglePanelW(this, m_conf); - m_widgets.push_back(w); - tabWidget->addTab(w, QObject::tr("Web history")); + idx = m_w->addPanel("Web history"); + setupWebHistoryPanel(idx); #endif - w = new ConfSearchPanelW(this, m_conf); - m_widgets.push_back(w); - tabWidget->addTab(w, QObject::tr("Search parameters")); + + idx = m_w->addPanel(tr("Search parameters")); + setupSearchPanel(idx); } -ConfBeaglePanelW::ConfBeaglePanelW(QWidget *parent, ConfNull *config) - : QWidget(parent) +bool ConfIndexW::setupTopPanel(int idx) { - QVBoxLayout *vboxLayout = new QVBoxLayout(this); - vboxLayout->setSpacing(spacing); - vboxLayout->setMargin(margin); + m_w->addParam(idx, ConfTabsW::CFPT_DNL, "topdirs", + tr("Top directories"), + tr("The list of directories where recursive " + "indexing starts. Default: your home.")); - ConfLink lnk1(new ConfLinkRclRep(config, "processwebqueue")); - ConfParamBoolW* cp1 = - new ConfParamBoolW(this, lnk1, tr("Process the WEB history queue"), - tr("Enables indexing Firefox visited pages.
" - "(you need also install the Firefox Recoll plugin)" - )); - vboxLayout->addWidget(cp1); + ConfParamW *cparam = m_w->addParam( + idx, ConfTabsW::CFPT_STRL, "skippedPaths", tr("Skipped paths"), + tr("These are pathnames of directories which indexing " + "will not enter.
Path elements may contain wildcards. " + "The entries must match the paths seen by the indexer " + "(e.g.: if topdirs includes '/home/me' and '/home' is " + "actually a link to '/usr/home', a correct skippedPath entry " + "would be '/home/me/tmp*', not '/usr/home/me/tmp*')")); + cparam->setFsEncoding(true); + + if (m_stemlangs.empty()) { + vector cstemlangs = Rcl::Db::getStemmerNames(); + for (const auto &clang : cstemlangs) { + m_stemlangs.push_back(u8s2qs(clang)); + } + } + m_w->addParam(idx, ConfTabsW::CFPT_CSTRL, "indexstemminglanguages", + tr("Stemming languages"), + tr("The languages for which stemming expansion
" + "dictionaries will be built."), 0, 0, &m_stemlangs); - ConfLink lnk2(new ConfLinkRclRep(config, "webcachedir")); - ConfParamFNW* cp2 = - new ConfParamFNW(this, lnk2, tr("Web page store directory name"), - tr("The name for a directory where to store the copies " - "of visited web pages.
" - "A non-absolute path is taken relative to the " - "configuration directory."), true); - cp2->setEnabled(cp1->m_cb->isChecked()); - connect(cp1->m_cb, SIGNAL(toggled(bool)), cp2, SLOT(setEnabled(bool))); - vboxLayout->addWidget(cp2); + m_w->addParam(idx, ConfTabsW::CFPT_FN, "logfilename", + tr("Log file name"), + tr("The file where the messages will be written.
" + "Use 'stderr' for terminal output"), 0); + + m_w->addParam( + idx, ConfTabsW::CFPT_INT, "loglevel", tr("Log verbosity level"), + tr("This value adjusts the amount of messages,
from only " + "errors to a lot of debugging data."), 0, 6); - ConfLink lnk3(new ConfLinkRclRep(config, "webcachemaxmbs")); - ConfParamIntW *cp3 = - new ConfParamIntW(this, lnk3, tr("Max. size for the web store (MB)"), - tr("Entries will be recycled once the size is reached." - "
" - "Only increasing the size really makes sense because " - "reducing the value will not truncate an existing " - "file (only waste space at the end)." - ), - -1, 1000*1000); // Max 1TB... - cp3->setEnabled(cp1->m_cb->isChecked()); - connect(cp1->m_cb, SIGNAL(toggled(bool)), cp3, SLOT(setEnabled(bool))); - vboxLayout->addWidget(cp3); - vboxLayout->insertStretch(-1); + m_w->addParam(idx, ConfTabsW::CFPT_INT, "idxflushmb", + tr("Index flush megabytes interval"), + tr("This value adjust the amount of " + "data which is indexed between flushes to disk.
" + "This helps control the indexer memory usage. " + "Default 10MB "), 0, 1000); + + m_w->addParam(idx, ConfTabsW::CFPT_INT, "maxfsoccuppc", + tr("Max disk occupation (%, 0 means no limit)"), + tr("This is the percentage of disk usage " + "- total disk usage, not index size - at which " + "indexing will fail and stop.
" + "The default value of 0 removes any limit."), 0, 100); + + ConfParamW *bparam = m_w->addParam( + idx, ConfTabsW::CFPT_BOOL, "noaspell", tr("No aspell usage"), + tr("Disables use of aspell to generate spelling " + "approximation in the term explorer tool.
" + "Useful if aspell is absent or does not work. ")); + cparam = m_w->addParam( + idx, ConfTabsW::CFPT_STR, "aspellLanguage", + tr("Aspell language"), + tr("The language for the aspell dictionary. " + "This should look like 'en' or 'fr' ...
" + "If this value is not set, the NLS environment " + "will be used to compute it, which usually works. " + "To get an idea of what is installed on your system, " + "type 'aspell config' and look for .dat files inside " + "the 'data-dir' directory. ")); + m_w->enableLink(bparam, cparam, true); + + m_w->addParam( + idx, ConfTabsW::CFPT_FN, "dbdir", tr("Database directory name"), + tr("The name for a directory where to store the index
" + "A non-absolute path is taken relative to the " + "configuration directory. The default is 'xapiandb'."), true); + m_w->addParam(idx, ConfTabsW::CFPT_STR, "unac_except_trans", + tr("Unac exceptions"), + tr("

These are exceptions to the unac mechanism " + "which, by default, removes all diacritics, " + "and performs canonic decomposition. You can override " + "unaccenting for some characters, depending on your " + "language, and specify additional decompositions, " + "e.g. for ligatures. In each space-separated entry, " + "the first character is the source one, and the rest " + "is the translation." + )); + m_w->endOfList(idx); + return true; } -ConfSearchPanelW::ConfSearchPanelW(QWidget *parent, ConfNull *config) - : QWidget(parent) +bool ConfIndexW::setupWebHistoryPanel(int idx) { - QVBoxLayout *vboxLayout = new QVBoxLayout(this); - vboxLayout->setSpacing(spacing); - vboxLayout->setMargin(margin); + ConfParamW *bparam = m_w->addParam( + idx, ConfTabsW::CFPT_BOOL, "processwebqueue", + tr("Process the WEB history queue"), + tr("Enables indexing Firefox visited pages.
" + "(you need also install the Firefox Recoll plugin)")); + ConfParamW *cparam = m_w->addParam( + idx, ConfTabsW::CFPT_FN, "webcachedir", + tr("Web page store directory name"), + tr("The name for a directory where to store the copies " + "of visited web pages.
" + "A non-absolute path is taken relative to the " + "configuration directory."), 1); + m_w->enableLink(bparam, cparam); + cparam = m_w->addParam( + idx, ConfTabsW::CFPT_INT, "webcachemaxmbs", + tr("Max. size for the web store (MB)"), + tr("Entries will be recycled once the size is reached." + "
" + "Only increasing the size really makes sense because " + "reducing the value will not truncate an existing " + "file (only waste space at the end)." + ), -1, 1000*1000); // Max 1TB... + m_w->enableLink(bparam, cparam); + m_w->endOfList(idx); + return true; +} + +bool ConfIndexW::setupSearchPanel(int idx) +{ if (!o_index_stripchars) { - ConfLink lnk1(new ConfLinkRclRep(config, "autodiacsens")); - ConfParamBoolW* cp1 = - new ConfParamBoolW(this, lnk1, tr("Automatic diacritics sensitivity"), - tr("

Automatically trigger diacritics sensitivity " - "if the search term has accented characters " - "(not in unac_except_trans). Else you need to " - "use the query language and the D " - "modifier to specify " - "diacritics sensitivity." - )); - vboxLayout->addWidget(cp1); + m_w->addParam(idx, ConfTabsW::CFPT_BOOL, "autodiacsens", + tr("Automatic diacritics sensitivity"), + tr("

Automatically trigger diacritics sensitivity " + "if the search term has accented characters " + "(not in unac_except_trans). Else you need to " + "use the query language and the D " + "modifier to specify diacritics sensitivity.")); - ConfLink lnk2(new ConfLinkRclRep(config, "autocasesens")); - ConfParamBoolW* cp2 = - new ConfParamBoolW(this, lnk2, - tr("Automatic character case sensitivity"), - tr("

Automatically trigger character case " - "sensitivity if the entry has upper-case " - "characters in any but the first position. " - "Else you need to use the query language and " - "the C modifier to specify character-case " - "sensitivity." - )); - vboxLayout->addWidget(cp2); + m_w->addParam(idx, ConfTabsW::CFPT_BOOL, "autocasesens", + tr("Automatic character case sensitivity"), + tr("

Automatically trigger character case " + "sensitivity if the entry has upper-case " + "characters in any but the first position. " + "Else you need to use the query language and " + "the C modifier to specify character-case " + "sensitivity.")); } - ConfLink lnk3(new ConfLinkRclRep(config, "maxTermExpand")); - ConfParamIntW* cp3 = - new ConfParamIntW(this, lnk3, - tr("Maximum term expansion count"), - tr("

Maximum expansion count for a single term " - "(e.g.: when using wildcards). The default " - "of 10 000 is reasonable and will avoid " - "queries that appear frozen while the engine is " - "walking the term list." - )); - vboxLayout->addWidget(cp3); + m_w->addParam(idx, ConfTabsW::CFPT_INT, "maxTermExpand", + tr("Maximum term expansion count"), + tr("

Maximum expansion count for a single term " + "(e.g.: when using wildcards). The default " + "of 10 000 is reasonable and will avoid " + "queries that appear frozen while the engine is " + "walking the term list."), 0, 100000); + m_w->addParam(idx, ConfTabsW::CFPT_INT, "maxXapianClauses", + tr("Maximum Xapian clauses count"), + tr("

Maximum number of elementary clauses we " + "add to a single Xapian query. In some cases, " + "the result of term expansion can be " + "multiplicative, and we want to avoid using " + "excessive memory. The default of 100 000 " + "should be both high enough in most cases " + "and compatible with current typical hardware " + "configurations."), 0, 1000000); - ConfLink lnk4(new ConfLinkRclRep(config, "maxXapianClauses")); - ConfParamIntW* cp4 = - new ConfParamIntW(this, lnk4, - tr("Maximum Xapian clauses count"), - tr("

Maximum number of elementary clauses we " - "add to a single Xapian query. In some cases, " - "the result of term expansion can be " - "multiplicative, and we want to avoid using " - "excessive memory. The default of 100 000 " - "should be both high enough in most cases " - "and compatible with current typical hardware " - "configurations." - )); - vboxLayout->addWidget(cp4); - - vboxLayout->insertStretch(-1); + m_w->endOfList(idx); + return true; } -ConfTopPanelW::ConfTopPanelW(QWidget *parent, ConfNull *config) - : QWidget(parent) -{ - QWidget *w = 0; - - QGridLayout *gl1 = new QGridLayout(this); - gl1->setSpacing(spacing); - gl1->setMargin(margin); - - int gridrow = 0; - - w = new ConfParamDNLW(this, - ConfLink(new ConfLinkRclRep(config, "topdirs")), - tr("Top directories"), - tr("The list of directories where recursive " - "indexing starts. Default: your home.")); - setSzPol(w, QSizePolicy::Preferred, QSizePolicy::Preferred, 1, 3); - gl1->addWidget(w, gridrow++, 0, 1, 2); - - ConfParamSLW *eskp = new - ConfParamSLW(this, - ConfLink(new ConfLinkRclRep(config, "skippedPaths")), - tr("Skipped paths"), - tr("These are pathnames of directories which indexing " - "will not enter.
" - "Path elements may contain wildcards. " - "The entries must match the paths seen by the indexer " - "(e.g.: if topdirs includes '/home/me' and '/home' is " - "actually a link " - "to '/usr/home', a correct skippedPath entry " - "would be '/home/me/tmp*', not '/usr/home/me/tmp*')")); - eskp->setFsEncoding(true); - setSzPol(eskp, QSizePolicy::Preferred, QSizePolicy::Preferred, 1, 3); - gl1->addWidget(eskp, gridrow++, 0, 1, 2); - - vector cstemlangs = Rcl::Db::getStemmerNames(); - QStringList stemlangs; - for (vector::const_iterator it = cstemlangs.begin(); - it != cstemlangs.end(); it++) { - stemlangs.push_back(QString::fromUtf8(it->c_str())); - } - w = new - ConfParamCSLW(this, - ConfLink(new ConfLinkRclRep(config, - "indexstemminglanguages")), - tr("Stemming languages"), - tr("The languages for which stemming expansion
" - "dictionaries will be built."), stemlangs); - setSzPol(w, QSizePolicy::Preferred, QSizePolicy::Preferred, 1, 1); - gl1->addWidget(w, gridrow, 0); - - - w = new ConfParamFNW(this, - ConfLink(new ConfLinkRclRep(config, "logfilename")), - tr("Log file name"), - tr("The file where the messages will be written.
" - "Use 'stderr' for terminal output"), false, - u8s2qs(tmplocation()), - "log-recoll.txt"); - gl1->addWidget(w, gridrow++, 1); - - - w = new ConfParamIntW(this, - ConfLink(new ConfLinkRclRep(config, "loglevel")), - tr("Log verbosity level"), - tr("This value adjusts the amount of " - "messages,
from only errors to a " - "lot of debugging data."), 0, 6); - gl1->addWidget(w, gridrow, 0); - - w = new ConfParamIntW(this, - ConfLink(new ConfLinkRclRep(config, "idxflushmb")), - tr("Index flush megabytes interval"), - tr("This value adjust the amount of " - "data which is indexed between flushes to disk.
" - "This helps control the indexer memory usage. " - "Default 10MB "), 0, 1000); - gl1->addWidget(w, gridrow++, 1); - - w = new ConfParamIntW(this, - ConfLink(new ConfLinkRclRep(config, "maxfsoccuppc")), - tr("Max disk occupation (%, 0 means no limit)"), - tr("This is the percentage of disk usage " - "- total disk usage, not index size - at which " - "indexing will fail and stop.
" - "The default value of 0 removes any limit."), - 0, 100); - gl1->addWidget(w, gridrow++, 0); - - ConfParamBoolW* cpasp = - new ConfParamBoolW(this, - ConfLink(new ConfLinkRclRep(config, "noaspell")), - tr("No aspell usage"), - tr("Disables use of aspell to generate spelling " - "approximation in the term explorer tool.
" - "Useful if aspell is absent or does not work. ")); - gl1->addWidget(cpasp, gridrow, 0); - - ConfParamStrW* cpaspl = new - ConfParamStrW(this, - ConfLink(new ConfLinkRclRep(config, "aspellLanguage")), - tr("Aspell language"), - tr("The language for the aspell dictionary. " - "This should look like 'en' or 'fr' ...
" - "If this value is not set, the NLS environment " - "will be used to compute it, which usually works. " - "To get an idea of what is installed on your system, " - "type 'aspell config' and look for .dat files inside " - "the 'data-dir' directory. ")); - cpaspl->setEnabled(!cpasp->m_cb->isChecked()); - connect(cpasp->m_cb, SIGNAL(toggled(bool)), cpaspl,SLOT(setDisabled(bool))); - gl1->addWidget(cpaspl, gridrow++, 1); - - w = new - ConfParamFNW(this, - ConfLink(new ConfLinkRclRep(config, "dbdir")), - tr("Database directory name"), - tr("The name for a directory where to store the index
" - "A non-absolute path is taken relative to the " - "configuration directory. The default is 'xapiandb'." - ), true); - gl1->addWidget(w, gridrow++, 0, 1, 2); - - w = new - ConfParamStrW(this, - ConfLink(new ConfLinkRclRep(config, "unac_except_trans")), - tr("Unac exceptions"), - tr("

These are exceptions to the unac mechanism " - "which, by default, removes all diacritics, " - "and performs canonic decomposition. You can override " - "unaccenting for some characters, depending on your " - "language, and specify additional decompositions, " - "e.g. for ligatures. In each space-separated entry, " - "the first character is the source one, and the rest " - "is the translation." - )); - gl1->addWidget(w, gridrow++, 0, 1, 2); -} - -ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, +ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull **config, RclConfig *rclconf) : QWidget(parent), m_config(config) { @@ -482,14 +397,14 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, vboxLayout->setSpacing(spacing); vboxLayout->setMargin(margin); - m_subdirs = new - ConfParamDNLW(this, - ConfLink(new ConfLinkNullRep()), - QObject::tr("Customised subtrees"), - QObject::tr("The list of subdirectories in the indexed " - "hierarchy
where some parameters need " - "to be redefined. Default: empty.")); - m_subdirs->getListBox()->setSelectionMode(QAbstractItemView::SingleSelection); + m_subdirs = new ConfParamDNLW( + "bogus00", this, ConfLink(new confgui::ConfLinkNullRep()), + QObject::tr("Customised subtrees"), + QObject::tr("The list of subdirectories in the indexed " + "hierarchy
where some parameters need " + "to be redefined. Default: empty.")); + m_subdirs->getListBox()->setSelectionMode( + QAbstractItemView::SingleSelection); connect(m_subdirs->getListBox(), SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, @@ -502,14 +417,13 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, // customized in the system config like .thunderbird or // .purple. This doesn't prevent them to add and customize them // further. - vector allkeydirs = config->getSubKeys(true); - + vector allkeydirs = (*config)->getSubKeys(true); QStringList qls; - for (vector::const_iterator it = allkeydirs.begin(); - it != allkeydirs.end(); it++) { - qls.push_back(QString::fromUtf8(it->c_str())); + for (const auto& dir: allkeydirs) { + qls.push_back(u8s2qs(dir)); } m_subdirs->getListBox()->insertItems(0, qls); + vboxLayout->addWidget(m_subdirs); QFrame *line2 = new QFrame(this); @@ -520,13 +434,13 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, QLabel *explain = new QLabel(this); explain->setWordWrap(true); explain->setText( - QObject:: - tr("The parameters that follow are set either at the " - "top level, if nothing " - "or an empty line is selected in the listbox above, " - "or for the selected subdirectory. " - "You can add or remove directories by clicking " - "the +/- buttons.")); + QObject::tr( + "The parameters that follow are set either at the " + "top level, if nothing " + "or an empty line is selected in the listbox above, " + "or for the selected subdirectory. " + "You can add or remove directories by clicking " + "the +/- buttons.")); vboxLayout->addWidget(explain); @@ -539,7 +453,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, int gridy = 0; ConfParamSLW *eskn = new ConfParamSLW( - m_groupbox, + "skippedNames", m_groupbox, ConfLink(new ConfLinkPlusMinus( rclconf, config, "skippedNames", std::bind(&RclConfig::getSkippedNames, rclconf), &m_sk)), @@ -552,13 +466,12 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, vector amimes = rclconf->getAllMimeTypes(); QStringList amimesq; - for (vector::const_iterator it = amimes.begin(); - it != amimes.end(); it++) { - amimesq.push_back(QString::fromUtf8(it->c_str())); + for (const auto& mime: amimes) { + amimesq.push_back(u8s2qs(mime)); } ConfParamCSLW *eincm = new ConfParamCSLW( - m_groupbox, + "indexedmimetypes", m_groupbox, ConfLink(new ConfLinkRclRep(config, "indexedmimetypes", &m_sk)), tr("Only mime types"), tr("An exclusive list of indexed mime types.
Nothing " @@ -567,7 +480,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(eincm, gridy++, 1); ConfParamCSLW *eexcm = new ConfParamCSLW( - m_groupbox, + "excludedmimetypes", m_groupbox, ConfLink(new ConfLinkRclRep(config, "excludedmimetypes", &m_sk)), tr("Exclude mime types"), tr("Mime types not to be indexed"), amimesq); @@ -575,7 +488,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(eexcm, gridy, 0); ConfParamSLW *encs = new ConfParamSLW( - m_groupbox, + "noContentSuffixes", m_groupbox, ConfLink(new ConfLinkPlusMinus( rclconf, config, "noContentSuffixes", std::bind(&RclConfig::getStopSuffixes, rclconf), &m_sk)), @@ -594,20 +507,19 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, string cmd = "iconv"; int status = ex.doexec(cmd, args, 0, &icout); if (status) { - LOGERR("Can't get list of charsets from 'iconv -l'" ); + LOGERR("Can't get list of charsets from 'iconv -l'"); } icout = neutchars(icout, ","); - list ccsets; + vector ccsets; stringToStrings(icout, ccsets); QStringList charsets; charsets.push_back(""); - for (list::const_iterator it = ccsets.begin(); - it != ccsets.end(); it++) { - charsets.push_back(QString::fromUtf8(it->c_str())); + for (const auto& charset : ccsets) { + charsets.push_back(u8s2qs(charset)); } ConfParamCStrW *e21 = new ConfParamCStrW( - m_groupbox, + "defaultcharset", m_groupbox, ConfLink(new ConfLinkRclRep(config, "defaultcharset", &m_sk)), QObject::tr("Default
character set"), QObject::tr("Character set used for reading files " @@ -620,7 +532,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(e21, gridy++, 0); ConfParamBoolW *e3 = new ConfParamBoolW( - m_groupbox, + "followLinks", m_groupbox, ConfLink(new ConfLinkRclRep(config, "followLinks", &m_sk)), QObject::tr("Follow symbolic links"), QObject::tr("Follow symbolic links while " @@ -630,7 +542,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(e3, gridy, 0); ConfParamBoolW *eafln = new ConfParamBoolW( - m_groupbox, + "indexallfilenames", m_groupbox, ConfLink(new ConfLinkRclRep(config, "indexallfilenames", &m_sk)), QObject::tr("Index all file names"), QObject::tr("Index the names of files for which the contents " @@ -640,7 +552,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(eafln, gridy++, 1); ConfParamIntW *ezfmaxkbs = new ConfParamIntW( - m_groupbox, + "compressedfilemaxkbs", m_groupbox, ConfLink(new ConfLinkRclRep(config, "compressedfilemaxkbs", &m_sk)), tr("Max. compressed file size (KB)"), tr("This value sets a threshold beyond which compressed" @@ -650,7 +562,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(ezfmaxkbs, gridy, 0); ConfParamIntW *etxtmaxmbs = new ConfParamIntW( - m_groupbox, + "textfilemaxmbs", m_groupbox, ConfLink(new ConfLinkRclRep(config, "textfilemaxmbs", &m_sk)), tr("Max. text file size (MB)"), tr("This value sets a threshold beyond which text " @@ -661,7 +573,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(etxtmaxmbs, gridy++, 1); ConfParamIntW *etxtpagekbs = new ConfParamIntW( - m_groupbox, + "textfilepagekbs", m_groupbox, ConfLink(new ConfLinkRclRep(config, "textfilepagekbs", &m_sk)), tr("Text file page size (KB)"), tr("If this value is set (not equal to -1), text " @@ -672,7 +584,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, gl1->addWidget(etxtpagekbs, gridy, 0); ConfParamIntW *efiltmaxsecs = new ConfParamIntW( - m_groupbox, + "filtermaxseconds", m_groupbox, ConfLink(new ConfLinkRclRep(config, "filtermaxseconds", &m_sk)), tr("Max. filter exec. time (s)"), tr("External filters working longer than this will be " @@ -684,47 +596,55 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config, vboxLayout->addWidget(m_groupbox); subDirChanged(0, 0); + LOGDEB("ConfSubPanelW::ConfSubPanelW: done\n"); } -void ConfSubPanelW::reloadAll() +void ConfSubPanelW::loadValues() { - for (list::iterator it = m_widgets.begin(); - it != m_widgets.end(); it++) { - (*it)->loadValue(); + LOGDEB("ConfSubPanelW::loadValues\n"); + for (auto widget : m_widgets) { + widget->loadValue(); + } + LOGDEB("ConfSubPanelW::loadValues done\n"); +} + +void ConfSubPanelW::storeValues() +{ + for (auto widget : m_widgets) { + widget->storeValue(); } } void ConfSubPanelW::subDirChanged(QListWidgetItem *current, QListWidgetItem *) { - LOGDEB("ConfSubPanelW::subDirChanged\n" ); + LOGDEB("ConfSubPanelW::subDirChanged\n"); if (current == 0 || current->text() == "") { m_sk = ""; m_groupbox->setTitle(tr("Global")); } else { - m_sk = (const char *) current->text().toUtf8(); + m_sk = qs2utf8s(current->text()); m_groupbox->setTitle(current->text()); } - LOGDEB("ConfSubPanelW::subDirChanged: now [" << (m_sk) << "]\n" ); - reloadAll(); + LOGDEB("ConfSubPanelW::subDirChanged: now [" << m_sk << "]\n"); + loadValues(); + LOGDEB("ConfSubPanelW::subDirChanged: done\n"); } void ConfSubPanelW::subDirDeleted(QString sbd) { - LOGDEB("ConfSubPanelW::subDirDeleted(" << ((const char *)sbd.toUtf8()) << ")\n" ); + LOGDEB("ConfSubPanelW::subDirDeleted(" << qs2utf8s(sbd) << ")\n"); if (sbd == "") { // Can't do this, have to reinsert it QTimer::singleShot(0, this, SLOT(restoreEmpty())); return; } // Have to delete all entries for submap - m_config->eraseKey((const char *)sbd.toUtf8()); + (*m_config)->eraseKey(qs2utf8s(sbd)); } void ConfSubPanelW::restoreEmpty() { - LOGDEB("ConfSubPanelW::restoreEmpty()\n" ); + LOGDEB("ConfSubPanelW::restoreEmpty()\n"); m_subdirs->getListBox()->insertItem(0, ""); } - -} // Namespace confgui diff --git a/src/qtgui/confgui/confguiindex.h b/src/qtgui/confgui/confguiindex.h index 1d2ce3a9..be00ad68 100644 --- a/src/qtgui/confgui/confguiindex.h +++ b/src/qtgui/confgui/confguiindex.h @@ -30,78 +30,61 @@ #include #include #include +#include #include -#include -using std::string; -using std::list; +#include + +#include "confgui.h" class ConfNull; class RclConfig; -class ConfParamW; -class ConfParamDNLW; -namespace confgui { - -class ConfIndexW : public QDialog { +class ConfIndexW : public QWidget { Q_OBJECT public: - ConfIndexW(QWidget *parent, RclConfig *config); + ConfIndexW(QWidget *parent, RclConfig *config) + : m_parent(parent), m_rclconf(config) {} + public slots: + void showPrefs(bool modal); void acceptChanges(); - void rejectChanges(); - void reloadPanels(); + QWidget *getDialog() {return m_w;} + private: + void initPanels(); + bool setupTopPanel(int idx); + bool setupWebHistoryPanel(int idx); + bool setupSearchPanel(int idx); + + QWidget *m_parent; RclConfig *m_rclconf; - ConfNull *m_conf; - list m_widgets; - QTabWidget *tabWidget; - QDialogButtonBox *buttonBox; + ConfNull *m_conf{nullptr}; + confgui::ConfTabsW *m_w{nullptr}; + QStringList m_stemlangs; }; -/** - * A panel with the top-level parameters which can't be redefined in - * subdirectoriess: - */ -class ConfTopPanelW : public QWidget { - Q_OBJECT -public: - ConfTopPanelW(QWidget *parent, ConfNull *config); -}; -/** - * A panel for the parameters that can be changed in subdirectories: - */ -class ConfSubPanelW : public QWidget { - Q_OBJECT +/** A special panel for parameters which may change in subdirectories: */ +class ConfSubPanelW : public QWidget, public confgui::ConfPanelWIF { + Q_OBJECT; + public: - ConfSubPanelW(QWidget *parent, ConfNull *config, RclConfig *rclconf); + ConfSubPanelW(QWidget *parent, ConfNull **config, RclConfig *rclconf); + + virtual void storeValues(); + virtual void loadValues(); private slots: void subDirChanged(QListWidgetItem *, QListWidgetItem *); void subDirDeleted(QString); void restoreEmpty(); private: - string m_sk; - ConfParamDNLW *m_subdirs; - list m_widgets; - ConfNull *m_config; + std::string m_sk; + ConfNull **m_config; + confgui::ConfParamDNLW *m_subdirs; + std::vector m_widgets; QGroupBox *m_groupbox; - void reloadAll(); }; -class ConfBeaglePanelW : public QWidget { - Q_OBJECT -public: - ConfBeaglePanelW(QWidget *parent, ConfNull *config); -}; - -class ConfSearchPanelW : public QWidget { - Q_OBJECT -public: - ConfSearchPanelW(QWidget *parent, ConfNull *config); -}; - -} // Namespace confgui - #endif /* _confguiindex_h_included_ */ diff --git a/src/qtgui/rclm_wins.cpp b/src/qtgui/rclm_wins.cpp index 982af896..cbec0400 100644 --- a/src/qtgui/rclm_wins.cpp +++ b/src/qtgui/rclm_wins.cpp @@ -175,20 +175,15 @@ void RclMain::execIndexConfig() void RclMain::showIndexConfig(bool modal) { LOGDEB("showIndexConfig()\n" ); + bool created{false}; if (indexConfig == 0) { + created = true; indexConfig = new ConfIndexW(0, theconfig); - connect(new QShortcut(quitKeySeq, indexConfig), SIGNAL (activated()), - this, SLOT (fileExit())); - } else { - // Close and reopen, in hope that makes us visible... - indexConfig->close(); - indexConfig->reloadPanels(); } - if (modal) { - indexConfig->exec(); - indexConfig->setModal(false); - } else { - indexConfig->show(); + indexConfig->showPrefs(modal); + if (created) { + connect(new QShortcut(quitKeySeq, indexConfig->getDialog()), + SIGNAL (activated()), this, SLOT (fileExit())); } } diff --git a/src/qtgui/rclmain_w.h b/src/qtgui/rclmain_w.h index 97bcebb3..f33abc0e 100644 --- a/src/qtgui/rclmain_w.h +++ b/src/qtgui/rclmain_w.h @@ -45,16 +45,11 @@ class RTIToolW; class FragButs; class SpecIdxW; class WebcacheEdit; +class ConfIndexW; +class RclTrayIcon; #include "ui_rclmain.h" -namespace confgui { -class ConfIndexW; -} - -using confgui::ConfIndexW; - -class RclTrayIcon; class RclMain : public QMainWindow, public Ui::RclMainBase { Q_OBJECT;