on xenial help sign in
Merged trunk.
commita83983a5a0806cc8d184addd4243580abaaf86ed authorPawel Stolowski <pawel.stolowski@canonical.com> dateThu 8 Aug 2013, 12:31 (13 years ago) parent424d37bf7b0c63
218 files changed+4455−2921
ApplicationArguments.h+49 Applications/applications.js+2−2 CMakeLists.txt+1 CODING+5−15 Components/ApplicationManagerWrapper.qml+10−1 Components/ApplicationScreenshot.qml+1−1 Components/Carousel.qml+38−1 Components/FilterGrid.qml+2−2 Components/ListItems/Header.qml+1−1 Components/PageHeader.qml+1−1 Components/Showable.qml+5−14 Components/Stage.qml+14 Components/Tile.qml+1−1 Dash/Apps/RunningApplicationTile.qml+1−1 Dash/Dash.qml−3 Dash/DashApps.qml+1−1 Dash/DashBar.qml+1−1 Dash/DashContent.qml+5−2 Dash/DashHome.qml+1 Dash/DashMusic.qml+2−2 Dash/DashPreview.qml+1−1 Dash/DashVideos.qml+3−4 Dash/Generic/GenericCarousel.qml+58 Dash/Generic/GenericFilterGrid.qml+59 Panel/Menus/IndicatorMenuWindow.qml → Dash/Generic/GenericFilterGridPotrait.qml+9−14 Dash/GenericScopeView.qml+55−41 Dash/Music/AlbumTile.qml+2−2 Dash/Video/VideoPreview.qml+3−3 Greeter/Greeter.qml+2−3 Greeter/GreeterContent.qml−1 Greeter/Lockscreen.qml+9−9 Greeter/PinLockscreen.qml+110−41 Greeter/PinPadButton.qml+5−16 Notifications/Notification.qml+6−5 Notifications/Notifications.qml+1 Panel/IndicatorItem.qml+6−1 Panel/IndicatorRow.qml+34−49 Panel/Indicators.qml+102−137 Panel/Indicators/DatetimeIndicatorPage.qml+2−2 Panel/Indicators/DatetimeIndicatorWidget.qml+1−1 Panel/Indicators/DefaultIndicatorWidget.qml+1−1 Panel/Indicators/NetworkIndicatorPage.qml+1−2 Panel/Indicators/client/IndicatorsClient.qml+8−9 Panel/Indicators/client/IndicatorsPage.qml+57−12 Panel/Indicators/client/IndicatorsTree.qml+62 Panel/MenuContent.qml+22−71 Panel/Menus/Overview.qml−70 Panel/Menus/Overview/FlightModeWidget.qml−60 Panel/Menus/Overview/OverviewGrid.qml−135 Panel/Menus/Overview/VolumeWidget.qml−88 Panel/Menus/Overview/graphics/plane_icon@18.png Panel/Menus/Overview/graphics/sound_off_icon@18.png Panel/Menus/Overview/graphics/sound_on_icon@18.png Panel/Panel.qml+28−9 Panel/SearchIndicator.qml+3−5 Shell.qml+79−36 build−3 cmake/modules/Plugins.cmake+25−15 cmake/modules/autopilot.cmake+2−1 debian/changelog+268 debian/control+3−3 debian/unity8-private.install+1 main.cpp+4−6 plugins/CMakeLists.txt+1 plugins/HudClient/CMakeLists.txt+2−1 plugins/LightDM/CMakeLists.txt+2−1 plugins/ListViewWithPageHeader/CMakeLists.txt+7−2 plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+98−14 plugins/ListViewWithPageHeader/listviewwithpageheader.h+19−2 plugins/Powerd/CMakeLists.txt+13 plugins/Powerd/Powerd.cpp+36 plugins/Powerd/Powerd.h+40 plugins/Powerd/plugin.cpp+36 plugins/Powerd/plugin.h+35 plugins/Powerd/qmldir+3 plugins/Ubuntu/Gestures/CMakeLists.txt+2−1 plugins/Unity/CMakeLists.txt+3−2 plugins/Unity/Indicators/CMakeLists.txt+8−8 plugins/Unity/Indicators/Messaging/qml/CMakeLists.txt+4−14 plugins/Unity/Indicators/Network/CMakeLists.txt+6−3 plugins/Unity/Indicators/Network/qml/CMakeLists.txt+4−14 plugins/Unity/Indicators/Network/qml/PasswordPage.qml+1−1 plugins/Unity/Indicators/Network/qml/qmldir+1 plugins/Unity/Indicators/flatmenuproxymodel.h+3−1 plugins/Unity/Indicators/indicator.h+3−1 plugins/Unity/Indicators/indicators.h+7−5 plugins/Unity/Indicators/indicatorsmanager.h+4−3 plugins/Unity/Indicators/indicatorsmodel.h+2−1 plugins/Unity/Indicators/menucontentactivator.cpp+345 plugins/Unity/Indicators/menucontentactivator.h+117 plugins/Unity/Indicators/modelprinter.cpp+114 plugins/Unity/Indicators/modelprinter.h+50 plugins/Unity/Indicators/plugin.cpp+5 plugins/Unity/Indicators/qml/CMakeLists.txt+4−13 plugins/Unity/Indicators/qml/IndicatorPage.qml−6 plugins/Unity/Indicators/qml/qmldir+1 plugins/Unity/Indicators/unityindicatorsglobal.h+23 plugins/Unity/Launcher/CMakeLists.txt+1 plugins/Unity/Launcher/backend/launcherbackend.cpp+3−3 plugins/Unity/Launcher/qmldir+1 plugins/Unity/categories.cpp+6−3 plugins/Unity/categories.h+3−2 plugins/Unity/previewinfohint.cpp+2−2 plugins/Unity/scope.h−3 plugins/Unity/variantutils.cpp+2−118 plugins/Unity/variantutils.h−2 plugins/Utils/CMakeLists.txt+2−1 po/ar.po+3−27 po/az.po+4−10 po/bg.po+3−15 po/ca.po+4−16 po/de.po+5−29 po/el.po+4−10 po/en_AU.po+3−27 po/en_GB.po+4−28 po/eo.po+3−3 po/es.po+2−2 po/fi.po+4−25 po/fo.po+4−10 po/fr.po+40−61 po/gl.po+4−16 po/he.po+4−10 po/hr.po+4−10 po/hu.po+4−10 po/hy.po+3−15 po/id.po+3−3 po/it.po+4−10 po/ja.po+3−3 po/kn.po+4−10 po/ko.po+4−4 po/ky.po+4−10 po/lv.po+4−10 po/my.po+4−7 po/nb.po+3−9 po/nl.po+4−10 po/pl.po+8−32 po/pt_BR.po+4−10 po/ro.po+4−10 po/ru.po+22−37 po/si.po+3−3 po/sl.po+2−2 po/sr.po+4−10 po/sv.po+3−3 po/te.po+4−4 po/tr.po+3−24 po/ug.po+6−27 po/uk.po+4−28 po/zh_CN.po+3−27 po/zh_TW.po+4−16 run_on_device+6−24 tests/autopilot/setup.py+17−6 tests/autopilot/unity8/__init__.py+90−5 tests/autopilot/unity8/indicators_client/__init__.py+1−1 tests/autopilot/unity8/indicators_client/tests/__init__.py+13−9 tests/autopilot/unity8/indicators_client/tests/test_battery.py+15−4 tests/autopilot/unity8/shell/__init__.py+35−5 tests/autopilot/unity8/shell/emulators/__init__.py+23−4 tests/autopilot/unity8/shell/emulators/dash.py+52 tests/autopilot/unity8/shell/emulators/greeter.py+43 tests/autopilot/unity8/shell/emulators/hud.py+80 tests/autopilot/unity8/shell/emulators/launcher.py+38 tests/autopilot/unity8/shell/emulators/main_window.py+44−13 tests/autopilot/unity8/shell/tests/__init__.py+216−58 tests/autopilot/unity8/shell/tests/helpers.py−161 tests/autopilot/unity8/shell/tests/test_hud.py+151 tests/autopilot/unity8/shell/tests/test_lock_screen.py+163 tests/autopilot/unity8/shell/tests/testbigscreen.py−25 tests/autopilot/unity8/shell/tests/testhud.py−145 tests/autopilot/unity8/shell/tests/testlockscreen.py−118 tests/mocks/CMakeLists.txt+1 tests/mocks/LightDM/demo/InfographicModelPrivate.cpp+3−3 tests/mocks/LightDM/demo/UsersModelPrivate.cpp+1−1 tests/mocks/LightDM/single/GreeterPrivate.cpp+2−4 tests/mocks/QMenuModel/CMakeLists.txt+11 tests/mocks/QMenuModel/QDBusActionGroup.qml+27 tests/mocks/QMenuModel/qmldir+2 tests/mocks/Ubuntu/Application/ApplicationManager.cpp+8−4 tests/mocks/Ubuntu/Application/ApplicationManager.h+4 tests/mocks/Unity/CMakeLists.txt+1 tests/mocks/Unity/Indicators/CMakeLists.txt+2−5 tests/mocks/Unity/Indicators/fakeplugin.cpp+4 tests/mocks/Unity/Indicators/qml/fake_menu_page1.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page2.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page3.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page4.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page5.qml−8 tests/mocks/Unity/Launcher/MockLauncherModel.cpp+1−1 tests/mocks/Unity/Notifications/CMakeLists.txt+11 tests/mocks/Unity/fake_categories.cpp+5−2 tests/mocks/Unity/fake_categories.h+2−1 tests/mocks/Unity/fake_scopes.cpp+2−2 tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6−1 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+50 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+102−2 tests/plugins/Unity/Indicators/CMakeLists.txt+1 tests/plugins/Unity/Indicators/indicatorsmanagertest.cpp+1−1 tests/plugins/Unity/Indicators/indicatorsmodeltest.cpp+1−1 tests/plugins/Unity/Indicators/menucontentactivatortest.cpp+303 tests/plugins/Unity/previewbindingstest.cpp−2 tests/plugins/Utils/qlimitproxymodeltest.cpp+1−1 tests/plugins/Utils/qsortfilterproxymodeltest.cpp+1−1 tests/qmltests/CMakeLists.txt+3−2 tests/qmltests/Components/tst_Stage.qml+1 tests/qmltests/Dash/tst_Dash.qml+4−4 tests/qmltests/Dash/tst_DashContent.qml+12−12 tests/qmltests/Dash/tst_FilterGrids.qml+1−1 tests/qmltests/Greeter/tst_Lockscreen.qml+1 tests/qmltests/Notifications/tst_Notifications.qml+20−9 tests/qmltests/Panel/Menus/tst_IndicatorMenuWindow.qml−68 tests/qmltests/Panel/tst_IndicatorItem.qml+10−16 tests/qmltests/Panel/tst_IndicatorRow.qml+21−35 tests/qmltests/Panel/tst_Indicators.qml+1−39 tests/qmltests/Panel/tst_MenuContent.qml+14−84 tests/qmltests/Panel/tst_Overview.qml−142 tests/qmltests/Panel/tst_Panel.qml+101−61 tests/qmltests/Panel/tst_SearchIndicator.qml+8−10 tests/qmltests/tst_Shell.qml+281 tests/utils/modules/Unity/Test/UnityTestCase.qml+32−23
ApplicationArguments.hnew file+49
@@ -0,0 +1,49 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authored by: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+
20+#ifndef APPLICATION_ARGUMENTS_H
21+#define APPLICATION_ARGUMENTS_H
22+
23+#include <QObject>
24+#include <QSize>
25+#include <QStringList>
26+
27+class ApplicationArguments : public QObject
28+{
29+ Q_OBJECT
30+public:
31+ ApplicationArguments(const QStringList& args) {
32+ if (args.contains(QLatin1String("-geometry")) && args.size() > args.indexOf(QLatin1String("-geometry")) + 1) {
33+ QStringList geometryArg = args.at(args.indexOf(QLatin1String("-geometry")) + 1).split('x');
34+ if (geometryArg.size() == 2) {
35+ m_size.rwidth() = geometryArg.at(0).toInt();
36+ m_size.rheight() = geometryArg.at(1).toInt();
37+ }
38+ }
39+ }
40+
41+ Q_INVOKABLE bool hasGeometry() const { return m_size.isValid(); }
42+ Q_INVOKABLE int width() const { return m_size.width(); }
43+ Q_INVOKABLE int height() const { return m_size.height(); }
44+
45+private:
46+ QSize m_size;
47+};
48+
49+#endif // APPLICATION_ARGUMENTS_H
Applications/applications.js+2−2
@@ -70,10 +70,10 @@ var __availableApplications = {
7070 'exec': '/usr/bin/qmlscene /usr/share/notes-app/NotesApp.qml',
7171 'stage': SideStage
7272 },
73− '/usr/share/applications/ubuntu-calendar-app.desktop': {
73+ '/usr/share/applications/calendar-app.desktop': {
7474 'name': i18n.tr("Calendar"),
7575 'icon': 'calendar',
76− 'exec': '/usr/bin/qmlscene /usr/share/ubuntu-calendar-app/calendar.qml',
76+ 'exec': '/usr/bin/qmlscene /usr/share/calendar-app/calendar.qml',
7777 'stage': SideStage
7878 },
7979 '/usr/share/applications/mediaplayer-app.desktop': {
CMakeLists.txt+1
@@ -101,6 +101,7 @@ set(shell_app_HDRS
101101
102102add_executable(${SHELL_APP}
103103 ${shellapplication_MOC_SRCS}
104+ ApplicationArguments.h
104105 main.cpp
105106 MouseTouchAdaptor.cpp
106107 )
CODING+5−15
@@ -23,19 +23,10 @@ $ cd ~/unity8/trunk
2323$ ./build --setup
2424
2525 this will:
26− - add the following PPA's
27− - ppa:phablet-team/desktop-deps
28− - ppa:canonical-qt5-edgers/qt5-proper
29− - ppa:ubuntu-sdk-team
3026 - install the required dependencies to build, as well as run on the desktop
3127 - it should also install unity-scope-home and unity-lens-application which
3228 are technically "recommends", not strict dependencies
3329
34−Note, once the PPA's are added, the script runs apt-get update, if you have
35−any failures associated with it, the build script will bail out of the setup
36−and fail to install all the required dependencies.
37−
38−
3930build Unity 8
4031-------------
4132
@@ -45,6 +36,7 @@ $ ./build
4536You may also rebuild with the -c for clean, which just deletes the build
4637directory.
4738
39+
4840Running Unity 8 on your desktop
4941===============================
5042
@@ -73,17 +65,15 @@ Notes
7365 - Create an EDS address book
7466 - Populate the address book with sample data
7567
68+
7669Running Unity 8 on devices
7770==========================
7871- Ubuntu Touch builds are currently only available in 13.10 flavour
79−- supported hardware should match one those listed here
72+- supported hardware should match one of those listed here
8073 https://wiki.ubuntu.com/Touch/Devices#Running_fine
8174- follow the Ubuntu Touch install instructions for your chosen device
8275 https://wiki.ubuntu.com/Touch/Install
83−- make sure your device is connected to a WiFi network
84−- If you haven’t already or if you’ve just freshly flashed your device
85− make sure you run phablet-network-setup which will allow package updates to
86− the device
76+- make sure your device is connected to a network
8777- also make sure you have your SSH key in ~/.ssh/id_rsa.pub (or install one
8878 on the device yourself)
8979
@@ -91,7 +81,6 @@ $ cd ~/unity/trunk
9181$ ./run_on_device --setup
9282 this will:
9383 - install your public SSH key on the device
94− - add ppa:canonical-qt5-edgers/qt5-proper and ppa:phablet-team
9584 - install the needed dependencies
9685
9786$ ./run_on_device
@@ -109,6 +98,7 @@ $ ./run_on_device -p OR -k
10998Notes
11099-----
111100- using adb over TCP has some advantages, Google will be of help here
101+ - NOTE: this is not yet available for flipped images
112102 - TL;DR: `adb tcpip 5555; adb connect $your_device_ip`
113103 - you can persist the above via `adb shell setprop persist.adb.tcp.port 5555`
114104 - it's unsafe - anyone can connect to your device
Components/ApplicationManagerWrapper.qml+10−1
@@ -29,6 +29,8 @@ Item {
2929 property bool keyboardVisible: ApplicationManager.keyboardVisible
3030 property int keyboardHeight: ApplicationManager.keyboardHeight
3131
32+ property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
33+
3234 Component.onCompleted: {
3335 // Start the watcher so that the ApplicationManager applications model can be populated.
3436 ApplicationManager.startWatcher();
@@ -121,9 +123,16 @@ Item {
121123 desktopFile = "/usr/share/applications/share-app.desktop"
122124 } else if (favoriteApplication == ApplicationManager.BrowserApplication) {
123125 desktopFile = "/usr/share/applications/webbrowser-app.desktop"
124− } else if (favoriteApplication == 4) { // ApplicationManager.PhoneApplication
126+ } else if (favoriteApplication == ApplicationManager.PhoneApplication) {
125127 desktopFile = "/usr/share/applications/phone-app.desktop"
128+ } else if (favoriteApplication == ApplicationManager.DialerApplication) {
129+ desktopFile = "/usr/share/applications/dialer-app.desktop"
130+ } else if (favoriteApplication == ApplicationManager.MessagingApplication) {
131+ desktopFile = "/usr/share/applications/messaging-app.desktop"
132+ } else if (favoriteApplication == ApplicationManager.AddressbookApplication) {
133+ desktopFile = "/usr/share/applications/address-book-app.desktop"
126134 }
135+
127136 applicationManager.focusRequested(desktopFile);
128137 }
129138 }
Components/ApplicationScreenshot.qml+1−1
@@ -46,7 +46,7 @@ Item {
4646 Rectangle {
4747 id: background
4848 anchors.fill: parent
49− color: "white"
49+ color: "white" // FIXME should use normal background color of Suru theme
5050 visible: applicationScreenshot.withBackground
5151 }
5252
Components/Carousel.qml+38−1
@@ -52,6 +52,12 @@ Item {
5252 /// @param itemY is y of the clicked delegate
5353 signal clicked(int index, var delegateItem, real itemY)
5454
55+ /// Emitted when the user pressed and held on an item
56+ /// @param index is the index of the held item
57+ /// @param delegateItem is the held component/delegate itself
58+ /// @param itemY is y of the held delegate
59+ signal pressAndHold(int index, var delegateItem, real itemY)
60+
5561 implicitHeight: listView.tileHeight * selectedItemScaleFactor
5662
5763 /* Basic idea behind the carousel effect is to move the items of the delegates (compacting /stuffing them).
@@ -159,6 +165,30 @@ Item {
159165 newContentXAnimation.start()
160166 }
161167
168+ function itemPressAndHold(index, delegateItem) {
169+ var x = CarouselJS.getXFromContinuousIndex(index,
170+ realWidth,
171+ realContentWidth,
172+ tileWidth,
173+ gapToMiddlePhase,
174+ gapToEndPhase,
175+ carousel.drawBuffer);
176+
177+ if (Math.abs(x - contentX) < 1) {
178+ /* We're pressAndHold the selected item and
179+ we're in the neighbourhood of radius 1 pixel from it.
180+ Let's emit the pressAndHold signal. */
181+ carousel.pressAndHold(index, delegateItem, delegateItem.y);
182+ return;
183+ }
184+
185+ stepAnimation.stop();
186+ newContentXAnimation.stop();
187+
188+ newContentX = x;
189+ newContentXAnimation.start();
190+ }
191+
162192 onMovementStarted: {
163193 stepAnimation.stop()
164194 newContentXAnimation.stop()
@@ -279,7 +309,14 @@ Item {
279309
280310 anchors.fill: parent
281311
282− onClicked: listView.itemClicked(index, item)
312+ onClicked: {
313+ listView.itemClicked(index, item)
314+ }
315+
316+ onPressAndHold: {
317+ listView.itemPressAndHold(index, item)
318+ }
319+
283320 }
284321 }
285322 }
Components/FilterGrid.qml+2−2
@@ -99,7 +99,7 @@ Item {
9999
100100 UbuntuShape {
101101 anchors.fill: parent
102− color: "#33ffffff"
102+ color: "#33ffffff" // FIXME no palette
103103 radius: "small"
104104 }
105105
@@ -123,7 +123,7 @@ Item {
123123 }
124124 text: (filter) ? "+ View all (" + model.count + ")" : "- Show fewer"
125125 fontSize: "small"
126− color: "#f3f3e7"
126+ color: Theme.palette.selected.backgroundText
127127 opacity: 0.6
128128 style: Text.Raised
129129 styleColor: "black"
Components/ListItems/Header.qml+1−1
@@ -45,7 +45,7 @@ Item {
4545 verticalCenter: parent.verticalCenter
4646 }
4747
48− color: "#f3f3e7" //at 60%
48+ color: Theme.palette.selected.backgroundText //at 60%
4949 opacity: 0.6
5050 font.family: "Ubuntu"
5151 fontSize: "medium"
Components/PageHeader.qml+1−1
@@ -90,7 +90,7 @@ Item {
9090 verticalCenter: parent.verticalCenter
9191 }
9292
93− color: "#f3f3e7"
93+ color: Theme.palette.selected.backgroundText
9494 opacity: 0.8
9595 font.family: "Ubuntu"
9696 font.weight: Font.Light
Components/Showable.qml+5−14
@@ -52,7 +52,7 @@ Item {
5252 function show() {
5353 required = true;
5454 if (created) {
55− __reallyShow(true);
55+ __reallyShow();
5656 } else {
5757 __shouldShow = true;
5858 }
@@ -60,16 +60,12 @@ Item {
6060
6161 onCreatedChanged: {
6262 if (created && __shouldShow) {
63− __reallyShow(true);
63+ __reallyShow();
6464 __shouldShow = false;
6565 }
6666 }
6767
68− function showWithoutAnimation() {
69− __reallyShow(false);
70− }
71−
72− function __reallyShow(animated) {
68+ function __reallyShow() {
7369 if (!available) {
7470 return false;
7571 }
@@ -81,13 +77,8 @@ Item {
8177 }
8278
8379 if (showAnimation != undefined) {
84− if (animated) {
85− if (!showAnimation.running) {
86− showAnimation.restart()
87− }
88− } else {
89− showAnimation.start();
90− showAnimation.complete();
80+ if (!showAnimation.running) {
81+ showAnimation.restart()
9182 }
9283 } else {
9384 visible = true;
Components/Stage.qml+14
@@ -39,6 +39,7 @@ Showable {
3939 type == ApplicationInfo.MainStage ? applicationManager.mainStageApplications
4040 : applicationManager.sideStageApplications
4141 property bool fullyShown: false
42+ property bool fullyHidden: true
4243 readonly property var focusedApplication:
4344 type == ApplicationInfo.MainStage ? applicationManager.mainStageFocusedApplication
4445 : applicationManager.sideStageFocusedApplication
@@ -249,6 +250,19 @@ Showable {
249250 }
250251 }
251252
253+ Connections {
254+ target: stage.applications
255+ onCountChanged: { __discardObsoleteScreenshots(); }
256+ ignoreUnknownSignals: true
257+ }
258+ onFullyHiddenChanged: { __discardObsoleteScreenshots(); }
259+ function __discardObsoleteScreenshots() {
260+ if (stage.fullyHidden && stage.applications && stage.applications.count == 0) {
261+ stage.focusedApplicationWhenUsingScreenshots = undefined;
262+ stage.__hideScreenshots();
263+ }
264+ }
265+
252266
253267 SequentialAnimation {
254268 id: showStartingApplicationAnimation
Components/Tile.qml+1−1
@@ -75,7 +75,7 @@ AbstractButton {
7575 rightMargin: units.gu(1)
7676 }
7777
78− color: "#f3f3e7"
78+ color: Theme.palette.selected.backgroundText
7979 opacity: 0.9
8080 style: Text.Raised
8181 styleColor: "black"
Dash/Apps/RunningApplicationTile.qml+1−1
@@ -113,7 +113,7 @@ AbstractButton {
113113 }
114114 text: (application) ? application.name : ""
115115
116− color: "#f3f3e7"
116+ color: Theme.palette.selected.backgroundText
117117 opacity: 0.9
118118 style: Text.Raised
119119 styleColor: "black"
Dash/Dash.qml−3
@@ -27,9 +27,6 @@ Showable {
2727 property string showScopeOnLoaded: "home.scope"
2828 property real contentScale: 1.0
2929
30− width: units.gu(40)
31− height: units.gu(71)
32−
3330 function setCurrentScope(scopeId, animate, reset) {
3431 var scopeIndex = filteredScopes.findFirst(Scopes.RoleId, scopeId)
3532
Dash/DashApps.qml+1−1
@@ -87,7 +87,7 @@ ScopeView {
8787 model: scopeView.scope.categories
8888
8989 delegate: Item {
90− Component.onCompleted: if (index == 3) scopeView.installedModel = Qt.binding(function() { return model.results; });
90+ Component.onCompleted: if (categoryId == "installed") scopeView.installedModel = Qt.binding(function() { return model.results; });
9191 }
9292 }
9393
Dash/DashBar.qml+1−1
@@ -117,7 +117,7 @@ Item {
117117
118118 Rectangle {
119119 id: highlightLine
120− color: "#dd4814"
120+ color: Theme.palette.selected.foreground
121121 height: parent.height
122122 anchors.bottom: parent.bottom
123123 z: 1
Dash/DashContent.qml+5−2
@@ -20,8 +20,6 @@ import Unity 0.1
2020
2121Item {
2222 id: dashContent
23− width: units.gu(40)
24− height: units.gu(71)
2523
2624 property var model: null
2725 property var scopes: null
@@ -117,6 +115,11 @@ Item {
117115 asynchronous: true
118116 source: scopeMapper.map(scope.id)
119117
118+ // these are needed for autopilot tests
119+ readonly property string scopeId: scope.id
120+ readonly property bool isCurrent: ListView.isCurrentItem
121+ readonly property bool isLoaded: status == Loader.Ready
122+
120123 onLoaded: {
121124 item.scope = Qt.binding(function() { return scope })
122125 item.isCurrent = Qt.binding(function() { return ListView.isCurrentItem })
Dash/DashHome.qml+1
@@ -26,6 +26,7 @@ import "Music"
2626
2727ScopeView {
2828 id: root
29+ objectName: "DashHome"
2930
3031 onMovementStarted: listView.showHeader()
3132
Dash/DashMusic.qml+2−2
@@ -52,7 +52,7 @@ ScopeView {
5252
5353 function getRenderer(categoryId) {
5454 switch (categoryId) {
55− case 1: return "Music/MusicCarousel.qml"
55+ case "featured": return "Music/MusicCarousel.qml"
5656 default: return "Music/MusicFilterGrid.qml"
5757 }
5858 }
@@ -69,7 +69,7 @@ ScopeView {
6969 id: base
7070 highlightWhenPressed: false
7171
72− property int categoryId: id
72+ property string categoryId: model.categoryId
7373
7474 Loader {
7575 anchors { top: parent.top; left: parent.left; right: parent.right }
Dash/DashPreview.qml+1−1
@@ -92,7 +92,7 @@ Rectangle {
9292 elide: Text.ElideRight
9393 fontSize: "x-large"
9494 font.weight: Font.Light
95− color: "#f3f3e7"
95+ color: Theme.palette.selected.backgroundText
9696 opacity: 0.9
9797 text: root.title
9898 style: Text.Raised
Dash/DashVideos.qml+3−4
@@ -53,7 +53,7 @@ ScopeView {
5353
5454 function getRenderer(categoryId) {
5555 switch (categoryId) {
56− case 1: return "Video/VideosCarousel.qml"
56+ case "featured": return "Video/VideosCarousel.qml"
5757 default: return "Video/VideosFilterGrid.qml"
5858 }
5959 }
@@ -102,8 +102,7 @@ ScopeView {
102102 delegate: ListItems.Base {
103103 id: base
104104 highlightWhenPressed: false
105− property int categoryIndex: index
106− property int categoryId: id
105+ property string categoryId: model.categoryId
107106
108107 Loader {
109108 id: loader
@@ -119,7 +118,7 @@ ScopeView {
119118 var dataItem;
120119 // VideosCarousel and VideosFilterGrid have different
121120 // clicked signals, accomodate for that
122− if (categoryId == 1) {
121+ if (categoryId == "featured") {
123122 var fileUri = delegateItem.model.uri.replace(/^[^:]+:/, "")
124123 dataItem = {fileUri: fileUri, nfoUri: delegateItem.model.comment}
125124 } else {
Dash/Generic/GenericCarousel.qmlnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../../Components"
20+import "../../Components/IconUtil.js" as IconUtil
21+
22+Carousel {
23+ id: genericCarousel
24+
25+ tileAspectRatio: 198 / 288
26+ minimumTileWidth: units.gu(13)
27+ itemComponent: carouselDelegateGeneric
28+ selectedItemScaleFactor: 1.14
29+ cacheBuffer: 1404 // 18px * 13gu * 6
30+ height: implicitHeight + units.gu(6)
31+
32+ Component {
33+ id: carouselDelegateGeneric
34+
35+ BaseCarouselDelegate {
36+ id: item
37+
38+ UbuntuShape {
39+ anchors.fill: parent
40+ radius: "medium"
41+ borderSource: ""
42+ image: Image {
43+ asynchronous: true
44+ sourceSize { width: item.width; height: item.height }
45+ source: model ? IconUtil.from_gicon(model.icon) : ""
46+ }
47+ }
48+
49+ BorderImage {
50+ anchors.centerIn: parent
51+ opacity: 0.6
52+ source: "../../Components/graphics/non-selected.sci"
53+ width: parent.width + units.gu(1.5)
54+ height: parent.height + units.gu(1.5)
55+ }
56+ }
57+ }
58+}
Dash/Generic/GenericFilterGrid.qmlnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../../Components"
19+import "../../Components/IconUtil.js" as IconUtil
20+
21+FilterGrid {
22+ id: filtergrid
23+
24+ filter: false
25+ minimumHorizontalSpacing: units.gu(0.5)
26+ delegateWidth: units.gu(11)
27+ delegateHeight: units.gu(9.5)
28+ verticalSpacing: units.gu(2)
29+
30+ property int iconWidth: units.gu(8)
31+ property int iconHeight: units.gu(7.5)
32+
33+ signal clicked(int index, var delegateItem, real itemY)
34+ signal pressAndHold(int index, var delegateItem, real itemY)
35+
36+ delegate: Tile {
37+ id: tile
38+ objectName: "delegate" + index
39+ width: filtergrid.cellWidth
40+ height: filtergrid.cellHeight
41+ text: model.title
42+ imageWidth: filtergrid.iconWidth
43+ imageHeight: filtergrid.iconHeight
44+
45+ source: IconUtil.from_gicon(model.icon)
46+
47+ fillMode: Image.PreserveAspectCrop
48+
49+ onClicked: {
50+ var data = { model: model }
51+ filtergrid.clicked(index, data, tile.y)
52+ }
53+
54+ onPressAndHold: {
55+ var data = { model: model }
56+ filtergrid.pressAndHold(index, data, tile.y)
57+ }
58+ }
59+}
Panel/Menus/IndicatorMenuWindow.qml → Dash/Generic/GenericFilterGridPotrait.qmlrenamed+9−14
@@ -15,21 +15,16 @@
1515 */
1616
1717import QtQuick 2.0
18+import "../../Components"
1819
19−Item {
20− id: menuWindow
20+GenericFilterGrid {
21+ id: filtergrid
2122
22− property bool shown: false
23− property int contentHeight: height
24− property string headingText: name
25− property string name
23+ minimumHorizontalSpacing: units.gu(0.5)
24+ delegateWidth: units.gu(11)
25+ delegateHeight: units.gu(18)
26+ verticalSpacing: units.gu(2)
2627
27− enabled: shown
28− opacity: shown ? 1.0 : 0.0
29− Behavior on opacity { NumberAnimation {duration: shown ? 300 : 150 } }
30−
31− // don't pass any events under this screen
32− MouseArea {
33− anchors.fill: parent
34− }
28+ iconWidth: (width / columns) * 0.8
29+ iconHeight: iconWidth * 16 / 11
3530}
Dash/GenericScopeView.qml+55−41
@@ -56,53 +56,45 @@ ScopeView {
5656 delegate: ListItems.Base {
5757 highlightWhenPressed: false
5858
59− FilterGrid {
60− id: filtergrid
61− model: results
62−
59+ Loader {
60+ id: rendererLoader
6361 anchors {
6462 top: parent.top
6563 left: parent.left
6664 right: parent.right
6765 }
6866
69− filter: false
70− minimumHorizontalSpacing: units.gu(0.5)
71− delegateWidth: units.gu(11)
72− delegateHeight: units.gu(18)
73− verticalSpacing: units.gu(2)
74−
75− delegate: Tile {
76− width: filtergrid.cellWidth
77− height: filtergrid.cellHeight
78− text: title
79− imageWidth: units.gu(11)
80− imageHeight: units.gu(16)
81−
82− source: IconUtil.from_gicon(icon)
83−
84− MouseArea {
85− anchors {
86− fill: parent
87− }
88− onClicked: {
89− mouse.accepted = true
90− effect.positionPx = mapToItem(categoryView, 0, 0).y
91− scopeView.scope.activate(uri, icon,
92− category, 0,
93− mimetype, title,
94− comment, dndUri,
95− metadata)
96− }
97− onPressAndHold: {
98− mouse.accepted = true
99− effect.positionPx = mapToItem(categoryView, 0, 0).y
100− scopeView.scope.preview(uri, icon,
101− category, 0,
102− mimetype, title,
103− comment, dndUri,
104− metadata)
105− }
67+ source: getRenderer(model.renderer, model.contentType)
68+
69+ onLoaded: {
70+ item.model = results
71+ }
72+
73+ Connections {
74+ target: rendererLoader.item
75+ onClicked: {
76+ effect.positionPx = mapToItem(categoryView, 0, itemY).y
77+ scopeView.scope.activate(delegateItem.model.uri,
78+ delegateItem.model.icon,
79+ delegateItem.model.category,
80+ 0,
81+ delegateItem.model.mimetype,
82+ delegateItem.model.title,
83+ delegateItem.model.comment,
84+ delegateItem.model.dndUri,
85+ delegateItem.model.metadata)
86+ }
87+ onPressAndHold: {
88+ effect.positionPx = mapToItem(categoryView, 0, itemY).y
89+ scopeView.scope.preview( delegateItem.model.uri,
90+ delegateItem.model.icon,
91+ delegateItem.model.category,
92+ 0,
93+ delegateItem.model.mimetype,
94+ delegateItem.model.title,
95+ delegateItem.model.comment,
96+ delegateItem.model.dndUri,
97+ delegateItem.model.metadata)
10698 }
10799 }
108100 }
@@ -122,6 +114,28 @@ ScopeView {
122114 }
123115 }
124116
117+ function getDefaultRendererId(contentType) {
118+ switch (contentType) {
119+ default: return "grid";
120+ }
121+ }
122+
123+ function getRenderer(rendererId, contentType) {
124+ if (rendererId == "default") {
125+ rendererId = getDefaultRendererId(contentType);
126+ }
127+ switch (rendererId) {
128+ case "grid": {
129+ switch (contentType) {
130+ case "video": return "Generic/GenericFilterGridPotrait.qml";
131+ default: return "Generic/GenericFilterGrid.qml";
132+ }
133+ }
134+ case "carousel": return "Generic/GenericCarousel.qml";
135+ default: return "Generic/GenericFilterGrid.qml";
136+ }
137+ }
138+
125139 OpenEffect {
126140 id: effect
127141 anchors {
Dash/Music/AlbumTile.qml+2−2
@@ -69,7 +69,7 @@ AbstractButton {
6969 rightMargin: units.gu(1)
7070 }
7171
72− color: "#f3f3e7"
72+ color: Theme.palette.selected.backgroundText
7373 opacity: 0.9
7474 style: Text.Raised
7575 styleColor: "black"
@@ -97,7 +97,7 @@ AbstractButton {
9797 rightMargin: units.gu(1)
9898 }
9999
100− color: "#f3f3e7"
100+ color: Theme.palette.selected.backgroundText
101101 opacity: 0.9
102102 style: Text.Raised
103103 styleColor: "black"
Dash/Video/VideoPreview.qml+3−3
@@ -48,7 +48,7 @@ DashPreview {
4848 property int buttonWidth: Math.min(units.gu(22), (width - spacing) / 2)
4949 Button {
5050 width: parent.buttonWidth
51− color: "#dd4814"
51+ color: Theme.palette.selected.foreground
5252 text: nfo.ready && nfo.video.buyPrice != "" ? "Buy for " + nfo.video.buyPrice : ""
5353 visible: text != ""
5454 iconSource: "graphics/icon_button_amazon.png"
@@ -56,7 +56,7 @@ DashPreview {
5656 }
5757 Button {
5858 width: parent.buttonWidth
59− color: "#dd4814"
59+ color: Theme.palette.selected.foreground
6060 text: nfo.ready && nfo.video.buyPrice != "" ? "Rent for " + nfo.video.rentPrice : ""
6161 visible: text != ""
6262 iconSource: "graphics/icon_button_u1.png"
@@ -73,7 +73,7 @@ DashPreview {
7373
7474 Label {
7575 text: nfo.ready ? nfo.video.plot : ""
76− color: "#f3f3e7"
76+ color: Theme.palette.selected.backgroundText
7777 opacity: .6
7878 fontSize: "medium"
7979 width: parent.width
Greeter/Greeter.qml+2−3
@@ -34,7 +34,7 @@ Showable {
3434
3535 property alias dragHandleWidth: dragHandle.width
3636 property alias model: greeterContentLoader.model
37− property bool locked: shown && multiUser && !greeterContentLoader.promptless
37+ property bool locked: shown && !LightDM.Greeter.promptless
3838
3939 readonly property bool narrowMode: !multiUser && width <= units.gu(60)
4040 readonly property bool multiUser: LightDM.Users.count > 1
@@ -59,7 +59,6 @@ Showable {
5959 anchors.fill: parent
6060 property var model: LightDM.Users
6161 property int currentIndex: 0
62− property bool promptless: item ? item.promptless : false
6362 property var infographicModel: LightDM.Infographic
6463
6564 source: required ? "GreeterContent.qml" : ""
@@ -113,7 +112,7 @@ Showable {
113112 // UI element)
114113 distanceThreshold: 0
115114
116− enabled: !greeter.locked
115+ enabled: greeter.narrowMode || !greeter.locked
117116
118117 direction: Direction.Leftwards
119118 }
Greeter/GreeterContent.qml−1
@@ -23,7 +23,6 @@ MouseArea {
2323 id: root
2424 anchors.fill: parent
2525
26− property bool promptless: loginLoader.status == Loader.Ready && LightDM.Greeter.promptless
2726 property bool ready: wallpaper.status == Image.Ready
2827 property bool leftTeaserPressed: teasingMouseArea.pressed &&
2928 teasingMouseArea.mouseX < teasingMouseArea.width / 2
Greeter/Lockscreen.qml+9−9
@@ -69,7 +69,7 @@ Showable {
6969 left: parent.left
7070 right: parent.right
7171 verticalCenter: parent.verticalCenter
72− verticalCenterOffset: root.alphaNumeric ? -units.gu(10) : 0
72+ verticalCenterOffset: root.alphaNumeric ? -units.gu(10) : -units.gu(4)
7373 }
7474 property bool resetting: false
7575
@@ -107,11 +107,11 @@ Showable {
107107 Column {
108108 anchors {
109109 left: parent.left
110− top: pinPadLoader.bottom
111− topMargin: units.gu(4)
112− right: parent.right
113110 bottom: parent.bottom
111+ bottomMargin: units.gu(4)
112+ right: parent.right
114113 }
114+ height: childrenRect.height
115115 spacing: units.gu(1)
116116
117117 Icon {
@@ -120,8 +120,8 @@ Showable {
120120 width: height
121121 anchors.horizontalCenter: parent.horizontalCenter
122122 name: "phone-app-call-symbolic"
123− color: "white"
124− opacity: 0.9
123+ color: "#f3f3e7"
124+ opacity: 0.6
125125
126126 MouseArea {
127127 anchors.fill: parent
@@ -130,9 +130,9 @@ Showable {
130130 }
131131
132132 Label {
133− text: i18n.tr("Emergency call")
134− color: "white"
135− opacity: 0.9
133+ text: i18n.tr("Emergency Call")
134+ color: "#f3f3e7"
135+ opacity: 0.6
136136 fontSize: "medium"
137137 anchors.horizontalCenter: parent.horizontalCenter
138138 }
Greeter/PinLockscreen.qml+110−41
@@ -16,15 +16,17 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import Ubuntu.Components.ListItems 0.1
1920import "../Components"
2021
2122Column {
2223 id: root
2324 anchors.centerIn: parent
24− spacing: units.gu(2.5)
25+ spacing: units.gu(3.5)
2526
2627 property alias placeholderText: pinentryField.placeholderText
27− property int padWidth: units.gu(32)
28+ property int padWidth: units.gu(34)
29+ property int padHeight: units.gu(28)
2830 property int pinLength: 4
2931
3032 signal entered(string passphrase)
@@ -37,70 +39,137 @@ Column {
3739 }
3840 }
3941
40− TextField {
42+
43+ UbuntuShape {
4144 id: pinentryField
4245 objectName: "pinentryField"
4346 anchors.horizontalCenter: parent.horizontalCenter
44− width: units.gu(32)
47+ color: "#55000000"
48+ width:root.padWidth
4549 height: units.gu(5)
46− echoMode: TextInput.Password
47− font.pixelSize: units.dp(44)
48− color: "white"
49− opacity: 0.9
50− hasClearButton: false
51− horizontalAlignment: Text.AlignHCenter
52−
50+ radius: "medium"
51+ property string text: ""
52+ property string placeholderText: ""
5353 onTextChanged: {
54− if (pinentryField.text.length === root.pinLength) {
55− root.entered(pinentryField.text);
54+ pinentryFieldLabel.text = "";
55+ for (var i = 0; i < text.length; ++i) {
56+ pinentryFieldLabel.text += "•";
57+ }
58+ if (text.length === root.pinLength) {
59+ root.entered(text);
5660 }
5761 }
5862
59− // Using a MouseArea to eat clicks. We don't want to disable the TextField for styling reasons
60− MouseArea {
61− anchors.fill: parent
63+ Label {
64+ id: pinentryFieldLabel
65+ anchors.centerIn: parent
66+ font.pixelSize: units.dp(44)
67+ color: "#f3f3e7"
68+ opacity: 0.6
69+ }
70+ Label {
71+ id: pinentryFieldPlaceHolder
72+ anchors.centerIn: parent
73+ color: "grey"
74+ text: parent.placeholderText
75+ visible: pinentryFieldLabel.text.length == 0
6276 }
6377 }
6478
65− Grid {
79+ UbuntuShape {
6680 anchors {
6781 left: parent.left
6882 right: parent.right
6983 margins: (parent.width - root.padWidth) / 2
7084 }
85+ height: root.padHeight
86+ color: "#55000000"
87+ radius: "medium"
88+
89+ ThinDivider {
90+ anchors {
91+ left: parent.left
92+ right: parent.right
93+ top: parent.top
94+ topMargin: root.padHeight / 4
95+ }
96+ }
97+ ThinDivider {
98+ anchors {
99+ left: parent.left
100+ right: parent.right
101+ verticalCenter: parent.verticalCenter
102+ }
103+ }
104+ ThinDivider {
105+ anchors {
106+ left: parent.left
107+ right: parent.right
108+ bottom: parent.bottom
109+ bottomMargin: root.padHeight / 4
110+ }
111+ }
71112
72− columns: 3
73− spacing: units.gu(1)
113+ ThinDivider {
114+ anchors.centerIn: parent
115+ anchors.horizontalCenterOffset: -root.padWidth / 6
116+ width: root.padHeight
117+ rotation: -90
118+ }
119+ ThinDivider {
120+ anchors.centerIn: parent
121+ anchors.horizontalCenterOffset: root.padWidth / 6
122+ width: root.padHeight
123+ rotation: -90
124+ }
74125
75− Repeater {
76− model: 9
126+ Grid {
127+ anchors {
128+ left: parent.left
129+ right: parent.right
130+ margins: (parent.width - root.padWidth) / 2
131+ }
77132
78− PinPadButton {
79− objectName: "pinPadButton" + (index + 1)
80− text: index + 1
133+ columns: 3
134+
135+ Repeater {
136+ model: 9
137+
138+ PinPadButton {
139+ objectName: "pinPadButton" + (index + 1)
140+ width: root.padWidth / 3
141+ height: root.padHeight / 4
142+ text: index + 1
81143
82− onClicked: {
83− pinentryField.text = pinentryField.text + text
144+ onClicked: {
145+ pinentryField.text = pinentryField.text + text;
146+ }
84147 }
85148 }
86− }
87149
88− PinPadButton {
89− objectName: "pinPadButtonBack"
90− iconName: "back"
91− onClicked: root.cancel();
150+ PinPadButton {
151+ objectName: "pinPadButtonBack"
152+ width: root.padWidth / 3
153+ height: root.padHeight / 4
154+ iconName: "back"
155+ onClicked: root.cancel();
156+ }
92157
93− }
94− PinPadButton {
95− objectName: "pinPadButton0"
96− text: "0"
97− onClicked: pinentryField.text = pinentryField.text + text
158+ PinPadButton {
159+ objectName: "pinPadButton0"
160+ width: root.padWidth / 3
161+ height: root.padHeight / 4
162+ text: "0"
163+ onClicked: pinentryField.text = pinentryField.text + text
164+ }
98165
99− }
100− PinPadButton {
101− objectName: "pinPadButtonErase"
102− iconName: "erase"
103− onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
166+ PinPadButton {
167+ objectName: "pinPadButtonErase"
168+ width: root.padWidth / 3
169+ height: root.padHeight / 4
170+ iconName: "erase"
171+ onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
172+ }
104173 }
105174 }
106175
Greeter/PinPadButton.qml+5−16
@@ -17,28 +17,20 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919
20−UbuntuShape {
20+Item {
2121 id: root
22− width: units.gu(10)
23− height: units.gu(7)
24− radius: "medium"
2522
2623 property alias text: label.text
2724 property alias iconName: icon.name
2825
2926 signal clicked()
3027
31− Behavior on color {
32− ColorAnimation { duration: 100 }
33− }
34−
3528 Label {
3629 id: label
3730 anchors.centerIn: parent
38− color: "white"
39− fontSize: "x-large"
40− font.weight: Font.Light
41− opacity: 0.9
31+ color: "#f3f3e7"
32+ fontSize: "large"
33+ font.weight: Font.DemiBold
4234 }
4335
4436 Icon {
@@ -46,14 +38,11 @@ UbuntuShape {
4638 height: units.gu(3)
4739 width: height
4840 anchors.centerIn: parent
49− color: "white"
50− opacity: 0.9
41+ color: "#f3f3e7"
5142 }
5243
5344 MouseArea {
5445 anchors.fill: parent
5546 onClicked: root.clicked()
56− onPressed: root.color = Qt.rgba(0, 0, 0, 0.3)
57− onReleased: root.color = Qt.rgba(0, 0, 0, 0)
5847 }
5948}
Notifications/Notification.qml+6−5
@@ -28,6 +28,7 @@ UbuntuShape {
2828 property var actions
2929 property var notificationId
3030 property var type
31+ property var hints
3132 property var notification
3233
3334 objectName: "background"
@@ -117,7 +118,7 @@ UbuntuShape {
117118 }
118119 fontSize: "medium"
119120 font.bold: true
120− color: "#f3f3e7"
121+ color: Theme.palette.selected.backgroundText
121122 elide: Text.ElideRight
122123 }
123124
@@ -131,7 +132,7 @@ UbuntuShape {
131132 }
132133 visible: body != ""
133134 fontSize: "small"
134− color: "#f3f3e7"
135+ color: Theme.palette.selected.backgroundText
135136 opacity: 0.6
136137 wrapMode: Text.WordWrap
137138 maximumLineCount: 10
@@ -164,7 +165,7 @@ UbuntuShape {
164165 bottom: parent.bottom
165166 }
166167 text: notification.type == Notification.SnapDecision && actionRepeater.count >= 2 ? actionRepeater.itemAt(1).actionLabel : ""
167− color: "#cdcdcb"
168+ gradient: UbuntuColors.greyGradient
168169 onClicked: {
169170 if (actionRepeater.count > 2) {
170171 buttonRow.expanded = !buttonRow.expanded
@@ -194,7 +195,7 @@ UbuntuShape {
194195 top: parent.top
195196 bottom: parent.bottom
196197 }
197− color: "#d85317"
198+ gradient: notification.hints == Notification.ButtonTint ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient
198199 visible: width > 0
199200 onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
200201 }
@@ -241,7 +242,7 @@ UbuntuShape {
241242
242243 text: loader.actionLabel
243244 height: units.gu(4)
244− color: "#cdcdcb"
245+ gradient: UbuntuColors.greyGradient
245246 onClicked: notification.notification.invokeAction(loader.actionId)
246247 }
247248 }
Notifications/Notifications.qml+1
@@ -32,6 +32,7 @@ ListView {
3232 right: parent.right
3333 }
3434 type: model.type
35+ hints: model.hints
3536 iconSource: model.icon
3637 secondaryIconSource: model.secondaryIcon
3738 summary: model.summary
Panel/IndicatorItem.qml+6−1
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Unity.Indicators 0.1 as Indicators
20+import "../Components"
2021
2122Item {
2223 id: indicatorItem
@@ -27,6 +28,7 @@ Item {
2728 property var indicatorProperties: undefined
2829
2930 opacity: dimmed ? 0.4 : 1
31+ Behavior on opacity { StandardAnimation {} }
3032
3133 // only visible when non-empty
3234 visible: loader.item != undefined && loader.status == Loader.Ready ? loader.item.enabled : false
@@ -47,11 +49,14 @@ Item {
4749 }
4850
4951 Rectangle {
50− color: "#dd4814"
52+ color: Theme.palette.selected.foreground
5153 objectName: "highlight"
5254 height: units.dp(2)
5355 width: parent.width
5456 anchors.top: parent.bottom
5557 visible: highlighted
58+
59+ opacity: highlighted ? 1 : 0
60+ Behavior on opacity { StandardAnimation {} }
5661 }
5762}
Panel/IndicatorRow.qml+34−49
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import "../Components"
1920
2021Item {
2122 id: indicatorRow
@@ -24,23 +25,19 @@ Item {
2425 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
2526 property alias row: row
2627 property QtObject indicatorsModel: null
27− property bool overviewActive: false // "state of the menu"
28−
29− Behavior on y {NumberAnimation {duration: 300; easing.type: Easing.OutCubic} }
3028
3129 width: units.gu(40)
3230 height: units.gu(3)
3331
34− Component.onCompleted: setDefaultItem()
35−
3632 function setDefaultItem() {
3733 // The leftmost indicator
38− var defaultItemIndex = 0
39− setItem(defaultItemIndex)
34+ setCurrentItem(0);
4035 }
4136
42− function setItem(index) {
43− currentItem = rowRepeater.itemAt(index)
37+ function setCurrentItem(index) {
38+ if (currentItemIndex !== index) {
39+ currentItem = rowRepeater.itemAt(index);
40+ }
4441 }
4542
4643 Row {
@@ -55,51 +52,39 @@ Item {
5552 objectName: "rowRepeater"
5653 model: indicatorsModel ? indicatorsModel : undefined
5754
58− IndicatorItem {
59− id: indicatorItem
55+ Item {
56+ id: itemWrapper
57+ height: indicatorRow.height
58+ width: childrenRect.width
6059
61− property int ownIndex: index
60+ property int ownIndex: index
61+ property alias highlighted: indicatorItem.highlighted
62+ property alias dimmed: indicatorItem.dimmed
6263
63− widgetSource: model.widgetSource
64+ IndicatorItem {
65+ id: indicatorItem
66+ height: parent.height
67+
68+ highlighted: indicatorRow.state != "initial" ? itemWrapper.ownIndex == indicatorRow.currentItemIndex : false
69+ dimmed: indicatorRow.state != "initial" ? itemWrapper.ownIndex != indicatorRow.currentItemIndex : false
70+
71+ widgetSource: model.widgetSource
72+ indicatorProperties : model.indicatorProperties
73+ }
6474
65− indicatorProperties : model.indicatorProperties
66− highlighted: indicatorRow.state == "reveal" || indicatorRow.state == "locked" || indicatorRow.state == "commit" ? ownIndex == indicatorRow.currentItemIndex : false
67− dimmed: { //See FIXME in Indicators regarding the "states" change
68− if (indicatorRow.state == "initial" || indicatorRow.state == "") {
69− return false;
70− } else if (indicatorRow.state == "hint") {
71− return true
72− } else {
73− return ownIndex != indicatorRow.currentItemIndex
74− }
75− }
76− height: indicatorRow.height
77− y: {
78− //FIXME: all indicators will be initial for now.
79− if (!highlighted && !overviewActive && (indicatorRow.state == "locked" || indicatorRow.state == "commit")) {
80− return -indicatorRow.height
81− } else {
82− return 0
83− }
84− }
85− Behavior on y {
86− NumberAnimation{
87− duration: {
88− if (index == 0) {
89− return 250
90− } else if (index == 1) {
91− return 150
92− } else if (index == 2) {
93− return 550
94− } else if (index == 3) {
95− return 400
96− } else {
97− return 100 + Math.random() * 200
98− }
99− }
100− easing.type: Easing.OutCubic
75+ opacity: {
76+ if (!indicatorItem.highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")) {
77+ return 0.0;
78+ } else {
79+ return 1.0;
10180 }
10281 }
82+ Behavior on opacity {
83+ StandardAnimation {
84+ // flow away from current index
85+ duration: (rowRepeater.count - Math.abs(indicatorRow.currentItemIndex - index)) * (500/rowRepeater.count)
86+ }
87+ }
10388 }
10489 }
10590 }
Panel/Indicators.qml+102−137
@@ -25,16 +25,15 @@ import "../Components/Math.js" as MathLocal
2525Showable {
2626 id: indicators
2727
28− property int referenceOpenedHeight: units.gu(71)
29− property real openedHeight: pinnedMode ? referenceOpenedHeight - panelHeight
30− : referenceOpenedHeight
28+ property real openedHeight: units.gu(71)
3129 property int panelHeight: units.gu(3)
3230 property bool pinnedMode: true //should be set true if indicators menu can cover whole screen
3331
3432 property int hintValue
35− readonly property int lockThreshold: referenceOpenedHeight / 2
33+ readonly property int lockThreshold: openedHeight / 2
3634 property bool fullyOpened: height == openedHeight
3735 property bool partiallyOpened: height > panelHeight && !fullyOpened
36+ property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
3837
3938 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
4039 // use its own values. Need to ask design about this.
@@ -43,6 +42,13 @@ Showable {
4342 duration: 350
4443 to: openedHeight
4544 easing.type: Easing.OutCubic
45+
46+ // Re-size if we've changed the openHeight while shown.
47+ onToChanged: {
48+ if (indicators.shown) {
49+ indicators.show();
50+ }
51+ }
4652 }
4753
4854 hideAnimation: StandardAnimation {
@@ -56,44 +62,32 @@ Showable {
5662
5763 onHeightChanged: {
5864 // need to use handle.get_height(). As the handle height depends on indicators.height changes (but this is called first!)
59− var contentProgress = indicators.height - handle.get_height()
65+ var revealProgress = indicators.height - panelHeight
6066 if (!showAnimation.running && !hideAnimation.running) {
61− if (contentProgress <= hintValue && indicators.state == "reveal") {
62− indicators.state = "hint"
63− menuContent.hideAll()
64− } else if (contentProgress > hintValue && contentProgress < lockThreshold) {
65− menuContent.showMenu()
66− indicators.state = "reveal"
67− } else if (contentProgress >= lockThreshold && lockThreshold > 0) {
68− // If we've shown the overview and are closing the view with progress changes (revealer handle),
69− // we dont want to switch to a indicator menu until we hit reveal state.
70− if (menuContent.overviewActive) {
71− menuContent.showOverview()
72− } else {
73− menuContent.showMenu()
74− }
75− indicators.state = "locked"
67+ if (revealProgress == 0) {
68+ indicators.state = "initial";
69+ } else if (revealProgress <= hintValue) {
70+ indicators.state = "hint";
71+ } else if (revealProgress > hintValue && revealProgress < lockThreshold) {
72+ indicators.state = "reveal";
73+ } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
74+ indicators.state = "locked";
7675 }
7776 }
7877
79− if (contentProgress == 0) {
80− menuContent.releaseContent()
78+ if (revealProgress == 0) {
79+ menuContent.releaseContent();
8180 }
8281 }
8382
84− function openOverview() {
85− indicatorRow.currentItem = null
86− menuContent.showOverview()
87− }
88−
8983 function calculateCurrentItem(xValue, useBuffer) {
90− var rowCoordinates
91− var itemCoordinates
92− var currentItem
93− var distanceFromRightEdge
94− var bufferExceeded = false
84+ var rowCoordinates;
85+ var itemCoordinates;
86+ var currentItem;
87+ var distanceFromRightEdge;
88+ var bufferExceeded = false;
9589
96− if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return
90+ if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
9791
9892 /*
9993 If user drags the indicator handle bar down a distance hintValue or less, this is 0.
@@ -102,14 +96,22 @@ Showable {
10296 */
10397 var verticalProgress =
10498 MathLocal.clamp((indicators.height - handle.height - hintValue) /
105− (lockThreshold - hintValue), 0, 1)
99+ (lockThreshold - hintValue), 0, 1);
100+
101+ /*
102+ Vertical velocity check. Don't change the indicator if we're moving too quickly.
103+ */
104+ var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
105+ if (verticalSpeed >= 0.05 && indicatorRow.currentItem!=null) {
106+ return;
107+ }
106108
107109 /*
108110 Percentage of an indicator icon's width the user's press can stray horizontally from the
109111 focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
110112 go right a distance of half an icon's width before focus moves to the icon on the right
111113 */
112− var maxBufferThreshold = 0.5
114+ var maxBufferThreshold = 0.5;
113115
114116 /*
115117 To help users find the indicator of their choice while opening the indicators, we add logic to add a
@@ -124,19 +126,21 @@ Showable {
124126 currentItem = indicatorRow.row.childAt(rowCoordinates.x, 0);
125127 if (currentItem && currentItem != indicatorRow.currentItem ) {
126128 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
127− distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width)
129+ distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
128130 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
129− bufferExceeded = true
131+ bufferExceeded = true;
130132 } else {
131133 if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
132− bufferExceeded = true
134+ bufferExceeded = true;
133135 } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
134− bufferExceeded = true
136+ bufferExceeded = true;
135137 }
136138 }
137139 if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItem < 0 || indicatorRow.currentItem == null) {
138140 indicatorRow.currentItem = currentItem;
139141 }
142+ } else if (!currentItem) {
143+ indicatorRow.setDefaultItem();
140144 }
141145 }
142146
@@ -169,14 +173,20 @@ Showable {
169173 left: parent.left
170174 right: parent.right
171175 top: indicatorRow.bottom
172− bottom: parent.bottom
176+ bottom: handle.top
173177 }
174178 indicatorsModel: indicatorsModel
175− animate: false
176− clip: indicators.partiallyOpened
179+ clip: !indicators.fullyOpened
177180
178− onMenuSelected: {
179− indicatorRow.setItem(index)
181+ Connections {
182+ target: indicatorRow
183+ onCurrentItemIndexChanged: menuContent.updateCurrentMenu();
184+ }
185+
186+ function updateCurrentMenu() {
187+ if (currentMenuIndex != indicatorRow.currentItemIndex) {
188+ currentMenuIndex = indicatorRow.currentItemIndex;
189+ }
180190 }
181191
182192 //small shadow gradient at bottom of menu
@@ -203,13 +213,13 @@ Showable {
203213 anchors {
204214 left: parent.left
205215 right: parent.right
206− top: menuContent.bottom
216+ bottom: parent.bottom
207217 }
208218 height: get_height()
209219 clip: height < handleImage.height
210220
211221 function get_height() {
212− return Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
222+ return Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0);
213223 }
214224
215225 BorderImage {
@@ -227,33 +237,14 @@ Showable {
227237 }
228238 }
229239
230− PanelSeparatorLine {
231− id: indicatorsSeparatorLine
232− visible: true
233− anchors {
234− top: handle.bottom
235− left: indicators.left
236− right: indicators.right
237− }
238− }
239−
240− BorderImage {
241− id: dropShadow
242− anchors {
243− top: indicators.top
244− bottom: indicatorsSeparatorLine.bottom
245− left: indicators.left
246− right: indicators.right
247− margins: -units.gu(1)
248− }
249− visible: indicators.height > panelHeight
250− source: "graphics/rectangular_dropshadow.sci"
251− }
252−
253240 PanelBackground {
254241 anchors.fill: indicatorRow
255242 }
256243
244+ IndicatorsDataModel {
245+ id: indicatorsModel
246+ }
247+
257248 IndicatorRow {
258249 id: indicatorRow
259250 objectName: "indicatorRow"
@@ -264,63 +255,46 @@ Showable {
264255 height: indicators.panelHeight
265256 indicatorsModel: indicatorsModel
266257 state: indicators.state
267− overviewActive: menuContent.overviewActive
268−
269− onCurrentItemIndexChanged: menuContent.currentIndex = currentItemIndex
270258
271− }
272−
273− IndicatorsDataModel {
274− id: indicatorsModel
259+ Connections {
260+ target: menuContent
261+ onCurrentMenuIndexChanged: {
262+ indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
263+ }
264+ }
275265 }
276266
277267 Connections {
278− target: hideAnimation
268+ target: showAnimation
279269 onRunningChanged: {
280− if (hideAnimation.running) {
281− indicators.state = "initial"
282− menuContent.hideAll()
283− } else {
284− if (state == "initial") indicatorRow.setDefaultItem()
270+ if (showAnimation.running) {
271+ indicators.state = "commit";
285272 }
286273 }
287274 }
275+
288276 Connections {
289− target: showAnimation
277+ target: hideAnimation
290278 onRunningChanged: {
291− if (showAnimation.running) {
292− if (indicators.state == "initial") {
293− openOverview()
294− } else {
295− indicators.calculateCurrentItem(dragHandle.touchX, false)
296− menuContent.showMenu()
297− }
298− indicators.state = "commit"
279+ if (hideAnimation.running) {
280+ indicators.state = "initial";
281+ indicatorRow.currentItem = null;
299282 }
300283 }
301284 }
302285
286+ property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
287+ // connections to the active drag handle
303288 Connections {
304− target: dragHandle
289+ target: activeDragHandle
305290 onTouchXChanged: {
306− var buffer = dragHandle.dragging ? true : false
307− indicators.calculateCurrentItem(dragHandle.touchX, buffer)
291+ indicators.calculateCurrentItem(activeDragHandle.touchX, true);
292+ }
293+ onTouchSceneYChanged: {
294+ yVelocityCalculator.trackedPosition = activeDragHandle.touchSceneY;
308295 }
309296 }
310297
311− // We start with pinned states. (default pinnedMode: true)
312− states: pinnedModeStates
313− // because of dynamic assignment of states, we need to assign state after completion.
314− Component.onCompleted: state = "initial"
315−
316− // changing states will reset state to "".
317− onPinnedModeChanged: {
318− var last_state = state;
319− states = (pinnedMode) ? pinnedModeStates : offScreenModeStates;
320− state = last_state;
321− }
322−
323− property var dragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle
324298 DragHandle {
325299 id: showDragHandle
326300 anchors.bottom: parent.bottom
@@ -334,42 +308,52 @@ Showable {
334308 hintDisplacement: pinnedMode ? indicators.hintValue : 0
335309 autoCompleteDragThreshold: maxTotalDragDistance / 2
336310 stretch: true
337− maxTotalDragDistance: openedHeight - handle.height
311+ maxTotalDragDistance: openedHeight - panelHeight
338312 distanceThreshold: pinnedMode ? 0 : units.gu(3)
339313
340314 onStatusChanged: {
341315 if (status === DirectionalDragArea.Recognized) {
342− menuContent.hideAll()
343− menuContent.activateContent()
316+ menuContent.activateContent();
344317 }
345318 }
346319 }
347320 DragHandle {
348321 id: hideDragHandle
349322 anchors.fill: handle
350− height: panelHeight
351323 direction: Direction.Upwards
352324 enabled: indicators.shown
353− hintDisplacement: units.gu(2)
325+ hintDisplacement: indicators.hintValue
354326 autoCompleteDragThreshold: maxTotalDragDistance / 6
355327 stretch: true
356− maxTotalDragDistance: referenceOpenedHeight - 2*panelHeight
328+ maxTotalDragDistance: openedHeight - panelHeight
357329 distanceThreshold: 0
358330 }
359331
360− property list<State> offScreenModeStates: [
332+ AxisVelocityCalculator {
333+ id: yVelocityCalculator
334+ }
335+
336+ states: [
361337 State {
362338 name: "initial"
363339 },
364340 State {
365341 name: "hint"
366− PropertyChanges { target: indicatorRow; y: panelHeight }
342+ PropertyChanges {
343+ target: indicatorRow;
344+ y: pinnedMode ? 0 : panelHeight
345+ }
346+ StateChangeScript {
347+ script: {
348+ if (activeDragHandle) {
349+ calculateCurrentItem(activeDragHandle.touchX, false);
350+ }
351+ }
352+ }
367353 },
368354 State {
369355 name: "reveal"
370356 extend: "hint"
371− PropertyChanges { target: menuContent; animate: true }
372− StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
373357 },
374358 State {
375359 name: "locked"
@@ -380,26 +364,7 @@ Showable {
380364 extend: "hint"
381365 }
382366 ]
383−
384− property list<State> pinnedModeStates: [
385− State {
386− name: "initial"
387− },
388− State {
389− name: "hint"
390− },
391− State {
392− name: "reveal"
393− PropertyChanges { target: menuContent; animate: true }
394− StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
395− },
396− State {
397− name: "locked"
398− },
399− State {
400− name: "commit"
401− }
402− ]
367+ state: "initial"
403368
404369 transitions: [
405370 Transition {
Panel/Indicators/DatetimeIndicatorPage.qml+2−2
@@ -54,7 +54,7 @@ Flickable {
5454 }
5555
5656 text: ""
57− color: "#f3f3e7"
57+ color: Theme.palette.selected.backgroundText
5858 font.weight: Font.Light
5959 font.pixelSize: units.gu(6)
6060 }
@@ -69,7 +69,7 @@ Flickable {
6969 bottomMargin: units.gu(1.5)
7070 }
7171 text: ""
72− color: "#f3f3e7"
72+ color: Theme.palette.selected.backgroundText
7373 fontSize: "small"
7474 }
7575 }
Panel/Indicators/DatetimeIndicatorWidget.qml+1−1
@@ -31,7 +31,7 @@ Indicators.IndicatorWidget {
3131 Label {
3232 id: timeLabel
3333 objectName: "timeLabel"
34− color: "#f3f3e7"
34+ color: Theme.palette.selected.backgroundText
3535 opacity: 0.8
3636 font.family: "Ubuntu"
3737 fontSize: "medium"
Panel/Indicators/DefaultIndicatorWidget.qml+1−1
@@ -52,7 +52,7 @@ Indicators.IndicatorWidget {
5252 Label {
5353 id: itemLabel
5454 objectName: "itemLabel"
55− color: "#f3f3e7"
55+ color: Theme.palette.selected.backgroundText
5656 opacity: 0.8
5757 font.family: "Ubuntu"
5858 fontSize: "medium"
Panel/Indicators/NetworkIndicatorPage.qml+1−2
@@ -49,7 +49,6 @@ PageStack {
4949
5050 ICNetwork.PasswordPage {
5151 agent: networkAgent
52− token: token
5352 }
5453 }
5554
@@ -57,7 +56,7 @@ PageStack {
5756 id: networkAgent
5857
5958 onSecretRequested: {
60− _network.push(passwordPageComponent);
59+ _network.push(passwordPageComponent, {"token": token});
6160 }
6261 }
6362
Panel/Indicators/client/IndicatorsClient.qml+8−9
@@ -27,16 +27,15 @@ Rectangle {
2727
2828 PageStack {
2929 id: pages
30−
3130 anchors.fill: parent
32− Component.onCompleted: root.reset()
33− }
31+ Component.onCompleted: reset()
3432
35− function reset() {
36− pages.clear();
37− var component = Qt.createComponent("IndicatorsList.qml");
38− var page = component.createObject(pages);
39− console.log(component.errorString());
40− pages.push(page);
33+ function reset() {
34+ clear();
35+ var component = Qt.createComponent("IndicatorsList.qml");
36+ var page = component.createObject(pages);
37+ console.log(component.errorString());
38+ push(page);
39+ }
4140 }
4241}
Panel/Indicators/client/IndicatorsPage.qml+57−12
@@ -15,35 +15,80 @@
1515 *
1616 * Authors:
1717 * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ * Nick Dedekind <nick.dedekind@canonical.com>
1819 */
1920
2021import QtQuick 2.0
2122import Ubuntu.Components 0.1
23+import Ubuntu.Components.ListItems 0.1 as ListItem
2224
2325Page {
24− id: _page
26+ id: page
2527
2628 title: indicatorProperties && indicatorProperties.title ? indicatorProperties.title : ""
2729 property variant indicatorProperties
28− property alias pageSource : page_loader.source
30+ property string pageSource : pageLoader.source
2931
3032 anchors.fill: parent
3133
34+ ListItem.Standard {
35+ id: visualCheckItem
36+ text: "Enable Visual Representation"
37+ control: Switch {
38+ id: visualCheck
39+ checked: true
40+ }
41+ }
42+
3243 Loader {
33− id: page_loader
34− objectName: "page_loader"
44+ id: pageLoader
45+ objectName: "pageLoader"
3546
36− anchors.fill: parent
47+ anchors {
48+ top: visualCheckItem.bottom
49+ left: parent.left
50+ right: parent.right
51+ bottom: buttons.top
52+ topMargin: units.gu(2)
53+ bottomMargin: units.gu(2)
54+ }
55+ source : visualCheck.checked ? page.pageSource : "IndicatorsTree.qml"
3756
38− onStatusChanged: {
39− if (status == Loader.Ready) {
40− for(var pName in indicatorProperties) {
41− if (item.hasOwnProperty(pName)) {
42− item[pName] = indicatorProperties[pName];
43− }
57+ onLoaded: {
58+ for(var pName in indicatorProperties) {
59+ if (item.hasOwnProperty(pName)) {
60+ item[pName] = indicatorProperties[pName];
4461 }
45− item.start();
4662 }
63+ item.start();
64+ }
65+ }
66+
67+ Item {
68+ id: buttons
69+ anchors {
70+ left: parent.left
71+ right: parent.right
72+ bottom: parent.bottom
73+ margins: units.gu(1)
74+ }
75+ height: childrenRect.height
76+
77+ Button {
78+ anchors {
79+ left: parent.left
80+ }
81+ text: "Back"
82+ onClicked: page.pageStack.reset()
83+ }
84+ Button {
85+ id: refresh
86+ visible: !visualCheck.checked
87+ anchors {
88+ right: parent.right
89+ }
90+ text: "Refresh"
91+ onClicked: pageLoader.item.refresh()
4792 }
4893 }
4994}
Panel/Indicators/client/IndicatorsTree.qmlnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dededkind@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Unity.Indicators 0.1 as Indicators
23+import QMenuModel 0.1
24+import Ubuntu.Components.ListItems 0.1 as ListItem
25+
26+Page {
27+ id: page
28+ anchors.fill: parent
29+
30+ property alias busType: menuModel.busType
31+ property alias busName: menuModel.busName
32+ property string actionsObjectPath
33+ property var menuObjectPaths: undefined
34+ readonly property string device: "phone"
35+
36+ property string deviceMenuObjectPath: menuObjectPaths.hasOwnProperty(device) ? menuObjectPaths[device] : ""
37+
38+ function start() {
39+ menuModel.start();
40+ }
41+
42+ QDBusMenuModel {
43+ id: menuModel
44+ objectPath: page.deviceMenuObjectPath
45+ }
46+
47+ Indicators.ModelPrinter {
48+ id: printer
49+ model: menuModel
50+ }
51+
52+ Flickable {
53+ anchors.fill: parent
54+ contentHeight: all_data.height
55+ clip:true
56+ Text {
57+ id: all_data
58+ color: "white"
59+ text: printer.text
60+ }
61+ }
62+}
Panel/MenuContent.qml+22−71
@@ -17,50 +17,31 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Unity.Indicators 0.1 as Indicators
20−import "Menus"
2120import "../Components"
2221
2322Rectangle {
2423 id: content
2524
2625 property QtObject indicatorsModel: null
27− property bool animate: true // FIXME: Remove. This doesnt seem to be being used and it's referenced in Indicators.
28− property bool overviewActive: true // "state of the menu"
29− property bool __shown: false
3026 property bool __contentActive: false
31− property alias currentIndex : menus.currentIndex
32− property color backgroundColor: "#221e1c"
27+ property alias currentMenuIndex : menus.currentIndex
28+ property color backgroundColor: "#221e1c" // FIXME not in palette yet
3329 property int contentReleaseInterval: 20000
3430
3531 width: units.gu(40)
3632 height: units.gu(42)
3733 color: backgroundColor
38− enabled: __shown
3934
4035 signal menuSelected(int index)
4136
42− function showMenu() {
43− __shown = true
44− overviewActive = false
45− }
46−
47− function showOverview() {
48− __shown = true
49− overviewActive = true
50− }
51−
52− function hideAll() {
53− __shown = false
54− }
55−
5637 function activateContent() {
57− contentReleaseTimer.stop()
58− __contentActive = true
38+ contentReleaseTimer.stop();
39+ __contentActive = true;
5940 }
6041
6142 function releaseContent() {
6243 if (__contentActive)
63− contentReleaseTimer.restart()
44+ contentReleaseTimer.restart();
6445 }
6546
6647 ListView {
@@ -72,7 +53,6 @@ Rectangle {
7253 width: parent.width
7354
7455 spacing: units.gu(0.5)
75− opacity: !overviewActive && __shown ? 1 : 0
7656 enabled: opacity != 0
7757 orientation: ListView.Horizontal
7858 model: indicatorsModel
@@ -83,24 +63,23 @@ Rectangle {
8363
8464 delegate: Loader {
8565 clip: true
86− property bool contentActive: content.__contentActive
66+ property bool contentActive: content.__contentActive && menuActivator.content[index].active
8767
8868 onContentActiveChanged: {
8969 if (contentActive && item) {
90− item.start()
70+ item.start();
9171 } else if (!contentActive && item) {
92− item.stop()
72+ item.stop();
9373 }
9474 }
9575
9676 width: menus.width
9777 height: menus.height
9878 source: pageSource
99− visible: content.__shown
10079 onVisibleChanged: {
10180 // Reset the indicator states
10281 if (!visible && item && item["reset"]) {
103− item.reset()
82+ item.reset();
10483 }
10584 }
10685 asynchronous: true
@@ -108,11 +87,11 @@ Rectangle {
10887 onLoaded: {
10988 for(var pName in indicatorProperties) {
11089 if (item.hasOwnProperty(pName)) {
111− item[pName] = indicatorProperties[pName]
90+ item[pName] = indicatorProperties[pName];
11291 }
11392 }
11493 if (contentActive && menus.visible) {
115− item.start()
94+ item.start();
11695 }
11796 }
11897
@@ -124,40 +103,6 @@ Rectangle {
124103 value: handle.height
125104 }
126105 }
127−
128− Behavior on opacity { NumberAnimation {duration: 200} }
129− }
130−
131− Overview {
132− id: overview
133− objectName: "overview"
134−
135− anchors.top: header.bottom
136− anchors.bottom: parent.bottom
137− // FIXME: Dont know why we're using handle height (introduces dep).. Check with design about bottom margin
138− anchors.bottomMargin: handle.height
139−
140− width: content.width
141− indicatorsModel: content.indicatorsModel
142− enabled: content.overviewActive && content.__shown
143− opacity: content.overviewActive && content.__shown ? 1 : 0
144− Behavior on opacity {NumberAnimation{duration: 200}}
145− visible: opacity != 0
146−
147− onMenuSelected: {
148− var storedDuration = menus.highlightMoveDuration
149− var storedVelocity = menus.highlightMoveVelocity
150− menus.highlightMoveDuration = 0
151− menus.highlightMoveVelocity = 100000
152−
153− menus.currentIndex = modelIndex
154− content.overviewActive = false
155−
156− menus.highlightMoveDuration = storedDuration
157− menus.highlightMoveVelocity = storedVelocity
158−
159− content.menuSelected(modelIndex)
160− }
161106 }
162107
163108 Rectangle {
@@ -181,14 +126,10 @@ Rectangle {
181126 right: parent.right
182127 }
183128 text: {
184− if (content.overviewActive)
185− return i18n.tr("Device");
186129 if (indicatorsModel && menus.currentIndex >= 0 && menus.currentIndex < indicatorsModel.count)
187130 return indicatorsModel.data(menus.currentIndex, Indicators.IndicatorsModelRole.Title);
188131 return "";
189132 }
190− opacity: __shown ? 1 : 0
191− Behavior on opacity {NumberAnimation{duration: 100}}
192133 }
193134 }
194135
@@ -196,6 +137,16 @@ Rectangle {
196137 id: contentReleaseTimer
197138
198139 interval: contentReleaseInterval
199− onTriggered: __contentActive = false
140+ onTriggered: {
141+ __contentActive = false;
142+ menuActivator.clear();
143+ }
144+ }
145+
146+ Indicators.MenuContentActivator {
147+ id: menuActivator
148+ running: content.__contentActive
149+ baseIndex: content.currentMenuIndex
150+ count: indicatorsModel.count
200151 }
201152}
Panel/Menus/Overview.qmldeleted−70
@@ -1,70 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components/ListItems" as ListItems
20−import "Overview"
21−
22−IndicatorMenuWindow {
23− id: overview
24−
25− property QtObject indicatorsModel: null
26−
27− signal menuSelected(int modelIndex)
28−
29− VisualItemModel {
30− id: itemModel
31−
32− FlightModeWidget {
33− anchors {
34− left: parent ? parent.left : undefined
35− right: parent ? parent.right : undefined
36− }
37− height: units.gu(8)
38−
39− ListItems.ThinDivider {
40− anchors {
41− bottom: parent.bottom
42− bottomMargin: -units.dp(1)
43− }
44− }
45− }
46−
47− VolumeWidget {
48− anchors {
49− left: parent ? parent.left : undefined
50− right: parent ? parent.right : undefined
51− }
52− height: units.gu(10)
53− }
54−
55− OverviewGrid {
56− model: indicatorsModel
57− anchors {
58− left: parent ? parent.left : undefined
59− right: parent ? parent.right : undefined
60− }
61− }
62− }
63−
64− ListView {
65− id: listView
66− anchors.fill: parent
67− model: itemModel
68− interactive: false
69− }
70−}
Panel/Menus/Overview/FlightModeWidget.qmldeleted−60
@@ -1,60 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: flightModeWidget
22−
23− Image {
24− id: flightIcon
25− source: "graphics/plane_icon.png"
26− anchors {
27− left: parent.left
28− leftMargin: units.gu(2)
29− verticalCenter: parent.verticalCenter
30− }
31− width: units.gu(4)
32− height: units.gu(4)
33− }
34−
35− Label {
36− anchors {
37− left: flightIcon.right
38− right: flightModeSwitch.left
39− margins: units.gu(2)
40− verticalCenter: parent.verticalCenter
41− }
42− text: i18n.tr("Flight mode")
43− color: "#f3f3e7"
44− style: Text.Raised
45− styleColor: "black"
46− opacity: 0.6;
47− fontSize: "medium"
48− elide: Text.ElideRight
49− horizontalAlignment: Text.AlignLeft
50− }
51−
52− Switch {
53− id: flightModeSwitch
54− anchors {
55− right: parent.right
56− rightMargin: units.gu(2)
57− verticalCenter: parent.verticalCenter
58− }
59− }
60−}
Panel/Menus/Overview/OverviewGrid.qmldeleted−135
@@ -1,135 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−import "../../../Components/ListItems" as ListItems
21−
22−Item {
23− id: overviewGrid
24−
25− height: childrenRect.height
26−
27− property var model
28−
29− UbuntuShape {
30− id: gridBackground
31− anchors.fill: grid
32− color: "#282421"
33− radius: "medium"
34− }
35−
36− GridView {
37− id: grid
38− objectName: "overviewGrid"
39−
40− property int columnCount: 3
41− property int rowCount: Math.ceil(model.count / columnCount)
42−
43− anchors {
44− top: parent.top
45− left: parent.left
46− right: parent.right
47− topMargin: units.gu(3)
48− leftMargin: units.gu(2)
49− rightMargin: units.gu(2)
50− }
51− height: cellWidth * rowCount
52− cellWidth: Math.floor((width) / columnCount)
53− cellHeight: cellWidth
54− model: overviewGrid.model
55− visible: opacity != 0
56− interactive: false
57− delegate:
58− AbstractButton {
59− objectName: "overviewGridButton" + index
60− width: grid.cellWidth
61− height: grid.cellHeight
62−
63− Loader {
64− id: loader
65− source: widgetSource
66−
67− width: units.gu(5)
68− height: units.gu(5)
69− anchors.centerIn: parent
70− anchors.verticalCenterOffset: -units.gu(1)
71−
72− onLoaded: {
73− for(var pName in indicatorProperties) {
74− if (item.hasOwnProperty(pName)) {
75− item[pName] = indicatorProperties[pName]
76− }
77− }
78− }
79− }
80−
81− Label {
82− text: title
83− color: "#f3f3e7"
84− fontSize: "small"
85− anchors {
86− left: parent.left
87− right: parent.right
88− bottom: parent.bottom
89− leftMargin: units.gu(0.5)
90− rightMargin: units.gu(0.5)
91− bottomMargin: units.gu(1.5)
92− }
93− elide: Text.ElideRight
94− horizontalAlignment: Text.AlignHCenter
95−
96− }
97− onClicked: overview.menuSelected(index)
98− }
99− }
100−
101− Item {
102− id: gridOverlay
103− anchors.fill: grid
104−
105− Column {
106− anchors {
107− left: parent.left
108− right: parent.right
109− }
110− spacing: grid.cellHeight
111− y: grid.cellHeight - units.dp(1)
112− Repeater {
113− model: grid.rowCount - 1
114− ListItems.ThinDivider {
115− anchors.margins: units.dp(1)
116− }
117− }
118− }
119−
120− Row {
121− anchors {
122− top: parent.top
123− bottom: parent.bottom
124− }
125− spacing: grid.cellWidth - units.dp(1)
126− x: grid.cellWidth - units.dp(1)
127− Repeater {
128− model: grid.columnCount - 1
129− ListItems.VerticalThinDivider {
130− anchors.margins: units.dp(1)
131− }
132− }
133− }
134− }
135−}
Panel/Menus/Overview/VolumeWidget.qmldeleted−88
@@ -1,88 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../../Components/"
20−
21−Item {
22− id: volumeWidget
23−
24− Image {
25− id: minVolumeIcon
26− objectName: "minVolumeIcon"
27− source: "graphics/sound_off_icon.png"
28− anchors {
29− left: parent.left
30− leftMargin: units.gu(2)
31− verticalCenter: parent.verticalCenter
32− }
33− width: units.gu(4)
34− height: units.gu(4)
35−
36− MouseArea {
37− anchors.fill: parent
38− onClicked: volumeControl.volumeDown();
39− }
40− }
41−
42− Slider {
43− id: slider
44− objectName: "volumeSlider"
45− anchors {
46− left: minVolumeIcon.right
47− right: maxVolumeIcon.left
48− margins: units.gu(1)
49− verticalCenter: parent.verticalCenter
50− }
51− live: false
52− minimumValue: 0
53− maximumValue: 100
54− value: 50
55−
56− onValueChanged: {
57− volumeControl.volume = value;
58− }
59−
60− Binding {
61− target: slider
62− property: "value"
63− value: volumeControl.volume
64− }
65−
66− function formatValue(v) {
67− return ""
68− }
69− }
70−
71− Image {
72− id: maxVolumeIcon
73− objectName: "maxVolumeIcon"
74− source: "graphics/sound_on_icon.png"
75− anchors {
76− right: parent.right
77− rightMargin: units.gu(2)
78− verticalCenter: parent.verticalCenter
79− }
80− width: units.gu(4)
81− height: units.gu(4)
82−
83− MouseArea {
84− anchors.fill: parent
85− onClicked: volumeControl.volumeUp();
86− }
87− }
88−}
Panel/Menus/Overview/graphics/plane_icon@18.pngdeleted

Binary file not shown.

Panel/Menus/Overview/graphics/sound_off_icon@18.pngdeleted

Binary file not shown.

Panel/Menus/Overview/graphics/sound_on_icon@18.pngdeleted

Binary file not shown.

Panel/Panel.qml+28−9
@@ -39,11 +39,8 @@ Item {
3939 }
4040 height: __panelMinusSeparatorLineHeight
4141 y: 0
42− onYChanged: indicatorsMenu.y = y;
4342
44− Behavior on y {
45− NumberAnimation { duration: 200 }
46− }
43+ Behavior on y { StandardAnimation {} }
4744 }
4845
4946 PanelSeparatorLine {
@@ -78,18 +75,40 @@ Item {
7875 id: indicatorsMenu
7976
8077 anchors.right: parent.right
81− y: 0
78+ y: panelBackground.y
8279 width: root.indicatorsMenuWidth
8380 shown: false
8481 hintValue: __panelMinusSeparatorLineHeight * 3
8582 panelHeight: __panelMinusSeparatorLineHeight
86− referenceOpenedHeight: parent.height
87−
83+ openedHeight: parent.height + (pinnedMode ? 0 : root.panelHeight)
8884 pinnedMode: !fullscreenMode
8985
9086 property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
9187 }
9288
89+ PanelSeparatorLine {
90+ id: indicatorsSeparatorLine
91+ visible: true
92+ anchors {
93+ left: indicatorsMenu.left
94+ right: indicatorsMenu.right
95+ }
96+ y: indicatorsMenu.visualBottom
97+ }
98+
99+ BorderImage {
100+ id: dropShadow
101+ anchors {
102+ top: indicators.top
103+ bottom: indicatorsSeparatorLine.bottom
104+ left: indicators.left
105+ right: indicators.right
106+ margins: -units.gu(1)
107+ }
108+ visible: indicatorsMenu.height > indicatorsMenu.panelHeight
109+ source: "graphics/rectangular_dropshadow.sci"
110+ }
111+
93112 SearchIndicator {
94113 id: search
95114 objectName: "search"
@@ -98,14 +117,14 @@ Item {
98117 state: {
99118 if (parent.width < indicatorsMenu.width + width) {
100119 if (indicatorsMenu.state != "initial") {
101− return "hiddenUp";
120+ return "hidden";
102121 }
103122 }
104123 if (root.searchVisible) {
105124 return "visible";
106125 }
107126
108− return "hiddenUp";
127+ return "hidden";
109128 }
110129
111130 width: units.gu(13)
Panel/SearchIndicator.qml+3−5
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import "../Components"
1920
2021Item {
2122 id: search
@@ -40,8 +41,7 @@ Item {
4041 width: parent.width
4142 height: parent.height
4243
43− Behavior on opacity {NumberAnimation {}}
44− Behavior on y {NumberAnimation {duration: 300; easing.type: Easing.OutCubic}}
44+ Behavior on opacity { StandardAnimation {} }
4545
4646 Image {
4747 id: icon
@@ -67,15 +67,13 @@ Item {
6767 name: "visible"
6868 PropertyChanges {
6969 target: container
70− y: 0
7170 opacity: 1
7271 }
7372 },
7473 State {
75− name: "hiddenUp"
74+ name: "hidden"
7675 PropertyChanges {
7776 target: container
78− y: -height
7977 opacity: 0
8078 }
8179 }
Shell.qml+79−36
@@ -19,6 +19,7 @@ import Ubuntu.Application 0.1
1919import Ubuntu.Components 0.1
2020import Ubuntu.Gestures 0.1
2121import LightDM 0.1 as LightDM
22+import Powerd 0.1
2223import "Dash"
2324import "Greeter"
2425import "Launcher"
@@ -36,8 +37,8 @@ FocusScope {
3637
3738 // this is only here to select the width / height of the window if not running fullscreen
3839 property bool tablet: false
39− width: tablet ? units.gu(160) : units.gu(40)
40− height: tablet ? units.gu(100) : units.gu(71)
40+ width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
41+ height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
4142
4243 property real edgeSize: units.gu(2)
4344 property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
@@ -62,6 +63,8 @@ FocusScope {
6263 property var applicationManager: ApplicationManagerWrapper {}
6364
6465 Component.onCompleted: {
66+ Theme.name = "Ubuntu.Components.Themes.SuruGradient"
67+
6568 applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
6669
6770 // FIXME: if application focused before shell starts, shell draws on top of it only.
@@ -119,19 +122,22 @@ FocusScope {
119122 Keys.onVolumeUpPressed: volumeControl.volumeUp()
120123 Keys.onVolumeDownPressed: volumeControl.volumeDown()
121124
122− Keys.onReleased: {
123− if (event.key == Qt.Key_PowerOff) {
124− greeter.show()
125− }
126− }
127−
128125 Item {
129126 id: underlay
127+ objectName: "underlay"
130128 anchors.fill: parent
131− visible: !(panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth)
132− && (stages.fullyHidden
133− || (stages.fullyShown && mainStage.usingScreenshots)
134− || !stages.fullyShown && (mainStage.usingScreenshots || (sideStage.shown && sideStage.usingScreenshots)))
129+
130+ // Whether the underlay is fully covered by opaque UI elements.
131+ property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
132+
133+ // Whether the user should see the topmost application surface (if there's one at all).
134+ property bool applicationSurfaceShouldBeSeen:
135+ (mainStage.applications && mainStage.applications.count > 0)
136+ && (!stages.fullyHidden && !mainStage.usingScreenshots)
137+
138+ // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
139+ // through the translucent parts of the shell surface.
140+ visible: !fullyCovered && !applicationSurfaceShouldBeSeen
135141
136142 Image {
137143 id: backgroundImage
@@ -149,6 +155,7 @@ FocusScope {
149155
150156 Dash {
151157 id: dash
158+ objectName: "dash"
152159
153160 available: !greeter.shown && !lockscreen.shown
154161 hides: [stages, launcher, panel.indicators]
@@ -176,7 +183,7 @@ FocusScope {
176183 }
177184 }
178185
179− // FIXME: only necessary because stagesRevealer.animatedProgress and
186+ // FIXME: only necessary because stagesOuterContainer.showProgress and
180187 // greeterRevealer.animatedProgress are not animated
181188 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
182189 }
@@ -196,6 +203,7 @@ FocusScope {
196203
197204 Showable {
198205 id: stages
206+ objectName: "stages"
199207
200208 x: width
201209
@@ -252,6 +260,7 @@ FocusScope {
252260
253261 anchors.fill: parent
254262 fullyShown: stages.fullyShown
263+ fullyHidden: stages.fullyHidden
255264 shouldUseScreenshots: !fullyShown
256265 rightEdgeEnabled: !sideStage.enabled
257266
@@ -263,9 +272,6 @@ FocusScope {
263272 function show() {
264273 stages.show();
265274 }
266− function showWithoutAnimation() {
267− stages.showWithoutAnimation();
268− }
269275 function hide() {
270276 }
271277
@@ -339,7 +345,7 @@ FocusScope {
339345 }
340346
341347 DragHandle {
342− id: stagesRevealer
348+ id: stagesDragHandle
343349
344350 anchors.top: parent.top
345351 anchors.bottom: parent.bottom
@@ -347,7 +353,11 @@ FocusScope {
347353
348354 width: shell.edgeSize
349355 direction: Direction.Leftwards
350− enabled: mainStage.applications.count > 0 || sideStage.applications.count > 0
356+ property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
357+
358+ maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
359+ // Make autocompletion impossible when !haveApps
360+ edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
351361 }
352362 }
353363 }
@@ -405,9 +415,6 @@ FocusScope {
405415
406416 dragHandleWidth: shell.edgeSize
407417
408− property var previousMainApp: null
409− property var previousSideApp: null
410−
411418 onShownChanged: {
412419 if (shown) {
413420 lockscreen.reset();
@@ -417,20 +424,6 @@ FocusScope {
417424 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
418425 }
419426 greeter.forceActiveFocus();
420− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
421− // the stage was actually shown
422− if (mainStage.fullyShown) greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
423− if (sideStage.fullyShown) greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
424− applicationManager.unfocusCurrentApplication();
425− } else {
426− if (greeter.previousMainApp) {
427− applicationManager.focusApplication(greeter.previousMainApp);
428− greeter.previousMainApp = null;
429− }
430− if (greeter.previousSideApp) {
431− applicationManager.focusApplication(greeter.previousSideApp);
432− greeter.previousSideApp = null;
433− }
434427 }
435428 }
436429
@@ -452,6 +445,42 @@ FocusScope {
452445 blockInput: greeter.shown || lockscreen.shown
453446 }
454447
448+ Connections {
449+ id: powerConnection
450+ target: Powerd
451+
452+ property var previousMainApp: null
453+ property var previousSideApp: null
454+
455+ function setFocused(focused) {
456+ if (!focused) {
457+ // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
458+ // the stage was actually shown
459+ if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
460+ if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
461+ applicationManager.unfocusCurrentApplication();
462+ } else {
463+ if (powerConnection.previousMainApp) {
464+ applicationManager.focusApplication(powerConnection.previousMainApp);
465+ powerConnection.previousMainApp = null;
466+ }
467+ if (powerConnection.previousSideApp) {
468+ applicationManager.focusApplication(powerConnection.previousSideApp);
469+ powerConnection.previousSideApp = null;
470+ }
471+ }
472+ }
473+
474+ onPowerStateChange: {
475+ if (state == 0) { // suspend
476+ powerConnection.setFocused(false);
477+ greeter.show();
478+ } else if (state == 1) { // active
479+ powerConnection.setFocused(true);
480+ }
481+ }
482+ }
483+
455484 Item {
456485 id: overlay
457486
@@ -537,7 +566,7 @@ FocusScope {
537566 anchors.bottom: parent.bottom
538567 width: parent.width
539568 dragAreaWidth: shell.edgeSize
540− available: !greeter.locked
569+ available: !greeter.shown || greeter.narrowMode
541570 onDashItemSelected: {
542571 greeter.hide()
543572 // Animate if moving between application and dash
@@ -632,4 +661,18 @@ FocusScope {
632661
633662 enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
634663 }
664+
665+ Label {
666+ anchors.fill: parent
667+ visible: applicationManager.fake
668+ text: "EARLY ALPHA\nNOT READY FOR USE"
669+ color: "lightgrey"
670+ opacity: 0.2
671+ font.weight: Font.Black
672+ horizontalAlignment: Text.AlignHCenter
673+ verticalAlignment: Text.AlignVCenter
674+ fontSizeMode: Text.Fit
675+ font.pixelSize: height/2
676+ rotation: -45
677+ }
635678}
build−3
@@ -36,9 +36,6 @@ BUILD_TYPE="debug"
3636[ $# -eq 1 ] && BUILD_TYPE="$1"
3737
3838install_dependencies() {
39− [ -f /etc/apt/sources.list.d/phablet-team-desktop-deps-${DISTRIB_CODENAME}.list ] || sudo add-apt-repository ppa:phablet-team/desktop-deps || exit 1
40− [ -f /etc/apt/sources.list.d/canonical-qt5-edgers-qt5-proper-${DISTRIB_CODENAME}.list ] || sudo add-apt-repository ppa:canonical-qt5-edgers/qt5-proper || exit 2;
41− [ -f /etc/apt/sources.list.d/ubuntu-sdk-team-ppa-${DISTRIB_CODENAME}.list ] || sudo add-apt-repository ppa:ubuntu-sdk-team/ppa || exit 3
4239 sudo apt-get update || exit 4
4340 echo "Installing Unity 8 dependencies.."
4441 sudo apt-get install devscripts \
cmake/modules/Plugins.cmake+25−15
@@ -1,17 +1,12 @@
1−# Creates targets for copying and installing qmlfiles and generating the qmltypes file for a plugin
1+# Creates target for copying and installing qmlfiles
22#
3−# export_qmlplugin(plugin version sub_path [TARGETS target1 [target2 ...]])
3+# export_qmlfiles(plugin sub_path)
44#
5−# TARGETS additional install targets (eg the plugin shared object)
65#
7−# Two targets will be created:
6+# Target to be created:
87# - plugin-qmlfiles - Copies the qml files (*.qml, *.js, qmldir) into the shadow build folder.
9−# - plugin-qmltypes - Generates the qmltypes file in the shadow build folder.
10−
118
12−macro(export_qmlplugin PLUGIN VERSION PLUGIN_SUBPATH)
13− set(multi_value_keywords TARGETS)
14− cmake_parse_arguments(qmlplugin "" "" "${multi_value_keywords}" ${ARGN})
9+macro(export_qmlfiles PLUGIN PLUGIN_SUBPATH)
1510
1611 file(GLOB QMLFILES
1712 *.qml
@@ -25,17 +20,32 @@ macro(export_qmlplugin PLUGIN VERSION PLUGIN_SUBPATH)
2520 DEPENDS ${QMLFILES}
2621 )
2722
23+ # install the qmlfiles file.
24+ install(FILES ${QMLFILES}
25+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
26+ )
27+endmacro(export_qmlfiles)
28+
29+
30+# Creates target for generating the qmltypes file for a plugin and installs plugin files
31+#
32+# export_qmlplugin(plugin version sub_path [TARGETS target1 [target2 ...]])
33+#
34+# TARGETS additional install targets (eg the plugin shared object)
35+#
36+# Target to be created:
37+# - plugin-qmltypes - Generates the qmltypes file in the shadow build folder.
38+
39+macro(export_qmlplugin PLUGIN VERSION PLUGIN_SUBPATH)
40+ set(multi_value_keywords TARGETS)
41+ cmake_parse_arguments(qmlplugin "" "" "${multi_value_keywords}" ${ARGN})
42+
2843 # create the plugin.qmltypes file
2944 add_custom_target(${PLUGIN}-qmltypes ALL
3045 COMMAND qmlplugindump -notrelocatable ${PLUGIN} ${VERSION} ${CMAKE_BINARY_DIR}/plugins > ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
3146 )
3247 add_dependencies(${PLUGIN}-qmltypes ${PLUGIN}-qmlfiles ${qmlplugin_TARGETS})
3348
34− # install the qmldir file.
35− install(FILES ${QMLFILES}
36− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
37− )
38−
3949 # install the qmltypes file.
4050 install(FILES ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
4151 DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
@@ -45,4 +55,4 @@ macro(export_qmlplugin PLUGIN VERSION PLUGIN_SUBPATH)
4555 install(TARGETS ${qmlplugin_TARGETS}
4656 DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
4757 )
48−endmacro(export_qmlplugin)
58+endmacro(export_qmlplugin)
cmake/modules/autopilot.cmake+2−1
@@ -2,8 +2,9 @@ add_custom_target(autopilot)
22
33function(declare_autopilot_test TEST_NAME TEST_SUITE WORKING_DIR)
44 add_custom_target(autopilot-${TEST_NAME}
5− COMMAND autopilot run ${TEST_SUITE}
5+ COMMAND LANG=C UBUNTU_ICON_THEME=ubuntu-mobile QML2_IMPORT_PATH=${SHELL_PRIVATE_LIBDIR}/qml/mocks autopilot run ${TEST_SUITE}
66 WORKING_DIRECTORY ${WORKING_DIR}
7+ DEPENDS install
78 )
89
910 add_dependencies(autopilot autopilot-${TEST_NAME})
debian/changelog+268
@@ -1,3 +1,271 @@
1+unity8 (7.81.3+13.10.20130807-0ubuntu1) saucy; urgency=low
2+
3+ [ Michał Sawicz ]
4+ * Drop ppa:ubuntu-unity/next.
5+ * Revert revision 161 that causes issues with invalid background.
6+
7+ [ Albert Astals ]
8+ * Fix off by one in the culling condition If you are on 0 and your
9+ height is 1 and viewport starts at 1 you have to be culled since you
10+ are not visible.
11+
12+ [ Ubuntu daily release ]
13+ * Automatic snapshot from revision 168
14+
15+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 07 Aug 2013 02:32:00 +0000
16+
17+unity8 (7.81.3+13.10.20130806-0ubuntu1) saucy; urgency=low
18+
19+ [ Michael Terry ]
20+ * Show the greeter when powerd tells us to, not just whenever we press
21+ the power key. (LP: #1186256)
22+
23+ [ Ubuntu daily release ]
24+ * Automatic snapshot from revision 164
25+
26+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 06 Aug 2013 03:43:01 +0000
27+
28+unity8 (7.81.3+13.10.20130805-0ubuntu1) saucy; urgency=low
29+
30+ [ Michael Terry ]
31+ * Fixes the lockscreen and swiping on the greeter still being possible
32+ even when in tablet mode. (LP: #1204984)
33+ * Watch powerd signals to notice a sleep and unfocus current app when
34+ that happens.
35+
36+ [ Michael Zanetti ]
37+ * make findChild also find invisible childs This considerably
38+ increases the amount of items to be searched up to a level where
39+ testShell didn't finish any more with searching. Hence this commit
40+ also changes findChild to do a breadth-first instead of a depth-
41+ first search.
42+ * Read background from GSettings or fallback to default_background.
43+
44+ [ Andrea Cimitan ]
45+ * Read background from GSettings or fallback to default_background.
46+
47+ [ Albert Astals ]
48+ * Make LVWPH provide a delegateIndex for sectionHeaders This way we
49+ can match the sectionHeader to the model easier in the qml/js side .
50+ * Fix tryCompare call The 4th parameter of tryCompare is timeout not
51+ message .
52+
53+ [ Daniel d'Andrada ]
54+ * Read background from GSettings or fallback to default_background.
55+
56+ [ Ubuntu daily release ]
57+ * Automatic snapshot from revision 162
58+
59+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 05 Aug 2013 02:32:05 +0000
60+
61+unity8 (7.81.3+13.10.20130802-0ubuntu1) saucy; urgency=low
62+
63+ [ Michael Terry ]
64+ * Make hud autopilot tests more reliable by fixing how it calculates
65+ relative coordinates.
66+
67+ [ Albert Astals ]
68+ * Only update the "section" if we are not culling the item If the item
69+ is not shown we should not care about its section.
70+
71+ [ Ubuntu daily release ]
72+ * Automatic snapshot from revision 155
73+
74+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 02 Aug 2013 02:40:11 +0000
75+
76+unity8 (7.81.3+13.10.20130801.1-0ubuntu1) saucy; urgency=low
77+
78+ [ Michał Sawicz ]
79+ * Add a disclaimer for the fake applications plugin.
80+
81+ [ Nick Dedekind ]
82+ * Removed animations from fake indicator pages.
83+
84+ [ Ubuntu daily release ]
85+ * Automatic snapshot from revision 152
86+
87+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 01 Aug 2013 14:30:40 +0000
88+
89+unity8 (7.81.3+13.10.20130801ubuntu.unity.next-0ubuntu1) saucy; urgency=low
90+
91+ [ Michael Zanetti ]
92+ * implemented new Lockscreen design.
93+
94+ [ Michał Sawicz ]
95+ * Fix mock VideoPreview to use the string categoryId as well.
96+
97+ [ Nick Dedekind ]
98+ * Added a text tree representation of the qmenumodel to the
99+ indicators-client application.
100+
101+ [ Albert Astals ]
102+ * Don't need deelistmodel here.
103+
104+ [ Ubuntu daily release ]
105+ * Automatic snapshot from revision 149 (ubuntu-unity/next)
106+
107+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 01 Aug 2013 02:32:03 +0000
108+
109+unity8 (7.81.3+13.10.20130730ubuntu.unity.next-0ubuntu1) saucy; urgency=low
110+
111+ [ Michał Sawicz ]
112+ * Adapt to Qt 5.1.
113+
114+ [ Albert Astals ]
115+ * Adapt to Qt 5.1.
116+
117+ [ Ubuntu daily release ]
118+ * Automatic snapshot from revision 143 (ubuntu-unity/next)
119+
120+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 30 Jul 2013 02:33:12 +0000
121+
122+unity8 (7.81.3+13.10.20130729ubuntu.unity.next-0ubuntu1) saucy; urgency=low
123+
124+ [ Michal Hruby ]
125+ * Remove the variant conversions methods as they were moved to dee-qt.
126+
127+ [ Michał Sawicz ]
128+ * Re-enable passphrase tests under UInput.
129+ * Use the new string categoryIds in custom video and music scope
130+ views. (LP: #1199322)
131+
132+ [ Nick Dedekind ]
133+ * Behavioural changes for indicators - Part 1 - Use standard
134+ animations. - Search bar animation less distracting. - Hinting
135+ animation shows header. - Vertical velocity detector to reduce
136+ accidental menu switches in dragging phase.
137+
138+ [ Gustavo Pichorim Boiko ]
139+ * Add entries to the new applications resulted from the split of the
140+ phone-app.
141+
142+ [ Ubuntu daily release ]
143+ * Automatic snapshot from revision 141 (ubuntu-unity/next)
144+
145+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 29 Jul 2013 03:41:07 +0000
146+
147+unity8 (7.81.3+13.10.20130726ubuntu.unity.next-0ubuntu1) saucy; urgency=low
148+
149+ [ Michal Hruby ]
150+ * Expose real category ids and not just indices.
151+ * Provide fallbacks for default renderer.
152+
153+ [ Daniel d'Andrada ]
154+ * Give a visual feedback on right-edge drag with no running apps (LP:
155+ #1116207). (LP: #1116207)
156+
157+ [ Albert Astals ]
158+ * Update m_firstVisibleIndex if there's no visible items anymore Also
159+ remove the check for m_visibleItems.isEmpty() on insert, the
160+ m_firstVisibleIndex == 0 already protects us against that.
161+
162+ [ Christopher Lee ]
163+ * Tests now use a default lightdm mock if not decorated. (LP:
164+ #1204772)
165+
166+ [ Ubuntu daily release ]
167+ * Automatic snapshot from revision 135 (ubuntu-unity/next)
168+
169+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 26 Jul 2013 07:06:08 +0000
170+
171+unity8 (7.81.3+13.10.20130725ubuntu.unity.next-0ubuntu1) saucy; urgency=low
172+
173+ [ Michal Hruby ]
174+ * Fix adding items into an empty LVWPH.
175+
176+ [ Michał Sawicz ]
177+ * Move to using upstart in run_on_device.
178+ * Added heeding and qmltest for button-tint hint.
179+ * Refactoring and cleanup of the Unity8 Autopilot tests.
180+ * Hide the Unity launcher during autopiloting and skip battery tests
181+ if unavailable.
182+
183+ [ Ying-Chun Liu ]
184+ * Let GenericScope support loading different renderers.
185+
186+ [ Nick Dedekind ]
187+ * Removed overview from indicators.
188+ * Menus for indicators is now created prioritised by distance from
189+ current item to speed up user experience.
190+ * Add ApplicationArguments to know the geometry from start.
191+
192+ [ Mirco Müller ]
193+ * Added heeding and qmltest for button-tint hint.
194+
195+ [ Christopher Lee ]
196+ * Refactoring and cleanup of the Unity8 Autopilot tests.
197+
198+ [ Thomi Richards ]
199+ * Refactoring and cleanup of the Unity8 Autopilot tests.
200+
201+ [ Ubuntu daily release ]
202+ * Automatic snapshot from revision 129 (ubuntu-unity/next)
203+
204+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 25 Jul 2013 03:02:12 +0000
205+
206+unity8 (7.81.3+13.10.20130718ubuntu.unity.next-0ubuntu1) saucy; urgency=low
207+
208+ [ Andrea Cimitan ]
209+ * Add support for the colour palette.
210+
211+ [ Omer Akram ]
212+ * fix the calendar icon in the launcher. (LP: #1201905)
213+
214+ [ Nick Dedekind ]
215+ * Export indicator plugin symbols using Q_DECL_EXPORT.
216+
217+ [ Ying-Chun Liu ]
218+ * Don't include .moc in previewbindingstest.cpp.
219+
220+ [ Ubuntu daily release ]
221+ * Automatic snapshot from revision 118 (ubuntu-unity/next)
222+
223+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 18 Jul 2013 06:07:00 +0000
224+
225+unity8 (7.81.3+13.10.20130717ubuntu.unity.next-0ubuntu1) saucy; urgency=low
226+
227+ [ Daniel d'Andrada ]
228+ * Remove dead code: Showable::showWithoutAnimation.
229+
230+ [ Nick Dedekind ]
231+ * Split Plugins export macro into export_qmlfiles and
232+ export_qmlplugins. Added qmltypes to indicators plugin.
233+
234+ [ Ubuntu daily release ]
235+ * Automatic snapshot from revision 112 (ubuntu-unity/next)
236+
237+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 17 Jul 2013 03:14:49 +0000
238+
239+unity8 (7.81.3+13.10.20130716ubuntu.unity.next-0ubuntu1) saucy; urgency=low
240+
241+ [ Pete Woods ]
242+ * Rename the demo user "single" to "phablet" Fix the infographics on
243+ the device At the moment the mock lightdm backend we are using says
244+ the current user is called "single", while in reality the processes
245+ all run as the "phablet" user.
246+
247+ [ Michał Sawicz ]
248+ * Only use ppa:ubuntu-unity/next and clean build scripts and CODING,
249+ accordingly.
250+ * Do not recommend indicator-power and indicator-sound. On device
251+ they're provided by lp:indicator-server for the time being.
252+ * Fix the Network page to provide the correct token. (LP: #1201529)
253+
254+ [ Ubuntu daily release ]
255+ * Automatic snapshot from revision 109 (ubuntu-unity/next)
256+
257+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 16 Jul 2013 02:32:03 +0000
258+
259+unity8 (7.81.3+13.10.20130714ubuntu.unity.next-0ubuntu1) saucy; urgency=low
260+
261+ [ Michael Terry ]
262+ * Change Ok to OK. (LP: #1131842)
263+
264+ [ Ubuntu daily release ]
265+ * Automatic snapshot from revision 104 (ubuntu-unity/next)
266+
267+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Sun, 14 Jul 2013 02:31:57 +0000
268+
1269unity8 (7.81.3+13.10.20130712ubuntu.unity.next-0ubuntu1) saucy; urgency=low
2270
3271 [ Michael Zanetti ]
debian/control+3−3
@@ -4,7 +4,7 @@ Priority: optional
44Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
55Build-Depends: cmake,
66 debhelper (>= 9),
7− libdee-qt5-dev (>= 3.0),
7+ libdee-qt5-dev (>= 3.2),
88 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
99 libgl1-mesa-dri,
1010 libgles2-mesa-dev[armhf],
@@ -71,8 +71,6 @@ Depends: qmenumodel-qml,
7171 ${shlibs:Depends},
7272Recommends: indicator-battery,
7373 indicator-messages,
74− indicator-network,
75− indicator-sound,
7674 indicator-time,
7775 ${unity-default-masterscopes},
7876Description: Unity 8 shell
@@ -90,6 +88,8 @@ Depends: indicators-client (>= ${source:Version}),
9088 ${misc:Depends},
9189 ${python:Depends},
9290 ${shlibs:Depends},
91+Recommends: gir1.2-glib-2.0,
92+ python-gi,
9393Description: Test package for Unity 8 shell
9494 Autopilot tests for the unity8 package
9595
debian/unity8-private.install+1
@@ -1,6 +1,7 @@
11usr/lib/*/unity8/qml/HudClient
22usr/lib/*/unity8/qml/LightDM
33usr/lib/*/unity8/qml/ListViewWithPageHeader
4+usr/lib/*/unity8/qml/Powerd
45usr/lib/*/unity8/qml/Ubuntu
56usr/lib/*/unity8/qml/Unity
67usr/lib/*/unity8/qml/Utils
main.cpp+4−6
@@ -18,6 +18,7 @@
1818 */
1919
2020// Qt
21+#include <QtQml>
2122#include <QtQuick/QQuickView>
2223#include <QtGui/QIcon>
2324#include <QtGui/QGuiApplication>
@@ -30,6 +31,7 @@
3031// local
3132#include "paths.h"
3233#include "MouseTouchAdaptor.h"
34+#include "ApplicationArguments.h"
3335
3436namespace {
3537
@@ -86,6 +88,7 @@ int main(int argc, char** argv)
8688 resolveIconTheme();
8789
8890 QStringList args = application.arguments();
91+ ApplicationArguments qmlArgs(args);
8992
9093 // The testability driver is only loaded by QApplication but not by QGuiApplication.
9194 // However, QApplication depends on QWidget which would add some unneeded overhead => Let's load the testability driver on our own.
@@ -110,6 +113,7 @@ int main(int argc, char** argv)
110113 view->setResizeMode(QQuickView::SizeRootObjectToView);
111114 view->setTitle("Qml Phone Shell");
112115 view->engine()->setBaseUrl(QUrl::fromLocalFile(::shellAppDirectory()));
116+ view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
113117 if (args.contains(QLatin1String("-frameless"))) {
114118 view->setFlags(Qt::FramelessWindowHint);
115119 }
@@ -141,12 +145,6 @@ int main(int argc, char** argv)
141145 if (qgetenv("QT_QPA_PLATFORM") == "ubuntu" || args.contains(QLatin1String("-fullscreen"))) {
142146 view->showFullScreen();
143147 } else {
144− if (args.contains(QLatin1String("-geometry")) && args.size() > args.indexOf(QLatin1String("-geometry")) + 1) {
145− QStringList geometryArg = args.at(args.indexOf(QLatin1String("-geometry")) + 1).split('x');
146− if (geometryArg.size() == 2) {
147− view->resize(geometryArg.at(0).toInt(), geometryArg.at(1).toInt());
148− }
149− }
150148 view->show();
151149 }
152150
plugins/CMakeLists.txt+1
@@ -4,3 +4,4 @@ add_subdirectory(Unity)
44add_subdirectory(HudClient)
55add_subdirectory(LightDM)
66add_subdirectory(ListViewWithPageHeader)
7+add_subdirectory(Powerd)
plugins/HudClient/CMakeLists.txt+2−1
@@ -38,5 +38,6 @@ target_link_libraries(HudClientQml
3838
3939qt5_use_modules(HudClientQml Qml)
4040
41−# export the qmldir and qmltypes files
41+# export the qmldir qmltypes and plugin files
42+export_qmlfiles(HudClient HudClient)
4243export_qmlplugin(HudClient 0.1 HudClient TARGETS HudClientQml)
plugins/LightDM/CMakeLists.txt+2−1
@@ -35,5 +35,6 @@ target_link_libraries(LightDM-qml
3535
3636qt5_use_modules(LightDM-qml Gui Qml)
3737
38−# export the qmldir and qmltypes files
38+# export the qmldir qmltypes and plugin files
39+export_qmlfiles(LightDM LightDM)
3940export_qmlplugin(LightDM 0.1 LightDM TARGETS LightDM-qml)
plugins/ListViewWithPageHeader/CMakeLists.txt+7−2
@@ -4,7 +4,11 @@ include(Plugins)
44# There's no cmake var for v8 include path :-/
55# so create one
66LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
7−SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
7+if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
8+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
9+else()
10+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
11+endif()
812
913include_directories(
1014 ${CMAKE_CURRENT_SOURCE_DIR}
@@ -33,5 +37,6 @@ target_link_libraries(ListViewWithPageHeader-qml
3337
3438qt5_use_modules(ListViewWithPageHeader-qml Qml Quick)
3539
36−# export the qmldir and qmltypes files
40+# export the qmldir qmltypes and plugin files
41+export_qmlfiles(ListViewWithPageHeader ListViewWithPageHeader)
3742export_qmlplugin(ListViewWithPageHeader 0.1 ListViewWithPageHeader TARGETS ListViewWithPageHeader-qml)
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+98−14
@@ -96,7 +96,11 @@
9696#include <qqmlengine.h>
9797#pragma GCC diagnostic push
9898#pragma GCC diagnostic ignored "-pedantic"
99+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
99100#include <private/qquickvisualdatamodel_p.h>
101+#else
102+#include <private/qqmldelegatemodel_p.h>
103+#endif
100104#include <private/qqmlglobal_p.h>
101105#include <private/qquickitem_p.h>
102106#include <private/qquickanimation_p.h>
@@ -183,10 +187,17 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
183187 if (!m_delegateModel) {
184188 createDelegateModel();
185189 } else {
190+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
186191 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
187192 }
188193 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
189194 connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
195+#else
196+ disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
197+ }
198+ m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
199+ connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
200+#endif
190201 Q_EMIT modelChanged();
191202 // TODO?
192203// Q_EMIT contentHeightChanged();
@@ -269,7 +280,7 @@ void ListViewWithPageHeader::setSectionDelegate(QQmlComponent *delegate)
269280
270281 m_sectionDelegate = delegate;
271282
272− m_topSectionItem = getSectionItem(QString());
283+ m_topSectionItem = getSectionItem(-1, QString());
273284 m_topSectionItem->setZ(3);
274285 QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
275286
@@ -446,8 +457,13 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
446457
447458void ListViewWithPageHeader::createDelegateModel()
448459{
460+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
449461 m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
450462 connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
463+#else
464+ m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
465+ connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
466+#endif
451467 if (isComponentComplete())
452468 m_delegateModel->componentComplete();
453469 updateWatchedRoles();
@@ -528,8 +544,13 @@ bool ListViewWithPageHeader::addVisibleItems(qreal fillFrom, qreal fillTo, bool
528544void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
529545{
530546 QQuickItem *item = listItem->m_item;
547+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
531548 QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
532549 if (flags & QQuickVisualModel::Destroyed) {
550+#else
551+ QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
552+ if (flags & QQmlDelegateModel::Destroyed) {
553+#endif
533554 item->setParentItem(nullptr);
534555 }
535556 delete listItem->m_sectionItem;
@@ -578,16 +599,17 @@ QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyI
578599 }
579600 }
580601
581− return getSectionItem(section);
602+ return getSectionItem(modelIndex, section);
582603}
583604
584−QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText)
605+QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, const QString &sectionText)
585606{
586607 QQuickItem *sectionItem = nullptr;
587608
588609 QQmlContext *creationContext = m_sectionDelegate->creationContext();
589610 QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));
590611 context->setContextProperty(QLatin1String("section"), sectionText);
612+ context->setContextProperty(QLatin1String("delegateIndex"), modelIndex);
591613 QObject *nobj = m_sectionDelegate->beginCreate(context);
592614 if (nobj) {
593615 QQml_setParent_noEvent(context, nobj);
@@ -658,9 +680,27 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
658680 return nullptr;
659681
660682 m_asyncRequestedIndex = -1;
683+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
661684 QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
685+#else
686+ QObject* object = m_delegateModel->object(modelIndex, asynchronous);
687+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
688+#endif
662689 if (!item) {
690+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
663691 m_asyncRequestedIndex = modelIndex;
692+#else
693+ if (object) {
694+ m_delegateModel->release(object);
695+ if (!m_delegateValidated) {
696+ m_delegateValidated = true;
697+ QObject* delegateObj = delegate();
698+ qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
699+ }
700+ } else {
701+ m_asyncRequestedIndex = modelIndex;
702+ }
703+#endif
664704 return 0;
665705 } else {
666706// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
@@ -694,7 +734,7 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
694734 releaseItem(listItem);
695735 listItem = nullptr;
696736 } else {
697− listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() < contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
737+ listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() <= contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
698738 if (m_visibleItems.isEmpty()) {
699739 m_visibleItems << listItem;
700740 } else {
@@ -711,8 +751,18 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
711751 }
712752}
713753
754+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
714755void ListViewWithPageHeader::itemCreated(int modelIndex, QQuickItem *item)
715756{
757+#else
758+void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
759+{
760+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
761+ if (!item) {
762+ qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
763+ return;
764+ }
765+#endif
716766// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
717767
718768 item->setParentItem(m_clipItem);
@@ -747,13 +797,22 @@ void ListViewWithPageHeader::onHeightChanged()
747797 polish();
748798}
749799
800+
801+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
750802void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bool /*reset*/)
803+#else
804+void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool /*reset*/)
805+#endif
751806{
752807 // TODO Do something with reset
753808// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
754809 const auto oldFirstVisibleIndex = m_firstVisibleIndex;
755810
811+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
756812 Q_FOREACH(const QQuickChangeSet::Remove &remove, changeSet.removes()) {
813+#else
814+ Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
815+#endif
757816// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
758817 if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
759818 const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
@@ -785,10 +844,14 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
785844 }
786845 if (growDown) {
787846 adjustMinYExtent();
788− } else if (remove.index <= m_firstVisibleIndex && !m_visibleItems.isEmpty()) {
789− // We removed the first item that is the one that positions the rest
790− // position the new first item correctly
791− m_visibleItems.first()->setY(oldFirstValidIndexPos);
847+ } else if (remove.index <= m_firstVisibleIndex) {
848+ if (!m_visibleItems.isEmpty()) {
849+ // We removed the first item that is the one that positions the rest
850+ // position the new first item correctly
851+ m_visibleItems.first()->setY(oldFirstValidIndexPos);
852+ } else {
853+ m_firstVisibleIndex = -1;
854+ }
792855 }
793856 } else if (remove.index + remove.count <= m_firstVisibleIndex) {
794857 m_firstVisibleIndex -= remove.count;
@@ -803,7 +866,11 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
803866 }
804867 }
805868
869+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
806870 Q_FOREACH(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
871+#else
872+ Q_FOREACH(const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
873+#endif
807874// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
808875 const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
809876 const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
@@ -866,6 +933,14 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
866933 adjustMinYExtent();
867934 }
868935
936+ for (int i = 0; i < m_visibleItems.count(); ++i) {
937+ ListItem *item = m_visibleItems[i];
938+ if (item->m_sectionItem) {
939+ QQmlContext *context = QQmlEngine::contextForObject(item->m_sectionItem)->parentContext();
940+ context->setContextProperty(QLatin1String("delegateIndex"), m_firstVisibleIndex + i);
941+ }
942+ }
943+
869944 layout();
870945 polish();
871946 m_contentHeightDirty = true;
@@ -965,17 +1040,12 @@ void ListViewWithPageHeader::layout()
9651040 int firstReallyVisibleItem = -1;
9661041 int modelIndex = m_firstVisibleIndex;
9671042 Q_FOREACH(ListItem *item, m_visibleItems) {
968− const bool cull = pos + item->height() < visibleFrom || pos >= visibleTo;
1043+ const bool cull = pos + item->height() <= visibleFrom || pos >= visibleTo;
9691044 item->setCulled(cull);
9701045 item->setY(pos);
9711046 if (!cull && firstReallyVisibleItem == -1) {
9721047 firstReallyVisibleItem = modelIndex;
9731048 if (m_topSectionItem) {
974− // Update the top sticky section header
975− const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
976− QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();
977− context->setContextProperty(QLatin1String("section"), section);
978−
9791049 // Positing the top section sticky item is a two step process
9801050 // First we set it either we cull it (because it doesn't need to be sticked to the top)
9811051 // or stick it to the top
@@ -992,8 +1062,22 @@ void ListViewWithPageHeader::layout()
9921062 QQuickItemPrivate::get(item->m_sectionItem)->setCulled(false);
9931063 }
9941064 } else {
1065+ // Update the top sticky section header
1066+ const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
1067+ QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();
1068+ context->setContextProperty(QLatin1String("section"), section);
1069+
9951070 QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);
9961071 m_topSectionItem->setY(topSectionStickPos);
1072+ int delegateIndex = modelIndex;
1073+ // Look for the first index with this section text
1074+ while (delegateIndex > 0) {
1075+ const QString prevSection = m_delegateModel->stringValue(delegateIndex - 1, m_sectionProperty);
1076+ if (prevSection != section)
1077+ break;
1078+ delegateIndex--;
1079+ }
1080+ context->setContextProperty(QLatin1String("delegateIndex"), delegateIndex);
9971081 if (item->m_sectionItem) {
9981082 QQuickItemPrivate::get(item->m_sectionItem)->setCulled(true);
9991083 }
plugins/ListViewWithPageHeader/listviewwithpageheader.h+19−2
@@ -24,9 +24,14 @@
2424#pragma GCC diagnostic pop
2525
2626class QAbstractItemModel;
27−class QQuickChangeSet;
2827class QQuickNumberAnimation;
28+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
29+class QQuickChangeSet;
2930class QQuickVisualDataModel;
31+#else
32+class QQmlChangeSet;
33+class QQmlDelegateModel;
34+#endif
3035
3136
3237/**
@@ -100,11 +105,19 @@ protected:
100105 void updatePolish();
101106
102107private Q_SLOTS:
108+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
103109 void itemCreated(int modelIndex, QQuickItem *item);
110+#else
111+ void itemCreated(int modelIndex, QObject *object);
112+#endif
104113 void onContentHeightChanged();
105114 void onContentWidthChanged();
106115 void onHeightChanged();
116+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
107117 void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
118+#else
119+ void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
120+#endif
108121 void onShowHeaderAnimationFinished();
109122
110123private:
@@ -139,9 +152,13 @@ private:
139152 void reallyReleaseItem(ListItem *item);
140153 void updateWatchedRoles();
141154 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
142− QQuickItem *getSectionItem(const QString &sectionText);
155+ QQuickItem *getSectionItem(int modelIndex, const QString &sectionText);
143156
157+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
144158 QQuickVisualDataModel *m_delegateModel;
159+#else
160+ QQmlDelegateModel *m_delegateModel;
161+#endif
145162
146163 // Index we are waiting because we requested it asynchronously
147164 int m_asyncRequestedIndex;
plugins/Powerd/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(Powerd-qml MODULE
6+ plugin.cpp
7+ Powerd.cpp
8+ )
9+
10+qt5_use_modules(Powerd-qml DBus Qml)
11+
12+export_qmlfiles(Powerd Powerd)
13+export_qmlplugin(Powerd 0.1 Powerd TARGETS Powerd-qml)
plugins/Powerd/Powerd.cppnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "Powerd.h"
20+
21+Powerd::Powerd(QObject* parent)
22+ : QObject(parent),
23+ powerd(NULL)
24+{
25+ powerd = new QDBusInterface("com.canonical.powerd",
26+ "/com/canonical/powerd",
27+ "com.canonical.powerd",
28+ QDBusConnection::SM_BUSNAME(), this);
29+
30+ powerd->connection().connect("com.canonical.powerd",
31+ "/com/canonical/powerd",
32+ "com.canonical.powerd",
33+ "SysPowerStateChange",
34+ this,
35+ SIGNAL(powerStateChange(int)));
36+}
plugins/Powerd/Powerd.hnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_POWERD_H
21+#define UNITY_POWERD_H
22+
23+#include <QtCore/QObject>
24+#include <QtDBus/QDBusInterface>
25+
26+class Powerd: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit Powerd(QObject *parent = 0);
32+
33+Q_SIGNALS:
34+ void powerStateChange(int state);
35+
36+private:
37+ QDBusInterface *powerd;
38+};
39+
40+#endif
plugins/Powerd/plugin.cppnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "plugin.h"
21+#include "Powerd.h"
22+
23+#include <QtQml/QtQml>
24+
25+static QObject *powerd_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
26+{
27+ Q_UNUSED(engine)
28+ Q_UNUSED(scriptEngine)
29+ return new Powerd();
30+}
31+
32+void PowerdPlugin::registerTypes(const char *uri)
33+{
34+ Q_ASSERT(uri == QLatin1String("Powerd"));
35+ qmlRegisterSingletonType<Powerd>(uri, 0, 1, "Powerd", powerd_provider);
36+}
plugins/Powerd/plugin.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef POWER_PLUGIN_H
21+#define POWER_PLUGIN_H
22+
23+#include <QtQml/QQmlEngine>
24+#include <QtQml/QQmlExtensionPlugin>
25+
26+class PowerdPlugin : public QQmlExtensionPlugin
27+{
28+ Q_OBJECT
29+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30+
31+public:
32+ void registerTypes(const char *uri);
33+};
34+
35+#endif
plugins/Powerd/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Powerd
2+plugin Powerd-qml
3+typeinfo plugin.qmltypes
plugins/Ubuntu/Gestures/CMakeLists.txt+2−1
@@ -23,5 +23,6 @@ qt5_use_modules(UbuntuGestureQml Core Quick)
2323# So that Foo.cpp can #include "Foo.moc"
2424include_directories(${CMAKE_CURRENT_BINARY_DIR})
2525
26−# export the qmldir and qmltypes files
26+# export the qmldir qmltypes and plugin files
27+export_qmlfiles(Ubuntu.Gestures Ubuntu/Gestures)
2728export_qmlplugin(Ubuntu.Gestures 0.1 Ubuntu/Gestures TARGETS UbuntuGestureQml)
plugins/Unity/CMakeLists.txt+3−2
@@ -5,7 +5,7 @@ add_subdirectory(Indicators)
55
66# Dependencies
77include(FindPkgConfig)
8−pkg_check_modules(QTDEE REQUIRED libdee-qt5)
8+pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2)
99pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
1010
1111include_directories(
@@ -61,7 +61,8 @@ target_link_libraries(Unity-qml
6161
6262qt5_use_modules(Unity-qml Qml)
6363
64−# export the qmldir and qmltypes files
64+# export the qmldir qmltypes and plugin files
65+export_qmlfiles(Unity Unity)
6566export_qmlplugin(Unity 0.1 Unity TARGETS Unity-qml)
6667
6768add_subdirectory(Launcher)
plugins/Unity/Indicators/CMakeLists.txt+8−8
@@ -1,3 +1,6 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
14project(IndicatorsQml)
25
36pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
@@ -20,8 +23,11 @@ set(IndicatorsQML_SOURCES
2023 indicators.h
2124 indicatorsmanager.cpp
2225 indicatorsmodel.cpp
26+ menucontentactivator.cpp
27+ modelprinter.cpp
2328 plugin.cpp
2429)
30+add_definitions(-DUNITYINDICATORS_LIBRARY)
2531
2632set(IndicatorsQML_RESOURCES
2733 resources/indicators.qrc
@@ -35,11 +41,6 @@ add_library(IndicatorsQml SHARED
3541 ${IndicatorsQML_RESOURCES_RCC}
3642 ${IndicatorsQML_SOURCES}
3743)
38−# Because this is an internal support library, we want
39−# to expose all symbols in it. Consider changing this
40−# either to a static library or just using the
41−# files directly in targets.
42−set_target_properties(IndicatorsQml PROPERTIES COMPILE_FLAGS -fvisibility=default)
4344
4445target_link_libraries(IndicatorsQml
4546 ${QMENUMODEL_LDFLAGS}
@@ -47,6 +48,5 @@ target_link_libraries(IndicatorsQml
4748
4849qt5_use_modules(IndicatorsQml Core Qml Quick)
4950
50−install(TARGETS IndicatorsQml
51− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity/Indicators
52− )
51+# export the qmltypes and plugin files
52+export_qmlplugin(Unity.Indicators 0.1 Unity/Indicators TARGETS IndicatorsQml)
plugins/Unity/Indicators/Messaging/qml/CMakeLists.txt+4−14
@@ -1,15 +1,5 @@
1−file(GLOB IndicatorsMessaging_QMLFILES
2− *.qml
3− *.js
4− qmldir
5−)
1+# export_qmlfiles macro
2+include(Plugins)
63
7−# copy qml & qmldir files into build directory for shadow builds
8−add_custom_target(UnityIndicatorsMessagingQmlFiles ALL
9− COMMAND cp ${IndicatorsMessaging_QMLFILES} ${CMAKE_BINARY_DIR}/plugins/Unity/Indicators/Messaging
10− DEPENDS ${IndicatorsMessaging_QMLFILES}
11−)
12−
13−install(FILES ${IndicatorsMessaging_QMLFILES}
14− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity/Indicators/Messaging
15−)
4+# export the qmldir, *.qml files.
5+export_qmlfiles(Unity.Indicators.Messaging Unity/Indicators/Messaging)
plugins/Unity/Indicators/Network/CMakeLists.txt+6−3
@@ -1,3 +1,6 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
14project(IndicatorsNetworkQml)
25
36pkg_check_modules(GLIB glib-2.0>=2.32)
@@ -32,9 +35,9 @@ if(LIBNM_GLIB_FOUND AND LIBNM_UTIL_FOUND AND GLIB_FOUND)
3235 ${LIBNM_UTIL_LIBRARIES}
3336 )
3437
35− install(TARGETS IndicatorsNetworkQml
36− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity/Indicators/Network
37− )
38+ # export the qmltypes and plugin files
39+ export_qmlplugin(Unity.Indicators.Network 0.1 Unity/Indicators/Network TARGETS IndicatorsNetworkQml)
40+
3841else()
3942 message(WARNING "Missing glib or libnm dependency for the network plugin, not building")
4043endif()
plugins/Unity/Indicators/Network/qml/CMakeLists.txt+4−14
@@ -1,15 +1,5 @@
1−file(GLOB IndicatorsNetwork_QMLFILES
2− *.qml
3− *.js
4− qmldir
5−)
1+# export_qmlplugin macro
2+include(Plugins)
63
7−# copy qml & qmldir files into build directory for shadow builds
8−add_custom_target(UnityIndicatorsNetworkQmlFiles ALL
9− COMMAND cp ${IndicatorsNetwork_QMLFILES} ${CMAKE_BINARY_DIR}/plugins/Unity/Indicators/Network
10− DEPENDS ${IndicatorsNetwork_QMLFILES}
11−)
12−
13−install(FILES ${IndicatorsNetwork_QMLFILES}
14− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity/Indicators/Network
15−)
4+# export the qmldir, *.qml files.
5+export_qmlfiles(Unity.Indicators.Network Unity/Indicators/Network)
plugins/Unity/Indicators/Network/qml/PasswordPage.qml+1−1
@@ -75,7 +75,7 @@ Page {
7575 }
7676
7777 Button {
78− text: "Ok"
78+ text: "OK"
7979 width: units.gu(10)
8080 onClicked: {
8181 agent.authenticate(token, password.text);
plugins/Unity/Indicators/Network/qml/qmldir+1
@@ -1,5 +1,6 @@
11module Unity.Indicators.Network
22plugin IndicatorsNetworkQml
3+typeinfo plugin.qmltypes
34
45NetworkPage 0.1 NetworkPage.qml
56AccessPoint 0.1 AccessPoint.qml
plugins/Unity/Indicators/flatmenuproxymodel.h+3−1
@@ -20,12 +20,14 @@
2020#ifndef FLATMENUPROXYMODEL_H
2121#define FLATMENUPROXYMODEL_H
2222
23+#include "unityindicatorsglobal.h"
24+
2325#include <QAbstractProxyModel>
2426#include <qdbusmenumodel.h>
2527
2628class SectionInfo;
2729
28−class FlatMenuProxyModel : public QAbstractProxyModel
30+class UNITYINDICATORS_EXPORT FlatMenuProxyModel : public QAbstractProxyModel
2931{
3032 Q_OBJECT
3133 Q_PROPERTY(int count READ count NOTIFY countChanged)
plugins/Unity/Indicators/indicator.h+3−1
@@ -21,10 +21,12 @@
2121#ifndef INDICATOR_H
2222#define INDICATOR_H
2323
24+#include "unityindicatorsglobal.h"
25+
2426#include <QObject>
2527#include <QSettings>
2628
27−class Indicator : public QObject
29+class UNITYINDICATORS_EXPORT Indicator : public QObject
2830{
2931 Q_OBJECT
3032 Q_PROPERTY(QString identifier READ identifier NOTIFY identifierChanged)
plugins/Unity/Indicators/indicators.h+7−5
@@ -19,9 +19,11 @@
1919#ifndef INDICATORS_H
2020#define INDICATORS_H
2121
22+#include "unityindicatorsglobal.h"
23+
2224#include <QObject>
2325
24−class ActionState : public QObject
26+class UNITYINDICATORS_EXPORT ActionState : public QObject
2527{
2628 Q_OBJECT
2729public:
@@ -36,7 +38,7 @@ public:
3638 ActionState(QObject*parent=0):QObject(parent) {}
3739};
3840
39−class NetworkActionState : public QObject
41+class UNITYINDICATORS_EXPORT NetworkActionState : public QObject
4042{
4143 Q_OBJECT
4244public:
@@ -49,7 +51,7 @@ public:
4951 NetworkActionState(QObject*parent=0):QObject(parent) {}
5052};
5153
52−class NetworkConnection : public QObject
54+class UNITYINDICATORS_EXPORT NetworkConnection : public QObject
5355{
5456 Q_OBJECT
5557public:
@@ -64,7 +66,7 @@ public:
6466 NetworkConnection(QObject*parent=0):QObject(parent) {}
6567};
6668
67−class IndicatorsModelRole : public QObject
69+class UNITYINDICATORS_EXPORT IndicatorsModelRole : public QObject
6870{
6971 Q_OBJECT
7072public:
@@ -83,7 +85,7 @@ public:
8385 IndicatorsModelRole(QObject*parent=0):QObject(parent) {}
8486};
8587
86−class FlatMenuProxyModelRole : public QObject
88+class UNITYINDICATORS_EXPORT FlatMenuProxyModelRole : public QObject
8789{
8890 Q_OBJECT
8991public:
plugins/Unity/Indicators/indicatorsmanager.h+4−3
@@ -19,15 +19,16 @@
1919#ifndef INDICATORS_MANAGER_H
2020#define INDICATORS_MANAGER_H
2121
22+#include "indicator.h"
23+#include "unityindicatorsglobal.h"
24+
2225#include <QObject>
2326#include <QFileSystemWatcher>
2427#include <QDir>
2528#include <QHash>
2629#include <QSharedPointer>
2730
28−#include "indicator.h"
29−
30−class IndicatorsManager : public QObject
31+class UNITYINDICATORS_EXPORT IndicatorsManager : public QObject
3132{
3233 Q_OBJECT
3334 Q_PROPERTY(bool loaded READ isLoaded NOTIFY loadedChanged)
plugins/Unity/Indicators/indicatorsmodel.h+2−1
@@ -22,13 +22,14 @@
2222#define INDICATORSMODEL_H
2323
2424#include "indicator.h"
25+#include "unityindicatorsglobal.h"
2526
2627#include <QAbstractListModel>
2728#include <QQmlEngine>
2829
2930class IndicatorsManager;
3031
31−class IndicatorsModel : public QAbstractListModel
32+class UNITYINDICATORS_EXPORT IndicatorsModel : public QAbstractListModel
3233{
3334 Q_OBJECT
3435 Q_ENUMS(Roles)
plugins/Unity/Indicators/menucontentactivator.cppnew file+345
@@ -0,0 +1,345 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+ #include "menucontentactivator.h"
20+
21+// Essentially a QTimer wrapper
22+class ContentTimer : public UnityIndicators::AbstractTimer
23+{
24+ Q_OBJECT
25+public:
26+ ContentTimer(QObject *parent) : UnityIndicators::AbstractTimer(parent) {
27+ m_timer.setSingleShot(false);
28+ connect(&m_timer, &QTimer::timeout,
29+ this, &UnityIndicators::AbstractTimer::timeout);
30+ }
31+ virtual int interval() const { return m_timer.interval(); }
32+ virtual void setInterval(int msecs) { m_timer.setInterval(msecs); }
33+ virtual void start() { m_timer.start(); UnityIndicators::AbstractTimer::start(); }
34+ virtual void stop() { m_timer.stop(); UnityIndicators::AbstractTimer::stop(); }
35+private:
36+ QTimer m_timer;
37+};
38+
39+class MenuContentActivatorPrivate : public QObject
40+{
41+ Q_OBJECT
42+public:
43+ MenuContentActivatorPrivate(MenuContentActivator* parent)
44+ : m_running(false),
45+ m_baseIndex(0),
46+ m_delta(0),
47+ m_count(0),
48+ m_timer(NULL),
49+ q(parent)
50+ {}
51+
52+ ~MenuContentActivatorPrivate()
53+ {
54+ qDeleteAll(m_content);
55+ m_content.clear();
56+ }
57+
58+ int findNextInactiveDelta(bool* finished = NULL);
59+
60+ static int content_count(QQmlListProperty<MenuContentState> *prop);
61+ static MenuContentState* content_at(QQmlListProperty<MenuContentState> *prop, int index);
62+
63+ bool m_running;
64+ int m_baseIndex;
65+ int m_delta;
66+ int m_count;
67+ UnityIndicators::AbstractTimer* m_timer;
68+ QMap<int, MenuContentState*> m_content;
69+ MenuContentActivator* q;
70+};
71+
72+MenuContentActivator::MenuContentActivator(QObject* parent)
73+ : QObject(parent),
74+ d(new MenuContentActivatorPrivate(this))
75+{
76+ qRegisterMetaType<QQmlListProperty<MenuContentState> > ("QQmlListProperty<MenuContentState>");
77+
78+ setContentTimer(new ContentTimer(this));
79+ d->m_timer->setInterval(75);
80+}
81+
82+MenuContentActivator::~MenuContentActivator()
83+{
84+ delete d;
85+}
86+
87+void MenuContentActivator::restart()
88+{
89+ // when we start, make sure we have the base index in the list.
90+ setMenuContentState(d->m_baseIndex, true);
91+ setDelta(0);
92+
93+ // check if we've finished before starting the timer.
94+ bool finished = false;
95+ d->findNextInactiveDelta(&finished);
96+ if (!finished) {
97+ d->m_timer->start();
98+ } else {
99+ d->m_timer->stop();
100+ }
101+
102+ if (!d->m_running) {
103+ d->m_running = true;
104+ Q_EMIT runningChanged(true);
105+ }
106+}
107+
108+void MenuContentActivator::stop()
109+{
110+ d->m_timer->stop();
111+ if (!d->m_running) {
112+ d->m_running = false;
113+ Q_EMIT runningChanged(false);
114+ }
115+}
116+
117+void MenuContentActivator::clear()
118+{
119+ qDeleteAll(d->m_content);
120+ d->m_content.clear();
121+
122+ setDelta(0);
123+ d->m_timer->stop();
124+
125+ Q_EMIT contentChanged();
126+}
127+
128+bool MenuContentActivator::isMenuContentActive(int index) const
129+{
130+ if (d->m_content.contains(index))
131+ return d->m_content[index]->isActive();
132+ return false;
133+}
134+
135+void MenuContentActivator::setRunning(bool running)
136+{
137+ if (running) {
138+ restart();
139+ } else {
140+ stop();
141+ }
142+}
143+
144+bool MenuContentActivator::isRunning() const
145+{
146+ return d->m_running;
147+}
148+
149+void MenuContentActivator::setBaseIndex(int index)
150+{
151+ if (d->m_baseIndex != index) {
152+ d->m_baseIndex = index;
153+
154+ if (isRunning()) {
155+ restart();
156+ }
157+
158+ Q_EMIT baseIndexChanged(index);
159+ }
160+}
161+
162+int MenuContentActivator::baseIndex() const
163+{
164+ return d->m_baseIndex;
165+}
166+
167+void MenuContentActivator::setCount(int count)
168+{
169+ if (d->m_count != count) {
170+ d->m_count = count;
171+ Q_EMIT countChanged(count);
172+
173+ if (isRunning()) {
174+ restart();
175+ }
176+ }
177+}
178+
179+int MenuContentActivator::count() const
180+{
181+ return d->m_count;
182+}
183+
184+void MenuContentActivator::setDelta(int delta)
185+{
186+ if (d->m_delta != delta) {
187+ d->m_delta = delta;
188+ Q_EMIT deltaChanged(d->m_delta);
189+ }
190+}
191+
192+int MenuContentActivator::delta() const
193+{
194+ return d->m_delta;
195+}
196+
197+QQmlListProperty<MenuContentState> MenuContentActivator::content()
198+{
199+ return QQmlListProperty<MenuContentState>(this,
200+ 0,
201+ MenuContentActivatorPrivate::content_count,
202+ MenuContentActivatorPrivate::content_at);
203+}
204+
205+void MenuContentActivator::onTimeout()
206+{
207+ bool finished = false;
208+ int tempDelta = d->findNextInactiveDelta(&finished);
209+ if (!finished) {
210+ setMenuContentState(d->m_baseIndex + tempDelta, true);
211+ setDelta(tempDelta);
212+ }
213+
214+ if (finished) {
215+ d->m_timer->stop();
216+ }
217+}
218+
219+void MenuContentActivator::setContentTimer(UnityIndicators::AbstractTimer *timer)
220+{
221+ int interval = 0;
222+ bool timerWasRunning = false;
223+
224+ // can be null when called from the constructor
225+ if (d->m_timer) {
226+ interval = d->m_timer->interval();
227+ timerWasRunning = d->m_timer->isRunning();
228+ if (d->m_timer->parent() == this) {
229+ delete d->m_timer;
230+ }
231+ }
232+
233+ d->m_timer = timer;
234+ timer->setInterval(interval);
235+ connect(timer, &UnityIndicators::AbstractTimer::timeout,
236+ this, &MenuContentActivator::onTimeout);
237+ if (timerWasRunning) {
238+ d->m_timer->start();
239+ }
240+}
241+
242+void MenuContentActivator::setMenuContentState(int index, bool active)
243+{
244+ if (d->m_content.contains(index)) {
245+ d->m_content[index]->setActive(active);
246+ } else {
247+ d->m_content[index] = new MenuContentState(active);
248+ Q_EMIT contentChanged();
249+ }
250+}
251+
252+int MenuContentActivatorPrivate::findNextInactiveDelta(bool* finished)
253+{
254+ if (m_count == 0 || m_baseIndex >= m_count) {
255+ if (finished) *finished = true;
256+ return 0;
257+ }
258+
259+ int tmpDelta = m_delta;
260+ bool topReached = false, bottomReached = false;
261+ while(true) {
262+
263+ // prechecks for bottom and top limits.
264+ if (tmpDelta > 0 && bottomReached) tmpDelta = -tmpDelta;
265+ if (tmpDelta < 0 && topReached) tmpDelta = (-tmpDelta) + 1;
266+
267+ if (tmpDelta > 0) {
268+ // negative of baseIndex
269+ tmpDelta = -tmpDelta;
270+ // reached the bottom?
271+ if (m_baseIndex + tmpDelta < 0) {
272+ bottomReached = true;
273+ // if we've reached the top as well, then we know we're done.
274+ if (topReached) {
275+ if (finished) *finished = true;
276+ return 0;
277+ }
278+ continue;
279+ }
280+ } else {
281+ // positive of baseIndex
282+ tmpDelta = (-tmpDelta) + 1;
283+ // reached the top?
284+ if (m_baseIndex + tmpDelta >= m_count) {
285+ topReached = true;
286+ // if we've reached the bottom as well, then we know we're done.
287+ if (bottomReached) {
288+ if (finished) *finished = true;
289+ return 0;
290+ }
291+ continue;
292+ }
293+ }
294+
295+ if (q->isMenuContentActive(m_baseIndex + tmpDelta)) {
296+ continue;
297+ }
298+ break;
299+ }
300+ if (finished) *finished = false;
301+ return tmpDelta;
302+}
303+
304+int MenuContentActivatorPrivate::content_count(QQmlListProperty<MenuContentState> *prop)
305+{
306+ MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
307+ // we'll create MenuContentState on demand.
308+ return p->count();
309+}
310+
311+MenuContentState* MenuContentActivatorPrivate::content_at(QQmlListProperty<MenuContentState> *prop, int index)
312+{
313+ MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
314+ MenuContentActivatorPrivate *d = p->d;
315+
316+ if (!d->m_content.contains(index)) {
317+ MenuContentState* content = new MenuContentState(false);
318+ d->m_content[index] = content;
319+ Q_EMIT p->contentChanged();
320+ return content;
321+ }
322+
323+ return d->m_content[index];
324+}
325+
326+MenuContentState::MenuContentState(bool active)
327+ : m_active(active)
328+{
329+}
330+
331+bool MenuContentState::isActive() const
332+{
333+ return m_active;
334+}
335+
336+void MenuContentState::setActive(bool active)
337+{
338+ if (m_active != active) {
339+ m_active = active;
340+ Q_EMIT activeChanged();
341+ }
342+}
343+
344+// Because we are defining a new QObject-based class (ContentTimer) here.
345+#include "menucontentactivator.moc"
plugins/Unity/Indicators/menucontentactivator.hnew file+117
@@ -0,0 +1,117 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef MENUCONTENTACTIVATOR_H
20+#define MENUCONTENTACTIVATOR_H
21+
22+#include "unityindicatorsglobal.h"
23+
24+#include <QObject>
25+#include <QTimer>
26+#include <QQmlListProperty>
27+
28+
29+namespace UnityIndicators {
30+/* Defines an interface for a Timer. */
31+class UNITYINDICATORS_EXPORT AbstractTimer : public QObject {
32+ Q_OBJECT
33+public:
34+ AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
35+ virtual int interval() const = 0;
36+ virtual void setInterval(int msecs) = 0;
37+ virtual void start() { m_isRunning = true; };
38+ virtual void stop() { m_isRunning = false; }
39+ bool isRunning() const { return m_isRunning; }
40+Q_SIGNALS:
41+ void timeout();
42+private:
43+ bool m_isRunning;
44+};
45+}
46+
47+/* Defines a object to express the active state of a menu. */
48+class UNITYINDICATORS_EXPORT MenuContentState : public QObject
49+{
50+ Q_OBJECT
51+ Q_PROPERTY(bool active READ isActive NOTIFY activeChanged)
52+public:
53+ MenuContentState(bool active);
54+
55+ bool isActive() const;
56+ void setActive(bool active);
57+
58+Q_SIGNALS:
59+ void activeChanged();
60+private:
61+ bool m_active;
62+};
63+
64+class MenuContentActivatorPrivate;
65+
66+class UNITYINDICATORS_EXPORT MenuContentActivator : public QObject
67+{
68+ Q_OBJECT
69+ Q_PROPERTY(int baseIndex READ baseIndex WRITE setBaseIndex NOTIFY baseIndexChanged)
70+ Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
71+ Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged)
72+ Q_PROPERTY(QQmlListProperty<MenuContentState> content READ content NOTIFY contentChanged DESIGNABLE false)
73+public:
74+ MenuContentActivator(QObject* parent = NULL);
75+ ~MenuContentActivator();
76+
77+ Q_INVOKABLE void restart();
78+ Q_INVOKABLE void stop();
79+ Q_INVOKABLE void clear();
80+ Q_INVOKABLE bool isMenuContentActive(int index) const;
81+
82+ void setRunning(bool running);
83+ bool isRunning() const;
84+
85+ void setBaseIndex(int index);
86+ int baseIndex() const;
87+
88+ void setCount(int index);
89+ int count() const;
90+
91+ void setDelta(int index);
92+ int delta() const;
93+
94+ QQmlListProperty<MenuContentState> content();
95+
96+ // Replaces the existing Timer with the given one.
97+ //
98+ // Useful for providing a fake timer when testing.
99+ void setContentTimer(UnityIndicators::AbstractTimer *timer);
100+ void setMenuContentState(int index, bool active);
101+
102+Q_SIGNALS:
103+ void baseIndexChanged(int baseIndex);
104+ void deltaChanged(int delta);
105+ void runningChanged(bool running);
106+ void countChanged(int count);
107+ void contentChanged();
108+
109+private Q_SLOTS:
110+ void onTimeout();
111+
112+private:
113+ MenuContentActivatorPrivate* d;
114+ friend class MenuContentActivatorPrivate;
115+};
116+
117+#endif // MENUCONTENTACTIVATOR_H
plugins/Unity/Indicators/modelprinter.cppnew file+114
@@ -0,0 +1,114 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+// self
21+#include "modelprinter.h"
22+
23+// Qt
24+#include <QTextStream>
25+
26+ModelPrinter::ModelPrinter(QObject *parent)
27+ : QObject(parent)
28+ , m_model(NULL)
29+{
30+}
31+
32+void ModelPrinter::setSourceModel(QAbstractItemModel * sourceModel)
33+{
34+ if (m_model != NULL) {
35+ disconnect(m_model);
36+ }
37+ if (m_model != sourceModel) {
38+ m_model = sourceModel;
39+ Q_EMIT modelChanged();
40+ Q_EMIT textChanged();
41+ }
42+ if (m_model != NULL) {
43+ connect(m_model, SIGNAL(modelReset()), this, SIGNAL(textChanged()));
44+ connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(textChanged()));
45+ connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(textChanged()));
46+ }
47+}
48+
49+QAbstractItemModel* ModelPrinter::sourceModel() const
50+{
51+ return m_model;
52+}
53+
54+QString ModelPrinter::text(const QModelIndex& index) const
55+{
56+ return recurseString(index, 0);
57+}
58+
59+QString tabify(int level) { QString str;
60+ for (int i = 0; i < level; i++) {
61+ str += " ";
62+ }
63+ return str;
64+}
65+
66+QString ModelPrinter::recurseString(const QModelIndex& index, int level) const
67+{
68+ if (!m_model)
69+ return "";
70+
71+ QString str;
72+ QTextStream stream(&str);
73+
74+ QHash<int, QByteArray> roleNames = m_model->roleNames();
75+ QList<int> roles = roleNames.keys();
76+ qSort(roles);
77+ Q_FOREACH(int role, roles) {
78+ QVariant vData = m_model->data(index, role);
79+ if (vData.canConvert(QMetaType::QVariantMap)) {
80+ QMapIterator<QString, QVariant> iter(vData.toMap());
81+ while (iter.hasNext()) {
82+ iter.next();
83+ stream << tabify(level)
84+ << roleNames[role]
85+ << "."
86+ << iter.key()
87+ << ": "
88+ << iter.value().toString()
89+ << endl;
90+ }
91+ }
92+ else {
93+ stream << tabify(level)
94+ << roleNames[role]
95+ << ": "
96+ << vData.toString()
97+ << endl;
98+ }
99+ }
100+
101+ int rowCount = m_model->rowCount(index);
102+ stream << tabify(level)
103+ << "child count"
104+ << ": "
105+ << rowCount
106+ << endl
107+ << endl;
108+
109+ for (int i = 0; i < rowCount; i++) {
110+ QModelIndex child = m_model->index(i, 0, index);
111+ str += recurseString(child, level+1);
112+ }
113+ return str;
114+}
plugins/Unity/Indicators/modelprinter.hnew file+50
@@ -0,0 +1,50 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#ifndef MODELPRINTER_H
21+#define MODELPRINTER_H
22+
23+#include <QSortFilterProxyModel>
24+
25+// This class acts as a namespace only, with the addition that its enums
26+// are registered to be exposed on the QML side.
27+class ModelPrinter : public QObject
28+{
29+ Q_OBJECT
30+
31+ Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY modelChanged)
32+ Q_PROPERTY(QString text READ text NOTIFY textChanged)
33+public:
34+ ModelPrinter(QObject* parent=0);
35+
36+ void setSourceModel(QAbstractItemModel* sourceModel);
37+ QAbstractItemModel* sourceModel() const;
38+
39+ Q_INVOKABLE QString text(const QModelIndex& index = QModelIndex()) const;
40+
41+Q_SIGNALS:
42+ void modelChanged();
43+ void textChanged();
44+
45+private:
46+ QString recurseString(const QModelIndex& index, int level) const;
47+ QAbstractItemModel* m_model;
48+};
49+
50+#endif // MODELPRINTER_H
plugins/Unity/Indicators/plugin.cpp+5
@@ -27,6 +27,8 @@
2727#include "indicatorsmanager.h"
2828#include "indicatorsmodel.h"
2929#include "indicators.h"
30+#include "menucontentactivator.h"
31+#include "modelprinter.h"
3032
3133void IndicatorsPlugin::registerTypes(const char *uri)
3234{
@@ -35,7 +37,10 @@ void IndicatorsPlugin::registerTypes(const char *uri)
3537 qmlRegisterType<IndicatorsManager>(uri, 0, 1, "IndicatorsManager");
3638 qmlRegisterType<FlatMenuProxyModel>(uri, 0, 1, "FlatMenuProxyModel");
3739 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
40+ qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
41+ qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
3842
43+ qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
3944 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
4045 qmlRegisterUncreatableType<NetworkActionState>(uri, 0, 1, "NetworkActionState", "Can't create NetworkActionState class");
4146 qmlRegisterUncreatableType<NetworkConnection>(uri, 0, 1, "NetworkConnection", "Can't create NetworkConnection class");
plugins/Unity/Indicators/qml/CMakeLists.txt+4−13
@@ -1,14 +1,5 @@
1−file(GLOB Indicators_QMLFILES
2− *.qml
3− qmldir
4−)
1+# export_qmlplugin macro
2+include(Plugins)
53
6−# copy qml & qmldir files into build directory for shadow builds
7−add_custom_target(UnityIndicatorsQmlFiles ALL
8− COMMAND cp ${Indicators_QMLFILES} ${CMAKE_BINARY_DIR}/plugins/Unity/Indicators
9− DEPENDS ${Indicators_QMLFILES}
10−)
11−
12−install(FILES ${Indicators_QMLFILES}
13− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity/Indicators
14−)
4+# export the qmldir, *.qml files.
5+export_qmlfiles(Unity.Indicators Unity/Indicators)
plugins/Unity/Indicators/qml/IndicatorPage.qml−6
@@ -188,10 +188,4 @@ IndicatorBase {
188188 mainMenu.currentIndex = -1;
189189 mainMenu.positionViewAtBeginning();
190190 }
191−
192− Component.onCompleted: {
193− if ((busType != 0) && (busName != "") && (deviceMenuObjectPath != "")) {
194− start();
195− }
196− }
197191}
plugins/Unity/Indicators/qml/qmldir+1
@@ -1,5 +1,6 @@
11module Unity.Indicators
22plugin IndicatorsQml
3+typeinfo plugin.qmltypes
34
45BasicMenuItem 0.1 BasicMenuItem.qml
56ButtonMenuItem 0.1 ButtonMenuItem.qml
plugins/Unity/Indicators/unityindicatorsglobal.hnew file+23
@@ -0,0 +1,23 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QtCore/QtGlobal>
18+
19+#if defined(UNITYINDICATORS_LIBRARY)
20+# define UNITYINDICATORS_EXPORT Q_DECL_EXPORT
21+#else
22+# define UNITYINDICATORS_EXPORT Q_DECL_IMPORT
23+#endif
plugins/Unity/Launcher/CMakeLists.txt+1
@@ -24,4 +24,5 @@ add_library(UnityLauncher-qml MODULE
2424qt5_use_modules(UnityLauncher-qml Qml)
2525
2626# export the qmldir and qmltypes files
27+export_qmlfiles(Unity.Launcher Unity/Launcher)
2728export_qmlplugin(Unity.Launcher 0.1 Unity/Launcher TARGETS UnityLauncher-qml)
plugins/Unity/Launcher/backend/launcherbackend.cpp+3−3
@@ -37,7 +37,7 @@ LauncherBackend::LauncherBackend(QObject *parent):
3737 QLatin1String("gmail-webapp.desktop") <<
3838 QLatin1String("ubuntu-weather-app.desktop") <<
3939 QLatin1String("notes-app.desktop") <<
40− QLatin1String("ubuntu-calendar-app.desktop");
40+ QLatin1String("calendar-app.desktop");
4141
4242 // TODO: get stuff from desktop files instead this hardcoded map
4343 m_displayNameMap.insert("phone-app.desktop", "Phone");
@@ -49,7 +49,7 @@ LauncherBackend::LauncherBackend(QObject *parent):
4949 m_displayNameMap.insert("gmail-webapp.desktop", "GMail");
5050 m_displayNameMap.insert("ubuntu-weather-app.desktop", "Weather");
5151 m_displayNameMap.insert("notes-app.desktop", "Notes");
52− m_displayNameMap.insert("ubuntu-calendar-app.desktop", "Calendar");
52+ m_displayNameMap.insert("calendar-app.desktop", "Calendar");
5353
5454 // TODO: get stuff from desktop files instead this hardcoded map
5555 m_iconMap.insert("phone-app.desktop", "phone-app");
@@ -61,7 +61,7 @@ LauncherBackend::LauncherBackend(QObject *parent):
6161 m_iconMap.insert("gmail-webapp.desktop", "gmail");
6262 m_iconMap.insert("ubuntu-weather-app.desktop", "weather");
6363 m_iconMap.insert("notes-app.desktop", "notepad");
64− m_iconMap.insert("ubuntu-calendar-app.desktop", "calendar");
64+ m_iconMap.insert("calendar-app.desktop", "calendar");
6565
6666}
6767
plugins/Unity/Launcher/qmldir+1
@@ -1,2 +1,3 @@
11module Unity.Launcher
22plugin UnityLauncher-qml
3+typeinfo plugin.qmltypes
plugins/Unity/categories.cpp+6−3
@@ -34,7 +34,7 @@ enum CategoryColumn {
3434Categories::Categories(QObject* parent)
3535 : DeeListModel(parent)
3636{
37− m_roles[Categories::RoleId] = "id";
37+ m_roles[Categories::RoleCategoryId] = "categoryId";
3838 m_roles[Categories::RoleName] = "name";
3939 m_roles[Categories::RoleIcon] = "icon";
4040 m_roles[Categories::RoleRenderer] = "renderer";
@@ -42,6 +42,7 @@ Categories::Categories(QObject* parent)
4242 m_roles[Categories::RoleHints] = "hints";
4343 m_roles[Categories::RoleResults] = "results";
4444 m_roles[Categories::RoleCount] = "count";
45+ m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
4546
4647 // TODO This should not be needed but accumulatting the count changes
4748 // makes the visualization more stable and also makes crashes on fast
@@ -130,8 +131,8 @@ Categories::data(const QModelIndex& index, int role) const
130131 }
131132
132133 switch (role) {
133− case RoleId:
134− return QVariant::fromValue(index.row());
134+ case RoleCategoryId:
135+ return DeeListModel::data(index, CategoryColumn::ID);
135136 case RoleName:
136137 return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
137138 case RoleIcon:
@@ -149,6 +150,8 @@ Categories::data(const QModelIndex& index, int role) const
149150 return QVariant::fromValue(getResults(index.row()));
150151 case RoleCount:
151152 return QVariant::fromValue(getResults(index.row())->rowCount());
153+ case RoleCategoryIndex:
154+ return QVariant::fromValue(index.row());
152155 default:
153156 return QVariant();
154157 }
plugins/Unity/categories.h+3−2
@@ -42,14 +42,15 @@ public:
4242 explicit Categories(QObject* parent = 0);
4343
4444 enum Roles {
45− RoleId,
45+ RoleCategoryId,
4646 RoleName,
4747 RoleIcon,
4848 RoleRenderer,
4949 RoleContentType,
5050 RoleHints,
5151 RoleResults,
52− RoleCount
52+ RoleCount,
53+ RoleCategoryIndex
5354 };
5455
5556 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
plugins/Unity/previewinfohint.cpp+2−2
@@ -17,9 +17,9 @@
1717 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20+#include <deelistmodel.h>
2021// local
2122#include "previewinfohint.h"
22−#include "variantutils.h"
2323
2424PreviewInfoHint::PreviewInfoHint(QObject *parent):
2525 QObject(parent),
@@ -61,7 +61,7 @@ QString PreviewInfoHint::iconHint() const
6161QVariant PreviewInfoHint::value() const
6262{
6363 if (m_unityInfoHint) {
64− return QVariantFromGVariant(m_unityInfoHint->value);
64+ return DeeListModel::VariantForData(m_unityInfoHint->value);
6565 }
6666 return QVariant();
6767}
plugins/Unity/scope.h−3
@@ -29,9 +29,6 @@
2929#include <UnityCore/Scope.h>
3030#include <UnityCore/Results.h>
3131
32−// dee-qt
33−#include "deelistmodel.h"
34−
3532#include "categories.h"
3633#include "filters.h"
3734
plugins/Unity/variantutils.cpp+2−118
@@ -17,131 +17,15 @@
1717 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20+#include <deelistmodel.h>
2021#include "variantutils.h"
2122
22−/* Returns floating ref */
23−GVariant* GVariantFromQVariant(const QVariant &var)
24−{
25− GVariant *gv = nullptr;
26−
27− switch (var.type()) {
28− case QVariant::String:
29− gv = g_variant_new_string(var.toString().toUtf8());
30− break;
31− case QVariant::UInt:
32− gv = g_variant_new_uint32(var.toUInt());
33− break;
34− case QVariant::Int:
35− gv = g_variant_new_int32(var.toInt());
36− break;
37− case QVariant::LongLong:
38− gv = g_variant_new_int64(var.toLongLong());
39− break;
40− case QVariant::ULongLong:
41− gv = g_variant_new_uint64(var.toULongLong());
42− break;
43− case QVariant::Double:
44− gv = g_variant_new_double(var.toDouble());
45− break;
46− case QVariant::Bool:
47− gv = g_variant_new_boolean(var.toBool());
48− break;
49− case QVariant::Hash: {
50− const auto hash = var.toHash();
51− GVariant **children = new GVariant*[hash.size()];
52− int cnt = 0;
53− QHash<QString, QVariant>::const_iterator it = hash.constBegin();
54− while (it != hash.constEnd()) {
55− GVariant *key = g_variant_new_string(it.key().toUtf8());
56− children[cnt++] = g_variant_new_dict_entry(key, g_variant_new_variant(GVariantFromQVariant(it.value())));
57− ++it;
58− }
59− gv = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, hash.size());
60− delete [] children;
61− break;
62− }
63− default:
64− break;
65− }
66− return gv;
67−}
68−
69−// implementation of this conversion taken from libdee-qt private utility function.
70−QVariant QVariantFromGVariant(GVariant *value)
71−{
72− /* We need to special-case a{sv} here as G_VARIANT_CLASS_ARRAY handles simple arrays;
73− we need to create QVariantHash, not a list */
74− if (g_variant_is_of_type(value, G_VARIANT_TYPE_VARDICT)) {
75− const gsize nChildren = g_variant_n_children(value);
76− QVariantHash hash;
77− for (gsize i = 0; i < nChildren; ++i)
78− {
79− GVariant* dict_entry = g_variant_get_child_value(value, i);
80−
81− gchar* dict_key;
82− GVariant *dict_var;
83− g_variant_get(dict_entry, "{&sv}", &dict_key, &dict_var);
84− hash.insert(QString::fromUtf8(dict_key), QVariantFromGVariant(dict_var));
85− g_variant_unref(dict_var);
86− g_variant_unref(dict_entry);
87− }
88− return hash;
89− }
90−
91− switch (g_variant_classify(value)) {
92− case G_VARIANT_CLASS_BOOLEAN:
93− return QVariant((bool) g_variant_get_boolean(value));
94− case G_VARIANT_CLASS_BYTE:
95− return QVariant((uchar) g_variant_get_byte(value));
96− case G_VARIANT_CLASS_INT16:
97− return QVariant((qint16) g_variant_get_int16(value));
98− case G_VARIANT_CLASS_UINT16:
99− return QVariant((quint16) g_variant_get_uint16(value));
100− case G_VARIANT_CLASS_INT32:
101− return QVariant((qint32) g_variant_get_int32(value));
102− case G_VARIANT_CLASS_UINT32:
103− return QVariant((quint32) g_variant_get_uint32(value));
104− case G_VARIANT_CLASS_INT64:
105− return QVariant((qint64) g_variant_get_int64(value));
106− case G_VARIANT_CLASS_UINT64:
107− return QVariant((quint64) g_variant_get_uint64(value));
108− case G_VARIANT_CLASS_DOUBLE:
109− return QVariant(g_variant_get_double(value));
110− case G_VARIANT_CLASS_STRING:
111− return QVariant(QString::fromUtf8(g_variant_get_string(value, NULL)));
112− case G_VARIANT_CLASS_ARRAY:
113− case G_VARIANT_CLASS_TUPLE:
114− {
115− const gsize nChildren = g_variant_n_children(value);
116− QList<QVariant> array;
117− for (gsize i = 0; i < nChildren; ++i)
118− {
119− GVariant* gvariant = g_variant_get_child_value(value, i);
120− array << QVariantFromGVariant(gvariant);
121− g_variant_unref(gvariant);
122− }
123− return array;
124− }
125− default:
126− /* Fallback on an empty QVariant.
127− FIXME: Missing conversion of following GVariant types:
128− - G_VARIANT_CLASS_HANDLE
129− - G_VARIANT_CLASS_OBJECT_PATH
130− - G_VARIANT_CLASS_SIGNATURE
131− - G_VARIANT_CLASS_VARIANT
132− - G_VARIANT_CLASS_MAYBE
133− - G_VARIANT_CLASS_DICT_ENTRY
134− */
135− return QVariant();
136− }
137−}
138−
13923unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val)
14024{
14125 unity::glib::HintsMap hintsMap;
14226 QHash<QString, QVariant>::const_iterator it = val.constBegin();
14327 while (it != val.constEnd()) {
144− hintsMap[it.key().toStdString()] = GVariantFromQVariant(it.value());
28+ hintsMap[it.key().toStdString()] = DeeListModel::DataFromVariant(it.value());
14529 ++it;
14630 }
14731 return hintsMap;
plugins/Unity/variantutils.h−2
@@ -26,8 +26,6 @@
2626// libunity-core
2727#include <UnityCore/Variant.h>
2828
29−GVariant* GVariantFromQVariant(const QVariant &value);
30−QVariant QVariantFromGVariant(GVariant *value);
3129unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
3230unity::glib::HintsMap convertToHintsMap(const QVariant &var);
3331
plugins/Utils/CMakeLists.txt+2−1
@@ -23,5 +23,6 @@ set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default)
2323
2424qt5_use_modules(Utils-qml Qml Quick)
2525
26−# export the qmldir and qmltypes files
26+# export the qmldir qmltypes and plugin files
27+export_qmlfiles(Utils Utils)
2728export_qmlplugin(Utils 0.1 Utils TARGETS Utils-qml)
po/ar.po+3−27
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-22 16:15+0000\n"
11+"PO-Revision-Date: 2013-06-26 23:26+0000\n"
1212"Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n"
1313"Language-Team: Arabic <ar@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,27 +218,3 @@ msgstr "عذراً، لا يوجد ما يطابق بحثك."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "أشخاص"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "الشاشة الرئيسية"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "الأشخاص المفضلون"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "أشخاص كانوا على اتصال مؤخرا"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "A-Z"
236−
237−#~ msgid "Recently in touch"
238−#~ msgstr "على اتصال موخرا"
239−
240−#~ msgid "New Contacts"
241−#~ msgstr "أشخاص جدد"
242−
243−#~ msgid "Favourites"
244−#~ msgstr "المفضلات"
po/az.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-26 23:48+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Azerbaijani <az@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Bağışlayın, amma axtarışınıza heç bir nəticə uyğun gəlmir."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "İnsanlar"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Əsas Ekran"
po/bg.po+3−15
@@ -8,15 +8,15 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-19 15:47+0000\n"
11+"PO-Revision-Date: 2013-06-27 00:06+0000\n"
1212"Last-Translator: Miroslav E. Hadzhiev (Хаджиев) "
1313"<miroslav.hadzhiev@gmail.com>\n"
1414"Language-Team: Bulgarian <bg@li.org>\n"
1515"MIME-Version: 1.0\n"
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
18−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
19−"X-Generator: Launchpad (build 16681)\n"
18+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
19+"X-Generator: Launchpad (build 16723)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -219,15 +219,3 @@ msgstr "Съжаляваме, няма нищо, което да отговар
219219#, qt-format
220220msgid "Please enter %1"
221221msgstr ""
222−
223−#~ msgid "Favourites"
224−#~ msgstr "Любими"
225−
226−#~ msgid "People"
227−#~ msgstr "Хора"
228−
229−#~ msgid "A-Z"
230−#~ msgstr "А-Я"
231−
232−#~ msgid "Home screen"
233−#~ msgstr "Начален екран"
po/ca.po+4−16
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 00:24+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Catalan <ca@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,15 +218,3 @@ msgstr "No hi ha res que coincideixi amb la cerca"
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Gent"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Pantalla d'inici"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Gent preferida"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "Gent amb qui heu parlat"
po/de.po+5−29
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-29 12:53+0000\n"
12−"Last-Translator: Phillip Sz <Unknown>\n"
11+"PO-Revision-Date: 2013-06-27 00:37+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: German <de@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18−"X-Generator: Launchpad (build 16692)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -217,28 +217,4 @@ msgstr "Entschuldigung, es wurden keine Treffer erzielt."
217217#: Shell.qml:383
218218#, qt-format
219219msgid "Please enter %1"
220−msgstr "Bitte geben Sie %1 ein"
221−
222−#~ msgid "People"
223−#~ msgstr "Personen"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Startseite"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Lieblingspersonen"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "Zuletzt kontaktierte Personen"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "A-Z"
236−
237−#~ msgid "Recently in touch"
238−#~ msgstr "Kürzlich im Gespräch"
239−
240−#~ msgid "New Contacts"
241−#~ msgstr "Neue Kontakte"
242−
243−#~ msgid "Favourites"
244−#~ msgstr "Favoriten"
220+msgstr ""
po/el.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 00:53+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Greek <el@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Λυπούμαστε, δεν υπάρχει τίποτα που να τ
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Πρόσωπα"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Αρχική οθόνη"
po/en_AU.po+3−27
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-18 20:36+0000\n"
11+"PO-Revision-Date: 2013-06-27 01:13+0000\n"
1212"Last-Translator: Jackson Doak <Doak.jackson@gmail.com>\n"
1313"Language-Team: English (Australia) <en_AU@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,27 +218,3 @@ msgstr "Sorry, there is nothing that matches your search."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "People"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Home screen"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Favourite People"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "People Recently in Touch"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "A-Z"
236−
237−#~ msgid "Recently in touch"
238−#~ msgstr "Recently in touch"
239−
240−#~ msgid "New Contacts"
241−#~ msgstr "New Contacts"
242−
243−#~ msgid "Favourites"
244−#~ msgstr "Favourites"
po/en_GB.po+4−28
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-27 00:22+0000\n"
12−"Last-Translator: Andi Chandler <Unknown>\n"
11+"PO-Revision-Date: 2013-06-27 08:53+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,27 +218,3 @@ msgstr "Sorry, there is nothing that matches your search."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr "Please enter %1"
221−
222−#~ msgid "Favourite People"
223−#~ msgstr "Favourite People"
224−
225−#~ msgid "People Recently in Touch"
226−#~ msgstr "People Recently in Touch"
227−
228−#~ msgid "People"
229−#~ msgstr "People"
230−
231−#~ msgid "A-Z"
232−#~ msgstr "A-Z"
233−
234−#~ msgid "Recently in touch"
235−#~ msgstr "Recently in touch"
236−
237−#~ msgid "New Contacts"
238−#~ msgstr "New Contacts"
239−
240−#~ msgid "Favourites"
241−#~ msgstr "Favourites"
242−
243−#~ msgid "Home screen"
244−#~ msgstr "Home screen"
po/eo.po+3−3
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
11+"PO-Revision-Date: 2013-06-26 22:35+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Esperanto <eo@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/es.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-09 06:13+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/fi.po+4−25
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-10 16:19+0000\n"
12−"Last-Translator: Jiri Grönroos <Unknown>\n"
11+"PO-Revision-Date: 2013-06-27 02:43+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Finnish <fi@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,24 +218,3 @@ msgstr "Hakuun täsmääviä tuloksia ei löydy."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Ihmiset"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Kotinäyttö"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Suosikkihenkilöt"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "Viimeksi yhteydessä olleet henkilöt"
233−
234−#~ msgid "Favourites"
235−#~ msgstr "Suosikit"
236−
237−#~ msgid "Recently in touch"
238−#~ msgstr "Viimeksi yhteydessä"
239−
240−#~ msgid "New Contacts"
241−#~ msgstr "Uudet yhteystiedot"
po/fo.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 02:57+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Faroese <fo@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Tíanverri er tað einki sum hóskar til tína leiting."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Fólk"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Heimaskíggi"
po/fr.po+40−61
@@ -8,62 +8,62 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-26 15:11+0000\n"
12−"Last-Translator: Anne <anneonyme017@gmail.com>\n"
11+"PO-Revision-Date: 2013-06-27 03:21+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.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"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
22−msgstr "Téléphone"
22+msgstr ""
2323
2424#: Applications/applications.js:29
2525msgid "Camera"
26−msgstr "Appareil photo"
26+msgstr ""
2727
2828#: Applications/applications.js:35
2929msgid "Gallery"
30−msgstr "Galerie"
30+msgstr ""
3131
3232#: Applications/applications.js:40
3333msgid "Facebook"
34−msgstr "Facebook"
34+msgstr ""
3535
3636#: Applications/applications.js:46
3737msgid "Browser"
38−msgstr "Navigateur"
38+msgstr ""
3939
4040#: Applications/applications.js:51
4141msgid "Twitter"
42−msgstr "Twitter"
42+msgstr ""
4343
4444#: Applications/applications.js:57
4545msgid "GMail"
46−msgstr "GMail"
46+msgstr ""
4747
4848#: Applications/applications.js:62
4949msgid "Weather"
50−msgstr "Météo"
50+msgstr ""
5151
5252#: Applications/applications.js:68
5353msgid "Notepad"
54−msgstr "Bloc-notes"
54+msgstr ""
5555
5656#: Applications/applications.js:74
5757msgid "Calendar"
58−msgstr "Agenda"
58+msgstr ""
5959
6060#: Applications/applications.js:80
6161msgid "Media Player"
62−msgstr "Lecteur multimédia"
62+msgstr ""
6363
6464#: Applications/applications.js:86
6565msgid "Evernote"
66−msgstr "Evernote"
66+msgstr ""
6767
6868#: Applications/applications.js:91
6969msgid "Map"
@@ -71,27 +71,27 @@ msgstr ""
7171
7272#: Applications/applications.js:96
7373msgid "Pinterest"
74−msgstr "Pinterest"
74+msgstr ""
7575
7676#: Applications/applications.js:101
7777msgid "SoundCloud"
78−msgstr "SoundCloud"
78+msgstr ""
7979
8080#: Applications/applications.js:106
8181msgid "Wikipedia"
82−msgstr "Wikipédia"
82+msgstr ""
8383
8484#: Applications/applications.js:111
8585msgid "YouTube"
86−msgstr "YouTube"
86+msgstr ""
8787
8888#: Components/PageHeader.qml:300
8989msgid "Recent searches"
90−msgstr "Recherches récentes"
90+msgstr ""
9191
9292#: Dash/DashApps.qml:65
9393msgid "Running apps"
94−msgstr "Applications en cours d’exécution"
94+msgstr ""
9595
9696#: Dash/DashApps.qml:68
9797msgid "Frequently used"
@@ -99,7 +99,7 @@ msgstr ""
9999
100100#: Dash/DashApps.qml:71
101101msgid "Installed"
102−msgstr "Installées"
102+msgstr ""
103103
104104#: Dash/DashApps.qml:74
105105msgid "Available for download"
@@ -111,19 +111,19 @@ msgstr "Applications"
111111
112112#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114−msgstr "Applications fréquemment utilisées"
114+msgstr ""
115115
116116#: Dash/DashHome.qml:43
117117msgid "Recent Music"
118−msgstr "Musique récente"
118+msgstr ""
119119
120120#: Dash/DashHome.qml:46
121121msgid "Videos Popular Online"
122−msgstr "Vidéos populaires en ligne"
122+msgstr ""
123123
124124#: Dash/DashHome.qml:175
125125msgid "Home"
126−msgstr "Accueil"
126+msgstr ""
127127
128128#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
129129msgid "Featured"
@@ -135,7 +135,7 @@ msgstr ""
135135
136136#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
137137msgid "New Releases"
138−msgstr "Nouveautés"
138+msgstr ""
139139
140140#: Dash/DashMusic.qml:30
141141msgid "Top Charting"
@@ -155,15 +155,15 @@ msgstr "Vidéos"
155155
156156#: Dash/Video/VideoPreview.qml:98
157157msgid "Directed by:"
158−msgstr "Réalisé par :"
158+msgstr ""
159159
160160#: Dash/Video/VideoPreview.qml:121
161161msgid "Starring:"
162−msgstr "Acteurs :"
162+msgstr ""
163163
164164#: Dash/Video/VideoPreview.qml:144
165165msgid "Author:"
166−msgstr "Auteur :"
166+msgstr ""
167167
168168#: Greeter/Lockscreen.qml:133
169169msgid "Emergency call"
@@ -172,27 +172,27 @@ msgstr ""
172172#: Greeter/PassphraseLockscreen.qml:59
173173#, qt-format
174174msgid "Hello %1"
175−msgstr "Bonjour %1"
175+msgstr ""
176176
177177#: Greeter/PassphraseLockscreen.qml:59
178178msgid "Hello"
179−msgstr "Bonjour"
179+msgstr ""
180180
181181#: Hud/HudParametrizedActionsPage.qml:132
182182msgid "Confirm"
183−msgstr "Confirmer"
183+msgstr ""
184184
185185#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
186186msgid "Type or say a command"
187−msgstr "Entrez ou dictez une commande"
187+msgstr ""
188188
189189#: Hud/Hud.qml:84
190190msgid "Loading. Please Wait..."
191−msgstr "Chargement. Veuillez patienter..."
191+msgstr ""
192192
193193#: Hud/Hud.qml:89
194194msgid "Speak Now..."
195−msgstr "Parlez maintenant..."
195+msgstr ""
196196
197197#: Hud/Hud.qml:94
198198msgid "Speaking..."
@@ -204,38 +204,17 @@ msgstr ""
204204
205205#: Panel/Menus/Overview/FlightModeWidget.qml:42
206206msgid "Flight mode"
207−msgstr "Mode avion"
207+msgstr ""
208208
209209#: Panel/SearchIndicator.qml:26
210210msgid "Search"
211−msgstr "Rechercher"
211+msgstr ""
212212
213213#: plugins/Unity/scope.cpp:268
214214msgid "Sorry, there is nothing that matches your search."
215−msgstr "Désolé, aucun résultat ne correspond à votre recherche."
215+msgstr ""
216216
217217#: Shell.qml:383
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "Home screen"
223−#~ msgstr "Écran d’accueil"
224−
225−#~ msgid "People"
226−#~ msgstr "Contacts"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Contacts favoris"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "Contacts récents"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "A-Z"
236−
237−#~ msgid "New Contacts"
238−#~ msgstr "Nouveaux contacts"
239−
240−#~ msgid "Favourites"
241−#~ msgstr "Favoris"
po/gl.po+4−16
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 03:38+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Galician <gl@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,15 +218,3 @@ msgstr "Sentímolo, non hai nada que coincida con esta busca."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Persoas"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Pantalla de inicio"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Xente favorita"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "Xente contactada recentemente"
po/he.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 03:54+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Hebrew <he@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "שום דבר אינו תואם לחיפוש שלך, עמך הסליחה
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "אנשים"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "מסך הבית"
po/hr.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 04:14+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Croatian <hr@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Nažalost, ne postoji ništa što odgovara vašoj pretrazi."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Osobe"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Početni zaslon"
po/hu.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 04:28+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Hungarian <hu@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Elnézést, nincs találat a keresésre."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Emberek"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Kezdőképernyő"
po/hy.po+3−15
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-07 12:42+0000\n"
11+"PO-Revision-Date: 2013-06-27 04:43+0000\n"
1212"Last-Translator: iAbaS <sosabazyan@yandex.ru>\n"
1313"Language-Team: Armenian <hy@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,15 +218,3 @@ msgstr "Կներերք, բայց Ձեր հարցումով ոչինչ չկար"
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People Recently in Touch"
223−#~ msgstr "Վերջին մարդիկ"
224−
225−#~ msgid "Favourite People"
226−#~ msgstr "Ֆավորիտներ"
227−
228−#~ msgid "People"
229−#~ msgstr "Մարդիկ"
230−
231−#~ msgid "Home screen"
232−#~ msgstr "Տուն"
po/id.po+3−3
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
11+"PO-Revision-Date: 2013-06-26 22:35+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Indonesian <id@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/it.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 05:14+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Italian <it@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Nessun risultato corrispondente alla ricerca."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Contatti"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Home"
po/ja.po+3−3
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-15 14:12+0000\n"
11+"PO-Revision-Date: 2013-06-26 22:36+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Japanese <ja@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/kn.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 05:43+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Kannada <kn@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "ಕ್ಷಮಿಸಿ ನಿಮ್ಮ ಶೋಧನೆಗೆ ಸರಿಯ
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "ಜನರು"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "ಹೋಮ್ ಸ್ಕ್ರೀನ್"
po/ko.po+4−4
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 05:59+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Korean <ko@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ky.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 06:17+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Kirghiz <ky@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Тилекке каршы, сиздин издөөңүзгө эч нер
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Адамдар"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Башкы экран"
po/lv.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 06:31+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Latvian <lv@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Diemžēl nekas neatbilst jūsu meklētajam."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Cilvēki"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Mājas ekrāns"
po/my.po+4−7
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 06:47+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Burmese <my@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,6 +218,3 @@ msgstr "ဆောရီး၊ သင်၏ရှာဖွေမူနှင့
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "လူ"
po/nb.po+3−9
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-17 09:10+0000\n"
11+"PO-Revision-Date: 2013-06-27 07:02+0000\n"
1212"Last-Translator: Joakim Langvand <jlangvand@gmail.com>\n"
1313"Language-Team: Norwegian Bokmal <nb@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Søket ga ingen treff."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Personer"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Hjemmeskjerm"
po/nl.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 07:19+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Dutch <nl@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Er is helaas niets dat met uw zoekopdracht overeenkomt."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Mensen"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Startscherm"
po/pl.po+8−32
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:43+0000\n"
12−"Last-Translator: Piotr Merski <Unknown>\n"
11+"PO-Revision-Date: 2013-06-27 08:52+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Polish <pl@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -167,16 +167,16 @@ msgstr "Autor:"
167167
168168#: Greeter/Lockscreen.qml:133
169169msgid "Emergency call"
170−msgstr ""
170+msgstr "Telefon alarmowy"
171171
172172#: Greeter/PassphraseLockscreen.qml:59
173173#, qt-format
174174msgid "Hello %1"
175−msgstr ""
175+msgstr "Witaj %1"
176176
177177#: Greeter/PassphraseLockscreen.qml:59
178178msgid "Hello"
179−msgstr ""
179+msgstr "Witaj"
180180
181181#: Hud/HudParametrizedActionsPage.qml:132
182182msgid "Confirm"
@@ -217,28 +217,4 @@ msgstr "Nie znaleziono pasujących wyników."
217217#: Shell.qml:383
218218#, qt-format
219219msgid "Please enter %1"
220−msgstr ""
221−
222−#~ msgid "Home screen"
223−#~ msgstr "Ekran domowy"
224−
225−#~ msgid "People"
226−#~ msgstr "Ludzie"
227−
228−#~ msgid "People Recently in Touch"
229−#~ msgstr "Osoby ostatnio w kontakcie"
230−
231−#~ msgid "Favourite People"
232−#~ msgstr "Ulubione kontakty"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "A-Z"
236−
237−#~ msgid "Recently in touch"
238−#~ msgstr "Ostatnio w kontakcie"
239−
240−#~ msgid "New Contacts"
241−#~ msgstr "Nowe kontakty"
242−
243−#~ msgid "Favourites"
244−#~ msgstr "Ulubione"
220+msgstr "Wprowadź %1"
po/pt_BR.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 07:39+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Desculpe, não há nada que corresponda à sua pesquisa."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Pessoas"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Tela inicial"
po/ro.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 07:53+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Romanian <ro@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -219,9 +219,3 @@ msgstr ""
219219#, qt-format
220220msgid "Please enter %1"
221221msgstr ""
222−
223−#~ msgid "People"
224−#~ msgstr "Persoane"
225−
226−#~ msgid "Home screen"
227−#~ msgstr "Ecran principal"
po/ru.po+22−37
@@ -8,58 +8,58 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-21 10:08+0000\n"
12−"Last-Translator: Andrey Dedikov <iamawesome.ndr@gmail.com>\n"
11+"PO-Revision-Date: 2013-06-28 06:40+0000\n"
12+"Last-Translator: Eugene Marshal <Unknown>\n"
1313"Language-Team: Russian <ru@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
22−msgstr ""
22+msgstr "Телефон"
2323
2424#: Applications/applications.js:29
2525msgid "Camera"
26−msgstr ""
26+msgstr "Камера"
2727
2828#: Applications/applications.js:35
2929msgid "Gallery"
30−msgstr ""
30+msgstr "Галерея"
3131
3232#: Applications/applications.js:40
3333msgid "Facebook"
34−msgstr ""
34+msgstr "Facebook"
3535
3636#: Applications/applications.js:46
3737msgid "Browser"
38−msgstr ""
38+msgstr "Обозреватель"
3939
4040#: Applications/applications.js:51
4141msgid "Twitter"
42−msgstr ""
42+msgstr "Twitter"
4343
4444#: Applications/applications.js:57
4545msgid "GMail"
46−msgstr ""
46+msgstr "GMail"
4747
4848#: Applications/applications.js:62
4949msgid "Weather"
50−msgstr ""
50+msgstr "Погода"
5151
5252#: Applications/applications.js:68
5353msgid "Notepad"
54−msgstr ""
54+msgstr "Блокнот"
5555
5656#: Applications/applications.js:74
5757msgid "Calendar"
58−msgstr ""
58+msgstr "Календарь"
5959
6060#: Applications/applications.js:80
6161msgid "Media Player"
62−msgstr ""
62+msgstr "Медиапроигрыватель"
6363
6464#: Applications/applications.js:86
6565msgid "Evernote"
@@ -67,7 +67,7 @@ msgstr "Evernote"
6767
6868#: Applications/applications.js:91
6969msgid "Map"
70−msgstr ""
70+msgstr "Карта"
7171
7272#: Applications/applications.js:96
7373msgid "Pinterest"
@@ -79,11 +79,11 @@ msgstr "SoundCloud"
7979
8080#: Applications/applications.js:106
8181msgid "Wikipedia"
82−msgstr ""
82+msgstr "Википедия"
8383
8484#: Applications/applications.js:111
8585msgid "YouTube"
86−msgstr ""
86+msgstr "YouTube"
8787
8888#: Components/PageHeader.qml:300
8989msgid "Recent searches"
@@ -131,7 +131,7 @@ msgstr ""
131131
132132#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
133133msgid "Recent"
134−msgstr ""
134+msgstr "Недавние"
135135
136136#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
137137msgid "New Releases"
@@ -163,11 +163,11 @@ msgstr "В главных ролях"
163163
164164#: Dash/Video/VideoPreview.qml:144
165165msgid "Author:"
166−msgstr ""
166+msgstr "Автор:"
167167
168168#: Greeter/Lockscreen.qml:133
169169msgid "Emergency call"
170−msgstr ""
170+msgstr "Экстренный вызов"
171171
172172#: Greeter/PassphraseLockscreen.qml:59
173173#, qt-format
@@ -217,19 +217,4 @@ msgstr "Извините, поиск не дал результатов."
217217#: Shell.qml:383
218218#, qt-format
219219msgid "Please enter %1"
220−msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Люди"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Главный экран"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Избранные контакты"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "Недавние контакты"
233−
234−#~ msgid "New Contacts"
235−#~ msgstr "Новые контакты"
220+msgstr "Пожалуйста, введите %1"
po/si.po+3−3
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
11+"PO-Revision-Date: 2013-06-26 22:36+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Sinhalese <si@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/sl.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-06 08:44+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/sr.po+4−10
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 09:19+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Serbian <sr@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,9 +218,3 @@ msgstr "Нажалост, претрага није наишла на икакв
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Људи"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Почетни екран"
po/sv.po+3−3
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
11+"PO-Revision-Date: 2013-06-26 22:36+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Swedish <sv@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/te.po+4−4
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 09:57+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Telugu <te@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/tr.po+3−24
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-24 17:24+0000\n"
11+"PO-Revision-Date: 2013-06-27 10:08+0000\n"
1212"Last-Translator: Adar Cem EREN <adarcemeren34@gmail.com>\n"
1313"Language-Team: Turkish <tr@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,24 +218,3 @@ msgstr "Üzgünüz, aramanızla eşleşen hiçbir şey yok."
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "Kişiler"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Başlangıç ekranı"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Favori Kişiler"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "En Son Konuşulan Kişiler"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "A-Z"
236−
237−#~ msgid "New Contacts"
238−#~ msgstr "Yeni Kişiler"
239−
240−#~ msgid "Favourites"
241−#~ msgstr "Favoriler"
po/ug.po+6−27
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-28 04:36+0000\n"
12−"Last-Translator: Gheyret T.Kenji <Unknown>\n"
11+"PO-Revision-Date: 2013-06-27 11:02+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Uyghur <ug@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18−"X-Generator: Launchpad (build 16692)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -172,7 +172,7 @@ msgstr "جىددىي تېلېفون"
172172#: Greeter/PassphraseLockscreen.qml:59
173173#, qt-format
174174msgid "Hello %1"
175−msgstr "سالام %1"
175+msgstr ""
176176
177177#: Greeter/PassphraseLockscreen.qml:59
178178msgid "Hello"
@@ -217,25 +217,4 @@ msgstr "كەچۈرۈڭ، ئىزدىگىنىڭىزگە ماس نەتىجە تېپ
217217#: Shell.qml:383
218218#, qt-format
219219msgid "Please enter %1"
220−msgstr "%1 نى كىرگۈزۈڭ"
221−
222−#~ msgid "Favourite People"
223−#~ msgstr "ھەمىشە ئالاقە قىلىدىغان كىشىلەر"
224−
225−#~ msgid "People Recently in Touch"
226−#~ msgstr "يېقىندا ئالاقە قىلغان كىشىلەر"
227−
228−#~ msgid "People"
229−#~ msgstr "كىشىلەر"
230−
231−#~ msgid "Home screen"
232−#~ msgstr "ماكان ئېكران"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "A-Z"
236−
237−#~ msgid "Recently in touch"
238−#~ msgstr "يېقىندا ئالاقە قىلغانلار"
239−
240−#~ msgid "New Contacts"
241−#~ msgstr "يېڭى ئالاقەداشلار"
220+msgstr ""
po/uk.po+4−28
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-29 14:27+0000\n"
12−"Last-Translator: Roman Koshkin <mar2008m@rambler.ru>\n"
11+"PO-Revision-Date: 2013-07-21 05:47+0000\n"
12+"Last-Translator: Ярослав Смук <Smuk.Slavko@yandex.ua>\n"
1313"Language-Team: Ukrainian <uk@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18−"X-Generator: Launchpad (build 16692)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,27 +218,3 @@ msgstr "Вибачте, для вказаних вами ключових слі
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr "Будь ласка, введіть %1"
221−
222−#~ msgid "People"
223−#~ msgstr "Люди"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "Екран домівки"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "Вибрані контакти"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "Недавні контакти"
233−
234−#~ msgid "A-Z"
235−#~ msgstr "А-Я"
236−
237−#~ msgid "New Contacts"
238−#~ msgstr "Нові контакти"
239−
240−#~ msgid "Favourites"
241−#~ msgstr "Улюблене"
242−
243−#~ msgid "Recently in touch"
244−#~ msgstr "Нещодавні контакти"
po/zh_CN.po+3−27
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-22 21:20+0000\n"
11+"PO-Revision-Date: 2013-06-27 10:33+0000\n"
1212"Last-Translator: Anthony Wong <anthony.wong@canonical.com>\n"
1313"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,27 +218,3 @@ msgstr "对不起,没有找到您想要的结果。"
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "Home screen"
223−#~ msgstr "主页"
224−
225−#~ msgid "Favourite People"
226−#~ msgstr "常用联系人"
227−
228−#~ msgid "People Recently in Touch"
229−#~ msgstr "近期联系人"
230−
231−#~ msgid "People"
232−#~ msgstr "联系人"
233−
234−#~ msgid "Recently in touch"
235−#~ msgstr "最近联系"
236−
237−#~ msgid "New Contacts"
238−#~ msgstr "新建联系人"
239−
240−#~ msgid "Favourites"
241−#~ msgstr "最爱"
242−
243−#~ msgid "A-Z"
244−#~ msgstr "A-Z"
po/zh_TW.po+4−16
@@ -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: 2013-06-26 22:58+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
11+"PO-Revision-Date: 2013-06-27 10:24+0000\n"
12+"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18−"X-Generator: Launchpad (build 16681)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -218,15 +218,3 @@ msgstr "很抱歉,找不到符合您想搜尋的結果。"
218218#, qt-format
219219msgid "Please enter %1"
220220msgstr ""
221−
222−#~ msgid "People"
223−#~ msgstr "朋友"
224−
225−#~ msgid "Home screen"
226−#~ msgstr "家屋畫面"
227−
228−#~ msgid "Favourite People"
229−#~ msgstr "喜歡的朋友"
230−
231−#~ msgid "People Recently in Touch"
232−#~ msgstr "最近接觸的朋友"
run_on_device+6−24
@@ -27,13 +27,13 @@ usage() {
2727 echo " -k, --keylock Enable a Keyboard lock screen when running"
2828 echo ""
2929 echo "IMPORTANT:"
30− echo " * Make sure to have the networking and PPAs setup on the device beforehand (phablet-deploy-networking && phablet-ppa-fetch)."
31− echo " * Execute that script from a directory containing a branch the shell code."
30+ echo " * Make sure to have networking setup on the device beforehand."
31+ echo " * Execute that script from a directory containing unity8 code."
3232 exit 1
3333}
3434
3535exec_with_ssh() {
36− ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT "bash -ic \"$@\""
36+ ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -t $USER@$TARGET_IP -p $TARGET_SSH_PORT sudo -u $USER -i bash -ic \"$@\"
3737}
3838
3939exec_with_adb() {
@@ -65,11 +65,9 @@ setup_adb_forwarding() {
6565}
6666
6767install_dependencies() {
68+ exec_with_adb apt-get update
6869 exec_with_adb apt-get -y install openssh-server
6970 exec_with_ssh $SUDO apt-get -y install build-essential rsync bzr ccache gdb ninja-build devscripts equivs
70− exec_with_ssh $SUDO add-apt-repository -y ppa:canonical-qt5-edgers/qt5-proper
71− exec_with_ssh $SUDO add-apt-repository -s -y ppa:phablet-team/ppa
72− exec_with_ssh $SUDO apt-get update
7371}
7472
7573sync_code() {
@@ -85,17 +83,6 @@ build() {
8583}
8684
8785run() {
88− SERVICEFILE="${CHROOT_PREFIX}/etc/device-services"
89− adb shell "egrep '$BINARY' $SERVICEFILE"
90− CONTAINS_SHELL=$?
91− if [ $CONTAINS_SHELL -eq 0 ]; then
92− echo "Modifying $SERVICEFILE on device. Old contents will be saved in $SERVICEFILE.backup"
93− adb shell cp $SERVICEFILE $SERVICEFILE.backup
94− adb shell sed -i "/$BINARY/d" $SERVICEFILE
95− if $FLIPPED; then exec_with_adb /usr/bin/service ubuntu-touch-session restart
96− else exec_with_adb /usr/bin/service ubuntu-session restart; fi
97− fi
98− adb shell pkill $BINARY
9986 ARGS="--nomousetouch"
10087 if $GDB; then
10188 ARGS="$ARGS --gdb"
@@ -107,14 +94,9 @@ run() {
10794 ARGS="$ARGS -k"
10895 fi
10996
97+ exec_with_ssh "stop unity8"
11098 exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS"
111−
112− if [ $CONTAINS_SHELL -eq 0 ]; then
113− echo "Restoring $SERVICEFILE on device from $SERVICEFILE.backup"
114− adb shell cp $SERVICEFILE.backup $SERVICEFILE
115− if $FLIPPED; then exec_with_adb /usr/bin/service ubuntu-touch-session restart
116− else exec_with_adb /usr/bin/service ubuntu-session restart; fi
117− fi
99+ exec_with_ssh "start unity8"
118100}
119101
120102set -- `getopt -n$0 -u -a --longoptions="setup,gdb,pinlock,keylock,help" "sgpkh" "$@"`
tests/autopilot/setup.py+17−6
@@ -1,11 +1,22 @@
11#!/usr/bin/python
2−
32# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
4−# Copyright 2013 Canonical
53#
6−# This program is free software: you can redistribute it and/or modify it
7−# under the terms of the GNU General Public License version 3, as published
8−# by the Free Software Foundation.
4+# Unity Autopilot Test Suite
5+# Copyright (C) 2012-2013 Canonical
6+#
7+# This program is free software: you can redistribute it and/or modify
8+# it under the terms of the GNU General Public License as published by
9+# the Free Software Foundation, either version 3 of the License, or
10+# (at your option) any later version.
11+#
12+# This program is distributed in the hope that it will be useful,
13+# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+# GNU General Public License for more details.
16+#
17+# You should have received a copy of the GNU General Public License
18+# along with this program. If not, see <http://www.gnu.org/licenses/>.
19+#
920
1021
1122from distutils.core import setup
@@ -14,7 +25,7 @@ from setuptools import find_packages
1425setup(
1526 name='unity',
1627 version='8.0',
17− description='Unity 8 autopilot tests.',
28+ description='Unity autopilot tests.',
1829 url='https://launchpad.net/unity',
1930 license='GPLv3',
2031 packages=find_packages(),
tests/autopilot/unity8/__init__.py+90−5
@@ -1,8 +1,93 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
32#
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.
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""unity autopilot tests and emulators - top level package."""
21+import os
22+import os.path
23+import subprocess
24+import sysconfig
25+
26+
27+def running_installed_tests():
28+ binary_path = get_binary_path()
29+ return binary_path.startswith('/usr')
30+
31+
32+def get_lib_path():
33+ """Return the library path to use in this test run."""
34+ if running_installed_tests():
35+ lib_path = os.path.join(
36+ "/usr/lib/",
37+ sysconfig.get_config_var('MULTIARCH'),
38+ "unity8"
39+ )
40+ else:
41+ binary_path = get_binary_path()
42+ lib_path = os.path.dirname(binary_path)
43+ return lib_path
44+
45+
46+def get_default_extra_mock_libraries():
47+ mocks_path = get_mocks_library_path()
48+ return os.path.join(mocks_path, 'libusermetrics')
49+
50+
51+def get_mocks_library_path():
52+ if running_installed_tests():
53+ mock_path = "qml/mocks/"
54+ else:
55+ mock_path = "../lib/x86_64-linux-gnu/unity8/qml/mocks/"
56+ lib_path = get_lib_path()
57+ ld_library_path = os.path.abspath(
58+ os.path.join(
59+ lib_path,
60+ mock_path,
61+ )
62+ )
63+
64+ if not os.path.exists(ld_library_path):
65+ raise RuntimeError(
66+ "Expected library path does not exists: %s." % (ld_library_path)
67+ )
68+ return ld_library_path
69+
70+
71+def get_binary_path(binary="unity8"):
72+ """Return the path to the specified binary."""
73+ binary_path = os.path.abspath(
74+ os.path.join(
75+ os.path.dirname(__file__),
76+ "../../../builddir/install/bin/%s" % binary
77+ )
78+ )
79+ if not os.path.exists(binary_path):
80+ try:
81+ binary_path = subprocess.check_output(['which', binary]).strip()
82+ except subprocess.CalledProcessError as e:
83+ raise RuntimeError("Unable to locate %s binary: %r" % (binary, e))
84+ return binary_path
85+
786
8−"""unity8 autopilot tests and emulators - top level package."""
87+def get_grid_size():
88+ grid_size = os.getenv('GRID_UNIT_PX')
89+ if grid_size is None:
90+ raise RuntimeError(
91+ "Environment variable GRID_UNIT_PX has not been set."
92+ )
93+ return int(grid_size)
tests/autopilot/unity8/indicators_client/__init__.py+1−1
@@ -5,4 +5,4 @@
55# under the terms of the GNU General Public License version 3, as published
66# by the Free Software Foundation.
77
8−"""unity8 indicators-client autopilot tests and emulators - sub level package."""
8+"""unity indicators-client autopilot tests and emulators - sub level package."""
tests/autopilot/unity8/indicators_client/tests/__init__.py+13−9
@@ -5,7 +5,7 @@
55# under the terms of the GNU General Public License version 3, as published
66# by the Free Software Foundation.
77
8−"""qml-phone-shell autopilot tests."""
8+"""indicators-client autopilot tests."""
99
1010import os.path
1111
@@ -15,6 +15,7 @@ from autopilot.matchers import Eventually
1515from autopilot.platform import model
1616from testtools.matchers import Equals
1717
18+from unity8 import get_binary_path
1819from unity8.indicators_client.emulators.main_window import MainWindow
1920from logging import getLogger
2021import sys
@@ -29,9 +30,12 @@ class IndicatorsTestCase(AutopilotTestCase):
2930
3031 """A common test case class that provides several useful methods for indicator tests."""
3132
33+ geometry = None
34+ grid_unit = None
35+
3236 if model() == 'Desktop':
3337 scenarios = [
34− ('with mouse', dict(input_device_class=Mouse)),
38+ ('with mouse', dict(input_device_class=Mouse, geometry="400x800", grid_unit="12")),
3539 ]
3640 else:
3741 scenarios = [
@@ -41,11 +45,11 @@ class IndicatorsTestCase(AutopilotTestCase):
4145 def setUp(self, geometry, grid_size):
4246 self.pointing_device = Pointer(self.input_device_class.create())
4347 super(IndicatorsTestCase, self).setUp()
44− if grid_size != "0":
45− os.environ['GRID_UNIT_PX'] = grid_size
48+ if grid_size is not None:
49+ self.patch_environment("GRID_UNIT_PX", str(grid_size))
4650 self.grid_size = int(grid_size)
4751 else:
48− self.grid_size = int(os.environ['GRID_UNIT_PX'])
52+ self.grid_size = int(os.getenv('GRID_UNIT_PX'))
4953
5054 if os.path.realpath(__file__).startswith("/usr/"):
5155 self.launch_test_installed(geometry)
@@ -53,15 +57,15 @@ class IndicatorsTestCase(AutopilotTestCase):
5357 self.launch_test_local(geometry)
5458
5559 def launch_test_local(self, geometry):
56− if geometry != "0x0":
57− self.app = self.launch_test_application("../../builddir/src/Panel/Indicators/client/indicators-client",
60+ if geometry is None:
61+ self.app = self.launch_test_application(get_binary_path("indicators-client"),
5862 "-geometry", geometry, app_type='qt')
5963 else:
60− self.app = self.launch_test_application("../../builddir/src/Panel/Indicators/client/indicators-client",
64+ self.app = self.launch_test_application(get_binary_path("indicators-client"),
6165 app_type='qt')
6266
6367 def launch_test_installed(self, geometry):
64− if geometry != "0x0":
68+ if geometry is not None:
6569 self.app = self.launch_test_application("indicators-client", "-geometry", geometry, app_type='qt')
6670 else:
6771 self.app = self.launch_test_application("indicators-client", app_type='qt')
tests/autopilot/unity8/indicators_client/tests/test_battery.py+15−4
@@ -8,6 +8,7 @@
88"""Add tests here if you want to ensure the behaviour of the power indicator menus are correct"""
99
1010from testtools.matchers import Equals, NotEquals
11+from autopilot.input import Touch
1112from autopilot.matchers import Eventually
1213
1314from unity8.indicators_client.tests import IndicatorsTestCase
@@ -17,7 +18,7 @@ import math
1718
1819class TestDisplayMenus(IndicatorsTestCase):
1920 def setUp(self):
20− super(TestDisplayMenus, self).setUp("400x800", "12")
21+ super(TestDisplayMenus, self).setUp(self.geometry, self.grid_unit)
2122
2223 # This opens the messaging menu so you don't have to do that in
2324 # every test case
@@ -25,7 +26,7 @@ class TestDisplayMenus(IndicatorsTestCase):
2526 self.pointing_device.move_to_object(self.main_window.get_battery_menu())
2627 self.pointing_device.click()
2728
28− fn_loader = lambda: self.app.select_single("IndicatorsPage/QQuickLoader", objectName="page_loader");
29+ fn_loader = lambda: self.app.select_single("IndicatorsPage/QQuickLoader", objectName="pageLoader");
2930 self.assertThat(fn_loader, Eventually(NotEquals(None)));
3031 page_loader = fn_loader();
3132 self.assertThat(page_loader.progress, Eventually(Equals(1.0)))
@@ -69,7 +70,11 @@ class TestDisplayMenus(IndicatorsTestCase):
6970
7071 # wait for the switch menu item
7172 fn_auto_brightness = lambda: self.app.select_single("SwitchMenuItem", objectName="auto-brightness");
72− self.assertThat(fn_auto_brightness, Eventually(NotEquals(None)));
73+ # FIXME: this should go away when we switch to indicator-power
74+ try:
75+ self.assertThat(fn_auto_brightness, Eventually(NotEquals(None)));
76+ except AssertionError:
77+ self.skipTest("WARNING: test skipped due to missing indicator-battery")
7378 auto_brightness = fn_auto_brightness();
7479
7580 old_ab_value = auto_brightness.checked
@@ -82,8 +87,14 @@ class TestDisplayMenus(IndicatorsTestCase):
8287 def test_brightness_slider(self):
8388 """Test the auto-bright switch"""
8489
90+ if self.input_device_class is Touch:
91+ self.skipTest("Dragging is broken with Touch input (LP: #1203808).")
8592 fn_brightness_menu = lambda: self.app.select_single("SliderMenuItem", objectName="brightness");
86− self.assertThat(fn_brightness_menu, Eventually(NotEquals(None)));
93+ # FIXME: this should go away when we switch to indicator-power
94+ try:
95+ self.assertThat(fn_brightness_menu, Eventually(NotEquals(None)));
96+ except AssertionError:
97+ self.skipTest("WARNING: test skipped due to missing indicator-battery")
8798 brightness_menu = fn_brightness_menu();
8899
89100 old_ab_value = brightness_menu.value
tests/autopilot/unity8/shell/__init__.py+35−5
@@ -1,8 +1,38 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
32#
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.
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""unity shell autopilot tests and emulators - sub level package."""
21+
22+from functools import wraps
23+import logging
24+
25+
26+logger = logging.getLogger(__name__)
27+
728
8−"""unity8 shell autopilot tests and emulators - sub level package."""
29+def with_lightdm_mock(mock_type):
30+ """A simple decorator that sets up the LightDM mock for a single test."""
31+ def with_lightdm_mock_internal(fn):
32+ @wraps(fn)
33+ def wrapper(*args, **kwargs):
34+ tests_self = args[0]
35+ tests_self.patch_lightdm_mock(mock_type)
36+ return fn(*args, **kwargs)
37+ return wrapper
38+ return with_lightdm_mock_internal
tests/autopilot/unity8/shell/emulators/__init__.py+23−4
@@ -1,6 +1,25 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
32#
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.
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+
21+from autopilot.introspection import CustomEmulatorBase
22+
23+
24+class UnityEmulatorBase(CustomEmulatorBase):
25+ """A base class for all unity emulators."""
tests/autopilot/unity8/shell/emulators/dash.pynew file+52
@@ -0,0 +1,52 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from unity8.shell.emulators import UnityEmulatorBase
21+
22+
23+class Dash(UnityEmulatorBase):
24+
25+ """An emulator that understands the Dash."""
26+
27+ def get_home_applications_grid(self):
28+ return self.select_single(
29+ "ApplicationsFilterGrid",
30+ objectName="dashHomeApplicationsGrid"
31+ )
32+
33+ def get_application_icon(self, text):
34+ """Returns a 'Tile' icon that has the text 'text' from the application
35+ grid.
36+
37+ Will return None if the icon isn't found.
38+
39+ :param text: String containing the text of the icon to search for.
40+
41+ """
42+ app_grid = self.get_home_applications_grid()
43+ resp_grid = app_grid.select_single('ResponsiveGridView')
44+ return resp_grid.select_single('Tile', text=text)
45+
46+ def get_scope(self, scope_name='home'):
47+ dash_content = self.select_single(
48+ 'QQuickListView',
49+ objectName='dashContentList'
50+ )
51+ scope_id = "%s.scope" % scope_name
52+ return dash_content.select_single('QQuickLoader', scopeId=scope_id)
tests/autopilot/unity8/shell/emulators/greeter.pynew file+43
@@ -0,0 +1,43 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from unity8.shell.emulators import UnityEmulatorBase
21+from autopilot.input import Touch
22+
23+
24+class Greeter(UnityEmulatorBase):
25+
26+ """An emulator that understands the greeter screen."""
27+
28+ def swipe(self):
29+ """Swipe the greeter screen away."""
30+ self.created.wait_for(True)
31+ touch = Touch.create()
32+
33+ rect = self.globalRect
34+ start_x = rect[0] + rect[2] - 3
35+ start_y = int(rect[1] + rect[3] / 2)
36+ stop_x = int(rect[0] + rect[2] * 0.2)
37+ stop_y = start_y
38+ touch.drag(start_x, start_y, stop_x, stop_y)
39+
40+ self.created.wait_for(False)
41+
42+ def get_prompt(self):
43+ return self.select_single("TextField", objectName="passwordInput")
tests/autopilot/unity8/shell/emulators/hud.pynew file+80
@@ -0,0 +1,80 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from collections import namedtuple
21+
22+from unity8 import get_grid_size
23+from unity8.shell.emulators import UnityEmulatorBase
24+from autopilot.input import Touch
25+
26+
27+SwipeCoords = namedtuple('SwipeCoords', 'start_x end_x start_y end_y')
28+
29+
30+class Hud(UnityEmulatorBase):
31+
32+ """An emulator that understands the Hud."""
33+
34+ def show(self):
35+ """Swipes open the Hud."""
36+ touch = Touch.create()
37+
38+ window = self.get_root_instance().select_single('QQuickView')
39+ hud_show_button = window.select_single("HudButton")
40+
41+ swipe_coords = self.get_button_swipe_coords(window, hud_show_button)
42+
43+ touch.press(swipe_coords.start_x, swipe_coords.start_y)
44+ touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
45+ try:
46+ hud_show_button.opacity.wait_for(1.0)
47+ touch.release()
48+ self.shown.wait_for(True)
49+ except AssertionError:
50+ raise
51+ finally:
52+ if touch._touch_finger is not None:
53+ touch.release()
54+
55+ def dismiss(self):
56+ """Closes the open Hud."""
57+ # Ensure that the Hud is actually open
58+ self.shown.wait_for(True)
59+ touch = Touch.create()
60+ x, y = self.get_close_button_coords()
61+ touch.tap(x, y)
62+ self.y.wait_for(self.height)
63+
64+ def get_close_button_coords(self):
65+ """Returns the coordinates of the Huds close button bar."""
66+ rect = self.globalRect
67+ x = int(rect[0] + rect[2] / 2)
68+ y = rect[1] + get_grid_size()
69+ return x, y
70+
71+ def get_button_swipe_coords(self, main_view, hud_show_button):
72+ """Returns the coords both start and end x,y for swiping to make the
73+ 'hud show' button appear.
74+ """
75+ start_x = int(main_view.x + (main_view.width / 2))
76+ end_x = start_x
77+ start_y = main_view.y + (main_view.height - 3)
78+ end_y = main_view.y + int(hud_show_button.y + (hud_show_button.height/2))
79+
80+ return SwipeCoords(start_x, end_x, start_y, end_y)
tests/autopilot/unity8/shell/emulators/launcher.pynew file+38
@@ -0,0 +1,38 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from unity8.shell.emulators import UnityEmulatorBase
21+from autopilot.input import Touch
22+
23+
24+class Launcher(UnityEmulatorBase):
25+
26+ """An emulator that understands the Launcher."""
27+
28+ def show(self):
29+ """Swipes open the launcher."""
30+ touch = Touch.create()
31+
32+ view = self.get_root_instance().select_single('QQuickView')
33+ start_x = view.x + 1
34+ start_y = view.y + view.height / 2
35+ stop_x = start_x + self.panelWidth + 1
36+ stop_y = start_y
37+ touch.drag(start_x, start_y, stop_x, stop_y)
38+ self.shown.wait_for(True)
tests/autopilot/unity8/shell/emulators/main_window.py+44−13
@@ -1,9 +1,28 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
32#
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.
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+
21+from unity8.shell.emulators.greeter import Greeter
22+from unity8.shell.emulators.hud import Hud
23+from unity8.shell.emulators.dash import Dash
24+from unity8.shell.emulators.launcher import Launcher
25+
726
827class MainWindow(object):
928 """An emulator class that makes it easy to interact with the shell"""
@@ -16,10 +35,13 @@ class MainWindow(object):
1635 return self.app.select_single("QQuickView")
1736
1837 def get_greeter(self):
19− return self.app.select_single("Greeter")
38+ return self.app.select_single(Greeter)
2039
2140 def get_greeter_content_loader(self):
22− return self.app.select_single("QQuickLoader", objectName="greeterContentLoader")
41+ return self.app.select_single(
42+ "QQuickLoader",
43+ objectName="greeterContentLoader"
44+ )
2345
2446 def get_login_loader(self):
2547 return self.app.select_single("QQuickLoader", objectName="loginLoader")
@@ -28,7 +50,7 @@ class MainWindow(object):
2850 return self.app.select_single("LoginList")
2951
3052 def get_hud(self):
31− return self.app.select_single("Hud")
53+ return self.app.select_single(Hud)
3254
3355 def get_hud_showable(self):
3456 return self.app.select_single("Showable", objectName="hudShowable")
@@ -37,25 +59,34 @@ class MainWindow(object):
3759 return self.app.select_single("HudButton")
3860
3961 def get_dash(self):
40− return self.app.select_single("Dash")
62+ return self.app.select_single(Dash)
4163
4264 def get_dash_home_applications_grid(self):
43− return self.app.select_single("ApplicationsFilterGrid", objectName="dashHomeApplicationsGrid")
65+ return self.app.select_single(
66+ "ApplicationsFilterGrid",
67+ objectName="dashHomeApplicationsGrid"
68+ )
4469
4570 def get_bottombar(self):
4671 return self.app.select_single("Bottombar")
4772
4873 def get_launcher(self):
49− return self.app.select_single("Launcher")
74+ return self.app.select_single(Launcher)
5075
5176 def get_pinPadLoader(self):
52− return self.app.select_single("QQuickLoader", objectName="pinPadLoader")
77+ return self.app.select_single(
78+ "QQuickLoader",
79+ objectName="pinPadLoader"
80+ )
5381
5482 def get_pinPadButton(self, buttonId):
55− return self.app.select_single("PinPadButton", objectName="pinPadButton%i" % buttonId)
83+ return self.app.select_single(
84+ "PinPadButton",
85+ objectName="pinPadButton%i" % buttonId
86+ )
5687
5788 def get_lockscreen(self):
5889 return self.app.select_single("Lockscreen")
5990
6091 def get_pinentryField(self):
61− return self.app.select_single("TextField", objectName="pinentryField")
92+ return self.app.select_single(objectName="pinentryField")
tests/autopilot/unity8/shell/tests/__init__.py+216−58
@@ -1,81 +1,239 @@
11# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
32#
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.
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
719
8−"""unity8 autopilot tests."""
20+"""unity autopilot tests."""
921
10−import os.path
11−import sysconfig
22+try:
23+ from gi.repository import Gio
24+except ImportError:
25+ Gio = None
1226
27+from autopilot.platform import model
1328from autopilot.testcase import AutopilotTestCase
1429from autopilot.matchers import Eventually
15−from autopilot.platform import model
16−from testtools.matchers import Equals
30+from autopilot.input import Touch
31+from autopilot.display import Display
32+import logging
33+import os.path
34+from testtools.matchers import Equals, NotEquals
1735
36+from unity8 import (
37+ get_lib_path,
38+ get_binary_path,
39+ get_mocks_library_path,
40+ get_default_extra_mock_libraries,
41+)
42+from unity8.shell.emulators import UnityEmulatorBase
43+from unity8.shell.emulators.dash import Dash
1844from unity8.shell.emulators.main_window import MainWindow
1945
20−class FormFactors(object):
21− Phone, Tablet, Desktop = range(3)
2246
23−class ShellTestCase(AutopilotTestCase):
47+logger = logging.getLogger(__name__)
2448
25− """A common test case class that provides several useful methods for shell tests."""
49+UNITYSHELL_GSETTINGS_SCHEMA = "org.compiz.unityshell"
50+UNITYSHELL_GSETTINGS_PATH = "/org/compiz/profiles/unity/plugins/unityshell/"
51+UNITYSHELL_LAUNCHER_KEY = "launcher-hide-mode"
52+UNITYSHELL_LAUNCHER_MODE = 1 # launcher hidden
2653
27− libdir = "/usr/lib/{0}/unity8".format(sysconfig.get_config_var('MULTIARCH'))
28− lightdm_mock = "full"
54+def _get_device_emulation_scenarios():
55+ if model() == 'Desktop':
56+ return [
57+ (
58+ 'Desktop Nexus 4',
59+ dict(app_width=768, app_height=1280, grid_unit_px=18)
60+ ),
61+ (
62+ 'Desktop Nexus 10',
63+ dict(app_width=2560, app_height=1600, grid_unit_px=20)
64+ ),
65+ ]
66+ else:
67+ return [
68+ (
69+ 'Native Device',
70+ dict(app_width=0, app_height=0, grid_unit_px=0)
71+ )
72+ ]
2973
30− def setUp(self, geometry, grid_size):
31− super(ShellTestCase, self).setUp()
32− # Lets assume we are installed system wide if this file is somewhere in /usr
33− if grid_size != "0":
34− os.environ['GRID_UNIT_PX'] = grid_size
35− self.grid_size = int(grid_size)
36− else:
37− self.grid_size = int(os.environ['GRID_UNIT_PX'])
38− if os.path.realpath(__file__).startswith("/usr/"):
39− self.launch_test_installed(geometry)
74+
75+class UnityTestCase(AutopilotTestCase):
76+
77+ """A test case base class for the Unity shell tests."""
78+
79+ def setUp(self):
80+ super(UnityTestCase, self).setUp()
81+ if Gio is not None and UNITYSHELL_GSETTINGS_SCHEMA in Gio.Settings.list_relocatable_schemas():
82+ # Hide Unity launcher
83+ self._unityshell_schema = Gio.Settings.new_with_path(UNITYSHELL_GSETTINGS_SCHEMA, UNITYSHELL_GSETTINGS_PATH)
84+ self._launcher_hide_mode = self._unityshell_schema.get_int(UNITYSHELL_LAUNCHER_KEY)
85+ self._unityshell_schema.set_int(UNITYSHELL_LAUNCHER_KEY, UNITYSHELL_LAUNCHER_MODE)
86+ self.addCleanup(self._reset_launcher)
87+
88+ self._proxy = None
89+ self._lightdm_mock_type = None
90+ self.touch = Touch.create()
91+ self._setup_display_details()
92+
93+ def _reset_launcher(self):
94+ """Reset Unity launcher hide mode"""
95+ self._unityshell_schema.set_int(UNITYSHELL_LAUNCHER_KEY, self._launcher_hide_mode)
96+
97+ def _setup_display_details(self):
98+ scale_divisor = self._determine_geometry()
99+ self._setup_grid_size(scale_divisor)
100+
101+ def _determine_geometry(self):
102+ """Use the geometry that may be supplied or use the default."""
103+ width = getattr(self, 'app_width', 0)
104+ height = getattr(self, 'app_height', 0)
105+ scale_divisor = 1
106+ if width == 0 and width == 0:
107+ self.unity_geometry_args = ['-fullscreen']
40108 else:
41− self.launch_test_local(geometry)
42−
43− def launch_test_local(self, geometry):
44− os.environ['LD_LIBRARY_PATH'] = "../../builddir/tests/mocks/libusermetrics:../../builddir/tests/mocks/LightDM" + self.lightdm_mock
45− os.environ['QML2_IMPORT_PATH'] = "../../builddir/tests/mocks"
46− if geometry != "0x0":
47− self.app = self.launch_test_application(
48− "../../builddir/unity8", "-geometry", geometry, "-frameless", app_type='qt')
109+ if self._geo_larger_than_display(width, height):
110+ scale_divisor = self._get_scaled_down_geo(width, height)
111+ width = width / scale_divisor
112+ height = height / scale_divisor
113+ logger.info(
114+ "Geometry larger than display, scaled down to: %dx%d",
115+ width,
116+ height
117+ )
118+ geo_string = "%dx%d" % (width, height)
119+ self.unity_geometry_args = [
120+ '-geometry',
121+ geo_string,
122+ '-frameless',
123+ '-mousetouch'
124+ ]
125+ return scale_divisor
126+
127+ def _setup_grid_size(self, scale_divisor):
128+ """Use the grid size that may be supplied or use the default."""
129+ if getattr(self, 'grid_unit_px', 0) == 0:
130+ self.grid_size = int(os.getenv('GRID_UNIT_PX'))
49131 else:
50− self.app = self.launch_test_application(
51− "../../builddir/unity8", "-fullscreen", app_type='qt')
52−
53− def launch_test_installed(self, geometry):
54− os.environ['LD_LIBRARY_PATH'] = "{0}/qml/mocks/libusermetrics:{0}/qml/mocks/LightDM/{1}".format(self.libdir, self.lightdm_mock)
55− os.environ['QML2_IMPORT_PATH'] = "{0}/qml/mocks".format(self.libdir)
56− if model() == 'Desktop' and geometry != "0x0":
57− self.app = self.launch_test_application(
58− "unity8", "-geometry", geometry, "-frameless", app_type='qt')
132+ self.grid_size = int(self.grid_unit_px / scale_divisor)
133+ self.patch_environment("GRID_UNIT_PX", str(self.grid_size))
134+
135+ def _geo_larger_than_display(self, width, height):
136+ should_scale = getattr(self, 'scale_geo', True)
137+ if should_scale:
138+ screen = Display.create()
139+ screen_width = screen.get_screen_width()
140+ screen_height = screen.get_screen_height()
141+ return (width > screen_width) or (height > screen_height)
59142 else:
60− self.app = self.launch_test_application(
61− "unity8", "-fullscreen", app_type='qt')
143+ return False
144+
145+ def _get_scaled_down_geo(self, width, height):
146+ divisor = 1
147+ while self._geo_larger_than_display(width / divisor, height / divisor):
148+ divisor = divisor * 2
149+ return divisor
150+
151+ def launch_unity(self):
152+ """Launch the unity shell, return a proxy object for it."""
153+ binary_path = get_binary_path()
154+ lib_path = get_lib_path()
155+
156+ logger.info(
157+ "Lib path is '%s', binary path is '%s'",
158+ lib_path,
159+ binary_path
160+ )
161+
162+ if self._lightdm_mock_type is None:
163+ self.patch_lightdm_mock()
164+ self._setup_extra_mock_environment_patch()
165+
166+ app_proxy = self.launch_test_application(
167+ binary_path,
168+ *self.unity_geometry_args,
169+ app_type='qt',
170+ emulator_base=UnityEmulatorBase
171+ )
172+ self._set_proxy(app_proxy)
173+
174+ # Ensure that the dash is visible before we return:
175+ logger.debug("Unity started, waiting for it to be ready.")
176+ self.assertUnityReady()
177+ logger.debug("Unity loaded and ready.")
178+
179+ return app_proxy
180+
181+ def patch_lightdm_mock(self, mock_type='single'):
182+ self._lightdm_mock_type = mock_type
183+ logger.info("Setting up LightDM mock type '%s'", mock_type)
184+ new_ld_library_path = "%s:%s" % (
185+ get_default_extra_mock_libraries(),
186+ self._get_lightdm_mock_path(mock_type)
187+ )
188+ logger.info("New library path: %s", new_ld_library_path)
189+
190+ self.patch_environment('LD_LIBRARY_PATH', new_ld_library_path)
191+
192+ def _get_lightdm_mock_path(self, mock_type):
193+ lib_path = get_mocks_library_path()
194+ lightdm_mock_path = os.path.abspath(
195+ os.path.join(lib_path, "LightDM", mock_type)
196+ )
197+
198+ if not os.path.exists(lightdm_mock_path):
199+ raise RuntimeError(
200+ "LightDM mock '%s' does not exist at path '%s'."
201+ % (mock_type, lightdm_mock_path)
202+ )
203+ return lightdm_mock_path
204+
205+ def _setup_extra_mock_environment_patch(self):
206+ mocks_library_path = get_mocks_library_path()
207+ self.patch_environment('QML2_IMPORT_PATH', mocks_library_path)
208+
209+ def _set_proxy(self, proxy):
210+ """Keep a copy of the proxy object, so we can use it to get common
211+ parts of the shell later on.
212+
213+ """
214+ self._proxy = proxy
215+ self.addCleanup(self._clear_proxy)
216+
217+ def _clear_proxy(self):
218+ self._proxy = None
62219
63− def skipWrapper(*args, **kwargs):
64− pass
220+ def assertUnityReady(self):
221+ dash = self.get_dash()
222+ home_scope = dash.get_scope('home')
65223
66− def form_factor(self):
67− return FormFactors.Desktop
224+ # FIXME! There is a huge timeout here for when we're doing CI on
225+ # VMs. See lp:1203715
226+ self.assertThat(
227+ home_scope.isLoaded,
228+ Eventually(Equals(True), timeout=60)
229+ )
230+ self.assertThat(home_scope.isCurrent, Eventually(Equals(True)))
68231
69− def __getattribute__(self, attr_name):
70− attr = object.__getattribute__(self, attr_name);
71− if attr_name.startswith("test_"):
72− try:
73− if self.form_factor() in attr.blacklist:
74− return self.skipWrapper
75− except:
76− pass
77− return attr
232+ def get_dash(self):
233+ dash = self._proxy.select_single(Dash)
234+ self.assertThat(dash, NotEquals(None))
235+ return dash
78236
79237 @property
80238 def main_window(self):
81− return MainWindow(self.app)
239+ return MainWindow(self._proxy)
tests/autopilot/unity8/shell/tests/helpers.pydeleted−161
@@ -1,161 +0,0 @@
1−# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
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−from testtools.matchers import Equals, NotEquals
9−from autopilot.matchers import Eventually
10−
11−import logging
12−
13−logger = logging.getLogger(__name__)
14−
15−class TestShellHelpers(object):
16− """Helpers for testing the Shell"""
17−
18− def select_greeter_user(self, username):
19− greeter = self.main_window.get_greeter()
20− self.assertThat(greeter.created, Eventually(Equals(True)))
21− self.assertThat(greeter.multiUser, Eventually(Equals(True)))
22−
23− login_loader = self.main_window.get_login_loader()
24− self.assertThat(login_loader.progress, Eventually(Equals(1)))
25−
26− login_list = self.main_window.get_login_list()
27− list_view = login_list.get_children_by_type("QQuickListView")[0]
28−
29− try_count = 0
30− max_tries = 50 # just in case we go off rails
31− while try_count < max_tries:
32− users = list_view.get_children_by_type("QQuickItem")[0].get_children_by_type("QQuickItem")
33− target_user = None
34− for user in users:
35− try:
36− user_label = user.get_children_by_type("Label")[0]
37− if user.opacity < 0.1:
38− continue # off-screen item
39− if user_label.text == username:
40− target_user = user
41− break
42− elif target_user is None or user.y > target_user.y:
43− target_user = user
44− except Exception:
45− pass
46− if target_user is None:
47− break
48− user_label = target_user.get_children_by_type("Label")[0]
49− self.touch.tap_object(user_label)
50− self.assertThat(list_view.movingInternally, Eventually(Equals(False)))
51− if user_label.text == username:
52− return login_list.get_children_by_type("TextField")[0]
53− try_count = try_count + 1
54− self.fail() # We didn't find it
55−
56− def unlock_greeter(self, retries=2):
57− greeter = self.main_window.get_greeter()
58− self.assertThat(greeter.created, Eventually(Equals(True)))
59−
60− if greeter.multiUser:
61− password_field = self.select_greeter_user("No Password")
62− self.assertThat(password_field.opacity, Eventually(Equals(1)))
63− self.touch.tap_object(password_field)
64−
65− else:
66− rect = greeter.globalRect
67− start_x = rect[0] + rect[2] - 3
68− start_y = int(rect[1] + rect[3] / 2)
69− stop_x = int(rect[0] + rect[2] * 0.2)
70− stop_y = start_y
71− self.touch.drag(start_x, start_y, stop_x, stop_y)
72−
73− # Because the shell loads up lots of stuff, unlocking the greeter can
74− # be a bit stuttery while scopes are still consuming all resources.
75− # Give it another (max retries) chance
76− try:
77− self.assertThat(greeter.created, Eventually(Equals(False)))
78− except:
79− if retries > 0:
80− logger.warning("Failed to unlock greeter. Retrying...")
81− self.unlock_greeter(retries-1)
82− else:
83− logger.warning("Failed to unlock greeter. Giving up. Tests may fail...")
84−
85−
86− def open_first_dash_home_app(self, retries=2):
87− self.assertThat(lambda: self.main_window.get_dash_home_applications_grid(), Eventually(NotEquals(None)))
88− app_grid = self.main_window.get_dash_home_applications_grid()
89− # Wait for the grids to be expanded
90− self.assertThat(app_grid.get_children()[0].totalContentHeight, Eventually(NotEquals(0)))
91− self.assertThat(app_grid.get_children()[0].height, Eventually(Equals(app_grid.get_children()[0].totalContentHeight)))
92− first_app = app_grid.get_children()[0].get_children()[0].get_children()[0].get_children()[0]
93− self.touch.tap_object(first_app)
94− bottombar = self.main_window.get_bottombar()
95−
96− # if we have huge amounts of pixels (e.g. Nexus10), but slow video (e.g. VM) it might take a little
97− # until the dash is fully rendered after sliding away the greeter/lockscreen and the click might
98− # go to the void for the first time because there's no real way to know what the display has
99− # painted already. Give it another (max retries) chance.
100− try:
101− self.assertThat(lambda: getattr(bottombar, "applicationIsOnForeground"),
102− Eventually(Equals(True)))
103− except:
104− if retries > 0:
105− logger.warning("Failed to launch app. Retrying...")
106− self.open_first_dash_home_app(retries-1)
107− else:
108− logger.warning("Failed to launch app. Giving up. Tests may fail...")
109−
110−
111− def show_hud(self, retries=2):
112− self.open_first_dash_home_app()
113−
114− hud_show_button = self.main_window.get_hud_show_button()
115− hud = self.main_window.get_hud()
116− window = self.main_window.get_qml_view()
117− start_x = int(window.x + window.width / 2)
118− start_y = window.y + window.height - 3
119− self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
120− self.touch.press(start_x, start_y)
121− self.touch._finger_move(start_x, start_y - self.grid_size)
122− self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
123− self.touch._finger_move(start_x, start_y - self.grid_size * 2)
124− self.touch._finger_move(start_x, start_y - self.grid_size * 3)
125− self.touch._finger_move(start_x, start_y - self.grid_size * 4)
126− try:
127− self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
128− except:
129− if retries > 0:
130− logger.warning("Failed to get hud button to show. Retrying...")
131− self.touch.release()
132− self.show_hud(retries-1)
133− return
134− else:
135− logger.warning("Failed to get hud button to show. Giving up. Tests may fail...")
136− self.assertThat(hud_show_button.mouseOver, Eventually(Equals(False)))
137− self.touch._finger_move(start_x, start_y - self.grid_size * 34)
138− self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
139− self.assertThat(hud_show_button.mouseOver, Eventually(Equals(True)))
140− self.touch.release()
141− self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
142− self.assertThat(hud.shown, Eventually(Equals(True)))
143−
144− def close_hud_click(self):
145− hud = self.main_window.get_hud()
146− self.assertThat(hud.shown, Eventually(Equals(True)))
147− rect = hud.globalRect
148− x = int(rect[0] + rect[2] / 2)
149− y = rect[1] + self.grid_size
150− self.touch.tap(x, y)
151− self.assertThat(hud.shown, Eventually(Equals(False)))
152−
153− def show_launcher(self):
154− launcher = self.main_window.get_launcher()
155− view = self.main_window.get_qml_view()
156− start_x = view.x + 1
157− start_y = view.y + view.height / 2
158− stop_x = start_x + launcher.panelWidth + 1
159− stop_y = start_y
160− self.touch.drag(start_x, start_y, stop_x, stop_y)
161− self.assertThat(launcher.shown, Eventually(Equals(True)))
tests/autopilot/unity8/shell/tests/test_hud.pynew file+151
@@ -0,0 +1,151 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+from __future__ import absolute_import
21+
22+from unity8.shell import with_lightdm_mock
23+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
24+
25+from testtools.matchers import Equals
26+from autopilot.matchers import Eventually
27+
28+
29+class TestHud(UnityTestCase):
30+
31+ """Tests the Shell HUD."""
32+
33+ scenarios = _get_device_emulation_scenarios()
34+
35+ def test_show_hud_button_appears(self):
36+ """Swiping up while an app is active must show the 'show hud' button.
37+
38+ """
39+ self.launch_unity()
40+ self.main_window.get_greeter().swipe()
41+ window = self.main_window.get_qml_view()
42+ hud_show_button = self.main_window.get_hud_show_button()
43+ hud = self.main_window.get_hud()
44+
45+ self._launch_test_app_from_app_screen()
46+
47+ swipe_coords = hud.get_button_swipe_coords(
48+ window,
49+ hud_show_button
50+ )
51+ self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
52+ self.addCleanup(self.touch.release)
53+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
54+ self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
55+
56+ def test_show_hud_appears(self):
57+ """Releasing the touch on the 'show hud' button must display the hud.
58+
59+ """
60+ self.launch_unity()
61+ self.main_window.get_greeter().swipe()
62+ window = self.main_window.get_qml_view()
63+ hud_show_button = self.main_window.get_hud_show_button()
64+ hud = self.main_window.get_hud()
65+
66+ self._launch_test_app_from_app_screen()
67+
68+ swipe_coords = hud.get_button_swipe_coords(
69+ window,
70+ hud_show_button
71+ )
72+ self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
73+ self.addCleanup(self._maybe_release_finger)
74+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
75+
76+ self.assertThat(hud.shown, Eventually(Equals(False)))
77+ self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
78+ self.touch.release()
79+ self.assertThat(hud.shown, Eventually(Equals(True)))
80+
81+ def test_hide_hud_click(self):
82+ """Tapping the close button of the Hud must dismiss it."""
83+ self.launch_unity()
84+ self.main_window.get_greeter().swipe()
85+ hud = self.main_window.get_hud()
86+
87+ self._launch_test_app_from_app_screen()
88+ hud.show()
89+
90+ x, y = hud.get_close_button_coords()
91+ self.touch.tap(x, y)
92+ self.assertThat(hud.shown, Eventually(Equals(False)))
93+
94+ def test_hide_hud_dragging(self):
95+ """Once open the Hud must close if the upper bar is dragged and
96+ released downward.
97+
98+ """
99+ self.launch_unity()
100+ self.main_window.get_greeter().swipe()
101+ hud = self.main_window.get_hud()
102+ window = self.main_window.get_qml_view()
103+
104+ self._launch_test_app_from_app_screen()
105+ hud.show()
106+
107+ start_x, start_y = hud.get_close_button_coords()
108+ end_x = start_x
109+ end_y = int(window.height / 2)
110+
111+ self.touch.drag(start_x, start_y, end_x, end_y)
112+ self.assertThat(hud.shown, Eventually(Equals(False)))
113+
114+ def test_launcher_hides_hud(self):
115+ """Opening the Launcher while the Hud is active must close the Hud."""
116+ self.launch_unity()
117+ self.main_window.get_greeter().swipe()
118+ hud = self.main_window.get_hud()
119+ launcher = self.main_window.get_launcher()
120+
121+ self._launch_test_app_from_app_screen()
122+
123+ hud.show()
124+ launcher.show()
125+
126+ self.assertThat(hud.shown, Eventually(Equals(False)))
127+
128+ def _launch_test_app_from_app_screen(self):
129+ """Launches the camera app using the Dash UI.
130+
131+ Because when testing on the desktop running
132+ self.launch_application() will launch the application on the desktop
133+ itself and not within the Unity UI.
134+
135+ """
136+ dash = self.main_window.get_dash()
137+ icon = dash.get_application_icon('Camera')
138+ self.touch.tap_object(icon)
139+
140+ # Ensure application is open
141+ bottombar = self.main_window.get_bottombar()
142+ self.assertThat(bottombar.applicationIsOnForeground,
143+ Eventually(Equals(True)))
144+
145+ # Because some tests are manually manipulating the finger, we want to
146+ # cleanup if the test fails, but we don't want to fail with an exception if
147+ # we don't.
148+ def _maybe_release_finger(self):
149+ """Only release the finger if it is in fact down."""
150+ if self.touch._touch_finger is not None:
151+ self.touch.release()
tests/autopilot/unity8/shell/tests/test_lock_screen.pynew file+163
@@ -0,0 +1,163 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2012-2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+
21+from __future__ import absolute_import
22+
23+from unity8.shell import with_lightdm_mock
24+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
25+
26+from autopilot.matchers import Eventually
27+from autopilot.platform import model
28+from testtools import skipUnless
29+from testtools.matchers import Equals
30+
31+
32+class TestLockscreen(UnityTestCase):
33+
34+ """Tests for the lock screen."""
35+
36+ scenarios = _get_device_emulation_scenarios()
37+
38+ @with_lightdm_mock("single-pin")
39+ def test_can_unlock_pin_screen(self):
40+ """Must be able to unlock the PIN entry lock screen."""
41+ self.launch_unity()
42+ greeter = self.main_window.get_greeter()
43+
44+ if greeter.narrowMode:
45+ greeter.swipe()
46+ lockscreen = self._wait_for_lockscreen()
47+ self._enter_pincode("1234")
48+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
49+ else:
50+ self._enter_prompt_passphrase("1234")
51+ self.assertThat(greeter.shown, Eventually(Equals(False)))
52+
53+ @with_lightdm_mock("single-passphrase")
54+ def test_can_unlock_passphrase_screen(self):
55+ """Must be able to unlock the passphrase entry screen."""
56+ self.launch_unity()
57+ greeter = self.main_window.get_greeter()
58+
59+ if greeter.narrowMode:
60+ greeter.swipe()
61+ lockscreen = self._wait_for_lockscreen()
62+ self._enter_pin_passphrase("password")
63+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
64+ else:
65+ self._enter_prompt_passphrase("password")
66+ self.assertThat(greeter.shown, Eventually(Equals(False)))
67+
68+ @with_lightdm_mock("single-pin")
69+ def test_pin_screen_wrong_code(self):
70+ """Entering the wrong pin code must not dismiss the lock screen."""
71+ self.launch_unity()
72+ greeter = self.main_window.get_greeter()
73+
74+ if greeter.narrowMode:
75+ greeter.swipe()
76+ lockscreen = self._wait_for_lockscreen()
77+ self._enter_pincode("4321")
78+ pinentryField = self.main_window.get_pinentryField()
79+ self.assertThat(pinentryField.text, Eventually(Equals("")))
80+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
81+ else:
82+ self._enter_prompt_passphrase("4231")
83+ prompt = self.main_window.get_greeter().get_prompt()
84+ self.assertThat(prompt.text, Eventually(Equals("")))
85+ self.assertThat(greeter.shown, Eventually(Equals(True)))
86+
87+ @with_lightdm_mock("single-passphrase")
88+ def test_passphrase_screen_wrong_password(self):
89+ """Entering the wrong password must not dismiss the lock screen."""
90+ self.launch_unity()
91+ greeter = self.main_window.get_greeter()
92+
93+ if greeter.narrowMode:
94+ greeter.swipe()
95+ lockscreen = self._wait_for_lockscreen()
96+ self._enter_pin_passphrase("foobar")
97+ pinentryField = self.main_window.get_pinentryField()
98+ self.assertThat(pinentryField.text, Eventually(Equals("")))
99+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
100+ else:
101+ self._enter_prompt_passphrase("foobar")
102+ prompt = self.main_window.get_greeter().get_prompt()
103+ self.assertThat(prompt.text, Eventually(Equals("")))
104+ self.assertThat(greeter.shown, Eventually(Equals(True)))
105+
106+ def _wait_for_lockscreen(self):
107+ """Wait for the lock screen to load, and return it."""
108+ pinPadLoader = self.main_window.get_pinPadLoader()
109+ self.assertThat(pinPadLoader.progress, Eventually(Equals(1)))
110+ lockscreen = self.main_window.get_lockscreen()
111+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
112+ return lockscreen
113+
114+ def _enter_pincode(self, code):
115+ """Enter code 'code' into the single-pin lightdm pincode entry
116+ screen.
117+
118+ :param code: must be a string of numeric characters.
119+ :raises: TypeError if code is not a string.
120+ :raises: ValueError if code contains non-numeric characters.
121+
122+ """
123+
124+ if not isinstance(code, basestring):
125+ raise TypeError("'code' parameter must be a string.")
126+ for num in code:
127+ if not num.isdigit():
128+ raise ValueError(
129+ "'code' parameter contains non-numeric characters."
130+ )
131+ self.touch.tap_object(self.main_window.get_pinPadButton(int(num)))
132+
133+ def _enter_pin_passphrase(self, passphrase):
134+ """Enter the password specified in 'passphrase' into the password entry
135+ field of the pin lock screen.
136+
137+ :param passphrase: The string you want to enter.
138+ :raises: TypeError if passphrase is not a string.
139+
140+ """
141+ if not isinstance(passphrase, basestring):
142+ raise TypeError("'passphrase' parameter must be a string.")
143+
144+ pinentryField = self.main_window.get_pinentryField()
145+ self.touch.tap_object(pinentryField)
146+ self.keyboard.type(passphrase)
147+ self.keyboard.type("\n")
148+
149+ def _enter_prompt_passphrase(self, passphrase):
150+ """Enter the password specified in 'passphrase' into the password entry
151+ field of the main user list's prompt.
152+
153+ :param passphrase: The string you want to enter.
154+ :raises: TypeError if passphrase is not a string.
155+
156+ """
157+ if not isinstance(passphrase, basestring):
158+ raise TypeError("'passphrase' parameter must be a string.")
159+
160+ prompt = self.main_window.get_greeter().get_prompt()
161+ self.touch.tap_object(prompt)
162+ self.keyboard.type(passphrase)
163+ self.keyboard.type("\n")
tests/autopilot/unity8/shell/tests/testbigscreen.pydeleted−25
@@ -1,25 +0,0 @@
1−# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
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−"""Add tests here if you want to ensure everything is aligned correctly on huge screens. Because this test does not fit on most screens, you should not use input devices here or your tests are likely to fail"""
9−
10−from testtools.matchers import Equals
11−from autopilot.matchers import Eventually
12−
13−from unity8.shell.tests import ShellTestCase
14−
15−class TestBig(ShellTestCase):
16− def setUp(self):
17− super(TestBig, self).setUp("2560x1600", "20")
18− self.assertThat(self.main_window.get_qml_view().visible, Eventually(Equals(True)))
19−
20− def tearDown(self):
21− super(TestBig, self).tearDown()
22−
23− def test_hud_not_shown_greeter(self):
24− hud_showable = self.main_window.get_hud_showable()
25− self.assertThat(hud_showable.y, Eventually(Equals(1600)))
tests/autopilot/unity8/shell/tests/testhud.pydeleted−145
@@ -1,145 +0,0 @@
1−# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
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−
9−# This file contains general purpose test cases for Unity.
10−# Each test written in this file will be executed for a variety of
11−# configurations, such as Phone, Tablet or Desktop form factors.
12−#
13−# Sometimes there is the need to disable a certain test for a particular
14−# configuration. To do so, add this in a new line directly below your test:
15−#
16−# test_testname.blacklist = (FormFactors.Tablet, FormFactors.Desktop,)
17−#
18−# Available form factors are:
19−# FormFactors.Phone
20−# FormFactors.Tablet
21−# FormFactors.Desktop
22−
23−
24−"""Tests for the Shell"""
25−
26−from __future__ import absolute_import
27−
28−from unity8.shell.tests import ShellTestCase, FormFactors
29−from unity8.shell.tests.helpers import TestShellHelpers
30−
31−from autopilot.input import Mouse, Touch, Pointer
32−from testtools.matchers import Equals, NotEquals, GreaterThan, MismatchError
33−from autopilot.matchers import Eventually
34−from autopilot.display import Display
35−from autopilot.platform import model
36−
37−import unittest
38−import time
39−import os
40−from os import path
41−
42−
43−class TestHud(ShellTestCase, TestShellHelpers):
44−
45− """Tests the Shell"""
46−
47− # Scenarios:
48− # Fill in the scenarios to run the whole test suite with multiple configurations.
49− # Use app_width, app_height and grid_unit_px to set the apps geometry.
50− # Set app_width and app_height to 0 to use fullscreen.
51− # Set grid_unit_px to 0 to use the current system environment.
52−
53− if model() == 'Desktop':
54− scenarios = [
55− ('Nexus 4', dict(app_width=768, app_height=1280, grid_unit_px=18, lightdm_mock="single")),
56− ('Nexus 10', dict(app_width=2560, app_height=1600, grid_unit_px=20, lightdm_mock="full")),
57−# TODO: don't run fullscreen tests just yet as the VM is performing too badly for that. Enable this once
58−# Autopilot tests are running on bear metal.
59−# ('Fullscreen', dict(app_width=0, app_height=0, grid_unit_px=10, lightdm_mock="full")),
60− ]
61− else:
62− scenarios = [
63− ('Fullscreen', dict(app_width=0, app_height=0, grid_unit_px=0, lightdm_mock="single")),
64− ]
65−
66− def setUp(self):
67− self.touch = Touch.create()
68−
69− sg = Display().create()
70− divisor = 1
71− while (sg.get_screen_width() < self.app_width / divisor or sg.get_screen_height() < self.app_height / divisor):
72− divisor = divisor * 2
73− super(TestHud, self).setUp("%sx%s" % (self.app_width / divisor, self.app_height / divisor), "%s" % (self.grid_unit_px / divisor))
74−
75− dash = self.main_window.get_dash()
76− self.assertThat(dash.showScopeOnLoaded, Eventually(Equals(""), timeout=30))
77−
78− def test_show_hud(self):
79− hud = self.main_window.get_hud()
80− self.unlock_greeter()
81− self.show_hud()
82− self.assertThat(hud.shown, Eventually(Equals(True)))
83−
84− def test_show_hud_button_dont_open(self):
85− self.unlock_greeter()
86− self.open_first_dash_home_app()
87− hud_show_button = self.main_window.get_hud_show_button()
88− hud = self.main_window.get_hud()
89− window = self.main_window.get_qml_view()
90− start_x = int(window.x + window.width / 2)
91− start_y = window.y + window.height - 2
92− self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
93− self.touch.press(start_x, start_y)
94− self.touch._finger_move(start_x, start_y - self.grid_size)
95− self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
96− self.touch._finger_move(start_x, start_y - self.grid_size * 2)
97− self.touch._finger_move(start_x, start_y - self.grid_size * 3)
98− self.touch._finger_move(start_x, start_y - self.grid_size * 4)
99− self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
100− self.assertThat(hud_show_button.mouseOver, Eventually(Equals(False)))
101− self.touch._finger_move(start_x, start_y - self.grid_size * 34)
102− self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
103− self.assertThat(hud_show_button.mouseOver, Eventually(Equals(True)))
104− self.touch._finger_move(start_x, start_y - self.grid_size)
105− self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
106− self.assertThat(hud_show_button.mouseOver, Eventually(Equals(False)))
107− self.touch.release()
108− self.assertThat(hud_show_button.opacity, Eventually(Equals(0)))
109− self.assertThat(hud.shown, Eventually(Equals(False)))
110−
111− def test_hide_hud_click(self):
112− hud = self.main_window.get_hud()
113− self.unlock_greeter()
114− self.show_hud()
115− self.close_hud_click()
116− self.assertThat(hud.shown, Eventually(Equals(False)))
117−
118− def test_hide_hud_click_outside_handle(self):
119− hud = self.main_window.get_hud()
120− self.unlock_greeter()
121− self.show_hud()
122− rect = hud.globalRect
123− x = int(rect[0] + rect[2] / 2)
124− y = rect[1] + hud.handleHeight + 1
125− self.touch.tap(x, y)
126− self.assertRaises(MismatchError, lambda: self.assertThat(hud.shown, Eventually(Equals(False), timeout=3)))
127−
128− def test_hide_hud_dragging(self):
129− hud = self.main_window.get_hud()
130− self.unlock_greeter()
131− self.show_hud()
132− rect = hud.globalRect
133− start_x = rect[0] + (rect[2] - rect[0]) / 2
134− start_y = rect[1] + 1
135− stop_x = start_x
136− stop_y = start_y + (rect[3] - rect[1]) / 2
137− self.touch.drag(start_x, start_y, stop_x, stop_y)
138− self.assertThat(hud.shown, Eventually(Equals(False)))
139−
140− def test_hide_hud_launcher(self):
141− hud = self.main_window.get_hud()
142− self.unlock_greeter()
143− self.show_hud()
144− self.show_launcher()
145− self.assertThat(hud.shown, Eventually(Equals(False)))
tests/autopilot/unity8/shell/tests/testlockscreen.pydeleted−118
@@ -1,118 +0,0 @@
1−# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−# Copyright 2013 Canonical
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−
9−# This file contains general purpose test cases for Unity.
10−# Each test written in this file will be executed for a variety of
11−# configurations, such as Phone, Tablet or Desktop form factors.
12−#
13−# Sometimes there is the need to disable a certain test for a particular
14−# configuration. To do so, add this in a new line directly below your test:
15−#
16−# test_testname.blacklist = (FormFactors.Tablet, FormFactors.Desktop,)
17−#
18−# Available form factors are:
19−# FormFactors.Phone
20−# FormFactors.Tablet
21−# FormFactors.Desktop
22−
23−
24−"""Tests for the Shell"""
25−
26−from __future__ import absolute_import
27−
28−from unity8.shell.tests import ShellTestCase, FormFactors
29−from unity8.shell.tests.helpers import TestShellHelpers
30−
31−from autopilot.input import Mouse, Touch, Pointer
32−from testtools.matchers import Equals, NotEquals, GreaterThan, MismatchError
33−from autopilot.matchers import Eventually
34−from autopilot.display import Display
35−from autopilot.platform import model
36−
37−import unittest
38−import time
39−import os
40−from os import path
41−
42−
43−class TestLockscreens(ShellTestCase, TestShellHelpers):
44−
45− """Tests the Lockscreens"""
46−
47− # Scenarios:
48− # Fill in the scenarios to run the whole test suite with multiple configurations.
49− # Use app_width, app_height and grid_unit_px to set the apps geometry.
50− # Set app_width and app_height to 0 to use fullscreen.
51− # Set grid_unit_px to 0 to use the current system environment.
52−
53− if model() == 'Desktop':
54− scenarios = [
55− ('Pinlock', dict(app_width=768, app_height=1280, grid_unit_px=18, lightdm_mock="single-pin")),
56− ('Keylock', dict(app_width=768, app_height=1280, grid_unit_px=18, lightdm_mock="single-passphrase")),
57− ]
58− else:
59− scenarios = [
60− ('Pinlock', dict(app_width=0, app_height=0, grid_unit_px=0, lightdm_mock="single-pin")),
61− ('Keylock', dict(app_width=0, app_height=0, grid_unit_px=0, lightdm_mock="single-key")),
62− ]
63−
64− def setUp(self):
65− self.touch = Touch.create()
66−
67− sg = Display().create()
68− divisor = 1
69− while (sg.get_screen_width() < self.app_width / divisor or sg.get_screen_height() < self.app_height / divisor):
70− divisor = divisor * 2
71− super(TestLockscreens, self).setUp("%sx%s" % (self.app_width / divisor, self.app_height / divisor), "%s" % (self.grid_unit_px / divisor))
72−
73− dash = self.main_window.get_dash()
74− self.assertThat(dash.showScopeOnLoaded, Eventually(Equals(""), timeout=30))
75−
76− def test_unlock(self):
77− self.unlock_greeter()
78−
79− pinPadLoader = self.main_window.get_pinPadLoader();
80− self.assertThat(pinPadLoader.progress, Eventually(Equals(1)))
81− lockscreen = self.main_window.get_lockscreen();
82− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
83−
84− if self.lightdm_mock == "single-pin":
85− self.touch.tap_object(self.main_window.get_pinPadButton(1))
86− self.touch.tap_object(self.main_window.get_pinPadButton(2))
87− self.touch.tap_object(self.main_window.get_pinPadButton(3))
88− self.touch.tap_object(self.main_window.get_pinPadButton(4))
89− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
90− else:
91− pinentryField = self.main_window.get_pinentryField()
92− self.touch.tap_object(pinentryField)
93− self.keyboard.type("password\n")
94− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
95−
96− def test_unlock_wrong(self):
97− self.unlock_greeter()
98−
99− pinPadLoader = self.main_window.get_pinPadLoader();
100− self.assertThat(pinPadLoader.progress, Eventually(Equals(1)))
101− lockscreen = self.main_window.get_lockscreen();
102− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
103− pinentryField = self.main_window.get_pinentryField()
104−
105− if self.lightdm_mock == "single-pin":
106− self.touch.tap_object(self.main_window.get_pinPadButton(4))
107− self.touch.tap_object(self.main_window.get_pinPadButton(3))
108− self.touch.tap_object(self.main_window.get_pinPadButton(2))
109− self.assertThat(pinentryField.text, Eventually(Equals("432")))
110− self.touch.tap_object(self.main_window.get_pinPadButton(1))
111−
112− self.assertThat(pinentryField.text, Eventually(Equals("")))
113− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
114− else:
115− self.touch.tap_object(pinentryField)
116− self.keyboard.type("foobar\n")
117− self.assertThat(pinentryField.text, Eventually(Equals("")))
118− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
tests/mocks/CMakeLists.txt+1
@@ -1,5 +1,6 @@
11add_subdirectory(libusermetrics)
22add_subdirectory(LightDM)
3+add_subdirectory(QMenuModel)
34add_subdirectory(Ubuntu)
45add_subdirectory(Unity)
56add_subdirectory(HudClient)
tests/mocks/LightDM/demo/InfographicModelPrivate.cpp+3−3
@@ -54,7 +54,7 @@ void InfographicModelPrivate::generateFakeData()
5454 QSharedPointer<InfographicData> data(
5555 new InfographicData("<b>52km</b> travelled", yellowTheme, firstMonth,
5656 orangeTheme, secondMonth, this));
57− m_fakeData.insert("guest", data);
57+ m_fakeData.insert("phablet", data);
5858 }
5959
6060 {
@@ -69,7 +69,7 @@ void InfographicModelPrivate::generateFakeData()
6969 QSharedPointer<InfographicData> data(
7070 new InfographicData("<b>33</b> messages today", pinkTheme,
7171 firstMonth, orangeTheme, secondMonth, this));
72− m_fakeData.insert("guest", data);
72+ m_fakeData.insert("phablet", data);
7373 }
7474
7575 {
@@ -84,7 +84,7 @@ void InfographicModelPrivate::generateFakeData()
8484 QSharedPointer<InfographicData> data(
8585 new InfographicData("<b>69</b> minutes talk time", darkPurpleTheme,
8686 firstMonth, redTheme, secondMonth, this));
87− m_fakeData.insert("guest", data);
87+ m_fakeData.insert("phablet", data);
8888 }
8989}
9090
tests/mocks/LightDM/demo/UsersModelPrivate.cpp+1−1
@@ -26,7 +26,7 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
2626{
2727 entries =
2828 {
29− { "single", "Guest", 0, 0, false, false, 0, 0 },
29+ { "phablet", "Guest", 0, 0, false, false, 0, 0 },
3030 };
3131}
3232
tests/mocks/LightDM/single/GreeterPrivate.cpp+2−4
@@ -34,10 +34,8 @@ void GreeterPrivate::handleAuthenticate()
3434{
3535 Q_Q(Greeter);
3636
37− if (authenticationUser == "one") {
38− authenticated = true;
39− Q_EMIT q->authenticationComplete();
40− }
37+ authenticated = true;
38+ Q_EMIT q->authenticationComplete();
4139}
4240
4341void GreeterPrivate::handleRespond(QString const &response)
tests/mocks/QMenuModel/CMakeLists.txtnew file+11
@@ -0,0 +1,11 @@
1+file(GLOB QMLFILES
2+ *.qml
3+ *.js
4+ qmldir
5+)
6+
7+# copy files into build directory for shadow builds
8+add_custom_target(QMenuModelQmlFiles ALL
9+ COMMAND cp ${QMLFILES} ${CMAKE_CURRENT_BINARY_DIR}
10+ DEPENDS ${QMLFILES}
11+)
tests/mocks/QMenuModel/QDBusActionGroup.qmlnew file+27
@@ -0,0 +1,27 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Daniel d'Andrada <daniel.dandrada@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+import QtQuick 2.0
21+
22+QtObject {
23+ property int busType
24+ property string busName
25+ property string objectPath
26+ function start() {}
27+}
tests/mocks/QMenuModel/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module QMenuModel
2+QDBusActionGroup 0.1 QDBusActionGroup.qml
tests/mocks/Ubuntu/Application/ApplicationManager.cpp+8−4
@@ -37,8 +37,6 @@ ApplicationManager::ApplicationManager(QObject *parent)
3737 , m_sideStage(0)
3838{
3939 buildListOfAvailableApplications();
40− createMainStageComponent();
41− createSideStageComponent();
4240}
4341
4442ApplicationManager::~ApplicationManager()
@@ -321,10 +319,10 @@ void ApplicationManager::buildListOfAvailableApplications()
321319 m_availableApplications.append(application);
322320
323321 application = new ApplicationInfo(this);
324− application->setDesktopFile("/usr/share/applications/ubuntu-calendar-app.desktop");
322+ application->setDesktopFile("/usr/share/applications/calendar-app.desktop");
325323 application->setName("Calendar");
326324 application->setIcon("calendar");
327− application->setExec("/usr/bin/qmlscene /usr/share/ubuntu-calendar-app/calendar.qml");
325+ application->setExec("/usr/bin/qmlscene /usr/share/calendar-app/calendar.qml");
328326 application->setStage(ApplicationInfo::SideStage);
329327 application->setHandle(nextHandle++);
330328 m_availableApplications.append(application);
@@ -403,6 +401,9 @@ void ApplicationManager::createMainStageComponent()
403401
404402void ApplicationManager::createMainStage()
405403{
404+ if (!m_mainStageComponent)
405+ createMainStageComponent();
406+
406407 // The assumptions I make here really should hold.
407408 QQuickView *quickView =
408409 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
@@ -437,6 +438,9 @@ void ApplicationManager::createSideStageComponent()
437438
438439void ApplicationManager::createSideStage()
439440{
441+ if (!m_sideStageComponent)
442+ createSideStageComponent();
443+
440444 // The assumptions I make here really should hold.
441445 QQuickView *quickView =
442446 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
tests/mocks/Ubuntu/Application/ApplicationManager.h+4
@@ -46,6 +46,8 @@ class ApplicationManager : public QObject {
4646 Q_PROPERTY(ApplicationInfo* sideStageFocusedApplication READ sideStageFocusedApplication
4747 NOTIFY sideStageFocusedApplicationChanged)
4848
49+ Q_PROPERTY(bool fake READ fake CONSTANT)
50+
4951 public:
5052 ApplicationManager(QObject *parent = NULL);
5153 virtual ~ApplicationManager();
@@ -80,6 +82,8 @@ class ApplicationManager : public QObject {
8082 ApplicationInfo* mainStageFocusedApplication() const;
8183 ApplicationInfo* sideStageFocusedApplication() const;
8284
85+ bool fake() { return true; }
86+
8387 Q_INVOKABLE void focusApplication(int handle);
8488 Q_INVOKABLE void unfocusCurrentApplication(StageHint stageHint);
8589 Q_INVOKABLE ApplicationInfo* startProcess(QString desktopFile,
tests/mocks/Unity/CMakeLists.txt+1
@@ -44,3 +44,4 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
4444 )
4545
4646add_subdirectory(Launcher)
47+add_subdirectory(Notifications)
tests/mocks/Unity/Indicators/CMakeLists.txt+2−5
@@ -12,6 +12,7 @@ include_directories(
1212set(IndicatorsFakeQml_SOURCES
1313 fakeplugin.cpp
1414 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/indicators.h
15+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/menucontentactivator.cpp
1516)
1617
1718set(IndicatorsFakeQml_RESOURCES
@@ -26,11 +27,7 @@ add_library(IndicatorsFakeQml SHARED
2627 ${IndicatorsFakeQml_RESOURCES_RCC}
2728 ${IndicatorsFakeQml_SOURCES}
2829)
29−# Because this is an internal support library, we want
30−# to expose all symbols in it. Consider changing this
31−# either to a static library or just using the
32−# files directly in targets.
33−set_target_properties(IndicatorsFakeQml PROPERTIES COMPILE_FLAGS -fvisibility=default)
30+add_definitions(-DUNITYINDICATORS_LIBRARY)
3431
3532target_link_libraries(IndicatorsFakeQml)
3633
tests/mocks/Unity/Indicators/fakeplugin.cpp+4
@@ -24,11 +24,15 @@
2424
2525// local
2626#include "indicators.h"
27+#include "menucontentactivator.h"
2728
2829void IndicatorsFakePlugin::registerTypes(const char * uri)
2930{
3031 Q_INIT_RESOURCE(indicators_fake);
3132
33+ qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
34+
35+ qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
3236 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
3337 qmlRegisterUncreatableType<NetworkActionState>(uri, 0, 1, "NetworkActionState", "Can't create NetworkActionState class");
3438 qmlRegisterUncreatableType<NetworkConnection>(uri, 0, 1, "NetworkConnection", "Can't create NetworkConnection class");
tests/mocks/Unity/Indicators/qml/fake_menu_page1.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page2.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page3.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page4.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page5.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+1−1
@@ -40,7 +40,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
4040 m_list.append(item);
4141 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad");
4242 m_list.append(item);
43− item = new MockLauncherItem("ubuntu-calendar-app", "/usr/share/applications/ubuntu-calendar-app.desktop","Calendar", "calendar");
43+ item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar");
4444 m_list.append(item);
4545}
4646
tests/mocks/Unity/Notifications/CMakeLists.txtnew file+11
@@ -0,0 +1,11 @@
1+file(GLOB QMLFILES
2+ *.qml
3+ *.js
4+ qmldir
5+)
6+
7+# copy files into build directory for shadow builds
8+add_custom_target(NotificationsQmlFiles ALL
9+ COMMAND cp ${QMLFILES} ${CMAKE_CURRENT_BINARY_DIR}
10+ DEPENDS ${QMLFILES}
11+)
tests/mocks/Unity/fake_categories.cpp+5−2
@@ -32,10 +32,11 @@ Categories::Categories(QObject* parent)
3232 m_roles[Categories::RoleName] = "name";
3333 m_roles[Categories::RoleIcon] = "icon";
3434 m_roles[Categories::RoleRenderer] = "renderer";
35− m_roles[Categories::RoleContentType] = "content_type";
35+ m_roles[Categories::RoleContentType] = "contentType";
3636 m_roles[Categories::RoleHints] = "hints";
3737 m_roles[Categories::RoleResults] = "results";
3838 m_roles[Categories::RoleCount] = "count";
39+ m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
3940
4041 // TODO This should not be needed but accumulatting the count changes
4142 // makes the visualization more stable and also makes crashes on fast
@@ -154,7 +155,7 @@ Categories::data(const QModelIndex& index, int role) const
154155
155156 switch (role) {
156157 case RoleId:
157− return QVariant::fromValue(index.row());
158+ return DeeListModel::data(index, 0); //ID
158159 case RoleName:
159160 return DeeListModel::data(index, 1); //DISPLAY_NAME
160161 case RoleIcon:
@@ -172,6 +173,8 @@ Categories::data(const QModelIndex& index, int role) const
172173 return QVariant::fromValue(getFilter(index.row()));
173174 case RoleCount:
174175 return QVariant::fromValue(getFilter(index.row())->rowCount());
176+ case RoleCategoryIndex:
177+ return QVariant::fromValue(index.row());
175178 default:
176179 return QVariant();
177180 }
tests/mocks/Unity/fake_categories.h+2−1
@@ -41,7 +41,8 @@ public:
4141 RoleContentType,
4242 RoleHints,
4343 RoleResults,
44− RoleCount
44+ RoleCount,
45+ RoleCategoryIndex
4546 };
4647
4748 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
tests/mocks/Unity/fake_scopes.cpp+2−2
@@ -52,8 +52,8 @@ void Scopes::updateScopes()
5252 clear();
5353 addScope(new Scope("MockScope1", "People", true, this));
5454 addScope(new Scope("MockScope2", "Music", false, this));
55− addScope(new Scope("MockScope3", "Home", true, this));
56− addScope(new Scope("MockScope4", "Applications", true, this));
55+ addScope(new Scope("home.scope", "Home", true, this));
56+ addScope(new Scope("applications.scope", "Applications", true, this));
5757 addScope(new Scope("MockScope5", "Videos", true, this));
5858
5959 if (!m_loaded) {
tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6−1
@@ -1,7 +1,12 @@
11# There's no cmake var for v8 include path :-/
22# so create one
33LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
4−SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
4+if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
5+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
6+else()
7+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
8+endif()
9+
510
611include_directories(
712 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+50
@@ -22,7 +22,11 @@
2222#include <QtTestGui>
2323#pragma GCC diagnostic push
2424#pragma GCC diagnostic ignored "-pedantic"
25+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
2526#include <private/qquicklistmodel_p.h>
27+#else
28+#include <private/qqmllistmodel_p.h>
29+#endif
2630#include <private/qquickanimation_p.h>
2731#include <private/qquickitem_p.h>
2832#pragma GCC diagnostic pop
@@ -115,7 +119,11 @@ private Q_SLOTS:
115119 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
116120 view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test.qml"));
117121 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
122+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
118123 model = view->rootObject()->findChild<QQuickListModel*>();
124+#else
125+ model = view->rootObject()->findChild<QQmlListModel*>();
126+#endif
119127 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
120128 QVERIFY(lvwph);
121129 QVERIFY(model);
@@ -991,6 +999,25 @@ private Q_SLOTS:
991999 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
9921000 }
9931001
1002+ void testInsertToEmpty()
1003+ {
1004+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
1005+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
1006+ QCOMPARE(lvwph->m_minYExtent, 0.);
1007+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1008+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1009+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1010+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1011+ QCOMPARE(lvwph->contentY(), 0.);
1012+
1013+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100));
1014+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 125));
1015+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1016+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1017+ verifyItem(0, 50., 125., false);
1018+ verifyItem(1, 175., 100., false);
1019+ }
1020+
9941021 void testRemoveItemsAtTop()
9951022 {
9961023 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
@@ -1363,10 +1390,33 @@ private Q_SLOTS:
13631390 lvwph->showHeader();
13641391 }
13651392
1393+ void testCullOnBottomEdge()
1394+ {
1395+ changeContentY(200);
1396+
1397+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1398+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1399+ verifyItem(0, -150., 150., true);
1400+ verifyItem(1, 0., 200., false);
1401+ verifyItem(2, 200., 350., false);
1402+ verifyItem(3, 550., 350., true);
1403+ QCOMPARE(lvwph->m_minYExtent, 0.);
1404+ QCOMPARE(lvwph->m_clipItem->y(), 200.);
1405+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1406+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1407+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1408+ QCOMPARE(lvwph->contentY(), 200.);
1409+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1410+ }
1411+
13661412private:
13671413 QQuickView *view;
13681414 ListViewWithPageHeader *lvwph;
1415+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
13691416 QQuickListModel *model;
1417+#else
1418+ QQmlListModel *model;
1419+#endif
13701420 QQmlComponent *otherDelegate;
13711421};
13721422
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+102−2
@@ -22,7 +22,11 @@
2222#include <QtTestGui>
2323#pragma GCC diagnostic push
2424#pragma GCC diagnostic ignored "-pedantic"
25+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
2526#include <private/qquicklistmodel_p.h>
27+#else
28+#include <private/qqmllistmodel_p.h>
29+#endif
2630#include <private/qquickanimation_p.h>
2731#include <private/qquickitem_p.h>
2832#pragma GCC diagnostic pop
@@ -41,6 +45,7 @@ private:
4145 QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
4246 if (!sectionHeader.isNull()) {
4347 QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
48+ QCOMPARE(sectionDelegateIndex(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), lvwph->m_firstVisibleIndex + visibleIndex);
4449 }
4550 }
4651
@@ -112,6 +117,11 @@ private:
112117 return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
113118 }
114119
120+ int sectionDelegateIndex(QQuickItem *item)
121+ {
122+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
123+ }
124+
115125private Q_SLOTS:
116126
117127 void initTestCase()
@@ -124,7 +134,11 @@ private Q_SLOTS:
124134 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
125135 view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_section.qml"));
126136 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
137+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
127138 model = view->rootObject()->findChild<QQuickListModel*>();
139+#else
140+ model = view->rootObject()->findChild<QQmlListModel*>();
141+#endif
128142 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
129143 QVERIFY(lvwph);
130144 QVERIFY(model);
@@ -212,6 +226,7 @@ private Q_SLOTS:
212226 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
213227 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
214228 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
229+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
215230 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
216231 }
217232
@@ -233,6 +248,7 @@ private Q_SLOTS:
233248 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
234249 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
235250 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
251+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
236252 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
237253 }
238254
@@ -254,6 +270,7 @@ private Q_SLOTS:
254270 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
255271 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
256272 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
273+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
257274 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
258275
259276 changeContentY(-30);
@@ -272,6 +289,7 @@ private Q_SLOTS:
272289 QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
273290 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
274291 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
292+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
275293 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
276294 }
277295
@@ -327,6 +345,7 @@ private Q_SLOTS:
327345 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
328346 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
329347 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
348+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
330349 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
331350
332351 lvwph->positionAtBeginning();
@@ -352,6 +371,7 @@ private Q_SLOTS:
352371 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
353372 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
354373 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
374+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
355375 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
356376
357377 lvwph->positionAtBeginning();
@@ -396,6 +416,7 @@ private Q_SLOTS:
396416 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
397417 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
398418 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
419+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
399420 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
400421
401422 model->setProperty(0, "size", 400);
@@ -415,6 +436,7 @@ private Q_SLOTS:
415436 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
416437 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
417438 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
439+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
418440 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
419441
420442 scrollToTop();
@@ -468,6 +490,7 @@ private Q_SLOTS:
468490 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
469491 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
470492 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
493+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
471494 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
472495
473496 model->setProperty(0, "size", 400);
@@ -487,6 +510,7 @@ private Q_SLOTS:
487510 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
488511 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
489512 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
513+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
490514 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
491515
492516 scrollToTop();
@@ -523,6 +547,7 @@ private Q_SLOTS:
523547 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
524548 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
525549 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
550+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
526551 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
527552
528553 changeContentY(-30);
@@ -540,6 +565,7 @@ private Q_SLOTS:
540565 QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
541566 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
542567 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
568+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
543569 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
544570
545571 changeContentY(30);
@@ -557,6 +583,7 @@ private Q_SLOTS:
557583 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
558584 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
559585 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
586+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
560587 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
561588
562589 changeContentY(-30);
@@ -574,6 +601,7 @@ private Q_SLOTS:
574601 QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
575602 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
576603 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
604+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
577605 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
578606 }
579607
@@ -594,6 +622,7 @@ private Q_SLOTS:
594622 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
595623 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
596624 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
625+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
597626 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
598627
599628 lvwph->setDelegate(otherDelegate);
@@ -652,6 +681,7 @@ private Q_SLOTS:
652681 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
653682 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
654683 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
684+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
655685 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
656686
657687 scrollToTop();
@@ -690,6 +720,7 @@ private Q_SLOTS:
690720 QTRY_VERIFY(lvwph->isAtYEnd());
691721 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
692722 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
723+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
693724 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
694725
695726 scrollToTop();
@@ -726,6 +757,7 @@ private Q_SLOTS:
726757 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
727758 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
728759 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
760+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
729761 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
730762 }
731763
@@ -810,6 +842,7 @@ private Q_SLOTS:
810842 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
811843 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
812844 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
845+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
813846 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
814847
815848 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -830,6 +863,7 @@ private Q_SLOTS:
830863 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
831864 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
832865 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
866+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 4);
833867 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
834868
835869 scrollToTop();
@@ -870,6 +904,7 @@ private Q_SLOTS:
870904 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
871905 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
872906 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
907+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
873908 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
874909
875910 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 3), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -890,6 +925,7 @@ private Q_SLOTS:
890925 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
891926 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
892927 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
928+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
893929 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
894930 }
895931
@@ -912,6 +948,7 @@ private Q_SLOTS:
912948 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
913949 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
914950 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
951+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
915952 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
916953
917954 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -932,6 +969,7 @@ private Q_SLOTS:
932969 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
933970 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
934971 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
972+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 4);
935973 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
936974 }
937975
@@ -954,6 +992,7 @@ private Q_SLOTS:
954992 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
955993 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
956994 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
995+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
957996 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
958997
959998 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -974,6 +1013,7 @@ private Q_SLOTS:
9741013 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
9751014 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
9761015 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1016+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
9771017 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
9781018
9791019 scrollToTop();
@@ -1021,6 +1061,7 @@ private Q_SLOTS:
10211061 QVERIFY(!lvwph->isAtYEnd());
10221062 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
10231063 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1064+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
10241065 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
10251066
10261067 scrollToBottom();
@@ -1041,6 +1082,7 @@ private Q_SLOTS:
10411082 QVERIFY(lvwph->isAtYEnd());
10421083 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
10431084 QCOMPARE(section(lvwph->m_topSectionItem), QString("Lazy"));
1085+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 5);
10441086 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
10451087 }
10461088
@@ -1094,6 +1136,7 @@ private Q_SLOTS:
10941136 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
10951137 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
10961138 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1139+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 13);
10971140 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
10981141
10991142 changeContentY(-1700);
@@ -1118,9 +1161,29 @@ private Q_SLOTS:
11181161 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
11191162 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
11201163 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1164+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 4);
11211165 QCOMPARE(lvwph->m_topSectionItem->y(), -23.);
11221166 }
11231167
1168+ void testInsertToEmpty()
1169+ {
1170+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
1171+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
1172+ QCOMPARE(lvwph->m_minYExtent, 0.);
1173+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1174+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1175+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1176+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1177+ QCOMPARE(lvwph->contentY(), 0.);
1178+
1179+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
1180+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
1181+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1182+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1183+ verifyItem(0, 50., 140., false, "Agressive", false);
1184+ verifyItem(1, 190., 165., false, "Regular", false);
1185+ }
1186+
11241187 void testRemoveItemsAtTop()
11251188 {
11261189 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
@@ -1160,6 +1223,7 @@ private Q_SLOTS:
11601223 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
11611224 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
11621225 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1226+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
11631227 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
11641228 }
11651229
@@ -1183,6 +1247,7 @@ private Q_SLOTS:
11831247 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
11841248 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
11851249 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1250+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
11861251 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
11871252 }
11881253
@@ -1205,6 +1270,7 @@ private Q_SLOTS:
12051270 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12061271 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12071272 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1273+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12081274 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12091275
12101276 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 1), Q_ARG(QVariant, 1));
@@ -1224,6 +1290,7 @@ private Q_SLOTS:
12241290 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12251291 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12261292 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1293+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
12271294 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12281295 }
12291296
@@ -1246,6 +1313,7 @@ private Q_SLOTS:
12461313 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12471314 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12481315 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1316+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12491317 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12501318
12511319 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 3), Q_ARG(QVariant, 1));
@@ -1265,6 +1333,7 @@ private Q_SLOTS:
12651333 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12661334 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12671335 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1336+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12681337 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12691338 }
12701339
@@ -1344,6 +1413,7 @@ private Q_SLOTS:
13441413 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
13451414 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
13461415 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1416+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
13471417 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
13481418
13491419 QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 5), Q_ARG(QVariant, 1));
@@ -1364,6 +1434,7 @@ private Q_SLOTS:
13641434 QVERIFY(!lvwph->isAtYEnd());
13651435 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
13661436 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1437+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
13671438 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
13681439 }
13691440
@@ -1387,6 +1458,7 @@ private Q_SLOTS:
13871458 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
13881459 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
13891460 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1461+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
13901462 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
13911463
13921464 model->setProperty(1, "size", 100);
@@ -1407,6 +1479,7 @@ private Q_SLOTS:
14071479 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14081480 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14091481 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1482+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
14101483 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14111484 }
14121485
@@ -1428,7 +1501,7 @@ private Q_SLOTS:
14281501 QCOMPARE(lvwph->m_headerItem->y(), 0.);
14291502 QCOMPARE(lvwph->m_headerItem->height(), 50.);
14301503 QCOMPARE(lvwph->contentY(), 20.);
1431− QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1504+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14321505 QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14331506
14341507 lvwph->showHeader();
@@ -1448,6 +1521,7 @@ private Q_SLOTS:
14481521 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
14491522 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14501523 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
1524+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
14511525 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14521526
14531527 scrollToTop();
@@ -1483,9 +1557,10 @@ private Q_SLOTS:
14831557 QCOMPARE(lvwph->m_headerItem->y(), 0.);
14841558 QCOMPARE(lvwph->m_headerItem->height(), 50.);
14851559 QCOMPARE(lvwph->contentY(), 375.);
1486− QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1560+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14871561 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14881562 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1563+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
14891564 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14901565
14911566 lvwph->showHeader();
@@ -1506,6 +1581,7 @@ private Q_SLOTS:
15061581 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
15071582 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
15081583 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1584+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
15091585 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
15101586
15111587 scrollToTop();
@@ -1615,10 +1691,34 @@ private Q_SLOTS:
16151691 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
16161692 }
16171693
1694+ void testCullOnBottomEdge()
1695+ {
1696+ changeContentY(240);
1697+
1698+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1699+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1700+ verifyItem(0, -190., 190., true, "Agressive", true);
1701+ verifyItem(1, 0., 240., false, "Regular", false);
1702+ verifyItem(2, 240., 390., false, "Mild", false);
1703+ verifyItem(3, 630., 390., true, "Bold", true);
1704+ QCOMPARE(lvwph->m_minYExtent, 0.);
1705+ QCOMPARE(lvwph->m_clipItem->y(), 240.);
1706+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1707+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1708+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1709+ QCOMPARE(lvwph->contentY(), 240.);
1710+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1711+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1712+ }
1713+
16181714private:
16191715 QQuickView *view;
16201716 ListViewWithPageHeader *lvwph;
1717+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
16211718 QQuickListModel *model;
1719+#else
1720+ QQmlListModel *model;
1721+#endif
16221722 QQmlComponent *otherDelegate;
16231723};
16241724
tests/plugins/Unity/Indicators/CMakeLists.txt+1
@@ -24,4 +24,5 @@ endmacro(run_tests)
2424run_tests(
2525 indicatorsmanagertest
2626 indicatorsmodeltest
27+ menucontentactivatortest
2728 )
tests/plugins/Unity/Indicators/indicatorsmanagertest.cpp+1−1
@@ -134,5 +134,5 @@ private Q_SLOTS:
134134 }
135135};
136136
137−QTEST_MAIN(IndicatorsManagerTest)
137+QTEST_GUILESS_MAIN(IndicatorsManagerTest)
138138#include "indicatorsmanagertest.moc"
tests/plugins/Unity/Indicators/indicatorsmodeltest.cpp+1−1
@@ -97,6 +97,6 @@ private Q_SLOTS:
9797 }
9898};
9999
100−QTEST_MAIN(IndicatorsModelTest)
100+QTEST_GUILESS_MAIN(IndicatorsModelTest)
101101
102102#include "indicatorsmodeltest.moc"
tests/plugins/Unity/Indicators/menucontentactivatortest.cppnew file+303
@@ -0,0 +1,303 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#include "menucontentactivator.h"
21+#include "paths.h"
22+
23+#include <QtTest>
24+#include <QDebug>
25+
26+class FakeTimer : public UnityIndicators::AbstractTimer
27+{
28+ Q_OBJECT
29+public:
30+ FakeTimer(QObject *parent = 0)
31+ : UnityIndicators::AbstractTimer(parent)
32+ {}
33+
34+ virtual int interval() const { return m_duration; }
35+ virtual void setInterval(int msecs) { m_duration = msecs; }
36+
37+ void emitTimeout() {
38+ if (isRunning()) {
39+ Q_EMIT timeout();
40+ }
41+ }
42+private:
43+ int m_duration;
44+};
45+
46+
47+class MenuConentActivatorTest : public QObject
48+{
49+ Q_OBJECT
50+private Q_SLOTS:
51+ void init() // called right before each and every test function is executed
52+ {
53+ m_fakeTimeSource = new FakeTimer(this);
54+ m_deltas.clear();
55+ }
56+ void cleanup() // called right after each and every test function is executed
57+ {
58+ delete m_fakeTimeSource;
59+ m_fakeTimeSource = 0;
60+ }
61+
62+ /*
63+ * Tests the ordering of activation
64+ */
65+ void testContentActiveChange()
66+ {
67+ MenuContentActivator activator;
68+ activator.setContentTimer(m_fakeTimeSource);
69+ activator.setCount(10);
70+ activator.setBaseIndex(5);
71+ activator.restart();
72+
73+ QCOMPARE(activator.isMenuContentActive(4), false);
74+ QCOMPARE(activator.isMenuContentActive(5), true); // always active at base index.
75+ QCOMPARE(activator.isMenuContentActive(6), false);
76+
77+ m_fakeTimeSource->emitTimeout();
78+ QCOMPARE(activator.isMenuContentActive(4), false);
79+ QCOMPARE(activator.isMenuContentActive(5), true);
80+ QCOMPARE(activator.isMenuContentActive(6), true);
81+ QCOMPARE(activator.isMenuContentActive(7), false);
82+
83+ m_fakeTimeSource->emitTimeout();
84+ QCOMPARE(activator.isMenuContentActive(3), false);
85+ QCOMPARE(activator.isMenuContentActive(4), true);
86+ QCOMPARE(activator.isMenuContentActive(5), true);
87+ QCOMPARE(activator.isMenuContentActive(6), true);
88+ QCOMPARE(activator.isMenuContentActive(7), false);
89+
90+ m_fakeTimeSource->emitTimeout();
91+ QCOMPARE(activator.isMenuContentActive(3), false);
92+ QCOMPARE(activator.isMenuContentActive(4), true);
93+ QCOMPARE(activator.isMenuContentActive(5), true);
94+ QCOMPARE(activator.isMenuContentActive(6), true);
95+ QCOMPARE(activator.isMenuContentActive(7), true);
96+ QCOMPARE(activator.isMenuContentActive(8), false);
97+
98+ m_fakeTimeSource->emitTimeout();
99+ QCOMPARE(activator.isMenuContentActive(2), false);
100+ QCOMPARE(activator.isMenuContentActive(3), true);
101+ QCOMPARE(activator.isMenuContentActive(4), true);
102+ QCOMPARE(activator.isMenuContentActive(5), true);
103+ QCOMPARE(activator.isMenuContentActive(6), true);
104+ QCOMPARE(activator.isMenuContentActive(7), true);
105+ QCOMPARE(activator.isMenuContentActive(8), false);
106+
107+ m_fakeTimeSource->emitTimeout();
108+ QCOMPARE(activator.isMenuContentActive(2), false);
109+ QCOMPARE(activator.isMenuContentActive(3), true);
110+ QCOMPARE(activator.isMenuContentActive(4), true);
111+ QCOMPARE(activator.isMenuContentActive(5), true);
112+ QCOMPARE(activator.isMenuContentActive(6), true);
113+ QCOMPARE(activator.isMenuContentActive(7), true);
114+ QCOMPARE(activator.isMenuContentActive(8), true);
115+ QCOMPARE(activator.isMenuContentActive(9), false);
116+
117+ m_fakeTimeSource->emitTimeout();
118+ QCOMPARE(activator.isMenuContentActive(1), false);
119+ QCOMPARE(activator.isMenuContentActive(2), true);
120+ QCOMPARE(activator.isMenuContentActive(3), true);
121+ QCOMPARE(activator.isMenuContentActive(4), true);
122+ QCOMPARE(activator.isMenuContentActive(5), true);
123+ QCOMPARE(activator.isMenuContentActive(6), true);
124+ QCOMPARE(activator.isMenuContentActive(7), true);
125+ QCOMPARE(activator.isMenuContentActive(8), true);
126+ QCOMPARE(activator.isMenuContentActive(9), false);
127+
128+ m_fakeTimeSource->emitTimeout();
129+ QCOMPARE(activator.isMenuContentActive(1), false);
130+ QCOMPARE(activator.isMenuContentActive(2), true);
131+ QCOMPARE(activator.isMenuContentActive(3), true);
132+ QCOMPARE(activator.isMenuContentActive(4), true);
133+ QCOMPARE(activator.isMenuContentActive(5), true);
134+ QCOMPARE(activator.isMenuContentActive(6), true);
135+ QCOMPARE(activator.isMenuContentActive(7), true);
136+ QCOMPARE(activator.isMenuContentActive(8), true);
137+ QCOMPARE(activator.isMenuContentActive(9), true);
138+ QCOMPARE(activator.isMenuContentActive(10), false);
139+
140+ m_fakeTimeSource->emitTimeout();
141+ QCOMPARE(activator.isMenuContentActive(0), false);
142+ QCOMPARE(activator.isMenuContentActive(1), true);
143+ QCOMPARE(activator.isMenuContentActive(2), true);
144+ QCOMPARE(activator.isMenuContentActive(3), true);
145+ QCOMPARE(activator.isMenuContentActive(4), true);
146+ QCOMPARE(activator.isMenuContentActive(5), true);
147+ QCOMPARE(activator.isMenuContentActive(6), true);
148+ QCOMPARE(activator.isMenuContentActive(7), true);
149+ QCOMPARE(activator.isMenuContentActive(8), true);
150+ QCOMPARE(activator.isMenuContentActive(9), true);
151+ QCOMPARE(activator.isMenuContentActive(10), false);
152+
153+ m_fakeTimeSource->emitTimeout();
154+ QCOMPARE(activator.isMenuContentActive(-1), false);
155+ QCOMPARE(activator.isMenuContentActive(0), true);
156+ QCOMPARE(activator.isMenuContentActive(1), true);
157+ QCOMPARE(activator.isMenuContentActive(2), true);
158+ QCOMPARE(activator.isMenuContentActive(3), true);
159+ QCOMPARE(activator.isMenuContentActive(4), true);
160+ QCOMPARE(activator.isMenuContentActive(5), true);
161+ QCOMPARE(activator.isMenuContentActive(6), true);
162+ QCOMPARE(activator.isMenuContentActive(7), true);
163+ QCOMPARE(activator.isMenuContentActive(8), true);
164+ QCOMPARE(activator.isMenuContentActive(9), true);
165+ QCOMPARE(activator.isMenuContentActive(10), false);
166+ }
167+
168+ /*
169+ * Tests the delta calculation for each timeout.
170+ */
171+ void testDelta()
172+ {
173+ MenuContentActivator activator;
174+ activator.setContentTimer(m_fakeTimeSource);
175+ activator.setCount(9);
176+ activator.setBaseIndex(3);
177+
178+ connect(&activator, &MenuContentActivator::deltaChanged,
179+ this, &MenuConentActivatorTest::onDeltaChange);
180+ activator.restart();
181+
182+ QCOMPARE(m_deltas, QList<int>()); // empty
183+ QCOMPARE(getIndexList(&activator), QList<int>()); // empty
184+
185+ m_fakeTimeSource->emitTimeout();
186+ QCOMPARE(m_deltas, QList<int>() << 1);
187+ QCOMPARE(getIndexList(&activator), QList<int>() << 4);
188+
189+ m_fakeTimeSource->emitTimeout();
190+ QCOMPARE(m_deltas, QList<int>() << 1 << -1);
191+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2);
192+
193+ m_fakeTimeSource->emitTimeout();
194+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2);
195+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5);
196+
197+ m_fakeTimeSource->emitTimeout();
198+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2);
199+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1);
200+
201+ m_fakeTimeSource->emitTimeout();
202+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3);
203+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6);
204+
205+ m_fakeTimeSource->emitTimeout();
206+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3);
207+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0);
208+
209+ m_fakeTimeSource->emitTimeout();
210+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3 << 4);
211+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0 << 7);
212+
213+ m_fakeTimeSource->emitTimeout();
214+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3 << 4 << 5);
215+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0 << 7 << 8);
216+
217+ m_fakeTimeSource->emitTimeout();
218+ QCOMPARE(m_deltas, QList<int>() << 1 << -1 << 2 << -2 << 3 << -3 << 4 << 5);
219+ QCOMPARE(getIndexList(&activator), QList<int>() << 4 << 2 << 5 << 1 << 6 << 0 << 7 << 8);
220+ }
221+
222+ /*
223+ * Tests that changing the base index re-prioritizes the activation
224+ * around the base index.
225+ */
226+ void testBaseIndexChange()
227+ {
228+ MenuContentActivator activator;
229+ activator.setContentTimer(m_fakeTimeSource);
230+ activator.setCount(12);
231+ activator.setBaseIndex(5);
232+ activator.restart();
233+
234+ m_fakeTimeSource->emitTimeout();
235+ m_fakeTimeSource->emitTimeout();
236+ QCOMPARE(activator.isMenuContentActive(3), false);
237+ QCOMPARE(activator.isMenuContentActive(4), true);
238+ QCOMPARE(activator.isMenuContentActive(5), true); // always active at base index.
239+ QCOMPARE(activator.isMenuContentActive(6), true);
240+ QCOMPARE(activator.isMenuContentActive(7), false);
241+
242+ activator.setBaseIndex(8);
243+ QCOMPARE(activator.isMenuContentActive(3), false);
244+ QCOMPARE(activator.isMenuContentActive(4), true);
245+ QCOMPARE(activator.isMenuContentActive(5), true);
246+ QCOMPARE(activator.isMenuContentActive(6), true);
247+ QCOMPARE(activator.isMenuContentActive(7), false);
248+ QCOMPARE(activator.isMenuContentActive(8), true);
249+ QCOMPARE(activator.isMenuContentActive(9), false);
250+
251+ m_fakeTimeSource->emitTimeout();
252+ QCOMPARE(activator.isMenuContentActive(3), false);
253+ QCOMPARE(activator.isMenuContentActive(4), true);
254+ QCOMPARE(activator.isMenuContentActive(5), true);
255+ QCOMPARE(activator.isMenuContentActive(6), true);
256+ QCOMPARE(activator.isMenuContentActive(7), false);
257+ QCOMPARE(activator.isMenuContentActive(8), true);
258+ QCOMPARE(activator.isMenuContentActive(9), true);
259+ QCOMPARE(activator.isMenuContentActive(10), false);
260+
261+ m_fakeTimeSource->emitTimeout();
262+ QCOMPARE(activator.isMenuContentActive(3), false);
263+ QCOMPARE(activator.isMenuContentActive(4), true);
264+ QCOMPARE(activator.isMenuContentActive(5), true);
265+ QCOMPARE(activator.isMenuContentActive(6), true);
266+ QCOMPARE(activator.isMenuContentActive(7), true);
267+ QCOMPARE(activator.isMenuContentActive(8), true);
268+ QCOMPARE(activator.isMenuContentActive(9), true);
269+ QCOMPARE(activator.isMenuContentActive(10), false);
270+
271+ m_fakeTimeSource->emitTimeout();
272+ QCOMPARE(activator.isMenuContentActive(3), false);
273+ QCOMPARE(activator.isMenuContentActive(4), true);
274+ QCOMPARE(activator.isMenuContentActive(5), true);
275+ QCOMPARE(activator.isMenuContentActive(6), true);
276+ QCOMPARE(activator.isMenuContentActive(7), true);
277+ QCOMPARE(activator.isMenuContentActive(8), true);
278+ QCOMPARE(activator.isMenuContentActive(9), true);
279+ QCOMPARE(activator.isMenuContentActive(10), true);
280+ QCOMPARE(activator.isMenuContentActive(11), false);
281+ }
282+
283+ void onDeltaChange(int delta)
284+ {
285+ m_deltas << delta;
286+ }
287+
288+private:
289+ QList<int> getIndexList(MenuContentActivator* activator)
290+ {
291+ QList<int> list;
292+ Q_FOREACH(int delta, m_deltas) {
293+ list << (activator->baseIndex() + delta);
294+ }
295+ return list;
296+ }
297+
298+ FakeTimer* m_fakeTimeSource;
299+ QList<int> m_deltas;
300+};
301+
302+QTEST_GUILESS_MAIN(MenuConentActivatorTest)
303+#include "menucontentactivatortest.moc"
tests/plugins/Unity/previewbindingstest.cpp−2
@@ -165,5 +165,3 @@ void PreviewBindingsTest::testSocialPreview()
165165}
166166
167167QTEST_MAIN(PreviewBindingsTest)
168−
169−#include "previewbindingstest.moc"
tests/plugins/Utils/qlimitproxymodeltest.cpp+1−1
@@ -481,6 +481,6 @@ private Q_SLOTS:
481481 }
482482};
483483
484−QTEST_MAIN(QLimitProxyModelTest)
484+QTEST_GUILESS_MAIN(QLimitProxyModelTest)
485485
486486#include "qlimitproxymodeltest.moc"
tests/plugins/Utils/qsortfilterproxymodeltest.cpp+1−1
@@ -285,6 +285,6 @@ private Q_SLOTS:
285285 }
286286};
287287
288−QTEST_MAIN(QSortFilterProxyModelTest)
288+QTEST_GUILESS_MAIN(QSortFilterProxyModelTest)
289289
290290#include "qsortfilterproxymodeltest.moc"
tests/qmltests/CMakeLists.txt+3−2
@@ -25,6 +25,9 @@ add_qml_test(utils/Unity/Test UnityTest)
2525set(qmltest_DEFAULT_TARGETS qmluitests)
2626set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
2727set(qmltest_DEFAULT_PROPERTIES "")
28+
29+add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
30+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
2831add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
2932add_qml_test(Components DraggingArea)
3033add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
@@ -61,10 +64,8 @@ add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_P
6164add_qml_test(Panel IndicatorRow)
6265add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
6366add_qml_test(Panel MenuContent)
64−add_qml_test(Panel Overview)
6567add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
6668add_qml_test(Panel SearchIndicator)
67−add_qml_test(Panel/Menus IndicatorMenuWindow IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS})
6869add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
6970 ${CMAKE_BINARY_DIR}/tests/mocks
7071 ${CMAKE_BINARY_DIR}/plugins)
tests/qmltests/Components/tst_Stage.qml+1
@@ -161,6 +161,7 @@ Rectangle {
161161 applicationManager: fakeAppManager
162162 rightEdgeDraggingAreaWidth: units.gu(2)
163163 fullyShown: true
164+ fullyHidden: false
164165 newApplicationScreenshot: FakeApplicationScreenshot {
165166 id: newAppScreenshot
166167 parent: stage
tests/qmltests/Dash/tst_Dash.qml+4−4
@@ -38,8 +38,8 @@ Item {
3838 scopeDelegateMapping: {
3939 "MockScope1": "../tests/qmltests/Dash/qml/fake_scopeView1.qml",
4040 "MockScope2": "../tests/qmltests/Dash/qml/fake_scopeView2.qml",
41− "MockScope3": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
42− "MockScope4": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
41+ "home.scope": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
42+ "applications.scope": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
4343 }
4444 genericScope: "../tests/qmltests/Dash/qml/fake_generic_scopeView.qml"
4545 }
@@ -69,8 +69,8 @@ Item {
6969 return [
7070 { tag: "MockScope1", visualIndex: 0, shouldBeVisible: true },
7171 { tag: "MockScope2", visualIndex: -1, shouldBeVisible: false },
72− { tag: "MockScope3", visualIndex: 1, shouldBeVisible: true },
73− { tag: "MockScope4", visualIndex: 2, shouldBeVisible: true },
72+ { tag: "home.scope", visualIndex: 1, shouldBeVisible: true },
73+ { tag: "applications.scope", visualIndex: 2, shouldBeVisible: true },
7474 { tag: "MockScope5", visualIndex: 3, shouldBeVisible: true },
7575 ]
7676 }
tests/qmltests/Dash/tst_DashContent.qml+12−12
@@ -31,8 +31,8 @@ Item {
3131 property var scopeStatus: {
3232 'MockScope1': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
3333 'MockScope2': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
34− 'MockScope3': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
35− 'MockScope4': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
34+ 'home.scope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
35+ 'applications.scope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
3636 'MockScope5': { 'movementStarted': 0, 'positionedAtBeginning': 0 }
3737 }
3838
@@ -55,8 +55,8 @@ Item {
5555 scopeDelegateMapping: {
5656 "MockScope1": "../tests/qmltests/Dash/qml/fake_scopeView1.qml",
5757 "MockScope2": "../tests/qmltests/Dash/qml/fake_scopeView2.qml",
58− "MockScope3": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
59− "MockScope4": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
58+ "home.scope": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
59+ "applications.scope": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
6060 }
6161 genericScope: "../tests/qmltests/Dash/qml/fake_generic_scopeView.qml"
6262 }
@@ -68,11 +68,11 @@ Item {
6868 scopeStatus["MockScope2"].movementStarted = 0;
6969 scopeStatus["MockScope2"].positionedAtBeginning = 0;
7070
71− scopeStatus["MockScope3"].movementStarted = 0;
72− scopeStatus["MockScope3"].positionedAtBeginning = 0;
71+ scopeStatus["home.scope"].movementStarted = 0;
72+ scopeStatus["home.scope"].positionedAtBeginning = 0;
7373
74− scopeStatus["MockScope4"].movementStarted = 0;
75− scopeStatus["MockScope4"].positionedAtBeginning = 0;
74+ scopeStatus["applications.scope"].movementStarted = 0;
75+ scopeStatus["applications.scope"].positionedAtBeginning = 0;
7676
7777 scopeStatus["MockScope5"].movementStarted = 0;
7878 scopeStatus["MockScope5"].positionedAtBeginning = 0;
@@ -127,8 +127,8 @@ Item {
127127 compare(movementStartedSpy.count, 1, "DashContent should have emitted movementStarted signal when content list did.");
128128 compare(scopeStatus["MockScope1"].movementStarted, 1, "MockScope1 should have emitted movementStarted signal when content list did.");
129129 compare(scopeStatus["MockScope2"].movementStarted, 1, "MockScope2 should have emitted movementStarted signal when content list did.");
130− compare(scopeStatus["MockScope3"].movementStarted, 1, "MockScope3 should have emitted movementStarted signal when content list did.");
131− compare(scopeStatus["MockScope4"].movementStarted, 1, "MockScope4 should have emitted movementStarted signal when content list did.");
130+ compare(scopeStatus["home.scope"].movementStarted, 1, "home.scope should have emitted movementStarted signal when content list did.");
131+ compare(scopeStatus["applications.scope"].movementStarted, 1, "applications.scope should have emitted movementStarted signal when content list did.");
132132 compare(scopeStatus["MockScope5"].movementStarted, 1, "MockScope5 should have emitted movementStarted signal when content list did.");
133133 }
134134
@@ -140,8 +140,8 @@ Item {
140140 dashContent.positionedAtBeginning();
141141 compare(scopeStatus["MockScope1"].positionedAtBeginning, 1, "MockScope1 should have emitted positionedAtBeginning signal when DashContent did.");
142142 compare(scopeStatus["MockScope2"].positionedAtBeginning, 1, "MockScope2 should have emitted positionedAtBeginning signal when DashContent did.");
143− compare(scopeStatus["MockScope3"].positionedAtBeginning, 1, "MockScope3 should have emitted positionedAtBeginning signal when DashContent did.");
144− compare(scopeStatus["MockScope4"].positionedAtBeginning, 1, "MockScope4 should have emitted positionedAtBeginning signal when DashContent did.");
143+ compare(scopeStatus["home.scope"].positionedAtBeginning, 1, "home.scope should have emitted positionedAtBeginning signal when DashContent did.");
144+ compare(scopeStatus["applications.scope"].positionedAtBeginning, 1, "applications.scope should have emitted positionedAtBeginning signal when DashContent did.");
145145 compare(scopeStatus["MockScope5"].positionedAtBeginning, 1, "MockScope5 should have emitted positionedAtBeginning signal when DashContent did.");
146146 }
147147
tests/qmltests/Dash/tst_FilterGrids.qml+1−1
@@ -118,7 +118,7 @@ Rectangle {
118118 gridLoader.source = "../../../Dash/" + data.component;
119119
120120 // Wait until the FilterGrid is loaded by the loader
121− tryCompare(gridLoader, "status", Loader.Ready, "Loader couldn't load " + data.component);
121+ tryCompare(gridLoader, "status", Loader.Ready);
122122
123123 // Wait until the GridView inside the model has finished rendering
124124 var gridView = findChild(gridLoader, "responsiveGridViewGrid");
tests/qmltests/Greeter/tst_Lockscreen.qml+1
@@ -186,6 +186,7 @@ Rectangle {
186186 function test_unlock(data) {
187187 unlockedCheckBox.checked = false
188188 LightDM.Greeter.authenticate(data.username)
189+ waitForRendering(lockscreen)
189190
190191 var inputField = findChild(lockscreen, "pinentryField")
191192 if (data.alphanumeric) {
tests/qmltests/Notifications/tst_Notifications.qml+20−9
@@ -48,6 +48,7 @@ Row {
4848 function addSnapDecisionNotification() {
4949 var n = {
5050 type: Notification.SnapDecision,
51+ hints: Notification.ButtonTint,
5152 summary: "Tom Ato",
5253 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
5354 icon: "../graphics/avatars/funky.png",
@@ -189,8 +190,9 @@ Row {
189190 function test_NotificationRenderer_data() {
190191 return [
191192 {
192− tag: "Snap Decision with secondary icon",
193+ tag: "Snap Decision with secondary icon and button-tint",
193194 type: Notification.SnapDecision,
195+ hints: Notification.ButtonTint,
194196 summary: "Tom Ato",
195197 body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
196198 icon: "../graphics/avatars/funky.png",
@@ -205,7 +207,8 @@ Row {
205207 interactiveAreaEnabled: false,
206208 iconVisible: true,
207209 secondaryIconVisible: true,
208− buttonRowVisible: true
210+ buttonRowVisible: true,
211+ buttonTinted: true
209212 },
210213 {
211214 tag: "Ephemeral notification - icon-summary layout",
@@ -220,7 +223,8 @@ Row {
220223 interactiveAreaEnabled: false,
221224 iconVisible: false,
222225 secondaryIconVisible: true,
223− buttonRowVisible: false
226+ buttonRowVisible: false,
227+ buttonTinted: false
224228 },
225229 {
226230 tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
@@ -235,7 +239,8 @@ Row {
235239 interactiveAreaEnabled: false,
236240 iconVisible: false,
237241 secondaryIconVisible: true,
238− buttonRowVisible: false
242+ buttonRowVisible: false,
243+ buttonTinted: false
239244 },
240245 {
241246 tag: "Interactive notification",
@@ -250,10 +255,11 @@ Row {
250255 interactiveAreaEnabled: true,
251256 iconVisible: true,
252257 secondaryIconVisible: false,
253− buttonRowVisible: false
258+ buttonRowVisible: false,
259+ buttonTinted: false
254260 },
255261 {
256− tag: "Snap Decision without secondary icon",
262+ tag: "Snap Decision without secondary icon and no button-tint",
257263 type: Notification.SnapDecision,
258264 summary: "Bro Coly",
259265 body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.",
@@ -266,7 +272,8 @@ Row {
266272 interactiveAreaEnabled: false,
267273 iconVisible: true,
268274 secondaryIconVisible: false,
269− buttonRowVisible: true
275+ buttonRowVisible: true,
276+ buttonTinted: false
270277 },
271278 {
272279 tag: "Ephemeral notification",
@@ -281,7 +288,8 @@ Row {
281288 interactiveAreaEnabled: false,
282289 iconVisible: true,
283290 secondaryIconVisible: true,
284− buttonRowVisible: false
291+ buttonRowVisible: false,
292+ buttonTinted: false
285293 }
286294 ]
287295 }
@@ -356,6 +364,9 @@ Row {
356364 actionSpy.clear()
357365 }
358366
367+ // check the tinting of the positive/right button
368+ verify(buttonAccept.gradient === data.buttonTinted ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient, "button has the wrong color-tint")
369+
359370 // click the positive/right button
360371 mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2)
361372 actionSpy.wait()
@@ -370,7 +381,7 @@ Row {
370381 mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
371382 waitForRendering(notification)
372383 actionSpy.clear()
373− 
384+
374385 // test the additional buttons
375386 for (var i = 2; i < data.actions.length; i++) {
376387 waitForRendering(notification)
tests/qmltests/Panel/Menus/tst_IndicatorMenuWindow.qmldeleted−68
@@ -1,68 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../.."
20−import "../../../../Panel/Menus"
21−import Ubuntu.Components 0.1
22−import Unity.Test 0.1 as UT
23−
24−Item {
25− id: testIndicatorMenuWindowItem
26− width: units.gu(9)
27− height: units.gu(3)
28−
29− MouseArea {
30− id: mouseArea
31− anchors.fill: parent
32− }
33−
34− IndicatorMenuWindow {
35− id: indicatorMenuWindow
36− name: "TestIndicatorMenuWindow"
37− anchors.fill: parent
38− }
39−
40− UT.UnityTestCase {
41− name: "IndicatorMenuWindow"
42− when: windowShown
43−
44− function test_mouseEvent_data() {
45− return [
46− {tag: "visible", shown: true, opacity: 1.0, mouseClicks: 0},
47− {tag: "invisible", shown: false, opacity: 0.0, mouseClicks: 1},
48− ]
49− }
50−
51− function test_mouseEvent(data) {
52− indicatorMenuWindow.shown = data.shown
53− tryCompare(indicatorMenuWindow, "opacity", data.opacity)
54−
55− clickedSpy.clear()
56− mouseClick(indicatorMenuWindow, indicatorMenuWindow.width / 2,
57− indicatorMenuWindow.height / 2)
58− compare(clickedSpy.count, data.mouseClicks,
59− "Check for Mouse event eating by indicatorMenuWindow failed")
60− }
61− }
62−
63− SignalSpy {
64− id: clickedSpy
65− target: mouseArea
66− signalName: "clicked"
67− }
68−}
tests/qmltests/Panel/tst_IndicatorItem.qml+10−16
@@ -34,34 +34,28 @@ Rectangle {
3434 UT.UnityTestCase {
3535 name: "IndicatorItem"
3636
37− function init_test() {
38− }
39−
4037 function test_dimmed() {
41− init_test()
42−
43− indicatorItem.dimmed = true
44− compare(indicatorItem.opacity > 0, true, "IndicatorItem opacity should not be 0")
45− compare(indicatorItem.opacity < 1, true, "IndicatorItem opacity should not be 1")
38+ indicatorItem.dimmed = false;
39+ tryCompareFunction(function(){return indicatorItem.opacity}, 1.0);
40+ indicatorItem.dimmed = true;
41+ tryCompareFunction(function(){return indicatorItem.opacity < 1.0}, true);
4642 }
4743
4844 function test_highlight() {
49− var itemHighlight = findChild(indicatorItem, "highlight")
50− verify(itemHighlight != undefined)
45+ var itemHighlight = findChild(indicatorItem, "highlight");
46+ verify(itemHighlight != undefined);
5147
5248 indicatorItem.highlighted = true;
53− compare(itemHighlight.visible, true, "Indicator should be highlighted")
49+ compare(itemHighlight.visible, true, "Indicator should be highlighted");
5450
5551 indicatorItem.highlighted = false;
56− compare(itemHighlight.visible, false, "Indicator should not be highlighted")
52+ compare(itemHighlight.visible, false, "Indicator should not be highlighted");
5753 }
5854
5955 function test_empty() {
60− init_test()
61−
62− compare(indicatorItem.visible, false, "IndicatorItem should not be visible.")
56+ compare(indicatorItem.visible, false, "IndicatorItem should not be visible.");
6357 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
64− tryCompare(indicatorItem, "visible", true)
58+ tryCompare(indicatorItem, "visible", true);
6559 }
6660 }
6761}
tests/qmltests/Panel/tst_IndicatorRow.qml+21−35
@@ -32,7 +32,6 @@ Item {
3232
3333 function init_test()
3434 {
35− indicatorRow.overviewActive = false;
3635 indicatorRow.state = "initial";
3736 indicatorRow.currentItem = null;
3837 }
@@ -62,13 +61,13 @@ Item {
6261
6362 function test_set_current_item() {
6463 init_test();
65− indicatorRow.setItem(0);
64+ indicatorRow.setCurrentItem(0);
6665 compare(indicatorRow.indicatorsModel.get(indicatorRow.currentItemIndex).title, "Menu1", "Incorrect item at position 0");
6766
68− indicatorRow.setItem(1);
67+ indicatorRow.setCurrentItem(1);
6968 compare(indicatorRow.indicatorsModel.get(indicatorRow.currentItemIndex).title, "Menu2", "Incorrect item at position 1");
7069
71− indicatorRow.setItem(2);
70+ indicatorRow.setCurrentItem(2);
7271 compare(indicatorRow.indicatorsModel.get(indicatorRow.currentItemIndex).title, "Menu3", "Incorrect item at position 2");
7372 }
7473 }
@@ -84,13 +83,13 @@ Item {
8483 function test_current_item_commit() {
8584 init_test();
8685
87− indicatorRow.setItem(1);
86+ indicatorRow.setCurrentItem(1);
8887 indicatorRow.state = "commit";
89− tryCompare(get_indicator_item_at(0), "y", -indicatorRow.height);
90− tryCompare(get_indicator_item_at(1), "y", 0);
91− tryCompare(get_indicator_item_at(2), "y", -indicatorRow.height);
92− tryCompare(get_indicator_item_at(3), "y", -indicatorRow.height);
93− tryCompare(get_indicator_item_at(4), "y", -indicatorRow.height);
88+ tryCompare(get_indicator_item_at(0), "opacity", 0.0);
89+ tryCompare(get_indicator_item_at(1), "opacity", 1.0);
90+ tryCompare(get_indicator_item_at(2), "opacity", 0.0);
91+ tryCompare(get_indicator_item_at(3), "opacity", 0.0);
92+ tryCompare(get_indicator_item_at(4), "opacity", 0.0);
9493
9594 }
9695 }
@@ -107,7 +106,7 @@ Item {
107106 init_test();
108107
109108 indicatorRow.state = "initial";
110− indicatorRow.setItem(0);
109+ indicatorRow.setCurrentItem(0);
111110
112111 compare(indicatorRow.currentItem.highlighted, false, "Indicator should not highlight when in initial state");
113112 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in initial state");
@@ -120,9 +119,9 @@ Item {
120119 init_test();
121120
122121 indicatorRow.state = "hint";
123− indicatorRow.setItem(0);
122+ indicatorRow.setCurrentItem(0);
124123
125− compare(indicatorRow.currentItem.highlighted, false, "Indicator should not highlight when in hint state");
124+ compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in hint state");
126125 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in hint state");
127126 compare(get_indicator_item_at(2).highlighted, false, "Other indicators should not highlight when in hint state");
128127 compare(get_indicator_item_at(3).highlighted, false, "Other indicators should not highlight when in hint state");
@@ -133,7 +132,7 @@ Item {
133132 init_test();
134133
135134 indicatorRow.state = "reveal";
136− indicatorRow.setItem(0);
135+ indicatorRow.setCurrentItem(0);
137136
138137 compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in reveal state");
139138 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in commit state");
@@ -146,7 +145,7 @@ Item {
146145 init_test();
147146
148147 indicatorRow.state = "commit";
149− indicatorRow.setItem(0);
148+ indicatorRow.setCurrentItem(0);
150149
151150 compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in commit state");
152151 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in commit state");
@@ -159,7 +158,7 @@ Item {
159158 init_test();
160159
161160 indicatorRow.state = "locked";
162− indicatorRow.setItem(0);
161+ indicatorRow.setCurrentItem(0);
163162
164163 compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in locked state");
165164 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in locked state");
@@ -181,7 +180,7 @@ Item {
181180 init_test();
182181
183182 indicatorRow.state = "initial";
184− indicatorRow.setItem(0);
183+ indicatorRow.setCurrentItem(0);
185184
186185 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in intiial state");
187186 compare(get_indicator_item_at(1).dimmed, false, "Other indicators should not dim when in initial state");
@@ -194,9 +193,9 @@ Item {
194193 init_test();
195194
196195 indicatorRow.state = "hint";
197− indicatorRow.setItem(0);
196+ indicatorRow.setCurrentItem(0);
198197
199− compare(get_indicator_item_at(0).dimmed, true, "Current indicator should dim when in hint state");
198+ compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in hint state");
200199 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in hint state");
201200 compare(get_indicator_item_at(2).dimmed, true, "Other indicators should dim when in hint state");
202201 compare(get_indicator_item_at(3).dimmed, true, "Other indicators should dim when in hint state");
@@ -207,7 +206,7 @@ Item {
207206 init_test();
208207
209208 indicatorRow.state = "reveal";
210− indicatorRow.setItem(0);
209+ indicatorRow.setCurrentItem(0);
211210
212211 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in reveal state");
213212 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in reveal state");
@@ -220,7 +219,7 @@ Item {
220219 init_test();
221220
222221 indicatorRow.state = "commit";
223− indicatorRow.setItem(0);
222+ indicatorRow.setCurrentItem(0);
224223
225224 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in commit state");
226225 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in commit state");
@@ -233,7 +232,7 @@ Item {
233232 init_test();
234233
235234 indicatorRow.state = "locked";
236− indicatorRow.setItem(0);
235+ indicatorRow.setCurrentItem(0);
237236
238237 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in locked state");
239238 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in locked state");
@@ -241,18 +240,5 @@ Item {
241240 compare(get_indicator_item_at(3).dimmed, true, "Other indicators should dim when in locked state");
242241 compare(get_indicator_item_at(4).dimmed, true, "Other indicators should dim when in locked state");
243242 }
244−
245− function test_active_overview() {
246− init_test();
247−
248− indicatorRow.overviewActive = true;
249− indicatorRow.state = "commit";
250−
251− compare(get_indicator_item_at(0).dimmed, true, "Indicator should dim when in overview");
252− compare(get_indicator_item_at(1).dimmed, true, "Indicator should dim when in overview");
253− compare(get_indicator_item_at(2).dimmed, true, "Indicator should dim when in overview");
254− compare(get_indicator_item_at(3).dimmed, true, "Indicator should dim when in overview");
255− compare(get_indicator_item_at(4).dimmed, true, "Indicator should dim when in overview");
256− }
257243 }
258244}
tests/qmltests/Panel/tst_Indicators.qml+1−39
@@ -69,7 +69,6 @@ Item {
6969
7070 onClicked: {
7171 if (!indicators.shown) {
72− indicators.openOverview();
7372 indicators.show();
7473 } else {
7574 indicators.hide();
@@ -89,47 +88,10 @@ Item {
8988 tryCompare(indicators, "state", "initial");
9089 }
9190
92− // Showing the indicators should fully open the indicator panel with the overview menu visible.
91+ // Showing the indicators should fully open the indicator panel.
9392 function test_show() {
9493 indicators.show()
9594 tryCompare(indicators, "fullyOpened", true);
96−
97− // A show must open the indicators.
98− compare(findChild(indicators, "indicatorRow").overviewActive, true, "Overview indicator should be active when opened overview.")
99− }
100−
101− // Opening the overview menu will activate the overview panel.
102− function test_open_overview() {
103− indicators.openOverview();
104− compare(findChild(indicators, "indicatorRow").overviewActive, true, "Overview should be active when opened overview.")
105− }
106−
107− // Showing the indicators, then changing the progress (simulating drag) should keep the overview panel open until
108− // the reveal state is reached.
109− function test_slow_close_open_overview() {
110−
111− var indicator_row = findChild(indicators, "indicatorRow");
112− verify(indicator_row != undefined);
113−
114− indicators.show()
115− // wait for animation to end. (progress needs to be updated)
116− tryCompare(indicators.showAnimation, "running", false);
117− compare(indicator_row.overviewActive, true, "Overview should be active when opened overview.")
118−
119− // iteratively decrease the progress and ensure that it keeps the correct behaviour
120− var current_progress = indicators.progress - shell.height/20;
121− while (current_progress > 0) {
122− indicators.progress = current_progress;
123−
124− if (indicators.state == "commit" || indicators.state == "locked") {
125− compare(indicator_row.overviewActive, true, "Overview should be active when in locked or commit state after show.")
126− }
127− else if (indicators.state == "reveal" || indicators.state == "hint") {
128− compare(indicator_row.overviewActive, false, "Overview should be not active when not in commit or locked state.")
129− }
130−
131− current_progress = current_progress - shell.height/20;
132− }
13395 }
13496
13597 // Test the change in the revealer lateral position changes the current panel menu to fit the position
tests/qmltests/Panel/tst_MenuContent.qml+14−84
@@ -52,8 +52,8 @@ Item {
5252 height: parent.height - 50
5353 }
5454
55− Item {
56− id: click_me
55+ Rectangle {
56+ color: "#bbbbbb"
5757
5858 height: 50
5959 anchors {
@@ -62,65 +62,30 @@ Item {
6262 right: parent.right
6363 }
6464
65− Rectangle {
66− color: "#999999"
67−
68− anchors {
69− top: parent.top
70− left: parent.left
71− right: parent.horizontalCenter
72− bottom: parent.bottom
73− }
74−
75− Text {
76− text: "Devices"
77− anchors.fill: parent
78− horizontalAlignment: Text.AlignHCenter
79− verticalAlignment: Text.AlignVCenter
80− }
81−
82− MouseArea {
83− anchors.fill: parent
84− onClicked: menuContent.showOverview()
85− }
65+ Text {
66+ text: "Next Indicator"
67+ anchors.fill: parent
68+ horizontalAlignment: Text.AlignHCenter
69+ verticalAlignment: Text.AlignVCenter
8670 }
8771
88− Rectangle {
89− color: "#bbbbbb"
90−
91− anchors {
92− top: parent.top
93− left: parent.horizontalCenter
94− right: parent.right
95− bottom: parent.bottom
96− }
97−
98− Text {
99− text: "Next Indicator"
100− anchors.fill: parent
101− horizontalAlignment: Text.AlignHCenter
102− verticalAlignment: Text.AlignVCenter
103− }
104−
105− MouseArea {
106− anchors.fill: parent
107− onClicked: activate_next_content()
108− }
72+ MouseArea {
73+ anchors.fill: parent
74+ onClicked: activate_next_content()
10975 }
11076 }
11177
11278 function activate_next_content()
11379 {
114− if (menuContent.currentIndex == -1)
80+ if (menuContent.currentMenuIndex == -1)
11581 activate_content(0);
11682 else
117− activate_content((menuContent.currentIndex + 1) % indicatorsModel.count)
83+ activate_content((menuContent.currentMenuIndex + 1) % indicatorsModel.count)
11884 }
11985
12086 function activate_content(index)
12187 {
122− menuContent.currentIndex = index
123− menuContent.showMenu();
88+ menuContent.currentMenuIndex = index
12489 }
12590
12691 function get_test_menu_objecName(index) {
@@ -151,7 +116,6 @@ Item {
151116 when: windowShown
152117
153118 function init() {
154− menuContent.hideAll();
155119 if (menuContent.__contentActive)
156120 menuContent.releaseContent();
157121 tryCompare(menuContent, "__contentActive", false);
@@ -174,40 +138,6 @@ Item {
174138 compare(menus.currentIndex, menu_index, "Current menu index does not match selected menu index");
175139 tryCompareFunction(current_menu_equals_test_menu, true);
176140 }
177− // overview should not be visible.
178− tryCompare(findChild(menuContent, "overview"), "visible", false);
179− }
180−
181− function test_show_overview() {
182− menuContent.showOverview();
183−
184− var overview = findChild(menuContent, "overview");
185− tryCompare(overview, "visible", true);
186− tryCompare(overview, "enabled", true);
187− tryCompare(overview, "opacity", 1.0);
188−
189− // menus should not be enabled.
190− tryCompare(findChild(menuContent, "menus"), "opacity", 0);
191− tryCompare(findChild(menuContent, "menus"), "enabled", false);
192− }
193−
194− function test_overview_menuSelected_signal() {
195− menuContent.showOverview();
196−
197− var overview = findChild(menuContent, "overview");
198− var menus = menu_content_test.findChild(menuContent, "menus")
199−
200− var menu_count = indicatorsModel.count;
201− verify(menu_count > 0, "Menu count should be greater than zero");
202− for (var i = 0; i < menu_count; i++) {
203− // manually emit signal from overview.
204− // we dont want to go with mouse events here, otherwise we're testing the overview and not the signal.
205− overview.menuSelected(i);
206−
207− test_menu_objectName = get_test_menu_objecName(i);
208− compare(menus.currentIndex, i, "Current menu index does not match selected menu index");
209− tryCompareFunction(current_menu_equals_test_menu, true);
210− }
211141 }
212142
213143 // Calling activateContent should call start on all menus
@@ -267,7 +197,7 @@ Item {
267197
268198 for (var i = 0; i < 100; i++) {
269199 activate_content(i % menu_count);
270− compare(menuContent.currentIndex, i%menu_count);
200+ compare(menuContent.currentMenuIndex, i%menu_count);
271201 }
272202 wait(100);
273203 }
tests/qmltests/Panel/tst_Overview.qmldeleted−142
@@ -1,142 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import ".."
20−import "../../../Panel/Menus"
21−import "../../../Components"
22−import Unity.Test 0.1 as UT
23−import Unity.Indicators 0.1 as Indicators
24−
25−Rectangle {
26− id: shell
27− width: units.gu(40)
28− height: units.gu(80)
29− color: "black"
30−
31− Overview {
32− id: overview
33− anchors.fill: parent
34− indicatorsModel: mockModel
35− shown: true
36− }
37−
38− Item {
39− id: volumeControl
40− property int volume
41− function volumeUp() {
42− volume = Math.min(100, volume + 10);
43− }
44− function volumeDown() {
45− volume = Math.max(0, volume - 10);
46− }
47− }
48−
49− ListModel {
50− id: mockModel
51− ListElement {title: "fake1"; widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget1.qml"; indicatorProperties: ""}
52− ListElement {title: "fake2"; widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget2.qml"; indicatorProperties: ""}
53− ListElement {title: "fake3"; widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget3.qml"; indicatorProperties: ""}
54− }
55−
56− ListModel {
57− id: mockModel2
58− }
59−
60− SignalSpy {
61− id: clickSpy
62− target: overview
63− signalName: "menuSelected"
64− }
65−
66− UT.UnityTestCase {
67− name: "Overview"
68− when: windowShown
69−
70− function initTestCase() {
71− // Spin the event loop once because the UI builds up delayed
72− wait(0);
73− }
74−
75− function test_menuSelected() {
76− overview.indicatorsModel = mockModel;
77−
78− for (var i = 0; i < mockModel.count; ++i) {
79− var button = findChild(overview, "overviewGridButton" + i);
80− clickSpy.clear();
81− mouseClick(button, button.width / 2, button.height / 2);
82− compare(clickSpy.count, 1, "Clicking on grid didn't work");
83− compare(clickSpy.signalArguments[0][0], i, "Clicking the grid returned a wrong index");
84− }
85− }
86−
87− function test_dynamic_addition() {
88− var overviewGrid = findChild(overview, "overviewGrid");
89−
90− for(var i = 0; i < mockModel.count; ++i) {
91− mockModel2.append(mockModel.get(i));
92− }
93− overview.indicatorsModel = mockModel2;
94− overviewGrid.forceLayout();
95− waitForRendering(overviewGrid);
96−
97− var button = findChild(overview, "overviewGridButton2");
98− verify(button !== undefined, "button2 wasn't found");
99− button = findChild(overview, "overviewGridButton3");
100− compare(button, undefined, "There should only be 3 buttons... found at least 4...");
101−
102− mockModel2.append({title: "humppa", widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget4.qml", indicatorProperties: ""})
103− overviewGrid.forceLayout();
104− waitForRendering(overviewGrid);
105−
106− button = findChild(overview, "overviewGridButton3");
107− verify(button !== undefined, "button3 wasn't found");
108− }
109−
110− function test_volume_slider_data() {
111− return [
112− {tag: "0%", sliderPos:0},
113− {tag: "100%", sliderPos: 100},
114− {tag: "50%", sliderPos: 50}
115− ];
116− }
117−
118− function test_volume_slider(data) {
119− var volumeSlider = findChild(overview, "volumeSlider");
120− var startX = volumeSlider.width * volumeSlider.value / 100;
121− var startY = volumeSlider.y + volumeSlider.height / 2;
122− var stopX = (volumeSlider.width - units.gu(5)) * data.sliderPos / 100;
123− var stopY = volumeSlider.y + volumeSlider.height / 2;
124− mouseFlick(volumeSlider, startX, startY, stopX, stopY, true, true, 0.1);
125− }
126−
127− function test_volume_buttons(data) {
128− var volumeDownButton = findChild(overview, "minVolumeIcon");
129− var volumeUpButton = findChild(overview, "maxVolumeIcon");
130−
131− for (var i = 0; i < 10; ++i) {
132− mouseClick(volumeDownButton, volumeDownButton.width / 2, volumeDownButton.height / 2);
133− wait(0)
134− }
135− tryCompare(volumeControl, "volume", 0);
136− for (var i = 0; i < 10; ++i) {
137− mouseClick(volumeUpButton, 1, 1);
138− wait(0)
139− }
140− }
141− }
142−}
tests/qmltests/Panel/tst_Panel.qml+101−61
@@ -30,11 +30,11 @@ Item {
3030 width: units.gu(40)
3131 height: units.gu(80)
3232
33− property bool search_clicked: false
33+ property bool searchClicked: false
3434
3535 Connections {
3636 target: panel
37− onSearchClicked: search_clicked = true
37+ onSearchClicked: searchClicked = true
3838 }
3939
4040 Panel {
@@ -54,27 +54,26 @@ Item {
5454
5555
5656 function init() {
57− search_clicked = false;
57+ searchClicked = false;
5858 panel.indicators.hide();
5959 tryCompare(panel.indicators.hideAnimation, "running", false);
6060 tryCompare(panel.indicators, "state", "initial");
6161 }
6262
6363 function get_indicator_item(index) {
64− var row_repeater = findChild(panel.indicators, "rowRepeater");
65− verify(row_repeater != undefined)
66− return row_repeater.itemAt(index);
64+ var rowRepeater = findChild(panel.indicators, "rowRepeater");
65+ verify(rowRepeater != undefined);
66+ return rowRepeater.itemAt(index);
6767 }
6868
6969 function get_indicator_item_position(index) {
70+ var indicatorRow = findChild(panel.indicators, "indicatorRow");
71+ verify(indicatorRow != undefined);
7072
71− var indicator_row = findChild(panel.indicators, "indicatorRow");
72− verify(indicator_row != undefined)
73−
74− var indicator_item = get_indicator_item(index);
75− verify(indicator_item != undefined);
73+ var indicatorItem = get_indicator_item(index);
74+ verify(indicatorItem != undefined);
7675
77− return panel.mapFromItem(indicator_item, indicator_item.width/2, indicator_item.height/2);
76+ return panel.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
7877 }
7978
8079 // Pressing on the indicator panel should activate the indicator hints
@@ -83,11 +82,11 @@ Item {
8382 panel.fullscreenMode = false;
8483 // Wait for the indicators to get into position.
8584 // (switches between normal and fullscreen modes are animated)
86− tryCompare(panel.indicators, "y", 0)
85+ tryCompare(panel.indicators, "y", 0);
8786
88− var indicator_item_coord = get_indicator_item_position(0);
87+ var indicatorItemCoord = get_indicator_item_position(0);
8988
90− touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2)
89+ touchPress(panel, indicatorItemCoord.x, panel.panelHeight / 2);
9190
9291 // hint animation should be run, meaning that indicators will move downwards
9392 // by hintValue pixels without any drag taking place
@@ -96,7 +95,7 @@ Item {
9695 tryCompare(panel.indicators, "partiallyOpened", true);
9796 tryCompare(panel.indicators, "fullyOpened", false);
9897
99− touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2)
98+ touchRelease(panel, indicatorItemCoord.x, panel.panelHeight/2);
10099 }
101100
102101 // Pressing on the top edge of the screen should have no effect if the panel
@@ -105,31 +104,31 @@ Item {
105104 panel.fullscreenMode = true;
106105 // Wait for the indicators to get into position.
107106 // (switches between normal and fullscreen modes are animated)
108− tryCompare(panel.indicators, "y", -panel.panelHeight)
107+ tryCompare(panel.indicators, "y", -panel.panelHeight);
109108
110− var indicator_item_coord = get_indicator_item_position(0);
109+ var indicatorItemCoord = get_indicator_item_position(0);
111110
112− touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2)
111+ touchPress(panel, indicatorItemCoord.x, panel.panelHeight / 2);
113112
114113 // Give some time for a hint animation to change things, if any
115− wait(500)
114+ wait(500);
116115
117116 // no hint animation when fullscreen
118− compare(panel.indicators.y, -panel.panelHeight)
117+ compare(panel.indicators.y, -panel.panelHeight);
119118 var indicatorRow = findChild(panel.indicators, "indicatorRow");
120− verify(indicatorRow != undefined)
121− compare(indicatorRow.y, 0)
122− compare(panel.indicators.height, panel.indicators.panelHeight)
119+ verify(indicatorRow != undefined);
120+ compare(indicatorRow.y, 0);
121+ compare(panel.indicators.height, panel.indicators.panelHeight);
123122 compare(panel.indicators.partiallyOpened, false,
124123 "Indicator should not be partially opened when panel is pressed in" +
125− " fullscreenmode")
124+ " fullscreenmode");
126125 compare(panel.indicators.fullyOpened, false, "Indicator should not be partially" +
127− " opened when panel is pressed in fullscreenmode")
126+ " opened when panel is pressed in fullscreenmode");
128127
129− touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2)
128+ touchRelease(panel, indicatorItemCoord.x, panel.panelHeight/2);
130129 }
131130
132− function test_drag_show_data() { return get_window_data() }
131+ function test_drag_show_data() { return get_window_data(); }
133132
134133 // Dragging from a indicator item in the panel will gradually expose the
135134 // indicators, first by running the hint animation, then after dragging down will
@@ -137,53 +136,53 @@ Item {
137136 function test_drag_show(data) {
138137 panel.fullscreenMode = data.fullscreenFlag;
139138
140− var indicator_row = findChild(panel.indicators, "indicatorRow");
141− verify(indicator_row != undefined)
139+ var indicatorRow = findChild(panel.indicators, "indicatorRow");
140+ verify(indicatorRow != undefined);
142141
143− var row_repeater = findChild(panel.indicators, "rowRepeater");
144− verify(indicator_row != undefined)
142+ var rowRepeater = findChild(panel.indicators, "rowRepeater");
143+ verify(indicatorRow != undefined);
145144
146− var menu_content = findChild(panel.indicators, "menuContent");
147− verify(indicator_row != undefined)
145+ var menuContent = findChild(panel.indicators, "menuContent");
146+ verify(indicatorRow != undefined);
148147
149148 // Wait for the indicators to get into position.
150149 // (switches between normal and fullscreen modes are animated)
151150 if (data.fullscreenFlag) {
152− tryCompare(panel.indicators, "y", -panel.panelHeight)
151+ tryCompare(panel.indicators, "y", -panel.panelHeight);
153152 } else {
154− tryCompare(panel.indicators, "y", 0)
153+ tryCompare(panel.indicators, "y", 0);
155154 }
156155
157156 // do this for each indicator item
158− for (var i = 0; i < row_repeater.count; i++) {
157+ for (var i = 0; i < rowRepeater.count; i++) {
159158
160− var indicator_item = get_indicator_item(i);
161− verify(indicator_item != undefined)
159+ var indicatorItem = get_indicator_item(i);
160+ verify(indicatorItem != undefined);
162161
163− var indicator_item_coord = get_indicator_item_position(i);
162+ var indicatorItemCoord = get_indicator_item_position(i);
164163
165164 touchPress(panel,
166− indicator_item_coord.x, panel.panelHeight / 2)
165+ indicatorItemCoord.x, panel.panelHeight / 2);
167166
168167 // 1) Drag the mouse down
169168 touchFlick(panel,
170− indicator_item_coord.x, panel.panelHeight / 2,
171− indicator_item_coord.x, panel.height * 0.8,
172− false /* beginTouch */, false /* endTouch */)
169+ indicatorItemCoord.x, panel.panelHeight / 2,
170+ indicatorItemCoord.x, panel.height * 0.8,
171+ false /* beginTouch */, false /* endTouch */);
173172
174173 // Indicators height should follow the drag, and therefore increase accordingly.
175174 // They should be at least half-way through the screen
176175 tryCompareFunction(
177176 function() {return panel.indicators.height >= panel.height * 0.5},
178− true)
177+ true);
179178
180− touchRelease(panel, indicator_item_coord.x, panel.height * 0.8)
179+ touchRelease(panel, indicatorItemCoord.x, panel.height * 0.8);
181180
182− compare(indicator_row.currentItem, indicator_item,
183− "Incorrect item activated at position " + i)
184− compare(menu_content.__shown, true, "Menu conetent should be enabled for item at position " + i);
181+ compare(indicatorRow.currentItem, indicatorItem,
182+ "Incorrect item activated at position " + i);
183+ compare(menuContent.currentMenuIndex, i, "Menu conetent should be enabled for item at position " + i);
185184
186− // init for next indicator_item
185+ // init for next indicatorItem
187186 init();
188187 }
189188 }
@@ -192,26 +191,67 @@ Item {
192191 panel.fullscreenMode = false;
193192 panel.searchVisible = true;
194193
195− var search_indicator = findChild(panel, "search");
196− verify(search_indicator != undefined);
194+ var searchIndicator = findChild(panel, "search");
195+ verify(searchIndicator != undefined);
197196
198− tap(search_indicator, 1, 1)
197+ tap(searchIndicator, 1, 1);
199198
200− compare(search_clicked, true,
201− "Tapping search indicator while it was enabled did not emit searchClicked signal")
199+ compare(searchClicked, true,
200+ "Tapping search indicator while it was enabled did not emit searchClicked signal");
202201 }
203202
204203 function test_search_click_when_not_visible() {
205204 panel.fullscreenMode = false;
206− panel.searchVisible = false
205+ panel.searchVisible = false;
206+
207+ var searchIndicator = findChild(panel, "search");
208+ verify(searchIndicator != undefined);
209+
210+ tap(searchIndicator, 1, 1);
211+
212+ compare(searchClicked, false,
213+ "Tapping search indicator while it was not visible emitted searchClicked signal");
214+ }
215+
216+ // Test the vertical velocity check when flicking the indicators open at an angle.
217+ // If the vertical velocity is above a specific point, we shouldnt change active indicators
218+ // if the x position changes
219+ function test_vertical_velocity_detector() {
220+ panel.fullscreenMode = false;
221+ panel.searchVisible = false;
222+
223+ var indicatorRow = findChild(panel.indicators, "indicatorRow");
224+ verify(indicatorRow != undefined);
225+
226+ var rowRepeater = findChild(panel.indicators, "rowRepeater");
227+ verify(indicatorRow != undefined);
228+
229+ // Get the first indicator
230+ var indicatorItemFirst = get_indicator_item(0);
231+ verify(indicatorItemFirst != undefined);
232+
233+ var indicatorItemCoordFirst = get_indicator_item_position(0);
234+ var indicatorItemCoordNext = get_indicator_item_position(indicatorRow.count - 1);
235+
236+ touchPress(panel,
237+ indicatorItemCoordFirst.x, panel.panelHeight / 2);
238+
239+ // 1) Drag the mouse down to hint a bit
240+ touchFlick(panel,
241+ indicatorItemCoordFirst.x, panel.panelHeight / 2,
242+ indicatorItemCoordFirst.x, panel.panelHeight * 2,
243+ false /* beginTouch */, false /* endTouch */);
207244
208− var search_indicator = findChild(panel, "search");
209− verify(search_indicator != undefined);
245+ tryCompare(indicatorRow, "currentItem", indicatorItemFirst)
210246
211− tap(search_indicator, 1, 1)
247+ // 1) Flick mouse down to bottom
248+ touchFlick(panel,
249+ indicatorItemCoordFirst.x, panel.panelHeight * 2,
250+ indicatorItemCoordNext.x, panel.height,
251+ false /* beginTouch */, true /* endTouch */,
252+ units.gu(10) /* speed */, 30 /* iterations */); // more samples needed for accurate velocity
212253
213− compare(search_clicked, false,
214− "Tapping search indicator while it was not visible emitted searchClicked signal")
254+ compare(indicatorRow.currentItem, indicatorItemFirst, "First indicator should still be the current item");
215255 }
216256 }
217257}
tests/qmltests/Panel/tst_SearchIndicator.qml+8−10
@@ -41,24 +41,22 @@ Item {
4141 when: windowShown
4242
4343 function test_clickedSignal() {
44− clickedSpy.clear()
44+ clickedSpy.clear();
4545 mouseClick(searchIndicator,
4646 searchIndicator.width / 2, searchIndicator.height / 2);
47− compare(clickedSpy.count, 1)
47+ compare(clickedSpy.count, 1);
4848 }
4949
5050 function test_hideUp() {
51− var container = findChild(searchIndicator, "container")
52− searchIndicator.state = "hiddenUp"
53− tryCompare(container, "opacity", 0)
54− tryCompare(container, "y", -container.height)
51+ var container = findChild(searchIndicator, "container");
52+ searchIndicator.state = "hidden";
53+ tryCompare(container, "opacity", 0);
5554 }
5655
5756 function test_show() {
58− var container = findChild(searchIndicator, "container")
59− searchIndicator.state = "visible"
60− tryCompare(container, "opacity", 1)
61− tryCompare(container, "y", 0)
57+ var container = findChild(searchIndicator, "container");
58+ searchIndicator.state = "visible";
59+ tryCompare(container, "opacity", 1);
6260 }
6361 }
6462}
tests/qmltests/tst_Shell.qmlnew file+281
@@ -0,0 +1,281 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Daniel d'Andrada <daniel.dandrada@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+import QtQuick 2.0
21+import QtTest 1.0
22+import Ubuntu.Application 0.1
23+import Unity.Test 0.1 as UT
24+
25+import "../.."
26+
27+Item {
28+ width: shell.width
29+ height: shell.height
30+
31+ QtObject {
32+ id: applicationArguments
33+
34+ function hasGeometry() {
35+ return false;
36+ }
37+
38+ function width() {
39+ return 0;
40+ }
41+
42+ function height() {
43+ return 0;
44+ }
45+ }
46+
47+ Shell {
48+ id: shell
49+ }
50+
51+ UT.UnityTestCase {
52+ name: "Shell"
53+ when: windowShown
54+
55+ function initTestCase() {
56+ // swipe away the greeter/lockscreen
57+ var touchX = shell.width - (shell.edgeSize / 2);
58+ var touchY = shell.height / 2;
59+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
60+
61+ var dash = findChild(shell, "dash");
62+ // wait until the animation has finished
63+ tryCompare(dash, "contentScale", 1.0);
64+ tryCompare(dash, "opacity", 1.0);
65+ }
66+
67+ function cleanup() {
68+ // kill all (fake) running apps
69+ ApplicationManager.mainStageApplications.clear();
70+ ApplicationManager.sideStageApplications.clear();
71+
72+ var dashHome = findChild(shell, "DashHome");
73+ swipeUntilScopeViewIsReached(dashHome);
74+ }
75+
76+ /*
77+ Test the effect of a right-edge drag on the dash in 3 situations:
78+ 1 - when no application has been launched yet
79+ 2 - when there's a minimized application
80+ 3 - after the last running application has been closed/stopped
81+
82+ The behavior of Dash on 3 should be the same as on 1.
83+ */
84+ function test_rightEdgeDrag() {
85+ checkRightEdgeDragWithNoRunningApps();
86+
87+ dragLauncherIntoView();
88+
89+ // Launch an app from the launcher
90+ tapOnAppIconInLauncher();
91+ waitUntilApplicationWindowIsFullyVisible();
92+
93+ // Minimize the application we just launched
94+ swipeFromLeftEdge();
95+
96+ waitForUIToSettle();
97+
98+ checkRightEdgeDragWithMinimizedApp();
99+
100+ // Minimize that application once again
101+ swipeFromLeftEdge();
102+
103+ // kill it
104+ ApplicationManager.mainStageApplications.clear();
105+
106+ waitForUIToSettle();
107+
108+ // Right edge behavior should now be the same as before that app was launched
109+ checkRightEdgeDragWithNoRunningApps();
110+ }
111+
112+ /*
113+ Perform a right-edge drag when the Dash is being show and there are
114+ no running/minimized apps to be restored.
115+
116+ The expected behavior is that an animation should be played to hint the
117+ user that his right-edge drag gesture has been successfully recognized
118+ but there is no application to be brought to foreground.
119+ */
120+ function checkRightEdgeDragWithNoRunningApps() {
121+ var touchX = shell.width - (shell.edgeSize / 2);
122+ var touchY = shell.height / 2;
123+
124+ var dash = findChild(shell, "dash");
125+ // check that dash has normal scale and opacity
126+ compare(dash.contentScale, 1.0);
127+ compare(dash.opacity, 1.0);
128+
129+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
130+ true /* beginTouch */, false /* endTouch */);
131+
132+ // check that Dash has been scaled down and had its opacity reduced
133+ tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
134+ tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
135+
136+ touchRelease(shell, shell.width * 0.1, touchY);
137+
138+ // and now everything should have gone back to normal
139+ tryCompare(dash, "contentScale", 1.0);
140+ tryCompare(dash, "opacity", 1.0);
141+ }
142+
143+ /*
144+ Perform a right-edge drag when the Dash is being show and there is
145+ a running/minimized app to be restored.
146+
147+ The expected behavior is that the dash should fade away and ultimately be
148+ made invisible once the gesture is finished as the restored app will now
149+ be on foreground.
150+ */
151+ function checkRightEdgeDragWithMinimizedApp() {
152+ var touchX = shell.width - (shell.edgeSize / 2);
153+ var touchY = shell.height / 2;
154+
155+ var dash = findChild(shell, "dash");
156+ // check that dash has normal scale and opacity
157+ tryCompare(dash, "contentScale", 1.0);
158+ tryCompare(dash, "opacity", 1.0);
159+
160+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
161+ true /* beginTouch */, false /* endTouch */);
162+
163+ // check that Dash has been scaled down and had its opacity reduced
164+ tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
165+ tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
166+
167+ touchRelease(shell, shell.width * 0.1, touchY);
168+
169+ // dash should have gone away, now that the app is on foreground
170+ tryCompare(dash, "visible", false);
171+ }
172+
173+ // Wait for the whole UI to settle down
174+ function waitForUIToSettle() {
175+ waitUntilApplicationWindowIsFullyHidden();
176+ var dashContentList = findChild(shell, "dashContentList");
177+ tryCompare(dashContentList, "moving", false);
178+ }
179+
180+ function dragLauncherIntoView() {
181+ var launcherPanel = findChild(shell, "launcherPanel");
182+ verify(launcherPanel.x = - launcherPanel.width);
183+ swipeFromLeftEdge();
184+ tryCompare(launcherPanel, "x", 0);
185+ }
186+
187+ function tapOnAppIconInLauncher() {
188+ var launcherPanel = findChild(shell, "launcherPanel");
189+
190+ // pick the first icon, the one at the bottom.
191+ var appIcon = findChild(launcherPanel, "launcherDelegate0")
192+
193+ // Swipe upwards over the launcher to ensure that this icon
194+ // at the bottom is not folded and faded away.
195+ var touchStartX = launcherPanel.width / 2;
196+ var touchStartY = launcherPanel.height / 2;
197+ touchFlick(launcherPanel, touchStartX, touchStartY, touchStartX, 0);
198+ tryCompare(launcherPanel, "moving", false);
199+
200+ // NB tapping (i.e., using touch events) doesn't activate the icon... go figure...
201+ mouseClick(appIcon, appIcon.width / 2, appIcon.height / 2);
202+ }
203+
204+ function waitUntilApplicationWindowIsFullyVisible() {
205+ var underlay = findChild(shell, "underlay");
206+ tryCompare(underlay, "visible", false);
207+ }
208+
209+ function waitUntilApplicationWindowIsFullyHidden() {
210+ var stages = findChild(shell, "stages");
211+ tryCompare(stages, "fullyHidden", true);
212+ }
213+
214+ function swipeUntilScopeViewIsReached(scopeView) {
215+ while (!itemIsOnScreen(scopeView)) {
216+ if (itemIsToLeftOfScreen(scopeView)) {
217+ swipeRightFromCenter();
218+ } else {
219+ swipeLeftFromCenter();
220+ }
221+ waitUntilItemStopsMoving(scopeView);
222+ }
223+ }
224+
225+ function swipeFromLeftEdge() {
226+ var touchStartX = 2;
227+ var touchStartY = shell.height / 2;
228+ touchFlick(shell, touchStartX, touchStartY, shell.width * 0.75, touchStartY);
229+ }
230+
231+ function swipeLeftFromCenter() {
232+ var touchStartX = shell.width / 2;
233+ var touchStartY = shell.height / 2;
234+ touchFlick(shell, touchStartX, touchStartY, 0, touchStartY);
235+ }
236+
237+ function swipeRightFromCenter() {
238+ var touchStartX = shell.width / 2;
239+ var touchStartY = shell.height / 2;
240+ touchFlick(shell, touchStartX, touchStartY, shell.width, touchStartY);
241+ }
242+
243+ function swipeUpFromCenter() {
244+ var touchStartX = shell.width / 2;
245+ var touchStartY = shell.height / 2;
246+ touchFlick(shell, touchStartX, touchStartY, touchStartX, 0);
247+ }
248+
249+ function itemIsOnScreen(item) {
250+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
251+
252+ return itemRectInShell.x >= 0
253+ && itemRectInShell.y >= 0
254+ && itemRectInShell.x + itemRectInShell.width <= shell.width
255+ && itemRectInShell.y + itemRectInShell.height <= shell.height;
256+ }
257+
258+ function itemIsToLeftOfScreen(item) {
259+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
260+ return itemRectInShell.x < 0;
261+ }
262+
263+ function waitUntilItemStopsMoving(item) {
264+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
265+ var previousX = itemRectInShell.x;
266+ var previousY = itemRectInShell.y;
267+ var isStill = false;
268+
269+ do {
270+ wait(100);
271+ itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
272+ if (itemRectInShell.x == previousX && itemRectInShell.y == previousY) {
273+ isStill = true;
274+ } else {
275+ previousX = itemRectInShell.x;
276+ previousY = itemRectInShell.y;
277+ }
278+ } while (!isStill);
279+ }
280+ }
281+}
tests/utils/modules/Unity/Test/UnityTestCase.qml+32−23
@@ -32,32 +32,34 @@ TestCase {
3232 // Qt uses in QQuickViewTestUtil::flick
3333 // speed is in pixels/second
3434 function mouseFlick(item, x, y, toX, toY, pressMouse, releaseMouse,
35− speed) {
35+ speed, iterations) {
3636 pressMouse = ((pressMouse != null) ? pressMouse : true); // Default to true for pressMouse if not present
3737 releaseMouse = ((releaseMouse != null) ? releaseMouse : true); // Default to true for releaseMouse if not present
3838
3939 // set a default speed if not specified
4040 speed = (speed != null) ? speed : units.gu(10);
4141
42+ // set a default iterations if not specified
43+ iterations = (iterations !== undefined) ? iterations : 5
44+
4245 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
4346 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
4447
45− var nIterations = 5
46− var timeStep = totalTime / nIterations
47− var diffX = (toX - x) / nIterations
48− var diffY = (toY - y) / nIterations
48+ var timeStep = totalTime / iterations
49+ var diffX = (toX - x) / iterations
50+ var diffY = (toY - y) / iterations
4951 if (pressMouse) {
5052 fakeDateTime.currentTimeMs += timeStep
5153 mousePress(item, x, y)
5254 }
53− for (var i = 0; i < nIterations; ++i) {
55+ for (var i = 0; i < iterations; ++i) {
5456 fakeDateTime.currentTimeMs += timeStep
55− if (i === nIterations - 1) {
57+ if (i === iterations - 1) {
5658 // Avoid any rounding errors by making the last move be at precisely
5759 // the point specified
58− mouseMove(item, toX, toY, nIterations / speed)
60+ mouseMove(item, toX, toY, iterations / speed)
5961 } else {
60− mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, nIterations / speed)
62+ mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
6163 }
6264 }
6365 if (releaseMouse) {
@@ -70,11 +72,16 @@ TestCase {
7072 // Find an object with the given name recursively, starting
7173 // at the given object "obj"
7274 function findChild(obj,objectName) {
73− for (var i in obj.children) {
74− var child = obj.children[i];
75− if (child.objectName === objectName) return child;
76− var subChild = findChild(child,objectName);
77− if (subChild !== undefined) return subChild;
75+ var childs = new Array(0);
76+ childs.push(obj)
77+ while (childs.length > 0) {
78+ if (childs[0].objectName == objectName) {
79+ return childs[0]
80+ }
81+ for (var i in childs[0].data) {
82+ childs.push(childs[0].data[i])
83+ }
84+ childs.splice(0, 1);
7885 }
7986 return undefined;
8087 }
@@ -186,7 +193,7 @@ TestCase {
186193 }
187194
188195 // speed is in pixels/second
189− function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed) {
196+ function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
190197
191198 // Default to true for beginTouch if not present
192199 beginTouch = (beginTouch !== undefined) ? beginTouch : true
@@ -197,13 +204,15 @@ TestCase {
197204 // Set a default speed if not specified
198205 speed = (speed !== undefined) ? speed : units.gu(10)
199206
207+ // Set a default iterations if not specified
208+ var iterations = (iterations !== undefined) ? iterations : 5
209+
200210 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
201211 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
202212
203− var nIterations = 5
204− var timeStep = totalTime / nIterations
205− var diffX = (toX - x) / nIterations
206− var diffY = (toY - y) / nIterations
213+ var timeStep = totalTime / iterations
214+ var diffX = (toX - x) / iterations
215+ var diffY = (toY - y) / iterations
207216 if (beginTouch) {
208217 fakeDateTime.currentTimeMs += timeStep
209218
@@ -211,17 +220,17 @@ TestCase {
211220 event.press(0 /* touchId */, x, y)
212221 event.commit()
213222 }
214− for (var i = 0; i < nIterations; ++i) {
223+ for (var i = 0; i < iterations; ++i) {
215224 fakeDateTime.currentTimeMs += timeStep
216− if (i === nIterations - 1) {
225+ if (i === iterations - 1) {
217226 // Avoid any rounding errors by making the last move be at precisely
218227 // the point specified
219− wait(nIterations / speed)
228+ wait(iterations / speed)
220229 var event = touchEvent()
221230 event.move(0 /* touchId */, toX, toY)
222231 event.commit()
223232 } else {
224− wait(nIterations / speed)
233+ wait(iterations / speed)
225234 var event = touchEvent()
226235 event.move(0 /* touchId */, x + (i + 1) * diffX, y + (i + 1) * diffY)
227236 event.commit()