on cd077d5 help sign in
unity8/plugins/Wizard/keyboardLayoutsModel.cpp
173 lines 4.9 kB history raw
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 */
17#include <QDBusMetaType>
18#include <QDebug>
20#include "keyboardLayoutsModel.h"
22typedef QList<QMap<QString, QString>> StringMapList;
23Q_DECLARE_METATYPE(StringMapList)
25struct KeyboardLayoutInfo {
26 QString id;
27 QString displayName;
28 QString language;
29};
31KeyboardLayoutsModel::KeyboardLayoutsModel(QObject *parent)
32 : QAbstractListModel(parent)
34 m_roleNames = {
35 {LayoutIdRole, "layoutId"},
36 {DisplayNameRole, "displayName"},
37 {LanguageRole, "language"}
38 };
40 qDBusRegisterMetaType<StringMapList>();
41 m_xkbInfo = gnome_xkb_info_new();
43 buildModel();
44 connect(this, &KeyboardLayoutsModel::languageChanged, this, &KeyboardLayoutsModel::updateModel);
47KeyboardLayoutsModel::~KeyboardLayoutsModel()
49 if (m_xkbInfo != nullptr) {
50 g_object_unref(m_xkbInfo);
51 }
54QString KeyboardLayoutsModel::language() const
56 return m_language;
59void KeyboardLayoutsModel::setLanguage(const QString &language)
61 if (m_language == language)
62 return;
64 m_language = language;
65 Q_EMIT languageChanged(language);
68static bool compareLayouts(const KeyboardLayoutInfo &layout0, const KeyboardLayoutInfo &layout1)
70 QString name0(layout0.displayName);
71 QString name1(layout1.displayName);
73 if (name0 == name1) {
74 name0 = layout0.language;
75 name1 = layout1.language;
77 if (name0 == name1) {
78 name0 = layout0.id;
79 name1 = layout1.id;
80 }
81 }
83 return QString::localeAwareCompare(name0, name1) < 0;
86void KeyboardLayoutsModel::buildModel()
88 GList *sources, *tmp;
89 const gchar *display_name;
90 const gchar *short_name;
91 const gchar *xkb_layout;
92 const gchar *xkb_variant;
94 sources = gnome_xkb_info_get_all_layouts(m_xkbInfo);
96 for (tmp = sources; tmp != NULL; tmp = tmp->next) {
97 gboolean result = gnome_xkb_info_get_layout_info(m_xkbInfo, (const gchar *)tmp->data,
98 &display_name, &short_name, &xkb_layout, &xkb_variant);
99 if (!result) {
100 qWarning() << "!!! Skipping invalid layout";
101 continue;
102 }
104 KeyboardLayoutInfo layout;
105 layout.id = QString::fromUtf8((const gchar *)tmp->data);
106 layout.language = QString::fromUtf8(short_name);
107 layout.displayName = QString::fromUtf8(display_name);
109 m_db.append(layout);
110 qDebug() << "DB layout:" << layout.id << ", language:" << layout.language;
111 }
112 g_list_free(sources);
114 std::sort(m_db.begin(), m_db.end(), compareLayouts);
117void KeyboardLayoutsModel::updateModel()
119 beginResetModel();
120 m_layouts.clear();
122 const QString lang = m_language.section("_", 0, 0);
123 const QString country = m_language.section("_", 1, 1).toLower();
125 Q_FOREACH(const KeyboardLayoutInfo & info, m_db) {
126 const QString kbdCountry = info.id.section("+", 0, 0);
127 if (info.language == lang && // filter by language
128 (kbdCountry.startsWith(country) || kbdCountry.length() > 2)) { // and by known country, also insert anything that doesn't match the country
129 m_layouts.append(info);
130 qDebug() << "Inserted layout:" << info.id << ", language:" << info.language;
131 }
132 }
134 std::sort(m_layouts.begin(), m_layouts.end(), compareLayouts);
135 endResetModel();
138int KeyboardLayoutsModel::rowCount(const QModelIndex &parent) const
140 Q_UNUSED(parent)
141 return m_layouts.count();
144QVariant KeyboardLayoutsModel::data(const QModelIndex &index, int role) const
146 const int row = index.row();
148 if (row >= m_layouts.count()) {
149 qWarning() << Q_FUNC_INFO << "index out of bounds";
150 return QVariant();
151 }
153 KeyboardLayoutInfo layout = m_layouts.at(row);
155 switch (role) {
156 case Qt::DisplayRole:
157 case DisplayNameRole:
158 return layout.displayName;
159 case LayoutIdRole:
160 return layout.id;
161 case LanguageRole:
162 return layout.language;
163 default: {
164 qWarning() << Q_FUNC_INFO << "unsupported data role";
165 return QVariant();
166 }
167 }
170QHash<int, QByteArray> KeyboardLayoutsModel::roleNames() const
172 return m_roleNames;