Converted the index preferences to use the shared confgui code

This commit is contained in:
Jean-Francois Dockes 2019-09-22 09:23:17 +02:00
parent db3c401a23
commit 9e51ed8613
6 changed files with 1380 additions and 812 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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 * 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 * it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 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 * along with this program; if not, write to the
* Free Software Foundation, Inc., * 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_ #ifndef _confgui_h_included_
#define _confgui_h_included_ #define _confgui_h_included_
#include "autoconfig.h"
/** /**
* This file defines a number of simple classes (virtual base: ConfParamW) * This file defines a number of simple classes (virtual base: ConfParamW)
* which let the user input configuration parameters. * 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. * a file name, an integer, etc.
* *
* Each configuration gui object is linked to the configuration data through * Each configuration gui object is linked to the configuration data through
* a "link" object which knows the details of interacting with the actual * 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 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. * changed.
* *
* The widgets are typically linked to a temporary configuration object, which * The widgets are typically linked to a temporary configuration object, which
* is then copied to the actual configuration if the data is accepted, or * 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). * 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 <string> #include <string>
#include <limits.h> #include <limits.h>
#include <qglobal.h>
#include <qstring.h>
#include <qwidget.h>
#include <memory> #include <memory>
#include <vector>
#include <string>
#include <QString>
#include <QWidget>
#include <QDialog>
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
class QHBoxLayout; class QHBoxLayout;
class QLineEdit; class QLineEdit;
class QListWidget; class QListWidget;
class QSpinBox;
class QComboBox;
class QCheckBox;
class QPushButton; class QPushButton;
class QSpinBox;
class QTabWidget;
class QVBoxLayout;
namespace confgui { namespace confgui {
// A class to isolate the gui widget from the config storage mechanism /** Interface between the GUI widget and the config storage mechanism: */
class ConfLinkRep { class ConfLinkRep {
public: public:
virtual ~ConfLinkRep() {} virtual ~ConfLinkRep() {}
virtual bool set(const std::string& val) = 0; virtual bool set(const std::string& val) = 0;
virtual bool get(std::string& val) = 0; virtual bool get(std::string& val) = 0;
}; };
typedef std::shared_ptr<ConfLinkRep> ConfLink; typedef std::shared_ptr<ConfLinkRep> ConfLink;
// Useful to store/manage data which has no direct representation in // May be used to store/manage data which has no direct representation
// the config, ie list of subkey directories // in the config
class ConfLinkNullRep : public ConfLinkRep { class ConfLinkNullRep : public ConfLinkRep {
public: public:
virtual ~ConfLinkNullRep() {} virtual ~ConfLinkNullRep() {}
virtual bool set(const std::string&) virtual bool set(const std::string&) {
{ return true;
return true; }
} virtual bool get(std::string& val) {val = ""; 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 /** Add tab and return its identifier / index */
// parameter. Subclassed for specific parameter types. Basically int addPanel(const QString& title);
// 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);
};
// 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 /** Add parameter setter to specified tab */
class ConfParamIntW : public ConfParamW { ConfParamW *addParam(int tabindex, ParamType tp,
Q_OBJECT const QString& varname, const QString& label,
public: const QString& tooltip, int isdirorminval = 0,
// The default value is only used if none exists in the sample int maxval = 0, const QStringList* sl = 0);
// configuration file. Defaults are normally set in there. bool enableLink(ConfParamW* boolw, ConfParamW* otherw, bool revert = false);
ConfParamIntW(QWidget *parent, ConfLink cflink, void endOfList(int tabindex);
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;
};
// Arbitrary string /** Find param widget associated with given variable name */
class ConfParamStrW : public ConfParamW { ConfParamW *findParamW(const QString& varname);
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;
};
// Constrained string: choose from list void hideButtons();
class ConfParamCStrW : public ConfParamW {
Q_OBJECT public slots:
public: void acceptChanges();
ConfParamCStrW(QWidget *parent, ConfLink cflink, void rejectChanges();
const QString& lbltxt, void reloadPanels();
const QString& tltptxt, const QStringList& sl); void setCurrentIndex(int);
virtual void loadValue();
public slots: signals:
virtual void setEnabled(bool i) {if(m_cmb) ((QWidget*)m_cmb)->setEnabled(i);} /** This is emitted when acceptChanges() is called, after the
protected: * values have been stored */
QComboBox *m_cmb; void sig_prefsChanged();
};
// Boolean private:
class ConfParamBoolW : public ConfParamW { ConfLinkFact *m_makelink{nullptr};
Q_OBJECT std::vector<ConfPanelW *> m_panels;
public: // "Foreign" panels
ConfParamBoolW(QWidget *parent, ConfLink cflink, std::vector<ConfPanelWIF *> m_widgets;
const QString& lbltxt, // All params
const QString& tltptxt); std::vector<ConfParamW *> m_params;
virtual void loadValue(); QTabWidget *tabWidget{nullptr};
public slots: QDialogButtonBox *buttonBox{nullptr};
virtual void setEnabled(bool i) { };
if(m_cb) {
((QWidget*)m_cb)->setEnabled(i); /////////////////////////////////////////////////
} // 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<QWidget *> 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 // Int
class ConfParamFNW : public ConfParamW { class ConfParamIntW : public ConfParamW {
Q_OBJECT Q_OBJECT
public: public:
ConfParamFNW(QWidget *parent, ConfLink cflink, // The default value is only used if none exists in the sample
const QString& lbltxt, // configuration file. Defaults are normally set in there.
const QString& tltptxt, bool isdir = false, ConfParamIntW(const QString& varnm, QWidget *parent, ConfLink cflink,
QString dirloc = QString(), const QString& lbltxt,
QString dfltnm = QString() const QString& tltptxt,
); int minvalue = INT_MIN,
virtual void loadValue(); int maxvalue = INT_MAX,
protected slots: int defaultvalue = 0);
void showBrowserDialog(); virtual void loadValue();
public slots: virtual void storeValue();
virtual void setEnabled(bool i) { public slots:
if(m_le) ((QWidget*)m_le)->setEnabled(i); virtual void setEnabled(bool i) {
if(m_pb) ((QWidget*)m_pb)->setEnabled(i); if (m_sb) {
((QWidget*)m_sb)->setEnabled(i);
} }
protected: }
QLineEdit *m_le; protected:
QPushButton *m_pb; QSpinBox *m_sb;
bool m_isdir; int m_defaultvalue;
QString m_dirloc; int m_origvalue;
QString m_dfltnm; };
};
// String list // Arbitrary string
class ConfParamSLW : public ConfParamW { class ConfParamStrW : public ConfParamW {
Q_OBJECT Q_OBJECT
public: public:
ConfParamSLW(QWidget *parent, ConfLink cflink, ConfParamStrW(const QString& varnm, QWidget *parent, ConfLink cflink,
const QString& lbltxt, const QString& lbltxt,
const QString& tltptxt); const QString& tltptxt);
virtual void loadValue(); virtual void loadValue();
QListWidget *getListBox() {return m_lb;} virtual void storeValue();
public slots:
public slots: virtual void setEnabled(bool i) {
virtual void setEnabled(bool i) {if(m_lb) ((QWidget*)m_lb)->setEnabled(i);} if (m_le) {
protected slots: ((QWidget*)m_le)->setEnabled(i);
virtual void showInputDialog(); }
void deleteSelected(); }
signals: protected:
void entryDeleted(QString); QLineEdit *m_le;
protected: QString m_origvalue;
QListWidget *m_lb; };
void listToConf();
};
// Dir name list // Constrained string: choose from list
class ConfParamDNLW : public ConfParamSLW { class ConfParamCStrW : public ConfParamW {
Q_OBJECT Q_OBJECT
public: public:
ConfParamDNLW(QWidget *parent, ConfLink cflink, ConfParamCStrW(const QString& varnm, QWidget *parent, ConfLink cflink,
const QString& lbltxt, const QString& lbltxt,
const QString& tltptxt) const QString& tltptxt, const QStringList& sl);
: ConfParamSLW(parent, cflink, lbltxt, tltptxt) virtual void loadValue();
{ virtual void storeValue();
m_fsencoding = true; virtual void setList(const QStringList& sl);
} public slots:
protected slots: virtual void setEnabled(bool i) {
virtual void showInputDialog(); if (m_cmb) {
}; ((QWidget*)m_cmb)->setEnabled(i);
}
}
protected:
QComboBox *m_cmb;
QString m_origvalue;
};
// Constrained string list (chose from predefined) // File name
class ConfParamCSLW : public ConfParamSLW { class ConfParamFNW : public ConfParamW {
Q_OBJECT Q_OBJECT
public: public:
ConfParamCSLW(QWidget *parent, ConfLink cflink, ConfParamFNW(const QString& varnm, QWidget *parent, ConfLink cflink,
const QString& lbltxt, const QString& lbltxt,
const QString& tltptxt, const QString& tltptxt, bool isdir = false);
const QStringList& sl) virtual void loadValue();
: ConfParamSLW(parent, cflink, lbltxt, tltptxt), m_sl(sl) virtual void storeValue();
{ protected slots:
} void showBrowserDialog();
protected slots: public slots:
virtual void showInputDialog(); virtual void setEnabled(bool i) {
protected: if (m_le) {
const QStringList m_sl; ((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:
*
* <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>
* mpdhost = default-host
* <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>
* mpdport = defport
* <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>
* ownqueue =
* </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[output] toptxt the top level XML text (text not inside <var>,
* 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_ */ #endif /* _confgui_h_included_ */

View File

@ -28,15 +28,14 @@
#include <qcheckbox.h> #include <qcheckbox.h>
#include <QListWidget> #include <QListWidget>
#include <list> #include <vector>
#include <set> #include <set>
#include <string> #include <string>
#include <functional> #include <functional>
using std::list; using std::vector;
using std::set; using std::set;
using std::string; using std::string;
#include "confgui.h"
#include "recoll.h" #include "recoll.h"
#include "confguiindex.h" #include "confguiindex.h"
#include "smallut.h" #include "smallut.h"
@ -45,95 +44,90 @@ using std::string;
#include "execmd.h" #include "execmd.h"
#include "rclconfig.h" #include "rclconfig.h"
namespace confgui {
static const int spacing = 3; static const int spacing = 3;
static const int margin = 3; static const int margin = 3;
/** using namespace confgui;
* A Gui-to-Data link class for ConfTree
* Has a subkey pointer member which makes it easy to change the /* Link class for ConfTree. Has a subkey pointer member which makes it easy
* current subkey for a number at a time. * to change the current subkey for multiple instances. */
*/
class ConfLinkRclRep : public ConfLinkRep { class ConfLinkRclRep : public ConfLinkRep {
public: public:
ConfLinkRclRep(ConfNull *conf, const string& nm, ConfLinkRclRep(ConfNull **conf, const string& nm, string *sk = 0)
string *sk = 0)
: m_conf(conf), m_nm(nm), m_sk(sk) /* KEEP THE POINTER, shared data */ : m_conf(conf), m_nm(nm), m_sk(sk) /* KEEP THE POINTER, shared data */
{ } {}
virtual ~ConfLinkRclRep() {} virtual ~ConfLinkRclRep() {}
virtual bool set(const string& val) { virtual bool set(const string& val) {
if (!m_conf) if (!m_conf || !*m_conf)
return false; 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) if (!ret)
LOGERR("Value set failed\n" ); LOGERR("Value set failed\n" );
return ret; return ret;
} }
virtual bool get(string& val) { virtual bool get(string& val) {
if (!m_conf) if (!m_conf || !*m_conf)
return false; 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 [" << LOGDEB1("ConfLinkRcl::get: [" << m_nm << "] sk [" <<
getSk() << "] -> [" << (ret ? val : "no value") << "]\n" ); getSk() << "] -> [" << (ret ? val : "no value") << "]\n");
return ret; return ret;
} }
private: private:
string getSk() { string getSk() {
return m_sk ? *m_sk : string(); return m_sk ? *m_sk : string();
} }
ConfNull *m_conf; ConfNull **m_conf;
const string m_nm; const string m_nm;
const string *m_sk; const string *m_sk;
}; };
typedef std::function<vector<string>()> RclConfVecValueGetter;
/* Special link for skippedNames and noContentSuffixes which are /* Special link for skippedNames and noContentSuffixes which are
computed as set differences */ computed as set differences */
typedef std::function<vector<string>()> RclConfVecValueGetter;
class ConfLinkPlusMinus : public ConfLinkRep { class ConfLinkPlusMinus : public ConfLinkRep {
public: public:
ConfLinkPlusMinus(RclConfig *rclconf, ConfNull *conf, ConfLinkPlusMinus(RclConfig *rclconf, ConfNull **conf,
const string& basename, RclConfVecValueGetter getter, const string& basename, RclConfVecValueGetter getter,
string *sk = 0) string *sk = 0)
: m_rclconf(rclconf), m_conf(conf), : m_rclconf(rclconf), m_conf(conf),
m_basename(basename), m_getter(getter), 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 ~ConfLinkPlusMinus() {}
virtual bool set(const string& snval) { virtual bool set(const string& snval) {
if (!m_conf || !m_rclconf) if (!m_conf || !*m_conf || !m_rclconf)
return false; return false;
string sbase; string sbase;
m_conf->get(m_basename, sbase, getSk()); (*m_conf)->get(m_basename, sbase, getSk());
std::set<string> nval; std::set<string> nval;
stringToStrings(snval, nval); stringToStrings(snval, nval);
string splus, sminus; string splus, sminus;
RclConfig::setPlusMinus(sbase, nval, splus, sminus); RclConfig::setPlusMinus(sbase, nval, splus, sminus);
LOGDEB1("ConfLinkPlusMinus: base [" << sbase << "] nvalue [" << snval << LOGDEB1("ConfLinkPlusMinus: base [" << sbase << "] nvalue [" << snval <<
"] splus [" << splus << "] sminus [" << sminus << "]\n"); "] splus [" << splus << "] sminus [" << sminus << "]\n");
if (!m_conf->set(m_basename + "-", sminus, getSk())) { if (!(*m_conf)->set(m_basename + "-", sminus, getSk())) {
return false; return false;
} }
if (!m_conf->set(m_basename + "+", splus, getSk())) { if (!(*m_conf)->set(m_basename + "+", splus, getSk())) {
return false; return false;
} }
return true; return true;
} }
virtual bool get(string& val) { 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; return false;
m_rclconf->setKeyDir(getSk()); m_rclconf->setKeyDir(getSk());
vector<string> vval = m_getter(); vector<string> vval = m_getter();
val = stringsToString(vval); val = stringsToString(vval);
LOGDEB1("ConfLinkPlusMinus: "<<m_basename<<" -> " << val <<std::endl); LOGDEB1("ConfLinkPlusMinus: " << m_basename << " -> " << val << "\n");
return true; return true;
} }
@ -143,34 +137,58 @@ private:
} }
RclConfig *m_rclconf; RclConfig *m_rclconf;
ConfNull *m_conf; ConfNull **m_conf;
string m_basename; string m_basename;
RclConfVecValueGetter m_getter; RclConfVecValueGetter m_getter;
const string *m_sk; const string *m_sk;
}; };
ConfIndexW::ConfIndexW(QWidget *parent, RclConfig *config) class MyConfLinkFactRCL : public ConfLinkFact {
: QDialog(parent), m_rclconf(config) 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: ")); delete m_conf;
title += QString::fromLocal8Bit(config->getConfDir().c_str()); if (((m_conf = m_rclconf->cloneMainConfig()) == 0)) {
setWindowTitle(title); return;
tabWidget = new QTabWidget; }
reloadPanels(); m_conf->holdWrites(true);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok if (nullptr == m_w) {
| QDialogButtonBox::Cancel); 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; m_w->reloadPanels();
mainLayout->addWidget(tabWidget); if (modal) {
mainLayout->addWidget(buttonBox); m_w->exec();
setLayout(mainLayout); m_w->setModal(false);
} else {
resize(QSize(600, 450).expandedTo(minimumSizeHint())); m_w->show();
}
connect(buttonBox, SIGNAL(accepted()), this, SLOT(acceptChanges()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(rejectChanges()));
} }
void ConfIndexW::acceptChanges() void ConfIndexW::acceptChanges()
@ -180,7 +198,6 @@ void ConfIndexW::acceptChanges()
LOGERR("ConfIndexW::acceptChanges: no config\n" ); LOGERR("ConfIndexW::acceptChanges: no config\n" );
return; return;
} }
// Let the changes to disk
if (!m_conf->holdWrites(false)) { if (!m_conf->holdWrites(false)) {
QMessageBox::critical(0, "Recoll", QMessageBox::critical(0, "Recoll",
tr("Can't write configuration file")); tr("Can't write configuration file"));
@ -189,292 +206,190 @@ void ConfIndexW::acceptChanges()
delete m_conf; delete m_conf;
m_conf = 0; m_conf = 0;
m_rclconf->updateMainConfig(); m_rclconf->updateMainConfig();
hide();
} }
void ConfIndexW::rejectChanges() void ConfIndexW::initPanels()
{ {
LOGDEB("ConfIndexW::rejectChanges()\n" ); int idx = m_w->addPanel(tr("Global parameters"));
// Discard local changes. setupTopPanel(idx);
delete m_conf;
m_conf = 0;
hide();
}
void ConfIndexW::reloadPanels() idx = m_w->addForeignPanel(
{ new ConfSubPanelW(m_w, &m_conf, m_rclconf),
if ((m_conf = m_rclconf->cloneMainConfig()) == 0) tr("Local parameters"));
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"));
#ifndef _WIN32 #ifndef _WIN32
w = new ConfBeaglePanelW(this, m_conf); idx = m_w->addPanel("Web history");
m_widgets.push_back(w); setupWebHistoryPanel(idx);
tabWidget->addTab(w, QObject::tr("Web history"));
#endif #endif
w = new ConfSearchPanelW(this, m_conf);
m_widgets.push_back(w); idx = m_w->addPanel(tr("Search parameters"));
tabWidget->addTab(w, QObject::tr("Search parameters")); setupSearchPanel(idx);
} }
ConfBeaglePanelW::ConfBeaglePanelW(QWidget *parent, ConfNull *config) bool ConfIndexW::setupTopPanel(int idx)
: QWidget(parent)
{ {
QVBoxLayout *vboxLayout = new QVBoxLayout(this); m_w->addParam(idx, ConfTabsW::CFPT_DNL, "topdirs",
vboxLayout->setSpacing(spacing); tr("Top directories"),
vboxLayout->setMargin(margin); tr("The list of directories where recursive "
"indexing starts. Default: your home."));
ConfLink lnk1(new ConfLinkRclRep(config, "processwebqueue")); ConfParamW *cparam = m_w->addParam(
ConfParamBoolW* cp1 = idx, ConfTabsW::CFPT_STRL, "skippedPaths", tr("Skipped paths"),
new ConfParamBoolW(this, lnk1, tr("Process the WEB history queue"), tr("These are pathnames of directories which indexing "
tr("Enables indexing Firefox visited pages.<br>" "will not enter.<br>Path elements may contain wildcards. "
"(you need also install the Firefox Recoll plugin)" "The entries must match the paths seen by the indexer "
)); "(e.g.: if topdirs includes '/home/me' and '/home' is "
vboxLayout->addWidget(cp1); "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<string> 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<br>"
"dictionaries will be built."), 0, 0, &m_stemlangs);
ConfLink lnk2(new ConfLinkRclRep(config, "webcachedir")); m_w->addParam(idx, ConfTabsW::CFPT_FN, "logfilename",
ConfParamFNW* cp2 = tr("Log file name"),
new ConfParamFNW(this, lnk2, tr("Web page store directory name"), tr("The file where the messages will be written.<br>"
tr("The name for a directory where to store the copies " "Use 'stderr' for terminal output"), 0);
"of visited web pages.<br>"
"A non-absolute path is taken relative to the " m_w->addParam(
"configuration directory."), true); idx, ConfTabsW::CFPT_INT, "loglevel", tr("Log verbosity level"),
cp2->setEnabled(cp1->m_cb->isChecked()); tr("This value adjusts the amount of messages,<br>from only "
connect(cp1->m_cb, SIGNAL(toggled(bool)), cp2, SLOT(setEnabled(bool))); "errors to a lot of debugging data."), 0, 6);
vboxLayout->addWidget(cp2);
ConfLink lnk3(new ConfLinkRclRep(config, "webcachemaxmbs")); m_w->addParam(idx, ConfTabsW::CFPT_INT, "idxflushmb",
ConfParamIntW *cp3 = tr("Index flush megabytes interval"),
new ConfParamIntW(this, lnk3, tr("Max. size for the web store (MB)"), tr("This value adjust the amount of "
tr("Entries will be recycled once the size is reached." "data which is indexed between flushes to disk.<br>"
"<br>" "This helps control the indexer memory usage. "
"Only increasing the size really makes sense because " "Default 10MB "), 0, 1000);
"reducing the value will not truncate an existing "
"file (only waste space at the end)." m_w->addParam(idx, ConfTabsW::CFPT_INT, "maxfsoccuppc",
), tr("Max disk occupation (%, 0 means no limit)"),
-1, 1000*1000); // Max 1TB... tr("This is the percentage of disk usage "
cp3->setEnabled(cp1->m_cb->isChecked()); "- total disk usage, not index size - at which "
connect(cp1->m_cb, SIGNAL(toggled(bool)), cp3, SLOT(setEnabled(bool))); "indexing will fail and stop.<br>"
vboxLayout->addWidget(cp3); "The default value of 0 removes any limit."), 0, 100);
vboxLayout->insertStretch(-1);
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.<br> "
"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' ...<br>"
"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<br>"
"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("<p>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) bool ConfIndexW::setupWebHistoryPanel(int idx)
: QWidget(parent)
{ {
QVBoxLayout *vboxLayout = new QVBoxLayout(this); ConfParamW *bparam = m_w->addParam(
vboxLayout->setSpacing(spacing); idx, ConfTabsW::CFPT_BOOL, "processwebqueue",
vboxLayout->setMargin(margin); tr("Process the WEB history queue"),
tr("Enables indexing Firefox visited pages.<br>"
"(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.<br>"
"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."
"<br>"
"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) { if (!o_index_stripchars) {
ConfLink lnk1(new ConfLinkRclRep(config, "autodiacsens")); m_w->addParam(idx, ConfTabsW::CFPT_BOOL, "autodiacsens",
ConfParamBoolW* cp1 = tr("Automatic diacritics sensitivity"),
new ConfParamBoolW(this, lnk1, tr("Automatic diacritics sensitivity"), tr("<p>Automatically trigger diacritics sensitivity "
tr("<p>Automatically trigger diacritics sensitivity " "if the search term has accented characters "
"if the search term has accented characters " "(not in unac_except_trans). Else you need to "
"(not in unac_except_trans). Else you need to " "use the query language and the <i>D</i> "
"use the query language and the <i>D</i> " "modifier to specify diacritics sensitivity."));
"modifier to specify "
"diacritics sensitivity."
));
vboxLayout->addWidget(cp1);
ConfLink lnk2(new ConfLinkRclRep(config, "autocasesens")); m_w->addParam(idx, ConfTabsW::CFPT_BOOL, "autocasesens",
ConfParamBoolW* cp2 = tr("Automatic character case sensitivity"),
new ConfParamBoolW(this, lnk2, tr("<p>Automatically trigger character case "
tr("Automatic character case sensitivity"), "sensitivity if the entry has upper-case "
tr("<p>Automatically trigger character case " "characters in any but the first position. "
"sensitivity if the entry has upper-case " "Else you need to use the query language and "
"characters in any but the first position. " "the <i>C</i> modifier to specify character-case "
"Else you need to use the query language and " "sensitivity."));
"the <i>C</i> modifier to specify character-case "
"sensitivity."
));
vboxLayout->addWidget(cp2);
} }
ConfLink lnk3(new ConfLinkRclRep(config, "maxTermExpand")); m_w->addParam(idx, ConfTabsW::CFPT_INT, "maxTermExpand",
ConfParamIntW* cp3 = tr("Maximum term expansion count"),
new ConfParamIntW(this, lnk3, tr("<p>Maximum expansion count for a single term "
tr("Maximum term expansion count"), "(e.g.: when using wildcards). The default "
tr("<p>Maximum expansion count for a single term " "of 10 000 is reasonable and will avoid "
"(e.g.: when using wildcards). The default " "queries that appear frozen while the engine is "
"of 10 000 is reasonable and will avoid " "walking the term list."), 0, 100000);
"queries that appear frozen while the engine is "
"walking the term list."
));
vboxLayout->addWidget(cp3);
m_w->addParam(idx, ConfTabsW::CFPT_INT, "maxXapianClauses",
tr("Maximum Xapian clauses count"),
tr("<p>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")); m_w->endOfList(idx);
ConfParamIntW* cp4 = return true;
new ConfParamIntW(this, lnk4,
tr("Maximum Xapian clauses count"),
tr("<p>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);
} }
ConfTopPanelW::ConfTopPanelW(QWidget *parent, ConfNull *config) ConfSubPanelW::ConfSubPanelW(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.<br>"
"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<string> cstemlangs = Rcl::Db::getStemmerNames();
QStringList stemlangs;
for (vector<string>::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<br>"
"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.<br>"
"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,<br>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.<br>"
"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.<br>"
"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.<br> "
"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' ...<br>"
"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<br>"
"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("<p>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,
RclConfig *rclconf) RclConfig *rclconf)
: QWidget(parent), m_config(config) : QWidget(parent), m_config(config)
{ {
@ -482,14 +397,14 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
vboxLayout->setSpacing(spacing); vboxLayout->setSpacing(spacing);
vboxLayout->setMargin(margin); vboxLayout->setMargin(margin);
m_subdirs = new m_subdirs = new ConfParamDNLW(
ConfParamDNLW(this, "bogus00", this, ConfLink(new confgui::ConfLinkNullRep()),
ConfLink(new ConfLinkNullRep()), QObject::tr("<b>Customised subtrees"),
QObject::tr("<b>Customised subtrees"), QObject::tr("The list of subdirectories in the indexed "
QObject::tr("The list of subdirectories in the indexed " "hierarchy <br>where some parameters need "
"hierarchy <br>where some parameters need " "to be redefined. Default: empty."));
"to be redefined. Default: empty.")); m_subdirs->getListBox()->setSelectionMode(
m_subdirs->getListBox()->setSelectionMode(QAbstractItemView::SingleSelection); QAbstractItemView::SingleSelection);
connect(m_subdirs->getListBox(), connect(m_subdirs->getListBox(),
SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)),
this, this,
@ -502,14 +417,13 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
// customized in the system config like .thunderbird or // customized in the system config like .thunderbird or
// .purple. This doesn't prevent them to add and customize them // .purple. This doesn't prevent them to add and customize them
// further. // further.
vector<string> allkeydirs = config->getSubKeys(true); vector<string> allkeydirs = (*config)->getSubKeys(true);
QStringList qls; QStringList qls;
for (vector<string>::const_iterator it = allkeydirs.begin(); for (const auto& dir: allkeydirs) {
it != allkeydirs.end(); it++) { qls.push_back(u8s2qs(dir));
qls.push_back(QString::fromUtf8(it->c_str()));
} }
m_subdirs->getListBox()->insertItems(0, qls); m_subdirs->getListBox()->insertItems(0, qls);
vboxLayout->addWidget(m_subdirs); vboxLayout->addWidget(m_subdirs);
QFrame *line2 = new QFrame(this); QFrame *line2 = new QFrame(this);
@ -520,13 +434,13 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
QLabel *explain = new QLabel(this); QLabel *explain = new QLabel(this);
explain->setWordWrap(true); explain->setWordWrap(true);
explain->setText( explain->setText(
QObject:: QObject::tr(
tr("<i>The parameters that follow are set either at the " "<i>The parameters that follow are set either at the "
"top level, if nothing " "top level, if nothing "
"or an empty line is selected in the listbox above, " "or an empty line is selected in the listbox above, "
"or for the selected subdirectory. " "or for the selected subdirectory. "
"You can add or remove directories by clicking " "You can add or remove directories by clicking "
"the +/- buttons.")); "the +/- buttons."));
vboxLayout->addWidget(explain); vboxLayout->addWidget(explain);
@ -539,7 +453,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
int gridy = 0; int gridy = 0;
ConfParamSLW *eskn = new ConfParamSLW( ConfParamSLW *eskn = new ConfParamSLW(
m_groupbox, "skippedNames", m_groupbox,
ConfLink(new ConfLinkPlusMinus( ConfLink(new ConfLinkPlusMinus(
rclconf, config, "skippedNames", rclconf, config, "skippedNames",
std::bind(&RclConfig::getSkippedNames, rclconf), &m_sk)), std::bind(&RclConfig::getSkippedNames, rclconf), &m_sk)),
@ -552,13 +466,12 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
vector<string> amimes = rclconf->getAllMimeTypes(); vector<string> amimes = rclconf->getAllMimeTypes();
QStringList amimesq; QStringList amimesq;
for (vector<string>::const_iterator it = amimes.begin(); for (const auto& mime: amimes) {
it != amimes.end(); it++) { amimesq.push_back(u8s2qs(mime));
amimesq.push_back(QString::fromUtf8(it->c_str()));
} }
ConfParamCSLW *eincm = new ConfParamCSLW( ConfParamCSLW *eincm = new ConfParamCSLW(
m_groupbox, "indexedmimetypes", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "indexedmimetypes", &m_sk)), ConfLink(new ConfLinkRclRep(config, "indexedmimetypes", &m_sk)),
tr("Only mime types"), tr("Only mime types"),
tr("An exclusive list of indexed mime types.<br>Nothing " tr("An exclusive list of indexed mime types.<br>Nothing "
@ -567,7 +480,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
gl1->addWidget(eincm, gridy++, 1); gl1->addWidget(eincm, gridy++, 1);
ConfParamCSLW *eexcm = new ConfParamCSLW( ConfParamCSLW *eexcm = new ConfParamCSLW(
m_groupbox, "excludedmimetypes", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "excludedmimetypes", &m_sk)), ConfLink(new ConfLinkRclRep(config, "excludedmimetypes", &m_sk)),
tr("Exclude mime types"), tr("Exclude mime types"),
tr("Mime types not to be indexed"), amimesq); tr("Mime types not to be indexed"), amimesq);
@ -575,7 +488,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
gl1->addWidget(eexcm, gridy, 0); gl1->addWidget(eexcm, gridy, 0);
ConfParamSLW *encs = new ConfParamSLW( ConfParamSLW *encs = new ConfParamSLW(
m_groupbox, "noContentSuffixes", m_groupbox,
ConfLink(new ConfLinkPlusMinus( ConfLink(new ConfLinkPlusMinus(
rclconf, config, "noContentSuffixes", rclconf, config, "noContentSuffixes",
std::bind(&RclConfig::getStopSuffixes, rclconf), &m_sk)), std::bind(&RclConfig::getStopSuffixes, rclconf), &m_sk)),
@ -594,20 +507,19 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
string cmd = "iconv"; string cmd = "iconv";
int status = ex.doexec(cmd, args, 0, &icout); int status = ex.doexec(cmd, args, 0, &icout);
if (status) { 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, ","); icout = neutchars(icout, ",");
list<string> ccsets; vector<string> ccsets;
stringToStrings(icout, ccsets); stringToStrings(icout, ccsets);
QStringList charsets; QStringList charsets;
charsets.push_back(""); charsets.push_back("");
for (list<string>::const_iterator it = ccsets.begin(); for (const auto& charset : ccsets) {
it != ccsets.end(); it++) { charsets.push_back(u8s2qs(charset));
charsets.push_back(QString::fromUtf8(it->c_str()));
} }
ConfParamCStrW *e21 = new ConfParamCStrW( ConfParamCStrW *e21 = new ConfParamCStrW(
m_groupbox, "defaultcharset", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "defaultcharset", &m_sk)), ConfLink(new ConfLinkRclRep(config, "defaultcharset", &m_sk)),
QObject::tr("Default<br>character set"), QObject::tr("Default<br>character set"),
QObject::tr("Character set used for reading files " QObject::tr("Character set used for reading files "
@ -620,7 +532,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
gl1->addWidget(e21, gridy++, 0); gl1->addWidget(e21, gridy++, 0);
ConfParamBoolW *e3 = new ConfParamBoolW( ConfParamBoolW *e3 = new ConfParamBoolW(
m_groupbox, "followLinks", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "followLinks", &m_sk)), ConfLink(new ConfLinkRclRep(config, "followLinks", &m_sk)),
QObject::tr("Follow symbolic links"), QObject::tr("Follow symbolic links"),
QObject::tr("Follow symbolic links while " QObject::tr("Follow symbolic links while "
@ -630,7 +542,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
gl1->addWidget(e3, gridy, 0); gl1->addWidget(e3, gridy, 0);
ConfParamBoolW *eafln = new ConfParamBoolW( ConfParamBoolW *eafln = new ConfParamBoolW(
m_groupbox, "indexallfilenames", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "indexallfilenames", &m_sk)), ConfLink(new ConfLinkRclRep(config, "indexallfilenames", &m_sk)),
QObject::tr("Index all file names"), QObject::tr("Index all file names"),
QObject::tr("Index the names of files for which the contents " 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); gl1->addWidget(eafln, gridy++, 1);
ConfParamIntW *ezfmaxkbs = new ConfParamIntW( ConfParamIntW *ezfmaxkbs = new ConfParamIntW(
m_groupbox, "compressedfilemaxkbs", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "compressedfilemaxkbs", &m_sk)), ConfLink(new ConfLinkRclRep(config, "compressedfilemaxkbs", &m_sk)),
tr("Max. compressed file size (KB)"), tr("Max. compressed file size (KB)"),
tr("This value sets a threshold beyond which compressed" tr("This value sets a threshold beyond which compressed"
@ -650,7 +562,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
gl1->addWidget(ezfmaxkbs, gridy, 0); gl1->addWidget(ezfmaxkbs, gridy, 0);
ConfParamIntW *etxtmaxmbs = new ConfParamIntW( ConfParamIntW *etxtmaxmbs = new ConfParamIntW(
m_groupbox, "textfilemaxmbs", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "textfilemaxmbs", &m_sk)), ConfLink(new ConfLinkRclRep(config, "textfilemaxmbs", &m_sk)),
tr("Max. text file size (MB)"), tr("Max. text file size (MB)"),
tr("This value sets a threshold beyond which text " tr("This value sets a threshold beyond which text "
@ -661,7 +573,7 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
gl1->addWidget(etxtmaxmbs, gridy++, 1); gl1->addWidget(etxtmaxmbs, gridy++, 1);
ConfParamIntW *etxtpagekbs = new ConfParamIntW( ConfParamIntW *etxtpagekbs = new ConfParamIntW(
m_groupbox, "textfilepagekbs", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "textfilepagekbs", &m_sk)), ConfLink(new ConfLinkRclRep(config, "textfilepagekbs", &m_sk)),
tr("Text file page size (KB)"), tr("Text file page size (KB)"),
tr("If this value is set (not equal to -1), text " 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); gl1->addWidget(etxtpagekbs, gridy, 0);
ConfParamIntW *efiltmaxsecs = new ConfParamIntW( ConfParamIntW *efiltmaxsecs = new ConfParamIntW(
m_groupbox, "filtermaxseconds", m_groupbox,
ConfLink(new ConfLinkRclRep(config, "filtermaxseconds", &m_sk)), ConfLink(new ConfLinkRclRep(config, "filtermaxseconds", &m_sk)),
tr("Max. filter exec. time (s)"), tr("Max. filter exec. time (s)"),
tr("External filters working longer than this will be " tr("External filters working longer than this will be "
@ -684,47 +596,55 @@ ConfSubPanelW::ConfSubPanelW(QWidget *parent, ConfNull *config,
vboxLayout->addWidget(m_groupbox); vboxLayout->addWidget(m_groupbox);
subDirChanged(0, 0); subDirChanged(0, 0);
LOGDEB("ConfSubPanelW::ConfSubPanelW: done\n");
} }
void ConfSubPanelW::reloadAll() void ConfSubPanelW::loadValues()
{ {
for (list<ConfParamW*>::iterator it = m_widgets.begin(); LOGDEB("ConfSubPanelW::loadValues\n");
it != m_widgets.end(); it++) { for (auto widget : m_widgets) {
(*it)->loadValue(); widget->loadValue();
}
LOGDEB("ConfSubPanelW::loadValues done\n");
}
void ConfSubPanelW::storeValues()
{
for (auto widget : m_widgets) {
widget->storeValue();
} }
} }
void ConfSubPanelW::subDirChanged(QListWidgetItem *current, QListWidgetItem *) void ConfSubPanelW::subDirChanged(QListWidgetItem *current, QListWidgetItem *)
{ {
LOGDEB("ConfSubPanelW::subDirChanged\n" ); LOGDEB("ConfSubPanelW::subDirChanged\n");
if (current == 0 || current->text() == "") { if (current == 0 || current->text() == "") {
m_sk = ""; m_sk = "";
m_groupbox->setTitle(tr("Global")); m_groupbox->setTitle(tr("Global"));
} else { } else {
m_sk = (const char *) current->text().toUtf8(); m_sk = qs2utf8s(current->text());
m_groupbox->setTitle(current->text()); m_groupbox->setTitle(current->text());
} }
LOGDEB("ConfSubPanelW::subDirChanged: now [" << (m_sk) << "]\n" ); LOGDEB("ConfSubPanelW::subDirChanged: now [" << m_sk << "]\n");
reloadAll(); loadValues();
LOGDEB("ConfSubPanelW::subDirChanged: done\n");
} }
void ConfSubPanelW::subDirDeleted(QString sbd) void ConfSubPanelW::subDirDeleted(QString sbd)
{ {
LOGDEB("ConfSubPanelW::subDirDeleted(" << ((const char *)sbd.toUtf8()) << ")\n" ); LOGDEB("ConfSubPanelW::subDirDeleted(" << qs2utf8s(sbd) << ")\n");
if (sbd == "") { if (sbd == "") {
// Can't do this, have to reinsert it // Can't do this, have to reinsert it
QTimer::singleShot(0, this, SLOT(restoreEmpty())); QTimer::singleShot(0, this, SLOT(restoreEmpty()));
return; return;
} }
// Have to delete all entries for submap // Have to delete all entries for submap
m_config->eraseKey((const char *)sbd.toUtf8()); (*m_config)->eraseKey(qs2utf8s(sbd));
} }
void ConfSubPanelW::restoreEmpty() void ConfSubPanelW::restoreEmpty()
{ {
LOGDEB("ConfSubPanelW::restoreEmpty()\n" ); LOGDEB("ConfSubPanelW::restoreEmpty()\n");
m_subdirs->getListBox()->insertItem(0, ""); m_subdirs->getListBox()->insertItem(0, "");
} }
} // Namespace confgui

View File

@ -30,78 +30,61 @@
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QTabWidget> #include <QTabWidget>
#include <QListWidgetItem> #include <QListWidgetItem>
#include <QStringList>
#include <string> #include <string>
#include <list> #include <vector>
using std::string;
using std::list; #include "confgui.h"
class ConfNull; class ConfNull;
class RclConfig; class RclConfig;
class ConfParamW;
class ConfParamDNLW;
namespace confgui { class ConfIndexW : public QWidget {
class ConfIndexW : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
ConfIndexW(QWidget *parent, RclConfig *config); ConfIndexW(QWidget *parent, RclConfig *config)
: m_parent(parent), m_rclconf(config) {}
public slots: public slots:
void showPrefs(bool modal);
void acceptChanges(); void acceptChanges();
void rejectChanges(); QWidget *getDialog() {return m_w;}
void reloadPanels();
private: private:
void initPanels();
bool setupTopPanel(int idx);
bool setupWebHistoryPanel(int idx);
bool setupSearchPanel(int idx);
QWidget *m_parent;
RclConfig *m_rclconf; RclConfig *m_rclconf;
ConfNull *m_conf; ConfNull *m_conf{nullptr};
list<QWidget *> m_widgets; confgui::ConfTabsW *m_w{nullptr};
QTabWidget *tabWidget; QStringList m_stemlangs;
QDialogButtonBox *buttonBox;
}; };
/**
* 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 special panel for parameters which may change in subdirectories: */
* A panel for the parameters that can be changed in subdirectories: class ConfSubPanelW : public QWidget, public confgui::ConfPanelWIF {
*/ Q_OBJECT;
class ConfSubPanelW : public QWidget {
Q_OBJECT
public: public:
ConfSubPanelW(QWidget *parent, ConfNull *config, RclConfig *rclconf); ConfSubPanelW(QWidget *parent, ConfNull **config, RclConfig *rclconf);
virtual void storeValues();
virtual void loadValues();
private slots: private slots:
void subDirChanged(QListWidgetItem *, QListWidgetItem *); void subDirChanged(QListWidgetItem *, QListWidgetItem *);
void subDirDeleted(QString); void subDirDeleted(QString);
void restoreEmpty(); void restoreEmpty();
private: private:
string m_sk; std::string m_sk;
ConfParamDNLW *m_subdirs; ConfNull **m_config;
list<ConfParamW*> m_widgets; confgui::ConfParamDNLW *m_subdirs;
ConfNull *m_config; std::vector<confgui::ConfParamW*> m_widgets;
QGroupBox *m_groupbox; 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_ */ #endif /* _confguiindex_h_included_ */

View File

@ -175,20 +175,15 @@ void RclMain::execIndexConfig()
void RclMain::showIndexConfig(bool modal) void RclMain::showIndexConfig(bool modal)
{ {
LOGDEB("showIndexConfig()\n" ); LOGDEB("showIndexConfig()\n" );
bool created{false};
if (indexConfig == 0) { if (indexConfig == 0) {
created = true;
indexConfig = new ConfIndexW(0, theconfig); 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->showPrefs(modal);
indexConfig->exec(); if (created) {
indexConfig->setModal(false); connect(new QShortcut(quitKeySeq, indexConfig->getDialog()),
} else { SIGNAL (activated()), this, SLOT (fileExit()));
indexConfig->show();
} }
} }

View File

@ -45,16 +45,11 @@ class RTIToolW;
class FragButs; class FragButs;
class SpecIdxW; class SpecIdxW;
class WebcacheEdit; class WebcacheEdit;
class ConfIndexW;
class RclTrayIcon;
#include "ui_rclmain.h" #include "ui_rclmain.h"
namespace confgui {
class ConfIndexW;
}
using confgui::ConfIndexW;
class RclTrayIcon;
class RclMain : public QMainWindow, public Ui::RclMainBase { class RclMain : public QMainWindow, public Ui::RclMainBase {
Q_OBJECT; Q_OBJECT;