on xenial help sign in
implement Country page
e478b3aLukáš Tinkl
plugins/Wizard/LocalePlugin.cpp+6−5
@@ -35,14 +35,15 @@ QJsonObject LocaleAttached::languages() const
35 return result;
35 return result;
36}
36}
37
37
38−QJsonObject LocaleAttached::localesForLanguage(const QString &code) const
38+QJsonObject LocaleAttached::countriesForLanguage(const QString &code) const
39{
39{
40 QLocale tmp(code);
40 QLocale tmp(code);
41 const QList<QLocale> allLocales = QLocale::matchingLocales(tmp.language(), QLocale::AnyScript, QLocale::AnyCountry);
41 const QList<QLocale> allLocales = QLocale::matchingLocales(tmp.language(), QLocale::AnyScript, QLocale::AnyCountry);
42 QJsonObject result;
42 QJsonObject result;
43− for(const QLocale &loc: allLocales) {
43+ Q_FOREACH(const QLocale &loc, allLocales) {
44+ const QString countryCode = loc.name().section('_', 1, 1);
44− //qDebug() << "Matching locale:" << loc.name();
45+ //qDebug() << "Matching country:" << countryCode;
45− result.insert(loc.name(), QStringLiteral("%1 (%2)").arg(QLocale::languageToString(loc.language())).arg(QLocale::countryToString(loc.country())));
46+ result.insert(countryCode, QLocale::countryToString(loc.country()));
46 }
47 }
47 return result;
48 return result;
48}
49}
@@ -52,7 +53,7 @@ QJsonObject LocaleAttached::countries() const
52 const QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
53 const QList<QLocale> allLocales = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry);
53 QJsonObject result;
54 QJsonObject result;
54
55
55− for(const QLocale &loc: allLocales) {
56+ Q_FOREACH(const QLocale &loc, allLocales) {
56 const QString countryCode = loc.name().section('_', 1, 1);
57 const QString countryCode = loc.name().section('_', 1, 1);
57 if (!countryCode.isEmpty() && countryCode.length() == 2) {
58 if (!countryCode.isEmpty() && countryCode.length() == 2) {
58 result.insert(countryCode, QLocale::countryToString(loc.country()));
59 result.insert(countryCode, QLocale::countryToString(loc.country()));
plugins/Wizard/LocalePlugin.h+1−1
@@ -30,7 +30,7 @@ protected:
30
30
31public:
31public:
32 Q_INVOKABLE QJsonObject languages() const;
32 Q_INVOKABLE QJsonObject languages() const;
33− Q_INVOKABLE QJsonObject localesForLanguage(const QString &code) const;
33+ Q_INVOKABLE QJsonObject countriesForLanguage(const QString &code) const;
34 Q_INVOKABLE QJsonObject countries() const;
34 Q_INVOKABLE QJsonObject countries() const;
35
35
36 friend class LocalePlugin;
36 friend class LocalePlugin;
qml/Wizard/Page.qml+62−36
@@ -21,7 +21,10 @@ Item {
21 readonly property real buttonMargin: units.gu(3)
21 readonly property real buttonMargin: units.gu(3)
22 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
22 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
23 buttonMargin / 2
23 buttonMargin / 2
24+ readonly property real buttonBarHeight: units.gu(5)
25+
24 readonly property real topMargin: units.gu(11)
26 readonly property real topMargin: units.gu(11)
27+ readonly property real bottomMargin: units.gu(3)
25 readonly property real leftMargin: units.gu(3)
28 readonly property real leftMargin: units.gu(3)
26 readonly property real rightMargin: units.gu(3)
29 readonly property real rightMargin: units.gu(3)
27
30
@@ -43,64 +46,87 @@ Item {
43 visible: false
46 visible: false
44 anchors.fill: parent
47 anchors.fill: parent
45
48
46− Label {
49+ // title
47− id: titleLabel
50+ Rectangle {
51+ id: titleRect
48 anchors {
52 anchors {
49 top: parent.top
53 top: parent.top
50 left: parent.left
54 left: parent.left
51 right: parent.right
55 right: parent.right
52− topMargin: topMargin
53− leftMargin: leftMargin
54− rightMargin: rightMargin
55 }
56 }
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+ }
56− wrapMode: Text.Wrap
70+ wrapMode: Text.Wrap
57− text: title
71+ text: title
58− color: Theme.palette.normal.baseText
72+ color: "white"
59− fontSize: "x-large"
73+ fontSize: "x-large"
74+ }
60 }
75 }
61
76
77+ // content
62 Item {
78 Item {
63 id: contentHolder
79 id: contentHolder
64 anchors {
80 anchors {
65− top: titleLabel.bottom
81+ top: titleRect.bottom
66 left: parent.left
82 left: parent.left
67 right: parent.right
83 right: parent.right
68− bottom: backButton.top
84+ bottom: buttonRect.top
69− topMargin: units.gu(4)
70 leftMargin: leftMargin
85 leftMargin: leftMargin
71 rightMargin: rightMargin
86 rightMargin: rightMargin
72− bottomMargin: buttonMargin
73 }
87 }
74 }
88 }
75
89
76− StackButton {
90+ // button bar
77− id: backButton
91+ Rectangle {
78− objectName: "backButton"
92+ id: buttonRect
79− width: buttonWidth
80 anchors {
93 anchors {
81− left: parent.left
82 bottom: parent.bottom
94 bottom: parent.bottom
83− leftMargin: leftMargin
95+ left: parent.left
84− bottomMargin: buttonMargin
96+ right: parent.right
85 }
97 }
86− z: 1
98+ height: buttonBarHeight
87− text: i18n.ctr("Button: Go back one page in the Wizard", "Back")
99+ color: "#f5f5f5"
88− visible: pageStack.depth > 1 && hasBackButton
89− backArrow: true
90
100
91− onClicked: customBack ? backClicked() : pageStack.prev()
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
92− }
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
93
115
116+ onClicked: customBack ? backClicked() : pageStack.prev()
117+ }
118+
94− Loader {
119+ Loader {
95− id: forwardButton
120+ id: forwardButton
96− objectName: "forwardButton"
121+ objectName: "forwardButton"
97− width: buttonWidth
122+ width: buttonWidth
98− anchors {
123+ anchors {
99− right: parent.right
124+ right: parent.right
100− bottom: parent.bottom
125+ bottom: parent.bottom
101− rightMargin: buttonMargin
126+ rightMargin: rightMargin
102− bottomMargin: buttonMargin
127+ verticalCenter: parent.verticalCenter
128+ }
129+ z: 1
103 }
130 }
104− z: 1
105 }
131 }
106}
132}
qml/Wizard/Pages.qml+5−16
@@ -25,15 +25,13 @@ Item {
25 objectName: "wizardPages"
25 objectName: "wizardPages"
26 focus: true
26 focus: true
27
27
28− // The background wallpaper to use
29− property string background
30−
31 signal quit()
28 signal quit()
32
29
33 // These should be set by a security page and we apply the settings when
30 // These should be set by a security page and we apply the settings when
34 // the user exits the wizard.
31 // the user exits the wizard.
35 property int passwordMethod: UbuntuSecurityPrivacyPanel.Passcode
32 property int passwordMethod: UbuntuSecurityPrivacyPanel.Passcode
36 property string password: ""
33 property string password: ""
34+ property string language: ""
37
35
38 UbuntuSecurityPrivacyPanel {
36 UbuntuSecurityPrivacyPanel {
39 id: securityPrivacy
37 id: securityPrivacy
@@ -58,19 +56,10 @@ Item {
58 anchors.fill: parent
56 anchors.fill: parent
59 }
57 }
60
58
61− Image {
59+ Rectangle {
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
60+ id: background
72− fillMode: Image.PreserveAspectCrop
61+ anchors.fill: root
73− visible: status === Image.Ready
62+ color: "#fdfdfd"
74 }
63 }
75
64
76 PageList {
65 PageList {
qml/Wizard/Pages/10-language.qml+50−40
@@ -26,62 +26,50 @@ LocalComponents.Page {
26 title: i18n.tr("Language")
26 title: i18n.tr("Language")
27 forwardButtonSourceComponent: forwardButton
27 forwardButtonSourceComponent: forwardButton
28
28
29− property string selectedLanguage: ""
30−
31 UbuntuLanguagePlugin {
29 UbuntuLanguagePlugin {
32 id: plugin
30 id: plugin
33 }
31 }
34
32
35 Component.onCompleted: {
33 Component.onCompleted: {
36− populateModel(); // FIXME pass a list of detected languages here
34+ populateModel(["fr", "de"]); // FIXME pass a list of detected languages here
37 }
35 }
38
36
39 function populateModel(detectedLangs)
37 function populateModel(detectedLangs)
40 {
38 {
41− console.log("LanguagePage::populateModel: detected languages:" + detectedLangs);
39+ var langs = LocalePlugin.languages();
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− {
59 Object.keys(langs).map(function(code) { // prepare the object
40 Object.keys(langs).map(function(code) { // prepare the object
41+ //console.log("Got language:" + code);
60− return { "code": code, "name": langs[code] };
42+ return { "code": code, "language": langs[code] || code,
43+ "dept": detectedLangs.indexOf(code) !== -1 ? i18n.tr("Detected") : i18n.tr("All") };
61 })
44 })
62− .sort(function(a, b) { // sort by language name, not code
45+ .sort(function(a, b) { // group by status, sort by language name
46+ if (a.dept === b.dept) {
63− return a.name.localeCompare(b.name);
47+ return a.language.localeCompare(b.language);
48+ } else if (a.dept === i18n.tr("Detected")) {
49+ return -1
50+ }
51+ return 1
64 })
52 })
65− .forEach(function(language) { // build the model
53+ .forEach(function(lang) { // build the model
66− model.append(
54+ if (lang.code === "C") {
67− { "language": language.name,
55+ return;
68− "code": language.code
69− }
56+ }
70− );
57+ model.append(lang);
71 });
58 });
59+ busyIndicator.running = false;
60+ busyIndicator.visible = false;
72 }
61 }
73
62
74 ActivityIndicator {
63 ActivityIndicator {
75 id: busyIndicator;
64 id: busyIndicator;
76
65
77− anchors.centerIn: parent;
66+ anchors.centerIn: column;
78 running: true;
67 running: true;
79 }
68 }
80
69
81 Column {
70 Column {
82 id: column
71 id: column
83 anchors.fill: content
72 anchors.fill: content
84− spacing: units.gu(1)
85
73
86 ListView {
74 ListView {
87 id: languagesListView;
75 id: languagesListView;
@@ -89,18 +77,26 @@ LocalComponents.Page {
89 boundsBehavior: Flickable.StopAtBounds;
77 boundsBehavior: Flickable.StopAtBounds;
90 clip: true;
78 clip: true;
91 currentIndex: -1
79 currentIndex: -1
80+ snapMode: ListView.SnapToItem
92
81
93 anchors {
82 anchors {
94 left: parent.left;
83 left: parent.left;
95 right: parent.right;
84 right: parent.right;
96− topMargin: topMargin;
97 }
85 }
98
86
99− height: column.height - column.spacing - topMargin
87+ height: column.height
100
88
101 section {
89 section {
102− property: "language";
90+ property: "dept";
103− criteria: ViewSection.FirstCharacter;
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+ }
104 }
100 }
105
101
106 model: ListModel {
102 model: ListModel {
@@ -113,6 +109,7 @@ LocalComponents.Page {
113 readonly property bool isCurrent: index === ListView.view.currentIndex
109 readonly property bool isCurrent: index === ListView.view.currentIndex
114
110
115 Label {
111 Label {
112+ id: langLabel
116 text: language;
113 text: language;
117
114
118 anchors {
115 anchors {
@@ -123,12 +120,25 @@ LocalComponents.Page {
123
120
124 fontSize: "medium"
121 fontSize: "medium"
125 font.weight: itemDelegate.isCurrent ? Font.Normal : Font.Light
122 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
126 }
136 }
127
137
128 onClicked: {
138 onClicked: {
129− selectedLanguage = code
139+ root.language = code
130 ListView.view.currentIndex = index
140 ListView.view.currentIndex = index
131− print("Selected language: " + selectedLanguage)
141+ print("Selected language: " + root.language)
132 print("Current index: " + ListView.view.currentIndex)
142 print("Current index: " + ListView.view.currentIndex)
133 }
143 }
134 }
144 }
@@ -139,9 +149,9 @@ LocalComponents.Page {
139 id: forwardButton
149 id: forwardButton
140 LocalComponents.StackButton {
150 LocalComponents.StackButton {
141 text: i18n.tr("Next")
151 text: i18n.tr("Next")
142− enabled: selectedLanguage !== ""
152+ enabled: root.language !== ""
143 onClicked: {
153 onClicked: {
144− if (selectedLanguage !== plugin.languageCodes[plugin.currentLanguage]) {
154+ if (root.language !== plugin.languageCodes[plugin.currentLanguage]) {
145 //plugin.currentLanguage = listview.currentIndex; // setting system language by some magic index? wtf
155 //plugin.currentLanguage = listview.currentIndex; // setting system language by some magic index? wtf
146 //System.updateSessionLanguage(selectedLanguage); // TODO
156 //System.updateSessionLanguage(selectedLanguage); // TODO
147 i18n.language = i18n.language; // re-notify of change after above call (for qlocale change)
157 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 {
32 anchors.verticalCenter: parent.verticalCenter
32 anchors.verticalCenter: parent.verticalCenter
33 anchors.left: parent.left
33 anchors.left: parent.left
34 anchors.right: parent.right
34 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
36 font.weight: Font.DemiBold
36 font.weight: Font.DemiBold
37 text: {
37 text: {
38 if (backArrow) {
38 if (backArrow) {