on xenial help sign in
implement Country page

plus related changes in the LocalePlugin

commite478b3ad9861b3f6df037121ddb78df86b4332a6 authorLukáš Tinkl <lukas.tinkl@canonical.com> dateThu 25 Jun 2015, 16:00 (11 years ago) parent8131d9c
7 files changed+303−99
plugins/Wizard/LocalePlugin.cpp+6−5 plugins/Wizard/LocalePlugin.h+1−1 qml/Wizard/Page.qml+62−36 qml/Wizard/Pages.qml+5−16 qml/Wizard/Pages/10-language.qml+50−40 qml/Wizard/Pages/15-country.qml+178 qml/Wizard/StackButton.qml+1−1
plugins/Wizard/LocalePlugin.cpp+6−5
@@ -35,14 +35,15 @@ QJsonObject LocaleAttached::languages() const
3535 return result;
3636}
3737
38−QJsonObject LocaleAttached::localesForLanguage(const QString &code) const
38+QJsonObject LocaleAttached::countriesForLanguage(const QString &code) const
3939{
4040 QLocale tmp(code);
4141 const QList<QLocale> allLocales = QLocale::matchingLocales(tmp.language(), QLocale::AnyScript, QLocale::AnyCountry);
4242 QJsonObject result;
43− for(const QLocale &loc: allLocales) {
44− //qDebug() << "Matching locale:" << loc.name();
45− result.insert(loc.name(), QStringLiteral("%1 (%2)").arg(QLocale::languageToString(loc.language())).arg(QLocale::countryToString(loc.country())));
43+ Q_FOREACH(const QLocale &loc, allLocales) {
44+ const QString countryCode = loc.name().section('_', 1, 1);
45+ //qDebug() << "Matching country:" << countryCode;
46+ result.insert(countryCode, QLocale::countryToString(loc.country()));
4647 }
4748 return result;
4849}
@@ -52,7 +53,7 @@ QJsonObject LocaleAttached::countries() const
5253 const QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
5354 QJsonObject result;
5455
55− for(const QLocale &loc: allLocales) {
56+ Q_FOREACH(const QLocale &loc, allLocales) {
5657 const QString countryCode = loc.name().section('_', 1, 1);
5758 if (!countryCode.isEmpty() && countryCode.length() == 2) {
5859 result.insert(countryCode, QLocale::countryToString(loc.country()));
plugins/Wizard/LocalePlugin.h+1−1
@@ -30,7 +30,7 @@ protected:
3030
3131public:
3232 Q_INVOKABLE QJsonObject languages() const;
33− Q_INVOKABLE QJsonObject localesForLanguage(const QString &code) const;
33+ Q_INVOKABLE QJsonObject countriesForLanguage(const QString &code) const;
3434 Q_INVOKABLE QJsonObject countries() const;
3535
3636 friend class LocalePlugin;
qml/Wizard/Page.qml+62−36
@@ -21,7 +21,10 @@ Item {
2121 readonly property real buttonMargin: units.gu(3)
2222 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
2323 buttonMargin / 2
24+ readonly property real buttonBarHeight: units.gu(5)
25+
2426 readonly property real topMargin: units.gu(11)
27+ readonly property real bottomMargin: units.gu(3)
2528 readonly property real leftMargin: units.gu(3)
2629 readonly property real rightMargin: units.gu(3)
2730
@@ -43,64 +46,87 @@ Item {
4346 visible: false
4447 anchors.fill: parent
4548
46− Label {
47− id: titleLabel
49+ // title
50+ Rectangle {
51+ id: titleRect
4852 anchors {
4953 top: parent.top
5054 left: parent.left
5155 right: parent.right
52− topMargin: topMargin
53− leftMargin: leftMargin
54− rightMargin: rightMargin
5556 }
56− wrapMode: Text.Wrap
57− text: title
58− color: Theme.palette.normal.baseText
59− fontSize: "x-large"
57+ height: topMargin + bottomMargin
58+ color: "#650954"
59+
60+ Label {
61+ id: titleLabel
62+ anchors {
63+ left: parent.left
64+ right: parent.right
65+ bottom: parent.bottom
66+ bottomMargin: bottomMargin
67+ leftMargin: leftMargin
68+ rightMargin: rightMargin
69+ }
70+ wrapMode: Text.Wrap
71+ text: title
72+ color: "white"
73+ fontSize: "x-large"
74+ }
6075 }
6176
77+ // content
6278 Item {
6379 id: contentHolder
6480 anchors {
65− top: titleLabel.bottom
81+ top: titleRect.bottom
6682 left: parent.left
6783 right: parent.right
68− bottom: backButton.top
69− topMargin: units.gu(4)
84+ bottom: buttonRect.top
7085 leftMargin: leftMargin
7186 rightMargin: rightMargin
72− bottomMargin: buttonMargin
7387 }
7488 }
7589
76− StackButton {
77− id: backButton
78− objectName: "backButton"
79− width: buttonWidth
90+ // button bar
91+ Rectangle {
92+ id: buttonRect
8093 anchors {
81− left: parent.left
8294 bottom: parent.bottom
83− leftMargin: leftMargin
84− bottomMargin: buttonMargin
95+ left: parent.left
96+ right: parent.right
8597 }
86− z: 1
87− text: i18n.ctr("Button: Go back one page in the Wizard", "Back")
88− visible: pageStack.depth > 1 && hasBackButton
89− backArrow: true
98+ height: buttonBarHeight
99+ color: "#f5f5f5"
90100
91− onClicked: customBack ? backClicked() : pageStack.prev()
92− }
101+ StackButton {
102+ id: backButton
103+ objectName: "backButton"
104+ width: buttonWidth
105+ anchors {
106+ left: parent.left
107+ bottom: parent.bottom
108+ leftMargin: leftMargin
109+ verticalCenter: parent.verticalCenter
110+ }
111+ z: 1
112+ text: i18n.ctr("Button: Go back one page in the Wizard", "Back")
113+ visible: pageStack.depth > 1 && hasBackButton
114+ backArrow: true
93115
94− Loader {
95− id: forwardButton
96− objectName: "forwardButton"
97− width: buttonWidth
98− anchors {
99− right: parent.right
100− bottom: parent.bottom
101− rightMargin: buttonMargin
102− bottomMargin: buttonMargin
116+ onClicked: customBack ? backClicked() : pageStack.prev()
117+ }
118+
119+ Loader {
120+ id: forwardButton
121+ objectName: "forwardButton"
122+ width: buttonWidth
123+ anchors {
124+ right: parent.right
125+ bottom: parent.bottom
126+ rightMargin: rightMargin
127+ verticalCenter: parent.verticalCenter
128+ }
129+ z: 1
103130 }
104− z: 1
105131 }
106132}
qml/Wizard/Pages.qml+5−16
@@ -25,15 +25,13 @@ Item {
2525 objectName: "wizardPages"
2626 focus: true
2727
28− // The background wallpaper to use
29− property string background
30−
3128 signal quit()
3229
3330 // These should be set by a security page and we apply the settings when
3431 // the user exits the wizard.
3532 property int passwordMethod: UbuntuSecurityPrivacyPanel.Passcode
3633 property string password: ""
34+ property string language: ""
3735
3836 UbuntuSecurityPrivacyPanel {
3937 id: securityPrivacy
@@ -58,19 +56,10 @@ Item {
5856 anchors.fill: parent
5957 }
6058
61− Image {
62− id: image
63− // Use x/y/height/width instead of anchors so that we don't adjust
64− // the image when the OSK appears.
65− x: 0
66− y: 0
67− height: root.height
68− width: root.width
69− sourceSize.height: height
70− sourceSize.width: width
71− source: root.background
72− fillMode: Image.PreserveAspectCrop
73− visible: status === Image.Ready
59+ Rectangle {
60+ id: background
61+ anchors.fill: root
62+ color: "#fdfdfd"
7463 }
7564
7665 PageList {
qml/Wizard/Pages/10-language.qml+50−40
@@ -26,62 +26,50 @@ LocalComponents.Page {
2626 title: i18n.tr("Language")
2727 forwardButtonSourceComponent: forwardButton
2828
29− property string selectedLanguage: ""
30−
3129 UbuntuLanguagePlugin {
3230 id: plugin
3331 }
3432
3533 Component.onCompleted: {
36− populateModel(); // FIXME pass a list of detected languages here
34+ populateModel(["fr", "de"]); // FIXME pass a list of detected languages here
3735 }
3836
3937 function populateModel(detectedLangs)
4038 {
41− console.log("LanguagePage::populateModel: detected languages:" + detectedLangs);
42− var allLangs = LocalePlugin.languages();
43− if (!!detectedLangs) {
44− addLanguagesToModel(detectedLangs);
45− var remainingLangs = Object.keys(allLangs).filter(function(lang) {
46− return (detectedLangs.indexOf(lang) === -1);
47− });
48− addLanguagesToModel(remainingLangs); // FIXME this assumes an array
49− } else {
50− addLanguagesToModel(allLangs);
51− }
52−
53− busyIndicator.running = false;
54− busyIndicator.visible = false;
55− }
56−
57− function addLanguagesToModel(langs)
58− {
39+ var langs = LocalePlugin.languages();
5940 Object.keys(langs).map(function(code) { // prepare the object
60− return { "code": code, "name": langs[code] };
41+ //console.log("Got language:" + code);
42+ return { "code": code, "language": langs[code] || code,
43+ "dept": detectedLangs.indexOf(code) !== -1 ? i18n.tr("Detected") : i18n.tr("All") };
6144 })
62− .sort(function(a, b) { // sort by language name, not code
63− return a.name.localeCompare(b.name);
45+ .sort(function(a, b) { // group by status, sort by language name
46+ if (a.dept === b.dept) {
47+ return a.language.localeCompare(b.language);
48+ } else if (a.dept === i18n.tr("Detected")) {
49+ return -1
50+ }
51+ return 1
6452 })
65− .forEach(function(language) { // build the model
66− model.append(
67− { "language": language.name,
68− "code": language.code
69− }
70− );
53+ .forEach(function(lang) { // build the model
54+ if (lang.code === "C") {
55+ return;
56+ }
57+ model.append(lang);
7158 });
59+ busyIndicator.running = false;
60+ busyIndicator.visible = false;
7261 }
7362
7463 ActivityIndicator {
7564 id: busyIndicator;
7665
77− anchors.centerIn: parent;
66+ anchors.centerIn: column;
7867 running: true;
7968 }
8069
8170 Column {
8271 id: column
8372 anchors.fill: content
84− spacing: units.gu(1)
8573
8674 ListView {
8775 id: languagesListView;
@@ -89,18 +77,26 @@ LocalComponents.Page {
8977 boundsBehavior: Flickable.StopAtBounds;
9078 clip: true;
9179 currentIndex: -1
80+ snapMode: ListView.SnapToItem
9281
9382 anchors {
9483 left: parent.left;
9584 right: parent.right;
96− topMargin: topMargin;
9785 }
9886
99− height: column.height - column.spacing - topMargin
87+ height: column.height
10088
10189 section {
102− property: "language";
103− criteria: ViewSection.FirstCharacter;
90+ property: "dept";
91+ criteria: ViewSection.FullString;
92+ labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
93+ delegate: Component {
94+ Label {
95+ text: section
96+ fontSize: "large"
97+ color: "black"
98+ }
99+ }
104100 }
105101
106102 model: ListModel {
@@ -113,6 +109,7 @@ LocalComponents.Page {
113109 readonly property bool isCurrent: index === ListView.view.currentIndex
114110
115111 Label {
112+ id: langLabel
116113 text: language;
117114
118115 anchors {
@@ -123,12 +120,25 @@ LocalComponents.Page {
123120
124121 fontSize: "medium"
125122 font.weight: itemDelegate.isCurrent ? Font.Normal : Font.Light
123+ color: "black" // FIXME proper color from the theme
124+ }
125+
126+ Image {
127+ anchors {
128+ right: parent.right;
129+ verticalCenter: parent.verticalCenter;
130+ }
131+ fillMode: Image.PreserveAspectFit
132+ height: langLabel.paintedHeight
133+
134+ source: "image://theme/select"
135+ visible: itemDelegate.isCurrent
126136 }
127137
128138 onClicked: {
129− selectedLanguage = code
139+ root.language = code
130140 ListView.view.currentIndex = index
131− print("Selected language: " + selectedLanguage)
141+ print("Selected language: " + root.language)
132142 print("Current index: " + ListView.view.currentIndex)
133143 }
134144 }
@@ -139,9 +149,9 @@ LocalComponents.Page {
139149 id: forwardButton
140150 LocalComponents.StackButton {
141151 text: i18n.tr("Next")
142− enabled: selectedLanguage !== ""
152+ enabled: root.language !== ""
143153 onClicked: {
144− if (selectedLanguage !== plugin.languageCodes[plugin.currentLanguage]) {
154+ if (root.language !== plugin.languageCodes[plugin.currentLanguage]) {
145155 //plugin.currentLanguage = listview.currentIndex; // setting system language by some magic index? wtf
146156 //System.updateSessionLanguage(selectedLanguage); // TODO
147157 i18n.language = i18n.language; // re-notify of change after above call (for qlocale change)
qml/Wizard/Pages/15-country.qmlnew file+178
@@ -0,0 +1,178 @@
1+/*
2+ * Copyright (C) 2013, 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+import Ubuntu.Components 1.2
19+import Wizard 0.1
20+import ".." as LocalComponents
21+
22+LocalComponents.Page {
23+ objectName: "countryPage"
24+
25+ title: i18n.tr("Country")
26+ forwardButtonSourceComponent: forwardButton
27+
28+ property string selectedLocale: ""
29+ readonly property var preferedCountries: LocalePlugin.countriesForLanguage(root.language)
30+
31+ Component.onCompleted: {
32+ populateModel(preferedCountries, "CH"); // FIXME pass the detected country code here
33+ }
34+
35+ function populateModel(preferedCountries, detectedCountry)
36+ {
37+ console.log("RegionPage::populateModel: detected country:" + detectedCountry);
38+ var index = 0;
39+ var countries = LocalePlugin.countries();
40+ //console.log("All countries:" + countries);
41+ Object.keys(countries).map(function(code) { // prepare the object
42+ //console.log("Got country:" + code);
43+ return { "code": code, "country": countries[code] || code,
44+ "dept": code === detectedCountry ? i18n.tr("Detected") : Object.keys(preferedCountries).indexOf(code) !== -1 ? i18n.tr("Prefered") : i18n.tr("All") };
45+ })
46+ .sort(function(a, b) { // group by status, sort by country name
47+ if (a.dept === b.dept) {
48+ return a.country.localeCompare(b.country);
49+ } else if (a.dept === i18n.tr("Detected")) {
50+ return -1
51+ } else if (a.dept === i18n.tr("Prefered") && b.dept === i18n.tr("All")) {
52+ return -1
53+ }
54+ return 1
55+ })
56+ .forEach(function(country) { // build the model
57+ //console.debug("Adding country:" + country.code);
58+ if (country.code === "C") {
59+ return;
60+ }
61+ model.append(country);
62+ if (country.code === detectedCountry) { // preselect the detected country
63+ selectCountry(country.code, index)
64+ //regionsListView.positionViewAtIndex(index, ListView.Center)
65+ }
66+ index++;
67+ });
68+ busyIndicator.running = false;
69+ busyIndicator.visible = false;
70+ }
71+
72+ function selectCountry(code, index)
73+ {
74+ selectedLocale = root.language + "_" + code
75+ regionsListView.currentIndex = index
76+ }
77+
78+ ActivityIndicator {
79+ id: busyIndicator;
80+
81+ anchors.centerIn: column;
82+ running: true;
83+ }
84+
85+ Column {
86+ id: column
87+ anchors.fill: content
88+
89+ ListView {
90+ id: regionsListView;
91+
92+ boundsBehavior: Flickable.StopAtBounds;
93+ clip: true;
94+ currentIndex: -1
95+ snapMode: ListView.SnapToItem
96+
97+ anchors {
98+ left: parent.left;
99+ right: parent.right;
100+ }
101+
102+ height: column.height
103+
104+ section {
105+ property: "dept";
106+ criteria: ViewSection.FullString;
107+ labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
108+ delegate: Component {
109+ Label {
110+ text: section
111+ fontSize: "large"
112+ color: "black"
113+ }
114+ }
115+ }
116+
117+ model: ListModel {
118+ id: model;
119+ }
120+
121+ delegate: ListItem {
122+ id: itemDelegate;
123+
124+ readonly property bool isCurrent: index === ListView.view.currentIndex
125+
126+ Label {
127+ id: countryLabel
128+ text: country;
129+
130+ anchors {
131+ left: parent.left;
132+ right: parent.right;
133+ verticalCenter: parent.verticalCenter;
134+ }
135+
136+ fontSize: "medium"
137+ font.weight: itemDelegate.isCurrent ? Font.Normal : Font.Light
138+ color: "black" // FIXME proper color from the theme
139+ }
140+
141+ Image {
142+ anchors {
143+ right: parent.right;
144+ verticalCenter: parent.verticalCenter;
145+ }
146+ fillMode: Image.PreserveAspectFit
147+ height: countryLabel.paintedHeight
148+
149+ source: "image://theme/select"
150+ visible: itemDelegate.isCurrent
151+ }
152+
153+ onClicked: {
154+ selectCountry(code, index)
155+ print("Selected locale: " + selectedLocale)
156+ print("Current index: " + ListView.view.currentIndex)
157+ }
158+ }
159+ }
160+ }
161+
162+ Component {
163+ id: forwardButton
164+ LocalComponents.StackButton {
165+ text: i18n.tr("Next")
166+ enabled: selectedLocale !== ""
167+ onClicked: {
168+ // if (selectedLanguage !== plugin.languageCodes[plugin.currentLanguage]) {
169+ // //plugin.currentLanguage = listview.currentIndex; // setting system language by some magic index? wtf
170+ // //System.updateSessionLanguage(selectedLanguage); // TODO
171+ // i18n.language = i18n.language; // re-notify of change after above call (for qlocale change)
172+ // }
173+ // FIXME export the selected locale to the system
174+ pageStack.next()
175+ }
176+ }
177+ }
178+}
qml/Wizard/StackButton.qml+1−1
@@ -32,7 +32,7 @@ AbstractButton {
3232 anchors.verticalCenter: parent.verticalCenter
3333 anchors.left: parent.left
3434 anchors.right: parent.right
35− color: enabled ? Theme.palette.selected.backgroundText : Qt.darker(Theme.palette.selected.backgroundText, 1.5)
35+ color: enabled ? "black" : UbuntuColors.lightGrey // FIXME proper colors
3636 font.weight: Font.DemiBold
3737 text: {
3838 if (backArrow) {