Merge lp:~attente/ubuntu-system-settings/maliit-settings into lp:ubuntu-system-settings

Proposed by William Hua
Status: Merged
Approved by: Sebastien Bacher
Approved revision: 323
Merged at revision: 412
Proposed branch: lp:~attente/ubuntu-system-settings/maliit-settings
Merge into: lp:ubuntu-system-settings
Diff against target: 1883 lines (+1370/-189)
14 files modified
debian/control (+2/-0)
plugins/language/KeyboardLayoutItem.qml (+74/-0)
plugins/language/KeyboardLayouts.qml (+30/-42)
plugins/language/PageComponent.qml (+69/-28)
plugins/language/SpellChecking.qml (+29/-49)
plugins/language/SubsetView.qml (+90/-0)
plugins/language/keyboard-layout.cpp (+88/-0)
plugins/language/keyboard-layout.h (+68/-0)
plugins/language/language-plugin.cpp (+315/-60)
plugins/language/language-plugin.h (+68/-1)
plugins/language/language.pro (+9/-8)
plugins/language/plugin.cpp (+2/-1)
plugins/language/subset-model.cpp (+403/-0)
plugins/language/subset-model.h (+123/-0)
To merge this branch: bzr merge lp:~attente/ubuntu-system-settings/maliit-settings
Reviewer Review Type Date Requested Status
Sebastien Bacher (community) Approve
PS Jenkins bot continuous-integration Approve
Iain Lane Needs Fixing
Review via email: mp+182643@code.launchpad.net

Commit message

Hook up language panel to some maliit settings.

Description of the change

Hook up language panel to some maliit settings.

This depends on https://code.launchpad.net/~attente/ubuntu-keyboard/gsettings-schema/+merge/185121.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
295. By William Hua

Build depend on libqt5xmlpatterns5-dev.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
296. By William Hua

Subset model.

297. By William Hua

Simplify SubsetModel.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
298. By William Hua

Hook up signals and save enabled plugins.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
299. By William Hua

Animate subset changes.

300. By William Hua

[ Sebastien Bacher ]
* use the theme provider for themed icons.
[ Ubuntu daily release ]
* Automatic snapshot from revision 315
[ Sebastien Bacher ]
* sound: use the new ItemSelector list widget.
* battery: use the new ItemSelector list widget. Depends on the new
  toolkit version for that. If the configuration value is zero, than
  select the "never" entry as well.
[ Ubuntu daily release ]
* Automatic snapshot from revision 312
[ Sebastien Bacher ]
* stop using the deprecated gicon provider, use the new themed icon
  instead. Change the plugin icon code to support themed icons, as
  well as urls to file locations on disk.
[ Iain Lane ]
* UI (without backend) for setting/changing the unlock
  password/passphrase.
[ Ubuntu daily release ]
* Automatic snapshot from revision 309
[ Sebastien Bacher ]
* drop the gps control from the main screen.
[ Iain Lane ]
* Make the Automatic / Manual selector in Time & Date toggle
  timedated's NTP property.
[ Ubuntu daily release ]
* Automatic snapshot from revision 306
[ Guenter Schwann ]
* Use content hub for picking a background from the gallery.
[ Ubuntu daily release ]
* Automatic snapshot from revision 302
[ Iain Lane ]
* Add a custom AccountsService schema and set up two examples.
[ Ubuntu daily release ]
* Automatic snapshot from revision 296
[ Sebastien Bacher ]
* use a better icon, since the mobile theme provides one.
* battery: 100% is fully charged Since upower seems to not always
  consider 100% as fully charged, check for the charge, as well as for
  the status.
[ Ubuntu daily release ]
* Automatic snapshot from revision 294
[ Iain Lane ]
* Use battery's SleepValues panel for lock/sleep when idle timeout.
[ Ubuntu daily release ]
* Automatic snapshot from revision 290

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
301. By William Hua

Fix opacity issue.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Iain Lane (laney) wrote :

Sorry for not looking sooner.

I've done a quick review from the diff without building. I've only got one
style comment and one question at this point. :-)

Not sure why this wasn't picked up before, but our style is to use

  if (brackets_like_this) {
    // do stuff
  }

rather than

  if (brackets_like_this)
  {
    //do stuff
  }

What's the idea behind the SubsetModel stuff?

review: Needs Fixing
302. By William Hua

Fix braces style.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
William Hua (attente) wrote :

Iain, thanks for the review. The brace style is fixed.

The SubsetModel is an attempt to implement the behaviour in:

1. https://wiki.ubuntu.com/LanguageAndText#Phone:_.2BIBw-Keyboard_layouts.2BIB0_settings
2. https://wiki.ubuntu.com/LanguageAndText#Spell-checking [*]

using the available ListView component.

Particularly: "Unchecking a layout should, after a two-second delay in case you want to change your mind, remove it from the “Current layouts:” list."

But there's still a serious bug I'm running into that suggests it might be better to write a new SubsetView component instead, however...

[*] may be removed in the future

303. By William Hua

[ Sebastien Bacher ]
* background: use the new OptionSelector, tweak the UI to be closer
  from the visuals (move the labels at the bottom of the images, use
  smaller text, use correct spacing).
* battery: set current value on the graph.
* reset: implement backend to reset the unity launcher settings.
* storage: display the clicks' list rather than the fake datas.
* updates: use the new ItemSelector widget, updated the download
  option to match the current design as well, moving the selector in
  its own subpage.
* orientation: replace "Rotation lock" by "Orientation lock".
* language: use new ItemSelector widget.
* storage: use new ItemSelector widget.
* battery: on the desktop use idle-delay's key, which is not
  deprecated.
[ Iain Lane ]
* Make the panels display "Lock on idle" or "Sleep on idle" as
  appropriate.
* Add UI and backend for setting the time manually.
* Make the "Change passphrase" / "Change passcode" button work.
* Implement filtering in the main window.
* Typo fix "Septemper" → "September". (LP: #1221400)
* Set the unlock type in a QSettings file (~/.unity8-greeter-demo).
  (LP: #1218010)
* security-privacy: Implement changing password and validation of
  input.
[ Charles Kerr ]
* Fix NMClient leak, take battery capacity into account when
  determining the last time a discharging battery was full.
[ Ken VanDine ]
* Don't start the transfer from the importer, the hub now handles that
  when dispatching the transfer.
[ William Hua ]
* Replace page stack with sheet in display languages. (LP: #1222728)
[ Adolfo Jayme Barrientos ]
* Trivial typo fix: Conrifm → Confirm.
[ Ubuntu daily release ]
* Automatic snapshot from revision 341

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
304. By William Hua

Use GSettings instead of QSettings.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
305. By William Hua

Fix incorrect key name.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
William Hua (attente) wrote :
306. By William Hua

Don't watch for click, watch for checkEntry changes.

307. By William Hua

Rename keyboard plugins to keyboard layouts.

308. By William Hua

Debugging output.

309. By William Hua

Remove section role, replace with subset and superset roles.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
310. By William Hua

Merge trunk.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
311. By William Hua

Reset checkStatus binding.

312. By William Hua

Disable debug output.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
313. By William Hua

Implement spell checking front end.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
314. By William Hua

Disallow empty subsets.

315. By William Hua

Merge trunk.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
316. By William Hua

Add dummy icons.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
317. By William Hua

subset-model: support custom roles.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
318. By William Hua

[ Sebastien Bacher ]
* timedate: use the new itemselector widget.
* security: use the new ItemSelector widget.
* [storage] Add a C++ backend for reading the Click package metadata
  and turning it into a proper table model, allowing the QML side to
  be made far cleaner.
[ Iain Lane ]
* Update pot.
* Add the ability to hide deferred/unfinished panels or elements. Pass
  USS_SHOW_ALL_UI=1 to re-enable them.
* Hide the deferred brightness panel.
* Hide "messages on the welcome screen" toggle which is deferred.
* Flight mode is deferred. Hide it.
* Don't do anything when clicking on uncategorised items which have no
  pageComponent. They should handle this themselves in their entry
  component.
* [storage] Add a C++ backend for reading the Click package metadata
  and turning it into a proper table model, allowing the QML side to
  be made far cleaner.
[ Guenter Schwann ]
* Use start() to actually start the content picking transfer.
[ Ubuntu daily release ]
* Automatic snapshot from revision 358

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
319. By William Hua

Disable spell checking.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
320. By William Hua

Revert deletion of Spell Checking item.

321. By William Hua

Conditionally disable non-working components.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks for the work, that looks mostly good, some small review comments:

* could you version the ubuntu-keyboard-data depends to one adding the schemas?

* KeyboardLayoutItem

would it make sense to use a UbuntuShape widget rather for a custom Rectangle?

* > text: i18n.tr("Predictive text")

The title doesn't seem to match the spec (https://wiki.ubuntu.com/LanguageAndText#Phone), where did you get it?

* > text: i18n.tr("Key press feedback")

same

(I guess there has been some design changes there, if that's the case could you point to the update version/ask mpt to update the wiki?)

* Could you perhaps do a summary of the status of the osk side/what options are working/going to be supported this cycle (seems that most are going to be for next cycle which is ok)

If somebody else wants to give another look to the changes that would be welcome (especially the backend, there is quite some code there), otherwise I think we should just get that in and deal with issues (if there are some) in further updates.

review: Needs Fixing
Revision history for this message
William Hua (attente) wrote :

Thanks for the review, Seb. About the UbuntuShape vs Rectangle, UbuntuShape adds some highlights that make it resemble the checkbox, so I think we should stick with the Rectangle in this case.

What I know so far is that Spell Checking is definitely not in this cycle, and we are waiting for another MP to ubuntu-keyboard that switches to using the GSettings schema there.

322. By William Hua

Use Theme for colours.

323. By William Hua

Merge trunk.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
William Hua (attente) wrote :

I haven't tested this branch, and it's not yet reviewed, but this is the MP we're depending on: https://code.launchpad.net/~schwann/ubuntu-keyboard/keyboard-gsettings/+merge/187722.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks for the updates, the ubuntu-keyboard landed in saucy today so we can get your changes in as well!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2013-09-27 11:09:46 +0000
3+++ debian/control 2013-09-27 21:32:49 +0000
4@@ -11,6 +11,7 @@
5 libnm-glib-dev,
6 libofono-qt-dev,
7 libqmenumodel-dev,
8+ libqt5xmlpatterns5-dev,
9 libtimezonemap1-dev (>= 0.4.0.1),
10 libupower-glib-dev,
11 pkg-config,
12@@ -45,6 +46,7 @@
13 whoopsie-preferences (>= 0.9),
14 libsystemsettings1 (= ${binary:Version}),
15 system-image-dbus (>= 0.9),
16+ ubuntu-keyboard-data,
17 Recommends: ubuntu-mobile-icons,
18 ubuntu-system-settings-online-accounts,
19 Conflicts: ubuntu-system-settings-example
20
21=== added file 'plugins/language/KeyboardLayoutItem.qml'
22--- plugins/language/KeyboardLayoutItem.qml 1970-01-01 00:00:00 +0000
23+++ plugins/language/KeyboardLayoutItem.qml 2013-09-27 21:32:49 +0000
24@@ -0,0 +1,74 @@
25+/*
26+ * This file is part of system-settings
27+ *
28+ * Copyright (C) 2013 Canonical Ltd.
29+ *
30+ * Contact: William Hua <william.hua@canonical.com>
31+ *
32+ * This program is free software: you can redistribute it and/or modify it
33+ * under the terms of the GNU General Public License version 3, as published
34+ * by the Free Software Foundation.
35+ *
36+ * This program is distributed in the hope that it will be useful, but
37+ * WITHOUT ANY WARRANTY; without even the implied warranties of
38+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
39+ * PURPOSE. See the GNU General Public License for more details.
40+ *
41+ * You should have received a copy of the GNU General Public License along
42+ * with this program. If not, see <http://www.gnu.org/licenses/>.
43+ */
44+
45+import QtQuick 2.0
46+import Ubuntu.Components 0.1
47+import Ubuntu.Components.ListItems 0.1 as ListItem
48+
49+ListItem.Base {
50+ property alias name: name.text
51+ property alias checked: checkBox.checked
52+ property alias shortName: shortName.text
53+
54+ Row {
55+ anchors.top: parent.top
56+ anchors.bottom: parent.bottom
57+ spacing: units.gu(2)
58+
59+ CheckBox {
60+ id: checkBox
61+
62+ anchors.verticalCenter: parent.verticalCenter
63+ }
64+
65+ Row {
66+ anchors.top: parent.top
67+ anchors.bottom: parent.bottom
68+ spacing: units.gu(1)
69+
70+ Rectangle {
71+ width: units.gu(3.0)
72+ height: units.gu(3.0)
73+ radius: units.gu(0.5)
74+
75+ color: Theme.palette.normal.backgroundText
76+
77+ anchors.verticalCenter: parent.verticalCenter
78+
79+ Label {
80+ id: shortName
81+
82+ color: Theme.palette.normal.background
83+ fontSize: "small"
84+
85+ anchors.centerIn: parent
86+ }
87+ }
88+
89+ Label {
90+ id: name
91+
92+ anchors.verticalCenter: parent.verticalCenter
93+ }
94+ }
95+ }
96+
97+ onClicked: checked = !checked
98+}
99
100=== modified file 'plugins/language/KeyboardLayouts.qml'
101--- plugins/language/KeyboardLayouts.qml 2013-07-25 18:50:51 +0000
102+++ plugins/language/KeyboardLayouts.qml 2013-09-27 21:32:49 +0000
103@@ -18,54 +18,42 @@
104 * with this program. If not, see <http://www.gnu.org/licenses/>.
105 */
106
107-import QtQuick 2.0
108 import SystemSettings 1.0
109-import Ubuntu.Components 0.1
110 import Ubuntu.Components.ListItems 0.1 as ListItem
111+import Ubuntu.SystemSettings.LanguagePlugin 1.0
112
113 ItemPage {
114- id: root
115-
116 title: i18n.tr("Keyboard layouts")
117- flickable: scrollWidget
118-
119- Flickable {
120- id: scrollWidget
121+
122+ UbuntuLanguagePlugin {
123+ id: plugin
124+ }
125+
126+ SubsetView {
127+ id: subsetView
128+
129+ clip: true
130+
131 anchors.fill: parent
132- contentHeight: contentItem.childrenRect.height
133- boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
134-
135- Column {
136- anchors.fill: parent
137-
138- ListItem.Standard {
139- text: i18n.tr("Current layouts:")
140- }
141-
142- /* TODO: Get actual installed layouts. */
143-
144- SettingsCheckEntry {
145- textEntry: "English (US)"
146- checkStatus: true
147- }
148-
149- SettingsCheckEntry {
150- textEntry: "French"
151- checkStatus: true
152- }
153-
154- ListItem.Standard {
155- text: i18n.tr("All layouts available:")
156- }
157-
158- /* TODO: Get actual layouts. */
159-
160- SettingsCheckEntry {
161- textEntry: "Afghani"
162- }
163-
164- SettingsCheckEntry {
165- textEntry: "Akan"
166+
167+ subsetLabel: i18n.tr("Current layouts:")
168+ supersetLabel: i18n.tr("All layouts available:")
169+
170+ model: plugin.keyboardLayoutsModel
171+ delegate: KeyboardLayoutItem {
172+ name: model.language
173+ shortName: model.icon
174+ checked: model.checked
175+ enabled: model.enabled
176+
177+ onCheckedChanged: {
178+ var element = model.index < subsetView.model.subset.length ?
179+ subsetView.model.subset[model.index] :
180+ model.index - subsetView.model.subset.length
181+
182+ plugin.keyboardLayoutsModel.setChecked(element, checked, checked ? 0 : subsetView.delay)
183+
184+ checked = Qt.binding(function() { return model.checked })
185 }
186 }
187 }
188
189=== modified file 'plugins/language/PageComponent.qml'
190--- plugins/language/PageComponent.qml 2013-09-20 13:24:41 +0000
191+++ plugins/language/PageComponent.qml 2013-09-27 21:32:49 +0000
192@@ -29,7 +29,6 @@
193 id: root
194
195 title: i18n.tr("Language & Text")
196- flickable: scrollWidget
197
198 UbuntuLanguagePlugin {
199 id: plugin
200@@ -42,10 +41,11 @@
201 }
202
203 Flickable {
204- id: scrollWidget
205 anchors.fill: parent
206 contentHeight: contentItem.childrenRect.height
207- boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
208+ boundsBehavior: contentHeight > root.height ?
209+ Flickable.DragAndOvershootBounds :
210+ Flickable.StopAtBounds
211
212 Column {
213 anchors.fill: parent
214@@ -55,67 +55,108 @@
215 text: i18n.tr("Display language")
216 value: plugin.languages[plugin.currentLanguage]
217 progression: true
218+
219 onClicked: PopupUtils.open(displayLanguage)
220 }
221
222- ListItem.Divider {}
223+ ListItem.Divider {
224+ visible: showAllUI
225+ }
226
227 ListItem.SingleValue {
228+ visible: showAllUI
229+
230 text: i18n.tr("Keyboard layouts")
231- /* TODO: Get number of keyboard layouts */
232- value: "1"
233+ value: plugin.keyboardLayoutsModel.subset.length == 1 ?
234+ plugin.keyboardLayoutsModel.superset[plugin.keyboardLayoutsModel.subset[0]][0] :
235+ plugin.keyboardLayoutsModel.subset.length
236 progression: true
237+
238 onClicked: pageStack.push(Qt.resolvedUrl("KeyboardLayouts.qml"))
239 }
240
241- ListItem.Divider {}
242+ ListItem.Divider {
243+ visible: showAllUI
244+ }
245
246 ListItem.SingleValue {
247+ visible: showAllUI
248+
249 text: i18n.tr("Spell checking")
250- /* TODO: Get spell checking setting */
251- value: "UK English"
252+ value: plugin.spellCheckingModel.subset.length == 1 ?
253+ plugin.spellCheckingModel.superset[plugin.spellCheckingModel.subset[0]][0] :
254+ plugin.spellCheckingModel.subset.length
255 progression: true
256+
257 onClicked: pageStack.push(Qt.resolvedUrl("SpellChecking.qml"))
258 }
259
260 ListItem.Standard {
261- text: i18n.tr("Auto correction")
262- control: Switch {
263- enabled: false /* TODO: enable when there is a backend */
264- }
265- }
266+ visible: showAllUI
267
268- ListItem.Standard {
269 text: i18n.tr("Auto completion")
270- control: Switch {
271- enabled: false /* TODO: enable when there is a backend */
272- }
273- }
274-
275- ListItem.Divider {}
276-
277- ListItem.Standard {
278+
279+ control: Switch {
280+ checked: plugin.autoCompletion
281+
282+ onClicked: plugin.autoCompletion = checked
283+ }
284+ }
285+
286+ ListItem.Standard {
287+ visible: showAllUI
288+
289+ text: i18n.tr("Predictive text")
290+
291+ control: Switch {
292+ checked: plugin.predictiveText
293+
294+ onClicked: plugin.predictiveText = checked
295+ }
296+ }
297+
298+ ListItem.Divider {
299+ visible: showAllUI
300+ }
301+
302+ ListItem.Standard {
303+ visible: showAllUI
304+
305 text: i18n.tr("Auto capitalization")
306+
307 control: Switch {
308- enabled: false /* TODO: enable when there is a backend */
309+ checked: plugin.autoCapitalization
310+
311+ onClicked: plugin.autoCapitalization = checked
312 }
313 }
314
315 ListItem.Caption {
316+ visible: showAllUI
317+
318 text: i18n.tr("Turns on Shift to capitalize the first letter of each sentence.")
319 }
320
321- ListItem.Divider {}
322+ ListItem.Divider {
323+ visible: showAllUI
324+ }
325
326 ListItem.Standard {
327- text: i18n.tr("Auto punctuation")
328+ visible: showAllUI
329+
330+ text: i18n.tr("Key press feedback")
331+
332 control: Switch {
333- enabled: false /* TODO: enable when there is a backend */
334+ checked: plugin.keyPressFeedback
335+
336+ onClicked: plugin.keyPressFeedback = checked
337 }
338 }
339
340 ListItem.Caption {
341- text: i18n.tr("Adds a period, and any missing quotes or brackets, when you tap Space twice.")
342+ visible: showAllUI
343+
344+ text: i18n.tr("Vibrate or emit a sound whenever a key is pressed.")
345 }
346 }
347 }
348
349=== modified file 'plugins/language/SpellChecking.qml'
350--- plugins/language/SpellChecking.qml 2013-08-27 09:03:26 +0000
351+++ plugins/language/SpellChecking.qml 2013-09-27 21:32:49 +0000
352@@ -18,61 +18,41 @@
353 * with this program. If not, see <http://www.gnu.org/licenses/>.
354 */
355
356-import QtQuick 2.0
357 import SystemSettings 1.0
358 import Ubuntu.Components 0.1
359 import Ubuntu.Components.ListItems 0.1 as ListItem
360+import Ubuntu.SystemSettings.LanguagePlugin 1.0
361
362 ItemPage {
363- id: root
364-
365 title: i18n.tr("Spell checking")
366- flickable: scrollWidget
367-
368- Flickable {
369- id: scrollWidget
370- anchors.fill: parent
371- contentHeight: contentItem.childrenRect.height
372- boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
373-
374- Column {
375- anchors.fill: parent
376-
377- ListItem.Standard {
378- text: i18n.tr("Spell checking")
379- control: Switch {
380- enabled: false /* TODO: enable when there is a backend */
381- }
382- }
383-
384- ListItem.Divider {}
385-
386- ListItem.Standard {
387- text: i18n.tr("Current spelling languages:")
388- }
389-
390- /* TODO: Get real spelling language */
391-
392- SettingsCheckEntry {
393- textEntry: "English (US)"
394- checkStatus: true
395- }
396-
397- ListItem.Divider {}
398-
399- ListItem.Standard {
400- text: i18n.tr("All languages available:")
401- }
402-
403- /* TODO: Get real available languages */
404-
405- SettingsCheckEntry {
406- textEntry: "Afar"
407- }
408-
409- SettingsCheckEntry {
410- textEntry: "Afrikaans"
411- }
412+
413+ UbuntuLanguagePlugin {
414+ id: plugin
415+ }
416+
417+ ListItem.Standard {
418+ id: item
419+
420+ text: i18n.tr("Spell checking")
421+
422+ control: Switch {
423+ checked: plugin.spellChecking
424+
425+ onClicked: plugin.spellChecking = checked
426 }
427 }
428+
429+ SubsetView {
430+ clip: true
431+
432+ anchors.top: item.bottom
433+ anchors.left: parent.left
434+ anchors.right: parent.right
435+ anchors.bottom: parent.bottom
436+
437+ subsetLabel: i18n.tr("Current spelling languages:")
438+ supersetLabel: i18n.tr("All languages available:")
439+
440+ model: plugin.spellCheckingModel
441+ }
442 }
443
444=== added file 'plugins/language/SubsetView.qml'
445--- plugins/language/SubsetView.qml 1970-01-01 00:00:00 +0000
446+++ plugins/language/SubsetView.qml 2013-09-27 21:32:49 +0000
447@@ -0,0 +1,90 @@
448+/*
449+ * This file is part of system-settings
450+ *
451+ * Copyright (C) 2013 Canonical Ltd.
452+ *
453+ * Contact: William Hua <william.hua@canonical.com>
454+ *
455+ * This program is free software: you can redistribute it and/or modify it
456+ * under the terms of the GNU General Public License version 3, as published
457+ * by the Free Software Foundation.
458+ *
459+ * This program is distributed in the hope that it will be useful, but
460+ * WITHOUT ANY WARRANTY; without even the implied warranties of
461+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
462+ * PURPOSE. See the GNU General Public License for more details.
463+ *
464+ * You should have received a copy of the GNU General Public License along
465+ * with this program. If not, see <http://www.gnu.org/licenses/>.
466+ */
467+
468+import QtQuick 2.0
469+import SystemSettings 1.0
470+import Ubuntu.Components.ListItems 0.1 as ListItem
471+
472+ListView {
473+ id: root
474+
475+ property int delay: 2000
476+ property int duration: 100
477+
478+ property string subsetLabel
479+ property string supersetLabel
480+
481+ contentHeight: contentItem.childrenRect.height
482+ boundsBehavior: contentHeight > height ?
483+ Flickable.DragAndOvershootBounds :
484+ Flickable.StopAtBounds
485+
486+ section.property: "subset"
487+ section.delegate: ListItem.Standard {
488+ text: section == "true" ? subsetLabel : supersetLabel
489+ }
490+
491+ delegate: SettingsCheckEntry {
492+ textEntry: model.display
493+ checkStatus: model.checked
494+ enabled: model.enabled
495+
496+ onCheckStatusChanged: {
497+ var element = model.index < root.model.subset.length ?
498+ root.model.subset[model.index] :
499+ model.index - root.model.subset.length
500+
501+ root.model.setChecked(element, checkStatus, checkStatus ? 0 : delay)
502+
503+ checkStatus = Qt.binding(function() { return model.checked })
504+ }
505+ }
506+
507+ add: Transition {
508+ NumberAnimation {
509+ property: "opacity"
510+ duration: duration
511+ from: 0
512+ to: 1
513+ }
514+ }
515+
516+ displaced: Transition {
517+ NumberAnimation {
518+ property: "y"
519+ duration: duration
520+ }
521+ }
522+
523+ remove: Transition {
524+ ParallelAnimation {
525+ NumberAnimation {
526+ property: "opacity"
527+ duration: duration
528+ to: 0
529+ }
530+
531+ NumberAnimation {
532+ property: "y"
533+ duration: duration
534+ }
535+ }
536+ }
537+}
538
539=== added file 'plugins/language/keyboard-layout.cpp'
540--- plugins/language/keyboard-layout.cpp 1970-01-01 00:00:00 +0000
541+++ plugins/language/keyboard-layout.cpp 2013-09-27 21:32:49 +0000
542@@ -0,0 +1,88 @@
543+/*
544+ * This file is part of system-settings
545+ *
546+ * Copyright (C) 2013 Canonical Ltd.
547+ *
548+ * Contact: William Hua <william.hua@canonical.com>
549+ *
550+ * This program is free software: you can redistribute it and/or modify it
551+ * under the terms of the GNU General Public License version 3, as published
552+ * by the Free Software Foundation.
553+ *
554+ * This program is distributed in the hope that it will be useful, but
555+ * WITHOUT ANY WARRANTY; without even the implied warranties of
556+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
557+ * PURPOSE. See the GNU General Public License for more details.
558+ *
559+ * You should have received a copy of the GNU General Public License along
560+ * with this program. If not, see <http://www.gnu.org/licenses/>.
561+ */
562+
563+#include "keyboard-layout.h"
564+#include <QtXmlPatterns>
565+
566+KeyboardLayout::KeyboardLayout(const QString &name,
567+ const QString &language,
568+ const QString &displayName,
569+ const QString &shortName,
570+ QObject *parent) :
571+ QObject(parent),
572+ _name(name),
573+ _language(language),
574+ _displayName(displayName),
575+ _shortName(shortName)
576+{
577+}
578+
579+KeyboardLayout::KeyboardLayout(const QFileInfo &fileInfo,
580+ QObject *parent) :
581+ QObject(parent),
582+ _name(fileInfo.completeBaseName())
583+{
584+ QVariant path(fileInfo.canonicalFilePath());
585+
586+ QXmlQuery languageQuery;
587+ languageQuery.bindVariable("path", path);
588+ languageQuery.setQuery("xs:string(doc($path)/keyboard/@language)");
589+
590+ QStringList languageResults;
591+
592+ if (languageQuery.evaluateTo(&languageResults) && !languageResults.isEmpty())
593+ _language = languageResults.first();
594+
595+ QXmlQuery titleQuery;
596+ titleQuery.bindVariable("path", path);
597+ titleQuery.setQuery("xs:string(doc($path)/keyboard/@title)");
598+
599+ QStringList titleResults;
600+
601+ if (titleQuery.evaluateTo(&titleResults) && !titleResults.isEmpty())
602+ _displayName = titleResults.first();
603+
604+ _shortName = _language.left(2);
605+ _shortName[0] = _shortName[0].toUpper();
606+}
607+
608+const QString &
609+KeyboardLayout::name() const
610+{
611+ return _name;
612+}
613+
614+const QString &
615+KeyboardLayout::language() const
616+{
617+ return _language;
618+}
619+
620+const QString &
621+KeyboardLayout::displayName() const
622+{
623+ return _displayName;
624+}
625+
626+const QString &
627+KeyboardLayout::shortName() const
628+{
629+ return _shortName;
630+}
631
632=== added file 'plugins/language/keyboard-layout.h'
633--- plugins/language/keyboard-layout.h 1970-01-01 00:00:00 +0000
634+++ plugins/language/keyboard-layout.h 2013-09-27 21:32:49 +0000
635@@ -0,0 +1,68 @@
636+/*
637+ * This file is part of system-settings
638+ *
639+ * Copyright (C) 2013 Canonical Ltd.
640+ *
641+ * Contact: William Hua <william.hua@canonical.com>
642+ *
643+ * This program is free software: you can redistribute it and/or modify it
644+ * under the terms of the GNU General Public License version 3, as published
645+ * by the Free Software Foundation.
646+ *
647+ * This program is distributed in the hope that it will be useful, but
648+ * WITHOUT ANY WARRANTY; without even the implied warranties of
649+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
650+ * PURPOSE. See the GNU General Public License for more details.
651+ *
652+ * You should have received a copy of the GNU General Public License along
653+ * with this program. If not, see <http://www.gnu.org/licenses/>.
654+ */
655+
656+#ifndef KEYBOARD_LAYOUT_H
657+#define KEYBOARD_LAYOUT_H
658+
659+#include <QtCore>
660+
661+class KeyboardLayout : public QObject
662+{
663+private:
664+
665+ Q_OBJECT
666+
667+ Q_PROPERTY(QString name
668+ READ name
669+ CONSTANT)
670+
671+ Q_PROPERTY(QString language
672+ READ language
673+ CONSTANT)
674+
675+ Q_PROPERTY(QString displayName
676+ READ displayName
677+ CONSTANT)
678+
679+public:
680+
681+ explicit KeyboardLayout(const QString &name = QString(),
682+ const QString &language = QString(),
683+ const QString &displayName = QString(),
684+ const QString &shortName = QString(),
685+ QObject *parent = NULL);
686+
687+ explicit KeyboardLayout(const QFileInfo &fileInfo,
688+ QObject *parent = NULL);
689+
690+ const QString &name() const;
691+ const QString &language() const;
692+ const QString &displayName() const;
693+ const QString &shortName() const;
694+
695+private:
696+
697+ QString _name;
698+ QString _language;
699+ QString _displayName;
700+ QString _shortName;
701+};
702+
703+#endif // KEYBOARD_LAYOUT_H
704
705=== modified file 'plugins/language/language-plugin.cpp'
706--- plugins/language/language-plugin.cpp 2013-09-20 13:24:41 +0000
707+++ plugins/language/language-plugin.cpp 2013-09-27 21:32:49 +0000
708@@ -20,12 +20,29 @@
709
710 #include "language-plugin.h"
711 #include <act/act.h>
712-
713-static QList<QLocale> *locales;
714+#include "keyboard-layout.h"
715+
716+#define UBUNTU_KEYBOARD_SCHEMA_ID "com.canonical.keyboard.maliit"
717+
718+#define KEY_ENABLED_LAYOUTS "enabled-languages"
719+#define KEY_AUTO_CAPITALIZATION "auto-capitalization"
720+#define KEY_AUTO_COMPLETION "auto-completion"
721+#define KEY_PREDICTIVE_TEXT "predictive-text"
722+#define KEY_KEY_PRESS_FEEDBACK "key-press-feedback"
723+
724+#define LAYOUTS_DIR "/usr/share/maliit/plugins/com/ubuntu/languages"
725+
726+static QList<QLocale> *languageLocales;
727 static QHash<QLocale::Language, unsigned int> *languageIndices;
728-static QStringList *localeNames;
729+static QStringList *languageNames;
730 static QStringList *languageCodes;
731
732+static GSettings *maliitSettings;
733+static QList<KeyboardLayout *> *keyboardLayouts;
734+static SubsetModel *keyboardLayoutsModel;
735+
736+static SubsetModel *spellCheckingModel;
737+
738 static bool
739 compareLocales(const QLocale &locale0,
740 const QLocale &locale1)
741@@ -36,63 +53,74 @@
742 return name0 < name1;
743 }
744
745+static bool
746+compareLayouts(const KeyboardLayout *layout0,
747+ const KeyboardLayout *layout1)
748+{
749+ const QString &displayName0(layout0->displayName());
750+ const QString &displayName1(layout1->displayName());
751+ const QString &language0(layout0->language());
752+ const QString &language1(layout1->language());
753+ const QString &name0(layout0->name());
754+ const QString &name1(layout1->name());
755+
756+ return displayName0 < displayName1 || (displayName0 == displayName1 && (language0 < language1 || (language0 == language1 && name0 < name1)));
757+}
758+
759 static QList<QLocale> *
760-getLocales()
761+getLanguageLocales()
762 {
763- if (locales == NULL)
764- {
765- locales = new QList<QLocale>;
766+ if (languageLocales == NULL) {
767+ languageLocales = new QList<QLocale>;
768
769 QSet<QLocale::Language> allLanguages;
770- QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage,
771- QLocale::AnyScript,
772- QLocale::AnyCountry);
773-
774- for (QList<QLocale>::const_iterator i = allLocales.begin(); i != allLocales.end(); ++i)
775- {
776- QLocale::Language language = i->language();
777-
778- if (language != QLocale::AnyLanguage &&
779- !i->nativeLanguageName().trimmed().toCaseFolded().isEmpty() &&
780- !allLanguages.contains(language))
781- {
782- *locales += QLocale(language);
783+ QList<QLocale> allLocales(QLocale::matchingLocales(QLocale::AnyLanguage,
784+ QLocale::AnyScript,
785+ QLocale::AnyCountry));
786+
787+ for (QList<QLocale>::const_iterator i(allLocales.begin()); i != allLocales.end(); ++i) {
788+ QLocale::Language language(i->language());
789+
790+ bool uniqueLanguage(language != QLocale::AnyLanguage &&
791+ !i->nativeLanguageName().trimmed().toCaseFolded().isEmpty() &&
792+ !allLanguages.contains(language));
793+
794+ if (uniqueLanguage) {
795+ *languageLocales += QLocale(language);
796 allLanguages += language;
797 }
798 }
799
800- qSort(locales->begin(), locales->end(), compareLocales);
801+ qSort(languageLocales->begin(), languageLocales->end(), compareLocales);
802 }
803
804- return locales;
805+ return languageLocales;
806 }
807
808 static QHash<QLocale::Language, unsigned int> *
809 getLanguageIndices()
810 {
811- if (languageIndices == NULL)
812- {
813+ if (languageIndices == NULL) {
814 languageIndices = new QHash<QLocale::Language, unsigned int>;
815
816- for (int i = 0; i < getLocales()->length(); i++)
817- (*languageIndices)[(*getLocales())[i].language()] = i;
818+ for (int i(0); i < getLanguageLocales()->length(); i++)
819+ (*languageIndices)[(*getLanguageLocales())[i].language()] = i;
820 }
821
822 return languageIndices;
823 }
824
825 static QStringList *
826-getLocaleNames()
827+getLanguageNames()
828 {
829- if (localeNames == NULL)
830- {
831- localeNames = new QStringList;
832+ if (languageNames == NULL) {
833+ languageNames = new QStringList;
834
835- for (QList<QLocale>::const_iterator i = getLocales()->begin(); i != getLocales()->end(); ++i)
836- *localeNames += i->nativeLanguageName().trimmed();
837+ for (QList<QLocale>::const_iterator i(getLanguageLocales()->begin()); i != getLanguageLocales()->end(); ++i)
838+ *languageNames += i->nativeLanguageName().trimmed();
839 }
840
841- return localeNames;
842+ return languageNames;
843 }
844
845 static QStringList *
846@@ -101,21 +129,132 @@
847 if (languageCodes == NULL) {
848 languageCodes = new QStringList;
849
850- for (QList<QLocale>::const_iterator i(getLocales()->begin()); i != getLocales()->end(); ++i)
851+ for (QList<QLocale>::const_iterator i(getLanguageLocales()->begin()); i != getLanguageLocales()->end(); ++i)
852 *languageCodes += i->name().trimmed();
853 }
854
855 return languageCodes;
856 }
857
858-LanguagePlugin::LanguagePlugin(QObject *parent) : QObject(parent)
859+static GSettings *
860+getMaliitSettings()
861+{
862+ if (maliitSettings == NULL)
863+ maliitSettings = g_settings_new(UBUNTU_KEYBOARD_SCHEMA_ID);
864+
865+ return maliitSettings;
866+}
867+
868+static QList<KeyboardLayout *> *
869+getKeyboardLayouts()
870+{
871+ if (keyboardLayouts == NULL) {
872+ keyboardLayouts = new QList<KeyboardLayout *>;
873+
874+ QDir layoutsDir(LAYOUTS_DIR);
875+
876+ layoutsDir.setFilter(QDir::Files);
877+ layoutsDir.setNameFilters(QStringList("*.xml"));
878+ layoutsDir.setSorting(QDir::Name);
879+
880+ QFileInfoList fileInfoList(layoutsDir.entryInfoList());
881+
882+ for (QFileInfoList::const_iterator i(fileInfoList.begin()); i != fileInfoList.end(); ++i) {
883+ KeyboardLayout *layout(new KeyboardLayout(*i));
884+
885+ if (!layout->language().isEmpty())
886+ *keyboardLayouts += layout;
887+ }
888+
889+ qSort(keyboardLayouts->begin(), keyboardLayouts->end(), compareLayouts);
890+ }
891+
892+ return keyboardLayouts;
893+}
894+
895+static SubsetModel *
896+getKeyboardLayoutsModel()
897+{
898+ if (keyboardLayoutsModel == NULL) {
899+ QVariantList superset;
900+
901+ for (QList<KeyboardLayout *>::const_iterator i(getKeyboardLayouts()->begin()); i != getKeyboardLayouts()->end(); ++i) {
902+ QVariantList element;
903+
904+ if (!(*i)->displayName().isEmpty())
905+ element += (*i)->displayName();
906+ else
907+ element += (*i)->name();
908+
909+ element += (*i)->shortName();
910+ superset += QVariant(element);
911+ }
912+
913+ GVariantIter *iter;
914+ const gchar *language;
915+ QList<int> subset;
916+
917+ g_settings_get(getMaliitSettings(), KEY_ENABLED_LAYOUTS, "as", &iter);
918+
919+ while (g_variant_iter_next(iter, "&s", &language)) {
920+ for (int i(0); i < getKeyboardLayouts()->length(); i++) {
921+ if ((*getKeyboardLayouts())[i]->name() == language) {
922+ subset += i;
923+ break;
924+ }
925+ }
926+ }
927+
928+ g_variant_iter_free(iter);
929+
930+ QStringList customRoles;
931+ customRoles += "language";
932+ customRoles += "icon";
933+
934+ keyboardLayoutsModel = new SubsetModel();
935+ keyboardLayoutsModel->setCustomRoles(customRoles);
936+ keyboardLayoutsModel->setSuperset(superset);
937+ keyboardLayoutsModel->setSubset(subset);
938+ keyboardLayoutsModel->setAllowEmpty(false);
939+ }
940+
941+ return keyboardLayoutsModel;
942+}
943+
944+static SubsetModel *
945+getSpellCheckingModel()
946+{
947+ if (spellCheckingModel == NULL) {
948+ // TODO: populate spell checking model
949+ QVariantList superset;
950+
951+ for (QStringList::const_iterator i(getLanguageNames()->begin()); i != getLanguageNames()->end(); ++i) {
952+ QVariantList element;
953+ element += *i;
954+ superset += QVariant(element);
955+ }
956+
957+ spellCheckingModel = new SubsetModel();
958+ spellCheckingModel->setCustomRoles(QStringList("language"));
959+ spellCheckingModel->setSuperset(superset);
960+ spellCheckingModel->setSubset(QList<int>());
961+ spellCheckingModel->setAllowEmpty(false);
962+ }
963+
964+ return spellCheckingModel;
965+}
966+
967+LanguagePlugin::LanguagePlugin(QObject *parent) :
968+ QObject(parent),
969+ _updateKeyboardLayoutsConnected(false),
970+ _updateSpellCheckingConnected(false)
971 {
972 }
973
974 const QStringList &
975 LanguagePlugin::languages() const
976 {
977- return *getLocaleNames();
978+ return *getLanguageNames();
979 }
980
981 const QStringList &
982@@ -127,9 +266,9 @@
983 int
984 LanguagePlugin::currentLanguage() const
985 {
986- QLocale::Language language = QLocale::system().language();
987- QHash<QLocale::Language, unsigned int> *indices = getLanguageIndices();
988- QHash<QLocale::Language, unsigned int>::const_iterator i = indices->find(language);
989+ QLocale::Language language(QLocale::system().language());
990+ QHash<QLocale::Language, unsigned int> *indices(getLanguageIndices());
991+ QHash<QLocale::Language, unsigned int>::const_iterator i(indices->find(language));
992
993 return i != indices->end() ? *i : -1;
994 }
995@@ -141,14 +280,13 @@
996 {
997 Q_UNUSED(pspec);
998
999- ActUser *user = ACT_USER(object);
1000- gint index = GPOINTER_TO_INT(user_data);
1001+ ActUser *user(ACT_USER(object));
1002+ gint index(GPOINTER_TO_INT(user_data));
1003
1004- if (act_user_is_loaded(user))
1005- {
1006+ if (act_user_is_loaded(user)) {
1007 g_signal_handlers_disconnect_by_data(user, user_data);
1008
1009- act_user_set_language(user, qPrintable((*getLocales())[index].name()));
1010+ act_user_set_language(user, qPrintable((*getLanguageLocales())[index].name()));
1011 }
1012 }
1013
1014@@ -159,23 +297,20 @@
1015 {
1016 Q_UNUSED(pspec);
1017
1018- ActUserManager *manager = ACT_USER_MANAGER(object);
1019+ ActUserManager *manager(ACT_USER_MANAGER(object));
1020
1021 gboolean loaded;
1022 g_object_get(manager, "is-loaded", &loaded, NULL);
1023
1024- if (loaded)
1025- {
1026+ if (loaded) {
1027 g_signal_handlers_disconnect_by_data(manager, user_data);
1028
1029- const char *name = qgetenv("USER").constData();
1030-
1031- if (name != NULL && name[0] != '\0')
1032- {
1033- ActUser *user = act_user_manager_get_user(manager, name);
1034-
1035- if (user != NULL)
1036- {
1037+ const char *name(qPrintable(qgetenv("USER")));
1038+
1039+ if (name != NULL && name[0] != '\0') {
1040+ ActUser *user(act_user_manager_get_user(manager, name));
1041+
1042+ if (user != NULL) {
1043 if (act_user_is_loaded(user))
1044 setLanguageWithUser(G_OBJECT(user), NULL, user_data);
1045 else
1046@@ -188,12 +323,10 @@
1047 void
1048 LanguagePlugin::setCurrentLanguage(int index)
1049 {
1050- if (index >= 0 && index < getLocales()->length())
1051- {
1052- ActUserManager *manager = act_user_manager_get_default();
1053+ if (index >= 0 && index < getLanguageLocales()->length()) {
1054+ ActUserManager *manager(act_user_manager_get_default());
1055
1056- if (manager != NULL)
1057- {
1058+ if (manager != NULL) {
1059 gboolean loaded;
1060 g_object_get(manager, "is-loaded", &loaded, NULL);
1061
1062@@ -201,6 +334,128 @@
1063 setLanguageWithManager(G_OBJECT(manager), NULL, GINT_TO_POINTER(index));
1064 else
1065 g_signal_connect(manager, "notify::is-loaded", G_CALLBACK(setLanguageWithManager), GINT_TO_POINTER(index));
1066+
1067+ Q_EMIT currentLanguageChanged();
1068 }
1069 }
1070 }
1071+
1072+SubsetModel *
1073+LanguagePlugin::keyboardLayoutsModel()
1074+{
1075+ if (!_updateKeyboardLayoutsConnected) {
1076+ connect(getKeyboardLayoutsModel(), SIGNAL(subsetChanged()), SLOT(updateKeyboardLayouts()));
1077+
1078+ _updateKeyboardLayoutsConnected = true;
1079+ }
1080+
1081+ return getKeyboardLayoutsModel();
1082+}
1083+
1084+void
1085+LanguagePlugin::updateKeyboardLayouts()
1086+{
1087+ GVariantBuilder builder;
1088+ GVariant *currentLayouts;
1089+
1090+ g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));
1091+
1092+ for (QList<int>::const_iterator i(keyboardLayoutsModel()->subset().begin()); i != keyboardLayoutsModel()->subset().end(); ++i)
1093+ g_variant_builder_add(&builder, "s", qPrintable((*getKeyboardLayouts())[*i]->name()));
1094+
1095+ currentLayouts = g_variant_ref_sink(g_variant_builder_end(&builder));
1096+ g_settings_set_value(getMaliitSettings(), KEY_ENABLED_LAYOUTS, currentLayouts);
1097+ g_variant_unref(currentLayouts);
1098+}
1099+
1100+bool
1101+LanguagePlugin::spellChecking() const
1102+{
1103+ // TODO: get spell checking setting
1104+ return true;
1105+}
1106+
1107+void
1108+LanguagePlugin::setSpellChecking(bool value)
1109+{
1110+ // TODO: set spell checking setting
1111+ Q_UNUSED(value);
1112+}
1113+
1114+SubsetModel *
1115+LanguagePlugin::spellCheckingModel()
1116+{
1117+ if (!_updateSpellCheckingConnected) {
1118+ connect(getSpellCheckingModel(), SIGNAL(subsetChanged()), SLOT(updateSpellChecking()));
1119+
1120+ _updateSpellCheckingConnected = true;
1121+ }
1122+
1123+ return getSpellCheckingModel();
1124+}
1125+
1126+void
1127+LanguagePlugin::updateSpellChecking()
1128+{
1129+ // TODO: update spell checking
1130+}
1131+
1132+bool
1133+LanguagePlugin::autoCapitalization() const
1134+{
1135+ return g_settings_get_boolean(getMaliitSettings(), KEY_AUTO_CAPITALIZATION);
1136+}
1137+
1138+void
1139+LanguagePlugin::setAutoCapitalization(bool value)
1140+{
1141+ if (value != autoCapitalization()) {
1142+ g_settings_set_boolean(getMaliitSettings(), KEY_AUTO_CAPITALIZATION, value);
1143+ Q_EMIT autoCapitalizationChanged();
1144+ }
1145+}
1146+
1147+bool
1148+LanguagePlugin::autoCompletion() const
1149+{
1150+ return g_settings_get_boolean(getMaliitSettings(), KEY_AUTO_COMPLETION);
1151+}
1152+
1153+void
1154+LanguagePlugin::setAutoCompletion(bool value)
1155+{
1156+ if (value != autoCompletion()) {
1157+ g_settings_set_boolean(getMaliitSettings(), KEY_AUTO_COMPLETION, value);
1158+ Q_EMIT autoCompletionChanged();
1159+ }
1160+}
1161+
1162+bool
1163+LanguagePlugin::predictiveText() const
1164+{
1165+ return g_settings_get_boolean(getMaliitSettings(), KEY_PREDICTIVE_TEXT);
1166+}
1167+
1168+void
1169+LanguagePlugin::setPredictiveText(bool value)
1170+{
1171+ if (value != predictiveText()) {
1172+ g_settings_set_boolean(getMaliitSettings(), KEY_PREDICTIVE_TEXT, value);
1173+ Q_EMIT predictiveTextChanged();
1174+ }
1175+}
1176+
1177+bool
1178+LanguagePlugin::keyPressFeedback() const
1179+{
1180+ return g_settings_get_boolean(getMaliitSettings(), KEY_KEY_PRESS_FEEDBACK);
1181+}
1182+
1183+void
1184+LanguagePlugin::setKeyPressFeedback(bool value)
1185+{
1186+ if (value != keyPressFeedback()) {
1187+ g_settings_set_boolean(getMaliitSettings(), KEY_KEY_PRESS_FEEDBACK, value);
1188+ Q_EMIT keyPressFeedbackChanged();
1189+ }
1190+}
1191
1192=== modified file 'plugins/language/language-plugin.h'
1193--- plugins/language/language-plugin.h 2013-09-20 13:24:41 +0000
1194+++ plugins/language/language-plugin.h 2013-09-27 21:32:49 +0000
1195@@ -22,6 +22,7 @@
1196 #define LANGUAGE_PLUGIN_H
1197
1198 #include <QtCore>
1199+#include "subset-model.h"
1200
1201 class LanguagePlugin : public QObject
1202 {
1203@@ -39,7 +40,41 @@
1204
1205 Q_PROPERTY(int currentLanguage
1206 READ currentLanguage
1207- WRITE setCurrentLanguage)
1208+ WRITE setCurrentLanguage
1209+ NOTIFY currentLanguageChanged)
1210+
1211+ Q_PROPERTY(SubsetModel *keyboardLayoutsModel
1212+ READ keyboardLayoutsModel
1213+ CONSTANT)
1214+
1215+ Q_PROPERTY(bool spellChecking
1216+ READ spellChecking
1217+ WRITE setSpellChecking
1218+ NOTIFY spellCheckingChanged)
1219+
1220+ Q_PROPERTY(SubsetModel *spellCheckingModel
1221+ READ spellCheckingModel
1222+ CONSTANT)
1223+
1224+ Q_PROPERTY(bool autoCapitalization
1225+ READ autoCapitalization
1226+ WRITE setAutoCapitalization
1227+ NOTIFY autoCapitalizationChanged)
1228+
1229+ Q_PROPERTY(bool autoCompletion
1230+ READ autoCompletion
1231+ WRITE setAutoCompletion
1232+ NOTIFY autoCompletionChanged)
1233+
1234+ Q_PROPERTY(bool predictiveText
1235+ READ predictiveText
1236+ WRITE setPredictiveText
1237+ NOTIFY predictiveTextChanged)
1238+
1239+ Q_PROPERTY(bool keyPressFeedback
1240+ READ keyPressFeedback
1241+ WRITE setKeyPressFeedback
1242+ NOTIFY keyPressFeedbackChanged)
1243
1244 public:
1245
1246@@ -51,6 +86,38 @@
1247
1248 int currentLanguage() const;
1249 void setCurrentLanguage(int index);
1250+ Q_SIGNAL void currentLanguageChanged() const;
1251+
1252+ SubsetModel *keyboardLayoutsModel();
1253+ Q_SLOT void updateKeyboardLayouts();
1254+
1255+ bool spellChecking() const;
1256+ void setSpellChecking(bool value);
1257+ Q_SIGNAL void spellCheckingChanged() const;
1258+
1259+ SubsetModel *spellCheckingModel();
1260+ Q_SLOT void updateSpellChecking();
1261+
1262+ bool autoCapitalization() const;
1263+ void setAutoCapitalization(bool value);
1264+ Q_SIGNAL void autoCapitalizationChanged() const;
1265+
1266+ bool autoCompletion() const;
1267+ void setAutoCompletion(bool value);
1268+ Q_SIGNAL void autoCompletionChanged() const;
1269+
1270+ bool predictiveText() const;
1271+ void setPredictiveText(bool value);
1272+ Q_SIGNAL void predictiveTextChanged() const;
1273+
1274+ bool keyPressFeedback() const;
1275+ void setKeyPressFeedback(bool value);
1276+ Q_SIGNAL void keyPressFeedbackChanged() const;
1277+
1278+private:
1279+
1280+ bool _updateKeyboardLayoutsConnected;
1281+ bool _updateSpellCheckingConnected;
1282 };
1283
1284 #endif // LANGUAGE_PLUGIN_H
1285
1286=== modified file 'plugins/language/language.pro'
1287--- plugins/language/language.pro 2013-08-02 12:08:52 +0000
1288+++ plugins/language/language.pro 2013-09-27 21:32:49 +0000
1289@@ -4,11 +4,12 @@
1290 TEMPLATE = lib
1291 TARGET = language
1292
1293-QML_SOURCES = DisplayLanguage.qml \
1294- KeyboardLayouts.qml \
1295- PageComponent.qml \
1296- SpellChecking.qml
1297-
1298+QML_SOURCES = DisplayLanguage.qml \
1299+ KeyboardLayoutItem.qml \
1300+ KeyboardLayouts.qml \
1301+ PageComponent.qml \
1302+ SpellChecking.qml \
1303+ SubsetView.qml
1304 OTHER_FILES += $${QML_SOURCES}
1305
1306 settings.files = $${TARGET}.settings
1307@@ -25,7 +26,7 @@
1308
1309 # C++ bits
1310 TARGET = UbuntuLanguagePlugin
1311-QT += qml quick dbus
1312+QT += qml quick dbus xmlpatterns
1313 CONFIG += qt link_pkgconfig plugin no_keywords
1314
1315 #comment in the following line to enable traces
1316@@ -38,8 +39,8 @@
1317 PKGCONFIG += accountsservice glib-2.0
1318
1319 # Input
1320-HEADERS += language-plugin.h plugin.h
1321-SOURCES += language-plugin.cpp plugin.cpp
1322+HEADERS += keyboard-layout.h language-plugin.h plugin.h subset-model.h
1323+SOURCES += keyboard-layout.cpp language-plugin.cpp plugin.cpp subset-model.cpp
1324
1325 # Install path for the plugin
1326 installPath = $${PLUGIN_PRIVATE_MODULE_DIR}/$$replace(uri, \\., /)
1327
1328=== modified file 'plugins/language/plugin.cpp'
1329--- plugins/language/plugin.cpp 2013-07-16 14:40:55 +0000
1330+++ plugins/language/plugin.cpp 2013-09-27 21:32:49 +0000
1331@@ -20,14 +20,15 @@
1332 */
1333
1334 #include <QtQml>
1335-#include <QtQml/QQmlContext>
1336 #include "plugin.h"
1337+#include "subset-model.h"
1338 #include "language-plugin.h"
1339
1340 void BackendPlugin::registerTypes(const char *uri)
1341 {
1342 Q_ASSERT(uri == QLatin1String("Ubuntu.SystemSettings.LanguagePlugin"));
1343
1344+ qmlRegisterType<SubsetModel>(uri, 1, 0, "SubsetModel");
1345 qmlRegisterType<LanguagePlugin>(uri, 1, 0, "UbuntuLanguagePlugin");
1346 }
1347
1348
1349=== added file 'plugins/language/subset-model.cpp'
1350--- plugins/language/subset-model.cpp 1970-01-01 00:00:00 +0000
1351+++ plugins/language/subset-model.cpp 2013-09-27 21:32:49 +0000
1352@@ -0,0 +1,403 @@
1353+/*
1354+ * This file is part of system-settings
1355+ *
1356+ * Copyright (C) 2013 Canonical Ltd.
1357+ *
1358+ * Contact: William Hua <william.hua@canonical.com>
1359+ *
1360+ * This program is free software: you can redistribute it and/or modify it
1361+ * under the terms of the GNU General Public License version 3, as published
1362+ * by the Free Software Foundation.
1363+ *
1364+ * This program is distributed in the hope that it will be useful, but
1365+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1366+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1367+ * PURPOSE. See the GNU General Public License for more details.
1368+ *
1369+ * You should have received a copy of the GNU General Public License along
1370+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1371+ */
1372+
1373+#include "subset-model.h"
1374+
1375+#define CHECKED_ROLE (Qt::CheckStateRole)
1376+#define ENABLED_ROLE (Qt::UserRole + 0)
1377+#define SUBSET_ROLE (Qt::UserRole + 1)
1378+#define SUPERSET_ROLE (Qt::UserRole + 2)
1379+#define DISPLAY_ROLE (Qt::UserRole + 3)
1380+#define CUSTOM_ROLE (Qt::UserRole + 4)
1381+
1382+bool
1383+changeLessThan(const SubsetModel::Change *change0,
1384+ const SubsetModel::Change *change1)
1385+{
1386+ return change0->finish < change1->finish;
1387+}
1388+
1389+SubsetModel::SubsetModel(QObject *parent) :
1390+ QAbstractListModel(parent),
1391+ _allowEmpty(true),
1392+ _checked(0),
1393+ _ignore(QDateTime::currentMSecsSinceEpoch())
1394+{
1395+}
1396+
1397+const QStringList &
1398+SubsetModel::customRoles() const
1399+{
1400+ return _customRoles;
1401+}
1402+
1403+void
1404+SubsetModel::setCustomRoles(const QStringList &customRoles)
1405+{
1406+ if (customRoles != _customRoles) {
1407+ _customRoles = customRoles;
1408+
1409+ Q_EMIT customRolesChanged();
1410+ }
1411+}
1412+
1413+const QVariantList &
1414+SubsetModel::superset() const
1415+{
1416+ return _superset;
1417+}
1418+
1419+void
1420+SubsetModel::setSuperset(const QVariantList &superset)
1421+{
1422+ if (superset != _superset) {
1423+ beginResetModel();
1424+
1425+ for (QList<State *>::iterator i(_state.begin()); i != _state.end(); ++i)
1426+ delete *i;
1427+
1428+ _ignore = QDateTime::currentMSecsSinceEpoch();
1429+ _superset = superset;
1430+ _subset.clear();
1431+ _state.clear();
1432+ _checked = 0;
1433+
1434+ for (int i(0); i < _superset.length(); i++) {
1435+ State *state(new State);
1436+ state->checked = false;
1437+ state->check = _ignore;
1438+ state->uncheck = _ignore;
1439+
1440+ _state += state;
1441+ }
1442+
1443+ if (!_allowEmpty && !_superset.isEmpty()) {
1444+ _subset += 0;
1445+ _state[0]->checked = true;
1446+ _checked = 1;
1447+ }
1448+
1449+ endResetModel();
1450+
1451+ Q_EMIT subsetChanged();
1452+ Q_EMIT supersetChanged();
1453+ }
1454+}
1455+
1456+const QList<int> &
1457+SubsetModel::subset() const
1458+{
1459+ return _subset;
1460+}
1461+
1462+void
1463+SubsetModel::setSubset(const QList<int> &subset)
1464+{
1465+ if (subset != _subset) {
1466+ beginResetModel();
1467+
1468+ _ignore = QDateTime::currentMSecsSinceEpoch();
1469+ _subset.clear();
1470+ _checked = 0;
1471+
1472+ for (QList<State *>::iterator i(_state.begin()); i != _state.end(); ++i) {
1473+ (*i)->checked = false;
1474+ (*i)->check = _ignore;
1475+ (*i)->uncheck = _ignore;
1476+ }
1477+
1478+ for (QList<int>::const_iterator i(subset.begin()); i != subset.end(); ++i) {
1479+ if (0 <= *i && *i < _superset.length()) {
1480+ _subset += *i;
1481+
1482+ if (!_state[*i]->checked) {
1483+ _state[*i]->checked = true;
1484+ _checked++;
1485+ }
1486+ }
1487+ }
1488+
1489+ if (!_allowEmpty && _checked == 0 && !_superset.isEmpty()) {
1490+ _subset += 0;
1491+ _state[0]->checked = true;
1492+ _checked = 1;
1493+ }
1494+
1495+ endResetModel();
1496+
1497+ Q_EMIT subsetChanged();
1498+ }
1499+}
1500+
1501+bool
1502+SubsetModel::allowEmpty() const
1503+{
1504+ return _allowEmpty;
1505+}
1506+
1507+void
1508+SubsetModel::setAllowEmpty(bool allowEmpty)
1509+{
1510+ if (allowEmpty != _allowEmpty) {
1511+ _allowEmpty = allowEmpty;
1512+
1513+ if (!_allowEmpty && _checked == 0) {
1514+ _subset += 0;
1515+ _state[0]->checked = true;
1516+ _checked = 1;
1517+ }
1518+
1519+ if (_checked == 1) {
1520+ int single(-1);
1521+
1522+ for (int i(0); i < _state.length(); i++) {
1523+ if (_state[i]->checked) {
1524+ single = i;
1525+ break;
1526+ }
1527+ }
1528+
1529+ for (int i(0); i < _subset.length(); i++) {
1530+ if (_subset[i] == single) {
1531+ QModelIndex row(index(i, 0));
1532+ Q_EMIT dataChanged(row, row, QVector<int>(1, ENABLED_ROLE));
1533+ }
1534+ }
1535+
1536+ if (single >= 0) {
1537+ QModelIndex row(index(_subset.length() + single, 0));
1538+ Q_EMIT dataChanged(row, row, QVector<int>(1, ENABLED_ROLE));
1539+ }
1540+ }
1541+
1542+ Q_EMIT allowEmptyChanged();
1543+ }
1544+}
1545+
1546+bool
1547+SubsetModel::checked(int element)
1548+{
1549+ return _state[element]->checked;
1550+}
1551+
1552+void
1553+SubsetModel::setChecked(int element,
1554+ bool checked,
1555+ int timeout)
1556+{
1557+ qint64 time(QDateTime::currentMSecsSinceEpoch());
1558+
1559+ if (checked)
1560+ _state[element]->check = time;
1561+ else
1562+ _state[element]->uncheck = time;
1563+
1564+ if (checked != _state[element]->checked) {
1565+ _state[element]->checked = checked;
1566+
1567+ if (checked)
1568+ _checked++;
1569+ else
1570+ _checked--;
1571+
1572+ if (!_allowEmpty && (_checked == 1 || (_checked == 2 && checked))) {
1573+ int single(-1);
1574+
1575+ for (int i(0); i < _state.length(); i++) {
1576+ if (i != element && _state[i]->checked) {
1577+ single = i;
1578+ break;
1579+ }
1580+ }
1581+
1582+ for (int i(0); i < _subset.length(); i++) {
1583+ if (_subset[i] == single) {
1584+ QModelIndex row(index(i, 0));
1585+ Q_EMIT dataChanged(row, row, QVector<int>(1, ENABLED_ROLE));
1586+ }
1587+ }
1588+
1589+ if (single >= 0) {
1590+ QModelIndex row(index(_subset.length() + single, 0));
1591+ Q_EMIT dataChanged(row, row, QVector<int>(1, ENABLED_ROLE));
1592+ }
1593+ }
1594+
1595+ for (int i(0); i < _subset.length(); i++) {
1596+ if (_subset[i] == element) {
1597+ QModelIndex row(index(i, 0));
1598+ Q_EMIT dataChanged(row, row, QVector<int>(1, CHECKED_ROLE));
1599+ }
1600+ }
1601+
1602+ QModelIndex row(index(_subset.length() + element, 0));
1603+ Q_EMIT dataChanged(row, row, QVector<int>(1, CHECKED_ROLE));
1604+
1605+ Change *change(new Change);
1606+ change->element = element;
1607+ change->checked = checked;
1608+ change->start = time;
1609+ change->finish = time + timeout;
1610+
1611+ _change.insert(qUpperBound(_change.begin(), _change.end(), change, changeLessThan), change);
1612+
1613+ QTimer::singleShot(timeout, this, SLOT(timerExpired()));
1614+ }
1615+}
1616+
1617+QHash<int, QByteArray>
1618+SubsetModel::roleNames() const
1619+{
1620+ QHash<int, QByteArray> roleNames;
1621+
1622+ roleNames.insert(CHECKED_ROLE, "checked");
1623+ roleNames.insert(ENABLED_ROLE, "enabled");
1624+ roleNames.insert(SUBSET_ROLE, "subset");
1625+ roleNames.insert(SUPERSET_ROLE, "superset");
1626+ roleNames.insert(DISPLAY_ROLE, "display");
1627+
1628+ for (int i = 0; i < _customRoles.length(); i++)
1629+ roleNames.insert(CUSTOM_ROLE + i, _customRoles[i].toUtf8());
1630+
1631+ return roleNames;
1632+}
1633+
1634+int
1635+SubsetModel::rowCount(const QModelIndex &parent) const
1636+{
1637+ Q_UNUSED(parent);
1638+
1639+ return _subset.length() + _superset.length();
1640+}
1641+
1642+Qt::ItemFlags
1643+SubsetModel::flags(const QModelIndex &index) const
1644+{
1645+ Q_UNUSED(index);
1646+
1647+ return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
1648+}
1649+
1650+QVariant
1651+SubsetModel::data(const QModelIndex &index,
1652+ int role) const
1653+{
1654+ switch (role) {
1655+ case CHECKED_ROLE:
1656+ return _state[elementAtIndex(index)]->checked ? Qt::Checked : Qt::Unchecked;
1657+
1658+ case ENABLED_ROLE:
1659+ return _allowEmpty || _checked != 1 || !_state[elementAtIndex(index)]->checked;
1660+
1661+ case SUBSET_ROLE:
1662+ case SUPERSET_ROLE:
1663+ return (role == SUBSET_ROLE) == (index.row() < _subset.length());
1664+
1665+ case DISPLAY_ROLE:
1666+ role = CUSTOM_ROLE;
1667+ break;
1668+ }
1669+
1670+ int column = role - CUSTOM_ROLE;
1671+ int element = elementAtIndex(index);
1672+ QVariantList list = _superset[element].toList();
1673+
1674+ if (0 <= column && column < list.length())
1675+ return list[column];
1676+
1677+ return QVariant();
1678+}
1679+
1680+bool
1681+SubsetModel::setData(const QModelIndex &index,
1682+ const QVariant &value,
1683+ int role)
1684+{
1685+ switch (role) {
1686+ case CHECKED_ROLE:
1687+ switch (static_cast<QMetaType::Type>(value.type())) {
1688+ case QMetaType::Bool:
1689+ case QMetaType::QChar:
1690+ case QMetaType::Int:
1691+ case QMetaType::UInt:
1692+ case QMetaType::LongLong:
1693+ case QMetaType::ULongLong:
1694+ setChecked(elementAtIndex(index), value.toBool(), 0);
1695+
1696+ return true;
1697+
1698+ default:
1699+ break;
1700+ }
1701+
1702+ break;
1703+ }
1704+
1705+ return false;
1706+}
1707+
1708+void
1709+SubsetModel::timerExpired()
1710+{
1711+ Change *change(_change.first());
1712+
1713+ _change.removeFirst();
1714+
1715+ if (change->start > _ignore) {
1716+ if (change->checked) {
1717+ if (change->start > _state[change->element]->uncheck) {
1718+ if (!_subset.contains(change->element)) {
1719+ beginInsertRows(QModelIndex(), _subset.length(), _subset.length());
1720+ _subset += change->element;
1721+ endInsertRows();
1722+
1723+ Q_EMIT subsetChanged();
1724+ }
1725+ }
1726+ }
1727+ else {
1728+ if (change->start > _state[change->element]->check) {
1729+ for (int i(0); i < _subset.length(); i++) {
1730+ while (i < _subset.length() && _subset[i] == change->element) {
1731+ beginRemoveRows(QModelIndex(), i, i);
1732+ _subset.removeAt(i);
1733+ endRemoveRows();
1734+ }
1735+ }
1736+
1737+ Q_EMIT subsetChanged();
1738+ }
1739+ }
1740+ }
1741+
1742+ delete change;
1743+}
1744+
1745+int
1746+SubsetModel::elementAtRow(int row) const
1747+{
1748+ return row < _subset.length() ? _subset[row] : row - _subset.length();
1749+}
1750+
1751+int
1752+SubsetModel::elementAtIndex(const QModelIndex &index) const
1753+{
1754+ return elementAtRow(index.row());
1755+}
1756
1757=== added file 'plugins/language/subset-model.h'
1758--- plugins/language/subset-model.h 1970-01-01 00:00:00 +0000
1759+++ plugins/language/subset-model.h 2013-09-27 21:32:49 +0000
1760@@ -0,0 +1,123 @@
1761+/*
1762+ * This file is part of system-settings
1763+ *
1764+ * Copyright (C) 2013 Canonical Ltd.
1765+ *
1766+ * Contact: William Hua <william.hua@canonical.com>
1767+ *
1768+ * This program is free software: you can redistribute it and/or modify it
1769+ * under the terms of the GNU General Public License version 3, as published
1770+ * by the Free Software Foundation.
1771+ *
1772+ * This program is distributed in the hope that it will be useful, but
1773+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1774+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1775+ * PURPOSE. See the GNU General Public License for more details.
1776+ *
1777+ * You should have received a copy of the GNU General Public License along
1778+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1779+ */
1780+
1781+#ifndef SUBSET_MODEL_H
1782+#define SUBSET_MODEL_H
1783+
1784+#include <QtCore>
1785+
1786+class SubsetModel : public QAbstractListModel
1787+{
1788+protected:
1789+
1790+ Q_OBJECT
1791+
1792+public:
1793+
1794+ Q_PROPERTY(QStringList customRoles
1795+ READ customRoles
1796+ WRITE setCustomRoles
1797+ NOTIFY customRolesChanged)
1798+
1799+ Q_PROPERTY(QVariantList superset
1800+ READ superset
1801+ WRITE setSuperset
1802+ NOTIFY supersetChanged)
1803+
1804+ Q_PROPERTY(QList<int> subset
1805+ READ subset
1806+ WRITE setSubset
1807+ NOTIFY subsetChanged)
1808+
1809+ Q_PROPERTY(bool allowEmpty
1810+ READ allowEmpty
1811+ WRITE setAllowEmpty
1812+ NOTIFY allowEmptyChanged)
1813+
1814+ explicit SubsetModel(QObject *parent = NULL);
1815+
1816+ virtual const QStringList &customRoles() const;
1817+ virtual void setCustomRoles(const QStringList &customRoles);
1818+ Q_SIGNAL virtual void customRolesChanged() const;
1819+
1820+ virtual const QVariantList &superset() const;
1821+ virtual void setSuperset(const QVariantList &superset);
1822+ Q_SIGNAL virtual void supersetChanged() const;
1823+
1824+ virtual const QList<int> &subset() const;
1825+ virtual void setSubset(const QList<int> &subset);
1826+ Q_SIGNAL virtual void subsetChanged() const;
1827+
1828+ virtual bool allowEmpty() const;
1829+ virtual void setAllowEmpty(bool allowEmpty);
1830+ Q_SIGNAL virtual void allowEmptyChanged() const;
1831+
1832+ Q_INVOKABLE virtual bool checked(int element);
1833+ Q_INVOKABLE virtual void setChecked(int element,
1834+ bool checked,
1835+ int timeout);
1836+
1837+ virtual QHash<int, QByteArray> roleNames() const;
1838+
1839+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
1840+
1841+ virtual Qt::ItemFlags flags(const QModelIndex &index) const;
1842+ virtual QVariant data(const QModelIndex &index,
1843+ int role = Qt::DisplayRole) const;
1844+ virtual bool setData(const QModelIndex &index,
1845+ const QVariant &value,
1846+ int role = Qt::EditRole);
1847+
1848+protected:
1849+
1850+ Q_SLOT virtual void timerExpired();
1851+
1852+ virtual int elementAtRow(int row) const;
1853+ virtual int elementAtIndex(const QModelIndex &index) const;
1854+
1855+ struct State {
1856+ bool checked;
1857+ qint64 check;
1858+ qint64 uncheck;
1859+ };
1860+
1861+ struct Change {
1862+ int element;
1863+ bool checked;
1864+ qint64 start;
1865+ qint64 finish;
1866+ };
1867+
1868+ QStringList _customRoles;
1869+ QVariantList _superset;
1870+ QList<int> _subset;
1871+ bool _allowEmpty;
1872+
1873+ QList<State *> _state;
1874+ QList<Change *> _change;
1875+
1876+ int _checked;
1877+ qint64 _ignore;
1878+
1879+ friend bool changeLessThan(const Change *change0,
1880+ const Change *change1);
1881+};
1882+
1883+#endif // SUBSET_MODEL_H

Subscribers

People subscribed via source and target branches