on xenial help sign in
Merge with trunk
commit0868a6b5bf445a59cfb182577be2aa024e51909c authorNick Dedekind <nicholas.dedekind@gmail.com> dateMon 5 Aug 2013, 09:36 (13 years ago) parenta67c059b754d9f
133 files changed+2005−529
Components/ApplicationManagerWrapper.qml+10−1 Components/CrossFadeImage.qml+3−1 Components/Stage.qml+14 Dash/DashApps.qml+1−1 Dash/DashHome.qml+1 Dash/DashMusic.qml+2−2 Dash/DashVideos.qml+3−4 Dash/GenericScopeView.qml+9 Greeter/Greeter.qml+2−3 Greeter/GreeterContent.qml−2 Greeter/Lockscreen.qml+9−9 Greeter/PinLockscreen.qml+110−41 Greeter/PinPadButton.qml+5−16 Panel/Indicators/client/IndicatorsClient.qml+8−9 Panel/Indicators/client/IndicatorsPage.qml+57−12 Panel/Indicators/client/IndicatorsTree.qml+62 Shell.qml+92−35 debian/changelog+145 debian/control+6−2 debian/unity8-private.install+1 main.cpp+1−1 plugins/CMakeLists.txt+1 plugins/ListViewWithPageHeader/CMakeLists.txt+5−1 plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+97−13 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/Unity/CMakeLists.txt+1−1 plugins/Unity/Indicators/CMakeLists.txt+1 plugins/Unity/Indicators/modelprinter.cpp+114 plugins/Unity/Indicators/modelprinter.h+50 plugins/Unity/Indicators/plugin.cpp+2 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 po/ar.po+2−2 po/az.po+2−2 po/bg.po+2−2 po/ca.po+2−2 po/de.po+2−2 po/el.po+2−2 po/en_AU.po+2−2 po/en_GB.po+2−2 po/eo.po+2−2 po/es.po+2−2 po/fi.po+2−2 po/fo.po+2−2 po/fr.po+2−2 po/gl.po+2−2 po/he.po+2−2 po/hr.po+2−2 po/hu.po+2−2 po/hy.po+2−2 po/id.po+2−2 po/it.po+2−2 po/ja.po+2−2 po/kn.po+2−2 po/ko.po+2−2 po/ky.po+2−2 po/lv.po+2−2 po/my.po+2−2 po/nb.po+2−2 po/nl.po+2−2 po/pl.po+2−2 po/pt_BR.po+2−2 po/ro.po+2−2 po/ru.po+2−2 po/si.po+2−2 po/sl.po+2−2 po/sr.po+2−2 po/sv.po+2−2 po/te.po+2−2 po/tr.po+2−2 po/ug.po+2−2 po/uk.po+2−2 po/zh_CN.po+2−2 po/zh_TW.po+2−2 tests/autopilot/unity8/indicators_client/tests/test_battery.py+11−3 tests/autopilot/unity8/shell/__init__.py+1−27 tests/autopilot/unity8/shell/emulators/greeter.py+4−1 tests/autopilot/unity8/shell/emulators/hud.py+4−7 tests/autopilot/unity8/shell/emulators/main_window.py+1−1 tests/autopilot/unity8/shell/tests/__init__.py+53−1 tests/autopilot/unity8/shell/tests/test_hud.py+5−10 tests/autopilot/unity8/shell/tests/test_lock_screen.py+58−28 tests/data/unity/backgrounds/blue.png tests/data/unity/backgrounds/red.png tests/mocks/CMakeLists.txt+2 tests/mocks/GSettings/CMakeLists.txt+31 tests/mocks/GSettings/fake_gsettings.cpp+102 tests/mocks/GSettings/fake_gsettings.h+90 tests/mocks/GSettings/plugin.cpp+33 tests/mocks/GSettings/plugin.h+31 tests/mocks/GSettings/qmldir+2 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+6−2 tests/mocks/Ubuntu/Application/ApplicationManager.h+4 tests/mocks/Unity/CMakeLists.txt+1 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/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+12 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+63−2 tests/plugins/Unity/Indicators/indicatorsmanagertest.cpp+1−1 tests/plugins/Unity/Indicators/indicatorsmodeltest.cpp+1−1 tests/plugins/Unity/Indicators/menucontentactivatortest.cpp+1−1 tests/plugins/Utils/qlimitproxymodeltest.cpp+1−1 tests/plugins/Utils/qsortfilterproxymodeltest.cpp+1−1 tests/qmltests/CMakeLists.txt+3 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/tst_Shell.qml+295 tests/utils/modules/Unity/Test/UnityTestCase.qml+10−5
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/CrossFadeImage.qml+3−1
@@ -85,7 +85,7 @@ Item {
8585 Connections {
8686 target: __nextImage
8787 onStatusChanged: {
88− if (__nextImage.status == Image.Ready) {
88+ if (__nextImage.status == Image.Ready || __nextImage.status == Image.Error) {
8989 swapImages();
9090 }
9191 }
@@ -96,6 +96,7 @@ Item {
9696 anchors.fill: parent
9797 cache: false
9898 asynchronous: true
99+ fillMode: Image.PreserveAspectCrop
99100 z: 1
100101 }
101102
@@ -104,6 +105,7 @@ Item {
104105 anchors.fill: parent
105106 cache: false
106107 asynchronous: true
108+ fillMode: Image.PreserveAspectCrop
107109 z: 0
108110 }
109111
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
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/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/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/GenericScopeView.qml+9
@@ -114,7 +114,16 @@ ScopeView {
114114 }
115115 }
116116
117+ function getDefaultRendererId(contentType) {
118+ switch (contentType) {
119+ default: return "grid";
120+ }
121+ }
122+
117123 function getRenderer(rendererId, contentType) {
124+ if (rendererId == "default") {
125+ rendererId = getDefaultRendererId(contentType);
126+ }
118127 switch (rendererId) {
119128 case "grid": {
120129 switch (contentType) {
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−2
@@ -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
@@ -38,7 +37,6 @@ MouseArea {
3837
3938 source: shell.background
4039 anchors.fill: parent
41− crossFade: false
4240 fadeInFirst: false
4341 }
4442
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}
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+}
Shell.qml+92−35
@@ -15,10 +15,12 @@
1515 */
1616
1717import QtQuick 2.0
18+import GSettings 1.0
1819import Ubuntu.Application 0.1
1920import Ubuntu.Components 0.1
2021import Ubuntu.Gestures 0.1
2122import LightDM 0.1 as LightDM
23+import Powerd 0.1
2224import "Dash"
2325import "Greeter"
2426import "Launcher"
@@ -36,12 +38,12 @@ FocusScope {
3638
3739 // this is only here to select the width / height of the window if not running fullscreen
3840 property bool tablet: false
39− width: tablet ? units.gu(160) : ApplicationArguments.hasGeometry() ? ApplicationArguments.width() : units.gu(40)
40− height: tablet ? units.gu(100) : ApplicationArguments.hasGeometry() ? ApplicationArguments.height() : units.gu(71)
41+ width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
42+ height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
4143
4244 property real edgeSize: units.gu(2)
43− property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
44− property url background: default_background
45+ property url defaultBackground: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
46+ property url background: backgroundSettings.pictureUri
4547 readonly property real panelHeight: panel.panelHeight
4648
4749 property bool dashShown: dash.shown
@@ -112,6 +114,11 @@ FocusScope {
112114 }
113115 }
114116
117+ GSettings {
118+ id: backgroundSettings
119+ schema.id: "org.gnome.desktop.background"
120+ }
121+
115122 VolumeControl {
116123 id: volumeControl
117124 }
@@ -127,18 +134,31 @@ FocusScope {
127134
128135 Item {
129136 id: underlay
137+ objectName: "underlay"
130138 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)))
135139
136− Image {
140+ // Whether the underlay is fully covered by opaque UI elements.
141+ property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
142+
143+ // Whether the user should see the topmost application surface (if there's one at all).
144+ property bool applicationSurfaceShouldBeSeen:
145+ (mainStage.applications && mainStage.applications.count > 0)
146+ && (!stages.fullyHidden && !mainStage.usingScreenshots)
147+
148+ // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
149+ // through the translucent parts of the shell surface.
150+ visible: !fullyCovered && !applicationSurfaceShouldBeSeen
151+
152+ CrossFadeImage {
137153 id: backgroundImage
154+ objectName: "backgroundImage"
138155 source: shell.background
139− sourceSize.width: parent.width
140− sourceSize.height: parent.height
141156 anchors.fill: parent
157+ onStatusChanged: {
158+ if (status == Image.Error) {
159+ backgroundSettings.pictureUri = shell.defaultBackground
160+ }
161+ }
142162 }
143163
144164 Rectangle {
@@ -149,6 +169,7 @@ FocusScope {
149169
150170 Dash {
151171 id: dash
172+ objectName: "dash"
152173
153174 available: !greeter.shown && !lockscreen.shown
154175 hides: [stages, launcher, panel.indicators]
@@ -176,13 +197,12 @@ FocusScope {
176197 }
177198 }
178199
179− // FIXME: only necessary because stagesRevealer.animatedProgress and
200+ // FIXME: only necessary because stagesOuterContainer.showProgress and
180201 // greeterRevealer.animatedProgress are not animated
181202 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
182203 }
183204 }
184205
185−
186206 Item {
187207 id: stagesOuterContainer
188208
@@ -196,6 +216,7 @@ FocusScope {
196216
197217 Showable {
198218 id: stages
219+ objectName: "stages"
199220
200221 x: width
201222
@@ -246,12 +267,12 @@ FocusScope {
246267 ignoreUnknownSignals: true
247268 }
248269
249−
250270 Stage {
251271 id: mainStage
252272
253273 anchors.fill: parent
254274 fullyShown: stages.fullyShown
275+ fullyHidden: stages.fullyHidden
255276 shouldUseScreenshots: !fullyShown
256277 rightEdgeEnabled: !sideStage.enabled
257278
@@ -336,7 +357,7 @@ FocusScope {
336357 }
337358
338359 DragHandle {
339− id: stagesRevealer
360+ id: stagesDragHandle
340361
341362 anchors.top: parent.top
342363 anchors.bottom: parent.bottom
@@ -344,7 +365,11 @@ FocusScope {
344365
345366 width: shell.edgeSize
346367 direction: Direction.Leftwards
347− enabled: mainStage.applications.count > 0 || sideStage.applications.count > 0
368+ property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
369+
370+ maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
371+ // Make autocompletion impossible when !haveApps
372+ edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
348373 }
349374 }
350375 }
@@ -402,9 +427,6 @@ FocusScope {
402427
403428 dragHandleWidth: shell.edgeSize
404429
405− property var previousMainApp: null
406− property var previousSideApp: null
407−
408430 onShownChanged: {
409431 if (shown) {
410432 lockscreen.reset();
@@ -414,27 +436,13 @@ FocusScope {
414436 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
415437 }
416438 greeter.forceActiveFocus();
417− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
418− // the stage was actually shown
419− if (mainStage.fullyShown) greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
420− if (sideStage.fullyShown) greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
421− applicationManager.unfocusCurrentApplication();
422− } else {
423− if (greeter.previousMainApp) {
424− applicationManager.focusApplication(greeter.previousMainApp);
425− greeter.previousMainApp = null;
426− }
427− if (greeter.previousSideApp) {
428− applicationManager.focusApplication(greeter.previousSideApp);
429− greeter.previousSideApp = null;
430− }
431439 }
432440 }
433441
434442 onUnlocked: greeter.hide()
435443 onSelected: {
436444 var bgPath = greeter.model.data(uid, LightDM.UserRoles.BackgroundPathRole)
437− shell.background = bgPath ? bgPath : default_background
445+ shell.background = bgPath ? bgPath : defaultBackground
438446 }
439447
440448 onLeftTeaserPressedChanged: {
@@ -449,6 +457,41 @@ FocusScope {
449457 blockInput: greeter.shown || lockscreen.shown
450458 }
451459
460+ Connections {
461+ id: powerConnection
462+ target: Powerd
463+
464+ property var previousMainApp: null
465+ property var previousSideApp: null
466+
467+ function setFocused(focused) {
468+ if (!focused) {
469+ // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
470+ // the stage was actually shown
471+ if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
472+ if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
473+ applicationManager.unfocusCurrentApplication();
474+ } else {
475+ if (powerConnection.previousMainApp) {
476+ applicationManager.focusApplication(powerConnection.previousMainApp);
477+ powerConnection.previousMainApp = null;
478+ }
479+ if (powerConnection.previousSideApp) {
480+ applicationManager.focusApplication(powerConnection.previousSideApp);
481+ powerConnection.previousSideApp = null;
482+ }
483+ }
484+ }
485+
486+ onPowerStateChange: {
487+ if (state == 0) { // suspend
488+ powerConnection.setFocused(false);
489+ } else if (state == 1) { // active
490+ powerConnection.setFocused(true);
491+ }
492+ }
493+ }
494+
452495 Item {
453496 id: overlay
454497
@@ -534,7 +577,7 @@ FocusScope {
534577 anchors.bottom: parent.bottom
535578 width: parent.width
536579 dragAreaWidth: shell.edgeSize
537− available: !greeter.locked
580+ available: !greeter.shown || greeter.narrowMode
538581 onDashItemSelected: {
539582 greeter.hide()
540583 // Animate if moving between application and dash
@@ -629,4 +672,18 @@ FocusScope {
629672
630673 enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
631674 }
675+
676+ Label {
677+ anchors.fill: parent
678+ visible: applicationManager.fake
679+ text: "EARLY ALPHA\nNOT READY FOR USE"
680+ color: "lightgrey"
681+ opacity: 0.2
682+ font.weight: Font.Black
683+ horizontalAlignment: Text.AlignHCenter
684+ verticalAlignment: Text.AlignVCenter
685+ fontSizeMode: Text.Fit
686+ font.pixelSize: height/2
687+ rotation: -45
688+ }
632689}
debian/changelog+145
@@ -1,3 +1,148 @@
1+unity8 (7.81.3+13.10.20130802-0ubuntu1) saucy; urgency=low
2+
3+ [ Michael Terry ]
4+ * Make hud autopilot tests more reliable by fixing how it calculates
5+ relative coordinates.
6+
7+ [ Albert Astals ]
8+ * Only update the "section" if we are not culling the item If the item
9+ is not shown we should not care about its section.
10+
11+ [ Ubuntu daily release ]
12+ * Automatic snapshot from revision 155
13+
14+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 02 Aug 2013 02:40:11 +0000
15+
16+unity8 (7.81.3+13.10.20130801.1-0ubuntu1) saucy; urgency=low
17+
18+ [ Michał Sawicz ]
19+ * Add a disclaimer for the fake applications plugin.
20+
21+ [ Nick Dedekind ]
22+ * Removed animations from fake indicator pages.
23+
24+ [ Ubuntu daily release ]
25+ * Automatic snapshot from revision 152
26+
27+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 01 Aug 2013 14:30:40 +0000
28+
29+unity8 (7.81.3+13.10.20130801ubuntu.unity.next-0ubuntu1) saucy; urgency=low
30+
31+ [ Michael Zanetti ]
32+ * implemented new Lockscreen design.
33+
34+ [ Michał Sawicz ]
35+ * Fix mock VideoPreview to use the string categoryId as well.
36+
37+ [ Nick Dedekind ]
38+ * Added a text tree representation of the qmenumodel to the
39+ indicators-client application.
40+
41+ [ Albert Astals ]
42+ * Don't need deelistmodel here.
43+
44+ [ Ubuntu daily release ]
45+ * Automatic snapshot from revision 149 (ubuntu-unity/next)
46+
47+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 01 Aug 2013 02:32:03 +0000
48+
49+unity8 (7.81.3+13.10.20130730ubuntu.unity.next-0ubuntu1) saucy; urgency=low
50+
51+ [ Michał Sawicz ]
52+ * Adapt to Qt 5.1.
53+
54+ [ Albert Astals ]
55+ * Adapt to Qt 5.1.
56+
57+ [ Ubuntu daily release ]
58+ * Automatic snapshot from revision 143 (ubuntu-unity/next)
59+
60+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 30 Jul 2013 02:33:12 +0000
61+
62+unity8 (7.81.3+13.10.20130729ubuntu.unity.next-0ubuntu1) saucy; urgency=low
63+
64+ [ Michal Hruby ]
65+ * Remove the variant conversions methods as they were moved to dee-qt.
66+
67+ [ Michał Sawicz ]
68+ * Re-enable passphrase tests under UInput.
69+ * Use the new string categoryIds in custom video and music scope
70+ views. (LP: #1199322)
71+
72+ [ Nick Dedekind ]
73+ * Behavioural changes for indicators - Part 1 - Use standard
74+ animations. - Search bar animation less distracting. - Hinting
75+ animation shows header. - Vertical velocity detector to reduce
76+ accidental menu switches in dragging phase.
77+
78+ [ Gustavo Pichorim Boiko ]
79+ * Add entries to the new applications resulted from the split of the
80+ phone-app.
81+
82+ [ Ubuntu daily release ]
83+ * Automatic snapshot from revision 141 (ubuntu-unity/next)
84+
85+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 29 Jul 2013 03:41:07 +0000
86+
87+unity8 (7.81.3+13.10.20130726ubuntu.unity.next-0ubuntu1) saucy; urgency=low
88+
89+ [ Michal Hruby ]
90+ * Expose real category ids and not just indices.
91+ * Provide fallbacks for default renderer.
92+
93+ [ Daniel d'Andrada ]
94+ * Give a visual feedback on right-edge drag with no running apps (LP:
95+ #1116207). (LP: #1116207)
96+
97+ [ Albert Astals ]
98+ * Update m_firstVisibleIndex if there's no visible items anymore Also
99+ remove the check for m_visibleItems.isEmpty() on insert, the
100+ m_firstVisibleIndex == 0 already protects us against that.
101+
102+ [ Christopher Lee ]
103+ * Tests now use a default lightdm mock if not decorated. (LP:
104+ #1204772)
105+
106+ [ Ubuntu daily release ]
107+ * Automatic snapshot from revision 135 (ubuntu-unity/next)
108+
109+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 26 Jul 2013 07:06:08 +0000
110+
111+unity8 (7.81.3+13.10.20130725ubuntu.unity.next-0ubuntu1) saucy; urgency=low
112+
113+ [ Michal Hruby ]
114+ * Fix adding items into an empty LVWPH.
115+
116+ [ Michał Sawicz ]
117+ * Move to using upstart in run_on_device.
118+ * Added heeding and qmltest for button-tint hint.
119+ * Refactoring and cleanup of the Unity8 Autopilot tests.
120+ * Hide the Unity launcher during autopiloting and skip battery tests
121+ if unavailable.
122+
123+ [ Ying-Chun Liu ]
124+ * Let GenericScope support loading different renderers.
125+
126+ [ Nick Dedekind ]
127+ * Removed overview from indicators.
128+ * Menus for indicators is now created prioritised by distance from
129+ current item to speed up user experience.
130+ * Add ApplicationArguments to know the geometry from start.
131+
132+ [ Mirco Müller ]
133+ * Added heeding and qmltest for button-tint hint.
134+
135+ [ Christopher Lee ]
136+ * Refactoring and cleanup of the Unity8 Autopilot tests.
137+
138+ [ Thomi Richards ]
139+ * Refactoring and cleanup of the Unity8 Autopilot tests.
140+
141+ [ Ubuntu daily release ]
142+ * Automatic snapshot from revision 129 (ubuntu-unity/next)
143+
144+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 25 Jul 2013 03:02:12 +0000
145+
1146unity8 (7.81.3+13.10.20130718ubuntu.unity.next-0ubuntu1) saucy; urgency=low
2147
3148 [ Andrea Cimitan ]
debian/control+6−2
@@ -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],
@@ -56,8 +56,10 @@ Description: Indicators client test application
5656
5757Package: unity8
5858Architecture: any
59−Depends: qmenumodel-qml,
59+Depends: gsettings-desktop-schemas,
60+ qmenumodel-qml,
6061 qtdeclarative5-dee-plugin,
62+ qtdeclarative5-gsettings1.0,
6163 qtdeclarative5-ubuntu-ui-toolkit-plugin,
6264 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
6365 qtdeclarative5-xmllistmodel-plugin,
@@ -87,6 +89,8 @@ Depends: indicators-client (>= ${source:Version}),
8789 ${misc:Depends},
8890 ${python:Depends},
8991 ${shlibs:Depends},
92+Recommends: gir1.2-glib-2.0,
93+ python-gi,
9094Description: Test package for Unity 8 shell
9195 Autopilot tests for the unity8 package
9296
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+1−1
@@ -113,7 +113,7 @@ int main(int argc, char** argv)
113113 view->setResizeMode(QQuickView::SizeRootObjectToView);
114114 view->setTitle("Qml Phone Shell");
115115 view->engine()->setBaseUrl(QUrl::fromLocalFile(::shellAppDirectory()));
116− view->rootContext()->setContextProperty("ApplicationArguments", &qmlArgs);
116+ view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
117117 if (args.contains(QLatin1String("-frameless"))) {
118118 view->setFlags(Qt::FramelessWindowHint);
119119 }
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/ListViewWithPageHeader/CMakeLists.txt+5−1
@@ -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}
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+97−13
@@ -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;
@@ -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,10 +866,14 @@ 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();
809− const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && !m_visibleItems.isEmpty() && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
876+ const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
810877 if (insertingInValidIndexes || firstItemWithViewOnTop)
811878 {
812879 // If the items we are adding won't be really visible
@@ -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;
@@ -971,11 +1046,6 @@ void ListViewWithPageHeader::layout()
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/Unity/CMakeLists.txt+1−1
@@ -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(
plugins/Unity/Indicators/CMakeLists.txt+1
@@ -24,6 +24,7 @@ set(IndicatorsQML_SOURCES
2424 indicatorsmanager.cpp
2525 indicatorsmodel.cpp
2626 menucontentactivator.cpp
27+ modelprinter.cpp
2728 plugin.cpp
2829)
2930add_definitions(-DUNITYINDICATORS_LIBRARY)
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+2
@@ -28,6 +28,7 @@
2828#include "indicatorsmodel.h"
2929#include "indicators.h"
3030#include "menucontentactivator.h"
31+#include "modelprinter.h"
3132
3233void IndicatorsPlugin::registerTypes(const char *uri)
3334{
@@ -36,6 +37,7 @@ void IndicatorsPlugin::registerTypes(const char *uri)
3637 qmlRegisterType<IndicatorsManager>(uri, 0, 1, "IndicatorsManager");
3738 qmlRegisterType<FlatMenuProxyModel>(uri, 0, 1, "FlatMenuProxyModel");
3839 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
40+ qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
3941 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
4042
4143 qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
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
3734class Preview;
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
po/ar.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/az.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/bg.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
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-07-17 07:49+0000\n"
19−"X-Generator: Launchpad (build 16696)\n"
18+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
19+"X-Generator: Launchpad (build 16718)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/ca.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/de.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/el.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/en_AU.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/en_GB.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/eo.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/fi.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/fo.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/fr.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/gl.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/he.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/hr.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/hu.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/hy.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/id.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/it.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ja.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/kn.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ko.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ky.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/lv.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/my.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/nb.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/nl.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/pl.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/pt_BR.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ro.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ru.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/si.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/sr.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/sv.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/te.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/tr.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ug.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/uk.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-22 06:19+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/zh_CN.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/zh_TW.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-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-07-31 06:28+0000\n"
18+"X-Generator: Launchpad (build 16718)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
tests/autopilot/unity8/indicators_client/tests/test_battery.py+11−3
@@ -26,7 +26,7 @@ class TestDisplayMenus(IndicatorsTestCase):
2626 self.pointing_device.move_to_object(self.main_window.get_battery_menu())
2727 self.pointing_device.click()
2828
29− fn_loader = lambda: self.app.select_single("IndicatorsPage/QQuickLoader", objectName="page_loader");
29+ fn_loader = lambda: self.app.select_single("IndicatorsPage/QQuickLoader", objectName="pageLoader");
3030 self.assertThat(fn_loader, Eventually(NotEquals(None)));
3131 page_loader = fn_loader();
3232 self.assertThat(page_loader.progress, Eventually(Equals(1.0)))
@@ -70,7 +70,11 @@ class TestDisplayMenus(IndicatorsTestCase):
7070
7171 # wait for the switch menu item
7272 fn_auto_brightness = lambda: self.app.select_single("SwitchMenuItem", objectName="auto-brightness");
73− 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")
7478 auto_brightness = fn_auto_brightness();
7579
7680 old_ab_value = auto_brightness.checked
@@ -86,7 +90,11 @@ class TestDisplayMenus(IndicatorsTestCase):
8690 if self.input_device_class is Touch:
8791 self.skipTest("Dragging is broken with Touch input (LP: #1203808).")
8892 fn_brightness_menu = lambda: self.app.select_single("SliderMenuItem", objectName="brightness");
89− 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")
9098 brightness_menu = fn_brightness_menu();
9199
92100 old_ab_value = brightness_menu.value
tests/autopilot/unity8/shell/__init__.py+1−27
@@ -21,9 +21,6 @@
2121
2222from functools import wraps
2323import logging
24−import os.path
25−
26−from unity8 import get_mocks_library_path, get_default_extra_mock_libraries
2724
2825
2926logger = logging.getLogger(__name__)
@@ -34,31 +31,8 @@ def with_lightdm_mock(mock_type):
3431 def with_lightdm_mock_internal(fn):
3532 @wraps(fn)
3633 def wrapper(*args, **kwargs):
37− logger.info("Setting up LightDM mock type '%s'", mock_type)
38− new_ld_library_path = "%s:%s" % (
39− get_default_extra_mock_libraries(),
40− _get_ld_library_path(mock_type)
41− )
42− logger.info("New library path: %s", new_ld_library_path)
4334 tests_self = args[0]
44− tests_self.patch_environment(
45− 'LD_LIBRARY_PATH',
46− new_ld_library_path
47− )
35+ tests_self.patch_lightdm_mock(mock_type)
4836 return fn(*args, **kwargs)
4937 return wrapper
5038 return with_lightdm_mock_internal
51−
52−
53−def _get_ld_library_path(mock_type):
54− lib_path = get_mocks_library_path()
55− new_ld_library_path = os.path.abspath(
56− os.path.join(lib_path, "LightDM", mock_type)
57− )
58−
59− if not os.path.exists(new_ld_library_path):
60− raise RuntimeError(
61− "LightDM mock '%s' does not exist at path '%s'."
62− % (mock_type, new_ld_library_path)
63− )
64− return new_ld_library_path
tests/autopilot/unity8/shell/emulators/greeter.py+4−1
@@ -25,7 +25,7 @@ class Greeter(UnityEmulatorBase):
2525
2626 """An emulator that understands the greeter screen."""
2727
28− def unlock(self):
28+ def swipe(self):
2929 """Swipe the greeter screen away."""
3030 self.created.wait_for(True)
3131 touch = Touch.create()
@@ -38,3 +38,6 @@ class Greeter(UnityEmulatorBase):
3838 touch.drag(start_x, start_y, stop_x, stop_y)
3939
4040 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.py+4−7
@@ -38,13 +38,10 @@ class Hud(UnityEmulatorBase):
3838 window = self.get_root_instance().select_single('QQuickView')
3939 hud_show_button = window.select_single("HudButton")
4040
41− start_x = int(window.x + (window.width / 2))
42− end_x = start_x
43− start_y = window.y + window.height
44− end_y = int(hud_show_button.y + (hud_show_button.height/2))
41+ swipe_coords = self.get_button_swipe_coords(window, hud_show_button)
4542
46− touch.press(start_x, start_y)
47− touch._finger_move(end_x, end_y)
43+ touch.press(swipe_coords.start_x, swipe_coords.start_y)
44+ touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
4845 try:
4946 hud_show_button.opacity.wait_for(1.0)
5047 touch.release()
@@ -78,6 +75,6 @@ class Hud(UnityEmulatorBase):
7875 start_x = int(main_view.x + (main_view.width / 2))
7976 end_x = start_x
8077 start_y = main_view.y + (main_view.height - 3)
81− end_y = int(hud_show_button.y + (hud_show_button.height/2))
78+ end_y = main_view.y + int(hud_show_button.y + (hud_show_button.height/2))
8279
8380 return SwipeCoords(start_x, end_x, start_y, end_y)
tests/autopilot/unity8/shell/emulators/main_window.py+1−1
@@ -89,4 +89,4 @@ class MainWindow(object):
8989 return self.app.select_single("Lockscreen")
9090
9191 def get_pinentryField(self):
92− return self.app.select_single("TextField", objectName="pinentryField")
92+ return self.app.select_single(objectName="pinentryField")
tests/autopilot/unity8/shell/tests/__init__.py+53−1
@@ -19,6 +19,11 @@
1919
2020"""unity autopilot tests."""
2121
22+try:
23+ from gi.repository import Gio
24+except ImportError:
25+ Gio = None
26+
2227from autopilot.platform import model
2328from autopilot.testcase import AutopilotTestCase
2429from autopilot.matchers import Eventually
@@ -28,7 +33,12 @@ import logging
2833import os.path
2934from testtools.matchers import Equals, NotEquals
3035
31−from unity8 import get_lib_path, get_binary_path, get_mocks_library_path
36+from unity8 import (
37+ get_lib_path,
38+ get_binary_path,
39+ get_mocks_library_path,
40+ get_default_extra_mock_libraries,
41+)
3242from unity8.shell.emulators import UnityEmulatorBase
3343from unity8.shell.emulators.dash import Dash
3444from unity8.shell.emulators.main_window import MainWindow
@@ -36,6 +46,10 @@ from unity8.shell.emulators.main_window import MainWindow
3646
3747logger = logging.getLogger(__name__)
3848
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
3953
4054def _get_device_emulation_scenarios():
4155 if model() == 'Desktop':
@@ -64,10 +78,22 @@ class UnityTestCase(AutopilotTestCase):
6478
6579 def setUp(self):
6680 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+
6788 self._proxy = None
89+ self._lightdm_mock_type = None
6890 self.touch = Touch.create()
6991 self._setup_display_details()
7092
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+
7197 def _setup_display_details(self):
7298 scale_divisor = self._determine_geometry()
7399 self._setup_grid_size(scale_divisor)
@@ -133,6 +159,8 @@ class UnityTestCase(AutopilotTestCase):
133159 binary_path
134160 )
135161
162+ if self._lightdm_mock_type is None:
163+ self.patch_lightdm_mock()
136164 self._setup_extra_mock_environment_patch()
137165
138166 app_proxy = self.launch_test_application(
@@ -150,6 +178,30 @@ class UnityTestCase(AutopilotTestCase):
150178
151179 return app_proxy
152180
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+
153205 def _setup_extra_mock_environment_patch(self):
154206 mocks_library_path = get_mocks_library_path()
155207 self.patch_environment('QML2_IMPORT_PATH', mocks_library_path)
tests/autopilot/unity8/shell/tests/test_hud.py+5−10
@@ -32,13 +32,12 @@ class TestHud(UnityTestCase):
3232
3333 scenarios = _get_device_emulation_scenarios()
3434
35− @with_lightdm_mock("single")
3635 def test_show_hud_button_appears(self):
3736 """Swiping up while an app is active must show the 'show hud' button.
3837
3938 """
4039 self.launch_unity()
41− self.main_window.get_greeter().unlock()
40+ self.main_window.get_greeter().swipe()
4241 window = self.main_window.get_qml_view()
4342 hud_show_button = self.main_window.get_hud_show_button()
4443 hud = self.main_window.get_hud()
@@ -54,13 +53,12 @@ class TestHud(UnityTestCase):
5453 self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
5554 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
5655
57− @with_lightdm_mock("single")
5856 def test_show_hud_appears(self):
5957 """Releasing the touch on the 'show hud' button must display the hud.
6058
6159 """
6260 self.launch_unity()
63− self.main_window.get_greeter().unlock()
61+ self.main_window.get_greeter().swipe()
6462 window = self.main_window.get_qml_view()
6563 hud_show_button = self.main_window.get_hud_show_button()
6664 hud = self.main_window.get_hud()
@@ -80,11 +78,10 @@ class TestHud(UnityTestCase):
8078 self.touch.release()
8179 self.assertThat(hud.shown, Eventually(Equals(True)))
8280
83− @with_lightdm_mock("single")
8481 def test_hide_hud_click(self):
8582 """Tapping the close button of the Hud must dismiss it."""
8683 self.launch_unity()
87− self.main_window.get_greeter().unlock()
84+ self.main_window.get_greeter().swipe()
8885 hud = self.main_window.get_hud()
8986
9087 self._launch_test_app_from_app_screen()
@@ -94,14 +91,13 @@ class TestHud(UnityTestCase):
9491 self.touch.tap(x, y)
9592 self.assertThat(hud.shown, Eventually(Equals(False)))
9693
97− @with_lightdm_mock("single")
9894 def test_hide_hud_dragging(self):
9995 """Once open the Hud must close if the upper bar is dragged and
10096 released downward.
10197
10298 """
10399 self.launch_unity()
104− self.main_window.get_greeter().unlock()
100+ self.main_window.get_greeter().swipe()
105101 hud = self.main_window.get_hud()
106102 window = self.main_window.get_qml_view()
107103
@@ -115,11 +111,10 @@ class TestHud(UnityTestCase):
115111 self.touch.drag(start_x, start_y, end_x, end_y)
116112 self.assertThat(hud.shown, Eventually(Equals(False)))
117113
118− @with_lightdm_mock("single")
119114 def test_launcher_hides_hud(self):
120115 """Opening the Launcher while the Hud is active must close the Hud."""
121116 self.launch_unity()
122− self.main_window.get_greeter().unlock()
117+ self.main_window.get_greeter().swipe()
123118 hud = self.main_window.get_hud()
124119 launcher = self.main_window.get_launcher()
125120
tests/autopilot/unity8/shell/tests/test_lock_screen.py+58−28
@@ -40,54 +40,68 @@ class TestLockscreen(UnityTestCase):
4040 """Must be able to unlock the PIN entry lock screen."""
4141 self.launch_unity()
4242 greeter = self.main_window.get_greeter()
43− greeter.unlock()
4443
45− lockscreen = self._wait_for_lockscreen()
46− self._enter_pincode("1234")
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)))
4752
48− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
49−
50− @skipUnless(model() == 'Desktop', "Broken passphrase entry on UInput (LP: #1203788).")
5153 @with_lightdm_mock("single-passphrase")
5254 def test_can_unlock_passphrase_screen(self):
5355 """Must be able to unlock the passphrase entry screen."""
5456 self.launch_unity()
5557 greeter = self.main_window.get_greeter()
56− greeter.unlock()
57−
58− lockscreen = self._wait_for_lockscreen()
59− self._enter_passphrase("password")
6058
61− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
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)))
6267
6368 @with_lightdm_mock("single-pin")
6469 def test_pin_screen_wrong_code(self):
6570 """Entering the wrong pin code must not dismiss the lock screen."""
6671 self.launch_unity()
6772 greeter = self.main_window.get_greeter()
68− greeter.unlock()
69−
70− lockscreen = self._wait_for_lockscreen()
71− self._enter_pincode("4321")
7273
73− pinentryField = self.main_window.get_pinentryField()
74− self.assertThat(pinentryField.text, Eventually(Equals("")))
75− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
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)))
7686
77− @skipUnless(model() == 'Desktop', "Broken passphrase entry on UInput (LP: #1203788).")
7887 @with_lightdm_mock("single-passphrase")
7988 def test_passphrase_screen_wrong_password(self):
8089 """Entering the wrong password must not dismiss the lock screen."""
8190 self.launch_unity()
8291 greeter = self.main_window.get_greeter()
83− greeter.unlock()
8492
85− lockscreen = self._wait_for_lockscreen()
86− self._enter_passphrase("foobar")
87−
88− pinentryField = self.main_window.get_pinentryField()
89− self.assertThat(pinentryField.text, Eventually(Equals("")))
90− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
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)))
91105
92106 def _wait_for_lockscreen(self):
93107 """Wait for the lock screen to load, and return it."""
@@ -116,9 +130,9 @@ class TestLockscreen(UnityTestCase):
116130 )
117131 self.touch.tap_object(self.main_window.get_pinPadButton(int(num)))
118132
119− def _enter_passphrase(self, passphrase):
133+ def _enter_pin_passphrase(self, passphrase):
120134 """Enter the password specified in 'passphrase' into the password entry
121− field.
135+ field of the pin lock screen.
122136
123137 :param passphrase: The string you want to enter.
124138 :raises: TypeError if passphrase is not a string.
@@ -131,3 +145,19 @@ class TestLockscreen(UnityTestCase):
131145 self.touch.tap_object(pinentryField)
132146 self.keyboard.type(passphrase)
133147 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/data/unity/backgrounds/blue.pngnew file

Binary file not shown.

tests/data/unity/backgrounds/red.pngnew file

Binary file not shown.

tests/mocks/CMakeLists.txt+2
@@ -1,5 +1,7 @@
1+add_subdirectory(GSettings)
12add_subdirectory(libusermetrics)
23add_subdirectory(LightDM)
4+add_subdirectory(QMenuModel)
35add_subdirectory(Ubuntu)
46add_subdirectory(Unity)
57add_subdirectory(HudClient)
tests/mocks/GSettings/CMakeLists.txtnew file+31
@@ -0,0 +1,31 @@
1+set(CMAKE_AUTOMOC ON)
2+
3+include(FindPkgConfig)
4+find_package(Qt5Core REQUIRED)
5+find_package(Qt5Quick REQUIRED)
6+
7+include_directories(
8+ ${CMAKE_CURRENT_BINARY_DIR}
9+ ${Qt5Core_INCLUDE_DIRS}
10+ ${Qt5Quick_INCLUDE_DIRS}
11+)
12+
13+add_definitions(-DQT_NO_KEYWORDS)
14+
15+set(GSettingsQML_SOURCES
16+ fake_gsettings.cpp
17+ plugin.cpp
18+)
19+
20+add_library(FakeGSettingsQml MODULE ${GSettingsQML_SOURCES})
21+target_link_libraries(FakeGSettingsQml
22+ ${Qt5Core_LIBRARIES}
23+ ${Qt5Quick_LIBRARIES}
24+)
25+
26+qt5_use_modules(FakeGSettingsQml Qml)
27+
28+# copy qmldir file into build directory for shadow builds
29+file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
30+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
31+ )
tests/mocks/GSettings/fake_gsettings.cppnew file+102
@@ -0,0 +1,102 @@
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+
17+#include "fake_gsettings.h"
18+
19+#include <QList>
20+
21+GSettingsControllerQml* GSettingsControllerQml::s_controllerInstance = 0;
22+
23+GSettingsControllerQml::GSettingsControllerQml() {
24+}
25+
26+GSettingsControllerQml::~GSettingsControllerQml() {
27+ s_controllerInstance = 0;
28+}
29+
30+GSettingsControllerQml* GSettingsControllerQml::instance() {
31+ if(!s_controllerInstance) {
32+ s_controllerInstance = new GSettingsControllerQml();
33+ }
34+ return s_controllerInstance;
35+}
36+
37+void GSettingsControllerQml::registerSettingsObject(GSettingsQml *obj) {
38+ m_registeredGSettings.append(obj);
39+}
40+
41+void GSettingsControllerQml::unRegisterSettingsObject(GSettingsQml *obj) {
42+ m_registeredGSettings.removeOne(obj);
43+}
44+
45+void GSettingsControllerQml::setPictureUri(const QString &str) {
46+ Q_FOREACH (GSettingsQml *obj, m_registeredGSettings) {
47+ obj->setPictureUri(str);
48+ }
49+}
50+
51+GSettingsSchemaQml::GSettingsSchemaQml(QObject *parent): QObject(parent) {
52+}
53+
54+QByteArray GSettingsSchemaQml::id() const {
55+ return m_id;
56+}
57+
58+void GSettingsSchemaQml::setId(const QByteArray &id) {
59+ if (m_id.isEmpty()) {
60+ qWarning("GSettings.schema.id may only be set on construction");
61+ return;
62+ }
63+
64+ m_id = id;
65+}
66+
67+QByteArray GSettingsSchemaQml::path() const {
68+ return m_path;
69+}
70+
71+void GSettingsSchemaQml::setPath(const QByteArray &path) {
72+ if (m_path.isEmpty()) {
73+ qWarning("GSettings.schema.path may only be set on construction");
74+ return;
75+ }
76+
77+ m_path = path;
78+}
79+
80+GSettingsQml::GSettingsQml(QObject *parent): QObject(parent) {
81+ m_schema = new GSettingsSchemaQml(this);
82+ GSettingsControllerQml::instance()->registerSettingsObject(this);
83+}
84+
85+GSettingsQml::~GSettingsQml() {
86+ GSettingsControllerQml::instance()->unRegisterSettingsObject(this);
87+}
88+
89+GSettingsSchemaQml * GSettingsQml::schema() const {
90+ return m_schema;
91+}
92+
93+QString GSettingsQml::pictureUri() const {
94+ return m_pictureUri;
95+}
96+
97+void GSettingsQml::setPictureUri(const QString &str) {
98+ if (str != m_pictureUri) {
99+ m_pictureUri = str;
100+ Q_EMIT pictureUriChanged(m_pictureUri);
101+ }
102+}
tests/mocks/GSettings/fake_gsettings.hnew file+90
@@ -0,0 +1,90 @@
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+
17+#ifndef FAKE_GSETTINGS_H
18+#define FAKE_GSETTINGS_H
19+
20+#include <QList>
21+#include <QtQml>
22+
23+class GSettingsSchemaQml: public QObject
24+{
25+ Q_OBJECT
26+
27+ Q_PROPERTY(QByteArray id READ id WRITE setId)
28+
29+public:
30+ GSettingsSchemaQml(QObject *parent = NULL);
31+
32+ QByteArray id() const;
33+ void setId(const QByteArray &id);
34+
35+ QByteArray path() const;
36+ void setPath(const QByteArray &path);
37+
38+private:
39+ QByteArray m_id;
40+ QByteArray m_path;
41+};
42+
43+class GSettingsQml: public QObject
44+{
45+ Q_OBJECT
46+
47+ Q_PROPERTY(GSettingsSchemaQml* schema READ schema NOTIFY schemaChanged)
48+ Q_PROPERTY(QString pictureUri READ pictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
49+
50+public:
51+ GSettingsQml(QObject *parent = NULL);
52+ ~GSettingsQml();
53+
54+ GSettingsSchemaQml * schema() const;
55+ QString pictureUri() const;
56+
57+ void setPictureUri(const QString &str);
58+
59+Q_SIGNALS:
60+ void schemaChanged();
61+ void pictureUriChanged(const QString&);
62+
63+private:
64+ GSettingsSchemaQml* m_schema;
65+
66+ QString m_pictureUri;
67+
68+ friend class GSettingsSchemaQml;
69+};
70+
71+class GSettingsControllerQml: public QObject
72+{
73+ Q_OBJECT
74+
75+public:
76+ static GSettingsControllerQml* instance();
77+ ~GSettingsControllerQml();
78+
79+ void registerSettingsObject(GSettingsQml *obj);
80+ void unRegisterSettingsObject(GSettingsQml *obj);
81+ Q_INVOKABLE void setPictureUri(const QString &str);
82+
83+private:
84+ GSettingsControllerQml();
85+
86+ static GSettingsControllerQml* s_controllerInstance;
87+ QList<GSettingsQml *> m_registeredGSettings;
88+};
89+
90+#endif // FAKE_GSETTINGS_H
tests/mocks/GSettings/plugin.cppnew file+33
@@ -0,0 +1,33 @@
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 "plugin.h"
18+#include "fake_gsettings.h"
19+
20+#include <QtQml>
21+
22+static QObject* controllerProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
23+{
24+ return GSettingsControllerQml::instance();
25+}
26+
27+void FakeGSettingsQmlPlugin::registerTypes(const char *uri)
28+{
29+ qmlRegisterSingletonType<GSettingsControllerQml>(uri, 1, 0, "GSettingsController", controllerProvider);
30+ qmlRegisterType<GSettingsQml>(uri, 1, 0, "GSettings");
31+ qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
32+ "GSettingsSchema can only be used inside of a GSettings component");
33+}
tests/mocks/GSettings/plugin.hnew file+31
@@ -0,0 +1,31 @@
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+#ifndef PLUGIN_H
18+#define PLUGIN_H
19+
20+#include <QtQml/QQmlExtensionPlugin>
21+
22+class FakeGSettingsQmlPlugin : public QQmlExtensionPlugin
23+{
24+ Q_OBJECT
25+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
26+
27+public:
28+ void registerTypes(const char *uri);
29+};
30+
31+#endif // PLUGIN_H
tests/mocks/GSettings/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module GSettings
2+plugin FakeGSettingsQml
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+6−2
@@ -37,8 +37,6 @@ ApplicationManager::ApplicationManager(QObject *parent)
3737 , m_sideStage(0)
3838{
3939 buildListOfAvailableApplications();
40− createMainStageComponent();
41− createSideStageComponent();
4240}
4341
4442ApplicationManager::~ApplicationManager()
@@ -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/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/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+12
@@ -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);
@@ -1385,7 +1393,11 @@ private Q_SLOTS:
13851393private:
13861394 QQuickView *view;
13871395 ListViewWithPageHeader *lvwph;
1396+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
13881397 QQuickListModel *model;
1398+#else
1399+ QQmlListModel *model;
1400+#endif
13891401 QQmlComponent *otherDelegate;
13901402};
13911403
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+63−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,6 +1161,7 @@ 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
@@ -1179,6 +1223,7 @@ private Q_SLOTS:
11791223 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
11801224 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
11811225 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1226+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
11821227 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
11831228 }
11841229
@@ -1202,6 +1247,7 @@ private Q_SLOTS:
12021247 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12031248 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12041249 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1250+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12051251 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12061252 }
12071253
@@ -1224,6 +1270,7 @@ private Q_SLOTS:
12241270 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12251271 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12261272 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1273+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12271274 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12281275
12291276 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 1), Q_ARG(QVariant, 1));
@@ -1243,6 +1290,7 @@ private Q_SLOTS:
12431290 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12441291 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12451292 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1293+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
12461294 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12471295 }
12481296
@@ -1265,6 +1313,7 @@ private Q_SLOTS:
12651313 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12661314 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12671315 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1316+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12681317 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12691318
12701319 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 3), Q_ARG(QVariant, 1));
@@ -1284,6 +1333,7 @@ private Q_SLOTS:
12841333 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12851334 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12861335 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1336+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12871337 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12881338 }
12891339
@@ -1363,6 +1413,7 @@ private Q_SLOTS:
13631413 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
13641414 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
13651415 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1416+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
13661417 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
13671418
13681419 QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 5), Q_ARG(QVariant, 1));
@@ -1383,6 +1434,7 @@ private Q_SLOTS:
13831434 QVERIFY(!lvwph->isAtYEnd());
13841435 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
13851436 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1437+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
13861438 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
13871439 }
13881440
@@ -1406,6 +1458,7 @@ private Q_SLOTS:
14061458 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14071459 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14081460 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1461+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
14091462 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14101463
14111464 model->setProperty(1, "size", 100);
@@ -1426,6 +1479,7 @@ private Q_SLOTS:
14261479 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14271480 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14281481 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1482+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
14291483 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14301484 }
14311485
@@ -1447,7 +1501,7 @@ private Q_SLOTS:
14471501 QCOMPARE(lvwph->m_headerItem->y(), 0.);
14481502 QCOMPARE(lvwph->m_headerItem->height(), 50.);
14491503 QCOMPARE(lvwph->contentY(), 20.);
1450− QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1504+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14511505 QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14521506
14531507 lvwph->showHeader();
@@ -1467,6 +1521,7 @@ private Q_SLOTS:
14671521 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
14681522 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14691523 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
1524+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
14701525 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14711526
14721527 scrollToTop();
@@ -1502,9 +1557,10 @@ private Q_SLOTS:
15021557 QCOMPARE(lvwph->m_headerItem->y(), 0.);
15031558 QCOMPARE(lvwph->m_headerItem->height(), 50.);
15041559 QCOMPARE(lvwph->contentY(), 375.);
1505− QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1560+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
15061561 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
15071562 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1563+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
15081564 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
15091565
15101566 lvwph->showHeader();
@@ -1525,6 +1581,7 @@ private Q_SLOTS:
15251581 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
15261582 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
15271583 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1584+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
15281585 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
15291586
15301587 scrollToTop();
@@ -1637,7 +1694,11 @@ private Q_SLOTS:
16371694private:
16381695 QQuickView *view;
16391696 ListViewWithPageHeader *lvwph;
1697+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
16401698 QQuickListModel *model;
1699+#else
1700+ QQmlListModel *model;
1701+#endif
16411702 QQmlComponent *otherDelegate;
16421703};
16431704
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.cpp+1−1
@@ -299,5 +299,5 @@ private:
299299 QList<int> m_deltas;
300300};
301301
302−QTEST_MAIN(MenuConentActivatorTest)
302+QTEST_GUILESS_MAIN(MenuConentActivatorTest)
303303#include "menucontentactivatortest.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
@@ -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} ${CMAKE_BINARY_DIR}/tests/mocks
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)
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/tst_Shell.qmlnew file+295
@@ -0,0 +1,295 @@
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 GSettings 1.0
23+import Ubuntu.Application 0.1
24+import Unity.Test 0.1 as UT
25+
26+import "../.."
27+
28+Item {
29+ width: shell.width
30+ height: shell.height
31+
32+ QtObject {
33+ id: applicationArguments
34+
35+ function hasGeometry() {
36+ return false;
37+ }
38+
39+ function width() {
40+ return 0;
41+ }
42+
43+ function height() {
44+ return 0;
45+ }
46+ }
47+
48+ Shell {
49+ id: shell
50+ }
51+
52+ UT.UnityTestCase {
53+ name: "Shell"
54+ when: windowShown
55+
56+ function initTestCase() {
57+ // swipe away the greeter/lockscreen
58+ var touchX = shell.width - (shell.edgeSize / 2);
59+ var touchY = shell.height / 2;
60+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
61+
62+ var dash = findChild(shell, "dash");
63+ // wait until the animation has finished
64+ tryCompare(dash, "contentScale", 1.0);
65+ tryCompare(dash, "opacity", 1.0);
66+ }
67+
68+ function cleanup() {
69+ // kill all (fake) running apps
70+ ApplicationManager.mainStageApplications.clear();
71+ ApplicationManager.sideStageApplications.clear();
72+
73+ var dashHome = findChild(shell, "DashHome");
74+ swipeUntilScopeViewIsReached(dashHome);
75+ }
76+
77+ /*
78+ Test the effect of a right-edge drag on the dash in 3 situations:
79+ 1 - when no application has been launched yet
80+ 2 - when there's a minimized application
81+ 3 - after the last running application has been closed/stopped
82+
83+ The behavior of Dash on 3 should be the same as on 1.
84+ */
85+ function test_rightEdgeDrag() {
86+ checkRightEdgeDragWithNoRunningApps();
87+
88+ dragLauncherIntoView();
89+
90+ // Launch an app from the launcher
91+ tapOnAppIconInLauncher();
92+ waitUntilApplicationWindowIsFullyVisible();
93+
94+ // Minimize the application we just launched
95+ swipeFromLeftEdge();
96+
97+ waitForUIToSettle();
98+
99+ checkRightEdgeDragWithMinimizedApp();
100+
101+ // Minimize that application once again
102+ swipeFromLeftEdge();
103+
104+ // kill it
105+ ApplicationManager.mainStageApplications.clear();
106+
107+ waitForUIToSettle();
108+
109+ // Right edge behavior should now be the same as before that app was launched
110+ checkRightEdgeDragWithNoRunningApps();
111+ }
112+
113+ /*
114+ Perform a right-edge drag when the Dash is being show and there are
115+ no running/minimized apps to be restored.
116+
117+ The expected behavior is that an animation should be played to hint the
118+ user that his right-edge drag gesture has been successfully recognized
119+ but there is no application to be brought to foreground.
120+ */
121+ function checkRightEdgeDragWithNoRunningApps() {
122+ var touchX = shell.width - (shell.edgeSize / 2);
123+ var touchY = shell.height / 2;
124+
125+ var dash = findChild(shell, "dash");
126+ // check that dash has normal scale and opacity
127+ compare(dash.contentScale, 1.0);
128+ compare(dash.opacity, 1.0);
129+
130+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
131+ true /* beginTouch */, false /* endTouch */);
132+
133+ // check that Dash has been scaled down and had its opacity reduced
134+ tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
135+ tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
136+
137+ touchRelease(shell, shell.width * 0.1, touchY);
138+
139+ // and now everything should have gone back to normal
140+ tryCompare(dash, "contentScale", 1.0);
141+ tryCompare(dash, "opacity", 1.0);
142+ }
143+
144+ /*
145+ Perform a right-edge drag when the Dash is being show and there is
146+ a running/minimized app to be restored.
147+
148+ The expected behavior is that the dash should fade away and ultimately be
149+ made invisible once the gesture is finished as the restored app will now
150+ be on foreground.
151+ */
152+ function checkRightEdgeDragWithMinimizedApp() {
153+ var touchX = shell.width - (shell.edgeSize / 2);
154+ var touchY = shell.height / 2;
155+
156+ var dash = findChild(shell, "dash");
157+ // check that dash has normal scale and opacity
158+ tryCompare(dash, "contentScale", 1.0);
159+ tryCompare(dash, "opacity", 1.0);
160+
161+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
162+ true /* beginTouch */, false /* endTouch */);
163+
164+ // check that Dash has been scaled down and had its opacity reduced
165+ tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
166+ tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
167+
168+ touchRelease(shell, shell.width * 0.1, touchY);
169+
170+ // dash should have gone away, now that the app is on foreground
171+ tryCompare(dash, "visible", false);
172+ }
173+
174+ // Wait for the whole UI to settle down
175+ function waitForUIToSettle() {
176+ waitUntilApplicationWindowIsFullyHidden();
177+ var dashContentList = findChild(shell, "dashContentList");
178+ tryCompare(dashContentList, "moving", false);
179+ }
180+
181+ function dragLauncherIntoView() {
182+ var launcherPanel = findChild(shell, "launcherPanel");
183+ verify(launcherPanel.x = - launcherPanel.width);
184+ swipeFromLeftEdge();
185+ tryCompare(launcherPanel, "x", 0);
186+ }
187+
188+ function tapOnAppIconInLauncher() {
189+ var launcherPanel = findChild(shell, "launcherPanel");
190+
191+ // pick the first icon, the one at the bottom.
192+ var appIcon = findChild(launcherPanel, "launcherDelegate0")
193+
194+ // Swipe upwards over the launcher to ensure that this icon
195+ // at the bottom is not folded and faded away.
196+ var touchStartX = launcherPanel.width / 2;
197+ var touchStartY = launcherPanel.height / 2;
198+ touchFlick(launcherPanel, touchStartX, touchStartY, touchStartX, 0);
199+ tryCompare(launcherPanel, "moving", false);
200+
201+ // NB tapping (i.e., using touch events) doesn't activate the icon... go figure...
202+ mouseClick(appIcon, appIcon.width / 2, appIcon.height / 2);
203+ }
204+
205+ function waitUntilApplicationWindowIsFullyVisible() {
206+ var underlay = findChild(shell, "underlay");
207+ tryCompare(underlay, "visible", false);
208+ }
209+
210+ function waitUntilApplicationWindowIsFullyHidden() {
211+ var stages = findChild(shell, "stages");
212+ tryCompare(stages, "fullyHidden", true);
213+ }
214+
215+ function swipeUntilScopeViewIsReached(scopeView) {
216+ while (!itemIsOnScreen(scopeView)) {
217+ if (itemIsToLeftOfScreen(scopeView)) {
218+ swipeRightFromCenter();
219+ } else {
220+ swipeLeftFromCenter();
221+ }
222+ waitUntilItemStopsMoving(scopeView);
223+ }
224+ }
225+
226+ function swipeFromLeftEdge() {
227+ var touchStartX = 2;
228+ var touchStartY = shell.height / 2;
229+ touchFlick(shell, touchStartX, touchStartY, shell.width * 0.75, touchStartY);
230+ }
231+
232+ function swipeLeftFromCenter() {
233+ var touchStartX = shell.width / 2;
234+ var touchStartY = shell.height / 2;
235+ touchFlick(shell, touchStartX, touchStartY, 0, touchStartY);
236+ }
237+
238+ function swipeRightFromCenter() {
239+ var touchStartX = shell.width / 2;
240+ var touchStartY = shell.height / 2;
241+ touchFlick(shell, touchStartX, touchStartY, shell.width, touchStartY);
242+ }
243+
244+ function swipeUpFromCenter() {
245+ var touchStartX = shell.width / 2;
246+ var touchStartY = shell.height / 2;
247+ touchFlick(shell, touchStartX, touchStartY, touchStartX, 0);
248+ }
249+
250+ function itemIsOnScreen(item) {
251+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
252+
253+ return itemRectInShell.x >= 0
254+ && itemRectInShell.y >= 0
255+ && itemRectInShell.x + itemRectInShell.width <= shell.width
256+ && itemRectInShell.y + itemRectInShell.height <= shell.height;
257+ }
258+
259+ function itemIsToLeftOfScreen(item) {
260+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
261+ return itemRectInShell.x < 0;
262+ }
263+
264+ function waitUntilItemStopsMoving(item) {
265+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
266+ var previousX = itemRectInShell.x;
267+ var previousY = itemRectInShell.y;
268+ var isStill = false;
269+
270+ do {
271+ wait(100);
272+ itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
273+ if (itemRectInShell.x == previousX && itemRectInShell.y == previousY) {
274+ isStill = true;
275+ } else {
276+ previousX = itemRectInShell.x;
277+ previousY = itemRectInShell.y;
278+ }
279+ } while (!isStill);
280+ }
281+
282+ function test_wallpaper_data() {
283+ return [
284+ {tag: "red", url: "tests/data/unity/backgrounds/red.png"},
285+ {tag: "blue", url: "tests/data/unity/backgrounds/blue.png"}
286+ ]
287+ }
288+
289+ function test_wallpaper(data) {
290+ var backgroundImage = findChild(shell, "backgroundImage")
291+ GSettingsController.setPictureUri(data.url)
292+ tryCompareFunction(function() { return backgroundImage.source.toString().indexOf(data.url) !== -1; }, true)
293+ }
294+ }
295+}
tests/utils/modules/Unity/Test/UnityTestCase.qml+10−5
@@ -72,11 +72,16 @@ TestCase {
7272 // Find an object with the given name recursively, starting
7373 // at the given object "obj"
7474 function findChild(obj,objectName) {
75− for (var i in obj.children) {
76− var child = obj.children[i];
77− if (child.objectName === objectName) return child;
78− var subChild = findChild(child,objectName);
79− 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);
8085 }
8186 return undefined;
8287 }