on xenial help sign in
merge trunk
commit8182fb8e96c1b7ab8008a80b01e479a3e9553482 authorMichał Sawicz <michal.sawicz@canonical.com> dateFri 9 Aug 2013, 09:40 (13 years ago) parent64b86580b48d4e
140 files changed+2762−859
CODING+2−11 Components/ApplicationManagerWrapper.qml+10−1 Components/Stage.qml+14 Dash/DashApps.qml+1−1 Dash/DashHome.qml+1 Dash/DashMusic.qml+2−2 Dash/DashVideos.qml+3−4 Dash/GenericScopeView.qml+9 Greeter/Greeter.qml+2−3 Greeter/GreeterContent.qml−1 Greeter/Lockscreen.qml+9−9 Greeter/PinLockscreen.qml+110−41 Greeter/PinPadButton.qml+5−16 Panel/IndicatorItem.qml+5 Panel/IndicatorRow.qml+34−48 Panel/Indicators.qml+89−102 Panel/Indicators/client/IndicatorsClient.qml+8−9 Panel/Indicators/client/IndicatorsPage.qml+57−12 Panel/Indicators/client/IndicatorsTree.qml+62 Panel/MenuContent.qml+2−2 Panel/Panel.qml+28−9 Panel/SearchIndicator.qml+3−5 Shell.qml+77−33 build−1 cmake/modules/Plugins.cmake+18−9 debian/changelog+236 debian/control+5−3 debian/unity8-private.install+1 main.cpp+1−1 plugins/CMakeLists.txt+1 plugins/ListViewWithPageHeader/CMakeLists.txt+5−1 plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+167−29 plugins/ListViewWithPageHeader/listviewwithpageheader.h+27−3 plugins/Powerd/CMakeLists.txt+13 plugins/Powerd/Powerd.cpp+36 plugins/Powerd/Powerd.h+40 plugins/Powerd/plugin.cpp+36 plugins/Powerd/plugin.h+35 plugins/Powerd/qmldir+3 plugins/Unity/CMakeLists.txt+1−1 plugins/Unity/Indicators/CMakeLists.txt+1 plugins/Unity/Indicators/flatmenuproxymodel.cpp+10−7 plugins/Unity/Indicators/modelprinter.cpp+114 plugins/Unity/Indicators/modelprinter.h+50 plugins/Unity/Indicators/plugin.cpp+2 plugins/Unity/categories.cpp+6−3 plugins/Unity/categories.h+3−2 plugins/Unity/previewinfohint.cpp+2−2 plugins/Unity/scope.h−3 plugins/Unity/variantutils.cpp+2−118 plugins/Unity/variantutils.h−2 po/ar.po+2−2 po/az.po+2−2 po/bg.po+2−2 po/ca.po+2−2 po/de.po+2−2 po/el.po+2−2 po/en_AU.po+2−2 po/en_GB.po+2−2 po/eo.po+2−2 po/es.po+2−2 po/fi.po+2−2 po/fo.po+2−2 po/fr.po+2−2 po/gl.po+2−2 po/he.po+2−2 po/hr.po+2−2 po/hu.po+2−2 po/hy.po+2−2 po/id.po+2−2 po/it.po+2−2 po/ja.po+2−2 po/kn.po+2−2 po/ko.po+2−2 po/ky.po+2−2 po/lv.po+2−2 po/my.po+2−2 po/nb.po+2−2 po/nl.po+2−2 po/pl.po+2−2 po/pt_BR.po+2−2 po/ro.po+2−2 po/ru.po+2−2 po/si.po+2−2 po/sl.po+2−2 po/sr.po+2−2 po/sv.po+2−2 po/te.po+2−2 po/tr.po+2−2 po/ug.po+2−2 po/uk.po+2−2 po/zh_CN.po+2−2 po/zh_TW.po+2−2 run_on_device+2−2 tests/autopilot/unity8/indicators_client/tests/test_battery.py+11−5 tests/autopilot/unity8/shell/__init__.py+1−27 tests/autopilot/unity8/shell/emulators/greeter.py+4−1 tests/autopilot/unity8/shell/emulators/hud.py+4−7 tests/autopilot/unity8/shell/emulators/main_window.py+1−1 tests/autopilot/unity8/shell/tests/__init__.py+53−1 tests/autopilot/unity8/shell/tests/test_hud.py+5−10 tests/autopilot/unity8/shell/tests/test_lock_screen.py+58−28 tests/mocks/CMakeLists.txt+1 tests/mocks/LightDM/single/GreeterPrivate.cpp+2−4 tests/mocks/QMenuModel/CMakeLists.txt+11 tests/mocks/QMenuModel/QDBusActionGroup.qml+27 tests/mocks/QMenuModel/qmldir+2 tests/mocks/Ubuntu/Application/ApplicationManager.cpp+6−2 tests/mocks/Ubuntu/Application/ApplicationManager.h+4 tests/mocks/Unity/CMakeLists.txt+1 tests/mocks/Unity/Indicators/qml/fake_menu_page1.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page2.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page3.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page4.qml−8 tests/mocks/Unity/Indicators/qml/fake_menu_page5.qml−8 tests/mocks/Unity/Notifications/CMakeLists.txt+11 tests/mocks/Unity/fake_categories.cpp+5−2 tests/mocks/Unity/fake_categories.h+2−1 tests/mocks/Unity/fake_scopes.cpp+2−2 tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6−1 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+237−3 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+408−5 tests/plugins/Unity/Indicators/indicatorsmanagertest.cpp+1−1 tests/plugins/Unity/Indicators/indicatorsmodeltest.cpp+1−1 tests/plugins/Unity/Indicators/menucontentactivatortest.cpp+1−1 tests/plugins/Utils/qlimitproxymodeltest.cpp+1−1 tests/plugins/Utils/qsortfilterproxymodeltest.cpp+1−1 tests/qmltests/CMakeLists.txt+3 tests/qmltests/Components/tst_Stage.qml+1 tests/qmltests/Dash/tst_Dash.qml+4−4 tests/qmltests/Dash/tst_DashContent.qml+12−12 tests/qmltests/Dash/tst_FilterGrids.qml+1−1 tests/qmltests/Greeter/tst_Lockscreen.qml+1 tests/qmltests/Panel/tst_IndicatorItem.qml+10−16 tests/qmltests/Panel/tst_IndicatorRow.qml+21−21 tests/qmltests/Panel/tst_MenuContent.qml+4−4 tests/qmltests/Panel/tst_Panel.qml+83−43 tests/qmltests/Panel/tst_SearchIndicator.qml+8−10 tests/qmltests/tst_Shell.qml+281 tests/utils/modules/Unity/Test/UnityTestCase.qml+32−23
CODING+2−11
@@ -23,16 +23,10 @@ $ cd ~/unity8/trunk
2323$ ./build --setup
2424
2525 this will:
26− - add ppa:ubuntu-unity/next
2726 - install the required dependencies to build, as well as run on the desktop
2827 - it should also install unity-scope-home and unity-lens-application which
2928 are technically "recommends", not strict dependencies
3029
31−Note, once the PPA is added, the script runs apt-get update, if you have
32−any failures associated with it, the build script will bail out of the setup
33−and fail to install all the required dependencies.
34−
35−
3630build Unity 8
3731-------------
3832
@@ -75,14 +69,11 @@ Notes
7569Running Unity 8 on devices
7670==========================
7771- Ubuntu Touch builds are currently only available in 13.10 flavour
78−- supported hardware should match one those listed here
72+- supported hardware should match one of those listed here
7973 https://wiki.ubuntu.com/Touch/Devices#Running_fine
8074- follow the Ubuntu Touch install instructions for your chosen device
8175 https://wiki.ubuntu.com/Touch/Install
82−- make sure your device is connected to a WiFi network
83−- If you haven’t already or if you’ve just freshly flashed your device
84− make sure you run phablet-network-setup which will allow package updates to
85− the device
76+- make sure your device is connected to a network
8677- also make sure you have your SSH key in ~/.ssh/id_rsa.pub (or install one
8778 on the device yourself)
8879
Components/ApplicationManagerWrapper.qml+10−1
@@ -29,6 +29,8 @@ Item {
2929 property bool keyboardVisible: ApplicationManager.keyboardVisible
3030 property int keyboardHeight: ApplicationManager.keyboardHeight
3131
32+ property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
33+
3234 Component.onCompleted: {
3335 // Start the watcher so that the ApplicationManager applications model can be populated.
3436 ApplicationManager.startWatcher();
@@ -121,9 +123,16 @@ Item {
121123 desktopFile = "/usr/share/applications/share-app.desktop"
122124 } else if (favoriteApplication == ApplicationManager.BrowserApplication) {
123125 desktopFile = "/usr/share/applications/webbrowser-app.desktop"
124− } else if (favoriteApplication == 4) { // ApplicationManager.PhoneApplication
126+ } else if (favoriteApplication == ApplicationManager.PhoneApplication) {
125127 desktopFile = "/usr/share/applications/phone-app.desktop"
128+ } else if (favoriteApplication == ApplicationManager.DialerApplication) {
129+ desktopFile = "/usr/share/applications/dialer-app.desktop"
130+ } else if (favoriteApplication == ApplicationManager.MessagingApplication) {
131+ desktopFile = "/usr/share/applications/messaging-app.desktop"
132+ } else if (favoriteApplication == ApplicationManager.AddressbookApplication) {
133+ desktopFile = "/usr/share/applications/address-book-app.desktop"
126134 }
135+
127136 applicationManager.focusRequested(desktopFile);
128137 }
129138 }
Components/Stage.qml+14
@@ -39,6 +39,7 @@ Showable {
3939 type == ApplicationInfo.MainStage ? applicationManager.mainStageApplications
4040 : applicationManager.sideStageApplications
4141 property bool fullyShown: false
42+ property bool fullyHidden: true
4243 readonly property var focusedApplication:
4344 type == ApplicationInfo.MainStage ? applicationManager.mainStageFocusedApplication
4445 : applicationManager.sideStageFocusedApplication
@@ -249,6 +250,19 @@ Showable {
249250 }
250251 }
251252
253+ Connections {
254+ target: stage.applications
255+ onCountChanged: { __discardObsoleteScreenshots(); }
256+ ignoreUnknownSignals: true
257+ }
258+ onFullyHiddenChanged: { __discardObsoleteScreenshots(); }
259+ function __discardObsoleteScreenshots() {
260+ if (stage.fullyHidden && stage.applications && stage.applications.count == 0) {
261+ stage.focusedApplicationWhenUsingScreenshots = undefined;
262+ stage.__hideScreenshots();
263+ }
264+ }
265+
252266
253267 SequentialAnimation {
254268 id: showStartingApplicationAnimation
Dash/DashApps.qml+1−1
@@ -87,7 +87,7 @@ ScopeView {
8787 model: scopeView.scope.categories
8888
8989 delegate: Item {
90− Component.onCompleted: if (index == 3) scopeView.installedModel = Qt.binding(function() { return model.results; });
90+ Component.onCompleted: if (categoryId == "installed") scopeView.installedModel = Qt.binding(function() { return model.results; });
9191 }
9292 }
9393
Dash/DashHome.qml+1
@@ -26,6 +26,7 @@ import "Music"
2626
2727ScopeView {
2828 id: root
29+ objectName: "DashHome"
2930
3031 onMovementStarted: listView.showHeader()
3132
Dash/DashMusic.qml+2−2
@@ -52,7 +52,7 @@ ScopeView {
5252
5353 function getRenderer(categoryId) {
5454 switch (categoryId) {
55− case 1: return "Music/MusicCarousel.qml"
55+ case "featured": return "Music/MusicCarousel.qml"
5656 default: return "Music/MusicFilterGrid.qml"
5757 }
5858 }
@@ -69,7 +69,7 @@ ScopeView {
6969 id: base
7070 highlightWhenPressed: false
7171
72− property int categoryId: id
72+ property string categoryId: model.categoryId
7373
7474 Loader {
7575 anchors { top: parent.top; left: parent.left; right: parent.right }
Dash/DashVideos.qml+3−4
@@ -53,7 +53,7 @@ ScopeView {
5353
5454 function getRenderer(categoryId) {
5555 switch (categoryId) {
56− case 1: return "Video/VideosCarousel.qml"
56+ case "featured": return "Video/VideosCarousel.qml"
5757 default: return "Video/VideosFilterGrid.qml"
5858 }
5959 }
@@ -102,8 +102,7 @@ ScopeView {
102102 delegate: ListItems.Base {
103103 id: base
104104 highlightWhenPressed: false
105− property int categoryIndex: index
106− property int categoryId: id
105+ property string categoryId: model.categoryId
107106
108107 Loader {
109108 id: loader
@@ -119,7 +118,7 @@ ScopeView {
119118 var dataItem;
120119 // VideosCarousel and VideosFilterGrid have different
121120 // clicked signals, accomodate for that
122− if (categoryId == 1) {
121+ if (categoryId == "featured") {
123122 var fileUri = delegateItem.model.uri.replace(/^[^:]+:/, "")
124123 dataItem = {fileUri: fileUri, nfoUri: delegateItem.model.comment}
125124 } else {
Dash/GenericScopeView.qml+9
@@ -114,7 +114,16 @@ ScopeView {
114114 }
115115 }
116116
117+ function getDefaultRendererId(contentType) {
118+ switch (contentType) {
119+ default: return "grid";
120+ }
121+ }
122+
117123 function getRenderer(rendererId, contentType) {
124+ if (rendererId == "default") {
125+ rendererId = getDefaultRendererId(contentType);
126+ }
118127 switch (rendererId) {
119128 case "grid": {
120129 switch (contentType) {
Greeter/Greeter.qml+2−3
@@ -34,7 +34,7 @@ Showable {
3434
3535 property alias dragHandleWidth: dragHandle.width
3636 property alias model: greeterContentLoader.model
37− property bool locked: shown && multiUser && !greeterContentLoader.promptless
37+ property bool locked: shown && !LightDM.Greeter.promptless
3838
3939 readonly property bool narrowMode: !multiUser && width <= units.gu(60)
4040 readonly property bool multiUser: LightDM.Users.count > 1
@@ -59,7 +59,6 @@ Showable {
5959 anchors.fill: parent
6060 property var model: LightDM.Users
6161 property int currentIndex: 0
62− property bool promptless: item ? item.promptless : false
6362 property var infographicModel: LightDM.Infographic
6463
6564 source: required ? "GreeterContent.qml" : ""
@@ -113,7 +112,7 @@ Showable {
113112 // UI element)
114113 distanceThreshold: 0
115114
116− enabled: !greeter.locked
115+ enabled: greeter.narrowMode || !greeter.locked
117116
118117 direction: Direction.Leftwards
119118 }
Greeter/GreeterContent.qml−1
@@ -23,7 +23,6 @@ MouseArea {
2323 id: root
2424 anchors.fill: parent
2525
26− property bool promptless: loginLoader.status == Loader.Ready && LightDM.Greeter.promptless
2726 property bool ready: wallpaper.status == Image.Ready
2827 property bool leftTeaserPressed: teasingMouseArea.pressed &&
2928 teasingMouseArea.mouseX < teasingMouseArea.width / 2
Greeter/Lockscreen.qml+9−9
@@ -69,7 +69,7 @@ Showable {
6969 left: parent.left
7070 right: parent.right
7171 verticalCenter: parent.verticalCenter
72− verticalCenterOffset: root.alphaNumeric ? -units.gu(10) : 0
72+ verticalCenterOffset: root.alphaNumeric ? -units.gu(10) : -units.gu(4)
7373 }
7474 property bool resetting: false
7575
@@ -107,11 +107,11 @@ Showable {
107107 Column {
108108 anchors {
109109 left: parent.left
110− top: pinPadLoader.bottom
111− topMargin: units.gu(4)
112− right: parent.right
113110 bottom: parent.bottom
111+ bottomMargin: units.gu(4)
112+ right: parent.right
114113 }
114+ height: childrenRect.height
115115 spacing: units.gu(1)
116116
117117 Icon {
@@ -120,8 +120,8 @@ Showable {
120120 width: height
121121 anchors.horizontalCenter: parent.horizontalCenter
122122 name: "phone-app-call-symbolic"
123− color: "white"
124− opacity: 0.9
123+ color: "#f3f3e7"
124+ opacity: 0.6
125125
126126 MouseArea {
127127 anchors.fill: parent
@@ -130,9 +130,9 @@ Showable {
130130 }
131131
132132 Label {
133− text: i18n.tr("Emergency call")
134− color: "white"
135− opacity: 0.9
133+ text: i18n.tr("Emergency Call")
134+ color: "#f3f3e7"
135+ opacity: 0.6
136136 fontSize: "medium"
137137 anchors.horizontalCenter: parent.horizontalCenter
138138 }
Greeter/PinLockscreen.qml+110−41
@@ -16,15 +16,17 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import Ubuntu.Components.ListItems 0.1
1920import "../Components"
2021
2122Column {
2223 id: root
2324 anchors.centerIn: parent
24− spacing: units.gu(2.5)
25+ spacing: units.gu(3.5)
2526
2627 property alias placeholderText: pinentryField.placeholderText
27− property int padWidth: units.gu(32)
28+ property int padWidth: units.gu(34)
29+ property int padHeight: units.gu(28)
2830 property int pinLength: 4
2931
3032 signal entered(string passphrase)
@@ -37,70 +39,137 @@ Column {
3739 }
3840 }
3941
40− TextField {
42+
43+ UbuntuShape {
4144 id: pinentryField
4245 objectName: "pinentryField"
4346 anchors.horizontalCenter: parent.horizontalCenter
44− width: units.gu(32)
47+ color: "#55000000"
48+ width:root.padWidth
4549 height: units.gu(5)
46− echoMode: TextInput.Password
47− font.pixelSize: units.dp(44)
48− color: "white"
49− opacity: 0.9
50− hasClearButton: false
51− horizontalAlignment: Text.AlignHCenter
52−
50+ radius: "medium"
51+ property string text: ""
52+ property string placeholderText: ""
5353 onTextChanged: {
54− if (pinentryField.text.length === root.pinLength) {
55− root.entered(pinentryField.text);
54+ pinentryFieldLabel.text = "";
55+ for (var i = 0; i < text.length; ++i) {
56+ pinentryFieldLabel.text += "•";
57+ }
58+ if (text.length === root.pinLength) {
59+ root.entered(text);
5660 }
5761 }
5862
59− // Using a MouseArea to eat clicks. We don't want to disable the TextField for styling reasons
60− MouseArea {
61− anchors.fill: parent
63+ Label {
64+ id: pinentryFieldLabel
65+ anchors.centerIn: parent
66+ font.pixelSize: units.dp(44)
67+ color: "#f3f3e7"
68+ opacity: 0.6
69+ }
70+ Label {
71+ id: pinentryFieldPlaceHolder
72+ anchors.centerIn: parent
73+ color: "grey"
74+ text: parent.placeholderText
75+ visible: pinentryFieldLabel.text.length == 0
6276 }
6377 }
6478
65− Grid {
79+ UbuntuShape {
6680 anchors {
6781 left: parent.left
6882 right: parent.right
6983 margins: (parent.width - root.padWidth) / 2
7084 }
85+ height: root.padHeight
86+ color: "#55000000"
87+ radius: "medium"
88+
89+ ThinDivider {
90+ anchors {
91+ left: parent.left
92+ right: parent.right
93+ top: parent.top
94+ topMargin: root.padHeight / 4
95+ }
96+ }
97+ ThinDivider {
98+ anchors {
99+ left: parent.left
100+ right: parent.right
101+ verticalCenter: parent.verticalCenter
102+ }
103+ }
104+ ThinDivider {
105+ anchors {
106+ left: parent.left
107+ right: parent.right
108+ bottom: parent.bottom
109+ bottomMargin: root.padHeight / 4
110+ }
111+ }
71112
72− columns: 3
73− spacing: units.gu(1)
113+ ThinDivider {
114+ anchors.centerIn: parent
115+ anchors.horizontalCenterOffset: -root.padWidth / 6
116+ width: root.padHeight
117+ rotation: -90
118+ }
119+ ThinDivider {
120+ anchors.centerIn: parent
121+ anchors.horizontalCenterOffset: root.padWidth / 6
122+ width: root.padHeight
123+ rotation: -90
124+ }
74125
75− Repeater {
76− model: 9
126+ Grid {
127+ anchors {
128+ left: parent.left
129+ right: parent.right
130+ margins: (parent.width - root.padWidth) / 2
131+ }
77132
78− PinPadButton {
79− objectName: "pinPadButton" + (index + 1)
80− text: index + 1
133+ columns: 3
134+
135+ Repeater {
136+ model: 9
137+
138+ PinPadButton {
139+ objectName: "pinPadButton" + (index + 1)
140+ width: root.padWidth / 3
141+ height: root.padHeight / 4
142+ text: index + 1
81143
82− onClicked: {
83− pinentryField.text = pinentryField.text + text
144+ onClicked: {
145+ pinentryField.text = pinentryField.text + text;
146+ }
84147 }
85148 }
86− }
87149
88− PinPadButton {
89− objectName: "pinPadButtonBack"
90− iconName: "back"
91− onClicked: root.cancel();
150+ PinPadButton {
151+ objectName: "pinPadButtonBack"
152+ width: root.padWidth / 3
153+ height: root.padHeight / 4
154+ iconName: "back"
155+ onClicked: root.cancel();
156+ }
92157
93− }
94− PinPadButton {
95− objectName: "pinPadButton0"
96− text: "0"
97− onClicked: pinentryField.text = pinentryField.text + text
158+ PinPadButton {
159+ objectName: "pinPadButton0"
160+ width: root.padWidth / 3
161+ height: root.padHeight / 4
162+ text: "0"
163+ onClicked: pinentryField.text = pinentryField.text + text
164+ }
98165
99− }
100− PinPadButton {
101− objectName: "pinPadButtonErase"
102− iconName: "erase"
103− onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
166+ PinPadButton {
167+ objectName: "pinPadButtonErase"
168+ width: root.padWidth / 3
169+ height: root.padHeight / 4
170+ iconName: "erase"
171+ onClicked: pinentryField.text = pinentryField.text.substring(0, pinentryField.text.length-1)
172+ }
104173 }
105174 }
106175
Greeter/PinPadButton.qml+5−16
@@ -17,28 +17,20 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919
20−UbuntuShape {
20+Item {
2121 id: root
22− width: units.gu(10)
23− height: units.gu(7)
24− radius: "medium"
2522
2623 property alias text: label.text
2724 property alias iconName: icon.name
2825
2926 signal clicked()
3027
31− Behavior on color {
32− ColorAnimation { duration: 100 }
33− }
34−
3528 Label {
3629 id: label
3730 anchors.centerIn: parent
38− color: "white"
39− fontSize: "x-large"
40− font.weight: Font.Light
41− opacity: 0.9
31+ color: "#f3f3e7"
32+ fontSize: "large"
33+ font.weight: Font.DemiBold
4234 }
4335
4436 Icon {
@@ -46,14 +38,11 @@ UbuntuShape {
4638 height: units.gu(3)
4739 width: height
4840 anchors.centerIn: parent
49− color: "white"
50− opacity: 0.9
41+ color: "#f3f3e7"
5142 }
5243
5344 MouseArea {
5445 anchors.fill: parent
5546 onClicked: root.clicked()
56− onPressed: root.color = Qt.rgba(0, 0, 0, 0.3)
57− onReleased: root.color = Qt.rgba(0, 0, 0, 0)
5847 }
5948}
Panel/IndicatorItem.qml+5
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Unity.Indicators 0.1 as Indicators
20+import "../Components"
2021
2122Item {
2223 id: indicatorItem
@@ -27,6 +28,7 @@ Item {
2728 property var indicatorProperties: undefined
2829
2930 opacity: dimmed ? 0.4 : 1
31+ Behavior on opacity { StandardAnimation {} }
3032
3133 // only visible when non-empty
3234 visible: loader.item != undefined && loader.status == Loader.Ready ? loader.item.enabled : false
@@ -53,5 +55,8 @@ Item {
5355 width: parent.width
5456 anchors.top: parent.bottom
5557 visible: highlighted
58+
59+ opacity: highlighted ? 1 : 0
60+ Behavior on opacity { StandardAnimation {} }
5661 }
5762}
Panel/IndicatorRow.qml+34−48
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import "../Components"
1920
2021Item {
2122 id: indicatorRow
@@ -25,21 +26,18 @@ Item {
2526 property alias row: row
2627 property QtObject indicatorsModel: null
2728
28− Behavior on y {NumberAnimation {duration: 300; easing.type: Easing.OutCubic} }
29−
3029 width: units.gu(40)
3130 height: units.gu(3)
3231
33− Component.onCompleted: setDefaultItem()
34−
3532 function setDefaultItem() {
3633 // The leftmost indicator
37− var defaultItemIndex = 0
38− setItem(defaultItemIndex)
34+ setCurrentItem(0);
3935 }
4036
41− function setItem(index) {
42− currentItem = rowRepeater.itemAt(index)
37+ function setCurrentItem(index) {
38+ if (currentItemIndex !== index) {
39+ currentItem = rowRepeater.itemAt(index);
40+ }
4341 }
4442
4543 Row {
@@ -54,51 +52,39 @@ Item {
5452 objectName: "rowRepeater"
5553 model: indicatorsModel ? indicatorsModel : undefined
5654
57− IndicatorItem {
58− id: indicatorItem
55+ Item {
56+ id: itemWrapper
57+ height: indicatorRow.height
58+ width: childrenRect.width
5959
60− property int ownIndex: index
60+ property int ownIndex: index
61+ property alias highlighted: indicatorItem.highlighted
62+ property alias dimmed: indicatorItem.dimmed
6163
62− widgetSource: model.widgetSource
64+ IndicatorItem {
65+ id: indicatorItem
66+ height: parent.height
67+
68+ highlighted: indicatorRow.state != "initial" ? itemWrapper.ownIndex == indicatorRow.currentItemIndex : false
69+ dimmed: indicatorRow.state != "initial" ? itemWrapper.ownIndex != indicatorRow.currentItemIndex : false
70+
71+ widgetSource: model.widgetSource
72+ indicatorProperties : model.indicatorProperties
73+ }
6374
64− indicatorProperties : model.indicatorProperties
65− highlighted: indicatorRow.state == "reveal" || indicatorRow.state == "locked" || indicatorRow.state == "commit" ? ownIndex == indicatorRow.currentItemIndex : false
66− dimmed: { //See FIXME in Indicators regarding the "states" change
67− if (indicatorRow.state == "initial" || indicatorRow.state == "") {
68− return false;
69− } else if (indicatorRow.state == "hint") {
70− return true
71− } else {
72− return ownIndex != indicatorRow.currentItemIndex
73− }
74− }
75− height: indicatorRow.height
76− y: {
77− //FIXME: all indicators will be initial for now.
78− if (!highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")) {
79− return -indicatorRow.height
80− } else {
81− return 0
82− }
83− }
84− Behavior on y {
85− NumberAnimation{
86− duration: {
87− if (index == 0) {
88− return 250
89− } else if (index == 1) {
90− return 150
91− } else if (index == 2) {
92− return 550
93− } else if (index == 3) {
94− return 400
95− } else {
96− return 100 + Math.random() * 200
97− }
98− }
99− easing.type: Easing.OutCubic
75+ opacity: {
76+ if (!indicatorItem.highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")) {
77+ return 0.0;
78+ } else {
79+ return 1.0;
10080 }
10181 }
82+ Behavior on opacity {
83+ StandardAnimation {
84+ // flow away from current index
85+ duration: (rowRepeater.count - Math.abs(indicatorRow.currentItemIndex - index)) * (500/rowRepeater.count)
86+ }
87+ }
10288 }
10389 }
10490 }
Panel/Indicators.qml+89−102
@@ -25,16 +25,15 @@ import "../Components/Math.js" as MathLocal
2525Showable {
2626 id: indicators
2727
28− property int referenceOpenedHeight: units.gu(71)
29− property real openedHeight: pinnedMode ? referenceOpenedHeight - panelHeight
30− : referenceOpenedHeight
28+ property real openedHeight: units.gu(71)
3129 property int panelHeight: units.gu(3)
3230 property bool pinnedMode: true //should be set true if indicators menu can cover whole screen
3331
3432 property int hintValue
35− readonly property int lockThreshold: referenceOpenedHeight / 2
33+ readonly property int lockThreshold: openedHeight / 2
3634 property bool fullyOpened: height == openedHeight
3735 property bool partiallyOpened: height > panelHeight && !fullyOpened
36+ property real visualBottom: Math.max(y+height, y+indicatorRow.y+indicatorRow.height)
3837
3938 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
4039 // use its own values. Need to ask design about this.
@@ -43,6 +42,13 @@ Showable {
4342 duration: 350
4443 to: openedHeight
4544 easing.type: Easing.OutCubic
45+
46+ // Re-size if we've changed the openHeight while shown.
47+ onToChanged: {
48+ if (indicators.shown) {
49+ indicators.show();
50+ }
51+ }
4652 }
4753
4854 hideAnimation: StandardAnimation {
@@ -56,28 +62,30 @@ Showable {
5662
5763 onHeightChanged: {
5864 // need to use handle.get_height(). As the handle height depends on indicators.height changes (but this is called first!)
59− var contentProgress = indicators.height - handle.get_height();
65+ var revealProgress = indicators.height - panelHeight
6066 if (!showAnimation.running && !hideAnimation.running) {
61− if (contentProgress <= hintValue && indicators.state == "reveal") {
67+ if (revealProgress == 0) {
68+ indicators.state = "initial";
69+ } else if (revealProgress <= hintValue) {
6270 indicators.state = "hint";
63− } else if (contentProgress > hintValue && contentProgress < lockThreshold) {
71+ } else if (revealProgress > hintValue && revealProgress < lockThreshold) {
6472 indicators.state = "reveal";
65− } else if (contentProgress >= lockThreshold && lockThreshold > 0) {
73+ } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
6674 indicators.state = "locked";
6775 }
6876 }
6977
70− if (contentProgress == 0) {
78+ if (revealProgress == 0) {
7179 menuContent.releaseContent();
7280 }
7381 }
7482
7583 function calculateCurrentItem(xValue, useBuffer) {
76− var rowCoordinates
77− var itemCoordinates
78− var currentItem
79− var distanceFromRightEdge
80− var bufferExceeded = false
84+ var rowCoordinates;
85+ var itemCoordinates;
86+ var currentItem;
87+ var distanceFromRightEdge;
88+ var bufferExceeded = false;
8189
8290 if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
8391
@@ -90,6 +98,14 @@ Showable {
9098 MathLocal.clamp((indicators.height - handle.height - hintValue) /
9199 (lockThreshold - hintValue), 0, 1);
92100
101+ /*
102+ Vertical velocity check. Don't change the indicator if we're moving too quickly.
103+ */
104+ var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
105+ if (verticalSpeed >= 0.05 && indicatorRow.currentItem!=null) {
106+ return;
107+ }
108+
93109 /*
94110 Percentage of an indicator icon's width the user's press can stray horizontally from the
95111 focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
@@ -110,7 +126,7 @@ Showable {
110126 currentItem = indicatorRow.row.childAt(rowCoordinates.x, 0);
111127 if (currentItem && currentItem != indicatorRow.currentItem ) {
112128 itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
113− distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width)
129+ distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
114130 if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
115131 bufferExceeded = true;
116132 } else {
@@ -123,6 +139,8 @@ Showable {
123139 if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItem < 0 || indicatorRow.currentItem == null) {
124140 indicatorRow.currentItem = currentItem;
125141 }
142+ } else if (!currentItem) {
143+ indicatorRow.setDefaultItem();
126144 }
127145 }
128146
@@ -155,13 +173,20 @@ Showable {
155173 left: parent.left
156174 right: parent.right
157175 top: indicatorRow.bottom
158− bottom: parent.bottom
176+ bottom: handle.top
159177 }
160178 indicatorsModel: indicatorsModel
161179 clip: !indicators.fullyOpened
162180
163− onMenuSelected: {
164− indicatorRow.setItem(index)
181+ Connections {
182+ target: indicatorRow
183+ onCurrentItemIndexChanged: menuContent.updateCurrentMenu();
184+ }
185+
186+ function updateCurrentMenu() {
187+ if (currentMenuIndex != indicatorRow.currentItemIndex) {
188+ currentMenuIndex = indicatorRow.currentItemIndex;
189+ }
165190 }
166191
167192 //small shadow gradient at bottom of menu
@@ -188,7 +213,7 @@ Showable {
188213 anchors {
189214 left: parent.left
190215 right: parent.right
191− top: menuContent.bottom
216+ bottom: parent.bottom
192217 }
193218 height: get_height()
194219 clip: height < handleImage.height
@@ -212,33 +237,14 @@ Showable {
212237 }
213238 }
214239
215− PanelSeparatorLine {
216− id: indicatorsSeparatorLine
217− visible: true
218− anchors {
219− top: handle.bottom
220− left: indicators.left
221− right: indicators.right
222− }
223− }
224−
225− BorderImage {
226− id: dropShadow
227− anchors {
228− top: indicators.top
229− bottom: indicatorsSeparatorLine.bottom
230− left: indicators.left
231− right: indicators.right
232− margins: -units.gu(1)
233− }
234− visible: indicators.height > panelHeight
235− source: "graphics/rectangular_dropshadow.sci"
236− }
237−
238240 PanelBackground {
239241 anchors.fill: indicatorRow
240242 }
241243
244+ IndicatorsDataModel {
245+ id: indicatorsModel
246+ }
247+
242248 IndicatorRow {
243249 id: indicatorRow
244250 objectName: "indicatorRow"
@@ -250,58 +256,45 @@ Showable {
250256 indicatorsModel: indicatorsModel
251257 state: indicators.state
252258
253− onCurrentItemIndexChanged: menuContent.currentIndex = currentItemIndex
254−
255− }
256−
257− IndicatorsDataModel {
258− id: indicatorsModel
259− }
260−
261− Connections {
262− target: hideAnimation
263− onRunningChanged: {
264− if (hideAnimation.running) {
265− indicators.state = "initial"
266− } else {
267− if (state == "initial") {
268− indicatorRow.setDefaultItem();
269− menuContent.releaseContent();
270− }
259+ Connections {
260+ target: menuContent
261+ onCurrentMenuIndexChanged: {
262+ indicatorRow.setCurrentItem(menuContent.currentMenuIndex);
271263 }
272264 }
273265 }
266+
274267 Connections {
275268 target: showAnimation
276269 onRunningChanged: {
277270 if (showAnimation.running) {
278− indicators.calculateCurrentItem(dragHandle.touchX, false);
279271 indicators.state = "commit";
280272 }
281273 }
282274 }
283275
284276 Connections {
285− target: dragHandle
286− onTouchXChanged: {
287− var buffer = dragHandle.dragging ? true : false;
288− indicators.calculateCurrentItem(dragHandle.touchX, buffer);
277+ target: hideAnimation
278+ onRunningChanged: {
279+ if (hideAnimation.running) {
280+ indicators.state = "initial";
281+ indicatorRow.currentItem = null;
282+ }
289283 }
290284 }
291285
292− // We start with pinned states. (default pinnedMode: true)
293− states: pinnedModeStates
294− // because of dynamic assignment of states, we need to assign state after completion.
295− Component.onCompleted: state = "initial"
296−
297− // changing states will reset state to "".
298− onPinnedModeChanged: {
299− var last_state = state;
300− states = (pinnedMode) ? pinnedModeStates : offScreenModeStates;
301− state = last_state;
286+ property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
287+ // connections to the active drag handle
288+ Connections {
289+ target: activeDragHandle
290+ onTouchXChanged: {
291+ indicators.calculateCurrentItem(activeDragHandle.touchX, true);
292+ }
293+ onTouchSceneYChanged: {
294+ yVelocityCalculator.trackedPosition = activeDragHandle.touchSceneY;
295+ }
302296 }
303297
304− property var dragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle
305298 DragHandle {
306299 id: showDragHandle
307300 anchors.bottom: parent.bottom
@@ -315,7 +308,7 @@ Showable {
315308 hintDisplacement: pinnedMode ? indicators.hintValue : 0
316309 autoCompleteDragThreshold: maxTotalDragDistance / 2
317310 stretch: true
318− maxTotalDragDistance: openedHeight - handle.height
311+ maxTotalDragDistance: openedHeight - panelHeight
319312 distanceThreshold: pinnedMode ? 0 : units.gu(3)
320313
321314 onStatusChanged: {
@@ -327,28 +320,40 @@ Showable {
327320 DragHandle {
328321 id: hideDragHandle
329322 anchors.fill: handle
330− height: panelHeight
331323 direction: Direction.Upwards
332324 enabled: indicators.shown
333− hintDisplacement: units.gu(2)
325+ hintDisplacement: indicators.hintValue
334326 autoCompleteDragThreshold: maxTotalDragDistance / 6
335327 stretch: true
336− maxTotalDragDistance: referenceOpenedHeight - 2*panelHeight
328+ maxTotalDragDistance: openedHeight - panelHeight
337329 distanceThreshold: 0
338330 }
339331
340− property list<State> offScreenModeStates: [
332+ AxisVelocityCalculator {
333+ id: yVelocityCalculator
334+ }
335+
336+ states: [
341337 State {
342338 name: "initial"
343339 },
344340 State {
345341 name: "hint"
346− PropertyChanges { target: indicatorRow; y: panelHeight }
342+ PropertyChanges {
343+ target: indicatorRow;
344+ y: pinnedMode ? 0 : panelHeight
345+ }
346+ StateChangeScript {
347+ script: {
348+ if (activeDragHandle) {
349+ calculateCurrentItem(activeDragHandle.touchX, false);
350+ }
351+ }
352+ }
347353 },
348354 State {
349355 name: "reveal"
350356 extend: "hint"
351− StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
352357 },
353358 State {
354359 name: "locked"
@@ -359,25 +364,7 @@ Showable {
359364 extend: "hint"
360365 }
361366 ]
362−
363− property list<State> pinnedModeStates: [
364− State {
365− name: "initial"
366− },
367− State {
368− name: "hint"
369− },
370− State {
371− name: "reveal"
372− StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
373− },
374− State {
375− name: "locked"
376− },
377− State {
378− name: "commit"
379− }
380− ]
367+ state: "initial"
381368
382369 transitions: [
383370 Transition {
Panel/Indicators/client/IndicatorsClient.qml+8−9
@@ -27,16 +27,15 @@ Rectangle {
2727
2828 PageStack {
2929 id: pages
30−
3130 anchors.fill: parent
32− Component.onCompleted: root.reset()
33− }
31+ Component.onCompleted: reset()
3432
35− function reset() {
36− pages.clear();
37− var component = Qt.createComponent("IndicatorsList.qml");
38− var page = component.createObject(pages);
39− console.log(component.errorString());
40− pages.push(page);
33+ function reset() {
34+ clear();
35+ var component = Qt.createComponent("IndicatorsList.qml");
36+ var page = component.createObject(pages);
37+ console.log(component.errorString());
38+ push(page);
39+ }
4140 }
4241}
Panel/Indicators/client/IndicatorsPage.qml+57−12
@@ -15,35 +15,80 @@
1515 *
1616 * Authors:
1717 * Renato Araujo Oliveira Filho <renato@canonical.com>
18+ * Nick Dedekind <nick.dedekind@canonical.com>
1819 */
1920
2021import QtQuick 2.0
2122import Ubuntu.Components 0.1
23+import Ubuntu.Components.ListItems 0.1 as ListItem
2224
2325Page {
24− id: _page
26+ id: page
2527
2628 title: indicatorProperties && indicatorProperties.title ? indicatorProperties.title : ""
2729 property variant indicatorProperties
28− property alias pageSource : page_loader.source
30+ property string pageSource : pageLoader.source
2931
3032 anchors.fill: parent
3133
34+ ListItem.Standard {
35+ id: visualCheckItem
36+ text: "Enable Visual Representation"
37+ control: Switch {
38+ id: visualCheck
39+ checked: true
40+ }
41+ }
42+
3243 Loader {
33− id: page_loader
34− objectName: "page_loader"
44+ id: pageLoader
45+ objectName: "pageLoader"
3546
36− anchors.fill: parent
47+ anchors {
48+ top: visualCheckItem.bottom
49+ left: parent.left
50+ right: parent.right
51+ bottom: buttons.top
52+ topMargin: units.gu(2)
53+ bottomMargin: units.gu(2)
54+ }
55+ source : visualCheck.checked ? page.pageSource : "IndicatorsTree.qml"
3756
38− onStatusChanged: {
39− if (status == Loader.Ready) {
40− for(var pName in indicatorProperties) {
41− if (item.hasOwnProperty(pName)) {
42− item[pName] = indicatorProperties[pName];
43− }
57+ onLoaded: {
58+ for(var pName in indicatorProperties) {
59+ if (item.hasOwnProperty(pName)) {
60+ item[pName] = indicatorProperties[pName];
4461 }
45− item.start();
4662 }
63+ item.start();
64+ }
65+ }
66+
67+ Item {
68+ id: buttons
69+ anchors {
70+ left: parent.left
71+ right: parent.right
72+ bottom: parent.bottom
73+ margins: units.gu(1)
74+ }
75+ height: childrenRect.height
76+
77+ Button {
78+ anchors {
79+ left: parent.left
80+ }
81+ text: "Back"
82+ onClicked: page.pageStack.reset()
83+ }
84+ Button {
85+ id: refresh
86+ visible: !visualCheck.checked
87+ anchors {
88+ right: parent.right
89+ }
90+ text: "Refresh"
91+ onClicked: pageLoader.item.refresh()
4792 }
4893 }
4994}
Panel/Indicators/client/IndicatorsTree.qmlnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dededkind@canonical.com>
18+ */
19+
20+import QtQuick 2.0
21+import Ubuntu.Components 0.1
22+import Unity.Indicators 0.1 as Indicators
23+import QMenuModel 0.1
24+import Ubuntu.Components.ListItems 0.1 as ListItem
25+
26+Page {
27+ id: page
28+ anchors.fill: parent
29+
30+ property alias busType: menuModel.busType
31+ property alias busName: menuModel.busName
32+ property string actionsObjectPath
33+ property var menuObjectPaths: undefined
34+ readonly property string device: "phone"
35+
36+ property string deviceMenuObjectPath: menuObjectPaths.hasOwnProperty(device) ? menuObjectPaths[device] : ""
37+
38+ function start() {
39+ menuModel.start();
40+ }
41+
42+ QDBusMenuModel {
43+ id: menuModel
44+ objectPath: page.deviceMenuObjectPath
45+ }
46+
47+ Indicators.ModelPrinter {
48+ id: printer
49+ model: menuModel
50+ }
51+
52+ Flickable {
53+ anchors.fill: parent
54+ contentHeight: all_data.height
55+ clip:true
56+ Text {
57+ id: all_data
58+ color: "white"
59+ text: printer.text
60+ }
61+ }
62+}
Panel/MenuContent.qml+2−2
@@ -24,7 +24,7 @@ Rectangle {
2424
2525 property QtObject indicatorsModel: null
2626 property bool __contentActive: false
27− property alias currentIndex : menus.currentIndex
27+ property alias currentMenuIndex : menus.currentIndex
2828 property color backgroundColor: "#221e1c" // FIXME not in palette yet
2929 property int contentReleaseInterval: 20000
3030
@@ -146,7 +146,7 @@ Rectangle {
146146 Indicators.MenuContentActivator {
147147 id: menuActivator
148148 running: content.__contentActive
149− baseIndex: content.currentIndex
149+ baseIndex: content.currentMenuIndex
150150 count: indicatorsModel.count
151151 }
152152}
Panel/Panel.qml+28−9
@@ -39,11 +39,8 @@ Item {
3939 }
4040 height: __panelMinusSeparatorLineHeight
4141 y: 0
42− onYChanged: indicatorsMenu.y = y;
4342
44− Behavior on y {
45− NumberAnimation { duration: 200 }
46− }
43+ Behavior on y { StandardAnimation {} }
4744 }
4845
4946 PanelSeparatorLine {
@@ -78,18 +75,40 @@ Item {
7875 id: indicatorsMenu
7976
8077 anchors.right: parent.right
81− y: 0
78+ y: panelBackground.y
8279 width: root.indicatorsMenuWidth
8380 shown: false
8481 hintValue: __panelMinusSeparatorLineHeight * 3
8582 panelHeight: __panelMinusSeparatorLineHeight
86− referenceOpenedHeight: parent.height
87−
83+ openedHeight: parent.height + (pinnedMode ? 0 : root.panelHeight)
8884 pinnedMode: !fullscreenMode
8985
9086 property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
9187 }
9288
89+ PanelSeparatorLine {
90+ id: indicatorsSeparatorLine
91+ visible: true
92+ anchors {
93+ left: indicatorsMenu.left
94+ right: indicatorsMenu.right
95+ }
96+ y: indicatorsMenu.visualBottom
97+ }
98+
99+ BorderImage {
100+ id: dropShadow
101+ anchors {
102+ top: indicators.top
103+ bottom: indicatorsSeparatorLine.bottom
104+ left: indicators.left
105+ right: indicators.right
106+ margins: -units.gu(1)
107+ }
108+ visible: indicatorsMenu.height > indicatorsMenu.panelHeight
109+ source: "graphics/rectangular_dropshadow.sci"
110+ }
111+
93112 SearchIndicator {
94113 id: search
95114 objectName: "search"
@@ -98,14 +117,14 @@ Item {
98117 state: {
99118 if (parent.width < indicatorsMenu.width + width) {
100119 if (indicatorsMenu.state != "initial") {
101− return "hiddenUp";
120+ return "hidden";
102121 }
103122 }
104123 if (root.searchVisible) {
105124 return "visible";
106125 }
107126
108− return "hiddenUp";
127+ return "hidden";
109128 }
110129
111130 width: units.gu(13)
Panel/SearchIndicator.qml+3−5
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import "../Components"
1920
2021Item {
2122 id: search
@@ -40,8 +41,7 @@ Item {
4041 width: parent.width
4142 height: parent.height
4243
43− Behavior on opacity {NumberAnimation {}}
44− Behavior on y {NumberAnimation {duration: 300; easing.type: Easing.OutCubic}}
44+ Behavior on opacity { StandardAnimation {} }
4545
4646 Image {
4747 id: icon
@@ -67,15 +67,13 @@ Item {
6767 name: "visible"
6868 PropertyChanges {
6969 target: container
70− y: 0
7170 opacity: 1
7271 }
7372 },
7473 State {
75− name: "hiddenUp"
74+ name: "hidden"
7675 PropertyChanges {
7776 target: container
78− y: -height
7977 opacity: 0
8078 }
8179 }
Shell.qml+77−33
@@ -19,6 +19,7 @@ import Ubuntu.Application 0.1
1919import Ubuntu.Components 0.1
2020import Ubuntu.Gestures 0.1
2121import LightDM 0.1 as LightDM
22+import Powerd 0.1
2223import "Dash"
2324import "Greeter"
2425import "Launcher"
@@ -36,8 +37,8 @@ FocusScope {
3637
3738 // this is only here to select the width / height of the window if not running fullscreen
3839 property bool tablet: false
39− width: tablet ? units.gu(160) : ApplicationArguments.hasGeometry() ? ApplicationArguments.width() : units.gu(40)
40− height: tablet ? units.gu(100) : ApplicationArguments.hasGeometry() ? ApplicationArguments.height() : units.gu(71)
40+ width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
41+ height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
4142
4243 property real edgeSize: units.gu(2)
4344 property url default_background: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
@@ -121,19 +122,22 @@ FocusScope {
121122 Keys.onVolumeUpPressed: volumeControl.volumeUp()
122123 Keys.onVolumeDownPressed: volumeControl.volumeDown()
123124
124− Keys.onReleased: {
125− if (event.key == Qt.Key_PowerOff) {
126− greeter.show()
127− }
128− }
129−
130125 Item {
131126 id: underlay
127+ objectName: "underlay"
132128 anchors.fill: parent
133− visible: !(panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth)
134− && (stages.fullyHidden
135− || (stages.fullyShown && mainStage.usingScreenshots)
136− || !stages.fullyShown && (mainStage.usingScreenshots || (sideStage.shown && sideStage.usingScreenshots)))
129+
130+ // Whether the underlay is fully covered by opaque UI elements.
131+ property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
132+
133+ // Whether the user should see the topmost application surface (if there's one at all).
134+ property bool applicationSurfaceShouldBeSeen:
135+ (mainStage.applications && mainStage.applications.count > 0)
136+ && (!stages.fullyHidden && !mainStage.usingScreenshots)
137+
138+ // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
139+ // through the translucent parts of the shell surface.
140+ visible: !fullyCovered && !applicationSurfaceShouldBeSeen
137141
138142 Image {
139143 id: backgroundImage
@@ -151,6 +155,7 @@ FocusScope {
151155
152156 Dash {
153157 id: dash
158+ objectName: "dash"
154159
155160 available: !greeter.shown && !lockscreen.shown
156161 hides: [stages, launcher, panel.indicators]
@@ -178,7 +183,7 @@ FocusScope {
178183 }
179184 }
180185
181− // FIXME: only necessary because stagesRevealer.animatedProgress and
186+ // FIXME: only necessary because stagesOuterContainer.showProgress and
182187 // greeterRevealer.animatedProgress are not animated
183188 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
184189 }
@@ -198,6 +203,7 @@ FocusScope {
198203
199204 Showable {
200205 id: stages
206+ objectName: "stages"
201207
202208 x: width
203209
@@ -254,6 +260,7 @@ FocusScope {
254260
255261 anchors.fill: parent
256262 fullyShown: stages.fullyShown
263+ fullyHidden: stages.fullyHidden
257264 shouldUseScreenshots: !fullyShown
258265 rightEdgeEnabled: !sideStage.enabled
259266
@@ -338,7 +345,7 @@ FocusScope {
338345 }
339346
340347 DragHandle {
341− id: stagesRevealer
348+ id: stagesDragHandle
342349
343350 anchors.top: parent.top
344351 anchors.bottom: parent.bottom
@@ -346,7 +353,11 @@ FocusScope {
346353
347354 width: shell.edgeSize
348355 direction: Direction.Leftwards
349− enabled: mainStage.applications.count > 0 || sideStage.applications.count > 0
356+ property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
357+
358+ maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
359+ // Make autocompletion impossible when !haveApps
360+ edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
350361 }
351362 }
352363 }
@@ -404,9 +415,6 @@ FocusScope {
404415
405416 dragHandleWidth: shell.edgeSize
406417
407− property var previousMainApp: null
408− property var previousSideApp: null
409−
410418 onShownChanged: {
411419 if (shown) {
412420 lockscreen.reset();
@@ -416,20 +424,6 @@ FocusScope {
416424 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
417425 }
418426 greeter.forceActiveFocus();
419− // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
420− // the stage was actually shown
421− if (mainStage.fullyShown) greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
422− if (sideStage.fullyShown) greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
423− applicationManager.unfocusCurrentApplication();
424− } else {
425− if (greeter.previousMainApp) {
426− applicationManager.focusApplication(greeter.previousMainApp);
427− greeter.previousMainApp = null;
428− }
429− if (greeter.previousSideApp) {
430− applicationManager.focusApplication(greeter.previousSideApp);
431− greeter.previousSideApp = null;
432− }
433427 }
434428 }
435429
@@ -451,6 +445,42 @@ FocusScope {
451445 blockInput: greeter.shown || lockscreen.shown
452446 }
453447
448+ Connections {
449+ id: powerConnection
450+ target: Powerd
451+
452+ property var previousMainApp: null
453+ property var previousSideApp: null
454+
455+ function setFocused(focused) {
456+ if (!focused) {
457+ // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
458+ // the stage was actually shown
459+ if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
460+ if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
461+ applicationManager.unfocusCurrentApplication();
462+ } else {
463+ if (powerConnection.previousMainApp) {
464+ applicationManager.focusApplication(powerConnection.previousMainApp);
465+ powerConnection.previousMainApp = null;
466+ }
467+ if (powerConnection.previousSideApp) {
468+ applicationManager.focusApplication(powerConnection.previousSideApp);
469+ powerConnection.previousSideApp = null;
470+ }
471+ }
472+ }
473+
474+ onPowerStateChange: {
475+ if (state == 0) { // suspend
476+ powerConnection.setFocused(false);
477+ greeter.show();
478+ } else if (state == 1) { // active
479+ powerConnection.setFocused(true);
480+ }
481+ }
482+ }
483+
454484 Item {
455485 id: overlay
456486
@@ -536,7 +566,7 @@ FocusScope {
536566 anchors.bottom: parent.bottom
537567 width: parent.width
538568 dragAreaWidth: shell.edgeSize
539− available: !greeter.locked
569+ available: !greeter.shown || greeter.narrowMode
540570 onDashItemSelected: {
541571 greeter.hide()
542572 // Animate if moving between application and dash
@@ -631,4 +661,18 @@ FocusScope {
631661
632662 enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
633663 }
664+
665+ Label {
666+ anchors.fill: parent
667+ visible: applicationManager.fake
668+ text: "EARLY ALPHA\nNOT READY FOR USE"
669+ color: "lightgrey"
670+ opacity: 0.2
671+ font.weight: Font.Black
672+ horizontalAlignment: Text.AlignHCenter
673+ verticalAlignment: Text.AlignVCenter
674+ fontSizeMode: Text.Fit
675+ font.pixelSize: height/2
676+ rotation: -45
677+ }
634678}
build−1
@@ -36,7 +36,6 @@ BUILD_TYPE="debug"
3636[ $# -eq 1 ] && BUILD_TYPE="$1"
3737
3838install_dependencies() {
39− [ -f /etc/apt/sources.list.d/ubuntu-unity-next-${DISTRIB_CODENAME}.list ] || sudo add-apt-repository ppa:ubuntu-unity/next || exit 1
4039 sudo apt-get update || exit 4
4140 echo "Installing Unity 8 dependencies.."
4241 sudo apt-get install devscripts \
cmake/modules/Plugins.cmake+18−9
@@ -1,3 +1,9 @@
1+find_program(qmlplugindump_exe qmlplugindump)
2+
3+if(NOT qmlplugindump_exe)
4+ msg(FATAL_ERROR "Could not locate qmlplugindump.")
5+endif()
6+
17# Creates target for copying and installing qmlfiles
28#
39# export_qmlfiles(plugin sub_path)
@@ -40,16 +46,19 @@ macro(export_qmlplugin PLUGIN VERSION PLUGIN_SUBPATH)
4046 set(multi_value_keywords TARGETS)
4147 cmake_parse_arguments(qmlplugin "" "" "${multi_value_keywords}" ${ARGN})
4248
43− # create the plugin.qmltypes file
44− add_custom_target(${PLUGIN}-qmltypes ALL
45− COMMAND qmlplugindump -notrelocatable ${PLUGIN} ${VERSION} ${CMAKE_BINARY_DIR}/plugins > ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
46− )
47− add_dependencies(${PLUGIN}-qmltypes ${PLUGIN}-qmlfiles ${qmlplugin_TARGETS})
49+ # Only try to generate .qmltypes if not cross compiling
50+ if(NOT CMAKE_CROSSCOMPILING)
51+ # create the plugin.qmltypes file
52+ add_custom_target(${PLUGIN}-qmltypes ALL
53+ COMMAND ${qmlplugindump_exe} -notrelocatable ${PLUGIN} ${VERSION} ${CMAKE_BINARY_DIR}/plugins > ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
54+ )
55+ add_dependencies(${PLUGIN}-qmltypes ${PLUGIN}-qmlfiles ${qmlplugin_TARGETS})
4856
49− # install the qmltypes file.
50− install(FILES ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
51− DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
52− )
57+ # install the qmltypes file.
58+ install(FILES ${CMAKE_BINARY_DIR}/plugins/${PLUGIN_SUBPATH}/plugin.qmltypes
59+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/${PLUGIN_SUBPATH}
60+ )
61+ endif()
5362
5463 # install the additional targets
5564 install(TARGETS ${qmlplugin_TARGETS}
debian/changelog+236
@@ -1,3 +1,239 @@
1+unity8 (7.81.3+13.10.20130809-0ubuntu1) saucy; urgency=low
2+
3+ [ Michał Sawicz ]
4+ * Prepare unity8 for cross-building.
5+
6+ [ Ubuntu daily release ]
7+ * Automatic snapshot from revision 176
8+
9+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 09 Aug 2013 02:32:10 +0000
10+
11+unity8 (7.81.3+13.10.20130808-0ubuntu1) saucy; urgency=low
12+
13+ [ Michał Sawicz ]
14+ * Re-enable battery slider test.
15+
16+ [ Nick Dedekind ]
17+ * Workaround for non-deletion of indicator page menu items. (LP:
18+ #1183065, #1206991)
19+
20+ [ Albert Astals ]
21+ * LVPWH: Fix regression handling the sticky top section culling r166
22+ introduced the regression, this fixes it+tests.
23+ * Implement+test the maximizeVisibleArea function Tries to show as
24+ much possible of an index that is already shown on screen Will be
25+ used for the dash category expansion.
26+
27+ [ Ubuntu daily release ]
28+ * Automatic snapshot from revision 174
29+
30+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 08 Aug 2013 15:23:17 +0000
31+
32+unity8 (7.81.3+13.10.20130807-0ubuntu1) saucy; urgency=low
33+
34+ [ Michał Sawicz ]
35+ * Drop ppa:ubuntu-unity/next.
36+ * Revert revision 161 that causes issues with invalid background.
37+
38+ [ Albert Astals ]
39+ * Fix off by one in the culling condition If you are on 0 and your
40+ height is 1 and viewport starts at 1 you have to be culled since you
41+ are not visible.
42+
43+ [ Ubuntu daily release ]
44+ * Automatic snapshot from revision 168
45+
46+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 07 Aug 2013 02:32:00 +0000
47+
48+unity8 (7.81.3+13.10.20130806-0ubuntu1) saucy; urgency=low
49+
50+ [ Michael Terry ]
51+ * Show the greeter when powerd tells us to, not just whenever we press
52+ the power key. (LP: #1186256)
53+
54+ [ Ubuntu daily release ]
55+ * Automatic snapshot from revision 164
56+
57+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 06 Aug 2013 03:43:01 +0000
58+
59+unity8 (7.81.3+13.10.20130805-0ubuntu1) saucy; urgency=low
60+
61+ [ Michael Terry ]
62+ * Fixes the lockscreen and swiping on the greeter still being possible
63+ even when in tablet mode. (LP: #1204984)
64+ * Watch powerd signals to notice a sleep and unfocus current app when
65+ that happens.
66+
67+ [ Michael Zanetti ]
68+ * make findChild also find invisible childs This considerably
69+ increases the amount of items to be searched up to a level where
70+ testShell didn't finish any more with searching. Hence this commit
71+ also changes findChild to do a breadth-first instead of a depth-
72+ first search.
73+ * Read background from GSettings or fallback to default_background.
74+
75+ [ Andrea Cimitan ]
76+ * Read background from GSettings or fallback to default_background.
77+
78+ [ Albert Astals ]
79+ * Make LVWPH provide a delegateIndex for sectionHeaders This way we
80+ can match the sectionHeader to the model easier in the qml/js side .
81+ * Fix tryCompare call The 4th parameter of tryCompare is timeout not
82+ message .
83+
84+ [ Daniel d'Andrada ]
85+ * Read background from GSettings or fallback to default_background.
86+
87+ [ Ubuntu daily release ]
88+ * Automatic snapshot from revision 162
89+
90+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 05 Aug 2013 02:32:05 +0000
91+
92+unity8 (7.81.3+13.10.20130802-0ubuntu1) saucy; urgency=low
93+
94+ [ Michael Terry ]
95+ * Make hud autopilot tests more reliable by fixing how it calculates
96+ relative coordinates.
97+
98+ [ Albert Astals ]
99+ * Only update the "section" if we are not culling the item If the item
100+ is not shown we should not care about its section.
101+
102+ [ Ubuntu daily release ]
103+ * Automatic snapshot from revision 155
104+
105+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 02 Aug 2013 02:40:11 +0000
106+
107+unity8 (7.81.3+13.10.20130801.1-0ubuntu1) saucy; urgency=low
108+
109+ [ Michał Sawicz ]
110+ * Add a disclaimer for the fake applications plugin.
111+
112+ [ Nick Dedekind ]
113+ * Removed animations from fake indicator pages.
114+
115+ [ Ubuntu daily release ]
116+ * Automatic snapshot from revision 152
117+
118+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 01 Aug 2013 14:30:40 +0000
119+
120+unity8 (7.81.3+13.10.20130801ubuntu.unity.next-0ubuntu1) saucy; urgency=low
121+
122+ [ Michael Zanetti ]
123+ * implemented new Lockscreen design.
124+
125+ [ Michał Sawicz ]
126+ * Fix mock VideoPreview to use the string categoryId as well.
127+
128+ [ Nick Dedekind ]
129+ * Added a text tree representation of the qmenumodel to the
130+ indicators-client application.
131+
132+ [ Albert Astals ]
133+ * Don't need deelistmodel here.
134+
135+ [ Ubuntu daily release ]
136+ * Automatic snapshot from revision 149 (ubuntu-unity/next)
137+
138+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 01 Aug 2013 02:32:03 +0000
139+
140+unity8 (7.81.3+13.10.20130730ubuntu.unity.next-0ubuntu1) saucy; urgency=low
141+
142+ [ Michał Sawicz ]
143+ * Adapt to Qt 5.1.
144+
145+ [ Albert Astals ]
146+ * Adapt to Qt 5.1.
147+
148+ [ Ubuntu daily release ]
149+ * Automatic snapshot from revision 143 (ubuntu-unity/next)
150+
151+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Tue, 30 Jul 2013 02:33:12 +0000
152+
153+unity8 (7.81.3+13.10.20130729ubuntu.unity.next-0ubuntu1) saucy; urgency=low
154+
155+ [ Michal Hruby ]
156+ * Remove the variant conversions methods as they were moved to dee-qt.
157+
158+ [ Michał Sawicz ]
159+ * Re-enable passphrase tests under UInput.
160+ * Use the new string categoryIds in custom video and music scope
161+ views. (LP: #1199322)
162+
163+ [ Nick Dedekind ]
164+ * Behavioural changes for indicators - Part 1 - Use standard
165+ animations. - Search bar animation less distracting. - Hinting
166+ animation shows header. - Vertical velocity detector to reduce
167+ accidental menu switches in dragging phase.
168+
169+ [ Gustavo Pichorim Boiko ]
170+ * Add entries to the new applications resulted from the split of the
171+ phone-app.
172+
173+ [ Ubuntu daily release ]
174+ * Automatic snapshot from revision 141 (ubuntu-unity/next)
175+
176+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 29 Jul 2013 03:41:07 +0000
177+
178+unity8 (7.81.3+13.10.20130726ubuntu.unity.next-0ubuntu1) saucy; urgency=low
179+
180+ [ Michal Hruby ]
181+ * Expose real category ids and not just indices.
182+ * Provide fallbacks for default renderer.
183+
184+ [ Daniel d'Andrada ]
185+ * Give a visual feedback on right-edge drag with no running apps (LP:
186+ #1116207). (LP: #1116207)
187+
188+ [ Albert Astals ]
189+ * Update m_firstVisibleIndex if there's no visible items anymore Also
190+ remove the check for m_visibleItems.isEmpty() on insert, the
191+ m_firstVisibleIndex == 0 already protects us against that.
192+
193+ [ Christopher Lee ]
194+ * Tests now use a default lightdm mock if not decorated. (LP:
195+ #1204772)
196+
197+ [ Ubuntu daily release ]
198+ * Automatic snapshot from revision 135 (ubuntu-unity/next)
199+
200+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 26 Jul 2013 07:06:08 +0000
201+
202+unity8 (7.81.3+13.10.20130725ubuntu.unity.next-0ubuntu1) saucy; urgency=low
203+
204+ [ Michal Hruby ]
205+ * Fix adding items into an empty LVWPH.
206+
207+ [ Michał Sawicz ]
208+ * Move to using upstart in run_on_device.
209+ * Added heeding and qmltest for button-tint hint.
210+ * Refactoring and cleanup of the Unity8 Autopilot tests.
211+ * Hide the Unity launcher during autopiloting and skip battery tests
212+ if unavailable.
213+
214+ [ Ying-Chun Liu ]
215+ * Let GenericScope support loading different renderers.
216+
217+ [ Nick Dedekind ]
218+ * Removed overview from indicators.
219+ * Menus for indicators is now created prioritised by distance from
220+ current item to speed up user experience.
221+ * Add ApplicationArguments to know the geometry from start.
222+
223+ [ Mirco Müller ]
224+ * Added heeding and qmltest for button-tint hint.
225+
226+ [ Christopher Lee ]
227+ * Refactoring and cleanup of the Unity8 Autopilot tests.
228+
229+ [ Thomi Richards ]
230+ * Refactoring and cleanup of the Unity8 Autopilot tests.
231+
232+ [ Ubuntu daily release ]
233+ * Automatic snapshot from revision 129 (ubuntu-unity/next)
234+
235+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 25 Jul 2013 03:02:12 +0000
236+
1237unity8 (7.81.3+13.10.20130718ubuntu.unity.next-0ubuntu1) saucy; urgency=low
2238
3239 [ Andrea Cimitan ]
debian/control+5−3
@@ -4,7 +4,7 @@ Priority: optional
44Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
55Build-Depends: cmake,
66 debhelper (>= 9),
7− libdee-qt5-dev (>= 3.0),
7+ libdee-qt5-dev (>= 3.2),
88 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
99 libgl1-mesa-dri,
1010 libgles2-mesa-dev[armhf],
@@ -22,9 +22,9 @@ Build-Depends: cmake,
2222 libusermetricsoutput1-dev,
2323 libxcb1-dev,
2424 pkg-config,
25− python (>= 2.7),
25+ python:any (>= 2.7),
2626 python-setuptools,
27− python3,
27+ python3:any,
2828 qt5-default,
2929 qtbase5-dev,
3030 qtbase5-private-dev,
@@ -87,6 +87,8 @@ Depends: indicators-client (>= ${source:Version}),
8787 ${misc:Depends},
8888 ${python:Depends},
8989 ${shlibs:Depends},
90+Recommends: gir1.2-glib-2.0,
91+ python-gi,
9092Description: Test package for Unity 8 shell
9193 Autopilot tests for the unity8 package
9294
debian/unity8-private.install+1
@@ -1,6 +1,7 @@
11usr/lib/*/unity8/qml/HudClient
22usr/lib/*/unity8/qml/LightDM
33usr/lib/*/unity8/qml/ListViewWithPageHeader
4+usr/lib/*/unity8/qml/Powerd
45usr/lib/*/unity8/qml/Ubuntu
56usr/lib/*/unity8/qml/Unity
67usr/lib/*/unity8/qml/Utils
main.cpp+1−1
@@ -113,7 +113,7 @@ int main(int argc, char** argv)
113113 view->setResizeMode(QQuickView::SizeRootObjectToView);
114114 view->setTitle("Qml Phone Shell");
115115 view->engine()->setBaseUrl(QUrl::fromLocalFile(::shellAppDirectory()));
116− view->rootContext()->setContextProperty("ApplicationArguments", &qmlArgs);
116+ view->rootContext()->setContextProperty("applicationArguments", &qmlArgs);
117117 if (args.contains(QLatin1String("-frameless"))) {
118118 view->setFlags(Qt::FramelessWindowHint);
119119 }
plugins/CMakeLists.txt+1
@@ -4,3 +4,4 @@ add_subdirectory(Unity)
44add_subdirectory(HudClient)
55add_subdirectory(LightDM)
66add_subdirectory(ListViewWithPageHeader)
7+add_subdirectory(Powerd)
plugins/ListViewWithPageHeader/CMakeLists.txt+5−1
@@ -4,7 +4,11 @@ include(Plugins)
44# There's no cmake var for v8 include path :-/
55# so create one
66LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
7−SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
7+if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
8+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
9+else()
10+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
11+endif()
812
913include_directories(
1014 ${CMAKE_CURRENT_SOURCE_DIR}
plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+167−29
@@ -96,7 +96,11 @@
9696#include <qqmlengine.h>
9797#pragma GCC diagnostic push
9898#pragma GCC diagnostic ignored "-pedantic"
99+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
99100#include <private/qquickvisualdatamodel_p.h>
101+#else
102+#include <private/qqmldelegatemodel_p.h>
103+#endif
100104#include <private/qqmlglobal_p.h>
101105#include <private/qquickitem_p.h>
102106#include <private/qquickanimation_p.h>
@@ -156,16 +160,16 @@ ListViewWithPageHeader::ListViewWithPageHeader()
156160// m_clipItem = new QQuickRectangle(contentItem());
157161// ((QQuickRectangle*)m_clipItem)->setColor(Qt::gray);
158162
159− m_headerShowAnimation = new QQuickNumberAnimation(this);
160− m_headerShowAnimation->setEasing(QEasingCurve::OutQuad);
161− m_headerShowAnimation->setProperty("contentY");
162− m_headerShowAnimation->setDuration(200);
163− m_headerShowAnimation->setTargetObject(this);
163+ m_contentYAnimation = new QQuickNumberAnimation(this);
164+ m_contentYAnimation->setEasing(QEasingCurve::OutQuad);
165+ m_contentYAnimation->setProperty("contentY");
166+ m_contentYAnimation->setDuration(200);
167+ m_contentYAnimation->setTargetObject(this);
164168
165169 connect(this, SIGNAL(contentWidthChanged()), this, SLOT(onContentWidthChanged()));
166170 connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
167171 connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
168− connect(m_headerShowAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
172+ connect(m_contentYAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
169173}
170174
171175ListViewWithPageHeader::~ListViewWithPageHeader()
@@ -183,10 +187,17 @@ void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
183187 if (!m_delegateModel) {
184188 createDelegateModel();
185189 } else {
190+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
186191 disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
187192 }
188193 m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
189194 connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
195+#else
196+ disconnect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
197+ }
198+ m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
199+ connect(m_delegateModel, SIGNAL(modelUpdated(QQmlChangeSet,bool)), this, SLOT(onModelUpdated(QQmlChangeSet,bool)));
200+#endif
190201 Q_EMIT modelChanged();
191202 // TODO?
192203// Q_EMIT contentHeightChanged();
@@ -269,7 +280,7 @@ void ListViewWithPageHeader::setSectionDelegate(QQmlComponent *delegate)
269280
270281 m_sectionDelegate = delegate;
271282
272− m_topSectionItem = getSectionItem(QString());
283+ m_topSectionItem = getSectionItem(-1, QString());
273284 m_topSectionItem->setZ(3);
274285 QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
275286
@@ -363,11 +374,48 @@ void ListViewWithPageHeader::showHeader()
363374 layout();
364375 }
365376 }
366− m_headerShowAnimation->setTo(to);
367− m_headerShowAnimation->start();
377+ m_contentYAnimation->setTo(to);
378+ contentYAnimationType = ContentYAnimationShowHeader;
379+ m_contentYAnimation->start();
368380 }
369381}
370382
383+bool ListViewWithPageHeader::maximizeVisibleArea(int modelIndex)
384+{
385+ ListItem *listItem = itemAtIndex(modelIndex);
386+ if (listItem)
387+ {
388+ const auto listItemY = m_clipItem->y() + listItem->y();
389+ if (listItemY > contentY() && listItemY + listItem->height() > contentY() + height()) {
390+ // we can scroll the list up to show more stuff
391+ const auto to = qMin(listItemY, listItemY + listItem->height() - height());
392+ m_contentYAnimation->setTo(to);
393+ contentYAnimationType = ContentYAnimationMaximizeVisibleArea;
394+ m_contentYAnimation->start();
395+ } else if ((listItemY < contentY() && listItemY + listItem->height() < contentY() + height()) ||
396+ (m_topSectionItem && !listItem->m_sectionItem && listItemY - m_topSectionItem->height() < contentY() && listItemY + listItem->height() < contentY() + height()))
397+ {
398+ // we can scroll the list down to show more stuff
399+ auto realVisibleListItemY = listItemY;
400+ if (m_topSectionItem) {
401+ // If we are showing the top section sticky item and this item doesn't have a section
402+ // item we have to make sure to scroll it a bit more so that it is not underlapping
403+ // the top section sticky item
404+ bool topSectionShown = !QQuickItemPrivate::get(m_topSectionItem)->culled;
405+ if (topSectionShown && !listItem->m_sectionItem) {
406+ realVisibleListItemY -= m_topSectionItem->height();
407+ }
408+ }
409+ const auto to = qMax(realVisibleListItemY, listItemY + listItem->height() - height());
410+ m_contentYAnimation->setTo(to);
411+ contentYAnimationType = ContentYAnimationMaximizeVisibleArea;
412+ m_contentYAnimation->start();
413+ }
414+ return true;
415+ }
416+ return false;
417+}
418+
371419qreal ListViewWithPageHeader::minYExtent() const
372420{
373421// qDebug() << "ListViewWithPageHeader::minYExtent" << m_minYExtent;
@@ -389,6 +437,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
389437 QQuickFlickable::viewportMoved(orient);
390438// qDebug() << "ListViewWithPageHeader::viewportMoved" << contentY();
391439 qreal diff = m_previousContentY - contentY();
440+ const bool showHeaderAnimationRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationShowHeader;
392441 if (m_headerItem) {
393442 auto oldHeaderItemShownHeight = m_headerItemShownHeight;
394443 if (contentY() < -m_minYExtent) {
@@ -399,16 +448,20 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
399448 m_headerItem->setHeight(m_headerItem->implicitHeight());
400449 // We are going down (but it's not because of the rebound at the end)
401450 // (but the header was not shown by it's own position)
402− // or the header is partially shown
451+ // or the header is partially shown and we are not doing a maximizeVisibleArea either
403452 const bool scrolledUp = m_previousContentY > contentY();
404453 const bool notRebounding = contentY() + height() < contentHeight();
405454 const bool notShownByItsOwn = contentY() + diff > m_headerItem->y() + m_headerItem->height();
455+ const bool maximizeVisibleAreaRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationMaximizeVisibleArea;
406456
407457 if (!scrolledUp && contentY() == -m_minYExtent) {
408458 m_headerItemShownHeight = 0;
409459 m_headerItem->setY(contentY());
410− } else if ((scrolledUp && notRebounding && notShownByItsOwn) || (m_headerItemShownHeight > 0)) {
411− m_headerItemShownHeight += diff;
460+ } else if ((scrolledUp && notRebounding && notShownByItsOwn && !maximizeVisibleAreaRunning) || (m_headerItemShownHeight > 0)) {
461+ if (maximizeVisibleAreaRunning && diff > 0) // If we are maximizing and the header was shown, make sure we hide it
462+ m_headerItemShownHeight -= diff;
463+ else
464+ m_headerItemShownHeight += diff;
412465 if (contentY() == -m_minYExtent) {
413466 m_headerItemShownHeight = 0;
414467 } else {
@@ -424,7 +477,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
424477 // We will be changing the clip item, need to accomadate for it
425478 // otherwise we move the firstItem down/up twice (unless the
426479 // show header animation is running, where we want to keep the viewport stable)
427− if (!m_headerShowAnimation->isRunning()) {
480+ if (!showHeaderAnimationRunning) {
428481 diff += oldHeaderItemShownHeight - m_headerItemShownHeight;
429482 } else {
430483 diff = -diff;
@@ -434,7 +487,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
434487 updateClipItem();
435488 ListItem *firstItem = m_visibleItems.first();
436489 firstItem->setY(firstItem->y() + diff);
437− if (m_headerShowAnimation->isRunning()) {
490+ if (showHeaderAnimationRunning) {
438491 adjustMinYExtent();
439492 }
440493 }
@@ -446,8 +499,13 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
446499
447500void ListViewWithPageHeader::createDelegateModel()
448501{
502+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
449503 m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
450504 connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
505+#else
506+ m_delegateModel = new QQmlDelegateModel(qmlContext(this), this);
507+ connect(m_delegateModel, SIGNAL(createdItem(int,QObject*)), this, SLOT(itemCreated(int,QObject*)));
508+#endif
451509 if (isComponentComplete())
452510 m_delegateModel->componentComplete();
453511 updateWatchedRoles();
@@ -528,8 +586,13 @@ bool ListViewWithPageHeader::addVisibleItems(qreal fillFrom, qreal fillTo, bool
528586void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
529587{
530588 QQuickItem *item = listItem->m_item;
589+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
531590 QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
532591 if (flags & QQuickVisualModel::Destroyed) {
592+#else
593+ QQmlDelegateModel::ReleaseFlags flags = m_delegateModel->release(item);
594+ if (flags & QQmlDelegateModel::Destroyed) {
595+#endif
533596 item->setParentItem(nullptr);
534597 }
535598 delete listItem->m_sectionItem;
@@ -578,16 +641,17 @@ QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyI
578641 }
579642 }
580643
581− return getSectionItem(section);
644+ return getSectionItem(modelIndex, section);
582645}
583646
584−QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText)
647+QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, const QString &sectionText)
585648{
586649 QQuickItem *sectionItem = nullptr;
587650
588651 QQmlContext *creationContext = m_sectionDelegate->creationContext();
589652 QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));
590653 context->setContextProperty(QLatin1String("section"), sectionText);
654+ context->setContextProperty(QLatin1String("delegateIndex"), modelIndex);
591655 QObject *nobj = m_sectionDelegate->beginCreate(context);
592656 if (nobj) {
593657 QQml_setParent_noEvent(context, nobj);
@@ -658,9 +722,27 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
658722 return nullptr;
659723
660724 m_asyncRequestedIndex = -1;
725+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
661726 QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
727+#else
728+ QObject* object = m_delegateModel->object(modelIndex, asynchronous);
729+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
730+#endif
662731 if (!item) {
732+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
663733 m_asyncRequestedIndex = modelIndex;
734+#else
735+ if (object) {
736+ m_delegateModel->release(object);
737+ if (!m_delegateValidated) {
738+ m_delegateValidated = true;
739+ QObject* delegateObj = delegate();
740+ qmlInfo(delegateObj ? delegateObj : this) << "Delegate must be of Item type";
741+ }
742+ } else {
743+ m_asyncRequestedIndex = modelIndex;
744+ }
745+#endif
664746 return 0;
665747 } else {
666748// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
@@ -694,7 +776,7 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
694776 releaseItem(listItem);
695777 listItem = nullptr;
696778 } else {
697− listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() < contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
779+ listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() <= contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
698780 if (m_visibleItems.isEmpty()) {
699781 m_visibleItems << listItem;
700782 } else {
@@ -711,8 +793,18 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
711793 }
712794}
713795
796+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
714797void ListViewWithPageHeader::itemCreated(int modelIndex, QQuickItem *item)
715798{
799+#else
800+void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
801+{
802+ QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
803+ if (!item) {
804+ qWarning() << "ListViewWithPageHeader::itemCreated got a non item for index" << modelIndex;
805+ return;
806+ }
807+#endif
716808// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
717809
718810 item->setParentItem(m_clipItem);
@@ -747,13 +839,22 @@ void ListViewWithPageHeader::onHeightChanged()
747839 polish();
748840}
749841
842+
843+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
750844void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bool /*reset*/)
845+#else
846+void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool /*reset*/)
847+#endif
751848{
752849 // TODO Do something with reset
753850// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
754851 const auto oldFirstVisibleIndex = m_firstVisibleIndex;
755852
853+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
756854 Q_FOREACH(const QQuickChangeSet::Remove &remove, changeSet.removes()) {
855+#else
856+ Q_FOREACH(const QQmlChangeSet::Remove &remove, changeSet.removes()) {
857+#endif
757858// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
758859 if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
759860 const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
@@ -785,10 +886,14 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
785886 }
786887 if (growDown) {
787888 adjustMinYExtent();
788− } else if (remove.index <= m_firstVisibleIndex && !m_visibleItems.isEmpty()) {
789− // We removed the first item that is the one that positions the rest
790− // position the new first item correctly
791− m_visibleItems.first()->setY(oldFirstValidIndexPos);
889+ } else if (remove.index <= m_firstVisibleIndex) {
890+ if (!m_visibleItems.isEmpty()) {
891+ // We removed the first item that is the one that positions the rest
892+ // position the new first item correctly
893+ m_visibleItems.first()->setY(oldFirstValidIndexPos);
894+ } else {
895+ m_firstVisibleIndex = -1;
896+ }
792897 }
793898 } else if (remove.index + remove.count <= m_firstVisibleIndex) {
794899 m_firstVisibleIndex -= remove.count;
@@ -803,10 +908,14 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
803908 }
804909 }
805910
911+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
806912 Q_FOREACH(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
913+#else
914+ Q_FOREACH(const QQmlChangeSet::Insert &insert, changeSet.inserts()) {
915+#endif
807916// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
808917 const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
809− const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && !m_visibleItems.isEmpty() && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
918+ const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
810919 if (insertingInValidIndexes || firstItemWithViewOnTop)
811920 {
812921 // If the items we are adding won't be really visible
@@ -866,6 +975,14 @@ void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bo
866975 adjustMinYExtent();
867976 }
868977
978+ for (int i = 0; i < m_visibleItems.count(); ++i) {
979+ ListItem *item = m_visibleItems[i];
980+ if (item->m_sectionItem) {
981+ QQmlContext *context = QQmlEngine::contextForObject(item->m_sectionItem)->parentContext();
982+ context->setContextProperty(QLatin1String("delegateIndex"), m_firstVisibleIndex + i);
983+ }
984+ }
985+
869986 layout();
870987 polish();
871988 m_contentHeightDirty = true;
@@ -965,24 +1082,31 @@ void ListViewWithPageHeader::layout()
9651082 int firstReallyVisibleItem = -1;
9661083 int modelIndex = m_firstVisibleIndex;
9671084 Q_FOREACH(ListItem *item, m_visibleItems) {
968− const bool cull = pos + item->height() < visibleFrom || pos >= visibleTo;
1085+ const bool cull = pos + item->height() <= visibleFrom || pos >= visibleTo;
9691086 item->setCulled(cull);
9701087 item->setY(pos);
9711088 if (!cull && firstReallyVisibleItem == -1) {
9721089 firstReallyVisibleItem = modelIndex;
9731090 if (m_topSectionItem) {
974− // Update the top sticky section header
975− const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
976− QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();
977− context->setContextProperty(QLatin1String("section"), section);
978−
9791091 // Positing the top section sticky item is a two step process
9801092 // First we set it either we cull it (because it doesn't need to be sticked to the top)
9811093 // or stick it to the top
9821094 // Then after the loop we'll make sure that if there's another section just below it
9831095 // pushed the sticky section up to make it disappear
9841096 const qreal topSectionStickPos = m_headerItemShownHeight + contentY() - m_clipItem->y();
985− if (topSectionStickPos <= pos) {
1097+ bool showStickySectionItem;
1098+ // We need to show the "top section sticky item" when the position at the "top" of the
1099+ // viewport is bigger than the start of the position of the first visible item
1100+ // i.e. the first visible item starts before the viewport, or when the first
1101+ // visible item starts just at the viewport start and it does not have its own section item
1102+ if (topSectionStickPos > pos) {
1103+ showStickySectionItem = true;
1104+ } else if (topSectionStickPos == pos) {
1105+ showStickySectionItem = !item->m_sectionItem;
1106+ } else {
1107+ showStickySectionItem = false;
1108+ }
1109+ if (!showStickySectionItem) {
9861110 QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
9871111 if (item->m_sectionItem) {
9881112 // This seems it should happen since why would we cull the top section
@@ -992,8 +1116,22 @@ void ListViewWithPageHeader::layout()
9921116 QQuickItemPrivate::get(item->m_sectionItem)->setCulled(false);
9931117 }
9941118 } else {
1119+ // Update the top sticky section header
1120+ const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
1121+ QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();
1122+ context->setContextProperty(QLatin1String("section"), section);
1123+
9951124 QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);
9961125 m_topSectionItem->setY(topSectionStickPos);
1126+ int delegateIndex = modelIndex;
1127+ // Look for the first index with this section text
1128+ while (delegateIndex > 0) {
1129+ const QString prevSection = m_delegateModel->stringValue(delegateIndex - 1, m_sectionProperty);
1130+ if (prevSection != section)
1131+ break;
1132+ delegateIndex--;
1133+ }
1134+ context->setContextProperty(QLatin1String("delegateIndex"), delegateIndex);
9971135 if (item->m_sectionItem) {
9981136 QQuickItemPrivate::get(item->m_sectionItem)->setCulled(true);
9991137 }
plugins/ListViewWithPageHeader/listviewwithpageheader.h+27−3
@@ -24,9 +24,14 @@
2424#pragma GCC diagnostic pop
2525
2626class QAbstractItemModel;
27−class QQuickChangeSet;
2827class QQuickNumberAnimation;
28+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
29+class QQuickChangeSet;
2930class QQuickVisualDataModel;
31+#else
32+class QQmlChangeSet;
33+class QQmlDelegateModel;
34+#endif
3035
3136
3237/**
@@ -84,6 +89,11 @@ public:
8489 Q_INVOKABLE void positionAtBeginning();
8590 Q_INVOKABLE void showHeader();
8691
92+ // The index has to be created for this to try to do something
93+ // Created items are those visible and the precached ones
94+ // Returns if the item existed or not
95+ Q_INVOKABLE bool maximizeVisibleArea(int modelIndex);
96+
8797Q_SIGNALS:
8898 void modelChanged();
8999 void delegateChanged();
@@ -100,11 +110,19 @@ protected:
100110 void updatePolish();
101111
102112private Q_SLOTS:
113+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
103114 void itemCreated(int modelIndex, QQuickItem *item);
115+#else
116+ void itemCreated(int modelIndex, QObject *object);
117+#endif
104118 void onContentHeightChanged();
105119 void onContentWidthChanged();
106120 void onHeightChanged();
121+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
107122 void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
123+#else
124+ void onModelUpdated(const QQmlChangeSet &changeSet, bool reset);
125+#endif
108126 void onShowHeaderAnimationFinished();
109127
110128private:
@@ -139,9 +157,13 @@ private:
139157 void reallyReleaseItem(ListItem *item);
140158 void updateWatchedRoles();
141159 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
142− QQuickItem *getSectionItem(const QString &sectionText);
160+ QQuickItem *getSectionItem(int modelIndex, const QString &sectionText);
143161
162+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
144163 QQuickVisualDataModel *m_delegateModel;
164+#else
165+ QQmlDelegateModel *m_delegateModel;
166+#endif
145167
146168 // Index we are waiting because we requested it asynchronously
147169 int m_asyncRequestedIndex;
@@ -165,7 +187,9 @@ private:
165187 qreal m_previousContentY;
166188 qreal m_headerItemShownHeight; // The height of header shown when the header is shown outside its topmost position
167189 // i.e. it's being shown after dragging down in the middle of the list
168− QQuickNumberAnimation *m_headerShowAnimation;
190+ enum ContentYAnimationType { ContentYAnimationShowHeader, ContentYAnimationMaximizeVisibleArea };
191+ ContentYAnimationType contentYAnimationType;
192+ QQuickNumberAnimation *m_contentYAnimation;
169193
170194 QQmlComponent *m_sectionDelegate;
171195 QString m_sectionProperty;
plugins/Powerd/CMakeLists.txtnew file+13
@@ -0,0 +1,13 @@
1+include(Plugins)
2+
3+add_definitions(-DSM_BUSNAME=systemBus)
4+
5+add_library(Powerd-qml MODULE
6+ plugin.cpp
7+ Powerd.cpp
8+ )
9+
10+qt5_use_modules(Powerd-qml DBus Qml)
11+
12+export_qmlfiles(Powerd Powerd)
13+export_qmlplugin(Powerd 0.1 Powerd TARGETS Powerd-qml)
plugins/Powerd/Powerd.cppnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Michael Terry <michael.terry@canonical.com>
17+ */
18+
19+#include "Powerd.h"
20+
21+Powerd::Powerd(QObject* parent)
22+ : QObject(parent),
23+ powerd(NULL)
24+{
25+ powerd = new QDBusInterface("com.canonical.powerd",
26+ "/com/canonical/powerd",
27+ "com.canonical.powerd",
28+ QDBusConnection::SM_BUSNAME(), this);
29+
30+ powerd->connection().connect("com.canonical.powerd",
31+ "/com/canonical/powerd",
32+ "com.canonical.powerd",
33+ "SysPowerStateChange",
34+ this,
35+ SIGNAL(powerStateChange(int)));
36+}
plugins/Powerd/Powerd.hnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef UNITY_POWERD_H
21+#define UNITY_POWERD_H
22+
23+#include <QtCore/QObject>
24+#include <QtDBus/QDBusInterface>
25+
26+class Powerd: public QObject
27+{
28+ Q_OBJECT
29+
30+public:
31+ explicit Powerd(QObject *parent = 0);
32+
33+Q_SIGNALS:
34+ void powerStateChange(int state);
35+
36+private:
37+ QDBusInterface *powerd;
38+};
39+
40+#endif
plugins/Powerd/plugin.cppnew file+36
@@ -0,0 +1,36 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#include "plugin.h"
21+#include "Powerd.h"
22+
23+#include <QtQml/QtQml>
24+
25+static QObject *powerd_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
26+{
27+ Q_UNUSED(engine)
28+ Q_UNUSED(scriptEngine)
29+ return new Powerd();
30+}
31+
32+void PowerdPlugin::registerTypes(const char *uri)
33+{
34+ Q_ASSERT(uri == QLatin1String("Powerd"));
35+ qmlRegisterSingletonType<Powerd>(uri, 0, 1, "Powerd", powerd_provider);
36+}
plugins/Powerd/plugin.hnew file+35
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (C) 2012,2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors: Gerry Boland <gerry.boland@canonical.com>
17+ * Michael Terry <michael.terry@canonical.com>
18+ */
19+
20+#ifndef POWER_PLUGIN_H
21+#define POWER_PLUGIN_H
22+
23+#include <QtQml/QQmlEngine>
24+#include <QtQml/QQmlExtensionPlugin>
25+
26+class PowerdPlugin : public QQmlExtensionPlugin
27+{
28+ Q_OBJECT
29+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
30+
31+public:
32+ void registerTypes(const char *uri);
33+};
34+
35+#endif
plugins/Powerd/qmldirnew file+3
@@ -0,0 +1,3 @@
1+module Powerd
2+plugin Powerd-qml
3+typeinfo plugin.qmltypes
plugins/Unity/CMakeLists.txt+1−1
@@ -5,7 +5,7 @@ add_subdirectory(Indicators)
55
66# Dependencies
77include(FindPkgConfig)
8−pkg_check_modules(QTDEE REQUIRED libdee-qt5)
8+pkg_check_modules(QTDEE REQUIRED libdee-qt5>=3.2)
99pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
1010
1111include_directories(
plugins/Unity/Indicators/CMakeLists.txt+1
@@ -24,6 +24,7 @@ set(IndicatorsQML_SOURCES
2424 indicatorsmanager.cpp
2525 indicatorsmodel.cpp
2626 menucontentactivator.cpp
27+ modelprinter.cpp
2728 plugin.cpp
2829)
2930add_definitions(-DUNITYINDICATORS_LIBRARY)
plugins/Unity/Indicators/flatmenuproxymodel.cpp+10−7
@@ -55,31 +55,34 @@ void FlatMenuProxyModel::setSourceModel(QAbstractItemModel *source)
5555 if (source) {
5656
5757 // FIXME - not working correctly with dynamic inserts/removes
58+ // FIXME 2 - We're using Queud connections as a workaround to QTBUG-32859
59+ // The signals from qmenumodel are coming straight off the glib event loop,
60+ // which is not supported and has the effect of listview delegates not to be deleted.
5861
5962 connect(source,
6063 SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)),
61− SLOT(onModelAboutToBeReset()));
64+ SLOT(onModelAboutToBeReset()), Qt::QueuedConnection);
6265 connect(source,
6366 SIGNAL(rowsInserted(QModelIndex,int,int)),
64− SLOT(onModelReset()));
67+ SLOT(onModelReset()), Qt::QueuedConnection);
6568
6669 connect(source,
6770 SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)),
68− SLOT(onModelAboutToBeReset()));
71+ SLOT(onModelAboutToBeReset()), Qt::QueuedConnection);
6972 connect(source,
7073 SIGNAL(rowsRemoved(QModelIndex,int,int)),
71− SLOT(onModelReset()));
74+ SLOT(onModelReset()), Qt::QueuedConnection);
7275
7376 connect(source,
7477 SIGNAL(modelAboutToBeReset()),
75− SLOT(onModelAboutToBeReset()));
78+ SLOT(onModelAboutToBeReset()), Qt::QueuedConnection);
7679 connect(source,
7780 SIGNAL(modelReset()),
78− SLOT(onModelReset()));
81+ SLOT(onModelReset()), Qt::QueuedConnection);
7982
8083 connect(source,
8184 SIGNAL(statusChanged(DBusEnums::ConnectionStatus)),
82− SIGNAL(statusChanged()));
85+ SIGNAL(statusChanged()), Qt::QueuedConnection);
8386
8487 // initiliaze rowCount
8588 QModelIndex lastItem = source->index(source->rowCount() - 1, 0);
plugins/Unity/Indicators/modelprinter.cppnew file+114
@@ -0,0 +1,114 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+// self
21+#include "modelprinter.h"
22+
23+// Qt
24+#include <QTextStream>
25+
26+ModelPrinter::ModelPrinter(QObject *parent)
27+ : QObject(parent)
28+ , m_model(NULL)
29+{
30+}
31+
32+void ModelPrinter::setSourceModel(QAbstractItemModel * sourceModel)
33+{
34+ if (m_model != NULL) {
35+ disconnect(m_model);
36+ }
37+ if (m_model != sourceModel) {
38+ m_model = sourceModel;
39+ Q_EMIT modelChanged();
40+ Q_EMIT textChanged();
41+ }
42+ if (m_model != NULL) {
43+ connect(m_model, SIGNAL(modelReset()), this, SIGNAL(textChanged()));
44+ connect(m_model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SIGNAL(textChanged()));
45+ connect(m_model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SIGNAL(textChanged()));
46+ }
47+}
48+
49+QAbstractItemModel* ModelPrinter::sourceModel() const
50+{
51+ return m_model;
52+}
53+
54+QString ModelPrinter::text(const QModelIndex& index) const
55+{
56+ return recurseString(index, 0);
57+}
58+
59+QString tabify(int level) { QString str;
60+ for (int i = 0; i < level; i++) {
61+ str += " ";
62+ }
63+ return str;
64+}
65+
66+QString ModelPrinter::recurseString(const QModelIndex& index, int level) const
67+{
68+ if (!m_model)
69+ return "";
70+
71+ QString str;
72+ QTextStream stream(&str);
73+
74+ QHash<int, QByteArray> roleNames = m_model->roleNames();
75+ QList<int> roles = roleNames.keys();
76+ qSort(roles);
77+ Q_FOREACH(int role, roles) {
78+ QVariant vData = m_model->data(index, role);
79+ if (vData.canConvert(QMetaType::QVariantMap)) {
80+ QMapIterator<QString, QVariant> iter(vData.toMap());
81+ while (iter.hasNext()) {
82+ iter.next();
83+ stream << tabify(level)
84+ << roleNames[role]
85+ << "."
86+ << iter.key()
87+ << ": "
88+ << iter.value().toString()
89+ << endl;
90+ }
91+ }
92+ else {
93+ stream << tabify(level)
94+ << roleNames[role]
95+ << ": "
96+ << vData.toString()
97+ << endl;
98+ }
99+ }
100+
101+ int rowCount = m_model->rowCount(index);
102+ stream << tabify(level)
103+ << "child count"
104+ << ": "
105+ << rowCount
106+ << endl
107+ << endl;
108+
109+ for (int i = 0; i < rowCount; i++) {
110+ QModelIndex child = m_model->index(i, 0, index);
111+ str += recurseString(child, level+1);
112+ }
113+ return str;
114+}
plugins/Unity/Indicators/modelprinter.hnew file+50
@@ -0,0 +1,50 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Authors:
17+ * Nick Dedekind <nick.dedekind@canonical.com>
18+ */
19+
20+#ifndef MODELPRINTER_H
21+#define MODELPRINTER_H
22+
23+#include <QSortFilterProxyModel>
24+
25+// This class acts as a namespace only, with the addition that its enums
26+// are registered to be exposed on the QML side.
27+class ModelPrinter : public QObject
28+{
29+ Q_OBJECT
30+
31+ Q_PROPERTY(QAbstractItemModel* model READ sourceModel WRITE setSourceModel NOTIFY modelChanged)
32+ Q_PROPERTY(QString text READ text NOTIFY textChanged)
33+public:
34+ ModelPrinter(QObject* parent=0);
35+
36+ void setSourceModel(QAbstractItemModel* sourceModel);
37+ QAbstractItemModel* sourceModel() const;
38+
39+ Q_INVOKABLE QString text(const QModelIndex& index = QModelIndex()) const;
40+
41+Q_SIGNALS:
42+ void modelChanged();
43+ void textChanged();
44+
45+private:
46+ QString recurseString(const QModelIndex& index, int level) const;
47+ QAbstractItemModel* m_model;
48+};
49+
50+#endif // MODELPRINTER_H
plugins/Unity/Indicators/plugin.cpp+2
@@ -28,6 +28,7 @@
2828#include "indicatorsmodel.h"
2929#include "indicators.h"
3030#include "menucontentactivator.h"
31+#include "modelprinter.h"
3132
3233void IndicatorsPlugin::registerTypes(const char *uri)
3334{
@@ -36,6 +37,7 @@ void IndicatorsPlugin::registerTypes(const char *uri)
3637 qmlRegisterType<IndicatorsManager>(uri, 0, 1, "IndicatorsManager");
3738 qmlRegisterType<FlatMenuProxyModel>(uri, 0, 1, "FlatMenuProxyModel");
3839 qmlRegisterType<IndicatorsModel>(uri, 0, 1, "IndicatorsModel");
40+ qmlRegisterType<ModelPrinter>(uri, 0, 1, "ModelPrinter");
3941 qmlRegisterType<MenuContentActivator>(uri, 0, 1, "MenuContentActivator");
4042
4143 qmlRegisterUncreatableType<MenuContentState>(uri, 0, 1, "MenuContentState", "Can't create MenuContentState class");
plugins/Unity/categories.cpp+6−3
@@ -34,7 +34,7 @@ enum CategoryColumn {
3434Categories::Categories(QObject* parent)
3535 : DeeListModel(parent)
3636{
37− m_roles[Categories::RoleId] = "id";
37+ m_roles[Categories::RoleCategoryId] = "categoryId";
3838 m_roles[Categories::RoleName] = "name";
3939 m_roles[Categories::RoleIcon] = "icon";
4040 m_roles[Categories::RoleRenderer] = "renderer";
@@ -42,6 +42,7 @@ Categories::Categories(QObject* parent)
4242 m_roles[Categories::RoleHints] = "hints";
4343 m_roles[Categories::RoleResults] = "results";
4444 m_roles[Categories::RoleCount] = "count";
45+ m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
4546
4647 // TODO This should not be needed but accumulatting the count changes
4748 // makes the visualization more stable and also makes crashes on fast
@@ -130,8 +131,8 @@ Categories::data(const QModelIndex& index, int role) const
130131 }
131132
132133 switch (role) {
133− case RoleId:
134− return QVariant::fromValue(index.row());
134+ case RoleCategoryId:
135+ return DeeListModel::data(index, CategoryColumn::ID);
135136 case RoleName:
136137 return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
137138 case RoleIcon:
@@ -149,6 +150,8 @@ Categories::data(const QModelIndex& index, int role) const
149150 return QVariant::fromValue(getResults(index.row()));
150151 case RoleCount:
151152 return QVariant::fromValue(getResults(index.row())->rowCount());
153+ case RoleCategoryIndex:
154+ return QVariant::fromValue(index.row());
152155 default:
153156 return QVariant();
154157 }
plugins/Unity/categories.h+3−2
@@ -42,14 +42,15 @@ public:
4242 explicit Categories(QObject* parent = 0);
4343
4444 enum Roles {
45− RoleId,
45+ RoleCategoryId,
4646 RoleName,
4747 RoleIcon,
4848 RoleRenderer,
4949 RoleContentType,
5050 RoleHints,
5151 RoleResults,
52− RoleCount
52+ RoleCount,
53+ RoleCategoryIndex
5354 };
5455
5556 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
plugins/Unity/previewinfohint.cpp+2−2
@@ -17,9 +17,9 @@
1717 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20+#include <deelistmodel.h>
2021// local
2122#include "previewinfohint.h"
22−#include "variantutils.h"
2323
2424PreviewInfoHint::PreviewInfoHint(QObject *parent):
2525 QObject(parent),
@@ -61,7 +61,7 @@ QString PreviewInfoHint::iconHint() const
6161QVariant PreviewInfoHint::value() const
6262{
6363 if (m_unityInfoHint) {
64− return QVariantFromGVariant(m_unityInfoHint->value);
64+ return DeeListModel::VariantForData(m_unityInfoHint->value);
6565 }
6666 return QVariant();
6767}
plugins/Unity/scope.h−3
@@ -29,9 +29,6 @@
2929#include <UnityCore/Scope.h>
3030#include <UnityCore/Results.h>
3131
32−// dee-qt
33−#include "deelistmodel.h"
34−
3532#include "categories.h"
3633
3734class Preview;
plugins/Unity/variantutils.cpp+2−118
@@ -17,131 +17,15 @@
1717 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20+#include <deelistmodel.h>
2021#include "variantutils.h"
2122
22−/* Returns floating ref */
23−GVariant* GVariantFromQVariant(const QVariant &var)
24−{
25− GVariant *gv = nullptr;
26−
27− switch (var.type()) {
28− case QVariant::String:
29− gv = g_variant_new_string(var.toString().toUtf8());
30− break;
31− case QVariant::UInt:
32− gv = g_variant_new_uint32(var.toUInt());
33− break;
34− case QVariant::Int:
35− gv = g_variant_new_int32(var.toInt());
36− break;
37− case QVariant::LongLong:
38− gv = g_variant_new_int64(var.toLongLong());
39− break;
40− case QVariant::ULongLong:
41− gv = g_variant_new_uint64(var.toULongLong());
42− break;
43− case QVariant::Double:
44− gv = g_variant_new_double(var.toDouble());
45− break;
46− case QVariant::Bool:
47− gv = g_variant_new_boolean(var.toBool());
48− break;
49− case QVariant::Hash: {
50− const auto hash = var.toHash();
51− GVariant **children = new GVariant*[hash.size()];
52− int cnt = 0;
53− QHash<QString, QVariant>::const_iterator it = hash.constBegin();
54− while (it != hash.constEnd()) {
55− GVariant *key = g_variant_new_string(it.key().toUtf8());
56− children[cnt++] = g_variant_new_dict_entry(key, g_variant_new_variant(GVariantFromQVariant(it.value())));
57− ++it;
58− }
59− gv = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, hash.size());
60− delete [] children;
61− break;
62− }
63− default:
64− break;
65− }
66− return gv;
67−}
68−
69−// implementation of this conversion taken from libdee-qt private utility function.
70−QVariant QVariantFromGVariant(GVariant *value)
71−{
72− /* We need to special-case a{sv} here as G_VARIANT_CLASS_ARRAY handles simple arrays;
73− we need to create QVariantHash, not a list */
74− if (g_variant_is_of_type(value, G_VARIANT_TYPE_VARDICT)) {
75− const gsize nChildren = g_variant_n_children(value);
76− QVariantHash hash;
77− for (gsize i = 0; i < nChildren; ++i)
78− {
79− GVariant* dict_entry = g_variant_get_child_value(value, i);
80−
81− gchar* dict_key;
82− GVariant *dict_var;
83− g_variant_get(dict_entry, "{&sv}", &dict_key, &dict_var);
84− hash.insert(QString::fromUtf8(dict_key), QVariantFromGVariant(dict_var));
85− g_variant_unref(dict_var);
86− g_variant_unref(dict_entry);
87− }
88− return hash;
89− }
90−
91− switch (g_variant_classify(value)) {
92− case G_VARIANT_CLASS_BOOLEAN:
93− return QVariant((bool) g_variant_get_boolean(value));
94− case G_VARIANT_CLASS_BYTE:
95− return QVariant((uchar) g_variant_get_byte(value));
96− case G_VARIANT_CLASS_INT16:
97− return QVariant((qint16) g_variant_get_int16(value));
98− case G_VARIANT_CLASS_UINT16:
99− return QVariant((quint16) g_variant_get_uint16(value));
100− case G_VARIANT_CLASS_INT32:
101− return QVariant((qint32) g_variant_get_int32(value));
102− case G_VARIANT_CLASS_UINT32:
103− return QVariant((quint32) g_variant_get_uint32(value));
104− case G_VARIANT_CLASS_INT64:
105− return QVariant((qint64) g_variant_get_int64(value));
106− case G_VARIANT_CLASS_UINT64:
107− return QVariant((quint64) g_variant_get_uint64(value));
108− case G_VARIANT_CLASS_DOUBLE:
109− return QVariant(g_variant_get_double(value));
110− case G_VARIANT_CLASS_STRING:
111− return QVariant(QString::fromUtf8(g_variant_get_string(value, NULL)));
112− case G_VARIANT_CLASS_ARRAY:
113− case G_VARIANT_CLASS_TUPLE:
114− {
115− const gsize nChildren = g_variant_n_children(value);
116− QList<QVariant> array;
117− for (gsize i = 0; i < nChildren; ++i)
118− {
119− GVariant* gvariant = g_variant_get_child_value(value, i);
120− array << QVariantFromGVariant(gvariant);
121− g_variant_unref(gvariant);
122− }
123− return array;
124− }
125− default:
126− /* Fallback on an empty QVariant.
127− FIXME: Missing conversion of following GVariant types:
128− - G_VARIANT_CLASS_HANDLE
129− - G_VARIANT_CLASS_OBJECT_PATH
130− - G_VARIANT_CLASS_SIGNATURE
131− - G_VARIANT_CLASS_VARIANT
132− - G_VARIANT_CLASS_MAYBE
133− - G_VARIANT_CLASS_DICT_ENTRY
134− */
135− return QVariant();
136− }
137−}
138−
13923unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val)
14024{
14125 unity::glib::HintsMap hintsMap;
14226 QHash<QString, QVariant>::const_iterator it = val.constBegin();
14327 while (it != val.constEnd()) {
144− hintsMap[it.key().toStdString()] = GVariantFromQVariant(it.value());
28+ hintsMap[it.key().toStdString()] = DeeListModel::DataFromVariant(it.value());
14529 ++it;
14630 }
14731 return hintsMap;
plugins/Unity/variantutils.h−2
@@ -26,8 +26,6 @@
2626// libunity-core
2727#include <UnityCore/Variant.h>
2828
29−GVariant* GVariantFromQVariant(const QVariant &value);
30−QVariant QVariantFromGVariant(GVariant *value);
3129unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
3230unity::glib::HintsMap convertToHintsMap(const QVariant &var);
3331
po/ar.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/az.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/bg.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"MIME-Version: 1.0\n"
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
18−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
19−"X-Generator: Launchpad (build 16696)\n"
18+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
19+"X-Generator: Launchpad (build 16723)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
po/ca.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/de.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/el.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/en_AU.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/en_GB.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/eo.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/es.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/fi.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/fo.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/fr.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/gl.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/he.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/hr.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/hu.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/hy.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/id.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/it.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ja.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/kn.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ko.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ky.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/lv.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/my.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/nb.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/nl.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/pl.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/pt_BR.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ro.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ru.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/si.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/sl.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/sr.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/sv.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/te.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/tr.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/ug.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/uk.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-22 06:19+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/zh_CN.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
po/zh_TW.po+2−2
@@ -14,8 +14,8 @@ msgstr ""
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2013-07-17 07:49+0000\n"
18−"X-Generator: Launchpad (build 16696)\n"
17+"X-Launchpad-Export-Date: 2013-08-08 05:15+0000\n"
18+"X-Generator: Launchpad (build 16723)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
run_on_device+2−2
@@ -27,8 +27,8 @@ usage() {
2727 echo " -k, --keylock Enable a Keyboard lock screen when running"
2828 echo ""
2929 echo "IMPORTANT:"
30− echo " * Make sure to have the networking and PPAs setup on the device beforehand (phablet-deploy-networking && phablet-ppa-fetch)."
31− echo " * Execute that script from a directory containing a branch the shell code."
30+ echo " * Make sure to have networking setup on the device beforehand."
31+ echo " * Execute that script from a directory containing unity8 code."
3232 exit 1
3333}
3434
tests/autopilot/unity8/indicators_client/tests/test_battery.py+11−5
@@ -26,7 +26,7 @@ class TestDisplayMenus(IndicatorsTestCase):
2626 self.pointing_device.move_to_object(self.main_window.get_battery_menu())
2727 self.pointing_device.click()
2828
29− fn_loader = lambda: self.app.select_single("IndicatorsPage/QQuickLoader", objectName="page_loader");
29+ fn_loader = lambda: self.app.select_single("IndicatorsPage/QQuickLoader", objectName="pageLoader");
3030 self.assertThat(fn_loader, Eventually(NotEquals(None)));
3131 page_loader = fn_loader();
3232 self.assertThat(page_loader.progress, Eventually(Equals(1.0)))
@@ -70,7 +70,11 @@ class TestDisplayMenus(IndicatorsTestCase):
7070
7171 # wait for the switch menu item
7272 fn_auto_brightness = lambda: self.app.select_single("SwitchMenuItem", objectName="auto-brightness");
73− self.assertThat(fn_auto_brightness, Eventually(NotEquals(None)));
73+ # FIXME: this should go away when we switch to indicator-power
74+ try:
75+ self.assertThat(fn_auto_brightness, Eventually(NotEquals(None)));
76+ except AssertionError:
77+ self.skipTest("WARNING: test skipped due to missing indicator-battery")
7478 auto_brightness = fn_auto_brightness();
7579
7680 old_ab_value = auto_brightness.checked
@@ -83,10 +87,12 @@ class TestDisplayMenus(IndicatorsTestCase):
8387 def test_brightness_slider(self):
8488 """Test the auto-bright switch"""
8589
86− if self.input_device_class is Touch:
87− self.skipTest("Dragging is broken with Touch input (LP: #1203808).")
8890 fn_brightness_menu = lambda: self.app.select_single("SliderMenuItem", objectName="brightness");
89− self.assertThat(fn_brightness_menu, Eventually(NotEquals(None)));
91+ # FIXME: this should go away when we switch to indicator-power
92+ try:
93+ self.assertThat(fn_brightness_menu, Eventually(NotEquals(None)));
94+ except AssertionError:
95+ self.skipTest("WARNING: test skipped due to missing indicator-battery")
9096 brightness_menu = fn_brightness_menu();
9197
9298 old_ab_value = brightness_menu.value
tests/autopilot/unity8/shell/__init__.py+1−27
@@ -21,9 +21,6 @@
2121
2222from functools import wraps
2323import logging
24−import os.path
25−
26−from unity8 import get_mocks_library_path, get_default_extra_mock_libraries
2724
2825
2926logger = logging.getLogger(__name__)
@@ -34,31 +31,8 @@ def with_lightdm_mock(mock_type):
3431 def with_lightdm_mock_internal(fn):
3532 @wraps(fn)
3633 def wrapper(*args, **kwargs):
37− logger.info("Setting up LightDM mock type '%s'", mock_type)
38− new_ld_library_path = "%s:%s" % (
39− get_default_extra_mock_libraries(),
40− _get_ld_library_path(mock_type)
41− )
42− logger.info("New library path: %s", new_ld_library_path)
4334 tests_self = args[0]
44− tests_self.patch_environment(
45− 'LD_LIBRARY_PATH',
46− new_ld_library_path
47− )
35+ tests_self.patch_lightdm_mock(mock_type)
4836 return fn(*args, **kwargs)
4937 return wrapper
5038 return with_lightdm_mock_internal
51−
52−
53−def _get_ld_library_path(mock_type):
54− lib_path = get_mocks_library_path()
55− new_ld_library_path = os.path.abspath(
56− os.path.join(lib_path, "LightDM", mock_type)
57− )
58−
59− if not os.path.exists(new_ld_library_path):
60− raise RuntimeError(
61− "LightDM mock '%s' does not exist at path '%s'."
62− % (mock_type, new_ld_library_path)
63− )
64− return new_ld_library_path
tests/autopilot/unity8/shell/emulators/greeter.py+4−1
@@ -25,7 +25,7 @@ class Greeter(UnityEmulatorBase):
2525
2626 """An emulator that understands the greeter screen."""
2727
28− def unlock(self):
28+ def swipe(self):
2929 """Swipe the greeter screen away."""
3030 self.created.wait_for(True)
3131 touch = Touch.create()
@@ -38,3 +38,6 @@ class Greeter(UnityEmulatorBase):
3838 touch.drag(start_x, start_y, stop_x, stop_y)
3939
4040 self.created.wait_for(False)
41+
42+ def get_prompt(self):
43+ return self.select_single("TextField", objectName="passwordInput")
tests/autopilot/unity8/shell/emulators/hud.py+4−7
@@ -38,13 +38,10 @@ class Hud(UnityEmulatorBase):
3838 window = self.get_root_instance().select_single('QQuickView')
3939 hud_show_button = window.select_single("HudButton")
4040
41− start_x = int(window.x + (window.width / 2))
42− end_x = start_x
43− start_y = window.y + window.height
44− end_y = int(hud_show_button.y + (hud_show_button.height/2))
41+ swipe_coords = self.get_button_swipe_coords(window, hud_show_button)
4542
46− touch.press(start_x, start_y)
47− touch._finger_move(end_x, end_y)
43+ touch.press(swipe_coords.start_x, swipe_coords.start_y)
44+ touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
4845 try:
4946 hud_show_button.opacity.wait_for(1.0)
5047 touch.release()
@@ -78,6 +75,6 @@ class Hud(UnityEmulatorBase):
7875 start_x = int(main_view.x + (main_view.width / 2))
7976 end_x = start_x
8077 start_y = main_view.y + (main_view.height - 3)
81− end_y = int(hud_show_button.y + (hud_show_button.height/2))
78+ end_y = main_view.y + int(hud_show_button.y + (hud_show_button.height/2))
8279
8380 return SwipeCoords(start_x, end_x, start_y, end_y)
tests/autopilot/unity8/shell/emulators/main_window.py+1−1
@@ -89,4 +89,4 @@ class MainWindow(object):
8989 return self.app.select_single("Lockscreen")
9090
9191 def get_pinentryField(self):
92− return self.app.select_single("TextField", objectName="pinentryField")
92+ return self.app.select_single(objectName="pinentryField")
tests/autopilot/unity8/shell/tests/__init__.py+53−1
@@ -19,6 +19,11 @@
1919
2020"""unity autopilot tests."""
2121
22+try:
23+ from gi.repository import Gio
24+except ImportError:
25+ Gio = None
26+
2227from autopilot.platform import model
2328from autopilot.testcase import AutopilotTestCase
2429from autopilot.matchers import Eventually
@@ -28,7 +33,12 @@ import logging
2833import os.path
2934from testtools.matchers import Equals, NotEquals
3035
31−from unity8 import get_lib_path, get_binary_path, get_mocks_library_path
36+from unity8 import (
37+ get_lib_path,
38+ get_binary_path,
39+ get_mocks_library_path,
40+ get_default_extra_mock_libraries,
41+)
3242from unity8.shell.emulators import UnityEmulatorBase
3343from unity8.shell.emulators.dash import Dash
3444from unity8.shell.emulators.main_window import MainWindow
@@ -36,6 +46,10 @@ from unity8.shell.emulators.main_window import MainWindow
3646
3747logger = logging.getLogger(__name__)
3848
49+UNITYSHELL_GSETTINGS_SCHEMA = "org.compiz.unityshell"
50+UNITYSHELL_GSETTINGS_PATH = "/org/compiz/profiles/unity/plugins/unityshell/"
51+UNITYSHELL_LAUNCHER_KEY = "launcher-hide-mode"
52+UNITYSHELL_LAUNCHER_MODE = 1 # launcher hidden
3953
4054def _get_device_emulation_scenarios():
4155 if model() == 'Desktop':
@@ -64,10 +78,22 @@ class UnityTestCase(AutopilotTestCase):
6478
6579 def setUp(self):
6680 super(UnityTestCase, self).setUp()
81+ if Gio is not None and UNITYSHELL_GSETTINGS_SCHEMA in Gio.Settings.list_relocatable_schemas():
82+ # Hide Unity launcher
83+ self._unityshell_schema = Gio.Settings.new_with_path(UNITYSHELL_GSETTINGS_SCHEMA, UNITYSHELL_GSETTINGS_PATH)
84+ self._launcher_hide_mode = self._unityshell_schema.get_int(UNITYSHELL_LAUNCHER_KEY)
85+ self._unityshell_schema.set_int(UNITYSHELL_LAUNCHER_KEY, UNITYSHELL_LAUNCHER_MODE)
86+ self.addCleanup(self._reset_launcher)
87+
6788 self._proxy = None
89+ self._lightdm_mock_type = None
6890 self.touch = Touch.create()
6991 self._setup_display_details()
7092
93+ def _reset_launcher(self):
94+ """Reset Unity launcher hide mode"""
95+ self._unityshell_schema.set_int(UNITYSHELL_LAUNCHER_KEY, self._launcher_hide_mode)
96+
7197 def _setup_display_details(self):
7298 scale_divisor = self._determine_geometry()
7399 self._setup_grid_size(scale_divisor)
@@ -133,6 +159,8 @@ class UnityTestCase(AutopilotTestCase):
133159 binary_path
134160 )
135161
162+ if self._lightdm_mock_type is None:
163+ self.patch_lightdm_mock()
136164 self._setup_extra_mock_environment_patch()
137165
138166 app_proxy = self.launch_test_application(
@@ -150,6 +178,30 @@ class UnityTestCase(AutopilotTestCase):
150178
151179 return app_proxy
152180
181+ def patch_lightdm_mock(self, mock_type='single'):
182+ self._lightdm_mock_type = mock_type
183+ logger.info("Setting up LightDM mock type '%s'", mock_type)
184+ new_ld_library_path = "%s:%s" % (
185+ get_default_extra_mock_libraries(),
186+ self._get_lightdm_mock_path(mock_type)
187+ )
188+ logger.info("New library path: %s", new_ld_library_path)
189+
190+ self.patch_environment('LD_LIBRARY_PATH', new_ld_library_path)
191+
192+ def _get_lightdm_mock_path(self, mock_type):
193+ lib_path = get_mocks_library_path()
194+ lightdm_mock_path = os.path.abspath(
195+ os.path.join(lib_path, "LightDM", mock_type)
196+ )
197+
198+ if not os.path.exists(lightdm_mock_path):
199+ raise RuntimeError(
200+ "LightDM mock '%s' does not exist at path '%s'."
201+ % (mock_type, lightdm_mock_path)
202+ )
203+ return lightdm_mock_path
204+
153205 def _setup_extra_mock_environment_patch(self):
154206 mocks_library_path = get_mocks_library_path()
155207 self.patch_environment('QML2_IMPORT_PATH', mocks_library_path)
tests/autopilot/unity8/shell/tests/test_hud.py+5−10
@@ -32,13 +32,12 @@ class TestHud(UnityTestCase):
3232
3333 scenarios = _get_device_emulation_scenarios()
3434
35− @with_lightdm_mock("single")
3635 def test_show_hud_button_appears(self):
3736 """Swiping up while an app is active must show the 'show hud' button.
3837
3938 """
4039 self.launch_unity()
41− self.main_window.get_greeter().unlock()
40+ self.main_window.get_greeter().swipe()
4241 window = self.main_window.get_qml_view()
4342 hud_show_button = self.main_window.get_hud_show_button()
4443 hud = self.main_window.get_hud()
@@ -54,13 +53,12 @@ class TestHud(UnityTestCase):
5453 self.touch._finger_move(swipe_coords.end_x, swipe_coords.end_y)
5554 self.assertThat(hud_show_button.opacity, Eventually(Equals(1.0)))
5655
57− @with_lightdm_mock("single")
5856 def test_show_hud_appears(self):
5957 """Releasing the touch on the 'show hud' button must display the hud.
6058
6159 """
6260 self.launch_unity()
63− self.main_window.get_greeter().unlock()
61+ self.main_window.get_greeter().swipe()
6462 window = self.main_window.get_qml_view()
6563 hud_show_button = self.main_window.get_hud_show_button()
6664 hud = self.main_window.get_hud()
@@ -80,11 +78,10 @@ class TestHud(UnityTestCase):
8078 self.touch.release()
8179 self.assertThat(hud.shown, Eventually(Equals(True)))
8280
83− @with_lightdm_mock("single")
8481 def test_hide_hud_click(self):
8582 """Tapping the close button of the Hud must dismiss it."""
8683 self.launch_unity()
87− self.main_window.get_greeter().unlock()
84+ self.main_window.get_greeter().swipe()
8885 hud = self.main_window.get_hud()
8986
9087 self._launch_test_app_from_app_screen()
@@ -94,14 +91,13 @@ class TestHud(UnityTestCase):
9491 self.touch.tap(x, y)
9592 self.assertThat(hud.shown, Eventually(Equals(False)))
9693
97− @with_lightdm_mock("single")
9894 def test_hide_hud_dragging(self):
9995 """Once open the Hud must close if the upper bar is dragged and
10096 released downward.
10197
10298 """
10399 self.launch_unity()
104− self.main_window.get_greeter().unlock()
100+ self.main_window.get_greeter().swipe()
105101 hud = self.main_window.get_hud()
106102 window = self.main_window.get_qml_view()
107103
@@ -115,11 +111,10 @@ class TestHud(UnityTestCase):
115111 self.touch.drag(start_x, start_y, end_x, end_y)
116112 self.assertThat(hud.shown, Eventually(Equals(False)))
117113
118− @with_lightdm_mock("single")
119114 def test_launcher_hides_hud(self):
120115 """Opening the Launcher while the Hud is active must close the Hud."""
121116 self.launch_unity()
122− self.main_window.get_greeter().unlock()
117+ self.main_window.get_greeter().swipe()
123118 hud = self.main_window.get_hud()
124119 launcher = self.main_window.get_launcher()
125120
tests/autopilot/unity8/shell/tests/test_lock_screen.py+58−28
@@ -40,54 +40,68 @@ class TestLockscreen(UnityTestCase):
4040 """Must be able to unlock the PIN entry lock screen."""
4141 self.launch_unity()
4242 greeter = self.main_window.get_greeter()
43− greeter.unlock()
4443
45− lockscreen = self._wait_for_lockscreen()
46− self._enter_pincode("1234")
44+ if greeter.narrowMode:
45+ greeter.swipe()
46+ lockscreen = self._wait_for_lockscreen()
47+ self._enter_pincode("1234")
48+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
49+ else:
50+ self._enter_prompt_passphrase("1234")
51+ self.assertThat(greeter.shown, Eventually(Equals(False)))
4752
48− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
49−
50− @skipUnless(model() == 'Desktop', "Broken passphrase entry on UInput (LP: #1203788).")
5153 @with_lightdm_mock("single-passphrase")
5254 def test_can_unlock_passphrase_screen(self):
5355 """Must be able to unlock the passphrase entry screen."""
5456 self.launch_unity()
5557 greeter = self.main_window.get_greeter()
56− greeter.unlock()
57−
58− lockscreen = self._wait_for_lockscreen()
59− self._enter_passphrase("password")
6058
61− self.assertThat(lockscreen.shown, Eventually(Equals(False)))
59+ if greeter.narrowMode:
60+ greeter.swipe()
61+ lockscreen = self._wait_for_lockscreen()
62+ self._enter_pin_passphrase("password")
63+ self.assertThat(lockscreen.shown, Eventually(Equals(False)))
64+ else:
65+ self._enter_prompt_passphrase("password")
66+ self.assertThat(greeter.shown, Eventually(Equals(False)))
6267
6368 @with_lightdm_mock("single-pin")
6469 def test_pin_screen_wrong_code(self):
6570 """Entering the wrong pin code must not dismiss the lock screen."""
6671 self.launch_unity()
6772 greeter = self.main_window.get_greeter()
68− greeter.unlock()
69−
70− lockscreen = self._wait_for_lockscreen()
71− self._enter_pincode("4321")
7273
73− pinentryField = self.main_window.get_pinentryField()
74− self.assertThat(pinentryField.text, Eventually(Equals("")))
75− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
74+ if greeter.narrowMode:
75+ greeter.swipe()
76+ lockscreen = self._wait_for_lockscreen()
77+ self._enter_pincode("4321")
78+ pinentryField = self.main_window.get_pinentryField()
79+ self.assertThat(pinentryField.text, Eventually(Equals("")))
80+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
81+ else:
82+ self._enter_prompt_passphrase("4231")
83+ prompt = self.main_window.get_greeter().get_prompt()
84+ self.assertThat(prompt.text, Eventually(Equals("")))
85+ self.assertThat(greeter.shown, Eventually(Equals(True)))
7686
77− @skipUnless(model() == 'Desktop', "Broken passphrase entry on UInput (LP: #1203788).")
7887 @with_lightdm_mock("single-passphrase")
7988 def test_passphrase_screen_wrong_password(self):
8089 """Entering the wrong password must not dismiss the lock screen."""
8190 self.launch_unity()
8291 greeter = self.main_window.get_greeter()
83− greeter.unlock()
8492
85− lockscreen = self._wait_for_lockscreen()
86− self._enter_passphrase("foobar")
87−
88− pinentryField = self.main_window.get_pinentryField()
89− self.assertThat(pinentryField.text, Eventually(Equals("")))
90− self.assertThat(lockscreen.shown, Eventually(Equals(True)))
93+ if greeter.narrowMode:
94+ greeter.swipe()
95+ lockscreen = self._wait_for_lockscreen()
96+ self._enter_pin_passphrase("foobar")
97+ pinentryField = self.main_window.get_pinentryField()
98+ self.assertThat(pinentryField.text, Eventually(Equals("")))
99+ self.assertThat(lockscreen.shown, Eventually(Equals(True)))
100+ else:
101+ self._enter_prompt_passphrase("foobar")
102+ prompt = self.main_window.get_greeter().get_prompt()
103+ self.assertThat(prompt.text, Eventually(Equals("")))
104+ self.assertThat(greeter.shown, Eventually(Equals(True)))
91105
92106 def _wait_for_lockscreen(self):
93107 """Wait for the lock screen to load, and return it."""
@@ -116,9 +130,9 @@ class TestLockscreen(UnityTestCase):
116130 )
117131 self.touch.tap_object(self.main_window.get_pinPadButton(int(num)))
118132
119− def _enter_passphrase(self, passphrase):
133+ def _enter_pin_passphrase(self, passphrase):
120134 """Enter the password specified in 'passphrase' into the password entry
121− field.
135+ field of the pin lock screen.
122136
123137 :param passphrase: The string you want to enter.
124138 :raises: TypeError if passphrase is not a string.
@@ -131,3 +145,19 @@ class TestLockscreen(UnityTestCase):
131145 self.touch.tap_object(pinentryField)
132146 self.keyboard.type(passphrase)
133147 self.keyboard.type("\n")
148+
149+ def _enter_prompt_passphrase(self, passphrase):
150+ """Enter the password specified in 'passphrase' into the password entry
151+ field of the main user list's prompt.
152+
153+ :param passphrase: The string you want to enter.
154+ :raises: TypeError if passphrase is not a string.
155+
156+ """
157+ if not isinstance(passphrase, basestring):
158+ raise TypeError("'passphrase' parameter must be a string.")
159+
160+ prompt = self.main_window.get_greeter().get_prompt()
161+ self.touch.tap_object(prompt)
162+ self.keyboard.type(passphrase)
163+ self.keyboard.type("\n")
tests/mocks/CMakeLists.txt+1
@@ -1,5 +1,6 @@
11add_subdirectory(libusermetrics)
22add_subdirectory(LightDM)
3+add_subdirectory(QMenuModel)
34add_subdirectory(Ubuntu)
45add_subdirectory(Unity)
56add_subdirectory(HudClient)
tests/mocks/LightDM/single/GreeterPrivate.cpp+2−4
@@ -34,10 +34,8 @@ void GreeterPrivate::handleAuthenticate()
3434{
3535 Q_Q(Greeter);
3636
37− if (authenticationUser == "one") {
38− authenticated = true;
39− Q_EMIT q->authenticationComplete();
40− }
37+ authenticated = true;
38+ Q_EMIT q->authenticationComplete();
4139}
4240
4341void GreeterPrivate::handleRespond(QString const &response)
tests/mocks/QMenuModel/CMakeLists.txtnew file+11
@@ -0,0 +1,11 @@
1+file(GLOB QMLFILES
2+ *.qml
3+ *.js
4+ qmldir
5+)
6+
7+# copy files into build directory for shadow builds
8+add_custom_target(QMenuModelQmlFiles ALL
9+ COMMAND cp ${QMLFILES} ${CMAKE_CURRENT_BINARY_DIR}
10+ DEPENDS ${QMLFILES}
11+)
tests/mocks/QMenuModel/QDBusActionGroup.qmlnew file+27
@@ -0,0 +1,27 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Daniel d'Andrada <daniel.dandrada@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+import QtQuick 2.0
21+
22+QtObject {
23+ property int busType
24+ property string busName
25+ property string objectPath
26+ function start() {}
27+}
tests/mocks/QMenuModel/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module QMenuModel
2+QDBusActionGroup 0.1 QDBusActionGroup.qml
tests/mocks/Ubuntu/Application/ApplicationManager.cpp+6−2
@@ -37,8 +37,6 @@ ApplicationManager::ApplicationManager(QObject *parent)
3737 , m_sideStage(0)
3838{
3939 buildListOfAvailableApplications();
40− createMainStageComponent();
41− createSideStageComponent();
4240}
4341
4442ApplicationManager::~ApplicationManager()
@@ -403,6 +401,9 @@ void ApplicationManager::createMainStageComponent()
403401
404402void ApplicationManager::createMainStage()
405403{
404+ if (!m_mainStageComponent)
405+ createMainStageComponent();
406+
406407 // The assumptions I make here really should hold.
407408 QQuickView *quickView =
408409 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
@@ -437,6 +438,9 @@ void ApplicationManager::createSideStageComponent()
437438
438439void ApplicationManager::createSideStage()
439440{
441+ if (!m_sideStageComponent)
442+ createSideStageComponent();
443+
440444 // The assumptions I make here really should hold.
441445 QQuickView *quickView =
442446 qobject_cast<QQuickView*>(QGuiApplication::topLevelWindows()[0]);
tests/mocks/Ubuntu/Application/ApplicationManager.h+4
@@ -46,6 +46,8 @@ class ApplicationManager : public QObject {
4646 Q_PROPERTY(ApplicationInfo* sideStageFocusedApplication READ sideStageFocusedApplication
4747 NOTIFY sideStageFocusedApplicationChanged)
4848
49+ Q_PROPERTY(bool fake READ fake CONSTANT)
50+
4951 public:
5052 ApplicationManager(QObject *parent = NULL);
5153 virtual ~ApplicationManager();
@@ -80,6 +82,8 @@ class ApplicationManager : public QObject {
8082 ApplicationInfo* mainStageFocusedApplication() const;
8183 ApplicationInfo* sideStageFocusedApplication() const;
8284
85+ bool fake() { return true; }
86+
8387 Q_INVOKABLE void focusApplication(int handle);
8488 Q_INVOKABLE void unfocusCurrentApplication(StageHint stageHint);
8589 Q_INVOKABLE ApplicationInfo* startProcess(QString desktopFile,
tests/mocks/Unity/CMakeLists.txt+1
@@ -44,3 +44,4 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
4444 )
4545
4646add_subdirectory(Launcher)
47+add_subdirectory(Notifications)
tests/mocks/Unity/Indicators/qml/fake_menu_page1.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page2.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page3.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page4.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Indicators/qml/fake_menu_page5.qml−8
@@ -32,13 +32,5 @@ Indicators.FakeMenuPage {
3232 horizontalCenter: parent.horizontalCenter
3333 verticalCenter: parent.verticalCenter
3434 }
35−
36− NumberAnimation on rotation {
37− id: rotation_animation
38− from: 0
39− to: 360
40− duration: 5000
41− loops: Animation.Infinite
42− }
4335 }
4436}
tests/mocks/Unity/Notifications/CMakeLists.txtnew file+11
@@ -0,0 +1,11 @@
1+file(GLOB QMLFILES
2+ *.qml
3+ *.js
4+ qmldir
5+)
6+
7+# copy files into build directory for shadow builds
8+add_custom_target(NotificationsQmlFiles ALL
9+ COMMAND cp ${QMLFILES} ${CMAKE_CURRENT_BINARY_DIR}
10+ DEPENDS ${QMLFILES}
11+)
tests/mocks/Unity/fake_categories.cpp+5−2
@@ -32,10 +32,11 @@ Categories::Categories(QObject* parent)
3232 m_roles[Categories::RoleName] = "name";
3333 m_roles[Categories::RoleIcon] = "icon";
3434 m_roles[Categories::RoleRenderer] = "renderer";
35− m_roles[Categories::RoleContentType] = "content_type";
35+ m_roles[Categories::RoleContentType] = "contentType";
3636 m_roles[Categories::RoleHints] = "hints";
3737 m_roles[Categories::RoleResults] = "results";
3838 m_roles[Categories::RoleCount] = "count";
39+ m_roles[Categories::RoleCategoryIndex] = "categoryIndex";
3940
4041 // TODO This should not be needed but accumulatting the count changes
4142 // makes the visualization more stable and also makes crashes on fast
@@ -154,7 +155,7 @@ Categories::data(const QModelIndex& index, int role) const
154155
155156 switch (role) {
156157 case RoleId:
157− return QVariant::fromValue(index.row());
158+ return DeeListModel::data(index, 0); //ID
158159 case RoleName:
159160 return DeeListModel::data(index, 1); //DISPLAY_NAME
160161 case RoleIcon:
@@ -172,6 +173,8 @@ Categories::data(const QModelIndex& index, int role) const
172173 return QVariant::fromValue(getFilter(index.row()));
173174 case RoleCount:
174175 return QVariant::fromValue(getFilter(index.row())->rowCount());
176+ case RoleCategoryIndex:
177+ return QVariant::fromValue(index.row());
175178 default:
176179 return QVariant();
177180 }
tests/mocks/Unity/fake_categories.h+2−1
@@ -41,7 +41,8 @@ public:
4141 RoleContentType,
4242 RoleHints,
4343 RoleResults,
44− RoleCount
44+ RoleCount,
45+ RoleCategoryIndex
4546 };
4647
4748 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
tests/mocks/Unity/fake_scopes.cpp+2−2
@@ -52,8 +52,8 @@ void Scopes::updateScopes()
5252 clear();
5353 addScope(new Scope("MockScope1", "People", true, this));
5454 addScope(new Scope("MockScope2", "Music", false, this));
55− addScope(new Scope("MockScope3", "Home", true, this));
56− addScope(new Scope("MockScope4", "Applications", true, this));
55+ addScope(new Scope("home.scope", "Home", true, this));
56+ addScope(new Scope("applications.scope", "Applications", true, this));
5757 addScope(new Scope("MockScope5", "Videos", true, this));
5858
5959 if (!m_loaded) {
tests/plugins/ListViewWithPageHeader/CMakeLists.txt+6−1
@@ -1,7 +1,12 @@
11# There's no cmake var for v8 include path :-/
22# so create one
33LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
4−SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
4+if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
5+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
6+else()
7+ SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
8+endif()
9+
510
611include_directories(
712 ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+237−3
@@ -22,7 +22,11 @@
2222#include <QtTestGui>
2323#pragma GCC diagnostic push
2424#pragma GCC diagnostic ignored "-pedantic"
25+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
2526#include <private/qquicklistmodel_p.h>
27+#else
28+#include <private/qqmllistmodel_p.h>
29+#endif
2630#include <private/qquickanimation_p.h>
2731#include <private/qquickitem_p.h>
2832#pragma GCC diagnostic pop
@@ -115,7 +119,11 @@ private Q_SLOTS:
115119 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
116120 view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test.qml"));
117121 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
122+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
118123 model = view->rootObject()->findChild<QQuickListModel*>();
124+#else
125+ model = view->rootObject()->findChild<QQmlListModel*>();
126+#endif
119127 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
120128 QVERIFY(lvwph);
121129 QVERIFY(model);
@@ -1237,7 +1245,7 @@ private Q_SLOTS:
12371245
12381246 lvwph->showHeader();
12391247
1240− QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1248+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
12411249 QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
12421250 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
12431251 verifyItem(0, -375., 150., true);
@@ -1293,7 +1301,7 @@ private Q_SLOTS:
12931301
12941302 lvwph->showHeader();
12951303
1296− QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1304+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
12971305 QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
12981306 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
12991307 verifyItem(0, -20., 150., false);
@@ -1331,7 +1339,7 @@ private Q_SLOTS:
13311339
13321340 lvwph->showHeader();
13331341
1334− QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1342+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
13351343 QTRY_VERIFY (lvwph->isAtYEnd());
13361344 }
13371345
@@ -1382,10 +1390,236 @@ private Q_SLOTS:
13821390 lvwph->showHeader();
13831391 }
13841392
1393+ void testCullOnBottomEdge()
1394+ {
1395+ changeContentY(200);
1396+
1397+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1398+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1399+ verifyItem(0, -150., 150., true);
1400+ verifyItem(1, 0., 200., false);
1401+ verifyItem(2, 200., 350., false);
1402+ verifyItem(3, 550., 350., true);
1403+ QCOMPARE(lvwph->m_minYExtent, 0.);
1404+ QCOMPARE(lvwph->m_clipItem->y(), 200.);
1405+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1406+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1407+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1408+ QCOMPARE(lvwph->contentY(), 200.);
1409+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1410+ }
1411+
1412+ void testMaximizeVisibleArea()
1413+ {
1414+ bool res = lvwph->maximizeVisibleArea(2);
1415+ QVERIFY(res);
1416+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1417+
1418+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1419+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1420+ verifyItem(0, -158., 150., true);
1421+ verifyItem(1, -8., 200., false);
1422+ verifyItem(2, 192, 350., false);
1423+ verifyItem(3, 542, 350., true);
1424+ QCOMPARE(lvwph->m_minYExtent, 0.);
1425+ QCOMPARE(lvwph->m_clipItem->y(), 208.);
1426+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1427+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1428+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1429+ QCOMPARE(lvwph->contentY(), 208.);
1430+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1431+ }
1432+
1433+ void testMaximizeVisibleAreaVisibleItems()
1434+ {
1435+ bool res = lvwph->maximizeVisibleArea(0);
1436+ QVERIFY(res);
1437+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1438+
1439+ verifyInitialTopPosition();
1440+
1441+ res = lvwph->maximizeVisibleArea(1);
1442+ QVERIFY(res);
1443+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1444+
1445+ verifyInitialTopPosition();
1446+ }
1447+
1448+ void testMaximizeVisibleAreaInvalidIndexes()
1449+ {
1450+ bool res = lvwph->maximizeVisibleArea(-1);
1451+ QVERIFY(!res);
1452+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1453+
1454+ verifyInitialTopPosition();
1455+
1456+ res = lvwph->maximizeVisibleArea(1000);
1457+ QVERIFY(!res);
1458+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1459+
1460+ verifyInitialTopPosition();
1461+
1462+ res = lvwph->maximizeVisibleArea(4);
1463+ QVERIFY(!res);
1464+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1465+
1466+ verifyInitialTopPosition();
1467+ }
1468+
1469+ void testMaximizeVisibleAreaBigElement()
1470+ {
1471+ model->setProperty(2, "size", 4000);
1472+ bool res = lvwph->maximizeVisibleArea(2);
1473+ QVERIFY(res);
1474+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1475+
1476+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1477+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1478+ verifyItem(0, -350., 150., true);
1479+ verifyItem(1, -200., 200., true);
1480+ verifyItem(2, 0, 4000., false);
1481+ QCOMPARE(lvwph->m_minYExtent, 0.);
1482+ QCOMPARE(lvwph->m_clipItem->y(), 400.);
1483+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1484+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1485+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1486+ QCOMPARE(lvwph->contentY(), 400.);
1487+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1488+ }
1489+
1490+ void testMaximizeVisibleAreaScrollDown()
1491+ {
1492+ changeContentY(250);
1493+ bool res = lvwph->maximizeVisibleArea(1);
1494+ QVERIFY(res);
1495+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1496+
1497+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1498+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1499+ verifyItem(0, -150., 150., true);
1500+ verifyItem(1, 0., 200., false);
1501+ verifyItem(2, 200, 350., false);
1502+ verifyItem(3, 550, 350., true);
1503+ QCOMPARE(lvwph->m_minYExtent, 0.);
1504+ QCOMPARE(lvwph->m_clipItem->y(), 200.);
1505+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1506+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1507+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1508+ QCOMPARE(lvwph->contentY(), 200.);
1509+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1510+ }
1511+
1512+ void testMaximizeVisibleAreaScrollDownBigElement()
1513+ {
1514+ model->setProperty(1, "size", 1000);
1515+ changeContentY(1150);
1516+ bool res = lvwph->maximizeVisibleArea(1);
1517+ QVERIFY(res);
1518+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1519+
1520+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1521+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1522+ verifyItem(0, -458., 1000., false);
1523+ verifyItem(1, 542., 350., true);
1524+ QCOMPARE(lvwph->m_minYExtent, 362.5);
1525+ QCOMPARE(lvwph->m_clipItem->y(), 658.);
1526+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1527+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1528+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1529+ QCOMPARE(lvwph->contentY(), 658.);
1530+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1531+ }
1532+
1533+ void testMaximizeVisibleAreaBigElementInTheMiddle()
1534+ {
1535+ model->setProperty(1, "size", 1000);
1536+ changeContentY(650);
1537+
1538+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1539+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1540+ verifyItem(0, -450., 1000., false);
1541+ verifyItem(1, 550., 350., true);
1542+ QCOMPARE(lvwph->m_minYExtent, 525.);
1543+ QCOMPARE(lvwph->m_clipItem->y(), 650.);
1544+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1545+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1546+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1547+ QCOMPARE(lvwph->contentY(), 650.);
1548+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1549+
1550+ bool res = lvwph->maximizeVisibleArea(1);
1551+ QVERIFY(res);
1552+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1553+
1554+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1555+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1556+ verifyItem(0, -450., 1000., false);
1557+ verifyItem(1, 550., 350., true);
1558+ QCOMPARE(lvwph->m_minYExtent, 525.);
1559+ QCOMPARE(lvwph->m_clipItem->y(), 650.);
1560+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1561+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1562+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1563+ QCOMPARE(lvwph->contentY(), 650.);
1564+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1565+ }
1566+
1567+ void testMaximizeVisibleAreaTopWithHalfPageHeader()
1568+ {
1569+ changeContentY(430);
1570+ changeContentY(-30);
1571+
1572+ bool res = lvwph->maximizeVisibleArea(1);
1573+ QVERIFY(res);
1574+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1575+
1576+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1577+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1578+ verifyItem(0, -150., 150., true);
1579+ verifyItem(1, 0., 200., false);
1580+ verifyItem(2, 200, 350., false);
1581+ verifyItem(3, 550, 350., true);
1582+ QCOMPARE(lvwph->m_minYExtent, 0.);
1583+ QCOMPARE(lvwph->m_clipItem->y(), 200.);
1584+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1585+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1586+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1587+ QCOMPARE(lvwph->contentY(), 200.);
1588+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1589+ }
1590+
1591+ void testMaximizeVisibleAreaBottomWithHalfPageHeader()
1592+ {
1593+ changeContentY(430);
1594+ changeContentY(-30);
1595+
1596+ bool res = lvwph->maximizeVisibleArea(3);
1597+ QVERIFY(res);
1598+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1599+
1600+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1601+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1602+ verifyItem(0, -358., 200., true);
1603+ verifyItem(1, -158., 350., false);
1604+ verifyItem(2, 192, 350., false);
1605+ verifyItem(3, 542, 350., true);
1606+ QCOMPARE(lvwph->m_minYExtent, 162.5);
1607+ QCOMPARE(lvwph->m_clipItem->y(), 558.);
1608+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1609+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1610+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1611+ QCOMPARE(lvwph->contentY(), 558.);
1612+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1613+ }
1614+
13851615private:
13861616 QQuickView *view;
13871617 ListViewWithPageHeader *lvwph;
1618+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
13881619 QQuickListModel *model;
1620+#else
1621+ QQmlListModel *model;
1622+#endif
13891623 QQmlComponent *otherDelegate;
13901624};
13911625
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+408−5
@@ -22,7 +22,11 @@
2222#include <QtTestGui>
2323#pragma GCC diagnostic push
2424#pragma GCC diagnostic ignored "-pedantic"
25+#if QT_VERSION < QT_VERSION_CHECK(5, 1, 0)
2526#include <private/qquicklistmodel_p.h>
27+#else
28+#include <private/qqmllistmodel_p.h>
29+#endif
2630#include <private/qquickanimation_p.h>
2731#include <private/qquickitem_p.h>
2832#pragma GCC diagnostic pop
@@ -41,6 +45,7 @@ private:
4145 QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
4246 if (!sectionHeader.isNull()) {
4347 QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
48+ QCOMPARE(sectionDelegateIndex(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), lvwph->m_firstVisibleIndex + visibleIndex);
4449 }
4550 }
4651
@@ -112,6 +117,11 @@ private:
112117 return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
113118 }
114119
120+ int sectionDelegateIndex(QQuickItem *item)
121+ {
122+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
123+ }
124+
115125private Q_SLOTS:
116126
117127 void initTestCase()
@@ -124,7 +134,11 @@ private Q_SLOTS:
124134 view->engine()->addImportPath(BUILT_PLUGINS_DIR);
125135 view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_section.qml"));
126136 lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
137+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
127138 model = view->rootObject()->findChild<QQuickListModel*>();
139+#else
140+ model = view->rootObject()->findChild<QQmlListModel*>();
141+#endif
128142 otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
129143 QVERIFY(lvwph);
130144 QVERIFY(model);
@@ -212,6 +226,7 @@ private Q_SLOTS:
212226 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
213227 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
214228 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
229+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
215230 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
216231 }
217232
@@ -233,6 +248,7 @@ private Q_SLOTS:
233248 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
234249 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
235250 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
251+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
236252 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
237253 }
238254
@@ -254,6 +270,7 @@ private Q_SLOTS:
254270 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
255271 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
256272 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
273+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
257274 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
258275
259276 changeContentY(-30);
@@ -272,6 +289,7 @@ private Q_SLOTS:
272289 QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
273290 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
274291 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
292+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
275293 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
276294 }
277295
@@ -327,6 +345,7 @@ private Q_SLOTS:
327345 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
328346 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
329347 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
348+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
330349 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
331350
332351 lvwph->positionAtBeginning();
@@ -352,6 +371,7 @@ private Q_SLOTS:
352371 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
353372 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
354373 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
374+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
355375 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
356376
357377 lvwph->positionAtBeginning();
@@ -396,6 +416,7 @@ private Q_SLOTS:
396416 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
397417 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
398418 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
419+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
399420 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
400421
401422 model->setProperty(0, "size", 400);
@@ -415,6 +436,7 @@ private Q_SLOTS:
415436 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
416437 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
417438 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
439+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
418440 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
419441
420442 scrollToTop();
@@ -468,6 +490,7 @@ private Q_SLOTS:
468490 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
469491 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
470492 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
493+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
471494 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
472495
473496 model->setProperty(0, "size", 400);
@@ -487,6 +510,7 @@ private Q_SLOTS:
487510 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
488511 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
489512 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
513+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
490514 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
491515
492516 scrollToTop();
@@ -523,6 +547,7 @@ private Q_SLOTS:
523547 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
524548 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
525549 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
550+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
526551 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
527552
528553 changeContentY(-30);
@@ -540,6 +565,7 @@ private Q_SLOTS:
540565 QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
541566 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
542567 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
568+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
543569 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
544570
545571 changeContentY(30);
@@ -557,6 +583,7 @@ private Q_SLOTS:
557583 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
558584 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
559585 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
586+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
560587 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
561588
562589 changeContentY(-30);
@@ -574,6 +601,7 @@ private Q_SLOTS:
574601 QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
575602 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
576603 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
604+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
577605 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
578606 }
579607
@@ -594,6 +622,7 @@ private Q_SLOTS:
594622 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
595623 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
596624 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
625+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
597626 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
598627
599628 lvwph->setDelegate(otherDelegate);
@@ -652,6 +681,7 @@ private Q_SLOTS:
652681 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
653682 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
654683 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
684+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
655685 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
656686
657687 scrollToTop();
@@ -690,6 +720,7 @@ private Q_SLOTS:
690720 QTRY_VERIFY(lvwph->isAtYEnd());
691721 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
692722 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
723+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
693724 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
694725
695726 scrollToTop();
@@ -726,6 +757,7 @@ private Q_SLOTS:
726757 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
727758 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
728759 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
760+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
729761 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
730762 }
731763
@@ -810,6 +842,7 @@ private Q_SLOTS:
810842 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
811843 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
812844 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
845+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
813846 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
814847
815848 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -830,6 +863,7 @@ private Q_SLOTS:
830863 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
831864 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
832865 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
866+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 4);
833867 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
834868
835869 scrollToTop();
@@ -870,6 +904,7 @@ private Q_SLOTS:
870904 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
871905 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
872906 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
907+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
873908 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
874909
875910 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 3), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -890,6 +925,7 @@ private Q_SLOTS:
890925 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
891926 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
892927 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
928+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
893929 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
894930 }
895931
@@ -912,6 +948,7 @@ private Q_SLOTS:
912948 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
913949 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
914950 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
951+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
915952 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
916953
917954 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -932,6 +969,7 @@ private Q_SLOTS:
932969 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
933970 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
934971 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
972+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 4);
935973 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
936974 }
937975
@@ -954,6 +992,7 @@ private Q_SLOTS:
954992 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
955993 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
956994 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
995+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
957996 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
958997
959998 QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
@@ -974,6 +1013,7 @@ private Q_SLOTS:
9741013 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
9751014 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
9761015 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1016+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
9771017 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
9781018
9791019 scrollToTop();
@@ -1021,6 +1061,7 @@ private Q_SLOTS:
10211061 QVERIFY(!lvwph->isAtYEnd());
10221062 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
10231063 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1064+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
10241065 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
10251066
10261067 scrollToBottom();
@@ -1041,6 +1082,7 @@ private Q_SLOTS:
10411082 QVERIFY(lvwph->isAtYEnd());
10421083 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
10431084 QCOMPARE(section(lvwph->m_topSectionItem), QString("Lazy"));
1085+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 5);
10441086 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
10451087 }
10461088
@@ -1094,6 +1136,7 @@ private Q_SLOTS:
10941136 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
10951137 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
10961138 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1139+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 13);
10971140 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
10981141
10991142 changeContentY(-1700);
@@ -1118,6 +1161,7 @@ private Q_SLOTS:
11181161 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
11191162 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
11201163 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1164+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 4);
11211165 QCOMPARE(lvwph->m_topSectionItem->y(), -23.);
11221166 }
11231167
@@ -1179,6 +1223,7 @@ private Q_SLOTS:
11791223 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
11801224 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
11811225 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1226+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
11821227 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
11831228 }
11841229
@@ -1202,6 +1247,7 @@ private Q_SLOTS:
12021247 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12031248 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12041249 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1250+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12051251 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12061252 }
12071253
@@ -1224,6 +1270,7 @@ private Q_SLOTS:
12241270 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12251271 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12261272 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1273+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12271274 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12281275
12291276 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 1), Q_ARG(QVariant, 1));
@@ -1243,6 +1290,7 @@ private Q_SLOTS:
12431290 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12441291 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12451292 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1293+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
12461294 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12471295 }
12481296
@@ -1265,6 +1313,7 @@ private Q_SLOTS:
12651313 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12661314 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12671315 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1316+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12681317 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12691318
12701319 QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 3), Q_ARG(QVariant, 1));
@@ -1284,6 +1333,7 @@ private Q_SLOTS:
12841333 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
12851334 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
12861335 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1336+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
12871337 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
12881338 }
12891339
@@ -1363,6 +1413,7 @@ private Q_SLOTS:
13631413 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
13641414 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
13651415 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1416+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 3);
13661417 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
13671418
13681419 QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 5), Q_ARG(QVariant, 1));
@@ -1383,6 +1434,7 @@ private Q_SLOTS:
13831434 QVERIFY(!lvwph->isAtYEnd());
13841435 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
13851436 QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1437+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
13861438 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
13871439 }
13881440
@@ -1406,6 +1458,7 @@ private Q_SLOTS:
14061458 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14071459 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14081460 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1461+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
14091462 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14101463
14111464 model->setProperty(1, "size", 100);
@@ -1426,6 +1479,7 @@ private Q_SLOTS:
14261479 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14271480 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14281481 QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1482+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
14291483 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14301484 }
14311485
@@ -1447,12 +1501,12 @@ private Q_SLOTS:
14471501 QCOMPARE(lvwph->m_headerItem->y(), 0.);
14481502 QCOMPARE(lvwph->m_headerItem->height(), 50.);
14491503 QCOMPARE(lvwph->contentY(), 20.);
1450− QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1504+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
14511505 QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14521506
14531507 lvwph->showHeader();
14541508
1455− QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1509+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
14561510 QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
14571511 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
14581512 verifyItem(0, -20., 190., false, "Agressive", true);
@@ -1467,6 +1521,7 @@ private Q_SLOTS:
14671521 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
14681522 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
14691523 QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
1524+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
14701525 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
14711526
14721527 scrollToTop();
@@ -1502,14 +1557,15 @@ private Q_SLOTS:
15021557 QCOMPARE(lvwph->m_headerItem->y(), 0.);
15031558 QCOMPARE(lvwph->m_headerItem->height(), 50.);
15041559 QCOMPARE(lvwph->contentY(), 375.);
1505− QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1560+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
15061561 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
15071562 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1563+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
15081564 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
15091565
15101566 lvwph->showHeader();
15111567
1512− QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1568+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
15131569 QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
15141570 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
15151571 verifyItem(0, -375., 190., true, "Agressive", true);
@@ -1525,6 +1581,7 @@ private Q_SLOTS:
15251581 QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
15261582 QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
15271583 QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1584+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
15281585 QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
15291586
15301587 scrollToTop();
@@ -1550,7 +1607,7 @@ private Q_SLOTS:
15501607
15511608 lvwph->showHeader();
15521609
1553− QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1610+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
15541611 QTRY_VERIFY (lvwph->isAtYEnd());
15551612 }
15561613
@@ -1634,10 +1691,356 @@ private Q_SLOTS:
16341691 QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
16351692 }
16361693
1694+ void testCullOnBottomEdge()
1695+ {
1696+ changeContentY(240);
1697+
1698+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1699+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1700+ verifyItem(0, -190., 190., true, "Agressive", true);
1701+ verifyItem(1, 0., 240., false, "Regular", false);
1702+ verifyItem(2, 240., 390., false, "Mild", false);
1703+ verifyItem(3, 630., 390., true, "Bold", true);
1704+ QCOMPARE(lvwph->m_minYExtent, 0.);
1705+ QCOMPARE(lvwph->m_clipItem->y(), 240.);
1706+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1707+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1708+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1709+ QCOMPARE(lvwph->contentY(), 240.);
1710+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1711+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1712+ }
1713+
1714+ void testSectionItemCullOnFirstSectionItemTopEdge()
1715+ {
1716+ changeContentY(50);
1717+
1718+ verifyItem(0, 0., 190., false, "Agressive", false);
1719+ verifyItem(1, 190., 240., false, "Regular", false);
1720+ verifyItem(2, 430., 390., false, "Mild", false);
1721+ QCOMPARE(lvwph->m_minYExtent, 0.);
1722+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
1723+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1724+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1725+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1726+ QCOMPARE(lvwph->contentY(), 50.);
1727+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1728+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1729+ }
1730+
1731+ void testSectionItemCullOnSecondSectionItemTopEdge()
1732+ {
1733+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1734+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1735+
1736+ changeContentY(140);
1737+
1738+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1739+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1740+ verifyItem(0, -90., 90., true, "Agressive", true);
1741+ verifyItem(1, 0., 50., false, QString(), false);
1742+ verifyItem(2, 50., 150., false, QString(), false);
1743+ verifyItem(3, 200., 240., false, "Regular", false);
1744+ verifyItem(4, 440., 390., false, "Mild", false);
1745+ QCOMPARE(lvwph->m_minYExtent, 0.);
1746+ QCOMPARE(lvwph->m_clipItem->y(), 140.);
1747+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1748+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1749+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1750+ QCOMPARE(lvwph->contentY(), 140.);
1751+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1752+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1753+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
1754+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
1755+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1756+ }
1757+
1758+ void testMaximizeVisibleArea()
1759+ {
1760+ bool res = lvwph->maximizeVisibleArea(2);
1761+ QVERIFY(res);
1762+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1763+
1764+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1765+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1766+ verifyItem(0, -278., 190., true, "Agressive", true);
1767+ verifyItem(1, -88., 240., false, "Regular", true);
1768+ verifyItem(2, 152, 390., false, "Mild", false);
1769+ verifyItem(3, 542, 390., true, "Bold", true);
1770+ QCOMPARE(lvwph->m_minYExtent, 0.);
1771+ QCOMPARE(lvwph->m_clipItem->y(), 328.);
1772+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1773+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1774+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1775+ QCOMPARE(lvwph->contentY(), 328.);
1776+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1777+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1778+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1779+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
1780+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1781+ }
1782+
1783+ void testMaximizeVisibleAreaVisibleItems()
1784+ {
1785+ bool res = lvwph->maximizeVisibleArea(0);
1786+ QVERIFY(res);
1787+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1788+
1789+ verifyInitialTopPosition();
1790+
1791+ res = lvwph->maximizeVisibleArea(1);
1792+ QVERIFY(res);
1793+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1794+
1795+ verifyInitialTopPosition();
1796+ }
1797+
1798+ void testMaximizeVisibleAreaInvalidIndexes()
1799+ {
1800+ bool res = lvwph->maximizeVisibleArea(-1);
1801+ QVERIFY(!res);
1802+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1803+
1804+ verifyInitialTopPosition();
1805+
1806+ res = lvwph->maximizeVisibleArea(1000);
1807+ QVERIFY(!res);
1808+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1809+
1810+ verifyInitialTopPosition();
1811+
1812+ res = lvwph->maximizeVisibleArea(3);
1813+ QVERIFY(!res);
1814+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1815+
1816+ verifyInitialTopPosition();
1817+ }
1818+
1819+ void testMaximizeVisibleAreaBigElement()
1820+ {
1821+ model->setProperty(2, "size", 4000);
1822+ verifyItem(2, 480, 4040., false, "Mild", false);
1823+
1824+ bool res = lvwph->maximizeVisibleArea(2);
1825+ QVERIFY(res);
1826+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1827+
1828+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1829+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1830+ verifyItem(0, -430., 190., true, "Agressive", true);
1831+ verifyItem(1, -240., 240., true, "Regular", true);
1832+ verifyItem(2, 0, 4040., false, "Mild", false);
1833+ QCOMPARE(lvwph->m_minYExtent, 0.);
1834+ QCOMPARE(lvwph->m_clipItem->y(), 480.);
1835+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1836+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1837+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1838+ QCOMPARE(lvwph->contentY(), 480.);
1839+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1840+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1841+ }
1842+
1843+ void testMaximizeVisibleAreaScrollDown()
1844+ {
1845+ changeContentY(350);
1846+ bool res = lvwph->maximizeVisibleArea(1);
1847+ QVERIFY(res);
1848+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1849+
1850+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1851+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1852+ verifyItem(0, -190., 190., true, "Agressive", true);
1853+ verifyItem(1, 0., 240., false, "Regular", false);
1854+ verifyItem(2, 240, 390., false, "Mild", false);
1855+ verifyItem(3, 630, 390., true, "Bold", true);
1856+ QCOMPARE(lvwph->m_minYExtent, 0.);
1857+ QCOMPARE(lvwph->m_clipItem->y(), 240.);
1858+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1859+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1860+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1861+ QCOMPARE(lvwph->contentY(), 240.);
1862+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1863+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1864+ }
1865+
1866+ void testMaximizeVisibleAreaScrollDownBigElement()
1867+ {
1868+ model->setProperty(1, "size", 1000);
1869+ changeContentY(1150);
1870+ bool res = lvwph->maximizeVisibleArea(1);
1871+ QVERIFY(res);
1872+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1873+
1874+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1875+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1876+ verifyItem(0, -498., 1040., false, "Regular", true);
1877+ verifyItem(1, 542., 390., true, "Mild", true);
1878+ QCOMPARE(lvwph->m_minYExtent, 1250/3.);
1879+ QCOMPARE(lvwph->m_clipItem->y(), 738.);
1880+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1881+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1882+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1883+ QCOMPARE(lvwph->contentY(), 738.);
1884+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1885+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1886+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1887+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
1888+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1889+ }
1890+
1891+ void testMaximizeVisibleAreaBigElementInTheMiddle()
1892+ {
1893+ model->setProperty(1, "size", 1000);
1894+ changeContentY(650);
1895+
1896+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1897+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1898+ verifyItem(0, -410., 1040., false, "Regular", true);
1899+ verifyItem(1, 630., 390., true, "Mild", true);
1900+ QCOMPARE(lvwph->m_minYExtent, 525.);
1901+ QCOMPARE(lvwph->m_clipItem->y(), 650.);
1902+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1903+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1904+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1905+ QCOMPARE(lvwph->contentY(), 650.);
1906+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1907+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1908+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1909+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
1910+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1911+
1912+ bool res = lvwph->maximizeVisibleArea(1);
1913+ QVERIFY(res);
1914+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1915+
1916+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1917+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1918+ verifyItem(0, -410., 1040., false, "Regular", true);
1919+ verifyItem(1, 630., 390., true, "Mild", true);
1920+ QCOMPARE(lvwph->m_minYExtent, 525.);
1921+ QCOMPARE(lvwph->m_clipItem->y(), 650.);
1922+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1923+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1924+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1925+ QCOMPARE(lvwph->contentY(), 650.);
1926+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1927+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1928+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1929+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 1);
1930+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1931+ }
1932+
1933+ void testMaximizeVisibleAreaTopWithHalfPageHeader()
1934+ {
1935+ changeContentY(430);
1936+ changeContentY(-30);
1937+
1938+ bool res = lvwph->maximizeVisibleArea(1);
1939+ QVERIFY(res);
1940+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1941+
1942+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1943+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1944+ verifyItem(0, -190., 190., true, "Agressive", true);
1945+ verifyItem(1, 0., 240., false, "Regular", false);
1946+ verifyItem(2, 240, 390., false, "Mild", false);
1947+ verifyItem(3, 630, 390., true, "Bold", true);
1948+ QCOMPARE(lvwph->m_minYExtent, 0.);
1949+ QCOMPARE(lvwph->m_clipItem->y(), 240.);
1950+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1951+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1952+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1953+ QCOMPARE(lvwph->contentY(), 240.);
1954+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1955+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1956+ }
1957+
1958+ void testMaximizeVisibleAreaBottomWithHalfPageHeader()
1959+ {
1960+ changeContentY(430);
1961+ changeContentY(-30);
1962+
1963+ bool res = lvwph->maximizeVisibleArea(3);
1964+ QVERIFY(res);
1965+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1966+
1967+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1968+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1969+ verifyItem(0, -478., 240., true, "Regular", true);
1970+ verifyItem(1, -238., 390., false, "Mild", true);
1971+ verifyItem(2, 152, 390., false, "Bold", false);
1972+ verifyItem(3, 542, 350., true, QString(), true);
1973+ QCOMPARE(lvwph->m_minYExtent, 152.5);
1974+ QCOMPARE(lvwph->m_clipItem->y(), 718.);
1975+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1976+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1977+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1978+ QCOMPARE(lvwph->contentY(), 718.);
1979+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1980+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1981+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1982+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 2);
1983+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1984+ }
1985+
1986+ void testMaximizeVisibleAreaTopSecondSectionItemStickySection()
1987+ {
1988+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
1989+ changeContentY(250);
1990+ bool res = lvwph->maximizeVisibleArea(1);
1991+ QVERIFY(res);
1992+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
1993+
1994+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1995+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1996+ verifyItem(0, -100., 140., false, "Agressive", true);
1997+ verifyItem(1, 40., 150., false, QString(), true);
1998+ verifyItem(2, 190, 240., false, "Regular", false);
1999+ verifyItem(3, 430, 390., false, "Mild", false);
2000+ QCOMPARE(lvwph->m_minYExtent, 0.);
2001+ QCOMPARE(lvwph->m_clipItem->y(), 150.);
2002+ QCOMPARE(lvwph->m_clipItem->clip(), false);
2003+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
2004+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
2005+ QCOMPARE(lvwph->contentY(), 150.);
2006+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
2007+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
2008+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
2009+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
2010+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
2011+
2012+ changeContentY(20);
2013+ res = lvwph->maximizeVisibleArea(1);
2014+ QVERIFY(res);
2015+ QTRY_VERIFY(!lvwph->m_contentYAnimation->isRunning());
2016+
2017+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
2018+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
2019+ verifyItem(0, -100., 140., false, "Agressive", true);
2020+ verifyItem(1, 40., 150., false, QString(), true);
2021+ verifyItem(2, 190, 240., false, "Regular", false);
2022+ verifyItem(3, 430, 390., false, "Mild", false);
2023+ QCOMPARE(lvwph->m_minYExtent, 0.);
2024+ QCOMPARE(lvwph->m_clipItem->y(), 150.);
2025+ QCOMPARE(lvwph->m_clipItem->clip(), false);
2026+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
2027+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
2028+ QCOMPARE(lvwph->contentY(), 150.);
2029+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
2030+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
2031+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
2032+ QCOMPARE(sectionDelegateIndex(lvwph->m_topSectionItem), 0);
2033+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
2034+ }
2035+
16372036private:
16382037 QQuickView *view;
16392038 ListViewWithPageHeader *lvwph;
2039+#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
16402040 QQuickListModel *model;
2041+#else
2042+ QQmlListModel *model;
2043+#endif
16412044 QQmlComponent *otherDelegate;
16422045};
16432046
tests/plugins/Unity/Indicators/indicatorsmanagertest.cpp+1−1
@@ -134,5 +134,5 @@ private Q_SLOTS:
134134 }
135135};
136136
137−QTEST_MAIN(IndicatorsManagerTest)
137+QTEST_GUILESS_MAIN(IndicatorsManagerTest)
138138#include "indicatorsmanagertest.moc"
tests/plugins/Unity/Indicators/indicatorsmodeltest.cpp+1−1
@@ -97,6 +97,6 @@ private Q_SLOTS:
9797 }
9898};
9999
100−QTEST_MAIN(IndicatorsModelTest)
100+QTEST_GUILESS_MAIN(IndicatorsModelTest)
101101
102102#include "indicatorsmodeltest.moc"
tests/plugins/Unity/Indicators/menucontentactivatortest.cpp+1−1
@@ -299,5 +299,5 @@ private:
299299 QList<int> m_deltas;
300300};
301301
302−QTEST_MAIN(MenuConentActivatorTest)
302+QTEST_GUILESS_MAIN(MenuConentActivatorTest)
303303#include "menucontentactivatortest.moc"
tests/plugins/Utils/qlimitproxymodeltest.cpp+1−1
@@ -481,6 +481,6 @@ private Q_SLOTS:
481481 }
482482};
483483
484−QTEST_MAIN(QLimitProxyModelTest)
484+QTEST_GUILESS_MAIN(QLimitProxyModelTest)
485485
486486#include "qlimitproxymodeltest.moc"
tests/plugins/Utils/qsortfilterproxymodeltest.cpp+1−1
@@ -285,6 +285,6 @@ private Q_SLOTS:
285285 }
286286};
287287
288−QTEST_MAIN(QSortFilterProxyModelTest)
288+QTEST_GUILESS_MAIN(QSortFilterProxyModelTest)
289289
290290#include "qsortfilterproxymodeltest.moc"
tests/qmltests/CMakeLists.txt+3
@@ -25,6 +25,9 @@ add_qml_test(utils/Unity/Test UnityTest)
2525set(qmltest_DEFAULT_TARGETS qmluitests)
2626set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
2727set(qmltest_DEFAULT_PROPERTIES "")
28+
29+add_qml_test(. Shell IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
30+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
2831add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
2932add_qml_test(Components DraggingArea)
3033add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
tests/qmltests/Components/tst_Stage.qml+1
@@ -161,6 +161,7 @@ Rectangle {
161161 applicationManager: fakeAppManager
162162 rightEdgeDraggingAreaWidth: units.gu(2)
163163 fullyShown: true
164+ fullyHidden: false
164165 newApplicationScreenshot: FakeApplicationScreenshot {
165166 id: newAppScreenshot
166167 parent: stage
tests/qmltests/Dash/tst_Dash.qml+4−4
@@ -38,8 +38,8 @@ Item {
3838 scopeDelegateMapping: {
3939 "MockScope1": "../tests/qmltests/Dash/qml/fake_scopeView1.qml",
4040 "MockScope2": "../tests/qmltests/Dash/qml/fake_scopeView2.qml",
41− "MockScope3": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
42− "MockScope4": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
41+ "home.scope": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
42+ "applications.scope": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
4343 }
4444 genericScope: "../tests/qmltests/Dash/qml/fake_generic_scopeView.qml"
4545 }
@@ -69,8 +69,8 @@ Item {
6969 return [
7070 { tag: "MockScope1", visualIndex: 0, shouldBeVisible: true },
7171 { tag: "MockScope2", visualIndex: -1, shouldBeVisible: false },
72− { tag: "MockScope3", visualIndex: 1, shouldBeVisible: true },
73− { tag: "MockScope4", visualIndex: 2, shouldBeVisible: true },
72+ { tag: "home.scope", visualIndex: 1, shouldBeVisible: true },
73+ { tag: "applications.scope", visualIndex: 2, shouldBeVisible: true },
7474 { tag: "MockScope5", visualIndex: 3, shouldBeVisible: true },
7575 ]
7676 }
tests/qmltests/Dash/tst_DashContent.qml+12−12
@@ -31,8 +31,8 @@ Item {
3131 property var scopeStatus: {
3232 'MockScope1': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
3333 'MockScope2': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
34− 'MockScope3': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
35− 'MockScope4': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
34+ 'home.scope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
35+ 'applications.scope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
3636 'MockScope5': { 'movementStarted': 0, 'positionedAtBeginning': 0 }
3737 }
3838
@@ -55,8 +55,8 @@ Item {
5555 scopeDelegateMapping: {
5656 "MockScope1": "../tests/qmltests/Dash/qml/fake_scopeView1.qml",
5757 "MockScope2": "../tests/qmltests/Dash/qml/fake_scopeView2.qml",
58− "MockScope3": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
59− "MockScope4": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
58+ "home.scope": "../tests/qmltests/Dash/qml/fake_scopeView3.qml",
59+ "applications.scope": "../tests/qmltests/Dash/qml/fake_scopeView4.qml"
6060 }
6161 genericScope: "../tests/qmltests/Dash/qml/fake_generic_scopeView.qml"
6262 }
@@ -68,11 +68,11 @@ Item {
6868 scopeStatus["MockScope2"].movementStarted = 0;
6969 scopeStatus["MockScope2"].positionedAtBeginning = 0;
7070
71− scopeStatus["MockScope3"].movementStarted = 0;
72− scopeStatus["MockScope3"].positionedAtBeginning = 0;
71+ scopeStatus["home.scope"].movementStarted = 0;
72+ scopeStatus["home.scope"].positionedAtBeginning = 0;
7373
74− scopeStatus["MockScope4"].movementStarted = 0;
75− scopeStatus["MockScope4"].positionedAtBeginning = 0;
74+ scopeStatus["applications.scope"].movementStarted = 0;
75+ scopeStatus["applications.scope"].positionedAtBeginning = 0;
7676
7777 scopeStatus["MockScope5"].movementStarted = 0;
7878 scopeStatus["MockScope5"].positionedAtBeginning = 0;
@@ -127,8 +127,8 @@ Item {
127127 compare(movementStartedSpy.count, 1, "DashContent should have emitted movementStarted signal when content list did.");
128128 compare(scopeStatus["MockScope1"].movementStarted, 1, "MockScope1 should have emitted movementStarted signal when content list did.");
129129 compare(scopeStatus["MockScope2"].movementStarted, 1, "MockScope2 should have emitted movementStarted signal when content list did.");
130− compare(scopeStatus["MockScope3"].movementStarted, 1, "MockScope3 should have emitted movementStarted signal when content list did.");
131− compare(scopeStatus["MockScope4"].movementStarted, 1, "MockScope4 should have emitted movementStarted signal when content list did.");
130+ compare(scopeStatus["home.scope"].movementStarted, 1, "home.scope should have emitted movementStarted signal when content list did.");
131+ compare(scopeStatus["applications.scope"].movementStarted, 1, "applications.scope should have emitted movementStarted signal when content list did.");
132132 compare(scopeStatus["MockScope5"].movementStarted, 1, "MockScope5 should have emitted movementStarted signal when content list did.");
133133 }
134134
@@ -140,8 +140,8 @@ Item {
140140 dashContent.positionedAtBeginning();
141141 compare(scopeStatus["MockScope1"].positionedAtBeginning, 1, "MockScope1 should have emitted positionedAtBeginning signal when DashContent did.");
142142 compare(scopeStatus["MockScope2"].positionedAtBeginning, 1, "MockScope2 should have emitted positionedAtBeginning signal when DashContent did.");
143− compare(scopeStatus["MockScope3"].positionedAtBeginning, 1, "MockScope3 should have emitted positionedAtBeginning signal when DashContent did.");
144− compare(scopeStatus["MockScope4"].positionedAtBeginning, 1, "MockScope4 should have emitted positionedAtBeginning signal when DashContent did.");
143+ compare(scopeStatus["home.scope"].positionedAtBeginning, 1, "home.scope should have emitted positionedAtBeginning signal when DashContent did.");
144+ compare(scopeStatus["applications.scope"].positionedAtBeginning, 1, "applications.scope should have emitted positionedAtBeginning signal when DashContent did.");
145145 compare(scopeStatus["MockScope5"].positionedAtBeginning, 1, "MockScope5 should have emitted positionedAtBeginning signal when DashContent did.");
146146 }
147147
tests/qmltests/Dash/tst_FilterGrids.qml+1−1
@@ -118,7 +118,7 @@ Rectangle {
118118 gridLoader.source = "../../../Dash/" + data.component;
119119
120120 // Wait until the FilterGrid is loaded by the loader
121− tryCompare(gridLoader, "status", Loader.Ready, "Loader couldn't load " + data.component);
121+ tryCompare(gridLoader, "status", Loader.Ready);
122122
123123 // Wait until the GridView inside the model has finished rendering
124124 var gridView = findChild(gridLoader, "responsiveGridViewGrid");
tests/qmltests/Greeter/tst_Lockscreen.qml+1
@@ -186,6 +186,7 @@ Rectangle {
186186 function test_unlock(data) {
187187 unlockedCheckBox.checked = false
188188 LightDM.Greeter.authenticate(data.username)
189+ waitForRendering(lockscreen)
189190
190191 var inputField = findChild(lockscreen, "pinentryField")
191192 if (data.alphanumeric) {
tests/qmltests/Panel/tst_IndicatorItem.qml+10−16
@@ -34,34 +34,28 @@ Rectangle {
3434 UT.UnityTestCase {
3535 name: "IndicatorItem"
3636
37− function init_test() {
38− }
39−
4037 function test_dimmed() {
41− init_test()
42−
43− indicatorItem.dimmed = true
44− compare(indicatorItem.opacity > 0, true, "IndicatorItem opacity should not be 0")
45− compare(indicatorItem.opacity < 1, true, "IndicatorItem opacity should not be 1")
38+ indicatorItem.dimmed = false;
39+ tryCompareFunction(function(){return indicatorItem.opacity}, 1.0);
40+ indicatorItem.dimmed = true;
41+ tryCompareFunction(function(){return indicatorItem.opacity < 1.0}, true);
4642 }
4743
4844 function test_highlight() {
49− var itemHighlight = findChild(indicatorItem, "highlight")
50− verify(itemHighlight != undefined)
45+ var itemHighlight = findChild(indicatorItem, "highlight");
46+ verify(itemHighlight != undefined);
5147
5248 indicatorItem.highlighted = true;
53− compare(itemHighlight.visible, true, "Indicator should be highlighted")
49+ compare(itemHighlight.visible, true, "Indicator should be highlighted");
5450
5551 indicatorItem.highlighted = false;
56− compare(itemHighlight.visible, false, "Indicator should not be highlighted")
52+ compare(itemHighlight.visible, false, "Indicator should not be highlighted");
5753 }
5854
5955 function test_empty() {
60− init_test()
61−
62− compare(indicatorItem.visible, false, "IndicatorItem should not be visible.")
56+ compare(indicatorItem.visible, false, "IndicatorItem should not be visible.");
6357 indicatorItem.widgetSource = "qrc:/tests/indciators/qml/fake_menu_widget1.qml";
64− tryCompare(indicatorItem, "visible", true)
58+ tryCompare(indicatorItem, "visible", true);
6559 }
6660 }
6761}
tests/qmltests/Panel/tst_IndicatorRow.qml+21−21
@@ -61,13 +61,13 @@ Item {
6161
6262 function test_set_current_item() {
6363 init_test();
64− indicatorRow.setItem(0);
64+ indicatorRow.setCurrentItem(0);
6565 compare(indicatorRow.indicatorsModel.get(indicatorRow.currentItemIndex).title, "Menu1", "Incorrect item at position 0");
6666
67− indicatorRow.setItem(1);
67+ indicatorRow.setCurrentItem(1);
6868 compare(indicatorRow.indicatorsModel.get(indicatorRow.currentItemIndex).title, "Menu2", "Incorrect item at position 1");
6969
70− indicatorRow.setItem(2);
70+ indicatorRow.setCurrentItem(2);
7171 compare(indicatorRow.indicatorsModel.get(indicatorRow.currentItemIndex).title, "Menu3", "Incorrect item at position 2");
7272 }
7373 }
@@ -83,13 +83,13 @@ Item {
8383 function test_current_item_commit() {
8484 init_test();
8585
86− indicatorRow.setItem(1);
86+ indicatorRow.setCurrentItem(1);
8787 indicatorRow.state = "commit";
88− tryCompare(get_indicator_item_at(0), "y", -indicatorRow.height);
89− tryCompare(get_indicator_item_at(1), "y", 0);
90− tryCompare(get_indicator_item_at(2), "y", -indicatorRow.height);
91− tryCompare(get_indicator_item_at(3), "y", -indicatorRow.height);
92− tryCompare(get_indicator_item_at(4), "y", -indicatorRow.height);
88+ tryCompare(get_indicator_item_at(0), "opacity", 0.0);
89+ tryCompare(get_indicator_item_at(1), "opacity", 1.0);
90+ tryCompare(get_indicator_item_at(2), "opacity", 0.0);
91+ tryCompare(get_indicator_item_at(3), "opacity", 0.0);
92+ tryCompare(get_indicator_item_at(4), "opacity", 0.0);
9393
9494 }
9595 }
@@ -106,7 +106,7 @@ Item {
106106 init_test();
107107
108108 indicatorRow.state = "initial";
109− indicatorRow.setItem(0);
109+ indicatorRow.setCurrentItem(0);
110110
111111 compare(indicatorRow.currentItem.highlighted, false, "Indicator should not highlight when in initial state");
112112 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in initial state");
@@ -119,9 +119,9 @@ Item {
119119 init_test();
120120
121121 indicatorRow.state = "hint";
122− indicatorRow.setItem(0);
122+ indicatorRow.setCurrentItem(0);
123123
124− compare(indicatorRow.currentItem.highlighted, false, "Indicator should not highlight when in hint state");
124+ compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in hint state");
125125 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in hint state");
126126 compare(get_indicator_item_at(2).highlighted, false, "Other indicators should not highlight when in hint state");
127127 compare(get_indicator_item_at(3).highlighted, false, "Other indicators should not highlight when in hint state");
@@ -132,7 +132,7 @@ Item {
132132 init_test();
133133
134134 indicatorRow.state = "reveal";
135− indicatorRow.setItem(0);
135+ indicatorRow.setCurrentItem(0);
136136
137137 compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in reveal state");
138138 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in commit state");
@@ -145,7 +145,7 @@ Item {
145145 init_test();
146146
147147 indicatorRow.state = "commit";
148− indicatorRow.setItem(0);
148+ indicatorRow.setCurrentItem(0);
149149
150150 compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in commit state");
151151 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in commit state");
@@ -158,7 +158,7 @@ Item {
158158 init_test();
159159
160160 indicatorRow.state = "locked";
161− indicatorRow.setItem(0);
161+ indicatorRow.setCurrentItem(0);
162162
163163 compare(indicatorRow.currentItem.highlighted, true, "Indicator should highlight when in locked state");
164164 compare(get_indicator_item_at(1).highlighted, false, "Other indicators should not highlight when in locked state");
@@ -180,7 +180,7 @@ Item {
180180 init_test();
181181
182182 indicatorRow.state = "initial";
183− indicatorRow.setItem(0);
183+ indicatorRow.setCurrentItem(0);
184184
185185 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in intiial state");
186186 compare(get_indicator_item_at(1).dimmed, false, "Other indicators should not dim when in initial state");
@@ -193,9 +193,9 @@ Item {
193193 init_test();
194194
195195 indicatorRow.state = "hint";
196− indicatorRow.setItem(0);
196+ indicatorRow.setCurrentItem(0);
197197
198− compare(get_indicator_item_at(0).dimmed, true, "Current indicator should dim when in hint state");
198+ compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in hint state");
199199 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in hint state");
200200 compare(get_indicator_item_at(2).dimmed, true, "Other indicators should dim when in hint state");
201201 compare(get_indicator_item_at(3).dimmed, true, "Other indicators should dim when in hint state");
@@ -206,7 +206,7 @@ Item {
206206 init_test();
207207
208208 indicatorRow.state = "reveal";
209− indicatorRow.setItem(0);
209+ indicatorRow.setCurrentItem(0);
210210
211211 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in reveal state");
212212 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in reveal state");
@@ -219,7 +219,7 @@ Item {
219219 init_test();
220220
221221 indicatorRow.state = "commit";
222− indicatorRow.setItem(0);
222+ indicatorRow.setCurrentItem(0);
223223
224224 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in commit state");
225225 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in commit state");
@@ -232,7 +232,7 @@ Item {
232232 init_test();
233233
234234 indicatorRow.state = "locked";
235− indicatorRow.setItem(0);
235+ indicatorRow.setCurrentItem(0);
236236
237237 compare(get_indicator_item_at(0).dimmed, false, "Current indicator should not dim when in locked state");
238238 compare(get_indicator_item_at(1).dimmed, true, "Other indicators should dim when in locked state");
tests/qmltests/Panel/tst_MenuContent.qml+4−4
@@ -77,15 +77,15 @@ Item {
7777
7878 function activate_next_content()
7979 {
80− if (menuContent.currentIndex == -1)
80+ if (menuContent.currentMenuIndex == -1)
8181 activate_content(0);
8282 else
83− activate_content((menuContent.currentIndex + 1) % indicatorsModel.count)
83+ activate_content((menuContent.currentMenuIndex + 1) % indicatorsModel.count)
8484 }
8585
8686 function activate_content(index)
8787 {
88− menuContent.currentIndex = index
88+ menuContent.currentMenuIndex = index
8989 }
9090
9191 function get_test_menu_objecName(index) {
@@ -197,7 +197,7 @@ Item {
197197
198198 for (var i = 0; i < 100; i++) {
199199 activate_content(i % menu_count);
200− compare(menuContent.currentIndex, i%menu_count);
200+ compare(menuContent.currentMenuIndex, i%menu_count);
201201 }
202202 wait(100);
203203 }
tests/qmltests/Panel/tst_Panel.qml+83−43
@@ -30,11 +30,11 @@ Item {
3030 width: units.gu(40)
3131 height: units.gu(80)
3232
33− property bool search_clicked: false
33+ property bool searchClicked: false
3434
3535 Connections {
3636 target: panel
37− onSearchClicked: search_clicked = true
37+ onSearchClicked: searchClicked = true
3838 }
3939
4040 Panel {
@@ -54,27 +54,26 @@ Item {
5454
5555
5656 function init() {
57− search_clicked = false;
57+ searchClicked = false;
5858 panel.indicators.hide();
5959 tryCompare(panel.indicators.hideAnimation, "running", false);
6060 tryCompare(panel.indicators, "state", "initial");
6161 }
6262
6363 function get_indicator_item(index) {
64− var row_repeater = findChild(panel.indicators, "rowRepeater");
65− verify(row_repeater != undefined);
66− return row_repeater.itemAt(index);
64+ var rowRepeater = findChild(panel.indicators, "rowRepeater");
65+ verify(rowRepeater != undefined);
66+ return rowRepeater.itemAt(index);
6767 }
6868
6969 function get_indicator_item_position(index) {
70+ var indicatorRow = findChild(panel.indicators, "indicatorRow");
71+ verify(indicatorRow != undefined);
7072
71− var indicator_row = findChild(panel.indicators, "indicatorRow");
72− verify(indicator_row != undefined);
73−
74− var indicator_item = get_indicator_item(index);
75− verify(indicator_item != undefined);
73+ var indicatorItem = get_indicator_item(index);
74+ verify(indicatorItem != undefined);
7675
77− return panel.mapFromItem(indicator_item, indicator_item.width/2, indicator_item.height/2);
76+ return panel.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
7877 }
7978
8079 // Pressing on the indicator panel should activate the indicator hints
@@ -85,9 +84,9 @@ Item {
8584 // (switches between normal and fullscreen modes are animated)
8685 tryCompare(panel.indicators, "y", 0);
8786
88− var indicator_item_coord = get_indicator_item_position(0);
87+ var indicatorItemCoord = get_indicator_item_position(0);
8988
90− touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2);
89+ touchPress(panel, indicatorItemCoord.x, panel.panelHeight / 2);
9190
9291 // hint animation should be run, meaning that indicators will move downwards
9392 // by hintValue pixels without any drag taking place
@@ -96,7 +95,7 @@ Item {
9695 tryCompare(panel.indicators, "partiallyOpened", true);
9796 tryCompare(panel.indicators, "fullyOpened", false);
9897
99− touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2);
98+ touchRelease(panel, indicatorItemCoord.x, panel.panelHeight/2);
10099 }
101100
102101 // Pressing on the top edge of the screen should have no effect if the panel
@@ -107,9 +106,9 @@ Item {
107106 // (switches between normal and fullscreen modes are animated)
108107 tryCompare(panel.indicators, "y", -panel.panelHeight);
109108
110− var indicator_item_coord = get_indicator_item_position(0);
109+ var indicatorItemCoord = get_indicator_item_position(0);
111110
112− touchPress(panel, indicator_item_coord.x, panel.panelHeight / 2);
111+ touchPress(panel, indicatorItemCoord.x, panel.panelHeight / 2);
113112
114113 // Give some time for a hint animation to change things, if any
115114 wait(500);
@@ -126,7 +125,7 @@ Item {
126125 compare(panel.indicators.fullyOpened, false, "Indicator should not be partially" +
127126 " opened when panel is pressed in fullscreenmode");
128127
129− touchRelease(panel, indicator_item_coord.x, panel.panelHeight/2);
128+ touchRelease(panel, indicatorItemCoord.x, panel.panelHeight/2);
130129 }
131130
132131 function test_drag_show_data() { return get_window_data(); }
@@ -137,14 +136,14 @@ Item {
137136 function test_drag_show(data) {
138137 panel.fullscreenMode = data.fullscreenFlag;
139138
140− var indicator_row = findChild(panel.indicators, "indicatorRow");
141− verify(indicator_row != undefined);
139+ var indicatorRow = findChild(panel.indicators, "indicatorRow");
140+ verify(indicatorRow != undefined);
142141
143− var row_repeater = findChild(panel.indicators, "rowRepeater");
144− verify(indicator_row != undefined);
142+ var rowRepeater = findChild(panel.indicators, "rowRepeater");
143+ verify(indicatorRow != undefined);
145144
146− var menu_content = findChild(panel.indicators, "menuContent");
147− verify(indicator_row != undefined);
145+ var menuContent = findChild(panel.indicators, "menuContent");
146+ verify(indicatorRow != undefined);
148147
149148 // Wait for the indicators to get into position.
150149 // (switches between normal and fullscreen modes are animated)
@@ -155,20 +154,20 @@ Item {
155154 }
156155
157156 // do this for each indicator item
158− for (var i = 0; i < row_repeater.count; i++) {
157+ for (var i = 0; i < rowRepeater.count; i++) {
159158
160− var indicator_item = get_indicator_item(i);
161− verify(indicator_item != undefined);
159+ var indicatorItem = get_indicator_item(i);
160+ verify(indicatorItem != undefined);
162161
163− var indicator_item_coord = get_indicator_item_position(i);
162+ var indicatorItemCoord = get_indicator_item_position(i);
164163
165164 touchPress(panel,
166− indicator_item_coord.x, panel.panelHeight / 2);
165+ indicatorItemCoord.x, panel.panelHeight / 2);
167166
168167 // 1) Drag the mouse down
169168 touchFlick(panel,
170− indicator_item_coord.x, panel.panelHeight / 2,
171− indicator_item_coord.x, panel.height * 0.8,
169+ indicatorItemCoord.x, panel.panelHeight / 2,
170+ indicatorItemCoord.x, panel.height * 0.8,
172171 false /* beginTouch */, false /* endTouch */);
173172
174173 // Indicators height should follow the drag, and therefore increase accordingly.
@@ -177,13 +176,13 @@ Item {
177176 function() {return panel.indicators.height >= panel.height * 0.5},
178177 true);
179178
180− touchRelease(panel, indicator_item_coord.x, panel.height * 0.8);
179+ touchRelease(panel, indicatorItemCoord.x, panel.height * 0.8);
181180
182− compare(indicator_row.currentItem, indicator_item,
181+ compare(indicatorRow.currentItem, indicatorItem,
183182 "Incorrect item activated at position " + i);
184− compare(menu_content.currentIndex, i, "Menu conetent should be enabled for item at position " + i);
183+ compare(menuContent.currentMenuIndex, i, "Menu conetent should be enabled for item at position " + i);
185184
186− // init for next indicator_item
185+ // init for next indicatorItem
187186 init();
188187 }
189188 }
@@ -192,12 +191,12 @@ Item {
192191 panel.fullscreenMode = false;
193192 panel.searchVisible = true;
194193
195− var search_indicator = findChild(panel, "search");
196− verify(search_indicator != undefined);
194+ var searchIndicator = findChild(panel, "search");
195+ verify(searchIndicator != undefined);
197196
198− tap(search_indicator, 1, 1);
197+ tap(searchIndicator, 1, 1);
199198
200− compare(search_clicked, true,
199+ compare(searchClicked, true,
201200 "Tapping search indicator while it was enabled did not emit searchClicked signal");
202201 }
203202
@@ -205,13 +204,54 @@ Item {
205204 panel.fullscreenMode = false;
206205 panel.searchVisible = false;
207206
208− var search_indicator = findChild(panel, "search");
209− verify(search_indicator != undefined);
207+ var searchIndicator = findChild(panel, "search");
208+ verify(searchIndicator != undefined);
210209
211− tap(search_indicator, 1, 1);
210+ tap(searchIndicator, 1, 1);
212211
213− compare(search_clicked, false,
212+ compare(searchClicked, false,
214213 "Tapping search indicator while it was not visible emitted searchClicked signal");
215214 }
215+
216+ // Test the vertical velocity check when flicking the indicators open at an angle.
217+ // If the vertical velocity is above a specific point, we shouldnt change active indicators
218+ // if the x position changes
219+ function test_vertical_velocity_detector() {
220+ panel.fullscreenMode = false;
221+ panel.searchVisible = false;
222+
223+ var indicatorRow = findChild(panel.indicators, "indicatorRow");
224+ verify(indicatorRow != undefined);
225+
226+ var rowRepeater = findChild(panel.indicators, "rowRepeater");
227+ verify(indicatorRow != undefined);
228+
229+ // Get the first indicator
230+ var indicatorItemFirst = get_indicator_item(0);
231+ verify(indicatorItemFirst != undefined);
232+
233+ var indicatorItemCoordFirst = get_indicator_item_position(0);
234+ var indicatorItemCoordNext = get_indicator_item_position(indicatorRow.count - 1);
235+
236+ touchPress(panel,
237+ indicatorItemCoordFirst.x, panel.panelHeight / 2);
238+
239+ // 1) Drag the mouse down to hint a bit
240+ touchFlick(panel,
241+ indicatorItemCoordFirst.x, panel.panelHeight / 2,
242+ indicatorItemCoordFirst.x, panel.panelHeight * 2,
243+ false /* beginTouch */, false /* endTouch */);
244+
245+ tryCompare(indicatorRow, "currentItem", indicatorItemFirst)
246+
247+ // 1) Flick mouse down to bottom
248+ touchFlick(panel,
249+ indicatorItemCoordFirst.x, panel.panelHeight * 2,
250+ indicatorItemCoordNext.x, panel.height,
251+ false /* beginTouch */, true /* endTouch */,
252+ units.gu(10) /* speed */, 30 /* iterations */); // more samples needed for accurate velocity
253+
254+ compare(indicatorRow.currentItem, indicatorItemFirst, "First indicator should still be the current item");
255+ }
216256 }
217257}
tests/qmltests/Panel/tst_SearchIndicator.qml+8−10
@@ -41,24 +41,22 @@ Item {
4141 when: windowShown
4242
4343 function test_clickedSignal() {
44− clickedSpy.clear()
44+ clickedSpy.clear();
4545 mouseClick(searchIndicator,
4646 searchIndicator.width / 2, searchIndicator.height / 2);
47− compare(clickedSpy.count, 1)
47+ compare(clickedSpy.count, 1);
4848 }
4949
5050 function test_hideUp() {
51− var container = findChild(searchIndicator, "container")
52− searchIndicator.state = "hiddenUp"
53− tryCompare(container, "opacity", 0)
54− tryCompare(container, "y", -container.height)
51+ var container = findChild(searchIndicator, "container");
52+ searchIndicator.state = "hidden";
53+ tryCompare(container, "opacity", 0);
5554 }
5655
5756 function test_show() {
58− var container = findChild(searchIndicator, "container")
59− searchIndicator.state = "visible"
60− tryCompare(container, "opacity", 1)
61− tryCompare(container, "y", 0)
57+ var container = findChild(searchIndicator, "container");
58+ searchIndicator.state = "visible";
59+ tryCompare(container, "opacity", 1);
6260 }
6361 }
6462}
tests/qmltests/tst_Shell.qmlnew file+281
@@ -0,0 +1,281 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Daniel d'Andrada <daniel.dandrada@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+import QtQuick 2.0
21+import QtTest 1.0
22+import Ubuntu.Application 0.1
23+import Unity.Test 0.1 as UT
24+
25+import "../.."
26+
27+Item {
28+ width: shell.width
29+ height: shell.height
30+
31+ QtObject {
32+ id: applicationArguments
33+
34+ function hasGeometry() {
35+ return false;
36+ }
37+
38+ function width() {
39+ return 0;
40+ }
41+
42+ function height() {
43+ return 0;
44+ }
45+ }
46+
47+ Shell {
48+ id: shell
49+ }
50+
51+ UT.UnityTestCase {
52+ name: "Shell"
53+ when: windowShown
54+
55+ function initTestCase() {
56+ // swipe away the greeter/lockscreen
57+ var touchX = shell.width - (shell.edgeSize / 2);
58+ var touchY = shell.height / 2;
59+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY);
60+
61+ var dash = findChild(shell, "dash");
62+ // wait until the animation has finished
63+ tryCompare(dash, "contentScale", 1.0);
64+ tryCompare(dash, "opacity", 1.0);
65+ }
66+
67+ function cleanup() {
68+ // kill all (fake) running apps
69+ ApplicationManager.mainStageApplications.clear();
70+ ApplicationManager.sideStageApplications.clear();
71+
72+ var dashHome = findChild(shell, "DashHome");
73+ swipeUntilScopeViewIsReached(dashHome);
74+ }
75+
76+ /*
77+ Test the effect of a right-edge drag on the dash in 3 situations:
78+ 1 - when no application has been launched yet
79+ 2 - when there's a minimized application
80+ 3 - after the last running application has been closed/stopped
81+
82+ The behavior of Dash on 3 should be the same as on 1.
83+ */
84+ function test_rightEdgeDrag() {
85+ checkRightEdgeDragWithNoRunningApps();
86+
87+ dragLauncherIntoView();
88+
89+ // Launch an app from the launcher
90+ tapOnAppIconInLauncher();
91+ waitUntilApplicationWindowIsFullyVisible();
92+
93+ // Minimize the application we just launched
94+ swipeFromLeftEdge();
95+
96+ waitForUIToSettle();
97+
98+ checkRightEdgeDragWithMinimizedApp();
99+
100+ // Minimize that application once again
101+ swipeFromLeftEdge();
102+
103+ // kill it
104+ ApplicationManager.mainStageApplications.clear();
105+
106+ waitForUIToSettle();
107+
108+ // Right edge behavior should now be the same as before that app was launched
109+ checkRightEdgeDragWithNoRunningApps();
110+ }
111+
112+ /*
113+ Perform a right-edge drag when the Dash is being show and there are
114+ no running/minimized apps to be restored.
115+
116+ The expected behavior is that an animation should be played to hint the
117+ user that his right-edge drag gesture has been successfully recognized
118+ but there is no application to be brought to foreground.
119+ */
120+ function checkRightEdgeDragWithNoRunningApps() {
121+ var touchX = shell.width - (shell.edgeSize / 2);
122+ var touchY = shell.height / 2;
123+
124+ var dash = findChild(shell, "dash");
125+ // check that dash has normal scale and opacity
126+ compare(dash.contentScale, 1.0);
127+ compare(dash.opacity, 1.0);
128+
129+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
130+ true /* beginTouch */, false /* endTouch */);
131+
132+ // check that Dash has been scaled down and had its opacity reduced
133+ tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
134+ tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
135+
136+ touchRelease(shell, shell.width * 0.1, touchY);
137+
138+ // and now everything should have gone back to normal
139+ tryCompare(dash, "contentScale", 1.0);
140+ tryCompare(dash, "opacity", 1.0);
141+ }
142+
143+ /*
144+ Perform a right-edge drag when the Dash is being show and there is
145+ a running/minimized app to be restored.
146+
147+ The expected behavior is that the dash should fade away and ultimately be
148+ made invisible once the gesture is finished as the restored app will now
149+ be on foreground.
150+ */
151+ function checkRightEdgeDragWithMinimizedApp() {
152+ var touchX = shell.width - (shell.edgeSize / 2);
153+ var touchY = shell.height / 2;
154+
155+ var dash = findChild(shell, "dash");
156+ // check that dash has normal scale and opacity
157+ tryCompare(dash, "contentScale", 1.0);
158+ tryCompare(dash, "opacity", 1.0);
159+
160+ touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
161+ true /* beginTouch */, false /* endTouch */);
162+
163+ // check that Dash has been scaled down and had its opacity reduced
164+ tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true);
165+ tryCompareFunction(function() { return dash.opacity <= 0.5; }, true);
166+
167+ touchRelease(shell, shell.width * 0.1, touchY);
168+
169+ // dash should have gone away, now that the app is on foreground
170+ tryCompare(dash, "visible", false);
171+ }
172+
173+ // Wait for the whole UI to settle down
174+ function waitForUIToSettle() {
175+ waitUntilApplicationWindowIsFullyHidden();
176+ var dashContentList = findChild(shell, "dashContentList");
177+ tryCompare(dashContentList, "moving", false);
178+ }
179+
180+ function dragLauncherIntoView() {
181+ var launcherPanel = findChild(shell, "launcherPanel");
182+ verify(launcherPanel.x = - launcherPanel.width);
183+ swipeFromLeftEdge();
184+ tryCompare(launcherPanel, "x", 0);
185+ }
186+
187+ function tapOnAppIconInLauncher() {
188+ var launcherPanel = findChild(shell, "launcherPanel");
189+
190+ // pick the first icon, the one at the bottom.
191+ var appIcon = findChild(launcherPanel, "launcherDelegate0")
192+
193+ // Swipe upwards over the launcher to ensure that this icon
194+ // at the bottom is not folded and faded away.
195+ var touchStartX = launcherPanel.width / 2;
196+ var touchStartY = launcherPanel.height / 2;
197+ touchFlick(launcherPanel, touchStartX, touchStartY, touchStartX, 0);
198+ tryCompare(launcherPanel, "moving", false);
199+
200+ // NB tapping (i.e., using touch events) doesn't activate the icon... go figure...
201+ mouseClick(appIcon, appIcon.width / 2, appIcon.height / 2);
202+ }
203+
204+ function waitUntilApplicationWindowIsFullyVisible() {
205+ var underlay = findChild(shell, "underlay");
206+ tryCompare(underlay, "visible", false);
207+ }
208+
209+ function waitUntilApplicationWindowIsFullyHidden() {
210+ var stages = findChild(shell, "stages");
211+ tryCompare(stages, "fullyHidden", true);
212+ }
213+
214+ function swipeUntilScopeViewIsReached(scopeView) {
215+ while (!itemIsOnScreen(scopeView)) {
216+ if (itemIsToLeftOfScreen(scopeView)) {
217+ swipeRightFromCenter();
218+ } else {
219+ swipeLeftFromCenter();
220+ }
221+ waitUntilItemStopsMoving(scopeView);
222+ }
223+ }
224+
225+ function swipeFromLeftEdge() {
226+ var touchStartX = 2;
227+ var touchStartY = shell.height / 2;
228+ touchFlick(shell, touchStartX, touchStartY, shell.width * 0.75, touchStartY);
229+ }
230+
231+ function swipeLeftFromCenter() {
232+ var touchStartX = shell.width / 2;
233+ var touchStartY = shell.height / 2;
234+ touchFlick(shell, touchStartX, touchStartY, 0, touchStartY);
235+ }
236+
237+ function swipeRightFromCenter() {
238+ var touchStartX = shell.width / 2;
239+ var touchStartY = shell.height / 2;
240+ touchFlick(shell, touchStartX, touchStartY, shell.width, touchStartY);
241+ }
242+
243+ function swipeUpFromCenter() {
244+ var touchStartX = shell.width / 2;
245+ var touchStartY = shell.height / 2;
246+ touchFlick(shell, touchStartX, touchStartY, touchStartX, 0);
247+ }
248+
249+ function itemIsOnScreen(item) {
250+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
251+
252+ return itemRectInShell.x >= 0
253+ && itemRectInShell.y >= 0
254+ && itemRectInShell.x + itemRectInShell.width <= shell.width
255+ && itemRectInShell.y + itemRectInShell.height <= shell.height;
256+ }
257+
258+ function itemIsToLeftOfScreen(item) {
259+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
260+ return itemRectInShell.x < 0;
261+ }
262+
263+ function waitUntilItemStopsMoving(item) {
264+ var itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
265+ var previousX = itemRectInShell.x;
266+ var previousY = itemRectInShell.y;
267+ var isStill = false;
268+
269+ do {
270+ wait(100);
271+ itemRectInShell = item.mapToItem(shell, 0, 0, item.width, item.height);
272+ if (itemRectInShell.x == previousX && itemRectInShell.y == previousY) {
273+ isStill = true;
274+ } else {
275+ previousX = itemRectInShell.x;
276+ previousY = itemRectInShell.y;
277+ }
278+ } while (!isStill);
279+ }
280+ }
281+}
tests/utils/modules/Unity/Test/UnityTestCase.qml+32−23
@@ -32,32 +32,34 @@ TestCase {
3232 // Qt uses in QQuickViewTestUtil::flick
3333 // speed is in pixels/second
3434 function mouseFlick(item, x, y, toX, toY, pressMouse, releaseMouse,
35− speed) {
35+ speed, iterations) {
3636 pressMouse = ((pressMouse != null) ? pressMouse : true); // Default to true for pressMouse if not present
3737 releaseMouse = ((releaseMouse != null) ? releaseMouse : true); // Default to true for releaseMouse if not present
3838
3939 // set a default speed if not specified
4040 speed = (speed != null) ? speed : units.gu(10);
4141
42+ // set a default iterations if not specified
43+ iterations = (iterations !== undefined) ? iterations : 5
44+
4245 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
4346 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
4447
45− var nIterations = 5
46− var timeStep = totalTime / nIterations
47− var diffX = (toX - x) / nIterations
48− var diffY = (toY - y) / nIterations
48+ var timeStep = totalTime / iterations
49+ var diffX = (toX - x) / iterations
50+ var diffY = (toY - y) / iterations
4951 if (pressMouse) {
5052 fakeDateTime.currentTimeMs += timeStep
5153 mousePress(item, x, y)
5254 }
53− for (var i = 0; i < nIterations; ++i) {
55+ for (var i = 0; i < iterations; ++i) {
5456 fakeDateTime.currentTimeMs += timeStep
55− if (i === nIterations - 1) {
57+ if (i === iterations - 1) {
5658 // Avoid any rounding errors by making the last move be at precisely
5759 // the point specified
58− mouseMove(item, toX, toY, nIterations / speed)
60+ mouseMove(item, toX, toY, iterations / speed)
5961 } else {
60− mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, nIterations / speed)
62+ mouseMove(item, x + (i + 1) * diffX, y + (i + 1) * diffY, iterations / speed)
6163 }
6264 }
6365 if (releaseMouse) {
@@ -70,11 +72,16 @@ TestCase {
7072 // Find an object with the given name recursively, starting
7173 // at the given object "obj"
7274 function findChild(obj,objectName) {
73− for (var i in obj.children) {
74− var child = obj.children[i];
75− if (child.objectName === objectName) return child;
76− var subChild = findChild(child,objectName);
77− if (subChild !== undefined) return subChild;
75+ var childs = new Array(0);
76+ childs.push(obj)
77+ while (childs.length > 0) {
78+ if (childs[0].objectName == objectName) {
79+ return childs[0]
80+ }
81+ for (var i in childs[0].data) {
82+ childs.push(childs[0].data[i])
83+ }
84+ childs.splice(0, 1);
7885 }
7986 return undefined;
8087 }
@@ -186,7 +193,7 @@ TestCase {
186193 }
187194
188195 // speed is in pixels/second
189− function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed) {
196+ function touchFlick(item, x, y, toX, toY, beginTouch, endTouch, speed, iterations) {
190197
191198 // Default to true for beginTouch if not present
192199 beginTouch = (beginTouch !== undefined) ? beginTouch : true
@@ -197,13 +204,15 @@ TestCase {
197204 // Set a default speed if not specified
198205 speed = (speed !== undefined) ? speed : units.gu(10)
199206
207+ // Set a default iterations if not specified
208+ var iterations = (iterations !== undefined) ? iterations : 5
209+
200210 var distance = Math.sqrt(Math.pow(toX - x, 2) + Math.pow(toY - y, 2))
201211 var totalTime = (distance / speed) * 1000 /* converting speed to pixels/ms */
202212
203− var nIterations = 5
204− var timeStep = totalTime / nIterations
205− var diffX = (toX - x) / nIterations
206− var diffY = (toY - y) / nIterations
213+ var timeStep = totalTime / iterations
214+ var diffX = (toX - x) / iterations
215+ var diffY = (toY - y) / iterations
207216 if (beginTouch) {
208217 fakeDateTime.currentTimeMs += timeStep
209218
@@ -211,17 +220,17 @@ TestCase {
211220 event.press(0 /* touchId */, x, y)
212221 event.commit()
213222 }
214− for (var i = 0; i < nIterations; ++i) {
223+ for (var i = 0; i < iterations; ++i) {
215224 fakeDateTime.currentTimeMs += timeStep
216− if (i === nIterations - 1) {
225+ if (i === iterations - 1) {
217226 // Avoid any rounding errors by making the last move be at precisely
218227 // the point specified
219− wait(nIterations / speed)
228+ wait(iterations / speed)
220229 var event = touchEvent()
221230 event.move(0 /* touchId */, toX, toY)
222231 event.commit()
223232 } else {
224− wait(nIterations / speed)
233+ wait(iterations / speed)
225234 var event = touchEvent()
226235 event.move(0 /* touchId */, x + (i + 1) * diffX, y + (i + 1) * diffY)
227236 event.commit()