on xenial help sign in
Initial move of wizard source code to unity8
commit23a2ae1a289c7e08582e98e283908fa7ceef0477 authorMichael Terry <michael.terry@canonical.com> dateTue 11 Nov 2014, 17:00 (12 years ago) parentdef9525
45 files changed+2810−1
CMakeLists.txt+1 debian/control+13 debian/rules+1−1 debian/ubuntu-system-settings-wizard.install+5 debian/ubuntu-system-settings-wizard.lintian-overrides+1 tests/CMakeLists.txt+1 tests/wizard/CMakeLists.txt+5 tests/wizard/tst_pagelist.cpp+156 wizard/50-com.ubuntu.system-settings.wizard.pkla+6 wizard/CMakeLists.txt+65 wizard/PageList.cpp+111 wizard/PageList.h+55 wizard/Unity/Application/CMakeLists.txt+3 wizard/Unity/Application/OSKController.qml+20 wizard/Unity/Application/qmldir+2 wizard/Unity/CMakeLists.txt+1 wizard/Utils/CMakeLists.txt+27 wizard/Utils/plugin.cpp+41 wizard/Utils/plugin.h+33 wizard/Utils/qmldir+2 wizard/Utils/qsortfilterproxymodelqml.cpp+167 wizard/Utils/qsortfilterproxymodelqml.h+63 wizard/Utils/system.cpp+118 wizard/Utils/system.h+57 wizard/main.cpp+93 wizard/qml/Components/CheckableSetting.qml+85 wizard/qml/Components/InputMethod.qml+113 wizard/qml/Components/Page.qml+107 wizard/qml/Components/StackButton.qml+47 wizard/qml/Pages/10-welcome.qml+93 wizard/qml/Pages/20-sim.qml+71 wizard/qml/Pages/30-passwd-type.qml+119 wizard/qml/Pages/40-wifi.qml+200 wizard/qml/Pages/50-location.qml+149 wizard/qml/Pages/60-reporting.qml+52 wizard/qml/Pages/80-finished.qml+55 wizard/qml/Pages/data/meet_ubuntu_simcard@30.png wizard/qml/Pages/here-terms.qml+117 wizard/qml/Pages/passwd-confirm.qml+79 wizard/qml/Pages/passwd-set.qml+87 wizard/qml/main.qml+246 wizard/test.sh+18 wizard/ubuntu-system-settings-wizard-cleanup.conf+20 wizard/ubuntu-system-settings-wizard-set-lang.conf+30 wizard/ubuntu-system-settings-wizard.conf+75
CMakeLists.txt+1
@@ -116,6 +116,7 @@ add_subdirectory(tools)
116116add_subdirectory(qml)
117117add_subdirectory(tests)
118118add_subdirectory(plugins)
119+add_subdirectory(wizard)
119120
120121#
121122# Data files
debian/control+13
@@ -23,6 +23,7 @@ Build-Depends: cmake,
2323 libpulse-dev,
2424 libqmenumodel-dev (>= 0.2.8),
2525 libqt5xmlpatterns5-dev,
26+ libsystemsettings-dev,
2627 libunity-api-dev (>= 7.93),
2728 libusermetricsoutput1-dev,
2829 libxcb1-dev,
@@ -191,3 +192,15 @@ Multi-Arch: foreign
191192Depends: ${misc:Depends},
192193Description: Documentation for Unity8
193194 The Unity 8 shell is the primary user interface for Ubuntu devices. (documentation)
195+
196+Package: ubuntu-system-settings-wizard
197+Architecture: any
198+Depends: unity8 (= ${binary:Version}),
199+ ${misc:Depends},
200+ ${shlibs:Depends},
201+Recommends: qtdeclarative5-qtmir-plugin (>= 0.4),
202+Breaks: ubuntu-system-settings (<< 0.4),
203+Replaces: ubuntu-system-settings (<< 0.4),
204+Description: Welcome Wizard for Ubuntu Touch
205+ This package contains the Welcome Wizard used on the Ubuntu Touch images,
206+ it's designed for phones, tablets and convergent devices.
debian/rules+1−1
@@ -40,7 +40,7 @@ override_dh_install:
4040
4141# use private lib directories
4242override_dh_makeshlibs:
43− dh_makeshlibs -Nunity8-private -Nunity8-fake-env
43+ dh_makeshlibs -Nunity8-private -Nunity8-fake-env -Nubuntu-system-settings-wizard
4444
4545# libMockLightDM-qml.so links against liblightdm-qt5-2.so which doesn't exist
4646override_dh_shlibdeps:
debian/ubuntu-system-settings-wizard.installnew file+5
@@ -0,0 +1,5 @@
1+usr/bin/system-settings-wizard
2+usr/share/ubuntu/settings/wizard
3+usr/share/upstart/sessions/ubuntu-system-settings-wizard*.conf
4+usr/lib/*/ubuntu-system-settings/private/Ubuntu/SystemSettings/Wizard
5+var/lib/polkit-1/localauthority/10-vendor.d/50-com.ubuntu.system-settings.wizard.pkla
debian/ubuntu-system-settings-wizard.lintian-overridesnew file+1
@@ -0,0 +1 @@
1+ubuntu-system-settings-wizard: binary-without-manpage usr/bin/system-settings-wizard
tests/CMakeLists.txt+1
@@ -14,3 +14,4 @@ add_subdirectory(whitespace)
1414add_subdirectory(plugins)
1515add_subdirectory(utils)
1616add_subdirectory(uqmlscene)
17+add_subdirectory(wizard)
tests/wizard/CMakeLists.txtnew file+5
@@ -0,0 +1,5 @@
1+add_executable(tst-pagelist tst_pagelist.cpp ${CMAKE_SOURCE_DIR}/wizard/PageList.cpp)
2+set_target_properties(tst-pagelist PROPERTIES
3+ INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR};${CMAKE_SOURCE_DIR}/wizard")
4+qt5_use_modules(tst-pagelist Core Test)
5+add_test(tst-pagelist tst-pagelist)
tests/wizard/tst_pagelist.cppnew file+156
@@ -0,0 +1,156 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2014 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#include "PageList.h"
20+
21+#include <QDebug>
22+#include <QObject>
23+#include <QTemporaryDir>
24+#include <QTest>
25+
26+#define PAGES_PATH "ubuntu/settings/wizard/qml/Pages"
27+
28+class PageListTest: public QObject
29+{
30+ Q_OBJECT
31+
32+public:
33+ PageListTest() {};
34+
35+private Q_SLOTS:
36+ void testCollect();
37+ void testIterate();
38+ void testIgnoreNonNumbered();
39+ void testIgnoreNonQml();
40+ void testIgnoreDuplicates();
41+ void testDisabled();
42+
43+private:
44+ void fillRoot(const QTemporaryDir &root);
45+ void makeFile(const QTemporaryDir &root, const QString &dir, const QString &filename);
46+};
47+
48+void PageListTest::fillRoot(const QTemporaryDir &root)
49+{
50+ QVERIFY(root.isValid());
51+ QDir rootDir = root.path();
52+ QVERIFY(rootDir.mkpath(QString("a/") + PAGES_PATH));
53+ QVERIFY(rootDir.mkpath(QString("b/") + PAGES_PATH));
54+ QVERIFY(rootDir.mkpath(QString("c/") + PAGES_PATH));
55+ qputenv("XDG_DATA_DIRS", QString(rootDir.path() + "/a:" +
56+ rootDir.path() + "/b:" +
57+ rootDir.path() + "/c").toLatin1());
58+}
59+
60+void PageListTest::makeFile(const QTemporaryDir &root, const QString &dir, const QString &filename)
61+{
62+ QFile file(root.path() + "/" + dir + "/" + PAGES_PATH + "/" + filename);
63+ QVERIFY(file.open(QIODevice::WriteOnly));
64+ file.close();
65+ QVERIFY(file.exists());
66+}
67+
68+void PageListTest::testCollect()
69+{
70+ QTemporaryDir root;
71+ fillRoot(root);
72+ makeFile(root, "a", "3.qml");
73+ makeFile(root, "b", "1.qml");
74+ makeFile(root, "c", "2.qml");
75+
76+ PageList pageList;
77+ QCOMPARE(pageList.entries(), QStringList() << "1.qml" << "2.qml" << "3.qml");
78+ QCOMPARE(pageList.paths(), QStringList() << root.path() + "/b/" + PAGES_PATH + "/1.qml"
79+ << root.path() + "/c/" + PAGES_PATH + "/2.qml"
80+ << root.path() + "/a/" + PAGES_PATH + "/3.qml");
81+}
82+
83+void PageListTest::testIterate()
84+{
85+ QTemporaryDir root;
86+ fillRoot(root);
87+ makeFile(root, "a", "1.qml");
88+ makeFile(root, "a", "2.qml");
89+ makeFile(root, "a", "3.qml");
90+
91+ PageList pageList;
92+ QCOMPARE(pageList.index(), -1);
93+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/1.qml");
94+ QCOMPARE(pageList.prev(), QString());
95+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/2.qml");
96+ QCOMPARE(pageList.prev(), root.path() + "/a/" + PAGES_PATH + "/1.qml");
97+ QCOMPARE(pageList.index(), 0);
98+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/2.qml");
99+ QCOMPARE(pageList.next(), root.path() + "/a/" + PAGES_PATH + "/3.qml");
100+ QCOMPARE(pageList.index(), 2);
101+ QCOMPARE(pageList.next(), QString());
102+ QCOMPARE(pageList.index(), 2);
103+}
104+
105+void PageListTest::testIgnoreNonNumbered()
106+{
107+ QTemporaryDir root;
108+ fillRoot(root);
109+ makeFile(root, "a", "1.qml");
110+ makeFile(root, "a", "nope.qml");
111+
112+ PageList pageList;
113+ QCOMPARE(pageList.entries(), QStringList() << "1.qml");
114+}
115+
116+void PageListTest::testIgnoreNonQml()
117+{
118+ QTemporaryDir root;
119+ fillRoot(root);
120+ makeFile(root, "a", "1.qml");
121+ makeFile(root, "a", "2");
122+ makeFile(root, "a", "2.txt");
123+
124+ PageList pageList;
125+ QCOMPARE(pageList.entries(), QStringList() << "1.qml");
126+}
127+
128+void PageListTest::testIgnoreDuplicates()
129+{
130+ QTemporaryDir root;
131+ fillRoot(root);
132+ makeFile(root, "a", "1.qml");
133+ makeFile(root, "b", "1.qml");
134+
135+ PageList pageList;
136+ QCOMPARE(pageList.paths(), QStringList() << root.path() + "/a/" + PAGES_PATH + "/1.qml");
137+}
138+
139+void PageListTest::testDisabled()
140+{
141+ QTemporaryDir root;
142+ fillRoot(root);
143+ makeFile(root, "a", "1.qml.disabled"); // before the fact
144+ makeFile(root, "b", "1.qml");
145+ makeFile(root, "b", "2.qml");
146+ makeFile(root, "b", "2.qml.disabled"); // same dir
147+ makeFile(root, "b", "3.qml");
148+ makeFile(root, "b", "4.qml"); // only survivor
149+ makeFile(root, "c", "3.qml.disabled"); // after the fact
150+
151+ PageList pageList;
152+ QCOMPARE(pageList.entries(), QStringList() << "4.qml");
153+}
154+
155+QTEST_MAIN(PageListTest)
156+#include "tst_pagelist.moc"
wizard/50-com.ubuntu.system-settings.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
wizard/CMakeLists.txtnew file+65
@@ -0,0 +1,65 @@
1+# This file uses a lot of namespacing like "ubuntu-system-settings" instead of
2+# "unity8". This is because we have imported it from ubuntu-system-settings
3+# and haven't fully integrated it yet.
4+
5+include_directories(
6+ ${CMAKE_CURRENT_BINARY_DIR}
7+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
8+)
9+
10+set(PLUGIN_MANIFEST_DIR_BASE share/ubuntu/settings/system)
11+set(PLUGIN_MODULE_DIR_BASE ubuntu-system-settings)
12+set(PLUGIN_PRIVATE_MODULE_DIR_BASE "${PLUGIN_MODULE_DIR_BASE}/private")
13+set(PLUGIN_QML_DIR_BASE share/ubuntu/settings/system/qml-plugins)
14+
15+set(PLUGIN_MANIFEST_DIR "${CMAKE_INSTALL_PREFIX}/${PLUGIN_MANIFEST_DIR_BASE}")
16+set(PLUGIN_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${PLUGIN_MODULE_DIR_BASE}")
17+set(PLUGIN_PRIVATE_MODULE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${PLUGIN_PRIVATE_MODULE_DIR_BASE}")
18+set(PLUGIN_QML_DIR "${CMAKE_INSTALL_PREFIX}/${PLUGIN_QML_DIR_BASE}")
19+
20+add_definitions(-DI18N_DOMAIN="unity8")
21+add_definitions(-DPLUGIN_MANIFEST_DIR="${PLUGIN_MANIFEST_DIR}")
22+add_definitions(-DPLUGIN_MODULE_DIR="${PLUGIN_MODULE_DIR}")
23+add_definitions(-DPLUGIN_PRIVATE_MODULE_DIR="${PLUGIN_PRIVATE_MODULE_DIR}")
24+add_definitions(-DPLUGIN_QML_DIR="${PLUGIN_QML_DIR}")
25+
26+execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=plugindir unity-shell-api OUTPUT_VARIABLE SHELL_PLUGINDIR OUTPUT_STRIP_TRAILING_WHITESPACE)
27+if(SHELL_PLUGINDIR STREQUAL "")
28+ message(FATAL_ERROR "Could not determine plugin import dir.")
29+endif()
30+
31+add_definitions(-DSHELL_PLUGINDIR="${SHELL_PLUGINDIR}")
32+
33+set(WIZARD_ROOT "${CMAKE_INSTALL_PREFIX}/share")
34+add_definitions(-DWIZARD_ROOT="${WIZARD_ROOT}")
35+
36+file(GLOB_RECURSE QML_FILES
37+ qml/*
38+)
39+
40+set(WIZARD_SOURCES
41+ main.cpp
42+ PageList.cpp
43+)
44+
45+add_executable(system-settings-wizard
46+ ${WIZARD_SOURCES}
47+ ${system-settings-wizard-resources}
48+ ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
49+)
50+
51+qt5_use_modules(system-settings-wizard Core Gui Quick Qml)
52+
53+add_subdirectory(Unity)
54+add_subdirectory(Utils)
55+
56+install(TARGETS system-settings-wizard RUNTIME DESTINATION bin)
57+install(FILES ubuntu-system-settings-wizard.conf
58+ ubuntu-system-settings-wizard-cleanup.conf
59+ ubuntu-system-settings-wizard-set-lang.conf
60+ DESTINATION share/upstart/sessions)
61+
62+set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
63+install(FILES 50-com.ubuntu.system-settings.wizard.pkla DESTINATION ${POLKIT_LIB_DIR}/localauthority/10-vendor.d)
64+
65+install(DIRECTORY qml DESTINATION ${WIZARD_ROOT}/ubuntu/settings/wizard)
wizard/PageList.cppnew file+111
@@ -0,0 +1,111 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2014 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+/**
20+ * This class lets the list of wizard pages be dynamic.
21+ * - To add new ones, drop them into
22+ * $XDG_DATA_DIRS/ubuntu/settings/wizard/qml/Pages with a numbered prefix,
23+ * like "21-custom-page.qml". The number determines the order in the page
24+ * sequence that your page will appear.
25+ * - To disable an existing page, add a file like "21-custom-page.qml.disabled"
26+ * - To go to the next page, use pageStack.next()
27+ * - To go back to the previous page, use pageStack.prev()
28+ * - To load a page outside of the normal flow (so that it doesn't affect the
29+ * back button), use pageStack.push(Qt.resolvedUrl("custom-page.qml")) in
30+ * your page.
31+ * - See default pages for plenty of examples.
32+ */
33+
34+#include "PageList.h"
35+#include <QDir>
36+#include <QStandardPaths>
37+
38+#include <QDebug>
39+PageList::PageList(QObject *parent)
40+ : QObject(parent),
41+ m_index(-1),
42+ m_pages()
43+{
44+ QString qmlSuffix = ".qml";
45+ QString disabledSuffix = ".disabled";
46+ QSet<QString> disabledPages;
47+ QStringList dataDirs = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
48+
49+ QString rootDir = qgetenv("UBUNTU_SYSTEM_SETTINGS_WIZARD_ROOT"); // for testing
50+ if (!rootDir.isEmpty())
51+ dataDirs = QStringList() << rootDir;
52+
53+ Q_FOREACH(const QString &dataDir, dataDirs) {
54+ QDir dir(dataDir + "/ubuntu/settings/wizard/qml/Pages");
55+ QStringList entries = dir.entryList(QStringList("[0-9]*"), QDir::Files | QDir::Readable);
56+ Q_FOREACH(const QString &entry, entries) {
57+ if (!m_pages.contains(entry) && entry.endsWith(qmlSuffix))
58+ m_pages.insert(entry, dir.absoluteFilePath(entry));
59+ else if (entry.endsWith(qmlSuffix + disabledSuffix))
60+ disabledPages.insert(entry.left(entry.size() - disabledSuffix.size()));
61+ }
62+ }
63+
64+ // Now remove any explicitly disabled entries
65+ Q_FOREACH(const QString &page, disabledPages) {
66+ m_pages.remove(page);
67+ }
68+}
69+
70+QStringList PageList::entries() const
71+{
72+ return m_pages.keys();
73+}
74+
75+QStringList PageList::paths() const
76+{
77+ return m_pages.values();
78+}
79+
80+int PageList::index() const
81+{
82+ return m_index;
83+}
84+
85+int PageList::numPages() const
86+{
87+ return m_pages.size();
88+}
89+
90+QString PageList::prev()
91+{
92+ if (m_index > 0)
93+ return m_pages.values()[setIndex(m_index - 1)];
94+ else
95+ return QString();
96+}
97+
98+QString PageList::next()
99+{
100+ if (m_index < m_pages.count() - 1)
101+ return m_pages.values()[setIndex(m_index + 1)];
102+ else
103+ return QString();
104+}
105+
106+int PageList::setIndex(int index)
107+{
108+ m_index = index;
109+ Q_EMIT indexChanged();
110+ return m_index;
111+}
wizard/PageList.hnew file+55
@@ -0,0 +1,55 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2014 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#ifndef PAGELIST_H
20+#define PAGEList_H
21+
22+#include <QMap>
23+#include <QObject>
24+#include <QString>
25+
26+class PageList : public QObject
27+{
28+ Q_OBJECT
29+ Q_PROPERTY(int index READ index NOTIFY indexChanged)
30+ Q_PROPERTY(int numPages READ numPages NOTIFY numPagesChanged)
31+
32+public:
33+ explicit PageList(QObject *parent = 0);
34+
35+ QStringList entries() const;
36+ QStringList paths() const;
37+ int index() const;
38+ int numPages() const;
39+
40+public Q_SLOTS:
41+ QString prev();
42+ QString next();
43+
44+Q_SIGNALS:
45+ void indexChanged();
46+ void numPagesChanged(); // never emitted, just here to quiet Qml warnings
47+
48+private:
49+ int setIndex(int index);
50+
51+ int m_index;
52+ QMap<QString, QString> m_pages;
53+};
54+
55+#endif // PAGELIST_H
wizard/Unity/Application/CMakeLists.txtnew file+3
@@ -0,0 +1,3 @@
1+# This is just a small fake Unity.Application for non-Mir environments
2+set(PLUG_DIR ${PLUGIN_PRIVATE_MODULE_DIR}/Ubuntu/SystemSettings/Wizard/NonMir/Unity/Application)
3+install(FILES qmldir OSKController.qml DESTINATION ${PLUG_DIR})
wizard/Unity/Application/OSKController.qmlnew file+20
@@ -0,0 +1,20 @@
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+
19+Item {
20+}
wizard/Unity/Application/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Unity.Application
2+OSKController 0.1 OSKController.qml
wizard/Unity/CMakeLists.txtnew file+1
@@ -0,0 +1 @@
1+add_subdirectory(Application)
wizard/Utils/CMakeLists.txtnew file+27
@@ -0,0 +1,27 @@
1+include_directories(
2+ ${CMAKE_CURRENT_SOURCE_DIR}
3+ ${CMAKE_CURRENT_BINARY_DIR}
4+ ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
5+)
6+
7+set(QMLPLUGIN_SRC
8+ qsortfilterproxymodelqml.cpp
9+ plugin.cpp
10+ system.cpp
11+ )
12+
13+add_library(WizardUtils-qml SHARED
14+ ${QMLPLUGIN_SRC}
15+ )
16+
17+# Because this is an internal support library, we want
18+# to expose all symbols in it. Consider changing this
19+# either to a static library or just using the
20+# files directly in targets.
21+set_target_properties(WizardUtils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
22+
23+qt5_use_modules(WizardUtils-qml DBus Qml Quick)
24+
25+set(PLUG_DIR ${PLUGIN_PRIVATE_MODULE_DIR}/Ubuntu/SystemSettings/Wizard/Utils)
26+install(FILES qmldir DESTINATION ${PLUG_DIR})
27+install(TARGETS WizardUtils-qml DESTINATION ${PLUG_DIR})
wizard/Utils/plugin.cppnew file+41
@@ -0,0 +1,41 @@
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+// Qt
18+#include <QtQml/qqml.h>
19+#include <QQmlContext>
20+#include <QDebug>
21+// self
22+#include "plugin.h"
23+
24+// local
25+#include "qsortfilterproxymodelqml.h"
26+#include "system.h"
27+
28+static QObject *system_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
29+{
30+ Q_UNUSED(engine)
31+ Q_UNUSED(scriptEngine)
32+ return new System();
33+}
34+
35+void UtilsPlugin::registerTypes(const char *uri)
36+{
37+ Q_ASSERT(uri == QLatin1String("Ubuntu.SystemSettings.Wizard.Utils"));
38+ qmlRegisterType<QAbstractItemModel>();
39+ qmlRegisterType<QSortFilterProxyModelQML>(uri, 0, 1, "SortFilterProxyModel");
40+ qmlRegisterSingletonType<System>(uri, 0, 1, "System", system_provider);
41+}
wizard/Utils/plugin.hnew 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+
18+#ifndef UTILS_PLUGIN_H
19+#define UTILS_PLUGIN_H
20+
21+#include <QtQml/QQmlEngine>
22+#include <QtQml/QQmlExtensionPlugin>
23+
24+class UtilsPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif
wizard/Utils/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Ubuntu.SystemSettings.Wizard.Utils
2+plugin WizardUtils-qml
wizard/Utils/qsortfilterproxymodelqml.cppnew file+167
@@ -0,0 +1,167 @@
1+/*
2+ * Copyright (C) 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 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+// self
18+#include "qsortfilterproxymodelqml.h"
19+
20+// Qt
21+#include <QDebug>
22+
23+QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
24+ : QSortFilterProxyModel(parent)
25+ , m_invertMatch(false)
26+{
27+ connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
28+ connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged()));
29+ connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
30+}
31+
32+/*
33+ * Enter row index of filtered/sorted model, returns row index of source model
34+ */
35+int QSortFilterProxyModelQML::mapRowToSource(int row)
36+{
37+ if (sourceModel() == NULL)
38+ return -1;
39+
40+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
41+}
42+
43+QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
44+{
45+ return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
46+}
47+
48+void
49+QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
50+{
51+ if (itemModel == NULL) {
52+ return;
53+ }
54+
55+ if (itemModel != sourceModel()) {
56+ if (sourceModel() != NULL) {
57+ sourceModel()->disconnect(this);
58+ }
59+
60+ setSourceModel(itemModel);
61+
62+ connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged()));
63+ connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
64+ connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
65+
66+ Q_EMIT totalCountChanged();
67+ Q_EMIT modelChanged();
68+ }
69+}
70+
71+QVariantMap
72+QSortFilterProxyModelQML::get(int row)
73+{
74+ QVariantMap res;
75+ const QHash<int, QByteArray> roles = roleNames();
76+ auto it = roles.begin();
77+ for ( ; it != roles.end(); ++it) {
78+ res[*it] = data(row, it.key());
79+ }
80+ return res;
81+}
82+
83+QVariant
84+QSortFilterProxyModelQML::data(int row, int role)
85+{
86+ if (sourceModel() == NULL) {
87+ return QVariant();
88+ }
89+
90+ return index(row, 0).data(role);
91+}
92+
93+int
94+QSortFilterProxyModelQML::totalCount() const
95+{
96+ if (sourceModel() != NULL) {
97+ return sourceModel()->rowCount();
98+ } else {
99+ return 0;
100+ }
101+}
102+
103+int
104+QSortFilterProxyModelQML::count()
105+{
106+ return rowCount();
107+}
108+
109+bool
110+QSortFilterProxyModelQML::invertMatch() const
111+{
112+ return m_invertMatch;
113+}
114+
115+void
116+QSortFilterProxyModelQML::setInvertMatch(bool invertMatch)
117+{
118+ if (invertMatch != m_invertMatch) {
119+ m_invertMatch = invertMatch;
120+ Q_EMIT invertMatchChanged(invertMatch);
121+ invalidateFilter();
122+ }
123+}
124+
125+bool
126+QSortFilterProxyModelQML::filterAcceptsRow(int sourceRow,
127+ const QModelIndex &sourceParent) const
128+{
129+ // If there's no regexp set, always accept all rows indepenently of the invertMatch setting
130+ if (filterRegExp().isEmpty()) {
131+ return true;
132+ }
133+
134+ bool result = QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
135+ return (m_invertMatch) ? !result : result;
136+}
137+
138+int
139+QSortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
140+{
141+ QModelIndexList matches = match(index(0, 0), role, value, 1, Qt::MatchExactly);
142+ if (!matches.isEmpty()) {
143+ return matches.first().row();
144+ } else {
145+ return -1;
146+ }
147+}
148+
149+int
150+QSortFilterProxyModelQML::mapFromSource(int row)
151+{
152+ if (sourceModel() != NULL) {
153+ return QSortFilterProxyModel::mapFromSource(sourceModel()->index(row, 0)).row();
154+ } else {
155+ return -1;
156+ }
157+}
158+
159+int
160+QSortFilterProxyModelQML::mapToSource(int row)
161+{
162+ if (sourceModel() != NULL) {
163+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
164+ } else {
165+ return -1;
166+ }
167+}
wizard/Utils/qsortfilterproxymodelqml.hnew file+63
@@ -0,0 +1,63 @@
1+/*
2+ * Copyright (C) 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 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 QSORTFILTERPROXYMODELQML_H
18+#define QSORTFILTERPROXYMODELQML_H
19+
20+#include <QSortFilterProxyModel>
21+
22+class QSortFilterProxyModelQML : public QSortFilterProxyModel
23+{
24+ Q_OBJECT
25+
26+ Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setModel NOTIFY modelChanged)
27+ Q_PROPERTY(int totalCount READ totalCount NOTIFY totalCountChanged)
28+ Q_PROPERTY(int count READ count NOTIFY countChanged)
29+ Q_PROPERTY(bool invertMatch READ invertMatch WRITE setInvertMatch NOTIFY invertMatchChanged)
30+
31+public:
32+ explicit QSortFilterProxyModelQML(QObject *parent = 0);
33+
34+ Q_INVOKABLE QVariantMap get(int row); // Use with caution, it can be slow to query all the roles
35+ Q_INVOKABLE QVariant data(int row, int role);
36+ Q_INVOKABLE int count();
37+ Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
38+ Q_INVOKABLE int mapRowToSource(int row);
39+ virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
40+
41+ /* getters */
42+ int totalCount() const;
43+ bool invertMatch() const;
44+ QHash<int, QByteArray> roleNames() const;
45+
46+ /* setters */
47+ void setModel(QAbstractItemModel *model);
48+ void setInvertMatch(bool invertMatch);
49+
50+ Q_INVOKABLE int mapFromSource(int row);
51+ Q_INVOKABLE int mapToSource(int row);
52+
53+Q_SIGNALS:
54+ void totalCountChanged();
55+ void countChanged();
56+ void invertMatchChanged(bool);
57+ void modelChanged();
58+
59+private:
60+ bool m_invertMatch;
61+};
62+
63+#endif // QSORTFILTERPROXYMODELQML_H
wizard/Utils/system.cppnew file+118
@@ -0,0 +1,118 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2014 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#include "system.h"
20+#include <QDBusInterface>
21+#include <QDBusPendingCall>
22+#include <QDBusPendingReply>
23+#include <QFile>
24+#include <QProcess>
25+#include <unistd.h>
26+
27+#define HERE_IFACE "com.ubuntu.location.providers.here.AccountsService"
28+#define ENABLED_PROP "LicenseAccepted"
29+#define PATH_PROP "LicenseBasePath"
30+
31+System::System()
32+ : QObject(),
33+ m_accounts(nullptr),
34+ m_hereEnabled(false),
35+ m_hereLicensePath(" ") // use a single space to indicate it is unasssigned
36+{
37+ m_accounts = new QDBusInterface("org.freedesktop.Accounts",
38+ "/org/freedesktop/Accounts/User" + QString::number(geteuid()),
39+ "org.freedesktop.DBus.Properties",
40+ QDBusConnection::systemBus(),
41+ this);
42+
43+ m_accounts->connection().connect(m_accounts->service(),
44+ m_accounts->path(),
45+ m_accounts->interface(),
46+ "PropertiesChanged",
47+ this,
48+ SLOT(propertiesChanged(QString, QVariantMap, QStringList)));
49+
50+ QDBusPendingCall call = m_accounts->asyncCall("Get", HERE_IFACE, PATH_PROP);
51+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
52+ QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
53+ this, SLOT(getHereLicensePathFinished(QDBusPendingCallWatcher *)));
54+}
55+
56+void System::propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
57+{
58+ if (interface == HERE_IFACE) {
59+ if (changed.contains(ENABLED_PROP)) {
60+ m_hereEnabled = changed[ENABLED_PROP].toBool();
61+ Q_EMIT hereEnabledChanged();
62+ } else if (invalid.contains(ENABLED_PROP)) {
63+ QDBusPendingCall call = m_accounts->asyncCall("Get", HERE_IFACE, ENABLED_PROP);
64+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(call, this);
65+ QObject::connect(watcher, SIGNAL(finished(QDBusPendingCallWatcher *)),
66+ this, SLOT(getHereEnabledFinished(QDBusPendingCallWatcher *)));
67+ }
68+ }
69+}
70+
71+void System::getHereEnabledFinished(QDBusPendingCallWatcher *watcher)
72+{
73+ QDBusPendingReply<QVariant> reply = *watcher;
74+ if (!reply.isError()) {
75+ QVariant value = reply.argumentAt<0>();
76+ m_hereEnabled = value.toBool();
77+ Q_EMIT hereEnabledChanged();
78+ }
79+ watcher->deleteLater();
80+}
81+
82+void System::getHereLicensePathFinished(QDBusPendingCallWatcher *watcher)
83+{
84+ QDBusPendingReply<QVariant> reply = *watcher;
85+
86+ m_hereLicensePath = "";
87+
88+ if (!reply.isError()) {
89+ QVariant value = reply.argumentAt<0>();
90+ if (QFile::exists(value.toString())) {
91+ m_hereLicensePath = value.toString();
92+ }
93+ }
94+
95+ Q_EMIT hereLicensePathChanged();
96+
97+ watcher->deleteLater();
98+}
99+
100+bool System::hereEnabled() const
101+{
102+ return m_hereEnabled;
103+}
104+
105+void System::setHereEnabled(bool enabled)
106+{
107+ m_accounts->asyncCall("Set", HERE_IFACE, ENABLED_PROP, QVariant::fromValue(QDBusVariant(enabled)));
108+}
109+
110+QString System::hereLicensePath() const
111+{
112+ return m_hereLicensePath;
113+}
114+
115+void System::updateSessionLanguage()
116+{
117+ QProcess::startDetached("sh -c \"initctl start ubuntu-system-settings-wizard-set-lang; initctl emit --no-wait indicator-services-start; initctl start --no-wait maliit-server\"");
118+}
wizard/Utils/system.hnew file+57
@@ -0,0 +1,57 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2014 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#include <QObject>
20+#include <QString>
21+
22+class QDBusInterface;
23+class QDBusPendingCallWatcher;
24+
25+class System : public QObject
26+{
27+ Q_OBJECT
28+ Q_PROPERTY(bool hereEnabled READ hereEnabled WRITE setHereEnabled NOTIFY hereEnabledChanged)
29+ Q_PROPERTY(QString hereLicensePath READ hereLicensePath NOTIFY hereLicensePathChanged)
30+
31+public:
32+ System();
33+
34+ bool hereEnabled() const;
35+ void setHereEnabled(bool enabled);
36+
37+ QString hereLicensePath() const;
38+
39+public Q_SLOTS:
40+ void updateSessionLanguage();
41+
42+Q_SIGNALS:
43+ void hereEnabledChanged();
44+ void hereLicensePathChanged();
45+
46+private Q_SLOTS:
47+ void propertiesChanged(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
48+ void getHereEnabledFinished(QDBusPendingCallWatcher *watcher);
49+ void getHereLicensePathFinished(QDBusPendingCallWatcher *watcher);
50+
51+private:
52+ Q_DISABLE_COPY(System)
53+
54+ QDBusInterface *m_accounts;
55+ bool m_hereEnabled;
56+ QString m_hereLicensePath;
57+};
wizard/main.cppnew file+93
@@ -0,0 +1,93 @@
1+/*
2+ * This file is part of system-settings
3+ *
4+ * Copyright (C) 2014 Canonical Ltd.
5+ *
6+ * This program is free software: you can redistribute it and/or modify it
7+ * under the terms of the GNU General Public License version 3, as published
8+ * by the Free Software Foundation.
9+ *
10+ * This program is distributed in the hope that it will be useful, but
11+ * WITHOUT ANY WARRANTY; without even the implied warranties of
12+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13+ * PURPOSE. See the GNU General Public License for more details.
14+ *
15+ * You should have received a copy of the GNU General Public License along
16+ * with this program. If not, see <http://www.gnu.org/licenses/>.
17+ */
18+
19+#include <csignal>
20+#include <libintl.h>
21+#include <qpa/qplatformnativeinterface.h>
22+#include <QDebug>
23+#include <QGuiApplication>
24+#include <QLibrary>
25+#include <QObject>
26+#include <QProcess>
27+#include <QQmlContext>
28+#include <QQmlEngine>
29+#include <QQuickItem>
30+#include <QQuickView>
31+#include <QTimer>
32+
33+#include "PageList.h"
34+
35+void handleQuit()
36+{
37+ QProcess::startDetached("initctl start ubuntu-system-settings-wizard-cleanup");
38+}
39+
40+int main(int argc, const char *argv[])
41+{
42+ bool isMirServer = false;
43+ if (qgetenv("QT_QPA_PLATFORM") == "ubuntumirclient") {
44+ setenv("QT_QPA_PLATFORM", "mirserver", 1 /* overwrite */);
45+ isMirServer = true;
46+ }
47+
48+ QGuiApplication::setApplicationName("System Settings Wizard");
49+ QGuiApplication *application = new QGuiApplication(argc, (char**)argv);
50+
51+ bindtextdomain(I18N_DOMAIN, NULL);
52+ textdomain(I18N_DOMAIN);
53+
54+ QQuickView* view = new QQuickView();
55+ view->setResizeMode(QQuickView::SizeRootObjectToView);
56+ view->setTitle("Welcome Wizard");
57+
58+ QString rootDir = qgetenv("UBUNTU_SYSTEM_SETTINGS_WIZARD_ROOT"); // for testing
59+ if (rootDir.isEmpty())
60+ rootDir = WIZARD_ROOT;
61+
62+ QString modulesDir = qgetenv("UBUNTU_SYSTEM_SETTINGS_WIZARD_MODULES"); // for testing
63+ if (modulesDir.isEmpty())
64+ modulesDir = PLUGIN_PRIVATE_MODULE_DIR;
65+
66+ if (!isMirServer) {
67+ view->engine()->addImportPath(modulesDir + "/Ubuntu/SystemSettings/Wizard/NonMir");
68+ }
69+ view->engine()->addImportPath(modulesDir);
70+ view->engine()->addImportPath(PLUGIN_QML_DIR);
71+ view->engine()->addImportPath(SHELL_PLUGINDIR);
72+
73+ PageList pageList;
74+ view->rootContext()->setContextProperty("pageList", &pageList);
75+ view->setSource(QUrl(rootDir + "/ubuntu/settings/wizard/qml/main.qml"));
76+ view->setColor("transparent");
77+
78+ QObject::connect(view->engine(), &QQmlEngine::quit, handleQuit);
79+
80+ if (isMirServer) {
81+ view->showFullScreen();
82+ } else {
83+ view->show();
84+ }
85+
86+ int result = application->exec();
87+
88+ delete view;
89+ delete application;
90+ return result;
91+}
92+
93+#include "main.moc"
wizard/qml/Components/CheckableSetting.qmlnew file+85
@@ -0,0 +1,85 @@
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 QMenuModel 0.1
19+import Ubuntu.Components 1.1
20+import Ubuntu.Components.ListItems 1.0 as ListItem
21+
22+ListItem.Empty {
23+ id: listItem
24+
25+ property alias text: label.text
26+ property bool checked: false
27+ property real leftMargin
28+ property real rightMargin
29+
30+ readonly property real labelOffset: label.x
31+
32+ signal linkActivated(string link)
33+
34+ implicitHeight: Math.max(label.height, checkBox.height)
35+
36+ Item {
37+ anchors.fill: parent
38+
39+ CheckBox {
40+ id: checkBox
41+
42+ anchors {
43+ left: parent.left
44+ top: parent.top
45+ leftMargin: listItem.leftMargin
46+ }
47+
48+ Component.onCompleted: {
49+ checked = listItem.checked;
50+ }
51+
52+ onClicked: {
53+ listItem.checked = checked
54+ listItem.triggered(listItem.checked)
55+ }
56+
57+ Connections {
58+ target: listItem
59+ onCheckedChanged: checkBox.checked = listItem.checked
60+ }
61+
62+ Connections {
63+ target: listItem.__mouseArea
64+ onClicked: {
65+ listItem.checked = !listItem.checked
66+ listItem.triggered(listItem.checked)
67+ }
68+ }
69+ }
70+
71+ Label {
72+ id: label
73+ anchors {
74+ left: checkBox.right
75+ right: parent.right
76+ verticalCenter: parent.verticalCenter
77+ leftMargin: units.gu(2)
78+ rightMargin: listItem.rightMargin
79+ }
80+ wrapMode: Text.Wrap
81+ linkColor: Theme.palette.normal.foregroundText
82+ onLinkActivated: listItem.linkActivated(link)
83+ }
84+ }
85+}
wizard/qml/Components/InputMethod.qmlnew file+113
@@ -0,0 +1,113 @@
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.0
18+import Unity.Application 0.1
19+import Ubuntu.Components 0.1
20+
21+// TODO: try to share this code with that from the unity8 shell
22+
23+Item {
24+ id: root
25+
26+ Connections {
27+ target: SurfaceManager
28+ onSurfaceCreated: {
29+ if (surface.type == MirSurfaceItem.InputMethod) {
30+ root.surface = surface;
31+ }
32+ }
33+
34+ onSurfaceDestroyed: {
35+ if (root.surface == surface) {
36+ root.surface = null;
37+ surface.parent = null;
38+ }
39+ if (!surface.parent) {
40+ // there's no one displaying it. delete it right away
41+ surface.release();
42+ }
43+ }
44+ }
45+
46+ property var surface: null
47+
48+ property int transitionDuration: UbuntuAnimation.FastDuration
49+
50+ state: {
51+ if (surface && surface.state != MirSurfaceItem.Minimized) {
52+ return "shown";
53+ } else {
54+ return "hidden";
55+ }
56+ }
57+
58+ states: [
59+ State {
60+ name: "shown"
61+ PropertyChanges {
62+ target: root
63+ visible: true
64+ y: 0
65+ }
66+ },
67+ State {
68+ name: "hidden"
69+ PropertyChanges {
70+ target: root
71+ visible: false
72+ // half-way down because the vkb occupies only the lower half of the surface
73+ // TODO: consider keyboard rotation
74+ y: root.parent.height / 2.0
75+ }
76+ }
77+ ]
78+
79+ transitions: [
80+ Transition {
81+ from: "*"; to: "*"
82+ PropertyAction { property: "visible"; value: true }
83+ UbuntuNumberAnimation { property: "y"; duration: transitionDuration }
84+ }
85+ ]
86+
87+ Connections {
88+ target: surface
89+ ignoreUnknownSignals: true // don't wanna spam the log when surface is null
90+ onStateChanged: {
91+ if (state == MirSurfaceItem.Minimized) {
92+ root.hide();
93+ } else if (state == MirSurfaceItem.Maximized) {
94+ root.show();
95+ }
96+ }
97+ }
98+
99+ onSurfaceChanged: {
100+ if (surface) {
101+ surface.parent = root;
102+ surface.anchors.fill = root;
103+ }
104+ }
105+
106+ Component.onDestruction: {
107+ if (surface) {
108+ surface.parent = null;
109+ surface.release();
110+ surface = null;
111+ }
112+ }
113+}
wizard/qml/Components/Page.qmlnew file+107
@@ -0,0 +1,107 @@
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 "." as LocalComponents
20+
21+Item {
22+ readonly property real buttonMargin: units.gu(2)
23+ readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
24+ buttonMargin / 2
25+ readonly property real topMargin: units.gu(8)
26+ readonly property real leftMargin: units.gu(2)
27+ readonly property real rightMargin: units.gu(2)
28+
29+ // If you want to skip a page, mark skipValid false while you figure out
30+ // whether to skip, then set it to true once you've determined the value
31+ // of the skip property.
32+ property bool skipValid: true
33+ property bool skip: false
34+
35+ property bool hasBackButton: true
36+ property bool customBack: false
37+ property alias forwardButtonSourceComponent: forwardButton.sourceComponent
38+ property alias content: contentHolder
39+
40+ property string title: ""
41+
42+ signal backClicked()
43+
44+ visible: false
45+ anchors.fill: parent
46+
47+ // We want larger than even fontSize: "x-large", so we use a Text instead
48+ // of a Label.
49+ Text {
50+ id: titleLabel
51+ anchors {
52+ top: parent.top
53+ left: parent.left
54+ right: parent.right
55+ topMargin: topMargin
56+ leftMargin: leftMargin
57+ rightMargin: rightMargin
58+ }
59+ wrapMode: Text.Wrap
60+ text: title
61+ color: Theme.palette.normal.baseText
62+ font.pixelSize: units.gu(4)
63+ }
64+
65+ Item {
66+ id: contentHolder
67+ anchors {
68+ top: titleLabel.bottom
69+ left: parent.left
70+ right: parent.right
71+ bottom: backButton.top
72+ topMargin: units.gu(4)
73+ leftMargin: leftMargin
74+ rightMargin: rightMargin
75+ bottomMargin: buttonMargin
76+ }
77+ }
78+
79+ LocalComponents.StackButton {
80+ id: 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+ width: buttonWidth
99+ anchors {
100+ right: parent.right
101+ bottom: parent.bottom
102+ rightMargin: buttonMargin
103+ bottomMargin: buttonMargin
104+ }
105+ z: 1
106+ }
107+}
wizard/qml/Components/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+}
wizard/qml/Pages/10-welcome.qmlnew file+93
@@ -0,0 +1,93 @@
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 Ubuntu.SystemSettings.Wizard.Utils 0.1
22+import "../Components" as LocalComponents
23+
24+LocalComponents.Page {
25+ title: i18n.tr("Hi!")
26+ forwardButtonSourceComponent: forwardButton
27+
28+ UbuntuLanguagePlugin {
29+ id: plugin
30+ }
31+
32+ Column {
33+ id: column
34+ anchors.fill: content
35+ spacing: units.gu(1)
36+
37+ Label {
38+ id: label1
39+ anchors.left: parent.left
40+ anchors.right: parent.right
41+ wrapMode: Text.Wrap
42+ text: i18n.tr("Welcome to your Ubuntu phone.")
43+ }
44+
45+ Label {
46+ id: label2
47+ anchors.left: parent.left
48+ anchors.right: parent.right
49+ wrapMode: Text.Wrap
50+ text: i18n.tr("Let’s get started.")
51+ }
52+
53+ Item { // spacer
54+ height: units.gu(2)
55+ width: units.gu(1) // needed else it will be ignored
56+ }
57+
58+ ComboButton {
59+ id: combo
60+ anchors.left: parent.left
61+ anchors.right: parent.right
62+ text: listview.currentItem.text
63+ onClicked: expanded = !expanded
64+ expandedHeight: column.height - combo.y
65+ UbuntuListView {
66+ id: listview
67+ model: plugin.languageNames
68+ currentIndex: plugin.currentLanguage
69+ delegate: Standard {
70+ text: modelData
71+ onClicked: {
72+ listview.currentIndex = index
73+ combo.expanded = false
74+ i18n.language = plugin.languageCodes[index]
75+ i18n.domain = i18n.domain
76+ }
77+ }
78+ }
79+ }
80+ }
81+
82+ Component {
83+ id: forwardButton
84+ LocalComponents.StackButton {
85+ text: i18n.tr("Continue")
86+ onClicked: {
87+ plugin.currentLanguage = listview.currentIndex
88+ System.updateSessionLanguage()
89+ pageStack.next()
90+ }
91+ }
92+ }
93+}
wizard/qml/Pages/20-sim.qmlnew file+71
@@ -0,0 +1,71 @@
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 "../Components" as LocalComponents
21+
22+LocalComponents.Page {
23+ title: i18n.tr("Add a SIM card and restart your device")
24+ forwardButtonSourceComponent: forwardButton
25+
26+ // No need for skipValid, since OfonoManager does everything synchronously
27+ skip: !manager.available || manager.modems.length === 0 || simManager0.present || simManager1.present
28+
29+ OfonoManager {
30+ id: manager
31+ }
32+
33+ // Ideally we would query the system more cleverly than hardcoding two
34+ // modems. But we don't yet have a more clever way. :(
35+ OfonoSimManager {
36+ id: simManager0
37+ modemPath: manager.modems.length >= 1 ? manager.modems[0] : ""
38+ }
39+
40+ OfonoSimManager {
41+ id: simManager1
42+ modemPath: manager.modems.length >= 2 ? manager.modems[1] : ""
43+ }
44+
45+ Column {
46+ anchors.fill: content
47+ spacing: units.gu(4)
48+
49+ Label {
50+ anchors.left: parent.left
51+ anchors.right: parent.right
52+ wrapMode: Text.Wrap
53+ text: i18n.tr("Without it, you won’t be able to make calls or use text messaging.")
54+ }
55+
56+ Image {
57+ id: image
58+ source: "data/meet_ubuntu_simcard@30.png"
59+ height: units.gu(6.5)
60+ width: units.gu(9)
61+ }
62+ }
63+
64+ Component {
65+ id: forwardButton
66+ LocalComponents.StackButton {
67+ text: i18n.tr("Skip")
68+ onClicked: pageStack.next()
69+ }
70+ }
71+}
wizard/qml/Pages/30-passwd-type.qmlnew file+119
@@ -0,0 +1,119 @@
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 "../Components" 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+ title: i18n.tr("Lock security")
38+ forwardButtonSourceComponent: forwardButton
39+
40+ function indexToMethod(index) {
41+ if (index === 0)
42+ return UbuntuSecurityPrivacyPanel.Swipe
43+ else if (index === 1)
44+ return UbuntuSecurityPrivacyPanel.Passcode
45+ else
46+ return UbuntuSecurityPrivacyPanel.Passphrase
47+ }
48+
49+ function methodToIndex(method) {
50+ if (method === UbuntuSecurityPrivacyPanel.Swipe)
51+ return 0
52+ else if (method === UbuntuSecurityPrivacyPanel.Passcode)
53+ return 1
54+ else
55+ return 2
56+ }
57+
58+ Connections {
59+ target: root
60+ onPasswordMethodChanged: selector.selectedIndex = methodToIndex(root.passwordMethod)
61+ }
62+
63+ Column {
64+ id: column
65+ anchors.fill: content
66+ spacing: units.gu(4)
67+
68+ Label {
69+ anchors.left: parent.left
70+ anchors.right: parent.right
71+ wrapMode: Text.Wrap
72+ text: i18n.tr("Please select how you’d like to unlock your phone.")
73+ }
74+
75+ ItemSelector {
76+ id: selector
77+ expanded: true
78+ anchors.left: parent.left
79+ anchors.right: parent.right
80+
81+ model: ["", "", ""] // otherwise the delegate will show the text itself and we only want subText
82+
83+ selectedIndex: methodToIndex(root.passwordMethod)
84+
85+ delegate: OptionSelectorDelegate {
86+ // use subText because we want the text to be small, and we have no other way to control it
87+ subText: {
88+ var method = indexToMethod(index)
89+ var name = ""
90+ var desc = ""
91+ if (method === UbuntuSecurityPrivacyPanel.Swipe) {
92+ name = i18n.tr("Swipe")
93+ desc = i18n.tr("No security")
94+ } else if (method === UbuntuSecurityPrivacyPanel.Passcode) {
95+ name = i18n.tr("Passcode")
96+ desc = i18n.tr("4 digits only")
97+ } else {
98+ name = i18n.tr("Passphrase")
99+ desc = i18n.tr("Numbers and letters")
100+ }
101+ return "<b>%1</b> (%2)".arg(name).arg(desc)
102+ }
103+ }
104+
105+ style: Item {}
106+ }
107+ }
108+
109+ Component {
110+ id: forwardButton
111+ LocalComponents.StackButton {
112+ text: i18n.tr("Continue")
113+ onClicked: {
114+ root.passwordMethod = indexToMethod(selector.selectedIndex)
115+ pageStack.load(Qt.resolvedUrl("passwd-set.qml"))
116+ }
117+ }
118+ }
119+}
wizard/qml/Pages/40-wifi.qmlnew file+200
@@ -0,0 +1,200 @@
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.SystemSettings.Wizard.Utils 0.1
22+import Ubuntu.Settings.Menus 0.1 as Menus
23+import "../Components" as LocalComponents
24+
25+LocalComponents.Page {
26+ id: wifiPage
27+ title: i18n.tr("Connect to Wi‑Fi")
28+ forwardButtonSourceComponent: forwardButton
29+
30+ readonly property bool connected: mainMenu.connectedAPs === 1
31+
32+ function getExtendedProperty(object, propertyName, defaultValue) {
33+ if (object && object.hasOwnProperty(propertyName)) {
34+ return object[propertyName];
35+ }
36+ return defaultValue;
37+ }
38+
39+ QMenuModel.UnityMenuModel {
40+ id: menuModel
41+ busName: "com.canonical.indicator.network"
42+ actions: { "indicator": "/com/canonical/indicator/network" }
43+ menuObjectPath: "/com/canonical/indicator/network/phone_wifi_settings"
44+ }
45+
46+ Component {
47+ id: accessPointComponent
48+ ListItem.Standard {
49+ id: accessPoint
50+ objectName: "accessPoint"
51+
52+ property QtObject menuData: null
53+ property var unityMenuModel: menuModel
54+ property var extendedData: menuData && menuData.ext || undefined
55+ property var strengthAction: QMenuModel.UnityMenuAction {
56+ model: unityMenuModel
57+ index: menuIndex
58+ name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
59+ }
60+ property bool checked: menuData && menuData.isToggled || false
61+ property bool secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
62+ property bool adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
63+ property int signalStrength: strengthAction.valid ? strengthAction.state : 0
64+ property int menuIndex: -1
65+
66+ function loadAttributes() {
67+ if (!unityMenuModel || menuIndex == -1) return;
68+ unityMenuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
69+ 'x-canonical-wifi-ap-is-secure': 'bool',
70+ 'x-canonical-wifi-ap-strength-action': 'string'});
71+ }
72+
73+ signal activate()
74+
75+ text: menuData && menuData.label || ""
76+ enabled: menuData && menuData.sensitive || false
77+ iconName: {
78+ var imageName = "nm-signal-100";
79+
80+ if (adHoc) {
81+ imageName = "nm-adhoc";
82+ } else if (signalStrength == 0) {
83+ imageName = "nm-signal-00";
84+ } else if (signalStrength <= 25) {
85+ imageName = "nm-signal-25";
86+ } else if (signalStrength <= 50) {
87+ imageName = "nm-signal-50";
88+ } else if (signalStrength <= 75) {
89+ imageName = "nm-signal-75";
90+ }
91+
92+ if (secure) {
93+ imageName += "-secure";
94+ }
95+ return imageName;
96+ }
97+ iconFrame: false
98+ control: CheckBox {
99+ id: checkBoxActive
100+
101+ onClicked: {
102+ accessPoint.activate();
103+ }
104+ }
105+ style: Rectangle {
106+ color: "#4c000000"
107+ }
108+
109+ Component.onCompleted: {
110+ loadAttributes();
111+ }
112+ onUnityMenuModelChanged: {
113+ loadAttributes();
114+ }
115+ onMenuIndexChanged: {
116+ loadAttributes();
117+ }
118+ onCheckedChanged: {
119+ // Can't rely on binding. Checked is assigned on click.
120+ checkBoxActive.checked = checked;
121+ if (checked) {
122+ mainMenu.connectedAPs++
123+ } else {
124+ mainMenu.connectedAPs--
125+ }
126+ }
127+ onActivate: unityMenuModel.activate(menuIndex);
128+ }
129+ }
130+
131+ Column {
132+ id: column
133+ spacing: units.gu(2)
134+ anchors.top: content.top
135+ anchors.bottom: content.bottom
136+ anchors.left: wifiPage.left
137+ anchors.right: wifiPage.right
138+
139+ Label {
140+ id: label
141+ anchors.left: parent.left
142+ anchors.leftMargin: leftMargin
143+ anchors.right: parent.right
144+ anchors.rightMargin: rightMargin
145+ fontSize: "small"
146+ text: mainMenu.count > 0 ? i18n.tr("Available networks…")
147+ : i18n.tr("No available networks.")
148+ }
149+
150+ Flickable {
151+ anchors.left: parent.left
152+ anchors.right: parent.right
153+ height: column.height - label.height - column.spacing
154+ contentHeight: contentItem.childrenRect.height
155+ clip: true
156+ flickDeceleration: 1500 * units.gridUnit / 8
157+ maximumFlickVelocity: 2500 * units.gridUnit / 8
158+ boundsBehavior: (contentHeight > height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
159+
160+ Column {
161+ anchors.left: parent.left
162+ anchors.right: parent.right
163+
164+ Repeater {
165+ id: mainMenu
166+
167+ // FIXME Check connection better https://bugs.launchpad.net/indicator-network/+bug/1349371
168+ property int connectedAPs: 0
169+
170+ model: menuModel
171+
172+ delegate: Loader {
173+ id: loader
174+
175+ readonly property bool isAccessPoint: model.type === "unity.widgets.systemsettings.tablet.accesspoint"
176+
177+ anchors.left: parent.left
178+ anchors.right: parent.right
179+ height: isAccessPoint ? units.gu(6) : 0
180+ asynchronous: true
181+ sourceComponent: isAccessPoint ? accessPointComponent : null
182+
183+ onLoaded: {
184+ item.menuData = Qt.binding(function() { return model; });
185+ item.menuIndex = Qt.binding(function() { return index; });
186+ }
187+ }
188+ }
189+ }
190+ }
191+ }
192+
193+ Component {
194+ id: forwardButton
195+ LocalComponents.StackButton {
196+ text: (connected || mainMenu.count === 0) ? i18n.tr("Continue") : i18n.tr("Skip")
197+ onClicked: pageStack.next()
198+ }
199+ }
200+}
wizard/qml/Pages/50-location.qmlnew file+149
@@ -0,0 +1,149 @@
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 QMenuModel 0.1 as QMenuModel
19+import Qt.labs.folderlistmodel 2.1
20+import Ubuntu.Components 1.1
21+import Ubuntu.SystemSettings.Wizard.Utils 0.1
22+import "../Components" as LocalComponents
23+
24+LocalComponents.Page {
25+ title: i18n.tr("Location")
26+ forwardButtonSourceComponent: forwardButton
27+
28+ property bool pathSet: System.hereLicensePath !== " " // single space means it's unassigned
29+ property bool countSet: false
30+ skipValid: pathSet && (System.hereLicensePath === "" || countSet)
31+ skip: skipValid && (System.hereLicensePath === "" || termsModel.count === 0)
32+
33+ Connections {
34+ target: termsModel
35+ onCountChanged: if (pathSet) countSet = true
36+ }
37+
38+ FolderListModel {
39+ id: termsModel
40+ folder: System.hereLicensePath
41+ nameFilters: ["*.html"]
42+ showDirs: false
43+ showOnlyReadable: true
44+ }
45+
46+ QMenuModel.QDBusActionGroup {
47+ id: locationActionGroup
48+ busType: QMenuModel.DBus.SessionBus
49+ busName: "com.canonical.indicator.location"
50+ objectPath: "/com/canonical/indicator/location"
51+ property variant location: action("location-detection-enabled")
52+ property variant gps: action("gps-detection-enabled")
53+ Component.onCompleted: start()
54+ }
55+
56+ Column {
57+ id: column
58+ anchors.fill: content
59+ spacing: units.gu(3)
60+
61+ Label {
62+ anchors.left: parent.left
63+ anchors.right: parent.right
64+ wrapMode: Text.Wrap
65+ text: i18n.tr("Let the phone detect your location:")
66+ }
67+
68+ LocalComponents.CheckableSetting {
69+ id: gpsCheck
70+ showDivider: false
71+ text: i18n.tr("Using GPS only (less accurate)")
72+ onTriggered: {
73+ gpsCheck.checked = true;
74+ hereCheck.checked = false;
75+ nopeCheck.checked = false;
76+ }
77+ }
78+
79+ Column {
80+ anchors.left: parent.left
81+ anchors.right: parent.right
82+ height: childrenRect.height
83+
84+ LocalComponents.CheckableSetting {
85+ id: hereCheck
86+ showDivider: false
87+ text: i18n.tr("Using GPS, anonymized Wi-Fi and cellular network info (recommended)")
88+ checked: true
89+ onTriggered: {
90+ gpsCheck.checked = false;
91+ hereCheck.checked = true;
92+ nopeCheck.checked = false;
93+ }
94+ }
95+
96+ Label {
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+ showDivider: false
111+ text: i18n.tr("Not at all")
112+ onTriggered: {
113+ gpsCheck.checked = false;
114+ hereCheck.checked = false;
115+ nopeCheck.checked = true;
116+ }
117+ }
118+
119+ Label {
120+ anchors.left: parent.left
121+ anchors.right: parent.right
122+ wrapMode: Text.Wrap
123+ text: i18n.tr("You can change your mind later in <b>System Settings</b>.")
124+ }
125+ }
126+
127+ Component {
128+ id: forwardButton
129+ LocalComponents.StackButton {
130+ text: i18n.tr("Continue")
131+ onClicked: {
132+ var locationOn = gpsCheck.checked || hereCheck.checked;
133+ var gpsOn = gpsCheck.checked || hereCheck.checked;
134+ var hereOn = hereCheck.checked;
135+
136+ // location service doesn't currently listen to updateState
137+ // requests, so we activate the actions if needed.
138+ if (locationActionGroup.location.state != locationOn) {
139+ locationActionGroup.location.activate();
140+ }
141+ if (locationActionGroup.gps.state != gpsOn) {
142+ locationActionGroup.gps.activate();
143+ }
144+ System.hereEnabled = hereOn;
145+ pageStack.next()
146+ }
147+ }
148+ }
149+}
wizard/qml/Pages/60-reporting.qmlnew file+52
@@ -0,0 +1,52 @@
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 "../Components" as LocalComponents
20+
21+LocalComponents.Page {
22+ title: i18n.tr("Improving your experience")
23+ forwardButtonSourceComponent: forwardButton
24+
25+ Column {
26+ id: column
27+ anchors.fill: content
28+ spacing: units.gu(2)
29+
30+ Label {
31+ anchors.left: parent.left
32+ anchors.right: parent.right
33+ wrapMode: Text.Wrap
34+ text: i18n.tr("Your phone is set up to automatically report errors to Canonical and its partners, the makers of the operating system.")
35+ }
36+
37+ Label {
38+ anchors.left: parent.left
39+ anchors.right: parent.right
40+ wrapMode: Text.Wrap
41+ text: i18n.tr("This can be disabled in <b>System Settings</b> under <b>Security &amp; Privacy</b>")
42+ }
43+ }
44+
45+ Component {
46+ id: forwardButton
47+ LocalComponents.StackButton {
48+ text: i18n.tr("Continue")
49+ onClicked: pageStack.next()
50+ }
51+ }
52+}
wizard/qml/Pages/80-finished.qmlnew file+55
@@ -0,0 +1,55 @@
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 "../Components" as LocalComponents
20+
21+LocalComponents.Page {
22+ title: i18n.tr("All done")
23+ forwardButtonSourceComponent: forwardButton
24+ hasBackButton: false
25+
26+ Column {
27+ id: column
28+ anchors.fill: content
29+ spacing: units.gu(1)
30+
31+ Label {
32+ anchors.left: parent.left
33+ anchors.right: parent.right
34+ wrapMode: Text.Wrap
35+ fontSize: "large"
36+ font.bold: true
37+ text: i18n.tr("Nice work!")
38+ }
39+
40+ Label {
41+ anchors.left: parent.left
42+ anchors.right: parent.right
43+ wrapMode: Text.Wrap
44+ text: i18n.tr("Your phone is now ready to use.")
45+ }
46+ }
47+
48+ Component {
49+ id: forwardButton
50+ LocalComponents.StackButton {
51+ text: i18n.tr("Finish")
52+ onClicked: root.quitWizard()
53+ }
54+ }
55+}
wizard/qml/Pages/data/meet_ubuntu_simcard@30.pngnew file

Binary file not shown.

wizard/qml/Pages/here-terms.qmlnew file+117
@@ -0,0 +1,117 @@
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 Qt.labs.folderlistmodel 2.1
19+import Ubuntu.Components 1.1
20+import Ubuntu.SystemSettings.Wizard.Utils 0.1
21+import Ubuntu.Web 0.2
22+import "../Components" as LocalComponents
23+
24+LocalComponents.Page {
25+ title: i18n.tr("Terms & Conditions")
26+ customBack: true
27+
28+ FolderListModel {
29+ id: termsModel
30+ folder: System.hereLicensePath
31+ nameFilters: ["*.html"]
32+ showDirs: false
33+ showOnlyReadable: true
34+ onCountChanged: loadFileContent()
35+ }
36+
37+ function makeFileName(lang, country) {
38+ return lang + "_" + country + ".html"
39+ }
40+
41+ function defaultCountryForLanguage(lang) {
42+ if (lang === "da") return "DK"
43+ if (lang === "en") return "US"
44+ if (lang === "ko") return "KR"
45+ if (lang === "zh") return "CN"
46+ return lang.toUpperCase()
47+ }
48+
49+ function determineFileName() {
50+ var codes = i18n.language.split(".")[0].split("_")
51+ var defaultCountry = defaultCountryForLanguage(codes[0])
52+ if (codes.count === 1)
53+ codes = [codes[0], defaultCountry]
54+ var perfectMatch = makeFileName(codes[0], codes[1])
55+ var nearMatch = makeFileName(codes[0], defaultCountry)
56+ var nearMatchExists = false
57+
58+ for (var i = 0; i < termsModel.count; i++) {
59+ var fileName = termsModel.get(i, "fileName")
60+ if (fileName == perfectMatch) {
61+ return perfectMatch
62+ } else if (fileName == nearMatch) {
63+ nearMatchExists = true
64+ }
65+ }
66+
67+ if (nearMatchExists) {
68+ return nearMatch
69+ } else {
70+ return makeFileName("en", "US")
71+ }
72+ }
73+
74+ function loadFileContent() {
75+ var xhr = new XMLHttpRequest
76+ xhr.open("GET", System.hereLicensePath + "/" + determineFileName())
77+ xhr.onreadystatechange = function() {
78+ if (xhr.readyState == XMLHttpRequest.DONE) {
79+ termsLabel.text = xhr.responseText
80+ }
81+ }
82+ xhr.send()
83+ }
84+
85+ onBackClicked: {
86+ if (webview.visible) {
87+ termsLabel.visible = true
88+ } else {
89+ pageStack.prev()
90+ }
91+ }
92+
93+ Column {
94+ id: column
95+ anchors.fill: content
96+
97+ Label {
98+ id: termsLabel
99+ anchors.left: parent.left
100+ anchors.right: parent.right
101+ wrapMode: Text.Wrap
102+ linkColor: Theme.palette.normal.foregroundText
103+ onLinkActivated: {
104+ webview.url = link
105+ termsLabel.visible = false
106+ }
107+ }
108+
109+ WebView {
110+ id: webview
111+ anchors.left: parent.left
112+ anchors.right: parent.right
113+ height: parent.height
114+ visible: !termsLabel.visible
115+ }
116+ }
117+}
wizard/qml/Pages/passwd-confirm.qmlnew file+79
@@ -0,0 +1,79 @@
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 "../Components" as LocalComponents
21+import "file:///usr/share/unity8/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+ forwardButtonSourceComponent: forwardButton
31+
32+ skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
33+
34+ // If we are entering this page, clear any saved password and get focus
35+ onEnabledChanged: if (enabled) lockscreen.clear(false)
36+
37+ UnityComponents.Lockscreen {
38+ id: lockscreen
39+ anchors {
40+ fill: parent
41+ topMargin: topMargin
42+ leftMargin: leftMargin
43+ rightMargin: rightMargin
44+ bottomMargin: buttonMargin
45+ }
46+
47+ infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
48+ i18n.tr("Confirm passphrase") :
49+ i18n.tr("Confirm passcode")
50+
51+ errorText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
52+ i18n.tr("Sorry, incorrect passphrase.") + "\n" + i18n.tr("Please try again.") :
53+ i18n.tr("Sorry, incorrect passcode.") + "\n" + i18n.tr("Please try again.")
54+
55+ showEmergencyCallButton: false
56+ showCancelButton: false
57+ alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
58+ minPinLength: 4
59+ maxPinLength: 4
60+
61+ onEntered: {
62+ if (passphrase === root.password) {
63+ pageStack.next()
64+ } else {
65+ clear(true)
66+ }
67+ }
68+ }
69+
70+ Component {
71+ id: forwardButton
72+ LocalComponents.StackButton {
73+ visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
74+ enabled: root.password === lockscreen.passphrase
75+ text: i18n.tr("Continue")
76+ onClicked: pageStack.next()
77+ }
78+ }
79+}
wizard/qml/Pages/passwd-set.qmlnew file+87
@@ -0,0 +1,87 @@
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 "../Components" as LocalComponents
21+import "file:///usr/share/unity8/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+ forwardButtonSourceComponent: forwardButton
31+
32+ skip: root.passwordMethod === UbuntuSecurityPrivacyPanel.Swipe
33+
34+ // If we are entering this page, clear any saved password and get focus
35+ onEnabledChanged: if (enabled) lockscreen.clear(false)
36+
37+ function confirm() {
38+ root.password = lockscreen.passphrase;
39+ pageStack.load(Qt.resolvedUrl("passwd-confirm.qml"));
40+ }
41+
42+ UnityComponents.Lockscreen {
43+ id: lockscreen
44+ anchors {
45+ fill: parent
46+ topMargin: topMargin
47+ leftMargin: leftMargin
48+ rightMargin: rightMargin
49+ bottomMargin: buttonMargin
50+ }
51+
52+ infoText: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase ?
53+ i18n.tr("Enter passphrase") :
54+ i18n.tr("Choose your passcode")
55+
56+ // Note that the number four comes from PAM settings,
57+ // which we don't have a good way to interrogate. We
58+ // only do this matching instead of PAM because we want
59+ // to set the password via PAM in a different place
60+ // than this page. See comments at top of passwd-type file.
61+ errorText: i18n.tr("Passphrase must be 4 characters long")
62+
63+ showEmergencyCallButton: false
64+ showCancelButton: false
65+ alphaNumeric: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
66+ minPinLength: 4
67+ maxPinLength: 4
68+
69+ onEntered: {
70+ if (passphrase.length >= 4) {
71+ passwdSetPage.confirm();
72+ } else {
73+ lockscreen.clear(true)
74+ }
75+ }
76+ }
77+
78+ Component {
79+ id: forwardButton
80+ LocalComponents.StackButton {
81+ visible: root.passwordMethod === UbuntuSecurityPrivacyPanel.Passphrase
82+ enabled: lockscreen.passphrase.length >= 4
83+ text: i18n.tr("Continue")
84+ onClicked: passwdSetPage.confirm()
85+ }
86+ }
87+}
wizard/qml/main.qmlnew file+246
@@ -0,0 +1,246 @@
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 GSettings 1.0
19+import Ubuntu.Components 1.1
20+import Ubuntu.SystemSettings.SecurityPrivacy 1.0
21+import Unity.Application 0.1
22+import Unity.Notifications 1.0 as NotificationBackend
23+import Unity.Session 0.1
24+import "Components"
25+import "file:///usr/share/unity8/Notifications" as Notifications // FIXME This should become a module or go away
26+import "file:///usr/share/unity8/Components" as UnityComponents
27+
28+Item {
29+ id: root
30+ width: units.gu(40)
31+ height: units.gu(71)
32+ focus: true
33+
34+ // These should be set by a security page and we apply the settings when
35+ // the user exits the wizard.
36+ property int passwordMethod: UbuntuSecurityPrivacyPanel.Passcode
37+ property string password: ""
38+
39+ Component.onCompleted: {
40+ Theme.name = "Ubuntu.Components.Themes.SuruGradient"
41+ // A visible selected background looks bad in ListItem widgets with our theme
42+ Theme.palette.selected.background = "#00000000"
43+ i18n.domain = "unity8"
44+ }
45+
46+ UbuntuSecurityPrivacyPanel {
47+ id: securityPrivacy
48+ }
49+
50+ function quitWizard() {
51+ // Immediately go to black to give quick feedback
52+ blackCover.visible = true
53+
54+ var errorMsg = securityPrivacy.setSecurity("", password, passwordMethod)
55+ if (errorMsg !== "") {
56+ // Ignore (but log) any errors, since we're past where the user set
57+ // the method. Worst case, we just leave the user with a swipe
58+ // security method and they fix it in the system settings.
59+ console.log("Error setting security method:", errorMsg)
60+ }
61+
62+ Qt.quit()
63+ }
64+
65+ // This is just a little screen to immediately go to black once the wizard
66+ // is done, to give quick feedback to the user.
67+ Rectangle {
68+ id: blackCover
69+ color: "#000000"
70+ anchors.fill: parent
71+ z: 1
72+ visible: false
73+ }
74+
75+ MainView {
76+ anchors.fill: parent
77+ headerColor: "#57365E"
78+ backgroundColor: "#A55263"
79+ footerColor: "#D75669"
80+ anchorToKeyboard: true
81+ useDeprecatedToolbar: false
82+
83+ GSettings {
84+ id: background
85+ schema.id: "org.gnome.desktop.background"
86+ }
87+
88+ Image {
89+ id: image
90+ // Use x/y/height/width instead of anchors so that we don't adjust
91+ // the image when the OSK appears.
92+ x: 0
93+ y: 0
94+ height: root.height
95+ width: root.width
96+ source: background.pictureUri
97+ fillMode: Image.PreserveAspectCrop
98+ visible: status === Image.Ready
99+ }
100+
101+ PageStack {
102+ id: pageStack
103+
104+ function next() {
105+ // If we've opened any extra (non-main) pages, pop them before
106+ // continuing so back button returns to the previous main page.
107+ while (pageList.index < pageStack.depth - 1)
108+ pop()
109+ load(pageList.next())
110+ }
111+
112+ function prev() {
113+ if (pageList.index >= pageStack.depth - 1)
114+ pageList.prev() // update pageList.index, but not for extra pages
115+ pop()
116+ if (!currentPage || currentPage.opacity === 0) { // undo skipped pages
117+ prev()
118+ } else {
119+ currentPage.enabled = true
120+ }
121+ }
122+
123+ function load(path) {
124+ if (currentPage) {
125+ currentPage.enabled = false
126+ }
127+
128+ // First load it invisible, check that we should actually use
129+ // this page, and either skip it or continue.
130+ push(path, {"opacity": 0, "enabled": false})
131+
132+ // Check for immediate skip or not. We may have to wait for
133+ // skipValid to be assigned (see Connections object below)
134+ _checkSkip()
135+ }
136+
137+ function _checkSkip() {
138+ if (!currentPage) { // may have had a parse error
139+ next()
140+ } else if (currentPage.skipValid) {
141+ if (currentPage.skip) {
142+ next()
143+ } else {
144+ currentPage.opacity = 1
145+ currentPage.enabled = true
146+ }
147+ }
148+ }
149+
150+ Connections {
151+ target: pageStack.currentPage
152+ onSkipValidChanged: pageStack._checkSkip()
153+ }
154+
155+ Component.onCompleted: next()
156+ }
157+ }
158+
159+ Rectangle {
160+ id: modalNotificationBackground
161+ visible: notifications.useModal && (notifications.state == "narrow")
162+ anchors.fill: parent
163+ color: "#80000000"
164+
165+ MouseArea {
166+ anchors.fill: parent
167+ }
168+ }
169+
170+ InputMethod {
171+ anchors.fill: parent
172+ }
173+
174+ Notifications.Notifications {
175+ id: notifications
176+ model: NotificationBackend.Model
177+ margin: units.gu(1)
178+ anchors {
179+ top: parent.top
180+ right: parent.right
181+ bottom: parent.bottom
182+ }
183+ states: [
184+ State {
185+ name: "narrow"
186+ when: parent.width <= units.gu(60)
187+ AnchorChanges { target: notifications; anchors.left: parent.left }
188+ },
189+ State {
190+ name: "wide"
191+ when: parent.width > units.gu(60)
192+ AnchorChanges { target: notifications; anchors.left: undefined }
193+ PropertyChanges { target: notifications; width: units.gu(38) }
194+ }
195+ ]
196+ }
197+
198+ UnityComponents.Dialogs {
199+ id: dialogs
200+ anchors.fill: parent
201+ z: 10
202+ onPowerOffClicked: {
203+ shutdownFadeOutRectangle.enabled = true;
204+ shutdownFadeOutRectangle.visible = true;
205+ shutdownFadeOut.start();
206+ }
207+ }
208+
209+ Rectangle {
210+ id: shutdownFadeOutRectangle
211+ z: dialogs.z + 10
212+ enabled: false
213+ visible: false
214+ color: "black"
215+ anchors.fill: parent
216+ opacity: 0.0
217+ NumberAnimation on opacity {
218+ id: shutdownFadeOut
219+ from: 0.0
220+ to: 1.0
221+ onStopped: {
222+ if (shutdownFadeOutRectangle.enabled && shutdownFadeOutRectangle.visible) {
223+ DBusUnitySessionService.Shutdown();
224+ }
225+ }
226+ }
227+ }
228+
229+ Keys.onPressed: {
230+ if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
231+ dialogs.onPowerKeyPressed();
232+ event.accepted = true;
233+ } else {
234+ event.accepted = false;
235+ }
236+ }
237+
238+ Keys.onReleased: {
239+ if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) {
240+ dialogs.onPowerKeyReleased();
241+ event.accepted = true;
242+ } else {
243+ event.accepted = false;
244+ }
245+ }
246+}
wizard/test.shnew file+18
@@ -0,0 +1,18 @@
1+#!/bin/sh
2+
3+TOPDIR=$(readlink -e "$(dirname ${0})/..")
4+
5+LOCAL_PRIVATE_DIR=$(ls -d ${TOPDIR}/debian/tmp/usr/lib/*/ubuntu-system-settings/private)
6+if [ -n ${LOCAL_PRIVATE_DIR} ]; then
7+ echo "Testing against locally built version"
8+ export UBUNTU_SYSTEM_SETTINGS_WIZARD_ROOT="${TOPDIR}/debian/tmp/usr/share"
9+ export UBUNTU_SYSTEM_SETTINGS_WIZARD_MODULES="${LOCAL_PRIVATE_DIR}"
10+ export QML2_IMPORT_PATH=${LOCAL_PRIVATE_DIR}:${QML2_IMPORT_PATH}
11+ export PATH=${TOPDIR}/debian/tmp/usr/bin:${PATH}
12+else
13+ echo "Testing against system version"
14+fi
15+
16+export QML2_IMPORT_PATH=${TOPDIR}/tests/mocks:${QML2_IMPORT_PATH}
17+
18+exec system-settings-wizard
wizard/ubuntu-system-settings-wizard-cleanup.confnew file+20
@@ -0,0 +1,20 @@
1+description "Welcome to Ubuntu Cleanup"
2+author "Michael Terry <michael.terry@canonical.com>"
3+
4+# These are all tasks that need to be completed only if the wizard was
5+# intentionally stopped (i.e. the user clicked 'Finish' at the end)
6+
7+task
8+
9+# If you change this, also change it in the main upstart job
10+env RUN_FILE=".config/ubuntu-system-settings/wizard-has-run"
11+
12+script
13+ # Don't run again in the future. We do this here, rather than in the main
14+ # job because we only want to run this code if user actually clicked on the
15+ # "Finish" button.
16+ mkdir -p $(dirname "$HOME/$RUN_FILE")
17+ touch "$HOME/$RUN_FILE" || true
18+
19+ stop ubuntu-system-settings-wizard
20+end script
wizard/ubuntu-system-settings-wizard-set-lang.confnew file+30
@@ -0,0 +1,30 @@
1+description "Welcome to Ubuntu Cleanup"
2+author "Michael Terry <michael.terry@canonical.com>"
3+
4+# This job updates the system idea of what language is configured. It adjusts
5+# the upstart env and the DBus activation env. It also stops indicators and
6+# the OSK so that they can be restarted with the new env.
7+
8+task
9+
10+script
11+ setenv() {
12+ initctl set-env --global $1=$2
13+ gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'$1': '$2'}"
14+ }
15+
16+ UID=$(id -u)
17+
18+ # Change upstart's ideas about locales
19+ LANGUAGE=$(gdbus call --system --dest org.freedesktop.Accounts --object-path /org/freedesktop/Accounts/User$UID --method org.freedesktop.DBus.Properties.Get org.freedesktop.Accounts.User Language | cut -d\' -f2)
20+ setenv LANGUAGE $LANGUAGE
21+ echo "Set language for $USER_PATH as $LANGUAGE"
22+ LOCALE=$(gdbus call --system --dest org.freedesktop.Accounts --object-path /org/freedesktop/Accounts/User$UID --method org.freedesktop.DBus.Properties.Get org.freedesktop.Accounts.User FormatsLocale | cut -d\' -f2)
23+ setenv LC_ALL $LOCALE
24+ setenv LANG $LOCALE
25+ echo "Set locale as $LOCALE"
26+
27+ # Stop any indicators and OSK so they will be restarted with new environment
28+ initctl emit indicator-services-end
29+ stop maliit-server || true
30+end script
wizard/ubuntu-system-settings-wizard.confnew file+75
@@ -0,0 +1,75 @@
1+description "Welcome to Ubuntu"
2+author "Michael Terry <michael.terry@canonical.com>"
3+
4+start on starting unity8
5+task
6+
7+expect stop
8+
9+# If you change this, also change it in the cleanup upstart job
10+env RUN_FILE=".config/ubuntu-system-settings/wizard-has-run"
11+
12+pre-start script
13+ if [ -e "$HOME/$RUN_FILE" ]; then
14+ initctl set-env WIZARD_SKIPPED=true
15+ stop
16+ else
17+ # Stop unity8, we'll start it again in post-stop (this avoids a race
18+ # between post-stop and unity8 unpausing)
19+ stop --no-wait $JOB
20+
21+ # Tell unity-mir to raise SIGSTOP after we start
22+ initctl set-env UNITY_MIR_EMITS_SIGSTOP=1
23+
24+ if [ -n "$MIR_SOCKET" ]; then
25+ initctl set-env --global WIZARD_ORIG_MIR_SOCKET=$MIR_SOCKET
26+
27+ # Point wizard at unity-system-compositor
28+ MIR_SERVER_FILE=$XDG_RUNTIME_DIR/wizard_socket
29+ initctl set-env MIR_SERVER_FILE=$MIR_SERVER_FILE
30+ initctl set-env MIR_SERVER_HOST_SOCKET=$MIR_SOCKET
31+
32+ # Remove the socket if still there
33+ if [ -S "$MIR_SERVER_FILE" ]; then
34+ rm "$MIR_SERVER_FILE"
35+ fi
36+
37+ # Point future jobs in this session to our Mir socket instead of
38+ # unity-system-compositor's socket.
39+ initctl set-env --global MIR_SOCKET=$MIR_SERVER_FILE
40+ gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
41+ fi
42+ fi
43+end script
44+
45+exec system-settings-wizard
46+
47+post-stop script
48+ if [ -n "$WIZARD_SKIPPED" ]; then
49+ exit
50+ fi
51+
52+ setenv() {
53+ initctl set-env --global $1=$2
54+ gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'$1': '$2'}"
55+ }
56+
57+ echo "Ending wizard"
58+
59+ if [ -S "$MIR_SERVER_FILE" ]; then
60+ rm -f "$MIR_SERVER_FILE"
61+ fi
62+
63+ # Undo changes to global variables
64+ if [ -n "$WIZARD_ORIG_MIR_SOCKET" ]; then
65+ echo "Resetting MIR_SOCKET to $WIZARD_ORIG_MIR_SOCKET"
66+ setenv MIR_SOCKET $WIZARD_ORIG_MIR_SOCKET
67+ fi
68+
69+ # Stop any indicators and OSK so they will be restarted with new environment
70+ initctl emit indicator-services-end
71+ stop maliit-server || true
72+
73+ # And finally, resume unity8
74+ start --no-wait $JOB || true
75+end script