on xenial help sign in
merge prereq
22e3525Michael Zanetti
CMakeLists.txt+5
@@ -61,6 +61,11 @@ include(GNUInstallDirs)
61set(SHELL_APP_DIR ${CMAKE_INSTALL_DATADIR}/unity8)
61set(SHELL_APP_DIR ${CMAKE_INSTALL_DATADIR}/unity8)
62set(SHELL_PRIVATE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/unity8)
62set(SHELL_PRIVATE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/unity8)
63
63
64+execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=plugin_private_module_dir SystemSettings OUTPUT_VARIABLE USS_PRIVATE_PLUGINDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
65+if(USS_PRIVATE_PLUGINDIR STREQUAL "")
66+ message(FATAL_ERROR "Could not determine USS private plugin installation dir.")
67+endif()
68+
64execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=plugindir_suffix unity-shell-api OUTPUT_VARIABLE SHELL_INSTALL_QML OUTPUT_STRIP_TRAILING_WHITESPACE)
69execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=plugindir_suffix unity-shell-api OUTPUT_VARIABLE SHELL_INSTALL_QML OUTPUT_STRIP_TRAILING_WHITESPACE)
65if(SHELL_INSTALL_QML STREQUAL "")
70if(SHELL_INSTALL_QML STREQUAL "")
66 message(FATAL_ERROR "Could not determine plugin installation dir.")
71 message(FATAL_ERROR "Could not determine plugin installation dir.")
build.sh+1
@@ -54,6 +54,7 @@ install_dependencies() {
54 qtdeclarative5-unity-notifications-plugin \
54 qtdeclarative5-unity-notifications-plugin \
55 qml-module-ubuntu-connectivity \
55 qml-module-ubuntu-connectivity \
56 ubuntu-mobile-icons \
56 ubuntu-mobile-icons \
57+ ubuntu-system-settings \
57 unity-plugin-scopes \
58 unity-plugin-scopes \
58 xvfb \
59 xvfb \
59 || exit 5
60 || exit 5
debian/changelog+10
@@ -1,3 +1,13 @@
1+unity8 (8.01+15.04.20141204-0ubuntu1) vivid; urgency=low
2+
3+ [ Michael Terry ]
4+ * Import wizard code from ubuntu-system-settings.
5+ * Convert the welcome wizard from a separate executable into a qml
6+ plugin (with a small C++ plugin for support).
7+ * Add tests for welcome wizard.
8+
9+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 04 Dec 2014 20:55:11 +0000
10+
1unity8 (8.01+15.04.20141202-0ubuntu1) vivid; urgency=low
11unity8 (8.01+15.04.20141202-0ubuntu1) vivid; urgency=low
2
12
3 [ Michael Terry ]
13 [ Michael Terry ]
debian/control+7
@@ -24,6 +24,7 @@ Build-Depends: cmake,
24 libpulse-dev,
24 libpulse-dev,
25 libqmenumodel-dev (>= 0.2.8),
25 libqmenumodel-dev (>= 0.2.8),
26 libqt5xmlpatterns5-dev,
26 libqt5xmlpatterns5-dev,
27+ libsystemsettings-dev,
27 libunity-api-dev (>= 7.93),
28 libunity-api-dev (>= 7.93),
28 libusermetricsoutput1-dev,
29 libusermetricsoutput1-dev,
29 libxcb1-dev,
30 libxcb1-dev,
@@ -32,6 +33,7 @@ Build-Depends: cmake,
32 python3-all:any,
33 python3-all:any,
33 python3-setuptools,
34 python3-setuptools,
34 python:any (>= 2.7),
35 python:any (>= 2.7),
36+ qml-module-qt-labs-folderlistmodel,
35 qml-module-qtquick-layouts,
37 qml-module-qtquick-layouts,
36 qml-module-qtquick-xmllistmodel,
38 qml-module-qtquick-xmllistmodel,
37 qml-module-qtquick2,
39 qml-module-qtquick2,
@@ -46,6 +48,7 @@ Build-Depends: cmake,
46 qtdeclarative5-qtmultimedia-plugin,
48 qtdeclarative5-qtmultimedia-plugin,
47 qtdeclarative5-ubuntu-settings-components (>= 0.4),
49 qtdeclarative5-ubuntu-settings-components (>= 0.4),
48 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
50 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.1.1239) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.1.1239),
51+ qtdeclarative5-ubuntu-web-plugin,
49 ttf-ubuntu-font-family,
52 ttf-ubuntu-font-family,
50Standards-Version: 3.9.4
53Standards-Version: 3.9.4
51Homepage: http://launchpad.net/unity
54Homepage: http://launchpad.net/unity
@@ -83,10 +86,13 @@ Depends: gsettings-desktop-schemas,
83 libcap2-bin,
86 libcap2-bin,
84 libglib2.0-bin,
87 libglib2.0-bin,
85 qmenumodel-qml (>= 0.2.8),
88 qmenumodel-qml (>= 0.2.8),
89+ qml-module-qt-labs-folderlistmodel,
86 qml-module-qtquick-xmllistmodel,
90 qml-module-qtquick-xmllistmodel,
87 qtdeclarative5-gsettings1.0,
91 qtdeclarative5-gsettings1.0,
88 qtdeclarative5-qtmir-plugin (>= 0.4.4),
92 qtdeclarative5-qtmir-plugin (>= 0.4.4),
89 qtdeclarative5-ubuntu-telephony0.1,
93 qtdeclarative5-ubuntu-telephony0.1,
94+ qtdeclarative5-ubuntu-web-plugin,
95+ ubuntu-system-settings,
90 unity-launcher-impl-4,
96 unity-launcher-impl-4,
91 unity8-common (= ${source:Version}),
97 unity8-common (= ${source:Version}),
92 unity8-private (= ${binary:Version}),
98 unity8-private (= ${binary:Version}),
@@ -101,6 +107,7 @@ Breaks: indicator-network (<< 0.5.1+14.10.20141014),
101 unity8-greeter (<< 7.89),
107 unity8-greeter (<< 7.89),
102Replaces: ubuntu-touch-session (<< 0.82~),
108Replaces: ubuntu-touch-session (<< 0.82~),
103 unity8-greeter (<< 7.89),
109 unity8-greeter (<< 7.89),
110+Conflicts: ubuntu-system-settings-wizard,
104Description: Unity 8 shell
111Description: Unity 8 shell
105 The Unity 8 shell is the primary user interface for Ubuntu devices.
112 The Unity 8 shell is the primary user interface for Ubuntu devices.
106
113
debian/unity8-common.install+1
@@ -4,3 +4,4 @@ usr/share/unity8/Dash
4usr/share/unity8/Notifications
4usr/share/unity8/Notifications
5usr/share/unity8/graphics
5usr/share/unity8/graphics
6com.canonical.Unity8.gschema.xml usr/share/glib-2.0/schemas/
6com.canonical.Unity8.gschema.xml usr/share/glib-2.0/schemas/
7+var/lib/polkit-1/localauthority/10-vendor.d
debian/unity8-private.install+1
@@ -9,6 +9,7 @@ usr/lib/*/unity8/qml/ScreenGrabber
9usr/lib/*/unity8/qml/Ubuntu
9usr/lib/*/unity8/qml/Ubuntu
10usr/lib/*/unity8/qml/Unity
10usr/lib/*/unity8/qml/Unity
11usr/lib/*/unity8/qml/Utils
11usr/lib/*/unity8/qml/Utils
12+usr/lib/*/unity8/qml/Wizard
12usr/lib/*/unity8/libUbuntuGestures*
13usr/lib/*/unity8/libUbuntuGestures*
13usr/share/accountsservice/interfaces
14usr/share/accountsservice/interfaces
14usr/share/dbus-1/interfaces
15usr/share/dbus-1/interfaces
debian/unity8.install+1
@@ -10,4 +10,5 @@ usr/share/unity8/Launcher
10usr/share/unity8/Panel
10usr/share/unity8/Panel
11usr/share/unity8/Shell.qml
11usr/share/unity8/Shell.qml
12usr/share/unity8/Stages
12usr/share/unity8/Stages
13+usr/share/unity8/Wizard
13usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
14usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher
include/paths.h.in+2
@@ -71,9 +71,11 @@ inline QStringList fallbackImportPaths() {
71 QStringList paths;
71 QStringList paths;
72 if (isRunningInstalled()) {
72 if (isRunningInstalled()) {
73 paths << QString("@CMAKE_INSTALL_PREFIX@/@SHELL_INSTALL_QML@");
73 paths << QString("@CMAKE_INSTALL_PREFIX@/@SHELL_INSTALL_QML@");
74+ paths << QString("@USS_PRIVATE_PLUGINDIR@");
74 paths << QString("@SHELL_PLUGINDIR@");
75 paths << QString("@SHELL_PLUGINDIR@");
75 paths << QString("@CMAKE_INSTALL_PREFIX@/@SHELL_INSTALL_QML@/mocks");
76 paths << QString("@CMAKE_INSTALL_PREFIX@/@SHELL_INSTALL_QML@/mocks");
76 } else {
77 } else {
78+ paths << QString("@USS_PRIVATE_PLUGINDIR@");
77 paths << QString("@SHELL_PLUGINDIR@");
79 paths << QString("@SHELL_PLUGINDIR@");
78 paths << QString("@CMAKE_BINARY_DIR@/tests/mocks");
80 paths << QString("@CMAKE_BINARY_DIR@/tests/mocks");
79 }
81 }
plugins/AccountsService/AccountsService.cpp+61−2
@@ -19,23 +19,28 @@
19#include "AccountsService.h"
19#include "AccountsService.h"
20#include "AccountsServiceDBusAdaptor.h"
20#include "AccountsServiceDBusAdaptor.h"
21
21
22+#include <QFile>
22#include <QStringList>
23#include <QStringList>
23
24
24AccountsService::AccountsService(QObject* parent)
25AccountsService::AccountsService(QObject* parent)
25 : QObject(parent),
26 : QObject(parent),
26 m_service(new AccountsServiceDBusAdaptor(this)),
27 m_service(new AccountsServiceDBusAdaptor(this)),
27− m_user(qgetenv("USER")),
28+ m_user(""),
28 m_demoEdges(false),
29 m_demoEdges(false),
29 m_enableLauncherWhileLocked(false),
30 m_enableLauncherWhileLocked(false),
30 m_enableIndicatorsWhileLocked(false),
31 m_enableIndicatorsWhileLocked(false),
31 m_statsWelcomeScreen(false),
32 m_statsWelcomeScreen(false),
32 m_passwordDisplayHint(Keyboard),
33 m_passwordDisplayHint(Keyboard),
33− m_failedLogins(0)
34+ m_failedLogins(0),
35+ m_hereEnabled(false),
36+ m_hereLicensePath() // null means not set yet
34{
37{
35 connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
38 connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
36 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
39 this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
37 connect(m_service, SIGNAL(maybeChanged(const QString &)),
40 connect(m_service, SIGNAL(maybeChanged(const QString &)),
38 this, SLOT(maybeChanged(const QString &)));
41 this, SLOT(maybeChanged(const QString &)));
42+
43+ setUser(qgetenv("USER"));
39}
44}
40
45
41QString AccountsService::user() const
46QString AccountsService::user() const
@@ -45,6 +50,9 @@ QString AccountsService::user() const
45
50
46void AccountsService::setUser(const QString &user)
51void AccountsService::setUser(const QString &user)
47{
52{
53+ if (user.isEmpty() || m_user == user)
54+ return;
55+
48 m_user = user;
56 m_user = user;
49 Q_EMIT userChanged();
57 Q_EMIT userChanged();
50
58
@@ -55,6 +63,8 @@ void AccountsService::setUser(const QString &user)
55 updateStatsWelcomeScreen();
63 updateStatsWelcomeScreen();
56 updatePasswordDisplayHint();
64 updatePasswordDisplayHint();
57 updateFailedLogins();
65 updateFailedLogins();
66+ updateHereEnabled();
67+ updateHereLicensePath();
58}
68}
59
69
60bool AccountsService::demoEdges() const
70bool AccountsService::demoEdges() const
@@ -93,6 +103,26 @@ AccountsService::PasswordDisplayHint AccountsService::passwordDisplayHint() cons
93 return m_passwordDisplayHint;
103 return m_passwordDisplayHint;
94}
104}
95
105
106+bool AccountsService::hereEnabled() const
107+{
108+ return m_hereEnabled;
109+}
110+
111+void AccountsService::setHereEnabled(bool enabled)
112+{
113+ m_service->setUserProperty(m_user, "com.ubuntu.location.providers.here.AccountsService", "LicenseAccepted", enabled);
114+}
115+
116+QString AccountsService::hereLicensePath() const
117+{
118+ return m_hereLicensePath;
119+}
120+
121+bool AccountsService::hereLicensePathValid() const
122+{
123+ return !m_hereLicensePath.isNull();
124+}
125+
96void AccountsService::updateDemoEdges()
126void AccountsService::updateDemoEdges()
97{
127{
98 auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
128 auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
@@ -156,6 +186,28 @@ void AccountsService::updateFailedLogins()
156 }
186 }
157}
187}
158
188
189+void AccountsService::updateHereEnabled()
190+{
191+ bool hereEnabled = m_service->getUserProperty(m_user, "com.ubuntu.location.providers.here.AccountsService", "LicenseAccepted").toBool();
192+ if (m_hereEnabled != hereEnabled) {
193+ m_hereEnabled = hereEnabled;
194+ Q_EMIT hereEnabledChanged();
195+ }
196+}
197+
198+void AccountsService::updateHereLicensePath()
199+{
200+ QString hereLicensePath = m_service->getUserProperty(m_user, "com.ubuntu.location.providers.here.AccountsService", "LicenseBasePath").toString();
201+
202+ if (hereLicensePath.isEmpty() || !QFile::exists(hereLicensePath))
203+ hereLicensePath = "";
204+
205+ if (m_hereLicensePath.isNull() || m_hereLicensePath != hereLicensePath) {
206+ m_hereLicensePath = hereLicensePath;
207+ Q_EMIT hereLicensePathChanged();
208+ }
209+}
210+
159uint AccountsService::failedLogins() const
211uint AccountsService::failedLogins() const
160{
212{
161 return m_failedLogins;
213 return m_failedLogins;
@@ -195,6 +247,13 @@ void AccountsService::propertiesChanged(const QString &user, const QString &inte
195 if (changed.contains("EnableIndicatorsWhileLocked")) {
247 if (changed.contains("EnableIndicatorsWhileLocked")) {
196 updateEnableIndicatorsWhileLocked();
248 updateEnableIndicatorsWhileLocked();
197 }
249 }
250+ } else if (interface == "com.ubuntu.location.providers.here.AccountsService") {
251+ if (changed.contains("LicenseAccepted")) {
252+ updateHereEnabled();
253+ }
254+ if (changed.contains("LicenseBasePath")) {
255+ updateHereLicensePath();
256+ }
198 }
257 }
199}
258}
200
259
plugins/AccountsService/AccountsService.h+20
@@ -55,6 +55,16 @@ class AccountsService: public QObject
55 READ failedLogins
55 READ failedLogins
56 WRITE setFailedLogins
56 WRITE setFailedLogins
57 NOTIFY failedLoginsChanged)
57 NOTIFY failedLoginsChanged)
58+ Q_PROPERTY(bool hereEnabled
59+ READ hereEnabled
60+ WRITE setHereEnabled
61+ NOTIFY hereEnabledChanged)
62+ Q_PROPERTY(QString hereLicensePath
63+ READ hereLicensePath
64+ NOTIFY hereLicensePathChanged)
65+ Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that
66+ READ hereLicensePathValid
67+ NOTIFY hereLicensePathChanged)
58
68
59public:
69public:
60 enum PasswordDisplayHint {
70 enum PasswordDisplayHint {
@@ -75,6 +85,10 @@ public:
75 PasswordDisplayHint passwordDisplayHint() const;
85 PasswordDisplayHint passwordDisplayHint() const;
76 uint failedLogins() const;
86 uint failedLogins() const;
77 void setFailedLogins(uint failedLogins);
87 void setFailedLogins(uint failedLogins);
88+ bool hereEnabled() const;
89+ void setHereEnabled(bool enabled);
90+ QString hereLicensePath() const;
91+ bool hereLicensePathValid() const;
78
92
79Q_SIGNALS:
93Q_SIGNALS:
80 void userChanged();
94 void userChanged();
@@ -85,6 +99,8 @@ Q_SIGNALS:
85 void statsWelcomeScreenChanged();
99 void statsWelcomeScreenChanged();
86 void passwordDisplayHintChanged();
100 void passwordDisplayHintChanged();
87 void failedLoginsChanged();
101 void failedLoginsChanged();
102+ void hereEnabledChanged();
103+ void hereLicensePathChanged();
88
104
89private Q_SLOTS:
105private Q_SLOTS:
90 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
106 void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
@@ -98,6 +114,8 @@ private:
98 void updateStatsWelcomeScreen();
114 void updateStatsWelcomeScreen();
99 void updatePasswordDisplayHint();
115 void updatePasswordDisplayHint();
100 void updateFailedLogins();
116 void updateFailedLogins();
117+ void updateHereEnabled();
118+ void updateHereLicensePath();
101
119
102 AccountsServiceDBusAdaptor *m_service;
120 AccountsServiceDBusAdaptor *m_service;
103 QString m_user;
121 QString m_user;
@@ -108,6 +126,8 @@ private:
108 bool m_statsWelcomeScreen;
126 bool m_statsWelcomeScreen;
109 PasswordDisplayHint m_passwordDisplayHint;
127 PasswordDisplayHint m_passwordDisplayHint;
110 uint m_failedLogins;
128 uint m_failedLogins;
129+ bool m_hereEnabled;
130+ QString m_hereLicensePath;
111};
131};
112
132
113#endif
133#endif
plugins/CMakeLists.txt+1
@@ -21,3 +21,4 @@ add_subdirectory(ScreenGrabber)
21add_subdirectory(Ubuntu)
21add_subdirectory(Ubuntu)
22add_subdirectory(Unity)
22add_subdirectory(Unity)
23add_subdirectory(Utils)
23add_subdirectory(Utils)
24+add_subdirectory(Wizard)
plugins/Unity/Launcher/desktopfilehandler.cpp+1−1
@@ -110,7 +110,7 @@ QString DesktopFileHandler::displayName() const
110 settings.beginGroup("Desktop Entry");
110 settings.beginGroup("Desktop Entry");
111
111
112 // First try to find Name[xx_YY] and Name[xx] in .desktop file
112 // First try to find Name[xx_YY] and Name[xx] in .desktop file
113− QString locale = QLocale::system().name();
113+ QString locale = QLocale().name();
114 QString shortLocale = locale.split('_').first();
114 QString shortLocale = locale.split('_').first();
115
115
116 if (locale != shortLocale && settings.contains(QString("Name[%1]").arg(locale))) {
116 if (locale != shortLocale && settings.contains(QString("Name[%1]").arg(locale))) {
plugins/Unity/Launcher/launcheritem.cpp+11−4
@@ -60,6 +60,10 @@ void LauncherItem::setName(const QString &name)
60{
60{
61 if (m_name != name) {
61 if (m_name != name) {
62 m_name = name;
62 m_name = name;
63+ QuickListEntry entry;
64+ entry.setActionId("launch_item");
65+ entry.setText(m_name);
66+ m_quickList->updateAction(entry);
63 Q_EMIT nameChanged(name);
67 Q_EMIT nameChanged(name);
64 }
68 }
65}
69}
@@ -86,12 +90,15 @@ void LauncherItem::setPinned(bool pinned)
86{
90{
87 if (m_pinned != pinned) {
91 if (m_pinned != pinned) {
88 m_pinned = pinned;
92 m_pinned = pinned;
89− QuickListEntry entry;
90− entry.setActionId("pin_item");
91− entry.setText(pinned ? gettext("Unpin shortcut") : gettext("Pin shortcut"));
92− m_quickList->updateAction(entry);
93 Q_EMIT pinnedChanged(pinned);
93 Q_EMIT pinnedChanged(pinned);
94 }
94 }
95+
96+ // Even if pinned status didn't change, we want to update text in case
97+ // the locale has changed since we last set pinned status.
98+ QuickListEntry entry;
99+ entry.setActionId("pin_item");
100+ entry.setText(pinned ? gettext("Unpin shortcut") : gettext("Pin shortcut"));
101+ m_quickList->updateAction(entry);
95}
102}
96
103
97bool LauncherItem::running() const
104bool LauncherItem::running() const
plugins/Unity/Launcher/launchermodel.cpp+1
@@ -370,6 +370,7 @@ void LauncherModel::refresh()
370 int idx = m_list.indexOf(item);
370 int idx = m_list.indexOf(item);
371 item->setName(desktopFile.displayName());
371 item->setName(desktopFile.displayName());
372 item->setIcon(desktopFile.icon());
372 item->setIcon(desktopFile.icon());
373+ item->setPinned(item->pinned()); // update pinned text if needed
373 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon);
374 Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleName << RoleIcon);
374 }
375 }
375 }
376 }
plugins/Unity/Launcher/launchermodel.h+1−1
@@ -58,6 +58,7 @@ public:
58
58
59public Q_SLOTS:
59public Q_SLOTS:
60 void requestRemove(const QString &appId);
60 void requestRemove(const QString &appId);
61+ Q_INVOKABLE void refresh();
61
62
62private:
63private:
63 void storeAppList();
64 void storeAppList();
@@ -68,7 +69,6 @@ private Q_SLOTS:
68 void countChanged(const QString &appId, int count);
69 void countChanged(const QString &appId, int count);
69 void countVisibleChanged(const QString &appId, int count);
70 void countVisibleChanged(const QString &appId, int count);
70 void progressChanged(const QString &appId, int progress);
71 void progressChanged(const QString &appId, int progress);
71− void refresh();
72
72
73 void applicationAdded(const QModelIndex &parent, int row);
73 void applicationAdded(const QModelIndex &parent, int row);
74 void applicationRemoved(const QModelIndex &parent, int row);
74 void applicationRemoved(const QModelIndex &parent, int row);
plugins/Wizard/50-com.canonical.unity.wizard.pklanew file+6
@@ -0,0 +1,6 @@
1+[Allow welcome wizard to set AccountsService fields]
2+Identity=unix-user:lightdm
3+Action=org.freedesktop.accounts.user-administration
4+ResultActive=yes
5+ResultInactive=no
6+ResultAny=no
plugins/Wizard/CMakeLists.txtnew file+11
@@ -0,0 +1,11 @@
1+add_library(Wizard-qml MODULE
2+ plugin.cpp
3+ PageList.cpp
4+ System.cpp
5+)
6+
7+qt5_use_modules(Wizard-qml DBus Qml)
8+add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml)
9+
10+set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
11+install(FILES 50-com.canonical.unity.wizard.pkla DESTINATION ${POLKIT_LIB_DIR}/localauthority/10-vendor.d)
plugins/Wizard/PageList.cppnew file+112
@@ -0,0 +1,112 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+/**
18+ * This class lets the list of wizard pages be dynamic.
19+ * - To add new ones, drop them into
20+ * $XDG_DATA_DIRS/Wizard/Pages with a numbered prefix,
21+ * like "21-custom-page.qml". The number determines the order in the page
22+ * sequence that your page will appear.
23+ * - To disable an existing page, add a file like "21-custom-page.qml.disabled"
24+ * - To go to the next page, use pageStack.next()
25+ * - To go back to the previous page, use pageStack.prev()
26+ * - To load a page outside of the normal flow (so that it doesn't affect the
27+ * back button), use pageStack.push(Qt.resolvedUrl("custom-page.qml")) in
28+ * your page.
29+ * - See default pages for plenty of examples.
30+ */
31+
32+#include "PageList.h"
33+#include <paths.h>
34+#include <QDir>
35+#include <QSet>
36+#include <QStandardPaths>
37+
38+PageList::PageList(QObject *parent)
39+ : QObject(parent),
40+ m_index(-1),
41+ m_pages()
42+{
43+ QString qmlSuffix = ".qml";
44+ QString disabledSuffix = ".disabled";
45+ QSet<QString> disabledPages;
46+ QStringList dataDirs;
47+
48+ if (!isRunningInstalled() && getenv("UNITY_TEST_ENV") == nullptr) {
49+ dataDirs = QStringList() << qmlDirectory();
50+ } else {
51+ dataDirs = shellDataDirs();
52+ }
53+
54+ Q_FOREACH(const QString &dataDir, dataDirs) {
55+ QDir dir(dataDir + "/Wizard/Pages");
56+ QStringList entries = dir.entryList(QStringList("[0-9]*"), QDir::Files | QDir::Readable);
57+ Q_FOREACH(const QString &entry, entries) {
58+ if (!m_pages.contains(entry) && entry.endsWith(qmlSuffix))
59+ m_pages.insert(entry, dir.absoluteFilePath(entry));
60+ else if (entry.endsWith(qmlSuffix + disabledSuffix))
61+ disabledPages.insert(entry.left(entry.size() - disabledSuffix.size()));
62+ }
63+ }
64+
65+ // Now remove any explicitly disabled entries
66+ Q_FOREACH(const QString &page, disabledPages) {
67+ m_pages.remove(page);
68+ }
69+}
70+
71+QStringList PageList::entries() const
72+{
73+ return m_pages.keys();
74+}
75+
76+QStringList PageList::paths() const
77+{
78+ return m_pages.values();
79+}
80+
81+int PageList::index() const
82+{
83+ return m_index;
84+}
85+
86+int PageList::numPages() const
87+{
88+ return m_pages.size();
89+}
90+
91+QString PageList::prev()
92+{
93+ if (m_index > 0)
94+ return m_pages.values()[setIndex(m_index - 1)];
95+ else
96+ return QString();
97+}
98+
99+QString PageList::next()
100+{
101+ if (m_index < m_pages.count() - 1)
102+ return m_pages.values()[setIndex(m_index + 1)];
103+ else
104+ return QString();
105+}
106+
107+int PageList::setIndex(int index)
108+{
109+ m_index = index;
110+ Q_EMIT indexChanged();
111+ return m_index;
112+}
plugins/Wizard/PageList.hnew file+53
@@ -0,0 +1,53 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef WIZARD_PAGELIST_H
18+#define WIZARD_PAGELIST_H
19+
20+#include <QMap>
21+#include <QObject>
22+#include <QString>
23+
24+class PageList : public QObject
25+{
26+ Q_OBJECT
27+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
28+ Q_PROPERTY(int numPages READ numPages NOTIFY numPagesChanged)
29+
30+public:
31+ explicit PageList(QObject *parent = 0);
32+
33+ QStringList entries() const;
34+ QStringList paths() const;
35+ int index() const;
36+ int numPages() const;
37+
38+public Q_SLOTS:
39+ QString prev();
40+ QString next();
41+
42+Q_SIGNALS:
43+ void indexChanged();
44+ void numPagesChanged(); // never emitted, just here to quiet Qml warnings
45+
46+private:
47+ int setIndex(int index);
48+
49+ int m_index;
50+ QMap<QString, QString> m_pages;
51+};
52+
53+#endif // WIZARD_PAGELIST_H
plugins/Wizard/System.cppnew file+99
@@ -0,0 +1,99 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "System.h"
18+
19+#include <QDBusInterface>
20+#include <QDBusMetaType>
21+#include <QDir>
22+#include <QFile>
23+#include <QLocale>
24+#include <QMap>
25+#include <QProcess>
26+
27+System::System()
28+ : QObject(),
29+ m_fsWatcher()
30+{
31+ // Register the argument needed for UpdateActivationEnvironment below
32+ qDBusRegisterMetaType<QMap<QString,QString>>();
33+
34+ m_fsWatcher.addPath(wizardEnabledPath());
35+ connect(&m_fsWatcher, SIGNAL(fileChanged(const QString &)),
36+ this, SIGNAL(wizardEnabledChanged()));
37+}
38+
39+QString System::wizardEnabledPath()
40+{
41+ // Uses ubuntu-system-settings namespace for historic compatibility reasons
42+ return QDir::home().filePath(".config/ubuntu-system-settings/wizard-has-run");
43+}
44+
45+bool System::wizardEnabled() const
46+{
47+ return !QFile::exists(wizardEnabledPath());
48+}
49+
50+void System::setWizardEnabled(bool enabled)
51+{
52+ if (wizardEnabled() == enabled)
53+ return;
54+
55+ if (enabled) {
56+ QFile::remove(wizardEnabledPath());
57+ } else {
58+ QDir(wizardEnabledPath()).mkpath("..");
59+ QFile(wizardEnabledPath()).open(QIODevice::WriteOnly);
60+ m_fsWatcher.addPath(wizardEnabledPath());
61+ wizardEnabledChanged();
62+ }
63+}
64+
65+void System::setSessionVariable(const QString &variable, const QString &value)
66+{
67+ // We need to update both upstart's and DBus's environment
68+ QProcess::execute(QString("initctl set-env --global %1=%2").arg(variable, value));
69+
70+ QDBusInterface iface("org.freedesktop.DBus",
71+ "/org/freedesktop/DBus",
72+ "org.freedesktop.DBus",
73+ QDBusConnection::sessionBus());
74+
75+ QMap<QString,QString> valueMap;
76+ valueMap.insert(variable, value);
77+ iface.call("UpdateActivationEnvironment", QVariant::fromValue(valueMap));
78+}
79+
80+void System::updateSessionLanguage(const QString &locale)
81+{
82+ QString language = locale.split(".")[0];
83+
84+ setSessionVariable("LANGUAGE", language);
85+ setSessionVariable("LANG", locale);
86+ setSessionVariable("LC_ALL", locale);
87+
88+ // QLocale caches the default locale on startup, and Qt uses that cached
89+ // copy when formatting dates. So manually update it here.
90+ QLocale::setDefault(QLocale(locale));
91+
92+ // Restart bits of the session to pick up new language.
93+ QProcess::startDetached("sh -c \"initctl emit indicator-services-end; \
94+ initctl stop scope-registry; \
95+ initctl stop smart-scopes-proxy; \
96+ initctl emit --no-wait indicator-services-start; \
97+ initctl restart --no-wait maliit-server; \
98+ initctl restart --no-wait unity8-dash\"");
99+}
plugins/Wizard/System.hnew file+50
@@ -0,0 +1,50 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef WIZARD_SYSTEM_H
18+#define WIZARD_SYSTEM_H
19+
20+#include <QFileSystemWatcher>
21+#include <QObject>
22+#include <QString>
23+
24+class System : public QObject
25+{
26+ Q_OBJECT
27+ Q_PROPERTY(bool wizardEnabled READ wizardEnabled WRITE setWizardEnabled NOTIFY wizardEnabledChanged)
28+
29+public:
30+ System();
31+
32+ bool wizardEnabled() const;
33+ void setWizardEnabled(bool enabled);
34+
35+public Q_SLOTS:
36+ void updateSessionLanguage(const QString &locale);
37+
38+Q_SIGNALS:
39+ void wizardEnabledChanged();
40+
41+private:
42+ Q_DISABLE_COPY(System)
43+
44+ static QString wizardEnabledPath();
45+ static void setSessionVariable(const QString &variable, const QString &value);
46+
47+ QFileSystemWatcher m_fsWatcher;
48+};
49+
50+#endif
plugins/Wizard/Wizard.qmltypesnew file+36
@@ -0,0 +1,36 @@
1+import QtQuick.tooling 1.1
2+
3+// This file describes the plugin-supplied types contained in the library.
4+// It is used for QML tooling purposes only.
5+//
6+// This file was auto-generated by:
7+// 'qmlplugindump -notrelocatable Wizard 0.1 plugins'
8+
9+Module {
10+ Component {
11+ name: "PageList"
12+ prototype: "QObject"
13+ exports: ["Wizard/PageList 0.1"]
14+ isCreatable: false
15+ isSingleton: true
16+ exportMetaObjectRevisions: [0]
17+ Property { name: "index"; type: "int"; isReadonly: true }
18+ Property { name: "numPages"; type: "int"; isReadonly: true }
19+ Method { name: "prev"; type: "string" }
20+ Method { name: "next"; type: "string" }
21+ }
22+ Component {
23+ name: "System"
24+ prototype: "QObject"
25+ exports: ["Wizard/System 0.1"]
26+ isCreatable: false
27+ isSingleton: true
28+ exportMetaObjectRevisions: [0]
29+ Property { name: "wizardEnabled"; type: "bool" }
30+ Method {
31+ name: "updateSessionLanguage"
32+ Parameter { name: "locale"; type: "string" }
33+ }
34+ }
35+}
36+
plugins/Wizard/plugin.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "plugin.h"
18+#include "PageList.h"
19+#include "System.h"
20+
21+#include <QtQml/qqml.h>
22+
23+static QObject *system_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
24+{
25+ Q_UNUSED(engine)
26+ Q_UNUSED(scriptEngine)
27+ return new System();
28+}
29+
30+void WizardPlugin::registerTypes(const char *uri)
31+{
32+ Q_ASSERT(uri == QLatin1String("Wizard"));
33+ qmlRegisterType<PageList>(uri, 0, 1, "PageList");
34+ qmlRegisterSingletonType<System>(uri, 0, 1, "System", system_provider);
35+}
plugins/Wizard/plugin.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2014 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+#ifndef WIZARD_PLUGIN_H
18+#define WIZARD_PLUGIN_H
19+
20+#include <QtQml/QQmlEngine>
21+#include <QtQml/QQmlExtensionPlugin>
22+
23+class WizardPlugin : public QQmlExtensionPlugin
24+{
25+ Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27+
28+public:
29+ void registerTypes(const char *uri);
30+};
31+
32+#endif
plugins/Wizard/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Wizard
2+plugin Wizard-qml
3+typeinfo Wizard.qmltypes
po/zh_CN.po+4−4
@@ -8,19 +8,19 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-11-07 10:59+0100\n"
10"POT-Creation-Date: 2014-11-07 10:59+0100\n"
11−"PO-Revision-Date: 2014-08-12 14:09+0000\n"
11+"PO-Revision-Date: 2014-12-04 11:57+0000\n"
12−"Last-Translator: Anthony Wong <anthony.wong@ubuntu.com>\n"
12+"Last-Translator: Mo <alimo199x@gmail.com>\n"
13"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
13"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
17"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-12-03 06:50+0000\n"
18+"X-Launchpad-Export-Date: 2014-12-05 06:25+0000\n"
19"X-Generator: Launchpad (build 17274)\n"
19"X-Generator: Launchpad (build 17274)\n"
20
20
21#: plugins/LightDM/Greeter.cpp:130
21#: plugins/LightDM/Greeter.cpp:130
22msgid "Password: "
22msgid "Password: "
23−msgstr ""
23+msgstr "密码: "
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:45
25#: plugins/Unity/Launcher/launcheritem.cpp:45
26#: plugins/Unity/Launcher/launcheritem.cpp:91
26#: plugins/Unity/Launcher/launcheritem.cpp:91
qml/CMakeLists.txt+1
@@ -13,6 +13,7 @@ set(QML_DIRS
13 Launcher
13 Launcher
14 Stages
14 Stages
15 Notifications
15 Notifications
16+ Wizard
16 )
17 )
17
18
18install(DIRECTORY ${QML_DIRS}
19install(DIRECTORY ${QML_DIRS}
qml/Components/Dialogs.qml+17−21
@@ -24,10 +24,6 @@ import Ubuntu.Components.Popups 0.1
24Item {
24Item {
25 id: root
25 id: root
26
26
27− // Explicitly use the right domain for this widget because it might be used
28− // in other applications like the welcome wizard.
29− readonly property string domain: "unity8"
30−
31 function onPowerKeyPressed() {
27 function onPowerKeyPressed() {
32 // FIXME: event.isAutoRepeat is always false on Nexus 4.
28 // FIXME: event.isAutoRepeat is always false on Nexus 4.
33 // So we use powerKeyTimer.running to avoid the PowerOff key repeat
29 // So we use powerKeyTimer.running to avoid the PowerOff key repeat
@@ -71,17 +67,17 @@ Item {
71 id: logoutDialog
67 id: logoutDialog
72 Dialog {
68 Dialog {
73 id: dialogueLogout
69 id: dialogueLogout
74− title: i18n.dtr(root.domain, "Log out")
70+ title: i18n.tr("Log out")
75− text: i18n.dtr(root.domain, "Are you sure you want to log out?")
71+ text: i18n.tr("Are you sure you want to log out?")
76 Button {
72 Button {
77− text: i18n.dtr(root.domain, "No")
73+ text: i18n.tr("No")
78 onClicked: {
74 onClicked: {
79 PopupUtils.close(dialogueLogout);
75 PopupUtils.close(dialogueLogout);
80 d.dialogShown = false;
76 d.dialogShown = false;
81 }
77 }
82 }
78 }
83 Button {
79 Button {
84− text: i18n.dtr(root.domain, "Yes")
80+ text: i18n.tr("Yes")
85 onClicked: {
81 onClicked: {
86 DBusUnitySessionService.Logout();
82 DBusUnitySessionService.Logout();
87 PopupUtils.close(dialogueLogout);
83 PopupUtils.close(dialogueLogout);
@@ -95,17 +91,17 @@ Item {
95 id: shutdownDialog
91 id: shutdownDialog
96 Dialog {
92 Dialog {
97 id: dialogueShutdown
93 id: dialogueShutdown
98− title: i18n.dtr(root.domain, "Shut down")
94+ title: i18n.tr("Shut down")
99− text: i18n.dtr(root.domain, "Are you sure you want to shut down?")
95+ text: i18n.tr("Are you sure you want to shut down?")
100 Button {
96 Button {
101− text: i18n.dtr(root.domain, "No")
97+ text: i18n.tr("No")
102 onClicked: {
98 onClicked: {
103 PopupUtils.close(dialogueShutdown);
99 PopupUtils.close(dialogueShutdown);
104 d.dialogShown = false;
100 d.dialogShown = false;
105 }
101 }
106 }
102 }
107 Button {
103 Button {
108− text: i18n.dtr(root.domain, "Yes")
104+ text: i18n.tr("Yes")
109 onClicked: {
105 onClicked: {
110 dBusUnitySessionServiceConnection.closeAllApps();
106 dBusUnitySessionServiceConnection.closeAllApps();
111 DBusUnitySessionService.Shutdown();
107 DBusUnitySessionService.Shutdown();
@@ -120,17 +116,17 @@ Item {
120 id: rebootDialog
116 id: rebootDialog
121 Dialog {
117 Dialog {
122 id: dialogueReboot
118 id: dialogueReboot
123− title: i18n.dtr(root.domain, "Reboot")
119+ title: i18n.tr("Reboot")
124− text: i18n.dtr(root.domain, "Are you sure you want to reboot?")
120+ text: i18n.tr("Are you sure you want to reboot?")
125 Button {
121 Button {
126− text: i18n.dtr(root.domain, "No")
122+ text: i18n.tr("No")
127 onClicked: {
123 onClicked: {
128 PopupUtils.close(dialogueReboot)
124 PopupUtils.close(dialogueReboot)
129 d.dialogShown = false;
125 d.dialogShown = false;
130 }
126 }
131 }
127 }
132 Button {
128 Button {
133− text: i18n.dtr(root.domain, "Yes")
129+ text: i18n.tr("Yes")
134 onClicked: {
130 onClicked: {
135 dBusUnitySessionServiceConnection.closeAllApps();
131 dBusUnitySessionServiceConnection.closeAllApps();
136 DBusUnitySessionService.Reboot();
132 DBusUnitySessionService.Reboot();
@@ -145,10 +141,10 @@ Item {
145 id: powerDialog
141 id: powerDialog
146 Dialog {
142 Dialog {
147 id: dialoguePower
143 id: dialoguePower
148− title: i18n.dtr(root.domain, "Power")
144+ title: i18n.tr("Power")
149− text: i18n.dtr(root.domain, "Are you sure you would like\nto power off?")
145+ text: i18n.tr("Are you sure you would like\nto power off?")
150 Button {
146 Button {
151− text: i18n.dtr(root.domain, "Power off")
147+ text: i18n.tr("Power off")
152 onClicked: {
148 onClicked: {
153 dBusUnitySessionServiceConnection.closeAllApps();
149 dBusUnitySessionServiceConnection.closeAllApps();
154 PopupUtils.close(dialoguePower);
150 PopupUtils.close(dialoguePower);
@@ -158,7 +154,7 @@ Item {
158 color: UbuntuColors.red
154 color: UbuntuColors.red
159 }
155 }
160 Button {
156 Button {
161− text: i18n.dtr(root.domain, "Restart")
157+ text: i18n.tr("Restart")
162 onClicked: {
158 onClicked: {
163 dBusUnitySessionServiceConnection.closeAllApps();
159 dBusUnitySessionServiceConnection.closeAllApps();
164 DBusUnitySessionService.Reboot();
160 DBusUnitySessionService.Reboot();
@@ -168,7 +164,7 @@ Item {
168 color: UbuntuColors.green
164 color: UbuntuColors.green
169 }
165 }
170 Button {
166 Button {
171− text: i18n.dtr(root.domain, "Cancel")
167+ text: i18n.tr("Cancel")
172 onClicked: {
168 onClicked: {
173 PopupUtils.close(dialoguePower);
169 PopupUtils.close(dialoguePower);
174 d.dialogShown = false;
170 d.dialogShown = false;
qml/Components/EdgeDemo.qml+19−6
@@ -17,6 +17,7 @@
17import AccountsService 0.1
17import AccountsService 0.1
18import LightDM 0.1 as LightDM
18import LightDM 0.1 as LightDM
19import QtQuick 2.0
19import QtQuick 2.0
20+import Ubuntu.Components 1.1
20
21
21Item {
22Item {
22 id: demo
23 id: demo
@@ -61,11 +62,16 @@ Item {
61 stagesEnabled = true
62 stagesEnabled = true
62 panelEnabled = true
63 panelEnabled = true
63 panelContentEnabled = true
64 panelContentEnabled = true
65+
66+ // Use a tiny delay for these destroy() calls because if a lot is
67+ // happening at once (like creating and being destroyed in same event
68+ // loop, as might happen when answering a call while demo is open),
69+ // the destroy() call will be ignored.
64− if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
70+ if (d.rightEdgeDemo) d.rightEdgeDemo.destroy(1);
65− if (d.topEdgeDemo) d.topEdgeDemo.destroy()
71+ if (d.topEdgeDemo) d.topEdgeDemo.destroy(1);
66− if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy()
72+ if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy(1);
67− if (d.leftEdgeDemo) d.leftEdgeDemo.destroy()
73+ if (d.leftEdgeDemo) d.leftEdgeDemo.destroy(1);
68− if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
74+ if (d.finalEdgeDemo) d.finalEdgeDemo.destroy(1);
69 }
75 }
70
76
71 function startDemo() {
77 function startDemo() {
@@ -97,12 +103,19 @@ Item {
97 property bool showEdgeDemo: AccountsService.demoEdges
103 property bool showEdgeDemo: AccountsService.demoEdges
98 property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user
104 property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user
99
105
100− onShowEdgeDemoChanged: {
106+ function restartDemo() {
101 stopDemo()
107 stopDemo()
102 if (d.showEdgeDemo) {
108 if (d.showEdgeDemo) {
103 startDemo()
109 startDemo()
104 }
110 }
105 }
111 }
112+
113+ onShowEdgeDemoChanged: restartDemo()
114+ }
115+
116+ Connections {
117+ target: i18n
118+ onLanguageChanged: d.restartDemo()
106 }
119 }
107
120
108 function startRightEdgeDemo() {
121 function startRightEdgeDemo() {
qml/Greeter/Clock.qml+10
@@ -34,6 +34,16 @@ Item {
34 }
34 }
35 }
35 }
36
36
37+ Connections {
38+ target: i18n
39+ onLanguageChanged: {
40+ if (visible) {
41+ timeLabel.text = Qt.formatTime(clock.currentDate); // kicks time
42+ clock.currentDate = new Date(); // kicks date
43+ }
44+ }
45+ }
46+
37 Indicators.SharedUnityMenuModel {
47 Indicators.SharedUnityMenuModel {
38 id: timeModel
48 id: timeModel
39 objectName: "timeModel"
49 objectName: "timeModel"
qml/Greeter/GreeterContent.qml+5
@@ -133,6 +133,11 @@ Item {
133 onSelected: infographics.selectedUser = greeterContentLoader.model.data(uid, LightDM.UserRoles.NameRole)
133 onSelected: infographics.selectedUser = greeterContentLoader.model.data(uid, LightDM.UserRoles.NameRole)
134 }
134 }
135
135
136+ Connections {
137+ target: i18n
138+ onLanguageChanged: greeterContentLoader.infographicModel.readyForDataChange()
139+ }
140+
136 anchors {
141 anchors {
137 verticalCenter: parent.verticalCenter
142 verticalCenter: parent.verticalCenter
138 left: narrowMode ? root.left : loginLoader.right
143 left: narrowMode ? root.left : loginLoader.right
qml/Launcher/Launcher.qml+5
@@ -119,6 +119,11 @@ Item {
119 onHint: hint();
119 onHint: hint();
120 }
120 }
121
121
122+ Connections {
123+ target: i18n
124+ onLanguageChanged: LauncherModel.refresh()
125+ }
126+
122 SequentialAnimation {
127 SequentialAnimation {
123 id: fadeOutAnimation
128 id: fadeOutAnimation
124 ScriptAction {
129 ScriptAction {
qml/Shell.qml+26−15
@@ -37,6 +37,7 @@ import "Components"
37import "Notifications"
37import "Notifications"
38import "Stages"
38import "Stages"
39import "Panel/Indicators"
39import "Panel/Indicators"
40+import "Wizard"
40import Unity.Notifications 1.0 as NotificationBackend
41import Unity.Notifications 1.0 as NotificationBackend
41import Unity.Session 0.1
42import Unity.Session 0.1
42import Unity.DashCommunicator 0.1
43import Unity.DashCommunicator 0.1
@@ -241,6 +242,14 @@ Item {
241 onApplicationAdded: {
242 onApplicationAdded: {
242 if (greeter.shown && appId != "unity8-dash") {
243 if (greeter.shown && appId != "unity8-dash") {
243 greeter.startUnlock()
244 greeter.startUnlock()
245+
246+ // If this happens on first boot, we may be in edge
247+ // tutorial or wizard while receiving a call. But a call
248+ // is more important than wizard so just bail out of those.
249+ if (edgeDemo.running) {
250+ edgeDemo.hideEdgeDemos();
251+ wizard.hide();
252+ }
244 }
253 }
245 if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
254 if (greeter.narrowMode && greeter.hasLockedApp && appId === greeter.lockedApp) {
246 lockscreen.hide() // show locked app
255 lockscreen.hide() // show locked app
@@ -365,6 +374,15 @@ Item {
365 minPinLength: 4
374 minPinLength: 4
366 maxPinLength: 4
375 maxPinLength: 4
367
376
377+ property string promptText
378+ infoText: promptText !== "" ? i18n.tr("Enter %1").arg(promptText) :
379+ alphaNumeric ? i18n.tr("Enter passphrase") :
380+ i18n.tr("Enter passcode")
381+ errorText: promptText !== "" ? i18n.tr("Sorry, incorrect %1").arg(promptText) :
382+ alphaNumeric ? i18n.tr("Sorry, incorrect passphrase") + "\n" +
383+ i18n.tr("Please re-enter") :
384+ i18n.tr("Sorry, incorrect passcode")
385+
368 // FIXME: We *should* show emergency dialer if there is a SIM present,
386 // FIXME: We *should* show emergency dialer if there is a SIM present,
369 // regardless of whether the side stage is enabled. But right now,
387 // regardless of whether the side stage is enabled. But right now,
370 // the assumption is that narrow screens are phones which have SIMs
388 // the assumption is that narrow screens are phones which have SIMs
@@ -418,20 +436,7 @@ Item {
418 return; // could happen if hideGreeter() comes in before we prompt
436 return; // could happen if hideGreeter() comes in before we prompt
419 }
437 }
420 if (greeter.narrowMode) {
438 if (greeter.narrowMode) {
421− if (isDefaultPrompt) {
439+ lockscreen.promptText = isDefaultPrompt ? "" : text.toLowerCase();
422− if (lockscreen.alphaNumeric) {
423− lockscreen.infoText = i18n.tr("Enter passphrase")
424− lockscreen.errorText = i18n.tr("Sorry, incorrect passphrase") + "\n" +
425− i18n.tr("Please re-enter")
426− } else {
427− lockscreen.infoText = i18n.tr("Enter passcode")
428− lockscreen.errorText = i18n.tr("Sorry, incorrect passcode")
429− }
430− } else {
431− lockscreen.infoText = i18n.tr("Enter %1").arg(text.toLowerCase())
432− lockscreen.errorText = i18n.tr("Sorry, incorrect %1").arg(text.toLowerCase())
433− }
434−
435 lockscreen.maybeShow();
440 lockscreen.maybeShow();
436 }
441 }
437 }
442 }
@@ -761,6 +766,12 @@ Item {
761 }
766 }
762 }
767 }
763
768
769+ Wizard {
770+ id: wizard
771+ anchors.fill: parent
772+ background: shell.background
773+ }
774+
764 Rectangle {
775 Rectangle {
765 id: modalNotificationBackground
776 id: modalNotificationBackground
766
777
@@ -822,7 +833,7 @@ Item {
822 id: edgeDemo
833 id: edgeDemo
823 objectName: "edgeDemo"
834 objectName: "edgeDemo"
824 z: dialogs.z + 10
835 z: dialogs.z + 10
825− paused: Powerd.status === Powerd.Off // Saves power
836+ paused: Powerd.status === Powerd.Off || wizard.active // Saves power
826 greeter: greeter
837 greeter: greeter
827 launcher: launcher
838 launcher: launcher
828 panel: panel
839 panel: panel
qml/Wizard/CheckableSetting.qmlnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 2014 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.1
19+import Ubuntu.Components.ListItems 1.0 as ListItem
20+
21+ListItem.Empty {
22+ id: listItem
23+
24+ property alias text: label.text
25+ property bool checked: false
26+ property real leftMargin
27+ property real rightMargin
28+
29+ readonly property real labelOffset: label.x
30+
31+ signal linkActivated(string link)
32+
33+ implicitHeight: Math.max(label.height, checkBox.height)
34+
35+ Item {
36+ anchors.fill: parent
37+
38+ CheckBox {
39+ id: checkBox
40+
41+ anchors {
42+ left: parent.left
43+ top: parent.top
44+ leftMargin: listItem.leftMargin
45+ }
46+
47+ Component.onCompleted: {
48+ checked = listItem.checked;
49+ }
50+
51+ onClicked: {
52+ listItem.checked = checked
53+ listItem.triggered(listItem.checked)
54+ }
55+
56+ Connections {
57+ target: listItem
58+ onCheckedChanged: checkBox.checked = listItem.checked
59+ }
60+
61+ Connections {
62+ target: listItem.__mouseArea
63+ onClicked: {
64+ listItem.checked = !listItem.checked
65+ listItem.triggered(listItem.checked)
66+ }
67+ }
68+ }
69+
70+ Label {
71+ id: label
72+ anchors {
73+ left: checkBox.right
74+ right: parent.right
75+ verticalCenter: parent.verticalCenter
76+ leftMargin: units.gu(2)
77+ rightMargin: listItem.rightMargin
78+ }
79+ wrapMode: Text.Wrap
80+ linkColor: Theme.palette.normal.foregroundText
81+ onLinkActivated: listItem.linkActivated(link)
82+ }
83+ }
84+}
qml/Wizard/Page.qmlnew file+108
@@ -0,0 +1,108 @@
1+/*
2+ * Copyright (C) 2013 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.1
19+
20+Item {
21+ readonly property real buttonMargin: units.gu(2)
22+ readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
23+ buttonMargin / 2
24+ readonly property real topMargin: units.gu(8)
25+ readonly property real leftMargin: units.gu(2)
26+ readonly property real rightMargin: units.gu(2)
27+
28+ // If you want to skip a page, mark skipValid false while you figure out
29+ // whether to skip, then set it to true once you've determined the value
30+ // of the skip property.
31+ property bool skipValid: true
32+ property bool skip: false
33+
34+ property bool hasBackButton: true
35+ property bool customBack: false
36+ property alias forwardButtonSourceComponent: forwardButton.sourceComponent
37+ property alias content: contentHolder
38+
39+ property string title: ""
40+
41+ signal backClicked()
42+
43+ visible: false
44+ anchors.fill: parent
45+
46+ // We want larger than even fontSize: "x-large", so we use a Text instead
47+ // of a Label.
48+ Text {
49+ id: titleLabel
50+ anchors {
51+ top: parent.top
52+ left: parent.left
53+ right: parent.right
54+ topMargin: topMargin
55+ leftMargin: leftMargin
56+ rightMargin: rightMargin
57+ }
58+ wrapMode: Text.Wrap
59+ text: title
60+ color: Theme.palette.normal.baseText
61+ font.pixelSize: units.gu(4)
62+ }
63+
64+ Item {
65+ id: contentHolder
66+ anchors {
67+ top: titleLabel.bottom
68+ left: parent.left
69+ right: parent.right
70+ bottom: backButton.top
71+ topMargin: units.gu(4)
72+ leftMargin: leftMargin
73+ rightMargin: rightMargin
74+ bottomMargin: buttonMargin
75+ }
76+ }
77+
78+ StackButton {
79+ id: backButton
80+ objectName: "backButton"
81+ width: buttonWidth
82+ anchors {
83+ left: parent.left
84+ bottom: parent.bottom
85+ leftMargin: buttonMargin
86+ bottomMargin: buttonMargin
87+ }
88+ z: 1
89+ text: i18n.tr("Back")
90+ visible: pageStack.depth > 1 && hasBackButton
91+ backArrow: true
92+
93+ onClicked: customBack ? backClicked() : pageStack.prev()
94+ }
95+
96+ Loader {
97+ id: forwardButton
98+ objectName: "forwardButton"
99+ width: buttonWidth
100+ anchors {
101+ right: parent.right
102+ bottom: parent.bottom
103+ rightMargin: buttonMargin
104+ bottomMargin: buttonMargin
105+ }
106+ z: 1
107+ }
108+}
qml/Wizard/Pages.qmlnew file+136
@@ -0,0 +1,136 @@
1+/*
2+ * Copyright (C) 2013 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.1
19+import Ubuntu.SystemSettings.SecurityPrivacy 1.0
20+import Wizard 0.1
21+import "../Components"
22+
23+Item {
24+ id: root
25+ objectName: "wizardPages"
26+ focus: true
27+
28+ // The background wallpaper to use
29+ property string background
30+
31+ signal quit()
32+
33+ // These should be set by a security page and we apply the settings when
34+ // the user exits the wizard.
35+ property int passwordMethod: UbuntuSecurityPrivacyPanel.Passcode
36+ property string password: ""
37+
38+ UbuntuSecurityPrivacyPanel {
39+ id: securityPrivacy
40+ objectName: "securityPrivacy"
41+ }
42+
43+ function quitWizard() {
44+ var errorMsg = securityPrivacy.setSecurity("", password, passwordMethod)
45+ if (errorMsg !== "") {
46+ // Ignore (but log) any errors, since we're past where the user set
47+ // the method. Worst case, we just leave the user with a swipe
48+ // security method and they fix it in the system settings.
49+ console.log("Error setting security method:", errorMsg)
50+ }
51+
52+ quit();
53+ }
54+
55+ MouseArea { // eat anything that gets past widgets
56+ anchors.fill: parent
57+ }
58+
59+ Image {
60+ id: image
61+ // Use x/y/height/width instead of anchors so that we don't adjust
62+ // the image when the OSK appears.
63+ x: 0
64+ y: 0
65+ height: root.height
66+ width: root.width
67+ sourceSize.height: height
68+ sourceSize.width: width
69+ source: root.background
70+ fillMode: Image.PreserveAspectCrop
71+ visible: status === Image.Ready
72+ }
73+
74+ PageList {
75+ id: pageList
76+ }
77+
78+ PageStack {
79+ id: pageStack
80+ objectName: "pageStack"
81+ anchors.fill: parent
82+
83+ function next() {
84+ // If we've opened any extra (non-main) pages, pop them before
85+ // continuing so back button returns to the previous main page.
86+ while (pageList.index < pageStack.depth - 1)
87+ pop()
88+ load(pageList.next())
89+ }
90+
91+ function prev() {
92+ if (pageList.index >= pageStack.depth - 1)
93+ pageList.prev() // update pageList.index, but not for extra pages
94+ pop()
95+ if (!currentPage || currentPage.opacity === 0) { // undo skipped pages
96+ prev()
97+ } else {
98+ currentPage.enabled = true
99+ }
100+ }
101+
102+ function load(path) {
103+ if (currentPage) {
104+ currentPage.enabled = false
105+ }
106+
107+ // First load it invisible, check that we should actually use
108+ // this page, and either skip it or continue.
109+ push(path, {"opacity": 0, "enabled": false})
110+
111+ // Check for immediate skip or not. We may have to wait for
112+ // skipValid to be assigned (see Connections object below)
113+ checkSkip()
114+ }
115+
116+ function checkSkip() {
117+ if (!currentPage) { // may have had a parse error
118+ next()
119+ } else if (currentPage.skipValid) {
120+ if (currentPage.skip) {
121+ next()
122+ } else {
123+ currentPage.opacity = 1
124+ currentPage.enabled = true
125+ }
126+ }
127+ }
128+
129+ Connections {
130+ target: pageStack.currentPage
131+ onSkipValidChanged: pageStack.checkSkip()
132+ }
133+
134+ Component.onCompleted: next()
135+ }
136+}
qml/Wizard/Pages/10-welcome.qmlnew file+99
@@ -0,0 +1,99 @@
1+/*
2+ * Copyright (C) 2013 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.1
19+import Ubuntu.Components.ListItems 0.1
20+import Ubuntu.SystemSettings.LanguagePlugin 1.0
21+import Wizard 0.1
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ objectName: "languagePage"
26+
27+ title: i18n.tr("Hi!")
28+ forwardButtonSourceComponent: forwardButton
29+
30+ UbuntuLanguagePlugin {
31+ id: plugin
32+ }
33+
34+ Column {
35+ id: column
36+ anchors.fill: content
37+ spacing: units.gu(1)
38+
39+ Label {
40+ id: label1
41+ anchors.left: parent.left
42+ anchors.right: parent.right
43+ wrapMode: Text.Wrap
44+ text: i18n.tr("Welcome to your Ubuntu phone.")
45+ }
46+
47+ Label {
48+ id: label2
49+ anchors.left: parent.left
50+ anchors.right: parent.right
51+ wrapMode: Text.Wrap
52+ text: i18n.tr("Let’s get started.")
53+ }
54+
55+ Item { // spacer
56+ height: units.gu(2)
57+ width: units.gu(1) // needed else it will be ignored
58+ }
59+
60+ ComboButton {
61+ id: combo
62+ objectName: "languageCombo"
63+ anchors.left: parent.left
64+ anchors.right: parent.right
65+ text: listview.currentItem.text
66+ onClicked: expanded = !expanded
67+ expandedHeight: column.height - combo.y
68+ UbuntuListView {
69+ id: listview
70+ model: plugin.languageNames
71+ currentIndex: plugin.currentLanguage
72+ delegate: Standard {
73+ objectName: "languageDelegate" + index
74+ text: modelData
75+ onClicked: {
76+ listview.currentIndex = index
77+ combo.expanded = false
78+ i18n.language = plugin.languageCodes[index]
79+ }
80+ }
81+ }
82+ }
83+ }
84+
85+ Component {
86+ id: forwardButton
87+ LocalComponents.StackButton {
88+ text: i18n.tr("Continue")
89+ onClicked: {
90+ if (plugin.currentLanguage !== listview.currentIndex) {
91+ plugin.currentLanguage = listview.currentIndex;
92+ System.updateSessionLanguage(plugin.languageCodes[listview.currentIndex]);
93+ i18n.language = i18n.language; // re-notify of change after above call (for qlocale change)
94+ }
95+ pageStack.next()
96+ }
97+ }
98+ }
99+}
qml/Wizard/Pages/20-sim.qmlnew file+73
@@ -0,0 +1,73 @@
1+/*
2+ * Copyright (C) 2013 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.0
18+import MeeGo.QOfono 0.2
19+import Ubuntu.Components 0.1
20+import ".." as LocalComponents
21+
22+LocalComponents.Page {
23+ objectName: "simPage"
24+
25+ title: i18n.tr("Add a SIM card and restart your device")
26+ forwardButtonSourceComponent: forwardButton
27+
28+ // No need for skipValid, since OfonoManager does everything synchronously
29+ skip: !manager.available || manager.modems.length === 0 || simManager0.present || simManager1.present
30+
31+ OfonoManager {
32+ id: manager
33+ }
34+
35+ // Ideally we would query the system more cleverly than hardcoding two
36+ // modems. But we don't yet have a more clever way. :(
37+ OfonoSimManager {
38+ id: simManager0
39+ modemPath: manager.modems.length >= 1 ? manager.modems[0] : ""
40+ }
41+
42+ OfonoSimManager {
43+ id: simManager1
44+ modemPath: manager.modems.length >= 2 ? manager.modems[1] : ""
45+ }
46+
47+ Column {
48+ anchors.fill: content
49+ spacing: units.gu(4)
50+
51+ Label {
52+ anchors.left: parent.left
53+ anchors.right: parent.right
54+ wrapMode: Text.Wrap
55+ text: i18n.tr("Without it, you won’t be able to make calls or use text messaging.")
56+ }
57+
58+ Image {
59+ id: image
60+ source: "data/meet_ubuntu_simcard@30.png"
61+ height: units.gu(6.5)
62+ width: units.gu(9)
63+ }
64+ }
65+
66+ Component {
67+ id: forwardButton
68+ LocalComponents.StackButton {
69+ text: i18n.tr("Skip")
70+ onClicked: pageStack.next()
71+ }
72+ }
73+}
qml/Wizard/Pages/30-passwd-type.qmlnew file+135
@@ -0,0 +1,135 @@
1+/*
2+ * Copyright (C) 2014 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.1
19+import Ubuntu.Components.ListItems 1.0
20+import Ubuntu.SystemSettings.SecurityPrivacy 1.0
21+import ".." as LocalComponents
22+
23+/**
24+ * One quirk with this page: we don't actually set the password. We avoid
25+ * doing it here because the user can come back to this page and change their
26+ * answer. We don't run as root, so if we did set the password immediately,
27+ * we'd need to prompt for their previous password when they came back and
28+ * changed their answer. Which is silly UX. So instead, we just keep track
29+ * of their choice and set the password at the end (see main.qml).
30+ * Setting the password shouldn't fail, since Ubuntu Touch has loose password
31+ * requirements, but we'll check what we can here. Ideally we'd be able to ask
32+ * the system if a password is legal without actually setting that password.
33+ */
34+
35+LocalComponents.Page {
36+ id: passwdPage
37+ objectName: "passwdPage"
38+
39+ title: i18n.tr("Lock security")
40+ forwardButtonSourceComponent: forwardButton
41+
42+ function indexToMethod(index) {
43+ if (index === 0)
44+ return UbuntuSecurityPrivacyPanel.Swipe
45+ else if (index === 1)
46+ return UbuntuSecurityPrivacyPanel.Passcode
47+ else
48+ return UbuntuSecurityPrivacyPanel.Passphrase
49+ }
50+
51+ function methodToIndex(method) {
52+ if (method === UbuntuSecurityPrivacyPanel.Swipe)
53+ return 0
54+ else if (method === UbuntuSecurityPrivacyPanel.Passcode)
55+ return 1
56+ else
57+ return 2
58+ }
59+
60+ Connections {
61+ target: root
62+ onPasswordMethodChanged: selector.selectedIndex = methodToIndex(root.passwordMethod)
63+ }
64+
65+ Column {
66+ id: column
67+ anchors.fill: content
68+ spacing: units.gu(4)
69+
70+ Label {
71+ anchors.left: parent.left
72+ anchors.right: parent.right
73+ wrapMode: Text.Wrap
74+ text: i18n.tr("Please select how you’d like to unlock your phone.")
75+ }
76+
77+ ItemSelector {
78+ id: selector
79+ expanded: true
80+ anchors.left: parent.left
81+ anchors.right: parent.right
82+ property color originalBackground
83+
84+ model: ["", "", ""] // otherwise the delegate will show the text itself and we only want subText
85+
86+ selectedIndex: methodToIndex(root.passwordMethod)
87+
88+ delegate: OptionSelectorDelegate {
89+ objectName: "passwdDelegate" + index
90+
91+ // use subText because we want the text to be small, and we have no other way to control it
92+ subText: {
93+ var method = indexToMethod(index)
94+ var name = ""
95+ var desc = ""
96+ if (method === UbuntuSecurityPrivacyPanel.Swipe) {
97+ name = i18n.tr("Swipe")
98+ desc = i18n.tr("No security")
99+ } else if (method === UbuntuSecurityPrivacyPanel.Passcode) {
100+ name = i18n.tr("Passcode")
101+ desc = i18n.tr("4 digits only")
102+ } else {
103+ name = i18n.tr("Passphrase")
104+ desc = i18n.tr("Numbers and letters")
105+ }
106+ return "<b>%1</b> (%2)".arg(name).arg(desc)
107+ }
108+ }
109+
110+ style: Item {}
111+
112+ Component.onCompleted: {
113+ // A visible selected background looks bad in ListItem widgets with our theme
114+ originalBackground = Theme.palette.selected.background
115+ Theme.palette.selected.background = "transparent"
116+ }
117+
118+ Component.onDestruction: {
119+ // Restore original theme background
120+ Theme.palette.selected.background = originalBackground
121+ }
122+ }
123+ }
124+
125+ Component {
126+ id: forwardButton
127+ LocalComponents.StackButton {
128+ text: i18n.tr("Continue")
129+ onClicked: {
130+ root.passwordMethod = indexToMethod(selector.selectedIndex)
131+ pageStack.load(Qt.resolvedUrl("passwd-set.qml"))
132+ }
133+ }
134+ }
135+}
qml/Wizard/Pages/40-wifi.qmlnew file+201
@@ -0,0 +1,201 @@
1+/*
2+ * Copyright (C) 2013 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.0
18+import QMenuModel 0.1 as QMenuModel
19+import Ubuntu.Components 0.1
20+import Ubuntu.Components.ListItems 0.1 as ListItem
21+import Ubuntu.Settings.Menus 0.1 as Menus
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ id: wifiPage
26+ objectName: "wifiPage"
27+
28+ title: i18n.tr("Connect to Wi‑Fi")
29+ forwardButtonSourceComponent: forwardButton
30+
31+ readonly property bool connected: mainMenu.connectedAPs === 1
32+
33+ function getExtendedProperty(object, propertyName, defaultValue) {
34+ if (object && object.hasOwnProperty(propertyName)) {
35+ return object[propertyName];
36+ }
37+ return defaultValue;
38+ }
39+
40+ QMenuModel.UnityMenuModel {
41+ id: menuModel
42+ busName: "com.canonical.indicator.network"
43+ actions: { "indicator": "/com/canonical/indicator/network" }
44+ menuObjectPath: "/com/canonical/indicator/network/phone_wifi_settings"
45+ }
46+
47+ Component {
48+ id: accessPointComponent
49+ ListItem.Standard {
50+ id: accessPoint
51+ objectName: "accessPoint"
52+
53+ property QtObject menuData: null
54+ property var unityMenuModel: menuModel
55+ property var extendedData: menuData && menuData.ext || undefined
56+ property var strengthAction: QMenuModel.UnityMenuAction {
57+ model: unityMenuModel
58+ index: menuIndex
59+ name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
60+ }
61+ property bool checked: menuData && menuData.isToggled || false
62+ property bool secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
63+ property bool adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
64+ property int signalStrength: strengthAction.valid ? strengthAction.state : 0
65+ property int menuIndex: -1
66+
67+ function loadAttributes() {
68+ if (!unityMenuModel || menuIndex == -1) return;
69+ unityMenuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
70+ 'x-canonical-wifi-ap-is-secure': 'bool',
71+ 'x-canonical-wifi-ap-strength-action': 'string'});
72+ }
73+
74+ signal activate()
75+
76+ text: menuData && menuData.label || ""
77+ enabled: menuData && menuData.sensitive || false
78+ iconName: {
79+ var imageName = "nm-signal-100";
80+
81+ if (adHoc) {
82+ imageName = "nm-adhoc";
83+ } else if (signalStrength == 0) {
84+ imageName = "nm-signal-00";
85+ } else if (signalStrength <= 25) {
86+ imageName = "nm-signal-25";
87+ } else if (signalStrength <= 50) {
88+ imageName = "nm-signal-50";
89+ } else if (signalStrength <= 75) {
90+ imageName = "nm-signal-75";
91+ }
92+
93+ if (secure) {
94+ imageName += "-secure";
95+ }
96+ return imageName;
97+ }
98+ iconFrame: false
99+ control: CheckBox {
100+ id: checkBoxActive
101+
102+ onClicked: {
103+ accessPoint.activate();
104+ }
105+ }
106+ style: Rectangle {
107+ color: "#4c000000"
108+ }
109+
110+ Component.onCompleted: {
111+ loadAttributes();
112+ }
113+ onUnityMenuModelChanged: {
114+ loadAttributes();
115+ }
116+ onMenuIndexChanged: {
117+ loadAttributes();
118+ }
119+ onCheckedChanged: {
120+ // Can't rely on binding. Checked is assigned on click.
121+ checkBoxActive.checked = checked;
122+ if (checked) {
123+ mainMenu.connectedAPs++
124+ } else {
125+ mainMenu.connectedAPs--
126+ }
127+ }
128+ onActivate: unityMenuModel.activate(menuIndex);
129+ }
130+ }
131+
132+ Column {
133+ id: column
134+ spacing: units.gu(2)
135+ anchors.top: content.top
136+ anchors.bottom: content.bottom
137+ anchors.left: wifiPage.left
138+ anchors.right: wifiPage.right
139+
140+ Label {
141+ id: label
142+ anchors.left: parent.left
143+ anchors.leftMargin: leftMargin
144+ anchors.right: parent.right
145+ anchors.rightMargin: rightMargin
146+ fontSize: "small"
147+ text: mainMenu.count > 0 ? i18n.tr("Available networks…")
148+ : i18n.tr("No available networks.")
149+ }
150+
151+ Flickable {
152+ anchors.left: parent.left
153+ anchors.right: parent.right
154+ height: column.height - label.height - column.spacing
155+ contentHeight: contentItem.childrenRect.height
156+ clip: true
157+ flickDeceleration: 1500 * units.gridUnit / 8
158+ maximumFlickVelocity: 2500 * units.gridUnit / 8
159+ boundsBehavior: (contentHeight > height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
160+
161+ Column {
162+ anchors.left: parent.left
163+ anchors.right: parent.right
164+
165+ Repeater {
166+ id: mainMenu
167+
168+ // FIXME Check connection better https://bugs.launchpad.net/indicator-network/+bug/1349371
169+ property int connectedAPs: 0
170+
171+ model: menuModel
172+
173+ delegate: Loader {
174+ id: loader
175+
176+ readonly property bool isAccessPoint: model.type === "unity.widgets.systemsettings.tablet.accesspoint"
177+
178+ anchors.left: parent.left
179+ anchors.right: parent.right
180+ height: isAccessPoint ? units.gu(6) : 0
181+ asynchronous: true
182+ sourceComponent: isAccessPoint ? accessPointComponent : null
183+
184+ onLoaded: {
185+ item.menuData = Qt.binding(function() { return model; });
186+ item.menuIndex = Qt.binding(function() { return index; });
187+ }
188+ }
189+ }
190+ }
191+ }
192+ }
193+
194+ Component {
195+ id: forwardButton
196+ LocalComponents.StackButton {
197+ text: (connected || mainMenu.count === 0) ? i18n.tr("Continue") : i18n.tr("Skip")
198+ onClicked: pageStack.next()
199+ }
200+ }
201+}
qml/Wizard/Pages/50-location.qmlnew file+150
@@ -0,0 +1,150 @@
1+/*
2+ * Copyright (C) 2013,2014 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 AccountsService 0.1
19+import QMenuModel 0.1 as QMenuModel
20+import Qt.labs.folderlistmodel 2.1
21+import Ubuntu.Components 1.1
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ objectName: "locationPage"
26+
27+ title: i18n.tr("Location")
28+ forwardButtonSourceComponent: forwardButton
29+
30+ property bool pathSet: AccountsService.hereLicensePathValid
31+ skipValid: pathSet && (AccountsService.hereLicensePath === "" || termsModel.count > 0)
32+ skip: skipValid && (AccountsService.hereLicensePath === "" || termsModel.count === 2) // no files but . and ..
33+
34+ FolderListModel {
35+ id: termsModel
36+ folder: AccountsService.hereLicensePath
37+ nameFilters: ["*.html"]
38+ showOnlyReadable: true
39+ showDotAndDotDot: true // so that count == 0 means we're not done scanning yet
40+ }
41+
42+ QMenuModel.QDBusActionGroup {
43+ id: locationActionGroup
44+ objectName: "locationActionGroup"
45+ busType: QMenuModel.DBus.SessionBus
46+ busName: "com.canonical.indicator.location"
47+ objectPath: "/com/canonical/indicator/location"
48+ property variant location: action("location-detection-enabled")
49+ property variant gps: action("gps-detection-enabled")
50+ Component.onCompleted: start()
51+ }
52+
53+ Column {
54+ id: column
55+ anchors.fill: content
56+ spacing: units.gu(3)
57+
58+ Label {
59+ anchors.left: parent.left
60+ anchors.right: parent.right
61+ wrapMode: Text.Wrap
62+ text: i18n.tr("Let the phone detect your location:")
63+ }
64+
65+ LocalComponents.CheckableSetting {
66+ id: gpsCheck
67+ objectName: "gpsCheck"
68+ showDivider: false
69+ text: i18n.tr("Using GPS only (less accurate)")
70+ onTriggered: {
71+ gpsCheck.checked = true;
72+ hereCheck.checked = false;
73+ nopeCheck.checked = false;
74+ }
75+ }
76+
77+ Column {
78+ anchors.left: parent.left
79+ anchors.right: parent.right
80+ height: childrenRect.height
81+
82+ LocalComponents.CheckableSetting {
83+ id: hereCheck
84+ objectName: "hereCheck"
85+ showDivider: false
86+ text: i18n.tr("Using GPS, anonymized Wi-Fi and cellular network info (recommended)")
87+ checked: true
88+ onTriggered: {
89+ gpsCheck.checked = false;
90+ hereCheck.checked = true;
91+ nopeCheck.checked = false;
92+ }
93+ }
94+
95+ Label {
96+ objectName: "hereTermsLink"
97+ anchors.left: parent.left
98+ anchors.leftMargin: hereCheck.labelOffset
99+ anchors.right: parent.right
100+ wrapMode: Text.Wrap
101+ linkColor: Theme.palette.normal.foregroundText
102+ // TRANSLATORS: HERE is a trademark for Nokia's location service, you probably shouldn't translate it
103+ text: i18n.tr("By selecting this option you agree to the Nokia HERE <a href='#'>terms and conditions</a>.")
104+ onLinkActivated: pageStack.load(Qt.resolvedUrl("here-terms.qml"))
105+ }
106+ }
107+
108+ LocalComponents.CheckableSetting {
109+ id: nopeCheck
110+ objectName: "nopeCheck"
111+ showDivider: false
112+ text: i18n.tr("Not at all")
113+ onTriggered: {
114+ gpsCheck.checked = false;
115+ hereCheck.checked = false;
116+ nopeCheck.checked = true;
117+ }
118+ }
119+
120+ Label {
121+ anchors.left: parent.left
122+ anchors.right: parent.right
123+ wrapMode: Text.Wrap
124+ text: i18n.tr("You can change your mind later in <b>System Settings</b>.")
125+ }
126+ }
127+
128+ Component {
129+ id: forwardButton
130+ LocalComponents.StackButton {
131+ text: i18n.tr("Continue")
132+ onClicked: {
133+ var locationOn = gpsCheck.checked || hereCheck.checked;
134+ var gpsOn = gpsCheck.checked || hereCheck.checked;
135+ var hereOn = hereCheck.checked;
136+
137+ // location service doesn't currently listen to updateState
138+ // requests, so we activate the actions if needed.
139+ if (locationActionGroup.location.state != locationOn) {
140+ locationActionGroup.location.activate();
141+ }
142+ if (locationActionGroup.gps.state != gpsOn) {
143+ locationActionGroup.gps.activate();
144+ }
145+ AccountsService.hereEnabled = hereOn;
146+ pageStack.next()
147+ }
148+ }
149+ }
150+}
qml/Wizard/Pages/60-reporting.qmlnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 2013,2014 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.0
18+import Ubuntu.Components 0.1
19+import ".." as LocalComponents
20+
21+LocalComponents.Page {
22+ objectName: "reportingPage"
23+
24+ title: i18n.tr("Improving your experience")
25+ forwardButtonSourceComponent: forwardButton
26+
27+ Column {
28+ id: column
29+ anchors.fill: content
30+ spacing: units.gu(2)
31+
32+ Label {
33+ anchors.left: parent.left
34+ anchors.right: parent.right
35+ wrapMode: Text.Wrap
36+ text: i18n.tr("Your phone is set up to automatically report errors to Canonical and its partners, the makers of the operating system.")
37+ }
38+
39+ Label {
40+ anchors.left: parent.left
41+ anchors.right: parent.right
42+ wrapMode: Text.Wrap
43+ text: i18n.tr("This can be disabled in <b>System Settings</b> under <b>Security &amp; Privacy</b>")
44+ }
45+ }
46+
47+ Component {
48+ id: forwardButton
49+ LocalComponents.StackButton {
50+ text: i18n.tr("Continue")
51+ onClicked: pageStack.next()
52+ }
53+ }
54+}
qml/Wizard/Pages/80-finished.qmlnew file+57
@@ -0,0 +1,57 @@
1+/*
2+ * Copyright (C) 2013,2014 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.0
18+import Ubuntu.Components 0.1
19+import ".." as LocalComponents
20+
21+LocalComponents.Page {
22+ objectName: "finishedPage"
23+
24+ title: i18n.tr("All done")
25+ forwardButtonSourceComponent: forwardButton
26+ hasBackButton: false
27+
28+ Column {
29+ id: column
30+ anchors.fill: content
31+ spacing: units.gu(1)
32+
33+ Label {
34+ anchors.left: parent.left
35+ anchors.right: parent.right
36+ wrapMode: Text.Wrap
37+ fontSize: "large"
38+ font.bold: true
39+ text: i18n.tr("Nice work!")
40+ }
41+
42+ Label {
43+ anchors.left: parent.left
44+ anchors.right: parent.right
45+ wrapMode: Text.Wrap
46+ text: i18n.tr("Your phone is now ready to use.")
47+ }
48+ }
49+
50+ Component {
51+ id: forwardButton
52+ LocalComponents.StackButton {
53+ text: i18n.tr("Finish")
54+ onClicked: root.quitWizard()
55+ }
56+ }
57+}
qml/Wizard/Pages/data/meet_ubuntu_simcard@30.pngnew file

Binary file not shown.

qml/Wizard/Pages/here-terms.qmlnew file+121
@@ -0,0 +1,121 @@
1+/*
2+ * Copyright (C) 2014 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 AccountsService 0.1
19+import Qt.labs.folderlistmodel 2.1
20+import Ubuntu.Components 1.1
21+import Ubuntu.Web 0.2
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ objectName: "hereTermsPage"
26+
27+ title: i18n.tr("Terms & Conditions")
28+ customBack: true
29+
30+ FolderListModel {
31+ id: termsModel
32+ folder: AccountsService.hereLicensePath
33+ nameFilters: ["*.html"]
34+ showDirs: false
35+ showOnlyReadable: true
36+ onCountChanged: loadFileContent()
37+ }
38+
39+ function makeFileName(lang, country) {
40+ return lang + "_" + country + ".html"
41+ }
42+
43+ function defaultCountryForLanguage(lang) {
44+ if (lang === "da") return "DK"
45+ if (lang === "en") return "US"
46+ if (lang === "ko") return "KR"
47+ if (lang === "zh") return "CN"
48+ return lang.toUpperCase()
49+ }
50+
51+ function determineFileName() {
52+ var codes = i18n.language.split(".")[0].split("_")
53+ var defaultCountry = defaultCountryForLanguage(codes[0])
54+ if (codes.count === 1)
55+ codes = [codes[0], defaultCountry]
56+ var perfectMatch = makeFileName(codes[0], codes[1])
57+ var nearMatch = makeFileName(codes[0], defaultCountry)
58+ var nearMatchExists = false
59+
60+ for (var i = 0; i < termsModel.count; i++) {
61+ var fileName = termsModel.get(i, "fileName")
62+ if (fileName == perfectMatch) {
63+ return perfectMatch
64+ } else if (fileName == nearMatch) {
65+ nearMatchExists = true
66+ }
67+ }
68+
69+ if (nearMatchExists) {
70+ return nearMatch
71+ } else {
72+ return makeFileName("en", "US")
73+ }
74+ }
75+
76+ function loadFileContent() {
77+ var xhr = new XMLHttpRequest
78+ xhr.open("GET", AccountsService.hereLicensePath + "/" + determineFileName())
79+ xhr.onreadystatechange = function() {
80+ if (xhr.readyState == XMLHttpRequest.DONE) {
81+ termsLabel.text = xhr.responseText
82+ }
83+ }
84+ xhr.send()
85+ }
86+
87+ onBackClicked: {
88+ if (webview.visible) {
89+ termsLabel.visible = true
90+ } else {
91+ pageStack.prev()
92+ }
93+ }
94+
95+ Column {
96+ id: column
97+ anchors.fill: content
98+
99+ Label {
100+ id: termsLabel
101+ objectName: "termsLabel"
102+ anchors.left: parent.left
103+ anchors.right: parent.right
104+ wrapMode: Text.Wrap
105+ linkColor: Theme.palette.normal.foregroundText
106+ onLinkActivated: {
107+ webview.url = link
108+ termsLabel.visible = false
109+ }
110+ }
111+
112+ WebView {
113+ id: webview
114+ objectName: "webview"
115+ anchors.left: parent.left
116+ anchors.right: parent.right
117+ height: parent.height
118+ visible: !termsLabel.visible
119+ }
120+ }
121+}
qml/Wizard/Pages/passwd-confirm.qmlnew file+86
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (C) 2014 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.1
19+import Ubuntu.SystemSettings.SecurityPrivacy 1.0
20+import ".." as LocalComponents
21+import "../../Components" as UnityComponents
22+
23+/**
24+ * See the main passwd-type page for an explanation of why we don't actually
25+ * directly set the password here.
26+ */
27+
28+LocalComponents.Page {
29+ id: passwdConfirmPage
30+ objectName: "passwdConfirmPage"
31+ forwardButtonSourceComponent: forwardButton
32+
33+ skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
34+
35+ // If we are entering this page, clear any saved password and get focus
36+ onEnabledChanged: if (enabled) lockscreen.clear(false)
37+
38+ UnityComponents.Lockscreen {
39+ id: lockscreen
40+ anchors {
41+ fill: parent
42+ topMargin: topMargin
43+ leftMargin: leftMargin
44+ rightMargin: rightMargin
45+ bottomMargin: buttonMargin
46+ }
47+
48+ infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
49+ i18n.tr("Confirm passphrase") :
50+ i18n.tr("Confirm passcode")
51+
52+ errorText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
53+ i18n.tr("Sorry, incorrect passphrase.") + "\n" + i18n.tr("Please try again.") :
54+ i18n.tr("Sorry, incorrect passcode.") + "\n" + i18n.tr("Please try again.")
55+
56+ showEmergencyCallButton: false
57+ showCancelButton: false
58+ alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
59+ minPinLength: 4
60+ maxPinLength: 4
61+
62+ onEntered: {
63+ if (passphrase === root.password) {
64+ confirmTimer.start()
65+ } else {
66+ clear(true)
67+ }
68+ }
69+
70+ Timer {
71+ id: confirmTimer
72+ interval: UbuntuAnimation.SnapDuration
73+ onTriggered: pageStack.next()
74+ }
75+ }
76+
77+ Component {
78+ id: forwardButton
79+ LocalComponents.StackButton {
80+ visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
81+ enabled: root.password === lockscreen.passphrase
82+ text: i18n.tr("Continue")
83+ onClicked: pageStack.next()
84+ }
85+ }
86+}
qml/Wizard/Pages/passwd-set.qmlnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (C) 2014 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.1
19+import Ubuntu.SystemSettings.SecurityPrivacy 1.0
20+import ".." as LocalComponents
21+import "../../Components" as UnityComponents
22+
23+/**
24+ * See the main passwd-type page for an explanation of why we don't actually
25+ * directly set the password here.
26+ */
27+
28+LocalComponents.Page {
29+ id: passwdSetPage
30+ objectName: "passwdSetPage"
31+ forwardButtonSourceComponent: forwardButton
32+
33+ skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
34+
35+ // If we are entering this page, clear any saved password and get focus
36+ onEnabledChanged: if (enabled) lockscreen.clear(false)
37+
38+ function confirm() {
39+ root.password = lockscreen.passphrase;
40+ confirmTimer.start()
41+ }
42+
43+ Timer {
44+ id: confirmTimer
45+ interval: UbuntuAnimation.SnapDuration
46+ onTriggered: pageStack.load(Qt.resolvedUrl("passwd-confirm.qml"));
47+ }
48+
49+ UnityComponents.Lockscreen {
50+ id: lockscreen
51+ anchors {
52+ fill: parent
53+ topMargin: topMargin
54+ leftMargin: leftMargin
55+ rightMargin: rightMargin
56+ bottomMargin: buttonMargin
57+ }
58+
59+ infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
60+ i18n.tr("Enter passphrase") :
61+ i18n.tr("Choose your passcode")
62+
63+ // Note that the number four comes from PAM settings,
64+ // which we don't have a good way to interrogate. We
65+ // only do this matching instead of PAM because we want
66+ // to set the password via PAM in a different place
67+ // than this page. See comments at top of passwd-type file.
68+ errorText: i18n.tr("Passphrase must be 4 characters long")
69+
70+ showEmergencyCallButton: false
71+ showCancelButton: false
72+ alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
73+ minPinLength: 4
74+ maxPinLength: 4
75+
76+ onEntered: {
77+ if (passphrase.length >= 4) {
78+ passwdSetPage.confirm();
79+ } else {
80+ lockscreen.clear(true)
81+ }
82+ }
83+ }
84+
85+ Component {
86+ id: forwardButton
87+ LocalComponents.StackButton {
88+ visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
89+ enabled: lockscreen.passphrase.length >= 4
90+ text: i18n.tr("Continue")
91+ onClicked: passwdSetPage.confirm()
92+ }
93+ }
94+}
qml/Wizard/StackButton.qmlnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (C) 2014 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.1
19+
20+AbstractButton {
21+ id: stackButton
22+
23+ property string text
24+
25+ property bool backArrow: false
26+
27+ width: label.width
28+ height: label.height + units.gu(4)
29+
30+ Label {
31+ id: label
32+ anchors.verticalCenter: parent.verticalCenter
33+ anchors.left: parent.left
34+ anchors.right: parent.right
35+ color: enabled ? Theme.palette.selected.backgroundText : Qt.darker(Theme.palette.selected.backgroundText, 1.5)
36+ text: {
37+ if (backArrow) {
38+ // Translators: This is the arrow for "Back" buttons
39+ return i18n.tr("〈 %1".arg(stackButton.text))
40+ } else {
41+ // Translators: This is the arrow for "Forward" buttons
42+ return i18n.tr("%1 〉".arg(stackButton.text))
43+ }
44+ }
45+ horizontalAlignment: backArrow ? Text.AlignLeft : Text.AlignRight
46+ }
47+}
qml/Wizard/Wizard.qmlnew file+55
@@ -0,0 +1,55 @@
1+/*
2+ * Copyright (C) 2013 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.1
19+import Wizard 0.1
20+import "../Components"
21+
22+Showable {
23+ id: root
24+
25+ // The background wallpaper to use
26+ property string background
27+
28+ readonly property alias active: loader.active
29+
30+ hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
31+
32+ onRequiredChanged: {
33+ if (!required) {
34+ System.wizardEnabled = false;
35+ }
36+ }
37+
38+ Loader {
39+ id: loader
40+ anchors.fill: parent
41+ active: System.wizardEnabled
42+ source: "Pages.qml"
43+
44+ Binding {
45+ target: loader.item
46+ property: "background"
47+ value: root.background
48+ }
49+
50+ Connections {
51+ target: loader.item
52+ onQuit: root.hide()
53+ }
54+ }
55+}
tests/mocks/AccountsService/AccountsService.cpp+37−1
@@ -27,7 +27,9 @@ AccountsService::AccountsService(QObject* parent)
27 m_backgroundFile(qmlDirectory() + "graphics/phone_background.jpg"),
27 m_backgroundFile(qmlDirectory() + "graphics/phone_background.jpg"),
28 m_statsWelcomeScreen(true),
28 m_statsWelcomeScreen(true),
29 m_failedLogins(0),
29 m_failedLogins(0),
30− m_demoEdges(false)
30+ m_demoEdges(false),
31+ m_hereEnabled(false),
32+ m_hereLicensePath("")
31{
33{
32}
34}
33
35
@@ -116,3 +118,37 @@ void AccountsService::setFailedLogins(uint failedLogins)
116 m_failedLogins = failedLogins;
118 m_failedLogins = failedLogins;
117 failedLoginsChanged();
119 failedLoginsChanged();
118}
120}
121+
122+bool AccountsService::hereEnabled() const
123+{
124+ return m_hereEnabled;
125+}
126+
127+void AccountsService::setHereEnabled(bool enabled)
128+{
129+ m_hereEnabled = enabled;
130+ hereEnabledChanged();
131+}
132+
133+QString AccountsService::hereLicensePath() const
134+{
135+ return m_hereLicensePath;
136+}
137+
138+void AccountsService::setHereLicensePath(const QString &path)
139+{
140+ // Path should always be valid (this code is all synchronous)
141+ if (path == " ") {
142+ m_hereLicensePath = QString::null;
143+ } else if (path.isNull()) { // because qml collapses null and empty
144+ m_hereLicensePath = "";
145+ } else {
146+ m_hereLicensePath = path;
147+ }
148+ hereLicensePathChanged();
149+}
150+
151+bool AccountsService::hereLicensePathValid() const
152+{
153+ return !m_hereLicensePath.isNull();
154+}
tests/mocks/AccountsService/AccountsService.h+20
@@ -59,6 +59,17 @@ class AccountsService: public QObject
59 READ failedLogins
59 READ failedLogins
60 WRITE setFailedLogins
60 WRITE setFailedLogins
61 NOTIFY failedLoginsChanged)
61 NOTIFY failedLoginsChanged)
62+ Q_PROPERTY(bool hereEnabled
63+ READ hereEnabled
64+ WRITE setHereEnabled
65+ NOTIFY hereEnabledChanged)
66+ Q_PROPERTY(QString hereLicensePath
67+ READ hereLicensePath
68+ WRITE setHereLicensePath // only available in mock
69+ NOTIFY hereLicensePathChanged)
70+ Q_PROPERTY(bool hereLicensePathValid // qml sees a null string as "", so we use proxy setting for that
71+ READ hereLicensePathValid
72+ NOTIFY hereLicensePathChanged)
62
73
63public:
74public:
64 enum PasswordDisplayHint {
75 enum PasswordDisplayHint {
@@ -83,6 +94,11 @@ public:
83 PasswordDisplayHint passwordDisplayHint() const;
94 PasswordDisplayHint passwordDisplayHint() const;
84 uint failedLogins() const;
95 uint failedLogins() const;
85 void setFailedLogins(uint failedLogins);
96 void setFailedLogins(uint failedLogins);
97+ bool hereEnabled() const;
98+ void setHereEnabled(bool enabled);
99+ QString hereLicensePath() const;
100+ void setHereLicensePath(const QString &path);
101+ bool hereLicensePathValid() const;
86
102
87Q_SIGNALS:
103Q_SIGNALS:
88 void userChanged();
104 void userChanged();
@@ -93,6 +109,8 @@ Q_SIGNALS:
93 void statsWelcomeScreenChanged();
109 void statsWelcomeScreenChanged();
94 void passwordDisplayHintChanged();
110 void passwordDisplayHintChanged();
95 void failedLoginsChanged();
111 void failedLoginsChanged();
112+ void hereEnabledChanged();
113+ void hereLicensePathChanged();
96
114
97private:
115private:
98 bool m_enableLauncherWhileLocked;
116 bool m_enableLauncherWhileLocked;
@@ -102,6 +120,8 @@ private:
102 bool m_statsWelcomeScreen;
120 bool m_statsWelcomeScreen;
103 uint m_failedLogins;
121 uint m_failedLogins;
104 bool m_demoEdges;
122 bool m_demoEdges;
123+ bool m_hereEnabled;
124+ QString m_hereLicensePath;
105};
125};
106
126
107#endif
127#endif
tests/mocks/CMakeLists.txt+2
@@ -32,11 +32,13 @@ add_subdirectory(AccountsService)
32add_subdirectory(GSettings.1.0)
32add_subdirectory(GSettings.1.0)
33add_subdirectory(libusermetrics)
33add_subdirectory(libusermetrics)
34add_subdirectory(LightDM)
34add_subdirectory(LightDM)
35+add_subdirectory(MeeGo)
35add_subdirectory(Powerd)
36add_subdirectory(Powerd)
36add_subdirectory(QMenuModel)
37add_subdirectory(QMenuModel)
37add_subdirectory(Ubuntu)
38add_subdirectory(Ubuntu)
38add_subdirectory(Unity)
39add_subdirectory(Unity)
39add_subdirectory(QtMultimedia)
40add_subdirectory(QtMultimedia)
41+add_subdirectory(Wizard)
40
42
41install(
43install(
42 DIRECTORY data
44 DIRECTORY data
tests/mocks/MeeGo/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(QOfono)
tests/mocks/MeeGo/QOfono/CMakeLists.txtnew file+10
@@ -0,0 +1,10 @@
1+set(MOCK_QOFONO_SOURCES
2+ plugin.cpp
3+ MockQOfono.cpp
4+)
5+
6+add_library(MockQOfono MODULE ${MOCK_QOFONO_SOURCES})
7+
8+qt5_use_modules(MockQOfono Qml Quick Core)
9+
10+add_unity8_mock(MeeGo.QOfono 0.2 MeeGo/QOfono TARGETS MockQOfono)
tests/mocks/MeeGo/QOfono/MockOfonoManager.qmlnew file+23
@@ -0,0 +1,23 @@
1+/*
2+ * Copyright (C) 2014 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 MeeGo.QOfono 0.2
19+
20+Item {
21+ readonly property var modems: MockQOfono.modems
22+ readonly property bool available: MockQOfono.available
23+}
tests/mocks/MeeGo/QOfono/MockOfonoSimManager.qmlnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 2014 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 MeeGo.QOfono 0.2
19+
20+Item {
21+ id: simManager
22+
23+ property string modemPath
24+ readonly property alias present: d.present
25+
26+ QtObject {
27+ id: d
28+
29+ property bool present: false
30+
31+ function updatePresence() {
32+ d.present = MockQOfono.isModemPresent(simManager.modemPath)
33+ }
34+ }
35+
36+ onModemPathChanged: d.updatePresence()
37+
38+ Connections {
39+ target: MockQOfono
40+ onModemsChanged: d.updatePresence()
41+ }
42+}
tests/mocks/MeeGo/QOfono/MockQOfono.cppnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 2014 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+#include "MockQOfono.h"
18+
19+MockQOfono::MockQOfono(QObject *parent)
20+ : QObject(parent),
21+ m_available(false),
22+ m_modems()
23+{
24+}
25+
26+bool MockQOfono::available() const
27+{
28+ return m_available;
29+}
30+
31+void MockQOfono::setAvailable(bool available)
32+{
33+ m_available = available;
34+ Q_EMIT availableChanged();
35+}
36+
37+QStringList MockQOfono::modems() const
38+{
39+ return m_modems.keys();
40+}
41+
42+void MockQOfono::setModems(const QStringList &modems, const QList<bool> &present)
43+{
44+ m_modems.clear();
45+ for (int i = 0; i < modems.length(); i++) {
46+ m_modems[modems[i]] = present[i];
47+ }
48+ Q_EMIT modemsChanged();
49+}
50+
51+bool MockQOfono::isModemPresent(const QString &modem)
52+{
53+ return m_modems.value(modem, false);
54+}
tests/mocks/MeeGo/QOfono/MockQOfono.hnew file+52
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (C) 2014 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+// This class just exists as a backend for the instantiable Qml objects to pull
18+// from. It exists only for this mock plugin.
19+
20+#ifndef MOCK_QOFONO_H
21+#define MOCK_QOFONO_H
22+
23+#include <QObject>
24+#include <QMap>
25+#include <QStringList>
26+
27+class MockQOfono : public QObject
28+{
29+ Q_OBJECT
30+ Q_PROPERTY(bool available READ available WRITE setAvailable NOTIFY availableChanged)
31+ Q_PROPERTY(QStringList modems READ modems NOTIFY modemsChanged)
32+
33+public:
34+ explicit MockQOfono(QObject *parent = 0);
35+
36+ bool available() const;
37+ void setAvailable(bool available);
38+ QStringList modems() const;
39+
40+ Q_INVOKABLE void setModems(const QStringList &modems, const QList<bool> &present);
41+ Q_INVOKABLE bool isModemPresent(const QString &modem);
42+
43+Q_SIGNALS:
44+ void availableChanged();
45+ void modemsChanged();
46+
47+private:
48+ bool m_available;
49+ QMap<QString, bool> m_modems;
50+};
51+
52+#endif // MOCK_QOFONO_H
tests/mocks/MeeGo/QOfono/plugin.cppnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2014 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+#include "plugin.h"
18+#include "MockQOfono.h"
19+
20+#include <QtQml>
21+
22+static QObject *mock_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
23+{
24+ Q_UNUSED(engine)
25+ Q_UNUSED(scriptEngine)
26+ return new MockQOfono();
27+}
28+
29+void BackendPlugin::registerTypes(const char *uri)
30+{
31+ Q_ASSERT(uri == QLatin1String("MeeGo.QOfono"));
32+ qmlRegisterSingletonType<MockQOfono>(uri, 0, 2, "MockQOfono", mock_provider); // just for mock
33+}
tests/mocks/MeeGo/QOfono/plugin.hnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2014 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+#ifndef MOCK_QOFONO_PLUGIN_H
18+#define MOCK_QOFONO_PLUGIN_H
19+
20+#include <QQmlExtensionPlugin>
21+
22+class BackendPlugin : public QQmlExtensionPlugin
23+{
24+ Q_OBJECT
25+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26+
27+public:
28+ void registerTypes(const char *uri);
29+};
30+
31+#endif // MOCK_QOFONO_PLUGIN_H
tests/mocks/MeeGo/QOfono/qmldirnew file+4
@@ -0,0 +1,4 @@
1+module MeeGo.QOfono
2+plugin MockQOfono
3+OfonoManager 0.2 MockOfonoManager.qml
4+OfonoSimManager 0.2 MockOfonoSimManager.qml
tests/mocks/QMenuModel/CMakeLists.txt+1
@@ -5,6 +5,7 @@ include_directories(
5
5
6set(QMenuModelQml_SOURCES
6set(QMenuModelQml_SOURCES
7 actionstateparser.cpp
7 actionstateparser.cpp
8+ dbus-enums.h
8 plugin.cpp
9 plugin.cpp
9 unitymenumodel.cpp
10 unitymenumodel.cpp
10)
11)
tests/mocks/QMenuModel/QDBusActionGroup.qml+12
@@ -21,6 +21,7 @@ import QtQuick 2.0
21import Ubuntu.Settings.Menus 0.1 as Menus
21import Ubuntu.Settings.Menus 0.1 as Menus
22
22
23QtObject {
23QtObject {
24+ id: actionGroup
24 property int busType
25 property int busType
25 property string busName
26 property string busName
26 property string objectPath
27 property string objectPath
@@ -78,6 +79,17 @@ QtObject {
78 'percent': 0.0
79 'percent': 0.0
79 }
80 }
80 }
81 }
82+ case "gps-detection-enabled":
83+ case "location-detection-enabled":
84+ return Qt.createQmlObject("
85+import QtQuick 2.3
86+QtObject {
87+ property bool valid: true
88+ property bool state: false
89+ function activate() {
90+ state = !state;
91+ }
92+}", actionGroup);
81 default:
93 default:
82 break;
94 break;
83 }
95 }
tests/mocks/QMenuModel/dbus-enums.hnew file+52
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright 2012 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Olivier Tilloy <olivier.tilloy@canonical.com>
18+ */
19+
20+#ifndef __DBUS_ENUMS__
21+#define __DBUS_ENUMS__
22+
23+#include <QObject>
24+
25+// This class acts as a namespace only, with the addition that its enums
26+// are registered to be exposed on the QML side.
27+class DBusEnums : public QObject
28+{
29+ Q_OBJECT
30+
31+ Q_ENUMS(BusType)
32+ Q_ENUMS(ConnectionStatus)
33+
34+public:
35+ enum BusType {
36+ None = 0,
37+ SessionBus,
38+ SystemBus,
39+ LastBusType
40+ };
41+
42+ enum ConnectionStatus {
43+ Disconnected = 0,
44+ Connecting,
45+ Connected
46+ };
47+
48+private:
49+ DBusEnums() {}
50+};
51+
52+#endif // __DBUS_ENUMS__
tests/mocks/QMenuModel/plugin.cpp+3
@@ -19,12 +19,15 @@
19#include "plugin.h"
19#include "plugin.h"
20#include "unitymenumodel.h"
20#include "unitymenumodel.h"
21#include "actionstateparser.h"
21#include "actionstateparser.h"
22+#include "dbus-enums.h"
22
23
23#include <QtQml/qqml.h>
24#include <QtQml/qqml.h>
24
25
25void QMenuModelPlugin::registerTypes(const char *uri)
26void QMenuModelPlugin::registerTypes(const char *uri)
26{
27{
27 Q_ASSERT(uri == QLatin1String("QMenuModel"));
28 Q_ASSERT(uri == QLatin1String("QMenuModel"));
29+ qmlRegisterUncreatableType<DBusEnums>(uri, 0, 1, "DBus",
30+ "DBus is only a namespace");
28 qmlRegisterType<UnityMenuModel>(uri, 0, 1, "UnityMenuModel");
31 qmlRegisterType<UnityMenuModel>(uri, 0, 1, "UnityMenuModel");
29 qmlRegisterType<ActionStateParser>(uri, 0, 1, "ActionStateParser");
32 qmlRegisterType<ActionStateParser>(uri, 0, 1, "ActionStateParser");
30}
33}
tests/mocks/Ubuntu/CMakeLists.txt+1
@@ -2,5 +2,6 @@ add_subdirectory(Connectivity)
2add_subdirectory(DownloadDaemonListener)
2add_subdirectory(DownloadDaemonListener)
3add_subdirectory(Payments)
3add_subdirectory(Payments)
4add_subdirectory(SystemImage)
4add_subdirectory(SystemImage)
5+add_subdirectory(SystemSettings)
5add_subdirectory(Telephony)
6add_subdirectory(Telephony)
6add_subdirectory(Thumbnailer)
7add_subdirectory(Thumbnailer)
tests/mocks/Ubuntu/SystemSettings/CMakeLists.txtnew file+2
@@ -0,0 +1,2 @@
1+add_subdirectory(LanguagePlugin)
2+add_subdirectory(SecurityPrivacy)
tests/mocks/Ubuntu/SystemSettings/LanguagePlugin/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_unity8_mock(Ubuntu.SystemSettings.LanguagePlugin 1.0 Ubuntu/SystemSettings/LanguagePlugin)
tests/mocks/Ubuntu/SystemSettings/LanguagePlugin/MockLanguagePlugin.qmlnew file+23
@@ -0,0 +1,23 @@
1+/*
2+ * Copyright (C) 2014 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+
19+Item {
20+ property var languageNames: ["English", "French", "Spanish"]
21+ property var languageCodes: ["en", "fr", "es"]
22+ property int currentLanguage: 0
23+}
tests/mocks/Ubuntu/SystemSettings/LanguagePlugin/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.SystemSettings.LanguagePlugin
2+UbuntuLanguagePlugin 1.0 MockLanguagePlugin.qml
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/CMakeLists.txtnew file+10
@@ -0,0 +1,10 @@
1+set(MOCK_SECURITYPRIVACY_SOURCES
2+ plugin.cpp
3+ MockSecurityPrivacy.cpp
4+)
5+
6+add_library(MockSecurityPrivacy MODULE ${MOCK_SECURITYPRIVACY_SOURCES})
7+
8+qt5_use_modules(MockSecurityPrivacy Qml Quick Core)
9+
10+add_unity8_mock(Ubuntu.SystemSettings.SecurityPrivacy 1.0 Ubuntu/SystemSettings/SecurityPrivacy TARGETS MockSecurityPrivacy)
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/MockSecurityPrivacy.cppnew file+28
@@ -0,0 +1,28 @@
1+/*
2+ * Copyright (C) 2014 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+#include "MockSecurityPrivacy.h"
18+
19+MockSecurityPrivacy::MockSecurityPrivacy(QObject *parent)
20+ : QObject(parent)
21+{
22+}
23+
24+QString MockSecurityPrivacy::setSecurity(const QString &oldPasswd, const QString &newPasswd, SecurityType newType)
25+{
26+ Q_EMIT setSecurityCalled(oldPasswd, newPasswd, newType);
27+ return "";
28+}
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/MockSecurityPrivacy.hnew file+42
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (C) 2014 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+#ifndef MOCK_SECURITYPRIVACY_H
18+#define MOCK_SECURITYPRIVACY_H
19+
20+#include <QObject>
21+
22+class MockSecurityPrivacy : public QObject
23+{
24+ Q_OBJECT
25+ Q_ENUMS(SecurityType)
26+
27+public:
28+ enum SecurityType {
29+ Swipe,
30+ Passcode,
31+ Passphrase,
32+ };
33+
34+ MockSecurityPrivacy(QObject *parent = 0);
35+
36+ Q_INVOKABLE QString setSecurity(const QString &oldPasswd, const QString &newPasswd, SecurityType newType);
37+
38+Q_SIGNALS:
39+ void setSecurityCalled(const QString &oldPasswd, const QString &newPasswd, SecurityType newType); // only in mock
40+};
41+
42+#endif // MOCK_SECURITYPRIVACY_H
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/plugin.cppnew file+26
@@ -0,0 +1,26 @@
1+/*
2+ * Copyright (C) 2014 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+#include "plugin.h"
18+#include "MockSecurityPrivacy.h"
19+
20+#include <QtQml>
21+
22+void BackendPlugin::registerTypes(const char *uri)
23+{
24+ Q_ASSERT(uri == QLatin1String("Ubuntu.SystemSettings.SecurityPrivacy"));
25+ qmlRegisterType<MockSecurityPrivacy>(uri, 1, 0, "UbuntuSecurityPrivacyPanel");
26+}
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/plugin.hnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2014 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+#ifndef MOCK_SECURITYPRIVACY_PLUGIN_H
18+#define MOCK_SECURITYPRIVACY_PLUGIN_H
19+
20+#include <QQmlExtensionPlugin>
21+
22+class BackendPlugin : public QQmlExtensionPlugin
23+{
24+ Q_OBJECT
25+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26+
27+public:
28+ void registerTypes(const char *uri);
29+};
30+
31+#endif // MOCK_SECURITYPRIVACY_PLUGIN_H
tests/mocks/Ubuntu/SystemSettings/SecurityPrivacy/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.SystemSettings.SecurityPrivacy
2+plugin MockSecurityPrivacy
tests/mocks/Wizard/CMakeLists.txtnew file+12
@@ -0,0 +1,12 @@
1+include_directories(
2+ ${CMAKE_SOURCE_DIR}/plugins/Wizard
3+)
4+
5+add_library(MockWizard-qml MODULE
6+ mockplugin.cpp
7+ MockSystem.cpp
8+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
9+)
10+
11+qt5_use_modules(MockWizard-qml Qml)
12+add_unity8_mock(Wizard 0.1 Wizard TARGETS MockWizard-qml)
tests/mocks/Wizard/MockSystem.cppnew file+39
@@ -0,0 +1,39 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "MockSystem.h"
18+
19+MockSystem::MockSystem()
20+ : QObject(),
21+ m_wizardEnabled(false)
22+{
23+}
24+
25+bool MockSystem::wizardEnabled() const
26+{
27+ return m_wizardEnabled;
28+}
29+
30+void MockSystem::setWizardEnabled(bool enabled)
31+{
32+ m_wizardEnabled = enabled;
33+ Q_EMIT wizardEnabledChanged();
34+}
35+
36+void MockSystem::updateSessionLanguage(const QString &locale)
37+{
38+ Q_EMIT updateSessionLanguageCalled(locale);
39+}
tests/mocks/Wizard/MockSystem.hnew file+47
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef WIZARD_MOCK_SYSTEM_H
18+#define WIZARD_MOCK_SYSTEM_H
19+
20+#include <QObject>
21+#include <QString>
22+
23+class MockSystem : public QObject
24+{
25+ Q_OBJECT
26+ Q_PROPERTY(bool wizardEnabled READ wizardEnabled WRITE setWizardEnabled NOTIFY wizardEnabledChanged)
27+
28+public:
29+ MockSystem();
30+
31+ bool wizardEnabled() const;
32+ void setWizardEnabled(bool enabled);
33+
34+public Q_SLOTS:
35+ void updateSessionLanguage(const QString &locale);
36+
37+Q_SIGNALS:
38+ void wizardEnabledChanged();
39+ void updateSessionLanguageCalled(const QString &locale); // only in mock
40+
41+private:
42+ Q_DISABLE_COPY(MockSystem)
43+
44+ bool m_wizardEnabled;
45+};
46+
47+#endif
tests/mocks/Wizard/Wizard.qmltypesnew file+36
@@ -0,0 +1,36 @@
1+import QtQuick.tooling 1.1
2+
3+// This file describes the plugin-supplied types contained in the library.
4+// It is used for QML tooling purposes only.
5+//
6+// This file was auto-generated by:
7+// 'qmlplugindump -notrelocatable Wizard 0.1 tests/mocks'
8+
9+Module {
10+ Component {
11+ name: "MockSystem"
12+ prototype: "QObject"
13+ exports: ["Wizard/System 0.1"]
14+ isCreatable: false
15+ isSingleton: true
16+ exportMetaObjectRevisions: [0]
17+ Property { name: "wizardEnabled"; type: "bool" }
18+ Method {
19+ name: "updateSessionLanguage"
20+ Parameter { name: "locale"; type: "string" }
21+ }
22+ }
23+ Component {
24+ name: "PageList"
25+ prototype: "QObject"
26+ exports: ["Wizard/PageList 0.1"]
27+ isCreatable: false
28+ isSingleton: true
29+ exportMetaObjectRevisions: [0]
30+ Property { name: "index"; type: "int"; isReadonly: true }
31+ Property { name: "numPages"; type: "int"; isReadonly: true }
32+ Method { name: "prev"; type: "string" }
33+ Method { name: "next"; type: "string" }
34+ }
35+}
36+
tests/mocks/Wizard/mockplugin.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 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+#include "mockplugin.h"
18+#include "MockSystem.h"
19+#include "PageList.h"
20+
21+#include <QtQml/qqml.h>
22+
23+static QObject *system_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
24+{
25+ Q_UNUSED(engine)
26+ Q_UNUSED(scriptEngine)
27+ return new MockSystem();
28+}
29+
30+void MockWizardPlugin::registerTypes(const char *uri)
31+{
32+ Q_ASSERT(uri == QLatin1String("Wizard"));
33+ qmlRegisterType<PageList>(uri, 0, 1, "PageList");
34+ qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", system_provider);
35+}
tests/mocks/Wizard/mockplugin.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2014 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+#ifndef MOCK_WIZARD_PLUGIN_H
18+#define MOCK_WIZARD_PLUGIN_H
19+
20+#include <QtQml/QQmlEngine>
21+#include <QtQml/QQmlExtensionPlugin>
22+
23+class MockWizardPlugin : public QQmlExtensionPlugin
24+{
25+ Q_OBJECT
26+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
27+
28+public:
29+ void registerTypes(const char *uri);
30+};
31+
32+#endif
tests/mocks/Wizard/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Wizard
2+plugin MockWizard-qml
3+typeinfo Wizard.qmltypes
tests/plugins/CMakeLists.txt+1
@@ -4,3 +4,4 @@ add_subdirectory(Dash)
4add_subdirectory(Ubuntu)
4add_subdirectory(Ubuntu)
5add_subdirectory(Unity)
5add_subdirectory(Unity)
6add_subdirectory(Utils)
6add_subdirectory(Utils)
7+add_subdirectory(Wizard)
tests/plugins/Wizard/CMakeLists.txtnew file+18
@@ -0,0 +1,18 @@
1+include_directories(
2+ ${CMAKE_CURRENT_BINARY_DIR}
3+ ${CMAKE_SOURCE_DIR}/plugins/Wizard
4+)
5+
6+add_executable(tst-wizard-pagelist
7+ tst_pagelist.cpp
8+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/PageList.cpp
9+)
10+qt5_use_modules(tst-wizard-pagelist Core Qml Test)
11+add_test(NAME wizardpagelisttest COMMAND env UNITY_TEST_ENV=1 ${CMAKE_CURRENT_BINARY_DIR}/tst-wizard-pagelist)
12+
13+add_executable(tst-wizard-system
14+ tst_system.cpp
15+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/System.cpp
16+)
17+qt5_use_modules(tst-wizard-system Core DBus Qml Test)
18+add_test(NAME wizardsystemtest COMMAND ${CMAKE_CURRENT_BINARY_DIR}/tst-wizard-system)
tests/plugins/Wizard/tst_pagelist.cppnew file+154
@@ -0,0 +1,154 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "PageList.h"
18+
19+#include <QDebug>
20+#include <QObject>
21+#include <QTemporaryDir>
22+#include <QTest>
23+
24+#define PAGES_PATH "Wizard/Pages"
25+
26+class PageListTest: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ PageListTest() {};
32+
33+private Q_SLOTS:
34+ void testCollect();
35+ void testIterate();
36+ void testIgnoreNonNumbered();
37+ void testIgnoreNonQml();
38+ void testIgnoreDuplicates();
39+ void testDisabled();
40+
41+private:
42+ void fillRoot(const QTemporaryDir &root);
43+ void makeFile(const QTemporaryDir &root, const QString &dir, const QString &filename);
44+};
45+
46+void PageListTest::fillRoot(const QTemporaryDir &root)
47+{
48+ QVERIFY(root.isValid());
49+ QDir rootDir = root.path();
50+ QVERIFY(rootDir.mkpath(QString("a/") + PAGES_PATH));
51+ QVERIFY(rootDir.mkpath(QString("b/") + PAGES_PATH));
52+ QVERIFY(rootDir.mkpath(QString("c/") + PAGES_PATH));
53+ qputenv("XDG_DATA_DIRS", QString(rootDir.path() + "/a:" +
54+ rootDir.path() + "/b:" +
55+ rootDir.path() + "/c").toLatin1());
56+}
57+
58+void PageListTest::makeFile(const QTemporaryDir &root, const QString &dir, const QString &filename)
59+{
60+ QFile file(root.path() + "/" + dir + "/" + PAGES_PATH + "/" + filename);
61+ QVERIFY(file.open(QIODevice::WriteOnly));
62+ file.close();
63+ QVERIFY(file.exists());
64+}
65+
66+void PageListTest::testCollect()
67+{
68+ QTemporaryDir root;
69+ fillRoot(root);
70+ makeFile(root, "a", "3.qml");
71+ makeFile(root, "b", "1.qml");
72+ makeFile(root, "c", "2.qml");
73+
74+ PageList pageList;
75+ QCOMPARE(pageList.entries(), QStringList() << "1.qml" << "2.qml" << "3.qml");
76+ QCOMPARE(pageList.paths(), QStringList() << root.path() + "/b/" + PAGES_PATH + "/1.qml"
77+ << root.path() + "/c/" + PAGES_PATH + "/2.qml"
78+ << root.path() + "/a/" + PAGES_PATH + "/3.qml");
79+}
80+
81+void PageListTest::testIterate()
82+{
83+ QTemporaryDir root;
84+ fillRoot(root);
85+ makeFile(root, "a", "1.qml");
86+ makeFile(root, "a", "2.qml");
87+ makeFile(root, "a", "3.qml");
88+
89+ PageList pageList;
90+ QCOMPARE(pageList.index(), -1);
91+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/1.qml");
92+ QCOMPARE(pageList.prev(), QString());
93+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/2.qml");
94+ QCOMPARE(pageList.prev(), root.path() + "/a/" + PAGES_PATH + "/1.qml");
95+ QCOMPARE(pageList.index(), 0);
96+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/2.qml");
97+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/3.qml");
98+ QCOMPARE(pageList.index(), 2);
99+ QCOMPARE(pageList.next(), QString());
100+ QCOMPARE(pageList.index(), 2);
101+}
102+
103+void PageListTest::testIgnoreNonNumbered()
104+{
105+ QTemporaryDir root;
106+ fillRoot(root);
107+ makeFile(root, "a", "1.qml");
108+ makeFile(root, "a", "nope.qml");
109+
110+ PageList pageList;
111+ QCOMPARE(pageList.entries(), QStringList() << "1.qml");
112+}
113+
114+void PageListTest::testIgnoreNonQml()
115+{
116+ QTemporaryDir root;
117+ fillRoot(root);
118+ makeFile(root, "a", "1.qml");
119+ makeFile(root, "a", "2");
120+ makeFile(root, "a", "2.txt");
121+
122+ PageList pageList;
123+ QCOMPARE(pageList.entries(), QStringList() << "1.qml");
124+}
125+
126+void PageListTest::testIgnoreDuplicates()
127+{
128+ QTemporaryDir root;
129+ fillRoot(root);
130+ makeFile(root, "a", "1.qml");
131+ makeFile(root, "b", "1.qml");
132+
133+ PageList pageList;
134+ QCOMPARE(pageList.paths(), QStringList() << root.path() + "/a/" + PAGES_PATH + "/1.qml");
135+}
136+
137+void PageListTest::testDisabled()
138+{
139+ QTemporaryDir root;
140+ fillRoot(root);
141+ makeFile(root, "a", "1.qml.disabled"); // before the fact
142+ makeFile(root, "b", "1.qml");
143+ makeFile(root, "b", "2.qml");
144+ makeFile(root, "b", "2.qml.disabled"); // same dir
145+ makeFile(root, "b", "3.qml");
146+ makeFile(root, "b", "4.qml"); // only survivor
147+ makeFile(root, "c", "3.qml.disabled"); // after the fact
148+
149+ PageList pageList;
150+ QCOMPARE(pageList.entries(), QStringList() << "4.qml");
151+}
152+
153+QTEST_MAIN(PageListTest)
154+#include "tst_pagelist.moc"
tests/plugins/Wizard/tst_system.cppnew file+124
@@ -0,0 +1,124 @@
1+/*
2+ * Copyright (C) 2014 Canonical Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it
5+ * under the terms of the GNU General Public License version 3, as published
6+ * by the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but
9+ * WITHOUT ANY WARRANTY; without even the implied warranties of
10+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11+ * PURPOSE. See the GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License along
14+ * with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "System.h"
18+
19+#include <QDebug>
20+#include <QObject>
21+#include <QSignalSpy>
22+#include <QTemporaryDir>
23+#include <QTest>
24+
25+class SystemTest: public QObject
26+{
27+ Q_OBJECT
28+
29+public:
30+ SystemTest();
31+
32+private Q_SLOTS:
33+ void testEnable();
34+ void testDisable();
35+ void testNoticeChanges();
36+
37+private:
38+ void enable();
39+ void disable();
40+ bool isEnabled();
41+
42+ QTemporaryDir dir;
43+ QDir enableDir;
44+ QFile enableFile;
45+};
46+
47+SystemTest::SystemTest()
48+{
49+ qputenv("HOME", dir.path().toUtf8());
50+ enableDir.setPath(dir.path() + "/.config/ubuntu-system-settings");
51+ enableFile.setFileName(enableDir.filePath("wizard-has-run"));
52+}
53+
54+void SystemTest::enable()
55+{
56+ enableFile.remove();
57+ QCOMPARE(isEnabled(), true);
58+}
59+
60+void SystemTest::disable()
61+{
62+ enableDir.mkpath(".");
63+ enableFile.open(QIODevice::WriteOnly);
64+ enableFile.close();
65+ QCOMPARE(isEnabled(), false);
66+}
67+
68+bool SystemTest::isEnabled()
69+{
70+ return !enableFile.exists();
71+}
72+
73+void SystemTest::testEnable()
74+{
75+ disable();
76+
77+ System system;
78+ QVERIFY(!system.wizardEnabled());
79+
80+ system.setWizardEnabled(true);
81+ QVERIFY(system.wizardEnabled());
82+ QVERIFY(isEnabled());
83+}
84+
85+void SystemTest::testDisable()
86+{
87+ enable();
88+
89+ System system;
90+ QVERIFY(system.wizardEnabled());
91+
92+ system.setWizardEnabled(false);
93+ QVERIFY(!system.wizardEnabled());
94+ QVERIFY(!isEnabled());
95+}
96+
97+void SystemTest::testNoticeChanges()
98+{
99+ enable();
100+
101+ System system;
102+ QSignalSpy spy(&system, SIGNAL(wizardEnabledChanged()));
103+
104+ // System only guarantees its signals work correcty when using its own set
105+ // methods (i.e. it won't necessarily notice if we modify the file behind
106+ // the scenes). This is because watching all parent directories of the
107+ // wizard-has-run file with QFileSystemWatcher is a nightmare and waste of
108+ // resources for the corner case it is. So we'll just test the set method.
109+
110+ system.setWizardEnabled(false);
111+ QTRY_COMPARE(spy.count(), 1);
112+
113+ system.setWizardEnabled(true);
114+ QTRY_COMPARE(spy.count(), 2);
115+
116+ system.setWizardEnabled(false);
117+ QTRY_COMPARE(spy.count(), 3);
118+
119+ system.setWizardEnabled(true);
120+ QTRY_COMPARE(spy.count(), 4);
121+}
122+
123+QTEST_MAIN(SystemTest)
124+#include "tst_system.moc"
tests/qmltests/CMakeLists.txt+1
@@ -87,3 +87,4 @@ add_qml_test(Stages SpreadDelegate ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_D
87add_qml_test(Stages SurfaceContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
87add_qml_test(Stages SurfaceContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
88add_qml_test(Stages SessionContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
88add_qml_test(Stages SessionContainer ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
89add_qml_test(Stages Splash)
89add_qml_test(Stages Splash)
90+add_qml_test(Wizard Wizard)
tests/qmltests/Wizard/licenses/en_US.htmlnew file+1
@@ -0,0 +1 @@
1+en_US
tests/qmltests/Wizard/licenses/fr_CA.htmlnew file+1
@@ -0,0 +1 @@
1+fr_CA
tests/qmltests/Wizard/licenses/fr_FR.htmlnew file+1
@@ -0,0 +1 @@
1+fr_FR
tests/qmltests/Wizard/tst_Wizard.qmlnew file+479
@@ -0,0 +1,479 @@
1+/*
2+ * Copyright 2014 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 QtTest 1.0
19+import AccountsService 0.1
20+import MeeGo.QOfono 0.2
21+import Ubuntu.Components 1.1
22+import Ubuntu.SystemSettings.SecurityPrivacy 1.0
23+import Unity.Test 0.1 as UT
24+import Wizard 0.1
25+import "../../../qml/Wizard"
26+
27+Item {
28+ id: root
29+ width: units.gu(40)
30+ height: units.gu(71)
31+
32+ Loader {
33+ id: wizardLoader
34+ anchors.fill: parent
35+
36+ property bool itemDestroyed: false
37+ sourceComponent: Component {
38+ Wizard {
39+ id: wizard
40+ anchors.fill: parent
41+ background: Qt.resolvedUrl("../../../qml/graphics/phone_background.jpg")
42+
43+ Component.onDestruction: {
44+ wizardLoader.itemDestroyed = true;
45+ }
46+ }
47+ }
48+ }
49+
50+ SignalSpy {
51+ id: updateSessionLanguageSpy
52+ target: System
53+ signalName: "updateSessionLanguageCalled"
54+ }
55+
56+ SignalSpy {
57+ id: setSecuritySpy
58+ signalName: "setSecurityCalled"
59+ }
60+
61+ function setup() {
62+ AccountsService.hereEnabled = false;
63+ AccountsService.hereLicensePath = Qt.resolvedUrl("licenses");
64+ i18n.language = "en";
65+ MockQOfono.setModems(["sim1"], [false]);
66+ MockQOfono.available = true;
67+ System.wizardEnabled = true;
68+
69+ updateSessionLanguageSpy.clear();
70+ setSecuritySpy.clear();
71+ }
72+
73+ Component.onCompleted: {
74+ Theme.name = "Ubuntu.Components.Themes.SuruGradient";
75+ setup();
76+ }
77+
78+ UT.UnityTestCase {
79+ id: wizardTests
80+ name: "Wizard"
81+ when: windowShown
82+
83+ property Item wizard: wizardLoader.status === Loader.Ready ? wizardLoader.item : null
84+
85+ function cleanup() {
86+ wizardLoader.itemDestroyed = false;
87+
88+ wizardLoader.active = false;
89+
90+ tryCompare(wizardLoader, "status", Loader.Null);
91+ tryCompare(wizardLoader, "item", null);
92+ // Loader.status might be Loader.Null and Loader.item might be null but the Loader
93+ // item might still be alive. So if we set Loader.active back to true
94+ // again right now we will get the very same Shell instance back. So no reload
95+ // actually took place. Likely because Loader waits until the next event loop
96+ // iteration to do its work. So to ensure the reload, we will wait until the
97+ // Shell instance gets destroyed.
98+ tryCompare(wizardLoader, "itemDestroyed", true);
99+
100+ // reload our test subject to get it in a fresh state once again
101+ wizardLoader.active = true;
102+
103+ tryCompare(wizardLoader, "status", Loader.Ready);
104+
105+ var pages = findChild(wizard, "wizardPages");
106+ var security = findInvisibleChild(pages, "securityPrivacy");
107+ setSecuritySpy.target = security;
108+
109+ setup();
110+ }
111+
112+ function waitForPage(name) {
113+ var pages = findChild(wizard, "wizardPages");
114+ var stack = findChild(pages, "pageStack");
115+ // don't simply call tryCompare here, because stack.currentPage will be swapped out itself
116+ tryCompareFunction(function() { return stack.currentPage.objectName; }, name);
117+ tryCompare(stack.currentPage, "opacity", 1.0);
118+ tryCompare(stack.currentPage, "enabled", true);
119+ waitForRendering(stack.currentPage);
120+ return stack.currentPage;
121+ }
122+
123+ function goToPage(name, skipSim, skipLocation) {
124+ if (skipSim === undefined) {
125+ skipSim = false;
126+ }
127+ if (skipLocation === undefined) {
128+ skipLocation = false;
129+ }
130+
131+ var page = waitForPage("languagePage");
132+ if (name === page.objectName) return page;
133+ tap(findChild(page, "forwardButton"));
134+
135+ if (!skipSim) {
136+ page = waitForPage("simPage");
137+ if (name === page.objectName) return page;
138+ tap(findChild(page, "forwardButton"));
139+ }
140+
141+ page = waitForPage("passwdPage");
142+ if (name === page.objectName) return page;
143+ tap(findChild(page, "passwdDelegate0"));
144+ tap(findChild(page, "forwardButton"));
145+
146+ page = waitForPage("wifiPage");
147+ if (name === page.objectName) return page;
148+ tap(findChild(page, "forwardButton"));
149+
150+ if (!skipLocation) {
151+ page = waitForPage("locationPage");
152+ if (name === page.objectName) return page;
153+ tap(findChild(page, "forwardButton"));
154+ }
155+
156+ page = waitForPage("reportingPage");
157+ if (name === page.objectName) return page;
158+ tap(findChild(page, "forwardButton"));
159+
160+ page = waitForPage("finishedPage");
161+ if (name === page.objectName) return page;
162+ tap(findChild(page, "forwardButton"));
163+
164+ tryCompare(wizard, "shown", false);
165+ compare(name, null);
166+ return null;
167+ }
168+
169+ function test_languageChange() {
170+ var page = goToPage("languagePage");
171+ tap(findChild(page, "languageCombo"));
172+ waitForRendering(findChild(page, "languageDelegate1"));
173+
174+ // For some reason, the delegate *sometimes* (like 1 in 10 maybe)
175+ // needs more time before it can process a tap() call. I can't
176+ // find a rhyme or reason, its properties all seem the same in
177+ // cases where it works and does not. This failure to receive a
178+ // tap() call below does *not* happen when running in xvfb, so
179+ // jenkins is unaffected (and we don't have to worry about 100 not
180+ // being enough time in its slow environment). This wait() call is
181+ // just to help local runs not trip up.
182+ wait(100);
183+ tap(findChild(page, "languageDelegate1"));
184+
185+ tryCompare(i18n, "language", "fr");
186+ tap(findChild(page, "forwardButton"));
187+ tryCompare(updateSessionLanguageSpy, "count", 1);
188+ compare(updateSessionLanguageSpy.signalArguments[0][0], "fr");
189+ }
190+
191+ function test_languageNoChange() {
192+ goToPage("simPage"); // one past language page
193+ compare(updateSessionLanguageSpy.count, 0);
194+ }
195+
196+ function test_simUnavailableSkip() {
197+ MockQOfono.available = false;
198+ goToPage("passwdPage", true);
199+ }
200+
201+ function test_simNoModemsSkip() {
202+ MockQOfono.setModems([], []);
203+ goToPage("passwdPage", true);
204+ }
205+
206+ function test_simFirstSkip() {
207+ MockQOfono.setModems(["a", "b"], [true, false]);
208+ goToPage("passwdPage", true);
209+ }
210+
211+ function test_simSecondSkip() {
212+ MockQOfono.setModems(["a", "b"], [false, true]);
213+ goToPage("passwdPage", true);
214+ }
215+
216+ function test_simBothSkip() {
217+ MockQOfono.setModems(["a", "b"], [true, true]);
218+ goToPage("passwdPage", true);
219+ }
220+
221+ function enterPasscode(passcode) {
222+ for (var i = 0; i < passcode.length; ++i) {
223+ var character = passcode.charAt(i);
224+ var button = findChild(wizard, "pinPadButton" + character);
225+ tap(button);
226+ }
227+ }
228+
229+ function test_passwdPasscode() {
230+ var page = goToPage("passwdPage");
231+
232+ tap(findChild(page, "forwardButton"));
233+ page = waitForPage("passwdSetPage");
234+
235+ enterPasscode("1111");
236+ page = waitForPage("passwdConfirmPage");
237+
238+ // make sure we go back to 'set' page not 'type' page
239+ tap(findChild(page, "backButton"));
240+ page = waitForPage("passwdSetPage");
241+
242+ enterPasscode("1111");
243+ page = waitForPage("passwdConfirmPage");
244+
245+ enterPasscode("1112");
246+ var error = findChild(page, "wrongNoticeLabel");
247+ tryCompareFunction(function() { return error.text !== ""; }, true);
248+
249+ enterPasscode("1111");
250+ page = waitForPage("wifiPage");
251+
252+ // now finish up
253+ tap(findChild(page, "forwardButton"));
254+ page = waitForPage("locationPage");
255+ tap(findChild(page, "forwardButton"));
256+ page = waitForPage("reportingPage");
257+ tap(findChild(page, "forwardButton"));
258+ page = waitForPage("finishedPage");
259+ tap(findChild(page, "forwardButton"));
260+
261+ tryCompare(setSecuritySpy, "count", 1);
262+ compare(setSecuritySpy.signalArguments[0][0], "");
263+ compare(setSecuritySpy.signalArguments[0][1], "1111");
264+ compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Passcode);
265+ }
266+
267+ function test_passwdPassphrase() {
268+ var page = goToPage("passwdPage");
269+ tap(findChild(page, "passwdDelegate2"));
270+
271+ tap(findChild(page, "forwardButton"));
272+ page = waitForPage("passwdSetPage");
273+
274+ typeString("aaa");
275+ var continueButton = findChild(page, "forwardButton");
276+ tryCompare(continueButton.item, "enabled", false);
277+ keyClick(Qt.Key_Enter);
278+ var error = findChild(page, "wrongNoticeLabel");
279+ tryCompareFunction(function() { return error.text !== ""; }, true);
280+
281+ typeString("aaaa");
282+ tap(continueButton);
283+ page = waitForPage("passwdConfirmPage");
284+
285+ // make sure we go back to 'set' page not 'type' page
286+ var back = findChild(page, "backButton");
287+ tap(back);
288+ page = waitForPage("passwdSetPage");
289+
290+ typeString("aaaa");
291+ keyClick(Qt.Key_Enter);
292+ page = waitForPage("passwdConfirmPage");
293+
294+ continueButton = findChild(page, "forwardButton");
295+ typeString("aaab");
296+ tryCompare(continueButton.item, "enabled", false);
297+ keyClick(Qt.Key_Enter);
298+ var error = findChild(page, "wrongNoticeLabel");
299+ tryCompareFunction(function() { return error.text !== ""; }, true);
300+
301+ typeString("aaaa");
302+ tap(continueButton);
303+ page = waitForPage("wifiPage");
304+
305+ // now finish up
306+ tap(findChild(page, "forwardButton"));
307+ page = waitForPage("locationPage");
308+ tap(findChild(page, "forwardButton"));
309+ page = waitForPage("reportingPage");
310+ tap(findChild(page, "forwardButton"));
311+ page = waitForPage("finishedPage");
312+ tap(findChild(page, "forwardButton"));
313+
314+ tryCompare(setSecuritySpy, "count", 1);
315+ compare(setSecuritySpy.signalArguments[0][0], "");
316+ compare(setSecuritySpy.signalArguments[0][1], "aaaa");
317+ compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Passphrase);
318+ }
319+
320+ function test_passwdSwipe() {
321+ goToPage(null);
322+
323+ tryCompare(setSecuritySpy, "count", 1);
324+ compare(setSecuritySpy.signalArguments[0][0], "");
325+ compare(setSecuritySpy.signalArguments[0][1], "");
326+ compare(setSecuritySpy.signalArguments[0][2], UbuntuSecurityPrivacyPanel.Swipe);
327+ }
328+
329+ function test_locationSkipNoPath() {
330+ AccountsService.hereLicensePath = "";
331+ goToPage("reportingPage", false, true);
332+ }
333+
334+ function test_locationSkipNoFiles() {
335+ AccountsService.hereLicensePath = Qt.resolvedUrl("nolicenses");
336+ goToPage("reportingPage", false, true);
337+ }
338+
339+ function test_locationWaitOnPath() {
340+ AccountsService.hereLicensePath = " "; // means we're still getting the path from dbus
341+
342+ var page = goToPage("wifiPage");
343+
344+ var pages = findChild(wizard, "wizardPages");
345+ var stack = findChild(pages, "pageStack");
346+ tap(findChild(page, "forwardButton"));
347+ // don't simply call tryCompare here, because stack.currentPage will be swapped out itself
348+ tryCompareFunction(function() { return stack.currentPage.objectName; }, "locationPage");
349+ compare(stack.currentPage.enabled, false);
350+ compare(stack.currentPage.skipValid, false);
351+
352+ AccountsService.hereLicensePath = "";
353+ waitForPage("reportingPage");
354+ }
355+
356+ function test_locationGpsOnly() {
357+ var page = goToPage("locationPage");
358+ var gpsCheck = findChild(page, "gpsCheck");
359+ var hereCheck = findChild(page, "hereCheck");
360+ var nopeCheck = findChild(page, "nopeCheck");
361+
362+ var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
363+ tryCompare(locationActionGroup.location, "state", false);
364+ tryCompare(locationActionGroup.gps, "state", false);
365+
366+ tap(gpsCheck);
367+ tryCompare(gpsCheck, "checked", true);
368+ tryCompare(hereCheck, "checked", false);
369+ tryCompare(nopeCheck, "checked", false);
370+
371+ tap(findChild(page, "forwardButton"));
372+ tryCompare(AccountsService, "hereEnabled", false);
373+ tryCompare(locationActionGroup.location, "state", true);
374+ tryCompare(locationActionGroup.gps, "state", true);
375+ }
376+
377+ function test_locationNope() {
378+ var page = goToPage("locationPage");
379+ var gpsCheck = findChild(page, "gpsCheck");
380+ var hereCheck = findChild(page, "hereCheck");
381+ var nopeCheck = findChild(page, "nopeCheck");
382+
383+ var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
384+ tryCompare(locationActionGroup.location, "state", false);
385+ tryCompare(locationActionGroup.gps, "state", false);
386+
387+ tap(nopeCheck);
388+ tryCompare(gpsCheck, "checked", false);
389+ tryCompare(hereCheck, "checked", false);
390+ tryCompare(nopeCheck, "checked", true);
391+
392+ tap(findChild(page, "forwardButton"));
393+ tryCompare(AccountsService, "hereEnabled", false);
394+ tryCompare(locationActionGroup.location, "state", false);
395+ tryCompare(locationActionGroup.gps, "state", false);
396+ }
397+
398+ function test_locationHere() {
399+ var page = goToPage("locationPage");
400+ var gpsCheck = findChild(page, "gpsCheck");
401+ var hereCheck = findChild(page, "hereCheck");
402+ var nopeCheck = findChild(page, "nopeCheck");
403+
404+ var locationActionGroup = findInvisibleChild(page, "locationActionGroup");
405+ tryCompare(locationActionGroup.location, "state", false);
406+ tryCompare(locationActionGroup.gps, "state", false);
407+
408+ // no tap because HERE is the default
409+ tryCompare(gpsCheck, "checked", false);
410+ tryCompare(hereCheck, "checked", true);
411+ tryCompare(nopeCheck, "checked", false);
412+
413+ tap(findChild(page, "forwardButton"));
414+ tryCompare(AccountsService, "hereEnabled", true);
415+ tryCompare(locationActionGroup.location, "state", true);
416+ tryCompare(locationActionGroup.gps, "state", true);
417+ }
418+
419+ function test_locationHereTerms() {
420+ var page = goToPage("locationPage");
421+
422+ var link = findChild(page, "hereTermsLink");
423+
424+ // Test our language lookup code a bit
425+
426+ i18n.language = "fr_FR.UTF-8";
427+ link.linkActivated("not-used");
428+ page = waitForPage("hereTermsPage");
429+ tryCompare(findChild(page, "termsLabel"), "text", "fr_FR\n");
430+ tap(findChild(page, "backButton"));
431+ waitForPage("locationPage");
432+
433+ i18n.language = "fr_CA";
434+ link.linkActivated("not-used");
435+ page = waitForPage("hereTermsPage");
436+ tryCompare(findChild(page, "termsLabel"), "text", "fr_CA\n");
437+ tap(findChild(page, "backButton"));
438+ waitForPage("locationPage");
439+
440+ i18n.language = "fr_US";
441+ link.linkActivated("not-used");
442+ page = waitForPage("hereTermsPage");
443+ tryCompare(findChild(page, "termsLabel"), "text", "fr_FR\n");
444+ tap(findChild(page, "backButton"));
445+ waitForPage("locationPage");
446+
447+ i18n.language = "fr.utf8";
448+ link.linkActivated("not-used");
449+ page = waitForPage("hereTermsPage");
450+ tryCompare(findChild(page, "termsLabel"), "text", "fr_FR\n");
451+ tap(findChild(page, "backButton"));
452+ waitForPage("locationPage");
453+
454+ i18n.language = "es"; // will not be found
455+ link.linkActivated("not-used");
456+ page = waitForPage("hereTermsPage");
457+ tryCompare(findChild(page, "termsLabel"), "text", "en_US\n");
458+
459+ // OK, done with languages, back to actual page
460+
461+ var label = findChild(page, "termsLabel");
462+ label.linkActivated(Qt.resolvedUrl("licenses/en_US.html"));
463+ tryCompare(label, "visible", false);
464+
465+ var webview = findChild(page, "webview");
466+ tryCompare(webview, "visible", true);
467+ tryCompare(webview, "url", Qt.resolvedUrl("licenses/en_US.html"));
468+ tryCompare(webview, "loadProgress", 100);
469+
470+ tap(findChild(page, "backButton"));
471+ waitForPage("hereTermsPage"); // confirm we're on same page
472+ tryCompare(webview, "visible", false);
473+ tryCompare(label, "visible", true);
474+
475+ tap(findChild(page, "backButton"));
476+ waitForPage("locationPage");
477+ }
478+ }
479+}