on xenial help sign in
Merge from trunk
commite8ce05299c31bc370f3f6fd9eb5c35de5ee8686f authorMichael Terry <michael.terry@canonical.com> dateTue 24 Sep 2013, 15:00 (13 years ago) parentebc518b28f4b33
56 files changed+1282−408
Components/CrossFadeImage.qml−151 Components/VolumeControl.qml+5−20 Dash/GenericScopeView.qml+10−1 Dash/Music/MusicFilterGrid.qml+12−2 Dash/graphics/phone/home.png Dash/graphics/phone/music.png Dash/graphics/phone/videos.png Dash/graphics/tablet/apps.png Dash/graphics/tablet/home.png Dash/graphics/tablet/music.png Dash/graphics/tablet/people.png Dash/graphics/tablet/videos.png Greeter/GreeterContent.qml+1−1 MouseTouchAdaptor.cpp+29−12 MouseTouchAdaptor.h+2−5 Panel/Indicators/DefaultIndicatorWidget.qml+1−5 Panel/MenuContent.qml+12−2 Shell.qml+21−10 debian/changelog+82 debian/unity8-private.install+1 main.cpp−1 plugins/AccountsService/AccountsService.cpp+3−3 plugins/AccountsService/AccountsService.h+6−6 plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+15−15 plugins/AccountsService/AccountsServiceDBusAdaptor.h+2−2 plugins/CMakeLists.txt+1 plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+13 plugins/ListViewWithPageHeader/listviewwithpageheader.h+1 plugins/SessionBroadcast/CMakeLists.txt+13 plugins/SessionBroadcast/SessionBroadcast.cpp+41 plugins/SessionBroadcast/SessionBroadcast.h+41 plugins/SessionBroadcast/plugin.cpp+35 plugins/SessionBroadcast/plugin.h+33 plugins/SessionBroadcast/qmldir+3 plugins/Unity/Launcher/launchermodel.cpp+12−3 plugins/Unity/categories.cpp+12−1 plugins/Unity/scope.cpp+13−1 po/is.po+256 po/sl.po+29−24 tests/autopilot/unity8/application_lifecycle/__init__.py+20 tests/autopilot/unity8/application_lifecycle/tests/__init__.py tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.py+136 tests/autopilot/unity8/shell/__init__.py+10 tests/autopilot/unity8/shell/tests/__init__.py+4−1 tests/mocks/AccountsService/AccountsService.cpp+3−3 tests/mocks/AccountsService/AccountsService.h+6−6 tests/plugins/AccountsService/client.cpp+2−2 tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsectionexternalmodel.cpp+251 tests/plugins/ListViewWithPageHeader/test_sectionexternalmodel.qml+74 tests/plugins/Unity/Launcher/launchermodeltest.cpp+61−2 tests/qmltests/CMakeLists.txt−1 tests/qmltests/Components/tst_CrossFadeImage.qml−125 tests/qmltests/Dash/tst_DashContent.qml+1−1 tests/qmltests/Dash/tst_GenericScopeView.qml+3 tests/uqmlscene/main.cpp−2
Components/CrossFadeImage.qmldeleted−151
@@ -1,151 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−Item {
20− property url source
21−
22− /*
23− * true: fade out old image in parallel with fading in the new one.
24− * false: fade in new image above old one.
25− *
26− * The reason why this is required is that crossfading has the isse that in
27− * the middle of the animation, both images are only 50% opaque which make
28− * any background shine through. Not wanted for background images etc, but
29− * wanted for overlays.
30− */
31− property bool crossFade: true
32−
33− /*
34− * true: the very first source url should be faded in already.
35− * false: the very first source url should just be shown without animation.
36− */
37− property bool fadeInFirst: true
38−
39− readonly property size sourceSize: __currentImage.sourceSize
40− readonly property var status: __currentImage ? __currentImage.status : Image.Null
41− readonly property bool running: crossFadeImages.running || nextImageFadeIn.running
42−
43− property Image __currentImage: image1
44− property Image __nextImage: image2
45−
46− function swapImages() {
47− __currentImage.z = 0
48− __nextImage.z = 1
49− if (crossFade) {
50− crossFadeImages.start();
51− } else {
52− nextImageFadeIn.start();
53− }
54−
55− var tmpImage = __currentImage
56− __currentImage = __nextImage
57− __nextImage = tmpImage
58− }
59−
60− onSourceChanged: {
61− // On creation, the souce handler is called before image pointers are set.
62− if (__currentImage === null) {
63− __currentImage = image1;
64− __nextImage = image2;
65− }
66−
67− crossFadeImages.stop();
68− nextImageFadeIn.stop();
69−
70− // Don't fade in initial picture, only fade changes
71− if (__currentImage.source == "" && !fadeInFirst) {
72− __currentImage.source = source;
73− } else {
74− nextImageFadeIn.stop();
75− __nextImage.opacity = 0.0;
76− __nextImage.source = source;
77−
78− // If case the image is still in QML's cache, status will be "Ready" immediately
79− if (__nextImage.status == Image.Ready || __nextImage.source == "") {
80− swapImages();
81− }
82− }
83− }
84−
85− Connections {
86− target: __nextImage
87− onStatusChanged: {
88− if (__nextImage.status == Image.Ready || __nextImage.status == Image.Error) {
89− swapImages();
90− }
91− }
92− }
93−
94− Image {
95− id: image1
96− anchors.fill: parent
97− cache: false
98− asynchronous: true
99− fillMode: Image.PreserveAspectCrop
100− z: 1
101− }
102−
103− Image {
104− id: image2
105− anchors.fill: parent
106− cache: false
107− asynchronous: true
108− fillMode: Image.PreserveAspectCrop
109− z: 0
110− }
111−
112− NumberAnimation {
113− id: nextImageFadeIn
114− target: __nextImage
115− property: "opacity"
116− duration: 400
117− to: 1.0
118− easing.type: Easing.InOutQuad
119−
120− onRunningChanged: {
121− if (!running) {
122− __nextImage.source = "";
123− }
124− }
125− }
126−
127− ParallelAnimation {
128− id: crossFadeImages
129− NumberAnimation {
130− target: __nextImage
131− property: "opacity"
132− duration: 400
133− to: 1.0
134− easing.type: Easing.InOutQuad
135− }
136−
137− NumberAnimation {
138− target: __currentImage
139− property: "opacity"
140− duration: 400
141− to: 0
142− easing.type: Easing.InOutQuad
143− }
144−
145− onRunningChanged: {
146− if (!running) {
147− __nextImage.source = "";
148− }
149− }
150− }
151−}
Components/VolumeControl.qml+5−20
@@ -21,37 +21,22 @@ Item {
2121 id: root
2222 objectName: "volumeControl"
2323 visible: false
24− property int volume
2524
2625 QDBusActionGroup {
2726 id: actionGroup
2827 busType: 1
29− busName: "com.canonical.settings.sound"
30− objectPath: "/com/canonical/settings/sound"
28+ busName: "com.canonical.indicator.sound"
29+ objectPath: "/com/canonical/indicator/sound"
3130
32− property variant actionObject: action("volume")
33− property variant serverVolume: actionObject.valid ? actionObject.state: 0
34− }
35−
36− Binding {
37− target: root
38− property: "volume"
39− value: actionGroup.serverVolume * 100
40− }
41−
42− onVolumeChanged: {
43− if (actionGroup.serverVolume != volume) {
44− var targetVolume = Math.min(1, Math.max(0, volume / 100));
45− actionGroup.actionObject.updateState(targetVolume);
46− }
31+ property variant actionObject: action("scroll")
4732 }
4833
4934 function volumeUp() {
50− actionGroup.actionObject.updateState(Math.min(1, volume/100 + 0.10));
35+ actionGroup.actionObject.activate(1);
5136 }
5237
5338 function volumeDown() {
54− actionGroup.actionObject.updateState(Math.max(0, volume/100 - 0.10));
39+ actionGroup.actionObject.activate(-1);
5540 }
5641
5742 Component.onCompleted: actionGroup.start()
Dash/GenericScopeView.qml+10−1
@@ -21,10 +21,11 @@ import "../Components/ListItems" as ListItems
2121
2222ScopeView {
2323 id: scopeView
24− property alias previewShown: previewLoader.onScreen
24+ readonly property alias previewShown: previewLoader.onScreen
2525
2626 onIsCurrentChanged: {
2727 pageHeader.resetSearch();
28+ previewLoader.open = false;
2829 }
2930
3031 onMovementStarted: categoryView.showHeader()
@@ -35,6 +36,12 @@ ScopeView {
3536 value: pageHeader.searchQuery
3637 }
3738
39+ Binding {
40+ target: pageHeader
41+ property: "searchQuery"
42+ value: scopeView.scope.searchQuery
43+ }
44+
3845 Connections {
3946 target: panel
4047 onSearchClicked: if (isCurrent) {
@@ -179,6 +186,7 @@ ScopeView {
179186 case "grid": {
180187 switch (contentType) {
181188 case "video": return "Generic/GenericFilterGridPotrait.qml";
189+ case "music": return "Music/MusicFilterGrid.qml";
182190 default: return "Generic/GenericFilterGrid.qml";
183191 }
184192 }
@@ -246,6 +254,7 @@ ScopeView {
246254 }
247255
248256 Loader {
257+ objectName: "previewLoader"
249258 id: previewLoader
250259 property var previewData
251260 height: effect.bottomGapPx - effect.topGapPx
Dash/Music/MusicFilterGrid.qml+12−2
@@ -29,19 +29,29 @@ FilterGrid {
2929 readonly property int iconWidth: (width / columns) * 0.8
3030 readonly property int iconHeight: iconWidth
3131
32− signal clicked(int index)
32+ signal clicked(int index, var delegateItem, real itemY)
33+ signal pressAndHold(int index, var delegateItem, real itemY)
3334
3435 delegate: AlbumTile {
36+ id: tile
3537 objectName: "delegate" + index
3638 width: filterGrid.cellWidth
3739 height: filterGrid.cellHeight
3840 iconWidth: filterGrid.iconWidth
3941 iconHeight: filterGrid.iconHeight
42+
4043 artist: model.title
4144 album: model.comment
4245 source: model.icon
46+
4347 onClicked: {
44− filterGrid.clicked(index);
48+ var data = { model: model }
49+ filterGrid.clicked(index, data, tile.y)
50+ }
51+
52+ onPressAndHold: {
53+ var data = { model: model }
54+ filterGrid.pressAndHold(index, data, tile.y)
4555 }
4656 }
4757}
Dash/graphics/phone/home.pngdeleted

Binary file not shown.

Dash/graphics/phone/music.pngdeleted

Binary file not shown.

Dash/graphics/phone/videos.pngdeleted

Binary file not shown.

Dash/graphics/tablet/apps.pngdeleted

Binary file not shown.

Dash/graphics/tablet/home.pngdeleted

Binary file not shown.

Dash/graphics/tablet/music.pngdeleted

Binary file not shown.

Dash/graphics/tablet/people.pngdeleted

Binary file not shown.

Dash/graphics/tablet/videos.pngdeleted

Binary file not shown.

Greeter/GreeterContent.qml+1−1
@@ -47,7 +47,7 @@ MouseArea {
4747 id: wallpaper
4848 objectName: "wallpaper"
4949 anchors.fill: parent
50− fadeInFirst: false
50+ fillMode: Image.PreserveAspectCrop
5151 }
5252
5353 // See Shell.qml's backgroundSettings treatment for why we need a separate
MouseTouchAdaptor.cpp+29−12
@@ -39,24 +39,16 @@ Qt::MouseButton translateMouseButton(xcb_button_t detail)
3939} // end of anonymous namespace
4040
4141MouseTouchAdaptor::MouseTouchAdaptor()
42− : m_targetWindow(0)
43− , m_leftButtonIsPressed(false)
42+ : m_leftButtonIsPressed(false)
4443{
4544 m_touchDevice = new QTouchDevice;
4645 m_touchDevice->setType(QTouchDevice::TouchScreen);
4746 QWindowSystemInterface::registerTouchDevice(m_touchDevice);
4847}
4948
50−void MouseTouchAdaptor::setTargetWindow(QWindow *window)
51−{
52− m_targetWindow = window;
53−}
54−
5549bool MouseTouchAdaptor::nativeEventFilter(const QByteArray & eventType,
5650 void * message, long * /*result*/)
5751{
58− Q_ASSERT(m_targetWindow);
59−
6052 if (eventType != "xcb_generic_event_t") {
6153 // wrong backend.
6254 qWarning("MouseTouchAdaptor: XCB backend not in use. Adaptor inoperative!");
@@ -91,7 +83,9 @@ bool MouseTouchAdaptor::handleButtonPress(xcb_button_press_event_t *pressEvent)
9183
9284 QPoint windowPos(pressEvent->event_x, pressEvent->event_y);
9385
94− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
86+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(pressEvent->event));
87+
88+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
9589 false /* autoCommit */);
9690 touchEvent.press(0 /* touchId */, windowPos);
9791 touchEvent.commit(false /* processEvents */);
@@ -110,7 +104,9 @@ bool MouseTouchAdaptor::handleButtonRelease(xcb_button_release_event_t *releaseE
110104
111105 QPoint windowPos(releaseEvent->event_x, releaseEvent->event_y);
112106
113− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
107+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(releaseEvent->event));
108+
109+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
114110 false /* autoCommit */);
115111 touchEvent.release(0 /* touchId */, windowPos);
116112 touchEvent.commit(false /* processEvents */);
@@ -127,10 +123,31 @@ bool MouseTouchAdaptor::handleMotionNotify(xcb_motion_notify_event_t *event)
127123
128124 QPoint windowPos(event->event_x, event->event_y);
129125
130− QTouchEventSequence touchEvent = QTest::touchEvent(m_targetWindow, m_touchDevice,
126+ QWindow *targetWindow = findQWindowWithXWindowID(static_cast<WId>(event->event));
127+
128+ QTouchEventSequence touchEvent = QTest::touchEvent(targetWindow, m_touchDevice,
131129 false /* autoCommit */);
132130 touchEvent.move(0 /* touchId */, windowPos);
133131 touchEvent.commit(false /* processEvents */);
134132
135133 return true;
136134}
135+
136+QWindow *MouseTouchAdaptor::findQWindowWithXWindowID(WId windowId)
137+{
138+ QWindowList windowList = QGuiApplication::topLevelWindows();
139+ QWindow *foundWindow = nullptr;
140+
141+ int i = 0;
142+ while (!foundWindow && i < windowList.count()) {
143+ QWindow *window = windowList[i];
144+ if (window->winId() == windowId) {
145+ foundWindow = window;
146+ } else {
147+ ++i;
148+ }
149+ }
150+
151+ Q_ASSERT(foundWindow);
152+ return foundWindow;
153+}
MouseTouchAdaptor.h+2−5
@@ -20,11 +20,11 @@
2020#define MOUSE_TOUCH_ADAPTOR_H
2121
2222#include <QtCore/QAbstractNativeEventFilter>
23+#include <QWindow>
2324#include <xcb/xcb.h>
2425
2526class QMouseEvent;
2627class QTouchDevice;
27−class QWindow;
2828
2929// Transforms QMouseEvents into single-finger QTouchEvents.
3030class MouseTouchAdaptor : public QAbstractNativeEventFilter {
@@ -32,9 +32,6 @@ class MouseTouchAdaptor : public QAbstractNativeEventFilter {
3232public:
3333 MouseTouchAdaptor();
3434
35− // The window that will receive the generated QTouchEvents
36− void setTargetWindow(QWindow *window);
37−
3835 // Filters mouse events and posts the equivalent QTouchEvents.
3936 virtual bool nativeEventFilter(const QByteArray & eventType, void *message, long *result);
4037
@@ -43,8 +40,8 @@ private:
4340 bool handleButtonPress(xcb_button_press_event_t *pressEvent);
4441 bool handleButtonRelease(xcb_button_release_event_t *releaseEvent);
4542 bool handleMotionNotify(xcb_motion_notify_event_t *event);
43+ QWindow *findQWindowWithXWindowID(WId windowId);
4644
47− QWindow *m_targetWindow;
4845 QTouchDevice *m_touchDevice;
4946 bool m_leftButtonIsPressed;
5047};
Panel/Indicators/DefaultIndicatorWidget.qml+1−5
@@ -24,6 +24,7 @@ import Unity.IndicatorsLegacy 0.1 as Indicators
2424Indicators.IndicatorWidget {
2525 id: indicatorWidget
2626
27+ enabled:true
2728 width: itemRow.width + units.gu(0.5)
2829
2930 property alias label: itemLabel.text
@@ -63,19 +64,14 @@ Indicators.IndicatorWidget {
6364
6465 onActionStateChanged: {
6566 if (action == undefined || !action.valid) {
66− enabled = false;
6767 return;
6868 }
6969
7070 if (action.state == undefined) {
71− label = "";
72− iconSource = "";
73− enabled = false;
7471 return;
7572 }
7673
7774 label = action.state[Indicators.ActionState.Label];
7875 iconSource = "image://theme/" + action.state[Indicators.ActionState.IconSource];
79− enabled = action.state[Indicators.ActionState.Visible];
8076 }
8177}
Panel/MenuContent.qml+12−2
@@ -109,7 +109,7 @@ MainView {
109109 source: pageSource
110110 asynchronous: true
111111
112− property bool contentActive: content.__contentActive
112+ property bool contentActive: content.__contentActive && menuActivator.content[index].active
113113
114114 onContentActiveChanged: {
115115 if (contentActive && item) {
@@ -146,6 +146,16 @@ MainView {
146146 id: contentReleaseTimer
147147
148148 interval: contentReleaseInterval
149− onTriggered: content.__contentActive = false
149+ onTriggered: {
150+ content.__contentActive = false;
151+ menuActivator.clear();
152+ }
153+ }
154+
155+ Indicators.MenuContentActivator {
156+ id: menuActivator
157+ running: content.__contentActive
158+ baseIndex: content.currentMenuIndex
159+ count: indicatorsModel.count
150160 }
151161}
Shell.qml+21−10
@@ -23,6 +23,7 @@ import Ubuntu.Gestures 0.1
2323import Unity.Launcher 0.1
2424import LightDM 0.1 as LightDM
2525import Powerd 0.1
26+import SessionBroadcast 0.1
2627import "Dash"
2728import "Greeter"
2829import "Launcher"
@@ -83,6 +84,8 @@ FocusScope {
8384
8485 readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication
8586 || !!applicationManager.sideStageFocusedApplication
87+ // Used for autopilot testing.
88+ readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId
8689
8790 readonly property bool fullscreenMode: {
8891 if (greeter.shown || lockscreen.shown) {
@@ -195,6 +198,7 @@ FocusScope {
195198
196199 anchors.fill: parent
197200 source: shell.background
201+ fillMode: Image.PreserveAspectCrop
198202 }
199203
200204 Rectangle {
@@ -545,6 +549,17 @@ FocusScope {
545549 }
546550 }
547551
552+ function showHome() {
553+ greeter.hide()
554+ // Animate if moving between application and dash
555+ if (!stages.shown) {
556+ dash.setCurrentScope("home.scope", true, false)
557+ } else {
558+ dash.setCurrentScope("home.scope", false, false)
559+ }
560+ stages.hide()
561+ }
562+
548563 Item {
549564 id: overlay
550565
@@ -632,16 +647,7 @@ FocusScope {
632647 width: parent.width
633648 dragAreaWidth: shell.edgeSize
634649 available: (!greeter.shown || greeter.narrowMode) && edgeDemo.launcherEnabled
635− onDashItemSelected: {
636− greeter.hide()
637− // Animate if moving between application and dash
638− if (!stages.shown) {
639− dash.setCurrentScope("home.scope", true, false)
640− } else {
641− dash.setCurrentScope("home.scope", false, false)
642− }
643− stages.hide();
644− }
650+ onDashItemSelected: showHome()
645651 onDash: {
646652 if (stages.shown) {
647653 dash.setCurrentScope("applications.scope", true, false)
@@ -749,4 +755,9 @@ FocusScope {
749755 indicators: panel.indicators
750756 underlay: underlay
751757 }
758+
759+ Connections {
760+ target: SessionBroadcast
761+ onShowHome: showHome()
762+ }
752763}
debian/changelog+82
@@ -1,3 +1,85 @@
1+unity8 (7.81.3+13.10.20130924.2-0ubuntu1) saucy; urgency=low
2+
3+ [ Michal Hruby ]
4+ * Fix the signal prototypes on music grid renderer. (LP: #1228390)
5+
6+ [ Michael Zanetti ]
7+ * use less auto variables, align coding style, constify and Qt'ify API
8+ in AccountsService plugin.
9+
10+ [ Nick Dedekind ]
11+ * Re-enable MenuContentActivator in Indicators.
12+
13+ [ Albert Astals ]
14+ * LVWPH: Update the section header on list change events.
15+
16+ [ Pawel Stolowski ]
17+ * Check results model ptr returned by GetResultsFromCategory method
18+ from UnityCore. (LP: #1228097, #1211595)
19+
20+ [ Ubuntu daily release ]
21+ * Automatic snapshot from revision 340
22+
23+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 24 Sep 2013 14:40:01 +0000
24+
25+unity8 (7.81.3+13.10.20130919.3-0ubuntu1) saucy; urgency=low
26+
27+ [ Michal Hruby ]
28+ * Add support for music grid renderer to GenericScopeView.
29+
30+ [ Nick Dedekind ]
31+ * Fixed the removal of messaging widget due to incompatible action
32+ state. (LP: #1225017)
33+
34+ [ Christopher Lee ]
35+ * Addition of initial autopilot tests for the application lifecycle.
36+
37+ [ Lars Uebernickel ]
38+ * VolumeControl: use action of the new indicator indicator-sound
39+ recently gained an action to increase and decrease the volume. This
40+ patch makes use of that to get rid of a bus round trip (to get the
41+ current volume) and a race (when the volume gets set between
42+ fetching the current volume and setting the new volume). (LP:
43+ #1219057)
44+
45+ [ Michael Terry ]
46+ * When AccountsService.backgroundFile is unset/invalid, have the
47+ greeter fall back to whatever the shell background is.
48+ * Add a tiny SessionBroadcast plugin that listens to unity-greeter-
49+ session-broadcast for the ShowHome signal.
50+
51+ [ Daniel d'Andrada ]
52+ * Remove obsolete, unused graphics.
53+ * Make MouseTouchAdaptor work with multiple QWindows.
54+
55+ [ Michael Zanetti ]
56+ * change how icons are searched a) try to find it the Icon as is b)
57+ prepend with Path if a Path variable is given c) fall back to the
58+ image://theme/ with just the icon name . (LP: #1225186)
59+ * fix an issue with removing a running app from the launcher and
60+ always store pinning to the config.
61+ * collapse any open preview when programmatically switching current
62+ dash index. (LP: #1221137)
63+
64+ [ Ubuntu daily release ]
65+ * Automatic snapshot from revision 333
66+
67+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 19 Sep 2013 15:15:07 +0000
68+
69+unity8 (7.81.3+13.10.20130916-0ubuntu1) saucy; urgency=low
70+
71+ [ Michael Zanetti ]
72+ * allow left edge gesture to minimize apps even when launcher is
73+ already visible.
74+ * Don't hide the launcher on changes in the stages.
75+ * ssh is now installed per default, but it's set to manual in the
76+ ssh.override.
77+
78+ [ Ubuntu daily release ]
79+ * Automatic snapshot from revision 320
80+
81+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 16 Sep 2013 11:49:28 +0000
82+
183unity8 (7.81.3+13.10.20130912-0ubuntu1) saucy; urgency=low
284
385 [ Michael Zanetti ]
debian/unity8-private.install+1
@@ -3,6 +3,7 @@ usr/lib/*/unity8/qml/HudClient
33usr/lib/*/unity8/qml/LightDM
44usr/lib/*/unity8/qml/ListViewWithPageHeader
55usr/lib/*/unity8/qml/Powerd
6+usr/lib/*/unity8/qml/SessionBroadcast
67usr/lib/*/unity8/qml/Ubuntu
78usr/lib/*/unity8/qml/Unity
89usr/lib/*/unity8/qml/Utils
main.cpp−1
@@ -144,7 +144,6 @@ int startShell(int argc, const char** argv, void* server)
144144 MouseTouchAdaptor *mouseTouchAdaptor = 0;
145145 if (args.contains(QLatin1String("-mousetouch"))) {
146146 mouseTouchAdaptor = new MouseTouchAdaptor;
147− mouseTouchAdaptor->setTargetWindow(view);
148147 application->installNativeEventFilter(mouseTouchAdaptor);
149148 }
150149
plugins/AccountsService/AccountsService.cpp+3−3
@@ -32,7 +32,7 @@ AccountsService::AccountsService(QObject* parent)
3232 this, SLOT(maybeChanged(const QString &)));
3333}
3434
35−QString AccountsService::getUser()
35+QString AccountsService::user() const
3636{
3737 return m_user;
3838}
@@ -46,7 +46,7 @@ void AccountsService::setUser(const QString &user)
4646 updateBackgroundFile();
4747}
4848
49−bool AccountsService::getDemoEdges()
49+bool AccountsService::demoEdges() const
5050{
5151 return m_demoEdges;
5252}
@@ -57,7 +57,7 @@ void AccountsService::setDemoEdges(bool demoEdges)
5757 m_service->setUserProperty(m_user, "com.canonical.unity.AccountsService", "demo-edges", demoEdges);
5858}
5959
60−QString AccountsService::getBackgroundFile()
60+QString AccountsService::backgroundFile() const
6161{
6262 return m_backgroundFile;
6363}
plugins/AccountsService/AccountsService.h+6−6
@@ -28,25 +28,25 @@ class AccountsService: public QObject
2828{
2929 Q_OBJECT
3030 Q_PROPERTY (QString user
31− READ getUser
31+ READ user
3232 WRITE setUser
3333 NOTIFY userChanged)
3434 Q_PROPERTY (bool demoEdges
35− READ getDemoEdges
35+ READ demoEdges
3636 WRITE setDemoEdges
3737 NOTIFY demoEdgesChanged)
3838 Q_PROPERTY (QString backgroundFile
39− READ getBackgroundFile
39+ READ backgroundFile
4040 NOTIFY backgroundFileChanged)
4141
4242public:
4343 explicit AccountsService(QObject *parent = 0);
4444
45− QString getUser();
45+ QString user() const;
4646 void setUser(const QString &user);
47− bool getDemoEdges();
47+ bool demoEdges() const;
4848 void setDemoEdges(bool demoEdges);
49− QString getBackgroundFile();
49+ QString backgroundFile() const;
5050
5151Q_SIGNALS:
5252 void userChanged();
plugins/AccountsService/AccountsServiceDBusAdaptor.cpp+15−15
@@ -24,13 +24,13 @@
2424
2525AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
2626 : QObject(parent),
27− accounts_manager(NULL),
28− users()
27+ m_accountsManager(NULL),
28+ m_users()
2929{
30− auto connection = QDBusConnection::SM_BUSNAME();
31− auto interface = connection.interface();
30+ QDBusConnection connection = QDBusConnection::SM_BUSNAME();
31+ QDBusConnectionInterface *interface = connection.interface();
3232 interface->startService("org.freedesktop.Accounts");
33− accounts_manager = new QDBusInterface("org.freedesktop.Accounts",
33+ m_accountsManager = new QDBusInterface("org.freedesktop.Accounts",
3434 "/org/freedesktop/Accounts",
3535 "org.freedesktop.Accounts",
3636 connection, this);
@@ -38,9 +38,9 @@ AccountsServiceDBusAdaptor::AccountsServiceDBusAdaptor(QObject* parent)
3838
3939QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const QString &interface, const QString &property)
4040{
41− auto iface = getUserInterface(user);
41+ QDBusInterface *iface = getUserInterface(user);
4242 if (iface != nullptr && iface->isValid()) {
43− auto answer = iface->call("Get", interface, property);
43+ QDBusMessage answer = iface->call("Get", interface, property);
4444 if (answer.type() == QDBusMessage::ReplyMessage) {
4545 return answer.arguments()[0].value<QDBusVariant>().variant();
4646 }
@@ -50,7 +50,7 @@ QVariant AccountsServiceDBusAdaptor::getUserProperty(const QString &user, const
5050
5151void AccountsServiceDBusAdaptor::setUserProperty(const QString &user, const QString &interface, const QString &property, const QVariant &value)
5252{
53− auto iface = getUserInterface(user);
53+ QDBusInterface *iface = getUserInterface(user);
5454 if (iface != nullptr && iface->isValid()) {
5555 // The value needs to be carefully wrapped
5656 iface->call("Set", interface, property, QVariant::fromValue(QDBusVariant(value)));
@@ -76,7 +76,7 @@ void AccountsServiceDBusAdaptor::maybeChangedSlot()
7676QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
7777{
7878 QMap<QString, QDBusInterface *>::const_iterator i;
79− for (i = users.constBegin(); i != users.constEnd(); ++i) {
79+ for (i = m_users.constBegin(); i != m_users.constEnd(); ++i) {
8080 if (i.value()->path() == path) {
8181 return i.key();
8282 }
@@ -86,16 +86,16 @@ QString AccountsServiceDBusAdaptor::getUserForPath(const QString &path)
8686
8787QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user)
8888{
89− auto iface = users.value(user);
90− if (iface == nullptr && accounts_manager->isValid()) {
91− auto answer = accounts_manager->call("FindUserByName", user);
89+ QDBusInterface *iface = m_users.value(user);
90+ if (iface == nullptr && m_accountsManager->isValid()) {
91+ QDBusMessage answer = m_accountsManager->call("FindUserByName", user);
9292 if (answer.type() == QDBusMessage::ReplyMessage) {
93− auto path = answer.arguments()[0].value<QDBusObjectPath>().path();
93+ QString path = answer.arguments()[0].value<QDBusObjectPath>().path();
9494
9595 iface = new QDBusInterface("org.freedesktop.Accounts",
9696 path,
9797 "org.freedesktop.DBus.Properties",
98− accounts_manager->connection(), this);
98+ m_accountsManager->connection(), this);
9999
100100 // With its own pre-defined properties, AccountsService is oddly
101101 // close-lipped. It won't send out proper DBus.Properties notices,
@@ -119,7 +119,7 @@ QDBusInterface *AccountsServiceDBusAdaptor::getUserInterface(const QString &user
119119 this,
120120 SLOT(propertiesChangedSlot(QString, QVariantMap, QStringList)));
121121
122− users.insert(user, iface);
122+ m_users.insert(user, iface);
123123 }
124124 }
125125 return iface;
plugins/AccountsService/AccountsServiceDBusAdaptor.h+2−2
@@ -47,8 +47,8 @@ private:
4747 QDBusInterface *getUserInterface(const QString &user);
4848 QString getUserForPath(const QString &path);
4949
50− QDBusInterface *accounts_manager;
51− QMap<QString, QDBusInterface *> users;
50+ QDBusInterface *m_accountsManager;
51+ QMap<QString, QDBusInterface *> m_users;
5252};
5353
5454#endif
plugins/CMakeLists.txt+1
@@ -3,6 +3,7 @@ add_subdirectory(HudClient)
33add_subdirectory(LightDM)
44add_subdirectory(ListViewWithPageHeader)
55add_subdirectory(Powerd)
6+add_subdirectory(SessionBroadcast)
67add_subdirectory(Ubuntu)
78add_subdirectory(Unity)
89add_subdirectory(Utils)
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+13
@@ -199,6 +199,7 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
199199 connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
200200#endif
201201 Q_EMIT modelChanged();
202+ polish();
202203 // TODO?
203204// Q_EMIT contentHeightChanged();
204205// Q_EMIT contentYChanged();
@@ -1006,6 +1007,18 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
10061007 }
10071008 }
10081009
1010+ Q_FOREACH(const QQuickChangeSet::Change &change, changeSet.changes()) {
1011+// qDebug() << "ListViewWithPageHeader::onModelUpdated Change" << change.index << change.count;
1012+ for (int i = change.index; i < change.count; ++i) {
1013+ ListItem *item = itemAtIndex(i);
1014+ if (item && item->m_sectionItem) {
1015+ QQmlContext *context = QQmlEngine::contextForObject(item->m_sectionItem)->parentContext();
1016+ const QString sectionText = m_delegateModel->stringValue(i, m_sectionProperty);
1017+ context->setContextProperty(QLatin1String("section"), sectionText);
1018+ }
1019+ }
1020+ }
1021+
10091022 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
10101023 adjustMinYExtent();
10111024 }
plugins/ListViewWithPageHeader/listviewwithpageheader.h+1
@@ -63,6 +63,7 @@ class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeLi
6363
6464 friend class ListViewWithPageHeaderTest;
6565 friend class ListViewWithPageHeaderTestSection;
66+ friend class ListViewWithPageHeaderTestExternalModel;
6667
6768public:
6869 ListViewWithPageHeader();
plugins/SessionBroadcast/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(SessionBroadcast-qml MODULE
6+ SessionBroadcast.cpp
7+ plugin.cpp
8+ )
9+
10+qt5_use_modules(SessionBroadcast-qml DBus Qml)
11+
12+export_qmlfiles(SessionBroadcast SessionBroadcast)
13+export_qmlplugin(SessionBroadcast 0.1 SessionBroadcast TARGETS SessionBroadcast-qml)
plugins/SessionBroadcast/SessionBroadcast.cppnew file+41
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "SessionBroadcast.h"
20+#include <QDBusConnection>
21+
22+SessionBroadcast::SessionBroadcast(QObject* parent)
23+ : QObject(parent)
24+{
25+ auto connection = QDBusConnection::SM_BUSNAME();
26+
27+ connection.connect("com.canonical.Unity.Greeter.Broadcast",
28+ "/com/canonical/Unity/Greeter/Broadcast",
29+ "com.canonical.Unity.Greeter.Broadcast",
30+ "ShowHome",
31+ this,
32+ SLOT(onShowHome(const QString &)));
33+}
34+
35+void SessionBroadcast::onShowHome(const QString &username)
36+{
37+ // Only listen to requests meant for us
38+ if (username == qgetenv("USER")) {
39+ Q_EMIT showHome();
40+ }
41+}
plugins/SessionBroadcast/SessionBroadcast.hnew file+41
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_H
20+#define UNITY_SESSIONBROADCAST_H
21+
22+#include <QObject>
23+#include <QString>
24+
25+class QDBusInterface;
26+
27+class SessionBroadcast: public QObject
28+{
29+ Q_OBJECT
30+
31+public:
32+ explicit SessionBroadcast(QObject *parent = 0);
33+
34+Q_SIGNALS:
35+ void showHome();
36+
37+private Q_SLOTS:
38+ void onShowHome(const QString &username);
39+};
40+
41+#endif
plugins/SessionBroadcast/plugin.cppnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "plugin.h"
20+#include "SessionBroadcast.h"
21+
22+#include <QtQml>
23+
24+static QObject *broadcast_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
25+{
26+ Q_UNUSED(engine)
27+ Q_UNUSED(scriptEngine)
28+ return new SessionBroadcast();
29+}
30+
31+void SessionBroadcastPlugin::registerTypes(const char *uri)
32+{
33+ Q_ASSERT(uri == QLatin1String("SessionBroadcast"));
34+ qmlRegisterSingletonType<SessionBroadcast>(uri, 0, 1, "SessionBroadcast", broadcast_provider);
35+}
plugins/SessionBroadcast/plugin.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#ifndef UNITY_SESSIONBROADCAST_PLUGIN_H
20+#define UNITY_SESSIONBROADCAST_PLUGIN_H
21+
22+#include <QQmlExtensionPlugin>
23+
24+class SessionBroadcastPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif
plugins/SessionBroadcast/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module SessionBroadcast
2+plugin SessionBroadcast-qml
3+typeinfo plugin.qmltypes
plugins/Unity/Launcher/launchermodel.cpp+12−3
@@ -115,9 +115,11 @@ void LauncherModel::move(int oldIndex, int newIndex)
115115 m_list.move(oldIndex, newIndex);
116116 endMoveRows();
117117
118− storeAppList();
119−
120− pin(m_list.at(newIndex)->appId());
118+ if (!m_list.at(newIndex)->pinned()) {
119+ pin(m_list.at(newIndex)->appId());
120+ } else {
121+ storeAppList();
122+ }
121123}
122124
123125void LauncherModel::pin(const QString &appId, int index)
@@ -146,6 +148,8 @@ void LauncherModel::pin(const QString &appId, int index)
146148 m_list.insert(index, item);
147149 endInsertRows();
148150 }
151+
152+ storeAppList();
149153}
150154
151155void LauncherModel::requestRemove(const QString &appId)
@@ -155,6 +159,11 @@ void LauncherModel::requestRemove(const QString &appId)
155159 return;
156160 }
157161
162+ if (m_appManager->findApplication(appId)) {
163+ m_list.at(index)->setPinned(false);
164+ return;
165+ }
166+
158167 beginRemoveRows(QModelIndex(), index, index);
159168 m_list.takeAt(index)->deleteLater();
160169 endRemoveRows();
plugins/Unity/categories.cpp+12−1
@@ -21,6 +21,7 @@
2121// self
2222#include "categories.h"
2323#include "categoryresults.h"
24+#include <QDebug>
2425
2526// TODO: use something from libunity once it's public
2627enum CategoryColumn {
@@ -62,7 +63,17 @@ Categories::getResults(int index) const
6263
6364 unsigned categoryIndex = static_cast<unsigned>(index);
6465 auto unity_results = m_unityScope->GetResultsForCategory(categoryIndex);
65− results->setModel(unity_results->model());
66+ if (unity_results) {
67+ results->setModel(unity_results->model());
68+ } else {
69+ // No results model returned by unity core; this can be the case when the global
70+ // results model of this scope is still not set in unity core. Don't set backend
71+ // model in DeeListModel - it will still beahve properly as an empty model. Since
72+ // we're connected to the category model change signal, and it is set by unity core
73+ // at the same time as results model (on channel opening), we'll reset category
74+ // results models with proper models when we're notifed again.
75+ qWarning() << "No results model for category" << categoryIndex;
76+ }
6677
6778 m_results.insert(index, results);
6879 }
plugins/Unity/scope.cpp+13−1
@@ -175,7 +175,12 @@ void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVaria
175175 const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
176176{
177177 auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
178− m_unityScope->Preview(res);
178+ // canned queries don't have previews, must be activated
179+ if (uri.toString().startsWith("x-unity-no-preview-scopes-query://")) {
180+ m_unityScope->Activate(res);
181+ } else {
182+ m_unityScope->Preview(res);
183+ }
179184}
180185
181186void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
@@ -199,6 +204,13 @@ void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::Sco
199204 qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
200205 }
201206 break;
207+ case unity::dash::PERFORM_SEARCH:
208+ if (hints.find("query") != hints.end()) {
209+ // note: this will emit searchQueryChanged, and shell will call setSearchQuery back with a new query,
210+ // but it will get ignored.
211+ setSearchQuery(QString::fromStdString(g_variant_get_string(hints.at("query"), nullptr)));
212+ }
213+ break;
202214 default:
203215 qWarning() << "Unhandled activation response:" << type;
204216 }
po/is.ponew file+256
@@ -0,0 +1,256 @@
1+# Icelandic translation for unity8
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11+"PO-Revision-Date: 2013-09-18 16:22+0000\n"
12+"Last-Translator: Andri Thorlacius <Unknown>\n"
13+"Language-Team: Icelandic <is@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2013-09-19 05:14+0000\n"
19+"X-Generator: Launchpad (build 16765)\n"
20+
21+#: Applications/applications.js:23
22+msgid "Phone"
23+msgstr "Sími"
24+
25+#: Applications/applications.js:29
26+msgid "Camera"
27+msgstr "Myndavél"
28+
29+#: Applications/applications.js:35
30+msgid "Gallery"
31+msgstr "Myndasafn"
32+
33+#: Applications/applications.js:40
34+msgid "Facebook"
35+msgstr "Facebook"
36+
37+#: Applications/applications.js:46
38+msgid "Browser"
39+msgstr "Vafri"
40+
41+#: Applications/applications.js:51
42+msgid "Twitter"
43+msgstr "Twitter"
44+
45+#: Applications/applications.js:57
46+msgid "GMail"
47+msgstr "GMail"
48+
49+#: Applications/applications.js:62
50+msgid "Weather"
51+msgstr "Veður"
52+
53+#: Applications/applications.js:68
54+msgid "Notepad"
55+msgstr "Skrifblokk"
56+
57+#: Applications/applications.js:74
58+msgid "Calendar"
59+msgstr "Dagatal"
60+
61+#: Applications/applications.js:80
62+msgid "Media Player"
63+msgstr "Margmiðlunarspilari"
64+
65+#: Applications/applications.js:86
66+msgid "Evernote"
67+msgstr "Evernote"
68+
69+#: Applications/applications.js:91
70+msgid "Map"
71+msgstr "Kort"
72+
73+#: Applications/applications.js:96
74+msgid "Pinterest"
75+msgstr "Pinterest"
76+
77+#: Applications/applications.js:101
78+msgid "SoundCloud"
79+msgstr "SoundCloud"
80+
81+#: Applications/applications.js:106
82+msgid "Wikipedia"
83+msgstr "Wikipedia"
84+
85+#: Applications/applications.js:111
86+msgid "YouTube"
87+msgstr "YouTube"
88+
89+#: Components/EdgeDemoOverlay.qml:145
90+msgid "Skip intro"
91+msgstr "Hoppa yfir kynningu"
92+
93+#: Components/EdgeDemo.qml:98
94+msgid "Right edge"
95+msgstr "Hægri brún"
96+
97+#: Components/EdgeDemo.qml:99
98+msgid "Try swiping from the right edge to unlock the phone"
99+msgstr ""
100+"Prufaðu að renna puttanum frá hægri brúninni til að aflæsa símanum þínum."
101+
102+#: Components/EdgeDemo.qml:135
103+msgid "Top edge"
104+msgstr "Efri brún"
105+
106+#: Components/EdgeDemo.qml:136
107+msgid "Try swiping from the top edge to access the indicators"
108+msgstr ""
109+
110+#: Components/EdgeDemo.qml:161
111+msgid "Close"
112+msgstr "Loka"
113+
114+#: Components/EdgeDemo.qml:162
115+msgid "Swipe up again to close the settings screen"
116+msgstr ""
117+
118+#: Components/EdgeDemo.qml:189
119+msgid "Left edge"
120+msgstr "Vinstri brún"
121+
122+#: Components/EdgeDemo.qml:190
123+msgid "Swipe from the left to reveal the launcher for quick access to apps"
124+msgstr ""
125+
126+#: Components/EdgeDemo.qml:217
127+msgid "Well done"
128+msgstr "Vel gert"
129+
130+#: Components/EdgeDemo.qml:218
131+msgid "You have now mastered the edge gestures and can start using the phone"
132+msgstr ""
133+
134+#: Components/PageHeader.qml:298
135+msgid "Recent searches"
136+msgstr "Nýlegar leitir"
137+
138+#. TRANSLATORS: Number of persons who rated this app
139+#: Dash/Apps/AppInfo.qml:73
140+#, qt-format
141+msgid "(%1)"
142+msgstr "(%1)"
143+
144+#. TRANSLATORS: Number of persons who wrote reviews for this app
145+#: Dash/Apps/AppInfo.qml:85
146+#, qt-format
147+msgid "%1 review"
148+msgid_plural "%1 reviews"
149+msgstr[0] "%1 ummæli"
150+msgstr[1] "%1 ummæli"
151+
152+#: Dash/Apps/AppPreview.qml:175
153+msgid "Rate this"
154+msgstr "Gefa þessu einkunn"
155+
156+#: Dash/Apps/AppReviews.qml:72
157+msgid "Add a review"
158+msgstr "Gefa umsögn"
159+
160+#: Dash/Apps/AppReviews.qml:84
161+msgid "Review"
162+msgstr "Umsögn"
163+
164+#: Dash/Apps/AppReviews.qml:118
165+msgid "Send"
166+msgstr "Senda"
167+
168+#: Dash/Apps/AppReviews.qml:136
169+msgid "Comments:"
170+msgstr "Athugasemdir:"
171+
172+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173+msgid "Featured"
174+msgstr "Efst á baugi"
175+
176+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
177+msgid "Recent"
178+msgstr "Nýlegt"
179+
180+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
181+msgid "New Releases"
182+msgstr "Nýjar Útgáfur"
183+
184+#: Dash/DashMusic.qml:30
185+msgid "Top Charting"
186+msgstr "Topp Listi"
187+
188+#: Dash/DashMusic.qml:91
189+msgid "Music"
190+msgstr "Tónlist"
191+
192+#: Dash/DashVideos.qml:31
193+msgid "Popular Online"
194+msgstr "Vinsælt á Netinu"
195+
196+#: Dash/DashVideos.qml:146
197+msgid "Videos"
198+msgstr "Myndbönd"
199+
200+#: Dash/Video/VideoPreview.qml:130
201+msgid "Directed by:"
202+msgstr "Leikstýrt af:"
203+
204+#: Dash/Video/VideoPreview.qml:153
205+msgid "Starring:"
206+msgstr "Meðal leikara eru:"
207+
208+#: Dash/Video/VideoPreview.qml:176
209+msgid "Author:"
210+msgstr "Höfundur:"
211+
212+#: Greeter/Lockscreen.qml:134
213+msgid "Emergency Call"
214+msgstr "Neyðarsímtal"
215+
216+#: Greeter/PassphraseLockscreen.qml:59
217+#, qt-format
218+msgid "Hello %1"
219+msgstr "Hæ %1"
220+
221+#: Greeter/PassphraseLockscreen.qml:59
222+msgid "Hello"
223+msgstr "Hæ"
224+
225+#: Hud/HudParametrizedActionsPage.qml:132
226+msgid "Confirm"
227+msgstr "Staðfesta"
228+
229+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
230+msgid "Type or say a command"
231+msgstr "Skrifaðu eða segðu eitthvað"
232+
233+#: Hud/Hud.qml:84
234+msgid "Loading. Please Wait..."
235+msgstr "Hleð. Vinsamlegast Bíðið..."
236+
237+#: Hud/Hud.qml:89
238+msgid "Speak Now..."
239+msgstr "Talaðu Núna..."
240+
241+#: Hud/Hud.qml:94
242+msgid "Speaking..."
243+msgstr "Tala..."
244+
245+#: Panel/SearchIndicator.qml:27
246+msgid "Search"
247+msgstr "Leita"
248+
249+#: plugins/Unity/scope.cpp:317
250+msgid "Sorry, there is nothing that matches your search."
251+msgstr "Því miður, það var ekkert sem passaði við leitarorðið þitt."
252+
253+#: Shell.qml:429
254+#, qt-format
255+msgid "Please enter %1"
256+msgstr ""
po/sl.po+29−24
@@ -8,7 +8,7 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2013-08-27 13:36-0400\n"
11−"PO-Revision-Date: 2013-07-02 12:59+0000\n"
11+"PO-Revision-Date: 2013-09-19 19:48+0000\n"
1212"Last-Translator: Damir Jerovšek <Unknown>\n"
1313"Language-Team: Slovenian <sl@li.org>\n"
1414"MIME-Version: 1.0\n"
@@ -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-30 05:37+0000\n"
20−"X-Generator: Launchpad (build 16750)\n"
19+"X-Launchpad-Export-Date: 2013-09-20 06:21+0000\n"
20+"X-Generator: Launchpad (build 16765)\n"
2121
2222#: Applications/applications.js:23
2323msgid "Phone"
@@ -25,7 +25,7 @@ msgstr "Telefon"
2525
2626#: Applications/applications.js:29
2727msgid "Camera"
28−msgstr ""
28+msgstr "Fotoaparat"
2929
3030#: Applications/applications.js:35
3131msgid "Gallery"
@@ -89,47 +89,50 @@ msgstr "YouTube"
8989
9090#: Components/EdgeDemoOverlay.qml:145
9191msgid "Skip intro"
92−msgstr ""
92+msgstr "Preskoči uvod"
9393
9494#: Components/EdgeDemo.qml:98
9595msgid "Right edge"
96−msgstr ""
96+msgstr "Desni rob"
9797
9898#: Components/EdgeDemo.qml:99
9999msgid "Try swiping from the right edge to unlock the phone"
100−msgstr ""
100+msgstr "Poskusite povleči od desnega roba za odklep telefona"
101101
102102#: Components/EdgeDemo.qml:135
103103msgid "Top edge"
104−msgstr ""
104+msgstr "Zgornji rob"
105105
106106#: Components/EdgeDemo.qml:136
107107msgid "Try swiping from the top edge to access the indicators"
108−msgstr ""
108+msgstr "Poskusite povleči od zgornjega roba za dostop do kazalnikov"
109109
110110#: Components/EdgeDemo.qml:161
111111msgid "Close"
112−msgstr ""
112+msgstr "Zapri"
113113
114114#: Components/EdgeDemo.qml:162
115115msgid "Swipe up again to close the settings screen"
116−msgstr ""
116+msgstr "Povlecite ponovno navzgor za zaprtje zaslona z nastavitvami"
117117
118118#: Components/EdgeDemo.qml:189
119119msgid "Left edge"
120−msgstr ""
120+msgstr "Levi rob"
121121
122122#: Components/EdgeDemo.qml:190
123123msgid "Swipe from the left to reveal the launcher for quick access to apps"
124124msgstr ""
125+"Poskusite povleči od leve za razkritje zaganjalnika za hiter dostop do "
126+"programov"
125127
126128#: Components/EdgeDemo.qml:217
127129msgid "Well done"
128−msgstr ""
130+msgstr "Odlično"
129131
130132#: Components/EdgeDemo.qml:218
131133msgid "You have now mastered the edge gestures and can start using the phone"
132134msgstr ""
135+"Zdaj, ko ste osvojili kretnje z robovi, lahko začnete uporabljati telefon"
133136
134137#: Components/PageHeader.qml:298
135138msgid "Recent searches"
@@ -139,35 +142,37 @@ msgstr "Nedavna iskanja"
139142#: Dash/Apps/AppInfo.qml:73
140143#, qt-format
141144msgid "(%1)"
142−msgstr ""
145+msgstr "(%1)"
143146
144147#. TRANSLATORS: Number of persons who wrote reviews for this app
145148#: Dash/Apps/AppInfo.qml:85
146149#, qt-format
147150msgid "%1 review"
148151msgid_plural "%1 reviews"
149−msgstr[0] ""
150−msgstr[1] ""
152+msgstr[0] "%1 ocen"
153+msgstr[1] "%1 ocena"
154+msgstr[2] "%1 oceni"
155+msgstr[3] "%1 ocene"
151156
152157#: Dash/Apps/AppPreview.qml:175
153158msgid "Rate this"
154−msgstr ""
159+msgstr "Ocenite"
155160
156161#: Dash/Apps/AppReviews.qml:72
157162msgid "Add a review"
158−msgstr ""
163+msgstr "Dodaj oceno"
159164
160165#: Dash/Apps/AppReviews.qml:84
161166msgid "Review"
162−msgstr ""
167+msgstr "Ocena"
163168
164169#: Dash/Apps/AppReviews.qml:118
165170msgid "Send"
166−msgstr ""
171+msgstr "Pošlji"
167172
168173#: Dash/Apps/AppReviews.qml:136
169174msgid "Comments:"
170−msgstr ""
175+msgstr "Opombe:"
171176
172177#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
173178msgid "Featured"
@@ -211,7 +216,7 @@ msgstr ""
211216
212217#: Greeter/Lockscreen.qml:134
213218msgid "Emergency Call"
214−msgstr ""
219+msgstr "Klic v sili"
215220
216221#: Greeter/PassphraseLockscreen.qml:59
217222#, qt-format
@@ -220,7 +225,7 @@ msgstr "Pozdravljeni, %1"
220225
221226#: Greeter/PassphraseLockscreen.qml:59
222227msgid "Hello"
223−msgstr ""
228+msgstr "Pozdravljeni"
224229
225230#: Hud/HudParametrizedActionsPage.qml:132
226231msgid "Confirm"
@@ -253,4 +258,4 @@ msgstr "Nič se ne ujema z vašim iskalnim nizom."
253258#: Shell.qml:429
254259#, qt-format
255260msgid "Please enter %1"
256−msgstr ""
261+msgstr "Vnesite %1"
tests/autopilot/unity8/application_lifecycle/__init__.pynew file+20
@@ -0,0 +1,20 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle base package."""
tests/autopilot/unity8/application_lifecycle/tests/__init__.pynew file

No changes to the content.

tests/autopilot/unity8/application_lifecycle/tests/test_application_lifecycle.pynew file+136
@@ -0,0 +1,136 @@
1+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2+#
3+# Unity Autopilot Test Suite
4+# Copyright (C) 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify
7+# it under the terms of the GNU General Public License as published by
8+# the Free Software Foundation, either version 3 of the License, or
9+# (at your option) any later version.
10+#
11+# This program is distributed in the hope that it will be useful,
12+# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+# GNU General Public License for more details.
15+#
16+# You should have received a copy of the GNU General Public License
17+# along with this program. If not, see <http://www.gnu.org/licenses/>.
18+#
19+
20+"""Tests for the application lifecycle."""
21+
22+from __future__ import absolute_import
23+
24+from unity8.shell import disable_qml_mocking
25+from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
26+
27+from autopilot.matchers import Eventually
28+from autopilot.platform import model
29+from testtools.matchers import Equals, NotEquals
30+
31+import logging
32+
33+logger = logging.getLogger(__name__)
34+
35+
36+class ApplicationLifecycleTests(UnityTestCase):
37+
38+ scenarios = _get_device_emulation_scenarios()
39+
40+ def setUp(self):
41+ super(ApplicationLifecycleTests, self).setUp()
42+ if model() == "Desktop":
43+ self.skipTest("Test cannot be run on the desktop.")
44+
45+ def swipe_screen_from_right(self):
46+ qml_view = self.main_window.get_qml_view()
47+ width = qml_view.width
48+ height = qml_view.height
49+ start_x = width
50+ start_y = int(height/2)
51+ end_x = int(width/2)
52+ end_y = start_y
53+
54+ logger.info("Swiping screen from the right edge")
55+ self.touch.drag(start_x, start_y, end_x, end_y)
56+
57+ def _get_current_focused_app_id(self):
58+ return self._proxy.select_single("Shell").currentFocusedAppId
59+
60+ def _launch_app(self, app_name):
61+ """Launches the application *app_name*
62+
63+ Assumes that the desktop file resides at:
64+ /usr/share/applications/{app_name}.desktop
65+
66+ """
67+ desktop_file = "--desktop_file_hint="\
68+ "/usr/share/applications/{app_name}.desktop".format(
69+ app_name=app_name
70+ )
71+ return self.launch_test_application(
72+ app_name,
73+ desktop_file,
74+ "--stage_hint=main_stage",
75+ app_type='qt'
76+ )
77+
78+ @disable_qml_mocking
79+ def test_can_launch_application(self):
80+ """Must be able to launch an application."""
81+ self.launch_unity()
82+ self.main_window.get_greeter().swipe()
83+
84+ app = self._launch_app("messaging-app")
85+
86+ self.assertThat(app, NotEquals(None))
87+ self.assertThat(
88+ self._get_current_focused_app_id(),
89+ Eventually(Equals("messaging-app"))
90+ )
91+
92+ @disable_qml_mocking
93+ def test_can_launch_multiple_applications(self):
94+ """A second application launched must be focused."""
95+ self.launch_unity()
96+ self.main_window.get_greeter().swipe()
97+
98+ self._launch_app("messaging-app")
99+ self.assertThat(
100+ self._get_current_focused_app_id(),
101+ Eventually(Equals("messaging-app"))
102+ )
103+
104+ self._launch_app("address-book-app")
105+ self.assertThat(
106+ self._get_current_focused_app_id(),
107+ Eventually(Equals("address-book-app"))
108+ )
109+
110+ @disable_qml_mocking
111+ def test_app_moves_from_unfocused_to_focused(self):
112+ """An application that is in the unfocused state must be able to be
113+ brought back to the focused state.
114+
115+ """
116+ self.launch_unity()
117+ self.main_window.get_greeter().swipe()
118+
119+ self._launch_app("messaging-app")
120+ self.assertThat(
121+ self._get_current_focused_app_id(),
122+ Eventually(Equals("messaging-app"))
123+ )
124+
125+ self._launch_app("address-book-app")
126+ self.assertThat(
127+ self._get_current_focused_app_id(),
128+ Eventually(Equals("address-book-app"))
129+ )
130+
131+ self.swipe_screen_from_right()
132+
133+ self.assertThat(
134+ self._get_current_focused_app_id(),
135+ Eventually(Equals("messaging-app"))
136+ )
tests/autopilot/unity8/shell/__init__.py+10
@@ -36,3 +36,13 @@ def with_lightdm_mock(mock_type):
3636 return fn(*args, **kwargs)
3737 return wrapper
3838 return with_lightdm_mock_internal
39+
40+
41+def disable_qml_mocking(fn):
42+ """Simple decorator that disables the QML mocks from being loaded."""
43+ @wraps(fn)
44+ def wrapper(*args, **kwargs):
45+ tests_self = args[0]
46+ tests_self._qml_mock_enabled = False
47+ return fn(*args, **kwargs)
48+ return wrapper
tests/autopilot/unity8/shell/tests/__init__.py+4−1
@@ -86,6 +86,7 @@ class UnityTestCase(AutopilotTestCase):
8686
8787 self._proxy = None
8888 self._lightdm_mock_type = None
89+ self._qml_mock_enabled = True
8990 self.touch = Touch.create()
9091 self._setup_display_details()
9192
@@ -160,7 +161,9 @@ class UnityTestCase(AutopilotTestCase):
160161
161162 if self._lightdm_mock_type is None:
162163 self.patch_lightdm_mock()
163− self._setup_extra_mock_environment_patch()
164+
165+ if self._qml_mock_enabled:
166+ self._setup_extra_mock_environment_patch()
164167
165168 app_proxy = self.launch_test_application(
166169 binary_path,
tests/mocks/AccountsService/AccountsService.cpp+3−3
@@ -24,7 +24,7 @@ AccountsService::AccountsService(QObject* parent)
2424{
2525}
2626
27−QString AccountsService::getUser()
27+QString AccountsService::user() const
2828{
2929 return "testuser";
3030}
@@ -34,7 +34,7 @@ void AccountsService::setUser(const QString &user)
3434 Q_UNUSED(user)
3535}
3636
37−bool AccountsService::getDemoEdges()
37+bool AccountsService::demoEdges() const
3838{
3939 return false;
4040}
@@ -44,7 +44,7 @@ void AccountsService::setDemoEdges(bool demoEdges)
4444 Q_UNUSED(demoEdges)
4545}
4646
47−QString AccountsService::getBackgroundFile()
47+QString AccountsService::backgroundFile() const
4848{
4949 return m_backgroundFile;
5050}
tests/mocks/AccountsService/AccountsService.h+6−6
@@ -28,26 +28,26 @@ class AccountsService: public QObject
2828{
2929 Q_OBJECT
3030 Q_PROPERTY (QString user
31− READ getUser
31+ READ user
3232 WRITE setUser
3333 NOTIFY userChanged)
3434 Q_PROPERTY (bool demoEdges
35− READ getDemoEdges
35+ READ demoEdges
3636 WRITE setDemoEdges
3737 NOTIFY demoEdgesChanged)
3838 Q_PROPERTY (QString backgroundFile
39− READ getBackgroundFile
39+ READ backgroundFile
4040 WRITE setBackgroundFile // only available in mock
4141 NOTIFY backgroundFileChanged)
4242
4343public:
4444 explicit AccountsService(QObject *parent = 0);
4545
46− QString getUser();
46+ QString user() const;
4747 void setUser(const QString &user);
48− bool getDemoEdges();
48+ bool demoEdges() const;
4949 void setDemoEdges(bool demoEdges);
50− QString getBackgroundFile();
50+ QString backgroundFile() const;
5151 void setBackgroundFile(const QString &backgroundFile);
5252
5353Q_SIGNALS:
tests/plugins/AccountsService/client.cpp+2−2
@@ -50,9 +50,9 @@ private Q_SLOTS:
5050 AccountsService session;
5151 session.setUser("testuser");
5252 session.setDemoEdges(true);
53− QCOMPARE(session.getDemoEdges(), true);
53+ QCOMPARE(session.demoEdges(), true);
5454 session.setDemoEdges(false);
55− QCOMPARE(session.getDemoEdges(), false);
55+ QCOMPARE(session.demoEdges(), false);
5656 }
5757};
5858
tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6
@@ -32,5 +32,11 @@ qt5_use_modules(listviewwithpageheadertestsectionExec Test Core Qml)
3232target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
3333add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
3434
35+add_executable(listviewwithpageheadertestsectionexternalmodelExec listviewwithpageheadertestsectionexternalmodel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/ListViewWithPageHeader/listviewwithpageheader.cpp)
36+qt5_use_modules(listviewwithpageheadertestsectionexternalmodelExec Test Core Qml)
37+target_link_libraries(listviewwithpageheadertestsectionexternalmodelExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
38+add_custom_target(testlistviewwithpageheadersectionexternalmodel ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionexternalmodelExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersectionexternalmodel.xml,xunitxml -o -,txt)
39+
3540add_dependencies(qmluitests testlistviewwithpageheader)
3641add_dependencies(qmluitests testlistviewwithpageheadersection)
42+add_dependencies(qmluitests testlistviewwithpageheadersectionexternalmodel)
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsectionexternalmodel.cppnew file+251
@@ -0,0 +1,251 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "listviewwithpageheader.h"
18+
19+#include <QAbstractItemModel>
20+#include <QQmlEngine>
21+#include <QQuickView>
22+#include <QSignalSpy>
23+#include <QSortFilterProxyModel>
24+#include <QtTestGui>
25+#pragma GCC diagnostic push
26+#pragma GCC diagnostic ignored "-pedantic"
27+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
28+#include <private/qquicklistmodel_p.h>
29+#else
30+#include <private/qqmllistmodel_p.h>
31+#endif
32+#include <private/qquickanimation_p.h>
33+#include <private/qquickitem_p.h>
34+#pragma GCC diagnostic pop
35+
36+class StringListModel : public QAbstractListModel
37+{
38+public:
39+ StringListModel()
40+ {
41+ list << "A" << "B" << "C" << "D" << "E" << "F" << "G" << "H";
42+ }
43+
44+ int rowCount(const QModelIndex &parent) const
45+ {
46+ if (parent.isValid())
47+ return 0;
48+ else
49+ return list.count();
50+ }
51+
52+ QVariant data(const QModelIndex &index, int role) const
53+ {
54+ if (role == Qt::SizeHintRole) return 50;
55+ else if (role == Qt::DisplayRole) return list[index.row()];
56+ return QVariant();
57+ }
58+
59+ QHash<int, QByteArray> roleNames() const
60+ {
61+ QHash<int, QByteArray> hash;
62+ hash.insert(Qt::DisplayRole, "type");
63+ hash.insert(Qt::SizeHintRole, "size");
64+ return hash;
65+ }
66+
67+ void moveLastToFirst()
68+ {
69+ const int last = list.count() - 1;
70+ beginMoveRows(QModelIndex(), last, last, QModelIndex(), 0);
71+ list.move(last, 0);
72+ endMoveRows();
73+ }
74+
75+ QStringList list;
76+};
77+
78+class ListViewWithPageHeaderTestSection : public QObject
79+{
80+ Q_OBJECT
81+
82+private:
83+ void verifyItem(int visibleIndex, qreal pos, qreal height, bool culled, const QString &sectionHeader, bool sectionHeaderCulled)
84+ {
85+ QTRY_VERIFY(visibleIndex < lvwph->m_visibleItems.count());
86+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->y(), pos);
87+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->height(), height);
88+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_item)->culled, culled);
89+ QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
90+ if (!sectionHeader.isNull()) {
91+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
92+ QCOMPARE(sectionDelegateIndex(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), lvwph->m_firstVisibleIndex + visibleIndex);
93+ }
94+ }
95+
96+ void changeContentY(qreal change)
97+ {
98+ const qreal dest = lvwph->contentY() + change;
99+ if (dest > lvwph->contentY()) {
100+ const qreal jump = 25;
101+ while (lvwph->contentY() + jump < dest) {
102+ lvwph->setContentY(lvwph->contentY() + jump);
103+ QTest::qWait(1);
104+ }
105+ } else {
106+ const qreal jump = -25;
107+ while (lvwph->contentY() + jump > dest) {
108+ lvwph->setContentY(lvwph->contentY() + jump);
109+ QTest::qWait(1);
110+ }
111+ }
112+ lvwph->setContentY(dest);
113+ QTest::qWait(1);
114+ }
115+
116+ void scrollToTop()
117+ {
118+ const qreal jump = -25;
119+ while (!lvwph->isAtYBeginning()) {
120+ if (lvwph->contentY() + jump > -lvwph->minYExtent()) {
121+ lvwph->setContentY(lvwph->contentY() + jump);
122+ } else {
123+ lvwph->setContentY(lvwph->contentY() - 1);
124+ }
125+ QTest::qWait(1);
126+ }
127+ }
128+
129+ void scrollToBottom()
130+ {
131+ const qreal jump = 25;
132+ while (!lvwph->isAtYEnd()) {
133+ if (lvwph->contentY() + lvwph->height() + jump < lvwph->contentHeight()) {
134+ lvwph->setContentY(lvwph->contentY() + jump);
135+ } else {
136+ lvwph->setContentY(lvwph->contentY() + 1);
137+ }
138+ QTest::qWait(1);
139+ }
140+ }
141+
142+ void verifyInitialTopPosition()
143+ {
144+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
145+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
146+ QCOMPARE(lvwph->m_minYExtent, 0.);
147+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
148+ QCOMPARE(lvwph->m_clipItem->clip(), false);
149+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
150+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
151+ QCOMPARE(lvwph->contentY(), 0.);
152+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
153+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
154+ }
155+
156+ QString section(QQuickItem *item)
157+ {
158+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
159+ }
160+
161+ int sectionDelegateIndex(QQuickItem *item)
162+ {
163+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
164+ }
165+
166+private Q_SLOTS:
167+
168+ void initTestCase()
169+ {
170+ }
171+
172+ void init()
173+ {
174+ view = new QQuickView();
175+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
176+ view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_sectionexternalmodel.qml"));
177+ lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
178+ QVERIFY(lvwph);
179+ view->show();
180+ QTest::qWaitForWindowExposed(view);
181+
182+ verifyInitialTopPosition();
183+ }
184+
185+ void cleanup()
186+ {
187+ delete view;
188+ }
189+
190+ void testCreationDeletion()
191+ {
192+ // Nothing, init/cleanup already tests this
193+ }
194+
195+ void testMoveWithProxy()
196+ {
197+ StringListModel m;
198+ QSortFilterProxyModel proxy;
199+ proxy.setSourceModel(&m);
200+
201+ lvwph->setModel(&proxy);
202+
203+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
204+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
205+ verifyItem(0, 50., 90., false, "A", false);
206+ verifyItem(1, 140., 90., false, "B", false);
207+ verifyItem(2, 230., 90., false, "C", false);
208+ verifyItem(3, 320., 90., false, "D", false);
209+ verifyItem(4, 410., 90., false, "E", false);
210+ verifyItem(5, 500., 90., false, "F", false);
211+ verifyItem(6, 590., 90., true, "G", true);
212+ verifyItem(7, 680., 90., true, "H", true);
213+ QCOMPARE(lvwph->m_minYExtent, 0.);
214+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
215+ QCOMPARE(lvwph->m_clipItem->clip(), false);
216+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
217+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
218+ QCOMPARE(lvwph->contentY(), 0.);
219+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
220+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
221+
222+ m.moveLastToFirst();
223+
224+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 8);
225+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
226+ verifyItem(0, 50., 90., false, "H", false);
227+ verifyItem(1, 140., 90., false, "A", false);
228+ verifyItem(2, 230., 90., false, "B", false);
229+ verifyItem(3, 320., 90., false, "C", false);
230+ verifyItem(4, 410., 90., false, "D", false);
231+ verifyItem(5, 500., 90., false, "E", false);
232+ verifyItem(6, 590., 90., true, "F", true);
233+ verifyItem(7, 680., 90., true, "G", true);
234+ QCOMPARE(lvwph->m_minYExtent, 0.);
235+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
236+ QCOMPARE(lvwph->m_clipItem->clip(), false);
237+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
238+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
239+ QCOMPARE(lvwph->contentY(), 0.);
240+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
241+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
242+ }
243+
244+private:
245+ QQuickView *view;
246+ ListViewWithPageHeader *lvwph;
247+};
248+
249+QTEST_MAIN(ListViewWithPageHeaderTestSection)
250+
251+#include "listviewwithpageheadertestsectionexternalmodel.moc"
tests/plugins/ListViewWithPageHeader/test_sectionexternalmodel.qmlnew file+74
@@ -0,0 +1,74 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import ListViewWithPageHeader 0.1
19+
20+Rectangle {
21+ width: 300
22+ height: 542
23+ color: "lightblue"
24+
25+ ListViewWithPageHeader {
26+ id: listView
27+ width: parent.width
28+ anchors.top: parent.top
29+ anchors.bottom: parent.bottom
30+ model: model
31+ delegate: Rectangle {
32+ property bool timerDone: false
33+ width: parent.width - 20
34+ x: 10
35+ color: index % 2 == 0 ? "red" : "blue"
36+ height: timerDone ? size : 350
37+ Text {
38+ text: index
39+ }
40+ Timer {
41+ id: sizeTimer
42+ interval: 10;
43+ onTriggered: {
44+ timerDone = true
45+ }
46+ }
47+ Component.onCompleted: {
48+ sizeTimer.start()
49+ }
50+ }
51+
52+ pageHeader: Rectangle {
53+ color: "transparent"
54+ width: parent.width
55+ height: 50
56+ implicitHeight: 50
57+ Text {
58+ anchors.fill: parent
59+ text: "APPS"
60+ font.pixelSize: 40
61+ }
62+ }
63+
64+ sectionProperty: "type"
65+ sectionDelegate: Component {
66+ Rectangle {
67+ color: "green"
68+ height: 40
69+ Text { text: section; font.pixelSize: 34 }
70+ anchors { left: parent.left; right: parent.right }
71+ }
72+ }
73+ }
74+}
tests/plugins/Unity/Launcher/launchermodeltest.cpp+61−2
@@ -62,7 +62,14 @@ public:
6262 return QString();
6363 }
6464 unity::shell::application::ApplicationInfoInterface *get(int index) const { return m_list.at(index); }
65− unity::shell::application::ApplicationInfoInterface *findApplication(const QString &) const { return nullptr; }
65+ unity::shell::application::ApplicationInfoInterface *findApplication(const QString &appId) const {
66+ Q_FOREACH(MockApp* app, m_list) {
67+ if (app->appId() == appId) {
68+ return app;
69+ }
70+ }
71+ return nullptr;
72+ }
6673 unity::shell::application::ApplicationInfoInterface *startApplication(const QString &, const QStringList &) { return nullptr; }
6774 bool stopApplication(const QString &) { return false; }
6875 bool focusApplication(const QString &appId) {
@@ -151,9 +158,54 @@ private Q_SLOTS:
151158 QCOMPARE(launcherModel->get(1)->pinned(), false);
152159 }
153160
161+ void testRemove_data() {
162+
163+ QTest::addColumn<bool>("pinned");
164+ QTest::addColumn<bool>("running");
165+
166+ QTest::newRow("non-pinned, running") << false << true;
167+ QTest::newRow("pinned, running") << true << false;
168+ QTest::newRow("pinned, non-running") << true << false;
169+ }
170+
154171 void testRemove() {
172+ QFETCH(bool, pinned);
173+ QFETCH(bool, running);
174+
175+ // In the beginning we always have two items
155176 QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
156− launcherModel->requestRemove(launcherModel->get(0)->appId());
177+
178+ // pin one if required
179+ if (pinned) {
180+ launcherModel->pin(launcherModel->get(1)->appId());
181+ }
182+
183+ // stop it if required
184+ if (!running) {
185+ appManager->removeApplication(1);
186+ }
187+
188+ // Now remove it
189+ launcherModel->requestRemove(launcherModel->get(1)->appId());
190+
191+ if (running) {
192+ // both apps are running, both apps must still be here
193+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
194+
195+ // Item must be unpinned now
196+ QCOMPARE(launcherModel->get(1)->pinned(), false);
197+
198+ } else if (pinned) {
199+ // Item 1 must go away, item 0 is here to stay
200+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
201+ }
202+
203+ // done our checks. now stop the app if was still running
204+ if (running) {
205+ appManager->removeApplication(1);
206+ }
207+
208+ // It needs to go away in any case now
157209 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
158210 }
159211
@@ -181,6 +233,13 @@ private Q_SLOTS:
181233
182234 // quicklist needs to transform to remove item. trigger it and check it item goes away
183235 launcherModel->quickListActionInvoked(launcherModel->get(0)->appId(), pinActionIndex);
236+ QCOMPARE(launcherModel->get(0)->pinned(), false);
237+
238+ // still needs to be here as the app is still here
239+ QCOMPARE(launcherModel->rowCount(QModelIndex()), 2);
240+ // close the app
241+ appManager->removeApplication(0);
242+ // Now it needs to go away
184243 QCOMPARE(launcherModel->rowCount(QModelIndex()), 1);
185244 }
186245
tests/qmltests/CMakeLists.txt−1
@@ -13,7 +13,6 @@ set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
1313set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
1414add_qml_test(Components AnimationControllerWithSignals)
1515add_qml_test(Components Carousel)
16−add_qml_test(Components CrossFadeImage)
1716add_qml_test(Components MathLocal)
1817add_qml_test(Components OpenEffect)
1918add_qml_test(Components RatingStars)
tests/qmltests/Components/tst_CrossFadeImage.qmldeleted−125
@@ -1,125 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../Components"
20−
21−TestCase {
22− name: "CrossFadeImage"
23−
24− property alias status: crossFadeImage.status
25− property alias source: crossFadeImage.source
26− property alias crossFade: crossFadeImage.crossFade
27− property alias fadeInFirst: crossFadeImage.fadeInFirst
28− property alias running: crossFadeImage.running
29−
30− CrossFadeImage {
31− id: crossFadeImage
32− }
33−
34− SignalSpy {
35− id: signalSpy
36− target: crossFadeImage
37− }
38−
39− function initTestFunction(argCrossFade, argFadeInFirst) {
40− source = ""
41− crossFade = argCrossFade
42− fadeInFirst = argFadeInFirst
43− compare(status, Image.Null, "Could not reset CrossFadeImage")
44− }
45−
46− function loadImage(url) {
47− console.log("Loading image...")
48− source = url
49−
50− signalSpy.signalName = "statusChanged"
51− signalSpy.wait()
52−
53− if (status == Image.Null) {
54− signalSpy.clear()
55− signalSpy.wait()
56− }
57−
58− if (status == Image.Loading) {
59− signalSpy.clear()
60− signalSpy.wait()
61− }
62−
63− compare(status, Image.Ready, "Image not ready")
64− console.log("Image loaded.")
65− }
66−
67− function waitForAnimation() {
68− signalSpy.signalName = "runningChanged"
69−
70− if (!running) {
71− signalSpy.clear()
72− signalSpy.wait()
73− compare(running, true, "Animation did not start")
74− }
75−
76− signalSpy.clear()
77− console.log("Waiting for animation to finish...")
78− signalSpy.wait()
79− compare(running, false, "Animation did not stop within 5 seconds.")
80− }
81−
82− function cleanupTest() {
83− compare(running, false, "Animation is running after testcase")
84− compare(crossFadeImage.__nextImage.source, "", "nextimage source is not reset")
85− }
86−
87− function test_fadeFirst() {
88− initTestFunction(true, true)
89−
90− loadImage("../../../graphics/phone_background.jpg")
91−
92− waitForAnimation()
93−
94− cleanupTest()
95− }
96−
97− function test_no_fadeFirst() {
98− initTestFunction(true, false)
99−
100− loadImage("../../../graphics/phone_background.jpg")
101−
102− cleanupTest()
103− }
104−
105− function test_crossFade() {
106− initTestFunction(true, false)
107−
108− loadImage("../../../graphics/phone_background.jpg")
109−
110− loadImage("../../../graphics/tablet_background.jpg")
111−
112− // Due to the internal implementation, __currentImage and __nextImage are swapped before the animation starts
113− // Make sure z order reflects that too.
114− compare(crossFadeImage.__currentImage.z > crossFadeImage.__nextImage.z, true, "new image should be above old image")
115− compare(crossFadeImage.__currentImage.opacity < 0.5, true)
116− compare(crossFadeImage.__nextImage.opacity > 0.5, true)
117−
118− waitForAnimation()
119−
120− compare(crossFadeImage.__currentImage.opacity > 0.5, true)
121− compare(crossFadeImage.__nextImage.opacity < 0.5, true)
122−
123− cleanupTest()
124− }
125−}
tests/qmltests/Dash/tst_DashContent.qml+1−1
@@ -106,7 +106,7 @@ Item {
106106 contentEndReachedSpy.clear()
107107 clear_scope_status();
108108
109− // clear, wait for dahs to empty and load scopes.
109+ // clear, wait for dash to empty and load scopes.
110110 var dashContentList = findChild(dashContent, "dashContentList");
111111 verify(dashContentList != undefined)
112112 scopesModel.clear();
tests/qmltests/Dash/tst_GenericScopeView.qml+3
@@ -44,10 +44,13 @@ Item {
4444
4545 function test_isCurrent() {
4646 var pageHeader = findChild(genericScopeView, "pageHeader");
47+ var previewLoader = findChild(genericScopeView, "previewLoader");
4748 genericScopeView.isCurrent = true
4849 pageHeader.searchQuery = "test"
50+ previewLoader.open = true
4951 genericScopeView.isCurrent = false
5052 tryCompare(pageHeader, "searchQuery", "")
53+ tryCompare(genericScopeView, "previewShown", false);
5154 }
5255 }
5356 }
tests/uqmlscene/main.cpp−2
@@ -497,8 +497,6 @@ int main(int argc, char ** argv)
497497 }
498498
499499 if (window) {
500− mouseTouchAdaptor.setTargetWindow(window);
501−
502500 QSurfaceFormat surfaceFormat = window->requestedFormat();
503501 if (options.multisample)
504502 surfaceFormat.setSamples(16);