Correction bug : OptionWidget options non restorées après apply then Cancel
[ardoise:ardoise.git] / options.cpp
1 /*******************************************
2  *
3  * Copyright © 2013 Léo Flaventin Hauchecorne
4  *
5  * This file is part of Ardoise.
6  *
7  * Ardoise is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Ardoise is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
19  ********************************************/
20
21 #include <iostream>
22 #include "options.h"
23 #include <QCoreApplication>
24 #include <QLabel>
25 #include <QCheckBox>
26 #include <QSpinBox>
27 #include <QFormLayout>
28 #include <QComboBox>
29 #include <QLocale>
30
31 #include <QJsonArray>
32 #include <QJsonDocument>
33 #include <QJsonObject>
34 #include <QJsonParseError>
35 #include <QJsonValue>
36
37 #include "optionswidget.h"
38
39 Option::Option(const QString &name, const QVariant & _value, const char * text, const char * desc, const QString &path) :
40 QObject(),
41 m_name(name),
42 m_path(path),
43 m_text(text),
44 m_desc(desc),
45 value(_value),
46 storedValue(_value),
47 defaultValue(_value)
48 {
49 }
50
51 bool Option::setValue(const QVariant &_value)
52 {
53    if(_value.type()!=value.type()) return false;
54    value = _value;
55    return true;
56 }
57
58 QWidget *Option::modifier() const
59 {
60    QWidget * w = nullptr;
61    switch(value.type())
62    {
63    case QMetaType::Bool:
64    {
65       QCheckBox * cb = new QCheckBox();
66       cb->setChecked(value.toBool());
67       w = cb;
68       break;
69    }
70    case QMetaType::Int:
71    {
72       QSpinBox * sb = new QSpinBox();
73       sb->setValue(value.toInt());
74       w = sb;
75       break;
76    }
77    default: ;
78    }
79    w->setToolTip(desc());
80    return w;
81 }
82
83 void Option::retranslateModifier(QWidget *mod) const
84 {
85    mod->setToolTip(desc());
86 }
87
88 QLabel *Option::label() const
89 {
90    if(!*m_text) return nullptr;
91    QLabel * lab = new QLabel(text());
92    lab->setToolTip(desc());
93    return lab;
94 }
95
96 void Option::retranslateLabel(QLabel *lab) const
97 {
98    lab->setText(text());
99    lab->setToolTip(desc());
100 }
101
102 QString Option::text() const
103 {
104    return QCoreApplication::translate("OptionsWidget", m_text);
105 }
106
107 QString Option::desc() const
108 {
109    return QCoreApplication::translate("OptionsWidget", m_desc);
110 }
111
112 bool Option::applyModifier(QWidget *w)
113 {
114    switch(value.type())
115    {
116    case QMetaType::Bool:
117    {
118       QCheckBox * cb = static_cast<QCheckBox*>(w);
119       return setValue(QVariant(cb->isChecked()));
120    }
121    case QMetaType::Int:
122    {
123       QSpinBox * sb = static_cast<QSpinBox*>(w);
124       return setValue(sb->value());
125    }
126    default :
127       break;
128    }
129    return false;
130 }
131
132 void Option::storeCurrent()
133 {
134    storedValue = value;
135 }
136
137 void Option::restoreStored(QWidget *mod)
138 {
139    restoreValue(mod, storedValue);
140 }
141
142 void Option::restoreDefault(QWidget *mod)
143 {
144    restoreValue(mod, defaultValue);
145 }
146
147 void Option::restoreValue(QWidget *mod, const QVariant &v)
148 {
149    switch(v.type())
150    {
151    case QMetaType::Bool:
152    {
153       QCheckBox * cb = static_cast<QCheckBox*>(mod);
154       value = v;
155       if(cb) cb->setChecked(value.toBool());
156       break;
157    }
158    case QMetaType::Int:
159    {
160       QSpinBox * sb = static_cast<QSpinBox*>(mod);
161       value = v;
162       if(sb) sb->setValue(value.toInt());
163       break;
164    }
165    default :
166       break;
167    }
168 }
169
170 ///////////////////////////////////////////////////////////////////////////////
171 ///////////////////////////////////////////////////////////////////////////////
172 ///////////////////////////////////////////////////////////////////////////////
173
174 bool Options::m_created = false;
175 QHash<QString, Option*> Options::optionTable;
176 QList<Option*> Options::optionList;
177
178 void Options::create()
179 {
180    if(m_created) throw "Options already created";
181    m_created = true;
182 }
183
184 void Options::destroy()
185 {
186    m_created = false;
187    auto it = optionList.begin(), end = optionList.end();
188    for(; it!=end; ++it)
189    {
190       delete *it;
191    }
192    optionTable.clear();
193    optionList.clear();
194 }
195
196 OptionsWidget *Options::optionsWidget()
197 {
198    return new OptionsWidget(optionList);
199 }
200
201 bool Options::addOption(Option *opt)
202 {
203    auto it = optionTable.find(opt->name());
204    if(it == optionTable.end())
205    {
206       optionTable[opt->name()] = opt;
207       optionList.push_back(opt);
208       return true;
209    }
210    if(it.value() == opt)
211    {
212       optionList.append(optionList.takeAt(optionList.indexOf(opt))); // NOTE : possibilité d'obtenir l'index en l'enregistrant dans Option
213       return true;
214    }
215    delete opt;
216    return false;
217 }
218
219 QVariant Options::get(const QString &key)
220 {
221    auto it = optionTable.find(key);
222    if(it == optionTable.end()) return QVariant();
223    return it.value()->getValue();
224 }
225
226 const Option *Options::getOption(const QString &key)
227 {
228    auto it = optionTable.find(key);
229    if(it == optionTable.end()) return nullptr;
230    return it.value();
231 }
232
233 bool Options::set(const QString &key, QVariant value)
234 {
235    auto it = optionTable.find(key);
236    if(it == optionTable.end())
237    {
238       Option * opt = new Option(key, value, "");
239       optionTable[opt->name()] = opt;
240       optionList.push_back(opt);
241       return true;
242    }
243    else
244    {
245       return it.value()->setValue(value);
246    }
247 }
248
249 static inline QVariant value2variant(const QJsonValue & v)
250 {
251    switch(v.type())
252    {
253    case QJsonValue::Double :
254    {
255       double val = v.toDouble();
256       int val2 = val;
257       if(val == (double) val2)
258       {
259          return QVariant(val2);
260       }
261       else return QVariant((double) val);
262    }
263    case QJsonValue::String:
264       return QVariant(v.toString());
265    case QJsonValue::Bool:
266       return QVariant(v.toBool());
267    case QJsonValue::Array:
268       return QVariant(v.toArray().toVariantList());
269    case QJsonValue::Object:
270       return QVariant(v.toObject().toVariantMap());
271    default:
272       break;
273    }
274    return QVariant();
275 }
276
277 void Options::readConf(const QByteArray & in)
278 {
279    QJsonParseError e;
280    QJsonDocument doc = QJsonDocument::fromJson(in, &e);
281    if(e.error != QJsonParseError::NoError)
282    {
283       std::cerr<<"at "<<e.offset<<" : "<<e.errorString().toStdString();
284       return;
285    }
286    QJsonObject root = doc.object();
287    for(QJsonObject::Iterator it = root.begin(), end = root.end() ; it!=end ; ++it)
288    {
289       set(it.key(), value2variant(it.value()));
290    }
291 }
292
293 QByteArray Options::saveConf()
294 {
295    QJsonObject o;
296    for(auto it = optionList.begin(), end = optionList.end() ; it != end ; ++it)
297    {
298       Option * & val = *it;
299       o[val->name()] = QJsonValue::fromVariant(val->getPrintedValue());
300    }
301    return QJsonDocument(o).toJson();
302 }
303
304 ///////////////////////////////////////////////////////////////////////////////
305 ///////////////////////////////////////////////////////////////////////////////
306 ///////////////////////////////////////////////////////////////////////////////
307
308 ComboOption::ComboOption(const QString &name, int defaultValue, const QStringList &_choices, const char *text, const char *desc, const QString &path) :
309 Option(name, defaultValue, text, desc, path),
310 value(defaultValue),
311 choices(_choices)
312 {
313 }
314
315 bool ComboOption::setValue(const QVariant &_value)
316 {
317    if(_value.type() == QMetaType::QString)
318    {
319       return setValue(_value.toString());
320    }
321    else if(_value.type() == QMetaType::Int)
322    {
323       return setValue(_value.toInt());
324    }
325    return false;
326 }
327
328 bool ComboOption::setValue(const QString & str)
329 {
330    return setValue(choices.indexOf(str));
331 }
332
333 bool ComboOption::setValue(int ind)
334 {
335    if(ind<0 || ind>=choices.size()) return false;
336    value = ind;
337    emit valueChanged(value);
338    return true;
339 }
340
341 QWidget *ComboOption::modifier() const
342 {
343    QComboBox * cb = new QComboBox();
344    cb->addItems(choices);
345    cb->setCurrentIndex(value);
346    return cb;
347 }
348
349 bool ComboOption::applyModifier(QWidget *w)
350 {
351    QComboBox * cb = qobject_cast<QComboBox *>(w);
352    if(!cb) return false;
353    return setValue(cb->currentIndex());
354 }
355
356 void ComboOption::storeCurrent()
357 {
358    storedValue = value;
359 }
360
361 void ComboOption::restoreValue(QWidget *mod, const QVariant &v)
362 {
363    QComboBox * cb = qobject_cast<QComboBox *>(mod);
364    if(!cb) return;
365    setValue(v.toInt());
366    cb->setCurrentIndex(v.toInt());
367 }
368
369 void ComboOption::changeValue(int ind)
370 {
371    setValue(ind);
372 }
373
374 ///////////////////////////////////////////////////////////////////////////////
375
376 QStringList ComboOptionTr::csl2sl(const QList<char *> &l1)
377 {
378    QStringList l2;
379    for(char * entry : l1)
380    {
381       l2<<QString(entry);
382    }
383    return l2;
384 }
385
386 ComboOptionTr::ComboOptionTr(const QString & name, int _defaultValue, const QList<char *> & _choices, const char *_text, const char *_desc, const QString &_path) :
387 ComboOption(name, _defaultValue, csl2sl(_choices), _text, _desc, _path)
388 {
389 }
390
391 QWidget *ComboOptionTr::modifier() const
392 {
393    QStringList ch2;
394    for(char * entry : choices)
395    {
396       ch2<<QCoreApplication::translate("OptionsWidget", entry);
397    }
398    QComboBox * cb = new QComboBox();
399    cb->addItems(ch2);
400    return cb;
401 }
402
403 ///////////////////////////////////////////////////////////////////////////////
404
405 extern QTranslator * translator;
406
407 static QStringList nativeLangNames(const QList<QLocale> &locales)
408 {
409    QStringList l;
410    for(auto it = locales.begin(), end = locales.end() ; it!=end ; ++it)
411    {
412       l<<it->nativeLanguageName();
413    }
414    return l;
415 }
416
417 LanguageOption::LanguageOption(const QString &name, int defaultValue, const QList<QLocale> &locales, const char *text, const char *desc, const QString &path) :
418 ComboOption(name, defaultValue, nativeLangNames(locales), text, desc, path),
419 m_locales(locales)
420 {
421 }
422
423 bool LanguageOption::setValue(const QString &str)
424 {
425    QLocale l(str);
426    int ind = m_locales.indexOf(l);
427    if(ind != -1) return setValue(ind);
428    return ComboOption::setValue(str);
429 }
430
431 bool LanguageOption::setValue(int ind)
432 {
433    if(!ComboOption::setValue(ind)) return false;
434    translator->load(m_locales[value], "ardoise",  "_", ":/translations/");
435    return true;
436 }
437
438 QVariant LanguageOption::getPrintedValue() const
439 {
440    return QVariant(currentLang());
441 }
442
443 QLocale LanguageOption::currentLocale() const
444 {
445    return m_locales[value];
446 }
447
448 QString LanguageOption::currentLang() const
449 {
450    return currentLocale().name().split("_").at(0);
451 }
452
453 ///////////////////////////////////////////////////////////////////////////////
454 ///////////////////////////////////////////////////////////////////////////////
455 ///////////////////////////////////////////////////////////////////////////////
456
457 StringListOption::StringListOption(const QString &name, const QVariant &value, const char *text, const char *desc, const QString &path) :
458 Option(name, value, text, desc, path)
459 {
460 }
461
462 bool StringListOption::setValue(const QVariant &_value)
463 {
464    if(_value.canConvert<QStringList>())
465    {
466       value = _value.toStringList();
467       return true;
468    }
469    return false;
470 }