Merge lp:~attente/ubuntu-system-settings/maliit-settings into lp:ubuntu-system-settings
- maliit-settings
- Merge into trunk
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 |
Related bugs: |
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:/
PS Jenkins bot (ps-jenkins) wrote : | # |
- 295. By William Hua
-
Build depend on libqt5xmlpatter
ns5-dev.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:295
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 296. By William Hua
-
Subset model.
- 297. By William Hua
-
Simplify SubsetModel.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:297
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 298. By William Hua
-
Hook up signals and save enabled plugins.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:298
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 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
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:300
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 301. By William Hua
-
Fix opacity issue.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:301
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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_
// do stuff
}
rather than
if (brackets_
{
//do stuff
}
What's the idea behind the SubsetModel stuff?
- 302. By William Hua
-
Fix braces style.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:302
http://
Executed test runs:
FAILURE: http://
Click here to trigger a rebuild:
http://
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:/
2. https:/
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
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:303
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 304. By William Hua
-
Use GSettings instead of QSettings.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:304
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 305. By William Hua
-
Fix incorrect key name.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:305
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
William Hua (attente) wrote : | # |
This MP now depends on https:/
- 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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:309
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 310. By William Hua
-
Merge trunk.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:310
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 311. By William Hua
-
Reset checkStatus binding.
- 312. By William Hua
-
Disable debug output.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:312
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 313. By William Hua
-
Implement spell checking front end.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:313
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 314. By William Hua
-
Disallow empty subsets.
- 315. By William Hua
-
Merge trunk.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:314
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:315
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 316. By William Hua
-
Add dummy icons.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:316
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 317. By William Hua
-
subset-model: support custom roles.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:317
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 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
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:318
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 319. By William Hua
-
Disable spell checking.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:319
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 320. By William Hua
-
Revert deletion of Spell Checking item.
- 321. By William Hua
-
Conditionally disable non-working components.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:321
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Sebastien Bacher (seb128) wrote : | # |
Thanks for the work, that looks mostly good, some small review comments:
* could you version the ubuntu-
* 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:/
* > 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.
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.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:322
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
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:/
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:323
http://
Executed test runs:
SUCCESS: http://
Click here to trigger a rebuild:
http://
Sebastien Bacher (seb128) wrote : | # |
Thanks for the updates, the ubuntu-keyboard landed in saucy today so we can get your changes in as well!
Preview Diff
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 |
FAILED: Continuous integration, rev:294 jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- ci/255/ jenkins. qa.ubuntu. com/job/ ubuntu- system- settings- saucy-amd64- ci/255/ console
http://
Executed test runs:
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ ubuntu- system- settings- ci/255/ rebuild
http://