Switch to unified view

a b/cfgui/confgui.h
1
/* Copyright (C) 2007-2018 J.F.Dockes
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
6
 *
7
 *   This program is distributed in the hope that it will be useful,
8
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 *   GNU General Public License for more details.
11
 *
12
 *   You should have received a copy of the GNU General Public License
13
 *   along with this program; if not, write to the
14
 *   Free Software Foundation, Inc.,
15
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
16
 */
17
#ifndef _confgui_h_included_
18
#define _confgui_h_included_
19
/**
20
 * This file defines a number of simple classes (virtual base: ConfParamW)
21
 * which let the user input configuration parameters.
22
 *
23
 * Subclasses are defined for entering different kind of data, ie a string,
24
 * a file name, an integer, etc.
25
 *
26
 * Each configuration gui object is linked to the configuration data through
27
 * a "link" object which knows the details of interacting with the actual
28
 * configuration data, like the parameter name, the actual config object,
29
 * the method to call etc.
30
 *
31
 * The link object is set when the input widget is created and cannot be
32
 * changed.
33
 *
34
 * The widgets are typically linked to a temporary configuration object, which
35
 * is then copied to the actual configuration if the data is accepted, or
36
 * destroyed and recreated as a copy if Cancel is pressed (you have to
37
 * delete/recreate the widgets in this case as the links are no longer valid).
38
 *
39
 * The set() methods of the link objects are only called if the
40
 * current value() differs from the value obtained by get() when the
41
 * object was initialized. This can be used to avoid cluttering the
42
 * output with values which are unmodified from the defaults.
43
 *
44
 * The file also defines a multi-tabbed dialog container for the
45
 * parameter objects, with simple interface methods to create/add
46
 * panels and elements.
47
 */
48
49
#include <string>
50
#include <limits.h>
51
52
#include <memory>
53
#include <vector>
54
#include <string>
55
56
#include <QString>
57
#include <QWidget>
58
#include <QDialog>
59
60
class ConfNull;
61
class QCheckBox;
62
class QComboBox;
63
class QDialogButtonBox;
64
class QHBoxLayout;
65
class QLineEdit;
66
class QListWidget;
67
class QPushButton;
68
class QSpinBox;
69
class QTabWidget;
70
class QVBoxLayout;
71
72
namespace confgui {
73
74
/** Interface between the GUI widget and the config storage mechanism: */
75
class ConfLinkRep {
76
public:
77
    virtual ~ConfLinkRep() {}
78
    virtual bool set(const std::string& val) = 0;
79
    virtual bool get(std::string& val) = 0;
80
};
81
typedef std::shared_ptr<ConfLinkRep> ConfLink;
82
83
/** Link maker class */
84
class ConfLinkFact {
85
public:
86
    virtual ~ConfLinkFact() {}
87
    virtual ConfLink operator()(const QString& nm) = 0;
88
};
89
90
class ConfPanelWIF {
91
public:
92
    virtual ~ConfPanelWIF() {}
93
    virtual void storeValues() = 0;
94
    virtual void loadValues() = 0;
95
};
96
97
class ConfPanelW;
98
class ConfParamW;
99
100
/** The top level widget has tabs, each tab/panel has multiple widgets
101
 *  for setting parameter values */
102
class ConfTabsW : public QDialog {
103
    Q_OBJECT;
104
105
public:
106
    ConfTabsW(QWidget *parent, const QString& title, ConfLinkFact *linkfact);
107
108
    enum ParamType {CFPT_BOOL, CFPT_INT, CFPT_STR, CFPT_CSTR, CFPT_FN,
109
                    CFPT_STRL, CFPT_DNL, CFPT_CSTRL
110
    };
111
112
    /** Add tab and return its identifier / index */
113
    int addPanel(const QString& title);
114
115
    /** Add foreign tab where we only know to call loadvalues/storevalues.
116
     * The object has to derive from QWidget */
117
    int addForeignPanel(ConfPanelWIF* w, const QString& title);
118
119
    /** Add parameter setter to specified tab */
120
    ConfParamW *addParam(int tabindex, ParamType tp,
121
                         const QString& varname, const QString& label,
122
                         const QString& tooltip, int isdirorminval = 0,
123
                         int maxval = 0, const QStringList* sl = 0);
124
    bool enableLink(ConfParamW* boolw, ConfParamW* otherw, bool revert = false);
125
    void endOfList(int tabindex);
126
127
    /** Find param widget associated with given variable name */
128
    ConfParamW *findParamW(const QString& varname);
129
130
    void hideButtons();
131
                      
132
public slots:
133
    void acceptChanges();
134
    void rejectChanges();
135
    void reloadPanels();
136
    void setCurrentIndex(int);
137
    
138
signals:
139
    /** This is emitted when acceptChanges() is called, after the
140
     *  values have been stored */
141
    void sig_prefsChanged();
142
143
private:
144
    ConfLinkFact *m_makelink{nullptr};
145
    std::vector<ConfPanelW *> m_panels;
146
    // "Foreign" panels
147
    std::vector<ConfPanelWIF *> m_widgets;
148
    // All params
149
    std::vector<ConfParamW *> m_params;
150
    QTabWidget       *tabWidget{nullptr};
151
    QDialogButtonBox *buttonBox{nullptr};
152
};
153
154
/////////////////////////////////////////////////
155
// The rest of the class definitions are only useful if you need to
156
// access a specific element for customisation (use findParamW() and a
157
// dynamic cast).
158
159
/** A panel/tab contains multiple controls for parameters */
160
class ConfPanelW : public QWidget {
161
    Q_OBJECT
162
public:
163
    ConfPanelW(QWidget *parent);
164
    void addWidget(QWidget *w);
165
    void storeValues();
166
    void loadValues();
167
    void endOfList();
168
private:
169
    QVBoxLayout *m_vboxlayout;
170
    std::vector<QWidget *> m_widgets;
171
};
172
173
/** Config panel element: manages one configuration
174
 *  parameter. Subclassed for specific parameter types.
175
 */
176
class ConfParamW : public QWidget {
177
    Q_OBJECT
178
public:
179
    ConfParamW(const QString& varnm, QWidget *parent, ConfLink cflink)
180
        : QWidget(parent), m_varname(varnm),
181
          m_cflink(cflink), m_fsencoding(false) {
182
    }
183
    virtual void loadValue() = 0;
184
    virtual void setFsEncoding(bool onoff) {
185
        m_fsencoding = onoff;
186
    }
187
    const QString& getVarName() {
188
        return m_varname;
189
    }
190
public slots:
191
    virtual void setEnabled(bool) = 0;
192
    virtual void storeValue() = 0;
193
194
protected:
195
    QString      m_varname;
196
    ConfLink     m_cflink;
197
    QHBoxLayout *m_hl;
198
    // File names are encoded as local8bit in the config files. Other
199
    // are encoded as utf-8
200
    bool         m_fsencoding;
201
    virtual bool createCommon(const QString& lbltxt, const QString& tltptxt);
202
    void setValue(const QString& newvalue);
203
    void setValue(int newvalue);
204
    void setValue(bool newvalue);
205
};
206
207
//////// Widgets for setting the different types of configuration parameters:
208
209
/**  Boolean */
210
class ConfParamBoolW : public ConfParamW {
211
    Q_OBJECT
212
public:
213
    ConfParamBoolW(const QString& varnm, QWidget *parent, ConfLink cflink,
214
                   const QString& lbltxt,
215
                   const QString& tltptxt, bool deflt = false);
216
    virtual void loadValue();
217
    virtual void storeValue();
218
public slots:
219
    virtual void setEnabled(bool i) {
220
        if (m_cb) {
221
            ((QWidget*)m_cb)->setEnabled(i);
222
        }
223
    }
224
public:
225
    QCheckBox *m_cb;
226
    bool m_dflt;
227
    bool m_origvalue;
228
};
229
230
// Int
231
class ConfParamIntW : public ConfParamW {
232
    Q_OBJECT
233
public:
234
    // The default value is only used if none exists in the sample
235
    // configuration file. Defaults are normally set in there.
236
    ConfParamIntW(const QString& varnm, QWidget *parent, ConfLink cflink,
237
                  const QString& lbltxt,
238
                  const QString& tltptxt,
239
                  int minvalue = INT_MIN,
240
                  int maxvalue = INT_MAX,
241
                  int defaultvalue = 0);
242
    virtual void loadValue();
243
    virtual void storeValue();
244
public slots:
245
    virtual void setEnabled(bool i) {
246
        if (m_sb) {
247
            ((QWidget*)m_sb)->setEnabled(i);
248
        }
249
    }
250
protected:
251
    QSpinBox *m_sb;
252
    int       m_defaultvalue;
253
    int       m_origvalue;
254
};
255
256
// Arbitrary string
257
class ConfParamStrW : public ConfParamW {
258
    Q_OBJECT
259
public:
260
    ConfParamStrW(const QString& varnm, QWidget *parent, ConfLink cflink,
261
                  const QString& lbltxt,
262
                  const QString& tltptxt);
263
    virtual void loadValue();
264
    virtual void storeValue();
265
public slots:
266
    virtual void setEnabled(bool i) {
267
        if (m_le) {
268
            ((QWidget*)m_le)->setEnabled(i);
269
        }
270
    }
271
protected:
272
    QLineEdit *m_le;
273
    QString m_origvalue;
274
};
275
276
// Constrained string: choose from list
277
class ConfParamCStrW : public ConfParamW {
278
    Q_OBJECT
279
public:
280
    ConfParamCStrW(const QString& varnm, QWidget *parent, ConfLink cflink,
281
                   const QString& lbltxt,
282
                   const QString& tltptxt, const QStringList& sl);
283
    virtual void loadValue();
284
    virtual void storeValue();
285
    virtual void setList(const QStringList& sl);
286
public slots:
287
    virtual void setEnabled(bool i) {
288
        if (m_cmb) {
289
            ((QWidget*)m_cmb)->setEnabled(i);
290
        }
291
    }
292
protected:
293
    QComboBox *m_cmb;
294
    QString m_origvalue;
295
};
296
297
// File name
298
class ConfParamFNW : public ConfParamW {
299
    Q_OBJECT
300
public:
301
    ConfParamFNW(const QString& varnm, QWidget *parent, ConfLink cflink,
302
                 const QString& lbltxt,
303
                 const QString& tltptxt, bool isdir = false);
304
    virtual void loadValue();
305
    virtual void storeValue();
306
protected slots:
307
    void showBrowserDialog();
308
public slots:
309
    virtual void setEnabled(bool i) {
310
        if (m_le) {
311
            ((QWidget*)m_le)->setEnabled(i);
312
        }
313
        if (m_pb) {
314
            ((QWidget*)m_pb)->setEnabled(i);
315
        }
316
    }
317
protected:
318
    QLineEdit *m_le;
319
    QPushButton *m_pb;
320
    bool       m_isdir;
321
    QString m_origvalue;
322
};
323
324
// String list
325
class ConfParamSLW : public ConfParamW {
326
    Q_OBJECT
327
public:
328
    ConfParamSLW(const QString& varnm, QWidget *parent, ConfLink cflink,
329
                 const QString& lbltxt,
330
                 const QString& tltptxt);
331
    virtual void loadValue();
332
    virtual void storeValue();
333
    QListWidget *getListBox() {
334
        return m_lb;
335
    }
336
337
public slots:
338
    virtual void setEnabled(bool i) {
339
        if (m_lb) {
340
            ((QWidget*)m_lb)->setEnabled(i);
341
        }
342
    }
343
protected slots:
344
    virtual void showInputDialog();
345
    void deleteSelected();
346
signals:
347
    void entryDeleted(QString);
348
protected:
349
    QListWidget *m_lb;
350
    void listToConf();
351
    std::string m_origvalue;
352
};
353
354
// Dir name list
355
class ConfParamDNLW : public ConfParamSLW {
356
    Q_OBJECT
357
public:
358
    ConfParamDNLW(const QString& varnm, QWidget *parent, ConfLink cflink,
359
                  const QString& lbltxt,
360
                  const QString& tltptxt)
361
        : ConfParamSLW(varnm, parent, cflink, lbltxt, tltptxt) {
362
        m_fsencoding = true;
363
    }
364
protected slots:
365
    virtual void showInputDialog();
366
};
367
368
// Constrained string list (chose from predefined)
369
class ConfParamCSLW : public ConfParamSLW {
370
    Q_OBJECT
371
public:
372
    ConfParamCSLW(const QString& varnm, QWidget *parent, ConfLink cflink,
373
                  const QString& lbltxt,
374
                  const QString& tltptxt,
375
                  const QStringList& sl)
376
        : ConfParamSLW(varnm, parent, cflink, lbltxt, tltptxt), m_sl(sl) {
377
    }
378
protected slots:
379
    virtual void showInputDialog();
380
protected:
381
    const QStringList m_sl;
382
};
383
384
#ifdef ENABLE_XMLCONF
385
/**
386
 * Interpret an XML string and create a configuration interface. XML sample:
387
 *
388
 * <confcomments>
389
 *   <filetitle>Configuration file parameters for upmpdcli</filetitle>
390
 *   <grouptitle>MPD parameters</grouptitle>
391
 *   <var name="mpdhost" type="string">
392
 *     <brief>Host MPD runs on.</brief>
393
 *     <descr>Defaults to localhost. This can also be specified as -h</descr>
394
 *   </var>
395
 *   mpdhost = default-host
396
 *   <var name="mpdport" type="int" values="0 65635 6600">
397
 *     <brief>IP port used by MPD</brief>. 
398
 *     <descr>Can also be specified as -p port. Defaults to the...</descr>
399
 *   </var>
400
 *   mpdport = defport
401
 *   <var name="ownqueue" type="bool" values="1">
402
 *     <brief>Set if we own the MPD queue.</brief>
403
 *     <descr>If this is set (on by default), we own the MPD...</descr>
404
 *   </var>
405
 *   ownqueue = 
406
 * </confcomments>
407
 *
408
 * <grouptitle> creates a panel in which the following <var> are set.
409
 * The <var> attributes should be self-explanatory. "values"
410
 * is used for different things depending on the var type
411
 * (min/max, default, str list). Check the code about this. 
412
 * type values: "bool" "int" "string" "cstr" "cstrl" "fn" "dfn" "strl" "dnl"
413
 *
414
 * The XML would typically exist as comments inside a reference configuration
415
 * file (ConfSimple can extract such comments).
416
 *
417
 * This means that the reference configuration file can generate both
418
 * the documentation and the GUI interface.
419
 * 
420
 * @param xml the input xml
421
 * @param[output] toptxt the top level XML text (text not inside <var>, 
422
 *   normally commented variable assignments). This will be evaluated
423
 *   as a config for default values.
424
 * @lnkf factory to create the objects which link the GUI to the
425
 *   storage mechanism.
426
 */
427
extern ConfTabsW *xmlToConfGUI(const std::string& xml,
428
                               std::string& toptxt,
429
                               ConfLinkFact* lnkf,
430
                               QWidget *parent);
431
#endif
432
433
}
434
435
#endif /* _confgui_h_included_ */