on xenial help sign in
WIP keyboard layouts model
commiteb5ccd8f8b777b23e0d2b55f355ed2e421f8f3cd authorLukáš Tinkl <lukas.tinkl@canonical.com> dateTue 17 May 2016, 18:29 (10 years ago) parentc59babe
11 files changed+247−50
CMakeLists.txt+1 debian/control+1 plugins/Wizard/CMakeLists.txt+6−3 plugins/Wizard/Wizard.qmltypes−33 plugins/Wizard/keyboardLayoutsModel.cpp+165 plugins/Wizard/keyboardLayoutsModel.h+64 plugins/Wizard/plugin.cpp+2 plugins/Wizard/qmldir−1 tests/mocks/Ubuntu/SystemSettings/LanguagePlugin/LanguagePlugin.qmltypes−10 tests/mocks/Wizard/CMakeLists.txt+6−3 tests/mocks/Wizard/mockplugin.cpp+2
CMakeLists.txt+1
@@ -62,6 +62,7 @@ pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
6262pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
6363pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
6464pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
65+pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
6566
6667# Standard install paths
6768include(GNUInstallDirs)
debian/control+1
@@ -16,6 +16,7 @@ Build-Depends: cmake,
1616 libconnectivity-qt1-dev (>= 0.7.1),
1717 libevdev-dev,
1818 libgeonames-dev (>= 0.2),
19+ libgnome-desktop-3-dev,
1920 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
2021 libgl1-mesa-dri,
2122 libgles2-mesa-dev[armhf],
plugins/Wizard/CMakeLists.txt+6−3
@@ -1,4 +1,6 @@
1−include_directories(${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS})
1+pkg_search_module(GD3 REQUIRED gnome-desktop-3.0)
2+
3+include_directories(${GD3_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS})
24
35add_library(Wizard-qml MODULE
46 plugin.cpp
@@ -7,10 +9,11 @@ add_library(Wizard-qml MODULE
79 LocalePlugin.cpp
810 timezonemodel.cpp
911 Status.cpp
12+ keyboardLayoutsModel.cpp
1013)
1114
12−qt5_use_modules(Wizard-qml DBus Qml Concurrent)
13−target_link_libraries(Wizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
15+qt5_use_modules(Wizard-qml DBus Qml)
16+target_link_libraries(Wizard-qml ${GD3_LDFLAGS} ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
1417add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml)
1518
1619set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
plugins/Wizard/Wizard.qmltypesdeleted−33
@@ -1,33 +0,0 @@
1−import QtQuick.tooling 1.1
2−
3−// This file describes the plugin-supplied types contained in the library.
4−// It is used for QML tooling purposes only.
5−//
6−// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable Wizard 0.1 plugins'
8−
9−Module {
10− Component {
11− name: "PageList"
12− prototype: "QObject"
13− exports: ["Wizard/PageList 0.1"]
14− exportMetaObjectRevisions: [0]
15− Property { name: "index"; type: "int"; isReadonly: true }
16− Property { name: "numPages"; type: "int"; isReadonly: true }
17− Method { name: "prev"; type: "string" }
18− Method { name: "next"; type: "string" }
19− }
20− Component {
21− name: "System"
22− prototype: "QObject"
23− exports: ["Wizard/System 0.1"]
24− isCreatable: false
25− isSingleton: true
26− exportMetaObjectRevisions: [0]
27− Property { name: "wizardEnabled"; type: "bool" }
28− Method {
29− name: "updateSessionLanguage"
30− Parameter { name: "locale"; type: "string" }
31− }
32− }
33−}
plugins/Wizard/keyboardLayoutsModel.cppnew file+165
@@ -0,0 +1,165 @@
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+#include "keyboardLayoutsModel.h"
21+
22+typedef QList<QMap<QString, QString>> StringMapList;
23+Q_DECLARE_METATYPE(StringMapList)
24+
25+struct KeyboardLayoutInfo {
26+ QString id;
27+ QString displayName;
28+ QString shortName; // language
29+ QString layoutAndVariant;
30+};
31+
32+KeyboardLayoutsModel::KeyboardLayoutsModel(QObject *parent)
33+ : QAbstractListModel(parent)
34+{
35+ m_roleNames = {
36+ {LayoutIdRole, "layoutId"},
37+ {DisplayNameRole, "displayName"},
38+ {ShortNameRole, "shortName"},
39+ {LayoutAndVariantRole, "layoutAndVariant"}
40+ };
41+
42+ qDBusRegisterMetaType<StringMapList>();
43+ m_xkbInfo = gnome_xkb_info_new();
44+
45+ connect(this, &KeyboardLayoutsModel::languageChanged, this, &KeyboardLayoutsModel::buildModel);
46+ buildModel();
47+}
48+
49+KeyboardLayoutsModel::~KeyboardLayoutsModel()
50+{
51+ if (m_xkbInfo != nullptr) {
52+ g_object_unref(m_xkbInfo);
53+ }
54+}
55+
56+QString KeyboardLayoutsModel::language() const
57+{
58+ return m_language;
59+}
60+
61+void KeyboardLayoutsModel::setLanguage(const QString &language)
62+{
63+ if (m_language == language)
64+ return;
65+
66+ m_language = language;
67+ Q_EMIT languageChanged(language);
68+}
69+
70+static bool compareLayouts(const KeyboardLayoutInfo &layout0, const KeyboardLayoutInfo &layout1)
71+{
72+ QString name0(layout0.displayName);
73+ QString name1(layout1.displayName);
74+
75+ if (name0 == name1) {
76+ name0 = layout0.shortName;
77+ name1 = layout1.shortName;
78+
79+ if (name0 == name1) {
80+ name0 = layout0.id;
81+ name1 = layout1.id;
82+ }
83+ }
84+
85+ return QString::localeAwareCompare(name0, name1) < 0;
86+}
87+
88+void KeyboardLayoutsModel::buildModel()
89+{
90+ beginResetModel();
91+
92+ if (m_language.isEmpty()) {
93+ GList *sources, *tmp;
94+ const gchar *display_name;
95+ const gchar *short_name;
96+ const gchar *xkb_layout;
97+ const gchar *xkb_variant;
98+ sources = gnome_xkb_info_get_all_layouts(m_xkbInfo);
99+
100+ m_layouts.clear();
101+ m_layouts.reserve(g_list_length(sources));
102+
103+ for (tmp = sources; tmp != NULL; tmp = tmp->next) {
104+ gnome_xkb_info_get_layout_info(m_xkbInfo, (const gchar *)tmp->data,
105+ &display_name, &short_name, &xkb_layout, &xkb_variant);
106+
107+ KeyboardLayoutInfo layout;
108+ layout.id = QString::fromUtf8((const gchar *)tmp->data);
109+ layout.shortName = QString::fromUtf8(short_name);
110+ layout.displayName = QString::fromUtf8(display_name);
111+ layout.layoutAndVariant = QString::fromUtf8(g_strconcat(xkb_layout, "+", xkb_variant, NULL));
112+
113+ if (!layout.shortName.isEmpty()) {
114+ qDebug() << "Appending layout with id:" << layout.id;
115+ m_layouts.append(layout);
116+ }
117+
118+ }
119+ g_list_free(sources);
120+ std::sort(m_layouts.begin(), m_layouts.end(), compareLayouts);
121+ } else {
122+ // TODO
123+ }
124+
125+ endResetModel();
126+}
127+
128+int KeyboardLayoutsModel::rowCount(const QModelIndex &parent) const
129+{
130+ Q_UNUSED(parent)
131+ return m_layouts.count();
132+}
133+
134+QVariant 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+ 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 ShortNameRole:
152+ return layout.shortName;
153+ case LayoutAndVariantRole:
154+ return layout.layoutAndVariant;
155+ default: {
156+ qWarning() << Q_FUNC_INFO << "unsupported data role";
157+ return QVariant();
158+ }
159+ }
160+}
161+
162+QHash<int, QByteArray> KeyboardLayoutsModel::roleNames() const
163+{
164+ return m_roleNames;
165+}
plugins/Wizard/keyboardLayoutsModel.hnew file+64
@@ -0,0 +1,64 @@
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+#ifndef KEYBOARDLAYOUTSMODEL_H
18+#define KEYBOARDLAYOUTSMODEL_H
19+
20+#include <QAbstractListModel>
21+
22+#define GNOME_DESKTOP_USE_UNSTABLE_API
23+#include <libgnome-desktop/gnome-xkb-info.h>
24+
25+struct KeyboardLayoutInfo;
26+
27+class KeyboardLayoutsModel: public QAbstractListModel
28+{
29+ Q_OBJECT
30+
31+ Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged)
32+
33+public:
34+ explicit KeyboardLayoutsModel(QObject * parent = nullptr);
35+ ~KeyboardLayoutsModel();
36+
37+ enum Roles {
38+ LayoutIdRole = Qt::UserRole + 1,
39+ DisplayNameRole,
40+ ShortNameRole,
41+ LayoutAndVariantRole,
42+ };
43+
44+ QString language() const;
45+ void setLanguage(const QString &language);
46+
47+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
48+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
49+ QHash<int, QByteArray> roleNames() const override;
50+
51+Q_SIGNALS:
52+ void languageChanged(const QString &language);
53+
54+private Q_SLOTS:
55+ void buildModel();
56+
57+private:
58+ QString m_language;
59+ QHash<int, QByteArray> m_roleNames;
60+ QVector<KeyboardLayoutInfo> m_layouts;
61+ GnomeXkbInfo *m_xkbInfo = nullptr;
62+};
63+
64+#endif
plugins/Wizard/plugin.cpp+2
@@ -20,6 +20,7 @@
2020#include "timezonemodel.h"
2121#include "LocalePlugin.h"
2222#include "Status.h"
23+#include "keyboardLayoutsModel.h"
2324
2425#include <QtQml/qqml.h>
2526
@@ -30,5 +31,6 @@ void WizardPlugin::registerTypes(const char *uri)
3031 qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; });
3132 qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
3233 qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
34+ qmlRegisterType<KeyboardLayoutsModel>(uri, 0, 1, "KeyboardLayoutsModel");
3335 qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
3436}
plugins/Wizard/qmldir−1
@@ -1,3 +1,2 @@
11module Wizard
22plugin Wizard-qml
3−typeinfo Wizard.qmltypes
tests/mocks/Ubuntu/SystemSettings/LanguagePlugin/LanguagePlugin.qmltypesdeleted−10
@@ -1,10 +0,0 @@
1−import QtQuick.tooling 1.1
2−
3−// This file describes the plugin-supplied types contained in the library.
4−// It is used for QML tooling purposes only.
5−//
6−// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable Ubuntu.SystemSettings.LanguagePlugin 1.0 tests/mocks'
8−
9−Module {
10−}
tests/mocks/Wizard/CMakeLists.txt+6−3
@@ -1,5 +1,7 @@
1+pkg_search_module(GD3 REQUIRED gnome-desktop-3.0)
2+
13include_directories(
2− ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS}
4+ ${GD3_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS}
35 ${CMAKE_SOURCE_DIR}/plugins/Wizard
46)
57
@@ -10,8 +12,9 @@ add_library(MockWizard-qml MODULE
1012 ${CMAKE_SOURCE_DIR}/plugins/Wizard/timezonemodel.cpp
1113 ${CMAKE_SOURCE_DIR}/plugins/Wizard/LocalePlugin.cpp
1214 ${CMAKE_SOURCE_DIR}/plugins/Wizard/Status.cpp
15+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/keyboardLayoutsModel.cpp
1316)
1417
15−qt5_use_modules(MockWizard-qml DBus Qml Concurrent)
16−target_link_libraries(MockWizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
18+qt5_use_modules(MockWizard-qml DBus Qml)
19+target_link_libraries(MockWizard-qml ${GD3_LDFLAGS} ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
1720add_unity8_mock(Wizard 0.1 Wizard TARGETS MockWizard-qml)
tests/mocks/Wizard/mockplugin.cpp+2
@@ -20,6 +20,7 @@
2020#include "timezonemodel.h"
2121#include "LocalePlugin.h"
2222#include "Status.h"
23+#include "keyboardLayoutsModel.h"
2324
2425#include <QtQml/qqml.h>
2526
@@ -30,5 +31,6 @@ void MockWizardPlugin::registerTypes(const char *uri)
3031 qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new MockSystem; });
3132 qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
3233 qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
34+ qmlRegisterType<KeyboardLayoutsModel>(uri, 0, 1, "KeyboardLayoutsModel");
3335 qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
3436}