on xenial help sign in
merge trunk
commit68ed6f03394979c949a1065a5dfd4a3b994d0b20 authorLukáš Tinkl <lukas.tinkl@canonical.com> dateMon 15 Aug 2016, 23:34 (10 years ago) parent621ae3beba0bb7
81 files changed+1428−650
.crossbuilder/post_deploy+1 CMakeLists.txt+2−1 CODING+20−59 build.sh+6−37 debian/changelog+37 debian/control+4−3 plugins/AccountsService/AccountsService.cpp+20−2 plugins/AccountsService/AccountsService.h+2−3 plugins/Dash/CardCreator.js+30−26 plugins/Dash/CardCreatorCache.qml+3−3 plugins/LightDM/IntegratedLightDM/liblightdm/UsersModel.cpp−2 plugins/Ubuntu/SystemImage/CMakeLists.txt+5 plugins/Ubuntu/SystemImage/SystemImage.cpp+127−5 plugins/Ubuntu/SystemImage/SystemImage.h+52−2 plugins/Ubuntu/SystemImage/plugin.cpp+3−9 plugins/Ubuntu/SystemImage/plugin.h+1−1 plugins/Unity/Indicators/actionrootstate.cpp+1−1 plugins/Utils/deviceconfigparser.cpp+1−1 plugins/Utils/timezoneFormatter.cpp+1−1 plugins/Utils/windowstatestorage.cpp+3−1 plugins/Wizard/CMakeLists.txt+6−3 plugins/Wizard/PageList.cpp+16−1 plugins/Wizard/System.cpp+9−1 plugins/Wizard/System.h+5−1 plugins/Wizard/keyboardLayoutsModel.cpp+163 plugins/Wizard/keyboardLayoutsModel.h+66 plugins/Wizard/plugin.cpp+2 plugins/Wizard/qmldir−1 plugins/Wizard/timezonemodel.cpp+5−5 po/am.po+4−4 po/fr.po+5−5 po/unity8.pot+59−16 qml/Dash/CardCarousel.qml+1−1 qml/Dash/CardTool.qml+2−2 qml/Dash/GenericScopeView.qml+7−6 qml/Launcher/Launcher.qml+1 qml/Notifications/Notification.qml+9−28 qml/Notifications/NotificationMenuItemFactory.qml−3 qml/Notifications/Notifications.qml+10−25 qml/OrientedShell.qml+10−3 qml/Shell.qml+1−1 qml/Stages/ApplicationWindow.qml+1 qml/Stages/DecoratedWindow.qml+1 qml/Stages/DesktopStage.qml+2−1 qml/Stages/PhoneStage.qml+1−1 qml/Stages/SpreadDelegate.qml+1 qml/Stages/TabletStage.qml+2−2 qml/Wizard/Page.qml+1−1 qml/Wizard/Pages/10-welcome.qml+2−1 qml/Wizard/Pages/20-keyboard.qml+160 qml/Wizard/Pages/30-wifi.qml+10−5 qml/Wizard/Pages/77-system-update.qml+156 qml/Wizard/WizardItemSelector.qml+128 run.sh−70 run_on_device.sh−164 src/SecondaryWindow.cpp+1−1 tests/mocks/AccountsService/AccountsService.h+1−1 tests/mocks/Ubuntu/SystemImage/MockSystemImage.cpp+24−1 tests/mocks/Ubuntu/SystemImage/MockSystemImage.h+22−2 tests/mocks/Unity/Application/ApplicationInfo.cpp−8 tests/mocks/Unity/Application/ApplicationInfo.h−4 tests/mocks/Unity/Application/ApplicationManager.cpp−10 tests/mocks/Unity/Notifications/MockNotificationModel.cpp+4−6 tests/mocks/Unity/Notifications/MockNotificationModel.h+2−4 tests/mocks/Wizard/CMakeLists.txt+6−3 tests/mocks/Wizard/MockSystem.cpp+8 tests/mocks/Wizard/MockSystem.h+4 tests/mocks/Wizard/mockplugin.cpp+2 tests/plugins/Unity/Launcher/launchermodeltest.cpp−2 tests/plugins/Wizard/tst_pagelist.cpp+30−1 tests/qmltests/Dash/tst_CardCarousel.qml+24 tests/qmltests/Launcher/tst_Launcher.qml+9−2 tests/qmltests/Notifications/tst_Notifications.qml+6−23 tests/qmltests/Notifications/tst_OptionToggle.qml+1−16 tests/qmltests/Notifications/tst_SwipeToAct.qml+4−18 tests/qmltests/Notifications/tst_VisualSnapDecisionsQueue.qml+7−23 tests/qmltests/Stages/tst_TabletStage.qml+6−3 tests/qmltests/Wizard/tst_Wizard.qml+47−2 tests/qmltests/tst_OrientedShell.qml+30−6 tests/qmltests/tst_Shell.qml+23−4 tools/registry-tracker.cpp+2−2
.crossbuilder/post_deploynew file+1
@@ -0,0 +1 @@
1+restart unity8
CMakeLists.txt+2−1
@@ -57,11 +57,12 @@ find_package(Qt5DBus 5.4 REQUIRED)
5757find_package(Qt5Concurrent 5.4 REQUIRED)
5858find_package(Qt5Sql 5.4 REQUIRED)
5959
60−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=19)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=20)
6161pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
6262pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
6363pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
6464pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
65+pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0)
6566
6667pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
6768
CODING+20−59
@@ -15,23 +15,17 @@ download source
1515 $ bzr branch lp:unity8 ~/unity8/trunk
1616 $ cd ~/unity8/trunk
1717
18−install dependencies
18+install dependencies and build Unity 8
1919--------------------
20−If its your first time, install build dependencies
2120
2221$ cd ~/unity8/trunk
23−$ ./build.sh --setup
24−
25− this will:
26− - install the required dependencies to build, as well as run on the desktop
27− - it should also install unity-scope-home and unity-lens-application which
28− are technically "recommends", not strict dependencies
22+$ ./build.sh
2923
30−build Unity 8
31−-------------
24+ If its your first time, this will install the required dependencies to build and
25+ build it.
3226
33−$ cd ~/unity8/trunk
34−$ ./build.sh
27+ You might want to also install unity-scope-home and unity-scope-click which
28+ are technically "recommends", not strict dependencies
3529
3630You may also rebuild with the -c for clean, which just deletes the build
3731directory.
@@ -43,13 +37,15 @@ Running Unity 8 on your desktop
4337run the Unity 8 shell
4438---------------------
4539$ cd ~/unity8/trunk
46−$ ./run.sh
40+$ cd builddir
4741
48−Options can be passed to test the lock screen
49−$ ./run.sh -p OR -k
42+Each component of unity8 can be ran independently for development and testing
43+For example:
44+$ make tryShell
45+$ make tryLauncher
46+$ make tryLockscreen
5047
51−-p is for pin lock, for which the default prompt answer is "1234"
52−-k is for keylock passphrase, for which the default prompt answer is "password"
48+Check out the tests/qmltests/ directory for a list of things that can be ran.
5349
5450Notes
5551-----
@@ -70,50 +66,15 @@ Notes
7066
7167Running Unity 8 on devices
7268==========================
73−- Ubuntu Touch builds are currently only available in 14.04 flavour
74−- supported hardware should match one of those listed here
75− https://wiki.ubuntu.com/Touch/Devices#Running_fine
76−- follow the Ubuntu Touch install instructions for your chosen device
77− https://wiki.ubuntu.com/Touch/Install
78−- make sure your device is connected to a network
79−- also make sure you have your SSH key in ~/.ssh/id_rsa.pub (or install one
80− on the device yourself)
81−
82−$ cd ~/unity/trunk
83−$ ./run_on_device.sh --setup
84− this will:
85− - install your public SSH key on the device
86− - install the needed dependencies
8769
88−$ ./run_on_device.sh
89− this will:
90− - rsync the code to the device
91− - build on the device
92− - replace the running shell
93−
94−Options can be passed to test the lock screen
95−$ ./run_on_device.sh -p OR -k
96−
97−-p is for pin lock, for which the default prompt answer is "1234"
98−-k is for keylock passphrase, for which the default prompt answer is "password"
99−
100−Notes
101−-----
102−- using adb over TCP has some advantages, Google will be of help here
103− - NOTE: this is not yet available for flipped images
104− - TL;DR: `adb tcpip 5555; adb connect $your_device_ip`
105− - you can persist the above via `adb shell setprop persist.adb.tcp.port 5555`
106− - it's unsafe - anyone can connect to your device
107− - with TCP the Nexus 10 doesn't drop the adb connection when locking
108− the screen
109−- exporting ANDROID_SERIAL=$your_device_serial or
110− ANDROID_SERIAL=$your_device_ip:5555 will make adb not complain about
111− multiple devices
112−- you can export TARGET_IP=$your_device_ip TARGET_SSH_PORT=22 for run_on_device.sh
113− to not use adb forwarding - useful if you use multiple devices
114−- using Ninja (package ninja-build - run_on_device.sh -s installs this now)
115− will improve build times (especially in the nothing-to-build case)
70+Running unity8 on a device should be done using crossbuilder.
71+Go to
72+* https://launchpad.net/crossbuilder and
73+* https://wiki.ubuntu.com/Touch/Crossbuilder
74+for more details on crossbuilder.
11675
76+unity8 will automatically restart on the phone once deployment
77+has finished due to post-build-steps set up in this repository.
11778
11879Coding guidelines
11980=================
build.sh+6−37
@@ -9,7 +9,6 @@ usage() {
99 echo "usage: build [OPTIONS] [BUILD_TYPE]\n" >&2
1010 echo "Script to build the shell. If BUILD_TYPE is not specified, it defaults to \"debug\".\n" >&2
1111 echo "OPTIONS:" >&2
12− echo " -s, --setup Setup the build environment and branch Unity" >&2
1312 echo " -c, --clean Clean the build tree before building" >&2
1413 echo >&2
1514 exit 1
@@ -22,7 +21,6 @@ eval set -- "$ARGS"
2221while [ $# -gt 0 ]
2322do
2423 case "$1" in
25− -s|--setup) SETUP=true;;
2624 -c|--clean) CLEAN=true;;
2725 -h|--help) usage;;
2826 --) shift;break;;
@@ -35,31 +33,6 @@ done
3533BUILD_TYPE="debug"
3634[ $# -eq 1 ] && BUILD_TYPE="$1"
3735
38−install_dependencies() {
39− sudo apt-get update || exit 4
40− echo "Installing Unity 8 dependencies.."
41− sudo apt-get install devscripts \
42− equivs \
43− gsettings-desktop-schemas \
44− gsettings-ubuntu-schemas \
45− pay-service \
46− qmenumodel-qml \
47− qml-module-qtquick-layouts \
48− qml-module-qtquick-xmllistmodel \
49− qml-module-ubuntu-components \
50− qml-module-ubuntu-thumbnailer0.1 \
51− qtdeclarative5-gsettings1.0 \
52− qtdeclarative5-ubuntu-settings-components \
53− qtdeclarative5-ubuntu-telephony0.1 \
54− qtdeclarative5-unity-notifications-plugin \
55− qml-module-ubuntu-connectivity \
56− ubuntu-mobile-icons \
57− ubuntu-system-settings \
58− unity-plugin-scopes \
59− xvfb \
60− || exit 5
61−}
62−
6336mk_build_deps() {
6437 if [ ! -f control -o $CODE_DIR/debian/control -nt control ]; then
6538 sed 's/\:native//g' $CODE_DIR/debian/control > control
@@ -85,13 +58,9 @@ else
8558 BUILD_COMMAND="make -j$NUM_JOBS"
8659fi
8760
88−if $SETUP; then
89− install_dependencies
90−else
91− if $CLEAN; then rm -rf builddir; fi
92− mkdir -p builddir
93− cd builddir
94− mk_build_deps
95− cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CODE_DIR ${GENERATOR} || exit 6
96− ${BUILD_COMMAND} || exit 7
97−fi
61+if $CLEAN; then rm -rf builddir; fi
62+mkdir -p builddir
63+cd builddir
64+mk_build_deps
65+cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CODE_DIR ${GENERATOR} || exit 6
66+${BUILD_COMMAND} || exit 7
debian/changelog+37
@@ -1,3 +1,40 @@
1+unity8 (8.14+16.10.20160811.1-0ubuntu1) yakkety; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Take into account carousel selectedItemScaleFactor when setting card
5+ fixedArtShapeSize (LP: #1599238)
6+ * Remove unused LimitProxyModel
7+ * Do not calculate implicitHeight for Cards in a CardGrid
8+ * Small clazy fixes
9+
10+ [ Daniel d'Andrada ]
11+ * Remove stage property from Application
12+
13+ [ Larry Price ]
14+ * Allow libertine-scope to show empty search result hint unmodified.
15+ (LP: #1606693)
16+
17+ [ Lukáš Tinkl ]
18+ * Open the quicklist (context) menu also using the Menu key (LP:
19+ #1608265)
20+ * Fix incorrect SIM PIN dialog position when entering a wrong PIN (LP:
21+ #1596076)
22+ * Apply the correct keymap also on prompt surfaces (LP: #1610124)
23+ * Implement an optional system update feature during OOBE wizard (LP:
24+ #1580785)
25+ * Implement a page for choosing HW keyboard layout in OOBE wizard
26+
27+ [ Michael Zanetti ]
28+ * Clean up some build script legacy
29+ * Add a crossbuilder_post file to make crossbuilder restart unity8
30+ after deploying
31+ * fixes for the automatic switching between usage modes (LP: #1590944)
32+
33+ [ Omer Akram ]
34+ * Add object names for setup wizard
35+
36+ -- Michał Sawicz <michal.sawicz@canonical.com> Thu, 11 Aug 2016 06:28:20 +0000
37+
138unity8 (8.14+16.10.20160803-0ubuntu1) yakkety; urgency=medium
239
340 [ Albert Astals Cid ]
debian/control+4−3
@@ -17,6 +17,7 @@ Build-Depends: cmake,
1717 libconnectivity-qt1-dev (>= 0.7.1),
1818 libevdev-dev,
1919 libgeonames-dev (>= 0.2),
20+ libgnome-desktop-3-dev,
2021 libgl1-mesa-dev[!arm64 !armhf] | libgl-dev[!arm64 !armhf],
2122 libgl1-mesa-dri,
2223 libgles2-mesa-dev[arm64 armhf],
@@ -34,7 +35,7 @@ Build-Depends: cmake,
3435 libubuntugestures5-dev (>= 1.3.2030),
3536 libubuntugestures5-private-dev (>= 1.3.2030),
3637 libudev-dev,
37− libunity-api-dev (>= 7.116),
38+ libunity-api-dev (>= 7.117),
3839 libusermetricsoutput1-dev,
3940# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
4041 libx11-dev[!arm64 !armhf],
@@ -152,7 +153,7 @@ Depends: qml-module-qtquick-layouts,
152153 qtdeclarative5-ubuntu-settings-components (>= 0.7),
153154 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
154155 ubuntu-thumbnailer-impl-0,
155− unity-application-impl-19,
156+ unity-application-impl-20,
156157 unity-notifications-impl-3,
157158 unity-plugin-scopes | unity-scopes-impl,
158159 unity-scopes-impl-12,
@@ -198,7 +199,7 @@ Pre-Depends: ${misc:Pre-Depends},
198199Depends: ${misc:Depends},
199200 ${shlibs:Depends},
200201Provides: unity-application-impl,
201− unity-application-impl-19,
202+ unity-application-impl-20,
202203Replaces: unity8-autopilot (<< 8.02+15.04.20150422-0ubuntu1)
203204Description: Fake environment for running Unity 8 shell
204205 Provides fake implementations of some QML modules used by Unity 8 shell
plugins/AccountsService/AccountsService.cpp+20−2
@@ -68,9 +68,9 @@ Q_DECLARE_METATYPE(StringMapList)
6868QVariant primaryButtonConverter(const QVariant &value)
6969{
7070 QString stringValue = value.toString();
71− if (stringValue == "left") {
71+ if (stringValue == QLatin1String("left")) {
7272 return QVariant::fromValue(0);
73− } else if (stringValue == "right") {
73+ } else if (stringValue == QLatin1String("right")) {
7474 return QVariant::fromValue(1); // Mir is less clear on this -- any non-zero value is the same
7575 } else {
7676 return QVariant::fromValue(0); // default to left
@@ -284,6 +284,24 @@ QStringList AccountsService::keymaps() const
284284 return {QStringLiteral("us")};
285285}
286286
287+void AccountsService::setKeymaps(const QStringList &keymaps)
288+{
289+ if (keymaps.isEmpty()) {
290+ qWarning() << "Setting empty keymaps is not supported";
291+ return;
292+ }
293+
294+ StringMapList result;
295+ Q_FOREACH(const QString &keymap, keymaps) {
296+ StringMap map;
297+ map.insert(QStringLiteral("xkb"), keymap);
298+ result.append(map);
299+ }
300+
301+ setProperty(IFACE_ACCOUNTS_USER, PROP_INPUT_SOURCES, QVariant::fromValue(result));
302+ Q_EMIT keymapsChanged();
303+}
304+
287305uint AccountsService::failedFingerprintLogins() const
288306{
289307 return getProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_FINGERPRINT_LOGINS).toUInt();
plugins/AccountsService/AccountsService.h+2−3
@@ -79,9 +79,7 @@ class AccountsService: public QObject
7979 NOTIFY hereLicensePathChanged)
8080 Q_PROPERTY(QString realName READ realName WRITE setRealName NOTIFY realNameChanged)
8181 Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged)
82− Q_PROPERTY(QStringList keymaps
83− READ keymaps
84− NOTIFY keymapsChanged)
82+ Q_PROPERTY(QStringList keymaps READ keymaps WRITE setKeymaps NOTIFY keymapsChanged)
8583
8684public:
8785 enum PasswordDisplayHint {
@@ -117,6 +115,7 @@ public:
117115 QString email() const;
118116 void setEmail(const QString &email);
119117 QStringList keymaps() const;
118+ void setKeymaps(const QStringList &keymaps);
120119
121120Q_SIGNALS:
122121 void userChanged();
plugins/Dash/CardCreator.js+30−26
@@ -429,7 +429,7 @@ function sanitizeColor(colorString) {
429429 return colorString;
430430}
431431
432−function cardString(template, components, isCardTool, artShapeStyle) {
432+function cardString(template, components, isCardTool, artShapeStyle, categoryLayout) {
433433 var code;
434434
435435 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
@@ -935,29 +935,33 @@ function cardString(template, components, isCardTool, artShapeStyle) {
935935 code += kTouchdownCode.arg(touchdownAnchors);
936936 }
937937
938− var implicitHeight = 'implicitHeight: ';
939− if (hasSocialActions) {
940− implicitHeight += 'socialActionsRow.y + socialActionsRow.height + units.gu(1);\n';
941− } else if (hasSummary) {
942− implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
943− } else if (isAudio) {
944− implicitHeight += 'audioButton.height;\n';
945− } else if (headerAsOverlay) {
946− implicitHeight += 'artShapeLoader.height;\n';
947− } else if (hasHeaderRow) {
948− implicitHeight += 'row.y + row.height + units.gu(1);\n';
949− } else if (hasMascot) {
950− implicitHeight += 'mascotImage.y + mascotImage.height;\n';
951− } else if (hasTitleContainer) {
952− implicitHeight += 'headerTitleContainer.y + headerTitleContainer.height + units.gu(1);\n';
953− } else if (hasAttributes) {
954− implicitHeight += 'attributesRow.y + attributesRow.height + units.gu(1);\n';
955− } else if (hasSubtitle) {
956− implicitHeight += 'subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
957− } else if (hasTitle) {
958− implicitHeight += 'titleLabel.y + titleLabel.height + units.gu(1);\n';
959− } else if (hasArt) {
960− implicitHeight += 'artShapeLoader.height;\n';
938+ if (isCardTool || categoryLayout !== "grid") {
939+ var implicitHeight = 'implicitHeight: ';
940+ if (hasSocialActions) {
941+ implicitHeight += 'socialActionsRow.y + socialActionsRow.height + units.gu(1);\n';
942+ } else if (hasSummary) {
943+ implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
944+ } else if (isAudio) {
945+ implicitHeight += 'audioButton.height;\n';
946+ } else if (headerAsOverlay) {
947+ implicitHeight += 'artShapeLoader.height;\n';
948+ } else if (hasHeaderRow) {
949+ implicitHeight += 'row.y + row.height + units.gu(1);\n';
950+ } else if (hasMascot) {
951+ implicitHeight += 'mascotImage.y + mascotImage.height;\n';
952+ } else if (hasTitleContainer) {
953+ implicitHeight += 'headerTitleContainer.y + headerTitleContainer.height + units.gu(1);\n';
954+ } else if (hasAttributes) {
955+ implicitHeight += 'attributesRow.y + attributesRow.height + units.gu(1);\n';
956+ } else if (hasSubtitle) {
957+ implicitHeight += 'subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
958+ } else if (hasTitle) {
959+ implicitHeight += 'titleLabel.y + titleLabel.height + units.gu(1);\n';
960+ } else if (hasArt) {
961+ implicitHeight += 'artShapeLoader.height;\n';
962+ } else {
963+ implicitHeight = '';
964+ }
961965 } else {
962966 implicitHeight = '';
963967 }
@@ -968,13 +972,13 @@ function cardString(template, components, isCardTool, artShapeStyle) {
968972 return code;
969973}
970974
971−function createCardComponent(parent, template, components, isCardTool, artShapeStyle, identifier) {
975+function createCardComponent(parent, template, components, isCardTool, artShapeStyle, categoryLayout, identifier) {
972976 var imports = 'import QtQuick 2.4; \n\
973977 import Ubuntu.Components 1.3; \n\
974978 import Ubuntu.Settings.Components 0.1; \n\
975979 import Dash 0.1;\n\
976980 import Utils 0.1;\n';
977− var card = cardString(template, components, isCardTool, artShapeStyle);
981+ var card = cardString(template, components, isCardTool, artShapeStyle, categoryLayout);
978982 var code = imports + 'Component {\n' + card + '}\n';
979983
980984 try {
plugins/Dash/CardCreatorCache.qml+3−3
@@ -23,16 +23,16 @@ QtObject {
2323
2424 property var cache: new Object();
2525
26− function getCardComponent(template, components, isCardTool, artShapeStyle) {
26+ function getCardComponent(template, components, isCardTool, artShapeStyle, categoryLayout) {
2727 if (template === undefined || components === undefined)
2828 return undefined;
2929
3030 var tString = JSON.stringify(template);
3131 var cString = JSON.stringify(components);
32− var allString = tString + cString + isCardTool + artShapeStyle;
32+ var allString = tString + cString + isCardTool + artShapeStyle + categoryLayout;
3333 var component = cache[allString];
3434 if (component === undefined) {
35− component = CardCreator.createCardComponent(root, template, components, isCardTool, artShapeStyle, allString);
35+ component = CardCreator.createCardComponent(root, template, components, isCardTool, artShapeStyle, categoryLayout, allString);
3636 cache[allString] = component;
3737 }
3838 return component;
plugins/LightDM/IntegratedLightDM/liblightdm/UsersModel.cpp−2
@@ -40,8 +40,6 @@ UsersModel::UsersModel(QObject *parent) :
4040 QAbstractListModel(parent),
4141 d_ptr(new UsersModelPrivate(this))
4242{
43− Q_D(UsersModel);
44−
4543 // Extend roleNames (we want to keep the "display" role)
4644 QHash<int, QByteArray> roles = roleNames();
4745 roles[NameRole] = "name";
plugins/Ubuntu/SystemImage/CMakeLists.txt+5
@@ -1,3 +1,7 @@
1+include_directories(
2+ ${GLIB_INCLUDE_DIRS}
3+)
4+
15set(SYSTEMIMAGE_SOURCES
26 plugin.cpp
37 SystemImage.cpp
@@ -6,5 +10,6 @@ set(SYSTEMIMAGE_SOURCES
610add_library(SystemImage MODULE ${SYSTEMIMAGE_SOURCES})
711
812qt5_use_modules(SystemImage Qml DBus Core)
13+target_link_libraries(SystemImage ${GLIB_LIBRARIES})
914
1015add_unity8_plugin(Ubuntu.SystemImage 0.1 Ubuntu/SystemImage TARGETS SystemImage)
plugins/Ubuntu/SystemImage/SystemImage.cpp+127−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -14,20 +14,142 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17−#include "SystemImage.h"
1817#include <QDBusConnection>
1918#include <QDBusPendingCall>
19+#include <QDBusReply>
20+#include <QDebug>
21+
22+#include <glib.h>
23+
24+#include "SystemImage.h"
25+
26+#define SYSTEMIMAGE_SERVICE QStringLiteral("com.canonical.SystemImage")
27+#define SYSTEMIMAGE_PATH QStringLiteral("/Service")
28+#define SYSTEMIMAGE_IFACE QStringLiteral("com.canonical.SystemImage")
29+
30+Q_LOGGING_CATEGORY(SYSTEMIMAGEPLUGIN, "unity8.systemimage", QtWarningMsg)
31+
32+#define DEBUG_MSG qCDebug(SYSTEMIMAGEPLUGIN).nospace().noquote() << Q_FUNC_INFO
33+#define WARNING_MSG qCWarning(SYSTEMIMAGEPLUGIN).nospace().noquote() << Q_FUNC_INFO
2034
2135SystemImage::SystemImage(QObject *parent)
2236 : QObject(parent)
2337{
38+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateAvailableStatus"),
39+ this, SLOT(onUpdateAvailableStatus(bool,bool,QString,int,QString,QString)));
40+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateDownloaded"),
41+ this, SLOT(onUpdateDownloaded()));
42+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("UpdateFailed"),
43+ this, SLOT(onUpdateFailed(int,QString)));
44+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("Applied"),
45+ this, SLOT(onUpdateApplied(bool)));
46+ QDBusConnection::systemBus().connect(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE, QStringLiteral("Rebooting"),
47+ this, SLOT(onRebooting(bool)));
48+}
49+
50+void SystemImage::checkForUpdate()
51+{
52+ DEBUG_MSG << "Checking for update";
53+ const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
54+ QStringLiteral("CheckForUpdate"));
55+ QDBusConnection::systemBus().asyncCall(msg);
56+}
57+
58+void SystemImage::applyUpdate()
59+{
60+ DEBUG_MSG << "Applying update";
61+ setUpdateApplying(true);
62+
63+ const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
64+ QStringLiteral("ApplyUpdate"));
65+ QDBusConnection::systemBus().asyncCall(msg);
2466}
2567
2668void SystemImage::factoryReset()
2769{
28− const QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral("com.canonical.SystemImage"),
29− QStringLiteral("/Service"),
30− QStringLiteral("com.canonical.SystemImage"),
70+ const QDBusMessage msg = QDBusMessage::createMethodCall(SYSTEMIMAGE_SERVICE, SYSTEMIMAGE_PATH, SYSTEMIMAGE_IFACE,
3171 QStringLiteral("FactoryReset"));
3272 QDBusConnection::systemBus().asyncCall(msg);
3373}
74+
75+void SystemImage::onUpdateAvailableStatus(bool is_available, bool downloading, const QString &available_version, int update_size,
76+ const QString &last_update_date, const QString &error_reason)
77+{
78+ DEBUG_MSG << "A new update is " << (is_available ? "" : "NOT") << "available";
79+
80+ if (is_available == m_updateAvailable) {
81+ return;
82+ }
83+
84+ m_updateAvailable = is_available;
85+ m_downloading = downloading;
86+ m_availableVersion = available_version;
87+ m_updateSize = formatSize(update_size);
88+ m_lastUpdateDate = last_update_date;
89+ m_errorReason = error_reason;
90+ Q_EMIT updateAvailableStatus();
91+
92+ DEBUG_MSG << "Downloading: " << downloading << ", version: " << available_version << ", last update: " << last_update_date <<
93+ ", size: " << m_updateSize;
94+}
95+
96+void SystemImage::onUpdateDownloaded()
97+{
98+ DEBUG_MSG << "Update downloaded";
99+
100+ m_downloaded = true;
101+ Q_EMIT updateDownloadedChanged();
102+}
103+
104+void SystemImage::onUpdateFailed(int /*consecutive_failure_count*/, const QString &last_reason)
105+{
106+ WARNING_MSG << "System Update failed: " << last_reason;
107+ setUpdateApplying(false);
108+}
109+
110+void SystemImage::onUpdateApplied(bool applied)
111+{
112+ DEBUG_MSG << "System Update applied with status: " << applied;
113+ setUpdateApplying(false);
114+ if (applied) {
115+ resetUpdateStatus();
116+ Q_EMIT updateAvailableStatus();
117+ }
118+}
119+
120+void SystemImage::onRebooting(bool status)
121+{
122+ setUpdateApplying(false);
123+ DEBUG_MSG << "Rebooting: " << status;
124+}
125+
126+void SystemImage::setUpdateApplying(bool status)
127+{
128+ if (status != m_updateApplying) {
129+ m_updateApplying = status;
130+ Q_EMIT updateApplyingChanged();
131+ }
132+}
133+
134+void SystemImage::resetUpdateStatus()
135+{
136+ m_updateAvailable = false;
137+ m_updateApplying = false;
138+ m_downloading = false;
139+ m_downloaded = false;
140+ m_availableVersion.clear();
141+ m_updateSize.clear();
142+ m_lastUpdateDate.clear();
143+ m_errorReason.clear();
144+}
145+
146+QString SystemImage::formatSize(quint64 size) const
147+{
148+ guint64 g_size = size;
149+
150+ gchar * formatted_size = g_format_size(g_size);
151+ QString q_formatted_size = QString::fromLocal8Bit(formatted_size);
152+ g_free(formatted_size);
153+
154+ return q_formatted_size;
155+}
plugins/Ubuntu/SystemImage/SystemImage.h+52−2
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -18,17 +18,67 @@
1818#define SYSTEMIMAGE_H
1919
2020#include <QObject>
21+#include <QLoggingCategory>
22+
23+Q_DECLARE_LOGGING_CATEGORY(SYSTEMIMAGEPLUGIN)
2124
2225class SystemImage : public QObject
2326{
2427 Q_OBJECT
2528 Q_DISABLE_COPY(SystemImage)
2629
30+ Q_PROPERTY(bool updateAvailable READ updateAvailable NOTIFY updateAvailableStatus)
31+ Q_PROPERTY(bool updateDownloading READ updateDownloading NOTIFY updateAvailableStatus)
32+ Q_PROPERTY(QString availableVersion READ availableVersion NOTIFY updateAvailableStatus)
33+ Q_PROPERTY(QString updateSize READ updateSize NOTIFY updateAvailableStatus)
34+ Q_PROPERTY(bool updateApplying READ updateApplying NOTIFY updateApplyingChanged)
35+ Q_PROPERTY(bool updateDownloaded READ updateDownloaded NOTIFY updateDownloadedChanged)
36+
2737public:
28− explicit SystemImage(QObject *parent = 0);
38+ explicit SystemImage(QObject *parent = nullptr);
2939 ~SystemImage() = default;
3040
41+ bool updateAvailable() const { return m_updateAvailable; }
42+ bool updateDownloading() const { return m_downloading; }
43+ QString availableVersion() const { return m_availableVersion; }
44+ QString updateSize() const { return m_updateSize; }
45+ bool updateApplying() const { return m_updateApplying; }
46+ bool updateDownloaded() const { return m_downloaded; }
47+
48+public Q_SLOTS:
49+ Q_INVOKABLE void checkForUpdate();
50+ Q_INVOKABLE void applyUpdate();
3151 Q_INVOKABLE void factoryReset();
52+
53+private Q_SLOTS:
54+ void onUpdateAvailableStatus(bool is_available, bool updateDownloading, const QString &available_version,
55+ int update_size, const QString &last_update_date, const QString &error_reason);
56+ void onUpdateDownloaded();
57+ void onUpdateFailed(int consecutive_failure_count, const QString & last_reason);
58+ void onUpdateApplied(bool applied);
59+ void onRebooting(bool status);
60+
61+Q_SIGNALS:
62+ void updateAvailableStatus();
63+ void updateDownloadedChanged();
64+ void updateApplyingChanged();
65+
66+private Q_SLOTS:
67+ void setUpdateApplying(bool status);
68+
69+private:
70+ void resetUpdateStatus();
71+ QString formatSize(quint64 size) const;
72+
73+private:
74+ bool m_updateAvailable = false;
75+ bool m_updateApplying = false;
76+ bool m_downloading = false;
77+ bool m_downloaded = false;
78+ QString m_availableVersion;
79+ QString m_updateSize;
80+ QString m_lastUpdateDate;
81+ QString m_errorReason;
3282};
3383
3484#endif // SYSTEMIMAGE_H
plugins/Ubuntu/SystemImage/plugin.cpp+3−9
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -19,16 +19,10 @@
1919
2020#include <QtQml>
2121
22−static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
23−{
24− Q_UNUSED(engine)
25− Q_UNUSED(scriptEngine)
26− return new SystemImage();
27−}
28−
2922void BackendPlugin::registerTypes(const char *uri)
3023{
3124 Q_ASSERT(uri == QLatin1String("Ubuntu.SystemImage"));
3225
33− qmlRegisterSingletonType<SystemImage>(uri, 0, 1, "SystemImage", service_provider);
26+ qmlRegisterSingletonType<SystemImage>(uri, 0, 1, "SystemImage",
27+ [](QQmlEngine*, QJSEngine*) -> QObject* { return new SystemImage; });
3428}
plugins/Ubuntu/SystemImage/plugin.h+1−1
@@ -22,7 +22,7 @@
2222class BackendPlugin : public QQmlExtensionPlugin
2323{
2424 Q_OBJECT
25− Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
25+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
2626
2727public:
2828 void registerTypes(const char *uri) override;
plugins/Unity/Indicators/actionrootstate.cpp+1−1
@@ -44,7 +44,7 @@ void ActionRootState::setActionGroup(QDBusActionGroup *actionGroup)
4444 connect(m_actionGroup, &QDBusActionGroup::statusChanged, this, [&](bool) { updateActionState(); });
4545 connect(m_actionGroup, &QDBusActionGroup::actionAppear, this, [&](const QString&) { updateActionState(); });
4646 connect(m_actionGroup, &QDBusActionGroup::actionVanish, this, [&](const QString&) { updateActionState(); });
47− connect(m_actionGroup, &QDBusActionGroup::actionStateChanged, this, [&](QVariant) { updateActionState(); });
47+ connect(m_actionGroup, &QDBusActionGroup::actionStateChanged, this, [&](const QVariant&) { updateActionState(); });
4848
4949 connect(m_actionGroup, &QObject::destroyed, this, [&](QObject*) { updateActionState(); });
5050 }
plugins/Utils/deviceconfigparser.cpp+1−1
@@ -26,7 +26,7 @@ DeviceConfigParser::DeviceConfigParser(QObject *parent): QObject(parent)
2626 // Local files have highest priority
2727 QString path;
2828 Q_FOREACH (const QString &standardPath, QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation)) {
29− if (QFileInfo(standardPath + "/devices.conf").exists()) {
29+ if (QFileInfo::exists(standardPath + "/devices.conf")) {
3030 path = standardPath + "/devices.conf";
3131 break;
3232 }
plugins/Utils/timezoneFormatter.cpp+1−1
@@ -39,7 +39,7 @@ QString TimezoneFormatter::currentTimeInTimezoneWithAbbrev(const QVariant &tzId)
3939 QTimeZone tz(tzId.toByteArray());
4040 if (tz.isValid()) {
4141 const QDateTime now = QDateTime::currentDateTime().toTimeZone(tz);
42− return QStringLiteral("%1 %2").arg(now.time().toString(QStringLiteral("h:mm"))).arg(tz.abbreviation(now));
42+ return QStringLiteral("%1 %2").arg(now.time().toString(QStringLiteral("h:mm")), tz.abbreviation(now));
4343 }
4444 return QString();
4545}
plugins/Utils/windowstatestorage.cpp+3−1
@@ -28,7 +28,9 @@
2828QMutex WindowStateStorage::s_mutex;
2929
3030inline QString sanitiseString(QString string) {
31− return string.remove("\"").remove("'").remove("\\");
31+ return string.remove(QLatin1Char('\"'))
32+ .remove(QLatin1Char('\''))
33+ .remove(QLatin1Char('\\'));
3234}
3335
3436WindowStateStorage::WindowStateStorage(QObject *parent):
plugins/Wizard/CMakeLists.txt+6−3
@@ -1,4 +1,6 @@
1−include_directories(${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS})
1+pkg_search_module(GD3 REQUIRED gnome-desktop-3.0)
2+
3+include_directories(SYSTEM ${GD3_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS})
24
35add_library(Wizard-qml MODULE
46 plugin.cpp
@@ -7,10 +9,11 @@ add_library(Wizard-qml MODULE
79 LocalePlugin.cpp
810 timezonemodel.cpp
911 Status.cpp
12+ keyboardLayoutsModel.cpp
1013)
1114
12−qt5_use_modules(Wizard-qml DBus Qml Concurrent)
13−target_link_libraries(Wizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
15+qt5_use_modules(Wizard-qml DBus Qml)
16+target_link_libraries(Wizard-qml ${GD3_LDFLAGS} ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
1417add_unity8_plugin(Wizard 0.1 Wizard TARGETS Wizard-qml)
1518
1619set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
plugins/Wizard/PageList.cpp+16−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical Ltd.
2+ * Copyright (C) 2014-2016 Canonical Ltd.
33 *
44 * This program is free software: you can redistribute it and/or modify it
55 * under the terms of the GNU General Public License version 3, as published
@@ -34,6 +34,7 @@
3434#include <QDir>
3535#include <QSet>
3636#include <QStandardPaths>
37+#include <QSettings>
3738
3839PageList::PageList(QObject *parent)
3940 : QObject(parent),
@@ -66,6 +67,20 @@ PageList::PageList(QObject *parent)
6667 Q_FOREACH(const QString &page, disabledPages) {
6768 m_pages.remove(page);
6869 }
70+
71+ // If there was a system update installed, skip until the last page to just greet the user
72+ QSettings settings;
73+ if (settings.value(QStringLiteral("Wizard/SkipUntilFinishedPage")).toBool()) {
74+ const QString lastPage = m_pages.lastKey();
75+ Q_FOREACH(const QString &page, m_pages.keys()) {
76+ if (Q_UNLIKELY(page != lastPage)) {
77+ m_pages.remove(page);
78+ }
79+ }
80+
81+ // ... and reset it again for the next run
82+ settings.remove(QStringLiteral("Wizard/SkipUntilFinishedPage"));
83+ }
6984}
7085
7186QStringList PageList::entries() const
plugins/Wizard/System.cpp+9−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014-2015 Canonical Ltd.
2+ * Copyright (C) 2014-2016 Canonical Ltd.
33 *
44 * This program is free software: you can redistribute it and/or modify it
55 * under the terms of the GNU General Public License version 3, as published
@@ -26,6 +26,7 @@
2626#include <QMap>
2727#include <QProcess>
2828#include <QDebug>
29+#include <QSettings>
2930
3031System::System()
3132 : QObject()
@@ -110,3 +111,10 @@ void System::updateSessionLocale(const QString &locale)
110111 initctl restart --no-wait indicator-messages; \
111112 initctl restart --no-wait unity8-dash\""));
112113}
114+
115+void System::skipUntilFinishedPage()
116+{
117+ QSettings settings;
118+ settings.setValue(QStringLiteral("Wizard/SkipUntilFinishedPage"), true);
119+ settings.sync();
120+}
plugins/Wizard/System.h+5−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014-2015 Canonical Ltd.
2+ * Copyright (C) 2014-2016 Canonical Ltd.
33 *
44 * This program is free software: you can redistribute it and/or modify it
55 * under the terms of the GNU General Public License version 3, as published
@@ -35,6 +35,10 @@ public:
3535
3636public Q_SLOTS:
3737 void updateSessionLocale(const QString &locale);
38+ /**
39+ * Mark the wizard to skip all the pages and just show the last (welcome to ubuntu) page
40+ */
41+ void skipUntilFinishedPage();
3842
3943Q_SIGNALS:
4044 void wizardEnabledChanged();
plugins/Wizard/keyboardLayoutsModel.cppnew file+163
@@ -0,0 +1,163 @@
1+/*
2+ * Copyright (C) 2016 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 <QDBusMetaType>
18+#include <QDebug>
19+
20+#define GNOME_DESKTOP_USE_UNSTABLE_API
21+#include <libgnome-desktop/gnome-xkb-info.h>
22+
23+#include "keyboardLayoutsModel.h"
24+
25+typedef QList<QMap<QString, QString>> StringMapList;
26+Q_DECLARE_METATYPE(StringMapList)
27+
28+KeyboardLayoutsModel::KeyboardLayoutsModel(QObject *parent)
29+ : QAbstractListModel(parent)
30+{
31+ m_roleNames = {
32+ {LayoutIdRole, "layoutId"},
33+ {DisplayNameRole, "displayName"},
34+ {LanguageRole, "language"}
35+ };
36+
37+ qDBusRegisterMetaType<StringMapList>();
38+
39+ buildModel();
40+ connect(this, &KeyboardLayoutsModel::languageChanged, this, &KeyboardLayoutsModel::updateModel);
41+}
42+
43+QString KeyboardLayoutsModel::language() const
44+{
45+ return m_language;
46+}
47+
48+void KeyboardLayoutsModel::setLanguage(const QString &language)
49+{
50+ if (m_language == language)
51+ return;
52+
53+ m_language = language;
54+ Q_EMIT languageChanged(language);
55+}
56+
57+static bool compareLayouts(const KeyboardLayoutInfo &layout0, const KeyboardLayoutInfo &layout1)
58+{
59+ QString name0(layout0.id);
60+ QString name1(layout1.id);
61+
62+ if (name0 == name1) {
63+ name0 = layout0.displayName;
64+ name1 = layout1.displayName;
65+
66+ if (name0 == name1) {
67+ name0 = layout0.language;
68+ name1 = layout1.language;
69+ }
70+ }
71+
72+ return QString::localeAwareCompare(name0, name1) < 0;
73+}
74+
75+void KeyboardLayoutsModel::buildModel()
76+{
77+ GList *sources, *tmp;
78+ const gchar *display_name;
79+ const gchar *short_name;
80+ const gchar *xkb_layout;
81+ const gchar *xkb_variant;
82+
83+ GnomeXkbInfo * xkbInfo(gnome_xkb_info_new());
84+
85+ sources = gnome_xkb_info_get_all_layouts(xkbInfo);
86+
87+ for (tmp = sources; tmp != NULL; tmp = tmp->next) {
88+ gboolean result = gnome_xkb_info_get_layout_info(xkbInfo, (const gchar *)tmp->data,
89+ &display_name, &short_name, &xkb_layout, &xkb_variant);
90+ if (!result) {
91+ qWarning() << "Skipping invalid layout";
92+ continue;
93+ }
94+
95+ KeyboardLayoutInfo layout;
96+ layout.id = QString::fromUtf8((const gchar *)tmp->data);
97+ layout.language = QString::fromUtf8(short_name);
98+ layout.displayName = QString::fromUtf8(display_name);
99+
100+ m_db.append(layout);
101+ }
102+ g_list_free(sources);
103+ g_object_unref(xkbInfo);
104+
105+ std::sort(m_db.begin(), m_db.end(), compareLayouts);
106+}
107+
108+void KeyboardLayoutsModel::updateModel()
109+{
110+ beginResetModel();
111+ m_layouts.clear();
112+
113+ const QString lang = m_language.section("_", 0, 0);
114+ const QString country = m_language.section("_", 1, 1).toLower();
115+
116+ Q_FOREACH(const KeyboardLayoutInfo & info, m_db) {
117+ const QString kbdCountry = info.id.section("+", 0, 0);
118+ if (info.language == lang && // filter by language
119+ (kbdCountry.startsWith(country) || kbdCountry.length() > 2)) { // and by known country, also insert anything that doesn't match the country
120+ m_layouts.append(info);
121+ }
122+ }
123+
124+ std::sort(m_layouts.begin(), m_layouts.end(), compareLayouts);
125+ endResetModel();
126+}
127+
128+int KeyboardLayoutsModel::rowCount(const QModelIndex &parent) const
129+{
130+ Q_UNUSED(parent)
131+ return m_layouts.count();
132+}
133+
134+QVariant KeyboardLayoutsModel::data(const QModelIndex &index, int role) const
135+{
136+ const int row = index.row();
137+
138+ if (row >= m_layouts.count()) {
139+ qWarning() << Q_FUNC_INFO << "index out of bounds";
140+ return QVariant();
141+ }
142+
143+ const KeyboardLayoutInfo &layout = m_layouts.at(row);
144+
145+ switch (role) {
146+ case Qt::DisplayRole:
147+ case DisplayNameRole:
148+ return layout.displayName;
149+ case LayoutIdRole:
150+ return layout.id;
151+ case LanguageRole:
152+ return layout.language;
153+ default: {
154+ qWarning() << Q_FUNC_INFO << "unsupported data role";
155+ return QVariant();
156+ }
157+ }
158+}
159+
160+QHash<int, QByteArray> KeyboardLayoutsModel::roleNames() const
161+{
162+ return m_roleNames;
163+}
plugins/Wizard/keyboardLayoutsModel.hnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2016 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 KEYBOARDLAYOUTSMODEL_H
18+#define KEYBOARDLAYOUTSMODEL_H
19+
20+#include <QAbstractListModel>
21+
22+struct KeyboardLayoutInfo {
23+ QString id;
24+ QString displayName;
25+ QString language;
26+};
27+
28+class KeyboardLayoutsModel: public QAbstractListModel
29+{
30+ Q_OBJECT
31+
32+ Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged)
33+
34+public:
35+ explicit KeyboardLayoutsModel(QObject * parent = nullptr);
36+ ~KeyboardLayoutsModel() = default;
37+
38+ enum Roles {
39+ LayoutIdRole = Qt::UserRole + 1,
40+ DisplayNameRole,
41+ LanguageRole
42+ };
43+
44+ QString language() const;
45+ void setLanguage(const QString &language);
46+
47+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
48+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
49+ QHash<int, QByteArray> roleNames() const override;
50+
51+Q_SIGNALS:
52+ void languageChanged(const QString &language);
53+
54+private Q_SLOTS:
55+ void updateModel();
56+
57+private:
58+ void buildModel();
59+
60+ QString m_language;
61+ QHash<int, QByteArray> m_roleNames;
62+ QVector<KeyboardLayoutInfo> m_layouts;
63+ QVector<KeyboardLayoutInfo> m_db;
64+};
65+
66+#endif
plugins/Wizard/plugin.cpp+2
@@ -20,6 +20,7 @@
2020#include "timezonemodel.h"
2121#include "LocalePlugin.h"
2222#include "Status.h"
23+#include "keyboardLayoutsModel.h"
2324
2425#include <QtQml/qqml.h>
2526
@@ -30,5 +31,6 @@ void WizardPlugin::registerTypes(const char *uri)
3031 qmlRegisterSingletonType<System>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new System; });
3132 qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
3233 qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
34+ qmlRegisterType<KeyboardLayoutsModel>(uri, 0, 1, "KeyboardLayoutsModel");
3335 qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
3436}
plugins/Wizard/qmldir−1
@@ -1,3 +1,2 @@
11module Wizard
22plugin Wizard-qml
3−typeinfo Wizard.qmltypes
plugins/Wizard/timezonemodel.cpp+5−5
@@ -60,12 +60,12 @@ QVariant TimeZoneLocationModel::data(const QModelIndex &index, int role) const
6060
6161 switch (role) {
6262 case Qt::DisplayRole:
63− return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city))
64− .arg(geonames_city_get_state(city))
65− .arg(geonames_city_get_country(city));
63+ return QStringLiteral("%1, %2, %3").arg(geonames_city_get_name(city),
64+ geonames_city_get_state(city),
65+ geonames_city_get_country(city));
6666 case SimpleRole:
67− return QStringLiteral("%1, %2").arg(geonames_city_get_name(city))
68− .arg(geonames_city_get_country(city));
67+ return QStringLiteral("%1, %2").arg(geonames_city_get_name(city),
68+ geonames_city_get_country(city));
6969 case TimeZoneRole:
7070 return geonames_city_get_timezone(city);
7171 case CountryRole:
po/am.po+4−4
@@ -8,14 +8,14 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2016-08-03 15:56+0000\n"
11−"PO-Revision-Date: 2016-07-05 02:15+0000\n"
11+"PO-Revision-Date: 2016-08-13 14:45+0000\n"
1212"Last-Translator: samson <Unknown>\n"
1313"Language-Team: Amharic <am@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-08-09 05:46+0000\n"
18+"X-Launchpad-Export-Date: 2016-08-14 05:36+0000\n"
1919"X-Generator: Launchpad (build 18169)\n"
2020
2121#: plugins/LightDM/Greeter.cpp:123
@@ -444,11 +444,11 @@ msgstr "እንደገና ይሞክሩ"
444444
445445#: qml/Greeter/LoginList.qml:63
446446msgid "Passphrase"
447−msgstr ""
447+msgstr "የማለፊያ ሐረግ"
448448
449449#: qml/Greeter/LoginList.qml:64
450450msgid "Passcode"
451−msgstr ""
451+msgstr "ማለፊያ ኮድ"
452452
453453#: qml/Greeter/LoginList.qml:87
454454msgid "Retry"
po/fr.po+5−5
@@ -8,14 +8,14 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2016-08-03 15:56+0000\n"
11−"PO-Revision-Date: 2016-07-06 14:47+0000\n"
12−"Last-Translator: Jean-Marc <Unknown>\n"
11+"PO-Revision-Date: 2016-08-14 10:36+0000\n"
12+"Last-Translator: Anne <anneonyme017@gmail.com>\n"
1313"Language-Team: French <fr@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-08-09 05:47+0000\n"
18+"X-Launchpad-Export-Date: 2016-08-15 05:42+0000\n"
1919"X-Generator: Launchpad (build 18169)\n"
2020
2121#: plugins/LightDM/Greeter.cpp:123
@@ -454,11 +454,11 @@ msgstr "Réessayer"
454454
455455#: qml/Greeter/LoginList.qml:63
456456msgid "Passphrase"
457−msgstr ""
457+msgstr "Phrase secrète"
458458
459459#: qml/Greeter/LoginList.qml:64
460460msgid "Passcode"
461−msgstr ""
461+msgstr "Code"
462462
463463#: qml/Greeter/LoginList.qml:87
464464msgid "Retry"
po/unity8.pot+59−16
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2016-08-03 15:56+0000\n"
11+"POT-Creation-Date: 2016-08-11 06:28+0000\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -360,15 +360,15 @@ msgstr ""
360360msgid "Reset"
361361msgstr ""
362362
363−#: qml/Dash/GenericScopeView.qml:580 qml/Dash/GenericScopeView.qml:775
363+#: qml/Dash/GenericScopeView.qml:585 qml/Dash/GenericScopeView.qml:780
364364msgid "Show less"
365365msgstr ""
366366
367−#: qml/Dash/GenericScopeView.qml:580
367+#: qml/Dash/GenericScopeView.qml:585
368368msgid "Show all"
369369msgstr ""
370370
371−#: qml/Dash/GenericScopeView.qml:637
371+#: qml/Dash/GenericScopeView.qml:642
372372msgctxt "Label: Hint for dash search line edit"
373373msgid "Search"
374374msgstr ""
@@ -631,36 +631,50 @@ msgstr ""
631631msgid "Language"
632632msgstr ""
633633
634−#: qml/Wizard/Pages/10-welcome.qml:171 qml/Wizard/Pages/30-wifi.qml:206
635−#: qml/Wizard/Pages/40-location.qml:271 qml/Wizard/Pages/50-timezone.qml:270
636−#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/70-passwd-type.qml:144
634+#: qml/Wizard/Pages/10-welcome.qml:172 qml/Wizard/Pages/20-keyboard.qml:151
635+#: qml/Wizard/Pages/30-wifi.qml:206 qml/Wizard/Pages/40-location.qml:271
636+#: qml/Wizard/Pages/50-timezone.qml:270 qml/Wizard/Pages/60-account.qml:65
637+#: qml/Wizard/Pages/70-passwd-type.qml:144
637638#: qml/Wizard/Pages/75-report-check.qml:84
638639#: qml/Wizard/Pages/passcode-desktop.qml:141
639640#: qml/Wizard/Pages/password-set.qml:141
640641msgid "Next"
641642msgstr ""
642643
643−#: qml/Wizard/Pages/30-wifi.qml:29
644+#: qml/Wizard/Pages/20-keyboard.qml:30
645+msgid "Select Keyboard"
646+msgstr ""
647+
648+#: qml/Wizard/Pages/20-keyboard.qml:70
649+msgid "Keyboard language"
650+msgstr ""
651+
652+#: qml/Wizard/Pages/20-keyboard.qml:92
653+msgid "Keyboard layout"
654+msgstr ""
655+
656+#: qml/Wizard/Pages/20-keyboard.qml:151 qml/Wizard/Pages/30-wifi.qml:206
657+#: qml/Wizard/Pages/60-account.qml:65
658+#: qml/Wizard/Pages/77-system-update.qml:152 qml/Wizard/Pages/sim.qml:101
659+msgid "Skip"
660+msgstr ""
661+
662+#: qml/Wizard/Pages/30-wifi.qml:30
644663msgid "Connect to Wi‑Fi"
645664msgstr ""
646665
647−#: qml/Wizard/Pages/30-wifi.qml:130
666+#: qml/Wizard/Pages/30-wifi.qml:131
648667msgid "Connected"
649668msgstr ""
650669
651−#: qml/Wizard/Pages/30-wifi.qml:163
670+#: qml/Wizard/Pages/30-wifi.qml:164
652671msgid "Available Wi-Fi networks"
653672msgstr ""
654673
655−#: qml/Wizard/Pages/30-wifi.qml:164
674+#: qml/Wizard/Pages/30-wifi.qml:165
656675msgid "No available Wi-Fi networks"
657676msgstr ""
658677
659−#: qml/Wizard/Pages/30-wifi.qml:206 qml/Wizard/Pages/60-account.qml:65
660−#: qml/Wizard/Pages/sim.qml:101
661−msgid "Skip"
662−msgstr ""
663−
664678#: qml/Wizard/Pages/40-location.qml:27
665679msgid "Location Services"
666680msgstr ""
@@ -744,6 +758,35 @@ msgstr ""
744758msgid "Privacy policy"
745759msgstr ""
746760
761+#: qml/Wizard/Pages/77-system-update.qml:28
762+msgid "Update Device"
763+msgstr ""
764+
765+#: qml/Wizard/Pages/77-system-update.qml:55
766+msgid ""
767+"There is a system update available and ready to install. Afterwards, the "
768+"device will automatically restart."
769+msgstr ""
770+
771+#: qml/Wizard/Pages/77-system-update.qml:76
772+msgctxt "string identifying name of the update"
773+msgid "Ubuntu system"
774+msgstr ""
775+
776+#: qml/Wizard/Pages/77-system-update.qml:83
777+#, qt-format
778+msgctxt "version of the system update"
779+msgid "Version %1"
780+msgstr ""
781+
782+#: qml/Wizard/Pages/77-system-update.qml:102
783+msgid "This could take a few minutes..."
784+msgstr ""
785+
786+#: qml/Wizard/Pages/77-system-update.qml:116
787+msgid "Install and restart now"
788+msgstr ""
789+
747790#: qml/Wizard/Pages/80-finished.qml:89
748791msgid "Welcome to Ubuntu"
749792msgstr ""
qml/Dash/CardCarousel.qml+1−1
@@ -62,7 +62,7 @@ DashRenderer {
6262 asynchronous: true
6363 onLoaded: {
6464 item.fixedHeaderHeight = Qt.binding(function() { return carousel.headerHeight; });
65− item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
65+ item.fixedArtShapeSize = Qt.binding(function() { return Qt.size(cardTool.artShapeSize.width / carousel.selectedItemScaleFactor, cardTool.artShapeSize.height / carousel.selectedItemScaleFactor); });
6666 item.height = Qt.binding(function() { return cardTool.cardHeight; });
6767 item.cardData = Qt.binding(function() { return model; });
6868 item.fontScale = Qt.binding(function() { return carousel.fontScale; });
qml/Dash/CardTool.qml+2−2
@@ -71,7 +71,7 @@ Item {
7171 // Not readonly because gets overwritten from GenericScopeView in some cases
7272 property string artShapeStyle: categoryLayout === "carousel" ? "shadow" : "inset"
7373
74− property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, false, cardTool.artShapeStyle);
74+ property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, false, cardTool.artShapeStyle, cardTool.categoryLayout);
7575
7676 // FIXME: Saviq
7777 // Only way for the card below to actually be laid out completely.
@@ -213,7 +213,7 @@ Item {
213213 "attributes": attributesModel.model,
214214 "socialActions": socialActionsModel.model
215215 }
216− sourceComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true, cardTool.artShapeStyle);
216+ sourceComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true, cardTool.artShapeStyle, cardTool.categoryLayout);
217217 onLoaded: {
218218 item.objectName = "cardToolCard";
219219 item.width = Qt.binding(function() { return cardTool.cardWidth !== -1 ? cardTool.cardWidth : item.implicitWidth; });
qml/Dash/GenericScopeView.qml+7−6
@@ -343,7 +343,7 @@ FocusScope {
343343 updateRanges();
344344 clickScopeSizingHacks();
345345 if (scope && (scope.id === "clickscope" || scope.id === "libertine-scope.ubuntu_libertine-scope")) {
346− if (scope.id === "libertine-scope.ubuntu_libertine-scope" || categoryId === "predefined" || categoryId === "local") {
346+ if (isLibertineContainerCategory() || categoryId === "predefined" || categoryId === "local") {
347347 cardTool.artShapeSize = Qt.binding(function() { return Qt.size(units.gu(8), units.gu(7.5)) });
348348 cardTool.artShapeStyle = "icon";
349349 } else {
@@ -366,10 +366,15 @@ FocusScope {
366366 property int pxpgu: units.gu(1);
367367 onPxpguChanged: clickScopeSizingHacks();
368368
369+ // Returns true if the current category pertains to a Libertine container
370+ function isLibertineContainerCategory() {
371+ return scope && scope.id === "libertine-scope.ubuntu_libertine-scope" && categoryId !== "hint";
372+ }
373+
369374 function clickScopeSizingHacks() {
370375 if (scope &&
371376 ((scope.id === "clickscope" && (categoryId === "predefined" || categoryId === "local")) ||
372− scope.id === "libertine-scope.ubuntu_libertine-scope")) {
377+ isLibertineContainerCategory())) {
373378 // Yeah, hackish :/
374379 if (scopeView.width > units.gu(45)) {
375380 if (scopeView.width >= units.gu(70)) {
@@ -793,10 +798,6 @@ FocusScope {
793798 }
794799 }
795800
796− LimitProxyModel {
797− id: previewLimitModel
798− }
799−
800801 Loader {
801802 id: subPageLoader
802803 objectName: "subPageLoader"
qml/Launcher/Launcher.qml+1
@@ -170,6 +170,7 @@ FocusScope {
170170 event.accepted = true;
171171 break;
172172 case Qt.Key_Right:
173+ case Qt.Key_Menu:
173174 panel.openQuicklist(panel.highlightIndex)
174175 event.accepted = true;
175176 break;
qml/Notifications/Notification.qml+9−28
@@ -55,29 +55,11 @@ StyledItem {
5555 name: "Ubuntu.Components.Themes.Ambiance"
5656 }
5757
58− signal dismissed()
59−
60− readonly property bool expanded: {
61− var result = false;
62−
63− if (type === Notification.SnapDecision) {
64− if (ListView.view.currentIndex === index || fullscreen) {
65− result = true;
66− } else {
67− if (ListView.view.count > 2) {
68− if (ListView.view.currentIndex === -1 && index == 1) {
69− result = true;
70− } else {
71− result = false;
72− }
73− } else {
74− result = true;
75− }
76− }
77− }
78−
79− return result;
80− }
58+ readonly property bool expanded: type === Notification.SnapDecision && // expand only snap decisions, if...
59+ (fullscreen || // - it's a fullscreen one
60+ ListView.view.currentIndex === index || // - it's the one the user clicked on
61+ (ListView.view.currentIndex === -1 && index == 0) // - the first one after the user closed the previous one
62+ )
8163
8264 NotificationAudio {
8365 id: sound
@@ -125,7 +107,6 @@ StyledItem {
125107 notification.notification.invokeAction(notification.actions.data(1, ActionModel.RoleActionId));
126108
127109 notification.notification.close();
128− notification.dismissed()
129110 }
130111
131112 Behavior on x {
@@ -142,9 +123,11 @@ StyledItem {
142123 if (fullscreen) {
143124 notification.notification.urgency = Notification.Critical;
144125 }
126+ ListView.view.topmostIsFullscreen = fullscreen;
145127 }
146128
147− Behavior on height {
129+ Behavior on implicitHeight {
130+ enabled: !fullscreen
148131 UbuntuNumberAnimation {
149132 duration: UbuntuAnimation.SnapDuration
150133 }
@@ -217,7 +200,6 @@ StyledItem {
217200 onNameOwnerChanged: {
218201 if (lastNameOwner !== "" && nameOwner === "" && notification.notification !== undefined) {
219202 notification.notification.close()
220− notification.dismissed()
221203 }
222204 lastNameOwner = nameOwner
223205 }
@@ -239,7 +221,7 @@ StyledItem {
239221 if (notification.type === Notification.Interactive) {
240222 notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
241223 } else {
242− notificationList.currentIndex = index;
224+ notification.ListView.view.currentIndex = index;
243225 }
244226 }
245227 onReleased: {
@@ -443,7 +425,6 @@ StyledItem {
443425 }
444426 onAccepted: {
445427 notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
446− notification.dismissed()
447428 }
448429 }
449430 }
qml/Notifications/NotificationMenuItemFactory.qml−3
@@ -151,18 +151,15 @@ Loader {
151151 onEntered: {
152152 menuModel.changeState(menuIndex, passphrase);
153153 clear(false);
154− notification.dismissed()
155154 }
156155
157156 onCancel: {
158157 menuModel.activate(menuIndex, false);
159− notification.dismissed()
160158 }
161159
162160 onEmergencyCall: {
163161 shell.startLockedApp("dialer-app");
164162 menuModel.activate(menuIndex, false);
165− notification.dismissed()
166163 }
167164
168165 property var extendedData: menuData && menuData.ext || undefined
qml/Notifications/Notifications.qml+10−25
@@ -26,7 +26,7 @@ ListView {
2626 objectName: "notificationList"
2727 interactive: false
2828
29− readonly property bool hasNotification: count > 1 // placeholder is index 0
29+ readonly property bool hasNotification: count > 0
3030 property real margin
3131 property bool hasMouse
3232 property url background: ""
@@ -42,17 +42,10 @@ ListView {
4242 filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
4343 }
4444
45− readonly property bool topmostIsFullscreen: fullscreenIndex != -1
45+ property bool topmostIsFullscreen: false
4646 spacing: topmostIsFullscreen ? 0 : units.gu(1)
4747
48− currentIndex: count > 1 ? 1 : -1
49−
50− property int fullscreenIndex: -1
51− onFullscreenIndexChanged: {
52− if (fullscreenIndex != -1) {
53− positionViewAtIndex(fullscreenIndex, ListView.Beginning);
54− }
55− }
48+ currentIndex: -1
5649
5750 delegate: Notification {
5851 objectName: "notification" + index
@@ -72,25 +65,17 @@ ListView {
7265 hasMouse: notificationList.hasMouse
7366 background: notificationList.background
7467
68+ Component.onCompleted: topmostIsFullscreen = false; // async, the factory loader will set fullscreen to true later
69+
70+ property int theIndex: index
71+ onTheIndexChanged: {
72+ ListView.view.topmostIsFullscreen = fullscreen; // when we get pushed down by e.g. volume notification
73+ }
74+
7575 // make sure there's no opacity-difference between the several
7676 // elements in a notification
7777 // FIXME: disabled all transitions because of LP: #1354406 workaround
7878 //layer.enabled: add.running || remove.running || populate.running
79−
80− onFullscreenChanged: updateListTopMostIsFullscreen();
81−
82− function updateListTopMostIsFullscreen() {
83− if (fullscreen) {
84− fullscreenIndex = index;
85− }
86− }
87−
88− onDismissed: {
89− if (fullscreenIndex == index) {
90− fullscreenIndex = -1;
91− notificationList.positionViewAtBeginning();
92− }
93− }
9479 }
9580
9681 // FIXME: disabled all transitions because of LP: #1354406 workaround
qml/OrientedShell.qml+10−3
@@ -32,6 +32,8 @@ Item {
3232 implicitWidth: units.gu(40)
3333 implicitHeight: units.gu(71)
3434
35+ onWidthChanged: calculateUsageMode();
36+
3537 DeviceConfiguration {
3638 id: deviceConfiguration
3739 name: applicationArguments.deviceName
@@ -103,10 +105,15 @@ Item {
103105 if (unity8Settings.usageMode === undefined)
104106 return; // gsettings isn't loaded yet, we'll try again in Component.onCompleted
105107
106− console.log("Pointer input devices changed:", pointerInputDevices, "current mode:", unity8Settings.usageMode, "old device count", miceModel.oldCount + touchPadModel.oldCount)
108+ console.log("Calculating new usage mode. Pointer devices:", pointerInputDevices, "current mode:", unity8Settings.usageMode, "old device count", miceModel.oldCount + touchPadModel.oldCount, "root width:", root.width / units.gu(1), "height:", root.height / units.gu(1))
107109 if (unity8Settings.usageMode === "Windowed") {
108− if (pointerInputDevices === 0) {
109− // All pointer devices have been unplugged. Move to staged.
110+ if (Math.min(root.width, root.height) > units.gu(60)) {
111+ if (pointerInputDevices === 0) {
112+ // All pointer devices have been unplugged. Move to staged.
113+ unity8Settings.usageMode = "Staged";
114+ }
115+ } else {
116+ // The display is not large enough, use staged.
110117 unity8Settings.usageMode = "Staged";
111118 }
112119 } else {
qml/Shell.qml+1−1
@@ -86,7 +86,7 @@ StyledItem {
8686 if (startingUp) {
8787 // Ensure we don't rotate during start up
8888 return Qt.PrimaryOrientation;
89− } else if (greeter && greeter.shown) {
89+ } else if (showingGreeter || notifications.topmostIsFullscreen) {
9090 return Qt.PrimaryOrientation;
9191 } else if (applicationsDisplayLoader.item) {
9292 return shell.orientations.map(applicationsDisplayLoader.item.supportedOrientations);
qml/Stages/ApplicationWindow.qml+1
@@ -27,6 +27,7 @@ FocusScope {
2727 property alias interactive: surfaceContainer.interactive
2828 property bool orientationChangesEnabled: d.supportsSurfaceResize ? d.surfaceOldEnoughToBeResized : true
2929 readonly property string title: surface && surface.name !== "" ? surface.name : d.name
30+ readonly property QtObject focusedSurface: d.focusedSurface.surface
3031
3132 // overridable from outside
3233 property bool fullscreen: {
qml/Stages/DecoratedWindow.qml+1
@@ -26,6 +26,7 @@ FocusScope {
2626
2727 property alias application: applicationWindow.application
2828 property alias surface: applicationWindow.surface
29+ readonly property alias focusedSurface: applicationWindow.focusedSurface
2930 property alias active: decoration.active
3031 readonly property alias title: applicationWindow.title
3132 property alias fullscreen: applicationWindow.fullscreen
qml/Stages/DesktopStage.qml+2−1
@@ -230,7 +230,7 @@ AbstractStage {
230230 Binding {
231231 target: MirFocusController
232232 property: "focusedSurface"
233− value: priv.focusedAppDelegate ? priv.focusedAppDelegate.surface : null
233+ value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
234234 when: !appRepeater.startingUp && root.parent
235235 }
236236
@@ -334,6 +334,7 @@ AbstractStage {
334334
335335 readonly property var surface: model.surface
336336 readonly property alias resizeArea: resizeArea
337+ readonly property alias focusedSurface: decoratedWindow.focusedSurface
337338
338339 readonly property bool isDash: model.application.appId == "unity8-dash"
339340
qml/Stages/PhoneStage.qml+1−1
@@ -244,7 +244,7 @@ AbstractStage {
244244 Binding {
245245 target: MirFocusController
246246 property: "focusedSurface"
247− value: priv.focusedAppDelegate ? priv.focusedAppDelegate.surface : null
247+ value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
248248 when: root.parent && !spreadRepeater.startingUp
249249 }
250250
qml/Stages/SpreadDelegate.qml+1
@@ -37,6 +37,7 @@ FocusScope {
3737 | Qt.LandscapeOrientation
3838 | Qt.InvertedPortraitOrientation
3939 | Qt.InvertedLandscapeOrientation
40+ readonly property alias focusedSurface: appWindow.focusedSurface
4041
4142 // to be set from outside
4243 property bool interactive: true
qml/Stages/TabletStage.qml+2−2
@@ -307,7 +307,7 @@ AbstractStage {
307307 Binding {
308308 target: MirFocusController
309309 property: "focusedSurface"
310− value: priv.focusedAppDelegate ? priv.focusedAppDelegate.surface : null
310+ value: priv.focusedAppDelegate ? priv.focusedAppDelegate.focusedSurface : null
311311 when: root.parent && !spreadRepeater.startingUp
312312 }
313313
@@ -542,7 +542,7 @@ AbstractStage {
542542 if (!app) {
543543 return index;
544544 }
545− var stage = spreadRepeater.itemAt(index) ? spreadRepeater.itemAt(index).stage : app.stage;
545+ var stage = spreadRepeater.itemAt(index) ? spreadRepeater.itemAt(index).stage : ApplicationInfoInterface.MainStage;
546546
547547 // don't shuffle indexes greater than "actives or next"
548548 if (index > 2) return index;
qml/Wizard/Page.qml+1−1
@@ -21,7 +21,7 @@ import Wizard 0.1
2121Item {
2222 readonly property real maximumContentWidth: units.gu(50)
2323 readonly property bool wideMode: width > units.gu(90) && width > height
24− readonly property bool contentAnimationRunning: contentAnimation.running
24+ readonly property alias contentAnimationRunning: contentAnimation.running
2525
2626 readonly property real buttonMargin: units.gu(3)
2727 readonly property real buttonWidth: (width - buttonMargin * 2) / 2 -
qml/Wizard/Pages/10-welcome.qml+2−1
@@ -110,6 +110,7 @@ LocalComponents.Page {
110110
111111 ListView {
112112 id: languagesListView
113+ objectName: "languagesListView"
113114 clip: true
114115 snapMode: ListView.SnapToItem
115116
@@ -124,7 +125,7 @@ LocalComponents.Page {
124125
125126 delegate: ListItem {
126127 id: itemDelegate
127− objectName: "languageDelegate" + index
128+ objectName: "languageDelegate_" + langLabel.text.toLowerCase().replace(/\s+/g, '_')
128129 highlightColor: backgroundColor
129130 divider.colorFrom: dividerColor
130131 divider.colorTo: backgroundColor
qml/Wizard/Pages/20-keyboard.qmlnew file+160
@@ -0,0 +1,160 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Ubuntu.Components.ListItems 1.3
20+import Ubuntu.SystemSettings.LanguagePlugin 1.0
21+import Wizard 0.1
22+import AccountsService 0.1
23+import Unity.InputInfo 0.1
24+import Unity.Application 0.1
25+import ".." as LocalComponents
26+
27+LocalComponents.Page {
28+ objectName: "keyboardPage"
29+
30+ title: i18n.tr("Select Keyboard")
31+ forwardButtonSourceComponent: forwardButton
32+
33+ skip: keyboardsModel.count == 0
34+ skipValid: false
35+
36+ UbuntuLanguagePlugin {
37+ id: langPlugin
38+ }
39+
40+ KeyboardLayoutsModel {
41+ id: layoutsModel
42+ language: selectedLanguage
43+ }
44+
45+ InputDeviceModel {
46+ id: keyboardsModel
47+ deviceFilter: InputInfo.Keyboard
48+ Component.onCompleted: skipValid = true;
49+ }
50+
51+ readonly property string selectedLanguage: langPlugin.languageCodes[langSelector.selectedIndex].split(".")[0] // chop off the codeset (.UTF-8)
52+
53+ property string selectedKeymap: ""
54+
55+ Column {
56+ id: column
57+ spacing: units.gu(2)
58+
59+ anchors {
60+ fill: content
61+ leftMargin: wideMode ? parent.leftMargin : staticMargin
62+ rightMargin: wideMode ? parent.rightMargin : staticMargin
63+ topMargin: staticMargin
64+ }
65+
66+ Label {
67+ id: label1
68+ anchors.left: parent.left
69+ anchors.right: parent.right
70+ text: i18n.tr("Keyboard language")
71+ font.weight: Font.Normal
72+ color: textColor
73+ }
74+
75+ LocalComponents.WizardItemSelector {
76+ id: langSelector
77+ objectName: "langSelector"
78+ anchors.left: parent.left
79+ anchors.right: parent.right
80+ model: langPlugin.languageNames
81+ selectedIndex: langPlugin.languageCodes.indexOf(i18n.language)
82+ onSelectedIndexChanged: {
83+ keyboardListView.currentIndex = -1;
84+ selectedKeymap = "";
85+ }
86+ }
87+
88+ Label {
89+ id: label2
90+ anchors.left: parent.left
91+ anchors.right: parent.right
92+ text: i18n.tr("Keyboard layout")
93+ font.weight: Font.Normal
94+ color: textColor
95+ }
96+
97+ ListView {
98+ id: keyboardListView
99+ clip: true
100+ anchors.left: parent.left
101+ anchors.right: parent.right
102+ snapMode: ListView.SnapToItem
103+ model: layoutsModel
104+ currentIndex: -1
105+ opacity: langSelector.expanded ? 0.5 : 1
106+ height: column.height - label1.height - langSelector.height - label2.height - column.spacing * 3
107+ enabled: !langSelector.expanded
108+ Behavior on opacity {
109+ UbuntuNumberAnimation {}
110+ }
111+
112+ delegate: ListItem {
113+ id: itemDelegate
114+ objectName: "kbdDelegate" + index
115+ height: layout.height + (divider.visible ? divider.height : 0)
116+ readonly property bool isCurrent: index === ListView.view.currentIndex
117+ highlightColor: backgroundColor
118+ divider.colorFrom: dividerColor
119+ divider.colorTo: backgroundColor
120+
121+ ListItemLayout {
122+ id: layout
123+ title.text: displayName
124+ title.color: textColor
125+ subtitle.text: layoutId
126+ subtitle.color: textColor
127+ padding.leading: -units.gu(1)
128+ padding.trailing: -units.gu(1)
129+ Image {
130+ SlotsLayout.position: SlotsLayout.Trailing
131+ SlotsLayout.overrideVerticalPositioning: true
132+ fillMode: Image.PreserveAspectFit
133+ anchors.verticalCenter: parent.verticalCenter
134+ height: units.gu(1.5)
135+ source: "data/Tick@30.png"
136+ visible: itemDelegate.isCurrent
137+ }
138+ }
139+
140+ onClicked: {
141+ keyboardListView.currentIndex = index;
142+ selectedKeymap = layoutId;
143+ }
144+ }
145+ }
146+ }
147+
148+ Component {
149+ id: forwardButton
150+ LocalComponents.StackButton {
151+ text: keyboardListView.currentIndex != -1 ? i18n.tr("Next") : i18n.tr("Skip")
152+ onClicked: {
153+ if (keyboardListView.currentIndex != -1) {
154+ AccountsService.keymaps = selectedKeymap;
155+ }
156+ pageStack.next();
157+ }
158+ }
159+ }
160+}
qml/Wizard/Pages/30-wifi.qml+10−5
@@ -20,6 +20,7 @@ import QMenuModel 0.1 as QMenuModel
2020import Ubuntu.Components 1.3
2121import Wizard 0.1
2222import Ubuntu.Connectivity 1.0
23+import Ubuntu.SystemImage 0.1
2324import ".." as LocalComponents
2425
2526LocalComponents.Page {
@@ -72,7 +73,7 @@ LocalComponents.Page {
7273 id: accessPointComponent
7374 ListItem {
7475 id: accessPoint
75− objectName: "accessPoint"
76+ objectName: "accessPoint_" + apName.text.toLowerCase().replace(/\s+/g, '_')
7677 highlightColor: backgroundColor
7778 enabled: menuData && menuData.sensitive || false
7879 divider.colorFrom: dividerColor
@@ -158,7 +159,7 @@ LocalComponents.Page {
158159 anchors.right: parent.right
159160 anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
160161 font.weight: Font.Light
161− color: "#68064d"
162+ color: textColor
162163 wrapMode: Text.Wrap
163164 text: listview.count > 0 ? i18n.tr("Available Wi-Fi networks")
164165 : i18n.tr("No available Wi-Fi networks")
@@ -166,6 +167,7 @@ LocalComponents.Page {
166167
167168 ListView {
168169 id: listview
170+ objectName: "accessPointsListView"
169171 anchors.left: parent.left
170172 anchors.right: parent.right
171173 clip: true
@@ -173,8 +175,6 @@ LocalComponents.Page {
173175 Layout.fillHeight: true
174176
175177 delegate: Loader {
176− id: loader
177−
178178 readonly property bool isAccessPoint: model.type === "unity.widgets.systemsettings.tablet.accesspoint"
179179 readonly property bool isConnected: item && item.menuData && item.menuData.actionState
180180 readonly property bool isEnterprise: item && item.isEnterprise
@@ -204,7 +204,12 @@ LocalComponents.Page {
204204 id: forwardButton
205205 LocalComponents.StackButton {
206206 text: (connected || listview.count === 0) ? i18n.tr("Next") : i18n.tr("Skip")
207− onClicked: pageStack.next()
207+ onClicked: {
208+ if (connected) {
209+ SystemImage.checkForUpdate(); // initiate the background check for System Update
210+ }
211+ pageStack.next();
212+ }
208213 }
209214 }
210215}
qml/Wizard/Pages/77-system-update.qmlnew file+156
@@ -0,0 +1,156 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import QtQuick.Layouts 1.1
19+import Ubuntu.Components 1.3
20+import Ubuntu.SystemImage 0.1
21+import Wizard 0.1
22+import ".." as LocalComponents
23+
24+LocalComponents.Page {
25+ id: systemUpdatePage
26+ objectName: "systemUpdatePage"
27+
28+ title: i18n.tr("Update Device")
29+ forwardButtonSourceComponent: forwardButton
30+
31+ skip: !SystemImage.updateDownloaded // skip the page when the system update is not ready to install
32+
33+ Column {
34+ id: column
35+ anchors {
36+ fill: content
37+ leftMargin: systemUpdatePage.leftMargin
38+ rightMargin: systemUpdatePage.rightMargin
39+ topMargin: systemUpdatePage.customMargin
40+ }
41+ spacing: units.gu(3)
42+ opacity: spinner.running ? 0.5 : 1
43+ Behavior on opacity {
44+ UbuntuNumberAnimation {}
45+ }
46+
47+ Label {
48+ anchors.left: parent.left
49+ anchors.right: parent.right
50+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
51+ font.weight: Font.Light
52+ color: textColor
53+ wrapMode: Text.Wrap
54+ fontSize: "small"
55+ text: i18n.tr("There is a system update available and ready to install. Afterwards, the device will automatically restart.")
56+ }
57+
58+ GridLayout {
59+ rows: 3
60+ columns: 2
61+ rowSpacing: units.gu(1)
62+ columnSpacing: units.gu(2)
63+
64+ Image {
65+ Layout.rowSpan: 3
66+ Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
67+ sourceSize: Qt.size(units.gu(3), units.gu(3))
68+ fillMode: Image.PreserveAspectFit
69+ source: "image://theme/distributor-logo"
70+ }
71+
72+ Label {
73+ color: textColor
74+ font.weight: Font.Normal
75+ fontSize: "small"
76+ text: i18n.ctr("string identifying name of the update", "Ubuntu system")
77+ }
78+
79+ Label {
80+ font.weight: Font.Light
81+ fontSize: "small"
82+ color: textColor
83+ text: i18n.ctr("version of the system update", "Version %1").arg(SystemImage.availableVersion)
84+ }
85+
86+ Label {
87+ font.weight: Font.Light
88+ fontSize: "small"
89+ color: textColor
90+ text: SystemImage.updateSize
91+ }
92+ }
93+
94+ Label {
95+ anchors.left: parent.left
96+ anchors.right: parent.right
97+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
98+ font.weight: Font.Light
99+ color: textColor
100+ wrapMode: Text.Wrap
101+ fontSize: "small"
102+ text: i18n.tr("This could take a few minutes...")
103+ }
104+
105+ Rectangle {
106+ anchors.left: parent.left
107+ anchors.leftMargin: column.anchors.leftMargin == 0 ? staticMargin : 0
108+ color: theme.palette.normal.foreground
109+ radius: units.dp(4)
110+ width: buttonLabel.paintedWidth + units.gu(3)
111+ height: buttonLabel.paintedHeight + units.gu(1.8)
112+
113+ Label {
114+ id: buttonLabel
115+ color: textColor
116+ text: i18n.tr("Install and restart now")
117+ font.weight: Font.Light
118+ anchors.centerIn: parent
119+ }
120+
121+ AbstractButton {
122+ id: button
123+ objectName: "installButton"
124+ anchors.fill: parent
125+ onClicked: {
126+ System.skipUntilFinishedPage();
127+ SystemImage.applyUpdate();
128+ }
129+ }
130+
131+ transformOrigin: Item.Top
132+ scale: button.pressed ? 0.98 : 1.0
133+ Behavior on scale {
134+ ScaleAnimator {
135+ duration: UbuntuAnimation.SnapDuration
136+ easing.type: Easing.Linear
137+ }
138+ }
139+ }
140+ }
141+
142+ ActivityIndicator {
143+ id: spinner
144+ anchors.centerIn: systemUpdatePage
145+ running: SystemImage.updateApplying
146+ visible: running
147+ }
148+
149+ Component {
150+ id: forwardButton
151+ LocalComponents.StackButton {
152+ text: i18n.tr("Skip")
153+ onClicked: pageStack.next()
154+ }
155+ }
156+}
qml/Wizard/WizardItemSelector.qmlnew file+128
@@ -0,0 +1,128 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import Ubuntu.Components 1.3
19+import Ubuntu.Components.ListItems 1.3 as ListItem
20+
21+Rectangle {
22+ id: optionToggle
23+
24+ property bool expanded
25+ property var model
26+ property int selectedIndex: -1
27+ readonly property double itemHeight: units.gu(4)
28+ readonly property int maxVisibleItems: 6
29+
30+ color: theme.palette.normal.foreground
31+ height: expanded ? maxVisibleItems * itemHeight : itemHeight
32+ Behavior on height {
33+ UbuntuNumberAnimation { id: heightAnimation }
34+ }
35+
36+ width: parent.width
37+ radius: units.gu(0.6)
38+ clip: true
39+ border.width: units.dp(1)
40+ border.color: theme.palette.normal.base
41+
42+ Flickable {
43+ id: flickable
44+ interactive: expanded
45+ flickableDirection: Flickable.VerticalFlick
46+ width: parent.width
47+ height: parent.height
48+ contentHeight: optionToggleRepeater.count * itemHeight
49+
50+ Column {
51+ id: optionToggleContent
52+ width: parent.width
53+
54+ Repeater {
55+ id: optionToggleRepeater
56+ model: optionToggle.model
57+
58+ delegate: Loader {
59+ asynchronous: true
60+ visible: status === Loader.Ready
61+
62+ Component {
63+ id: optionToggleEntry
64+
65+ AbstractButton {
66+ width: optionToggleContent.width
67+ height: optionToggle.itemHeight
68+ onClicked: {
69+ if (expanded) {
70+ selectedIndex = index;
71+ }
72+ expanded = !expanded
73+ }
74+
75+ ListItem.ThinDivider {
76+ visible: expanded && index != 0
77+ }
78+
79+ Label {
80+ id: delegateLabel
81+ anchors {
82+ left: parent.left
83+ leftMargin: units.gu(1)
84+ right: parent.right
85+ rightMargin: units.gu(3)
86+ verticalCenter: parent.verticalCenter
87+ }
88+
89+ width: parent.width
90+ text: expanded ? modelData : optionToggle.model[selectedIndex]
91+ color: textColor
92+ font.weight: Font.Light
93+ maximumLineCount: 1
94+ elide: Text.ElideRight
95+ }
96+
97+ Icon {
98+ anchors {
99+ right: parent.right
100+ rightMargin: units.gu(1)
101+ verticalCenter: parent.verticalCenter
102+ }
103+
104+ visible: (index == 0 || !expanded) && !heightAnimation.running
105+ name: expanded ? "up" : "down"
106+ width: units.gu(1.5)
107+ height: width
108+ }
109+
110+ Image {
111+ anchors {
112+ right: parent.right
113+ rightMargin: units.gu(1)
114+ verticalCenter: parent.verticalCenter
115+ }
116+ visible: expanded && index == optionToggle.selectedIndex && index != 0
117+ height: units.gu(1.5)
118+ fillMode: Image.PreserveAspectFit
119+ source: Qt.resolvedUrl("Pages/data/Tick@30.png")
120+ }
121+ }
122+ }
123+ sourceComponent: optionToggleEntry
124+ }
125+ }
126+ }
127+ }
128+}
run.shdeleted−70
@@ -1,70 +0,0 @@
1−#!/bin/sh
2−
3−. /etc/environment
4−export QML2_IMPORT_PATH
5−
6−QML_PHONE_SHELL_PATH=./builddir/src/unity8
7−GDB=false
8−FAKE=false
9−USE_MOCKS=false
10−MOUSE_TOUCH=true
11−
12−usage() {
13− echo "usage: "$0" [OPTIONS]\n" >&2
14− echo "Script to run the shell.\n" >&2
15− echo "OPTIONS:" >&2
16− echo " -f, --fake Force use of fake Qml modules." >&2
17− echo " -g, --gdb Run through gdb." >&2
18− echo " -h, --help Show this help." >&2
19− echo " -m, --nomousetouch Run without -mousetouch argument." >&2
20− echo >&2
21− exit 1
22−}
23−
24−ARGS=`getopt -n$0 -u -a --longoptions="fake,gdb,help:,nomousetouch" -o "fghm" -- "$@"`
25−[ $? -ne 0 ] && usage
26−eval set -- "$ARGS"
27−
28−while [ $# -gt 0 ]
29−do
30− case "$1" in
31− -f|--fake) USE_MOCKS=true;;
32− -g|--gdb) GDB=true;;
33− -h|--help) usage;;
34− -m|--nomousetouch) MOUSE_TOUCH=false;;
35− --) shift;break;;
36− esac
37− shift
38−done
39−
40−if $USE_MOCKS; then
41− export QML2_IMPORT_PATH=$QML2_IMPORT_PATH:$PWD/builddir/tests/mocks:$PWD/builddir/plugins:$PWD/builddir/modules
42− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/LightDM/liblightdm:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/QMenuModel
43−else
44− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/plugins/LightDM/liblightdm
45−fi
46−
47−QML_PHONE_SHELL_ARGS="-windowgeometry=40gux68gu -devicename=mako"
48−if $MOUSE_TOUCH; then
49− QML_PHONE_SHELL_ARGS="$QML_PHONE_SHELL_ARGS -mousetouch"
50−fi
51−
52−control_c()
53−{
54− /sbin/initctl stop unity8
55− exit $?
56−}
57−
58−trap control_c INT
59−
60−if $GDB; then
61− gdb -ex run --args $QML_PHONE_SHELL_PATH $QML_PHONE_SHELL_ARGS $@
62−else
63− status=`/sbin/initctl status unity8`
64− if [ "$status" != "unity8 stop/waiting" ]; then
65− echo "Unity8 is already running, please stop it first"
66− exit 1
67− fi
68− /sbin/initctl start unity8 BINARY="`readlink -f $QML_PHONE_SHELL_PATH` $QML_PHONE_SHELL_ARGS $@" XDG_DATA_DIRS=$XDG_DATA_DIRS QML2_IMPORT_PATH=$QML2_IMPORT_PATH LD_LIBRARY_PATH=$LD_LIBRARY_PATH
69− tailf -n 0 ~/.cache/upstart/unity8.log
70−fi
run_on_device.shdeleted−164
@@ -1,164 +0,0 @@
1−#!/bin/bash
2−CODE_DIR=shell
3−USER=phablet
4−USER_ID=32011
5−PACKAGE=unity8
6−BINARY=unity8
7−TARGET_IP=127.0.0.1
8−TARGET_SSH_PORT=2222
9−TARGET_DEBUG_PORT=3768
10−RUN_OPTIONS=-qmljsdebugger=port:$TARGET_DEBUG_PORT
11−SETUP=false
12−GDB=false
13−PINLOCK=false
14−KEYLOCK=false
15−NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
16−FLIPPED=false
17−SSH_WAS_STARTED=0
18−SSH_STARTED=0
19−PASSWORD=""
20−PASSFILE=""
21−
22−usage() {
23− echo "usage: run_on_device -a SUDO_PASSWORD [OPTIONS]"
24− echo
25− echo "Script to setup a build environment for the shell and sync build and run it on the device"
26− echo
27− echo "OPTIONS:"
28− echo " -a, --password The sudo password to use"
29− echo " -s, --setup Setup the build environment"
30− echo " -g, --gdb Run with gdb"
31− echo " -p, --pinlock Enable a PIN lock screen when running"
32− echo " -k, --keylock Enable a Keyboard lock screen when running"
33− echo
34− echo "IMPORTANT:"
35− echo " * Make sure to have networking setup on the device beforehand."
36− echo " * Execute that script from a directory containing unity8 code."
37− exit 1
38−}
39−
40−start_ssh() {
41− if [ $SSH_STARTED -eq 0 ]; then
42− adb_sudo initctl start ssh
43− SSH_STARTED=1
44− fi
45−}
46−
47−exec_with_ssh() {
48− start_ssh
49− ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT sudo -u $USER -i bash -ic \"$@\"
50−}
51−
52−adb_sudo() {
53− adb shell "SUDO_ASKPASS=${PASSFILE} sudo --askpass $@"
54−}
55−
56−install_ssh_key() {
57− HOME_DIR="/home/phablet"
58− adb push ~/.ssh/id_rsa.pub $HOME_DIR/.ssh/authorized_keys
59− adb shell chmod 700 $HOME_DIR/.ssh
60− adb shell chmod 600 $HOME_DIR/.ssh/authorized_keys
61−}
62−
63−setup_adb_forwarding() {
64− adb forward tcp:$TARGET_SSH_PORT tcp:22
65− adb forward tcp:$TARGET_DEBUG_PORT tcp:$TARGET_DEBUG_PORT
66−}
67−
68−install_dependencies() {
69− phablet-config writable-image --remotepassword ${PASSWORD} -p build-essential \
70− -p rsync \
71− -p bzr \
72− -p ccache \
73− -p gdb \
74− -p ninja-build \
75− -p devscripts \
76− -p equivs
77−}
78−
79−sync_code() {
80− [ -e .bzr ] && bzr export --uncommitted --format=dir /tmp/$CODE_DIR
81− [ -e .git ] && git checkout-index -a -f --prefix=/tmp/$CODE_DIR/
82− start_ssh
83− rsync -crlOzv --delete --exclude builddir -e "ssh -p $TARGET_SSH_PORT -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" /tmp/$CODE_DIR/ $USER@$TARGET_IP:$CODE_DIR/
84− rm -rf /tmp/$CODE_DIR
85−}
86−
87−build() {
88− exec_with_ssh PATH=/usr/lib/ccache:$PATH "cd $CODE_DIR/ && PATH=/usr/lib/ccache:$PATH ./build.sh"
89−}
90−
91−run() {
92− ARGS="--nomousetouch"
93− if $GDB; then
94− ARGS="$ARGS --gdb"
95− fi
96− if $PINLOCK; then
97− ARGS="$ARGS -p"
98− fi
99− if $KEYLOCK; then
100− ARGS="$ARGS -k"
101− fi
102−
103− exec_with_ssh "stop unity8"
104− exec_with_ssh "start maliit-server"
105− exec_with_ssh "cd $CODE_DIR/ && ./run.sh $ARGS -- $RUN_OPTIONS"
106− exec_with_ssh "stop maliit-server"
107− exec_with_ssh "start unity8"
108−}
109−
110−set -- `getopt -n$0 -u -a --longoptions="password:,setup,gdb,pinlock,keylock,help" "a:sgpkh" "$@"`
111−
112−# FIXME: giving incorrect arguments does not call usage and exit
113−while [ $# -gt 0 ]
114−do
115− case "$1" in
116− -a|--password) PASSWORD=$2;;
117− -s|--setup) SETUP=true;;
118− -g|--gdb) GDB=true;;
119− -p|--pinlock) PINLOCK=true;;
120− -k|--keylock) KEYLOCK=true;;
121− -h|--help) usage;;
122− --) shift;break;;
123− esac
124− shift
125−done
126−
127−if [ -z "${PASSWORD}" ]; then
128− echo "ERROR: You need to provide a sudo password..."
129− echo
130− usage
131−fi
132−
133−PASSFILE=$(adb shell 'mktemp' | tr -d '\r')
134−adb shell "echo '#!/bin/sh' > ${PASSFILE}"
135−adb shell "echo \"echo \\\"${PASSWORD}\\\"\" >> ${PASSFILE}"
136−adb shell "chmod +x ${PASSFILE}"
137−
138−setup_adb_forwarding
139−
140−status_output=$(adb_sudo initctl status ssh)
141−if [[ $status_output == "ssh start/running, process "* ]]; then
142− SSH_WAS_STARTED=1
143−fi
144−SSH_STARTED=$SSH_WAS_STARTED
145−
146−if $SETUP; then
147− echo "Setting up environment for building shell.."
148− install_ssh_key
149− install_dependencies
150− sync_code
151−else
152− echo "Transferring code.."
153− sync_code
154− echo "Building.."
155− build
156− echo "Running.."
157− run
158−fi
159−
160−adb shell "rm ${PASSFILE}"
161−
162−if [ $SSH_WAS_STARTED -eq 0 ]; then
163− adb_sudo initctl stop ssh
164−fi
src/SecondaryWindow.cpp+1−1
@@ -30,7 +30,7 @@ SecondaryWindow::SecondaryWindow(QQmlEngine *engine)
3030 if (!ok) {
3131 pxpgu = 8;
3232 }
33− engine->rootContext()->setContextProperty("internalGu", pxpgu);
33+ engine->rootContext()->setContextProperty(QStringLiteral("internalGu"), pxpgu);
3434 setResizeMode(QQuickView::SizeRootObjectToView);
3535 setColor("black");
3636 setTitle(QStringLiteral("Unity8 Shell - Secondary Screen"));
tests/mocks/AccountsService/AccountsService.h+1−1
@@ -84,7 +84,7 @@ class AccountsService: public QObject
8484 Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY emailChanged)
8585 Q_PROPERTY(QStringList keymaps
8686 READ keymaps
87− WRITE setKeymaps // only in mock
87+ WRITE setKeymaps
8888 NOTIFY keymapsChanged)
8989
9090public:
tests/mocks/Ubuntu/SystemImage/MockSystemImage.cpp+24−1
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -14,6 +14,9 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17+#include <QDebug>
18+#include <QTimer>
19+
1720#include "MockSystemImage.h"
1821
1922MockSystemImage::MockSystemImage(QObject *parent)
@@ -21,7 +24,27 @@ MockSystemImage::MockSystemImage(QObject *parent)
2124{
2225}
2326
27+void MockSystemImage::checkForUpdate()
28+{
29+ qDebug() << "Doing a fake system update check";
30+}
31+
32+void MockSystemImage::applyUpdate()
33+{
34+ qDebug() << "Applying a fake system update";
35+ setUpdateApplying(true);
36+ QTimer::singleShot(3000, [this] {setUpdateApplying(false);});
37+}
38+
2439void MockSystemImage::factoryReset()
2540{
2641 Q_EMIT resettingDevice();
2742}
43+
44+void MockSystemImage::setUpdateApplying(bool status)
45+{
46+ if (status != m_updateApplying) {
47+ m_updateApplying = status;
48+ Q_EMIT updateApplyingChanged();
49+ }
50+}
tests/mocks/Ubuntu/SystemImage/MockSystemImage.h+22−2
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -24,13 +24,33 @@ class MockSystemImage : public QObject
2424 Q_OBJECT
2525 Q_DISABLE_COPY(MockSystemImage)
2626
27+ Q_PROPERTY(bool updateDownloaded READ updateDownloaded CONSTANT)
28+ Q_PROPERTY(QString availableVersion READ availableVersion CONSTANT)
29+ Q_PROPERTY(QString updateSize READ updateSize CONSTANT)
30+ Q_PROPERTY(bool updateApplying READ updateApplying NOTIFY updateApplyingChanged)
31+
2732public:
28− explicit MockSystemImage(QObject *parent = 0);
33+ explicit MockSystemImage(QObject *parent = nullptr);
2934
35+ Q_INVOKABLE void checkForUpdate();
36+ Q_INVOKABLE void applyUpdate();
3037 Q_INVOKABLE void factoryReset();
3138
39+ bool updateApplying() const { return m_updateApplying; }
40+ // these are const only in mock
41+ bool updateDownloaded() const { return true; }
42+ QString availableVersion() const { return QStringLiteral("42"); }
43+ QString updateSize() const { return QStringLiteral("4.2 MB"); }
44+
3245Q_SIGNALS:
3346 void resettingDevice(); // only for mock
47+ void updateApplyingChanged();
48+
49+private Q_SLOTS:
50+ void setUpdateApplying(bool status);
51+
52+private:
53+ bool m_updateApplying = false;
3454};
3555
3656#endif // MOCK_SYSTEMIMAGE_H
tests/mocks/Unity/Application/ApplicationInfo.cpp−8
@@ -175,14 +175,6 @@ void ApplicationInfo::setIcon(const QUrl &value)
175175 }
176176}
177177
178−void ApplicationInfo::setStage(Stage value)
179−{
180− if (value != m_stage) {
181− m_stage = value;
182− Q_EMIT stageChanged(value);
183− }
184−}
185−
186178void ApplicationInfo::setState(State value)
187179{
188180 if (value != m_state) {
tests/mocks/Unity/Application/ApplicationInfo.h−4
@@ -67,9 +67,6 @@ public:
6767
6868 QUrl icon() const override { return m_icon; }
6969
70− Q_INVOKABLE void setStage(Stage value) override; // invokable only for mock
71− Stage stage() const override { return m_stage; }
72−
7370 Q_INVOKABLE void setState(State value);
7471 State state() const override { return m_state; }
7572
@@ -137,7 +134,6 @@ private:
137134 QString m_appId;
138135 QString m_name;
139136 QUrl m_icon;
140− Stage m_stage{MainStage};
141137 State m_state{Stopped};
142138 bool m_fullscreen{false};
143139 Qt::ScreenOrientations m_supportedOrientations{Qt::PortraitOrientation |
tests/mocks/Unity/Application/ApplicationManager.cpp−10
@@ -102,8 +102,6 @@ QVariant ApplicationManager::data(const QModelIndex& index, int role) const {
102102 return app->comment();
103103 case RoleIcon:
104104 return app->icon();
105− case RoleStage:
106− return app->stage();
107105 case RoleState:
108106 return app->state();
109107 case RoleFocused:
@@ -166,11 +164,6 @@ bool ApplicationManager::add(ApplicationInfo *application) {
166164 if (!appIndex.isValid()) return;
167165 Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleState);
168166 });
169− connect(application, &ApplicationInfo::stageChanged, this, [application, this]() {
170− QModelIndex appIndex = findIndex(application);
171− if (!appIndex.isValid()) return;
172− Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << ApplicationManager::RoleStage);
173− });
174167
175168 connect(application, &ApplicationInfo::closed, this, [application, this]() {
176169 this->remove(application);
@@ -344,7 +337,6 @@ void ApplicationManager::buildListOfAvailableApplications()
344337 application->setScreenshotId("gallery");
345338 application->setIconId("gallery");
346339 application->setShellChrome(Mir::LowChrome);
347− application->setStage(ApplicationInfo::MainStage);
348340 m_availableApplications.append(application);
349341
350342 application = new ApplicationInfo(this);
@@ -381,7 +373,6 @@ void ApplicationManager::buildListOfAvailableApplications()
381373 application->setName("GMail");
382374 application->setIconId("gmail");
383375 application->setScreenshotId("gmail-webapp.svg");
384− application->setStage(ApplicationInfo::MainStage);
385376 application->setSupportedOrientations(Qt::PortraitOrientation
386377 | Qt::LandscapeOrientation
387378 | Qt::InvertedPortraitOrientation
@@ -393,7 +384,6 @@ void ApplicationManager::buildListOfAvailableApplications()
393384 application->setName("Music");
394385 application->setIconId("soundcloud");
395386 application->setScreenshotId("music");
396− application->setStage(ApplicationInfo::MainStage);
397387 application->setSupportedOrientations(Qt::PortraitOrientation
398388 | Qt::LandscapeOrientation
399389 | Qt::InvertedPortraitOrientation
tests/mocks/Unity/Notifications/MockNotificationModel.cpp+4−6
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2015 Canonical Ltd.
2+ * Copyright 2015-2016 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -13,8 +13,6 @@
1313 * You should have received a copy of the GNU Lesser General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 *
16− * Authors:
17− * Mirco Mueller <mirco.mueller@canonical.com>
1816 */
1917
2018#include "MockNotificationModel.h"
@@ -118,10 +116,10 @@ void MockNotificationModel::remove(const int id) {
118116 }
119117}
120118
121−void MockNotificationModel::removeSecond() {
122− if(m_queue.size() < 2)
119+void MockNotificationModel::removeFirst() {
120+ if(m_queue.isEmpty())
123121 return;
124− removeInternal(1);
122+ removeInternal(0);
125123}
126124
127125void MockNotificationModel::removeInternal(int loc) {
tests/mocks/Unity/Notifications/MockNotificationModel.h+2−4
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2015 Canonical Ltd.
2+ * Copyright 2015-2016 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -13,8 +13,6 @@
1313 * You should have received a copy of the GNU Lesser General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 *
16− * Authors:
17− * Mirco Mueller <mirco.mueller@canonical.com>
1816 */
1917
2018#ifndef MOCK_NOTIFICATION_MODEL_H
@@ -48,7 +46,7 @@ public:
4846
4947 Q_INVOKABLE int queued() const;
5048 Q_INVOKABLE void remove(const int id);
51− Q_INVOKABLE void removeSecond();
49+ Q_INVOKABLE void removeFirst();
5250
5351 int getCount() const;
5452
tests/mocks/Wizard/CMakeLists.txt+6−3
@@ -1,5 +1,7 @@
1+pkg_search_module(GD3 REQUIRED gnome-desktop-3.0)
2+
13include_directories(
2− ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS}
4+ ${GD3_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS} ${GEONAMES_INCLUDE_DIRS}
35 ${CMAKE_SOURCE_DIR}/plugins/Wizard
46)
57
@@ -10,8 +12,9 @@ add_library(MockWizard-qml MODULE
1012 ${CMAKE_SOURCE_DIR}/plugins/Wizard/timezonemodel.cpp
1113 ${CMAKE_SOURCE_DIR}/plugins/Wizard/LocalePlugin.cpp
1214 ${CMAKE_SOURCE_DIR}/plugins/Wizard/Status.cpp
15+ ${CMAKE_SOURCE_DIR}/plugins/Wizard/keyboardLayoutsModel.cpp
1316)
1417
15−qt5_use_modules(MockWizard-qml DBus Qml Concurrent)
16−target_link_libraries(MockWizard-qml ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
18+qt5_use_modules(MockWizard-qml DBus Qml)
19+target_link_libraries(MockWizard-qml ${GD3_LDFLAGS} ${GLIB_LDFLAGS} ${GEONAMES_LDFLAGS})
1720add_unity8_mock(Wizard 0.1 Wizard TARGETS MockWizard-qml)
tests/mocks/Wizard/MockSystem.cpp+8
@@ -15,6 +15,7 @@
1515 */
1616
1717#include <QDebug>
18+#include <QSettings>
1819
1920#include "MockSystem.h"
2021
@@ -39,3 +40,10 @@ void MockSystem::updateSessionLocale(const QString &locale)
3940{
4041 Q_EMIT updateSessionLocaleCalled(locale);
4142}
43+
44+void MockSystem::skipUntilFinishedPage()
45+{
46+ QSettings settings;
47+ settings.setValue(QStringLiteral("Wizard/SkipUntilFinishedPage"), true);
48+ settings.sync();
49+}
tests/mocks/Wizard/MockSystem.h+4
@@ -33,6 +33,10 @@ public:
3333
3434public Q_SLOTS:
3535 void updateSessionLocale(const QString &locale);
36+ /**
37+ * Mark the wizard to skip all the pages and just show the last (welcome to ubuntu) page
38+ */
39+ void skipUntilFinishedPage();
3640
3741Q_SIGNALS:
3842 void wizardEnabledChanged();
tests/mocks/Wizard/mockplugin.cpp+2
@@ -20,6 +20,7 @@
2020#include "timezonemodel.h"
2121#include "LocalePlugin.h"
2222#include "Status.h"
23+#include "keyboardLayoutsModel.h"
2324
2425#include <QtQml/qqml.h>
2526
@@ -30,5 +31,6 @@ void MockWizardPlugin::registerTypes(const char *uri)
3031 qmlRegisterSingletonType<MockSystem>(uri, 0, 1, "System", [](QQmlEngine*, QJSEngine*) -> QObject* { return new MockSystem; });
3132 qmlRegisterSingletonType<Status>(uri, 0, 1, "Status", [](QQmlEngine*, QJSEngine*) -> QObject* { return new Status; });
3233 qmlRegisterType<TimeZoneLocationModel>(uri, 0, 1, "TimeZoneModel");
34+ qmlRegisterType<KeyboardLayoutsModel>(uri, 0, 1, "KeyboardLayoutsModel");
3335 qmlRegisterType<LocalePlugin>(uri, 0, 1, "LocalePlugin");
3436}
tests/plugins/Unity/Launcher/launchermodeltest.cpp−2
@@ -49,8 +49,6 @@ public:
4949 QString name() const override { return "mock"; }
5050 QString comment() const override { return "this is a mock"; }
5151 QUrl icon() const override { return QUrl(); }
52− ApplicationInfoInterface::Stage stage() const override { return ApplicationInfoInterface::MainStage; }
53− void setStage(ApplicationInfoInterface::Stage) override {}
5452 ApplicationInfoInterface::State state() const override { return ApplicationInfoInterface::Running; }
5553 bool focused() const override { return m_focused; }
5654 QString splashTitle() const override { return QString(); }
tests/plugins/Wizard/tst_pagelist.cpp+30−1
@@ -20,6 +20,7 @@
2020#include <QObject>
2121#include <QTemporaryDir>
2222#include <QTest>
23+#include <QSettings>
2324
2425#define PAGES_PATH "Wizard/Pages"
2526
@@ -28,7 +29,7 @@ class PageListTest: public QObject
2829 Q_OBJECT
2930
3031public:
31− PageListTest() {};
32+ PageListTest() {}
3233
3334private Q_SLOTS:
3435 void testCollect();
@@ -37,6 +38,7 @@ private Q_SLOTS:
3738 void testIgnoreNonQml();
3839 void testIgnoreDuplicates();
3940 void testDisabled();
41+ void testSkipUntilLastPage();
4042
4143private:
4244 void fillRoot(const QTemporaryDir &root);
@@ -150,5 +152,32 @@ void PageListTest::testDisabled()
150152 QCOMPARE(pageList.entries(), QStringList() << "4.qml");
151153}
152154
155+void PageListTest::testSkipUntilLastPage() {
156+ PageList * pageList = nullptr;
157+ QTemporaryDir root;
158+ fillRoot(root);
159+
160+ makeFile(root, "a", "1.qml");
161+ makeFile(root, "a", "2.qml");
162+ makeFile(root, "a", "3.qml");
163+
164+ // normal run
165+ pageList = new PageList;
166+ QCOMPARE(pageList->numPages(), 3);
167+ delete pageList; pageList = nullptr;
168+
169+ // after system update had been installed, have the last page only
170+ QSettings settings;
171+ settings.setValue(QStringLiteral("Wizard/SkipUntilFinishedPage"), true);
172+ pageList = new PageList;
173+ QCOMPARE(pageList->entries(), {QStringLiteral("3.qml")}); // only the last page should be in the list
174+ delete pageList; pageList = nullptr;
175+
176+ // normal run again
177+ pageList = new PageList;
178+ QCOMPARE(pageList->numPages(), 3);
179+ delete pageList; pageList = nullptr;
180+}
181+
153182QTEST_MAIN(PageListTest)
154183#include "tst_pagelist.moc"
tests/qmltests/Dash/tst_CardCarousel.qml+24
@@ -70,6 +70,15 @@ Rectangle {
7070
7171 when: windowShown
7272
73+ function findScale(item) {
74+ var scale = 1;
75+ while (item) {
76+ scale = scale * item.scale;
77+ item = item.parent;
78+ }
79+ return scale;
80+ }
81+
7382 function test_non_overlaid_header_layout() {
7483 // When the header is non overlaid
7584 // we grow down to accomodate the header but the y of the list is the same
@@ -83,5 +92,20 @@ Rectangle {
8392 compare(listView.y, yPos);
8493 compare(cardCarousel.height, height + cTool.headerHeight);
8594 }
95+
96+ function test_item_fits_view_data() {
97+ return [
98+ {tag: "overlaid", template: overlaidTemplate},
99+ {tag: "nonOverlaid", template: nonOverlaidTemplate},
100+ ];
101+ }
102+
103+ function test_item_fits_view(data) {
104+ cTool.template = data.template;
105+ var delegate0 = findChild(cardCarousel, "carouselDelegate0");
106+ tryCompareFunction(function() { return delegate0.item != null; }, true);
107+ var scale = findScale(delegate0.item);
108+ verify(delegate0.item.implicitHeight * scale < cardCarousel.height);
109+ }
86110 }
87111}
tests/qmltests/Launcher/tst_Launcher.qml+9−2
@@ -1165,7 +1165,14 @@ Rectangle {
11651165 tryCompare(shortCutHint0, "visible", false);
11661166 }
11671167
1168− function test_keyboardNavigation() {
1168+ function test_keyboardNavigation_data() {
1169+ return [
1170+ {tag: "right key", key: Qt.Key_Right},
1171+ {tag: "menu key", key: Qt.Key_Menu}
1172+ ]
1173+ }
1174+
1175+ function test_keyboardNavigation(data) {
11691176 var bfbFocusHighlight = findChild(launcher, "bfbFocusHighlight");
11701177 var quickList = findChild(launcher, "quickList");
11711178 var launcherPanel = findChild(launcher, "launcherPanel");
@@ -1206,7 +1213,7 @@ Rectangle {
12061213 assertFocusOnIndex(0); // Back to Top
12071214
12081215 // Right opens the quicklist
1209− keyClick(Qt.Key_Right);
1216+ keyClick(data.key);
12101217 assertFocusOnIndex(0); // Navigating the quicklist... the launcher focus should not move
12111218 tryCompare(quickList, "visible", true);
12121219 tryCompare(quickList, "selectedIndex", 0)
tests/qmltests/Notifications/tst_Notifications.qml+6−23
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2015 Canonical Ltd.
2+ * Copyright 2015-2016 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -31,21 +31,6 @@ Item {
3131 height: notificationsRect.height
3232 property int index: 0
3333
34− // add the default/PlaceHolder notification to the model
35− Component.onCompleted: {
36− var component = Qt.createComponent("Notification.qml")
37− var n = component.createObject("notification", {"nid": index++,
38− "type": Notification.PlaceHolder,
39− "hints": {},
40− "summary": "",
41− "body": "",
42− "icon": "",
43− "secondaryIcon": "",
44− "rawActions": []})
45− n.completed.connect(mockModel.onCompleted)
46− mockModel.append(n)
47− }
48−
4934 Row {
5035 id: rootRow
5136
@@ -157,15 +142,13 @@ Item {
157142 }
158143
159144 function clearNotifications() {
160− while(mockModel.count > 1) {
161− remove1stNotification()
145+ while(mockModel.count > 0) {
146+ remove1stNotification();
162147 }
163148 }
164149
165150 function remove1stNotification() {
166− if (mockModel.count > 1) {
167− mockModel.removeSecond()
168− }
151+ mockModel.removeFirst();
169152 }
170153
171154 Rectangle {
@@ -791,13 +774,13 @@ Item {
791774 waitForRendering(notifications);
792775
793776 // first one should be expanded by default
794− var notification1 = findChild(notifications, "notification1") // 0 is placeholder...
777+ var notification1 = findChild(notifications, "notification0")
795778 verify(!!notification1, "notification wasn't found");
796779 waitForRendering(notification1);
797780 verify(notification1.expanded);
798781
799782 // click the 2nd one, verify it's now expanded
800− var notification2 = findChild(notifications, "notification2") // 0 is placeholder...
783+ var notification2 = findChild(notifications, "notification1")
801784 verify(!!notification2, "notification wasn't found");
802785 waitForRendering(notification2);
803786 mouseClick(notification2);
tests/qmltests/Notifications/tst_OptionToggle.qml+1−16
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2015 Canonical Ltd.
2+ * Copyright 2015-2016 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -51,21 +51,6 @@ Row {
5151 function getRaw(id) {
5252 return mockNotification.createObject(mockModel)
5353 }
54−
55− // add the default/PlaceHolder notification to the model
56− Component.onCompleted: {
57− var n = {
58− type: Notification.PlaceHolder,
59− hints: {},
60− summary: "",
61− body: "",
62− icon: "",
63− secondaryIcon: "",
64− actions: []
65− }
66−
67− append(n)
68− }
6954 }
7055
7156 function addSnapDecisionNotification() {
tests/qmltests/Notifications/tst_SwipeToAct.qml+4−18
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014, 2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -53,21 +53,6 @@ Item {
5353 function getRaw(id) {
5454 return mockNotification.createObject(mockModel)
5555 }
56−
57− // add the default/PlaceHolder notification to the model
58− Component.onCompleted: {
59− var n = {
60− type: Notification.PlaceHolder,
61− hints: {},
62− summary: "",
63− body: "",
64− icon: "",
65− secondaryIcon: "",
66− actions: []
67− }
68−
69− append(n)
70− }
7156 }
7257
7358 function addSwipeToActNotification() {
@@ -93,8 +78,9 @@ Item {
9378 }
9479
9580 function remove1stNotification() {
96− if (mockModel.count > 0)
97− mockModel.remove(0)
81+ if (mockModel.count > 0) {
82+ mockModel.remove(0);
83+ }
9884 }
9985
10086 Rectangle {
tests/qmltests/Notifications/tst_VisualSnapDecisionsQueue.qml+7−23
@@ -47,21 +47,6 @@ Row {
4747 function getRaw(id) {
4848 return mockNotification.createObject(mockModel)
4949 }
50−
51− // add the default/PlaceHolder notification to the model
52− Component.onCompleted: {
53− var n = {
54− type: Notification.PlaceHolder,
55− hints: {},
56− summary: "",
57− body: "",
58− icon: "",
59− secondaryIcon: "",
60− actions: []
61− }
62−
63− append(n)
64− }
6550 }
6651
6752 function addSomeSnapDecisionNotifications() {
@@ -123,14 +108,13 @@ Row {
123108 }
124109
125110 function clearNotifications() {
126− // remove all but the first (PlaceHolder) notification
127− mockModel.remove(1, mockModel.count - 1)
111+ mockModel.clear();
128112 }
129113
130114 function removeTopMostNotification() {
131− // leave real/first (PlaceHolder) notification untouched
132− if (mockModel.count > 1)
133− mockModel.remove(1)
115+ if (mockModel.count > 0) {
116+ mockModel.remove(0);
117+ }
134118 }
135119
136120 Rectangle {
@@ -205,11 +189,11 @@ Row {
205189 notifications.forceLayout();
206190 waitForRendering(notifications);
207191
208− var snap_decision = [findChild(notifications, "notification1"),
192+ var snap_decision = [findChild(notifications, "notification0"),
193+ findChild(notifications, "notification1"),
209194 findChild(notifications, "notification2"),
210195 findChild(notifications, "notification3"),
211− findChild(notifications, "notification4"),
212− findChild(notifications, "notification5")]
196+ findChild(notifications, "notification4")]
213197
214198 for (var index = 0; index < snap_decision.length; index++) {
215199 verify(snap_decision[index] !== undefined, index + ". snap-decision wasn't found");
tests/qmltests/Stages/tst_TabletStage.qml+6−3
@@ -290,8 +290,9 @@ Rectangle {
290290 var webbrowserSurfaceId = topSurfaceList.nextId;
291291 webbrowserCheckBox.checked = true;
292292 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
293− var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
294− compare(webbrowserApp.stage, ApplicationInfoInterface.MainStage);
293+ var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
294+ verify(webbrowserDelegate);
295+ compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
295296 var webbrowserWindow = findAppWindowForSurfaceId(webbrowserSurfaceId);
296297 verify(webbrowserWindow);
297298
@@ -397,8 +398,10 @@ Rectangle {
397398 var webbrowserSurfaceId = topSurfaceList.nextId;
398399 webbrowserCheckBox.checked = true;
399400 waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
401+ var webbrowserDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
402+ verify(webbrowserDelegate);
403+ compare(webbrowserDelegate.stage, ApplicationInfoInterface.MainStage);
400404 var webbrowserApp = ApplicationManager.findApplication(webbrowserCheckBox.appId);
401− compare(webbrowserApp.stage, ApplicationInfoInterface.MainStage);
402405
403406 var gallerySurfaceId = topSurfaceList.nextId;
404407 galleryCheckBox.checked = true;
tests/qmltests/Wizard/tst_Wizard.qml+47−2
@@ -24,6 +24,7 @@ import Ubuntu.SystemSettings.SecurityPrivacy 1.0
2424import Ubuntu.SystemSettings.TimeDate 1.1
2525import Unity.Test 0.1 as UT
2626import Wizard 0.1
27+import Unity.InputInfo 0.1
2728import "../../../qml/Wizard"
2829
2930Item {
@@ -41,7 +42,12 @@ Item {
4142 id: wizard
4243 anchors.fill: parent
4344
45+ Component.onCompleted: {
46+ MockInputDeviceBackend.addMockDevice("/test", InputInfo.Keyboard);
47+ }
48+
4449 Component.onDestruction: {
50+ MockInputDeviceBackend.removeDevice("/test");
4551 wizardLoader.itemDestroyed = true;
4652 }
4753 }
@@ -74,6 +80,12 @@ Item {
7480 signalName: "timeZoneChangedCalled"
7581 }
7682
83+ SignalSpy {
84+ id: kbdLayoutSpy
85+ target: AccountsService
86+ signalName: "keymapsChanged"
87+ }
88+
7789 function setup() {
7890 AccountsService.hereEnabled = false;
7991 AccountsService.hereLicensePath = Qt.resolvedUrl("licenses");
@@ -88,6 +100,7 @@ Item {
88100 activateLocationSpy.clear();
89101 activateGPSSpy.clear();
90102 timezoneSpy.clear();
103+ kbdLayoutSpy.clear();
91104
92105 ActionData.data = {
93106 "location-detection-enabled": {
@@ -176,6 +189,10 @@ Item {
176189 tap(findChild(page, "forwardButton"));
177190 }
178191
192+ page = waitForPage("keyboardPage");
193+ if (name === page.objectName) return page;
194+ tap(findChild(page, "forwardButton"));
195+
179196 page = waitForPage("wifiPage");
180197 if (name === page.objectName) return page;
181198 tap(findChild(page, "forwardButton"));
@@ -223,7 +240,7 @@ Item {
223240
224241 function test_languageChange() {
225242 var page = goToPage("languagePage");
226− tap(findChild(page, "languageDelegate1")); // should invoke "fr" lang
243+ tap(findChild(page, "languageDelegate_french_(france)")); // should invoke "fr" lang
227244
228245 tryCompare(i18n, "language", "fr_FR");
229246 tap(findChild(page, "forwardButton"));
@@ -281,7 +298,7 @@ Item {
281298
282299 // Make sure that moving from sim page lands on wifi page
283300 tap(findChild(page, "forwardButton"));
284− waitForPage("wifiPage"); // thus skipping passwdPage
301+ waitForPage("keyboardPage"); // thus skipping passwdPage
285302 }
286303
287304 function verifyAnimationsNotRunning(page) {
@@ -319,6 +336,8 @@ Item {
319336 // now finish up
320337 page = waitForPage("reportingPage");
321338 tap(findChild(page, "forwardButton"));
339+ page = waitForPage("systemUpdatePage");
340+ tap(findChild(page, "forwardButton"));
322341 page = waitForPage("finishedPage");
323342 waitUntilTransitionsEnd(page);
324343 tap(findChild(page, "finishButton"));
@@ -359,6 +378,8 @@ Item {
359378 // now finish up
360379 page = waitForPage("reportingPage");
361380 tap(findChild(page, "forwardButton"));
381+ page = waitForPage("systemUpdatePage");
382+ tap(findChild(page, "forwardButton"));
362383 page = waitForPage("finishedPage");
363384 waitUntilTransitionsEnd(page);
364385 tap(findChild(page, "finishButton"));
@@ -377,6 +398,8 @@ Item {
377398 tap(findChild(page, "forwardButton"));
378399 page = waitForPage("reportingPage");
379400 tap(findChild(page, "forwardButton"));
401+ page = waitForPage("systemUpdatePage");
402+ tap(findChild(page, "forwardButton"));
380403 page = waitForPage("finishedPage");
381404 waitUntilTransitionsEnd(page);
382405 tap(findChild(page, "finishButton"));
@@ -480,5 +503,27 @@ Item {
480503 tap(findChild(page, "nameInput"));
481504 typeString("foobar");
482505 }
506+
507+ function test_keyboardPage() {
508+ var page = goToPage("keyboardPage");
509+ var forwardButton = findChild(page, "forwardButton");
510+
511+ // change language
512+ var langSelector = findChild(page, "langSelector");
513+ verify(langSelector);
514+ langSelector.selectedIndex = 1; // should be fr_FR
515+ print("Selected language:", page.selectedLanguage);
516+
517+ // pick some layout
518+ var kbdDelegate = findChild(page, "kbdDelegate1");
519+ verify(kbdDelegate);
520+ mouseClick(kbdDelegate);
521+ verify(kbdDelegate.isCurrent);
522+ print("Selected keymap:", page.selectedKeymap);
523+
524+ // verify the keymapsChanged signal got fired
525+ tap(findChild(page, "forwardButton"));
526+ tryCompare(kbdLayoutSpy, "count", 1);
527+ }
483528 }
484529}
tests/qmltests/tst_OrientedShell.qml+30−6
@@ -515,7 +515,6 @@ Rectangle {
515515 compare(primaryDelegate.focus, true);
516516 compare(primaryApp.rotatesWindowContents, false);
517517 compare(primaryApp.supportedOrientations, Qt.PrimaryOrientation);
518− compare(primaryApp.stage, ApplicationInfoInterface.MainStage);
519518
520519 tryCompareFunction(function(){return primaryDelegate.surface != null;}, true);
521520 verify(checkAppSurfaceOrientation(primaryAppWindow, primaryApp, root.primaryOrientationAngle));
@@ -559,7 +558,8 @@ Rectangle {
559558 compare(ApplicationManager.focusedApplicationId, "primary-oriented-app");
560559 compare(primaryApp.rotatesWindowContents, false);
561560 compare(primaryApp.supportedOrientations, Qt.PrimaryOrientation);
562− compare(primaryApp.stage, ApplicationInfoInterface.MainStage);
561+ var primaryDelegate = findChild(shell, "spreadDelegate_" + primarySurfaceId);
562+ compare(primaryDelegate.stage, ApplicationInfoInterface.MainStage);
563563
564564 tryCompareFunction(function(){return primaryApp.surfaceList.count > 0;}, true);
565565
@@ -599,7 +599,6 @@ Rectangle {
599599 compare(gmailApp.rotatesWindowContents, false);
600600 compare(gmailApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
601601 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
602− compare(gmailApp.stage, ApplicationInfoInterface.MainStage);
603602
604603 // wait until it's able to rotate
605604 tryCompare(shell, "orientationChangesEnabled", true);
@@ -724,7 +723,6 @@ Rectangle {
724723 compare(gmailApp.rotatesWindowContents, false);
725724 compare(gmailApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
726725 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
727− compare(gmailApp.stage, ApplicationInfoInterface.MainStage);
728726
729727 waitUntilAppWindowIsFullyLoaded(gmailSurfaceId);
730728
@@ -736,7 +734,10 @@ Rectangle {
736734 compare(musicApp.rotatesWindowContents, false);
737735 compare(musicApp.supportedOrientations, Qt.PortraitOrientation | Qt.LandscapeOrientation
738736 | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation);
739− compare(musicApp.stage, ApplicationInfoInterface.MainStage);
737+ if (data.deviceName === "manta" || data.deviceName === "flo") {
738+ var musicDelegate = findChild(shell, "spreadDelegate_" + musicSurfaceId);
739+ compare(musicDelegate.stage, ApplicationInfoInterface.MainStage);
740+ }
740741
741742 waitUntilAppWindowIsFullyLoaded(musicSurfaceId);
742743 tryCompare(shell, "orientationChangesEnabled", true);
@@ -889,6 +890,7 @@ Rectangle {
889890 ];
890891 }
891892 function test_appInSideStageDoesntRotateOnStartUp(data) {
893+ WindowStateStorage.saveStage("twitter-webapp", ApplicationInfoInterface.SideStage)
892894 loadShell(data.deviceName);
893895
894896 var twitterDelegate = null;
@@ -905,9 +907,11 @@ Rectangle {
905907 signalSpy.target = null;
906908 signalSpy.signalName = "runningChanged";
907909
910+ var twitterSurfaceId = topLevelSurfaceList.nextId;
908911 var twitterApp = ApplicationManager.startApplication("twitter-webapp");
909912 verify(twitterApp);
910− twitterApp.stage = ApplicationInfoInterface.SideStage;
913+ var twitterDelegate = findChild(shell, "spreadDelegate_" + twitterSurfaceId);
914+ compare(twitterDelegate.stage, ApplicationInfoInterface.SideStage);
911915
912916 // ensure the mock twitter-webapp is as we expect
913917 compare(twitterApp.rotatesWindowContents, false);
@@ -1143,6 +1147,26 @@ Rectangle {
11431147 orientedShellLoader.width = oldWidth;
11441148 }
11451149
1150+ function test_screenSizeChanges() {
1151+ loadShell("mako")
1152+ var shell = findChild(orientedShell, "shell");
1153+
1154+ tryCompare(shell, "usageScenario", "phone");
1155+
1156+ // make screen larger
1157+ orientedShellLoader.width = units.gu(90);
1158+ tryCompare(shell, "usageScenario", "phone");
1159+
1160+ // plug a mouse
1161+ MockInputDeviceBackend.addMockDevice("/mouse0", InputInfo.Mouse);
1162+ tryCompare(shell, "usageScenario", "desktop");
1163+
1164+ // make the screen smaller again, it should go back to staged even though there's still a mouse around
1165+ orientedShellLoader.width = units.gu(40);
1166+
1167+ tryCompare(shell, "usageScenario", "phone");
1168+ }
1169+
11461170 function test_overrideStaged() {
11471171 loadShell("mako")
11481172
tests/qmltests/tst_Shell.qml+23−4
@@ -2103,8 +2103,13 @@ Rectangle {
21032103 waitUntilAppWindowIsFullyLoaded(app2SurfaceId);
21042104
21052105 // Sanity checking
2106− compare(app1.stage, ApplicationInfoInterface.MainStage);
2107− compare(app2.stage, ApplicationInfoInterface.MainStage);
2106+ if (data.usageScenario === "tablet") {
2107+ var app1Delegate = findChild(shell, "spreadDelegate_" + app1SurfaceId);
2108+ compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
2109+
2110+ var app2Delegate = findChild(shell, "spreadDelegate_" + app2SurfaceId);
2111+ compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
2112+ }
21082113 verify(!app1.isTouchApp);
21092114
21102115 var app1Surface = app1.surfaceList.get(0);
@@ -2139,8 +2144,13 @@ Rectangle {
21392144 waitUntilAppWindowIsFullyLoaded(app2SurfaceId);
21402145
21412146 // Sanity checking
2142− compare(app1.stage, ApplicationInfoInterface.MainStage);
2143− compare(app2.stage, ApplicationInfoInterface.MainStage);
2147+ if (data.usageScenario === "tablet") {
2148+ var app1Delegate = findChild(shell, "spreadDelegate_" + app1SurfaceId);
2149+ compare(app1Delegate.stage, ApplicationInfoInterface.MainStage);
2150+
2151+ var app2Delegate = findChild(shell, "spreadDelegate_" + app2SurfaceId);
2152+ compare(app2Delegate.stage, ApplicationInfoInterface.MainStage);
2153+ }
21442154
21452155 var app1Surface = app1.surfaceList.get(0);
21462156 verify(app1Surface);
@@ -2429,6 +2439,15 @@ Rectangle {
24292439 // verify the initial keymap of the newly started app is the first one from the list
24302440 tryCompare(appSurface, "keymap", "sk");
24312441
2442+ // try to create a prompt surface, verify it also has the same keymap
2443+ app.promptSurfaceList.createSurface();
2444+ var promptSurface = app.promptSurfaceList.get(0);
2445+ verify(promptSurface);
2446+ tryCompare(appSurface, "keymap", promptSurface.keymap);
2447+ // ... and that the controller's surface keymap is also the same
2448+ tryCompare(MirFocusController.focusedSurface, "keymap", "sk");
2449+ app.promptSurfaceList.get(0).close();
2450+
24322451 // switch to next keymap, should go to "cz+qwerty"
24332452 keyClick(Qt.Key_Space, Qt.MetaModifier);
24342453 tryCompare(appSurface, "keymap", "cz+qwerty");
tools/registry-tracker.cpp+2−2
@@ -110,7 +110,7 @@ void RegistryTracker::runRegistry()
110110 }
111111
112112 // FIXME: keep in sync with the SSRegistry config
113− QString runtime_ini = QString(RUNTIME_CONFIG).arg(m_registry_config.fileName()).arg(m_mw_config.fileName()).arg(m_serverScopes ? "SSRegistry" : "");
113+ QString runtime_ini = QString(RUNTIME_CONFIG).arg(m_registry_config.fileName(), m_mw_config.fileName(), m_serverScopes ? "SSRegistry" : "");
114114 if (!m_systemScopes) {
115115 m_scopeInstallDir.reset(new QTemporaryDir(tmp.filePath("scopes.XXXXXX")));
116116 if (!m_scopeInstallDir->isValid()) {
@@ -118,7 +118,7 @@ void RegistryTracker::runRegistry()
118118 }
119119 scopeInstallDir = m_scopeInstallDir->path();
120120 }
121− QString registry_ini = QString(REGISTRY_CONFIG).arg(m_mw_config.fileName()).arg(scopeInstallDir).arg(scopeRunnerBin);
121+ QString registry_ini = QString(REGISTRY_CONFIG).arg(m_mw_config.fileName(), scopeInstallDir, scopeRunnerBin);
122122 QString mw_ini = QString(MW_CONFIG).arg(m_endpoints_dir.path());
123123
124124 if (!m_systemScopes) {