1 /*
2 * SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 */
7
8 #include "optionwidget.h"
9 #include "config.h"
10 #include "configwidget.h"
11 #include "font.h"
12 #include "fontbutton.h"
13 #include "keylistwidget.h"
14 #include "listoptionwidget.h"
15 #include "logging.h"
16 #include "varianthelper.h"
17 #include <KColorButton>
18 #include <QCheckBox>
19 #include <QComboBox>
20 #include <QDialog>
21 #include <QDialogButtonBox>
22 #include <QFileInfo>
23 #include <QFormLayout>
24 #include <QLineEdit>
25 #include <QPointer>
26 #include <QProcess>
27 #include <QPushButton>
28 #include <QSpinBox>
29 #include <QToolButton>
30 #include <QVBoxLayout>
31 #include <fcitx-utils/color.h>
32 #include <fcitx-utils/i18n.h>
33 #include <fcitx-utils/standardpath.h>
34 #include <fcitxqtkeysequencewidget.h>
35
36 namespace fcitx {
37 namespace kcm {
38
39 namespace {
40
41 class IntegerOptionWidget : public OptionWidget {
42 Q_OBJECT
43 public:
IntegerOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)44 IntegerOptionWidget(const FcitxQtConfigOption &option, const QString &path,
45 QWidget *parent)
46 : OptionWidget(path, parent), spinBox_(new QSpinBox),
47 defaultValue_(option.defaultValue().variant().toString().toInt()) {
48 QVBoxLayout *layout = new QVBoxLayout;
49 layout->setMargin(0);
50
51 spinBox_ = new QSpinBox;
52 spinBox_->setMaximum(INT_MAX);
53 spinBox_->setMinimum(INT_MIN);
54 if (option.properties().contains("IntMax")) {
55 auto max = option.properties().value("IntMax");
56 if (max.type() == QVariant::String) {
57 spinBox_->setMaximum(max.toInt());
58 }
59 }
60 if (option.properties().contains("IntMin")) {
61 auto min = option.properties().value("IntMin");
62 if (min.type() == QVariant::String) {
63 spinBox_->setMinimum(min.toInt());
64 }
65 }
66 connect(spinBox_, qOverload<int>(&QSpinBox::valueChanged), this,
67 &OptionWidget::valueChanged);
68 layout->addWidget(spinBox_);
69 setLayout(layout);
70 }
71
readValueFrom(const QVariantMap & map)72 void readValueFrom(const QVariantMap &map) override {
73 auto value = readString(map, path());
74 if (value.isNull()) {
75 spinBox_->setValue(defaultValue_);
76 }
77 spinBox_->setValue(value.toInt());
78 }
79
writeValueTo(QVariantMap & map)80 void writeValueTo(QVariantMap &map) override {
81 writeVariant(map, path(), QString::number(spinBox_->value()));
82 }
83
restoreToDefault()84 void restoreToDefault() override { spinBox_->setValue(defaultValue_); }
85
86 private:
87 QSpinBox *spinBox_;
88 int defaultValue_;
89 };
90
91 class StringOptionWidget : public OptionWidget {
92 Q_OBJECT
93 public:
StringOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)94 StringOptionWidget(const FcitxQtConfigOption &option, const QString &path,
95 QWidget *parent)
96 : OptionWidget(path, parent), lineEdit_(new QLineEdit),
97 defaultValue_(option.defaultValue().variant().toString()) {
98 QVBoxLayout *layout = new QVBoxLayout;
99 layout->setMargin(0);
100
101 lineEdit_ = new QLineEdit;
102 connect(lineEdit_, &QLineEdit::textChanged, this,
103 &OptionWidget::valueChanged);
104 layout->addWidget(lineEdit_);
105 setLayout(layout);
106 }
107
readValueFrom(const QVariantMap & map)108 void readValueFrom(const QVariantMap &map) override {
109 auto value = readString(map, path());
110 lineEdit_->setText(value);
111 }
112
writeValueTo(QVariantMap & map)113 void writeValueTo(QVariantMap &map) override {
114 writeVariant(map, path(), lineEdit_->text());
115 }
116
restoreToDefault()117 void restoreToDefault() override { lineEdit_->setText(defaultValue_); }
118
119 private:
120 QLineEdit *lineEdit_;
121 QString defaultValue_;
122 };
123
124 class FontOptionWidget : public OptionWidget {
125 Q_OBJECT
126 public:
FontOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)127 FontOptionWidget(const FcitxQtConfigOption &option, const QString &path,
128 QWidget *parent)
129 : OptionWidget(path, parent), fontButton_(new FontButton),
130 defaultValue_(option.defaultValue().variant().toString()) {
131 QVBoxLayout *layout = new QVBoxLayout;
132 layout->setMargin(0);
133
134 connect(fontButton_, &FontButton::fontChanged, this,
135 &OptionWidget::valueChanged);
136 layout->addWidget(fontButton_);
137 setLayout(layout);
138 }
139
readValueFrom(const QVariantMap & map)140 void readValueFrom(const QVariantMap &map) override {
141 auto value = readString(map, path());
142 fontButton_->setFont(parseFont(value));
143 }
144
writeValueTo(QVariantMap & map)145 void writeValueTo(QVariantMap &map) override {
146 writeVariant(map, path(), fontButton_->fontName());
147 }
148
restoreToDefault()149 void restoreToDefault() override {
150 fontButton_->setFont(parseFont(defaultValue_));
151 }
152
153 private:
154 FontButton *fontButton_;
155 QString defaultValue_;
156 };
157
158 class BooleanOptionWidget : public OptionWidget {
159 Q_OBJECT
160 public:
BooleanOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)161 BooleanOptionWidget(const FcitxQtConfigOption &option, const QString &path,
162 QWidget *parent)
163 : OptionWidget(path, parent), checkBox_(new QCheckBox),
164 defaultValue_(option.defaultValue().variant().toString() == "True") {
165 QVBoxLayout *layout = new QVBoxLayout;
166 layout->setMargin(0);
167
168 connect(checkBox_, &QCheckBox::clicked, this,
169 &OptionWidget::valueChanged);
170 checkBox_->setText(option.description());
171 layout->addWidget(checkBox_);
172 setLayout(layout);
173 }
174
readValueFrom(const QVariantMap & map)175 void readValueFrom(const QVariantMap &map) override {
176 checkBox_->setChecked(readBool(map, path()));
177 }
178
writeValueTo(QVariantMap & map)179 void writeValueTo(QVariantMap &map) override {
180 QString value = checkBox_->isChecked() ? "True" : "False";
181 writeVariant(map, path(), value);
182 }
183
restoreToDefault()184 void restoreToDefault() override { checkBox_->setChecked(defaultValue_); }
185
186 private:
187 QCheckBox *checkBox_;
188 bool defaultValue_;
189 };
190
191 class KeyListOptionWidget : public OptionWidget {
192 Q_OBJECT
193 public:
KeyListOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)194 KeyListOptionWidget(const FcitxQtConfigOption &option, const QString &path,
195 QWidget *parent)
196 : OptionWidget(path, parent), keyListWidget_(new KeyListWidget) {
197 QVBoxLayout *layout = new QVBoxLayout;
198 layout->setMargin(0);
199
200 keyListWidget_ = new KeyListWidget(this);
201
202 keyListWidget_->setAllowModifierLess(
203 readString(option.properties(),
204 "ListConstrain/AllowModifierLess") == "True");
205 keyListWidget_->setAllowModifierOnly(
206 readString(option.properties(),
207 "ListConstrain/AllowModifierOnly") == "True");
208 connect(keyListWidget_, &KeyListWidget::keyChanged, this,
209 &OptionWidget::valueChanged);
210 layout->addWidget(keyListWidget_);
211
212 auto variant = option.defaultValue().variant();
213 QVariantMap map;
214 if (variant.canConvert<QDBusArgument>()) {
215 auto argument = qvariant_cast<QDBusArgument>(variant);
216 argument >> map;
217 }
218 defaultValue_ = readValue(map, "");
219 setLayout(layout);
220 }
221
readValueFrom(const QVariantMap & map)222 void readValueFrom(const QVariantMap &map) override {
223 keyListWidget_->setKeys(readValue(map, path()));
224 }
225
writeValueTo(QVariantMap & map)226 void writeValueTo(QVariantMap &map) override {
227 auto keys = keyListWidget_->keys();
228 int i = 0;
229 for (auto &key : keys) {
230 auto value = QString::fromUtf8(key.toString().data());
231 writeVariant(map, QString("%1/%2").arg(path()).arg(i), value);
232 i++;
233 }
234 if (keys.empty()) {
235 writeVariant(map, path(), QVariantMap());
236 }
237 }
238
restoreToDefault()239 void restoreToDefault() override { keyListWidget_->setKeys(defaultValue_); }
240
241 private:
readValue(const QVariantMap & map,const QString & path)242 QList<fcitx::Key> readValue(const QVariantMap &map, const QString &path) {
243 int i = 0;
244 QList<Key> keys;
245 while (true) {
246 auto value = readString(map, QString("%1%2%3")
247 .arg(path)
248 .arg(path.isEmpty() ? "" : "/")
249 .arg(i));
250 if (value.isNull()) {
251 break;
252 }
253 keys << Key(value.toUtf8().constData());
254 i++;
255 }
256 return keys;
257 }
258
259 KeyListWidget *keyListWidget_;
260 QList<fcitx::Key> defaultValue_;
261 };
262
263 class KeyOptionWidget : public OptionWidget {
264 Q_OBJECT
265 public:
KeyOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)266 KeyOptionWidget(const FcitxQtConfigOption &option, const QString &path,
267 QWidget *parent)
268 : OptionWidget(path, parent),
269 keyWidget_(new FcitxQtKeySequenceWidget(this)),
270 defaultValue_(
271 option.defaultValue().variant().toString().toUtf8().constData()) {
272 QVBoxLayout *layout = new QVBoxLayout;
273 layout->setMargin(0);
274
275 keyWidget_->setModifierlessAllowed(
276 readBool(option.properties(), "AllowModifierLess"));
277 keyWidget_->setModifierOnlyAllowed(
278 readBool(option.properties(), "AllowModifierOnly"));
279
280 connect(keyWidget_, &FcitxQtKeySequenceWidget::keySequenceChanged, this,
281 &OptionWidget::valueChanged);
282 layout->addWidget(keyWidget_);
283 setLayout(layout);
284 }
285
readValueFrom(const QVariantMap & map)286 void readValueFrom(const QVariantMap &map) override {
287 Key key;
288 auto value = readString(map, path());
289 key = Key(value.toUtf8().constData());
290 keyWidget_->setKeySequence({key});
291 }
292
writeValueTo(QVariantMap & map)293 void writeValueTo(QVariantMap &map) override {
294 auto keys = keyWidget_->keySequence();
295 Key key;
296 if (keys.size()) {
297 key = keys[0];
298 }
299 auto value = QString::fromUtf8(key.toString().data());
300 writeVariant(map, path(), value);
301 }
302
restoreToDefault()303 void restoreToDefault() override {
304 keyWidget_->setKeySequence({defaultValue_});
305 }
306
307 private:
308 FcitxQtKeySequenceWidget *keyWidget_;
309 fcitx::Key defaultValue_;
310 };
311
312 class EnumOptionWidget : public OptionWidget {
313 Q_OBJECT
314 public:
EnumOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)315 EnumOptionWidget(const FcitxQtConfigOption &option, const QString &path,
316 QWidget *parent)
317 : OptionWidget(path, parent), comboBox_(new QComboBox),
318 toolButton_(new QToolButton) {
319 auto *layout = new QHBoxLayout;
320 toolButton_->setIcon(QIcon::fromTheme("preferences-system-symbolic"));
321 layout->setMargin(0);
322
323 int i = 0;
324 while (true) {
325 auto value =
326 readString(option.properties(), QString("Enum/%1").arg(i));
327 if (value.isNull()) {
328 break;
329 }
330 auto text =
331 readString(option.properties(), QString("EnumI18n/%1").arg(i));
332 if (text.isEmpty()) {
333 text = value;
334 }
335 auto subConfigPath = readString(option.properties(),
336 QString("SubConfigPath/%1").arg(i));
337 comboBox_->addItem(text, value);
338 comboBox_->setItemData(i, subConfigPath, subConfigPathRole);
339 i++;
340 }
341 layout->addWidget(comboBox_);
342 layout->addWidget(toolButton_);
343 setLayout(layout);
344
345 connect(comboBox_, qOverload<int>(&QComboBox::currentIndexChanged),
346 this, &OptionWidget::valueChanged);
347
348 connect(comboBox_, qOverload<int>(&QComboBox::currentIndexChanged),
349 this, [this]() {
350 toolButton_->setVisible(
351 !comboBox_->currentData(subConfigPathRole)
352 .toString()
353 .isEmpty());
354 });
355
356 connect(toolButton_, &QToolButton::clicked, this, [this]() {
357 ConfigWidget *configWidget = getConfigWidget(this);
358 if (!configWidget) {
359 return;
360 }
361 QPointer<QDialog> dialog = ConfigWidget::configDialog(
362 this, configWidget->dbus(),
363 comboBox_->currentData(subConfigPathRole).toString(),
364 comboBox_->currentText());
365 dialog->exec();
366 delete dialog;
367 });
368
369 defaultValue_ = option.defaultValue().variant().toString();
370 }
371
readValueFrom(const QVariantMap & map)372 void readValueFrom(const QVariantMap &map) override {
373 auto value = readString(map, path());
374 auto idx = comboBox_->findData(value);
375 if (idx < 0) {
376 idx = comboBox_->findData(defaultValue_);
377 }
378 comboBox_->setCurrentIndex(idx);
379 toolButton_->setVisible(
380 !comboBox_->currentData(subConfigPathRole).toString().isEmpty());
381 }
382
writeValueTo(QVariantMap & map)383 void writeValueTo(QVariantMap &map) override {
384 writeVariant(map, path(), comboBox_->currentData().toString());
385 }
386
restoreToDefault()387 void restoreToDefault() override {
388 auto idx = comboBox_->findData(defaultValue_);
389 comboBox_->setCurrentIndex(idx);
390 }
391
392 private:
393 QComboBox *comboBox_;
394 QToolButton *toolButton_;
395 QString defaultValue_;
396 inline static constexpr int subConfigPathRole = Qt::UserRole + 1;
397 };
398
399 class ColorOptionWidget : public OptionWidget {
400 Q_OBJECT
401 public:
ColorOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)402 ColorOptionWidget(const FcitxQtConfigOption &option, const QString &path,
403 QWidget *parent)
404 : OptionWidget(path, parent), colorButton_(new KColorButton) {
405 QVBoxLayout *layout = new QVBoxLayout;
406 layout->setMargin(0);
407 layout->addWidget(colorButton_);
408 colorButton_->setAlphaChannelEnabled(true);
409 setLayout(layout);
410 connect(colorButton_, &KColorButton::changed, this,
411 &OptionWidget::valueChanged);
412
413 try {
414 defaultValue_.setFromString(
415 option.defaultValue().variant().toString().toStdString());
416 } catch (...) {
417 }
418 }
419
readValueFrom(const QVariantMap & map)420 void readValueFrom(const QVariantMap &map) override {
421 auto value = readString(map, path());
422 Color color;
423 try {
424 color.setFromString(value.toStdString());
425 } catch (...) {
426 color = defaultValue_;
427 }
428 QColor qcolor;
429 qcolor.setRedF(color.redF());
430 qcolor.setGreenF(color.greenF());
431 qcolor.setBlueF(color.blueF());
432 qcolor.setAlphaF(color.alphaF());
433 colorButton_->setColor(qcolor);
434 }
435
writeValueTo(QVariantMap & map)436 void writeValueTo(QVariantMap &map) override {
437 auto color = colorButton_->color();
438 Color fcitxColor;
439 fcitxColor.setRedF(color.redF());
440 fcitxColor.setGreenF(color.greenF());
441 fcitxColor.setBlueF(color.blueF());
442 fcitxColor.setAlphaF(color.alphaF());
443 writeVariant(map, path(),
444 QString::fromStdString(fcitxColor.toString()));
445 }
446
restoreToDefault()447 void restoreToDefault() override {
448 QColor qcolor;
449 qcolor.setRedF(defaultValue_.redF());
450 qcolor.setGreenF(defaultValue_.greenF());
451 qcolor.setBlueF(defaultValue_.blueF());
452 qcolor.setAlphaF(defaultValue_.alphaF());
453 colorButton_->setColor(qcolor);
454 }
455
456 private:
457 KColorButton *colorButton_;
458 Color defaultValue_;
459 };
460
461 class ExternalOptionWidget : public OptionWidget {
462 Q_OBJECT
463 public:
ExternalOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)464 ExternalOptionWidget(const FcitxQtConfigOption &option, const QString &path,
465 QWidget *parent)
466 : OptionWidget(path, parent),
467 uri_(readString(option.properties(), "External")),
468 launchSubConfig_(readBool(option.properties(), "LaunchSubConfig")) {
469 QVBoxLayout *layout = new QVBoxLayout;
470 layout->setMargin(0);
471
472 button_ = new QToolButton(this);
473 button_->setIcon(QIcon::fromTheme("preferences-system-symbolic"));
474 button_->setText(_("Configure"));
475 layout->addWidget(button_);
476 setLayout(layout);
477
478 connect(
479 button_, &QPushButton::clicked, this,
480 [this, parent, name = option.name()]() {
481 if (launchSubConfig_) {
482 ConfigWidget *configWidget = getConfigWidget(this);
483 if (!configWidget) {
484 return;
485 }
486 QPointer<QDialog> dialog = ConfigWidget::configDialog(
487 this, configWidget->dbus(), uri_, name);
488 dialog->exec();
489 delete dialog;
490 } else if (uri_.startsWith("fcitx://config/addon/")) {
491 QString wrapperPath = FCITX5_QT5_GUI_WRAPPER;
492 if (!QFileInfo(wrapperPath).isExecutable()) {
493 wrapperPath =
494 QString::fromStdString(stringutils::joinPath(
495 StandardPath::global().fcitxPath("libexecdir"),
496 "fcitx5-qt5-gui-wrapper"));
497 }
498 QStringList args;
499 if (QGuiApplication::platformName() == "xcb") {
500 auto wid = parent->winId();
501 if (wid) {
502 args << "-w";
503 args << QString::number(wid);
504 }
505 }
506 args << uri_;
507 qCDebug(KCM_FCITX5) << "Launch: " << wrapperPath << args;
508 QProcess::startDetached(wrapperPath, args);
509 } else {
510 // Assume this is a program path.
511 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
512 QStringList args = QProcess::splitCommand(uri_);
513 QString program = args.takeFirst();
514 QProcess::startDetached(program, args);
515 #else
516 QProcess::startDetached(uri_);
517 #endif
518 }
519 });
520 }
521
readValueFrom(const QVariantMap &)522 void readValueFrom(const QVariantMap &) override {}
writeValueTo(QVariantMap &)523 void writeValueTo(QVariantMap &) override {}
restoreToDefault()524 void restoreToDefault() override {}
525
526 private:
527 QToolButton *button_;
528 const QString uri_;
529 const bool launchSubConfig_;
530 };
531 } // namespace
532
addWidget(QFormLayout * layout,const fcitx::FcitxQtConfigOption & option,const QString & path,QWidget * parent)533 OptionWidget *OptionWidget::addWidget(QFormLayout *layout,
534 const fcitx::FcitxQtConfigOption &option,
535 const QString &path, QWidget *parent) {
536 OptionWidget *widget = nullptr;
537 if (option.type() == "Integer") {
538 widget = new IntegerOptionWidget(option, path, parent);
539 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
540 } else if (option.type() == "String") {
541 const auto isFont = readBool(option.properties(), "Font");
542 const auto isEnum = readBool(option.properties(), "IsEnum");
543 if (isFont) {
544 widget = new FontOptionWidget(option, path, parent);
545 } else if (isEnum) {
546 widget = new EnumOptionWidget(option, path, parent);
547 } else {
548 widget = new StringOptionWidget(option, path, parent);
549 }
550 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
551 } else if (option.type() == "Boolean") {
552 widget = new BooleanOptionWidget(option, path, parent);
553 layout->addRow("", widget);
554 } else if (option.type() == "Key") {
555 widget = new KeyOptionWidget(option, path, parent);
556 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
557 } else if (option.type() == "List|Key") {
558 widget = new KeyListOptionWidget(option, path, parent);
559 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
560 } else if (option.type() == "Enum") {
561 widget = new EnumOptionWidget(option, path, parent);
562 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
563 } else if (option.type() == "Color") {
564 widget = new ColorOptionWidget(option, path, parent);
565 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
566 } else if (option.type().startsWith("List|")) {
567 widget = new ListOptionWidget(option, path, parent);
568 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
569 } else if (option.type() == "External") {
570 widget = new ExternalOptionWidget(option, path, parent);
571 layout->addRow(QString(_("%1:")).arg(option.description()), widget);
572 }
573 if (widget) {
574 if (option.properties().contains("Tooltip")) {
575 widget->setToolTip(option.properties().value("Tooltip").toString());
576 }
577 }
578 return widget;
579 }
580
execOptionDialog(QWidget * parent,const fcitx::FcitxQtConfigOption & option,QVariant & result)581 bool OptionWidget::execOptionDialog(QWidget *parent,
582 const fcitx::FcitxQtConfigOption &option,
583 QVariant &result) {
584 QPointer<QDialog> dialog = new QDialog(parent);
585 dialog->setWindowIcon(QIcon::fromTheme("fcitx"));
586 dialog->setWindowTitle(option.description());
587 QVBoxLayout *dialogLayout = new QVBoxLayout;
588 dialog->setLayout(dialogLayout);
589
590 ConfigWidget *parentConfigWidget = getConfigWidget(parent);
591 OptionWidget *optionWidget = nullptr;
592 ConfigWidget *configWidget = nullptr;
593 if (parentConfigWidget->description().contains(option.type())) {
594 configWidget =
595 new ConfigWidget(parentConfigWidget->description(), option.type(),
596 parentConfigWidget->dbus());
597 configWidget->setValue(result);
598 dialogLayout->addWidget(configWidget);
599 } else {
600 QFormLayout *subLayout = new QFormLayout;
601 dialogLayout->addLayout(subLayout);
602 optionWidget =
603 addWidget(subLayout, option, QString("Value"), dialog.data());
604 if (!optionWidget) {
605 return false;
606 }
607 QVariantMap origin;
608 origin["Value"] = result;
609 optionWidget->readValueFrom(origin);
610 }
611
612 QDialogButtonBox *buttonBox =
613 new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
614 buttonBox->button(QDialogButtonBox::Ok)->setText(_("&OK"));
615 buttonBox->button(QDialogButtonBox::Cancel)->setText(_("&Cancel"));
616 dialogLayout->addWidget(buttonBox);
617
618 connect(buttonBox, &QDialogButtonBox::accepted, dialog, &QDialog::accept);
619 connect(buttonBox, &QDialogButtonBox::rejected, dialog, &QDialog::reject);
620
621 auto ret = dialog->exec();
622 bool dialogResult = false;
623 if (ret && dialog) {
624 if (optionWidget) {
625 if (optionWidget->isValid()) {
626 QVariantMap map;
627 optionWidget->writeValueTo(map);
628 result = map.value("Value");
629 dialogResult = true;
630 }
631 } else {
632 result = configWidget->value();
633 dialogResult = true;
634 }
635 }
636 delete dialog;
637 return dialogResult;
638 }
639
prettify(const fcitx::FcitxQtConfigOption & option,const QVariant & value)640 QString OptionWidget::prettify(const fcitx::FcitxQtConfigOption &option,
641 const QVariant &value) {
642 if (option.type() == "Integer") {
643 return value.toString();
644 } else if (option.type() == "String") {
645 return value.toString();
646 } else if (option.type() == "Boolean") {
647 return value.toString() == "True" ? _("Yes") : _("No");
648 } else if (option.type() == "Key") {
649 return value.toString();
650 } else if (option.type() == "Enum") {
651 QMap<QString, QString> enumMap;
652 int i = 0;
653 while (true) {
654 auto value =
655 readString(option.properties(), QString("Enum/%1").arg(i));
656 if (value.isNull()) {
657 break;
658 }
659 auto text =
660 readString(option.properties(), QString("EnumI18n/%1").arg(i));
661 if (text.isEmpty()) {
662 text = value;
663 }
664 enumMap[value] = text;
665 i++;
666 }
667 return enumMap.value(value.toString());
668 } else if (option.type().startsWith("List|")) {
669
670 int i = 0;
671 QStringList strs;
672 strs.clear();
673 auto subOption = option;
674 subOption.setType(option.type().mid(5)); // Remove List|
675 while (true) {
676 auto subValue = readVariant(value, QString(i));
677 strs << prettify(subOption, subValue);
678 i++;
679 }
680 return QString(_("[%1]")).arg(strs.join(" "));
681 } else {
682 auto *configWidget = getConfigWidget(this);
683 if (configWidget &&
684 configWidget->description().contains(option.type())) {
685 if (auto key =
686 option.properties().value("ListDisplayOption").toString();
687 !key.isEmpty()) {
688 const auto &options =
689 *configWidget->description().find(option.type());
690 for (const auto &option : options) {
691 if (option.name() == key) {
692 return prettify(option, readVariant(value, key));
693 }
694 }
695 }
696 }
697 }
698 return QString();
699 }
700
701 } // namespace kcm
702 } // namespace fcitx
703
704 #include "optionwidget.moc"
705