on xenial help sign in
merged with trunk
d8b257aNick Dedekind
Components/CrossFadeImage.qmldeleted−151
@@ -1,151 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−Item {
20− property url source
21−
22− /*
23− * true: fade out old image in parallel with fading in the new one.
24− * false: fade in new image above old one.
25− *
26− * The reason why this is required is that crossfading has the isse that in
27− * the middle of the animation, both images are only 50% opaque which make
28− * any background shine through. Not wanted for background images etc, but
29− * wanted for overlays.
30− */
31− property bool crossFade: true
32−
33− /*
34− * true: the very first source url should be faded in already.
35− * false: the very first source url should just be shown without animation.
36− */
37− property bool fadeInFirst: true
38−
39− readonly property size sourceSize: __currentImage.sourceSize
40− readonly property var status: __currentImage ? __currentImage.status : Image.Null
41− readonly property bool running: crossFadeImages.running || nextImageFadeIn.running
42−
43− property Image __currentImage: image1
44− property Image __nextImage: image2
45−
46− function swapImages() {
47− __currentImage.z = 0
48− __nextImage.z = 1
49− if (crossFade) {
50− crossFadeImages.start();
51− } else {
52− nextImageFadeIn.start();
53− }
54−
55− var tmpImage = __currentImage
56− __currentImage = __nextImage
57− __nextImage = tmpImage
58− }
59−
60− onSourceChanged: {
61− // On creation, the souce handler is called before image pointers are set.
62− if (__currentImage === null) {
63− __currentImage = image1;
64− __nextImage = image2;
65− }
66−
67− crossFadeImages.stop();
68− nextImageFadeIn.stop();
69−
70− // Don't fade in initial picture, only fade changes
71− if (__currentImage.source == "" && !fadeInFirst) {
72− __currentImage.source = source;
73− } else {
74− nextImageFadeIn.stop();
75− __nextImage.opacity = 0.0;
76− __nextImage.source = source;
77−
78− // If case the image is still in QML's cache, status will be "Ready" immediately
79− if (__nextImage.status == Image.Ready || __nextImage.source == "") {
80− swapImages();
81− }
82− }
83− }
84−
85− Connections {
86− target: __nextImage
87− onStatusChanged: {
88− if (__nextImage.status == Image.Ready || __nextImage.status == Image.Error) {
89− swapImages();
90− }
91− }
92− }
93−
94− Image {
95− id: image1
96− anchors.fill: parent
97− cache: false
98− asynchronous: true
99− fillMode: Image.PreserveAspectCrop
100− z: 1
101− }
102−
103− Image {
104− id: image2
105− anchors.fill: parent
106− cache: false
107− asynchronous: true
108− fillMode: Image.PreserveAspectCrop
109− z: 0
110− }
111−
112− NumberAnimation {
113− id: nextImageFadeIn
114− target: __nextImage
115− property: "opacity"
116− duration: 400
117− to: 1.0
118− easing.type: Easing.InOutQuad
119−
120− onRunningChanged: {
121− if (!running) {
122− __nextImage.source = "";
123− }
124− }
125− }
126−
127− ParallelAnimation {
128− id: crossFadeImages
129− NumberAnimation {
130− target: __nextImage
131− property: "opacity"
132− duration: 400
133− to: 1.0
134− easing.type: Easing.InOutQuad
135− }
136−
137− NumberAnimation {
138− target: __currentImage
139− property: "opacity"
140− duration: 400
141− to: 0
142− easing.type: Easing.InOutQuad
143− }
144−
145− onRunningChanged: {
146− if (!running) {
147− __nextImage.source = "";
148− }
149− }
150− }
151−}
Components/EdgeDemo.qml+1−1
@@ -169,7 +169,7 @@ Item {
169 "edge": "bottom",
169 "edge": "bottom",
170 "title": i18n.tr("Close"),
170 "title": i18n.tr("Close"),
171 "text": i18n.tr("Swipe up again to close the settings screen"),
171 "text": i18n.tr("Swipe up again to close the settings screen"),
172− "anchors.fill": demo.indicators,
172+ "anchors.fill": demo.indicators.content,
173 });
173 });
174 }
174 }
175 if (d.bottomEdgeDemo) {
175 if (d.bottomEdgeDemo) {
Components/EdgeDemoOverlay.qml+3
@@ -153,7 +153,10 @@ Showable {
153 font.underline: true
153 font.underline: true
154
154
155 MouseArea {
155 MouseArea {
156+ // Make clickable area bigger than just the link because
157+ // otherwise, the edge demo will feel hard to dismiss.
156 anchors.fill: parent
158 anchors.fill: parent
159+ anchors.margins: -units.gu(5)
157 onClicked: overlay.doSkip()
160 onClicked: overlay.doSkip()
158 }
161 }
159 }
162 }
Components/LazyImage.qmlnew file+172
@@ -0,0 +1,172 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michał Sawicz <michal.sawicz@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 Ubuntu.Components 0.1
22+
23+Item {
24+ id: root
25+
26+ property url source
27+ // TODO convert into enums when available in QML
28+ property string scaleTo
29+
30+ property real initialWidth: units.gu(10)
31+ property real initialHeight: units.gu(10)
32+
33+ property alias sourceSize: image.sourceSize
34+ property alias fillMode: image.fillMode
35+ property alias asynchronous: image.asynchronous
36+ property alias cache: image.cache
37+ property alias horizontalAlignment: image.horizontalAlignment
38+ property alias verticalAlignment: image.verticalAlignment
39+
40+ state: "default"
41+
42+ onSourceChanged: {
43+ if (state === "ready") {
44+ state = "default";
45+ image.nextSource = source;
46+ } else {
47+ image.source = source;
48+ }
49+ }
50+
51+ UbuntuShape {
52+ id: placeholder
53+ objectName: "placeholder"
54+ color: "#22FFFFFF"
55+ anchors.fill: parent
56+ visible: opacity != 0
57+
58+ ActivityIndicator {
59+ id: activity
60+ anchors.centerIn: parent
61+ opacity: 0
62+ visible: opacity != 0
63+
64+ running: visible
65+ }
66+
67+ Image {
68+ id: errorImage
69+ objectName: "errorImage"
70+ anchors.centerIn: parent
71+ opacity: 0
72+ visible: opacity != 0
73+
74+ source: "graphics/close.png"
75+ sourceSize { width: units.gu(3); height: units.gu(3) }
76+ }
77+ }
78+
79+ UbuntuShape {
80+ id: shape
81+ objectName: "shape"
82+ anchors.fill: parent
83+ opacity: 0
84+ visible: opacity != 0
85+
86+ image: Image {
87+ id: image
88+ objectName: "image"
89+
90+ property url nextSource
91+
92+ width: root.scaleTo == "height" ? implicitWidth * root.height / implicitHeight : implicitWidth
93+ height: root.scaleTo == "width" ? implicitHeight * root.width / implicitWidth : implicitHeight
94+ fillMode: Image.PreserveAspectCrop
95+ asynchronous: true
96+ cache: false
97+ horizontalAlignment: Image.AlignHCenter
98+ verticalAlignment: Image.AlignVCenter
99+ sourceSize.width: root.scaleTo == "width" ? root.width : 0
100+ sourceSize.height: root.scaleTo == "height" ? root.height : 0
101+ }
102+ }
103+
104+ states: [
105+ State {
106+ name: "default"
107+ when: image.source == ""
108+ PropertyChanges { target: root; implicitWidth: root.initialWidth; implicitHeight: root.initialHeight }
109+ PropertyChanges { target: errorImage; opacity: 0 }
110+ },
111+ State {
112+ name: "loading"
113+ extend: "default"
114+ when: image.status === Image.Loading
115+ PropertyChanges { target: activity; opacity: 1 }
116+ },
117+ State {
118+ name: "ready"
119+ when: image.status === Image.Ready && image.source != ""
120+ PropertyChanges { target: root; implicitWidth: image.width; implicitHeight: image.height }
121+ PropertyChanges { target: shape; opacity: 1 }
122+ PropertyChanges { target: placeholder; opacity: 0 }
123+ },
124+ State {
125+ name: "error"
126+ extend: "default"
127+ when: image.status === Image.Error
128+ PropertyChanges { target: errorImage; opacity: 1.0 }
129+ }
130+ ]
131+
132+ transitions: [
133+ Transition {
134+ to: "ready"
135+ objectName: "readyTransition"
136+ SequentialAnimation {
137+ PropertyAction { target: shape; property: "visible" }
138+ ParallelAnimation {
139+ NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
140+ UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
141+ NumberAnimation {
142+ targets: [placeholder, activity, errorImage]; property: "opacity";
143+ easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
144+ }
145+ }
146+ }
147+ },
148+
149+ Transition {
150+ to: "*"
151+ objectName: "genericTransition"
152+ SequentialAnimation {
153+ ParallelAnimation {
154+ NumberAnimation { target: shape; property: "opacity"; easing.type: Easing.Linear }
155+ NumberAnimation {
156+ targets: [placeholder, activity, errorImage]; property: "opacity";
157+ easing.type: Easing.Linear; duration: UbuntuAnimation.SnapDuration
158+ }
159+ UbuntuNumberAnimation { target: root; properties: "implicitWidth,implicitHeight" }
160+ }
161+ PropertyAction { target: shape; property: "visible" }
162+ }
163+
164+ onRunningChanged: {
165+ if (!running && state === "default" && image.nextSource !== "") {
166+ image.source = image.nextSource;
167+ image.nextSource = "";
168+ }
169+ }
170+ }
171+ ]
172+}
Components/ResponsiveGridView.qml+1−1
@@ -67,7 +67,7 @@ Item {
67
67
68 function columnsForSpacing(spacing) {
68 function columnsForSpacing(spacing) {
69 // minimum margin is half of the spacing
69 // minimum margin is half of the spacing
70− return Math.floor((parent.width - spacing/2) / (delegateWidth + spacing));
70+ return Math.max(1, Math.floor((parent.width - spacing/2) / (delegateWidth + spacing)));
71 }
71 }
72
72
73 property real allocatableHorizontalSpace: parent.width - columns * delegateWidth
73 property real allocatableHorizontalSpace: parent.width - columns * delegateWidth
Components/VolumeControl.qml+5−20
@@ -21,37 +21,22 @@ Item {
21 id: root
21 id: root
22 objectName: "volumeControl"
22 objectName: "volumeControl"
23 visible: false
23 visible: false
24− property int volume
25
24
26 QDBusActionGroup {
25 QDBusActionGroup {
27 id: actionGroup
26 id: actionGroup
28 busType: 1
27 busType: 1
29− busName: "com.canonical.settings.sound"
28+ busName: "com.canonical.indicator.sound"
30− objectPath: "/com/canonical/settings/sound"
29+ objectPath: "/com/canonical/indicator/sound"
31
30
32− property variant actionObject: action("volume")
31+ property variant actionObject: action("scroll")
33− property variant serverVolume: actionObject.valid ? actionObject.state: 0
34− }
35−
36− Binding {
37− target: root
38− property: "volume"
39− value: actionGroup.serverVolume * 100
40− }
41−
42− onVolumeChanged: {
43− if (actionGroup.serverVolume != volume) {
44− var targetVolume = Math.min(1, Math.max(0, volume / 100));
45− actionGroup.actionObject.updateState(targetVolume);
46− }
47 }
32 }
48
33
49 function volumeUp() {
34 function volumeUp() {
50− actionGroup.actionObject.updateState(Math.min(1, volume/100 + 0.10));
35+ actionGroup.actionObject.activate(1);
51 }
36 }
52
37
53 function volumeDown() {
38 function volumeDown() {
54− actionGroup.actionObject.updateState(Math.max(0, volume/100 - 0.10));
39+ actionGroup.actionObject.activate(-1);
55 }
40 }
56
41
57 Component.onCompleted: actionGroup.start()
42 Component.onCompleted: actionGroup.start()
Components/graphics/close@20.pngnew file

Binary file not shown.

Dash/Apps/AppPreview.qml+11
@@ -110,6 +110,10 @@ DashPreview {
110 onFinished: {
110 onFinished: {
111 root.previewData.execute(progressBar.model[0].id, { })
111 root.previewData.execute(progressBar.model[0].id, { })
112 }
112 }
113+
114+ onError: {
115+ root.previewData.execute(progressBar.model[1].id, { "error": error });
116+ }
113 }
117 }
114
118
115 }
119 }
@@ -187,12 +191,19 @@ DashPreview {
187 ListItem.ThinDivider { }
191 ListItem.ThinDivider { }
188
192
189 AppReviews {
193 AppReviews {
194+ id: appReviews
190 objectName: "appReviews"
195 objectName: "appReviews"
196+ // TODO: This should make this visible when the feature for reviews/comments is complete.
197+ visible: false
191 anchors { left: parent.left; right: parent.right }
198 anchors { left: parent.left; right: parent.right }
192
199
193 model: root.previewData.infoMap["comments"] ? root.previewData.infoMap["comments"].value : undefined
200 model: root.previewData.infoMap["comments"] ? root.previewData.infoMap["comments"].value : undefined
194
201
195 onSendReview: root.sendUserReview(review);
202 onSendReview: root.sendUserReview(review);
203+
204+ onEditing: {
205+ root.ensureVisible(appReviews.textArea);
206+ }
196 }
207 }
197 }
208 }
198 }
209 }
Dash/Apps/AppReviews.qml+3
@@ -23,8 +23,10 @@ Column {
23 id: root
23 id: root
24
24
25 property var model
25 property var model
26+ property alias textArea: reviewField
26
27
27 signal sendReview(string review)
28 signal sendReview(string review)
29+ signal editing
28
30
29 spacing: units.gu(2)
31 spacing: units.gu(2)
30 state: ""
32 state: ""
@@ -93,6 +95,7 @@ Column {
93 if(reviewField.focus){
95 if(reviewField.focus){
94 root.state = "editing";
96 root.state = "editing";
95 reviewField.selectAll();
97 reviewField.selectAll();
98+ root.editing();
96 }
99 }
97 }
100 }
98
101
Dash/DashPreview.qml+13
@@ -20,6 +20,7 @@ import Ubuntu.Components 0.1
20Rectangle {
20Rectangle {
21 id: root
21 id: root
22
22
23+ property int keyboardSize: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
23 property var previewData
24 property var previewData
24
25
25 property string title: ""
26 property string title: ""
@@ -38,6 +39,14 @@ Rectangle {
38 color: Qt.rgba(0, 0, 0, .3)
39 color: Qt.rgba(0, 0, 0, .3)
39 clip: true
40 clip: true
40
41
42+ function ensureVisible(item) {
43+ var o = leftFlickable.mapFromItem(item, 0, 0, item.width, item.height);
44+ var keyboardY = shell.height - root.keyboardSize;
45+ if ((o.y + o.height) > keyboardY) {
46+ leftFlickable.contentY += o.y + o.height - keyboardY;
47+ }
48+ }
49+
41 Connections {
50 Connections {
42 target: shell.applicationManager
51 target: shell.applicationManager
43 onMainStageFocusedApplicationChanged: {
52 onMainStageFocusedApplicationChanged: {
@@ -128,12 +137,16 @@ Rectangle {
128
137
129 Flickable {
138 Flickable {
130 id: leftFlickable
139 id: leftFlickable
140+ objectName: "leftFlickable"
131 anchors.top: parent.top
141 anchors.top: parent.top
132 anchors.bottom: parent.bottom
142 anchors.bottom: parent.bottom
133 width: root.narrowMode ? contentRow.width : contentRow.width * root.previewWidthRatio
143 width: root.narrowMode ? contentRow.width : contentRow.width * root.previewWidthRatio
134 contentHeight: leftColumn.height
144 contentHeight: leftColumn.height
145+ anchors.bottomMargin: root.keyboardSize
135 clip: true
146 clip: true
136
147
148+ Behavior on contentY { NumberAnimation { duration: 300 } }
149+
137 Column {
150 Column {
138 id: leftColumn
151 id: leftColumn
139 objectName: "leftColumn"
152 objectName: "leftColumn"
Dash/GenericScopeView.qml+24−8
@@ -21,10 +21,11 @@ import "../Components/ListItems" as ListItems
21
21
22ScopeView {
22ScopeView {
23 id: scopeView
23 id: scopeView
24− property alias previewShown: previewLoader.onScreen
24+ readonly property alias previewShown: previewLoader.onScreen
25
25
26 onIsCurrentChanged: {
26 onIsCurrentChanged: {
27 pageHeader.resetSearch();
27 pageHeader.resetSearch();
28+ previewLoader.open = false;
28 }
29 }
29
30
30 onMovementStarted: categoryView.showHeader()
31 onMovementStarted: categoryView.showHeader()
@@ -35,6 +36,12 @@ ScopeView {
35 value: pageHeader.searchQuery
36 value: pageHeader.searchQuery
36 }
37 }
37
38
39+ Binding {
40+ target: pageHeader
41+ property: "searchQuery"
42+ value: scopeView.scope.searchQuery
43+ }
44+
38 Connections {
45 Connections {
39 target: panel
46 target: panel
40 onSearchClicked: if (isCurrent) {
47 onSearchClicked: if (isCurrent) {
@@ -43,6 +50,12 @@ ScopeView {
43 }
50 }
44 }
51 }
45
52
53+ Connections {
54+ target: scopeView.scope
55+ onShowDash: previewLoader.open = false;
56+ onHideDash: previewLoader.open = false;
57+ }
58+
46 ScopeListView {
59 ScopeListView {
47 id: categoryView
60 id: categoryView
48 anchors.fill: parent
61 anchors.fill: parent
@@ -52,13 +65,14 @@ ScopeView {
52 onAtYEndChanged: if (atYEnd) endReached()
65 onAtYEndChanged: if (atYEnd) endReached()
53 onMovingChanged: if (moving && atYEnd) endReached()
66 onMovingChanged: if (moving && atYEnd) endReached()
54
67
55− property int expandedIndex: -1
68+ property string expandedCategoryId: ""
56
69
57 delegate: ListItems.Base {
70 delegate: ListItems.Base {
58 highlightWhenPressed: false
71 highlightWhenPressed: false
59
72
60 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
73 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
61 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
74 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
75+ readonly property string category: categoryId
62
76
63 Loader {
77 Loader {
64 id: rendererLoader
78 id: rendererLoader
@@ -80,7 +94,7 @@ ScopeView {
80 }
94 }
81 item.objectName = Qt.binding(function() { return categoryId })
95 item.objectName = Qt.binding(function() { return categoryId })
82 if (item.expandable) {
96 if (item.expandable) {
83− var shouldFilter = index != categoryView.expandedIndex;
97+ var shouldFilter = categoryId != categoryView.expandedCategoryId;
84 if (shouldFilter != item.filter) {
98 if (shouldFilter != item.filter) {
85 item.filter = shouldFilter;
99 item.filter = shouldFilter;
86 }
100 }
@@ -116,10 +130,10 @@ ScopeView {
116 }
130 }
117 Connections {
131 Connections {
118 target: categoryView
132 target: categoryView
119− onExpandedIndexChanged: {
133+ onExpandedCategoryIdChanged: {
120 var item = rendererLoader.item;
134 var item = rendererLoader.item;
121 if (item.expandable) {
135 if (item.expandable) {
122− var shouldFilter = index != categoryView.expandedIndex;
136+ var shouldFilter = categoryId != categoryView.expandedCategoryId;
123 if (shouldFilter != item.filter) {
137 if (shouldFilter != item.filter) {
124 // If the filter animation will be seen start it, otherwise, just flip the switch
138 // If the filter animation will be seen start it, otherwise, just flip the switch
125 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
139 var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
@@ -150,10 +164,10 @@ ScopeView {
150 return "";
164 return "";
151 }
165 }
152 onClicked: {
166 onClicked: {
153− if (categoryView.expandedIndex != delegateIndex)
167+ if (categoryView.expandedCategoryId != delegate.category)
154− categoryView.expandedIndex = delegateIndex;
168+ categoryView.expandedCategoryId = delegate.category;
155 else
169 else
156− categoryView.expandedIndex = -1;
170+ categoryView.expandedCategoryId = "";
157 }
171 }
158 }
172 }
159 pageHeader: PageHeader {
173 pageHeader: PageHeader {
@@ -179,6 +193,7 @@ ScopeView {
179 case "grid": {
193 case "grid": {
180 switch (contentType) {
194 switch (contentType) {
181 case "video": return "Generic/GenericFilterGridPotrait.qml";
195 case "video": return "Generic/GenericFilterGridPotrait.qml";
196+ case "music": return "Music/MusicFilterGrid.qml";
182 default: return "Generic/GenericFilterGrid.qml";
197 default: return "Generic/GenericFilterGrid.qml";
183 }
198 }
184 }
199 }
@@ -246,6 +261,7 @@ ScopeView {
246 }
261 }
247
262
248 Loader {
263 Loader {
264+ objectName: "previewLoader"
249 id: previewLoader
265 id: previewLoader
250 property var previewData
266 property var previewData
251 height: effect.bottomGapPx - effect.topGapPx
267 height: effect.bottomGapPx - effect.topGapPx
Dash/Music/MusicFilterGrid.qml+12−2
@@ -29,19 +29,29 @@ FilterGrid {
29 readonly property int iconWidth: (width / columns) * 0.8
29 readonly property int iconWidth: (width / columns) * 0.8
30 readonly property int iconHeight: iconWidth
30 readonly property int iconHeight: iconWidth
31
31
32− signal clicked(int index)
32+ signal clicked(int index, var delegateItem, real itemY)
33+ signal pressAndHold(int index, var delegateItem, real itemY)
33
34
34 delegate: AlbumTile {
35 delegate: AlbumTile {
36+ id: tile
35 objectName: "delegate" + index
37 objectName: "delegate" + index
36 width: filterGrid.cellWidth
38 width: filterGrid.cellWidth
37 height: filterGrid.cellHeight
39 height: filterGrid.cellHeight
38 iconWidth: filterGrid.iconWidth
40 iconWidth: filterGrid.iconWidth
39 iconHeight: filterGrid.iconHeight
41 iconHeight: filterGrid.iconHeight
42+
40 artist: model.title
43 artist: model.title
41 album: model.comment
44 album: model.comment
42 source: model.icon
45 source: model.icon
46+
43 onClicked: {
47 onClicked: {
48+ var data = { model: model }
44− filterGrid.clicked(index);
49+ filterGrid.clicked(index, data, tile.y)
50+ }
51+
52+ onPressAndHold: {
53+ var data = { model: model }
54+ filterGrid.pressAndHold(index, data, tile.y)
45 }
55 }
46 }
56 }
47}
57}
Dash/graphics/phone/home.pngdeleted

Binary file not shown.

Dash/graphics/phone/music.pngdeleted

Binary file not shown.

Dash/graphics/phone/videos.pngdeleted

Binary file not shown.

Dash/graphics/tablet/apps.pngdeleted

Binary file not shown.

Dash/graphics/tablet/home.pngdeleted

Binary file not shown.

Dash/graphics/tablet/music.pngdeleted

Binary file not shown.

Dash/graphics/tablet/people.pngdeleted

Binary file not shown.

Dash/graphics/tablet/videos.pngdeleted

Binary file not shown.

Greeter/Greeter.qml+2
@@ -26,6 +26,8 @@ Showable {
26 enabled: shown
26 enabled: shown
27 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
27 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
28
28
29+ property url defaultBackground
30+
29 // 1 when fully shown and 0 when fully hidden
31 // 1 when fully shown and 0 when fully hidden
30 property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
32 property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
31
33
Greeter/GreeterContent.qml+5−4
@@ -40,13 +40,14 @@ MouseArea {
40 color: "black"
40 color: "black"
41 }
41 }
42
42
43− property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : shell.defaultBackground
43+ property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : greeter.defaultBackground
44 onBackgroundValueChanged: wallpaper.source = backgroundValue
44 onBackgroundValueChanged: wallpaper.source = backgroundValue
45
45
46 CrossFadeImage {
46 CrossFadeImage {
47 id: wallpaper
47 id: wallpaper
48+ objectName: "wallpaper"
48 anchors.fill: parent
49 anchors.fill: parent
49− fadeInFirst: false
50+ fillMode: Image.PreserveAspectCrop
50 }
51 }
51
52
52 // See Shell.qml's backgroundSettings treatment for why we need a separate
53 // See Shell.qml's backgroundSettings treatment for why we need a separate
@@ -58,8 +59,8 @@ MouseArea {
58 sourceSize.height: 0
59 sourceSize.height: 0
59 sourceSize.width: 0
60 sourceSize.width: 0
60 onStatusChanged: {
61 onStatusChanged: {
61− if (status == Image.Error && source != shell.defaultBackground) {
62+ if (status == Image.Error && source != greeter.defaultBackground) {
62− wallpaper.source = shell.defaultBackground
63+ wallpaper.source = greeter.defaultBackground
63 }
64 }
64 }
65 }
65 }
66 }
MouseTouchAdaptor.cpp+29−12
@@ -39,24 +39,16 @@ Qt::MouseButton translateMouseButton(xcb_button_t detail)
39} // end of anonymous namespace
39} // end of anonymous namespace
40
40
41MouseTouchAdaptor::MouseTouchAdaptor()
41MouseTouchAdaptor::MouseTouchAdaptor()
42− : m_targetWindow(0)
43− , m_leftButtonIsPressed(false)
42+ : m_leftButtonIsPressed(false)
44{
43{
45 m_touchDevice = new QTouchDevice;
44 m_touchDevice = new QTouchDevice;
46 m_touchDevice->setType(QTouchDevice::TouchScreen);
45 m_touchDevice->setType(QTouchDevice::TouchScreen);
47 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
46 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
48}
47}
49
48
50−void MouseTouchAdaptor::setTargetWindow(QWindow *window)
51−{
52− m_targetWindow = window;
53−}
54−
55bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
49bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
56 void * message, long * /*result*/)
50 void * message, long * /*result*/)
57{
51{
58− Q_ASSERT(m_targetWindow);
59−
60 if (eventType != "xcb_generic_event_t") {
52 if (eventType != "xcb_generic_event_t") {
61 // wrong backend.
53 // wrong backend.
62 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
54 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
@@ -91,7 +83,9 @@ bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
91
83
92 QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
84 QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
93
85
86+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
87+
94− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
88+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
95 false /* autoCommit */);
89 false /* autoCommit */);
96 touchEvent.press(0 /* touchId */, windowPos);
90 touchEvent.press(0 /* touchId */, windowPos);
97 touchEvent.commit(false /* processEvents */);
91 touchEvent.commit(false /* processEvents */);
@@ -110,7 +104,9 @@ bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseE
110
104
111 QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
105 QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
112
106
107+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
108+
113− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
109+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
114 false /* autoCommit */);
110 false /* autoCommit */);
115 touchEvent.release(0 /* touchId */, windowPos);
111 touchEvent.release(0 /* touchId */, windowPos);
116 touchEvent.commit(false /* processEvents */);
112 touchEvent.commit(false /* processEvents */);
@@ -127,10 +123,31 @@ bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
127
123
128 QPoint windowPos(event->event_x, event->event_y);
124 QPoint windowPos(event->event_x, event->event_y);
129
125
126+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
127+
130− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
128+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
131 false /* autoCommit */);
129 false /* autoCommit */);
132 touchEvent.move(0 /* touchId */, windowPos);
130 touchEvent.move(0 /* touchId */, windowPos);
133 touchEvent.commit(false /* processEvents */);
131 touchEvent.commit(false /* processEvents */);
134
132
135 return true;
133 return true;
136}
134}
135+
136+QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
137+{
138+ QWindowList windowList = QGuiApplication::topLevelWindows();
139+ QWindow *foundWindow = nullptr;
140+
141+ int i = 0;
142+ while (!foundWindow && i < windowList.count()) {
143+ QWindow *window = windowList[i];
144+ if (window->winId() == windowId) {
145+ foundWindow = window;
146+ } else {
147+ ++i;
148+ }
149+ }
150+
151+ Q_ASSERT(foundWindow);
152+ return foundWindow;
153+}
MouseTouchAdaptor.h+2−5
@@ -20,11 +20,11 @@
20#define MOUSE_TOUCH_ADAPTOR_H
20#define MOUSE_TOUCH_ADAPTOR_H
21
21
22#include <QtCore/QAbstractNativeEventFilter>
22#include <QtCore/QAbstractNativeEventFilter>
23+#include <QWindow>
23#include <xcb/xcb.h>
24#include <xcb/xcb.h>
24
25
25class QMouseEvent;
26class QMouseEvent;
26class QTouchDevice;
27class QTouchDevice;
27−class QWindow;
28
28
29// Transforms QMouseEvents into single-finger QTouchEvents.
29// Transforms QMouseEvents into single-finger QTouchEvents.
30class MouseTouchAdaptor : public QAbstractNativeEventFilter {
30class MouseTouchAdaptor : public QAbstractNativeEventFilter {
@@ -32,9 +32,6 @@ class MouseTouchAdaptor : public QAbstractNativeEventFilter {
32public:
32public:
33 MouseTouchAdaptor();
33 MouseTouchAdaptor();
34
34
35− // The window that will receive the generated QTouchEvents
36− void setTargetWindow(QWindow *window);
37−
38 // Filters mouse events and posts the equivalent QTouchEvents.
35 // Filters mouse events and posts the equivalent QTouchEvents.
39 virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
36 virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
40
37
@@ -43,8 +40,8 @@ private:
43 bool handleButtonPress(xcb_button_press_event_t *pressEvent);
40 bool handleButtonPress(xcb_button_press_event_t *pressEvent);
44 bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
41 bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
45 bool handleMotionNotify(xcb_motion_notify_event_t *event);
42 bool handleMotionNotify(xcb_motion_notify_event_t *event);
43+ QWindow *findQWindowWithXWindowID(WId windowId);
46
44
47− QWindow *m_targetWindow;
48 QTouchDevice *m_touchDevice;
45 QTouchDevice *m_touchDevice;
49 bool m_leftButtonIsPressed;
46 bool m_leftButtonIsPressed;
50};
47};
Panel/Indicators.qml+1
@@ -35,6 +35,7 @@ Showable {
35 property bool partiallyOpened: height > panelHeight && !fullyOpened
35 property bool partiallyOpened: height > panelHeight && !fullyOpened
36 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
36 property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
37 property bool contentEnabled: true
37 property bool contentEnabled: true
38+ readonly property alias content: menuContent
38
39
39 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
40 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
40 // use its own values. Need to ask design about this.
41 // use its own values. Need to ask design about this.
Panel/Indicators/DefaultIndicatorWidget.qml+1−5
@@ -24,6 +24,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
24Indicators.IndicatorWidget {
24Indicators.IndicatorWidget {
25 id: indicatorWidget
25 id: indicatorWidget
26
26
27+ enabled:true
27 width: itemRow.width + units.gu(0.5)
28 width: itemRow.width + units.gu(0.5)
28
29
29 property alias label: itemLabel.text
30 property alias label: itemLabel.text
@@ -63,19 +64,14 @@ Indicators.IndicatorWidget {
63
64
64 onActionStateChanged: {
65 onActionStateChanged: {
65 if (action == undefined || !action.valid) {
66 if (action == undefined || !action.valid) {
66− enabled = false;
67 return;
67 return;
68 }
68 }
69
69
70 if (action.state == undefined) {
70 if (action.state == undefined) {
71− label = "";
72− iconSource = "";
73− enabled = false;
74 return;
71 return;
75 }
72 }
76
73
77 label = action.state[Indicators.ActionState.Label];
74 label = action.state[Indicators.ActionState.Label];
78 iconSource = "image://theme/" + action.state[Indicators.ActionState.IconSource];
75 iconSource = "image://theme/" + action.state[Indicators.ActionState.IconSource];
79− enabled = action.state[Indicators.ActionState.Visible];
80 }
76 }
81}
77}
Panel/MenuContent.qml+12−2
@@ -109,7 +109,7 @@ MainView {
109 source: pageSource
109 source: pageSource
110 asynchronous: true
110 asynchronous: true
111
111
112− property bool contentActive: content.__contentActive
112+ property bool contentActive: content.__contentActive && menuActivator.content[index].active
113
113
114 onContentActiveChanged: {
114 onContentActiveChanged: {
115 if (contentActive && item) {
115 if (contentActive && item) {
@@ -146,6 +146,16 @@ MainView {
146 id: contentReleaseTimer
146 id: contentReleaseTimer
147
147
148 interval: contentReleaseInterval
148 interval: contentReleaseInterval
149+ onTriggered: {
149− onTriggered: content.__contentActive = false
150+ content.__contentActive = false;
151+ menuActivator.clear();
152+ }
153+ }
154+
155+ Indicators.MenuContentActivator {
156+ id: menuActivator
157+ running: content.__contentActive
158+ baseIndex: content.currentMenuIndex
159+ count: indicatorsModel.count
150 }
160 }
151}
161}
Shell.qml+24−11
@@ -23,6 +23,7 @@ import Ubuntu.Gestures 0.1
23import Unity.Launcher 0.1
23import Unity.Launcher 0.1
24import LightDM 0.1 as LightDM
24import LightDM 0.1 as LightDM
25import Powerd 0.1
25import Powerd 0.1
26+import SessionBroadcast 0.1
26import "Dash"
27import "Dash"
27import "Greeter"
28import "Greeter"
28import "Launcher"
29import "Launcher"
@@ -83,6 +84,8 @@ FocusScope {
83
84
84 readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
85 readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
85 || !!applicationManager.sideStageFocusedApplication
86 || !!applicationManager.sideStageFocusedApplication
87+ // Used for autopilot testing.
88+ readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
86
89
87 readonly property bool fullscreenMode: {
90 readonly property bool fullscreenMode: {
88 if (greeter.shown || lockscreen.shown) {
91 if (greeter.shown || lockscreen.shown) {
@@ -195,6 +198,7 @@ FocusScope {
195
198
196 anchors.fill: parent
199 anchors.fill: parent
197 source: shell.background
200 source: shell.background
201+ fillMode: Image.PreserveAspectCrop
198 }
202 }
199
203
200 Rectangle {
204 Rectangle {
@@ -460,6 +464,8 @@ FocusScope {
460 hides: [launcher, panel.indicators, hud]
464 hides: [launcher, panel.indicators, hud]
461 shown: true
465 shown: true
462
466
467+ defaultBackground: shell.background
468+
463 y: panel.panelHeight
469 y: panel.panelHeight
464 width: parent.width
470 width: parent.width
465 height: parent.height - panel.panelHeight
471 height: parent.height - panel.panelHeight
@@ -543,6 +549,17 @@ FocusScope {
543 }
549 }
544 }
550 }
545
551
552+ function showHome() {
553+ greeter.hide()
554+ // Animate if moving between application and dash
555+ if (!stages.shown) {
556+ dash.setCurrentScope("home.scope", true, false)
557+ } else {
558+ dash.setCurrentScope("home.scope", false, false)
559+ }
560+ stages.hide()
561+ }
562+
546 Item {
563 Item {
547 id: overlay
564 id: overlay
548
565
@@ -608,7 +625,7 @@ FocusScope {
608 Bottombar {
625 Bottombar {
609 theHud: hud
626 theHud: hud
610 anchors.fill: parent
627 anchors.fill: parent
611− enabled: !panel.indicators.shown
628+ enabled: hud.available
612 applicationIsOnForeground: applicationFocused
629 applicationIsOnForeground: applicationFocused
613 }
630 }
614
631
@@ -630,16 +647,7 @@ FocusScope {
630 width: parent.width
647 width: parent.width
631 dragAreaWidth: shell.edgeSize
648 dragAreaWidth: shell.edgeSize
632 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
649 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
633− onDashItemSelected: {
650+ onDashItemSelected: showHome()
634− greeter.hide()
635− // Animate if moving between application and dash
636− if (!stages.shown) {
637− dash.setCurrentScope("home.scope", true, false)
638− } else {
639− dash.setCurrentScope("home.scope", false, false)
640− }
641− stages.hide();
642− }
643 onDash: {
651 onDash: {
644 if (stages.shown) {
652 if (stages.shown) {
645 dash.setCurrentScope("applications.scope", true, false)
653 dash.setCurrentScope("applications.scope", true, false)
@@ -747,4 +755,9 @@ FocusScope {
747 indicators: panel.indicators
755 indicators: panel.indicators
748 underlay: underlay
756 underlay: underlay
749 }
757 }
758+
759+ Connections {
760+ target: SessionBroadcast
761+ onShowHome: showHome()
762+ }
750}
763}
debian/changelog+137
@@ -1,3 +1,140 @@
1+unity8 (7.81.3+13.10.20130927.3-0ubuntu1) saucy; urgency=low
2+
3+ [ Michal Hruby ]
4+ * Correctly handle image URI scheme in results.
5+
6+ [ Michał Sawicz ]
7+ * Make SHOW_DASH and HIDE_DASH close the current preview. (LP:
8+ #1231404)
9+ * Add a LazyImage component that shows an activity spinner for long-
10+ loading images and handles aspect ratio properly.
11+ * Fix Qt 5.1 FTBFS and suppress some build warnings.
12+
13+ [ Albert Astals ]
14+ * Make sure we always have least have one column in the gridview. (LP:
15+ #1225391)
16+ * LVWPH: Make sure we always overshoot vertically. (LP: #1229851)
17+ * Remember the expanded categoryId and not the expanded index The
18+ index can change on search, and we still want to maintain it
19+ expanded in that case. (LP: #1230216)
20+ * Fix showHeader in an edge case of notShownByItsOwn Not all the tests
21+ i've added fail without the code fix, but i've added them just to be
22+ more covered . (LP: #1230187)
23+
24+ [ Diego Sarmentero ]
25+ * Handling error signal from the DownloadTracker plugin (BUG:
26+ #1229744). (LP: #1229744)
27+ * Remove "Reviews and Comments" section from Application Preview until
28+ the feature is ready (BUG: #1226632) - Detect when the keyboard is
29+ being shown to allow the user to scroll the Preview even more if
30+ necessary to interact with the components at the bottom of that
31+ preview, and don't leave those components obscured behind the
32+ keyboard (BUG: #1226638). (LP: #1226632, #1224717, #1226638)
33+
34+ [ Nick Dedekind ]
35+ * Brought messaging indicator inline with UnityMenuModel &
36+ UnityMenuAction. (LP: #1217676, #1217678)
37+
38+ [ Pawel Stolowski ]
39+ * Support canned search queries returned by Home Scope.
40+ * Cancel previous actions and previews on new activation / preview.
41+ Expose previewed data row in Preview object.
42+
43+ [ Michael Terry ]
44+ * Only enable the Bottombar when the HUD is available. (LP: #1220306)
45+ * Increase the "Skip intro" clickable area, making dismissing the edge
46+ demo intro feel more natural. (LP: #1220632)
47+
48+ [ Michael Zanetti ]
49+ * drop our CrossFadeImage in favor of the SDK one. (LP: #1227783)
50+
51+ [ Ubuntu daily release ]
52+ * Automatic snapshot from revision 358
53+
54+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 27 Sep 2013 14:13:22 +0000
55+
56+unity8 (7.81.3+13.10.20130924.2-0ubuntu1) saucy; urgency=low
57+
58+ [ Michal Hruby ]
59+ * Fix the signal prototypes on music grid renderer. (LP: #1228390)
60+
61+ [ Michael Zanetti ]
62+ * use less auto variables, align coding style, constify and Qt'ify API
63+ in AccountsService plugin.
64+
65+ [ Nick Dedekind ]
66+ * Re-enable MenuContentActivator in Indicators.
67+
68+ [ Albert Astals ]
69+ * LVWPH: Update the section header on list change events.
70+
71+ [ Pawel Stolowski ]
72+ * Check results model ptr returned by GetResultsFromCategory method
73+ from UnityCore. (LP: #1228097, #1211595)
74+
75+ [ Ubuntu daily release ]
76+ * Automatic snapshot from revision 340
77+
78+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 24 Sep 2013 14:40:01 +0000
79+
80+unity8 (7.81.3+13.10.20130919.3-0ubuntu1) saucy; urgency=low
81+
82+ [ Michal Hruby ]
83+ * Add support for music grid renderer to GenericScopeView.
84+
85+ [ Nick Dedekind ]
86+ * Fixed the removal of messaging widget due to incompatible action
87+ state. (LP: #1225017)
88+
89+ [ Christopher Lee ]
90+ * Addition of initial autopilot tests for the application lifecycle.
91+
92+ [ Lars Uebernickel ]
93+ * VolumeControl: use action of the new indicator indicator-sound
94+ recently gained an action to increase and decrease the volume. This
95+ patch makes use of that to get rid of a bus round trip (to get the
96+ current volume) and a race (when the volume gets set between
97+ fetching the current volume and setting the new volume). (LP:
98+ #1219057)
99+
100+ [ Michael Terry ]
101+ * When AccountsService.backgroundFile is unset/invalid, have the
102+ greeter fall back to whatever the shell background is.
103+ * Add a tiny SessionBroadcast plugin that listens to unity-greeter-
104+ session-broadcast for the ShowHome signal.
105+
106+ [ Daniel d'Andrada ]
107+ * Remove obsolete, unused graphics.
108+ * Make MouseTouchAdaptor work with multiple QWindows.
109+
110+ [ Michael Zanetti ]
111+ * change how icons are searched a) try to find it the Icon as is b)
112+ prepend with Path if a Path variable is given c) fall back to the
113+ image://theme/ with just the icon name . (LP: #1225186)
114+ * fix an issue with removing a running app from the launcher and
115+ always store pinning to the config.
116+ * collapse any open preview when programmatically switching current
117+ dash index. (LP: #1221137)
118+
119+ [ Ubuntu daily release ]
120+ * Automatic snapshot from revision 333
121+
122+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 19 Sep 2013 15:15:07 +0000
123+
124+unity8 (7.81.3+13.10.20130916-0ubuntu1) saucy; urgency=low
125+
126+ [ Michael Zanetti ]
127+ * allow left edge gesture to minimize apps even when launcher is
128+ already visible.
129+ * Don't hide the launcher on changes in the stages.
130+ * ssh is now installed per default, but it's set to manual in the
131+ ssh.override.
132+
133+ [ Ubuntu daily release ]
134+ * Automatic snapshot from revision 320
135+
136+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 16 Sep 2013 11:49:28 +0000
137+
1unity8 (7.81.3+13.10.20130912-0ubuntu1) saucy; urgency=low
138unity8 (7.81.3+13.10.20130912-0ubuntu1) saucy; urgency=low
2
139
3 [ Michael Zanetti ]
140 [ Michael Zanetti ]
debian/control+1−1
@@ -21,7 +21,7 @@ Build-Depends: cmake,
21 libqt5v8-5-private-dev,
21 libqt5v8-5-private-dev,
22 libsigc++-2.0-dev,
22 libsigc++-2.0-dev,
23 libunity-api-dev (>= 7.80.3),
23 libunity-api-dev (>= 7.80.3),
24− libunity-core-6.0-dev (<< 7.80),
24+ libunity-core-6.0-dev (>= 7.1.1),
25 libunity-dev (>= 7.0.12),
25 libunity-dev (>= 7.0.12),
26 libunity-mir-dev,
26 libunity-mir-dev,
27 libunity-scopes-json-def-phone,
27 libunity-scopes-json-def-phone,
debian/unity8-private.install+1
@@ -3,6 +3,7 @@ usr/lib/*/unity8/qml/HudClient
3usr/lib/*/unity8/qml/LightDM
3usr/lib/*/unity8/qml/LightDM
4usr/lib/*/unity8/qml/ListViewWithPageHeader
4usr/lib/*/unity8/qml/ListViewWithPageHeader
5usr/lib/*/unity8/qml/Powerd
5usr/lib/*/unity8/qml/Powerd
6+usr/lib/*/unity8/qml/SessionBroadcast
6usr/lib/*/unity8/qml/Ubuntu
7usr/lib/*/unity8/qml/Ubuntu
7usr/lib/*/unity8/qml/Unity
8usr/lib/*/unity8/qml/Unity
8usr/lib/*/unity8/qml/Utils
9usr/lib/*/unity8/qml/Utils
main.cpp−1
@@ -144,7 +144,6 @@ int startShell(int argc, const char** argv, void* server)
144 MouseTouchAdaptor *mouseTouchAdaptor = 0;
144 MouseTouchAdaptor *mouseTouchAdaptor = 0;
145 if (args.contains(QLatin1String("-mousetouch"))) {
145 if (args.contains(QLatin1String("-mousetouch"))) {
146 mouseTouchAdaptor = new MouseTouchAdaptor;
146 mouseTouchAdaptor = new MouseTouchAdaptor;
147− mouseTouchAdaptor->setTargetWindow(view);
148 application->installNativeEventFilter(mouseTouchAdaptor);
147 application->installNativeEventFilter(mouseTouchAdaptor);
149 }
148 }
150
149
plugins/AccountsService/AccountsService.cpp+3−3
@@ -32,7 +32,7 @@ AccountsService::AccountsService(QObject* parent)
32 this, SLOT(maybeChanged(const QString &)));
32 this, SLOT(maybeChanged(const QString &)));
33}
33}
34
34
35−QString AccountsService::getUser()
35+QString AccountsService::user() const
36{
36{
37 return m_user;
37 return m_user;
38}
38}
@@ -46,7 +46,7 @@ void AccountsService::setUser(const QString &user)
46 updateBackgroundFile();
46 updateBackgroundFile();
47}
47}
48
48
49−bool AccountsService::getDemoEdges()
49+bool AccountsService::demoEdges() const
50{
50{
51 return m_demoEdges;
51 return m_demoEdges;
52}
52}
@@ -57,7 +57,7 @@ void AccountsService::setDemoEdges(bool demoEdges)
57 m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
57 m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
58}
58}
59
59
60−QString AccountsService::getBackgroundFile()
60+QString AccountsService::backgroundFile() const
61{
61{
62 return m_backgroundFile;
62 return m_backgroundFile;
63}
63}
plugins/AccountsService/AccountsService.h+6−6
@@ -28,25 +28,25 @@ class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30 Q_PROPERTY (QString user
30 Q_PROPERTY (QString user
31− READ getUser
31+ READ user
32 WRITE setUser
32 WRITE setUser
33 NOTIFY userChanged)
33 NOTIFY userChanged)
34 Q_PROPERTY (bool demoEdges
34 Q_PROPERTY (bool demoEdges
35− READ getDemoEdges
35+ READ demoEdges
36 WRITE setDemoEdges
36 WRITE setDemoEdges
37 NOTIFY demoEdgesChanged)
37 NOTIFY demoEdgesChanged)
38 Q_PROPERTY (QString backgroundFile
38 Q_PROPERTY (QString backgroundFile
39− READ getBackgroundFile
39+ READ backgroundFile
40 NOTIFY backgroundFileChanged)
40 NOTIFY backgroundFileChanged)
41
41
42public:
42public:
43 explicit AccountsService(QObject *parent = 0);
43 explicit AccountsService(QObject *parent = 0);
44
44
45− QString getUser();
45+ QString user() const;
46 void setUser(const QString &user);
46 void setUser(const QString &user);
47− bool getDemoEdges();
47+ bool demoEdges() const;
48 void setDemoEdges(bool demoEdges);
48 void setDemoEdges(bool demoEdges);
49− QString getBackgroundFile();
49+ QString backgroundFile() const;
50
50
51Q_SIGNALS:
51Q_SIGNALS:
52 void userChanged();
52 void userChanged();
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+15−15
@@ -24,13 +24,13 @@
24
24
25AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
25AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
26 : QObject(parent),
26 : QObject(parent),
27− accounts_manager(NULL),
27+ m_accountsManager(NULL),
28− users()
28+ m_users()
29{
29{
30− auto connection = QDBusConnection::SM_BUSNAME();
30+ QDBusConnection connection = QDBusConnection::SM_BUSNAME();
31− auto interface = connection.interface();
31+ QDBusConnectionInterface *interface = connection.interface();
32 interface->startService("org.freedesktop.Accounts");
32 interface->startService("org.freedesktop.Accounts");
33− accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
33+ m_accountsManager = new QDBusInterface("org.freedesktop.Accounts",
34 "/org/freedesktop/Accounts",
34 "/org/freedesktop/Accounts",
35 "org.freedesktop.Accounts",
35 "org.freedesktop.Accounts",
36 connection, this);
36 connection, this);
@@ -38,9 +38,9 @@ AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
38
38
39QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
39QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
40{
40{
41− auto iface = getUserInterface(user);
41+ QDBusInterface *iface = getUserInterface(user);
42 if (iface != nullptr && iface->isValid()) {
42 if (iface != nullptr && iface->isValid()) {
43− auto answer = iface->call("Get", interface, property);
43+ QDBusMessage answer = iface->call("Get", interface, property);
44 if (answer.type() == QDBusMessage::ReplyMessage) {
44 if (answer.type() == QDBusMessage::ReplyMessage) {
45 return answer.arguments()[0].value<QDBusVariant>().variant();
45 return answer.arguments()[0].value<QDBusVariant>().variant();
46 }
46 }
@@ -50,7 +50,7 @@ QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const
50
50
51void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
51void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
52{
52{
53− auto iface = getUserInterface(user);
53+ QDBusInterface *iface = getUserInterface(user);
54 if (iface != nullptr && iface->isValid()) {
54 if (iface != nullptr && iface->isValid()) {
55 // The value needs to be carefully wrapped
55 // The value needs to be carefully wrapped
56 iface->call("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
56 iface->call("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
@@ -76,7 +76,7 @@ void AccountsServiceDBusAdaptor::maybeChangedSlot()
76QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
76QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
77{
77{
78 QMap<QString, QDBusInterface *>::const_iterator i;
78 QMap<QString, QDBusInterface *>::const_iterator i;
79− for (i = users.constBegin(); i != users.constEnd(); ++i) {
79+ for (i = m_users.constBegin(); i != m_users.constEnd(); ++i) {
80 if (i.value()->path() == path) {
80 if (i.value()->path() == path) {
81 return i.key();
81 return i.key();
82 }
82 }
@@ -86,16 +86,16 @@ QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
86
86
87QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user)
87QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user)
88{
88{
89− auto iface = users.value(user);
89+ QDBusInterface *iface = m_users.value(user);
90− if (iface == nullptr && accounts_manager->isValid()) {
90+ if (iface == nullptr && m_accountsManager->isValid()) {
91− auto answer = accounts_manager->call("FindUserByName", user);
91+ QDBusMessage answer = m_accountsManager->call("FindUserByName", user);
92 if (answer.type() == QDBusMessage::ReplyMessage) {
92 if (answer.type() == QDBusMessage::ReplyMessage) {
93− auto path = answer.arguments()[0].value<QDBusObjectPath>().path();
93+ QString path = answer.arguments()[0].value<QDBusObjectPath>().path();
94
94
95 iface = new QDBusInterface("org.freedesktop.Accounts",
95 iface = new QDBusInterface("org.freedesktop.Accounts",
96 path,
96 path,
97 "org.freedesktop.DBus.Properties",
97 "org.freedesktop.DBus.Properties",
98− accounts_manager->connection(), this);
98+ m_accountsManager->connection(), this);
99
99
100 // With its own pre-defined properties, AccountsService is oddly
100 // With its own pre-defined properties, AccountsService is oddly
101 // close-lipped. It won't send out proper DBus.Properties notices,
101 // close-lipped. It won't send out proper DBus.Properties notices,
@@ -119,7 +119,7 @@ QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user
119 this,
119 this,
120 SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
120 SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
121
121
122− users.insert(user, iface);
122+ m_users.insert(user, iface);
123 }
123 }
124 }
124 }
125 return iface;
125 return iface;
plugins/AccountsService/AccountsServiceDBusAdaptor.h+2−2
@@ -47,8 +47,8 @@ private:
47 QDBusInterface *getUserInterface(const QString &user);
47 QDBusInterface *getUserInterface(const QString &user);
48 QString getUserForPath(const QString &path);
48 QString getUserForPath(const QString &path);
49
49
50− QDBusInterface *accounts_manager;
50+ QDBusInterface *m_accountsManager;
51− QMap<QString, QDBusInterface *> users;
51+ QMap<QString, QDBusInterface *> m_users;
52};
52};
53
53
54#endif
54#endif
plugins/CMakeLists.txt+1
@@ -3,6 +3,7 @@ add_subdirectory(HudClient)
3add_subdirectory(LightDM)
3add_subdirectory(LightDM)
4add_subdirectory(ListViewWithPageHeader)
4add_subdirectory(ListViewWithPageHeader)
5add_subdirectory(Powerd)
5add_subdirectory(Powerd)
6+add_subdirectory(SessionBroadcast)
6add_subdirectory(Ubuntu)
7add_subdirectory(Ubuntu)
7add_subdirectory(Unity)
8add_subdirectory(Unity)
8add_subdirectory(Utils)
9add_subdirectory(Utils)
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+20−1
@@ -170,6 +170,8 @@ ListViewWithPageHeader::ListViewWithPageHeader()
170 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
170 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
171 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
171 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
172 connect(m_contentYAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
172 connect(m_contentYAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
173+
174+ setFlickableDirection(VerticalFlick);
173}
175}
174
176
175ListViewWithPageHeader::~ListViewWithPageHeader()
177ListViewWithPageHeader::~ListViewWithPageHeader()
@@ -199,6 +201,7 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
199 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
201 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
200#endif
202#endif
201 Q_EMIT modelChanged();
203 Q_EMIT modelChanged();
204+ polish();
202 // TODO?
205 // TODO?
203// Q_EMIT contentHeightChanged();
206// Q_EMIT contentHeightChanged();
204// Q_EMIT contentYChanged();
207// Q_EMIT contentYChanged();
@@ -482,7 +485,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
482 // or the header is partially shown and we are not doing a maximizeVisibleArea either
485 // or the header is partially shown and we are not doing a maximizeVisibleArea either
483 const bool scrolledUp = m_previousContentY > contentY();
486 const bool scrolledUp = m_previousContentY > contentY();
484 const bool notRebounding = contentY() + height() < contentHeight();
487 const bool notRebounding = contentY() + height() < contentHeight();
485− const bool notShownByItsOwn = contentY() + diff > m_headerItem->y() + m_headerItem->height();
488+ const bool notShownByItsOwn = contentY() + diff >= m_headerItem->y() + m_headerItem->height();
486 const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
489 const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
487
490
488 if (!scrolledUp && contentY() == -m_minYExtent) {
491 if (!scrolledUp && contentY() == -m_minYExtent) {
@@ -1006,6 +1009,22 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
1006 }
1009 }
1007 }
1010 }
1008
1011
1012+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1013+ Q_FOREACH(const QQuickChangeSet::Change &change, changeSet.changes()) {
1014+#else
1015+ Q_FOREACH(const QQmlChangeSet::Change &change, changeSet.changes()) {
1016+#endif
1017+// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1018+ for (int i = change.index; i < change.count; ++i) {
1019+ ListItem *item = itemAtIndex(i);
1020+ if (item && item->m_sectionItem) {
1021+ QQmlContext *context = QQmlEngine::contextForObject(item->m_sectionItem)->parentContext();
1022+ const QString sectionText = m_delegateModel->stringValue(i, m_sectionProperty);
1023+ context->setContextProperty(QLatin1String("section"), sectionText);
1024+ }
1025+ }
1026+ }
1027+
1009 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
1028 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
1010 adjustMinYExtent();
1029 adjustMinYExtent();
1011 }
1030 }
plugins/ListViewWithPageHeader/listviewwithpageheader.h+1
@@ -63,6 +63,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
63
63
64 friend class ListViewWithPageHeaderTest;
64 friend class ListViewWithPageHeaderTest;
65 friend class ListViewWithPageHeaderTestSection;
65 friend class ListViewWithPageHeaderTestSection;
66+ friend class ListViewWithPageHeaderTestExternalModel;
66
67
67public:
68public:
68 ListViewWithPageHeader();
69 ListViewWithPageHeader();
plugins/SessionBroadcast/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(SessionBroadcast-qml MODULE
6+ SessionBroadcast.cpp
7+ plugin.cpp
8+ )
9+
10+qt5_use_modules(SessionBroadcast-qml DBus Qml)
11+
12+export_qmlfiles(SessionBroadcast SessionBroadcast)
13+export_qmlplugin(SessionBroadcast 0.1 SessionBroadcast TARGETS SessionBroadcast-qml)
plugins/SessionBroadcast/SessionBroadcast.cppnew file+41
@@ -0,0 +1,41 @@
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 "SessionBroadcast.h"
20+#include <QDBusConnection>
21+
22+SessionBroadcast::SessionBroadcast(QObject* parent)
23+ : QObject(parent)
24+{
25+ auto connection = QDBusConnection::SM_BUSNAME();
26+
27+ connection.connect("com.canonical.Unity.Greeter.Broadcast",
28+ "/com/canonical/Unity/Greeter/Broadcast",
29+ "com.canonical.Unity.Greeter.Broadcast",
30+ "ShowHome",
31+ this,
32+ SLOT(onShowHome(const QString &)));
33+}
34+
35+void SessionBroadcast::onShowHome(const QString &username)
36+{
37+ // Only listen to requests meant for us
38+ if (username == qgetenv("USER")) {
39+ Q_EMIT showHome();
40+ }
41+}
plugins/SessionBroadcast/SessionBroadcast.hnew file+41
@@ -0,0 +1,41 @@
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+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_H
20+#define UNITY_SESSIONBROADCAST_H
21+
22+#include <QObject>
23+#include <QString>
24+
25+class QDBusInterface;
26+
27+class SessionBroadcast: public QObject
28+{
29+ Q_OBJECT
30+
31+public:
32+ explicit SessionBroadcast(QObject *parent = 0);
33+
34+Q_SIGNALS:
35+ void showHome();
36+
37+private Q_SLOTS:
38+ void onShowHome(const QString &username);
39+};
40+
41+#endif
plugins/SessionBroadcast/plugin.cppnew file+35
@@ -0,0 +1,35 @@
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+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "SessionBroadcast.h"
21+
22+#include <QtQml>
23+
24+static QObject *broadcast_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25+{
26+ Q_UNUSED(engine)
27+ Q_UNUSED(scriptEngine)
28+ return new SessionBroadcast();
29+}
30+
31+void SessionBroadcastPlugin::registerTypes(const char *uri)
32+{
33+ Q_ASSERT(uri == QLatin1String("SessionBroadcast"));
34+ qmlRegisterSingletonType<SessionBroadcast>(uri, 0, 1, "SessionBroadcast", broadcast_provider);
35+}
plugins/SessionBroadcast/plugin.hnew 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+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_PLUGIN_H
20+#define UNITY_SESSIONBROADCAST_PLUGIN_H
21+
22+#include <QQmlExtensionPlugin>
23+
24+class SessionBroadcastPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif
plugins/SessionBroadcast/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module SessionBroadcast
2+plugin SessionBroadcast-qml
3+typeinfo plugin.qmltypes
plugins/Unity/CMakeLists.txt+1
@@ -43,6 +43,7 @@ set(QMLPLUGIN_SRC
43 preview.cpp
43 preview.cpp
44 previewaction.cpp
44 previewaction.cpp
45 previewinfohint.cpp
45 previewinfohint.cpp
46+ result.cpp
46 showallfilteroption.cpp
47 showallfilteroption.cpp
47 signalslist.cpp
48 signalslist.cpp
48 socialpreview.cpp
49 socialpreview.cpp
plugins/Unity/Launcher/backend/launcherbackend.cpp+8−9
@@ -132,11 +132,7 @@ QString LauncherBackend::icon(const QString &appId) const
132 }
132 }
133 }
133 }
134
134
135− QFileInfo info(iconName);
136− if (info.exists()) {
137− return info.absoluteFilePath();
138− }
139− return "image://theme/" + iconName;
135+ return iconName;
140}
136}
141
137
142bool LauncherBackend::isPinned(const QString &appId) const
138bool LauncherBackend::isPinned(const QString &appId) const
@@ -296,15 +292,18 @@ LauncherBackendItem* LauncherBackend::parseDesktopFile(const QString &desktopFil
296{
292{
297 QSettings settings(desktopFile, QSettings::IniFormat);
293 QSettings settings(desktopFile, QSettings::IniFormat);
298
294
299−
300 LauncherBackendItem* item = new LauncherBackendItem();
295 LauncherBackendItem* item = new LauncherBackendItem();
301 item->desktopFile = desktopFile;
296 item->desktopFile = desktopFile;
302 item->displayName = settings.value("Desktop Entry/Name").toString();
297 item->displayName = settings.value("Desktop Entry/Name").toString();
303
298
304− if (settings.contains("Desktop Entry/Path")) {
305− item->icon = settings.value("Desktop Entry/Path").toString() + "/" + settings.value("Desktop Entry/Icon").toString();
299+ QString iconString = settings.value("Desktop Entry/Icon").toString();
300+ QString pathString = settings.value("Desktop Entry/Path").toString();
301+ if (QFileInfo(iconString).exists()) {
302+ item->icon = QFileInfo(iconString).absoluteFilePath();
303+ } else if (QFileInfo(pathString + '/' + iconString).exists()) {
304+ item->icon = pathString + '/' + iconString;
306 } else {
305 } else {
307− item->icon = settings.value("Desktop Entry/Icon").toString();
306+ item->icon = "image://theme/" + iconString;
308 }
307 }
309 item->pinned = false;
308 item->pinned = false;
310 return item;
309 return item;
plugins/Unity/Launcher/launchermodel.cpp+12−3
@@ -115,9 +115,11 @@ void LauncherModel::move(int oldIndex, int newIndex)
115 m_list.move(oldIndex, newIndex);
115 m_list.move(oldIndex, newIndex);
116 endMoveRows();
116 endMoveRows();
117
117
118− storeAppList();
118+ if (!m_list.at(newIndex)->pinned()) {
119−
120− pin(m_list.at(newIndex)->appId());
119+ pin(m_list.at(newIndex)->appId());
120+ } else {
121+ storeAppList();
122+ }
121}
123}
122
124
123void LauncherModel::pin(const QString &appId, int index)
125void LauncherModel::pin(const QString &appId, int index)
@@ -146,6 +148,8 @@ void LauncherModel::pin(const QString &appId, int index)
146 m_list.insert(index, item);
148 m_list.insert(index, item);
147 endInsertRows();
149 endInsertRows();
148 }
150 }
151+
152+ storeAppList();
149}
153}
150
154
151void LauncherModel::requestRemove(const QString &appId)
155void LauncherModel::requestRemove(const QString &appId)
@@ -155,6 +159,11 @@ void LauncherModel::requestRemove(const QString &appId)
155 return;
159 return;
156 }
160 }
157
161
162+ if (m_appManager->findApplication(appId)) {
163+ m_list.at(index)->setPinned(false);
164+ return;
165+ }
166+
158 beginRemoveRows(QModelIndex(), index, index);
167 beginRemoveRows(QModelIndex(), index, index);
159 m_list.takeAt(index)->deleteLater();
168 m_list.takeAt(index)->deleteLater();
160 endRemoveRows();
169 endRemoveRows();
plugins/Unity/categories.cpp+12−1
@@ -21,6 +21,7 @@
21// self
21// self
22#include "categories.h"
22#include "categories.h"
23#include "categoryresults.h"
23#include "categoryresults.h"
24+#include <QDebug>
24
25
25// TODO: use something from libunity once it's public
26// TODO: use something from libunity once it's public
26enum CategoryColumn {
27enum CategoryColumn {
@@ -62,7 +63,17 @@ Categories::getResults(int index) const
62
63
63 unsigned categoryIndex = static_cast<unsigned>(index);
64 unsigned categoryIndex = static_cast<unsigned>(index);
64 auto unity_results = m_unityScope->GetResultsForCategory(categoryIndex);
65 auto unity_results = m_unityScope->GetResultsForCategory(categoryIndex);
66+ if (unity_results) {
65− results->setModel(unity_results->model());
67+ results->setModel(unity_results->model());
68+ } else {
69+ // No results model returned by unity core; this can be the case when the global
70+ // results model of this scope is still not set in unity core. Don't set backend
71+ // model in DeeListModel - it will still beahve properly as an empty model. Since
72+ // we're connected to the category model change signal, and it is set by unity core
73+ // at the same time as results model (on channel opening), we'll reset category
74+ // results models with proper models when we're notifed again.
75+ qWarning() << "No results model for category" << categoryIndex;
76+ }
66
77
67 m_results.insert(index, results);
78 m_results.insert(index, results);
68 }
79 }
plugins/Unity/iconutils.cpp+1−1
@@ -30,7 +30,7 @@ QString gIconToDeclarativeImageProviderString(QString const &giconString)
30 if (giconString.isEmpty()) return giconString;
30 if (giconString.isEmpty()) return giconString;
31
31
32 if (giconString.startsWith('/') || giconString.startsWith(QLatin1String("http")) ||
32 if (giconString.startsWith('/') || giconString.startsWith(QLatin1String("http")) ||
33− giconString.startsWith(QLatin1String("file:"))) {
33+ giconString.startsWith(QLatin1String("file:")) || giconString.startsWith(QLatin1String("image:"))) {
34 return giconString;
34 return giconString;
35 }
35 }
36
36
plugins/Unity/plugin.cpp+2
@@ -35,6 +35,7 @@
35#include "categoryresults.h"
35#include "categoryresults.h"
36#include "bottombarvisibilitycommunicatorshell.h"
36#include "bottombarvisibilitycommunicatorshell.h"
37#include "genericoptionsmodel.h"
37#include "genericoptionsmodel.h"
38+#include "result.h"
38
39
39// libqtdee
40// libqtdee
40#include "deelistmodel.h"
41#include "deelistmodel.h"
@@ -50,6 +51,7 @@ void UnityPlugin::registerTypes(const char *uri)
50 qmlRegisterUncreatableType<PreviewInfoHint>(uri, 0, 1, "PreviewInfoHint", "Can't create PreviewInfoHint object in QML.");
51 qmlRegisterUncreatableType<PreviewInfoHint>(uri, 0, 1, "PreviewInfoHint", "Can't create PreviewInfoHint object in QML.");
51 qmlRegisterUncreatableType<SocialPreviewComment>(uri, 0, 1, "SocialPreviewComment", "Can't create SocialPreviewComment object in QML.");
52 qmlRegisterUncreatableType<SocialPreviewComment>(uri, 0, 1, "SocialPreviewComment", "Can't create SocialPreviewComment object in QML.");
52 qmlRegisterUncreatableType<GenericOptionsModel>(uri, 0, 1, "GenericOptionsModel", "Can't create options model in QML.");
53 qmlRegisterUncreatableType<GenericOptionsModel>(uri, 0, 1, "GenericOptionsModel", "Can't create options model in QML.");
54+ qmlRegisterUncreatableType<Result>(uri, 0, 1, "Result", "Can't create result object in QML.");
53 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
55 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
54 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
56 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
55 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
57 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
plugins/Unity/preview.cpp+17−2
@@ -39,9 +39,12 @@
39#include <UnityCore/MusicPreview.h>
39#include <UnityCore/MusicPreview.h>
40#include <UnityCore/SocialPreview.h>
40#include <UnityCore/SocialPreview.h>
41
41
42+#include <UnityCore/GLibWrapper.h>
43+
42Preview::Preview(QObject *parent):
44Preview::Preview(QObject *parent):
43 QObject(parent),
45 QObject(parent),
44− m_unityPreview(nullptr)
46+ m_unityPreview(nullptr),
47+ m_result(new Result(this))
45{
48{
46}
49}
47
50
@@ -123,6 +126,11 @@ QString Preview::imageSourceUri() const
123 return QString::null;
126 return QString::null;
124}
127}
125
128
129+QVariant Preview::result() const
130+{
131+ return QVariant::fromValue(m_result);
132+}
133+
126Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
134Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
127{
135{
128 Preview* preview = nullptr;
136 Preview* preview = nullptr;
@@ -151,6 +159,7 @@ Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
151void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
159void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
152{
160{
153 m_unityPreview = unityPreview;
161 m_unityPreview = unityPreview;
162+ m_result->setPreview(unityPreview);
154
163
155 qDeleteAll(m_infoHints);
164 qDeleteAll(m_infoHints);
156 m_infoHints.clear();
165 m_infoHints.clear();
@@ -181,8 +190,14 @@ void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& h
181{
190{
182 if (m_unityPreview) {
191 if (m_unityPreview) {
183 auto unityHints = convertToHintsMap(hints);
192 auto unityHints = convertToHintsMap(hints);
193+ m_actionCancellable.Renew();
184− m_unityPreview->PerformAction(actionId.toStdString(), unityHints);
194+ m_unityPreview->PerformAction(actionId.toStdString(), unityHints, nullptr, m_actionCancellable);
185 } else {
195 } else {
186 qWarning() << "Preview not set";
196 qWarning() << "Preview not set";
187 }
197 }
188}
198}
199+
200+void Preview::cancelAction()
201+{
202+ m_actionCancellable.Cancel();
203+}
plugins/Unity/preview.h+7
@@ -31,7 +31,9 @@
31#include <UnityCore/Preview.h>
31#include <UnityCore/Preview.h>
32
32
33// local
33// local
34+#include "result.h"
34#include "previewaction.h"
35#include "previewaction.h"
36+#include <UnityCore/GLibWrapper.h>
35
37
36class Q_DECL_EXPORT Preview : public QObject
38class Q_DECL_EXPORT Preview : public QObject
37{
39{
@@ -46,6 +48,7 @@ class Q_DECL_EXPORT Preview : public QObject
46 Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
48 Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
47 Q_PROPERTY(QString image READ image NOTIFY previewChanged)
49 Q_PROPERTY(QString image READ image NOTIFY previewChanged)
48 Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
50 Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
51+ Q_PROPERTY(QVariant result READ result NOTIFY previewChanged)
49
52
50public:
53public:
51 explicit Preview(QObject *parent = 0);
54 explicit Preview(QObject *parent = 0);
@@ -60,8 +63,10 @@ public:
60 QVariantMap infoHintsHash() const;
63 QVariantMap infoHintsHash() const;
61 QString image() const;
64 QString image() const;
62 QString imageSourceUri() const;
65 QString imageSourceUri() const;
66+ QVariant result() const;
63
67
64 Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
68 Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
69+ Q_INVOKABLE void cancelAction();
65
70
66Q_SIGNALS:
71Q_SIGNALS:
67 void previewChanged();
72 void previewChanged();
@@ -70,6 +75,7 @@ protected:
70 virtual void setUnityPreview(unity::dash::Preview::Ptr unityPreview);
75 virtual void setUnityPreview(unity::dash::Preview::Ptr unityPreview);
71
76
72 unity::dash::Preview::Ptr m_unityPreview;
77 unity::dash::Preview::Ptr m_unityPreview;
78+ Result* m_result;
73
79
74private:
80private:
75 void setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview);
81 void setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview);
@@ -77,6 +83,7 @@ private:
77 QList<QObject *> m_actions;
83 QList<QObject *> m_actions;
78 QList<QObject *> m_infoHints;
84 QList<QObject *> m_infoHints;
79 QVariantMap m_infoHintsHash;
85 QVariantMap m_infoHintsHash;
86+ unity::glib::Cancellable m_actionCancellable;
80};
87};
81
88
82Q_DECLARE_METATYPE(Preview *)
89Q_DECLARE_METATYPE(Preview *)
plugins/Unity/result.cppnew file+82
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@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+#include "result.h"
21+#include "variantutils.h"
22+
23+Result::Result(QObject *parent) :
24+ QObject(parent)
25+{
26+}
27+
28+Result::Result(unity::dash::Preview::Ptr preview, QObject *parent) :
29+ QObject(parent),
30+ m_preview(preview)
31+{
32+}
33+
34+void Result::setPreview(unity::dash::Preview::Ptr preview)
35+{
36+ m_preview = preview;
37+}
38+
39+QString Result::uri() const
40+{
41+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.uri) : QString::null;
42+}
43+
44+QString Result::iconHint() const
45+{
46+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.icon_hint) : QString::null;
47+}
48+
49+unsigned Result::categoryIndex() const
50+{
51+ return m_preview != nullptr ? m_preview->preview_result.category_index : 0;
52+}
53+
54+unsigned Result::resultType() const
55+{
56+ return m_preview != nullptr ? m_preview->preview_result.result_type : 0;
57+}
58+
59+QString Result::mimeType() const
60+{
61+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.mimetype) : QString::null;
62+}
63+
64+QString Result::title() const
65+{
66+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.name) : QString::null;
67+}
68+
69+QString Result::comment() const
70+{
71+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.comment) : QString::null;
72+}
73+
74+QString Result::dndUri() const
75+{
76+ return m_preview != nullptr ? QString::fromStdString(m_preview->preview_result.dnd_uri) : QString::null;
77+}
78+
79+QVariant Result::metadata() const
80+{
81+ return m_preview != nullptr ? convertToQVariantHash(m_preview->preview_result.hints) : QVariant();
82+}
plugins/Unity/result.hnew file+69
@@ -0,0 +1,69 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@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+#ifndef RESULT_H
21+#define RESULT_H
22+
23+// Qt
24+#include <QObject>
25+#include <QVariant>
26+
27+// libunity-core
28+#include <UnityCore/Preview.h>
29+
30+class Q_DECL_EXPORT Result : public QObject
31+{
32+ Q_OBJECT
33+
34+ Q_PROPERTY(QString uri READ uri CONSTANT)
35+ Q_PROPERTY(QString iconHint READ iconHint CONSTANT)
36+ Q_PROPERTY(unsigned categoryIndex READ categoryIndex CONSTANT)
37+ Q_PROPERTY(unsigned resultType READ resultType CONSTANT)
38+ Q_PROPERTY(QString mimeType READ mimeType CONSTANT)
39+ Q_PROPERTY(QString title READ title CONSTANT)
40+ Q_PROPERTY(QString comment READ comment CONSTANT)
41+ Q_PROPERTY(QString dndUri READ dndUri CONSTANT)
42+ Q_PROPERTY(QVariant metadata READ metadata CONSTANT)
43+
44+public:
45+ Result(QObject *parent = nullptr);
46+ Result(unity::dash::Preview::Ptr preview, QObject *parent = nullptr);
47+
48+ void setPreview(unity::dash::Preview::Ptr preview);
49+
50+ QString uri() const;
51+ QString iconHint() const;
52+ unsigned categoryIndex() const;
53+ unsigned resultType() const;
54+ QString mimeType() const;
55+ QString title() const;
56+ QString comment() const;
57+ QString dndUri() const;
58+ QVariant metadata() const;
59+
60+private:
61+ /* Keep reference to the original preview to access result attributes via it, rather than keeping copies of them;
62+ this will save us a bit on copying, especially as UI is mostly interested in just uri.
63+ */
64+ unity::dash::Preview::Ptr m_preview;
65+};
66+
67+Q_DECLARE_METATYPE(Result *)
68+
69+#endif
plugins/Unity/scope.cpp+20−1
@@ -175,7 +175,19 @@ void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVaria
175 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
175 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
176{
176{
177 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
177 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
178+ m_previewCancellable.Renew();
179+
180+ // canned queries don't have previews, must be activated
181+ if (uri.toString().startsWith("x-unity-no-preview-scopes-query://")) {
182+ m_unityScope->Activate(res);
183+ } else {
178− m_unityScope->Preview(res);
184+ m_unityScope->Preview(res, nullptr, m_previewCancellable);
185+ }
186+}
187+
188+void Scope::cancelActivation()
189+{
190+ m_previewCancellable.Cancel();
179}
191}
180
192
181void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
193void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
@@ -199,6 +211,13 @@ void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::Sco
199 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
211 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
200 }
212 }
201 break;
213 break;
214+ case unity::dash::PERFORM_SEARCH:
215+ if (hints.find("query") != hints.end()) {
216+ // note: this will emit searchQueryChanged, and shell will call setSearchQuery back with a new query,
217+ // but it will get ignored.
218+ setSearchQuery(QString::fromStdString(g_variant_get_string(hints.at("query"), nullptr)));
219+ }
220+ break;
202 default:
221 default:
203 qWarning() << "Unhandled activation response:" << type;
222 qWarning() << "Unhandled activation response:" << type;
204 }
223 }
plugins/Unity/scope.h+3
@@ -82,6 +82,8 @@ public:
82 Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
82 Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
83 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
83 const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
84 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
84 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
85+ Q_INVOKABLE void cancelActivation();
86+
85 void setUnityScope(const unity::dash::Scope::Ptr& scope);
87 void setUnityScope(const unity::dash::Scope::Ptr& scope);
86 unity::dash::Scope::Ptr unityScope() const;
88 unity::dash::Scope::Ptr unityScope() const;
87
89
@@ -131,6 +133,7 @@ private:
131 QString m_searchQuery;
133 QString m_searchQuery;
132 QString m_noResultsHint;
134 QString m_noResultsHint;
133 QString m_formFactor;
135 QString m_formFactor;
136+ unity::glib::Cancellable m_previewCancellable;
134};
137};
135
138
136Q_DECLARE_METATYPE(Scope*)
139Q_DECLARE_METATYPE(Scope*)
plugins/Unity/variantutils.cpp+9
@@ -40,3 +40,12 @@ unity::glib::HintsMap convertToHintsMap(const QVariant &var)
40 }
40 }
41 return unity::glib::HintsMap();
41 return unity::glib::HintsMap();
42}
42}
43+
44+QVariantHash convertToQVariantHash(const unity::glib::HintsMap& var)
45+{
46+ QVariantHash hash;
47+ for (auto hint: var) {
48+ hash.insert(QString::fromStdString(hint.first), DeeListModel::VariantForData(hint.second));
49+ }
50+ return hash;
51+}
plugins/Unity/variantutils.h+1
@@ -28,5 +28,6 @@
28
28
29unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
29unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
30unity::glib::HintsMap convertToHintsMap(const QVariant &var);
30unity::glib::HintsMap convertToHintsMap(const QVariant &var);
31+QVariantHash convertToQVariantHash(const unity::glib::HintsMap& var);
31
32
32#endif
33#endif
po/fi.po+15−15
@@ -8,15 +8,15 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-08-23 16:15+0000\n"
11+"PO-Revision-Date: 2013-09-26 09:25+0000\n"
12−"Last-Translator: Timo Jyrinki <timo.jyrinki@canonical.com>\n"
12+"Last-Translator: Jiri Grönroos <Unknown>\n"
13"Language-Team: Finnish <fi@li.org>\n"
13"Language-Team: Finnish <fi@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
17"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
18+"X-Launchpad-Export-Date: 2013-09-27 06:43+0000\n"
19−"X-Generator: Launchpad (build 16750)\n"
19+"X-Generator: Launchpad (build 16774)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -88,47 +88,47 @@ msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Ohita esittely"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Oikea reuna"
96
96
97#: Components/EdgeDemo.qml:99
97#: Components/EdgeDemo.qml:99
98msgid "Try swiping from the right edge to unlock the phone"
98msgid "Try swiping from the right edge to unlock the phone"
99−msgstr ""
99+msgstr "Vedä oikealta avataksesi puhelimen lukituksen"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Yläreuna"
104
104
105#: Components/EdgeDemo.qml:136
105#: Components/EdgeDemo.qml:136
106msgid "Try swiping from the top edge to access the indicators"
106msgid "Try swiping from the top edge to access the indicators"
107−msgstr ""
107+msgstr "Vedä yläreunasta käyttääksesi ilmaisimia"
108
108
109#: Components/EdgeDemo.qml:161
109#: Components/EdgeDemo.qml:161
110msgid "Close"
110msgid "Close"
111−msgstr ""
111+msgstr "Sulje"
112
112
113#: Components/EdgeDemo.qml:162
113#: Components/EdgeDemo.qml:162
114msgid "Swipe up again to close the settings screen"
114msgid "Swipe up again to close the settings screen"
115−msgstr ""
115+msgstr "Vedä uudestaan sulkeaksesi asetusnäkymän"
116
116
117#: Components/EdgeDemo.qml:189
117#: Components/EdgeDemo.qml:189
118msgid "Left edge"
118msgid "Left edge"
119−msgstr ""
119+msgstr "Vasen reuna"
120
120
121#: Components/EdgeDemo.qml:190
121#: Components/EdgeDemo.qml:190
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
122msgid "Swipe from the left to reveal the launcher for quick access to apps"
123−msgstr ""
123+msgstr "Vedä vasemmalta saattaaksesi sovellusten käynnistimen esiin"
124
124
125#: Components/EdgeDemo.qml:217
125#: Components/EdgeDemo.qml:217
126msgid "Well done"
126msgid "Well done"
127−msgstr ""
127+msgstr "Hyvin tehty"
128
128
129#: Components/EdgeDemo.qml:218
129#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
130msgid "You have now mastered the edge gestures and can start using the phone"
131−msgstr ""
131+msgstr "Hallitset nyt reunaeleet, joten voit aloittaa puhelimen käytön"
132
132
133#: Components/PageHeader.qml:298
133#: Components/PageHeader.qml:298
134msgid "Recent searches"
134msgid "Recent searches"
po/is.ponew file+256
@@ -0,0 +1,256 @@
1+# Icelandic translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-18 16:22+0000\n"
12+"Last-Translator: Andri Thorlacius <Unknown>\n"
13+"Language-Team: Icelandic <is@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-09-19 05:14+0000\n"
19+"X-Generator: Launchpad (build 16765)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr "Sími"
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr "Myndavél"
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr "Myndasafn"
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr "Facebook"
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr "Vafri"
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr "Twitter"
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr "GMail"
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr "Veður"
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr "Skrifblokk"
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr "Dagatal"
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr "Margmiðlunarspilari"
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr "Evernote"
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr "Kort"
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr "Pinterest"
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr "SoundCloud"
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr "Wikipedia"
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr "YouTube"
88+
89+#: Components/EdgeDemoOverlay.qml:145
90+msgid "Skip intro"
91+msgstr "Hoppa yfir kynningu"
92+
93+#: Components/EdgeDemo.qml:98
94+msgid "Right edge"
95+msgstr "Hægri brún"
96+
97+#: Components/EdgeDemo.qml:99
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+"Prufaðu að renna puttanum frá hægri brúninni til að aflæsa símanum þínum."
101+
102+#: Components/EdgeDemo.qml:135
103+msgid "Top edge"
104+msgstr "Efri brún"
105+
106+#: Components/EdgeDemo.qml:136
107+msgid "Try swiping from the top edge to access the indicators"
108+msgstr ""
109+
110+#: Components/EdgeDemo.qml:161
111+msgid "Close"
112+msgstr "Loka"
113+
114+#: Components/EdgeDemo.qml:162
115+msgid "Swipe up again to close the settings screen"
116+msgstr ""
117+
118+#: Components/EdgeDemo.qml:189
119+msgid "Left edge"
120+msgstr "Vinstri brún"
121+
122+#: Components/EdgeDemo.qml:190
123+msgid "Swipe from the left to reveal the launcher for quick access to apps"
124+msgstr ""
125+
126+#: Components/EdgeDemo.qml:217
127+msgid "Well done"
128+msgstr "Vel gert"
129+
130+#: Components/EdgeDemo.qml:218
131+msgid "You have now mastered the edge gestures and can start using the phone"
132+msgstr ""
133+
134+#: Components/PageHeader.qml:298
135+msgid "Recent searches"
136+msgstr "Nýlegar leitir"
137+
138+#. TRANSLATORS: Number of persons who rated this app
139+#: Dash/Apps/AppInfo.qml:73
140+#, qt-format
141+msgid "(%1)"
142+msgstr "(%1)"
143+
144+#. TRANSLATORS: Number of persons who wrote reviews for this app
145+#: Dash/Apps/AppInfo.qml:85
146+#, qt-format
147+msgid "%1 review"
148+msgid_plural "%1 reviews"
149+msgstr[0] "%1 ummæli"
150+msgstr[1] "%1 ummæli"
151+
152+#: Dash/Apps/AppPreview.qml:175
153+msgid "Rate this"
154+msgstr "Gefa þessu einkunn"
155+
156+#: Dash/Apps/AppReviews.qml:72
157+msgid "Add a review"
158+msgstr "Gefa umsögn"
159+
160+#: Dash/Apps/AppReviews.qml:84
161+msgid "Review"
162+msgstr "Umsögn"
163+
164+#: Dash/Apps/AppReviews.qml:118
165+msgid "Send"
166+msgstr "Senda"
167+
168+#: Dash/Apps/AppReviews.qml:136
169+msgid "Comments:"
170+msgstr "Athugasemdir:"
171+
172+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173+msgid "Featured"
174+msgstr "Efst á baugi"
175+
176+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177+msgid "Recent"
178+msgstr "Nýlegt"
179+
180+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
181+msgid "New Releases"
182+msgstr "Nýjar Útgáfur"
183+
184+#: Dash/DashMusic.qml:30
185+msgid "Top Charting"
186+msgstr "Topp Listi"
187+
188+#: Dash/DashMusic.qml:91
189+msgid "Music"
190+msgstr "Tónlist"
191+
192+#: Dash/DashVideos.qml:31
193+msgid "Popular Online"
194+msgstr "Vinsælt á Netinu"
195+
196+#: Dash/DashVideos.qml:146
197+msgid "Videos"
198+msgstr "Myndbönd"
199+
200+#: Dash/Video/VideoPreview.qml:130
201+msgid "Directed by:"
202+msgstr "Leikstýrt af:"
203+
204+#: Dash/Video/VideoPreview.qml:153
205+msgid "Starring:"
206+msgstr "Meðal leikara eru:"
207+
208+#: Dash/Video/VideoPreview.qml:176
209+msgid "Author:"
210+msgstr "Höfundur:"
211+
212+#: Greeter/Lockscreen.qml:134
213+msgid "Emergency Call"
214+msgstr "Neyðarsímtal"
215+
216+#: Greeter/PassphraseLockscreen.qml:59
217+#, qt-format
218+msgid "Hello %1"
219+msgstr "Hæ %1"
220+
221+#: Greeter/PassphraseLockscreen.qml:59
222+msgid "Hello"
223+msgstr "Hæ"
224+
225+#: Hud/HudParametrizedActionsPage.qml:132
226+msgid "Confirm"
227+msgstr "Staðfesta"
228+
229+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
230+msgid "Type or say a command"
231+msgstr "Skrifaðu eða segðu eitthvað"
232+
233+#: Hud/Hud.qml:84
234+msgid "Loading. Please Wait..."
235+msgstr "Hleð. Vinsamlegast Bíðið..."
236+
237+#: Hud/Hud.qml:89
238+msgid "Speak Now..."
239+msgstr "Talaðu Núna..."
240+
241+#: Hud/Hud.qml:94
242+msgid "Speaking..."
243+msgstr "Tala..."
244+
245+#: Panel/SearchIndicator.qml:27
246+msgid "Search"
247+msgstr "Leita"
248+
249+#: plugins/Unity/scope.cpp:317
250+msgid "Sorry, there is nothing that matches your search."
251+msgstr "Því miður, það var ekkert sem passaði við leitarorðið þitt."
252+
253+#: Shell.qml:429
254+#, qt-format
255+msgid "Please enter %1"
256+msgstr ""
po/sl.po+29−24
@@ -8,7 +8,7 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
10"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-02 12:59+0000\n"
11+"PO-Revision-Date: 2013-09-19 19:48+0000\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
@@ -16,8 +16,8 @@ msgstr ""
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
17"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
18"n%100==4 ? 3 : 0);\n"
18"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2013-08-30 05:37+0000\n"
19+"X-Launchpad-Export-Date: 2013-09-20 06:21+0000\n"
20−"X-Generator: Launchpad (build 16750)\n"
20+"X-Generator: Launchpad (build 16765)\n"
21
21
22#: Applications/applications.js:23
22#: Applications/applications.js:23
23msgid "Phone"
23msgid "Phone"
@@ -25,7 +25,7 @@ msgstr "Telefon"
25
25
26#: Applications/applications.js:29
26#: Applications/applications.js:29
27msgid "Camera"
27msgid "Camera"
28−msgstr ""
28+msgstr "Fotoaparat"
29
29
30#: Applications/applications.js:35
30#: Applications/applications.js:35
31msgid "Gallery"
31msgid "Gallery"
@@ -89,47 +89,50 @@ msgstr "YouTube"
89
89
90#: Components/EdgeDemoOverlay.qml:145
90#: Components/EdgeDemoOverlay.qml:145
91msgid "Skip intro"
91msgid "Skip intro"
92−msgstr ""
92+msgstr "Preskoči uvod"
93
93
94#: Components/EdgeDemo.qml:98
94#: Components/EdgeDemo.qml:98
95msgid "Right edge"
95msgid "Right edge"
96−msgstr ""
96+msgstr "Desni rob"
97
97
98#: Components/EdgeDemo.qml:99
98#: Components/EdgeDemo.qml:99
99msgid "Try swiping from the right edge to unlock the phone"
99msgid "Try swiping from the right edge to unlock the phone"
100−msgstr ""
100+msgstr "Poskusite povleči od desnega roba za odklep telefona"
101
101
102#: Components/EdgeDemo.qml:135
102#: Components/EdgeDemo.qml:135
103msgid "Top edge"
103msgid "Top edge"
104−msgstr ""
104+msgstr "Zgornji rob"
105
105
106#: Components/EdgeDemo.qml:136
106#: Components/EdgeDemo.qml:136
107msgid "Try swiping from the top edge to access the indicators"
107msgid "Try swiping from the top edge to access the indicators"
108−msgstr ""
108+msgstr "Poskusite povleči od zgornjega roba za dostop do kazalnikov"
109
109
110#: Components/EdgeDemo.qml:161
110#: Components/EdgeDemo.qml:161
111msgid "Close"
111msgid "Close"
112−msgstr ""
112+msgstr "Zapri"
113
113
114#: Components/EdgeDemo.qml:162
114#: Components/EdgeDemo.qml:162
115msgid "Swipe up again to close the settings screen"
115msgid "Swipe up again to close the settings screen"
116−msgstr ""
116+msgstr "Povlecite ponovno navzgor za zaprtje zaslona z nastavitvami"
117
117
118#: Components/EdgeDemo.qml:189
118#: Components/EdgeDemo.qml:189
119msgid "Left edge"
119msgid "Left edge"
120−msgstr ""
120+msgstr "Levi rob"
121
121
122#: Components/EdgeDemo.qml:190
122#: Components/EdgeDemo.qml:190
123msgid "Swipe from the left to reveal the launcher for quick access to apps"
123msgid "Swipe from the left to reveal the launcher for quick access to apps"
124msgstr ""
124msgstr ""
125+"Poskusite povleči od leve za razkritje zaganjalnika za hiter dostop do "
126+"programov"
125
127
126#: Components/EdgeDemo.qml:217
128#: Components/EdgeDemo.qml:217
127msgid "Well done"
129msgid "Well done"
128−msgstr ""
130+msgstr "Odlično"
129
131
130#: Components/EdgeDemo.qml:218
132#: Components/EdgeDemo.qml:218
131msgid "You have now mastered the edge gestures and can start using the phone"
133msgid "You have now mastered the edge gestures and can start using the phone"
132msgstr ""
134msgstr ""
135+"Zdaj, ko ste osvojili kretnje z robovi, lahko začnete uporabljati telefon"
133
136
134#: Components/PageHeader.qml:298
137#: Components/PageHeader.qml:298
135msgid "Recent searches"
138msgid "Recent searches"
@@ -139,35 +142,37 @@ msgstr "Nedavna iskanja"
139#: Dash/Apps/AppInfo.qml:73
142#: Dash/Apps/AppInfo.qml:73
140#, qt-format
143#, qt-format
141msgid "(%1)"
144msgid "(%1)"
142−msgstr ""
145+msgstr "(%1)"
143
146
144#. TRANSLATORS: Number of persons who wrote reviews for this app
147#. TRANSLATORS: Number of persons who wrote reviews for this app
145#: Dash/Apps/AppInfo.qml:85
148#: Dash/Apps/AppInfo.qml:85
146#, qt-format
149#, qt-format
147msgid "%1 review"
150msgid "%1 review"
148msgid_plural "%1 reviews"
151msgid_plural "%1 reviews"
149−msgstr[0] ""
152+msgstr[0] "%1 ocen"
153+msgstr[1] "%1 ocena"
150−msgstr[1] ""
154+msgstr[2] "%1 oceni"
155+msgstr[3] "%1 ocene"
151
156
152#: Dash/Apps/AppPreview.qml:175
157#: Dash/Apps/AppPreview.qml:175
153msgid "Rate this"
158msgid "Rate this"
154−msgstr ""
159+msgstr "Ocenite"
155
160
156#: Dash/Apps/AppReviews.qml:72
161#: Dash/Apps/AppReviews.qml:72
157msgid "Add a review"
162msgid "Add a review"
158−msgstr ""
163+msgstr "Dodaj oceno"
159
164
160#: Dash/Apps/AppReviews.qml:84
165#: Dash/Apps/AppReviews.qml:84
161msgid "Review"
166msgid "Review"
162−msgstr ""
167+msgstr "Ocena"
163
168
164#: Dash/Apps/AppReviews.qml:118
169#: Dash/Apps/AppReviews.qml:118
165msgid "Send"
170msgid "Send"
166−msgstr ""
171+msgstr "Pošlji"
167
172
168#: Dash/Apps/AppReviews.qml:136
173#: Dash/Apps/AppReviews.qml:136
169msgid "Comments:"
174msgid "Comments:"
170−msgstr ""
175+msgstr "Opombe:"
171
176
172#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173msgid "Featured"
178msgid "Featured"
@@ -211,7 +216,7 @@ msgstr ""
211
216
212#: Greeter/Lockscreen.qml:134
217#: Greeter/Lockscreen.qml:134
213msgid "Emergency Call"
218msgid "Emergency Call"
214−msgstr ""
219+msgstr "Klic v sili"
215
220
216#: Greeter/PassphraseLockscreen.qml:59
221#: Greeter/PassphraseLockscreen.qml:59
217#, qt-format
222#, qt-format
@@ -220,7 +225,7 @@ msgstr "Pozdravljeni, %1"
220
225
221#: Greeter/PassphraseLockscreen.qml:59
226#: Greeter/PassphraseLockscreen.qml:59
222msgid "Hello"
227msgid "Hello"
223−msgstr ""
228+msgstr "Pozdravljeni"
224
229
225#: Hud/HudParametrizedActionsPage.qml:132
230#: Hud/HudParametrizedActionsPage.qml:132
226msgid "Confirm"
231msgid "Confirm"
@@ -253,4 +258,4 @@ msgstr "Nič se ne ujema z vašim iskalnim nizom."
253#: Shell.qml:429
258#: Shell.qml:429
254#, qt-format
259#, qt-format
255msgid "Please enter %1"
260msgid "Please enter %1"
256−msgstr ""
261+msgstr "Vnesite %1"
tests/autopilot/unity8/application_lifecycle/__init__.pynew file+20
@@ -0,0 +1,20 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle base package."""
tests/autopilot/unity8/application_lifecycle/tests/__init__.pynew file

No changes to the content.

tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.pynew file+136
@@ -0,0 +1,136 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle."""
21+
22+from __future__ import absolute_import
23+
24+from unity8.shell import disable_qml_mocking
25+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26+
27+from autopilot.matchers import Eventually
28+from autopilot.platform import model
29+from testtools.matchers import Equals, NotEquals
30+
31+import logging
32+
33+logger = logging.getLogger(__name__)
34+
35+
36+class ApplicationLifecycleTests(UnityTestCase):
37+
38+ scenarios = _get_device_emulation_scenarios()
39+
40+ def setUp(self):
41+ super(ApplicationLifecycleTests, self).setUp()
42+ if model() == "Desktop":
43+ self.skipTest("Test cannot be run on the desktop.")
44+
45+ def swipe_screen_from_right(self):
46+ qml_view = self.main_window.get_qml_view()
47+ width = qml_view.width
48+ height = qml_view.height
49+ start_x = width
50+ start_y = int(height/2)
51+ end_x = int(width/2)
52+ end_y = start_y
53+
54+ logger.info("Swiping screen from the right edge")
55+ self.touch.drag(start_x, start_y, end_x, end_y)
56+
57+ def _get_current_focused_app_id(self):
58+ return self._proxy.select_single("Shell").currentFocusedAppId
59+
60+ def _launch_app(self, app_name):
61+ """Launches the application *app_name*
62+
63+ Assumes that the desktop file resides at:
64+ /usr/share/applications/{app_name}.desktop
65+
66+ """
67+ desktop_file = "--desktop_file_hint="\
68+ "/usr/share/applications/{app_name}.desktop".format(
69+ app_name=app_name
70+ )
71+ return self.launch_test_application(
72+ app_name,
73+ desktop_file,
74+ "--stage_hint=main_stage",
75+ app_type='qt'
76+ )
77+
78+ @disable_qml_mocking
79+ def test_can_launch_application(self):
80+ """Must be able to launch an application."""
81+ self.launch_unity()
82+ self.main_window.get_greeter().swipe()
83+
84+ app = self._launch_app("messaging-app")
85+
86+ self.assertThat(app, NotEquals(None))
87+ self.assertThat(
88+ self._get_current_focused_app_id(),
89+ Eventually(Equals("messaging-app"))
90+ )
91+
92+ @disable_qml_mocking
93+ def test_can_launch_multiple_applications(self):
94+ """A second application launched must be focused."""
95+ self.launch_unity()
96+ self.main_window.get_greeter().swipe()
97+
98+ self._launch_app("messaging-app")
99+ self.assertThat(
100+ self._get_current_focused_app_id(),
101+ Eventually(Equals("messaging-app"))
102+ )
103+
104+ self._launch_app("address-book-app")
105+ self.assertThat(
106+ self._get_current_focused_app_id(),
107+ Eventually(Equals("address-book-app"))
108+ )
109+
110+ @disable_qml_mocking
111+ def test_app_moves_from_unfocused_to_focused(self):
112+ """An application that is in the unfocused state must be able to be
113+ brought back to the focused state.
114+
115+ """
116+ self.launch_unity()
117+ self.main_window.get_greeter().swipe()
118+
119+ self._launch_app("messaging-app")
120+ self.assertThat(
121+ self._get_current_focused_app_id(),
122+ Eventually(Equals("messaging-app"))
123+ )
124+
125+ self._launch_app("address-book-app")
126+ self.assertThat(
127+ self._get_current_focused_app_id(),
128+ Eventually(Equals("address-book-app"))
129+ )
130+
131+ self.swipe_screen_from_right()
132+
133+ self.assertThat(
134+ self._get_current_focused_app_id(),
135+ Eventually(Equals("messaging-app"))
136+ )
tests/autopilot/unity8/shell/__init__.py+10
@@ -36,3 +36,13 @@ def with_lightdm_mock(mock_type):
36 return fn(*args, **kwargs)
36 return fn(*args, **kwargs)
37 return wrapper
37 return wrapper
38 return with_lightdm_mock_internal
38 return with_lightdm_mock_internal
39+
40+
41+def disable_qml_mocking(fn):
42+ """Simple decorator that disables the QML mocks from being loaded."""
43+ @wraps(fn)
44+ def wrapper(*args, **kwargs):
45+ tests_self = args[0]
46+ tests_self._qml_mock_enabled = False
47+ return fn(*args, **kwargs)
48+ return wrapper
tests/autopilot/unity8/shell/tests/__init__.py+4−1
@@ -86,6 +86,7 @@ class UnityTestCase(AutopilotTestCase):
86
86
87 self._proxy = None
87 self._proxy = None
88 self._lightdm_mock_type = None
88 self._lightdm_mock_type = None
89+ self._qml_mock_enabled = True
89 self.touch = Touch.create()
90 self.touch = Touch.create()
90 self._setup_display_details()
91 self._setup_display_details()
91
92
@@ -160,7 +161,9 @@ class UnityTestCase(AutopilotTestCase):
160
161
161 if self._lightdm_mock_type is None:
162 if self._lightdm_mock_type is None:
162 self.patch_lightdm_mock()
163 self.patch_lightdm_mock()
164+
165+ if self._qml_mock_enabled:
163− self._setup_extra_mock_environment_patch()
166+ self._setup_extra_mock_environment_patch()
164
167
165 app_proxy = self.launch_test_application(
168 app_proxy = self.launch_test_application(
166 binary_path,
169 binary_path,
tests/mocks/AccountsService/AccountsService.cpp+12−5
@@ -19,11 +19,12 @@
19#include "AccountsService.h"
19#include "AccountsService.h"
20
20
21AccountsService::AccountsService(QObject* parent)
21AccountsService::AccountsService(QObject* parent)
22− : QObject(parent)
22+ : QObject(parent),
23+ m_backgroundFile(TOP_SRCDIR "/graphics/phone_background.jpg")
23{
24{
24}
25}
25
26
26−QString AccountsService::getUser()
27+QString AccountsService::user() const
27{
28{
28 return "testuser";
29 return "testuser";
29}
30}
@@ -33,7 +34,7 @@ void AccountsService::setUser(const QString &user)
33 Q_UNUSED(user)
34 Q_UNUSED(user)
34}
35}
35
36
36−bool AccountsService::getDemoEdges()
37+bool AccountsService::demoEdges() const
37{
38{
38 return false;
39 return false;
39}
40}
@@ -43,7 +44,13 @@ void AccountsService::setDemoEdges(bool demoEdges)
43 Q_UNUSED(demoEdges)
44 Q_UNUSED(demoEdges)
44}
45}
45
46
46−QString AccountsService::getBackgroundFile()
47+QString AccountsService::backgroundFile() const
47{
48{
48− return TOP_SRCDIR "/graphics/phone_background.jpg";
49+ return m_backgroundFile;
50+}
51+
52+void AccountsService::setBackgroundFile(const QString &backgroundFile)
53+{
54+ m_backgroundFile = backgroundFile;
55+ backgroundFileChanged();
49}
56}
tests/mocks/AccountsService/AccountsService.h+11−6
@@ -28,30 +28,35 @@ class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30 Q_PROPERTY (QString user
30 Q_PROPERTY (QString user
31− READ getUser
31+ READ user
32 WRITE setUser
32 WRITE setUser
33 NOTIFY userChanged)
33 NOTIFY userChanged)
34 Q_PROPERTY (bool demoEdges
34 Q_PROPERTY (bool demoEdges
35− READ getDemoEdges
35+ READ demoEdges
36 WRITE setDemoEdges
36 WRITE setDemoEdges
37 NOTIFY demoEdgesChanged)
37 NOTIFY demoEdgesChanged)
38 Q_PROPERTY (QString backgroundFile
38 Q_PROPERTY (QString backgroundFile
39− READ getBackgroundFile
39+ READ backgroundFile
40+ WRITE setBackgroundFile // only available in mock
40 NOTIFY backgroundFileChanged)
41 NOTIFY backgroundFileChanged)
41
42
42public:
43public:
43 explicit AccountsService(QObject *parent = 0);
44 explicit AccountsService(QObject *parent = 0);
44
45
45− QString getUser();
46+ QString user() const;
46 void setUser(const QString &user);
47 void setUser(const QString &user);
47− bool getDemoEdges();
48+ bool demoEdges() const;
48 void setDemoEdges(bool demoEdges);
49 void setDemoEdges(bool demoEdges);
49− QString getBackgroundFile();
50+ QString backgroundFile() const;
51+ void setBackgroundFile(const QString &backgroundFile);
50
52
51Q_SIGNALS:
53Q_SIGNALS:
52 void userChanged();
54 void userChanged();
53 void demoEdgesChanged();
55 void demoEdgesChanged();
54 void backgroundFileChanged();
56 void backgroundFileChanged();
57+
58+private:
59+ QString m_backgroundFile;
55};
60};
56
61
57#endif
62#endif
tests/mocks/Ubuntu/DownloadDaemonListener/MockDownloadTracker.cpp+5
@@ -63,5 +63,10 @@ void MockDownloadTracker::startService()
63 if(!m_service.isEmpty() && !m_dbusPath.isEmpty()) {
63 if(!m_service.isEmpty() && !m_dbusPath.isEmpty()) {
64 m_active = true;
64 m_active = true;
65 Q_EMIT serviceReadyChanged(m_active);
65 Q_EMIT serviceReadyChanged(m_active);
66+ if(m_dbusPath == "finish") {
67+ Q_EMIT finished("downloadComplete");
68+ }else if(m_dbusPath == "error") {
69+ Q_EMIT error("DOWNLOAD ERROR");
70+ }
66 }
71 }
67}
72}
tests/mocks/Unity/fake_preview.cpp+2
@@ -63,4 +63,6 @@ QString Preview::imageSourceUri() const
63
63
64void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& hints)
64void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& hints)
65{
65{
66+ Q_UNUSED(actionId);
67+ Q_UNUSED(hints);
66}
68}
tests/mocks/Unity/fake_scope.h+2
@@ -90,6 +90,8 @@ Q_SIGNALS:
90 // signals triggered by activate(..) or preview(..) requests.
90 // signals triggered by activate(..) or preview(..) requests.
91 void previewReady(Preview *preview);
91 void previewReady(Preview *preview);
92 void activateApplication(const QString &desktop);
92 void activateApplication(const QString &desktop);
93+ void showDash();
94+ void hideDash();
93
95
94protected:
96protected:
95
97
tests/plugins/AccountsService/client.cpp+2−2
@@ -50,9 +50,9 @@ private Q_SLOTS:
50 AccountsService session;
50 AccountsService session;
51 session.setUser("testuser");
51 session.setUser("testuser");
52 session.setDemoEdges(true);
52 session.setDemoEdges(true);
53− QCOMPARE(session.getDemoEdges(), true);
53+ QCOMPARE(session.demoEdges(), true);
54 session.setDemoEdges(false);
54 session.setDemoEdges(false);
55− QCOMPARE(session.getDemoEdges(), false);
55+ QCOMPARE(session.demoEdges(), false);
56 }
56 }
57};
57};
58
58
tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6
@@ -32,5 +32,11 @@ qt5_use_modules(listviewwithpageheadertestsectionExec Test Core Qml)
32target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
32target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
33add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
33add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
34
34
35+add_executable(listviewwithpageheadertestsectionexternalmodelExec listviewwithpageheadertestsectionexternalmodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/ListViewWithPageHeader/listviewwithpageheader.cpp)
36+qt5_use_modules(listviewwithpageheadertestsectionexternalmodelExec Test Core Qml)
37+target_link_libraries(listviewwithpageheadertestsectionexternalmodelExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
38+add_custom_target(testlistviewwithpageheadersectionexternalmodel ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionexternalmodelExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersectionexternalmodel.xml,xunitxml -o -,txt)
39+
35add_dependencies(qmluitests testlistviewwithpageheader)
40add_dependencies(qmluitests testlistviewwithpageheader)
36add_dependencies(qmluitests testlistviewwithpageheadersection)
41add_dependencies(qmluitests testlistviewwithpageheadersection)
42+add_dependencies(qmluitests testlistviewwithpageheadersectionexternalmodel)
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+161
@@ -1655,6 +1655,167 @@ private Q_SLOTS:
1655 QCOMPARE(spy.count(), 0);
1655 QCOMPARE(spy.count(), 0);
1656 }
1656 }
1657
1657
1658+ void testOvershootOnSameSize()
1659+ {
1660+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
1661+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
1662+ QCOMPARE(lvwph->m_minYExtent, 0.);
1663+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1664+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1665+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1666+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1667+ QCOMPARE(lvwph->contentY(), 0.);
1668+
1669+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100));
1670+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 392));
1671+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1672+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1673+ verifyItem(0, 50., 392., false);
1674+ verifyItem(1, 442., 100., false);
1675+
1676+ QCOMPARE(lvwph->contentHeight(), lvwph->height());
1677+
1678+ QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 0));
1679+ QTest::qWait(100);
1680+ QTest::mouseMove(view, QPoint(0, 5));
1681+ QTest::qWait(100);
1682+ QTest::mouseMove(view, QPoint(0, 10));
1683+ QTest::qWait(100);
1684+ QTest::mouseMove(view, QPoint(0, 15));
1685+ QTest::qWait(100);
1686+ QTest::mouseMove(view, QPoint(0, 20));
1687+ QTest::qWait(100);
1688+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1689+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1690+ verifyItem(0, 55., 392., false);
1691+ verifyItem(1, 447., 100., false);
1692+ QCOMPARE(lvwph->m_minYExtent, 0.);
1693+ QCOMPARE(lvwph->m_clipItem->y(), -5.);
1694+
1695+ QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 15));
1696+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1697+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1698+ verifyItem(0, 50., 392., false);
1699+ verifyItem(1, 442., 100., false);
1700+ }
1701+
1702+ void testMaximizeVisibleAreaMoveDownAndShowHeader()
1703+ {
1704+ model->setProperty(0, "size", 800);
1705+ verifyItem(0, 50., 800., false);
1706+
1707+ lvwph->maximizeVisibleArea(0);
1708+ QTRY_COMPARE(lvwph->contentY(), 50.);
1709+
1710+ changeContentY(10);
1711+ QTRY_COMPARE(lvwph->contentY(), 60.);
1712+
1713+ lvwph->showHeader();
1714+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1715+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1716+ QCOMPARE(lvwph->m_minYExtent, 50.);
1717+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
1718+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1719+ QCOMPARE(lvwph->m_headerItem->y(), 10.);
1720+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1721+ QCOMPARE(lvwph->contentY(), 10.);
1722+ verifyItem(0, -60., 800., false);
1723+ }
1724+
1725+ void testMaximizeVisibleAreaMoveUpAndShowHeader()
1726+ {
1727+ model->setProperty(0, "size", 800);
1728+ verifyItem(0, 50., 800., false);
1729+
1730+ lvwph->maximizeVisibleArea(0);
1731+ QTRY_COMPARE(lvwph->contentY(), 50.);
1732+
1733+ changeContentY(-10);
1734+ QTRY_COMPARE(lvwph->contentY(), 40.);
1735+
1736+ lvwph->showHeader();
1737+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1738+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1739+ QCOMPARE(lvwph->m_minYExtent, 40.);
1740+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1741+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1742+ QTRY_COMPARE(lvwph->m_headerItem->y(), 0.);
1743+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1744+ QCOMPARE(lvwph->contentY(), 0.);
1745+ verifyItem(0, -40., 800., false);
1746+ }
1747+
1748+ void testMaximizeVisibleAreaMoveDownAndUpAndShowHeader()
1749+ {
1750+ model->setProperty(0, "size", 800);
1751+ verifyItem(0, 50., 800., false);
1752+
1753+ lvwph->maximizeVisibleArea(0);
1754+ QTRY_COMPARE(lvwph->contentY(), 50.);
1755+
1756+ changeContentY(-10);
1757+ QTRY_COMPARE(lvwph->contentY(), 40.);
1758+ changeContentY(10);
1759+ QTRY_COMPARE(lvwph->contentY(), 50.);
1760+
1761+ lvwph->showHeader();
1762+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1763+
1764+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1765+ QCOMPARE(lvwph->m_minYExtent, 50.);
1766+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1767+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1768+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1769+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1770+ QCOMPARE(lvwph->contentY(), 0.);
1771+ verifyItem(0, -50., 800., false);
1772+ }
1773+
1774+ void testMaximizeVisibleAreaMoveUpAndDownAndShowHeader()
1775+ {
1776+ model->setProperty(0, "size", 800);
1777+ verifyItem(0, 50., 800., false);
1778+
1779+ lvwph->maximizeVisibleArea(0);
1780+ QTRY_COMPARE(lvwph->contentY(), 50.);
1781+
1782+ changeContentY(10);
1783+ QTRY_COMPARE(lvwph->contentY(), 60.);
1784+ changeContentY(-10);
1785+ QTRY_COMPARE(lvwph->contentY(), 50.);
1786+
1787+ lvwph->showHeader();
1788+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1789+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1790+ QCOMPARE(lvwph->m_minYExtent, 40.);
1791+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
1792+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1793+ QCOMPARE(lvwph->m_headerItem->y(), 10.);
1794+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1795+ QCOMPARE(lvwph->contentY(), 10.);
1796+ verifyItem(0, -50., 800., false);
1797+ }
1798+
1799+ void testMaximizeVisibleAreaAndShowHeader()
1800+ {
1801+ model->setProperty(0, "size", 800);
1802+ verifyItem(0, 50., 800., false);
1803+
1804+ lvwph->maximizeVisibleArea(0);
1805+ QTRY_COMPARE(lvwph->contentY(), 50.);
1806+
1807+ lvwph->showHeader();
1808+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1809+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1810+ QCOMPARE(lvwph->m_minYExtent, 50.);
1811+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1812+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1813+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1814+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1815+ QCOMPARE(lvwph->contentY(), 0.);
1816+ verifyItem(0, -50., 800., false);
1817+ }
1818+
1658private:
1819private:
1659 QQuickView *view;
1820 QQuickView *view;
1660 ListViewWithPageHeader *lvwph;
1821 ListViewWithPageHeader *lvwph;
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsectionexternalmodel.cppnew file+251
@@ -0,0 +1,251 @@
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 "listviewwithpageheader.h"
18+
19+#include <QAbstractItemModel>
20+#include <QQmlEngine>
21+#include <QQuickView>
22+#include <QSignalSpy>
23+#include <QSortFilterProxyModel>
24+#include <QtTestGui>
25+#pragma GCC diagnostic push
26+#pragma GCC diagnostic ignored "-pedantic"
27+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
28+#include <private/qquicklistmodel_p.h>
29+#else
30+#include <private/qqmllistmodel_p.h>
31+#endif
32+#include <private/qquickanimation_p.h>
33+#include <private/qquickitem_p.h>
34+#pragma GCC diagnostic pop
35+
36+class StringListModel : public QAbstractListModel
37+{
38+public:
39+ StringListModel()
40+ {
41+ list << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
42+ }
43+
44+ int rowCount(const QModelIndex &parent) const
45+ {
46+ if (parent.isValid())
47+ return 0;
48+ else
49+ return list.count();
50+ }
51+
52+ QVariant data(const QModelIndex &index, int role) const
53+ {
54+ if (role == Qt::SizeHintRole) return 50;
55+ else if (role == Qt::DisplayRole) return list[index.row()];
56+ return QVariant();
57+ }
58+
59+ QHash<int, QByteArray> roleNames() const
60+ {
61+ QHash<int, QByteArray> hash;
62+ hash.insert(Qt::DisplayRole, "type");
63+ hash.insert(Qt::SizeHintRole, "size");
64+ return hash;
65+ }
66+
67+ void moveLastToFirst()
68+ {
69+ const int last = list.count() - 1;
70+ beginMoveRows(QModelIndex(), last, last, QModelIndex(), 0);
71+ list.move(last, 0);
72+ endMoveRows();
73+ }
74+
75+ QStringList list;
76+};
77+
78+class ListViewWithPageHeaderTestSection : public QObject
79+{
80+ Q_OBJECT
81+
82+private:
83+ void verifyItem(int visibleIndex, qreal pos, qreal height, bool culled, const QString &sectionHeader, bool sectionHeaderCulled)
84+ {
85+ QTRY_VERIFY(visibleIndex < lvwph->m_visibleItems.count());
86+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->y(), pos);
87+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->height(), height);
88+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_item)->culled, culled);
89+ QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
90+ if (!sectionHeader.isNull()) {
91+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
92+ QCOMPARE(sectionDelegateIndex(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), lvwph->m_firstVisibleIndex + visibleIndex);
93+ }
94+ }
95+
96+ void changeContentY(qreal change)
97+ {
98+ const qreal dest = lvwph->contentY() + change;
99+ if (dest > lvwph->contentY()) {
100+ const qreal jump = 25;
101+ while (lvwph->contentY() + jump < dest) {
102+ lvwph->setContentY(lvwph->contentY() + jump);
103+ QTest::qWait(1);
104+ }
105+ } else {
106+ const qreal jump = -25;
107+ while (lvwph->contentY() + jump > dest) {
108+ lvwph->setContentY(lvwph->contentY() + jump);
109+ QTest::qWait(1);
110+ }
111+ }
112+ lvwph->setContentY(dest);
113+ QTest::qWait(1);
114+ }
115+
116+ void scrollToTop()
117+ {
118+ const qreal jump = -25;
119+ while (!lvwph->isAtYBeginning()) {
120+ if (lvwph->contentY() + jump > -lvwph->minYExtent()) {
121+ lvwph->setContentY(lvwph->contentY() + jump);
122+ } else {
123+ lvwph->setContentY(lvwph->contentY() - 1);
124+ }
125+ QTest::qWait(1);
126+ }
127+ }
128+
129+ void scrollToBottom()
130+ {
131+ const qreal jump = 25;
132+ while (!lvwph->isAtYEnd()) {
133+ if (lvwph->contentY() + lvwph->height() + jump < lvwph->contentHeight()) {
134+ lvwph->setContentY(lvwph->contentY() + jump);
135+ } else {
136+ lvwph->setContentY(lvwph->contentY() + 1);
137+ }
138+ QTest::qWait(1);
139+ }
140+ }
141+
142+ void verifyInitialTopPosition()
143+ {
144+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
145+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
146+ QCOMPARE(lvwph->m_minYExtent, 0.);
147+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
148+ QCOMPARE(lvwph->m_clipItem->clip(), false);
149+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
150+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
151+ QCOMPARE(lvwph->contentY(), 0.);
152+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
153+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
154+ }
155+
156+ QString section(QQuickItem *item)
157+ {
158+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
159+ }
160+
161+ int sectionDelegateIndex(QQuickItem *item)
162+ {
163+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
164+ }
165+
166+private Q_SLOTS:
167+
168+ void initTestCase()
169+ {
170+ }
171+
172+ void init()
173+ {
174+ view = new QQuickView();
175+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
176+ view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_sectionexternalmodel.qml"));
177+ lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
178+ QVERIFY(lvwph);
179+ view->show();
180+ QTest::qWaitForWindowExposed(view);
181+
182+ verifyInitialTopPosition();
183+ }
184+
185+ void cleanup()
186+ {
187+ delete view;
188+ }
189+
190+ void testCreationDeletion()
191+ {
192+ // Nothing, init/cleanup already tests this
193+ }
194+
195+ void testMoveWithProxy()
196+ {
197+ StringListModel m;
198+ QSortFilterProxyModel proxy;
199+ proxy.setSourceModel(&m);
200+
201+ lvwph->setModel(&proxy);
202+
203+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
204+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
205+ verifyItem(0, 50., 90., false, "A", false);
206+ verifyItem(1, 140., 90., false, "B", false);
207+ verifyItem(2, 230., 90., false, "C", false);
208+ verifyItem(3, 320., 90., false, "D", false);
209+ verifyItem(4, 410., 90., false, "E", false);
210+ verifyItem(5, 500., 90., false, "F", false);
211+ verifyItem(6, 590., 90., true, "G", true);
212+ verifyItem(7, 680., 90., true, "H", true);
213+ QCOMPARE(lvwph->m_minYExtent, 0.);
214+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
215+ QCOMPARE(lvwph->m_clipItem->clip(), false);
216+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
217+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
218+ QCOMPARE(lvwph->contentY(), 0.);
219+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
220+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
221+
222+ m.moveLastToFirst();
223+
224+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
225+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
226+ verifyItem(0, 50., 90., false, "H", false);
227+ verifyItem(1, 140., 90., false, "A", false);
228+ verifyItem(2, 230., 90., false, "B", false);
229+ verifyItem(3, 320., 90., false, "C", false);
230+ verifyItem(4, 410., 90., false, "D", false);
231+ verifyItem(5, 500., 90., false, "E", false);
232+ verifyItem(6, 590., 90., true, "F", true);
233+ verifyItem(7, 680., 90., true, "G", true);
234+ QCOMPARE(lvwph->m_minYExtent, 0.);
235+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
236+ QCOMPARE(lvwph->m_clipItem->clip(), false);
237+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
238+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
239+ QCOMPARE(lvwph->contentY(), 0.);
240+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
241+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
242+ }
243+
244+private:
245+ QQuickView *view;
246+ ListViewWithPageHeader *lvwph;
247+};
248+
249+QTEST_MAIN(ListViewWithPageHeaderTestSection)
250+
251+#include "listviewwithpageheadertestsectionexternalmodel.moc"
tests/plugins/ListViewWithPageHeader/test_sectionexternalmodel.qmlnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import ListViewWithPageHeader 0.1
19+
20+Rectangle {
21+ width: 300
22+ height: 542
23+ color: "lightblue"
24+
25+ ListViewWithPageHeader {
26+ id: listView
27+ width: parent.width
28+ anchors.top: parent.top
29+ anchors.bottom: parent.bottom
30+ model: model
31+ delegate: Rectangle {
32+ property bool timerDone: false
33+ width: parent.width - 20
34+ x: 10
35+ color: index % 2 == 0 ? "red" : "blue"
36+ height: timerDone ? size : 350
37+ Text {
38+ text: index
39+ }
40+ Timer {
41+ id: sizeTimer
42+ interval: 10;
43+ onTriggered: {
44+ timerDone = true
45+ }
46+ }
47+ Component.onCompleted: {
48+ sizeTimer.start()
49+ }
50+ }
51+
52+ pageHeader: Rectangle {
53+ color: "transparent"
54+ width: parent.width
55+ height: 50
56+ implicitHeight: 50
57+ Text {
58+ anchors.fill: parent
59+ text: "APPS"
60+ font.pixelSize: 40
61+ }
62+ }
63+
64+ sectionProperty: "type"
65+ sectionDelegate: Component {
66+ Rectangle {
67+ color: "green"
68+ height: 40
69+ Text { text: section; font.pixelSize: 34 }
70+ anchors { left: parent.left; right: parent.right }
71+ }
72+ }
73+ }
74+}
tests/plugins/Unity/Launcher/click-icon.svgnew file

No changes to the content.

tests/plugins/Unity/Launcher/launcherbackendtest.cpp+10−2
@@ -26,6 +26,15 @@ class LauncherBackendTest : public QObject
26 Q_OBJECT
26 Q_OBJECT
27
27
28private Q_SLOTS:
28private Q_SLOTS:
29+
30+ void initTestCase()
31+ {
32+ // As we want to test absolute file paths in the .desktop file, we need to modify the
33+ // sample file and replace the path in there with the current build dir.
34+ QSettings settings(QDir::currentPath() + "/click-icon.desktop", QSettings::IniFormat);
35+ settings.setValue("Desktop Entry/Path", QDir::currentPath());
36+ }
37+
29 void testFileNames()
38 void testFileNames()
30 {
39 {
31 LauncherBackend backend(false);
40 LauncherBackend backend(false);
@@ -66,8 +75,7 @@ private Q_SLOTS:
66 QTest::newRow("fallback on theme") << "abs-icon" << "image://theme//path/to/icon.png";
75 QTest::newRow("fallback on theme") << "abs-icon" << "image://theme//path/to/icon.png";
67
76
68 // Click packages have a relative icon path but an absolute path as a separate entry
77 // Click packages have a relative icon path but an absolute path as a separate entry
69− // As we don't want to rely on a click app being installed for the test, accept it with the image://theme fallback
70− QTest::newRow("click package icon") << "click-icon" << "image://theme//path/to/some/click/app/click-icon.svg";
78+ QTest::newRow("click package icon") << "click-icon" << QDir::currentPath() + "/click-icon.svg";
71 }
79 }
72
80
73 void testIcon() {
81 void testIcon() {
tests/plugins/Unity/Launcher/launchermodeltest.cpp+61−2
@@ -62,7 +62,14 @@ public:
62 return QString();
62 return QString();
63 }
63 }
64 unity::shell::application::ApplicationInfoInterface *get(int index) const { return m_list.at(index); }
64 unity::shell::application::ApplicationInfoInterface *get(int index) const { return m_list.at(index); }
65− unity::shell::application::ApplicationInfoInterface *findApplication(const QString &) const { return nullptr; }
65+ unity::shell::application::ApplicationInfoInterface *findApplication(const QString &appId) const {
66+ Q_FOREACH(MockApp* app, m_list) {
67+ if (app->appId() == appId) {
68+ return app;
69+ }
70+ }
71+ return nullptr;
72+ }
66 unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
73 unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
67 bool stopApplication(const QString &) { return false; }
74 bool stopApplication(const QString &) { return false; }
68 bool focusApplication(const QString &appId) {
75 bool focusApplication(const QString &appId) {
@@ -151,9 +158,54 @@ private Q_SLOTS:
151 QCOMPARE(launcherModel->get(1)->pinned(), false);
158 QCOMPARE(launcherModel->get(1)->pinned(), false);
152 }
159 }
153
160
161+ void testRemove_data() {
162+
163+ QTest::addColumn<bool>("pinned");
164+ QTest::addColumn<bool>("running");
165+
166+ QTest::newRow("non-pinned, running") << false << true;
167+ QTest::newRow("pinned, running") << true << false;
168+ QTest::newRow("pinned, non-running") << true << false;
169+ }
170+
154 void testRemove() {
171 void testRemove() {
172+ QFETCH(bool, pinned);
173+ QFETCH(bool, running);
174+
175+ // In the beginning we always have two items
155 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
176 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
177+
178+ // pin one if required
179+ if (pinned) {
180+ launcherModel->pin(launcherModel->get(1)->appId());
181+ }
182+
183+ // stop it if required
184+ if (!running) {
185+ appManager->removeApplication(1);
186+ }
187+
188+ // Now remove it
156− launcherModel->requestRemove(launcherModel->get(0)->appId());
189+ launcherModel->requestRemove(launcherModel->get(1)->appId());
190+
191+ if (running) {
192+ // both apps are running, both apps must still be here
193+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
194+
195+ // Item must be unpinned now
196+ QCOMPARE(launcherModel->get(1)->pinned(), false);
197+
198+ } else if (pinned) {
199+ // Item 1 must go away, item 0 is here to stay
200+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
201+ }
202+
203+ // done our checks. now stop the app if was still running
204+ if (running) {
205+ appManager->removeApplication(1);
206+ }
207+
208+ // It needs to go away in any case now
157 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
209 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
158 }
210 }
159
211
@@ -181,6 +233,13 @@ private Q_SLOTS:
181
233
182 // quicklist needs to transform to remove item. trigger it and check it item goes away
234 // quicklist needs to transform to remove item. trigger it and check it item goes away
183 launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
235 launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
236+ QCOMPARE(launcherModel->get(0)->pinned(), false);
237+
238+ // still needs to be here as the app is still here
239+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
240+ // close the app
241+ appManager->removeApplication(0);
242+ // Now it needs to go away
184 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
243 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
185 }
244 }
186
245
tests/plugins/Unity/previewbindingstest.cpp+27
@@ -19,6 +19,7 @@
19
19
20#include <UnityCore/Preview.h>
20#include <UnityCore/Preview.h>
21#include <UnityCore/GLibWrapper.h>
21#include <UnityCore/GLibWrapper.h>
22+#include <UnityCore/Variant.h>
22#include <unity-protocol.h>
23#include <unity-protocol.h>
23
24
24#include "genericpreview.h"
25#include "genericpreview.h"
@@ -48,7 +49,23 @@ void PreviewBindingsTest::testGenericPreview()
48 UNITY_PROTOCOL_LAYOUT_HINT_LEFT);
49 UNITY_PROTOCOL_LAYOUT_HINT_LEFT);
49 unity::glib::Object<GObject> genPrv(rawPreview);
50 unity::glib::Object<GObject> genPrv(rawPreview);
50
51
52+ // create local result
53+ unity::glib::HintsMap hints;
54+ hints["a"] = unity::glib::Variant(g_variant_new_string("b"));
55+ unity::dash::LocalResult localResult;
56+ localResult.uri = "http://foo";
57+ localResult.icon_hint = "xyz";
58+ localResult.category_index = 1;
59+ localResult.result_type = 2;
60+ localResult.mimetype = "abc";
61+ localResult.name = "baz";
62+ localResult.comment = "qwerty";
63+ localResult.dnd_uri = "zzz";
64+ localResult.hints = hints;
65+
51 auto corePrv = unity::dash::Preview::PreviewForProtocolObject(genPrv);
66 auto corePrv = unity::dash::Preview::PreviewForProtocolObject(genPrv);
67+ corePrv->preview_result = localResult;
68+
52 auto prv = Preview::newFromUnityPreview(corePrv);
69 auto prv = Preview::newFromUnityPreview(corePrv);
53
70
54 QCOMPARE(prv != nullptr, true);
71 QCOMPARE(prv != nullptr, true);
@@ -64,6 +81,16 @@ void PreviewBindingsTest::testGenericPreview()
64 QCOMPARE(act->displayName(), QString("Action1"));
81 QCOMPARE(act->displayName(), QString("Action1"));
65 QCOMPARE(act->iconHint(), QString("/foo.png"));
82 QCOMPARE(act->iconHint(), QString("/foo.png"));
66
83
84+ Result* res = prv->result().value<Result*>();
85+ QCOMPARE(res->uri(), QString("http://foo"));
86+ QCOMPARE(res->iconHint(), QString("xyz"));
87+ QCOMPARE(res->categoryIndex(), 1u);
88+ QCOMPARE(res->resultType(), 2u);
89+ QCOMPARE(res->mimeType(), QString("abc"));
90+ QCOMPARE(res->title(), QString("baz"));
91+ QCOMPARE(res->dndUri(), QString("zzz"));
92+ QCOMPARE(res->metadata().toHash()["a"].toString(), QString("b"));
93+
67 g_object_unref(icon);
94 g_object_unref(icon);
68 g_object_unref(iconFile);
95 g_object_unref(iconFile);
69}
96}
tests/plugins/Unity/resultstest.cpp+1
@@ -71,6 +71,7 @@ void ResultsTest::testIconColumn_data()
71 QTest::newRow("absolute path") << "/usr/share/icons/example.png" << "/usr/share/icons/example.png";
71 QTest::newRow("absolute path") << "/usr/share/icons/example.png" << "/usr/share/icons/example.png";
72 QTest::newRow("file uri") << "file:///usr/share/icons/example.png" << "file:///usr/share/icons/example.png";
72 QTest::newRow("file uri") << "file:///usr/share/icons/example.png" << "file:///usr/share/icons/example.png";
73 QTest::newRow("http uri") << "http://images.ubuntu.com/example.jpg" << "http://images.ubuntu.com/example.jpg";
73 QTest::newRow("http uri") << "http://images.ubuntu.com/example.jpg" << "http://images.ubuntu.com/example.jpg";
74+ QTest::newRow("image uri") << "image://thumbnail/with/arguments?passed_to=ImageProvider" << "image://thumbnail/with/arguments?passed_to=ImageProvider";
74 QTest::newRow("themed icon") << "accessories-other" << "image://theme/accessories-other";
75 QTest::newRow("themed icon") << "accessories-other" << "image://theme/accessories-other";
75 QTest::newRow("fileicon") << ". GFileIcon http://example.org/resource.gif" << "http://example.org/resource.gif";
76 QTest::newRow("fileicon") << ". GFileIcon http://example.org/resource.gif" << "http://example.org/resource.gif";
76 QTest::newRow("themedicon") << ". GThemedIcon accessories-other accessories generic" << "image://theme/accessories-other,accessories,generic";
77 QTest::newRow("themedicon") << ". GThemedIcon accessories-other accessories generic" << "image://theme/accessories-other,accessories,generic";
tests/qmltests/CMakeLists.txt+1−1
@@ -13,7 +13,6 @@ set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
13set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
14add_qml_test(Components AnimationControllerWithSignals)
14add_qml_test(Components AnimationControllerWithSignals)
15add_qml_test(Components Carousel)
15add_qml_test(Components Carousel)
16−add_qml_test(Components CrossFadeImage)
17add_qml_test(Components MathLocal)
16add_qml_test(Components MathLocal)
18add_qml_test(Components OpenEffect)
17add_qml_test(Components OpenEffect)
19add_qml_test(Components RatingStars)
18add_qml_test(Components RatingStars)
@@ -32,6 +31,7 @@ add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugi
32add_qml_test(Components DraggingArea)
31add_qml_test(Components DraggingArea)
33add_qml_test(Components EdgeDemoOverlay)
32add_qml_test(Components EdgeDemoOverlay)
34add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
33add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
34+add_qml_test(Components LazyImage)
35add_qml_test(Components ResponsiveFlowView)
35add_qml_test(Components ResponsiveFlowView)
36add_qml_test(Components ResponsiveGridView)
36add_qml_test(Components ResponsiveGridView)
37add_qml_test(Components Revealer)
37add_qml_test(Components Revealer)
tests/qmltests/Components/tst_CrossFadeImage.qmldeleted−125
@@ -1,125 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../Components"
20−
21−TestCase {
22− name: "CrossFadeImage"
23−
24− property alias status: crossFadeImage.status
25− property alias source: crossFadeImage.source
26− property alias crossFade: crossFadeImage.crossFade
27− property alias fadeInFirst: crossFadeImage.fadeInFirst
28− property alias running: crossFadeImage.running
29−
30− CrossFadeImage {
31− id: crossFadeImage
32− }
33−
34− SignalSpy {
35− id: signalSpy
36− target: crossFadeImage
37− }
38−
39− function initTestFunction(argCrossFade, argFadeInFirst) {
40− source = ""
41− crossFade = argCrossFade
42− fadeInFirst = argFadeInFirst
43− compare(status, Image.Null, "Could not reset CrossFadeImage")
44− }
45−
46− function loadImage(url) {
47− console.log("Loading image...")
48− source = url
49−
50− signalSpy.signalName = "statusChanged"
51− signalSpy.wait()
52−
53− if (status == Image.Null) {
54− signalSpy.clear()
55− signalSpy.wait()
56− }
57−
58− if (status == Image.Loading) {
59− signalSpy.clear()
60− signalSpy.wait()
61− }
62−
63− compare(status, Image.Ready, "Image not ready")
64− console.log("Image loaded.")
65− }
66−
67− function waitForAnimation() {
68− signalSpy.signalName = "runningChanged"
69−
70− if (!running) {
71− signalSpy.clear()
72− signalSpy.wait()
73− compare(running, true, "Animation did not start")
74− }
75−
76− signalSpy.clear()
77− console.log("Waiting for animation to finish...")
78− signalSpy.wait()
79− compare(running, false, "Animation did not stop within 5 seconds.")
80− }
81−
82− function cleanupTest() {
83− compare(running, false, "Animation is running after testcase")
84− compare(crossFadeImage.__nextImage.source, "", "nextimage source is not reset")
85− }
86−
87− function test_fadeFirst() {
88− initTestFunction(true, true)
89−
90− loadImage("../../../graphics/phone_background.jpg")
91−
92− waitForAnimation()
93−
94− cleanupTest()
95− }
96−
97− function test_no_fadeFirst() {
98− initTestFunction(true, false)
99−
100− loadImage("../../../graphics/phone_background.jpg")
101−
102− cleanupTest()
103− }
104−
105− function test_crossFade() {
106− initTestFunction(true, false)
107−
108− loadImage("../../../graphics/phone_background.jpg")
109−
110− loadImage("../../../graphics/tablet_background.jpg")
111−
112− // Due to the internal implementation, __currentImage and __nextImage are swapped before the animation starts
113− // Make sure z order reflects that too.
114− compare(crossFadeImage.__currentImage.z > crossFadeImage.__nextImage.z, true, "new image should be above old image")
115− compare(crossFadeImage.__currentImage.opacity < 0.5, true)
116− compare(crossFadeImage.__nextImage.opacity > 0.5, true)
117−
118− waitForAnimation()
119−
120− compare(crossFadeImage.__currentImage.opacity > 0.5, true)
121− compare(crossFadeImage.__nextImage.opacity < 0.5, true)
122−
123− cleanupTest()
124− }
125−}
tests/qmltests/Components/tst_LazyImage.qmlnew file+156
@@ -0,0 +1,156 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import "../../../Components"
20+import Ubuntu.Components 0.1
21+import Unity.Test 0.1 as UT
22+import "tst_LazyImage"
23+
24+Rectangle {
25+ width: units.gu(120)
26+ height: units.gu(70)
27+
28+ Rectangle {
29+ id: baseRect
30+ anchors {
31+ fill: parent
32+ rightMargin: 2 * parent.width / 3
33+ }
34+
35+ color: "grey"
36+
37+ Column {
38+ anchors { fill: parent; margins: units.gu(5) }
39+
40+ Label {
41+ height: units.gu(4)
42+ text: "Unbound"
43+ color: "white"
44+ verticalAlignment: Text.AlignBottom
45+ }
46+
47+ LazyImage {
48+ id: lazy1
49+ }
50+
51+ Label {
52+ height: units.gu(4)
53+ text: "Width-bound"
54+ color: "white"
55+ verticalAlignment: Text.AlignBottom
56+ }
57+
58+ LazyImage {
59+ id: lazy2
60+ width: units.gu(30)
61+ scaleTo: "width"
62+ }
63+
64+ Label {
65+ height: units.gu(4)
66+ text: "Height-bound"
67+ color: "white"
68+ verticalAlignment: Text.AlignBottom
69+ }
70+
71+ LazyImage {
72+ id: lazy3
73+ height: units.gu(10)
74+ scaleTo: "height"
75+ }
76+ }
77+ }
78+
79+ Rectangle {
80+ id: controlsRect
81+ anchors {
82+ fill: parent
83+ leftMargin: parent.width / 3
84+ }
85+
86+ color: "lightgrey"
87+
88+ Column {
89+ id: controls
90+ spacing: units.gu(1)
91+
92+ anchors { fill: parent; margins: units.gu(3) }
93+
94+ ImageControls { id: controls1; image: lazy1 }
95+ ImageControls { id: controls2; image: lazy2 }
96+ ImageControls { id: controls3; image: lazy3 }
97+ }
98+ }
99+
100+ UT.UnityTestCase {
101+ name: "Stage"
102+ when: windowShown
103+
104+ function cleanup() {
105+ controls1.blank();
106+ tryCompare(lazy1, "width", units.gu(10));
107+ controls2.blank();
108+ tryCompare(lazy2, "height", units.gu(10));
109+ controls3.blank();
110+ tryCompare(lazy3, "width", units.gu(10));
111+ }
112+
113+ function test_lazyimage_data() {
114+ return [
115+ {tag: "Unbound Blank", image: lazy1, func: controls1.blank, width: units.gu(10), height: units.gu(10), placeholder: true},
116+ {tag: "Unbound Wide", image: lazy1, func: controls1.wide, transition: "readyTransition", width: 160, height: 80},
117+ {tag: "Unbound Square", image: lazy1, func: controls1.square, transition: "readyTransition", width: 160, height: 160},
118+ {tag: "Unbound Portrait", image: lazy1, func: controls1.portrait, transition: "readyTransition", width: 80, height: 160},
119+ {tag: "Unbound Bad path", image: lazy1, func: controls1.badpath, transition: "genericTransition", width: units.gu(10), height: units.gu(10), placeholder: true, error: true},
120+ {tag: "Width-bound Blank", image: lazy2, func: controls2.blank, width: units.gu(30), height: units.gu(10), placeholder: true},
121+ {tag: "Width-bound Wide", image: lazy2, func: controls2.wide, transition: "readyTransition", width: units.gu(30), height: units.gu(15)},
122+ {tag: "Width-bound Square", image: lazy2, func: controls2.square, transition: "readyTransition", width: units.gu(30), height: units.gu(30)},
123+ {tag: "Width-bound Portrait", image: lazy2, func: controls2.portrait, transition: "readyTransition", width: units.gu(30), height: units.gu(60)},
124+ {tag: "Width-bound Bad path", image: lazy2, func: controls2.badpath, transition: "genericTransition", width: units.gu(30), height: units.gu(10), placeholder: true, error: true},
125+ {tag: "Height-bound Blank", image: lazy3, func: controls3.blank, width: units.gu(10), height: units.gu(10), placeholder: true},
126+ {tag: "Height-bound Wide", image: lazy3, func: controls3.wide, transition: "readyTransition", width: units.gu(20), height: units.gu(10)},
127+ {tag: "Height-bound Square", image: lazy3, func: controls3.square, transition: "readyTransition", width: units.gu(10), height: units.gu(10)},
128+ {tag: "Height-bound Portrait", image: lazy3, func: controls3.portrait, transition: "readyTransition", width: units.gu(5), height: units.gu(10)},
129+ {tag: "Height-bound Bad path", image: lazy3, func: controls3.badpath, transition: "genericTransition", width: units.gu(10), height: units.gu(10), placeholder: true, error: true},
130+ ]
131+ }
132+
133+ function test_lazyimage(data) {
134+ data.func();
135+
136+ if (data.transition) {
137+ // wait for the transition to complete
138+ var transition = findInvisibleChild(data.image, data.transition);
139+ tryCompare(transition, "running", true);
140+ tryCompare(transition, "running", false);
141+ }
142+
143+ // check the dimensions
144+ compare(data.image.width, data.width);
145+ compare(data.image.height, data.height);
146+
147+ // check the placeholder
148+ var placeholder = findChild(data.image, "placeholder");
149+ compare(placeholder.visible, data.placeholder ? true : false);
150+
151+ // check the error image
152+ var error = findChild(data.image, "errorImage");
153+ compare(error.visible, data.error ? true : false);
154+ }
155+ }
156+}
tests/qmltests/Components/tst_LazyImage/ImageControls.qmlnew file+67
@@ -0,0 +1,67 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import "../../../../Components"
20+
21+Row {
22+ property LazyImage image
23+
24+ anchors { left: parent.left; right: parent.right }
25+ spacing: units.gu(1)
26+
27+ function blank() { blankButton.clicked() }
28+ function wide() { wideButton.clicked() }
29+ function square() { squareButton.clicked() }
30+ function portrait() { portraitButton.clicked() }
31+ function badpath() { badpathButton.clicked() }
32+
33+ Button {
34+ id: blankButton
35+ width: parent / 5
36+ text: "Blank"
37+ onClicked: image.source = ""
38+ }
39+
40+ Button {
41+ id: wideButton
42+ width: parent / 5
43+ text: "Wide"
44+ onClicked: image.source = "wide.png"
45+ }
46+
47+ Button {
48+ id: squareButton
49+ width: parent / 5
50+ text: "Square"
51+ onClicked: image.source = "square.png"
52+ }
53+
54+ Button {
55+ id: portraitButton
56+ width: parent / 5
57+ text: "Portrait"
58+ onClicked: image.source = "portrait.png"
59+ }
60+
61+ Button {
62+ id: badpathButton
63+ width: parent / 5
64+ text: "Bad path"
65+ onClicked: image.source = "bad/path"
66+ }
67+}
tests/qmltests/Components/tst_LazyImage/portrait.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_LazyImage/square.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_LazyImage/wide.pngnew file

Binary file not shown.

tests/qmltests/Dash/Apps/tst_AppPreview.qml+75−2
@@ -25,6 +25,9 @@ Item {
25 width: units.gu(60)
25 width: units.gu(60)
26 height: units.gu(80)
26 height: units.gu(80)
27
27
28+ // Fake shell
29+ QtObject { id: shell; property int height: appPreview.height }
30+
28 property var calls: []
31 property var calls: []
29
32
30 SignalSpy {
33 SignalSpy {
@@ -45,6 +48,8 @@ Item {
45 ["Unity User", 10, "10/02/2013", root.commentary],
48 ["Unity User", 10, "10/02/2013", root.commentary],
46 ]
49 ]
47 }
50 }
51+ QtObject { id: showProgress; property bool value: true }
52+ QtObject { id: progressSource; property string value: "service" }
48
53
49 QtObject {
54 QtObject {
50 id: data
55 id: data
@@ -66,8 +71,30 @@ Item {
66 ]
71 ]
67 }
72 }
68
73
74+ QtObject {
75+ id: dataProgress
76+ property string title: "Unity App"
77+ property string appIcon: "fake_image.png"
78+ property string description: "This is an Application description"
79+ property real rating: rating.value
80+ property int numRatings: reviews.value
81+ property var execute: root.fake_call
82+ property var infoMap: {
83+ "show_progressbar": showProgress,
84+ "more-screenshots": screenshots,
85+ "rated": rated,
86+ "comments": comments,
87+ "progressbar_source": progressSource
88+ }
89+ property var actions: [
90+ { "id": 123, "displayName": "action1" },
91+ { "id": 456, "displayName": "action2" },
92+ { "id": 789, "displayName": "action3" },
93+ ]
94+ }
95+
69 function fake_call(id, data){
96 function fake_call(id, data){
70− root.calls[root.calls.length] = id;
97+ root.calls[root.calls.length] = [id, data];
71 }
98 }
72
99
73 // The component under test
100 // The component under test
@@ -89,6 +116,10 @@ Item {
89 reviewField.focus = false;
116 reviewField.focus = false;
90 reviewField.text = "";
117 reviewField.text = "";
91 data.rating = rating.value;
118 data.rating = rating.value;
119+ dataProgress.infoMap["progressbar_source"].value = "service";
120+ var appReviews = findChild(appPreview, "appReviews");
121+ appReviews.visible = false;
122+ appPreview.keyboardSize = 0;
92 }
123 }
93
124
94 function test_actions() {
125 function test_actions() {
@@ -102,7 +133,7 @@ Item {
102
133
103 var actions = data.actions;
134 var actions = data.actions;
104 for(var i = 0; i < actions.length; i++) {
135 for(var i = 0; i < actions.length; i++) {
105− compare(root.calls[i], actions[i].id, "Id of action not found.");
136+ compare(root.calls[i][0], actions[i].id, "Id of action not found.");
106 }
137 }
107 }
138 }
108
139
@@ -124,6 +155,7 @@ Item {
124
155
125 function test_review_focus() {
156 function test_review_focus() {
126 var appReviews = findChild(appPreview, "appReviews");
157 var appReviews = findChild(appPreview, "appReviews");
158+ appReviews.visible = true;
127 var sendButton = findChild(appReviews, "sendButton");
159 var sendButton = findChild(appReviews, "sendButton");
128 var reviewField = findChild(appReviews, "reviewField");
160 var reviewField = findChild(appReviews, "reviewField");
129
161
@@ -162,5 +194,46 @@ Item {
162 verify(buttons.visible == true);
194 verify(buttons.visible == true);
163 }
195 }
164
196
197+ function test_progress_show() {
198+ appPreview.previewData = dataProgress;
199+ var progress = findChild(appPreview, "progressBar");
200+ verify(progress.visible == true);
201+ }
202+
203+ function test_progress_download_finish() {
204+ appPreview.previewData = dataProgress;
205+ var progress = findChild(appPreview, "progressBar");
206+ dataProgress.infoMap["progressbar_source"].value = "finish";
207+
208+ var actions = dataProgress.actions;
209+ compare(root.calls[0][0], actions[0].id, "Id of action not found.");
210+ compare(root.calls[0][1], {}, "Data of action not found.");
211+ }
212+
213+ function test_progress_download_error() {
214+ appPreview.previewData = dataProgress;
215+ var progress = findChild(appPreview, "progressBar");
216+ dataProgress.infoMap["progressbar_source"].value = "error";
217+
218+ var actions = dataProgress.actions;
219+ compare(root.calls[0][0], actions[1].id, "Id of action not found.");
220+ compare(root.calls[0][1], {"error": "DOWNLOAD ERROR"}, "Data of action not found.");
221+ }
222+
223+ function test_automatic_scroll_on_keyboard_shown() {
224+ waitForRendering(appPreview);
225+ var appReviews = findChild(appPreview, "appReviews");
226+ appReviews.visible = true;
227+
228+ var leftFlickable = findChild(appPreview, "leftFlickable");
229+ leftFlickable.contentY = leftFlickable.contentHeight;
230+ var reviewField = findChild(appReviews, "reviewField");
231+ appPreview.keyboardSize = 400;
232+ appReviews.editing(reviewField);
233+ var newFlickPos = leftFlickable.contentY;
234+ var keyboardY = shell.height - appPreview.keyboardSize;
235+ verify(newFlickPos < keyboardY);
236+ }
237+
165 }
238 }
166}
239}
tests/qmltests/Dash/tst_DashContent.qml+1−1
@@ -106,7 +106,7 @@ Item {
106 contentEndReachedSpy.clear()
106 contentEndReachedSpy.clear()
107 clear_scope_status();
107 clear_scope_status();
108
108
109− // clear, wait for dahs to empty and load scopes.
109+ // clear, wait for dash to empty and load scopes.
110 var dashContentList = findChild(dashContent, "dashContentList");
110 var dashContentList = findChild(dashContent, "dashContentList");
111 verify(dashContentList != undefined)
111 verify(dashContentList != undefined)
112 scopesModel.clear();
112 scopesModel.clear();
tests/qmltests/Dash/tst_GenericScopeView.qml+17
@@ -44,10 +44,27 @@ Item {
44
44
45 function test_isCurrent() {
45 function test_isCurrent() {
46 var pageHeader = findChild(genericScopeView, "pageHeader");
46 var pageHeader = findChild(genericScopeView, "pageHeader");
47+ var previewLoader = findChild(genericScopeView, "previewLoader");
47 genericScopeView.isCurrent = true
48 genericScopeView.isCurrent = true
48 pageHeader.searchQuery = "test"
49 pageHeader.searchQuery = "test"
50+ previewLoader.open = true
49 genericScopeView.isCurrent = false
51 genericScopeView.isCurrent = false
50 tryCompare(pageHeader, "searchQuery", "")
52 tryCompare(pageHeader, "searchQuery", "")
53+ tryCompare(genericScopeView, "previewShown", false);
54+ }
55+
56+ function test_showDash() {
57+ var previewLoader = findChild(genericScopeView, "previewLoader");
58+ previewLoader.open = true;
59+ scopes.get(0).showDash();
60+ tryCompare(genericScopeView, "previewShown", false);
61+ }
62+
63+ function test_hideDash() {
64+ var previewLoader = findChild(genericScopeView, "previewLoader");
65+ previewLoader.open = true;
66+ scopes.get(0).hideDash();
67+ tryCompare(genericScopeView, "previewShown", false);
51 }
68 }
52 }
69 }
53 }
70 }
tests/qmltests/Greeter/tst_Phone.qml+19−1
@@ -18,8 +18,8 @@ import QtQuick 2.0
18import QtTest 1.0
18import QtTest 1.0
19import ".."
19import ".."
20import "../../../Greeter"
20import "../../../Greeter"
21+import AccountsService 0.1
21import Ubuntu.Components 0.1
22import Ubuntu.Components 0.1
22−import LightDM 0.1 as LightDM
23import Unity.Test 0.1 as UT
23import Unity.Test 0.1 as UT
24
24
25Item {
25Item {
@@ -32,6 +32,8 @@ Item {
32 height: parent.height
32 height: parent.height
33 x: 0; y: 0
33 x: 0; y: 0
34
34
35+ defaultBackground: "../../../graphics/phone_background.jpg"
36+
35 property int minX: 0
37 property int minX: 0
36
38
37 onXChanged: {
39 onXChanged: {
@@ -102,5 +104,21 @@ Item {
102 // Wait until we're back to 0
104 // Wait until we're back to 0
103 tryCompareFunction(function() { return greeter.x;}, 0);
105 tryCompareFunction(function() { return greeter.x;}, 0);
104 }
106 }
107+
108+ function test_wallpaper_data() {
109+ return [
110+ {tag: "set", accounts: "../tests/data/unity/backgrounds/blue.png", expected: "blue.png"},
111+ {tag: "unset", accounts: "", expected: "background.jpg"},
112+ {tag: "invalid", accounts: "invalid", expected: "background.jpg"},
113+ ]
114+ }
115+
116+ function test_wallpaper(data) {
117+ var loader = findChild(greeter, "greeterContentLoader")
118+ var wallpaper = findChild(loader.item, "wallpaper")
119+ AccountsService.backgroundFile = data.accounts
120+ tryCompareFunction(function() { return wallpaper.source.toString().indexOf(data.expected) !== -1; }, true)
121+ tryCompare(wallpaper, "status", Image.Ready)
122+ }
105 }
123 }
106}
124}
tests/uqmlscene/main.cpp−2
@@ -497,8 +497,6 @@ int main(int argc, char ** argv)
497 }
497 }
498
498
499 if (window) {
499 if (window) {
500− mouseTouchAdaptor.setTargetWindow(window);
501−
502 QSurfaceFormat surfaceFormat = window->requestedFormat();
500 QSurfaceFormat surfaceFormat = window->requestedFormat();
503 if (options.multisample)
501 if (options.multisample)
504 surfaceFormat.setSamples(16);
502 surfaceFormat.setSamples(16);