Changeset View
Changeset View
Standalone View
Standalone View
kcms/keyboard/layoutmodel/fcitx_im_config_model.cpp
- This file was added.
1 | #include "fcitx_im_config_model.h" | ||||
---|---|---|---|---|---|
2 | | ||||
3 | #include <KConfigGroup> | ||||
4 | #include <KLocalizedString> | ||||
5 | #include <KSharedConfig> | ||||
6 | #include <QDBusInterface> | ||||
7 | #include <QDebug> | ||||
8 | #include <QFile> | ||||
9 | #include <QMetaEnum> | ||||
10 | #include <QSettings> | ||||
11 | | ||||
12 | #include "../fcitx/fcitxqtinputmethodproxy.h" | ||||
13 | #include "layout_list_model_fcitx.h" | ||||
14 | #include "../keyboard_dbus.h" | ||||
15 | | ||||
16 | FcitxIMListModel::FcitxIMListModel(QObject* parent) | ||||
17 | : LayoutListSortFilterProxyModel(parent) | ||||
18 | { | ||||
19 | setSourceModel(new LayoutListModelFcitx(this)); | ||||
20 | setSortRole(Roles::DescriptionRole); | ||||
21 | sort(0); | ||||
22 | } | ||||
23 | | ||||
24 | QHash<int, QByteArray> FcitxIMListModel::roleNames() const | ||||
25 | { | ||||
26 | return LayoutListModelBase::roleNames(); | ||||
27 | } | ||||
28 | | ||||
29 | bool FcitxIMListModel::filterAcceptsRow(int source_row, const QModelIndex &) const | ||||
30 | { | ||||
31 | QString name = sourceModel()->data(sourceModel()->index(source_row, 0), Roles::NameRole).toString(); | ||||
32 | return name.startsWith("fcitx-keyboard-"); | ||||
33 | } | ||||
34 | | ||||
35 | FcitxIMConfigModel::FcitxIMConfigModel(QString imName, QObject* parent) | ||||
36 | : QAbstractListModel(parent) | ||||
37 | , m_imName(imName) | ||||
38 | { | ||||
39 | QDBusInterface interface("org.fcitx.Fcitx", "/inputmethod", "org.fcitx.Fcitx.InputMethod"); | ||||
40 | QDBusMessage reply = interface.call("GetIMAddon", imName); | ||||
41 | m_addonName = reply.arguments().first().toString(); | ||||
42 | | ||||
43 | QString config_desc_path = QString("/usr/share/fcitx/configdesc/%1.desc").arg(m_addonName); | ||||
44 | | ||||
45 | // determine order of config items | ||||
46 | QFile config_desc_file(config_desc_path); | ||||
47 | config_desc_file.open(QIODevice::ReadOnly); | ||||
48 | if (!config_desc_file.isOpen()) { | ||||
49 | qWarning() << "Cannot open config description file"; | ||||
50 | return; | ||||
51 | } | ||||
52 | QTextStream stream(&config_desc_file); | ||||
53 | QString line; | ||||
54 | QStringList order; | ||||
55 | while (stream.readLineInto(&line)) { | ||||
56 | if (line.startsWith('[')) { | ||||
57 | order << line; | ||||
58 | } | ||||
59 | } | ||||
60 | config_desc_file.close(); | ||||
61 | | ||||
62 | // read description | ||||
63 | QSettings config_desc(config_desc_path, QSettings::IniFormat); | ||||
64 | for (QString group : config_desc.childGroups()) { | ||||
65 | if (group == "DescriptionFile") { | ||||
66 | continue; | ||||
67 | } | ||||
68 | config_desc.beginGroup(group); | ||||
69 | for (QString name : config_desc.childGroups()) { | ||||
70 | config_desc.beginGroup(name); | ||||
71 | | ||||
72 | ConfigItem item; | ||||
73 | item.group = group; | ||||
74 | item.name = name; | ||||
75 | item.description = config_desc.value("Description").toString(); | ||||
76 | item.default_value = config_desc.value("DefaultValue").toString(); | ||||
77 | | ||||
78 | QString type_string = config_desc.value("Type").toString(); | ||||
79 | if (type_string == "Integer") { | ||||
80 | item.type = ConfigType::IntegerType; | ||||
81 | } else if (type_string == "Char") { | ||||
82 | item.type = ConfigType::CharType; | ||||
83 | } else if (type_string == "String") { | ||||
84 | item.type = ConfigType::StringType; | ||||
85 | } else if (type_string == "I18NString") { | ||||
86 | item.type = ConfigType::I18NStringType; | ||||
87 | } else if (type_string == "Boolean") { | ||||
88 | item.type = ConfigType::BooleanType; | ||||
89 | } else if (type_string == "File") { | ||||
90 | item.type = ConfigType::FileType; | ||||
91 | } else if (type_string == "Font") { | ||||
92 | item.type = ConfigType::FontType; | ||||
93 | } else if (type_string == "Hotkey") { | ||||
94 | item.type = ConfigType::HotkeyType; | ||||
95 | } else if (type_string == "Enum") { | ||||
96 | item.type = ConfigType::EnumType; | ||||
97 | int num = config_desc.value("EnumCount").toInt(); | ||||
98 | QStringList list; | ||||
99 | for (int i = 0; i < num; ++i) { | ||||
100 | list << config_desc.value(QString("Enum%1").arg(i)).toString(); | ||||
101 | } | ||||
102 | item.data = list; | ||||
103 | } | ||||
104 | | ||||
105 | m_configs << item; | ||||
106 | | ||||
107 | config_desc.endGroup(); | ||||
108 | } | ||||
109 | config_desc.endGroup(); | ||||
110 | } | ||||
111 | | ||||
112 | std::sort(m_configs.begin(), m_configs.end(), [&](ConfigItem const& l, ConfigItem const& r) { | ||||
113 | int left = order.indexOf(QString("[%1/%2]").arg(l.group, l.name)); | ||||
114 | int right = order.indexOf(QString("[%1/%2]").arg(r.group, r.name)); | ||||
115 | Q_ASSERT(left != -1 && right != -1); | ||||
116 | return left < right; | ||||
117 | }); | ||||
118 | | ||||
119 | // read config values | ||||
120 | auto config_path = QString("fcitx/conf/%1.config").arg(m_addonName); | ||||
121 | KSharedConfigPtr config = KSharedConfig::openConfig(config_path, KConfig::SimpleConfig); | ||||
122 | | ||||
123 | for (auto& item : m_configs) { | ||||
124 | KConfigGroup group(config, item.group); | ||||
125 | | ||||
126 | switch (item.type) { | ||||
127 | case ConfigType::IntegerType: | ||||
128 | item.current_value = group.readEntry<int>(item.name, item.default_value.toInt()); | ||||
129 | break; | ||||
130 | case ConfigType::BooleanType: | ||||
131 | item.current_value = group.readEntry<bool>(item.name, item.default_value.toBool()); | ||||
132 | break; | ||||
133 | case ConfigType::EnumType: | ||||
134 | item.current_value = group.readEntry<QString>(item.name, item.default_value.toString()); | ||||
135 | break; | ||||
136 | case ConfigType::CharType: | ||||
137 | case ConfigType::StringType: | ||||
138 | case ConfigType::HotkeyType: | ||||
139 | item.current_value = group.readEntry<QString>(item.name, item.default_value.toString()); | ||||
140 | break; | ||||
141 | } | ||||
142 | } | ||||
143 | | ||||
144 | if (isRealIM()) { | ||||
145 | m_latinModeLayoutList = new FcitxIMListModel(this); | ||||
146 | | ||||
147 | KConfigGroup kxkbrc( | ||||
148 | KSharedConfig::openConfig(QStringLiteral("kxkbrc"), KConfig::NoGlobals), | ||||
149 | QStringLiteral("Layout")); | ||||
150 | | ||||
151 | setIsLatinSwitchingEnabled(kxkbrc.readEntry<bool>(QString("Fcitx%1LatinFallBackEnabled").arg(m_imName), false)); | ||||
152 | setSelectedLatinLayoutId(kxkbrc.readEntry<QString>(QString("Fcitx%1LatinFallBack").arg(m_imName), QString("us"))); | ||||
153 | } | ||||
154 | } | ||||
155 | | ||||
156 | int FcitxIMConfigModel::rowCount(const QModelIndex& parent) const | ||||
157 | { | ||||
158 | // For list models only the root node (an invalid parent) should return the list's size. For all | ||||
159 | // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. | ||||
160 | if (parent.isValid()) | ||||
161 | return 0; | ||||
162 | | ||||
163 | return m_configs.size(); | ||||
164 | } | ||||
165 | | ||||
166 | QVariant FcitxIMConfigModel::data(const QModelIndex& index, int role) const | ||||
167 | { | ||||
168 | if (!index.isValid()) | ||||
169 | return QVariant(); | ||||
170 | | ||||
171 | auto const& item = m_configs[index.row()]; | ||||
172 | switch (role) { | ||||
173 | case Roles::NameRole: | ||||
174 | return item.name; | ||||
175 | case Roles::GroupRole: | ||||
176 | return item.group; | ||||
177 | case Roles::TypeRole: | ||||
178 | return QMetaEnum::fromType<ConfigType>().valueToKey(item.type); | ||||
179 | case Roles::DescriptionRole: | ||||
180 | return item.description; | ||||
181 | case Roles::DataRole: | ||||
182 | return item.data; | ||||
183 | case Roles::CurrentValueRole: | ||||
184 | return item.current_value; | ||||
185 | } | ||||
186 | | ||||
187 | return QVariant(); | ||||
188 | } | ||||
189 | | ||||
190 | bool FcitxIMConfigModel::setData(const QModelIndex& index, const QVariant& value, int role) | ||||
191 | { | ||||
192 | qDebug() << "setData"; | ||||
193 | if (role == Roles::CurrentValueRole) { | ||||
194 | m_configs[index.row()].current_value = value; | ||||
195 | } | ||||
196 | return false; | ||||
197 | } | ||||
198 | | ||||
199 | QHash<int, QByteArray> FcitxIMConfigModel::roleNames() const | ||||
200 | { | ||||
201 | return { | ||||
202 | { Roles::NameRole, "name" }, | ||||
203 | { Roles::GroupRole, "group" }, | ||||
204 | { Roles::TypeRole, "type" }, | ||||
205 | { Roles::DescriptionRole, "description" }, | ||||
206 | { Roles::DataRole, "data" }, | ||||
207 | { Roles::CurrentValueRole, "current_value" } | ||||
208 | }; | ||||
209 | } | ||||
210 | | ||||
211 | void FcitxIMConfigModel::save() const | ||||
212 | { | ||||
213 | qDebug() << "save"; | ||||
214 | if (isRealIM()) { | ||||
215 | KConfigGroup kxkbrc( | ||||
216 | KSharedConfig::openConfig(QStringLiteral("kxkbrc"), KConfig::NoGlobals), | ||||
217 | QStringLiteral("Layout")); | ||||
218 | kxkbrc.writeEntry<bool>(QString("Fcitx%1LatinFallBackEnabled").arg(m_imName), isLatinSwitchingEnabled()); | ||||
219 | kxkbrc.writeEntry<QString>(QString("Fcitx%1LatinFallBack").arg(m_imName), m_selectedLatinLayoutId); | ||||
220 | kxkbrc.sync(); | ||||
221 | } | ||||
222 | | ||||
223 | auto config_path = QString("fcitx/conf/%1.config").arg(m_addonName); | ||||
224 | KSharedConfigPtr config = KSharedConfig::openConfig(config_path, KConfig::SimpleConfig); | ||||
225 | | ||||
226 | for (auto const& item : m_configs) { | ||||
227 | KConfigGroup group(config, item.group); | ||||
228 | | ||||
229 | switch (item.type) { | ||||
230 | case ConfigType::IntegerType: | ||||
231 | group.writeEntry<int>(item.name, item.current_value.toInt()); | ||||
232 | break; | ||||
233 | case ConfigType::BooleanType: | ||||
234 | group.writeEntry<bool>(item.name, item.current_value.toBool()); | ||||
235 | break; | ||||
236 | case ConfigType::EnumType: | ||||
237 | group.writeEntry<QString>(item.name, item.current_value.toString()); | ||||
238 | break; | ||||
239 | case ConfigType::CharType: | ||||
240 | case ConfigType::StringType: | ||||
241 | case ConfigType::HotkeyType: | ||||
242 | group.writeEntry<QString>(item.name, item.current_value.toString()); | ||||
243 | break; | ||||
244 | } | ||||
245 | | ||||
246 | group.sync(); | ||||
247 | } | ||||
248 | | ||||
249 | // dbus call to the kded (in X11) / kwin (in Wayland) to apply the config changes | ||||
250 | QDBusMessage message = QDBusMessage::createSignal( | ||||
251 | KEYBOARD_DBUS_OBJECT_PATH, | ||||
252 | KEYBOARD_DBUS_SERVICE_NAME, | ||||
253 | KEYBOARD_DBUS_CONFIG_RELOAD_MESSAGE); | ||||
254 | QDBusConnection::sessionBus().send(message); | ||||
255 | } | ||||
256 | | ||||
257 | FcitxIMListModel* FcitxIMConfigModel::latinModeLayoutList() const | ||||
258 | { | ||||
259 | return m_latinModeLayoutList; | ||||
260 | } | ||||
261 | | ||||
262 | bool FcitxIMConfigModel::isLatinSwitchingEnabled() const | ||||
263 | { | ||||
264 | return m_isLatinSwitchingEnabled; | ||||
265 | } | ||||
266 | | ||||
267 | void FcitxIMConfigModel::setIsLatinSwitchingEnabled(bool isLatinSwitchingEnabled) | ||||
268 | { | ||||
269 | if (m_isLatinSwitchingEnabled != isLatinSwitchingEnabled) { | ||||
270 | m_isLatinSwitchingEnabled = isLatinSwitchingEnabled; | ||||
271 | } | ||||
272 | } | ||||
273 | | ||||
274 | int FcitxIMConfigModel::selectedLatinLayoutIndex() const | ||||
275 | { | ||||
276 | for (int row = 0; row < m_latinModeLayoutList->rowCount(); ++row) { | ||||
277 | if (m_latinModeLayoutList->data(m_latinModeLayoutList->index(row, 0), Roles::NameRole) == m_selectedLatinLayoutId) { | ||||
278 | return row; | ||||
279 | } | ||||
280 | } | ||||
281 | return -1; | ||||
282 | } | ||||
283 | | ||||
284 | void FcitxIMConfigModel::setSelectedLatinLayoutIndex(int index) | ||||
285 | { | ||||
286 | if (selectedLatinLayoutIndex() != index) { | ||||
287 | m_selectedLatinLayoutId = m_latinModeLayoutList->data(m_latinModeLayoutList->index(index, 0), Roles::NameRole).toString(); | ||||
288 | emit selectedLatinLayoutIndexChanged(); | ||||
289 | } | ||||
290 | } | ||||
291 | | ||||
292 | QString FcitxIMConfigModel::selectedLatinLayoutId() const | ||||
293 | { | ||||
294 | return m_selectedLatinLayoutId; | ||||
295 | } | ||||
296 | | ||||
297 | void FcitxIMConfigModel::setSelectedLatinLayoutId(const QString &selectedLatinLayoutId) | ||||
298 | { | ||||
299 | if (m_selectedLatinLayoutId != selectedLatinLayoutId) { | ||||
300 | m_selectedLatinLayoutId = selectedLatinLayoutId; | ||||
301 | emit selectedLatinLayoutIndexChanged(); | ||||
302 | } | ||||
303 | } | ||||
304 | | ||||
305 | bool FcitxIMConfigModel::isRealIM() const | ||||
306 | { | ||||
307 | return !m_imName.startsWith("fcitx-keyboard-"); | ||||
308 | } |