1 /*
2 * SPDX-FileCopyrightText: 2017~2017 CSSlayer <wengxt@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 *
6 */
7 #include "listoptionwidget.h"
8 #include "varianthelper.h"
9 #include <QAbstractListModel>
10 #include <QDebug>
11 #include <QtGlobal>
12
13 namespace fcitx {
14 namespace kcm {
15
16 class ListOptionWidgetModel : public QAbstractListModel {
17 public:
ListOptionWidgetModel(ListOptionWidget * parent)18 ListOptionWidgetModel(ListOptionWidget *parent)
19 : QAbstractListModel(parent), parent_(parent) {}
20
data(const QModelIndex & index,int role=Qt::DisplayRole) const21 QVariant data(const QModelIndex &index,
22 int role = Qt::DisplayRole) const override {
23 if (!index.isValid() || index.row() >= values_.size()) {
24 return QVariant();
25 }
26 const auto &value = values_.at(index.row());
27
28 switch (role) {
29 case Qt::DisplayRole:
30 return parent_->prettify(parent_->subOption(), value);
31 case Qt::UserRole:
32 return value;
33 }
34 return QVariant();
35 }
36
rowCount(const QModelIndex & parent=QModelIndex ()) const37 int rowCount(const QModelIndex &parent = QModelIndex()) const override {
38 if (parent.isValid()) {
39 return 0;
40 }
41
42 return values_.size();
43 }
44
readValueFrom(const QVariantMap & map,const QString & path)45 void readValueFrom(const QVariantMap &map, const QString &path) {
46 beginResetModel();
47 int i = 0;
48 values_.clear();
49 while (true) {
50 auto value = readVariant(map, QString("%1%2%3")
51 .arg(path)
52 .arg(path.isEmpty() ? "" : "/")
53 .arg(i));
54 if (value.isNull()) {
55 break;
56 }
57 values_ << value;
58 i++;
59 }
60 endResetModel();
61 }
62
writeValueTo(QVariantMap & map,const QString & path)63 void writeValueTo(QVariantMap &map, const QString &path) {
64 int i = 0;
65 for (auto &value : values_) {
66 writeVariant(map, QString("%1/%2").arg(path).arg(i), value);
67 i++;
68 }
69 if (!i) {
70 map[path] = QVariantMap();
71 }
72 }
73
addItem(QVariant value)74 void addItem(QVariant value) {
75 beginInsertRows(QModelIndex(), values_.size(), values_.size());
76 values_.append(value);
77 endInsertRows();
78 }
79
editItem(const QModelIndex & index,QVariant value)80 void editItem(const QModelIndex &index, QVariant value) {
81 if (!index.isValid() || index.row() >= values_.size()) {
82 return;
83 }
84
85 values_[index.row()] = value;
86 Q_EMIT dataChanged(index, index);
87 }
88
removeItem(const QModelIndex & index)89 void removeItem(const QModelIndex &index) {
90 if (!index.isValid() || index.row() >= values_.size()) {
91 return;
92 }
93 beginRemoveRows(index.parent(), index.row(), index.row());
94 values_.removeAt(index.row());
95 endRemoveRows();
96 }
97
moveUpItem(const QModelIndex & index)98 void moveUpItem(const QModelIndex &index) {
99 if (!index.isValid() || index.row() >= values_.size() ||
100 index.row() == 0) {
101 return;
102 }
103 Q_EMIT layoutAboutToBeChanged();
104 if (!beginMoveRows(index.parent(), index.row(), index.row(),
105 index.parent(), index.row() - 1)) {
106 return;
107 }
108 #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
109 values_.swap(index.row() - 1, index.row());
110 #else
111 values_.swapItemsAt(index.row() - 1, index.row());
112 #endif
113 endMoveRows();
114 }
115
moveDownItem(const QModelIndex & index)116 void moveDownItem(const QModelIndex &index) {
117 if (!index.isValid() || index.row() >= values_.size() ||
118 index.row() + 1 == values_.size()) {
119 return;
120 }
121 if (!beginMoveRows(index.parent(), index.row(), index.row(),
122 index.parent(), index.row() + 2)) {
123 return;
124 }
125 #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
126 values_.swap(index.row(), index.row() + 1);
127 #else
128 values_.swapItemsAt(index.row(), index.row() + 1);
129 #endif
130 endMoveRows();
131 }
132
133 private:
134 QList<QVariant> values_;
135 ListOptionWidget *parent_;
136 };
137
ListOptionWidget(const FcitxQtConfigOption & option,const QString & path,QWidget * parent)138 ListOptionWidget::ListOptionWidget(const FcitxQtConfigOption &option,
139 const QString &path, QWidget *parent)
140 : OptionWidget(path, parent), model_(new ListOptionWidgetModel(this)),
141 subOption_(option) {
142 setupUi(this);
143 listView->setModel(model_);
144
145 subOption_.setType(option.type().mid(5)); // Remove List|
146 auto props = option.properties();
147 if (props.contains("ListConstrain")) {
148 auto itemConstrain = props.value("ListConstrain").toMap();
149 props.remove("ListConstrain");
150 for (auto iter = itemConstrain.begin(), end = itemConstrain.end();
151 iter != end; ++iter) {
152 props[iter.key()] = iter.value();
153 }
154 }
155 subOption_.setProperties(props);
156 subOption_.setDefaultValue(QDBusVariant());
157
158 connect(listView->selectionModel(), &QItemSelectionModel::currentRowChanged,
159 this, [this]() { updateButton(); });
160
161 connect(model_, &QAbstractListModel::rowsMoved, this,
162 [this]() { updateButton(); });
163 connect(addButton, &QAbstractButton::clicked, this, [this]() {
164 QVariant result;
165 auto ok = OptionWidget::execOptionDialog(this, subOption_, result);
166 if (ok) {
167 model_->addItem(result);
168 }
169 });
170 connect(editButton, &QAbstractButton::clicked, this, [this]() {
171 QVariant result = model_->data(listView->currentIndex(), Qt::UserRole);
172 auto ok = OptionWidget::execOptionDialog(this, subOption_, result);
173 if (ok) {
174 model_->editItem(listView->currentIndex(), result);
175 }
176 });
177 connect(removeButton, &QAbstractButton::clicked, this,
178 [this]() { model_->removeItem(listView->currentIndex()); });
179 connect(moveUpButton, &QAbstractButton::clicked, this,
180 [this]() { model_->moveUpItem(listView->currentIndex()); });
181 connect(moveDownButton, &QAbstractButton::clicked, this,
182 [this]() { model_->moveDownItem(listView->currentIndex()); });
183
184 auto variant = option.defaultValue().variant();
185 if (variant.canConvert<QDBusArgument>()) {
186 auto argument = qvariant_cast<QDBusArgument>(variant);
187 argument >> defaultValue_;
188 }
189
190 updateButton();
191 }
192
updateButton()193 void ListOptionWidget::updateButton() {
194 editButton->setEnabled(listView->currentIndex().isValid());
195 removeButton->setEnabled(listView->currentIndex().isValid());
196 moveUpButton->setEnabled(listView->currentIndex().isValid() &&
197 listView->currentIndex().row() != 0);
198 moveDownButton->setEnabled(listView->currentIndex().isValid() &&
199 listView->currentIndex().row() !=
200 model_->rowCount() - 1);
201 }
202
readValueFrom(const QVariantMap & map)203 void ListOptionWidget::readValueFrom(const QVariantMap &map) {
204 model_->readValueFrom(map, path());
205 }
206
writeValueTo(QVariantMap & map)207 void ListOptionWidget::writeValueTo(QVariantMap &map) {
208 model_->writeValueTo(map, path());
209 }
210
restoreToDefault()211 void ListOptionWidget::restoreToDefault() {
212 model_->readValueFrom(defaultValue_, "");
213 }
214
215 } // namespace kcm
216 } // namespace fcitx
217