on xenial help sign in
Merge from trunk
74dbdb8Michael Terry
Bottombar/Bottombar.qml+3−1
@@ -107,7 +107,7 @@ Item {
107 height: distanceThreshold
107 height: distanceThreshold
108 anchors.bottom: parent.bottom
108 anchors.bottom: parent.bottom
109
109
110− distanceThreshold: units.gu(8)
110+ distanceThreshold: units.gu(1)
111 enabled: !theHud.shown && bottombar.enabled && applicationIsOnForeground
111 enabled: !theHud.shown && bottombar.enabled && applicationIsOnForeground
112 direction: Direction.Upwards
112 direction: Direction.Upwards
113
113
@@ -119,6 +119,8 @@ Item {
119 if (previousStatus == DirectionalDragArea.Recognized) {
119 if (previousStatus == DirectionalDragArea.Recognized) {
120 if (hudButton.mouseOver) {
120 if (hudButton.mouseOver) {
121 hudButton.clicked()
121 hudButton.clicked()
122+ } else {
123+ bottombar.state = "hidden"
122 }
124 }
123 }
125 }
124 } else if (status === DirectionalDragArea.Undecided) {
126 } else if (status === DirectionalDragArea.Undecided) {
Components/EdgeDemo.qml+4−4
@@ -44,13 +44,13 @@ Item {
44
44
45 function hideEdgeDemoInShell() {
45 function hideEdgeDemoInShell() {
46 var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
46 var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
47− AccountsService.setUserProperty(user, "demo-edges", false);
47+ AccountsService.demoEdges = false;
48 d.showEdgeDemo = false;
48 d.showEdgeDemo = false;
49 stopDemo();
49 stopDemo();
50 }
50 }
51
51
52 function hideEdgeDemoInGreeter() {
52 function hideEdgeDemoInGreeter() {
53− // TODO: AccountsService.setUserProperty("lightdm", "demo-edges", false);
53+ // TODO: AccountsService.demoEdges = false as lightdm user
54 d.showEdgeDemoInGreeter = false;
54 d.showEdgeDemoInGreeter = false;
55 }
55 }
56
56
@@ -80,7 +80,7 @@ Item {
80 property QtObject leftEdgeDemo
80 property QtObject leftEdgeDemo
81 property QtObject finalEdgeDemo
81 property QtObject finalEdgeDemo
82 property bool showEdgeDemo: false
82 property bool showEdgeDemo: false
83− property bool showEdgeDemoInGreeter: d.showEdgeDemo // TODO: AccountsService.getUserProperty("lightdm", "demo-edges")
83+ property bool showEdgeDemoInGreeter: d.showEdgeDemo // TODO: AccountsService.demoEdges as lightdm user
84
84
85 onShowEdgeDemoInGreeterChanged: {
85 onShowEdgeDemoInGreeterChanged: {
86 if (!d.overlay && d.showEdgeDemoInGreeter) {
86 if (!d.overlay && d.showEdgeDemoInGreeter) {
@@ -126,7 +126,7 @@ Item {
126
126
127 onSelected: {
127 onSelected: {
128 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
128 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
129− d.showEdgeDemo = AccountsService.getUserProperty(user, "demo-edges")
129+ d.showEdgeDemo = AccountsService.demoEdges
130 }
130 }
131 }
131 }
132
132
Components/IconUtil.jsdeleted−42
@@ -1,42 +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−.pragma library
18−
19−// FIXME: a quick hack to get icons out of gicons and fallback to
20−// base icon for annotated icons. Doesn't correctly handle all icons.
21−// Proper global solution needed.
22−function from_gicon(name) {
23− var icon_name = name;
24− var annotated_re = /^. UnityProtocolAnnotatedIcon/;
25− if (annotated_re.test(name)) {
26− var base_icon_re = /'base-icon':.+?'(.+?)'/;
27− var base_icon = name.toString().match(base_icon_re);
28− return from_gicon(unescape(base_icon[1]));
29− } else {
30− var themed_re = /^. GThemedIcon (.+)/;
31− var themed = name.match(themed_re);
32− if (themed) {
33− return "image://theme/" + themed[1].replace(" ", ",");
34− }
35− }
36− var name_re = /^[a-z0-9\._-]+$/;
37− if (name_re.test(icon_name)) {
38− return "image://theme/" + icon_name;
39− } else {
40− return icon_name;
41− }
42−}
Dash/Apps/AppPreview.qml+1−2
@@ -20,7 +20,6 @@ import Ubuntu.Components.ListItems 0.1 as ListItem
20import Ubuntu.DownloadDaemonListener 0.1
20import Ubuntu.DownloadDaemonListener 0.1
21import ".."
21import ".."
22import "../../Components"
22import "../../Components"
23−import "../../Components/IconUtil.js" as IconUtil
24
23
25DashPreview {
24DashPreview {
26 id: root
25 id: root
@@ -137,7 +136,7 @@ DashPreview {
137 anchors { left: parent.left; right: parent.right }
136 anchors { left: parent.left; right: parent.right }
138
137
139 appName: root.previewData.title
138 appName: root.previewData.title
140− icon: IconUtil.from_gicon(root.previewData.appIcon)
139+ icon: root.previewData.appIcon
141 rating: Math.round(root.previewData.rating * 10)
140 rating: Math.round(root.previewData.rating * 10)
142 reviews: root.previewData.numRatings
141 reviews: root.previewData.numRatings
143 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
142 rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
Dash/Apps/ApplicationsFilterGrid.qml+1−2
@@ -17,7 +17,6 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import "../../Components"
18import "../../Components"
19import "../../Applications"
19import "../../Applications"
20−import "../../Components/IconUtil.js" as IconUtil
21
20
22FilterGrid {
21FilterGrid {
23 id: filterGrid
22 id: filterGrid
@@ -50,7 +49,7 @@ FilterGrid {
50 text: model.title ? model.title : application.name // FIXME: this is temporary
49 text: model.title ? model.title : application.name // FIXME: this is temporary
51 imageWidth: units.gu(8)
50 imageWidth: units.gu(8)
52 imageHeight: units.gu(7.5)
51 imageHeight: units.gu(7.5)
53− source: IconUtil.from_gicon(icon)
52+ source: icon
54 onClicked: filterGrid.clicked(index, application.desktopFile);
53 onClicked: filterGrid.clicked(index, application.desktopFile);
55 }
54 }
56}
55}
Dash/Generic/GenericCarousel.qml+1−2
@@ -17,7 +17,6 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import "../../Components"
19import "../../Components"
20−import "../../Components/IconUtil.js" as IconUtil
21
20
22Carousel {
21Carousel {
23 id: genericCarousel
22 id: genericCarousel
@@ -42,7 +41,7 @@ Carousel {
42 image: Image {
41 image: Image {
43 asynchronous: true
42 asynchronous: true
44 sourceSize { width: item.width; height: item.height }
43 sourceSize { width: item.width; height: item.height }
45− source: model ? IconUtil.from_gicon(model.icon) : ""
44+ source: model ? model.icon : ""
46 }
45 }
47 }
46 }
48
47
Dash/Generic/GenericFilterGrid.qml+1−2
@@ -16,7 +16,6 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import "../../Components"
18import "../../Components"
19−import "../../Components/IconUtil.js" as IconUtil
20
19
21FilterGrid {
20FilterGrid {
22 id: filtergrid
21 id: filtergrid
@@ -41,7 +40,7 @@ FilterGrid {
41 imageWidth: filtergrid.iconWidth
40 imageWidth: filtergrid.iconWidth
42 imageHeight: filtergrid.iconHeight
41 imageHeight: filtergrid.iconHeight
43
42
44− source: IconUtil.from_gicon(model.icon)
43+ source: model.icon
45
44
46 fillMode: Image.PreserveAspectCrop
45 fillMode: Image.PreserveAspectCrop
47
46
Dash/Generic/GenericPreview.qml+1−2
@@ -18,7 +18,6 @@ import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import "../../Components"
19import "../../Components"
20import "../../Components/ListItems" as ListItems
20import "../../Components/ListItems" as ListItems
21−import "../../Components/IconUtil.js" as IconUtil
22import ".."
21import ".."
23
22
24DashPreview {
23DashPreview {
@@ -27,7 +26,7 @@ DashPreview {
27 title: previewData.title
26 title: previewData.title
28 previewWidthRatio: 0.6
27 previewWidthRatio: 0.6
29
28
30− property url url: IconUtil.from_gicon(previewData.image)
29+ property url url: previewData.image
31
30
32 header: UbuntuShape {
31 header: UbuntuShape {
33 id: urlLoader
32 id: urlLoader
Dash/GenericScopeView.qml+4−5
@@ -18,7 +18,6 @@ import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import "../Components"
19import "../Components"
20import "../Components/ListItems" as ListItems
20import "../Components/ListItems" as ListItems
21−import "../Components/IconUtil.js" as IconUtil
22
21
23ScopeView {
22ScopeView {
24 id: scopeView
23 id: scopeView
@@ -74,12 +73,12 @@ ScopeView {
74 onLoaded: {
73 onLoaded: {
75 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
74 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
76 // TODO: the running apps grid doesn't support standard scope results model yet
75 // TODO: the running apps grid doesn't support standard scope results model yet
77− item.firstModel = results.firstModel
76+ item.firstModel = Qt.binding(function() { return results.firstModel })
78− item.secondModel = results.secondModel
77+ item.secondModel = Qt.binding(function() { return results.secondModel })
79 } else {
78 } else {
80− item.model = results
79+ item.model = Qt.binding(function() { return results })
81 }
80 }
82− item.objectName = categoryId
81+ item.objectName = Qt.binding(function() { return categoryId })
83 if (item.expandable) {
82 if (item.expandable) {
84 var shouldFilter = index != categoryView.expandedIndex;
83 var shouldFilter = index != categoryView.expandedIndex;
85 if (shouldFilter != item.filter) {
84 if (shouldFilter != item.filter) {
Greeter/GreeterContent.qml+19−2
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import AccountsService 0.1
18import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
19import LightDM 0.1 as LightDM
20import LightDM 0.1 as LightDM
20import "../Components"
21import "../Components"
@@ -39,14 +40,30 @@ MouseArea {
39 color: "black"
40 color: "black"
40 }
41 }
41
42
43+ property url backgroundValue: AccountsService.backgroundFile != undefined && AccountsService.backgroundFile.length > 0 ? AccountsService.backgroundFile : shell.defaultBackground
44+ onBackgroundValueChanged: wallpaper.source = backgroundValue
45+
42 CrossFadeImage {
46 CrossFadeImage {
43 id: wallpaper
47 id: wallpaper
44−
45− source: shell.background
46 anchors.fill: parent
48 anchors.fill: parent
47 fadeInFirst: false
49 fadeInFirst: false
48 }
50 }
49
51
52+ // See Shell.qml's backgroundSettings treatment for why we need a separate
53+ // Image, but it boils down to avoiding binding loop detection.
54+ Image {
55+ source: wallpaper.source
56+ height: 0
57+ width: 0
58+ sourceSize.height: 0
59+ sourceSize.width: 0
60+ onStatusChanged: {
61+ if (status == Image.Error && source != shell.defaultBackground) {
62+ wallpaper.source = shell.defaultBackground
63+ }
64+ }
65+ }
66+
50 Rectangle {
67 Rectangle {
51 anchors.fill: parent
68 anchors.fill: parent
52 color: "black"
69 color: "black"
Launcher/LauncherDelegate.qml+20−9
@@ -24,6 +24,7 @@ Item {
24 property int count: -1
24 property int count: -1
25 property int progress: -1
25 property int progress: -1
26 property bool highlighted: false
26 property bool highlighted: false
27+ property bool itemFocused: false
27 property real maxAngle: 0
28 property real maxAngle: 0
28 property bool inverted: false
29 property bool inverted: false
29
30
@@ -43,17 +44,18 @@ Item {
43 onCountChanged: shaderEffectSource.scheduleUpdate();
44 onCountChanged: shaderEffectSource.scheduleUpdate();
44 onProgressChanged: shaderEffectSource.scheduleUpdate();
45 onProgressChanged: shaderEffectSource.scheduleUpdate();
45 onHighlightedChanged: shaderEffectSource.scheduleUpdate();
46 onHighlightedChanged: shaderEffectSource.scheduleUpdate();
47+ onItemFocusedChanged: shaderEffectSource.scheduleUpdate();
46
48
47 Item {
49 Item {
48 id: iconItem
50 id: iconItem
49− width: parent.itemWidth
51+ width: parent.itemWidth + units.gu(1)
50− height: parent.itemHeight
52+ height: parent.itemHeight + units.gu(1)
51 anchors.centerIn: parent
53 anchors.centerIn: parent
52
54
53 UbuntuShape {
55 UbuntuShape {
54 id: iconShape
56 id: iconShape
55 anchors.fill: parent
57 anchors.fill: parent
56− anchors.margins: units.gu(0.5)
58+ anchors.margins: units.gu(1)
57 radius: "medium"
59 radius: "medium"
58
60
59 image: Image {
61 image: Image {
@@ -78,7 +80,7 @@ Item {
78 anchors {
80 anchors {
79 right: parent.right
81 right: parent.right
80 top: parent.top
82 top: parent.top
81− margins: -units.dp(1)
83+ margins: units.dp(3)
82 }
84 }
83 width: Math.min(root.itemWidth, Math.max(units.gu(3), countLabel.implicitWidth + units.gu(2.5)))
85 width: Math.min(root.itemWidth, Math.max(units.gu(3), countLabel.implicitWidth + units.gu(2.5)))
84 height: units.gu(3)
86 height: units.gu(3)
@@ -105,9 +107,9 @@ Item {
105 left: iconItem.left
107 left: iconItem.left
106 right: iconItem.right
108 right: iconItem.right
107 bottom: iconItem.bottom
109 bottom: iconItem.bottom
108− leftMargin: units.gu(0.5)
110+ leftMargin: units.gu(1)
109− rightMargin: units.gu(0.5)
111+ rightMargin: units.gu(1)
110− bottomMargin: units.gu(0.5)
112+ bottomMargin: units.gu(1)
111 }
113 }
112 height: units.gu(1.5)
114 height: units.gu(1.5)
113 visible: root.progress > -1
115 visible: root.progress > -1
@@ -136,14 +138,23 @@ Item {
136 }
138 }
137 }
139 }
138 }
140 }
141+ Image {
142+ objectName: "focusedHighlight"
143+ anchors {
144+ right: parent.right
145+ verticalCenter: parent.verticalCenter
146+ }
147+ visible: root.itemFocused
148+ source: "graphics/focused_app_arrow.png"
149+ }
139 }
150 }
140
151
141 ShaderEffect {
152 ShaderEffect {
142 id: transformEffect
153 id: transformEffect
143 anchors.centerIn: parent
154 anchors.centerIn: parent
144 anchors.verticalCenterOffset: root.offset
155 anchors.verticalCenterOffset: root.offset
145− width: parent.itemWidth
156+ width: iconItem.width
146− height: parent.itemHeight
157+ height: iconItem.height
147 property real itemOpacity: root.itemOpacity
158 property real itemOpacity: root.itemOpacity
148 property real brightness: Math.max(-1, root.brightness)
159 property real brightness: Math.max(-1, root.brightness)
149 property real angle: root.angle
160 property real angle: root.angle
Launcher/LauncherPanel.qml+3−2
@@ -50,8 +50,6 @@ Item {
50 id: mainColumn
50 id: mainColumn
51 anchors {
51 anchors {
52 fill: parent
52 fill: parent
53− leftMargin: units.gu(0.5)
54− rightMargin: units.gu(0.5)
55 }
53 }
56
54
57 MouseArea {
55 MouseArea {
@@ -94,6 +92,8 @@ Item {
94 fill: parent
92 fill: parent
95 topMargin: -extensionSize + units.gu(0.5)
93 topMargin: -extensionSize + units.gu(0.5)
96 bottomMargin: -extensionSize + units.gu(1)
94 bottomMargin: -extensionSize + units.gu(1)
95+ leftMargin: units.gu(0.5)
96+ rightMargin: units.gu(0.5)
97 }
97 }
98 topMargin: extensionSize
98 topMargin: extensionSize
99 bottomMargin: extensionSize
99 bottomMargin: extensionSize
@@ -156,6 +156,7 @@ Item {
156 iconName: model.icon
156 iconName: model.icon
157 count: model.count
157 count: model.count
158 progress: model.progress
158 progress: model.progress
159+ itemFocused: model.focused
159 inverted: root.inverted
160 inverted: root.inverted
160 z: -Math.abs(offset)
161 z: -Math.abs(offset)
161 maxAngle: 55
162 maxAngle: 55
Launcher/graphics/focused_app_arrow@30.pngnew file

Binary file not shown.

Panel/IndicatorItem.qml+2−3
@@ -26,13 +26,12 @@ Item {
26 property bool highlighted: false
26 property bool highlighted: false
27 property bool dimmed: false
27 property bool dimmed: false
28 property var indicatorProperties: undefined
28 property var indicatorProperties: undefined
29+ property bool indicatorVisible: loader.item ? loader.item.enabled : false
29
30
30 opacity: dimmed ? 0.4 : 1
31 opacity: dimmed ? 0.4 : 1
31 Behavior on opacity { StandardAnimation {} }
32 Behavior on opacity { StandardAnimation {} }
32
33
33− // only visible when non-empty
34− visible: loader.item != undefined && loader.status == Loader.Ready ? loader.item.enabled : false
35− width: visible ? loader.item.width : 0
34+ width: loader.item ? loader.item.width : 0
36
35
37 Loader {
36 Loader {
38 id: loader
37 id: loader
Panel/IndicatorRow.qml+19−1
@@ -16,6 +16,7 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19+import Unity.Indicators 0.1 as Indicators
19import "../Components"
20import "../Components"
20
21
21Item {
22Item {
@@ -25,6 +26,7 @@ Item {
25 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
26 readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
26 property alias row: row
27 property alias row: row
27 property QtObject indicatorsModel: null
28 property QtObject indicatorsModel: null
29+ property var visibleIndicators: defined
28
30
29 width: units.gu(40)
31 width: units.gu(40)
30 height: units.gu(3)
32 height: units.gu(3)
@@ -55,7 +57,8 @@ Item {
55 Item {
57 Item {
56 id: itemWrapper
58 id: itemWrapper
57 height: indicatorRow.height
59 height: indicatorRow.height
58− width: childrenRect.width
60+ width: indicatorItem.width
61+ visible: indicatorItem.indicatorVisible
59
62
60 property int ownIndex: index
63 property int ownIndex: index
61 property alias highlighted: indicatorItem.highlighted
64 property alias highlighted: indicatorItem.highlighted
@@ -70,6 +73,21 @@ Item {
70
73
71 widgetSource: model.widgetSource
74 widgetSource: model.widgetSource
72 indicatorProperties : model.indicatorProperties
75 indicatorProperties : model.indicatorProperties
76+
77+ Component.onCompleted: {
78+ if (visibleIndicators == undefined) {
79+ visibleIndicators = {}
80+ }
81+ indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
82+ indicatorRow.visibleIndicatorsChanged();
83+ }
84+ onIndicatorVisibleChanged: {
85+ if (visibleIndicators == undefined) {
86+ visibleIndicators = {}
87+ }
88+ indicatorRow.visibleIndicators[model.identifier] = indicatorVisible;
89+ indicatorRow.visibleIndicatorsChanged();
90+ }
73 }
91 }
74
92
75 opacity: {
93 opacity: {
Panel/Indicators.qml+17−2
@@ -180,11 +180,19 @@ Showable {
180 clip: !indicators.fullyOpened
180 clip: !indicators.fullyOpened
181 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
181 activeHeader: indicators.state == "hint" || indicators.state == "reveal"
182 enabled: contentEnabled
182 enabled: contentEnabled
183+ visibleIndicators: indicatorRow.visibleIndicators
183
184
184 Connections {
185 Connections {
186+ property bool enableIndexChangeSignal: true
187+
185− target: indicatorRow
188+ target: enableIndexChangeSignal ? indicatorRow : null
186 onCurrentItemIndexChanged: {
189 onCurrentItemIndexChanged: {
190+ var oldActive = enableIndexChangeSignal;
191+ enableIndexChangeSignal = false;
192+
187 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
193 menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex);
194+
195+ enableIndexChangeSignal = oldActive;
188 }
196 }
189 }
197 }
190
198
@@ -256,9 +264,16 @@ Showable {
256 state: indicators.state
264 state: indicators.state
257
265
258 Connections {
266 Connections {
267+ property bool enableIndexChangeSignal: true
268+
259− target: menuContent
269+ target: enableIndexChangeSignal ? menuContent : null
260 onCurrentMenuIndexChanged: {
270 onCurrentMenuIndexChanged: {
271+ var oldActive = enableIndexChangeSignal;
272+ enableIndexChangeSignal = false;
273+
261 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
274 indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
275+
276+ enableIndexChangeSignal = oldActive;
262 }
277 }
263 }
278 }
264 }
279 }
Panel/Indicators/DatetimeIndicatorWidget.qml+4−2
@@ -25,6 +25,7 @@ Indicators.IndicatorWidget {
25 id: indicatorWidget
25 id: indicatorWidget
26
26
27 width: timeLabel.width + units.gu(1)
27 width: timeLabel.width + units.gu(1)
28+ rootMenuType: "com.canonical.indicator.root.time"
28
29
29 property alias label: timeLabel.text
30 property alias label: timeLabel.text
30
31
@@ -52,14 +53,15 @@ Indicators.IndicatorWidget {
52
53
53 onActionStateChanged: {
54 onActionStateChanged: {
54 if (action == undefined || !action.valid) {
55 if (action == undefined || !action.valid) {
56+ enabled = false;
55 return;
57 return;
56 }
58 }
57
59
58 if (action.state == undefined) {
60 if (action.state == undefined) {
59− visible = false;
61+ enabled = false;
60 return;
62 return;
61 }
63 }
62
64
63− indicatorWidget.visible = action.state[3];
65+ enabled = action.state[3];
64 }
66 }
65}
67}
Panel/Indicators/DefaultIndicatorWidget.qml+1
@@ -63,6 +63,7 @@ Indicators.IndicatorWidget {
63
63
64 onActionStateChanged: {
64 onActionStateChanged: {
65 if (action == undefined || !action.valid) {
65 if (action == undefined || !action.valid) {
66+ enabled = false;
66 return;
67 return;
67 }
68 }
68
69
Panel/Indicators/NetworkIndicatorWidget.qml+3
@@ -43,14 +43,17 @@ Indicators.IndicatorWidget {
43
43
44 onActionStateChanged: {
44 onActionStateChanged: {
45 if (action == undefined || !action.valid) {
45 if (action == undefined || !action.valid) {
46+ enabled = false;
46 return;
47 return;
47 }
48 }
48
49
49 if (action.state == undefined) {
50 if (action.state == undefined) {
51+ enabled = false;
50 connectionState = 0;
52 connectionState = 0;
51 return;
53 return;
52 }
54 }
53
55
56+ enabled = true;
54 connectionState = action.state[Indicators.NetworkActionState.Connection];
57 connectionState = action.state[Indicators.NetworkActionState.Connection];
55 if (connectionState == Indicators.NetworkConnection.Activated) {
58 if (connectionState == Indicators.NetworkConnection.Activated) {
56 signalStrength = action.state[Indicators.NetworkActionState.SignalStrength];
59 signalStrength = action.state[Indicators.NetworkActionState.SignalStrength];
Panel/Indicators/SoundIndicatorWidget.qml+1
@@ -22,4 +22,5 @@ import QtQuick 2.0
22DefaultIndicatorWidget {
22DefaultIndicatorWidget {
23 // default the icon so we have something to show when we don't have the bus.
23 // default the icon so we have something to show when we don't have the bus.
24 iconSource: "image://theme/audio-volume-high"
24 iconSource: "image://theme/audio-volume-high"
25+ enabled: true
25}
26}
Panel/MenuContent.qml+25−7
@@ -17,6 +17,7 @@
17import QtQuick 2.0
17import QtQuick 2.0
18import Ubuntu.Components 0.1
18import Ubuntu.Components 0.1
19import Unity.Indicators 0.1 as Indicators
19import Unity.Indicators 0.1 as Indicators
20+import Utils 0.1
20import "../Components"
21import "../Components"
21
22
22// FIXME : We dont want to use MainView.
23// FIXME : We dont want to use MainView.
@@ -27,20 +28,23 @@ MainView {
27
28
28 property QtObject indicatorsModel: null
29 property QtObject indicatorsModel: null
29 property bool __contentActive: false
30 property bool __contentActive: false
30− readonly property int currentMenuIndex : tabs.selectedTabIndex
31+ readonly property int currentMenuIndex : filteredIndicators.mapToSource(tabs.selectedTabIndex)
31 backgroundColor: "#221e1c" // FIXME not in palette yet
32 backgroundColor: "#221e1c" // FIXME not in palette yet
32 property int contentReleaseInterval: 20000
33 property int contentReleaseInterval: 20000
33 property bool activeHeader: false
34 property bool activeHeader: false
35+ property alias visibleIndicators: visibleIndicatorsModel.visible
34
36
35 width: units.gu(40)
37 width: units.gu(40)
36 height: units.gu(42)
38 height: units.gu(42)
37
39
38 function setCurrentMenuIndex(index) {
40 function setCurrentMenuIndex(index) {
39− if (currentMenuIndex !== index) {
41+ var filteredIndex = filteredIndicators.mapFromSource(index)
40− if (currentMenuIndex == -1) {
42+
43+ if (tabs.selectedTabIndex !== filteredIndex) {
44+ if (tabs.selectedTabIndex == -1) {
41 tabs.tabBar.animate = false;
45 tabs.tabBar.animate = false;
42 }
46 }
43− tabs.selectedTabIndex = index;
47+ tabs.selectedTabIndex = filteredIndex;
44 tabs.tabBar.animate = true;
48 tabs.tabBar.animate = true;
45 }
49 }
46 }
50 }
@@ -61,6 +65,20 @@ MainView {
61 tabs.tabBar.alwaysSelectionMode = activeHeader;
65 tabs.tabBar.alwaysSelectionMode = activeHeader;
62 }
66 }
63
67
68+ SortFilterProxyModel {
69+ id: filteredIndicators
70+ model: visibleIndicatorsModel
71+ dynamicSortFilter: true
72+
73+ filterRole: Indicators.IndicatorsModelRole.IsVisible
74+ filterRegExp: RegExp("^true$")
75+ }
76+
77+ Indicators.VisibleIndicatorsModel {
78+ id: visibleIndicatorsModel
79+ model: indicatorsModel
80+ }
81+
64 Tabs {
82 Tabs {
65 id: tabs
83 id: tabs
66 objectName: "tabs"
84 objectName: "tabs"
@@ -69,8 +87,8 @@ MainView {
69
87
70 Repeater {
88 Repeater {
71 id: repeater
89 id: repeater
72− model: indicatorsModel
90+ model: filteredIndicators
73− objectName: "menus"
91+ objectName: "tabsRepeater"
74
92
75 // FIXME: This is needed because tabs dont handle repeaters well.
93 // FIXME: This is needed because tabs dont handle repeaters well.
76 // Due to the child ordering happening after child insertion.
94 // Due to the child ordering happening after child insertion.
@@ -114,7 +132,7 @@ MainView {
114 item[pName] = indicatorProperties[pName]
132 item[pName] = indicatorProperties[pName]
115 }
133 }
116 }
134 }
117− if (contentActive && menus.visible) {
135+ if (contentActive && tabs.visible) {
118 item.start()
136 item.start()
119 }
137 }
120 }
138 }
Shell.qml+11
@@ -15,6 +15,7 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import AccountsService 0.1
18import GSettings 1.0
19import GSettings 1.0
19import Ubuntu.Application 0.1
20import Ubuntu.Application 0.1
20import Ubuntu.Components 0.1
21import Ubuntu.Components 0.1
@@ -95,6 +96,15 @@ FocusScope {
95 greeter.hide();
96 greeter.hide();
96 shell.activateApplication(desktopFile);
97 shell.activateApplication(desktopFile);
97 }
98 }
99+
100+ onMainStageFocusedApplicationChanged: {
101+ var app = applicationManager.mainStageFocusedApplication
102+ if (app != null) {
103+ LauncherModel.applicationFocused(app.desktopFile);
104+ } else {
105+ LauncherModel.applicationFocused("");
106+ }
107+ }
98 }
108 }
99
109
100 function activateApplication(desktopFile, argument) {
110 function activateApplication(desktopFile, argument) {
@@ -469,6 +479,7 @@ FocusScope {
469 onSelected: {
479 onSelected: {
470 // Update launcher items for new user
480 // Update launcher items for new user
471 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
481 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
482+ AccountsService.user = user;
472 LauncherModel.setUser(user);
483 LauncherModel.setUser(user);
473 }
484 }
474
485
debian/changelog+13
@@ -1,3 +1,16 @@
1+unity8 (7.81.3+13.10.20130905.2-0ubuntu1) saucy; urgency=low
2+
3+ [ Michael Zanetti ]
4+ * Integrate Launcher with AppManager.
5+
6+ [ Nick Dedekind ]
7+ * Removed FIXME from slider int->double conversion.
8+
9+ [ Ubuntu daily release ]
10+ * Automatic snapshot from revision 291
11+
12+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 05 Sep 2013 10:48:02 +0000
13+
1unity8 (7.81.3+13.10.20130904.1-0ubuntu1) saucy; urgency=low
14unity8 (7.81.3+13.10.20130904.1-0ubuntu1) saucy; urgency=low
2
15
3 [ Nicolas d'Offay ]
16 [ Nicolas d'Offay ]
plugins/AccountsService/AccountsService.cpp+67−37
@@ -17,58 +17,88 @@
17 */
17 */
18
18
19#include "AccountsService.h"
19#include "AccountsService.h"
20−#include <QDBusConnection>
20+#include "AccountsServiceDBusAdaptor.h"
21−#include <QDBusConnectionInterface>
21+
22−#include <QDBusMessage>
22+#include <QStringList>
23−#include <QDBusVariant>
24
23
25AccountsService::AccountsService(QObject* parent)
24AccountsService::AccountsService(QObject* parent)
26 : QObject(parent),
25 : QObject(parent),
27− accounts_manager(NULL),
26+ m_service(new AccountsServiceDBusAdaptor(this)),
28− users()
27+ m_user(qgetenv("USER"))
29{
28{
30− auto connection = QDBusConnection::SM_BUSNAME();
29+ connect(m_service, SIGNAL(propertiesChanged(const QString &, const QString &, const QStringList &)),
31− auto interface = connection.interface();
30+ this, SLOT(propertiesChanged(const QString &, const QString &, const QStringList &)));
32− interface->startService("org.freedesktop.Accounts");
31+ connect(m_service, SIGNAL(maybeChanged(const QString &)),
33− accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
32+ this, SLOT(maybeChanged(const QString &)));
34− "/org/freedesktop/Accounts",
35− "org.freedesktop.Accounts",
36− connection, this);
37}
33}
38
34
39−QVariant AccountsService::getUserProperty(const QString &user, const QString &property)
35+QString AccountsService::getUser()
40{
36{
41− auto iface = getUserInterface(user);
37+ return m_user;
42− if (iface != nullptr && iface->isValid()) {
38+}
43− auto answer = iface->call("Get", "com.canonical.unity.AccountsService", property);
39+
44− if (answer.type() == QDBusMessage::ReplyMessage) {
40+void AccountsService::setUser(const QString &user)
45− return answer.arguments()[0].value<QDBusVariant>().variant();
41+{
46− }
42+ m_user = user;
43+ Q_EMIT userChanged();
44+
45+ updateDemoEdges();
46+ updateBackgroundFile();
47+}
48+
49+bool AccountsService::getDemoEdges()
50+{
51+ return m_demoEdges;
52+}
53+
54+void AccountsService::setDemoEdges(bool demoEdges)
55+{
56+ m_demoEdges = demoEdges;
57+ m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
58+}
59+
60+QString AccountsService::getBackgroundFile()
61+{
62+ return m_backgroundFile;
63+}
64+
65+void AccountsService::updateDemoEdges()
66+{
67+ auto demoEdges = m_service->getUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges").toBool();
68+ if (m_demoEdges != demoEdges) {
69+ m_demoEdges = demoEdges;
70+ Q_EMIT demoEdgesChanged();
47 }
71 }
48− return QVariant();
49}
72}
50
73
51−void AccountsService::setUserProperty(const QString &user, const QString &property, const QVariant &value)
74+void AccountsService::updateBackgroundFile()
52{
75{
53− auto iface = getUserInterface(user);
76+ auto backgroundFile = m_service->getUserProperty(m_user, "org.freedesktop.Accounts.User", "BackgroundFile").toString();
54− if (iface != nullptr && iface->isValid()) {
77+ if (m_backgroundFile != backgroundFile) {
55− // The value needs to be carefully wrapped
78+ m_backgroundFile = backgroundFile;
56− iface->call("Set", "com.canonical.unity.AccountsService", property, QVariant::fromValue(QDBusVariant(value)));
79+ Q_EMIT backgroundFileChanged();
57 }
80 }
58}
81}
59
82
60−QDBusInterface *AccountsService::getUserInterface(const QString &user)
83+void AccountsService::propertiesChanged(const QString &user, const QString &interface, const QStringList &changed)
61{
84{
62− auto iface = users.value(user);
85+ if (m_user != user) {
63− if (iface == nullptr && accounts_manager->isValid()) {
86+ return;
64− auto answer = accounts_manager->call("FindUserByName", user);
87+ }
65− if (answer.type() == QDBusMessage::ReplyMessage) {
88+
66− iface = new QDBusInterface("org.freedesktop.Accounts",
89+ if (interface == "com.canonical.unity.AccountsService") {
67− answer.arguments()[0].value<QDBusObjectPath>().path(),
90+ if (changed.contains("demo-edges")) {
68− "org.freedesktop.DBus.Properties",
91+ updateDemoEdges();
69− accounts_manager->connection(), this);
70− users.insert(user, iface);
71 }
92 }
72 }
93 }
94+}
95+
96+void AccountsService::maybeChanged(const QString &user)
97+{
98+ if (m_user != user) {
73− return iface;
99+ return;
100+ }
101+
102+ // Standard properties might have changed
103+ updateBackgroundFile();
74}
104}
plugins/AccountsService/AccountsService.h+34−8
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -19,26 +19,52 @@
19#ifndef UNITY_ACCOUNTSSERVICE_H
19#ifndef UNITY_ACCOUNTSSERVICE_H
20#define UNITY_ACCOUNTSSERVICE_H
20#define UNITY_ACCOUNTSSERVICE_H
21
21
22−#include <QDBusInterface>
23−#include <QMap>
24#include <QObject>
22#include <QObject>
25#include <QString>
23#include <QString>
26
24
25+class AccountsServiceDBusAdaptor;
26+
27class AccountsService: public QObject
27class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ getUser
32+ WRITE setUser
33+ NOTIFY userChanged)
34+ Q_PROPERTY (bool demoEdges
35+ READ getDemoEdges
36+ WRITE setDemoEdges
37+ NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (QString backgroundFile
39+ READ getBackgroundFile
40+ NOTIFY backgroundFileChanged)
30
41
31public:
42public:
32 explicit AccountsService(QObject *parent = 0);
43 explicit AccountsService(QObject *parent = 0);
33
44
34− Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &property);
45+ QString getUser();
46+ void setUser(const QString &user);
47+ bool getDemoEdges();
48+ void setDemoEdges(bool demoEdges);
49+ QString getBackgroundFile();
50+
51+Q_SIGNALS:
52+ void userChanged();
53+ void demoEdgesChanged();
54+ void backgroundFileChanged();
55+
56+private Q_SLOTS:
35− Q_INVOKABLE void setUserProperty(const QString &user, const QString &property, const QVariant &value);
57+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
58+ void maybeChanged(const QString &user);
36
59
37private:
60private:
38− QDBusInterface *getUserInterface(const QString &user);
61+ void updateDemoEdges();
62+ void updateBackgroundFile();
39
63
40− QDBusInterface *accounts_manager;
64+ AccountsServiceDBusAdaptor *m_service;
41− QMap<QString, QDBusInterface *> users;
65+ QString m_user;
66+ bool m_demoEdges;
67+ QString m_backgroundFile;
42};
68};
43
69
44#endif
70#endif
plugins/AccountsService/AccountsServiceDBusAdaptor.cppnew file+126
@@ -0,0 +1,126 @@
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 "AccountsServiceDBusAdaptor.h"
20+#include <QDBusConnection>
21+#include <QDBusConnectionInterface>
22+#include <QDBusMessage>
23+#include <QDBusVariant>
24+
25+AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
26+ : QObject(parent),
27+ accounts_manager(NULL),
28+ users()
29+{
30+ auto connection = QDBusConnection::SM_BUSNAME();
31+ auto interface = connection.interface();
32+ interface->startService("org.freedesktop.Accounts");
33+ accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
34+ "/org/freedesktop/Accounts",
35+ "org.freedesktop.Accounts",
36+ connection, this);
37+}
38+
39+QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
40+{
41+ auto iface = getUserInterface(user);
42+ if (iface != nullptr && iface->isValid()) {
43+ auto answer = iface->call("Get", interface, property);
44+ if (answer.type() == QDBusMessage::ReplyMessage) {
45+ return answer.arguments()[0].value<QDBusVariant>().variant();
46+ }
47+ }
48+ return QVariant();
49+}
50+
51+void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
52+{
53+ auto iface = getUserInterface(user);
54+ if (iface != nullptr && iface->isValid()) {
55+ // The value needs to be carefully wrapped
56+ iface->call("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
57+ }
58+}
59+
60+void AccountsServiceDBusAdaptor::propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid)
61+{
62+ // Merge changed and invalidated together
63+ QStringList combined;
64+ combined << invalid;
65+ combined << changed.keys();
66+ combined.removeDuplicates();
67+
68+ Q_EMIT propertiesChanged(getUserForPath(message().path()), interface, combined);
69+}
70+
71+void AccountsServiceDBusAdaptor::maybeChangedSlot()
72+{
73+ Q_EMIT maybeChanged(getUserForPath(message().path()));
74+}
75+
76+QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
77+{
78+ QMap<QString, QDBusInterface *>::const_iterator i;
79+ for (i = users.constBegin(); i != users.constEnd(); ++i) {
80+ if (i.value()->path() == path) {
81+ return i.key();
82+ }
83+ }
84+ return QString();
85+}
86+
87+QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user)
88+{
89+ auto iface = users.value(user);
90+ if (iface == nullptr && accounts_manager->isValid()) {
91+ auto answer = accounts_manager->call("FindUserByName", user);
92+ if (answer.type() == QDBusMessage::ReplyMessage) {
93+ auto path = answer.arguments()[0].value<QDBusObjectPath>().path();
94+
95+ iface = new QDBusInterface("org.freedesktop.Accounts",
96+ path,
97+ "org.freedesktop.DBus.Properties",
98+ accounts_manager->connection(), this);
99+
100+ // With its own pre-defined properties, AccountsService is oddly
101+ // close-lipped. It won't send out proper DBus.Properties notices,
102+ // but it does have one catch-all Changed() signal. So let's
103+ // listen to that.
104+ iface->connection().connect(
105+ iface->service(),
106+ path,
107+ "org.freedesktop.Accounts.User",
108+ "Changed",
109+ this,
110+ SLOT(maybeChangedSlot()));
111+
112+ // But custom properties do send out the right notifications, so
113+ // let's still listen there.
114+ iface->connection().connect(
115+ iface->service(),
116+ path,
117+ "org.freedesktop.DBus.Properties",
118+ "PropertiesChanged",
119+ this,
120+ SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
121+
122+ users.insert(user, iface);
123+ }
124+ }
125+ return iface;
126+}
plugins/AccountsService/AccountsServiceDBusAdaptor.hnew file+54
@@ -0,0 +1,54 @@
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_ACCOUNTSSERVICEDBUSADAPTOR_H
20+#define UNITY_ACCOUNTSSERVICEDBUSADAPTOR_H
21+
22+#include <QDBusContext>
23+#include <QDBusInterface>
24+#include <QMap>
25+#include <QObject>
26+#include <QString>
27+
28+class AccountsServiceDBusAdaptor: public QObject, public QDBusContext
29+{
30+ Q_OBJECT
31+
32+public:
33+ explicit AccountsServiceDBusAdaptor(QObject *parent = 0);
34+
35+ Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &interface, const QString &property);
36+ Q_INVOKABLE void setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value);
37+
38+Q_SIGNALS:
39+ void propertiesChanged(const QString &user, const QString &interface, const QStringList &changed);
40+ void maybeChanged(const QString &user); // Standard properties might have changed
41+
42+private Q_SLOTS:
43+ void propertiesChangedSlot(const QString &interface, const QVariantMap &changed, const QStringList &invalid);
44+ void maybeChangedSlot();
45+
46+private:
47+ QDBusInterface *getUserInterface(const QString &user);
48+ QString getUserForPath(const QString &path);
49+
50+ QDBusInterface *accounts_manager;
51+ QMap<QString, QDBusInterface *> users;
52+};
53+
54+#endif
plugins/AccountsService/CMakeLists.txt+1
@@ -4,6 +4,7 @@ add_definitions(-DSM_BUSNAME=systemBus)
4
4
5add_library(AccountsService-qml MODULE
5add_library(AccountsService-qml MODULE
6 AccountsService.cpp
6 AccountsService.cpp
7+ AccountsServiceDBusAdaptor.cpp
7 plugin.cpp
8 plugin.cpp
8 )
9 )
9
10
plugins/Unity/CMakeLists.txt+1
@@ -47,6 +47,7 @@ set(QMLPLUGIN_SRC
47 signalslist.cpp
47 signalslist.cpp
48 socialpreview.cpp
48 socialpreview.cpp
49 socialpreviewcomment.cpp
49 socialpreviewcomment.cpp
50+ iconutils.cpp
50 variantutils.cpp
51 variantutils.cpp
51)
52)
52
53
plugins/Unity/Indicators/CMakeLists.txt+9
@@ -34,11 +34,20 @@ set(IndicatorsQML_SOURCES
34 rootactionstate.cpp
34 rootactionstate.cpp
35 unitymenumodelcache.cpp
35 unitymenumodelcache.cpp
36 unitymenumodelstack.cpp
36 unitymenumodelstack.cpp
37+ visibleindicatorsmodel.cpp
37)
38)
38add_definitions(-DUNITYINDICATORS_LIBRARY)
39add_definitions(-DUNITYINDICATORS_LIBRARY)
39
40
41+set(IndicatorsQML_RESOURCES
42+ resources/indicators.qrc
43+)
44+
45+qt5_add_resources(IndicatorsQML_RESOURCES_RCC
46+ ${IndicatorsQML_RESOURCES}
47+)
40
48
41add_library(IndicatorsQml SHARED
49add_library(IndicatorsQml SHARED
50+ ${IndicatorsQML_RESOURCES_RCC}
42 ${IndicatorsQML_SOURCES}
51 ${IndicatorsQML_SOURCES}
43)
52)
44
53
plugins/Unity/Indicators/Network/qml/AccessPoint.qml+71−26
@@ -22,13 +22,15 @@ import Ubuntu.Components 0.1
22import Ubuntu.Components.ListItems 0.1 as ListItem
22import Ubuntu.Components.ListItems 0.1 as ListItem
23import Unity.Indicators 0.1 as Indicators
23import Unity.Indicators 0.1 as Indicators
24
24
25−Indicators.FramedMenuItem {
25+Indicators.BaseMenuItem {
26− id: accessPoint
26+ id: menuItem
27+ implicitHeight: units.gu(5.5)
27
28
28 property bool checked: false
29 property bool checked: false
29 property bool secure: false
30 property bool secure: false
30 property bool adHoc: false
31 property bool adHoc: false
31 property int signalStrength: 0
32 property int signalStrength: 0
33+ property alias text: label.text
32
34
33 signal activate()
35 signal activate()
34
36
@@ -37,36 +39,79 @@ Indicators.FramedMenuItem {
37 checkBoxActive.checked = checked;
39 checkBoxActive.checked = checked;
38 }
40 }
39
41
40− icon: {
42+ onClicked: {
41− var imageName = "nm-signal-100"
43+ checkBoxActive.clicked();
42−
44+ }
43− if (adHoc) {
45+
44− imageName = "nm-adhoc";
46+ CheckBox {
45− } else if (signalStrength == 0) {
47+ id: checkBoxActive
46− imageName = "nm-signal-00";
48+ height: units.gu(3)
47− } else if (signalStrength <= 25) {
49+ width: units.gu(3)
48− imageName = "nm-signal-25";
50+
49− } else if (signalStrength <= 50) {
51+ anchors {
50− imageName = "nm-signal-50";
52+ left: parent.left
51− } else if (signalStrength <= 75) {
53+ leftMargin: menuItem.__contentsMargins
52− imageName = "nm-signal-75";
54+ verticalCenter: parent.verticalCenter
53 }
55 }
54
56
55− if (secure) {
57+ onClicked: {
56− imageName += "-secure";
58+ menuItem.activate();
57 }
59 }
58− return "image://theme/" + imageName;
59 }
60 }
60
61
61− iconFrame: false
62+ Image {
62− control: CheckBox {
63+ id: iconSignal
63− id: checkBoxActive
64− height: units.gu(4)
65− width: units.gu(4)
66− anchors.centerIn: parent
67
64
68− onClicked: {
65+ width: height
69− accessPoint.activate();
66+ height: Math.min(units.gu(5), parent.height - units.gu(1))
67+ anchors {
68+ left: checkBoxActive.right
69+ leftMargin: units.gu(1)
70+ verticalCenter: parent.verticalCenter
71+ }
72+
73+ source: {
74+ var imageName = "nm-signal-100"
75+
76+ if (adHoc) {
77+ imageName = "nm-adhoc";
78+ } else if (signalStrength == 0) {
79+ imageName = "nm-signal-00";
80+ } else if (signalStrength <= 25) {
81+ imageName = "nm-signal-25";
82+ } else if (signalStrength <= 50) {
83+ imageName = "nm-signal-50";
84+ } else if (signalStrength <= 75) {
85+ imageName = "nm-signal-75";
86+ }
87+ return "image://theme/" + imageName;
88+ }
89+ }
90+
91+ Label {
92+ id: label
93+ anchors {
94+ left: iconSignal.right
95+ leftMargin: units.gu(1)
96+ verticalCenter: parent.verticalCenter
97+ right: iconSecure.visible ? iconSecure.left : parent.right
98+ rightMargin: menuItem.__contentsMargins
99+ }
100+ elide: Text.ElideRight
101+ opacity: label.enabled ? 1.0 : 0.5
102+ }
103+
104+ Image {
105+ id: iconSecure
106+ visible: secure
107+ source: "qrc:/indicators/artwork/network/secure.svg"
108+
109+ width: height
110+ height: Math.min(units.gu(4), parent.height - units.gu(1))
111+ anchors {
112+ right: parent.right
113+ rightMargin: units.gu(1)
114+ verticalCenter: parent.verticalCenter
70 }
115 }
71 }
116 }
72}
117}
plugins/Unity/Indicators/indicator.cpp−2
@@ -51,7 +51,6 @@ void Indicator::init(const QString& busName, const QSettings& settings)
51 }
51 }
52 }
52 }
53
53
54−
55 QVariantMap properties;
54 QVariantMap properties;
56 properties.clear();
55 properties.clear();
57 properties.insert("busType", 1);
56 properties.insert("busType", 1);
@@ -87,7 +86,6 @@ void Indicator::setPosition(int position)
87 }
86 }
88}
87}
89
88
90−
91QVariant Indicator::indicatorProperties() const
89QVariant Indicator::indicatorProperties() const
92{
90{
93 return m_properties;
91 return m_properties;
plugins/Unity/Indicators/indicator.h−4
@@ -29,10 +29,6 @@
29class UNITYINDICATORS_EXPORT Indicator : public QObject
29class UNITYINDICATORS_EXPORT Indicator : public QObject
30{
30{
31 Q_OBJECT
31 Q_OBJECT
32− Q_PROPERTY(QString identifier READ identifier NOTIFY identifierChanged)
33− Q_PROPERTY(int position READ position NOTIFY positionChanged)
34− Q_PROPERTY(QVariant indicatorProperties READ indicatorProperties NOTIFY indicatorPropertiesChanged)
35−
36public:
32public:
37 typedef QSharedPointer<Indicator> Ptr;
33 typedef QSharedPointer<Indicator> Ptr;
38
34
plugins/Unity/Indicators/indicators.h+1−1
@@ -79,7 +79,7 @@ public:
79 WidgetSource,
79 WidgetSource,
80 PageSource,
80 PageSource,
81 IndicatorProperties,
81 IndicatorProperties,
82− IsValid
82+ IsVisible
83 };
83 };
84
84
85 IndicatorsModelRole(QObject*parent=0):QObject(parent) {}
85 IndicatorsModelRole(QObject*parent=0):QObject(parent) {}
plugins/Unity/Indicators/indicatorsmodel.cpp−3
@@ -206,7 +206,6 @@ QHash<int, QByteArray> IndicatorsModel::roleNames() const
206 roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
206 roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
207 roles[IndicatorsModelRole::PageSource] = "pageSource";
207 roles[IndicatorsModelRole::PageSource] = "pageSource";
208 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
208 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
209− roles[IndicatorsModelRole::IsValid] = "isValid";
210 }
209 }
211 return roles;
210 return roles;
212}
211}
@@ -269,8 +268,6 @@ QVariant IndicatorsModel::data(const QModelIndex &index, int role) const
269 return QVariant(indicator->indicatorProperties());
268 return QVariant(indicator->indicatorProperties());
270 }
269 }
271 break;
270 break;
272− case IndicatorsModelRole::IsValid:
273− return (indicator ? true : false);
274 case IndicatorsModelRole::Title:
271 case IndicatorsModelRole::Title:
275 case IndicatorsModelRole::Description:
272 case IndicatorsModelRole::Description:
276 case IndicatorsModelRole::WidgetSource:
273 case IndicatorsModelRole::WidgetSource:
plugins/Unity/Indicators/indicatorsmodel.h+2−1
@@ -44,7 +44,7 @@ public:
44 Q_INVOKABLE void load();
44 Q_INVOKABLE void load();
45 Q_INVOKABLE void unload();
45 Q_INVOKABLE void unload();
46
46
47− Q_INVOKABLE QVariant data(int row, int role = Qt::DisplayRole) const;
47+ Q_INVOKABLE QVariant data(int row, int role) const;
48
48
49 /* QAbstractItemModel */
49 /* QAbstractItemModel */
50 QHash<int, QByteArray> roleNames() const;
50 QHash<int, QByteArray> roleNames() const;
@@ -56,6 +56,7 @@ public:
56 void setIndicatorData(const QVariant& data);
56 void setIndicatorData(const QVariant& data);
57 QVariant indicatorData() const;
57 QVariant indicatorData() const;
58
58
59+
59Q_SIGNALS:
60Q_SIGNALS:
60 void countChanged();
61 void countChanged();
61 void indicatorDataChanged(const QVariant& data);
62 void indicatorDataChanged(const QVariant& data);
plugins/Unity/Indicators/plugin.cpp+2
@@ -32,6 +32,7 @@
32#include "rootactionstate.h"
32#include "rootactionstate.h"
33#include "unitymenumodelcache.h"
33#include "unitymenumodelcache.h"
34#include "unitymenumodelstack.h"
34#include "unitymenumodelstack.h"
35+#include "visibleindicatorsmodel.h"
35
36
36static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37static QObject* menuModelCacheSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) {
37 Q_UNUSED(engine);
38 Q_UNUSED(engine);
@@ -47,6 +48,7 @@ void Indicators2Plugin::registerTypes(const char *uri)
47 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
48 qmlRegisterType<UnityMenuModelStack>(uri, 0, 1, "UnityMenuModelStack");
48 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
49 qmlRegisterType<RootActionState>(uri, 0, 1, "RootActionState");
49 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
50 qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
51+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
50
52
51 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
53 qmlRegisterSingletonType<UnityMenuModelCache>(uri, 0, 1, "UnityMenuModelCache", menuModelCacheSingleton);
52
54
plugins/Unity/Indicators/qml/IndicatorBase.qml−5
@@ -24,8 +24,6 @@ import Unity.Indicators 0.1 as Indicators
24Item {
24Item {
25 id: indicatorItem
25 id: indicatorItem
26
26
27− // FIXME : should be disabled until bus available when we have desktop indicators
28− // for now, disable when we dont habe the correct profile.
29 enabled: menuObjectPaths.hasOwnProperty(device)
27 enabled: menuObjectPaths.hasOwnProperty(device)
30
28
31 //const
29 //const
@@ -39,9 +37,6 @@ Item {
39
37
40 property string deviceMenuObjectPath: menuObjectPaths.hasOwnProperty(device) ? menuObjectPaths[device] : ""
38 property string deviceMenuObjectPath: menuObjectPaths.hasOwnProperty(device) ? menuObjectPaths[device] : ""
41
39
42− signal actionGroupUpdated()
43− signal modelUpdated()
44−
45 property alias menuModel: cachedModel.model
40 property alias menuModel: cachedModel.model
46
41
47 CachedUnityMenuModel {
42 CachedUnityMenuModel {
plugins/Unity/Indicators/qml/IndicatorWidget.qml+1
@@ -24,6 +24,7 @@ IndicatorBase {
24 id: indicatorWidget
24 id: indicatorWidget
25
25
26 active: true
26 active: true
27+ enabled: false
27 property int iconSize: height - units.gu(0.5)
28 property int iconSize: height - units.gu(0.5)
28
29
29 property var actionState: Indicators.RootActionState {
30 property var actionState: Indicators.RootActionState {
plugins/Unity/Indicators/qml/MenuItemFactory.qml+5−5
@@ -159,17 +159,17 @@ Item {
159 id: accessPoint;
159 id: accessPoint;
160 ICNetwork.AccessPoint {
160 ICNetwork.AccessPoint {
161 property QtObject menu: null
161 property QtObject menu: null
162−// property var strenthAction: QMenuModel.UnityMenuAction {
162+ property var strengthAction: QMenuModel.UnityMenuAction {
163−// model: menuFactory.model ? menuFactory.model : null
163+ model: menuFactory.model ? menuFactory.model : null
164−// name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
164+ name: menu ? menu.ext.xCanonicalWifiApStrengthAction : ""
165−// }
165+ }
166
166
167 text: menu && menu.label ? menu.label : ""
167 text: menu && menu.label ? menu.label : ""
168 icon: menu ? menu.icon : ""
168 icon: menu ? menu.icon : ""
169 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
169 secure: menu ? menu.ext.xCanonicalWifiApIsSecure : false
170 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
170 adHoc: menu ? menu.ext.xCanonicalWifiApIsAdhoc : false
171 checked: menu ? menu.isToggled : false
171 checked: menu ? menu.isToggled : false
172−// signalStrength: strenthAction.valid ? strenthAction.state : 0
172+ signalStrength: strengthAction.valid ? strengthAction.state : 0
173 enabled: menu ? menu.sensitive : false
173 enabled: menu ? menu.sensitive : false
174
174
175 Component.onCompleted: {
175 Component.onCompleted: {
plugins/Unity/Indicators/resources/artwork/network/secure.svgnew file+71
@@ -0,0 +1,71 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3+
4+<svg
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6+ xmlns:cc="http://creativecommons.org/ns#"
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8+ xmlns:svg="http://www.w3.org/2000/svg"
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ width="64"
13+ height="64"
14+ id="svg2986"
15+ version="1.1"
16+ inkscape:version="0.48.4 r9939"
17+ sodipodi:docname="secure.svg">
18+ <defs
19+ id="defs2988" />
20+ <sodipodi:namedview
21+ id="base"
22+ pagecolor="#ffffff"
23+ bordercolor="#666666"
24+ borderopacity="1.0"
25+ inkscape:pageopacity="0.0"
26+ inkscape:pageshadow="2"
27+ inkscape:zoom="7.9180415"
28+ inkscape:cx="7.5048745"
29+ inkscape:cy="29.401628"
30+ inkscape:current-layer="layer1"
31+ showgrid="true"
32+ inkscape:grid-bbox="true"
33+ inkscape:document-units="px"
34+ inkscape:snap-grids="false"
35+ inkscape:window-width="1549"
36+ inkscape:window-height="876"
37+ inkscape:window-x="51"
38+ inkscape:window-y="24"
39+ inkscape:window-maximized="1">
40+ <inkscape:grid
41+ type="xygrid"
42+ id="grid3012"
43+ empspacing="5"
44+ visible="true"
45+ enabled="true"
46+ snapvisiblegridlinesonly="true" />
47+ </sodipodi:namedview>
48+ <metadata
49+ id="metadata2991">
50+ <rdf:RDF>
51+ <cc:Work
52+ rdf:about="">
53+ <dc:format>image/svg+xml</dc:format>
54+ <dc:type
55+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
56+ <dc:title />
57+ </cc:Work>
58+ </rdf:RDF>
59+ </metadata>
60+ <g
61+ id="layer1"
62+ inkscape:label="Layer 1"
63+ inkscape:groupmode="layer"
64+ transform="translate(0,32)">
65+ <path
66+ inkscape:connector-curvature="0"
67+ d="M 29.999999,-18 C 25.568001,-18 22,-14.432 22,-10 v 6 h -2 c -1.107999,0 -2,0.892 -2,2 v 18 c 0,1.108 0.892001,2 2,2 h 24 c 1.108,0 2,-0.892 2,-2 V -2 c 0,-1.108 -0.892,-2 -2,-2 h -2 v -6 c 0,-4.432 -3.568001,-8 -8.000001,-8 h -4 z m 0,4 h 4 c 2.216,0 4,1.784 4,4 v 6 H 26.000001 v -6 c 0,-2.216 1.784,-4 3.999998,-4 z"
68+ style="fill:#dfdbd2;fill-rule:evenodd"
69+ id="path8" />
70+ </g>
71+</svg>
plugins/Unity/Indicators/resources/indicators.qrcnew file+5
@@ -0,0 +1,5 @@
1+<RCC>
2+ <qresource prefix="/indicators">
3+ <file>artwork/network/secure.svg</file>
4+ </qresource>
5+</RCC>
plugins/Unity/Indicators/visibleindicatorsmodel.cppnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (C) 2012, 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+// self
18+#include "visibleindicatorsmodel.h"
19+#include "indicators.h"
20+
21+VisibleIndicatorsModel::VisibleIndicatorsModel(QObject *parent)
22+ : QIdentityProxyModel(parent),
23+ m_inserting(false)
24+{
25+ QObject::connect(this, SIGNAL(rowsAboutToBeInserted(QModelIndex, int, int)), this, SLOT(onBeginRowInserted(QModelIndex, int, int)));
26+ QObject::connect(this, SIGNAL(rowsInserted(QModelIndex, int, int)), this, SLOT(onRowInserted(QModelIndex, int, int)));
27+}
28+
29+QHash<int, QByteArray> VisibleIndicatorsModel::roleNames() const
30+{
31+ static QHash<int, QByteArray> roles;
32+ if (roles.isEmpty())
33+ {
34+ roles[IndicatorsModelRole::Identifier] = "identifier";
35+ roles[IndicatorsModelRole::Position] = "position";
36+ roles[IndicatorsModelRole::Title] = "title";
37+ roles[IndicatorsModelRole::Description] = "description";
38+ roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
39+ roles[IndicatorsModelRole::PageSource] = "pageSource";
40+ roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
41+ roles[IndicatorsModelRole::IsVisible] = "isVisible";
42+ }
43+ return roles;
44+}
45+
46+void VisibleIndicatorsModel::setSourceModel(QAbstractItemModel *model)
47+{
48+ if (sourceModel() != model) {
49+ QIdentityProxyModel::setSourceModel(model);
50+ Q_EMIT modelChanged();
51+ }
52+}
53+
54+QVariantMap VisibleIndicatorsModel::visible() const
55+{
56+ return m_visible;
57+}
58+
59+void VisibleIndicatorsModel::onBeginRowInserted(const QModelIndex&, int, int)
60+{
61+ m_inserting = true;
62+}
63+
64+void VisibleIndicatorsModel::onRowInserted(const QModelIndex&, int, int)
65+{
66+ m_inserting = false;
67+}
68+
69+void VisibleIndicatorsModel::setVisible(const QVariantMap& visible)
70+{
71+ if (m_visible != visible) {
72+ m_visible = visible;
73+ Q_EMIT visibleChanged();
74+
75+ // need to tell the view that the visible data has changed.
76+ if (!m_inserting && rowCount() > 0) {
77+ Q_EMIT dataChanged(index(0, 0), index(rowCount() - 1, 0), QVector<int>() << IndicatorsModelRole::IsVisible);
78+ }
79+ }
80+}
81+
82+QVariant VisibleIndicatorsModel::data(const QModelIndex &index, int role) const
83+{
84+ if (role != IndicatorsModelRole::IsVisible) {
85+ return QIdentityProxyModel::data(index, role);
86+ }
87+
88+ if (!index.isValid()) {
89+ return false;
90+ }
91+
92+ QString ident = QIdentityProxyModel::data(index, IndicatorsModelRole::Identifier).toString();
93+ return m_visible.value(ident, false).toBool();
94+}
plugins/Unity/Indicators/visibleindicatorsmodel.hnew file+56
@@ -0,0 +1,56 @@
1+/*
2+ * Copyright (C) 2012, 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#ifndef VISIBLEINDICATORSMODEL_H
21+#define VISIBLEINDICATORSMODEL_H
22+
23+#include <QIdentityProxyModel>
24+
25+class VisibleIndicatorsModel : public QIdentityProxyModel
26+{
27+ Q_OBJECT
28+
29+ Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY modelChanged)
30+ Q_PROPERTY(QVariantMap visible READ visible WRITE setVisible NOTIFY visibleChanged)
31+
32+public:
33+ explicit VisibleIndicatorsModel(QObject *parent = 0);
34+
35+ virtual void setSourceModel(QAbstractItemModel *model);
36+ virtual QHash<int, QByteArray> roleNames() const;
37+ virtual QVariant data(const QModelIndex &index, int role) const;
38+
39+ QVariantMap visible() const;
40+ void setVisible(const QVariantMap& visible);
41+
42+public Q_SLOTS:
43+ void onBeginRowInserted(const QModelIndex&, int start, int end);
44+ void onRowInserted(const QModelIndex&, int start, int end);
45+
46+Q_SIGNALS:
47+ void totalCountChanged();
48+ void modelChanged();
49+ void visibleChanged();
50+
51+private:
52+ QVariantMap m_visible;
53+ bool m_inserting;
54+};
55+
56+#endif // VISIBLEINDICATORSMODEL_H
plugins/Unity/IndicatorsLegacy/qml/IndicatorWidget.qml+2−2
@@ -23,7 +23,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
23IndicatorBase {
23IndicatorBase {
24 id: indicatorWidget
24 id: indicatorWidget
25
25
26−// enabled: false // FIXME : should be disabled until bus available when we have desktop indicators
26+ enabled: false
27 property var action: undefined
27 property var action: undefined
28 property bool started: (busType != 0) && (busName != "") && (deviceMenuObjectPath != "")
28 property bool started: (busType != 0) && (busName != "") && (deviceMenuObjectPath != "")
29 property int iconSize: height - units.gu(0.5)
29 property int iconSize: height - units.gu(0.5)
@@ -40,7 +40,6 @@ IndicatorBase {
40 actionGroup.stop();
40 actionGroup.stop();
41 }
41 }
42 }
42 }
43− onActionChanged: actionStateChanged()
44 onActionGroupUpdated: update_state()
43 onActionGroupUpdated: update_state()
45 onModelUpdated: update_state()
44 onModelUpdated: update_state()
46
45
@@ -57,6 +56,7 @@ IndicatorBase {
57
56
58 if (extra.canonical_type === rootMenuType) {
57 if (extra.canonical_type === rootMenuType) {
59 action = actionGroup.action(proxyModel.data(0, Indicators.FlatMenuProxyModelRole.Action));
58 action = actionGroup.action(proxyModel.data(0, Indicators.FlatMenuProxyModelRole.Action));
59+ actionStateChanged();
60 }
60 }
61 }
61 }
62
62
plugins/Unity/Launcher/CMakeLists.txt+1−1
@@ -17,7 +17,7 @@ set(QMLLAUNCHERPLUGIN_SRC
17 quicklistmodel.cpp
17 quicklistmodel.cpp
18 common/quicklistentry.cpp
18 common/quicklistentry.cpp
19 backend/launcherbackend.cpp
19 backend/launcherbackend.cpp
20− ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
20+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
21 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
21 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
22 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
22 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
23 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
23 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
plugins/Unity/Launcher/backend/launcherbackend.cpp+36−8
@@ -18,13 +18,14 @@
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
19 */
20
20
21−#include "AccountsService.h"
21+#include "AccountsServiceDBusAdaptor.h"
22#include "launcherbackend.h"
22#include "launcherbackend.h"
23
23
24#include <QDir>
24#include <QDir>
25#include <QDBusArgument>
25#include <QDBusArgument>
26#include <QFileInfo>
26#include <QFileInfo>
27#include <QGSettings>
27#include <QGSettings>
28+#include <QDebug>
28
29
29class LauncherBackendItem
30class LauncherBackendItem
30{
31{
@@ -42,7 +43,7 @@ LauncherBackend::LauncherBackend(bool useStorage, QObject *parent):
42 m_accounts(nullptr)
43 m_accounts(nullptr)
43{
44{
44 if (useStorage) {
45 if (useStorage) {
45− m_accounts = new AccountsService(this);
46+ m_accounts = new AccountsServiceDBusAdaptor(this);
46 }
47 }
47 m_user = qgetenv("USER");
48 m_user = qgetenv("USER");
48 syncFromAccounts();
49 syncFromAccounts();
@@ -73,6 +74,19 @@ void LauncherBackend::setStoredApplications(const QStringList &appIds)
73 }
74 }
74 }
75 }
75 m_storedApps = appIds;
76 m_storedApps = appIds;
77+ Q_FOREACH(const QString &appId, appIds) {
78+ if (!m_itemCache.contains(appId)) {
79+ QString df = findDesktopFile(appId);
80+ if (!df.isEmpty()) {
81+ LauncherBackendItem *item = parseDesktopFile(df);
82+ m_itemCache.insert(appId, item);
83+ } else {
84+ // Cannot find any data for that app... ignoring it.
85+ qWarning() << "cannot find desktop file for" << appId << ". discarding app.";
86+ m_storedApps.removeAll(appId);
87+ }
88+ }
89+ }
76 syncToAccounts();
90 syncToAccounts();
77}
91}
78
92
@@ -199,8 +213,8 @@ void LauncherBackend::syncFromAccounts()
199
213
200 m_storedApps.clear();
214 m_storedApps.clear();
201
215
202− if (m_accounts && m_user.isEmpty()) {
216+ if (m_accounts && !m_user.isEmpty()) {
203− QVariant variant = m_accounts->getUserProperty(m_user, "launcher-items");
217+ QVariant variant = m_accounts->getUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items");
204 apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
218 apps = qdbus_cast<QList<QVariantMap>>(variant.value<QDBusArgument>());
205 defaults = isDefaultsItem(apps);
219 defaults = isDefaultsItem(apps);
206 }
220 }
@@ -210,7 +224,11 @@ void LauncherBackend::syncFromAccounts()
210 Q_FOREACH(const QString &entry, gSettings.get("favorites").toStringList()) {
224 Q_FOREACH(const QString &entry, gSettings.get("favorites").toStringList()) {
211 if (entry.startsWith("application://")) {
225 if (entry.startsWith("application://")) {
212 QString appId = entry;
226 QString appId = entry;
227+ // Transform "application://foobar.desktop" to "foobar"
213 appId.remove("application://");
228 appId.remove("application://");
229+ if (appId.endsWith(".desktop")) {
230+ appId.chop(8);
231+ }
214 QString df = findDesktopFile(appId);
232 QString df = findDesktopFile(appId);
215
233
216 if (!df.isEmpty()) {
234 if (!df.isEmpty()) {
@@ -239,7 +257,7 @@ void LauncherBackend::syncToAccounts()
239 items << itemToVariant(appId);
257 items << itemToVariant(appId);
240 }
258 }
241
259
242− m_accounts->setUserProperty(m_user, "launcher-items", QVariant::fromValue(items));
260+ m_accounts->setUserProperty(m_user, "com.canonical.unity.AccountsService", "launcher-items", QVariant::fromValue(items));
243 }
261 }
244}
262}
245
263
@@ -248,14 +266,24 @@ QString LauncherBackend::findDesktopFile(const QString &appId) const
248 int dashPos = -1;
266 int dashPos = -1;
249 QString helper = appId;
267 QString helper = appId;
250
268
269+ QStringList searchDirs;
270+ searchDirs << QDir::homePath() + "/.local/share/applications";
271+ searchDirs << "/usr/share/applications";
272+
273+#ifdef LAUNCHER_TESTING
274+ searchDirs << "";
275+#endif
276+
251 do {
277 do {
252 if (dashPos != -1) {
278 if (dashPos != -1) {
253 helper = helper.replace(dashPos, 1, '/');
279 helper = helper.replace(dashPos, 1, '/');
254 }
280 }
255
281
282+ Q_FOREACH(const QString &searchDir, searchDirs) {
256− QFileInfo fileInfo(QDir("/usr/share/applications"), helper);
283+ QFileInfo fileInfo(QDir(searchDir), helper + ".desktop");
257− if (fileInfo.exists()) {
284+ if (fileInfo.exists()) {
258− return fileInfo.absoluteFilePath();
285+ return fileInfo.absoluteFilePath();
286+ }
259 }
287 }
260
288
261 dashPos = helper.indexOf("-");
289 dashPos = helper.indexOf("-");
plugins/Unity/Launcher/backend/launcherbackend.h+2−2
@@ -25,7 +25,7 @@
25#include <QSettings>
25#include <QSettings>
26#include <QStringList>
26#include <QStringList>
27
27
28−class AccountsService;
28+class AccountsServiceDBusAdaptor;
29
29
30/**
30/**
31 * @brief An interface that provides all the data needed by the launcher.
31 * @brief An interface that provides all the data needed by the launcher.
@@ -156,7 +156,7 @@ private:
156 QList<QString> m_storedApps;
156 QList<QString> m_storedApps;
157 mutable QHash<QString, LauncherBackendItem*> m_itemCache;
157 mutable QHash<QString, LauncherBackendItem*> m_itemCache;
158
158
159− AccountsService *m_accounts;
159+ AccountsServiceDBusAdaptor *m_accounts;
160 QString m_user;
160 QString m_user;
161};
161};
162
162
plugins/Unity/Launcher/launcheritem.cpp+14
@@ -31,6 +31,7 @@ LauncherItem::LauncherItem(const QString &appId, const QString &desktopFile, con
31 m_recent(false),
31 m_recent(false),
32 m_progress(-1),
32 m_progress(-1),
33 m_count(0),
33 m_count(0),
34+ m_focused(false),
34 m_quickList(new QuickListModel(this))
35 m_quickList(new QuickListModel(this))
35{
36{
36 QuickListEntry nameAction;
37 QuickListEntry nameAction;
@@ -131,6 +132,19 @@ void LauncherItem::setCount(int count)
131 }
132 }
132}
133}
133
134
135+bool LauncherItem::focused() const
136+{
137+ return m_focused;
138+}
139+
140+void LauncherItem::setFocused(bool focused)
141+{
142+ if (m_focused != focused) {
143+ m_focused = focused;
144+ Q_EMIT focusedChanged(focused);
145+ }
146+}
147+
134unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
148unity::shell::launcher::QuickListModelInterface *LauncherItem::quickList() const
135{
149{
136 return m_quickList;
150 return m_quickList;
plugins/Unity/Launcher/launcheritem.h+4
@@ -54,6 +54,9 @@ public:
54 int count() const;
54 int count() const;
55 void setCount(int count);
55 void setCount(int count);
56
56
57+ bool focused() const;
58+ void setFocused(bool focused);
59+
57 unity::shell::launcher::QuickListModelInterface *quickList() const;
60 unity::shell::launcher::QuickListModelInterface *quickList() const;
58
61
59Q_SIGNALS:
62Q_SIGNALS:
@@ -70,6 +73,7 @@ private:
70 bool m_recent;
73 bool m_recent;
71 int m_progress;
74 int m_progress;
72 int m_count;
75 int m_count;
76+ bool m_focused;
73 QuickListModel *m_quickList;
77 QuickListModel *m_quickList;
74};
78};
75
79
plugins/Unity/Launcher/launchermodel.cpp+59
@@ -74,6 +74,8 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
74 return item->count();
74 return item->count();
75 case RoleProgress:
75 case RoleProgress:
76 return item->progress();
76 return item->progress();
77+ case RoleFocused:
78+ return item->focused();
77 }
79 }
78
80
79 return QVariant();
81 return QVariant();
@@ -191,6 +193,63 @@ void LauncherModel::setUser(const QString &username)
191 m_backend->setUser(username);
193 m_backend->setUser(username);
192}
194}
193
195
196+void LauncherModel::applicationFocused(const QString &appId)
197+{
198+ // Unfocus all apps
199+ for(int i = 0; i < m_list.count(); ++i) {
200+ LauncherItem *item = m_list.at(i);
201+ if (item->focused()) {
202+ item->setFocused(false);
203+ Q_EMIT dataChanged(this->index(i), this->index(i), QVector<int>() << RoleFocused);
204+ }
205+ }
206+
207+ if (appId.isEmpty()) {
208+ return;
209+ }
210+
211+ // FIXME: drop this once we get real appIds from the AppManager
212+ QString helper = appId.split('/').last();
213+ if (helper.endsWith(".desktop")) {
214+ helper.chop(8);
215+ }
216+
217+ int index = findApplication(helper);
218+ if (index >= 0) {
219+ m_list.at(index)->setFocused(true);
220+ Q_EMIT dataChanged(this->index(index), this->index(index), QVector<int>() << RoleFocused);
221+ } else {
222+ // Add app to recent apps
223+ QString desktopFile = m_backend->desktopFile(helper);
224+ QString appName = m_backend->displayName(helper);
225+ QString icon = m_backend->icon(helper);
226+
227+ LauncherItem *item = new LauncherItem(helper, desktopFile, appName, icon);
228+ item->setRecent(true);
229+ item->setFocused(true);
230+ beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
231+ m_list.append(item);
232+ endInsertRows();
233+
234+ // Clean up old recent apps
235+ QList<int> recentAppIndices;
236+ for (int i = 0; i < m_list.count(); ++i) {
237+ if (m_list.at(i)->recent()) {
238+ recentAppIndices << i;
239+ }
240+ }
241+ int run = 0;
242+ while (recentAppIndices.count() > 5) {
243+ beginRemoveRows(QModelIndex(), recentAppIndices.first() - run, recentAppIndices.first() - run);
244+ m_list.takeAt(recentAppIndices.first() - run)->deleteLater();
245+ endRemoveRows();
246+ recentAppIndices.takeFirst();
247+ ++run;
248+ }
249+ storeAppList();
250+ }
251+}
252+
194void LauncherModel::storeAppList()
253void LauncherModel::storeAppList()
195{
254{
196 QStringList appIds;
255 QStringList appIds;
plugins/Unity/Launcher/launchermodel.h+1
@@ -49,6 +49,7 @@ public:
49 Q_INVOKABLE void requestRemove(const QString &appId);
49 Q_INVOKABLE void requestRemove(const QString &appId);
50 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
50 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
51 Q_INVOKABLE void setUser(const QString &username);
51 Q_INVOKABLE void setUser(const QString &username);
52+ Q_INVOKABLE void applicationFocused(const QString &appId);
52
53
53private:
54private:
54 void storeAppList();
55 void storeAppList();
plugins/Unity/applicationpreview.cpp+5−1
@@ -19,6 +19,7 @@
19
19
20// local
20// local
21#include "applicationpreview.h"
21#include "applicationpreview.h"
22+#include "iconutils.h"
22
23
23#include <QDebug>
24#include <QDebug>
24
25
@@ -61,7 +62,10 @@ QString ApplicationPreview::license() const
61QString ApplicationPreview::appIcon() const
62QString ApplicationPreview::appIcon() const
62{
63{
63 if (m_unityAppPreview) {
64 if (m_unityAppPreview) {
64− return QString::fromUtf8(g_icon_to_string(m_unityAppPreview->app_icon()));
65+ auto giconString = g_icon_to_string(m_unityAppPreview->app_icon());
66+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
67+ g_free(giconString);
68+ return result;
65 } else {
69 } else {
66 qWarning() << "Preview not set";
70 qWarning() << "Preview not set";
67 }
71 }
plugins/Unity/categoryresults.cpp+5−2
@@ -19,6 +19,7 @@
19
19
20// self
20// self
21#include "categoryresults.h"
21#include "categoryresults.h"
22+#include "iconutils.h"
22
23
23// TODO: use something from libunity once it's public
24// TODO: use something from libunity once it's public
24enum ResultsColumn {
25enum ResultsColumn {
@@ -76,8 +77,10 @@ CategoryResults::data(const QModelIndex& index, int role) const
76 switch (role) {
77 switch (role) {
77 case RoleUri:
78 case RoleUri:
78 return DeeListModel::data(index, ResultsColumn::URI);
79 return DeeListModel::data(index, ResultsColumn::URI);
79− case RoleIconHint:
80+ case RoleIconHint: {
80− return DeeListModel::data(index, ResultsColumn::ICON_HINT);
81+ QString giconString(DeeListModel::data(index, ResultsColumn::ICON_HINT).toString());
82+ return QVariant::fromValue(gIconToDeclarativeImageProviderString(giconString));
83+ }
81 case RoleCategory:
84 case RoleCategory:
82 return DeeListModel::data(index, ResultsColumn::CATEGORY);
85 return DeeListModel::data(index, ResultsColumn::CATEGORY);
83 case RoleMimetype:
86 case RoleMimetype:
plugins/Unity/categoryresults.h+1−1
@@ -24,7 +24,7 @@
24// dee-qt
24// dee-qt
25#include "deelistmodel.h"
25#include "deelistmodel.h"
26
26
27−class CategoryResults : public DeeListModel
27+class Q_DECL_EXPORT CategoryResults : public DeeListModel
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30
30
plugins/Unity/iconutils.cppnew file+91
@@ -0,0 +1,91 @@
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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#include <QStringList>
21+#include <QUrl>
22+
23+#include <gio/gio.h>
24+#include "iconutils.h"
25+
26+#define BASE_THEME_ICON_URI "image://theme/"
27+
28+QString gIconToDeclarativeImageProviderString(QString const &giconString)
29+{
30+ if (giconString.isEmpty()) return giconString;
31+
32+ if (giconString.startsWith('/') || giconString.startsWith(QLatin1String("http")) ||
33+ giconString.startsWith(QLatin1String("file:"))) {
34+ return giconString;
35+ }
36+
37+ if (!giconString.startsWith(QLatin1String(". "))) {
38+ // must be a themed icon
39+ QString themedIcon(BASE_THEME_ICON_URI);
40+ themedIcon.append(giconString);
41+ return themedIcon;
42+ }
43+
44+ // special case annotated icon
45+ if (giconString.startsWith(QLatin1String(". UnityProtocolAnnotatedIcon "))) {
46+ QString annotatedIcon;
47+ QString serializedData(QUrl::fromPercentEncoding(giconString.mid(29).toUtf8()));
48+ GVariant *variant = g_variant_parse(G_VARIANT_TYPE_VARDICT, serializedData.toUtf8().constData(), NULL, NULL, NULL);
49+ gchar *baseUri;
50+ if (variant != NULL && g_variant_lookup(variant, "base-icon", "&s", &baseUri)) {
51+ annotatedIcon = gIconToDeclarativeImageProviderString(QString(baseUri));
52+ // FIXME: enclose in image://annotated/... once unity supports that
53+ }
54+ if (variant != NULL) g_variant_unref(variant);
55+
56+ return annotatedIcon;
57+ }
58+
59+ // handle real gicon strings
60+ QString result;
61+ GError *error = NULL;
62+ GIcon *icon = g_icon_new_for_string(giconString.toLocal8Bit().constData(), &error);
63+ if (error != NULL || icon == NULL) {
64+ qWarning("Unable to deserialize icon: %s", giconString.toLocal8Bit().constData());
65+ g_clear_error(&error);
66+ return result;
67+ }
68+
69+ if (G_IS_THEMED_ICON(icon)) {
70+ QString themedIcon(BASE_THEME_ICON_URI);
71+ QStringList list;
72+ const char* const *iconNames = g_themed_icon_get_names(G_THEMED_ICON(icon));
73+ if (iconNames != NULL) {
74+ for (const char * const *iter = iconNames; *iter != NULL; ++iter) {
75+ list << QLatin1String(*iter);
76+ }
77+ }
78+ themedIcon.append(list.join(QString(",")));
79+ result = themedIcon;
80+ } else if (G_IS_FILE_ICON(icon)) {
81+ GFile *file = g_file_icon_get_file(G_FILE_ICON(icon));
82+ gchar *uri = g_file_get_uri(file);
83+ QString iconUri(uri);
84+ g_free(uri);
85+ result = iconUri;
86+ }
87+
88+ g_object_unref(icon);
89+
90+ return result;
91+}
plugins/Unity/iconutils.hnew file+27
@@ -0,0 +1,27 @@
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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#ifndef ICONUTILS_H
21+#define ICONUTILS_H
22+
23+#include <QString>
24+
25+QString gIconToDeclarativeImageProviderString(QString const &giconString);
26+
27+#endif
plugins/Unity/preview.cpp+5−1
@@ -26,6 +26,7 @@
26#include "moviepreview.h"
26#include "moviepreview.h"
27#include "musicpreview.h"
27#include "musicpreview.h"
28#include "socialpreview.h"
28#include "socialpreview.h"
29+#include "iconutils.h"
29#include "variantutils.h"
30#include "variantutils.h"
30
31
31// Qt
32// Qt
@@ -102,7 +103,10 @@ QVariantMap Preview::infoHintsHash() const
102QString Preview::image() const
103QString Preview::image() const
103{
104{
104 if (m_unityPreview) {
105 if (m_unityPreview) {
105− return QString::fromUtf8(g_icon_to_string(m_unityPreview->image()));
106+ auto giconString = g_icon_to_string(m_unityPreview->image());
107+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
108+ g_free(giconString);
109+ return result;
106 } else {
110 } else {
107 qWarning() << "Preview not set";
111 qWarning() << "Preview not set";
108 }
112 }
plugins/Unity/socialpreview.cpp+5−1
@@ -19,6 +19,7 @@
19
19
20#include "socialpreview.h"
20#include "socialpreview.h"
21#include "socialpreviewcomment.h"
21#include "socialpreviewcomment.h"
22+#include "iconutils.h"
22
23
23#include <QDebug>
24#include <QDebug>
24
25
@@ -51,7 +52,10 @@ QString SocialPreview::content() const
51QString SocialPreview::avatar() const
52QString SocialPreview::avatar() const
52{
53{
53 if (m_unitySocialPreview) {
54 if (m_unitySocialPreview) {
54− return QString::fromUtf8(g_icon_to_string(m_unitySocialPreview->avatar()));
55+ auto giconString = g_icon_to_string(m_unitySocialPreview->avatar());
56+ QString result(gIconToDeclarativeImageProviderString(QString::fromUtf8(giconString)));
57+ g_free(giconString);
58+ return result;
55 } else {
59 } else {
56 qWarning() << "Preview not set";
60 qWarning() << "Preview not set";
57 }
61 }
plugins/Utils/qsortfilterproxymodelqml.cpp+20
@@ -121,3 +121,23 @@ QSortFilterProxyModelQML::findFirst(int role, const QVariant& value) const
121 return -1;
121 return -1;
122 }
122 }
123}
123}
124+
125+int
126+QSortFilterProxyModelQML::mapFromSource(int row)
127+{
128+ if (sourceModel() != NULL) {
129+ return QSortFilterProxyModel::mapFromSource(sourceModel()->index(row, 0)).row();
130+ } else {
131+ return -1;
132+ }
133+}
134+
135+int
136+QSortFilterProxyModelQML::mapToSource(int row)
137+{
138+ if (sourceModel() != NULL) {
139+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
140+ } else {
141+ return -1;
142+ }
143+}
plugins/Utils/qsortfilterproxymodelqml.h+3
@@ -45,6 +45,9 @@ public:
45 void setModel(QAbstractItemModel *model);
45 void setModel(QAbstractItemModel *model);
46 void setInvertMatch(bool invertMatch);
46 void setInvertMatch(bool invertMatch);
47
47
48+ Q_INVOKABLE int mapFromSource(int row);
49+ Q_INVOKABLE int mapToSource(int row);
50+
48Q_SIGNALS:
51Q_SIGNALS:
49 void totalCountChanged();
52 void totalCountChanged();
50 void countChanged();
53 void countChanged();
po/es.po+24−22
@@ -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-07-08 07:25+0000\n"
11+"PO-Revision-Date: 2013-09-04 22:12+0000\n"
12"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
12"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
13"Language-Team: Spanish <es@li.org>\n"
13"Language-Team: Spanish <es@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-05 05:35+0000\n"
19−"X-Generator: Launchpad (build 16750)\n"
19+"X-Generator: Launchpad (build 16758)\n"
20
20
21#: Applications/applications.js:23
21#: Applications/applications.js:23
22msgid "Phone"
22msgid "Phone"
@@ -88,47 +88,49 @@ msgstr "YouTube"
88
88
89#: Components/EdgeDemoOverlay.qml:145
89#: Components/EdgeDemoOverlay.qml:145
90msgid "Skip intro"
90msgid "Skip intro"
91−msgstr ""
91+msgstr "Omitir la introducción"
92
92
93#: Components/EdgeDemo.qml:98
93#: Components/EdgeDemo.qml:98
94msgid "Right edge"
94msgid "Right edge"
95−msgstr ""
95+msgstr "Borde derecho"
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 "Deslice el dedo desde el borde derecho para desbloquear el teléfono"
100
100
101#: Components/EdgeDemo.qml:135
101#: Components/EdgeDemo.qml:135
102msgid "Top edge"
102msgid "Top edge"
103−msgstr ""
103+msgstr "Borde superior"
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 "Deslice el dedo desde el borde superior para acceder a los menús"
108
108
109#: Components/EdgeDemo.qml:161
109#: Components/EdgeDemo.qml:161
110msgid "Close"
110msgid "Close"
111−msgstr ""
111+msgstr "Cerrar"
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 "Deslice hacia arriba para cerrar la pantalla de configuración"
116
116
117#: Components/EdgeDemo.qml:189
117#: Components/EdgeDemo.qml:189
118msgid "Left edge"
118msgid "Left edge"
119−msgstr ""
119+msgstr "Borde izquierdo"
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"
123msgstr ""
123msgstr ""
124+"Deslice el dedo desde la izquierda para mostrar el lanzador y acceder "
125+"rápidamente a las aplicaciones"
124
126
125#: Components/EdgeDemo.qml:217
127#: Components/EdgeDemo.qml:217
126msgid "Well done"
128msgid "Well done"
127−msgstr ""
129+msgstr "Bien hecho"
128
130
129#: Components/EdgeDemo.qml:218
131#: Components/EdgeDemo.qml:218
130msgid "You have now mastered the edge gestures and can start using the phone"
132msgid "You have now mastered the edge gestures and can start using the phone"
131−msgstr ""
133+msgstr "Ahora domina el uso de gestos de los bordes. Puede usar el teléfono"
132
134
133#: Components/PageHeader.qml:298
135#: Components/PageHeader.qml:298
134msgid "Recent searches"
136msgid "Recent searches"
@@ -138,35 +140,35 @@ msgstr "Búsquedas recientes"
138#: Dash/Apps/AppInfo.qml:73
140#: Dash/Apps/AppInfo.qml:73
139#, qt-format
141#, qt-format
140msgid "(%1)"
142msgid "(%1)"
141−msgstr ""
143+msgstr "(%1)"
142
144
143#. TRANSLATORS: Number of persons who wrote reviews for this app
145#. TRANSLATORS: Number of persons who wrote reviews for this app
144#: Dash/Apps/AppInfo.qml:85
146#: Dash/Apps/AppInfo.qml:85
145#, qt-format
147#, qt-format
146msgid "%1 review"
148msgid "%1 review"
147msgid_plural "%1 reviews"
149msgid_plural "%1 reviews"
148−msgstr[0] ""
150+msgstr[0] "%1 reseña"
149−msgstr[1] ""
151+msgstr[1] "%1 reseñas"
150
152
151#: Dash/Apps/AppPreview.qml:175
153#: Dash/Apps/AppPreview.qml:175
152msgid "Rate this"
154msgid "Rate this"
153−msgstr ""
155+msgstr "Valorar esto"
154
156
155#: Dash/Apps/AppReviews.qml:72
157#: Dash/Apps/AppReviews.qml:72
156msgid "Add a review"
158msgid "Add a review"
157−msgstr ""
159+msgstr "Añadir una reseña"
158
160
159#: Dash/Apps/AppReviews.qml:84
161#: Dash/Apps/AppReviews.qml:84
160msgid "Review"
162msgid "Review"
161−msgstr ""
163+msgstr "Reseñar"
162
164
163#: Dash/Apps/AppReviews.qml:118
165#: Dash/Apps/AppReviews.qml:118
164msgid "Send"
166msgid "Send"
165−msgstr ""
167+msgstr "Enviar"
166
168
167#: Dash/Apps/AppReviews.qml:136
169#: Dash/Apps/AppReviews.qml:136
168msgid "Comments:"
170msgid "Comments:"
169−msgstr ""
171+msgstr "Comentarios:"
170
172
171#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
172msgid "Featured"
174msgid "Featured"
@@ -210,7 +212,7 @@ msgstr "Autor:"
210
212
211#: Greeter/Lockscreen.qml:134
213#: Greeter/Lockscreen.qml:134
212msgid "Emergency Call"
214msgid "Emergency Call"
213−msgstr ""
215+msgstr "Llamada de emergencia"
214
216
215#: Greeter/PassphraseLockscreen.qml:59
217#: Greeter/PassphraseLockscreen.qml:59
216#, qt-format
218#, qt-format
tests/autopilot/unity8/shell/tests/test_hud.py+7−2
@@ -34,6 +34,8 @@ class TestHud(UnityTestCase):
34
34
35 def test_show_hud_button_appears(self):
35 def test_show_hud_button_appears(self):
36 """Swiping up while an app is active must show the 'show hud' button.
36 """Swiping up while an app is active must show the 'show hud' button.
37+ The button must disappear not opening the HUD when releasing the
38+ mouse again somewhere on the screen except on the button itself.
37
39
38 """
40 """
39 self.launch_unity()
41 self.launch_unity()
@@ -49,9 +51,12 @@ class TestHud(UnityTestCase):
49 hud_show_button
51 hud_show_button
50 )
52 )
51 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
53 self.touch.press(swipe_coords.start_x, swipe_coords.start_y)
52− self.addCleanup(self.touch.release)
54+ self.addCleanup(self._maybe_release_finger)
53− self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
55+ self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y + hud_show_button.height);
54 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
56 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
57+ self.touch.release();
58+ self.assertThat(hud_show_button.opacity, Eventually(Equals(0.0)))
59+ self.assertThat(hud.shown, Equals(False))
55
60
56 def test_show_hud_appears(self):
61 def test_show_hud_appears(self):
57 """Releasing the touch on the 'show hud' button must display the hud.
62 """Releasing the touch on the 'show hud' button must display the hud.
tests/mocks/AccountsService/AccountsService.cpp+19−3
@@ -23,11 +23,27 @@ AccountsService::AccountsService(QObject* parent)
23{
23{
24}
24}
25
25
26−QVariant AccountsService::getUserProperty(const QString &, const QString &)
26+QString AccountsService::getUser()
27{
27{
28− return QVariant(false);
28+ return "testuser";
29}
29}
30
30
31−void AccountsService::setUserProperty(const QString &, const QString &, const QVariant &)
31+void AccountsService::setUser(const QString &user)
32{
32{
33+ Q_UNUSED(user)
34+}
35+
36+bool AccountsService::getDemoEdges()
37+{
38+ return false;
39+}
40+
41+void AccountsService::setDemoEdges(bool demoEdges)
42+{
43+ Q_UNUSED(demoEdges)
44+}
45+
46+QString AccountsService::getBackgroundFile()
47+{
48+ return TOP_SRCDIR "/graphics/phone_background.jpg";
33}
49}
tests/mocks/AccountsService/AccountsService.h+22−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2013 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -27,12 +27,31 @@
27class AccountsService: public QObject
27class AccountsService: public QObject
28{
28{
29 Q_OBJECT
29 Q_OBJECT
30+ Q_PROPERTY (QString user
31+ READ getUser
32+ WRITE setUser
33+ NOTIFY userChanged)
34+ Q_PROPERTY (bool demoEdges
35+ READ getDemoEdges
36+ WRITE setDemoEdges
37+ NOTIFY demoEdgesChanged)
38+ Q_PROPERTY (QString backgroundFile
39+ READ getBackgroundFile
40+ NOTIFY backgroundFileChanged)
30
41
31public:
42public:
32 explicit AccountsService(QObject *parent = 0);
43 explicit AccountsService(QObject *parent = 0);
33
44
34− Q_INVOKABLE QVariant getUserProperty(const QString &user, const QString &property);
45+ QString getUser();
35− Q_INVOKABLE void setUserProperty(const QString &user, const QString &property, const QVariant &value);
46+ void setUser(const QString &user);
47+ bool getDemoEdges();
48+ void setDemoEdges(bool demoEdges);
49+ QString getBackgroundFile();
50+
51+Q_SIGNALS:
52+ void userChanged();
53+ void demoEdgesChanged();
54+ void backgroundFileChanged();
36};
55};
37
56
38#endif
57#endif
tests/mocks/AccountsService/CMakeLists.txt+2
@@ -1,3 +1,5 @@
1+add_definitions(-DTOP_SRCDIR="${CMAKE_SOURCE_DIR}")
2+
1add_library(MockAccountsService-qml MODULE
3add_library(MockAccountsService-qml MODULE
2 AccountsService.cpp
4 AccountsService.cpp
3 plugin.cpp
5 plugin.cpp
tests/mocks/LightDM/demo/GreeterPrivate.cpp+4−2
@@ -55,11 +55,13 @@ void GreeterPrivate::handleRespond(const QString &response)
55 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
55 QSettings settings(QDir::homePath() + "/.unity8-greeter-demo", QSettings::NativeFormat);
56 QVariant password = settings.value("password", "none");
56 QVariant password = settings.value("password", "none");
57
57
58+ QString passwordValue;
58 if (password == "pin") {
59 if (password == "pin") {
59− authenticated = (response == "1234");
60+ passwordValue = settings.value("passwordValue", "1234").toString();
60 } else {
61 } else {
61− authenticated = (response == "password");
62+ passwordValue = settings.value("passwordValue", "password").toString();
62 }
63 }
64+ authenticated = (response == passwordValue);
63 Q_EMIT q->authenticationComplete();
65 Q_EMIT q->authenticationComplete();
64}
66}
65
67
tests/mocks/Unity/CMakeLists.txt+3
@@ -17,6 +17,9 @@ add_definitions(-DQT_NO_KEYWORDS)
17
17
18set(UnityQML_SOURCES
18set(UnityQML_SOURCES
19 ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
19 ${CMAKE_SOURCE_DIR}/plugins/Unity/categoryresults.cpp
20+ ${CMAKE_SOURCE_DIR}/plugins/Unity/iconutils.cpp
21+ fake_applications_scope.cpp
22+ fake_preview.cpp
20 fake_scope.cpp
23 fake_scope.cpp
21 fake_scopes.cpp
24 fake_scopes.cpp
22 fake_categories.cpp
25 fake_categories.cpp
tests/mocks/Unity/Indicators/CMakeLists.txt+1
@@ -13,6 +13,7 @@ set(IndicatorsFakeQml_SOURCES
13 fakeplugin.cpp
13 fakeplugin.cpp
14 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/indicators.h
14 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/indicators.h
15 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/menucontentactivator.cpp
15 ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/menucontentactivator.cpp
16+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Indicators/visibleindicatorsmodel.cpp
16)
17)
17
18
18set(IndicatorsFakeQml_RESOURCES
19set(IndicatorsFakeQml_RESOURCES
tests/mocks/Unity/Indicators/IndicatorsModel.qml+47−76
@@ -23,82 +23,53 @@ ListModel {
23
23
24 function load() {}
24 function load() {}
25
25
26− ListElement {
26+ // Need to do this dynamically.
27+ // Apparently ListModels dont order roles visually when using ListElement
28+ // which throws off the filter for non-visible indicators.
29+ Component.onCompleted: {
27− identifier: "indicator-fake1";
30+ append({ "identifier": "indicator-fake1",
28− priority: 0
31+ "priority": 0,
29− title: "Menu1";
32+ "title": "Menu1",
30− description: "";
33+ "description": "",
31− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
34+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget1.qml",
32− pageSource: "qrc:/tests/indciators/qml/fake_menu_page1.qml";
35+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page1.qml",
33− indicatorProperties: "";
34− isValid: "";
35− }
36− ListElement {
37− identifier: "indicator-fake2";
38− priority: 1
39− title: "Menu2";
40− description: "";
41− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget2.qml";
42− pageSource: "qrc:/tests/indciators/qml/fake_menu_page2.qml";
43− indicatorProperties: "";
36+ "indicatorProperties": ""
44− isValid: "";
45− }
46− ListElement {
47− identifier: "indicator-fake3";
48− priority: 2
49− title: "Menu3";
50− description: "";
51− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget3.qml";
52− pageSource: "qrc:/tests/indciators/qml/fake_menu_page3.qml";
53− indicatorProperties: "";
54− isValid: "";
55− }
37+ });
56− ListElement {
57− identifier: "indicator-fake4";
58− priority: 3
59− title: "Menu4";
60− description: "";
61− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget4.qml";
62− pageSource: "qrc:/tests/indciators/qml/fake_menu_page4.qml";
63− indicatorProperties: "";
64− isValid: "";
65− }
66− ListElement {
67− identifier: "indicator-fake5";
68− priority: 4
69− title: "Menu5";
70− description: "";
71− widgetSource: "qrc:/tests/indciators/qml/fake_menu_widget5.qml";
72− pageSource: "qrc:/tests/indciators/qml/fake_menu_page5.qml";
73− indicatorProperties: "";
74− isValid: "";
75− }
76
38
77− function data(row, role) {
39+ append({ "identifier": "indicator-fake2",
78− if (role == Indicators.IndicatorsModelRole.Identifier) {
40+ "priority": 1,
79− return get(row).identifier;
41+ "title": "Menu2",
80− }
42+ "description": "",
81− else if (role == Indicators.IndicatorsModelRole.Priority) {
43+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget2.qml",
82− return get(row).priority
44+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page2.qml",
83− }
45+ "indicatorProperties": ""
84− else if (role == Indicators.IndicatorsModelRole.Title) {
85− return get(row).title
86− }
46+ });
87− else if (role == Indicators.IndicatorsModelRole.Description) {
47+
88− return get(row).description
48+ append({ "identifier": "indicator-fake3",
89− }
49+ "priority": 2,
90− else if (role == Indicators.IndicatorsModelRole.WidgetSource) {
50+ "title": "Menu3",
91− return get(row).widgetSource
51+ "description": "",
92− }
52+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget3.qml",
93− else if (role == Indicators.IndicatorsModelRole.PageSource) {
53+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page3.qml",
94− return get(row).pageSource
54+ "indicatorProperties": ""
95− }
96− else if (role == Indicators.IndicatorsModelRole.IndicatorProperties) {
97− return get(row).indicatorProperties
98− }
99− else if (role == Indicators.IndicatorsModelRole.IsValid) {
100− return get(row).isValid
101− }
102− }
55+ });
103
56
57+ append({ "identifier": "indicator-fake4",
58+ "priority": 3,
59+ "title": "Menu4",
60+ "description": "",
61+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget4.qml",
62+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page4.qml",
63+ "indicatorProperties": ""
64+ });
65+
66+ append({ "identifier": "indicator-fake5",
67+ "priority": 4,
68+ "title": "Menu5",
69+ "description": "",
70+ "widgetSource": "qrc:/tests/indciators/qml/fake_menu_widget5.qml",
71+ "pageSource": "qrc:/tests/indciators/qml/fake_menu_page5.qml",
72+ "indicatorProperties": ""
73+ });
74+ }
104}
75}
tests/mocks/Unity/Indicators/fakeplugin.cpp+2
@@ -25,12 +25,14 @@
25// local
25// local
26#include "indicators.h"
26#include "indicators.h"
27#include "menucontentactivator.h"
27#include "menucontentactivator.h"
28+#include "visibleindicatorsmodel.h"
28
29
29void IndicatorsFakePlugin::registerTypes(const char * uri)
30void IndicatorsFakePlugin::registerTypes(const char * uri)
30{
31{
31 Q_INIT_RESOURCE(indicators_fake);
32 Q_INIT_RESOURCE(indicators_fake);
32
33
33 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
34 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
35+ qmlRegisterType<VisibleIndicatorsModel>(uri, 0, 1, "VisibleIndicatorsModel");
34
36
35 qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
37 qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
36 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
38 qmlRegisterUncreatableType<ActionState>(uri, 0, 1, "ActionState", "Can't create ActionState class");
tests/mocks/Unity/Indicators/qml/fake_menu_widget2.qml+2
@@ -20,4 +20,6 @@ Rectangle {
20 width: 40
20 width: 40
21 height: 40
21 height: 40
22 color : "yellow"
22 color : "yellow"
23+
24+ enabled: false
23}
25}
tests/mocks/Unity/Launcher/MockLauncherItem.cpp+16
@@ -33,6 +33,7 @@ MockLauncherItem::MockLauncherItem(const QString &appId, const QString& desktopF
33 m_recent(false),
33 m_recent(false),
34 m_progress(-1),
34 m_progress(-1),
35 m_count(0),
35 m_count(0),
36+ m_focused(false),
36 m_quickList(new MockQuickListModel(this))
37 m_quickList(new MockQuickListModel(this))
37{
38{
38
39
@@ -128,6 +129,21 @@ void MockLauncherItem::setCount(int count)
128 }
129 }
129}
130}
130
131
132+bool MockLauncherItem::focused() const
133+{
134+ return m_focused;
135+}
136+
137+void MockLauncherItem::setFocused(bool focused)
138+{
139+ if (m_focused != focused)
140+ {
141+ m_focused = focused;
142+ Q_EMIT focusedChanged(focused);
143+ }
144+}
145+
146+
131unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
147unity::shell::launcher::QuickListModelInterface *MockLauncherItem::quickList() const
132{
148{
133 return m_quickList;
149 return m_quickList;
tests/mocks/Unity/Launcher/MockLauncherItem.h+4
@@ -52,6 +52,9 @@ public:
52 int count() const;
52 int count() const;
53 void setCount(int count);
53 void setCount(int count);
54
54
55+ bool focused() const;
56+ void setFocused(bool focused);
57+
55 unity::shell::launcher::QuickListModelInterface *quickList() const;
58 unity::shell::launcher::QuickListModelInterface *quickList() const;
56
59
57private:
60private:
@@ -64,6 +67,7 @@ private:
64 bool m_recent;
67 bool m_recent;
65 int m_progress;
68 int m_progress;
66 int m_count;
69 int m_count;
70+ bool m_focused;
67 MockQuickListModel *m_quickList;
71 MockQuickListModel *m_quickList;
68};
72};
69
73
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+9
@@ -25,6 +25,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
25 MockLauncherItem *item = new MockLauncherItem("phone-app", "/usr/share/applications/phone-app.desktop", "Phone", "phone-app", this);
25 MockLauncherItem *item = new MockLauncherItem("phone-app", "/usr/share/applications/phone-app.desktop", "Phone", "phone-app", this);
26 item->setProgress(0);
26 item->setProgress(0);
27 m_list.append(item);
27 m_list.append(item);
28+ item->setFocused(true);
28 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
29 item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
29 item->setProgress(10);
30 item->setProgress(10);
30 m_list.append(item);
31 m_list.append(item);
@@ -49,6 +50,7 @@ MockLauncherModel::MockLauncherModel(QObject* parent): LauncherModelInterface(pa
49 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
50 item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
50 item->setProgress(50);
51 item->setProgress(50);
51 item->setCount(5);
52 item->setCount(5);
53+ item->setFocused(true);
52 m_list.append(item);
54 m_list.append(item);
53 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
55 item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
54 m_list.append(item);
56 m_list.append(item);
@@ -85,6 +87,8 @@ QVariant MockLauncherModel::data(const QModelIndex& index, int role) const
85 return item->progress();
87 return item->progress();
86 case RoleCount:
88 case RoleCount:
87 return item->count();
89 return item->count();
90+ case RoleFocused:
91+ return item->focused();
88 }
92 }
89
93
90 return QVariant();
94 return QVariant();
@@ -180,3 +184,8 @@ void MockLauncherModel::setUser(const QString &username)
180 Q_UNUSED(username)
184 Q_UNUSED(username)
181 // TODO: implement this...
185 // TODO: implement this...
182}
186}
187+
188+void MockLauncherModel::applicationFocused(const QString &appId)
189+{
190+ Q_UNUSED(appId)
191+}
tests/mocks/Unity/Launcher/MockLauncherModel.h+1
@@ -44,6 +44,7 @@ public:
44 Q_INVOKABLE void requestRemove(const QString &appId);
44 Q_INVOKABLE void requestRemove(const QString &appId);
45 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
45 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
46 Q_INVOKABLE void setUser(const QString &username);
46 Q_INVOKABLE void setUser(const QString &username);
47+ Q_INVOKABLE void applicationFocused(const QString &appId);
47
48
48Q_SIGNALS:
49Q_SIGNALS:
49 void quickListTriggered(const QString &appId, int index);
50 void quickListTriggered(const QString &appId, int index);
tests/mocks/Unity/fake_applications_scope.cppnew file+68
@@ -0,0 +1,68 @@
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 "fake_applications_scope.h"
18+
19+static const gchar * categories_model_schema[] = {
20+ "s", //ID
21+ "s", // DISPLAY_NAME
22+ "s", // ICON_HINT
23+ "s", // RENDERER_NAME
24+ "a{sv}" // HINTS
25+};
26+
27+ApplicationsScope::ApplicationsScope(bool visible, QObject* parent)
28+ : Scope(parent)
29+{
30+ m_id = "applications.scope";
31+ m_name = "Applications";
32+ m_visible = visible;
33+ m_categories->setModel(createCategoriesModel());
34+}
35+
36+DeeModel* ApplicationsScope::createCategoriesModel()
37+{
38+ DeeModel* category_model = dee_sequence_model_new();
39+ dee_model_set_schema_full(category_model, categories_model_schema, G_N_ELEMENTS(categories_model_schema));
40+ GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
41+
42+ GVariant* children[1];
43+ children[0] = g_variant_new_dict_entry(g_variant_new_string("content-type"),
44+ g_variant_new_variant(g_variant_new_string("apps")));
45+ GVariant* recentHints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), children, 1);
46+ dee_model_append(category_model,
47+ "recent",
48+ "Recent",
49+ "gtk-apply",
50+ "special",
51+ recentHints);
52+
53+ dee_model_append(category_model,
54+ "installed",
55+ "Installed",
56+ "gtk-apply",
57+ "grid",
58+ hints);
59+
60+ dee_model_append(category_model,
61+ "suggested",
62+ "Suggested",
63+ "gtk-apply",
64+ "grid",
65+ hints);
66+
67+ return category_model;
68+}
tests/mocks/Unity/fake_applications_scope.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+
17+#ifndef FAKE_APPLICATIONS_SCOPE_H
18+#define FAKE_APPLICATIONS_SCOPE_H
19+
20+#include "fake_scope.h"
21+
22+class ApplicationsScope : public Scope
23+{
24+ Q_OBJECT
25+
26+public:
27+ ApplicationsScope(bool visible, QObject* parent = 0);
28+
29+private:
30+ DeeModel* createCategoriesModel();
31+};
32+
33+#endif // FAKE_APPLICATIONS_SCOPE_H
tests/mocks/Unity/fake_categories.cpp+84−9
@@ -24,11 +24,20 @@
24
24
25#define CATEGORY_COLUMN 2
25#define CATEGORY_COLUMN 2
26
26
27+// TODO: use something from libunity once it's public
28+enum CategoryColumn {
29+ ID,
30+ DISPLAY_NAME,
31+ ICON_HINT,
32+ RENDERER_NAME,
33+ HINTS
34+};
35+
27Categories::Categories(QObject* parent)
36Categories::Categories(QObject* parent)
28 : DeeListModel(parent)
37 : DeeListModel(parent)
29{
38{
30 // FIXME: need to clean up unused filters on countChanged
39 // FIXME: need to clean up unused filters on countChanged
31− m_roles[Categories::RoleId] = "id";
40+ m_roles[Categories::RoleCategoryId] = "categoryId";
32 m_roles[Categories::RoleName] = "name";
41 m_roles[Categories::RoleName] = "name";
33 m_roles[Categories::RoleIcon] = "icon";
42 m_roles[Categories::RoleIcon] = "icon";
34 m_roles[Categories::RoleRenderer] = "renderer";
43 m_roles[Categories::RoleRenderer] = "renderer";
@@ -73,6 +82,25 @@ Categories::onCountChanged()
73 }
82 }
74}
83}
75
84
85+void Categories::onRowCountChanged()
86+{
87+ QAbstractItemModel* model = qobject_cast<QAbstractItemModel*>(sender());
88+ // find the corresponding category index
89+ for (auto iter = m_overriddenCategories.begin(); iter != m_overriddenCategories.end(); ++iter) {
90+ if (iter.value() == model) {
91+ for (int i = 0; i < rowCount(); i++) {
92+ auto id = data(index(i), RoleCategoryId).toString();
93+ if (id != iter.key()) continue;
94+ QVector<int> roles;
95+ roles.append(RoleCount);
96+ QModelIndex changedIndex = index(i);
97+ Q_EMIT dataChanged(changedIndex, changedIndex, roles);
98+ break;
99+ }
100+ }
101+ }
102+}
103+
76void
104void
77Categories::onEmitCountChanged()
105Categories::onEmitCountChanged()
78{
106{
@@ -92,6 +120,41 @@ Categories::roleNames() const
92 return m_roles;
120 return m_roles;
93}
121}
94
122
123+void Categories::onOverrideModelDestroyed()
124+{
125+ QObject* model = sender();
126+ auto iter = m_overriddenCategories.begin();
127+ while (iter != m_overriddenCategories.end()) {
128+ if (iter.value() == model) {
129+ iter = m_overriddenCategories.erase(iter);
130+ continue;
131+ }
132+ ++iter;
133+ }
134+}
135+
136+void Categories::overrideResults(const QString& categoryId, QAbstractItemModel* model)
137+{
138+ m_overriddenCategories[categoryId] = model;
139+ // watch the model
140+ connect(model, &QObject::destroyed, this, &Categories::onOverrideModelDestroyed);
141+ connect(model, &QAbstractItemModel::rowsInserted, this, &Categories::onRowCountChanged);
142+ connect(model, &QAbstractItemModel::rowsRemoved, this, &Categories::onRowCountChanged);
143+ connect(model, &QAbstractItemModel::modelReset, this, &Categories::onRowCountChanged);
144+
145+ // emit the dataChanged signal if the category is already in the model
146+ for (int i = 0; i < rowCount(); i++) {
147+ auto id = data(index(i), RoleCategoryId).toString();
148+ if (id != categoryId) continue;
149+ QVector<int> roles;
150+ roles.append(RoleCount);
151+ roles.append(RoleResults);
152+ QModelIndex changedIndex = index(i);
153+ Q_EMIT dataChanged(changedIndex, changedIndex, roles);
154+ break;
155+ }
156+}
157+
95void Categories::setResultModel(DeeModel* model)
158void Categories::setResultModel(DeeModel* model)
96{
159{
97 // FIXME: should ref it
160 // FIXME: should ref it
@@ -153,24 +216,36 @@ Categories::data(const QModelIndex& index, int role) const
153 }
216 }
154
217
155 switch (role) {
218 switch (role) {
156− case RoleId:
219+ case RoleCategoryId:
157− return DeeListModel::data(index, 0); //ID
220+ return DeeListModel::data(index, CategoryColumn::ID);
158 case RoleName:
221 case RoleName:
159− return DeeListModel::data(index, 1); //DISPLAY_NAME
222+ return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
160 case RoleIcon:
223 case RoleIcon:
161− return DeeListModel::data(index, 2); //ICON_HINT
224+ return DeeListModel::data(index, CategoryColumn::ICON_HINT);
162 case RoleRenderer:
225 case RoleRenderer:
163− return DeeListModel::data(index, 3); //RENDERER_NAME
226+ return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
164 case RoleContentType:
227 case RoleContentType:
165 {
228 {
166− auto hints = DeeListModel::data(index, 4).toHash();
229+ auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
167− return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
230+ return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
168 }
231 }
169 case RoleHints:
232 case RoleHints:
170− return DeeListModel::data(index, 4); //HINTS
233+ return DeeListModel::data(index, CategoryColumn::HINTS);
171 case RoleResults:
234 case RoleResults:
235+ if (m_overriddenCategories.size() > 0)
236+ {
237+ auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
238+ if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
239+ return QVariant::fromValue(m_overriddenCategories[id]);
240+ }
172 return QVariant::fromValue(getFilter(index.row()));
241 return QVariant::fromValue(getFilter(index.row()));
173 case RoleCount:
242 case RoleCount:
243+ if (m_overriddenCategories.size() > 0)
244+ {
245+ auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
246+ if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
247+ return QVariant::fromValue(m_overriddenCategories[id]->rowCount());
248+ }
174 return QVariant::fromValue(getFilter(index.row())->rowCount());
249 return QVariant::fromValue(getFilter(index.row())->rowCount());
175 default:
250 default:
176 return QVariant();
251 return QVariant();
tests/mocks/Unity/fake_categories.h+6−1
@@ -34,7 +34,7 @@ class Categories : public DeeListModel
34public:
34public:
35 Categories(QObject* parent = 0);
35 Categories(QObject* parent = 0);
36 enum Roles {
36 enum Roles {
37− RoleId,
37+ RoleCategoryId,
38 RoleName,
38 RoleName,
39 RoleIcon,
39 RoleIcon,
40 RoleRenderer,
40 RoleRenderer,
@@ -44,6 +44,8 @@ public:
44 RoleCount
44 RoleCount
45 };
45 };
46
46
47+ Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
48+
47 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
49 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
48
50
49 QHash<int, QByteArray> roleNames() const;
51 QHash<int, QByteArray> roleNames() const;
@@ -53,7 +55,9 @@ public:
53
55
54private Q_SLOTS:
56private Q_SLOTS:
55 void onCountChanged();
57 void onCountChanged();
58+ void onRowCountChanged();
56 void onEmitCountChanged();
59 void onEmitCountChanged();
60+ void onOverrideModelDestroyed();
57
61
58private:
62private:
59 DeeModel* getResultsForCategory(unsigned index) const;
63 DeeModel* getResultsForCategory(unsigned index) const;
@@ -63,6 +67,7 @@ private:
63 QTimer m_timer;
67 QTimer m_timer;
64 QSet<DeeListModel*> m_timerFilters;
68 QSet<DeeListModel*> m_timerFilters;
65 QHash<int, QByteArray> m_roles;
69 QHash<int, QByteArray> m_roles;
70+ QMap<QString, QAbstractItemModel*> m_overriddenCategories;
66 mutable QMap<int, DeeListModel*> m_filters;
71 mutable QMap<int, DeeListModel*> m_filters;
67};
72};
68
73
tests/mocks/Unity/fake_preview.cppnew file+66
@@ -0,0 +1,66 @@
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 "fake_preview.h"
18+
19+QString Preview::rendererName() const
20+{
21+ return "foo";
22+}
23+
24+QString Preview::title() const
25+{
26+ return "Title";
27+}
28+
29+QString Preview::subtitle() const
30+{
31+ return "Subtitle";
32+}
33+
34+QString Preview::description() const
35+{
36+ return "Description";
37+}
38+
39+QVariant Preview::actions()
40+{
41+ return QVariant();
42+}
43+
44+QVariant Preview::infoHints()
45+{
46+ return QVariant();
47+}
48+
49+QVariantMap Preview::infoHintsHash() const
50+{
51+ return QVariantMap();
52+}
53+
54+QString Preview::image() const
55+{
56+ return "";
57+}
58+
59+QString Preview::imageSourceUri() const
60+{
61+ return "";
62+}
63+
64+void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& hints)
65+{
66+}
tests/mocks/Unity/fake_preview.hnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef FAKE_PREVIEW_H
18+#define FAKE_PREVIEW_H
19+
20+// Qt
21+#include <QObject>
22+#include <QString>
23+#include <QMetaType>
24+#include <QList>
25+#include <QVariantMap>
26+
27+class Q_DECL_EXPORT Preview : public QObject
28+{
29+ Q_OBJECT
30+
31+ Q_PROPERTY(QString rendererName READ rendererName NOTIFY previewChanged)
32+ Q_PROPERTY(QString title READ title NOTIFY previewChanged)
33+ Q_PROPERTY(QString subtitle READ subtitle NOTIFY previewChanged)
34+ Q_PROPERTY(QString description READ description NOTIFY previewChanged)
35+ Q_PROPERTY(QVariant actions READ actions NOTIFY previewChanged)
36+ Q_PROPERTY(QVariant infoHints READ infoHints NOTIFY previewChanged)
37+ Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
38+ Q_PROPERTY(QString image READ image NOTIFY previewChanged)
39+ Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
40+
41+public:
42+ explicit Preview(QObject *parent = 0);
43+
44+ QString rendererName() const;
45+ QString title() const;
46+ QString subtitle() const;
47+ QString description() const;
48+ QVariant actions();
49+ QVariant infoHints();
50+ QVariantMap infoHintsHash() const;
51+ QString image() const;
52+ QString imageSourceUri() const;
53+
54+ Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
55+
56+Q_SIGNALS:
57+ void previewChanged();
58+};
59+
60+Q_DECLARE_METATYPE(Preview *)
61+
62+#endif // FAKE_PREVIEW_H
tests/mocks/Unity/fake_scope.cpp+33−9
@@ -20,6 +20,8 @@
20#include <dee.h>
20#include <dee.h>
21#include "paths.h"
21#include "paths.h"
22
22
23+#include "fake_preview.h"
24+
23static DeeModel* create_categories_model(unsigned category_count);
25static DeeModel* create_categories_model(unsigned category_count);
24static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
26static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
25
27
@@ -127,6 +129,36 @@ void Scope::setNoResultsHint(const QString& str) {
127 }
129 }
128}
130}
129
131
132+void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
133+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
134+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
135+{
136+ Q_UNUSED(uri);
137+ Q_UNUSED(icon_hint);
138+ Q_UNUSED(category);
139+ Q_UNUSED(result_type);
140+ Q_UNUSED(mimetype);
141+ Q_UNUSED(title);
142+ Q_UNUSED(comment);
143+ Q_UNUSED(dnd_uri);
144+ Q_UNUSED(metadata);
145+}
146+
147+void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
148+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
149+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
150+{
151+ Q_UNUSED(uri);
152+ Q_UNUSED(icon_hint);
153+ Q_UNUSED(category);
154+ Q_UNUSED(result_type);
155+ Q_UNUSED(mimetype);
156+ Q_UNUSED(title);
157+ Q_UNUSED(comment);
158+ Q_UNUSED(dnd_uri);
159+ Q_UNUSED(metadata);
160+}
161+
130static const gchar * categories_model_schema[] = {
162static const gchar * categories_model_schema[] = {
131 "s", //ID
163 "s", //ID
132 "s", // DISPLAY_NAME
164 "s", // DISPLAY_NAME
@@ -168,14 +200,6 @@ static const gchar * results_model_schema[] = {
168 "a{sv}" // METADATA
200 "a{sv}" // METADATA
169};
201};
170
202
171−static const gchar * icons[] = {
172− "Applications.png",
173− "Home.png",
174− "Music.png",
175− "People.png",
176− "Videos.png",
177−};
178−
179DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
203DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
180 DeeModel* results_model = dee_sequence_model_new();
204 DeeModel* results_model = dee_sequence_model_new();
181 dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
205 dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
@@ -187,7 +211,7 @@ DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
187
211
188 dee_model_append(results_model,
212 dee_model_append(results_model,
189 ("uri://result."+std::to_string(i)).c_str(),
213 ("uri://result."+std::to_string(i)).c_str(),
190− (shellAppDirectory() + "Dash/graphics/scopeIcons/" + (icons[i%G_N_ELEMENTS(icons)])).toLatin1().data(),
214+ (shellAppDirectory() + "graphics/applicationIcons/dash.png").toLatin1().data(),
191 category,
215 category,
192 0,
216 0,
193 "application/x-desktop",
217 "application/x-desktop",
tests/mocks/Unity/fake_scope.h+15−1
@@ -21,6 +21,8 @@
21#include <QObject>
21#include <QObject>
22#include "fake_categories.h"
22#include "fake_categories.h"
23
23
24+class Preview;
25+
24class Scope : public QObject
26class Scope : public QObject
25{
27{
26 Q_OBJECT
28 Q_OBJECT
@@ -63,6 +65,13 @@ public:
63 void setNoResultsHint(const QString& hint);
65 void setNoResultsHint(const QString& hint);
64 void setFormFactor(const QString& form_factor);
66 void setFormFactor(const QString& form_factor);
65
67
68+ Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
69+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
70+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
71+ Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
72+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
73+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
74+
66Q_SIGNALS:
75Q_SIGNALS:
67 void idChanged(const QString&);
76 void idChanged(const QString&);
68 void nameChanged(const QString&);
77 void nameChanged(const QString&);
@@ -78,7 +87,12 @@ Q_SIGNALS:
78 void noResultsHintChanged();
87 void noResultsHintChanged();
79 void formFactorChanged();
88 void formFactorChanged();
80
89
81−private:
90+ // signals triggered by activate(..) or preview(..) requests.
91+ void previewReady(Preview *preview);
92+ void activateApplication(const QString &desktop);
93+
94+protected:
95+
82 QString m_id;
96 QString m_id;
83 QString m_iconHint;
97 QString m_iconHint;
84 QString m_description;
98 QString m_description;
tests/mocks/Unity/fake_scopes.cpp+4−1
@@ -19,6 +19,9 @@
19// Self
19// Self
20#include "fake_scopes.h"
20#include "fake_scopes.h"
21
21
22+// Local
23+#include "fake_applications_scope.h"
24+
22// TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
25// TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
23
26
24// Qt
27// Qt
@@ -53,7 +56,7 @@ void Scopes::updateScopes()
53 addScope(new Scope("MockScope1", "People", true, this));
56 addScope(new Scope("MockScope1", "People", true, this));
54 addScope(new Scope("MockScope2", "Music", false, this));
57 addScope(new Scope("MockScope2", "Music", false, this));
55 addScope(new Scope("home.scope", "Home", true, this));
58 addScope(new Scope("home.scope", "Home", true, this));
56− addScope(new Scope("applications.scope", "Applications", true, this));
59+ addScope(new ApplicationsScope(true, this));
57 addScope(new Scope("MockScope5", "Videos", true, this));
60 addScope(new Scope("MockScope5", "Videos", true, this));
58
61
59 if (!m_loaded) {
62 if (!m_loaded) {
tests/plugins/AccountsService/CMakeLists.txt+1
@@ -25,6 +25,7 @@ qt5_use_modules(mock-server Core DBus)
25
25
26add_executable(test-accountsservice
26add_executable(test-accountsservice
27 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
27 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
28+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
28 client.cpp
29 client.cpp
29 )
30 )
30qt5_use_modules(test-accountsservice Core DBus Test)
31qt5_use_modules(test-accountsservice Core DBus Test)
tests/plugins/AccountsService/client.cpp+19−7
@@ -18,6 +18,7 @@
18 */
18 */
19
19
20#include "AccountsService.h"
20#include "AccountsService.h"
21+#include "AccountsServiceDBusAdaptor.h"
21#include <QSignalSpy>
22#include <QSignalSpy>
22#include <QTest>
23#include <QTest>
23
24
@@ -30,17 +31,28 @@ private Q_SLOTS:
30 void testInvalids()
31 void testInvalids()
31 {
32 {
32 // Test various invalid calls
33 // Test various invalid calls
33− AccountsService session;
34+ AccountsServiceDBusAdaptor session;
34− QCOMPARE(session.getUserProperty("NOPE", "demo-edges"), QVariant());
35+ QCOMPARE(session.getUserProperty("NOPE", "com.canonical.unity.AccountsService", "demo-edges"), QVariant());
35− QCOMPARE(session.getUserProperty("testuser", "NOPE"), QVariant());
36+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "NOPE"), QVariant());
37+ }
38+
39+ void testGetSetServiceDBusAdaptor()
40+ {
41+ AccountsServiceDBusAdaptor session;
42+ session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(true));
43+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(true));
44+ session.setUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges", QVariant(false));
45+ QCOMPARE(session.getUserProperty("testuser", "com.canonical.unity.AccountsService", "demo-edges"), QVariant(false));
36 }
46 }
37
47
38− void testGetSet()
48+ void testGetSetService()
39 {
49 {
40 AccountsService session;
50 AccountsService session;
41− QCOMPARE(session.getUserProperty("testuser", "demo-edges"), QVariant(true));
51+ session.setUser("testuser");
42− session.setUserProperty("testuser", "demo-edges", QVariant(false));
52+ session.setDemoEdges(true);
53+ QCOMPARE(session.getDemoEdges(), true);
54+ session.setDemoEdges(false);
43− QCOMPARE(session.getUserProperty("testuser", "demo-edges"), QVariant(false));
55+ QCOMPARE(session.getDemoEdges(), false);
44 }
56 }
45};
57};
46
58
tests/plugins/Unity/CMakeLists.txt+4
@@ -5,6 +5,7 @@ pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
5pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
5pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
6pkg_check_modules(LIBUNITY REQUIRED unity)
6pkg_check_modules(LIBUNITY REQUIRED unity)
7pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0)
7pkg_check_modules(LIBSIGCPP REQUIRED sigc++-2.0)
8+pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2)
8
9
9include_directories(
10include_directories(
10 ${Unity-qml_SOURCE_DIR}
11 ${Unity-qml_SOURCE_DIR}
@@ -14,6 +15,7 @@ include_directories(
14 ${LIBUNITY_INCLUDE_DIRS}
15 ${LIBUNITY_INCLUDE_DIRS}
15 ${LIBSIGCPP_INCLUDE_DIRS}
16 ${LIBSIGCPP_INCLUDE_DIRS}
16 ${UNITYCORE_INCLUDE_DIRS}
17 ${UNITYCORE_INCLUDE_DIRS}
18+ ${QTDEE_INCLUDE_DIRS}
17 )
19 )
18
20
19macro(run_tests)
21macro(run_tests)
@@ -36,6 +38,7 @@ macro(run_tests)
36 ${LIBUNITY_LDFLAGS}
38 ${LIBUNITY_LDFLAGS}
37 ${LIBUNITYPROTO_LDFLAGS}
39 ${LIBUNITYPROTO_LDFLAGS}
38 ${LIBSIGCPP_LDFLAGS}
40 ${LIBSIGCPP_LDFLAGS}
41+ ${QTDEE_LDFLAGS}
39 )
42 )
40
43
41 set(_test_list "${_test_list};${_test}")
44 set(_test_list "${_test_list};${_test}")
@@ -46,4 +49,5 @@ run_tests(
46 signalslisttest
49 signalslisttest
47 previewbindingstest
50 previewbindingstest
48 filtersbindingstest
51 filtersbindingstest
52+ resultstest
49 )
53 )
tests/plugins/Unity/Launcher/CMakeLists.txt+37−4
@@ -1,4 +1,5 @@
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
1pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=2)
2
3
3include_directories(
4include_directories(
4 ${CMAKE_CURRENT_BINARY_DIR}
5 ${CMAKE_CURRENT_BINARY_DIR}
@@ -10,17 +11,49 @@ include_directories(
10
11
11add_definitions(-DSM_BUSNAME=sessionBus)
12add_definitions(-DSM_BUSNAME=sessionBus)
12add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
13add_definitions(-DSRCDIR="${CMAKE_CURRENT_SOURCE_DIR}")
14+add_definitions(-DLAUNCHER_TESTING)
13
15
16+### LauncherBackendTest
14−set(testCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
17+set(testBackendCommand ${CMAKE_CURRENT_BINARY_DIR}/launcherbackendtestExec
15 -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
18 -o ${CMAKE_BINARY_DIR}/launcherbackendtest.xml,xunitxml
16 -o -,txt)
19 -o -,txt)
17−add_test(NAME launcherbackendtest COMMAND ${testCommand})
20+add_test(NAME launcherbackendtest COMMAND ${testBackendCommand})
18−add_custom_target(launcherbackendtest ${testCommand})
21+add_custom_target(launcherbackendtest ${testBackendCommand})
19add_executable(launcherbackendtestExec
22add_executable(launcherbackendtestExec
20 launcherbackendtest.cpp
23 launcherbackendtest.cpp
21− ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsService.cpp
24+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
22 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
25 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
23 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
26 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
24 )
27 )
25target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
28target_link_libraries(launcherbackendtestExec ${GSETTINGS_QT_LDFLAGS})
26qt5_use_modules(launcherbackendtestExec Test Core DBus)
29qt5_use_modules(launcherbackendtestExec Test Core DBus)
30+
31+### LauncherModelTest
32+set(testModelCommand ${CMAKE_CURRENT_BINARY_DIR}/launchermodeltestExec
33+ -o ${CMAKE_BINARY_DIR}/launchermodeltest.xml,xunitxml
34+ -o -,txt)
35+add_test(NAME launchermodeltest COMMAND ${testModelCommand})
36+add_custom_target(launchermodeltest ${testModelCommand})
37+add_executable(launchermodeltestExec
38+ launchermodeltest.cpp
39+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launchermodel.cpp
40+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/launcheritem.cpp
41+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
42+ ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
43+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/backend/launcherbackend.cpp
44+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/common/quicklistentry.cpp
45+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
46+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
47+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
48+ )
49+target_link_libraries(launchermodeltestExec ${GSETTINGS_QT_LDFLAGS} )
50+qt5_use_modules(launchermodeltestExec Test Core DBus)
51+
52+# copy .desktop files into build directory for shadow builds
53+file(GLOB DESKTOP_FILES *.desktop)
54+
55+foreach(DESKTOP_FILE ${DESKTOP_FILES})
56+ file(COPY "${DESKTOP_FILE}"
57+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
58+ )
59+endforeach()
tests/plugins/Unity/Launcher/launcherbackendtest.cpp+14−15
@@ -20,7 +20,6 @@
20#include "launcherbackend.h"
20#include "launcherbackend.h"
21
21
22#include <QtTest>
22#include <QtTest>
23−#include <QDebug>
24
23
25class LauncherBackendTest : public QObject
24class LauncherBackendTest : public QObject
26{
25{
@@ -31,29 +30,29 @@ private Q_SLOTS:
31 {
30 {
32 LauncherBackend backend(false);
31 LauncherBackend backend(false);
33
32
34− backend.setStoredApplications(QStringList() << "relative.path" << "/full/path");
33+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "invalid");
35− QCOMPARE(backend.storedApplications(), QStringList() << "relative.path" << "/full/path");
34+ QCOMPARE(backend.storedApplications(), QStringList() << "rel-icon" << "abs-icon");
36 }
35 }
37
36
38 void testPinning()
37 void testPinning()
39 {
38 {
40 LauncherBackend backend(false);
39 LauncherBackend backend(false);
41
40
42− backend.setStoredApplications(QStringList() << "one" << "two");
41+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
43− QCOMPARE(backend.isPinned("one"), false);
42+ QCOMPARE(backend.isPinned("rel-icon"), false);
44− QCOMPARE(backend.isPinned("two"), false);
43+ QCOMPARE(backend.isPinned("abs-icon"), false);
45
44
46− backend.setPinned("two", true);
45+ backend.setPinned("rel-icon", true);
47− QCOMPARE(backend.isPinned("two"), true);
46+ QCOMPARE(backend.isPinned("rel-icon"), true);
48
47
49− backend.setStoredApplications(QStringList() << "one" << "two" << "three");
48+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon" << "no-name");
50− QCOMPARE(backend.isPinned("two"), true);
49+ QCOMPARE(backend.isPinned("rel-icon"), true);
51− QCOMPARE(backend.isPinned("three"), false);
50+ QCOMPARE(backend.isPinned("no-name"), false);
52
51
53− backend.setPinned("three", true);
52+ backend.setPinned("no-name", true);
54− backend.setStoredApplications(QStringList() << "one" << "two");
53+ backend.setStoredApplications(QStringList() << "rel-icon" << "abs-icon");
55− QCOMPARE(backend.isPinned("two"), true);
54+ QCOMPARE(backend.isPinned("rel-icon"), true);
56− QCOMPARE(backend.isPinned("three"), false); // doesn't exist anymore!
55+ QCOMPARE(backend.isPinned("no-name"), false); // doesn't exist anymore!
57 }
56 }
58};
57};
59
58
tests/plugins/Unity/Launcher/launchermodeltest.cppnew file+146
@@ -0,0 +1,146 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Michael Zanetti <michael.zanetti@canonical.com>
18+ */
19+
20+// unity-api
21+#include <unity/shell/launcher/LauncherModelInterface.h>
22+
23+#include "launcheritem.h"
24+#include "launchermodel.h"
25+
26+#include <QtTest>
27+
28+class LauncherModelTest : public QObject
29+{
30+ Q_OBJECT
31+
32+private:
33+ LauncherModel *launcherModel;
34+
35+private Q_SLOTS:
36+
37+ void initTestCase() {
38+ launcherModel = new LauncherModel(this);
39+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 0);
40+ }
41+
42+ void init() {
43+ qDebug() << "init";
44+ launcherModel->applicationFocused("abs-icon");
45+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
46+
47+ launcherModel->applicationFocused("no-icon.desktop");
48+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
49+
50+ launcherModel->applicationFocused(QString());
51+ }
52+
53+ void cleanup() {
54+ while (launcherModel->rowCount(QModelIndex()) > 0) {
55+ launcherModel->requestRemove(launcherModel->get(0)->appId());
56+ }
57+ }
58+
59+ void testMove() {
60+ QCOMPARE(launcherModel->get(0)->pinned(), false);
61+ QCOMPARE(launcherModel->get(1)->pinned(), false);
62+
63+ LauncherItemInterface *item0BeforeMove = launcherModel->get(0);
64+ LauncherItemInterface *item1BeforeMove = launcherModel->get(1);
65+ launcherModel->move(1, 0);
66+
67+ QCOMPARE(item0BeforeMove, launcherModel->get(1));
68+ QCOMPARE(item1BeforeMove, launcherModel->get(0));
69+
70+ // moved item must be pinned now
71+ QCOMPARE(item0BeforeMove->pinned(), false);
72+ QCOMPARE(item1BeforeMove->pinned(), true);
73+ }
74+
75+ void testPinning() {
76+ QCOMPARE(launcherModel->get(0)->pinned(), false);
77+ QCOMPARE(launcherModel->get(1)->pinned(), false);
78+ launcherModel->pin(launcherModel->get(0)->appId());
79+ QCOMPARE(launcherModel->get(0)->pinned(), true);
80+ QCOMPARE(launcherModel->get(1)->pinned(), false);
81+ }
82+
83+ void testRemove() {
84+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
85+ launcherModel->requestRemove(launcherModel->get(0)->appId());
86+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
87+ }
88+
89+ void testQuickListPinningRemoving() {
90+ // we start with 2 unpinned items
91+ QCOMPARE(launcherModel->get(0)->pinned(), false);
92+ QCOMPARE(launcherModel->get(1)->pinned(), false);
93+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
94+
95+ // find the Pin item in the quicklist
96+ QuickListModel *model = qobject_cast<QuickListModel*>(launcherModel->get(0)->quickList());
97+ int pinActionIndex = -1;
98+ for (int i = 0; i < model->rowCount(QModelIndex()); ++i) {
99+ if (model->get(i).actionId() == "pin_item") {
100+ pinActionIndex = i;
101+ break;
102+ }
103+ }
104+ QVERIFY(pinActionIndex >= 0);
105+
106+ // trigger pin item quicklist action => Item must be pinned now.
107+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
108+ QCOMPARE(launcherModel->get(0)->pinned(), true);
109+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
110+
111+ // quicklist needs to transform to remove item. trigger it and check it item goes away
112+ launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
113+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
114+ }
115+
116+ void testApplicationFocused() {
117+ // all apps unfocused at beginning...
118+ QCOMPARE(launcherModel->get(0)->focused(), false);
119+ QCOMPARE(launcherModel->get(1)->focused(), false);
120+
121+ launcherModel->applicationFocused("abs-icon");
122+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
123+ QCOMPARE(launcherModel->get(0)->focused(), true);
124+ QCOMPARE(launcherModel->get(1)->focused(), false);
125+
126+ launcherModel->applicationFocused("no-icon");
127+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
128+ QCOMPARE(launcherModel->get(0)->focused(), false);
129+ QCOMPARE(launcherModel->get(1)->focused(), true);
130+
131+ launcherModel->applicationFocused("rel-icon");
132+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
133+ QCOMPARE(launcherModel->get(0)->focused(), false);
134+ QCOMPARE(launcherModel->get(1)->focused(), false);
135+ QCOMPARE(launcherModel->get(2)->focused(), true);
136+
137+ launcherModel->applicationFocused(QString());
138+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 3);
139+ QCOMPARE(launcherModel->get(0)->focused(), false);
140+ QCOMPARE(launcherModel->get(1)->focused(), false);
141+ QCOMPARE(launcherModel->get(2)->focused(), false);
142+ }
143+};
144+
145+QTEST_GUILESS_MAIN(LauncherModelTest)
146+#include "launchermodeltest.moc"
tests/plugins/Unity/resultstest.cppnew file+104
@@ -0,0 +1,104 @@
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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#include <QTest>
21+#include <dee.h>
22+
23+#include "resultstest.h"
24+#include "categoryresults.h"
25+
26+static DeeModel* createBackendModel()
27+{
28+ auto model = dee_sequence_model_new();
29+ dee_model_set_schema(model, "s", "s", "u", "u", "s", "s", "s", "s", "a{sv}", NULL);
30+
31+ return model;
32+}
33+
34+void ResultsTest::testAllColumns()
35+{
36+ auto deeModel = createBackendModel();
37+ GVariantBuilder builder;
38+ g_variant_builder_init(&builder, G_VARIANT_TYPE_VARDICT);
39+ g_variant_builder_add(&builder, "{sv}", "metadata-field", g_variant_new_string("foo"));
40+ dee_model_append (deeModel,
41+ "test:uri",
42+ "themed-icon",
43+ 4,
44+ 0,
45+ "application/octet-stream",
46+ "Test",
47+ "Comment",
48+ "test:dnd-uri",
49+ g_variant_builder_end(&builder));
50+
51+ CategoryResults* results = new CategoryResults(this);
52+ results->setModel(deeModel);
53+
54+ auto index = results->index(0, 0); // there's just one result
55+ QCOMPARE(index.data(CategoryResults::Roles::RoleUri).toString(), QString("test:uri"));
56+ QCOMPARE(index.data(CategoryResults::Roles::RoleIconHint).toString(), QString("image://theme/themed-icon"));
57+ QCOMPARE(index.data(CategoryResults::Roles::RoleCategory).toInt(), 4);
58+ QCOMPARE(index.data(CategoryResults::Roles::RoleMimetype).toString(), QString("application/octet-stream"));
59+ QCOMPARE(index.data(CategoryResults::Roles::RoleTitle).toString(), QString("Test"));
60+ QCOMPARE(index.data(CategoryResults::Roles::RoleComment).toString(), QString("Comment"));
61+ QCOMPARE(index.data(CategoryResults::Roles::RoleDndUri).toString(), QString("test:dnd-uri"));
62+ auto metadata = index.data(CategoryResults::Roles::RoleMetadata).toHash();
63+ QCOMPARE(metadata["metadata-field"].toString(), QString("foo"));
64+}
65+
66+void ResultsTest::testIconColumn_data()
67+{
68+ QTest::addColumn<QString>("giconString");
69+ QTest::addColumn<QString>("result");
70+
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";
73+ QTest::newRow("http uri") << "http://images.ubuntu.com/example.jpg" << "http://images.ubuntu.com/example.jpg";
74+ 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("themedicon") << ". GThemedIcon accessories-other accessories generic" << "image://theme/accessories-other,accessories,generic";
77+ QTest::newRow("annotatedicon") << ". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'.%20GThemedIcon%20accessories-other%20accessories%20generic'%3E%7D" << "image://theme/accessories-other,accessories,generic";
78+}
79+
80+void ResultsTest::testIconColumn()
81+{
82+ QFETCH(QString, giconString);
83+ QFETCH(QString, result);
84+ auto deeModel = createBackendModel();
85+ dee_model_append (deeModel,
86+ "test:uri",
87+ giconString.toLocal8Bit().constData(),
88+ 0,
89+ 0,
90+ "application/octet-stream",
91+ "Test",
92+ "",
93+ "test:dnd-uri",
94+ g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0));
95+
96+ CategoryResults* results = new CategoryResults(this);
97+ results->setModel(deeModel);
98+
99+ auto index = results->index(0, 0); // there's just one result
100+ auto transformedIcon = index.data(CategoryResults::Roles::RoleIconHint).toString();
101+ QCOMPARE(transformedIcon, result);
102+}
103+
104+QTEST_MAIN(ResultsTest)
tests/plugins/Unity/resultstest.hnew 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:
17+ * Michal Hruby <michal.hruby@canonical.com>
18+ */
19+
20+#ifndef RESULTSTEST_H
21+#define RESULTSTEST_H
22+
23+#include <QObject>
24+
25+class ResultsTest : public QObject
26+{
27+ Q_OBJECT
28+
29+ private Q_SLOTS:
30+ void testAllColumns();
31+ void testIconColumn_data();
32+ void testIconColumn();
33+};
34+
35+#endif
tests/qmltests/CMakeLists.txt+1−2
@@ -14,7 +14,6 @@ set(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)
16add_qml_test(Components CrossFadeImage)
16add_qml_test(Components CrossFadeImage)
17−add_qml_test(Components IconUtil)
18add_qml_test(Components MathLocal)
17add_qml_test(Components MathLocal)
19add_qml_test(Components OpenEffect)
18add_qml_test(Components OpenEffect)
20add_qml_test(Components RatingStars)
19add_qml_test(Components RatingStars)
@@ -67,7 +66,7 @@ add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltes
67add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
66add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
68add_qml_test(Panel IndicatorRow)
67add_qml_test(Panel IndicatorRow)
69add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
68add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
70−add_qml_test(Panel MenuContent)
69+add_qml_test(Panel MenuContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
71add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
70add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
72add_qml_test(Panel SearchIndicator)
71add_qml_test(Panel SearchIndicator)
73add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
72add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
tests/qmltests/Components/tst_IconUtil.qmldeleted−38
@@ -1,38 +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/IconUtil.js" as IconUtil
20−
21−TestCase {
22− id: root
23− name: "IconUtil"
24−
25− function test_from_gicon_data() {
26− return [ {in: ". GThemedIcon one", out: "image://theme/one"},
27− {in: ". GThemedIcon one two", out: "image://theme/one,two"},
28− {in: ". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'.%20GThemedIcon%20one%20two'%3E%7D", out: "image://theme/one,two"},
29− {in: "icon.test_0-name", out: "image://theme/icon.test_0-name"},
30− {in: "?^713]p", out: "?^713]p"},
31− ]
32− }
33−
34− function test_from_gicon(data) {
35− var out = IconUtil.from_gicon(data.in)
36− compare(out, data.out)
37− }
38−}
tests/qmltests/Launcher/tst_Launcher.qml+8
@@ -198,6 +198,14 @@ Item {
198 compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
198 compare(findChild(delegate, "progressOverlay").visible, LauncherModel.get(i).progress >= 0)
199 }
199 }
200 }
200 }
201+
202+ function test_focusedHighlight() {
203+ var launcherListView = findChild(launcher, "launcherListView");
204+ for (var i = 0; i < launcherListView.count; ++i) {
205+ var delegate = findChild(launcherListView, "launcherDelegate" + i)
206+ compare(findChild(delegate, "focusedHighlight").visible, LauncherModel.get(i).focused)
207+ }
208+ }
201 }
209 }
202
210
203 UT.UnityTestCase {
211 UT.UnityTestCase {
tests/qmltests/Panel/tst_IndicatorItem.qml+2−2
@@ -53,9 +53,9 @@ Rectangle {
53 }
53 }
54
54
55 function test_empty() {
55 function test_empty() {
56− compare(indicatorItem.visible, false, "IndicatorItem should not be visible.");
56+ compare(indicatorItem.indicatorVisible, false, "IndicatorItem should not be visible.");
57 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
57 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
58− tryCompare(indicatorItem, "visible", true);
58+ tryCompare(indicatorItem, "indicatorVisible", true);
59 }
59 }
60 }
60 }
61}
61}
tests/qmltests/Panel/tst_Indicators.qml+30−11
@@ -100,26 +100,29 @@ Item {
100 {
100 {
101 // tests changing the lateral position of the revealer activates the correct indicator items.
101 // tests changing the lateral position of the revealer activates the correct indicator items.
102
102
103− var indicator_row = findChild(indicators, "indicatorRow")
103+ var indicatorRow = findChild(indicators, "indicatorRow")
104− var row_repeater = findChild(indicators, "rowRepeater")
104+ var rowRepeater = findChild(indicators, "rowRepeater")
105
105
106− for (var i = 0; i < row_repeater.count; i++) {
106+ for (var i = 0; i < rowRepeater.count; i++) {
107− var indicator_item = row_repeater.itemAt(i);
107+ var indicatorItem = rowRepeater.itemAt(i);
108
108
109+ if (!indicatorItem.visible)
110+ continue;
111+
109− var indicator_position = indicators.mapFromItem(indicator_item,
112+ var indicatorPosition = indicators.mapFromItem(indicatorItem,
110− indicator_item.width/2, indicator_item.height/2)
113+ indicatorItem.width/2, indicatorItem.height/2)
111
114
112 touchFlick(indicators,
115 touchFlick(indicators,
113− indicator_position.x, indicator_position.y,
116+ indicatorPosition.x, indicatorPosition.y,
114− indicator_position.x, indicators.openedHeight * 0.4,
117+ indicatorPosition.x, indicators.openedHeight * 0.4,
115 true /* beginTouch */, false /* endTouch */)
118 true /* beginTouch */, false /* endTouch */)
116
119
117− compare(indicator_row.currentItem, indicator_item,
120+ compare(indicatorRow.currentItem, indicatorItem,
118 "Incorrect item activated at position " + i);
121 "Incorrect item activated at position " + i);
119
122
120 touchFlick(indicators,
123 touchFlick(indicators,
121− indicator_position.x, indicators.openedHeight * 0.4,
124+ indicatorPosition.x, indicators.openedHeight * 0.4,
122− indicator_position.x, indicator_position.y,
125+ indicatorPosition.x, indicatorPosition.y,
123 false /* beginTouch */, true /* endTouch */)
126 false /* beginTouch */, true /* endTouch */)
124
127
125 // wait until fully closed
128 // wait until fully closed
@@ -158,5 +161,21 @@ Item {
158 compare(indicators.fullyOpened, true);
161 compare(indicators.fullyOpened, true);
159 }
162 }
160
163
164+ function test_row_visible_menuContent_visible_data() { return [
165+ {tag: "visible", index: 0, name: "indicator-fake1", visible: true },
166+ {tag: "invisible", index: 1, name: "indicator-fake2", visible: false }]
167+ }
168+
169+ function test_row_visible_menuContent_visible(data) {
170+ var indicatorTabs = findChild(indicators, "tabs");
171+ var rowRepeater = findChild(indicators, "rowRepeater");
172+
173+ var indicatorItem = rowRepeater.itemAt(data.index);
174+ tryCompareFunction(function() { return indicatorItem.width > 0}, true);
175+ tryCompare(indicatorItem, "visible", data.visible);
176+
177+ var indicatorTab = findChild(indicatorTabs, data.name)
178+ tryCompareFunction(function() { return indicatorTab !== undefined }, data.visible);
179+ }
161 }
180 }
162}
181}
tests/qmltests/Panel/tst_MenuContent.qml+9−2
@@ -48,8 +48,15 @@ Item {
48 id: menuContent
48 id: menuContent
49 indicatorsModel: indicatorsModel
49 indicatorsModel: indicatorsModel
50 contentReleaseInterval: 50
50 contentReleaseInterval: 50
51−
52 height: parent.height - 50
51 height: parent.height - 50
52+
53+ visibleIndicators: {
54+ 'indicator-fake1': true,
55+ 'indicator-fake2': true,
56+ 'indicator-fake3': true,
57+ 'indicator-fake4': true,
58+ 'indicator-fake5': true
59+ }
53 }
60 }
54
61
55 Rectangle {
62 Rectangle {
@@ -134,7 +141,7 @@ Item {
134 var menuIndex = i%menuCount;
141 var menuIndex = i%menuCount;
135
142
136 activate_content(menuIndex);
143 activate_content(menuIndex);
137− testTabObjectName = indicatorsModel.data(menuIndex, Indicators.IndicatorsModelRole.Identifier);
144+ testTabObjectName = indicatorsModel.get(menuIndex).identifier;
138 compare(tabs.selectedTabIndex, menuIndex, "Current tab index does not match selected tab index");
145 compare(tabs.selectedTabIndex, menuIndex, "Current tab index does not match selected tab index");
139 tryCompareFunction(selected_tab_equals_test_tab, true);
146 tryCompareFunction(selected_tab_equals_test_tab, true);
140 }
147 }
tests/qmltests/Panel/tst_Panel.qml+3
@@ -159,6 +159,9 @@ Item {
159 var indicatorItem = get_indicator_item(i);
159 var indicatorItem = get_indicator_item(i);
160 verify(indicatorItem != undefined);
160 verify(indicatorItem != undefined);
161
161
162+ if (!indicatorItem.visible)
163+ continue;
164+
162 var indicatorItemCoord = get_indicator_item_position(i);
165 var indicatorItemCoord = get_indicator_item_position(i);
163
166
164 touchPress(panel,
167 touchPress(panel,