on xenial help sign in
Merge from trunk
commit3720cd3ba850de515d18657f12e4150d1e9e2f6a authorMichael Terry <michael.terry@canonical.com> dateSun 25 Aug 2013, 17:00 (13 years ago) parent1e92c4c148c58f
103 files changed+2249−511
Components/EdgeDemo.qml+228 Components/DemoOverlay.qml → Components/EdgeDemoOverlay.qml+57−45 Dash/Apps/FrequentlyUsedAppsModel.qml+1−1 Launcher/LauncherPanel.qml+43−6 Panel/Indicators/NetworkIndicatorPage2.qml+82 Panel/IndicatorsDataModel.qml+1−9 Shell.qml+25−135 build+5−2 debian/changelog+63 debian/control+2−1 debian/rules+5 plugins/AccountsService/AccountsService.cpp+8−4 plugins/AccountsService/AccountsService.h+6−7 plugins/AccountsService/CMakeLists.txt+1−3 plugins/AccountsService/plugin.cpp+1−1 plugins/AccountsService/plugin.h+2−2 plugins/Powerd/Powerd.cpp+2−2 plugins/Powerd/Powerd.h+15−1 plugins/Unity/Indicators/CMakeLists.txt+1 plugins/Unity/Indicators/Network/CMakeLists.txt+45 plugins/Unity/Indicators/Network/networkagent.cpp+146 plugins/Unity/Indicators/Network/networkagent.h+65 plugins/Unity/Indicators/Network/plugin.cpp+31 plugins/Unity/Indicators/Network/plugin.h+32 plugins/Unity/Indicators/Network/qml/AccessPoint.qml+62 plugins/Unity/Indicators/Network/qml/CMakeLists.txt+5 plugins/Unity/Indicators/Network/qml/PasswordPage.qml+88 plugins/Unity/Indicators/Network/qml/PasswordTextField.qml+68 plugins/Unity/Indicators/Network/qml/WifiSection.qml+28 plugins/Unity/Indicators/Network/qml/qmldir+9 plugins/Unity/Indicators/Network/secret-agent.c+382 plugins/Unity/Indicators/Network/secret-agent.h+102 plugins/Unity/Indicators/qml/MenuItemFactory.qml+21 plugins/Unity/IndicatorsLegacy/Network/CMakeLists.txt+8−8 plugins/Unity/IndicatorsLegacy/Network/qml/qmldir+1−1 plugins/Unity/Launcher/launchermodel.cpp+28 plugins/Unity/Launcher/launchermodel.h+4 plugins/Unity/categories.cpp+6 plugins/Unity/categories.h+1 plugins/Unity/genericoptionsmodel.cpp+2−2 plugins/Unity/genericoptionsmodel.h+1−1 plugins/Unity/plugin.cpp+2 plugins/Utils/qlimitproxymodelqml.cpp+90−4 plugins/Utils/qlimitproxymodelqml.h+2 po/ar.po+2−2 po/az.po+2−2 po/bg.po+2−2 po/ca.po+2−2 po/de.po+2−2 po/el.po+2−2 po/en_AU.po+2−2 po/en_GB.po+2−2 po/eo.po+2−2 po/es.po+2−2 po/fi.po+2−2 po/fo.po+2−2 po/fr.po+2−2 po/gl.po+2−2 po/he.po+2−2 po/hr.po+2−2 po/hu.po+2−2 po/hy.po+2−2 po/id.po+2−2 po/it.po+2−2 po/ja.po+2−2 po/kn.po+2−2 po/ko.po+2−2 po/ky.po+2−2 po/lv.po+2−2 po/my.po+2−2 po/nb.po+2−2 po/nl.po+2−2 po/pl.po+2−2 po/pt_BR.po+2−2 po/ro.po+2−2 po/ru.po+2−2 po/si.po+2−2 po/sl.po+2−2 po/sr.po+2−2 po/sv.po+2−2 po/te.po+2−2 po/tr.po+2−2 po/ug.po+2−2 po/uk.po+2−2 po/unity8.pot+55−43 po/zh_CN.po+2−2 po/zh_TW.po+2−2 src/Panel/Indicators/servicefiles/CMakeLists.txt−1 src/Panel/Indicators/servicefiles/com.canonical.settings.network−10 tests/mocks/Powerd/Powerd.h+15−2 tests/mocks/Unity/Launcher/MockLauncherModel.cpp+6 tests/mocks/Unity/Launcher/MockLauncherModel.h+1 tests/plugins/AccountsService/AccountsServer.h+4−4 tests/plugins/AccountsService/PropertiesServer.h+4−4 tests/plugins/AccountsService/client.cpp+2−2 tests/plugins/AccountsService/server.cpp+1−1 tests/plugins/Utils/qlimitproxymodeltest.cpp+133−8 tests/qmltests/CMakeLists.txt+1−1 tests/qmltests/Components/tst_DemoOverlay.qml−99 tests/qmltests/Components/tst_EdgeDemoOverlay.qml+125 tests/qmltests/Greeter/tst_Clock.qml+1−1 tests/qmltests/Launcher/tst_Launcher.qml+33−13 tests/qmltests/tst_Shell.qml+7−3
Components/EdgeDemo.qmlnew file+228
@@ -0,0 +1,228 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import AccountsService 0.1
18+import LightDM 0.1 as LightDM
19+import QtQuick 2.0
20+
21+Item {
22+ id: demo
23+
24+ property Item greeter
25+ property Item dash
26+ property Item launcher
27+ property Item indicators
28+ property Item overlay
29+
30+ property bool launcherEnabled: true
31+ property bool dashEnabled: true
32+ property bool panelEnabled: true
33+
34+ property bool paused: false
35+
36+ onPausedChanged: {
37+ if (d.rightEdgeDemo) d.rightEdgeDemo.paused = paused
38+ if (d.topEdgeDemo) d.topEdgeDemo.paused = paused
39+ if (d.bottomEdgeDemo) d.bottomEdgeDemo.paused = paused
40+ if (d.leftEdgeDemo) d.leftEdgeDemo.paused = paused
41+ if (d.finalEdgeDemo) d.finalEdgeDemo.paused = paused
42+ }
43+
44+ function hideEdgeDemoInShell() {
45+ var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
46+ AccountsService.setUserProperty(user, "demo-edges", false);
47+ d.showEdgeDemo = false;
48+ stopDemo();
49+ }
50+
51+ function hideEdgeDemoInGreeter() {
52+ // TODO: AccountsService.setUserProperty("lightdm", "demo-edges", false);
53+ d.showEdgeDemoInGreeter = false;
54+ }
55+
56+ function hideEdgeDemos() {
57+ hideEdgeDemoInGreeter();
58+ hideEdgeDemoInShell();
59+ }
60+
61+ function stopDemo() {
62+ launcherEnabled = true
63+ dashEnabled = true
64+ panelEnabled = true
65+ if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
66+ if (d.topEdgeDemo) d.topEdgeDemo.destroy()
67+ if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy()
68+ if (d.leftEdgeDemo) d.leftEdgeDemo.destroy()
69+ if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
70+ }
71+
72+ QtObject {
73+ id: d
74+ property Component overlay
75+ property QtObject rightEdgeDemo
76+ property QtObject topEdgeDemo
77+ property QtObject bottomEdgeDemo
78+ property QtObject leftEdgeDemo
79+ property QtObject finalEdgeDemo
80+ property bool showEdgeDemo: false
81+ property bool showEdgeDemoInGreeter: d.showEdgeDemo // TODO: AccountsService.getUserProperty("lightdm", "demo-edges")
82+
83+ onShowEdgeDemoInGreeterChanged: {
84+ if (!d.overlay && d.showEdgeDemoInGreeter) {
85+ d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
86+ startRightEdgeDemo()
87+ }
88+ }
89+ }
90+
91+ function startRightEdgeDemo() {
92+ launcherEnabled = false;
93+ demo.dashEnabled = false;
94+ demo.panelEnabled = false;
95+ if (demo.greeter) {
96+ d.rightEdgeDemo = d.overlay.createObject(demo.greeter, {
97+ "edge": "right",
98+ "title": i18n.tr("Right edge"),
99+ "text": i18n.tr("Try swiping from the right edge to unlock the phone"),
100+ "anchors.fill": demo.greeter,
101+ });
102+ }
103+ if (d.rightEdgeDemo) {
104+ d.rightEdgeDemo.onSkip.connect(demo.hideEdgeDemos)
105+ } else {
106+ stopDemo();
107+ }
108+ }
109+
110+ Connections {
111+ target: demo.greeter
112+
113+ function hide() {
114+ if (d.rightEdgeDemo && d.rightEdgeDemo.active) {
115+ d.rightEdgeDemo.hide()
116+ hideEdgeDemoInGreeter()
117+ startTopEdgeDemo()
118+ }
119+ }
120+
121+ onUnlocked: hide()
122+ onShownChanged: if (!greeter.shown) hide()
123+
124+ onSelected: {
125+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
126+ d.showEdgeDemo = AccountsService.getUserProperty(user, "demo-edges")
127+ }
128+ }
129+
130+ function startTopEdgeDemo() {
131+ demo.panelEnabled = true;
132+ if (demo.dash) {
133+ d.topEdgeDemo = d.overlay.createObject(demo.dash, {
134+ "edge": "top",
135+ "title": i18n.tr("Top edge"),
136+ "text": i18n.tr("Try swiping from the top edge to access the indicators"),
137+ "anchors.fill": demo.dash,
138+ });
139+ }
140+ if (d.topEdgeDemo) {
141+ d.topEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
142+ } else {
143+ stopDemo();
144+ }
145+ }
146+
147+ Connections {
148+ target: demo.indicators
149+ onFullyOpenedChanged: {
150+ if (d.topEdgeDemo && d.topEdgeDemo.active && demo.indicators.fullyOpened) {
151+ d.topEdgeDemo.hideNow()
152+ startBottomEdgeDemo()
153+ }
154+ }
155+ }
156+
157+ function startBottomEdgeDemo() {
158+ if (demo.indicators) {
159+ d.bottomEdgeDemo = d.overlay.createObject(demo.indicators, {
160+ "edge": "bottom",
161+ "title": i18n.tr("Close"),
162+ "text": i18n.tr("Swipe up again to close the settings screen"),
163+ "anchors.fill": demo.indicators,
164+ });
165+ }
166+ if (d.bottomEdgeDemo) {
167+ d.bottomEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
168+ } else {
169+ stopDemo();
170+ }
171+ }
172+
173+ Connections {
174+ target: demo.indicators
175+ onPartiallyOpenedChanged: {
176+ if (d.bottomEdgeDemo && d.bottomEdgeDemo.active && !demo.indicators.partiallyOpened && !demo.indicators.fullyOpened) {
177+ d.bottomEdgeDemo.hideNow()
178+ startLeftEdgeDemo()
179+ }
180+ }
181+ }
182+
183+ function startLeftEdgeDemo() {
184+ demo.panelEnabled = false;
185+ demo.launcherEnabled = true;
186+ if (demo.dash) {
187+ d.leftEdgeDemo = d.overlay.createObject(demo.dash, {
188+ "edge": "left",
189+ "title": i18n.tr("Left edge"),
190+ "text": i18n.tr("Swipe from the left to reveal the launcher for quick access to apps"),
191+ "anchors.fill": demo.dash,
192+ });
193+ }
194+ if (d.leftEdgeDemo) {
195+ d.leftEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
196+ } else {
197+ stopDemo();
198+ }
199+ }
200+
201+ Connections {
202+ target: demo.launcher
203+ onStateChanged: {
204+ if (d.leftEdgeDemo && d.leftEdgeDemo.active && launcher.state == "visible") {
205+ d.leftEdgeDemo.hide()
206+ launcher.hide()
207+ startFinalEdgeDemo()
208+ }
209+ }
210+ }
211+
212+ function startFinalEdgeDemo() {
213+ demo.launcherEnabled = false;
214+ if (demo.dash) {
215+ d.finalEdgeDemo = d.overlay.createObject(demo.overlay, {
216+ "edge": "none",
217+ "title": i18n.tr("Well done"),
218+ "text": i18n.tr("You have now mastered the edge gestures and can start using the phone"),
219+ "anchors.fill": demo.overlay,
220+ });
221+ }
222+ if (d.finalEdgeDemo) {
223+ d.finalEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
224+ } else {
225+ stopDemo();
226+ }
227+ }
228+}
Components/DemoOverlay.qml → Components/EdgeDemoOverlay.qmlrenamed+57−45
@@ -14,12 +14,13 @@
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1515 */
1616
17+import Powerd 0.1
1718import QtQuick 2.0
1819import QtGraphicalEffects 1.0
1920import Ubuntu.Application 0.1
2021import Ubuntu.Components 0.1
2122
22−Item {
23+Showable {
2324 id: overlay
2425
2526 /*
@@ -30,38 +31,64 @@ Item {
3031 /*
3132 * This is the header displayed, like "Right edge".
3233 */
33− property string title
34+ property alias title: titleLabel.text
3435
3536 /*
3637 * This is the block of text displayed below the header.
3738 */
38− property string text
39+ property alias text: textLabel.text
3940
4041 /*
4142 * This is the text for the skip button.
4243 */
43− property string skipText: i18n.tr("Skip intro")
44+ property alias skipText: skipLabel.text
4445
4546 /*
46− * Whether this demo is allowed to run.
47+ * Whether this demo is running currently.
4748 */
48− property bool enabled: true
49+ readonly property bool active: available && visible
4950
5051 /*
51− * Whether this demo is running currently.
52+ * Whether animations are paused.
5253 */
53− readonly property bool active: enabled && visible
54−
55− property color __orange: Qt.hsla(16.0/360.0, 0.83, 0.47, 1.0)
56− property color __orange_transparent: Qt.hsla(16.0/360.0, 0.83, 0.47, 0.4)
57− property int __edge_margin: units.gu(4)
58− property int __text_margin: units.gu(3)
59− property int __anim_running: wholeAnimation.running // for testing
54+ property alias paused: wholeAnimation.paused
6055
6156 signal skip()
6257
58+ function doSkip() {
59+ d.skipOnHide = true;
60+ hide();
61+ }
62+
63+ function hideNow() {
64+ overlay.visible = false;
65+ overlay.available = false;
66+ if (d.skipOnHide) {
67+ overlay.skip();
68+ }
69+ }
70+
71+ showAnimation: StandardAnimation {
72+ property: "opacity"
73+ to: 1
74+ onRunningChanged: if (running) overlay.visible = true
75+ }
76+ hideAnimation: StandardAnimation {
77+ property: "opacity"
78+ to: 0
79+ duration: UbuntuAnimation.BriskDuration
80+ onRunningChanged: if (!running) overlay.hideNow()
81+ }
82+
83+ QtObject {
84+ id: d
85+ property bool skipOnHide: false
86+ property int edgeMargin: units.gu(4)
87+ }
88+
6389 Rectangle {
64− id: backgroundShade
90+ objectName: "backgroundShade"
91+
6592 anchors.fill: parent
6693 color: "black"
6794 opacity: 0.8
@@ -70,7 +97,7 @@ Item {
7097 MouseArea {
7198 anchors.fill: parent
7299 enabled: overlay.edge == "none" && overlay.opacity == 1.0
73− onClicked: fadeOutAnimation.running = true
100+ onClicked: overlay.doSkip()
74101 }
75102 }
76103
@@ -85,10 +112,10 @@ Item {
85112 Column {
86113 id: labelGroup
87114 layer.enabled: true // otherwise the underlining on "Skip intro" jumps
88− spacing: overlay.__text_margin
115+ spacing: units.gu(3)
89116
90117 anchors {
91− margins: overlay.__edge_margin
118+ margins: d.edgeMargin
92119 left: parent.left
93120 top: overlay.edge == "bottom" ? undefined : parent.top
94121 bottom: overlay.edge == "bottom" ? parent.bottom : undefined
@@ -96,7 +123,6 @@ Item {
96123
97124 Label {
98125 id: titleLabel
99− text: overlay.title
100126 fontSize: "x-large"
101127 width: units.gu(25)
102128 wrapMode: Text.WordWrap
@@ -104,7 +130,6 @@ Item {
104130
105131 Label {
106132 id: textLabel
107− text: overlay.text
108133 width: units.gu(25)
109134 wrapMode: Text.WordWrap
110135 }
@@ -112,14 +137,14 @@ Item {
112137 Label {
113138 id: skipLabel
114139 objectName: "skipLabel"
115− text: overlay.skipText
116− color: overlay.__orange
140+ text: i18n.tr("Skip intro")
141+ color: UbuntuColors.orange
117142 fontSize: "small"
118143 font.underline: true
119144
120145 MouseArea {
121146 anchors.fill: parent
122− onClicked: fadeOutAnimation.running = true
147+ onClicked: overlay.doSkip()
123148 }
124149 }
125150 }
@@ -132,11 +157,11 @@ Item {
132157 gradient: Gradient {
133158 GradientStop {
134159 position: 0.0
135− color: overlay.__orange_transparent
160+ color: Qt.hsla(16.0/360.0, 0.83, 0.47, 0.4) // UbuntuColors.orange, but transparent
136161 }
137162 GradientStop {
138163 position: 1.0
139− color: "#00000000"
164+ color: "transparent"
140165 }
141166 }
142167 anchors.fill: parent
@@ -165,22 +190,9 @@ Item {
165190 }
166191 }
167192
168− PropertyAnimation {
169− id: fadeOutAnimation
170− target: overlay
171− property: "opacity"
172− to: 0
173− duration: 250
174−
175− onStopped: {
176− overlay.enabled = false;
177− overlay.visible = false;
178− skip()
179− }
180− }
181−
182193 SequentialAnimation {
183194 id: wholeAnimation
195+ objectName: "wholeAnimation"
184196 running: overlay.active
185197
186198 ParallelAnimation {
@@ -199,20 +211,20 @@ Item {
199211 }
200212 from: {
201213 if (overlay.edge == "right") {
202− return overlay.__edge_margin + units.gu(3)
214+ return d.edgeMargin + units.gu(3)
203215 } else {
204− return overlay.__edge_margin - units.gu(3)
216+ return d.edgeMargin - units.gu(3)
205217 }
206218 }
207− to: overlay.__edge_margin
208− duration: overlay.edge == "none" ? 0 : 1000
219+ to: d.edgeMargin
220+ duration: overlay.edge == "none" ? 0 : UbuntuAnimation.SleepyDuration
209221 }
210222 StandardAnimation {
211223 target: overlay
212224 property: "opacity"
213225 from: 0.0
214226 to: 1.0
215− duration: 1000
227+ duration: UbuntuAnimation.SleepyDuration
216228 }
217229 }
218230
@@ -222,7 +234,7 @@ Item {
222234 property string prop: (overlay.edge == "left" || overlay.edge == "right") ? "x" : "y"
223235 property double endVal: units.dp(5) * ((overlay.edge == "left" || overlay.edge == "top") ? 1 : -1)
224236 property double maxGlow: units.dp(20)
225− property int duration: overlay.edge == "none" ? 0 : 1000
237+ property int duration: overlay.edge == "none" ? 0 : UbuntuAnimation.SleepyDuration
226238
227239 ParallelAnimation {
228240 StandardAnimation { target: hintGroup; property: hintAnimation.prop; from: 0; to: hintAnimation.endVal; duration: hintAnimation.duration }
Dash/Apps/FrequentlyUsedAppsModel.qml+1−1
@@ -38,7 +38,7 @@ ListModel {
3838 metadata: ""
3939 }
4040 ListElement {
41− uri: "application:///usr/share/applications/galery-app.desktop"
41+ uri: "application:///usr/share/applications/gallery-app.desktop"
4242 icon: "../../graphics/applicationIcons/gallery.png"
4343 category: 0
4444 mimetype: "application/x-desktop"
Launcher/LauncherPanel.qml+43−6
@@ -121,6 +121,12 @@ Item {
121121 property real realContentY: contentY - originY + topMargin
122122 property int realItemHeight: itemHeight + spacing
123123
124+ // In case the start dragging transition is running, we need to delay the
125+ // move because the displaced transition would clash with it and cause items
126+ // to be moved to wrong places
127+ property bool draggingTransitionRunning: false
128+ property int scheduledMoveTo: -1
129+
124130 displaced: Transition {
125131 NumberAnimation { properties: "x,y"; duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
126132 }
@@ -202,10 +208,26 @@ Item {
202208 UbuntuNumberAnimation { properties: "angle,offset" }
203209 },
204210 Transition {
211+ id: draggingTransition
205212 from: "selected"
206213 to: "dragging"
207− UbuntuNumberAnimation { properties: "height" }
208− NumberAnimation { target: dropIndicator; properties: "opacity"; duration: UbuntuAnimation.FastDuration }
214+ SequentialAnimation {
215+ PropertyAction { target: launcherListView; property: "draggingTransitionRunning"; value: true }
216+ ParallelAnimation {
217+ UbuntuNumberAnimation { properties: "height" }
218+ NumberAnimation { target: dropIndicator; properties: "opacity"; duration: UbuntuAnimation.FastDuration }
219+ }
220+ ScriptAction {
221+ script: {
222+ if (launcherListView.scheduledMoveTo > -1) {
223+ launcherListView.model.move(dndArea.draggedIndex, launcherListView.scheduledMoveTo)
224+ dndArea.draggedIndex = launcherListView.scheduledMoveTo
225+ launcherListView.scheduledMoveTo = -1
226+ }
227+ }
228+ }
229+ PropertyAction { target: launcherListView; property: "draggingTransitionRunning"; value: false }
230+ }
209231 },
210232 Transition {
211233 from: "dragging"
@@ -235,7 +257,7 @@ Item {
235257 property int draggedIndex: -1
236258 property var selectedItem
237259 property bool preDragging: false
238− property bool dragging: selectedItem !== undefined && selectedItem.dragging
260+ property bool dragging: selectedItem !== undefined && selectedItem !== null && selectedItem.dragging
239261 property bool postDragging: false
240262 property int startX
241263 property int startY
@@ -243,13 +265,20 @@ Item {
243265
244266 onPressed: {
245267 selectedItem = launcherListView.itemAt(mouseX, mouseY + launcherListView.realContentY)
246− selectedItem.highlighted = true
268+ if (selectedItem !== null) {
269+ selectedItem.highlighted = true
270+ }
247271 }
248272
249273 onClicked: {
250274 var index = Math.floor((mouseY + launcherListView.realContentY) / launcherListView.realItemHeight);
251275 var clickedItem = launcherListView.itemAt(mouseX, mouseY + launcherListView.realContentY)
252276
277+ // Check if we actually clicked an item or only at the spacing in between
278+ if (clickedItem === null) {
279+ return;
280+ }
281+
253282 // First/last item do the scrolling at more than 12 degrees
254283 if (index == 0 || index == launcherListView.count - 1) {
255284 if (clickedItem.angle > 12) {
@@ -287,6 +316,10 @@ Item {
287316 draggedIndex = -1;
288317 }
289318
319+ if (!selectedItem) {
320+ return;
321+ }
322+
290323 selectedItem.highlighted = false
291324 selectedItem.dragging = false;
292325 selectedItem = undefined;
@@ -376,8 +409,12 @@ Item {
376409 }
377410
378411 if (newIndex >= 0 && newIndex < launcherListView.count) {
379− launcherListView.model.move(draggedIndex, newIndex)
380− draggedIndex = newIndex
412+ if (launcherListView.draggingTransitionRunning) {
413+ launcherListView.scheduledMoveTo = newIndex
414+ } else {
415+ launcherListView.model.move(draggedIndex, newIndex)
416+ draggedIndex = newIndex
417+ }
381418 }
382419 }
383420 }
Panel/Indicators/NetworkIndicatorPage2.qmlnew file+82
@@ -0,0 +1,82 @@
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+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Unity.Indicators 0.1 as Indicators
22+import Unity.Indicators.Network 0.1 as ICNetwork
23+import Ubuntu.Components 0.1
24+
25+PageStack {
26+ id: networkPage
27+ // Stops the search for a parent tree node.
28+ // We don't want it going up to the indicator tabs.
29+ // FIXME: need a better way of doing this.
30+ // https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1211704
31+ __propagated: null
32+
33+ property alias title: _mainPage.title
34+ property alias emptyText: pluginItem.emptyText
35+ property alias busName: pluginItem.busName
36+ property alias actionsObjectPath : pluginItem.actionsObjectPath
37+ property alias menuObjectPaths : pluginItem.menuObjectPaths
38+
39+ anchors.fill: parent
40+
41+ Page {
42+ id: _mainPage
43+
44+ Indicators.IndicatorPage {
45+ id: pluginItem
46+ anchors.fill: parent
47+ }
48+ }
49+
50+ Component {
51+ id: passwordPageComponent
52+
53+ ICNetwork.PasswordPage {
54+ agent: networkAgent
55+ }
56+ }
57+
58+ ICNetwork.NetworkAgent {
59+ id: networkAgent
60+
61+ onSecretRequested: {
62+ networkPage.push(passwordPageComponent, {"token": token});
63+ }
64+ }
65+
66+ function start()
67+ {
68+ push(_mainPage);
69+ pluginItem.start();
70+ }
71+
72+ function stop()
73+ {
74+ clear();
75+ pluginItem.stop();
76+ }
77+
78+ function reset()
79+ {
80+ pluginItem.reset();
81+ }
82+}
Panel/IndicatorsDataModel.qml+1−9
@@ -49,7 +49,7 @@ Indicators.IndicatorsModel {
4949 'title': 'Networks',
5050 'description' : '',
5151 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorWidget2.qml',
52− 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorPage2.qml'
52+ 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/NetworkIndicatorPage2.qml'
5353 },
5454 'indicator-power' : {
5555 'title': 'Battery',
@@ -68,14 +68,6 @@ Indicators.IndicatorsModel {
6868 'description' : '',
6969 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorWidget2.qml',
7070 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/DefaultIndicatorPage2.qml'
71− },
72−
73− // OLD FORMAT INDICATORS
74− 'chewie-network' : {
75− 'title': 'Networks',
76− 'description' : '',
77− 'widgetSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/NetworkIndicatorWidget.qml',
78− 'pageSource' : ApplicationPaths.shellAppDirectory()+'/Panel/Indicators/NetworkIndicatorPage.qml'
7971 }
8072 }
8173}
Shell.qml+25−135
@@ -21,7 +21,6 @@ import Ubuntu.Components 0.1
2121import Ubuntu.Gestures 0.1
2222import Unity.Launcher 0.1
2323import LightDM 0.1 as LightDM
24−import AccountsService 0.1
2524import Powerd 0.1
2625import "Dash"
2726import "Greeter"
@@ -61,19 +60,6 @@ FocusScope {
6160 }
6261 }
6362
64− property bool showEdgeDemo: false
65− property bool showEdgeDemoInGreeter: showEdgeDemo //AccountsService.getUserProperty("lightdm", "demo-edges")
66−
67− function hideEdgeDemo() {
68− var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
69− AccountsService.setUserProperty(user, "demo-edges", false);
70− shell.showEdgeDemo = false;
71− }
72− function hideEdgeDemoInGreeter() {
73− //AccountsService.setUserProperty("lightdm", "demo-edges", false);
74− shell.showEdgeDemoInGreeter = false;
75− }
76−
7763 property ListModel searchHistory: SearchHistoryModel {}
7864
7965 property var applicationManager: ApplicationManagerWrapper {}
@@ -206,7 +192,7 @@ FocusScope {
206192 available: !greeter.shown && !lockscreen.shown
207193 hides: [stages, launcher, panel.indicators]
208194 shown: disappearingAnimationProgress !== 1.0
209− enabled: disappearingAnimationProgress === 0.0 && !leftEdgeDemo.active && !topEdgeDemo.active && !finalEdgeDemo.active
195+ enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled
210196 // FIXME: unfocus all applications when going back to the dash
211197 onEnabledChanged: {
212198 if (enabled) {
@@ -233,50 +219,6 @@ FocusScope {
233219 // greeterRevealer.animatedProgress are not animated
234220 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
235221 }
236−
237− DemoOverlay {
238− id: topEdgeDemo
239−
240− edge: "top"
241− title: i18n.tr("Top edge")
242− text: i18n.tr("Try swiping from the top edge to access the indicators")
243− anchors.fill: dash
244− visible: false
245− enabled: shell.showEdgeDemo
246− onSkip: shell.hideEdgeDemo()
247−
248− Connections {
249− target: greeter
250− onShownChanged: if (!greeter.shown) topEdgeDemo.visible = true
251− }
252−
253− Connections {
254− target: panel.indicators
255− onFullyOpenedChanged: if (panel.indicators.fullyOpened) topEdgeDemo.enabled = false
256− }
257− }
258−
259− DemoOverlay {
260− id: leftEdgeDemo
261−
262− edge: "left"
263− title: i18n.tr("Left edge")
264− text: i18n.tr("Swipe from the left to reveal the launcher for quick access to apps")
265− anchors.fill: dash
266− visible: false
267− enabled: shell.showEdgeDemo
268− onSkip: shell.hideEdgeDemo()
269−
270− Connections {
271− target: bottomEdgeDemo
272− onActiveChanged: if (!bottomEdgeDemo.active) leftEdgeDemo.visible = true
273− }
274−
275− Connections {
276− target: launcher
277− onProgressChanged: if (launcher.progress >= 1.0) leftEdgeDemo.enabled = false
278− }
279− }
280222 }
281223
282224 Item {
@@ -520,9 +462,6 @@ FocusScope {
520462
521463 onUnlocked: greeter.hide()
522464 onSelected: {
523− // Update edge demo hint
524− var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
525− shell.showEdgeDemo = AccountsService.getUserProperty(user, "demo-edges")
526465 // Update launcher items for new user
527466 LauncherModel.setUser(user);
528467 }
@@ -532,34 +471,6 @@ FocusScope {
532471 launcher.tease();
533472 }
534473 }
535−
536− DemoOverlay {
537− id: rightEdgeDemo
538−
539− edge: "right"
540− title: i18n.tr("Right edge")
541− text: i18n.tr("Try swiping from the right edge to unlock the phone")
542− anchors.fill: parent
543− visible: shell.showEdgeDemoInGreeter
544− onSkip: {
545− shell.hideEdgeDemoInGreeter()
546− shell.hideEdgeDemo()
547− }
548−
549− Connections {
550− target: greeter
551−
552− function hide() {
553− if (rightEdgeDemo.active) {
554− rightEdgeDemo.enabled = false
555− shell.hideEdgeDemoInGreeter()
556− }
557− }
558−
559− onUnlocked: hide()
560− onShownChanged: if (!greeter.shown) hide()
561− }
562− }
563474 }
564475
565476 InputFilterArea {
@@ -593,13 +504,22 @@ FocusScope {
593504 }
594505 }
595506
596− onPowerStateChange: {
597− if (state == 0) { // suspend
507+ onDisplayPowerStateChange: {
508+ // We ignore any display-off signals when the proximity sensor
509+ // is active. This usually indicates something like a phone call.
510+ if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
598511 powerConnection.setFocused(false);
599512 greeter.show();
600− } else if (state == 1) { // active
513+ } else if (status == Powerd.On) {
601514 powerConnection.setFocused(true);
602515 }
516+
517+ // No reason to chew demo CPU when user isn't watching
518+ if (status == Powerd.Off) {
519+ edgeDemo.paused = true;
520+ } else if (status == Powerd.On) {
521+ edgeDemo.paused = false;
522+ }
603523 }
604524 }
605525
@@ -614,7 +534,7 @@ FocusScope {
614534 indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
615535 indicators {
616536 hides: [launcher]
617− available: !rightEdgeDemo.active && !leftEdgeDemo.active && !finalEdgeDemo.active
537+ available: edgeDemo.panelEnabled
618538 }
619539 fullscreenMode: shell.fullscreenMode
620540 searchVisible: !greeter.shown && !lockscreen.shown
@@ -623,24 +543,6 @@ FocusScope {
623543 anchors.fill: parent
624544 blockInput: panel.indicators.shown
625545 }
626−
627− DemoOverlay {
628− id: bottomEdgeDemo
629−
630− edge: "bottom"
631− title: i18n.tr("Close")
632− text: i18n.tr("Swipe up again to close the settings screen")
633− anchors.fill: panel.indicators
634− visible: false
635− enabled: shell.showEdgeDemo
636− onSkip: shell.hideEdgeDemo()
637−
638− Connections {
639− target: panel.indicators
640− onFullyOpenedChanged: if (panel.indicators.fullyOpened) bottomEdgeDemo.visible = true
641− onPartiallyOpenedChanged: if (!panel.indicators.partiallyOpened && !panel.indicators.fullyOpened) bottomEdgeDemo.enabled = false
642− }
643− }
644546 }
645547
646548 Hud {
@@ -649,7 +551,7 @@ FocusScope {
649551 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
650552 height: parent.height
651553
652− available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && !topEdgeDemo.active
554+ available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && edgeDemo.dashEnabled
653555 shown: false
654556 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
655557 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
@@ -707,7 +609,7 @@ FocusScope {
707609 anchors.bottom: parent.bottom
708610 width: parent.width
709611 dragAreaWidth: shell.edgeSize
710− available: (!greeter.shown || greeter.narrowMode) && !rightEdgeDemo.active && !topEdgeDemo.active && !bottomEdgeDemo.active && !finalEdgeDemo.active
612+ available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
711613 onDashItemSelected: {
712614 greeter.hide()
713615 // Animate if moving between application and dash
@@ -765,27 +667,6 @@ FocusScope {
765667 }
766668 }
767669
768− DemoOverlay {
769− id: finalEdgeDemo
770−
771− edge: "none"
772− title: i18n.tr("Well done")
773− text: i18n.tr("You have now mastered the edge gestures and can start using the phone")
774− skipText: i18n.tr("Finish")
775− anchors.fill: overlay
776− visible: false
777− enabled: shell.showEdgeDemo
778− onSkip: {
779− launcher.hide();
780− shell.hideEdgeDemo();
781− }
782−
783− Connections {
784− target: leftEdgeDemo
785− onActiveChanged: if (!leftEdgeDemo.active) finalEdgeDemo.visible = true
786− }
787− }
788−
789670 focus: true
790671
791672 InputFilterArea {
@@ -837,4 +718,13 @@ FocusScope {
837718 rotation: -45
838719 scale: Math.min(parent.width, parent.height) / width
839720 }
721+
722+ EdgeDemo {
723+ id: edgeDemo
724+ greeter: greeter
725+ launcher: launcher
726+ dash: dash
727+ indicators: panel.indicators
728+ overlay: overlay
729+ }
840730}
build+5−2
@@ -40,11 +40,14 @@ install_dependencies() {
4040 echo "Installing Unity 8 dependencies.."
4141 sudo apt-get install devscripts \
4242 equivs \
43+ gsettings-desktop-schemas \
4344 qmenumodel-qml \
44− qtdeclarative5-ubuntu-ui-toolkit-plugin \
4545 qtdeclarative5-dee-plugin \
46+ qtdeclarative5-gsettings1.0 \
47+ qtdeclarative5-ubuntu-ui-toolkit-plugin \
48+ unity-notifications-impl \
49+ qtdeclarative5-xmllistmodel-plugin \
4650 ubuntu-mobile-icons \
47− unity-notifications-impl-1 \
4851 unity-scope-home \
4952 unity-lens-applications \
5053 || exit 5
debian/changelog+63
@@ -1,3 +1,66 @@
1+unity8 (7.81.3+13.10.20130821.2-0ubuntu1) saucy; urgency=low
2+
3+ [ Michael Terry ]
4+ * Listen to display-power-changed rather than system-power-changed
5+ signals when showing the greeter; ignore such signals when the
6+ proximity sensor is active. (LP: #1214477)
7+
8+ [ Pawel Stolowski ]
9+ * Added a role for accessing progress-source property of categories.
10+
11+ [ Ubuntu daily release ]
12+ * Automatic snapshot from revision 233
13+
14+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 21 Aug 2013 22:09:53 +0000
15+
16+unity8 (7.81.3+13.10.20130821.1-0ubuntu1) saucy; urgency=low
17+
18+ [ Michael Zanetti ]
19+ * allow testing at 11:13. Old code failed because the text actually
20+ says "11:13 AM".
21+ * add some checks if we actually clicked an item or in the spacing
22+ between them gets rid of some warnings printed by the launcher .
23+
24+ [ Michał Sawicz ]
25+ * Update runtime deps in the build script.
26+
27+ [ Nick Dedekind ]
28+ * Added/Updated legacy network indicator components to use with new
29+ indicator backend.
30+
31+ [ Albert Astals ]
32+ * Fix insertions/removals on the qlimitproxymodel . (LP: #1213959)
33+
34+ [ Ubuntu daily release ]
35+ * Automatic snapshot from revision 230
36+
37+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 21 Aug 2013 15:04:59 +0000
38+
39+unity8 (7.81.3+13.10.20130821-0ubuntu1) saucy; urgency=low
40+
41+ [ Michael Zanetti ]
42+ * added support for count emblems and progress overlays on the
43+ launcher.
44+
45+ [ Pawel Stolowski ]
46+ * Add role for getting filter options model. Add method to activate
47+ option based on index or id.
48+
49+ [ Ted Gould ]
50+ * Mark indicators-client as providing an indicator-renderer.
51+
52+ [ Nick Dedekind ]
53+ * Added flatmenuproxymodel pass-through signals from qmenumodel.
54+ * Renamed indicator-messaging to indicator-messages.
55+
56+ [ Gerry Boland ]
57+ * Typo fix in FrequentlyUsedAppsModel.
58+
59+ [ Ubuntu daily release ]
60+ * Automatic snapshot from revision 224
61+
62+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 21 Aug 2013 08:05:13 +0000
63+
164unity8 (7.81.3+13.10.20130820.2-0ubuntu1) saucy; urgency=low
265
366 [ Michael Zanetti ]
debian/control+2−1
@@ -21,7 +21,7 @@ Build-Depends: cmake,
2121 libsigc++-2.0-dev,
2222 libunity-api-dev (>= 7.80.3),
2323 libunity-core-6.0-dev (<< 7.80),
24− libunity-dev (>= 7.0.3),
24+ libunity-dev (>= 7.0.12),
2525 libunity-scopes-json-def-phone,
2626 libupstart-dev,
2727 libusermetricsoutput1-dev,
@@ -62,6 +62,7 @@ Description: Indicators client test application
6262
6363Package: unity8
6464Architecture: any
65+Provides: indicator-renderer,
6566Depends: gsettings-desktop-schemas,
6667 qmenumodel-qml (>= 0.2.7),
6768 qtdeclarative5-dee-plugin,
debian/rules+5
@@ -16,6 +16,11 @@ override_dh_auto_clean:
1616 dh_auto_clean
1717 rm -rf builddir
1818
19+override_dh_auto_configure:
20+ # Debian defines CMAKE_INSTALL_LOCALSTATEDIR as /usr/var, which is wrong.
21+ # So until Debian bug 719148 is fixed, do it ourselves.
22+ dh_auto_configure -- -DCMAKE_INSTALL_LOCALSTATEDIR="/var"
23+
1924override_dh_install:
2025 # install autopilot tests
2126 cd tests/autopilot; \
plugins/AccountsService/AccountsService.cpp+8−4
@@ -17,19 +17,23 @@
1717 */
1818
1919#include "AccountsService.h"
20−#include <QtDBus/QDBusConnection>
21−#include <QtDBus/QDBusMessage>
22−#include <QtDBus/QDBusVariant>
20+#include <QDBusConnection>
21+#include <QDBusConnectionInterface>
22+#include <QDBusMessage>
23+#include <QDBusVariant>
2324
2425AccountsService::AccountsService(QObject* parent)
2526 : QObject(parent),
2627 accounts_manager(NULL),
2728 users()
2829{
30+ auto connection = QDBusConnection::SM_BUSNAME();
31+ auto interface = connection.interface();
32+ interface->startService("org.freedesktop.Accounts");
2933 accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
3034 "/org/freedesktop/Accounts",
3135 "org.freedesktop.Accounts",
32− QDBusConnection::SM_BUSNAME(), this);
36+ connection, this);
3337}
3438
3539QVariant AccountsService::getUserProperty(const QString &user, const QString &property)
plugins/AccountsService/AccountsService.h+6−7
@@ -19,10 +19,10 @@
1919#ifndef UNITY_ACCOUNTSSERVICE_H
2020#define UNITY_ACCOUNTSSERVICE_H
2121
22−#include <QtDBus/QDBusInterface>
23−#include <QtCore/QMap>
24−#include <QtCore/QObject>
25−#include <QtCore/QString>
22+#include <QDBusInterface>
23+#include <QMap>
24+#include <QObject>
25+#include <QString>
2626
2727class AccountsService: public QObject
2828{
@@ -31,14 +31,13 @@ class AccountsService: public QObject
3131public:
3232 explicit AccountsService(QObject *parent = 0);
3333
34−public Q_SLOTS:
34+public Q_INVOKABLE:
3535 QVariant getUserProperty(const QString &user, const QString &property);
3636 void setUserProperty(const QString &user, const QString &property, const QVariant &value);
3737
38−private Q_SLOTS:
38+private:
3939 QDBusInterface *getUserInterface(const QString &user);
4040
41−private:
4241 QDBusInterface *accounts_manager;
4342 QMap<QString, QDBusInterface *> users;
4443};
plugins/AccountsService/CMakeLists.txt+1−3
@@ -12,9 +12,7 @@ qt5_use_modules(AccountsService-qml DBus Qml)
1212export_qmlfiles(AccountsService AccountsService)
1313export_qmlplugin(AccountsService 0.1 AccountsService TARGETS AccountsService-qml)
1414
15−# Debian defines CMAKE_INSTALL_LOCALSTATEDIR as /usr/var, which is wrong.
16−# So until Debian bug 719148 is fixed, hardcode it.
17−set(POLKIT_LIB_DIR "/var/lib/polkit-1")
15+set(POLKIT_LIB_DIR "${CMAKE_INSTALL_LOCALSTATEDIR}/lib/polkit-1")
1816set(POLKIT_DATA_DIR "${CMAKE_INSTALL_PREFIX}/share/polkit-1")
1917set(DBUS_IFACE_DIR "${CMAKE_INSTALL_PREFIX}/share/dbus-1/interfaces")
2018set(ACCOUNTS_IFACE_DIR "${CMAKE_INSTALL_PREFIX}/share/accountsservice/interfaces")
plugins/AccountsService/plugin.cpp+1−1
@@ -20,7 +20,7 @@
2020#include "AccountsService.h"
2121
2222#include <QDBusMetaType>
23−#include <QtQml/QtQml>
23+#include <QtQml>
2424
2525static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
2626{
plugins/AccountsService/plugin.h+2−2
@@ -19,8 +19,8 @@
1919#ifndef ACCOUNTSSERVICE_PLUGIN_H
2020#define ACCOUNTSSERVICE_PLUGIN_H
2121
22−#include <QtQml/QQmlEngine>
23−#include <QtQml/QQmlExtensionPlugin>
22+#include <QQmlEngine>
23+#include <QQmlExtensionPlugin>
2424
2525class AccountsServicePlugin : public QQmlExtensionPlugin
2626{
plugins/Powerd/Powerd.cpp+2−2
@@ -30,7 +30,7 @@ Powerd::Powerd(QObject* parent)
3030 powerd->connection().connect("com.canonical.powerd",
3131 "/com/canonical/powerd",
3232 "com.canonical.powerd",
33− "SysPowerStateChange",
33+ "DisplayPowerStateChange",
3434 this,
35− SIGNAL(powerStateChange(int)));
35+ SIGNAL(displayPowerStateChange(int, unsigned int)));
3636}
plugins/Powerd/Powerd.h+15−1
@@ -26,12 +26,26 @@
2626class Powerd: public QObject
2727{
2828 Q_OBJECT
29+ Q_ENUMS(Status)
30+ Q_FLAGS(DisplayFlag DisplayFlags)
2931
3032public:
33+ enum DisplayFlag {
34+ UseProximity = 1, // Use proximity sensor to override screen state
35+ DisableAutoBrightness = 2, // Force autobrightness to be disabled
36+ Bright = 4, // Request the screen to stay bright
37+ };
38+ Q_DECLARE_FLAGS(DisplayFlags, DisplayFlag)
39+
40+ enum Status {
41+ Off,
42+ On,
43+ };
44+
3145 explicit Powerd(QObject *parent = 0);
3246
3347Q_SIGNALS:
34− void powerStateChange(int state);
48+ void displayPowerStateChange(int status, unsigned int flags);
3549
3650private:
3751 QDBusInterface *powerd;
plugins/Unity/Indicators/CMakeLists.txt+1
@@ -12,6 +12,7 @@ find_package(Qt5Core REQUIRED)
1212find_package(Qt5Quick REQUIRED)
1313
1414add_subdirectory(qml)
15+add_subdirectory(Network)
1516
1617include_directories(
1718 ${CMAKE_CURRENT_SOURCE_DIR}
plugins/Unity/Indicators/Network/CMakeLists.txtnew file+45
@@ -0,0 +1,45 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
4+project(IndicatorsNetworkQml)
5+
6+pkg_check_modules(GLIB glib-2.0>=2.32)
7+pkg_check_modules(LIBNM_GLIB libnm-glib>=0.9.6)
8+pkg_check_modules(LIBNM_UTIL libnm-util>=0.9.6)
9+
10+if(LIBNM_GLIB_FOUND AND LIBNM_UTIL_FOUND AND GLIB_FOUND)
11+ set(INDICATORS_NETWORK_SRC
12+ networkagent.cpp
13+ plugin.cpp
14+ secret-agent.c
15+ )
16+
17+ add_library(IndicatorsNetworkQml MODULE
18+ ${INDICATORS_NETWORK_SRC}
19+ )
20+
21+ qt5_use_modules(IndicatorsNetworkQml Core Qml Widgets)
22+
23+ set_target_properties(IndicatorsNetworkQml PROPERTIES COMPILE_FLAGS -fPIC)
24+
25+ include_directories(
26+ ${CMAKE_CURRENT_SOURCE_DIR}
27+ ${GLIB_INCLUDE_DIRS}
28+ ${LIBNM_GLIB_INCLUDE_DIRS}
29+ ${LIBNM_UTIL_INCLUDE_DIRS}
30+ )
31+
32+ target_link_libraries(IndicatorsNetworkQml
33+ ${GLIB_LIBRARIES}
34+ ${LIBNM_GLIB_LIBRARIES}
35+ ${LIBNM_UTIL_LIBRARIES}
36+ )
37+
38+ # export the qmltypes and plugin files
39+ export_qmlplugin(Unity.Indicators.Network 0.1 Unity/Indicators/Network TARGETS IndicatorsNetworkQml)
40+
41+else()
42+ message(WARNING "Missing glib or libnm dependency for the network plugin, not building")
43+endif()
44+
45+add_subdirectory(qml)
plugins/Unity/Indicators/Network/networkagent.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+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+#include "networkagent.h"
22+
23+#include <QVariant>
24+#include <QApplication>
25+#include <QDebug>
26+
27+class NetworkAgentToken
28+{
29+public:
30+ NMConnection *connection;
31+ NMSettingWirelessSecurity *wisec;
32+ guint id;
33+ QByteArray keyMgmt;
34+
35+ NetworkAgentToken(NMConnection *connection,
36+ NMSettingWirelessSecurity *wisec,
37+ guint id,
38+ QByteArray keyMgmt)
39+ : connection(connection),
40+ wisec(wisec),
41+ id(id),
42+ keyMgmt(keyMgmt)
43+ {
44+ if (connection) {
45+ g_object_ref(connection);
46+ } else {
47+ qWarning() << "invalid connection object";
48+ }
49+ }
50+
51+ ~NetworkAgentToken()
52+ {
53+ if (connection) {
54+ g_object_unref(connection);
55+ }
56+ }
57+};
58+
59+NetworkAgent::NetworkAgent(QObject *parent)
60+ : QObject(parent)
61+{
62+ m_agent = unity_settings_secret_agent_new();
63+ g_signal_connect(G_OBJECT(m_agent),
64+ UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED,
65+ G_CALLBACK(onSecretRequested),
66+ this);
67+
68+ g_signal_connect(G_OBJECT(m_agent),
69+ UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED,
70+ G_CALLBACK(onSecretRequestCancelled),
71+ this);
72+}
73+
74+NetworkAgent::~NetworkAgent()
75+{
76+ nm_secret_agent_unregister(NM_SECRET_AGENT(m_agent));
77+ g_object_unref(m_agent);
78+}
79+
80+void NetworkAgent::authenticate(const QVariant &token, const QString &key)
81+{
82+ NetworkAgentToken *pToken = (NetworkAgentToken *) token.value<void *>();
83+ if (pToken == NULL) {
84+ return;
85+ }
86+
87+ if ((pToken->keyMgmt == "wpa-none") || (pToken->keyMgmt == "wpa-psk")) {
88+ g_object_set(G_OBJECT(pToken->wisec),
89+ NM_SETTING_WIRELESS_SECURITY_PSK, qPrintable(key),
90+ NULL);
91+ } else if (pToken->keyMgmt == "none") {
92+ g_object_set(G_OBJECT(pToken->wisec),
93+ NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, qPrintable(key),
94+ NULL);
95+ }
96+
97+ GHashTable *settings = nm_connection_to_hash(pToken->connection,
98+ NM_SETTING_HASH_FLAG_ALL);
99+
100+ unity_settings_secret_agent_provide_secret(m_agent,
101+ pToken->id, settings);
102+ g_hash_table_unref(settings);
103+ delete pToken;
104+}
105+
106+void NetworkAgent::cancel(const QVariant &token)
107+{
108+ NetworkAgentToken *pToken = (NetworkAgentToken *) token.value<void *>();
109+ if (pToken != NULL) {
110+ unity_settings_secret_agent_cancel_request(m_agent, pToken->id);
111+ delete pToken;
112+ }
113+}
114+
115+void NetworkAgent::onSecretRequested(UnitySettingsSecretAgent* /*agent*/,
116+ guint id,
117+ NMConnection* connection,
118+ const char* /*setting_name*/,
119+ const char** /*hints*/,
120+ NMSecretAgentGetSecretsFlags /*flags*/,
121+ NetworkAgent* self)
122+{
123+ NetworkAgentToken *token = new NetworkAgentToken(connection,
124+ NULL,
125+ id,
126+ NULL);
127+
128+ token->wisec = nm_connection_get_setting_wireless_security(connection);
129+ if (token->wisec) {
130+ token->keyMgmt = nm_setting_wireless_security_get_key_mgmt(token->wisec);
131+ }
132+
133+ QVariant varToken = qVariantFromValue((void *) token);
134+ Q_EMIT self->secretRequested(varToken);
135+}
136+
137+void NetworkAgent::onSecretRequestCancelled(UnitySettingsSecretAgent* /*agent*/,
138+ guint /*id*/,
139+ NMConnection* /*connection*/,
140+ const char* /*setting_name*/,
141+ const char** /*hints*/,
142+ NMSecretAgentGetSecretsFlags /*flags*/,
143+ NetworkAgent* /*self*/)
144+{
145+ //Do nothing for now
146+}
plugins/Unity/Indicators/Network/networkagent.hnew file+65
@@ -0,0 +1,65 @@
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+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+#ifndef NETWORKAGENT_H
22+#define NETWORKAGENT_H
23+
24+#include "secret-agent.h"
25+
26+#include <QObject>
27+
28+class NetworkAgentToken;
29+
30+class NetworkAgent : public QObject
31+{
32+ Q_OBJECT
33+public:
34+ NetworkAgent(QObject *parent=0);
35+ ~NetworkAgent();
36+
37+ Q_INVOKABLE void authenticate(const QVariant &token, const QString &key);
38+ Q_INVOKABLE void cancel(const QVariant &token);
39+
40+Q_SIGNALS:
41+ void secretRequested(const QVariant &token);
42+ void secretRequestCancelled();
43+
44+private:
45+ UnitySettingsSecretAgent *m_agent;
46+
47+ static void onSecretRequested(UnitySettingsSecretAgent *agent,
48+ guint id,
49+ NMConnection *connection,
50+ const char *setting_name,
51+ const char **hints,
52+ NMSecretAgentGetSecretsFlags flags,
53+ NetworkAgent *self);
54+
55+ static void onSecretRequestCancelled(UnitySettingsSecretAgent *agent,
56+ guint id,
57+ NMConnection *connection,
58+ const char *setting_name,
59+ const char **hints,
60+ NMSecretAgentGetSecretsFlags flags,
61+ NetworkAgent *self);
62+
63+};
64+
65+#endif
plugins/Unity/Indicators/Network/plugin.cppnew file+31
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (C) 2012 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+// Qt
20+#include <QtQml>
21+
22+// self
23+#include "plugin.h"
24+
25+// local
26+#include "networkagent.h"
27+
28+void IndicatorsNetworkPlugin::registerTypes(const char *uri)
29+{
30+ qmlRegisterType<NetworkAgent>(uri, 0, 1, "NetworkAgent");
31+}
plugins/Unity/Indicators/Network/plugin.hnew file+32
@@ -0,0 +1,32 @@
1+/*
2+ * Copyright (C) 2012 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Nick Dedekind <nick.dedekind@canonical.com>
17+ */
18+
19+#ifndef INDICATORS_NETWORK_PLUGIN_H
20+#define INDICATORS_NETWORK_PLUGIN_H
21+
22+#include <QtQml/QQmlExtensionPlugin>
23+
24+class IndicatorsNetworkPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+public:
29+ void registerTypes(const char *uri);
30+};
31+
32+#endif // INDICATORS_NETWORK_PLUGIN_H
plugins/Unity/Indicators/Network/qml/AccessPoint.qmlnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Ubuntu.Components.ListItems 0.1 as ListItem
23+import Unity.Indicators 0.1 as Indicators
24+
25+Indicators.FramedMenuItem {
26+ id: accessPoint
27+
28+ readonly property bool checked: menu ? menu.isToggled : false
29+
30+ onCheckedChanged: {
31+ // Can't rely on binding. Checked is assigned on click.
32+ checkBoxActive.checked = checked;
33+ }
34+
35+ // FIXME - we need to get the strength from menu.ext.xCanonicalWifiApStrengthAction
36+ // but UnityMenuModel doesnt support fetching actions not attached to menu item.
37+ function getNetworkIcon(data) {
38+ var imageName = "nm-signal-100"
39+
40+ if (data.ext.xCanonicalWifiApIsAdhoc) {
41+ imageName = "nm-adhoc";
42+ }
43+ if (data.ext.xCanonicalWifiApIsSecure) {
44+ imageName += "-secure";
45+ }
46+
47+ return "image://gicon/" + imageName;
48+ }
49+
50+ icon: menu ? getNetworkIcon(menu) : "image://gicon/wifi-none"
51+ iconFrame: false
52+ control: CheckBox {
53+ id: checkBoxActive
54+ height: units.gu(4)
55+ width: units.gu(4)
56+ anchors.centerIn: parent
57+
58+ onClicked: {
59+ accessPoint.activate();
60+ }
61+ }
62+}
plugins/Unity/Indicators/Network/qml/CMakeLists.txtnew file+5
@@ -0,0 +1,5 @@
1+# export_qmlplugin macro
2+include(Plugins)
3+
4+# export the qmldir, *.qml files.
5+export_qmlfiles(Unity.Indicators.Network Unity/Indicators/Network)
plugins/Unity/Indicators/Network/qml/PasswordPage.qmlnew file+88
@@ -0,0 +1,88 @@
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+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Ubuntu.Components.ListItems 0.1 as ListItem
23+import Unity.Indicators 0.1 as Indicators
24+
25+Page {
26+ id: pagePassword
27+
28+ property variant agent
29+ property variant token
30+
31+ anchors.fill: parent
32+ title: "Network Authentication"
33+
34+ Column {
35+ anchors {
36+ left: parent.left
37+ right: parent.right
38+ }
39+
40+ Indicators.SectionMenuItem {
41+ label: "Authentication"
42+ }
43+
44+ Indicators.FramedMenuItem {
45+ implicitHeight: password.height + units.gu(1)
46+
47+ PasswordTextField {
48+ id: password
49+ anchors {
50+ left: parent.left
51+ right: parent.right
52+ margins: units.gu(3)
53+ verticalCenter: parent.verticalCenter
54+ }
55+ }
56+ }
57+
58+ Indicators.FramedMenuItem {
59+ Row {
60+ anchors {
61+ right: parent.right
62+ verticalCenter: parent.verticalCenter
63+ margins: units.gu(3)
64+ }
65+
66+ spacing: units.gu(1)
67+
68+ Button {
69+ text: "Cancel"
70+ width: units.gu(10)
71+ onClicked: {
72+ agent.cancel(token);
73+ pageStack.pop();
74+ }
75+ }
76+
77+ Button {
78+ text: "OK"
79+ width: units.gu(10)
80+ onClicked: {
81+ agent.authenticate(token, password.text);
82+ pageStack.pop();
83+ }
84+ }
85+ }
86+ }
87+ }
88+}
plugins/Unity/Indicators/Network/qml/PasswordTextField.qmlnew file+68
@@ -0,0 +1,68 @@
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+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+
23+Item {
24+ id: textMenu
25+
26+ property alias text: textField.text
27+
28+ height: contentColumn.height
29+
30+ Column {
31+ id: contentColumn
32+ spacing: units.gu(0.5)
33+ anchors {
34+ left: parent.left
35+ right: parent.right
36+ }
37+
38+ TextField {
39+ id: textField
40+
41+ anchors {
42+ left: parent.left
43+ right: parent.right
44+ }
45+
46+ placeholderText: "Password"
47+ echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
48+ }
49+
50+ Row {
51+ anchors {
52+ left: parent.left
53+ right: parent.right
54+ }
55+
56+ spacing: units.gu(1)
57+
58+ CheckBox {
59+ id: showPassword
60+ }
61+
62+ Label {
63+ text: "Show password"
64+ anchors.verticalCenter: showPassword.verticalCenter
65+ }
66+ }
67+ }
68+}
plugins/Unity/Indicators/Network/qml/WifiSection.qmlnew file+28
@@ -0,0 +1,28 @@
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+ * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Unity.Indicators 0.1 as Indicators
23+
24+Indicators.SectionMenuItem {
25+ id: wifiSectionMenu
26+
27+ busy: menu ? menu.ext.xCanonicalBusyAction : false
28+}
plugins/Unity/Indicators/Network/qml/qmldirnew file+9
@@ -0,0 +1,9 @@
1+module Unity.Indicators.Network
2+plugin IndicatorsNetworkQml
3+typeinfo plugin.qmltypes
4+
5+NetworkPage 0.1 NetworkPage.qml
6+AccessPoint 0.1 AccessPoint.qml
7+PasswordPage 0.1 PasswordPage.qml
8+PasswordTextField 0.1 PasswordTextField.qml
9+WifiSection 0.1 WifiSection.qml
plugins/Unity/Indicators/Network/secret-agent.cnew file+382
@@ -0,0 +1,382 @@
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+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+
22+#include <glib.h>
23+#include <glib-object.h>
24+#include <nm-secret-agent.h>
25+#include "secret-agent.h"
26+
27+#define UNITY_SETTINGS_TYPE_SECRET_AGENT (unity_settings_secret_agent_get_type ())
28+#define UNITY_SETTINGS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgent))
29+#define UNITY_SETTINGS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
30+#define UNITY_SETTINGS_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT))
31+#define UNITY_SETTINGS_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT))
32+#define UNITY_SETTINGS_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
33+#define UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentPrivate))
34+
35+#define AGENT_ID "com.canonical.settings.network.nm-agent"
36+
37+static gpointer unity_settings_secret_agent_parent_class = NULL;
38+
39+typedef struct _UnitySettingsSecretAgentPrivate UnitySettingsSecretAgentPrivate;
40+
41+struct _UnitySettingsSecretAgentPrivate {
42+ GQueue *requests;
43+};
44+
45+typedef struct _SecretRequest {
46+ gint id;
47+ NMSecretAgent *agent;
48+ NMConnection *connection;
49+ const char *connection_path;
50+ const char *setting_name;
51+ const char **hints;
52+ NMSecretAgentGetSecretsFlags flags;
53+ NMSecretAgentGetSecretsFunc callback;
54+ gpointer callback_data;
55+} SecretRequest;
56+
57+GType unity_settings_secret_agent_get_type (void) G_GNUC_CONST;
58+enum {
59+ UNITY_SETTINGS_SECRET_AGENT_DUMMY_PROPERTY
60+};
61+
62+enum {
63+ SECRET_REQUESTED,
64+ REQUEST_CANCELLED,
65+ LAST_SIGNAL
66+};
67+
68+static guint signals[LAST_SIGNAL] = { 0 };
69+
70+UnitySettingsSecretAgent* unity_settings_secret_agent_new (void);
71+UnitySettingsSecretAgent* unity_settings_secret_agent_construct (GType object_type);
72+
73+int
74+secret_request_find (SecretRequest *req,
75+ guint *id)
76+{
77+ if (req->id > *id)
78+ return -1;
79+
80+ if (req->id < *id)
81+ return 1;
82+
83+ return 0;
84+}
85+
86+void
87+unity_settings_secret_agent_provide_secret (UnitySettingsSecretAgent *agent,
88+ guint request,
89+ GHashTable *secrets)
90+{
91+ GList *iter;
92+ SecretRequest *req;
93+ UnitySettingsSecretAgentPrivate *priv = agent->priv;
94+
95+ iter = g_queue_find_custom (priv->requests,
96+ &request,
97+ (GCompareFunc)secret_request_find);
98+
99+ if (iter == NULL || iter->data == NULL)
100+ {
101+ g_warning ("Secret request with id <%d> was not found", (int)request);
102+ return;
103+ }
104+
105+ req = iter->data;
106+
107+ req->callback (NM_SECRET_AGENT (agent),
108+ req->connection,
109+ secrets,
110+ NULL,
111+ req->callback_data);
112+
113+ g_queue_remove_all (priv->requests, req);
114+ g_free (req);
115+ return;
116+}
117+
118+void
119+free_request (SecretRequest *req)
120+{
121+ g_object_unref (req->connection);
122+ g_free (req);
123+}
124+
125+void
126+unity_settings_secret_agent_cancel_request (UnitySettingsSecretAgent *agent,
127+ guint request)
128+{
129+ GList *iter;
130+ SecretRequest *req;
131+ UnitySettingsSecretAgentPrivate *priv = agent->priv;
132+ GError *error;
133+
134+ iter = g_queue_find_custom (priv->requests,
135+ &request,
136+ (GCompareFunc)secret_request_find);
137+
138+ if (iter == NULL || iter->data == NULL)
139+ {
140+ g_warning ("Secret request with id <%d> was not found", (int)request);
141+ return;
142+ }
143+
144+ req = iter->data;
145+ error = g_error_new (NM_SECRET_AGENT_ERROR,
146+ NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
147+ "This secret request was canceled by the user.");
148+
149+ req->callback (NM_SECRET_AGENT (agent),
150+ req->connection,
151+ NULL,
152+ error,
153+ req->callback_data);
154+
155+ g_queue_remove_all (priv->requests, req);
156+ free_request (req);
157+ return;
158+}
159+
160+static void
161+delete_secrets (NMSecretAgent *agent,
162+ NMConnection *connection,
163+ const char *connection_path,
164+ NMSecretAgentDeleteSecretsFunc callback,
165+ gpointer callback_data)
166+{
167+ g_debug ("delete secrets");
168+}
169+
170+/* If it returns G_MAXUINT it's considered an error */
171+static guint
172+find_available_id (UnitySettingsSecretAgentPrivate *priv)
173+{
174+ guint i = 0;
175+ guint candidate = 0;
176+
177+ if (g_queue_get_length (priv->requests) == G_MAXUINT)
178+ return G_MAXUINT;
179+
180+ while (i < g_queue_get_length (priv->requests))
181+ {
182+ SecretRequest *req = (SecretRequest*)g_queue_peek_nth (priv->requests, i);
183+
184+ if (req->id == candidate)
185+ {
186+ candidate++;
187+ i = 0;
188+ }
189+ else
190+ {
191+ i++;
192+ }
193+ }
194+
195+ return i;
196+}
197+
198+static void
199+get_secrets (NMSecretAgent *agent,
200+ NMConnection *connection,
201+ const char *connection_path,
202+ const char *setting_name,
203+ const char **hints,
204+ NMSecretAgentGetSecretsFlags flags,
205+ NMSecretAgentGetSecretsFunc callback,
206+ gpointer callback_data)
207+{
208+ guint id;
209+ UnitySettingsSecretAgentPrivate *priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (agent);
210+ SecretRequest *req = NULL;
211+
212+ if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE)
213+ {
214+ GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
215+ NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
216+ "No password found for this connection.");
217+ callback (agent, connection, NULL, error, callback_data);
218+ g_error_free (error);
219+ return;
220+ }
221+
222+ id = find_available_id (priv);
223+ if (id == G_MAXUINT)
224+ {
225+ GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
226+ NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
227+ "Reached maximum number of requests.");
228+ callback (agent, connection, NULL, error, callback_data);
229+ g_error_free (error);
230+ return;
231+ }
232+
233+ /* Adding a request */
234+ req = (SecretRequest*) g_malloc0 (sizeof (SecretRequest));
235+ *req = ((SecretRequest)
236+ { id,
237+ agent,
238+ connection,
239+ connection_path,
240+ setting_name,
241+ hints,
242+ flags,
243+ callback,
244+ callback_data });
245+
246+ g_object_ref (connection);
247+
248+ g_queue_push_tail (priv->requests, req);
249+
250+ g_signal_emit_by_name (agent,
251+ UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED,
252+ id,
253+ connection,
254+ setting_name,
255+ hints,
256+ flags);
257+}
258+
259+static void
260+save_secrets (NMSecretAgent *agent,
261+ NMConnection *connection,
262+ const char *connection_path,
263+ NMSecretAgentSaveSecretsFunc callback,
264+ gpointer callback_data)
265+{
266+ g_debug ("save secrets");
267+}
268+
269+static void
270+cancel_get_secrets (NMSecretAgent *agent,
271+ const char *connection_path,
272+ const char *setting_name)
273+{
274+ g_debug ("cancel get secrets");
275+}
276+
277+UnitySettingsSecretAgent*
278+unity_settings_secret_agent_construct (GType object_type)
279+{
280+ UnitySettingsSecretAgent * self = NULL;
281+ self = (UnitySettingsSecretAgent*) g_object_new (object_type,
282+ NM_SECRET_AGENT_IDENTIFIER, AGENT_ID,
283+ NULL);
284+ return self;
285+}
286+
287+
288+UnitySettingsSecretAgent*
289+unity_settings_secret_agent_new (void)
290+{
291+ return unity_settings_secret_agent_construct (UNITY_SETTINGS_TYPE_SECRET_AGENT);
292+}
293+
294+static void
295+destroy_pending_request (gpointer data)
296+{
297+ SecretRequest* req = (SecretRequest*)data;
298+ /* Reporting the cancellation of all pending requests */
299+ g_signal_emit_by_name (req->agent,
300+ UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED,
301+ req->id);
302+
303+ free_request (req);
304+}
305+
306+static void
307+unity_settings_secret_agent_finalize (GObject *agent)
308+{
309+ UnitySettingsSecretAgentPrivate *priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (agent);
310+
311+ g_queue_free_full (priv->requests, destroy_pending_request);
312+}
313+
314+static void
315+unity_settings_secret_agent_class_init (UnitySettingsSecretAgentClass *klass)
316+{
317+ unity_settings_secret_agent_parent_class = g_type_class_peek_parent (klass);
318+ NMSecretAgentClass *parent_class = NM_SECRET_AGENT_CLASS (klass);
319+ parent_class->get_secrets = get_secrets;
320+ parent_class->save_secrets = save_secrets;
321+ parent_class->delete_secrets = delete_secrets;
322+ parent_class->cancel_get_secrets = cancel_get_secrets;
323+
324+ g_type_class_add_private (klass, sizeof(UnitySettingsSecretAgentPrivate));
325+ G_OBJECT_CLASS (klass)->finalize = unity_settings_secret_agent_finalize;
326+
327+
328+ signals[SECRET_REQUESTED] = g_signal_new (UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED,
329+ G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
330+ G_SIGNAL_RUN_FIRST,
331+ G_STRUCT_OFFSET (UnitySettingsSecretAgentClass, secret_requested),
332+ NULL, NULL, NULL,
333+ G_TYPE_NONE, 5,
334+ G_TYPE_UINT, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_UINT);
335+
336+ signals[REQUEST_CANCELLED] = g_signal_new (UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED,
337+ G_OBJECT_CLASS_TYPE (G_OBJECT_CLASS (klass)),
338+ G_SIGNAL_RUN_FIRST,
339+ G_STRUCT_OFFSET (UnitySettingsSecretAgentClass, request_cancelled),
340+ NULL, NULL, NULL,
341+ G_TYPE_NONE, 1,
342+ G_TYPE_UINT);
343+}
344+
345+
346+static void
347+unity_settings_secret_agent_instance_init (UnitySettingsSecretAgent *self)
348+{
349+ self->priv = UNITY_SETTINGS_SECRET_AGENT_GET_PRIVATE (self);
350+ self->priv->requests = g_queue_new ();
351+}
352+
353+GType
354+unity_settings_secret_agent_get_type (void)
355+{
356+ static volatile gsize unity_settings_secret_agent_type_id__volatile = 0;
357+ if (g_once_init_enter (&unity_settings_secret_agent_type_id__volatile))
358+ {
359+ static const GTypeInfo g_define_type_info =
360+ {
361+ sizeof (UnitySettingsSecretAgentClass),
362+ (GBaseInitFunc) NULL,
363+ (GBaseFinalizeFunc) NULL,
364+ (GClassInitFunc) unity_settings_secret_agent_class_init,
365+ (GClassFinalizeFunc) NULL,
366+ NULL,
367+ sizeof (UnitySettingsSecretAgent),
368+ 0,
369+ (GInstanceInitFunc) unity_settings_secret_agent_instance_init,
370+ NULL
371+ };
372+ GType unity_settings_secret_agent_type_id;
373+ unity_settings_secret_agent_type_id = g_type_register_static (NM_TYPE_SECRET_AGENT,
374+ "UnitySettingsSecretAgent",
375+ &g_define_type_info,
376+ 0);
377+ g_once_init_leave (&unity_settings_secret_agent_type_id__volatile,
378+ unity_settings_secret_agent_type_id);
379+ }
380+
381+ return unity_settings_secret_agent_type_id__volatile;
382+}
plugins/Unity/Indicators/Network/secret-agent.hnew file+102
@@ -0,0 +1,102 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Alberto Ruiz <alberto.ruiz@canonical.com>
18+ * Renato Araujo Oliveira Filho <renato@canonical.com>
19+ */
20+
21+#ifndef __SECRET_AGENT_H__
22+#define __SECRET_AGENT_H__
23+
24+#include <glib.h>
25+#include <glib-object.h>
26+#include <nm-secret-agent.h>
27+
28+/*
29+ * This class is a basic implementation of the NetworkManager SecretAgent base class.
30+ *
31+ * The purpose of this class is to handle credential requests from the network,
32+ * for example, from a WiFi hotspot or a VPN network.
33+ *
34+ * It queues requests objects (SecretRequest) on a GQueue in the private struct
35+ * of the class. And notifies the consumer of the class through the "secret-request"
36+ * and the "request-cancelled" signals with the following callback prototypes:
37+ *
38+ * void (*secret_requested) (UnitySettingsSecretAgent *self,
39+ * guint id,
40+ * NMConnection *connection,
41+ * const char *setting_name,
42+ * const char **hints,
43+ * NMSecretAgentGetSecretsFlags flags,
44+ * gpointer user_data);
45+ *
46+ * void (*request_cancelled) (UnitySettingsSecretAgent *self,
47+ * guint id,
48+ * gpointer user_data);
49+ *
50+ */
51+
52+
53+G_BEGIN_DECLS
54+
55+
56+#define UNITY_SETTINGS_TYPE_SECRET_AGENT (unity_settings_secret_agent_get_type ())
57+#define UNITY_SETTINGS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgent))
58+#define UNITY_SETTINGS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
59+#define UNITY_SETTINGS_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT))
60+#define UNITY_SETTINGS_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_SETTINGS_TYPE_SECRET_AGENT))
61+#define UNITY_SETTINGS_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_SETTINGS_TYPE_SECRET_AGENT, UnitySettingsSecretAgentClass))
62+
63+#define UNITY_SETTINGS_SECRET_AGENT_SECRET_REQUESTED "secret-requested"
64+#define UNITY_SETTINGS_SECRET_AGENT_REQUEST_CANCELLED "request-cancelled"
65+
66+typedef struct _UnitySettingsSecretAgent UnitySettingsSecretAgent;
67+typedef struct _UnitySettingsSecretAgentClass UnitySettingsSecretAgentClass;
68+typedef struct _UnitySettingsSecretAgentPrivate UnitySettingsSecretAgentPrivate;
69+
70+struct _UnitySettingsSecretAgent {
71+ NMSecretAgent parent_instance;
72+ UnitySettingsSecretAgentPrivate * priv;
73+};
74+
75+struct _UnitySettingsSecretAgentClass {
76+ NMSecretAgentClass parent_class;
77+
78+ void (*secret_requested) (UnitySettingsSecretAgent *self,
79+ guint id,
80+ NMConnection *connection,
81+ const char *setting_name,
82+ const char **hints,
83+ NMSecretAgentGetSecretsFlags flags);
84+
85+ void (*request_cancelled) (UnitySettingsSecretAgent *self,
86+ guint id);
87+};
88+
89+
90+GType unity_settings_secret_agent_get_type (void) G_GNUC_CONST;
91+UnitySettingsSecretAgent* unity_settings_secret_agent_new (void);
92+UnitySettingsSecretAgent* unity_settings_secret_agent_construct (GType object_type);
93+
94+void unity_settings_secret_agent_provide_secret (UnitySettingsSecretAgent *agent,
95+ guint request,
96+ GHashTable *secrets);
97+void unity_settings_secret_agent_cancel_request (UnitySettingsSecretAgent *agent,
98+ guint request);
99+
100+G_END_DECLS
101+
102+#endif
plugins/Unity/Indicators/qml/MenuItemFactory.qml+21
@@ -19,6 +19,7 @@
1919
2020import QtQuick 2.0
2121import Unity.Indicators 0.1 as Indicators
22+import Unity.Indicators.Network 0.1 as ICNetwork
2223
2324Item {
2425 id: menuFactory
@@ -38,6 +39,9 @@ Item {
3839
3940 "com.canonical.unity.slider" : sliderMenu,
4041 "com.canonical.unity.switch" : switchMenu,
42+
43+ "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
44+ "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
4145 }
4246
4347 Component {
@@ -57,6 +61,23 @@ Item {
5761 Component { id: progressMenu; Indicators.ProgressMenuItem {} }
5862 Component { id: standardMenu; Indicators.StandardMenuItem {} }
5963 Component { id: switchMenu; Indicators.SwitchMenuItem {} }
64+ Component {
65+ id: wifiSection;
66+ ICNetwork.WifiSection {
67+ Component.onCompleted: {
68+ model.loadExtendedAttributes(modelIndex, {'x-canonical-busy-action': 'bool'});
69+ }
70+ }
71+ }
72+ Component {
73+ id: accessPoint;
74+ ICNetwork.AccessPoint {
75+ Component.onCompleted: {
76+ model.loadExtendedAttributes(modelIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
77+ 'x-canonical-wifi-ap-is-secure': 'bool'});
78+ }
79+ }
80+ }
6081
6182 function load(modelData) {
6283 if (modelData.type !== undefined) {
plugins/Unity/IndicatorsLegacy/Network/CMakeLists.txt+8−8
@@ -1,26 +1,26 @@
11# export_qmlplugin macro
22include(Plugins)
33
4−project(IndicatorsNetworkQml)
4+project(IndicatorsLegacyNetworkQml)
55
66pkg_check_modules(GLIB glib-2.0>=2.32)
77pkg_check_modules(LIBNM_GLIB libnm-glib>=0.9.6)
88pkg_check_modules(LIBNM_UTIL libnm-util>=0.9.6)
99
1010if(LIBNM_GLIB_FOUND AND LIBNM_UTIL_FOUND AND GLIB_FOUND)
11− set(INDICATORS_NETWORK_SRC
11+ set(INDICATORS_LEGACY_NETWORK_SRC
1212 networkagent.cpp
1313 plugin.cpp
1414 secret-agent.c
1515 )
1616
17− add_library(IndicatorsNetworkQml MODULE
18− ${INDICATORS_NETWORK_SRC}
17+ add_library(IndicatorsLegacyNetworkQml MODULE
18+ ${INDICATORS_LEGACY_NETWORK_SRC}
1919 )
2020
21− qt5_use_modules(IndicatorsNetworkQml Core Qml Widgets)
21+ qt5_use_modules(IndicatorsLegacyNetworkQml Core Qml Widgets)
2222
23− set_target_properties(IndicatorsNetworkQml PROPERTIES COMPILE_FLAGS -fPIC)
23+ set_target_properties(IndicatorsLegacyNetworkQml PROPERTIES COMPILE_FLAGS -fPIC)
2424
2525 include_directories(
2626 ${CMAKE_CURRENT_SOURCE_DIR}
@@ -29,14 +29,14 @@ if(LIBNM_GLIB_FOUND AND LIBNM_UTIL_FOUND AND GLIB_FOUND)
2929 ${LIBNM_UTIL_INCLUDE_DIRS}
3030 )
3131
32− target_link_libraries(IndicatorsNetworkQml
32+ target_link_libraries(IndicatorsLegacyNetworkQml
3333 ${GLIB_LIBRARIES}
3434 ${LIBNM_GLIB_LIBRARIES}
3535 ${LIBNM_UTIL_LIBRARIES}
3636 )
3737
3838 # export the qmltypes and plugin files
39− export_qmlplugin(Unity.IndicatorsLegacy.Network 0.1 Unity/IndicatorsLegacy/Network TARGETS IndicatorsNetworkQml)
39+ export_qmlplugin(Unity.IndicatorsLegacy.Network 0.1 Unity/IndicatorsLegacy/Network TARGETS IndicatorsLegacyNetworkQml)
4040
4141else()
4242 message(WARNING "Missing glib or libnm dependency for the network plugin, not building")
plugins/Unity/IndicatorsLegacy/Network/qml/qmldir+1−1
@@ -1,5 +1,5 @@
11module Unity.IndicatorsLegacy.Network
2−plugin IndicatorsNetworkQml
2+plugin IndicatorsLegacyNetworkQml
33typeinfo plugin.qmltypes
44
55NetworkPage 0.1 NetworkPage.qml
plugins/Unity/Launcher/launchermodel.cpp+28
@@ -25,6 +25,9 @@ LauncherModel::LauncherModel(QObject *parent):
2525 LauncherModelInterface(parent),
2626 m_backend(new LauncherBackend(true, this))
2727{
28+ connect(m_backend, SIGNAL(countChanged(QString,int)), SLOT(countChanged(QString,int)));
29+ connect(m_backend, SIGNAL(progressChanged(QString,int)), SLOT(progressChanged(QString,int)));
30+
2831 Q_FOREACH (const QString &entry, m_backend->storedApplications()) {
2932 LauncherItem *item = new LauncherItem(entry,
3033 m_backend->desktopFile(entry),
@@ -67,6 +70,10 @@ QVariant LauncherModel::data(const QModelIndex &index, int role) const
6770 return item->icon();
6871 case RolePinned:
6972 return item->pinned();
73+ case RoleCount:
74+ return item->count();
75+ case RoleProgress:
76+ return item->progress();
7077 }
7178
7279 return QVariant();
@@ -205,3 +212,24 @@ int LauncherModel::findApplication(const QString &appId)
205212 }
206213 return -1;
207214}
215+
216+void LauncherModel::progressChanged(const QString &appId, int progress)
217+{
218+ int idx = findApplication(appId);
219+ if (idx >= 0) {
220+ LauncherItem *item = m_list.at(idx);
221+ item->setProgress(progress);
222+ Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleProgress);
223+ }
224+}
225+
226+
227+void LauncherModel::countChanged(const QString &appId, int count)
228+{
229+ int idx = findApplication(appId);
230+ if (idx >= 0) {
231+ LauncherItem *item = m_list.at(idx);
232+ item->setCount(count);
233+ Q_EMIT dataChanged(index(idx), index(idx), QVector<int>() << RoleCount);
234+ }
235+}
plugins/Unity/Launcher/launchermodel.h+4
@@ -54,6 +54,10 @@ private:
5454 void storeAppList();
5555 int findApplication(const QString &appId);
5656
57+private Q_SLOTS:
58+ void progressChanged(const QString &appId, int progress);
59+ void countChanged(const QString &appId, int count);
60+
5761private:
5862 QList<LauncherItem*> m_list;
5963 LauncherBackend *m_backend;
plugins/Unity/categories.cpp+6
@@ -39,6 +39,7 @@ Categories::Categories(QObject* parent)
3939 m_roles[Categories::RoleIcon] = "icon";
4040 m_roles[Categories::RoleRenderer] = "renderer";
4141 m_roles[Categories::RoleContentType] = "contentType";
42+ m_roles[Categories::RoleProgressSource] = "progressSource";
4243 m_roles[Categories::RoleHints] = "hints";
4344 m_roles[Categories::RoleResults] = "results";
4445 m_roles[Categories::RoleCount] = "count";
@@ -198,6 +199,11 @@ Categories::data(const QModelIndex& index, int role) const
198199 auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
199200 return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
200201 }
202+ case RoleProgressSource:
203+ {
204+ auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
205+ return hints.contains("progress-source") ? hints["progress-source"] : QVariant();
206+ }
201207 case RoleHints:
202208 return DeeListModel::data(index, CategoryColumn::HINTS);
203209 case RoleResults:
plugins/Unity/categories.h+1
@@ -47,6 +47,7 @@ public:
4747 RoleIcon,
4848 RoleRenderer,
4949 RoleContentType,
50+ RoleProgressSource,
5051 RoleHints,
5152 RoleResults,
5253 RoleCount,
plugins/Unity/genericoptionsmodel.cpp+2−2
@@ -76,9 +76,9 @@ int GenericOptionsModel::rowCount(const QModelIndex& /* parent */) const
7676 return m_options.size ();
7777}
7878
79−void GenericOptionsModel::setActive(QVector<AbstractFilterOption *>::size_type idx, bool value)
79+void GenericOptionsModel::setActive(int idx, bool value)
8080{
81− if (idx < m_options.size())
81+ if (idx >= 0 && idx < m_options.size())
8282 {
8383 m_options[idx]->setActive(value);
8484 }
plugins/Unity/genericoptionsmodel.h+1−1
@@ -49,7 +49,7 @@ public:
4949 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
5050 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
5151
52− Q_INVOKABLE void setActive(QVector<AbstractFilterOption *>::size_type idx, bool value);
52+ Q_INVOKABLE void setActive(int idx, bool value);
5353 Q_INVOKABLE void setActive(const QString &id, bool value);
5454
5555 AbstractFilterOption* getRawOption(QVector<AbstractFilterOption *>::size_type idx) const;
plugins/Unity/plugin.cpp+2
@@ -33,6 +33,7 @@
3333#include "categories.h"
3434#include "categoryresults.h"
3535#include "bottombarvisibilitycommunicatorshell.h"
36+#include "genericoptionsmodel.h"
3637
3738// libqtdee
3839#include "deelistmodel.h"
@@ -47,6 +48,7 @@ void UnityPlugin::registerTypes(const char *uri)
4748 qmlRegisterUncreatableType<PreviewAction>(uri, 0, 1, "PreviewAction", "Can't create PreviewAction object in QML.");
4849 qmlRegisterUncreatableType<PreviewInfoHint>(uri, 0, 1, "PreviewInfoHint", "Can't create PreviewInfoHint object in QML.");
4950 qmlRegisterUncreatableType<SocialPreviewComment>(uri, 0, 1, "SocialPreviewComment", "Can't create SocialPreviewComment object in QML.");
51+ qmlRegisterUncreatableType<GenericOptionsModel>(uri, 0, 1, "GenericOptionsModel", "Can't create options model in QML.");
5052 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
5153 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
5254 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
plugins/Utils/qlimitproxymodelqml.cpp+90−4
@@ -25,6 +25,8 @@ QLimitProxyModelQML::QLimitProxyModelQML(QObject *parent)
2525 , m_limit(-1)
2626 , m_sourceInserting(false)
2727 , m_sourceRemoving(false)
28+ , m_dataChangedBegin(-1)
29+ , m_dataChangedEnd(-1)
2830{
2931 connect(this, SIGNAL(modelReset()), SIGNAL(countChanged()));
3032 connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(countChanged()));
@@ -130,8 +132,45 @@ QLimitProxyModelQML::sourceRowsAboutToBeInserted(const QModelIndex &parent, int
130132 beginInsertRows(mapFromSource(parent), start, end);
131133 m_sourceInserting = true;
132134 } else if (start < m_limit) {
133− beginInsertRows(mapFromSource(parent), start, qMin(m_limit - 1, end));
134− m_sourceInserting = true;
135+ const int nSourceAddedItems = end - start + 1;
136+ const int currentCount = QIdentityProxyModel::rowCount();
137+ if (currentCount + nSourceAddedItems <= m_limit) {
138+ // After Inserting items we will be under the limit
139+ // so just proceed with the insertion normally
140+ beginInsertRows(mapFromSource(parent), start, end);
141+ m_sourceInserting = true;
142+ } else if (currentCount >= m_limit) {
143+ // We are already over the limit so to our users we are not adding items, just
144+ // changing it's data, i.e we had something like
145+ // A B C D E
146+ // with a limit of 5
147+ // after inserting (let's say three 'F' at position 1) we will have
148+ // A F F F B
149+ // so we just need to signal a dataChanged from 1 to 4
150+ m_dataChangedBegin = start;
151+ m_dataChangedEnd = m_limit - 1;
152+ } else { // currentCount < m_limit && currentCount + nSourceAddedItems > m_limit
153+ // We have less items than the limit but after adding them we will be over
154+ // To our users this means we need to insert some items and change the
155+ // data of some others, i.e we had something like
156+ // A B C
157+ // with a limit of 5
158+ // after inserting (let's say three 'F' at position 1) we will have
159+ // A F F F B
160+ // so we need to signal an insetion from position 1 to 2, instead of from
161+ // position 1 to 3 and a after that a data changed from 3 to 4
162+ const int nItemsToInsert = m_limit - currentCount;
163+ beginInsertRows(mapFromSource(parent), start, start + nItemsToInsert - 1);
164+ m_sourceInserting = true;
165+ m_dataChangedBegin = start + nItemsToInsert;
166+ m_dataChangedEnd = m_limit - 1;
167+ if (m_dataChangedBegin > m_dataChangedEnd) {
168+ // Just in case we were empty and insert 6 items with a limit of 5
169+ // We don't want to signal a dataChanged from 5 to 4
170+ m_dataChangedBegin = -1;
171+ m_dataChangedEnd = -1;
172+ }
173+ }
135174 }
136175}
137176
@@ -142,8 +181,45 @@ QLimitProxyModelQML::sourceRowsAboutToBeRemoved(const QModelIndex &parent, int s
142181 beginRemoveRows(mapFromSource(parent), start, end);
143182 m_sourceRemoving = true;
144183 } else if (start < m_limit) {
145− beginRemoveRows(mapFromSource(parent), start, qMin(m_limit - 1, end));
146− m_sourceRemoving = true;
184+ const int nSourceRemovedItems = end - start + 1;
185+ const int currentCount = QIdentityProxyModel::rowCount();
186+ if (currentCount <= m_limit) {
187+ // We are already under the limit so
188+ // so just proceed with the removal normally
189+ beginRemoveRows(mapFromSource(parent), start, end);
190+ m_sourceRemoving = true;
191+ } else if (currentCount - nSourceRemovedItems >= m_limit) {
192+ // Even after removing items we will be at or over the limit
193+ // So to our users we are not removing anything, just changing the data
194+ // i.e. we had a internal model with
195+ // A B C D E F G H
196+ // and a limit of 5, our users just see
197+ // A B C D E
198+ // so if we remove 3 items starting at 1 we have to expose
199+ // A E F G H
200+ // that is, a dataChanged from 1 to 4
201+ m_dataChangedBegin = start;
202+ m_dataChangedEnd = m_limit - 1;
203+ } else { // currentCount > m_limit && currentCount - nSourceRemovedItems < m_limit
204+ // We have more items than the limit but after removing we will be below it
205+ // So to our users we both removing and changing the data
206+ // i.e. we had a internal model with
207+ // A B C D E F G
208+ // and a limit of 5, our users just see
209+ // A B C D E
210+ // so if we remove items from 1 to 3 we have to expose
211+ // A E F G
212+ // that is, a remove from 4 to 4 and a dataChanged from 1 to 3
213+ const int nItemsToRemove = m_limit - (currentCount - nSourceRemovedItems);
214+ beginRemoveRows(mapFromSource(parent), m_limit - nItemsToRemove, m_limit - 1);
215+ m_sourceRemoving = true;
216+ m_dataChangedBegin = start;
217+ m_dataChangedEnd = m_limit - nItemsToRemove - 1;
218+ if (m_dataChangedBegin > m_dataChangedEnd) {
219+ m_dataChangedBegin = -1;
220+ m_dataChangedEnd = -1;
221+ }
222+ }
147223 }
148224}
149225
@@ -154,6 +230,11 @@ QLimitProxyModelQML::sourceRowsInserted(const QModelIndex & /*parent*/, int /*st
154230 endInsertRows();
155231 m_sourceInserting = false;
156232 }
233+ if (m_dataChangedBegin != -1 && m_dataChangedEnd != -1) {
234+ dataChanged(index(m_dataChangedBegin, 0), index(m_dataChangedEnd, 0));
235+ m_dataChangedBegin = -1;
236+ m_dataChangedEnd = -1;
237+ }
157238}
158239
159240void
@@ -163,4 +244,9 @@ QLimitProxyModelQML::sourceRowsRemoved(const QModelIndex & /*parent*/, int /*sta
163244 endRemoveRows();
164245 m_sourceRemoving = false;
165246 }
247+ if (m_dataChangedBegin != -1 && m_dataChangedEnd != -1) {
248+ dataChanged(index(m_dataChangedBegin, 0), index(m_dataChangedEnd, 0));
249+ m_dataChangedBegin = -1;
250+ m_dataChangedEnd = -1;
251+ }
166252}
plugins/Utils/qlimitproxymodelqml.h+2
@@ -55,6 +55,8 @@ private:
5555 int m_limit;
5656 bool m_sourceInserting;
5757 bool m_sourceRemoving;
58+ int m_dataChangedBegin;
59+ int m_dataChangedEnd;
5860};
5961
6062#endif // QLIMITPROXYMODELQML_H
po/ar.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
1818"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/az.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/bg.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
1818"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/ca.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/de.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/el.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/en_AU.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:26+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/en_GB.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:26+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/eo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/es.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/fi.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/fo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/fr.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/gl.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/he.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/hr.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/hu.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/hy.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/id.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/it.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/ja.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/kn.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/ko.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/ky.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/lv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/my.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/nb.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/nl.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/pl.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
1818"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/pt_BR.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:26+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/ro.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
1818"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/ru.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/si.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/sl.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
1818"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/sr.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/sv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/te.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/tr.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/ug.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:25+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/uk.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2013-08-14 06:26+0000\n"
20−"X-Generator: Launchpad (build 16723)\n"
19+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
20+"X-Generator: Launchpad (build 16734)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
po/unity8.pot+55−43
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2013-08-09 12:18+0200\n"
11+"POT-Creation-Date: 2013-08-22 09:59-0400\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -86,25 +86,29 @@ msgstr ""
8686msgid "YouTube"
8787msgstr ""
8888
89+#: Components/DemoOverlay.qml:44
90+msgid "Skip intro"
91+msgstr ""
92+
8993#: Components/PageHeader.qml:298
9094msgid "Recent searches"
9195msgstr ""
9296
9397#. TRANSLATORS: Number of persons who rated this app
94−#: Dash/Apps/AppInfo.qml:72
98+#: Dash/Apps/AppInfo.qml:73
9599#, qt-format
96100msgid "(%1)"
97101msgstr ""
98102
99103#. TRANSLATORS: Number of persons who wrote reviews for this app
100−#: Dash/Apps/AppInfo.qml:84 tests/qmltests/Dash/Apps/tst_AppPreview.qml:115
104+#: Dash/Apps/AppInfo.qml:85
101105#, qt-format
102106msgid "%1 review"
103107msgid_plural "%1 reviews"
104108msgstr[0] ""
105109msgstr[1] ""
106110
107−#: Dash/Apps/AppPreview.qml:181
111+#: Dash/Apps/AppPreview.qml:175
108112msgid "Rate this"
109113msgstr ""
110114
@@ -124,42 +128,6 @@ msgstr ""
124128msgid "Comments:"
125129msgstr ""
126130
127−#: Dash/DashApps.qml:65
128−msgid "Running apps"
129−msgstr ""
130−
131−#: Dash/DashApps.qml:68
132−msgid "Frequently used"
133−msgstr ""
134−
135−#: Dash/DashApps.qml:71
136−msgid "Installed"
137−msgstr ""
138−
139−#: Dash/DashApps.qml:74
140−msgid "Available for download"
141−msgstr ""
142−
143−#: Dash/DashApps.qml:168
144−msgid "Apps"
145−msgstr ""
146−
147−#: Dash/DashHome.qml:41
148−msgid "Frequent Apps"
149−msgstr ""
150−
151−#: Dash/DashHome.qml:44
152−msgid "Recent Music"
153−msgstr ""
154−
155−#: Dash/DashHome.qml:47
156−msgid "Videos Popular Online"
157−msgstr ""
158−
159−#: Dash/DashHome.qml:151
160−msgid "Home"
161−msgstr ""
162−
163131#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
164132msgid "Featured"
165133msgstr ""
@@ -200,7 +168,7 @@ msgstr ""
200168msgid "Author:"
201169msgstr ""
202170
203−#: Greeter/Lockscreen.qml:133
171+#: Greeter/Lockscreen.qml:134
204172msgid "Emergency Call"
205173msgstr ""
206174
@@ -237,11 +205,55 @@ msgstr ""
237205msgid "Search"
238206msgstr ""
239207
240−#: plugins/Unity/scope.cpp:298
208+#: plugins/Unity/scope.cpp:317
241209msgid "Sorry, there is nothing that matches your search."
242210msgstr ""
243211
244−#: Shell.qml:399
212+#: Shell.qml:240
213+msgid "Top edge"
214+msgstr ""
215+
216+#: Shell.qml:241
217+msgid "Try swiping from the top edge to access the indicators"
218+msgstr ""
219+
220+#: Shell.qml:262
221+msgid "Left edge"
222+msgstr ""
223+
224+#: Shell.qml:263
225+msgid "Swipe from the left to reveal the launcher for quick access to apps"
226+msgstr ""
227+
228+#: Shell.qml:487
245229#, qt-format
246230msgid "Please enter %1"
247231msgstr ""
232+
233+#: Shell.qml:537
234+msgid "Right edge"
235+msgstr ""
236+
237+#: Shell.qml:538
238+msgid "Try swiping from the right edge to unlock the phone"
239+msgstr ""
240+
241+#: Shell.qml:630
242+msgid "Close"
243+msgstr ""
244+
245+#: Shell.qml:631
246+msgid "Swipe up again to close the settings screen"
247+msgstr ""
248+
249+#: Shell.qml:771
250+msgid "Well done"
251+msgstr ""
252+
253+#: Shell.qml:772
254+msgid "You have now mastered the edge gestures and can start using the phone"
255+msgstr ""
256+
257+#: Shell.qml:773
258+msgid "Finish"
259+msgstr ""
po/zh_CN.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:26+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/zh_TW.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2013-08-14 06:26+0000\n"
19−"X-Generator: Launchpad (build 16723)\n"
18+"X-Launchpad-Export-Date: 2013-08-22 06:11+0000\n"
19+"X-Generator: Launchpad (build 16734)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
src/Panel/Indicators/servicefiles/CMakeLists.txt−1
@@ -1,6 +1,5 @@
11file(GLOB INDICATOR_SERVICE_FILES
22 ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.indicator.messages
3− ${CMAKE_CURRENT_SOURCE_DIR}/com.canonical.settings.network
43)
54
65# copy indicators files into build directory for shadow builds
src/Panel/Indicators/servicefiles/com.canonical.settings.networkdeleted−10
@@ -1,10 +0,0 @@
1−[Indicator Service]
2−Name=chewie-network
3−ObjectPath=/com/canonical/settings/network
4−Position=69
5−
6−[phone]
7−ObjectPath=/com/canonical/settings/network/phone
8−
9−[desktop]
10−ObjectPath=/com/canonical/settings/network/desktop
tests/mocks/Powerd/Powerd.h+15−2
@@ -20,17 +20,30 @@
2020#define UNITY_MOCK_POWERD_H
2121
2222#include <QtCore/QObject>
23−#include <QtDBus/QDBusInterface>
2423
2524class Powerd: public QObject
2625{
2726 Q_OBJECT
27+ Q_ENUMS(Status)
28+ Q_FLAGS(DisplayFlag DisplayFlags)
2829
2930public:
31+ enum DisplayFlag {
32+ UseProximity = 1, // Use proximity sensor to override screen state
33+ DisableAutoBrightness = 2, // Force autobrightness to be disabled
34+ Bright = 4, // Request the screen to stay bright
35+ };
36+ Q_DECLARE_FLAGS(DisplayFlags, DisplayFlag)
37+
38+ enum Status {
39+ Off,
40+ On,
41+ };
42+
3043 explicit Powerd(QObject *parent = 0);
3144
3245Q_SIGNALS:
33− void powerStateChange(int state);
46+ void displayPowerStateChange(int status, unsigned int flags);
3447};
3548
3649#endif
tests/mocks/Unity/Launcher/MockLauncherModel.cpp+6
@@ -174,3 +174,9 @@ int MockLauncherModel::findApp(const QString &appId)
174174 }
175175 return -1;
176176}
177+
178+void MockLauncherModel::setUser(const QString &username)
179+{
180+ Q_UNUSED(username)
181+ // TODO: implement this...
182+}
tests/mocks/Unity/Launcher/MockLauncherModel.h+1
@@ -43,6 +43,7 @@ public:
4343 Q_INVOKABLE void pin(const QString &appId, int index = -1);
4444 Q_INVOKABLE void requestRemove(const QString &appId);
4545 Q_INVOKABLE void quickListActionInvoked(const QString &appId, int actionIndex);
46+ Q_INVOKABLE void setUser(const QString &username);
4647
4748Q_SIGNALS:
4849 void quickListTriggered(const QString &appId, int index);
tests/plugins/AccountsService/AccountsServer.h+4−4
@@ -20,10 +20,10 @@
2020#ifndef UNITY_ACCOUNTSSERVER_H
2121#define UNITY_ACCOUNTSSERVER_H
2222
23−#include <QtCore/QObject>
24−#include <QtCore/QString>
25−#include <QtDBus/QDBusContext>
26−#include <QtDBus/QDBusObjectPath>
23+#include <QDBusContext>
24+#include <QDBusObjectPath>
25+#include <QObject>
26+#include <QString>
2727
2828class AccountsServer: public QObject, protected QDBusContext
2929{
tests/plugins/AccountsService/PropertiesServer.h+4−4
@@ -21,10 +21,10 @@
2121#define UNITY_PROPERTIESSERVER_H
2222
2323#include "PropertiesServer.h"
24−#include <QtCore/QObject>
25−#include <QtCore/QString>
26−#include <QtDBus/QDBusContext>
27−#include <QtDBus/QDBusVariant>
24+#include <QDBusContext>
25+#include <QDBusVariant>
26+#include <QObject>
27+#include <QString>
2828
2929class PropertiesServer: public QObject, protected QDBusContext
3030{
tests/plugins/AccountsService/client.cpp+2−2
@@ -18,8 +18,8 @@
1818 */
1919
2020#include "AccountsService.h"
21−#include <QtTest/QSignalSpy>
22−#include <QtTest/QTest>
21+#include <QSignalSpy>
22+#include <QTest>
2323
2424class AccountsServiceTest : public QObject
2525{
tests/plugins/AccountsService/server.cpp+1−1
@@ -21,7 +21,7 @@
2121#include "AccountsServer.h"
2222#include "PropertiesAdaptor.h"
2323#include "PropertiesServer.h"
24−#include <QtCore/QCoreApplication>
24+#include <QCoreApplication>
2525
2626int main(int argc, char *argv[])
2727{
tests/plugins/Utils/qlimitproxymodeltest.cpp+133−8
@@ -58,10 +58,17 @@ public:
5858 m_roles = roles;
5959 }
6060
61+ void clear()
62+ {
63+ beginRemoveRows(QModelIndex(), 0, m_list.count() - 1);
64+ m_list.clear();
65+ endRemoveRows();
66+ }
67+
6168 bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) {
6269 beginInsertRows(parent, row, row+count-1);
6370 for (int i=0; i<count; i++) {
64− m_list.insert(i+row, "test"+i);
71+ m_list.insert(i+row, QString::number(i));
6572 }
6673 endInsertRows();
6774 return true;
@@ -88,6 +95,60 @@ private:
8895 QHash<int, QByteArray> m_roles;
8996};
9097
98+class MirrorModel : public QObject
99+{
100+ Q_OBJECT
101+
102+public:
103+ MirrorModel(QAbstractItemModel *model) : m_mirror(model)
104+ {
105+ connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
106+ connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(rowsRemoved(QModelIndex,int,int)));
107+ connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(dataChanged(QModelIndex,QModelIndex)));
108+ }
109+
110+ void check()
111+ {
112+ QCOMPARE(m_list.count(), m_mirror->rowCount());
113+ for (int i = 0; i < m_list.count(); ++i) {
114+ QCOMPARE(m_list[i], m_mirror->data(m_mirror->index(i, 0)).toString());
115+ }
116+ }
117+
118+private Q_SLOTS:
119+ void rowsInserted(const QModelIndex &parent, int start, int end)
120+ {
121+ QVERIFY(!parent.isValid());
122+ for (int i = start; i <= end; ++i) {
123+ m_list.insert(i, m_mirror->data(m_mirror->index(i, 0)).toString());
124+ }
125+ }
126+
127+ void rowsRemoved(const QModelIndex &parent, int start, int end)
128+ {
129+ QVERIFY(!parent.isValid());
130+ for (int i = end; i >= start; --i) {
131+ m_list.removeAt(i);
132+ }
133+ }
134+
135+ void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
136+ {
137+ QVERIFY(topLeft.isValid());
138+ QVERIFY(bottomRight.isValid());
139+ QVERIFY(!topLeft.parent().isValid());
140+ QVERIFY(!bottomRight.parent().isValid());
141+ for (int i = topLeft.row(); i <= bottomRight.row(); ++i) {
142+ m_list[i] = m_mirror->data(m_mirror->index(i, 0)).toString();
143+ }
144+ }
145+
146+
147+private:
148+ QStringList m_list;
149+ QAbstractItemModel *m_mirror;
150+};
151+
91152class QLimitProxyModelTest : public QObject
92153{
93154 Q_OBJECT
@@ -401,15 +462,10 @@ private Q_SLOTS:
401462 QCOMPARE(spyOnCountChanged.count(), 0);
402463
403464 model.removeRows(2, 2);
404− QCOMPARE(spyOnRowsRemoved.count(), 1);
465+ QCOMPARE(spyOnRowsRemoved.count(), 0);
405466 QCOMPARE(spyOnRowsInserted.count(), 0);
406− QCOMPARE(spyOnCountChanged.count(), 1);
407− arguments = spyOnRowsRemoved.takeFirst();
408− QCOMPARE(arguments.at(1).toInt(), 2);
409− QCOMPARE(arguments.at(2).toInt(), 3);
467+ QCOMPARE(spyOnCountChanged.count(), 0);
410468 QCOMPARE(proxy.rowCount(), 7);
411− spyOnRowsInserted.clear();
412− spyOnCountChanged.clear();
413469
414470 model.removeRows(0, 7);
415471 QCOMPARE(spyOnRowsRemoved.count(), 1);
@@ -479,6 +535,75 @@ private Q_SLOTS:
479535 QCOMPARE(proxy.rowCount(), 5);
480536 QCOMPARE(spyOnCountChanged.count(), 1);
481537 }
538+
539+ void testMirrorModel() {
540+ QLimitProxyModelQML proxy;
541+ MockListModel model;
542+ MirrorModel mirror(&proxy);
543+
544+ proxy.setModel(&model);
545+ proxy.setLimit(5);
546+
547+ // Checks what happens when the model already has
548+ // more items than the limit and we add stuff to
549+ // the front
550+ model.insertRows(0, 7);
551+ mirror.check();
552+ model.insertRows(1, 3);
553+ mirror.check();
554+ model.clear();
555+ mirror.check();
556+
557+ // Checks what happens when the model does
558+ // not has more items than limit but adding
559+ // stuff to its front makes it go past the limit
560+ model.insertRows(0, 3);
561+ mirror.check();
562+ model.insertRows(1, 3);
563+ mirror.check();
564+ model.clear();
565+ mirror.check();
566+
567+ // Checks what happens when the model does
568+ // not has more items than limit and adding
569+ // stuff to its front makes it not go past the limit
570+ model.insertRows(0, 1);
571+ mirror.check();
572+ model.insertRows(1, 3);
573+ mirror.check();
574+ model.clear();
575+ mirror.check();
576+
577+ // Checks what happens when the model already has
578+ // more items than the limit and we remove stuff from
579+ // the front but it still has more than the limit
580+ model.insertRows(0, 10);
581+ mirror.check();
582+ model.removeRows(1, 3);
583+ mirror.check();
584+ model.clear();
585+ mirror.check();
586+
587+ // Checks what happens when the model already has
588+ // more items than the limit and we remove stuff from
589+ // the front but it has less than the limit
590+ model.insertRows(0, 6);
591+ mirror.check();
592+ model.removeRows(1, 3);
593+ mirror.check();
594+ model.clear();
595+ mirror.check();
596+
597+ // Checks what happens when the model has
598+ // less items than the limit and we remove stuff from
599+ // the front
600+ model.insertRows(0, 4);
601+ mirror.check();
602+ model.removeRows(1, 3);
603+ mirror.check();
604+ model.clear();
605+ mirror.check();
606+ }
482607};
483608
484609QTEST_GUILESS_MAIN(QLimitProxyModelTest)
tests/qmltests/CMakeLists.txt+1−1
@@ -28,9 +28,9 @@ set(qmltest_DEFAULT_PROPERTIES "")
2828
2929add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks
3030 ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
31−add_qml_test(Components DemoOverlay)
3231add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
3332add_qml_test(Components DraggingArea)
33+add_qml_test(Components EdgeDemoOverlay)
3434add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
3535add_qml_test(Components ResponsiveFlowView)
3636add_qml_test(Components ResponsiveGridView)
tests/qmltests/Components/tst_DemoOverlay.qmldeleted−99
@@ -1,99 +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 Unity.Test 0.1 as UT
20−import "../../../Components"
21−
22−Item {
23− id: root
24− width: 700
25− height: 500
26−
27− DemoOverlay {
28− id: top
29− edge: "top"
30− title: "Top"
31− text: "Displayed on top left"
32− x: 0
33− y: 0
34− width: parent.width/2
35− height: parent.height/2
36− }
37−
38− DemoOverlay {
39− id: right
40− edge: "right"
41− title: "Right"
42− text: "Displayed on top right"
43− x: parent.width/2
44− y: 0
45− width: parent.width/2
46− height: parent.height/2
47− }
48−
49− DemoOverlay {
50− id: left
51− edge: "left"
52− title: "Left"
53− text: "Displayed on bottom right"
54− x: parent.width/2
55− y: parent.height/2
56− width: parent.width/2
57− height: parent.height/2
58− enabled: false
59− }
60−
61− DemoOverlay {
62− id: bottom
63− edge: "bottom"
64− title: "Bottom"
65− text: "Displayed on bottom left"
66− x: 0
67− y: parent.height/2
68− width: parent.width/2
69− height: parent.height/2
70− }
71−
72− SignalSpy {
73− id: signalSpy
74− target: bottom
75− }
76−
77− UT.UnityTestCase {
78− name: "DemoOverlay"
79− when: windowShown
80−
81− function test_animations() {
82− compare(right.__anim_running, 1)
83−
84− compare(left.__anim_running, 0)
85− left.enabled = true
86− compare(left.__anim_running, 1)
87− }
88−
89− function test_skip() {
90− signalSpy.signalName = "skip"
91− signalSpy.clear()
92− var bottomSkip = findChild(bottom, "skipLabel")
93− mousePress(bottomSkip, 1, 1)
94− mouseRelease(bottomSkip, 1, 1)
95− signalSpy.wait()
96− compare(bottom.enabled, false)
97− }
98− }
99−}
tests/qmltests/Components/tst_EdgeDemoOverlay.qmlnew file+125
@@ -0,0 +1,125 @@
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 Unity.Test 0.1 as UT
20+import "../../../Components"
21+
22+Item {
23+ id: root
24+ width: boxWidth * 3
25+ height: boxHeight * 2
26+
27+ property int boxWidth: 250
28+ property int boxHeight: 250
29+
30+ EdgeDemoOverlay {
31+ id: top
32+ edge: "top"
33+ title: "Top"
34+ text: "Displayed on top left"
35+ anchors.left: parent.left
36+ anchors.top: parent.top
37+ width: boxWidth
38+ height: boxHeight
39+ }
40+
41+ EdgeDemoOverlay {
42+ id: right
43+ edge: "right"
44+ title: "Right"
45+ text: "Displayed on top right"
46+ anchors.right: parent.right
47+ anchors.top: parent.top
48+ width: boxWidth
49+ height: boxHeight
50+ }
51+
52+ EdgeDemoOverlay {
53+ id: left
54+ edge: "left"
55+ title: "Left"
56+ text: "Displayed on bottom right"
57+ anchors.right: parent.right
58+ anchors.bottom: parent.bottom
59+ width: boxWidth
60+ height: boxHeight
61+ available: false
62+ }
63+
64+ EdgeDemoOverlay {
65+ id: bottom
66+ edge: "bottom"
67+ title: "Bottom"
68+ text: "Displayed on bottom left"
69+ anchors.left: parent.left
70+ anchors.bottom: parent.bottom
71+ width: boxWidth
72+ height: boxHeight
73+ }
74+
75+ EdgeDemoOverlay {
76+ id: none
77+ edge: "none"
78+ title: "None"
79+ text: "Displayed on top middle"
80+ anchors.horizontalCenter: parent.horizontalCenter
81+ anchors.top: parent.top
82+ width: boxWidth
83+ height: boxHeight
84+ }
85+
86+ SignalSpy {
87+ id: signalSpy
88+ }
89+
90+ UT.UnityTestCase {
91+ name: "EdgeDemoOverlay"
92+ when: windowShown
93+
94+ function test_animations() {
95+ var rightAnim = findChild(right, "wholeAnimation")
96+ compare(rightAnim.running, true)
97+
98+ var leftAnim = findChild(left, "wholeAnimation")
99+ compare(leftAnim.running, false)
100+ left.available = true
101+ compare(leftAnim.running, true)
102+ }
103+
104+ function test_skip() {
105+ signalSpy.target = bottom
106+ signalSpy.signalName = "skip"
107+ signalSpy.clear()
108+ var bottomSkip = findChild(bottom, "skipLabel")
109+ mousePress(bottomSkip, 1, 1)
110+ mouseRelease(bottomSkip, 1, 1)
111+ signalSpy.wait()
112+ compare(bottom.available, false)
113+
114+ // Test that the 'none' edge skips anywhere
115+ signalSpy.target = none
116+ signalSpy.clear()
117+ var backgroundShade = findChild(none, "backgroundShade")
118+ tryCompare(none, "opacity", 1)
119+ mousePress(backgroundShade, 1, 1)
120+ mouseRelease(backgroundShade, 1, 1)
121+ signalSpy.wait()
122+ compare(none.available, false)
123+ }
124+ }
125+}
tests/qmltests/Greeter/tst_Clock.qml+1−1
@@ -70,7 +70,7 @@ Rectangle {
7070 compare(clock.__timerRunning, true, "Timer should be running")
7171 wait(0) // spin event loop to trigger the timer
7272 verify(dateLabel.text !== dateString)
73− if (timeLabel.text == "11:13") wait(60000) // next test will fail at 11:13, wait 1 minute
73+ if (timeLabel.text.indexOf("11:13") != -1) wait(60000) // next test will fail at 11:13, wait 1 minute
7474 verify(timeLabel.text !== timeString)
7575 }
7676
tests/qmltests/Launcher/tst_Launcher.qml+33−13
@@ -277,8 +277,9 @@ Item {
277277
278278 function test_dragndrop_data() {
279279 return [
280− {tag: "startDrag", fullDrag: false},
281− {tag: "fullDrag", fullDrag: true},
280+ {tag: "startDrag", fullDrag: false },
281+ {tag: "fullDrag horizontal", fullDrag: true, orientation: ListView.Horizontal },
282+ {tag: "fullDrag vertical", fullDrag: true, orientation: ListView.Vertical },
282283 ];
283284 }
284285
@@ -288,8 +289,8 @@ Item {
288289 var item0 = findChild(launcher, "launcherDelegate0")
289290 var fakeDragItem = findChild(launcher, "fakeDragItem")
290291 var initialItemHeight = draggedItem.height
291− var item5Name = LauncherModel.get(5).iconName
292− var item4Name = LauncherModel.get(4).iconName
292+ var item5 = LauncherModel.get(5).appId
293+ var item4 = LauncherModel.get(4).appId
293294
294295 // Initial state
295296 compare(draggedItem.itemOpacity, 1, "Item's opacity is not 1 at beginning")
@@ -297,28 +298,43 @@ Item {
297298 tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 0)
298299
299300 // Doing longpress
300− mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
301+ var currentMouseX = draggedItem.width / 2
302+ var currentMouseY = draggedItem.height / 2
303+ mousePress(draggedItem, currentMouseX, currentMouseY)
301304 // DraggedItem needs to hide and fakeDragItem become visible
302305 tryCompare(draggedItem, "itemOpacity", 0)
303306 tryCompare(fakeDragItem, "visible", true)
304307
305308 // Dragging a bit (> 1.5 gu)
306− mouseMove(draggedItem, -units.gu(2), draggedItem.height / 2)
309+ currentMouseX -= units.gu(2)
310+ mouseMove(draggedItem, currentMouseX, currentMouseY)
307311 // Other items need to expand and become 0.6 opaque
308312 tryCompare(item0, "angle", 0)
309313 tryCompare(item0, "itemOpacity", 0.6)
310314
311315 if (data.fullDrag) {
312316 // Dragging a bit more
313− mouseMove(draggedItem, -units.gu(15), draggedItem.height / 2, 100)
314− tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 1)
315− tryCompare(draggedItem, "height", units.gu(1))
317+ if (data.orientation == ListView.Horizontal) {
318+ currentMouseX -= units.gu(15)
319+ mouseMove(draggedItem, currentMouseX, currentMouseY, 100)
320+
321+ tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 1)
322+ tryCompare(draggedItem, "height", units.gu(1))
323+
324+ // Dragging downwards. Item needs to move in the model
325+ currentMouseY -= initialItemHeight * 1.5
326+ mouseMove(draggedItem, currentMouseX, currentMouseY)
327+ } else if (data.orientation == ListView.Vertical) {
328+ currentMouseY -= initialItemHeight * 1.5
329+ mouseMove(draggedItem, currentMouseX, currentMouseY, 100)
330+
331+ tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 1)
332+ tryCompare(draggedItem, "height", units.gu(1))
333+ }
316334
317− // Dragging downwards. Item needs to move in the model
318− mouseMove(draggedItem, -units.gu(15), -initialItemHeight)
319335 waitForRendering(draggedItem)
320− compare(LauncherModel.get(5).iconName, item4Name)
321− compare(LauncherModel.get(5).iconName, item5Name)
336+ compare(LauncherModel.get(5).appId, item4)
337+ compare(LauncherModel.get(4).appId, item5)
322338 }
323339
324340 // Releasing and checking if initial values are restored
@@ -326,6 +342,10 @@ Item {
326342 tryCompare(findChild(draggedItem, "dropIndicator"), "opacity", 0)
327343 tryCompare(draggedItem, "itemOpacity", 1)
328344 tryCompare(fakeDragItem, "visible", false)
345+
346+ // Click somewhere in the empty space to make it hide in case it isn't
347+ mouseClick(launcher, launcher.width - units.gu(1), units.gu(1));
348+ revealer.waitUntilLauncherDisappears();
329349 }
330350
331351 function test_quicklist_dismiss() {
tests/qmltests/tst_Shell.qml+7−3
@@ -125,13 +125,17 @@ Item {
125125 var mainApp = ApplicationManager.mainStageFocusedApplication;
126126 tryCompareFunction(function() { return mainApp != null; }, true);
127127
128− // Now suspend
129− Powerd.powerStateChange(0);
128+ // Try to suspend while proximity is engaged...
129+ Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity);
130+ tryCompare(greeter, "showProgress", 0);
131+
132+ // Now really suspend
133+ Powerd.displayPowerStateChange(Powerd.Off, 0);
130134 tryCompare(greeter, "showProgress", 1);
131135 tryCompare(ApplicationManager, "mainStageFocusedApplication", null);
132136
133137 // And wake up
134− Powerd.powerStateChange(1);
138+ Powerd.displayPowerStateChange(Powerd.On, 0);
135139 tryCompare(ApplicationManager, "mainStageFocusedApplication", mainApp);
136140 tryCompare(greeter, "showProgress", 1);
137141 }