Lomiri
Loading...
Searching...
No Matches
keyboardLayoutsModel.cpp
1/*
2 * Copyright (C) 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <QDBusMetaType>
18#include <QDebug>
19
20#define GNOME_DESKTOP_USE_UNSTABLE_API
21#include <libgnome-desktop/gnome-xkb-info.h>
22
23#include "keyboardLayoutsModel.h"
24
25typedef QList<QMap<QString, QString>> StringMapList;
26Q_DECLARE_METATYPE(StringMapList)
27
28KeyboardLayoutsModel::KeyboardLayoutsModel(QObject *parent)
29 : QAbstractListModel(parent)
30{
31 m_roleNames = {
32 {LayoutIdRole, "layoutId"},
33 {DisplayNameRole, "displayName"},
34 {LanguageRole, "language"}
35 };
36
37 qDBusRegisterMetaType<StringMapList>();
38
39 buildModel();
40 connect(this, &KeyboardLayoutsModel::languageChanged, this, &KeyboardLayoutsModel::updateModel);
41}
42
43QString KeyboardLayoutsModel::language() const
44{
45 return m_language;
46}
47
48void KeyboardLayoutsModel::setLanguage(const QString &language)
49{
50 if (m_language == language)
51 return;
52
53 m_language = language;
54 Q_EMIT languageChanged(language);
55}
56
57static bool compareLayouts(const KeyboardLayoutInfo &layout0, const KeyboardLayoutInfo &layout1)
58{
59 QString name0(layout0.id);
60 QString name1(layout1.id);
61
62 if (name0 == name1) {
63 name0 = layout0.displayName;
64 name1 = layout1.displayName;
65
66 if (name0 == name1) {
67 name0 = layout0.language;
68 name1 = layout1.language;
69 }
70 }
71
72 return QString::localeAwareCompare(name0, name1) < 0;
73}
74
75void KeyboardLayoutsModel::buildModel()
76{
77 GList *sources, *tmp;
78 const gchar *display_name;
79 const gchar *short_name;
80 const gchar *xkb_layout;
81 const gchar *xkb_variant;
82
83 GnomeXkbInfo * xkbInfo(gnome_xkb_info_new());
84
85 sources = gnome_xkb_info_get_all_layouts(xkbInfo);
86
87 for (tmp = sources; tmp != NULL; tmp = tmp->next) {
88 gboolean result = gnome_xkb_info_get_layout_info(xkbInfo, (const gchar *)tmp->data,
89 &display_name, &short_name, &xkb_layout, &xkb_variant);
90 if (!result) {
91 qWarning() << "Skipping invalid layout";
92 continue;
93 }
94
95 KeyboardLayoutInfo layout;
96 layout.id = QString::fromUtf8((const gchar *)tmp->data);
97 layout.language = QString::fromUtf8(short_name);
98 layout.displayName = QString::fromUtf8(display_name);
99
100 m_db.append(layout);
101 }
102 g_list_free(sources);
103 g_object_unref(xkbInfo);
104
105 std::sort(m_db.begin(), m_db.end(), compareLayouts);
106}
107
108void KeyboardLayoutsModel::updateModel()
109{
110 beginResetModel();
111 m_layouts.clear();
112
113 const QString lang = m_language.section("_", 0, 0);
114 const QString country = m_language.section("_", 1, 1).toLower();
115
116 Q_FOREACH(const KeyboardLayoutInfo & info, m_db) {
117 const QString kbdCountry = info.id.section("+", 0, 0);
118 if (info.language == lang && // filter by language
119 (kbdCountry.startsWith(country) || kbdCountry.length() > 2)) { // and by known country, also insert anything that doesn't match the country
120 m_layouts.append(info);
121 }
122 }
123
124 std::sort(m_layouts.begin(), m_layouts.end(), compareLayouts);
125 endResetModel();
126}
127
128int KeyboardLayoutsModel::rowCount(const QModelIndex &parent) const
129{
130 Q_UNUSED(parent)
131 return m_layouts.count();
132}
133
134QVariant KeyboardLayoutsModel::data(const QModelIndex &index, int role) const
135{
136 const int row = index.row();
137
138 if (row >= m_layouts.count()) {
139 qWarning() << Q_FUNC_INFO << "index out of bounds";
140 return QVariant();
141 }
142
143 const KeyboardLayoutInfo &layout = m_layouts.at(row);
144
145 switch (role) {
146 case Qt::DisplayRole:
147 case DisplayNameRole:
148 return layout.displayName;
149 case LayoutIdRole:
150 return layout.id;
151 case LanguageRole:
152 return layout.language;
153 default: {
154 qWarning() << Q_FUNC_INFO << "unsupported data role";
155 return QVariant();
156 }
157 }
158}
159
160QHash<int, QByteArray> KeyboardLayoutsModel::roleNames() const
161{
162 return m_roleNames;
163}