on xenial help sign in
Merged trunk.
commit925013ed7fa2f8f76f0bdee4eec31f77492aa5c2 authorPawel Stolowski <pawel.stolowski@canonical.com> dateFri 5 Jul 2013, 12:38 (13 years ago) parent543a6da584cf05
307 files changed+11488−4318
.bazaar/plugins/makecheck_unity_phablet.py+15−6 .bzrignore+1 Bottombar/Bottombar.qml+41−82 Bottombar/HudButton.qml+3−2 Bottombar/graphics/hud_invoke_button_active@20.png CMakeLists.txt+1 CODING+75−29 COPYING.LGPL+514 Components/Carousel.qml+2 Components/DragHandle.qml+212 Components/EdgeDragArea.qml+36 Components/EdgeDragEvaluator.qml+88 Components/FilterGrid.qml+1−1 Components/IconUtil.js+5−5 Components/ListItems/Base.qml+19−21 Components/ListItems/Header.qml−6 Components/ListItems/ThinDivider.qml−4 Components/ListViewWithPageHeader.qml−189 Components/PageHeader.qml+2−4 Components/Stage.qml+8−10 Components/Tile.qml+1−1 Components/UbuntuShapeForItem.qml+12−56 Components/WrongPasswordAnimation.qml+3−3 Components/graphics/icon_star_off@20.png Components/graphics/icon_star_on@20.png Components/graphics/non-selected@18.png Dash/Apps/ApplicationsFilterGrid.qml+3−2 Dash/Apps/RunningApplicationTile.qml+1−1 Dash/Apps/graphics/close_btn@9.png Dash/DashApps.qml+2−3 Dash/DashHome.qml+1−2 Dash/DashMusic.qml+1−2 Dash/DashVideos.qml+2−3 Dash/GenericScopeView.qml+1−1 Dash/Music/AlbumTile.qml+1−1 tests/qmltests/plugins/Dee/DeeVariantText.qml → Dash/ScopeListView.qml+4−3 Dash/graphics/icon_clear@20.png Dash/graphics/icon_listview_clear@20.png Dash/graphics/icon_search_active@20.png Dash/graphics/icon_search_inactive@20.png Dash/graphics/phone/home.png Dash/graphics/phone/music.png Dash/graphics/phone/screenshots/angrybirds@12.png Dash/graphics/phone/screenshots/browser@12.png Dash/graphics/phone/screenshots/camera@12.png Dash/graphics/phone/screenshots/facebook@12.png Dash/graphics/phone/screenshots/gallery@12.png Dash/graphics/phone/screenshots/map@12.png Dash/graphics/phone/screenshots/music@12.png Dash/graphics/phone/screenshots/phone@12.png Dash/graphics/phone/screenshots/settings@12.png Dash/graphics/phone/screenshots/twitter@12.png Dash/graphics/phone/videos.png Dash/graphics/play_button@18.png Dash/graphics/play_button_active@18.png Dash/graphics/play_button_active_big@20.png Dash/graphics/play_button_big@20.png Dash/graphics/tablet/apps.png Dash/graphics/tablet/home.png Dash/graphics/tablet/icon_close_preview@20.png Dash/graphics/tablet/music.png Dash/graphics/tablet/people.png Dash/graphics/tablet/videos.png Greeter/Greeter.qml+28−2 Greeter/GreeterContent.qml+4−1 Greeter/Lockscreen.qml+7−1 Greeter/LoginList.qml−8 Greeter/graphics/dot_empty.png Greeter/graphics/dot_filled.png Greeter/graphics/dot_pointer.png Greeter/graphics/infographic_circle.png Hud/SearchBar.qml−7 Hud/ToolBarIcon.qml+1−3 Hud/graphics/hud_bg@20.png Hud/graphics/hud_handlearrow@20.png Hud/graphics/hud_handlebar@20.png Hud/graphics/icon_clear@20.png Hud/graphics/icon_search@20.png LGPL_EXCEPTION.txt+22 Launcher/Launcher.qml+9−17 Launcher/LauncherDelegate.qml+202−39 Launcher/LauncherPanel.qml+106−52 Launcher/graphics/highlight@18.png Launcher/graphics/home@18.png Launcher/graphics/non-selected@18.png Launcher/graphics/selected@18.png Launcher/graphics/triangle@18.png Notifications/Notification.qml+109−12 Notifications/Notifications.qml+10−13 Panel/Indicators.qml+111−27 Panel/MenuContent.qml+1−1 Panel/Panel.qml+3−74 Panel/graphics/Battery@18.png Panel/graphics/Bluetooth@18.png Panel/graphics/Clock@18.png Panel/graphics/Location@18.png Panel/graphics/Messages@18.png Panel/graphics/Network@18.png Panel/graphics/Sound@18.png Panel/graphics/Sync@18.png Panel/graphics/System@18.png Panel/graphics/Time@18.png Panel/graphics/VerticalDivider@18.png Panel/graphics/rectangular_dropshadow@30.png Panel/graphics/search@12.png Shell.qml+46−41 build+18−8 build_unity−158 debian/changelog+122 debian/control+48−48 debian/copyright+13−3 debian/rules+23−2 debian/scopes-recommends-generator+27 debian/unity8-autopilot.install+1−1 debian/unity8-fake-env.install+1−1 debian/unity8-private.install+6 debian/unity8.install+15−20 graphics/12_10_background_wide@12.png graphics/applicationIcons/angrybirds@18.png graphics/applicationIcons/camera@18.png graphics/applicationIcons/dash@18.png graphics/applicationIcons/evernote@18.png graphics/applicationIcons/gallery@18.png graphics/applicationIcons/map@18.png graphics/applicationIcons/music@18.png graphics/applicationIcons/phone-app@18.png graphics/applicationIcons/pinterest@18.png graphics/applicationIcons/ski_safari@18.png graphics/applicationIcons/skype@18.png graphics/applicationIcons/twitter@18.png graphics/applicationIcons/youtube@18.png graphics/avatars/amanda@12.png graphics/avatars/anna_olsson@12.png graphics/avatars/funky@12.png graphics/clock@18.png main.cpp+26−7 paths.h.in+16−8 plugins/CMakeLists.txt+1 plugins/HudClient/CMakeLists.txt+2−2 plugins/LightDM/CMakeLists.txt+6−3 plugins/LightDM/Greeter.cpp+6−6 plugins/LightDM/Greeter.h+4−4 plugins/LightDM/plugin.cpp+5−4 plugins/ListViewWithPageHeader/CMakeLists.txt+44 plugins/ListViewWithPageHeader/listviewwithpageheader.cpp+1062 plugins/ListViewWithPageHeader/listviewwithpageheader.h+180 plugins/ListViewWithPageHeader/plugin.cpp+29 plugins/ListViewWithPageHeader/plugin.h+33 plugins/ListViewWithPageHeader/qmldir+2 plugins/Ubuntu/Gestures/AxisVelocityCalculator.cpp+31−16 plugins/Ubuntu/Gestures/AxisVelocityCalculator.h+31−20 plugins/Ubuntu/Gestures/CMakeLists.txt+2−2 plugins/Ubuntu/Gestures/Direction.cpp+5 plugins/Ubuntu/Gestures/Direction.h+1 plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+61−10 plugins/Ubuntu/Gestures/DirectionalDragArea.h+23−5 plugins/Unity/CMakeLists.txt+10−2 plugins/Unity/applicationpreview.cpp+96 plugins/Unity/applicationpreview.h+66 plugins/Unity/categories.cpp+26−17 plugins/Unity/categories.h+1 Notifications/timings.js → plugins/Unity/genericpreview.cpp+9−6 plugins/Unity/genericpreview.h+40 plugins/Unity/moviepreview.cpp+67 plugins/Unity/moviepreview.h+60 plugins/Unity/musicpreview.cpp+54 plugins/Unity/musicpreview.h+62 plugins/Unity/plugin.cpp+6 plugins/Unity/preview.cpp+173 plugins/Unity/preview.h+80 plugins/Unity/previewaction.cpp+75 plugins/Unity/previewaction.h+71 plugins/Unity/previewinfohint.cpp+67 plugins/Unity/previewinfohint.h+58 plugins/Unity/scope.cpp+79−11 plugins/Unity/scope.h+20−3 plugins/Unity/variantutils.cpp+158 plugins/Unity/variantutils.h+34 plugins/Utils/CMakeLists.txt+2−2 plugins/Utils/qlimitproxymodelqml.cpp+4−4 po/ar.po+40−48 po/az.po+18−44 po/bg.po+24−44 po/ca.po+24−44 po/de.po+42−50 po/el.po+18−44 po/en_AU.po+36−44 po/en_GB.po+41−49 po/eo.po+12−44 po/es.po+36−44 po/fi.po+33−44 po/fo.po+18−44 po/fr.po+71−82 po/gl.po+24−44 po/he.po+18−44 po/hr.po+18−44 po/hu.po+18−44 po/hy.po+24−44 po/id.po+12−44 po/it.po+18−44 po/ja.po+12−44 po/kn.po+18−44 po/ko.po+12−44 po/ky.po+18−44 po/lv.po+18−44 po/my.po+15−44 po/nb.po+18−44 po/nl.po+18−44 po/pl.po+36−44 po/pt_BR.po+18−44 po/ro.po+18−44 po/ru.po+35−52 po/si.po+12−44 po/sl.po+43−69 po/sr.po+18−44 po/sv.po+12−44 po/te.po+12−44 po/th.po+220 po/tr.po+59−70 po/ug.po+59−70 po/uk.po+42−50 po/unity8.pot+4−9 po/zh_CN.po+41−49 po/zh_TW.po+24−44 run+3−4 run_on_device+26−9 tests/autopilot/setup.py+21 tests/autopilot/unity8/tests/__init__.py+6−4 tests/autopilot/unity8/tests/helpers.py+2−1 tests/mocks/CMakeLists.txt+3 tests/qmltests/plugins/HudClient/CMakeLists.txt → tests/mocks/HudClient/CMakeLists.txt tests/qmltests/plugins/HudClient/fake_hud_plugin.cpp → tests/mocks/HudClient/fake_hud_plugin.cpp tests/qmltests/plugins/HudClient/fake_hud_plugin.h → tests/mocks/HudClient/fake_hud_plugin.h tests/qmltests/plugins/HudClient/fake_libhud_client.cpp → tests/mocks/HudClient/fake_libhud_client.cpp tests/qmltests/plugins/HudClient/libhud_client_stub.cpp → tests/mocks/HudClient/libhud_client_stub.cpp tests/qmltests/plugins/HudClient/libhud_client_stub.h → tests/mocks/HudClient/libhud_client_stub.h tests/qmltests/plugins/HudClient/qmldir → tests/mocks/HudClient/qmldir tests/mocks/LightDM/CMakeLists.txt+5−2 tests/mocks/LightDM/InfographicModel.cpp−416 tests/mocks/LightDM/InfographicModelPrivate.h−99 tests/mocks/LightDM/demo/CMakeLists.txt+11−2 tests/mocks/LightDM/demo/UsersModelPrivate.cpp+1−1 tests/mocks/LightDM/full/CMakeLists.txt+1−3 tests/mocks/LightDM/single-passphrase/CMakeLists.txt+1−3 tests/mocks/LightDM/single-passphrase/UsersModelPrivate.cpp+1−1 tests/mocks/LightDM/single-pin/CMakeLists.txt+1−3 tests/mocks/LightDM/single-pin/UsersModelPrivate.cpp+1−1 tests/mocks/LightDM/single/CMakeLists.txt+1−3 tests/mocks/LightDM/single/UsersModelPrivate.cpp+1−1 tests/mocks/Ubuntu/Application/CMakeLists.txt+2−2 tests/mocks/Ubuntu/CMakeLists.txt+1 tests/qmltests/plugins/Ubuntu/ChewieUI/CMakeLists.txt → tests/mocks/Ubuntu/ChewieUI/CMakeLists.txt tests/qmltests/plugins/Ubuntu/ChewieUI/fake_chewie_plugin.cpp → tests/mocks/Ubuntu/ChewieUI/fake_chewie_plugin.cpp tests/qmltests/plugins/Ubuntu/ChewieUI/fake_chewie_plugin.h → tests/mocks/Ubuntu/ChewieUI/fake_chewie_plugin.h tests/qmltests/plugins/Ubuntu/ChewieUI/fake_pluginmodel.cpp → tests/mocks/Ubuntu/ChewieUI/fake_pluginmodel.cpp tests/qmltests/plugins/Ubuntu/ChewieUI/fake_pluginmodel.h → tests/mocks/Ubuntu/ChewieUI/fake_pluginmodel.h tests/qmltests/plugins/Ubuntu/ChewieUI/qmldir → tests/mocks/Ubuntu/ChewieUI/qmldir tests/qmltests/plugins/Unity/CMakeLists.txt → tests/mocks/Unity/CMakeLists.txt tests/qmltests/plugins/Unity/Notifications/notification.js → tests/mocks/Unity/Notifications/notification.js tests/qmltests/plugins/Unity/Notifications/qmldir → tests/mocks/Unity/Notifications/qmldir tests/qmltests/plugins/Unity/fake_launchermodel.cpp → tests/mocks/Unity/fake_launchermodel.cpp tests/qmltests/plugins/Unity/fake_launchermodel.h → tests/mocks/Unity/fake_launchermodel.h tests/qmltests/plugins/Unity/fake_scope.cpp → tests/mocks/Unity/fake_scope.cpp tests/qmltests/plugins/Unity/fake_scope.h → tests/mocks/Unity/fake_scope.h tests/qmltests/plugins/Unity/fake_scopes.cpp → tests/mocks/Unity/fake_scopes.cpp tests/qmltests/plugins/Unity/fake_scopes.h → tests/mocks/Unity/fake_scopes.h tests/qmltests/plugins/Unity/fake_unity_plugin.cpp → tests/mocks/Unity/fake_unity_plugin.cpp tests/qmltests/plugins/Unity/fake_unity_plugin.h → tests/mocks/Unity/fake_unity_plugin.h tests/qmltests/plugins/Unity/qmldir → tests/mocks/Unity/qmldir tests/mocks/libusermetrics/CMakeLists.txt+17 tests/mocks/libusermetrics/ColorTheme.cpp+128 tests/mocks/libusermetrics/ColorTheme.h+68 tests/mocks/libusermetrics/UserMetrics.cpp+465 tests/mocks/LightDM/InfographicModel.h → tests/mocks/libusermetrics/UserMetrics.h+22−60 tests/mocks/libusermetrics/libusermetricsoutput/ColorTheme.h+1 tests/mocks/libusermetrics/libusermetricsoutput/UserMetrics.h+1 tests/plugins/CMakeLists.txt+2 tests/plugins/ListViewWithPageHeader/CMakeLists.txt+31 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cpp+1317 tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cpp+1567 tests/plugins/ListViewWithPageHeader/test.qml+96 tests/plugins/ListViewWithPageHeader/test_section.qml+106 tests/plugins/Ubuntu/Gestures/tst_AxisVelocityCalculator.cpp+40−28 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+99−11 tests/plugins/Unity/CMakeLists.txt+38 tests/plugins/Unity/previewbindingstest.cpp+114 plugins/LightDM/InfographicModel.h → tests/plugins/Unity/previewbindingstest.h+15−8 tests/plugins/Utils/qlimitproxymodeltest.cpp+15 tests/qmltests/CMakeLists.txt+15−15 tests/qmltests/Components/CMakeLists.txt+23 tests/qmltests/Components/tst_DragHandle.cpp+395 tests/qmltests/Components/tst_DragHandle.qml+146 tests/qmltests/Components/tst_DragHandle/HorizontalShowable.qml+100 tests/qmltests/Components/tst_DragHandle/TestButton.qml+41 tests/qmltests/Components/tst_DragHandle/UnityLogo.png tests/qmltests/Components/tst_DragHandle/VerticalShowable.qml+100 tests/qmltests/Components/tst_ListViewWithPageHeader.qml−351 tests/qmltests/Components/tst_Stage.qml+1−2 tests/qmltests/Greeter/tst_Lockscreen.qml+7−1 tests/qmltests/Greeter/tst_Phone.qml+40−1 tests/qmltests/Launcher/tst_Launcher.qml+40 tests/qmltests/Notifications/tst_Notifications.qml+48−7 tests/qmltests/Panel/tst_Indicators.qml+34−45 tests/qmltests/Panel/tst_Panel.qml+65−113 tests/qmltests/plugins/CMakeLists.txt−3 tests/qmltests/plugins/Dee/qmldir−3 tests/qmltests/plugins/Ubuntu/CMakeLists.txt−1
.bazaar/plugins/makecheck_unity_phablet.py+15−6
@@ -23,12 +23,21 @@ def execute_makecheck(local_branch, master_branch, old_revision_number, old_revi
2323
2424 os.chdir(local_path_from_url(master_branch.base))
2525
26− print "Executing 'make check'.."
27− if (subprocess.call("make check", shell=True) != 0):
28− raise errors.BzrError("Unit tests failed, fix them before committing!")
26+ print "Executing 'make -C builddir test'.."
27+ os.environ['CTEST_OUTPUT_ON_FAILURE'] = "1"
28+ if (subprocess.call("make -C builddir test", shell=True) != 0):
2929
30− print "Executing 'make qmluitests'.."
31− if (subprocess.call("make qmluitests", shell=True) != 0):
32− raise errors.BzrError("QML UI tests failed, fix them before committing!")
30+ print("\n\n*** Warning ***\n\nBasic tests failed. This commit will not pass continuous integration.")
31+
32+ branch = local_branch or master_branch
33+ revision = branch.repository.get_revision(future_revision_id)
34+ msg_file = open('message.txt', 'w')
35+ msg_file.write(revision.message)
36+ msg_file.close()
37+
38+ print("\n\nSaved commit message to $SRC_DIR/message.txt.")
39+ print("You can uncommit this revision, fix the tests and reuse your message running:\n\nbzr commit -F message.txt\n\n")
40+ elif os.path.isfile("message.txt"):
41+ os.remove("message.txt")
3342
3443branch.Branch.hooks.install_named_hook('pre_commit', execute_makecheck, 'make check pre-commit')
.bzrignore+1
@@ -7,3 +7,4 @@
77/.cproject
88/.settings
99/.pydevproject
10+message.txt
Bottombar/Bottombar.qml+41−82
@@ -18,38 +18,42 @@ import QtQuick 2.0
1818import "../Components"
1919import "../Components/Math.js" as MathLocal
2020import Unity 0.1
21+import Ubuntu.Gestures 0.1
2122
2223Item {
2324 id: bottombar
24− width: shell.width
25− height: shell.height
25+
26+ // Whether there's an application on foreground (as opposed to have shell's Dash on foreground)
27+ property bool applicationIsOnForeground
2628
2729 property variant theHud
2830 property bool enabled: false
2931 readonly property real bottomEdgeButtonCenterDistance: units.gu(34)
30− readonly property real bottomEdgeShowButtonDistance: units.gu(2)
31−
32− property bool __applicationInFocus: false
3332
34− state: "hidden"
33+ state: dragArea.status === DirectionalDragArea.Recognized ? "shown" : "hidden"
3534
3635 HudButton {
3736 id: hudButton
3837
39− x: MathLocal.clamp(hudButtonRevealer.pressedX - width / 2, 0, bottombar.width - width)
40− y: bottombar.height - bottomEdgeButtonCenterDistance - height / 2 - bottomMargin
41− Behavior on bottomMargin {
42− NumberAnimation{duration: hudButton.opacity < 0.01 ? 200 : 70; easing.type: Easing.OutQuart}
43− }
44− mouse: {
45− if (hudButtonRevealer.draggingArea.pressed) {
46− var mapped = mapFromItem(hudButtonRevealer.draggingArea, hudButtonRevealer.draggingArea.mouseX, hudButtonRevealer.draggingArea.mouseY)
47− return Qt.point(mapped.x, mapped.y)
38+ x: MathLocal.clamp(dragArea.touchStartX - (width / 2), 0, bottombar.width - width)
39+ y: bottombar.height - bottomEdgeButtonCenterDistance - (height / 2) - bottomMargin
40+
41+ mouseOver: {
42+ if (dragArea.status === DirectionalDragArea.Recognized) {
43+ var touchLocal = mapFromItem(dragArea, dragArea.touchX, dragArea.touchY)
44+ return touchLocal.x > 0 && touchLocal.x < width
45+ && touchLocal.y > 0 && touchLocal.y < height
4846 } else {
49− return mouse
47+ return false
5048 }
5149 }
5250
51+ onClicked: theHud.show()
52+
53+ Behavior on bottomMargin {
54+ NumberAnimation{duration: hudButton.opacity < 0.01 ? 200 : 70; easing.type: Easing.OutQuart}
55+ }
56+
5357 Behavior on opacity {
5458 NumberAnimation{ duration: 200; easing.type: Easing.OutCubic}
5559 }
@@ -60,74 +64,29 @@ Item {
6064 onShownChanged: bottomBarVisibilityCommunicatorShell.forceHidden = theHud.shown
6165 }
6266
63− function updateApplicationInFocus() {
64− if (shell.applicationManager.mainStageFocusedApplication || shell.applicationManager.sideStageFocusedApplication) {
65− __applicationInFocus = true
66− } else {
67− __applicationInFocus = false
68− }
69− }
70−
71− Connections {
72− target: shell.applicationManager
73− ignoreUnknownSignals: true
74− onMainStageFocusedApplicationChanged: updateApplicationInFocus()
75− onSideStageFocusedApplicationChanged: updateApplicationInFocus()
76− }
77−
78− Showable {
79− id: hudButtonShowable
80−
81− opacity: 1.0
67+ EdgeDragArea {
68+ id: dragArea
8269 width: parent.width
83− height: bottomEdgeShowButtonDistance
84− shown: false
85− showAnimation: StandardAnimation { property: "y"; duration: 350; to: hudButtonRevealer.openedValue; easing.type: Easing.OutCubic }
86− hideAnimation: StandardAnimation { property: "y"; duration: 350; to: hudButtonRevealer.closedValue; easing.type: Easing.OutCubic }
87− onYChanged: {
88− if (y == hudButtonRevealer.openedValue)
89− bottombar.state = "shown"
90− }
91−
92− // eater
93− MouseArea {
94− anchors.fill: parent
95− }
96− }
97−
98− Revealer {
99− id: hudButtonRevealer
100−
101− property double pressedX
102−
103− enabled: !theHud.shown && bottombar.enabled && __applicationInFocus
104− direction: Qt.RightToLeft
105− openedValue: bottombar.height - height
106− closedValue: bottombar.height
107− target: hudButtonShowable
108− width: hudButtonShowable.width
109− height: hudButtonShowable.height
110− anchors.bottom: bottombar.bottom
111− onOpenPressed: {
112− pressedX = mouseX
113− }
114−
115− onOpenReleased: {
116− if (hudButton.opacity != 0 && hudButton.mouseOver) {
117− hudButtonShowable.hide()
118− theHud.show()
119− } else {
120− hudButtonShowable.hide()
121− }
122− }
123− }
124−
125− Connections {
126− target: hudButtonShowable.hideAnimation
127− onRunningChanged: {
128− if (hudButtonShowable.hideAnimation.running) {
129− bottombar.state = "hidden"
70+ height: distanceThreshold
71+ anchors.bottom: parent.bottom
72+
73+ enabled: !theHud.shown && bottombar.enabled && applicationIsOnForeground
74+ direction: Direction.Upwards
75+
76+ property int previousStatus: -1
77+ property real touchStartX: -1
78+
79+ onStatusChanged: {
80+ if (status === DirectionalDragArea.WaitingForTouch) {
81+ if (previousStatus == DirectionalDragArea.Recognized) {
82+ if (hudButton.mouseOver) {
83+ hudButton.clicked()
84+ }
85+ }
86+ } else if (status === DirectionalDragArea.Undecided) {
87+ touchStartX = touchX
13088 }
89+ previousStatus = status
13190 }
13291 }
13392
Bottombar/HudButton.qml+3−2
@@ -20,10 +20,11 @@ import Ubuntu.Components 0.1
2020Item {
2121 id: item
2222
23+ property bool mouseOver
24+
2325 property int bottomMargin: units.gu(2)
24− property bool mouseOver: contains(mouse)
2526
26− property point mouse: Qt.point(-1,-1)
27+ signal clicked()
2728
2829 readonly property real scaleOnMouseOver: 1.2
2930
Bottombar/graphics/hud_invoke_button_active@20.png

Binary file not shown.

CMakeLists.txt+1
@@ -57,6 +57,7 @@ find_package(Qt5DBus)
5757include(GNUInstallDirs)
5858
5959set(SHELL_APP_DIR ${CMAKE_INSTALL_DATADIR}/unity8)
60+set(SHELL_PRIVATE_LIBDIR ${CMAKE_INSTALL_LIBDIR}/unity8)
6061
6162configure_file(paths.h.in ${CMAKE_CURRENT_BINARY_DIR}/paths.h @ONLY)
6263
CODING+75−29
@@ -1,43 +1,64 @@
11Building Unity 8
22================
33
4+Only Ubuntu 13.10 (saucy) is supported as a developement environment.
5+
46download source
57---------------
6−- the build requires some additional dependencies, so create the parent folder to not pollute your setup
7− $ mkdir ~/unity
8+- create a parent folder to not pollute your setup. so that you can have different unity
9+ branches there (trunk, WIP etc)
10+
11+ $ mkdir ~/unity8
812
913- fetch Unity 8 source
1014 $ sudo apt-get install bzr
11− $ bzr branch lp:unity/8.0 ~/unity/unity8
12− $ cd ~/unity/unity8
15+ $ bzr branch lp:unity8 ~/unity8/trunk
16+ $ cd ~/unity8/trunk
17+
18+install dependencies
19+--------------------
20+If its your first time, install build dependencies
21+
22+$ cd ~/unity8/trunk
23+$ ./build --setup
1324
14−build dependencies
15−------------------
16−If its your first time, download & build deps
17−$ ./build -s
1825 this will:
19− - add ppa:phablet-team/desktop-deps, ppa:canonical-qt5-edgers/qt5-proper, ppa:ubuntu-sdk-team
20− - build and install lp:libunity/phablet, lp:unity/phablet-mods, lp:hud/phablet locally
21− - install build dependencies
26+ - add the following PPA's
27+ - ppa:phablet-team/desktop-deps
28+ - ppa:canonical-qt5-edgers/qt5-proper
29+ - ppa:ubuntu-sdk-team
30+ - install the required dependencies to build, as well as run on the desktop
31+ - it should also install unity-scope-home and unity-lens-application which
32+ are technically "recommends", not strict dependencies
33+
34+Note, once the PPA's are added, the script runs apt-get update, if you have
35+any failures associated with it, the build script will bail out of the setup
36+and fail to install all the required dependencies.
37+
2238
2339build Unity 8
2440-------------
25−$ ./build
2641
27−subsequent updates of the dependencies
28−--------------------------------------
29−$ ./build_unity -u
30−$ ./build_unity
42+$ cd ~/unity8/trunk
43+$ ./build
3144
45+You may also rebuild with the -c for clean, which just deletes the build
46+directory.
3247
3348Running Unity 8 on your desktop
3449===============================
3550
3651run the Unity 8 shell
3752---------------------
38−$ cd ~/unity/unity8
53+$ cd ~/unity8/trunk
3954$ ./run
4055
56+Options can be passed to test the lock screen
57+$ ./run -p OR -k
58+
59+-p is for pin lock, for which the default prompt answer is "1234"
60+-k is for keylock passphrase, for which the default prompt answer is "password"
61+
4162Notes
4263-----
4364- to navigate, utilize the mouse left button as you would your finger
@@ -45,17 +66,29 @@ Notes
4566 put the *.mo files into correct structure. We'll look for a better solution
4667 later.
4768 $ cd builddir; make install
69+- if you wish to populate contacts
70+ $ sudo apt-get install gir1.2-ebook-1.2
71+ $ manage-address-book.py create
72+ this will:
73+ - Create an EDS address book
74+ - Populate the address book with sample data
4875
4976Running Unity 8 on devices
5077==========================
5178- Ubuntu Touch builds are currently only available in 13.10 flavour
52−- supported hardware should match one those listed here https://wiki.ubuntu.com/Touch/Devices#Running_fine
53−- follow the Ubuntu Touch install instructions for your chosen device https://wiki.ubuntu.com/Touch/Install
79+- supported hardware should match one those listed here
80+ https://wiki.ubuntu.com/Touch/Devices#Running_fine
81+- follow the Ubuntu Touch install instructions for your chosen device
82+ https://wiki.ubuntu.com/Touch/Install
5483- make sure your device is connected to a WiFi network
55−- also make sure you have your SSH key in ~/.ssh/id_rsa.pub (or install one on the device yourself)
56−
57−$ cd ~/unity/unity8
58−$ ./run_on_device -s
84+- If you haven’t already or if you’ve just freshly flashed your device
85+ make sure you run phablet-network-setup which will allow package updates to
86+ the device
87+- also make sure you have your SSH key in ~/.ssh/id_rsa.pub (or install one
88+ on the device yourself)
89+
90+$ cd ~/unity/trunk
91+$ ./run_on_device --setup
5992 this will:
6093 - install your public SSH key on the device
6194 - add ppa:canonical-qt5-edgers/qt5-proper and ppa:phablet-team
@@ -67,19 +100,27 @@ $ ./run_on_device
67100 - build on the device
68101 - replace the running shell
69102
103+Options can be passed to test the lock screen
104+$ ./run_on_device -p OR -k
105+
106+-p is for pin lock, for which the default prompt answer is "1234"
107+-k is for keylock passphrase, for which the default prompt answer is "password"
108+
70109Notes
71110-----
72111- using adb over TCP has some advantages, Google will be of help here
73112 - TL;DR: `adb tcpip 5555; adb connect $your_device_ip`
74113 - you can persist the above via `adb shell setprop persist.adb.tcp.port 5555`
75114 - it's unsafe - anyone can connect to your device
76− - with TCP the Nexus 10 doesn't drop the adb connection when locking the screen
77−- exporting ANDROID_SERIAL=$your_device_serial or ANDROID_SERIAL=$your_device_ip:5555
78− will make adb not complain about multiple devices
115+ - with TCP the Nexus 10 doesn't drop the adb connection when locking
116+ the screen
117+- exporting ANDROID_SERIAL=$your_device_serial or
118+ ANDROID_SERIAL=$your_device_ip:5555 will make adb not complain about
119+ multiple devices
79120- you can export TARGET_IP=$your_device_ip TARGET_SSH_PORT=22 for run_on_device
80121 to not use adb forwarding - useful if you use multiple devices
81−- using Ninja (package ninja-build - run_on_device -s installs this now) will improve
82− build times (especially in the nothing-to-build case)
122+- using Ninja (package ninja-build - run_on_device -s installs this now)
123+ will improve build times (especially in the nothing-to-build case)
83124
84125
85126Coding guidelines
@@ -90,4 +131,9 @@ https://launchpad.net/canonical-client-development-guidelines
90131
91132Development Environment
92133=======================
93−QtCreator (available via the Software Center) is the best IDE to hack on Unity 8.
134+QtCreator (available via the Software Center) is the best IDE to hack on
135+Unity 8.
136+
137+If using VIM, make sure you install some syntax highlighting for QML, like
138+https://github.com/peterhoeg/vim-qml
139+
COPYING.LGPLnew file+514
@@ -0,0 +1,514 @@
1+ GNU LESSER GENERAL PUBLIC LICENSE
2+
3+ The Qt Toolkit is Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4+ Contact: http://www.qt-project.org/legal
5+
6+ You may use, distribute and copy the Qt GUI Toolkit under the terms of
7+ GNU Lesser General Public License version 2.1, which is displayed below.
8+
9+-------------------------------------------------------------------------
10+
11+ GNU LESSER GENERAL PUBLIC LICENSE
12+ Version 2.1, February 1999
13+
14+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
15+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16+ Everyone is permitted to copy and distribute verbatim copies
17+ of this license document, but changing it is not allowed.
18+
19+[This is the first released version of the Lesser GPL. It also counts
20+ as the successor of the GNU Library Public License, version 2, hence
21+ the version number 2.1.]
22+
23+ Preamble
24+
25+ The licenses for most software are designed to take away your
26+freedom to share and change it. By contrast, the GNU General Public
27+Licenses are intended to guarantee your freedom to share and change
28+free software--to make sure the software is free for all its users.
29+
30+ This license, the Lesser General Public License, applies to some
31+specially designated software packages--typically libraries--of the
32+Free Software Foundation and other authors who decide to use it. You
33+can use it too, but we suggest you first think carefully about whether
34+this license or the ordinary General Public License is the better
35+strategy to use in any particular case, based on the explanations below.
36+
37+ When we speak of free software, we are referring to freedom of use,
38+not price. Our General Public Licenses are designed to make sure that
39+you have the freedom to distribute copies of free software (and charge
40+for this service if you wish); that you receive source code or can get
41+it if you want it; that you can change the software and use pieces of
42+it in new free programs; and that you are informed that you can do
43+these things.
44+
45+ To protect your rights, we need to make restrictions that forbid
46+distributors to deny you these rights or to ask you to surrender these
47+rights. These restrictions translate to certain responsibilities for
48+you if you distribute copies of the library or if you modify it.
49+
50+ For example, if you distribute copies of the library, whether gratis
51+or for a fee, you must give the recipients all the rights that we gave
52+you. You must make sure that they, too, receive or can get the source
53+code. If you link other code with the library, you must provide
54+complete object files to the recipients, so that they can relink them
55+with the library after making changes to the library and recompiling
56+it. And you must show them these terms so they know their rights.
57+
58+ We protect your rights with a two-step method: (1) we copyright the
59+library, and (2) we offer you this license, which gives you legal
60+permission to copy, distribute and/or modify the library.
61+
62+ To protect each distributor, we want to make it very clear that
63+there is no warranty for the free library. Also, if the library is
64+modified by someone else and passed on, the recipients should know
65+that what they have is not the original version, so that the original
66+author's reputation will not be affected by problems that might be
67+introduced by others.
68+
69+ Finally, software patents pose a constant threat to the existence of
70+any free program. We wish to make sure that a company cannot
71+effectively restrict the users of a free program by obtaining a
72+restrictive license from a patent holder. Therefore, we insist that
73+any patent license obtained for a version of the library must be
74+consistent with the full freedom of use specified in this license.
75+
76+ Most GNU software, including some libraries, is covered by the
77+ordinary GNU General Public License. This license, the GNU Lesser
78+General Public License, applies to certain designated libraries, and
79+is quite different from the ordinary General Public License. We use
80+this license for certain libraries in order to permit linking those
81+libraries into non-free programs.
82+
83+ When a program is linked with a library, whether statically or using
84+a shared library, the combination of the two is legally speaking a
85+combined work, a derivative of the original library. The ordinary
86+General Public License therefore permits such linking only if the
87+entire combination fits its criteria of freedom. The Lesser General
88+Public License permits more lax criteria for linking other code with
89+the library.
90+
91+ We call this license the "Lesser" General Public License because it
92+does Less to protect the user's freedom than the ordinary General
93+Public License. It also provides other free software developers Less
94+of an advantage over competing non-free programs. These disadvantages
95+are the reason we use the ordinary General Public License for many
96+libraries. However, the Lesser license provides advantages in certain
97+special circumstances.
98+
99+ For example, on rare occasions, there may be a special need to
100+encourage the widest possible use of a certain library, so that it becomes
101+a de-facto standard. To achieve this, non-free programs must be
102+allowed to use the library. A more frequent case is that a free
103+library does the same job as widely used non-free libraries. In this
104+case, there is little to gain by limiting the free library to free
105+software only, so we use the Lesser General Public License.
106+
107+ In other cases, permission to use a particular library in non-free
108+programs enables a greater number of people to use a large body of
109+free software. For example, permission to use the GNU C Library in
110+non-free programs enables many more people to use the whole GNU
111+operating system, as well as its variant, the GNU/Linux operating
112+system.
113+
114+ Although the Lesser General Public License is Less protective of the
115+users' freedom, it does ensure that the user of a program that is
116+linked with the Library has the freedom and the wherewithal to run
117+that program using a modified version of the Library.
118+
119+ The precise terms and conditions for copying, distribution and
120+modification follow. Pay close attention to the difference between a
121+"work based on the library" and a "work that uses the library". The
122+former contains code derived from the library, whereas the latter must
123+be combined with the library in order to run.
124+
125+ GNU LESSER GENERAL PUBLIC LICENSE
126+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
127+
128+ 0. This License Agreement applies to any software library or other
129+program which contains a notice placed by the copyright holder or
130+other authorized party saying it may be distributed under the terms of
131+this Lesser General Public License (also called "this License").
132+Each licensee is addressed as "you".
133+
134+ A "library" means a collection of software functions and/or data
135+prepared so as to be conveniently linked with application programs
136+(which use some of those functions and data) to form executables.
137+
138+ The "Library", below, refers to any such software library or work
139+which has been distributed under these terms. A "work based on the
140+Library" means either the Library or any derivative work under
141+copyright law: that is to say, a work containing the Library or a
142+portion of it, either verbatim or with modifications and/or translated
143+straightforwardly into another language. (Hereinafter, translation is
144+included without limitation in the term "modification".)
145+
146+ "Source code" for a work means the preferred form of the work for
147+making modifications to it. For a library, complete source code means
148+all the source code for all modules it contains, plus any associated
149+interface definition files, plus the scripts used to control compilation
150+and installation of the library.
151+
152+ Activities other than copying, distribution and modification are not
153+covered by this License; they are outside its scope. The act of
154+running a program using the Library is not restricted, and output from
155+such a program is covered only if its contents constitute a work based
156+on the Library (independent of the use of the Library in a tool for
157+writing it). Whether that is true depends on what the Library does
158+and what the program that uses the Library does.
159+
160+ 1. You may copy and distribute verbatim copies of the Library's
161+complete source code as you receive it, in any medium, provided that
162+you conspicuously and appropriately publish on each copy an
163+appropriate copyright notice and disclaimer of warranty; keep intact
164+all the notices that refer to this License and to the absence of any
165+warranty; and distribute a copy of this License along with the
166+Library.
167+
168+ You may charge a fee for the physical act of transferring a copy,
169+and you may at your option offer warranty protection in exchange for a
170+fee.
171+
172+ 2. You may modify your copy or copies of the Library or any portion
173+of it, thus forming a work based on the Library, and copy and
174+distribute such modifications or work under the terms of Section 1
175+above, provided that you also meet all of these conditions:
176+
177+ a) The modified work must itself be a software library.
178+
179+ b) You must cause the files modified to carry prominent notices
180+ stating that you changed the files and the date of any change.
181+
182+ c) You must cause the whole of the work to be licensed at no
183+ charge to all third parties under the terms of this License.
184+
185+ d) If a facility in the modified Library refers to a function or a
186+ table of data to be supplied by an application program that uses
187+ the facility, other than as an argument passed when the facility
188+ is invoked, then you must make a good faith effort to ensure that,
189+ in the event an application does not supply such function or
190+ table, the facility still operates, and performs whatever part of
191+ its purpose remains meaningful.
192+
193+ (For example, a function in a library to compute square roots has
194+ a purpose that is entirely well-defined independent of the
195+ application. Therefore, Subsection 2d requires that any
196+ application-supplied function or table used by this function must
197+ be optional: if the application does not supply it, the square
198+ root function must still compute square roots.)
199+
200+These requirements apply to the modified work as a whole. If
201+identifiable sections of that work are not derived from the Library,
202+and can be reasonably considered independent and separate works in
203+themselves, then this License, and its terms, do not apply to those
204+sections when you distribute them as separate works. But when you
205+distribute the same sections as part of a whole which is a work based
206+on the Library, the distribution of the whole must be on the terms of
207+this License, whose permissions for other licensees extend to the
208+entire whole, and thus to each and every part regardless of who wrote
209+it.
210+
211+Thus, it is not the intent of this section to claim rights or contest
212+your rights to work written entirely by you; rather, the intent is to
213+exercise the right to control the distribution of derivative or
214+collective works based on the Library.
215+
216+In addition, mere aggregation of another work not based on the Library
217+with the Library (or with a work based on the Library) on a volume of
218+a storage or distribution medium does not bring the other work under
219+the scope of this License.
220+
221+ 3. You may opt to apply the terms of the ordinary GNU General Public
222+License instead of this License to a given copy of the Library. To do
223+this, you must alter all the notices that refer to this License, so
224+that they refer to the ordinary GNU General Public License, version 2,
225+instead of to this License. (If a newer version than version 2 of the
226+ordinary GNU General Public License has appeared, then you can specify
227+that version instead if you wish.) Do not make any other change in
228+these notices.
229+
230+ Once this change is made in a given copy, it is irreversible for
231+that copy, so the ordinary GNU General Public License applies to all
232+subsequent copies and derivative works made from that copy.
233+
234+ This option is useful when you wish to copy part of the code of
235+the Library into a program that is not a library.
236+
237+ 4. You may copy and distribute the Library (or a portion or
238+derivative of it, under Section 2) in object code or executable form
239+under the terms of Sections 1 and 2 above provided that you accompany
240+it with the complete corresponding machine-readable source code, which
241+must be distributed under the terms of Sections 1 and 2 above on a
242+medium customarily used for software interchange.
243+
244+ If distribution of object code is made by offering access to copy
245+from a designated place, then offering equivalent access to copy the
246+source code from the same place satisfies the requirement to
247+distribute the source code, even though third parties are not
248+compelled to copy the source along with the object code.
249+
250+ 5. A program that contains no derivative of any portion of the
251+Library, but is designed to work with the Library by being compiled or
252+linked with it, is called a "work that uses the Library". Such a
253+work, in isolation, is not a derivative work of the Library, and
254+therefore falls outside the scope of this License.
255+
256+ However, linking a "work that uses the Library" with the Library
257+creates an executable that is a derivative of the Library (because it
258+contains portions of the Library), rather than a "work that uses the
259+library". The executable is therefore covered by this License.
260+Section 6 states terms for distribution of such executables.
261+
262+ When a "work that uses the Library" uses material from a header file
263+that is part of the Library, the object code for the work may be a
264+derivative work of the Library even though the source code is not.
265+Whether this is true is especially significant if the work can be
266+linked without the Library, or if the work is itself a library. The
267+threshold for this to be true is not precisely defined by law.
268+
269+ If such an object file uses only numerical parameters, data
270+structure layouts and accessors, and small macros and small inline
271+functions (ten lines or less in length), then the use of the object
272+file is unrestricted, regardless of whether it is legally a derivative
273+work. (Executables containing this object code plus portions of the
274+Library will still fall under Section 6.)
275+
276+ Otherwise, if the work is a derivative of the Library, you may
277+distribute the object code for the work under the terms of Section 6.
278+Any executables containing that work also fall under Section 6,
279+whether or not they are linked directly with the Library itself.
280+
281+ 6. As an exception to the Sections above, you may also combine or
282+link a "work that uses the Library" with the Library to produce a
283+work containing portions of the Library, and distribute that work
284+under terms of your choice, provided that the terms permit
285+modification of the work for the customer's own use and reverse
286+engineering for debugging such modifications.
287+
288+ You must give prominent notice with each copy of the work that the
289+Library is used in it and that the Library and its use are covered by
290+this License. You must supply a copy of this License. If the work
291+during execution displays copyright notices, you must include the
292+copyright notice for the Library among them, as well as a reference
293+directing the user to the copy of this License. Also, you must do one
294+of these things:
295+
296+ a) Accompany the work with the complete corresponding
297+ machine-readable source code for the Library including whatever
298+ changes were used in the work (which must be distributed under
299+ Sections 1 and 2 above); and, if the work is an executable linked
300+ with the Library, with the complete machine-readable "work that
301+ uses the Library", as object code and/or source code, so that the
302+ user can modify the Library and then relink to produce a modified
303+ executable containing the modified Library. (It is understood
304+ that the user who changes the contents of definitions files in the
305+ Library will not necessarily be able to recompile the application
306+ to use the modified definitions.)
307+
308+ b) Use a suitable shared library mechanism for linking with the
309+ Library. A suitable mechanism is one that (1) uses at run time a
310+ copy of the library already present on the user's computer system,
311+ rather than copying library functions into the executable, and (2)
312+ will operate properly with a modified version of the library, if
313+ the user installs one, as long as the modified version is
314+ interface-compatible with the version that the work was made with.
315+
316+ c) Accompany the work with a written offer, valid for at
317+ least three years, to give the same user the materials
318+ specified in Subsection 6a, above, for a charge no more
319+ than the cost of performing this distribution.
320+
321+ d) If distribution of the work is made by offering access to copy
322+ from a designated place, offer equivalent access to copy the above
323+ specified materials from the same place.
324+
325+ e) Verify that the user has already received a copy of these
326+ materials or that you have already sent this user a copy.
327+
328+ For an executable, the required form of the "work that uses the
329+Library" must include any data and utility programs needed for
330+reproducing the executable from it. However, as a special exception,
331+the materials to be distributed need not include anything that is
332+normally distributed (in either source or binary form) with the major
333+components (compiler, kernel, and so on) of the operating system on
334+which the executable runs, unless that component itself accompanies
335+the executable.
336+
337+ It may happen that this requirement contradicts the license
338+restrictions of other proprietary libraries that do not normally
339+accompany the operating system. Such a contradiction means you cannot
340+use both them and the Library together in an executable that you
341+distribute.
342+
343+ 7. You may place library facilities that are a work based on the
344+Library side-by-side in a single library together with other library
345+facilities not covered by this License, and distribute such a combined
346+library, provided that the separate distribution of the work based on
347+the Library and of the other library facilities is otherwise
348+permitted, and provided that you do these two things:
349+
350+ a) Accompany the combined library with a copy of the same work
351+ based on the Library, uncombined with any other library
352+ facilities. This must be distributed under the terms of the
353+ Sections above.
354+
355+ b) Give prominent notice with the combined library of the fact
356+ that part of it is a work based on the Library, and explaining
357+ where to find the accompanying uncombined form of the same work.
358+
359+ 8. You may not copy, modify, sublicense, link with, or distribute
360+the Library except as expressly provided under this License. Any
361+attempt otherwise to copy, modify, sublicense, link with, or
362+distribute the Library is void, and will automatically terminate your
363+rights under this License. However, parties who have received copies,
364+or rights, from you under this License will not have their licenses
365+terminated so long as such parties remain in full compliance.
366+
367+ 9. You are not required to accept this License, since you have not
368+signed it. However, nothing else grants you permission to modify or
369+distribute the Library or its derivative works. These actions are
370+prohibited by law if you do not accept this License. Therefore, by
371+modifying or distributing the Library (or any work based on the
372+Library), you indicate your acceptance of this License to do so, and
373+all its terms and conditions for copying, distributing or modifying
374+the Library or works based on it.
375+
376+ 10. Each time you redistribute the Library (or any work based on the
377+Library), the recipient automatically receives a license from the
378+original licensor to copy, distribute, link with or modify the Library
379+subject to these terms and conditions. You may not impose any further
380+restrictions on the recipients' exercise of the rights granted herein.
381+You are not responsible for enforcing compliance by third parties with
382+this License.
383+
384+ 11. If, as a consequence of a court judgment or allegation of patent
385+infringement or for any other reason (not limited to patent issues),
386+conditions are imposed on you (whether by court order, agreement or
387+otherwise) that contradict the conditions of this License, they do not
388+excuse you from the conditions of this License. If you cannot
389+distribute so as to satisfy simultaneously your obligations under this
390+License and any other pertinent obligations, then as a consequence you
391+may not distribute the Library at all. For example, if a patent
392+license would not permit royalty-free redistribution of the Library by
393+all those who receive copies directly or indirectly through you, then
394+the only way you could satisfy both it and this License would be to
395+refrain entirely from distribution of the Library.
396+
397+If any portion of this section is held invalid or unenforceable under any
398+particular circumstance, the balance of the section is intended to apply,
399+and the section as a whole is intended to apply in other circumstances.
400+
401+It is not the purpose of this section to induce you to infringe any
402+patents or other property right claims or to contest validity of any
403+such claims; this section has the sole purpose of protecting the
404+integrity of the free software distribution system which is
405+implemented by public license practices. Many people have made
406+generous contributions to the wide range of software distributed
407+through that system in reliance on consistent application of that
408+system; it is up to the author/donor to decide if he or she is willing
409+to distribute software through any other system and a licensee cannot
410+impose that choice.
411+
412+This section is intended to make thoroughly clear what is believed to
413+be a consequence of the rest of this License.
414+
415+ 12. If the distribution and/or use of the Library is restricted in
416+certain countries either by patents or by copyrighted interfaces, the
417+original copyright holder who places the Library under this License may add
418+an explicit geographical distribution limitation excluding those countries,
419+so that distribution is permitted only in or among countries not thus
420+excluded. In such case, this License incorporates the limitation as if
421+written in the body of this License.
422+
423+ 13. The Free Software Foundation may publish revised and/or new
424+versions of the Lesser General Public License from time to time.
425+Such new versions will be similar in spirit to the present version,
426+but may differ in detail to address new problems or concerns.
427+
428+Each version is given a distinguishing version number. If the Library
429+specifies a version number of this License which applies to it and
430+"any later version", you have the option of following the terms and
431+conditions either of that version or of any later version published by
432+the Free Software Foundation. If the Library does not specify a
433+license version number, you may choose any version ever published by
434+the Free Software Foundation.
435+
436+ 14. If you wish to incorporate parts of the Library into other free
437+programs whose distribution conditions are incompatible with these,
438+write to the author to ask for permission. For software which is
439+copyrighted by the Free Software Foundation, write to the Free
440+Software Foundation; we sometimes make exceptions for this. Our
441+decision will be guided by the two goals of preserving the free status
442+of all derivatives of our free software and of promoting the sharing
443+and reuse of software generally.
444+
445+ NO WARRANTY
446+
447+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
448+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
449+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
450+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
451+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
452+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
453+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
454+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
455+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
456+
457+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
458+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
459+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
460+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
461+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
462+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
463+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
464+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
465+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
466+DAMAGES.
467+
468+ END OF TERMS AND CONDITIONS
469+
470+ How to Apply These Terms to Your New Libraries
471+
472+ If you develop a new library, and you want it to be of the greatest
473+possible use to the public, we recommend making it free software that
474+everyone can redistribute and change. You can do so by permitting
475+redistribution under these terms (or, alternatively, under the terms of the
476+ordinary General Public License).
477+
478+ To apply these terms, attach the following notices to the library. It is
479+safest to attach them to the start of each source file to most effectively
480+convey the exclusion of warranty; and each file should have at least the
481+"copyright" line and a pointer to where the full notice is found.
482+
483+ <one line to give the library's name and a brief idea of what it does.>
484+ Copyright (C) <year> <name of author>
485+
486+ This library is free software; you can redistribute it and/or
487+ modify it under the terms of the GNU Lesser General Public
488+ License as published by the Free Software Foundation; either
489+ version 2.1 of the License, or (at your option) any later version.
490+
491+ This library is distributed in the hope that it will be useful,
492+ but WITHOUT ANY WARRANTY; without even the implied warranty of
493+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
494+ Lesser General Public License for more details.
495+
496+ You should have received a copy of the GNU Lesser General Public
497+ License along with this library; if not, write to the Free Software
498+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
499+
500+Also add information on how to contact you by electronic and paper mail.
501+
502+You should also get your employer (if you work as a programmer) or your
503+school, if any, to sign a "copyright disclaimer" for the library, if
504+necessary. Here is a sample; alter the names:
505+
506+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
507+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
508+
509+ <signature of Ty Coon>, 1 April 1990
510+ Ty Coon, President of Vice
511+
512+That's all there is to it!
513+
514+
Components/Carousel.qml+2
@@ -24,6 +24,8 @@ import "carousel.js" as CarouselJS
2424Item {
2525 id: carousel
2626
27+ clip: true // Don't leak horizontally to other dashes
28+
2729 /// The component to be used as delegate. This component has to be derived from BaseCarouselDelegate
2830 property Component itemComponent
2931 /// Model for the Carousel, which has to be a model usable by a ListView
Components/DragHandle.qmlnew file+212
@@ -0,0 +1,212 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Ubuntu.Gestures 0.1
20+import "Math.js" as MathLocal
21+
22+/*
23+ Put a DragHandle inside a Showable to enable the user to drag it from that handle.
24+ Main use case is to drag fullscreen Showables into the screen or off the screen.
25+
26+ This example shows a DragHandle placed on the right corner of a Showable, used
27+ to slide it away, off the screen.
28+
29+ Showable {
30+ x: 0
31+ y: 0
32+ width: ... // screen width
33+ height: ... // screen height
34+ shown: true
35+ ...
36+ DragHandle {
37+ anchors.right: parent.right
38+ anchors.top: parent.top
39+ anchors.bottom: parent.bottom
40+ width: units.gu(2)
41+
42+ direction: DirectionalDragArea::Leftwards
43+ }
44+ }
45+
46+ */
47+EdgeDragArea {
48+ id: dragArea
49+ objectName: "dragHandle"
50+
51+ // Disable gesture detection by default when hinting is used.
52+ // It doesn't make sense to have both.
53+ distanceThreshold: hintDisplacement > 0 ? 0 : units.gu(1.5)
54+
55+ property bool stretch: false
56+
57+ property alias autoCompleteDragThreshold: dragEvaluator.dragThreshold
58+
59+ // How far you can drag
60+ property real maxTotalDragDistance: {
61+ if (stretch) {
62+ 0; // not enough context information to set a sensible default
63+ } else {
64+ Direction.isHorizontal(direction) ? parent.width : parent.height;
65+ }
66+ }
67+
68+ property real hintDisplacement: 0
69+ SmoothedAnimation {
70+ id: hintingAnimation
71+ target: hintingAnimation
72+ property: "targetValue"
73+ duration: 150
74+ velocity: -1
75+ to: Direction.isPositive(direction) ? d.startValue + hintDisplacement
76+ : d.startValue - hintDisplacement
77+ property real targetValue
78+ onTargetValueChanged: {
79+ if (!running) {
80+ return;
81+ }
82+
83+ if (Direction.isPositive(direction)) {
84+ if (parent[d.targetProp] < targetValue) {
85+ parent[d.targetProp] = targetValue;
86+ }
87+ } else {
88+ if (parent[d.targetProp] > targetValue) {
89+ parent[d.targetProp] = targetValue;
90+ }
91+ }
92+ }
93+ }
94+
95+ // Private stuff
96+ QtObject {
97+ id: d
98+ property var previousStatus: undefined
99+ property real startValue
100+ property real minValue: Direction.isPositive(direction) ? startValue
101+ : startValue - maxTotalDragDistance
102+ property real maxValue: Direction.isPositive(direction) ? startValue + maxTotalDragDistance
103+ : startValue
104+
105+ property var dragParent: dragArea.parent
106+
107+ // The property of DragHandle's parent that will be modified
108+ property string targetProp: {
109+ if (stretch) {
110+ Direction.isHorizontal(direction) ? "width" : "height";
111+ } else {
112+ Direction.isHorizontal(direction) ? "x" : "y";
113+ }
114+ }
115+
116+ function limitMovement(step) {
117+ var targetValue = MathLocal.clamp(dragParent[targetProp] + step, minValue, maxValue);
118+ var step = targetValue - dragParent[targetProp];
119+
120+ if (hintDisplacement == 0) {
121+ return step;
122+ }
123+
124+ // we should not go behind hintingAnimation's current value
125+ if (Direction.isPositive(direction)) {
126+ if (dragParent[targetProp] + step < hintingAnimation.targetValue) {
127+ step = hintingAnimation.targetValue - dragParent[targetProp];
128+ }
129+ } else {
130+ if (dragParent[targetProp] + step > hintingAnimation.targetValue) {
131+ step = hintingAnimation.targetValue - dragParent[targetProp];
132+ }
133+ }
134+
135+ return step;
136+ }
137+
138+ function onFinishedRecognizedGesture() {
139+ if (dragEvaluator.shouldAutoComplete()) {
140+ completeDrag();
141+ } else {
142+ rollbackDrag();
143+ }
144+ }
145+
146+ function completeDrag() {
147+ if (dragParent.shown) {
148+ dragParent.hide();
149+ } else {
150+ dragParent.show();
151+ }
152+ }
153+
154+ function rollbackDrag() {
155+ if (dragParent.shown) {
156+ dragParent.show();
157+ } else {
158+ dragParent.hide();
159+ }
160+ }
161+ }
162+
163+ property alias edgeDragEvaluator: dragEvaluator
164+
165+ EdgeDragEvaluator {
166+ objectName: "edgeDragEvaluator"
167+ id: dragEvaluator
168+ trackedPosition: sceneDistance
169+ maxDragDistance: maxTotalDragDistance
170+ direction: dragArea.direction
171+ }
172+
173+ onDistanceChanged: {
174+ if (status === DirectionalDragArea.Recognized) {
175+ // don't go the whole distance in order to smooth out the movement
176+ var step = distance * 0.3;
177+
178+ step = d.limitMovement(step);
179+
180+ parent[d.targetProp] += step;
181+ }
182+ }
183+
184+ onDraggingChanged: {
185+ if (dragging) {
186+ if (hintDisplacement > 0) {
187+ hintingAnimation.targetValue = d.startValue;
188+ hintingAnimation.start();
189+ }
190+ } else {
191+ hintingAnimation.stop();
192+ }
193+ }
194+
195+ onStatusChanged: {
196+ if (status === DirectionalDragArea.WaitingForTouch) {
197+ if (d.previousStatus === DirectionalDragArea.Recognized) {
198+ d.onFinishedRecognizedGesture();
199+ }
200+ d.startValue = parent[d.targetProp];
201+ }
202+
203+ if (d.previousStatus === DirectionalDragArea.WaitingForTouch ||
204+ d.previousStatus === undefined) {
205+ dragEvaluator.reset();
206+ d.startValue = parent[d.targetProp];
207+ }
208+
209+ d.previousStatus = status;
210+ }
211+
212+}
Components/EdgeDragArea.qmlnew 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+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Ubuntu.Gestures 0.1
20+
21+/*
22+ A DirectionalDragArea wrapper that provides some well-chosen defaults
23+ for its gesture recognition parameters.
24+*/
25+DirectionalDragArea {
26+
27+ // TODO: Re-evaluate those or even the recognition heuristics itself once
28+ // we have gesture cancelling/forwarding in place.
29+ //
30+ // The idea here is that it's better having lax rules than false negatives.
31+ // False negatives are very frustrating to the user.
32+ maxDeviation: units.gu(3)
33+ wideningAngle: 50
34+ distanceThreshold: units.gu(1.5)
35+ minSpeed: units.gu(0) // some people were getting false negatives with it enabled.
36+}
Components/EdgeDragEvaluator.qmlnew file+88
@@ -0,0 +1,88 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Ubuntu.Gestures 0.1
20+
21+/*
22+ Evaluates end velocity (velocity at the moment the gesture ends) and travelled
23+ distance (delta between finger down and finger up positions) to determine
24+ whether the drag should continue by itself towards completion (auto-complete)
25+ after the finger has left the touchscreen.
26+ */
27+AxisVelocityCalculator {
28+
29+ // How far the drag can go, or should go to achieve completion.
30+ property real maxDragDistance
31+
32+ // Ending a drag at any point before this threshold will need some positive velocity
33+ // (i.e., towards the set direction) to get auto-completion (e.g. to get show()
34+ // called for a hidden Showable) and ending a drag at any point after this
35+ // threshold will need some negative velocity to avoid auto-completion.
36+ property real dragThreshold: maxDragDistance / 2
37+
38+ property real minDragDistance: maxDragDistance * 0.1
39+
40+ // Speed needed to get auto-completion for an hypothetical flick of length zero.
41+ //
42+ // This requirement is gradually reduced as flicks gets longer until it reaches
43+ // a value of zero for flicks of dragThreshold lenght.
44+ //
45+ // in pixels per second
46+ property real speedThreshold: units.gu(70)
47+
48+ property int direction
49+
50+ property real velocity
51+ property real minVelocity
52+
53+ // Returns whether the drag should continue by itself until completed.
54+ function shouldAutoComplete() {
55+ var deltaPos = trackedPosition - __startPosition;
56+ if (Math.abs(deltaPos) < minDragDistance) {
57+ velocity = 0;
58+ minVelocity = 0;
59+ return false;
60+ }
61+
62+ minVelocity = __calculateMinimumVelocityForAutoCompletion(deltaPos);
63+ velocity = calculate();
64+
65+ if (Direction.isPositive(direction) && (velocity >= minVelocity)
66+ || !Direction.isPositive(direction) && (velocity <= minVelocity)) {
67+ return true;
68+ } else {
69+ return false;
70+ }
71+ }
72+
73+ property real __startPosition
74+
75+ // speedThreshold in pixels per millisecond
76+ property real __speedThresholdMs: speedThreshold / 1000.0
77+
78+ // Minimum velocity when a drag total distance is zero
79+ property real __v0: Direction.isPositive(direction) ? __speedThresholdMs : - __speedThresholdMs
80+
81+ function __calculateMinimumVelocityForAutoCompletion(distance) {
82+ return __v0 - ((__speedThresholdMs / dragThreshold) * distance);
83+ }
84+
85+ function reset() {
86+ __startPosition = trackedPosition;
87+ }
88+}
Components/FilterGrid.qml+1−1
@@ -108,7 +108,7 @@ Item {
108108
109109 anchors.fill: parent
110110 radius: "small"
111− borderSource: ItemStyle.style.borderPressed
111+ borderSource: "radius_pressed.sci"
112112 opacity: button.pressed ? 1.0 : 0.0
113113 Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
114114 }
Components/IconUtil.js+5−5
@@ -26,17 +26,17 @@ function from_gicon(name) {
2626 var base_icon_re = /'base-icon':.+?'(.+?)'/;
2727 var base_icon = name.toString().match(base_icon_re);
2828 icon_name = base_icon[1];
29− }
30− else {
29+ } else {
3130 var themed_re = /^. GThemedIcon\s*([^\s]+)\s*/;
3231 var themed = name.match(themed_re);
3332 if (themed) {
3433 return "image://gicon/" + themed[1];
3534 }
3635 }
37− var remote_re = /^http/;
38− if (remote_re.test(icon_name)) {
36+ var name_re = /^[a-z0-9\._-]+$/;
37+ if (name_re.test(icon_name)) {
38+ return "image://gicon/" + icon_name;
39+ } else {
3940 return icon_name;
4041 }
41− return "image://gicon/" + icon_name;
4242}
Components/ListItems/Base.qml+19−21
@@ -54,35 +54,33 @@ AbstractButton {
5454 */
5555 function __showDivider() {
5656 // if we're not in ListView, always show a thin dividing line at the bottom
57− if (ListView.view !== null) {
58−
59− // if we're last item in ListView don't show divider
60− if (index === ListView.view.model.count - 1) return false;
57+ var model = null;
58+ if (typeof ListViewWithPageHeader !== 'undefined') {
59+ if (typeof ListViewWithPageHeader.model !== 'undefined') {
60+ model = ListViewWithPageHeader.model;
61+ }
62+ } else if (ListView.view !== null) {
63+ model = ListView.view.model;
6164 }
65+ // if we're last item in ListView don't show divider
66+ if (model && index === model.count - 1) return false;
67+
6268 return true;
6369 }
6470
65− property bool __clippingRequired: ListView.view !== null
66− && ListView.view.section.labelPositioning & ViewSection.CurrentLabelAtStart
67−
68− property real __yPositionRelativeToListView: ListView.view ? y - ListView.view.contentY : y
71+ /* Relevant really only for ListViewWithPageHeader case: specify how many pixels we can overlap with the section header */
72+ readonly property int allowedOverlap: units.dp(1)
6973
7074 property real __heightToClip: {
7175 // Check this is in position where clipping is needed
72− if (__clippingRequired && __yPositionRelativeToListView <= __sectionDelegateHeight
73− && __yPositionRelativeToListView > -height) {
74− return Math.min(__sectionDelegateHeight - __yPositionRelativeToListView, height);
75− } else {
76− return 0;
77− }
78− }
79−
80− property int __sectionDelegateHeight: {
81− if (__clippingRequired && ListView.view.hasOwnProperty("__sectionDelegateHeight")) {
82− return ListView.view.__sectionDelegateHeight;
83− } else {
84− return 0;
76+ if (typeof ListViewWithPageHeader !== 'undefined') {
77+ if (typeof heightToClip !== 'undefined') {
78+ if (heightToClip >= allowedOverlap) {
79+ return heightToClip - allowedOverlap;
80+ }
81+ }
8582 }
83+ return 0;
8684 }
8785
8886 /*!
Components/ListItems/Header.qml−6
@@ -25,12 +25,6 @@ Item {
2525 */
2626 property alias text: label.text
2727
28− /* When this header is used in a ListViewWithPageHeader with CurrentLabelAtStart mode, to stop
29− the list's delegates contents being visible through this header, they clip themselves
30− depending on their position. However to allow delegates underlap the bottom X pixels of this
31− header (so delegate appears through ThinDivider say) we set an offset property here. */
32− readonly property int bottomBorderAllowedOverlap: bottomBorder.allowedBottomOverlap
33−
3428 height: units.gu(4.5)
3529
3630 Item {
Components/ListItems/ThinDivider.qml−4
@@ -23,9 +23,5 @@ Image {
2323 }
2424 height: (visible) ? units.dp(2) : 0
2525
26− /* Relevant really only for ListViewWithPageHeader with Base delegates: should this image
27− be overlapping content, specify how many pixels from the bottom should be transparent */
28− readonly property int allowedBottomOverlap: units.dp(1)
29−
3026 source: "graphics/ListItemDividerHorizontal.png"
3127}
Components/ListViewWithPageHeader.qmldeleted−189
@@ -1,189 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import "Math.js" as MathLocal
19−
20−Item {
21− id: root
22− property Item pageHeader: null
23− property Component sectionDelegate: null
24− property string sectionProperty: ""
25− property alias model: listView.model
26− property alias delegate: listView.delegate
27− property ListView view: listView
28− property alias moving: flicker.moving
29− property alias atYEnd: flicker.atYEnd
30− property bool clipListView: true
31−
32− readonly property real __headerHeight: (pageHeader) ? pageHeader.implicitHeight : 0
33− property real __headerVisibleHeight: __headerHeight
34− readonly property real __overshootHeight: (flicker.contentY < 0) ? -flicker.contentY : 0
35−
36−
37− // TODO move to AnimationController
38− ParallelAnimation {
39− id: headerAnimation
40− property real targetContentY
41− NumberAnimation {
42− target: root
43− property: "__headerVisibleHeight"
44− to: root.__headerHeight
45− duration: 200
46− easing.type: Easing.OutQuad
47− }
48− NumberAnimation {
49− target: listView
50− property: "contentY"
51− to: headerAnimation.targetContentY
52− duration: 200
53− easing.type: Easing.OutQuad
54− }
55− }
56−
57− function positionAtBeginning() {
58− __headerVisibleHeight = __headerHeight
59− flicker.contentY = 0
60− }
61−
62− function showHeader() {
63− headerAnimation.targetContentY = listView.contentY + (__headerHeight - __headerVisibleHeight)
64− headerAnimation.start()
65− }
66−
67− function flick(xVelocity, yVelocity) {
68− flicker.flick(xVelocity, yVelocity);
69− }
70−
71− onPageHeaderChanged: {
72− pageHeader.parent = pageHeaderContainer;
73− pageHeader.anchors.fill = pageHeaderContainer;
74− }
75−
76− Item {
77− id: pageHeaderClipper
78− parent: flicker // parent to Flickable so mouse click events passed through to the header component
79− anchors {
80− top: parent.top
81− left: parent.left
82− right: parent.right
83− }
84− height: __headerVisibleHeight + __overshootHeight
85−
86− Item {
87− id: pageHeaderContainer
88− anchors {
89− left: parent.left
90− right: parent.right
91− bottom: parent.bottom
92− }
93− height: __headerHeight + __overshootHeight
94− }
95− }
96−
97− ListView {
98− id: listView
99− parent: flicker // parent to Flickable so mouse click events passed through to List delegates
100− anchors {
101− left: parent.left
102− right: parent.right
103− top: parent.top
104− topMargin: __headerVisibleHeight
105− }
106− height: root.height
107−
108− // FIXME scrolling workaround, see below
109− cacheBuffer: height*10
110−
111− section.property: sectionProperty
112− section.criteria: ViewSection.FullString
113− section.labelPositioning: ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
114− section.delegate: sectionDelegate
115−
116− interactive: false
117− clip: root.clipListView
118−
119− property int __sectionDelegateHeight: __getHeight(section.delegate)
120− function __getHeight(component) {
121− // want height (minus allowed overlap) of the section delegate as is needed for clipping
122− if (component === null) return 0;
123− var object = component.createObject(); //FIXME: throws 'section' not defined error
124− var value = object.height - object.bottomBorderAllowedOverlap;
125− object.destroy();
126− return value;
127− }
128−
129− property real previousOriginY: 0
130− onOriginYChanged: {
131− var deltaOriginY = originY - previousOriginY;
132− previousOriginY = originY;
133− /* When originY changes, it causes the top of the flicker and the top of the list to fall
134− out of sync - and thus the contentY positioning will be broken. To correct for this we
135− manually change the flickable's contentY here */
136− flicker.contentY -= deltaOriginY;
137− }
138−
139− /* For case when list content greater than container height and list scrolled down so header
140− hidden. If content shrinks to be smaller than the container height, we want the header to
141− re-appear */
142− property real __previousContentHeight: 0
143− onContentHeightChanged: {
144− var deltaContentHeight = contentHeight - __previousContentHeight;
145− __previousContentHeight = contentHeight;
146− if (contentHeight < height && deltaContentHeight < 0 && __headerVisibleHeight < height - contentHeight) {
147− __headerVisibleHeight = Math.min(height - contentHeight, __headerHeight);
148− }
149− }
150− }
151−
152− Flickable {
153− id: flicker
154− anchors.fill: parent
155− contentHeight: listView.contentHeight + __headerHeight
156− maximumFlickVelocity: height * 10
157− flickDeceleration: height * 2
158− onContentYChanged: {
159− var deltaContentY = contentY - __previousContentY;
160− __previousContentY = contentY;
161−
162− // first decide if movement will prompt the page header to change height
163− if ((deltaContentY < 0 && __headerVisibleHeight >= 0) ||
164− (deltaContentY > 0 && __headerVisibleHeight <= __headerHeight)) {
165−
166− // calculate header height - but prevent bounce from changing it
167− if (contentY > 0 && contentY < contentHeight - height) {
168− __headerVisibleHeight = MathLocal.clamp(__headerVisibleHeight - deltaContentY, 0, __headerHeight);
169− }
170− }
171−
172− // now we move list position, taking into account page header height
173−
174− // BUG: With section headers enabled, the values of originY and contentY appear not
175− // correct at the exact point originY changes. originY changes when the ListView
176− // deletes/creates hidden delegates which are above the visible delegates.
177− // As a result of this bug, you experience jittering scrolling when rapidly moving
178− // around in large lists. See https://bugreports.qt-project.org/browse/QTBUG-27997
179− // A workaround is to use a large enough cacheBuffer to prevent deletions/creations
180− // so effectively originY is always zero.
181− var newContentY = flicker.contentY + listView.originY - __headerHeight + __headerVisibleHeight
182− if (newContentY < listView.contentHeight) {
183− listView.contentY = newContentY;
184− }
185− }
186−
187− property real __previousContentY: 0
188− }
189−}
Components/PageHeader.qml+2−4
@@ -147,9 +147,8 @@ Item {
147147
148148 hasClearButton: false
149149
150− primaryItem: Button {
150+ primaryItem: AbstractButton {
151151 enabled: searchField.text != ""
152− ItemStyle.class: "transparent-button"
153152 onClicked: {
154153 if (searchField.text != "") {
155154 searchHistory.addQuery(searchField.text)
@@ -271,8 +270,7 @@ Item {
271270
272271 // FIXME: this should go into the first item below, but enable: false
273272 // prevents mouse events propagation
274− Button {
275− ItemStyle.class: "transparent-button"
273+ AbstractButton {
276274 anchors {
277275 top: parent.top
278276 right: parent.right
Components/Stage.qml+8−10
@@ -416,12 +416,14 @@ Showable {
416416 }
417417 }
418418
419− AxisVelocityCalculator {
420− id: dragVelocityCalculator
421− trackedPosition: rightEdgeDraggingArea.distance
419+ EdgeDragEvaluator {
420+ id: dragEvaluator
421+ trackedPosition: rightEdgeDraggingArea.touchX
422+ direction: rightEdgeDraggingArea.direction
423+ maxDragDistance: stage.width
422424 }
423425
424− DirectionalDragArea {
426+ EdgeDragArea {
425427 id: rightEdgeDraggingArea
426428
427429 enabled: {
@@ -439,10 +441,6 @@ Showable {
439441 anchors.right: parent.right
440442
441443 direction: Direction.Leftwards
442− maxDeviation: units.gu(1)
443− wideningAngle: 20
444− distanceThreshold: units.gu(3)
445− minSpeed: units.gu(5)
446444
447445 onDistanceChanged: {
448446 if (status !== DirectionalDragArea.Recognized)
@@ -478,7 +476,7 @@ Showable {
478476 }
479477
480478 function onUndecided() {
481− dragVelocityCalculator.reset()
479+ dragEvaluator.reset();
482480
483481 var nextApplication = null;
484482 if (stage.applications.count > 1) {
@@ -491,7 +489,7 @@ Showable {
491489 }
492490
493491 function onGestureEnded() {
494− if (stage.applications.count > 1 && dragVelocityCalculator.calculate() < 0) {
492+ if (stage.applications.count > 1 && dragEvaluator.shouldAutoComplete()) {
495493 switchToApplicationAnimationController.completeToEndWithSignal();
496494 } else {
497495 switchToApplicationAnimationController.completeToBeginningWithSignal();
Components/Tile.qml+1−1
@@ -51,7 +51,7 @@ AbstractButton {
5151
5252 anchors.fill: icon
5353 radius: "medium"
54− borderSource: ItemStyle.style.borderPressed
54+ borderSource: "radius_pressed.sci"
5555 opacity: root.pressed ? 1.0 : 0.0
5656 Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
5757 }
Components/UbuntuShapeForItem.qml+12−56
@@ -15,7 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18−import Ubuntu.Components 0.1 as Theming
18+import Ubuntu.Components 0.1
1919
2020/* FIXME: This component is duplicating the UbuntuShape from the SDK, but shapes more
2121 * general (Item-based) components. This ability should be incorporated into the SDK's
@@ -24,66 +24,22 @@ import Ubuntu.Components 0.1 as Theming
2424 */
2525
2626Item {
27− id: shape
27+ id: root
2828
29− Theming.ItemStyle.class: "UbuntuShape-radius-" + radius
29+ property alias radius: shape.radius
30+ property alias image: source.sourceItem
3031
31− property string radius: "small"
32− property url maskSource: Theming.ComponentUtils.style(shape, "maskSource", "")
33− property url borderSource: Theming.ComponentUtils.style(shape, "borderIdle", "")
34− property Item image
35−
36− implicitWidth: units.gu(8)
37− implicitHeight: units.gu(8)
38−
39− onWidthChanged: __updateImageDimensions()
40− onHeightChanged: __updateImageDimensions()
41− onImageChanged: __updateImageDimensions()
42−
43− function __updateImageDimensions() {
44− if (!image) return;
45− image.width = shape.width;
46− image.height = shape.height;
47− image.visible = false;
48− }
49−
50− ShaderEffect {
51− anchors.fill: parent
52− visible: shape.image
53−
54− property ShaderEffectSource mask: ShaderEffectSource {
55− sourceItem: BorderImage {
56− width: shape.width
57− height: shape.height
58− source: shape.maskSource
59− visible: false
60− }
61− }
62−
63− property ShaderEffectSource image: ShaderEffectSource {
64− sourceItem: shape.image
65− }
66−
67− fragmentShader:
68− "
69− varying highp vec2 qt_TexCoord0;
70− uniform lowp float qt_Opacity;
71− uniform sampler2D mask;
72− uniform sampler2D image;
73−
74− void main(void)
75− {
76− lowp vec4 maskColor = texture2D(mask, qt_TexCoord0.st);
77− lowp vec4 imageColor = texture2D(image, qt_TexCoord0.st);
78− gl_FragColor = imageColor * maskColor.a * qt_Opacity;
79− }
80− "
32+ ShaderEffectSource {
33+ id: source
34+ width: 1
35+ height: 1
36+ hideSource: true
8137 }
8238
83− BorderImage {
84− id: border
39+ Shape {
40+ id: shape
41+ image: source
8542
8643 anchors.fill: parent
87− source: shape.borderSource
8844 }
8945}
Components/WrongPasswordAnimation.qml+3−3
@@ -26,14 +26,14 @@ SequentialAnimation {
2626 property: "anchors.horizontalCenterOffset"
2727 duration: 50
2828 easing.type: Easing.InQuad
29− to: units.gu(2)
29+ to: units.gu(1)
3030 }
3131 NumberAnimation {
3232 target: root.target
3333 property: "anchors.horizontalCenterOffset"
3434 duration: 100
3535 easing.type: Easing.InOutQuad
36− to: -units.gu(2)
36+ to: -units.gu(1)
3737 }
3838 NumberAnimation {
3939 target: root.target
@@ -41,6 +41,6 @@ SequentialAnimation {
4141 properties: "anchors.horizontalCenterOffset"
4242 to: 0
4343 duration: 400
44− easing.overshoot: units.gu(2)
44+ easing.overshoot: units.gu(1)
4545 }
4646}
Components/graphics/icon_star_off@20.png

Binary file not shown.

Components/graphics/icon_star_on@20.png

Binary file not shown.

Components/graphics/non-selected@18.png

Binary file not shown.

Dash/Apps/ApplicationsFilterGrid.qml+3−2
@@ -17,11 +17,12 @@
1717import QtQuick 2.0
1818import "../../Components"
1919import "../../Applications"
20+import "../../Components/IconUtil.js" as IconUtil
2021
2122FilterGrid {
2223 id: filterGrid
2324
24− filter: true
25+ filter: false
2526 expandable: false
2627 minimumHorizontalSpacing: units.gu(0.5)
2728 maximumNumberOfColumns: 6
@@ -50,7 +51,7 @@ FilterGrid {
5051 text: model.column_5 ? model.column_5 : application.name // FIXME: this is temporary
5152 imageWidth: units.gu(8)
5253 imageHeight: units.gu(7.5)
53− source: icon.indexOf("/") == -1 ? "image://gicon/" + icon : icon
54+ source: IconUtil.from_gicon(icon)
5455 onClicked: filterGrid.clicked(index, application.desktopFile);
5556 }
5657}
Dash/Apps/RunningApplicationTile.qml+1−1
@@ -87,7 +87,7 @@ AbstractButton {
8787
8888 anchors.fill: shapedApplicationImage
8989 radius: "medium"
90− borderSource: ItemStyle.style.borderPressed
90+ borderSource: "radius_pressed.sci"
9191 opacity: root.pressed ? 1.0 : 0.0
9292 Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
9393 }
Dash/Apps/graphics/close_btn@9.png

Binary file not shown.

Dash/DashApps.qml+2−3
@@ -99,7 +99,7 @@ ScopeView {
9999 When using Loader to load external QML file in the list deelgate, the ListView has
100100 a bug where it can position the delegate content to overlap the section header
101101 of the ListView - a workaround is to use sourceComponent of Loader instead */
102− Component { id: runningApplicationsGrid; RunningApplicationsGrid {} }
102+ Component { id: runningApplicationsGrid; RunningApplicationsGrid { clip: true } }
103103 Component {
104104 id: applicationsFilterGrid;
105105 ApplicationsFilterGrid {
@@ -112,7 +112,7 @@ ScopeView {
112112 "ApplicationsFilterGrid": applicationsFilterGrid,
113113 }
114114
115− ListViewWithPageHeader {
115+ ScopeListView {
116116 id: categoryView
117117 anchors.fill: parent
118118 model: SortFilterProxyModel {
@@ -150,7 +150,6 @@ ScopeView {
150150 item.model = categoryModels[modelName]
151151 }
152152 }
153− asynchronous: true
154153 }
155154
156155 ListView.onRemove: SequentialAnimation {
Dash/DashHome.qml+1−2
@@ -130,7 +130,7 @@ ScopeView {
130130 "VideosGrid": videosGrid,
131131 }
132132
133− ListViewWithPageHeader {
133+ ScopeListView {
134134 id: listView
135135 anchors.fill: parent
136136 model: categoryListModel
@@ -161,7 +161,6 @@ ScopeView {
161161 item.clicked.connect(playVideo);
162162 }
163163 }
164− asynchronous: true
165164 }
166165 }
167166
Dash/DashMusic.qml+1−2
@@ -64,7 +64,7 @@ ScopeView {
6464 }
6565 }
6666
67− ListViewWithPageHeader {
67+ ScopeListView {
6868 id: categoryView
6969 anchors.fill: parent
7070 model: scopeView.categories
@@ -84,7 +84,6 @@ ScopeView {
8484 onLoaded: {
8585 item.model = results
8686 }
87− asynchronous: true
8887 }
8988 }
9089
Dash/DashVideos.qml+2−3
@@ -97,11 +97,11 @@ ScopeView {
9797 }
9898 }
9999
100− ListViewWithPageHeader {
100+ ScopeListView {
101101 id: categoryView
102102 anchors.fill: parent
103103 model: scopeView.categories
104− clipListView: !previewLoader.onScreen
104+ forceNoClip: previewLoader.onScreen
105105
106106 onAtYEndChanged: if (atYEnd) endReached()
107107 onMovingChanged: if (moving && atYEnd) endReached()
@@ -119,7 +119,6 @@ ScopeView {
119119 onLoaded: {
120120 item.model = results
121121 }
122− asynchronous: true
123122
124123 Connections {
125124 target: loader.item
Dash/GenericScopeView.qml+1−1
@@ -43,7 +43,7 @@ ScopeView {
4343 }
4444 }
4545
46− ListViewWithPageHeader {
46+ ScopeListView {
4747 id: categoryView
4848 anchors.fill: parent
4949 model: scopeView.categories
Dash/Music/AlbumTile.qml+1−1
@@ -45,7 +45,7 @@ AbstractButton {
4545
4646 anchors.fill: icon
4747 radius: "medium"
48− borderSource: ItemStyle.style.borderPressed
48+ borderSource: "radius_pressed.sci"
4949 opacity: root.pressed ? 1.0 : 0.0
5050 Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
5151 }
tests/qmltests/plugins/Dee/DeeVariantText.qml → Dash/ScopeListView.qmlrenamed+4−3
@@ -15,8 +15,9 @@
1515 */
1616
1717import QtQuick 2.0
18+import ListViewWithPageHeader 0.1
1819
19−Item {
20− property variant value
21− property string text
20+ListViewWithPageHeader {
21+ maximumFlickVelocity: height * 10
22+ flickDeceleration: height * 2
2223}
Dash/graphics/icon_clear@20.png

Binary file not shown.

Dash/graphics/icon_listview_clear@20.png

Binary file not shown.

Dash/graphics/icon_search_active@20.png

Binary file not shown.

Dash/graphics/icon_search_inactive@20.png

Binary file not shown.

Dash/graphics/phone/home.png

Binary file not shown.

Dash/graphics/phone/music.png

Binary file not shown.

Dash/graphics/phone/screenshots/angrybirds@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/browser@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/camera@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/facebook@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/gallery@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/map@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/music@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/phone@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/settings@12.png

Binary file not shown.

Dash/graphics/phone/screenshots/twitter@12.png

Binary file not shown.

Dash/graphics/phone/videos.png

Binary file not shown.

Dash/graphics/play_button@18.png

Binary file not shown.

Dash/graphics/play_button_active@18.png

Binary file not shown.

Dash/graphics/play_button_active_big@20.png

Binary file not shown.

Dash/graphics/play_button_big@20.png

Binary file not shown.

Dash/graphics/tablet/apps.png

Binary file not shown.

Dash/graphics/tablet/home.png

Binary file not shown.

Dash/graphics/tablet/icon_close_preview@20.png

Binary file not shown.

Dash/graphics/tablet/music.png

Binary file not shown.

Dash/graphics/tablet/people.png

Binary file not shown.

Dash/graphics/tablet/videos.png

Binary file not shown.

Greeter/Greeter.qml+28−2
@@ -16,14 +16,23 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import Ubuntu.Gestures 0.1
1920import LightDM 0.1 as LightDM
2021import "../Components"
22+import "../Components/Math.js" as MathLocal
2123
2224Showable {
2325 id: greeter
2426 enabled: shown
2527 created: greeterContentLoader.status == Loader.Ready && greeterContentLoader.item.ready
2628
29+ // 1 when fully shown and 0 when fully hidden
30+ property real showProgress: MathLocal.clamp((width + x) / width, 0, 1)
31+
32+ showAnimation: StandardAnimation { property: "x"; to: 0 }
33+ hideAnimation: StandardAnimation { property: "x"; to: -width }
34+
35+ property alias dragHandleWidth: dragHandle.width
2736 property alias model: greeterContentLoader.model
2837 property bool locked: shown && multiUser && !greeterContentLoader.promptless
2938
@@ -39,7 +48,7 @@ Showable {
3948 signal unlocked(int uid)
4049
4150 onRightTeaserPressedChanged: {
42− if (rightTeaserPressed) {
51+ if (rightTeaserPressed && !locked) {
4352 teasingTimer.start();
4453 }
4554 }
@@ -72,7 +81,7 @@ Showable {
7281 states: [
7382 State {
7483 name: "teasing"
75− when: greeter.rightTeaserPressed || teasingTimer.running
84+ when: teasingTimer.running
7685 PropertyChanges {
7786 target: greeter
7887 x: -units.gu(2)
@@ -91,4 +100,21 @@ Showable {
91100 }
92101 }
93102 ]
103+
104+ DragHandle {
105+ id: dragHandle
106+
107+ anchors.top: parent.top
108+ anchors.bottom: parent.bottom
109+ anchors.right: parent.right
110+
111+ // no need for requiring a directional drag since we are covering the screen
112+ // anyway (i.e., no change user could be trying to interact with some other
113+ // UI element)
114+ distanceThreshold: 0
115+
116+ enabled: !greeter.locked
117+
118+ direction: Direction.Leftwards
119+ }
94120}
Greeter/GreeterContent.qml+4−1
@@ -80,7 +80,9 @@ MouseArea {
8080 source: greeter.narrowMode ? "" : "LoginList.qml"
8181
8282 onLoaded: {
83− item.currentIndex = greeterContentLoader.currentIndex
83+ item.currentIndex = greeterContentLoader.currentIndex;
84+ selected(item.currentIndex);
85+ item.resetAuthentication();
8486 }
8587
8688 Binding {
@@ -122,6 +124,7 @@ MouseArea {
122124
123125 function updateUsername(uid) {
124126 greeterContentLoader.infographicModel.username = greeterContentLoader.model.data(uid, LightDM.UserRoles.NameRole)
127+ greeterContentLoader.infographicModel.readyForDataChangeSlot();
125128 }
126129
127130 anchors {
Greeter/Lockscreen.qml+7−1
@@ -41,7 +41,14 @@ Showable {
4141 signal cancel()
4242 signal emergencyCall()
4343
44+ onRequiredChanged: {
45+ if (required && pinPadLoader.item) {
46+ pinPadLoader.item.clear(false);
47+ }
48+ }
49+
4450 function reset() {
51+ // This causes the loader below to destry and recreate the source
4552 pinPadLoader.resetting = true;
4653 pinPadLoader.resetting = false;
4754 }
@@ -140,7 +147,6 @@ Showable {
140147 }
141148 if (LightDM.Greeter.authenticated) {
142149 root.unlocked();
143− pinPadLoader.item.clear(false);
144150 } else {
145151 pinPadLoader.item.clear(true);
146152 }
Greeter/LoginList.qml−8
@@ -66,14 +66,6 @@ Item {
6666
6767 readonly property bool movingInternally: moveTimer.running || userList.moving
6868
69− onCountChanged: {
70− // Start authentication when we start up
71− if (!LightDM.Greeter.authenticationUser && userList.currentItem) {
72− root.selected(userList.currentIndex);
73− root.resetAuthentication();
74− }
75− }
76−
7769 onCurrentIndexChanged: {
7870 if (LightDM.Greeter.authenticationUser != userList.model.data(currentIndex, LightDM.UserRoles.NameRole)) {
7971 root.resetAuthentication();
Greeter/graphics/dot_empty.png

Binary file not shown.

Greeter/graphics/dot_filled.png

Binary file not shown.

Greeter/graphics/dot_pointer.png

Binary file not shown.

Greeter/graphics/infographic_circle.png

Binary file not shown.

Hud/SearchBar.qml−7
@@ -55,13 +55,6 @@ Item {
5555 }
5656 }
5757
58− // Don't let the style play with our opacity
59− Binding {
60− target: searchBar.ItemStyle.style
61− property: "opacity"
62− value: 1
63− }
64−
6558 Item {
6659 id: primary
6760 height: searchBar.height
Hud/ToolBarIcon.qml+1−3
@@ -17,9 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919
20−Button {
21− ItemStyle.class: "transparent-button"
22−
20+AbstractButton {
2321 property alias source: image.source
2422
2523 height: units.gu(4)
Hud/graphics/hud_bg@20.png

Binary file not shown.

Hud/graphics/hud_handlearrow@20.png

Binary file not shown.

Hud/graphics/hud_handlebar@20.png

Binary file not shown.

Hud/graphics/icon_clear@20.png

Binary file not shown.

Hud/graphics/icon_search@20.png

Binary file not shown.

LGPL_EXCEPTION.txtnew file+22
@@ -0,0 +1,22 @@
1+Digia Qt LGPL Exception version 1.1
2+
3+As an additional permission to the GNU Lesser General Public License version
4+2.1, the object code form of a "work that uses the Library" may incorporate
5+material from a header file that is part of the Library. You may distribute
6+such object code under terms of your choice, provided that:
7+ (i) the header files of the Library have not been modified; and
8+ (ii) the incorporated material is limited to numerical parameters, data
9+ structure layouts, accessors, macros, inline functions and
10+ templates; and
11+ (iii) you comply with the terms of Section 6 of the GNU Lesser General
12+ Public License version 2.1.
13+
14+Moreover, you may apply this exception to a modified version of the Library,
15+provided that such modification does not involve copying material from the
16+Library into the modified Library's header files unless such material is
17+limited to (i) numerical parameters; (ii) data structure layouts;
18+(iii) accessors; and (iv) small macros, templates and inline functions of
19+five lines or less in length.
20+
21+Furthermore, you are not required to apply this additional permission to a
22+modified version of the Library.
Launcher/Launcher.qml+9−17
@@ -25,7 +25,6 @@ Item {
2525
2626 property bool available: true // can be used to disable all interactions
2727
28− property bool teasing: false
2928 property int panelWidth: units.gu(8.5)
3029 property int dragAreaWidth: units.gu(1)
3130 property real progress: dragArea.dragging && dragArea.touchX > panel.width ? dragArea.touchX : 0
@@ -50,7 +49,7 @@ Item {
5049 }
5150
5251 function hide() {
53− state = ""
52+ switchToNextState("")
5453 }
5554
5655 function switchToNextState(state) {
@@ -58,8 +57,8 @@ Item {
5857 animateTimer.start();
5958 }
6059
61− onTeasingChanged: {
62− if (teasing) {
60+ function tease() {
61+ if (available) {
6362 teaseTimer.start();
6463 }
6564 }
@@ -181,18 +180,11 @@ Item {
181180 }
182181 }
183182
184− DirectionalDragArea {
183+ EdgeDragArea {
185184 id: dragArea
186185
187186 direction: Direction.Rightwards
188187
189− // values to be tweaked and later removed from here and set in stone as defaults
190− // once we are confident it's all good.
191− maxDeviation: units.gu(1)
192− wideningAngle: 30
193− distanceThreshold: units.gu(3)
194− minSpeed: units.gu(5)
195−
196188 enabled: root.available && root.state !== "visible"
197189 width: root.dragAreaWidth
198190 height: root.height
@@ -215,11 +207,11 @@ Item {
215207
216208 onDraggingChanged: {
217209 if (!dragging) {
218− if (distance > root.width / 2) {
219− root.dash()
220− root.switchToNextState("")
221− } else if (distance > panel.width/2) {
210+ if (distance > panel.width / 2) {
222211 root.switchToNextState("visible")
212+ if (distance > panel.width * 2) {
213+ root.dash()
214+ }
223215 } else {
224216 root.switchToNextState("")
225217 }
@@ -244,7 +236,7 @@ Item {
244236 },
245237 State {
246238 name: "teasing"
247− when: root.teasing || teaseTimer.running
239+ when: teaseTimer.running
248240 PropertyChanges {
249241 target: panel
250242 x: -root.panelWidth + units.gu(2)
Launcher/LauncherDelegate.qml+202−39
@@ -25,6 +25,8 @@ Item {
2525 property real angle: 0
2626 property bool highlighted: false
2727 property real offset: 0
28+ property alias brightness: transformEffect.brightness
29+ property real itemOpacity: 1
2830
2931 property real maxAngle: 0
3032 property bool inverted: false
@@ -32,74 +34,237 @@ Item {
3234 readonly property int effectiveHeight: Math.cos(angle * Math.PI / 180) * height
3335 readonly property real foldedHeight: Math.cos(maxAngle * Math.PI / 180) * height
3436
35− property int itemsBeforeThis: 0
36− property int itemsAfterThis: 0
37−
3837 property bool dragging:false
3938
4039 signal clicked()
4140 signal longtap()
4241 signal released()
4342
44− UbuntuShape {
43+ Item {
4544 id: iconItem
46− color: Qt.rgba(0, 0, 1, 0.5)
4745 width: parent.width
4846 height: parent.height
4947 anchors.centerIn: parent
50− anchors.verticalCenterOffset: root.offset + (height - root.effectiveHeight)/2 * (angle < 0 ? -1 : 1)
51− rotation: root.inverted ? 180 : 0
52− radius: "medium"
53−
54− transform: Rotation {
55− axis { x: 1; y: 0; z: 0 }
56− origin { x: iconItem.width / 2; y: iconItem.height / 2; z: 0 }
57− angle: root.angle
58− }
59−
60− image: Image {
61− source: "../graphics/applicationIcons/" + root.iconName + ".png"
62− }
6348
64− MouseArea {
65− id: mouseArea
49+ UbuntuShape {
50+ id: iconShape
6651 anchors.fill: parent
67− onClicked: root.clicked()
68− onCanceled: root.released()
69− preventStealing: false
52+ anchors.margins: units.gu(0.5)
53+ radius: "medium"
7054
71− onPressAndHold: {
72− root.state = "moving"
55+ image: Image {
56+ id: iconImage
57+ sourceSize.width: iconShape.width
58+ sourceSize.height: iconShape.height
59+ source: "../graphics/applicationIcons/" + root.iconName + ".png"
7360 }
74− onReleased: {
75− root.state = "docked"
61+
62+ MouseArea {
63+ id: mouseArea
64+ anchors.fill: parent
65+ onClicked: root.clicked()
66+ onCanceled: root.released()
67+ preventStealing: false
68+ enabled: root.angle < 5
69+
70+ onPressAndHold: {
71+ root.state = "moving"
72+ }
73+ onReleased: {
74+ root.state = "docked"
75+ }
7676 }
7777 }
78−
7978 BorderImage {
8079 id: overlayHighlight
8180 anchors.centerIn: iconItem
8281 rotation: inverted ? 180 : 0
83− source: root.highlighted || mouseArea.pressed ? "graphics/selected.sci" : "graphics/non-selected.sci"
84− width: iconItem.width + units.gu(1.5)
82+ source: isSelected ? "graphics/selected.sci" : "graphics/non-selected.sci"
83+ width: root.width + units.gu(0.5)
8584 height: width
85+ property bool isSelected: root.highlighted || mouseArea.pressed
86+ onIsSelectedChanged: shaderEffectSource.scheduleUpdate();
8687 }
8788 }
8889
90+ ShaderEffect {
91+ id: transformEffect
92+ anchors.centerIn: parent
93+ anchors.verticalCenterOffset: root.offset
94+ width: parent.width
95+ height: parent.height
96+ property real itemOpacity: root.itemOpacity
97+ property real brightness: 0
98+ property real angle: root.angle
99+ rotation: root.inverted ? 180 : 0
100+
101+
102+ property variant source: ShaderEffectSource {
103+ id: shaderEffectSource
104+ sourceItem: iconItem
105+ hideSource: true
106+ live: false
107+ }
108+
109+ transform: [
110+ // Rotating 3 times at top/bottom because that increases the perspective.
111+ // This is a hack, but as QML does not support real 3D coordinates
112+ // getting a higher perspective can only be done by a hack. This is the most
113+ // readable/understandable one I could come up with.
114+ Rotation {
115+ axis { x: 1; y: 0; z: 0 }
116+ origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
117+ angle: root.angle * 0.7
118+ },
119+ Rotation {
120+ axis { x: 1; y: 0; z: 0 }
121+ origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
122+ angle: root.angle * 0.7
123+ },
124+ Rotation {
125+ axis { x: 1; y: 0; z: 0 }
126+ origin { x: iconItem.width / 2; y: angle > 0 ? 0 : iconItem.height; z: 0 }
127+ angle: root.angle * 0.7
128+ },
129+ // Because rotating it 3 times moves it more to the front/back, i.e. it gets
130+ // bigger/smaller and we need a scale to compensate that again.
131+ Scale {
132+ xScale: 1 - (Math.abs(angle) / 500)
133+ yScale: 1 - (Math.abs(angle) / 500)
134+ origin { x: iconItem.width / 2; y: iconItem.height / 2}
135+ }
136+ ]
137+
138+ // Using a fragment shader instead of QML's opacity and BrightnessContrast
139+ // to be able to do both in one step which gives quite some better performance
140+ fragmentShader: "
141+ varying highp vec2 qt_TexCoord0;
142+ uniform sampler2D source;
143+ uniform lowp float brightness;
144+ uniform lowp float itemOpacity;
145+ void main(void)
146+ {
147+ highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
148+ sourceColor.rgb = mix(sourceColor.rgb, vec3(step(0.0, brightness)), abs(brightness));
149+ sourceColor *= itemOpacity;
150+ gl_FragColor = sourceColor;
151+ }"
152+ }
153+
154+ QtObject {
155+ id: priv
156+
157+ property ListView listView: root.ListView.view
158+ property real totalUnfoldedHeight: listView.itemSize + listView.spacing
159+ property real totalEffectiveHeight: effectiveHeight + listView.spacing
160+ property real effectiveContentY: listView.contentY - listView.originY
161+ property real effectiveY: y - listView.originY
162+ property real distanceFromTopEdge: -(effectiveContentY + listView.topMargin - index*totalUnfoldedHeight)
163+ property real distanceFromBottomEdge: listView.height - listView.bottomMargin - (effectiveY+height) + effectiveContentY
164+
165+ property real distanceFromEdge: Math.abs(distanceFromBottomEdge) < Math.abs(distanceFromTopEdge) ? distanceFromBottomEdge : distanceFromTopEdge
166+ property real orientationFlag: Math.abs(distanceFromBottomEdge) < Math.abs(distanceFromTopEdge) ? -1 : 1
167+
168+ property real overlapWithFoldingArea: listView.foldingAreaHeight - distanceFromEdge
169+ }
170+
89171 states: [
90172 State {
91173 name: "docked"
92174 PropertyChanges {
93175 target: root
94− offset: if (launcherFlickable.contentY > itemsBeforeThis * (foldedHeight + launcherColumn.spacing*2)) {
95− return launcherFlickable.contentY - (index * (foldedHeight + launcherColumn.spacing*2));
96− } else if (y + height - launcherFlickable.contentY > launcherFlickable.height - (itemsAfterThis*(foldedHeight - launcherColumn.spacing))) {
97− return launcherFlickable.height - (y+height) + launcherFlickable.contentY - (itemsAfterThis*(foldedHeight - launcherColumn.spacing));
98− } else {
99− return 0;
176+
177+ // This is the offset that keeps the items inside the panel
178+ offset: {
179+ // First/last items are special
180+ if (index == 0 || index == priv.listView.count-1) {
181+ // Just keep them bound to the edges in case they're outside of the visible area
182+ if (priv.distanceFromEdge < 0) {
183+ return (-priv.distanceFromEdge - (height - effectiveHeight)) * priv.orientationFlag;
184+ }
185+ return 0;
186+ }
187+
188+ // Are we already completely outside the flickable? Stop the icon here.
189+ if (priv.distanceFromEdge < -priv.totalUnfoldedHeight) {
190+ return (-priv.distanceFromEdge - (root.height - effectiveHeight)) * priv.orientationFlag;
191+ }
192+
193+ // We're touching the edge, move slower than the actual flicking speed.
194+ if (priv.distanceFromEdge < 0) {
195+ return (Math.abs(priv.distanceFromEdge) * priv.totalEffectiveHeight / priv.totalUnfoldedHeight) * priv.orientationFlag
196+ }
197+ return 0;
198+ }
199+
200+ // The angle used for rotating
201+ angle: {
202+ // First/last items are special
203+ if (index == 0 || index == priv.listView.count-1) {
204+ if (priv.distanceFromEdge < 0) {
205+ // proportion equation: distanceFromTopEdge : angle = totalUnfoldedHeight/2 : maxAngle
206+ return Math.max(-maxAngle, priv.distanceFromEdge * maxAngle / (priv.listView.foldingAreaHeight)) * priv.orientationFlag
100207 }
101− angle: -Math.min(Math.max(offset * maxAngle / foldedHeight, -maxAngle), maxAngle)
208+ return 0; // Don't fold first/last item as long as inside the view
209+ }
102210
211+ // Are we in the already completely outside the flickable? Fold for the last 5 degrees
212+ if (priv.distanceFromEdge < 0) {
213+ // proportion equation: -distanceFromTopEdge : angle = totalUnfoldedHeight : 5
214+ return Math.max(-maxAngle, (priv.distanceFromEdge * 5 / priv.listView.foldingAreaHeight) - (maxAngle-5)) * priv.orientationFlag
215+ }
216+
217+ // We are overlapping with the folding area, fold the icon to maxAngle - 5 degrees
218+ if (priv.overlapWithFoldingArea > 0) {
219+ // proportion equation: overlap: totalHeight = angle : (maxAngle - 5)
220+ return -priv.overlapWithFoldingArea * (maxAngle -5) / priv.listView.foldingAreaHeight * priv.orientationFlag;
221+ }
222+ return 0;
223+ }
224+
225+ itemOpacity: {
226+ // First/last items are special
227+ if (index == 0 || index == priv.listView.count-1) {
228+ if (priv.distanceFromEdge < 0) {
229+ // Fade from 1 to 0 in the distance of 3 * foldingAreaHeight (which is when the next item reaches the edge)
230+ return 1.0 - (-priv.distanceFromEdge / (priv.listView.foldingAreaHeight * 3))
231+ }
232+ return 1; // Don't make first/last item transparent as long as inside the view
233+ }
234+
235+ // Are we already completely outside the flickable? Fade from 0.75 to 0 in 2 items height
236+ if (priv.distanceFromEdge < 0) {
237+ // proportion equation: -distanceFromEdge : 1-opacity = totalUnfoldedHeight : 0.75
238+ return 0.75 - (-priv.distanceFromEdge * 0.75 / (priv.totalUnfoldedHeight*2))
239+ }
240+
241+ // We are overlapping with the folding area, fade out to 0.75
242+ if (priv.overlapWithFoldingArea > 0) {
243+ // proportion equation: overlap : totalHeight = 1-opacity : 0.25
244+ return 1 - (priv.overlapWithFoldingArea * 0.25 / priv.listView.foldingAreaHeight)
245+ }
246+ return 1;
247+ }
248+
249+ brightness: {
250+ // First/last items are special
251+ if (index == 0 || index == priv.listView.count-1) {
252+ if (priv.distanceFromEdge < 0) {
253+ return -(-priv.distanceFromEdge / (priv.listView.foldingAreaHeight * 3))
254+ }
255+ return 0;
256+ }
257+ // Are we already completely outside the flickable? Fade from 0.7 to 0 in 2 items height
258+ if (priv.distanceFromEdge < 0) {
259+ return -0.3 - (-priv.distanceFromEdge * 0.1 / (priv.totalUnfoldedHeight*2))
260+ }
261+
262+ // We are overlapping with the folding area, fade out to 0.7
263+ if (priv.overlapWithFoldingArea > 0) {
264+ return - (priv.overlapWithFoldingArea * 0.3 / priv.listView.foldingAreaHeight)
265+ }
266+ return 0;
267+ }
103268 }
104269 },
105270
@@ -121,7 +286,5 @@ Item {
121286 drag.target: root
122287 }
123288 }
124−
125289 ]
126−
127290}
Launcher/LauncherPanel.qml+106−52
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Unity 0.1
20+import "../Components/ListItems"
2021
2122Item {
2223 id: root
@@ -26,7 +27,7 @@ Item {
2627 property var model
2728 property bool inverted: true
2829 property bool dragging: false
29− property bool moving: launcherFlickable.moving
30+ property bool moving: launcherListView.moving || launcherListView.flicking
3031 property int dragPosition: 0
3132 property int highlightIndex: -1
3233
@@ -34,23 +35,23 @@ Item {
3435 signal dashItemSelected(int index)
3536
3637 onDragPositionChanged: {
37− var effectiveDragPosition = root.inverted ? launcherFlickable.height - dragPosition : dragPosition - mainColumn.anchors.margins
38+ var effectiveDragPosition = root.inverted ? launcherListView.height - dragPosition : dragPosition - mainColumn.anchors.margins
3839
39− var hiddenContentHeight = launcherFlickable.contentHeight - launcherFlickable.height
40+ var hiddenContentHeight = launcherListView.contentHeight - launcherListView.height
4041 // Shortening scrollable height because the first/last item needs to be fully expanded before reaching the top/bottom
41− var scrollableHeight = launcherFlickable.height - (launcherFlickable.itemSize + launcherColumn.spacing) *2
42+ var scrollableHeight = launcherListView.height - (launcherListView.itemSize + launcherColumn.spacing) *2
4243 // As we shortened the scrollableHeight, lets move everything down by the itemSize
43− var shortenedEffectiveDragPosition = effectiveDragPosition - launcherFlickable.itemSize - launcherColumn.spacing
44+ var shortenedEffectiveDragPosition = effectiveDragPosition - launcherListView.itemSize - launcherColumn.spacing
4445 var newContentY = shortenedEffectiveDragPosition * hiddenContentHeight / scrollableHeight
4546
4647 // limit top/bottom to prevent overshooting
47− launcherFlickable.contentY = Math.min(hiddenContentHeight, Math.max(0, newContentY));
48+ launcherListView.contentY = Math.min(hiddenContentHeight, Math.max(0, newContentY));
4849
4950 // Now calculate the current index:
5051 // > the current mouse position + the hidden/scolled content on top is the mouse position in the averall view
5152 // > adjust that removing all the margins
5253 // > divide by itemSize to get index
53− highlightIndex = (effectiveDragPosition + launcherFlickable.contentY - mainColumn.anchors.margins*3 - launcherColumn.spacing/2) / (launcherFlickable.itemSize + launcherColumn.spacing)
54+ highlightIndex = (effectiveDragPosition + launcherListView.contentY - mainColumn.anchors.margins*3 - launcherColumn.spacing/2) / (launcherListView.itemSize + launcherColumn.spacing)
5455 }
5556
5657 BorderImage {
@@ -61,58 +62,111 @@ Item {
6162
6263 Column {
6364 id: mainColumn
64− anchors.fill: parent
65− anchors.margins: units.gu(1)
66− spacing: units.gu(1)
65+ anchors {
66+ fill: parent
67+ topMargin: units.gu(0.5)
68+ bottomMargin: units.gu(1)
69+ leftMargin: units.gu(0.5)
70+ rightMargin: units.gu(0.5)
71+ }
72+ spacing: units.gu(0.5)
6773
68− LauncherDelegate {
74+ MouseArea {
6975 id: dashItem
70− objectName: "dashItem"
71− width: launcherFlickable.itemSize
72− height: launcherFlickable.itemSize
73− anchors.horizontalCenter: parent.horizontalCenter
74− iconName: "dash"
76+ width: parent.width
77+ height: units.gu(6.5)
7578 onClicked: root.dashItemSelected(0)
79+ z: 1
80+ Image {
81+ objectName: "dashItem"
82+ width: units.gu(5.5)
83+ height: width
84+ anchors.centerIn: parent
85+ source: "graphics/home.png"
86+ }
7687 }
77− Flickable {
78− id: launcherFlickable
88+ ThinDivider {
89+ anchors {
90+ left: parent.left
91+ right: parent.right
92+ margins: -mainColumn.anchors.leftMargin
93+ }
94+ rotation: root.rotation
95+ }
96+
97+ Item {
7998 anchors.left: parent.left
8099 anchors.right: parent.right
81− height: parent.height - dashItem.height - parent.spacing
82− contentHeight: launcherColumn.height
83−
84− property int itemSize: width
85−
86− Column {
87− id: launcherColumn
88− width: parent.width
89− spacing: units.gu(1)
90− anchors.horizontalCenter: parent.horizontalCenter
91−
92− Repeater {
93− id: iconRepeater
94− model: root.model
95−
96− LauncherDelegate {
97− id: launcherDelegate
98− objectName: "launcherDelegate" + index
99− width: launcherFlickable.itemSize
100− height: launcherFlickable.itemSize
101− iconName: model.icon
102− inverted: root.inverted
103− highlighted: root.dragging && index === root.highlightIndex
104− z: -Math.abs(offset)
105− state: "docked"
106−
107− maxAngle: 60
108−
109− itemsBeforeThis: index
110− itemsAfterThis: iconRepeater.count - (index+1)
111−
112− onClicked: {
113− root.applicationSelected(launcherModel.get(index).desktopFile);
114− }
100+ height: parent.height - dashItem.height - parent.spacing*2
101+ ListView {
102+ id: launcherListView
103+ anchors.fill: parent
104+ anchors.topMargin: -itemSize
105+ anchors.bottomMargin: -itemSize
106+ topMargin: itemSize
107+ bottomMargin: itemSize
108+ height: parent.height - dashItem.height - parent.spacing*2
109+ model: root.model
110+ cacheBuffer: itemSize * 3
111+ snapMode: ListView.SnapToItem
112+ highlightRangeMode: ListView.ApplyRange
113+ preferredHighlightBegin: (height - itemSize) / 2
114+ preferredHighlightEnd: (height + itemSize) / 2
115+
116+ // The height of the area where icons start getting folded
117+ property int foldingAreaHeight: itemSize * 0.75
118+ property int itemSize: width
119+
120+ Component.onCompleted: {
121+ // This is needed because snapping would partially fold
122+ // the first item on initialisation. This can only be
123+ // overridden by mouse interactions - which is what flick()
124+ // simulates. Setting contentY to 0 would not work because
125+ // of this.
126+ flick(0, units.gu(20))
127+ }
128+
129+ delegate: LauncherDelegate {
130+ id: launcherDelegate
131+ objectName: "launcherDelegate" + index
132+ width: launcherListView.itemSize
133+ height: launcherListView.itemSize
134+ iconName: model.icon
135+ inverted: root.inverted
136+ highlighted: root.dragging && index === root.highlightIndex
137+ z: -Math.abs(offset)
138+ state: "docked"
139+ maxAngle: 60
140+
141+ onClicked: {
142+ root.applicationSelected(launcherModel.get(index).desktopFile);
143+ }
144+ }
145+
146+ MouseArea {
147+ id: topFoldingArea
148+ anchors {
149+ left: parent.left
150+ right: parent.right
151+ top: parent.top
152+ topMargin: launcherListView.topMargin
153+ }
154+ height: launcherListView.itemSize
155+ enabled: launcherListView.contentY > -launcherListView.topMargin
156+ onClicked: launcherListView.flick(0, units.gu(40))
157+ }
158+
159+ MouseArea {
160+ id: bottomFoldingArea
161+ anchors {
162+ left: parent.left
163+ right: parent.right
164+ bottom: parent.bottom
165+ bottomMargin: launcherListView.bottomMargin
115166 }
167+ height: launcherListView.itemSize
168+ enabled: launcherListView.contentHeight - launcherListView.height - launcherListView.contentY > -launcherListView.bottomMargin
169+ onClicked: launcherListView.flick(0, -units.gu(40))
116170 }
117171 }
118172 }
Launcher/graphics/highlight@18.png

Binary file not shown.

Launcher/graphics/home@18.pngnew file

Binary file not shown.

Launcher/graphics/non-selected@18.png

Binary file not shown.

Launcher/graphics/selected@18.png

Binary file not shown.

Launcher/graphics/triangle@18.png

Binary file not shown.

Notifications/Notification.qml+109−12
@@ -30,10 +30,25 @@ UbuntuShape {
3030 property var type
3131 property var notification
3232
33− implicitHeight: childrenRect.height
33+ objectName: "background"
34+ implicitHeight: contentColumn.height + contentColumn.spacing * 2
3435 color: Qt.rgba(0, 0, 0, 0.85)
3536 opacity: 0
3637
38+ clip: true
39+
40+ Behavior on implicitHeight {
41+ id: heightBehavior
42+
43+ enabled: false
44+ UbuntuNumberAnimation {
45+ duration: UbuntuAnimation.SnapDuration
46+ }
47+ }
48+
49+ // delay enabling height behavior until the add transition is complete
50+ onOpacityChanged: if (opacity == 1) heightBehavior.enabled = true
51+
3752 MouseArea {
3853 id: interactiveArea
3954
@@ -52,7 +67,7 @@ UbuntuShape {
5267 top: parent.top
5368 margins: spacing
5469 }
55− height: childrenRect.height + spacing
70+
5671 spacing: units.gu(1)
5772
5873 Row {
@@ -125,30 +140,112 @@ UbuntuShape {
125140 }
126141 }
127142
128− Row {
143+ Item {
129144 id: buttonRow
130145
131146 objectName: "buttonRow"
132− spacing: contentColumn.spacing
133− layoutDirection: Qt.RightToLeft
147+ anchors {
148+ left: parent.left
149+ right: parent.right
150+ }
134151 visible: notification.type == Notification.SnapDecision
152+ height: units.gu(4)
153+
154+ property real buttonWidth: (width - contentColumn.spacing) / 2
155+ property bool expanded
156+
157+ Button {
158+ id: leftButton
159+
160+ objectName: "button1"
161+ width: parent.expanded ? parent.width : parent.buttonWidth
162+ anchors {
163+ top: parent.top
164+ bottom: parent.bottom
165+ }
166+ text: notification.type == Notification.SnapDecision && actionRepeater.count >= 2 ? actionRepeater.itemAt(1).actionLabel : ""
167+ color: "#cdcdcb"
168+ onClicked: {
169+ if (actionRepeater.count > 2) {
170+ buttonRow.expanded = !buttonRow.expanded
171+ } else {
172+ notification.notification.invokeAction(actionRepeater.itemAt(1).actionId)
173+ }
174+ }
175+
176+ Behavior on width {
177+ UbuntuNumberAnimation {
178+ duration: UbuntuAnimation.SnapDuration
179+ }
180+ }
181+ }
182+
183+ Button {
184+ id: rightButton
185+
186+ objectName: "button0"
187+ anchors {
188+ left: leftButton.right
189+ leftMargin: contentColumn.spacing
190+ right: parent.right
191+ }
192+ text: notification.type == Notification.SnapDecision && actionRepeater.count >= 1 ? actionRepeater.itemAt(0).actionLabel : ""
193+ anchors {
194+ top: parent.top
195+ bottom: parent.bottom
196+ }
197+ color: "#d85317"
198+ visible: width > 0
199+ onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
200+ }
201+ }
202+
203+ Column {
204+ objectName: "buttonColumn"
205+ spacing: contentColumn.spacing
135206 anchors {
136207 left: parent.left
137208 right: parent.right
138209 }
139210
211+ // calculate initial position before Column takes over
212+ y: buttonRow.y + buttonRow.height + contentColumn.spacing
213+
214+ visible: notification.type == Notification.SnapDecision
215+ height: buttonRow.expanded ? implicitHeight : 0
216+
140217 Repeater {
141218 id: actionRepeater
219+
142220 model: notification.actions
221+ delegate: Loader {
222+ id: loader
143223
144− Button {
145− objectName: "button" + index
146− color: Positioner.isFirstItem ? "#d85317" : "#cdcdcb"
147− width: (buttonRow.width - buttonRow.spacing) / 2
148− height: units.gu(4)
149− text: label
150224 property string actionId: id
151− onClicked: notification.notification.invokeAction(id)
225+ property string actionLabel: label
226+
227+ anchors {
228+ left: parent.left
229+ right: parent.right
230+ }
231+
232+ Component {
233+ id: actionButton
234+
235+ Button {
236+ objectName: "button" + index
237+ anchors {
238+ left: parent.left
239+ right: parent.right
240+ }
241+
242+ text: loader.actionLabel
243+ height: units.gu(4)
244+ color: "#cdcdcb"
245+ onClicked: notification.notification.invokeAction(loader.actionId)
246+ }
247+ }
248+ sourceComponent: (index == 0 || index == 1) ? undefined : actionButton
152249 }
153250 }
154251 }
Notifications/Notifications.qml+10−13
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import "../Components"
20−import "timings.js" as Timings
2120
2221ListView {
2322 id: notificationList
@@ -40,40 +39,38 @@ ListView {
4039 actions: model.actions
4140 notificationId: model.id
4241 notification: notificationList.model.getRaw(notificationId)
42+
43+ // make sure there's no opacity-difference between the several
44+ // elements in a notification
45+ layer.enabled: add.running || remove.running || populate.running
4346 }
4447
4548 populate: Transition {
46− NumberAnimation {
49+ UbuntuNumberAnimation {
4750 property: "opacity"
4851 to: 1
49− duration: Timings.snapBeat
50− easing.type: Timings.easing
52+ duration: UbuntuAnimation.SnapDuration
5153 }
5254 }
5355
5456 add: Transition {
55− NumberAnimation {
57+ UbuntuNumberAnimation {
5658 property: "opacity"
5759 to: 1
58− duration: Timings.snapBeat
59− easing.type: Timings.easing
60+ duration: UbuntuAnimation.SnapDuration
6061 }
6162 }
6263
6364 remove: Transition {
64− NumberAnimation {
65+ UbuntuNumberAnimation {
6566 property: "opacity"
6667 to: 0
67− duration: Timings.fastBeat
68− easing.type: Timings.easing
6968 }
7069 }
7170
7271 displaced: Transition {
73− NumberAnimation {
72+ UbuntuNumberAnimation {
7473 properties: "x,y"
75− duration: Timings.fastBeat
76− easing.type: Timings.easing
7774 }
7875 }
7976}
Panel/Indicators.qml+111−27
@@ -16,32 +16,49 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19+import Ubuntu.Gestures 0.1
1920import Ubuntu.ChewieUI 0.1 as ChewieUI
2021
2122import "../Components"
23+import "../Components/ListItems"
2224import "../Components/Math.js" as MathLocal
2325
2426Showable {
2527 id: indicators
2628
27− property int progress: panelHeight
28− property int openedHeight: units.gu(71)
29+ property int referenceOpenedHeight: units.gu(71)
30+ property real openedHeight: pinnedMode ? referenceOpenedHeight - panelHeight
31+ : referenceOpenedHeight
2932 property int panelHeight: units.gu(3)
3033 property bool pinnedMode: true //should be set true if indicators menu can cover whole screen
3134
3235 property int hintValue
33− readonly property int lockThreshold: shell.height/2
34− property bool fullyOpened: revealer ? progress == revealer.openedValue : false
35− property bool partiallyOpened: revealer ? progress > revealer.closedValue && progress < revealer.openedValue : false
36+ readonly property int lockThreshold: referenceOpenedHeight / 2
37+ property bool fullyOpened: height == openedHeight
38+ property bool partiallyOpened: height > panelHeight && !fullyOpened
39+
40+ // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
41+ // use its own values. Need to ask design about this.
42+ showAnimation: StandardAnimation {
43+ property: "height"
44+ duration: 350
45+ to: openedHeight
46+ easing.type: Easing.OutCubic
47+ }
3648
37− property Revealer revealer: null
49+ hideAnimation: StandardAnimation {
50+ property: "height"
51+ duration: 350
52+ to: panelHeight
53+ easing.type: Easing.OutCubic
54+ }
3855
39− height: menuContent.height + handle.height + menuContent.y
56+ height: panelHeight
4057
41− onProgressChanged: {
42− // need to use handle.get_height(). As the handle height depends on progress changes (but this is called first!)
43− var contentProgress = progress - handle.get_height()
44− if (!showAnimation.running && !hideAnimation.running && !revealer.hintingAnimation.running) {
58+ onHeightChanged: {
59+ // need to use handle.get_height(). As the handle height depends on indicators.height changes (but this is called first!)
60+ var contentProgress = indicators.height - handle.get_height()
61+ if (!showAnimation.running && !hideAnimation.running) {
4562 if (contentProgress <= hintValue && indicators.state == "reveal") {
4663 indicators.state = "hint"
4764 menuContent.hideAll()
@@ -66,12 +83,6 @@ Showable {
6683 }
6784 }
6885
69− function handlePress() {
70− menuContent.hideAll()
71− menuContent.activateContent()
72− indicators.state = "hint"
73− }
74−
7586 function openOverview() {
7687 indicatorRow.currentItem = null
7788 menuContent.showOverview()
@@ -91,7 +102,9 @@ Showable {
91102 If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
92103 Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
93104 */
94− var verticalProgress = MathLocal.clamp((indicators.progress - handle.height - hintValue) / (lockThreshold - hintValue), 0, 1)
105+ var verticalProgress =
106+ MathLocal.clamp((indicators.height - handle.height - hintValue) /
107+ (lockThreshold - hintValue), 0, 1)
95108
96109 /*
97110 Percentage of an indicator icon's width the user's press can stray horizontally from the
@@ -139,6 +152,17 @@ Showable {
139152 }
140153 }
141154
155+ VerticalThinDivider {
156+ anchors {
157+ top: indicators.top
158+ topMargin: panelHeight
159+ bottom: handle.bottom
160+ right: indicators.left
161+ }
162+ width: units.dp(2)
163+ source: "graphics/VerticalDivider.png"
164+ }
165+
142166 MenuContent {
143167 id: menuContent
144168 objectName: "menuContent"
@@ -147,8 +171,8 @@ Showable {
147171 left: parent.left
148172 right: parent.right
149173 top: indicatorRow.bottom
174+ bottom: parent.bottom
150175 }
151− height: progress - y
152176 indicatorsModel: indicatorsModel
153177 animate: false
154178 clip: indicators.partiallyOpened
@@ -187,7 +211,7 @@ Showable {
187211 clip: height < handleImage.height
188212
189213 function get_height() {
190− return Math.max(Math.min(handleImage.height, progress - handleImage.height), 0)
214+ return Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
191215 }
192216
193217 BorderImage {
@@ -205,6 +229,29 @@ Showable {
205229 }
206230 }
207231
232+ PanelSeparatorLine {
233+ id: indicatorsSeparatorLine
234+ visible: true
235+ anchors {
236+ top: handle.bottom
237+ left: indicators.left
238+ right: indicators.right
239+ }
240+ }
241+
242+ BorderImage {
243+ id: dropShadow
244+ anchors {
245+ top: indicators.top
246+ bottom: indicatorsSeparatorLine.bottom
247+ left: indicators.left
248+ right: indicators.right
249+ margins: -units.gu(1)
250+ }
251+ visible: indicators.height > panelHeight
252+ source: "graphics/rectangular_dropshadow.sci"
253+ }
254+
208255 PanelBackground {
209256 anchors.fill: indicatorRow
210257 }
@@ -249,7 +296,7 @@ Showable {
249296 openOverview()
250297 }
251298 else {
252− indicators.calculateCurrentItem(revealer.lateralPosition, false)
299+ indicators.calculateCurrentItem(dragHandle.touchX, false)
253300 menuContent.showMenu()
254301 }
255302 indicators.state = "commit"
@@ -258,10 +305,10 @@ Showable {
258305 }
259306
260307 Connections {
261− target: revealer
262− onLateralPositionChanged: {
263− var buffer = revealer.dragging ? true : false
264− indicators.calculateCurrentItem(revealer.lateralPosition, buffer)
308+ target: dragHandle
309+ onTouchXChanged: {
310+ var buffer = dragHandle.dragging ? true : false
311+ indicators.calculateCurrentItem(dragHandle.touchX, buffer)
265312 }
266313 }
267314
@@ -277,6 +324,43 @@ Showable {
277324 state = last_state;
278325 }
279326
327+ property var dragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle
328+ DragHandle {
329+ id: showDragHandle
330+ anchors.bottom: parent.bottom
331+ // go beyond parent so that it stays reachable, at the top of the screen.
332+ anchors.bottomMargin: pinnedMode ? 0 : -panelHeight
333+ anchors.left: parent.left
334+ anchors.right: parent.right
335+ height: panelHeight
336+ direction: Direction.Downwards
337+ enabled: !indicators.shown
338+ hintDisplacement: pinnedMode ? indicators.hintValue : 0
339+ autoCompleteDragThreshold: maxTotalDragDistance / 2
340+ stretch: true
341+ maxTotalDragDistance: openedHeight - handle.height
342+ distanceThreshold: pinnedMode ? 0 : units.gu(3)
343+
344+ onStatusChanged: {
345+ if (status === DirectionalDragArea.Recognized) {
346+ menuContent.hideAll()
347+ menuContent.activateContent()
348+ }
349+ }
350+ }
351+ DragHandle {
352+ id: hideDragHandle
353+ anchors.fill: handle
354+ height: panelHeight
355+ direction: Direction.Upwards
356+ enabled: indicators.shown
357+ hintDisplacement: units.gu(2)
358+ autoCompleteDragThreshold: maxTotalDragDistance / 6
359+ stretch: true
360+ maxTotalDragDistance: referenceOpenedHeight - 2*panelHeight
361+ distanceThreshold: 0
362+ }
363+
280364 property list<State> offScreenModeStates: [
281365 State {
282366 name: "initial"
@@ -289,7 +373,7 @@ Showable {
289373 name: "reveal"
290374 extend: "hint"
291375 PropertyChanges { target: menuContent; animate: true }
292− StateChangeScript { script: calculateCurrentItem(revealer.lateralPosition, false); }
376+ StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
293377 },
294378 State {
295379 name: "locked"
@@ -311,7 +395,7 @@ Showable {
311395 State {
312396 name: "reveal"
313397 PropertyChanges { target: menuContent; animate: true }
314− StateChangeScript { script: calculateCurrentItem(revealer.lateralPosition, false); }
398+ StateChangeScript { script: calculateCurrentItem(dragHandle.touchX, false); }
315399 },
316400 State {
317401 name: "locked"
Panel/MenuContent.qml+1−1
@@ -98,7 +98,7 @@ Rectangle {
9898 visible: content.__shown
9999 onVisibleChanged: {
100100 // Reset the indicator states
101− if (!visible && item) {
101+ if (!visible && item && item["reset"]) {
102102 item.reset()
103103 }
104104 }
Panel/Panel.qml+3−74
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import "../Components"
20−import "../Components/ListItems"
2120
2221Item {
2322 id: root
@@ -75,29 +74,6 @@ Item {
7574 }
7675 }
7776
78− BorderImage {
79− id: dropShadow
80− anchors {
81− top: indicatorsMenu.top
82− bottom: indicatorsSeparatorLine.bottom
83− left: indicatorsMenu.left
84− right: indicatorsMenu.right
85− margins: -units.gu(1)
86− }
87− visible: indicatorsMenu.progress != indicatorRevealer.closedValue
88− source: "graphics/rectangular_dropshadow.sci"
89− }
90−
91− VerticalThinDivider {
92− anchors {
93− top: leftSeparatorLine.top
94− bottom: indicatorsSeparatorLine.top
95− right: indicatorsMenu.left
96− }
97− width: units.dp(2)
98− source: "graphics/VerticalDivider.png"
99− }
100−
10177 Indicators {
10278 id: indicatorsMenu
10379
@@ -105,58 +81,13 @@ Item {
10581 y: 0
10682 width: root.indicatorsMenuWidth
10783 shown: false
108− revealer: indicatorRevealer
109− hintValue: indicatorRevealer.hintDisplacement
84+ hintValue: __panelMinusSeparatorLineHeight * 3
11085 panelHeight: __panelMinusSeparatorLineHeight
111− showAnimation: StandardAnimation { property: "progress"; duration: 350; to: indicatorRevealer.openedValue; easing.type: Easing.OutCubic }
112− hideAnimation: StandardAnimation { property: "progress"; duration: 350; to: indicatorRevealer.closedValue; easing.type: Easing.OutCubic }
113− openedHeight: parent.height
86+ referenceOpenedHeight: parent.height
11487
11588 pinnedMode: !fullscreenMode
11689
117− property real unitProgress: (indicatorRevealer.closedValue - progress) / (indicatorRevealer.closedValue - indicatorRevealer.openedValue)
118− }
119−
120− PanelSeparatorLine {
121− id: indicatorsSeparatorLine
122− anchors {
123− top: indicatorsMenu.bottom
124− left: indicatorsMenu.left
125− right: parent.right
126− }
127− }
128−
129− Revealer {
130− id: indicatorRevealer
131− objectName: "indicatorRevealer"
132−
133− width: root.indicatorsMenuWidth
134− anchors {
135− top: parent.top
136− bottom: parent.bottom
137− right: parent.right
138− }
139− target: indicatorsMenu
140− handleSize: __panelMinusSeparatorLineHeight
141− closedValue: __panelMinusSeparatorLineHeight
142− dragVelocityThreshold: units.dp(1)
143− boundProperty: "progress"
144− hintDisplacement: __panelMinusSeparatorLineHeight * 3
145− openOnPress: !fullscreenMode
146− orientation: Qt.Vertical
147−
148− onOpenClicked: {
149− indicatorsMenu.openOverview();
150− indicatorsMenu.show();
151− }
152− onCloseClicked: indicatorsMenu.hide();
153−
154− onOpenPressed: indicatorsMenu.handlePress()
155−
156− function dragToValue(dragPosition) {
157− var offset = target.shown ? 0 : -hintDisplacement + handleSize;
158− return dragPosition + offset;
159− }
90+ property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
16091 }
16192
16293 SearchIndicator {
@@ -192,13 +123,11 @@ Item {
192123 name: "in" //fully opaque and visible at top edge of screen
193124 when: !fullscreenMode
194125 PropertyChanges { target: panelBackground; y: 0 }
195− PropertyChanges { target: indicatorRevealer; openedValue: indicatorsMenu.openedHeight - panelHeight }
196126 },
197127 State {
198128 name: "out" //pushed off screen
199129 when: fullscreenMode
200130 PropertyChanges { target: panelBackground; y: -panelHeight }
201− PropertyChanges { target: indicatorRevealer; openedValue: indicatorsMenu.openedHeight }
202131 }
203132 ]
204133}
Panel/graphics/Battery@18.png

Binary file not shown.

Panel/graphics/Bluetooth@18.png

Binary file not shown.

Panel/graphics/Clock@18.png

Binary file not shown.

Panel/graphics/Location@18.png

Binary file not shown.

Panel/graphics/Messages@18.png

Binary file not shown.

Panel/graphics/Network@18.png

Binary file not shown.

Panel/graphics/Sound@18.png

Binary file not shown.

Panel/graphics/Sync@18.png

Binary file not shown.

Panel/graphics/System@18.png

Binary file not shown.

Panel/graphics/Time@18.png

Binary file not shown.

Panel/graphics/VerticalDivider@18.png

Binary file not shown.

Panel/graphics/rectangular_dropshadow@30.png

Binary file not shown.

Panel/graphics/search@12.png

Binary file not shown.

Shell.qml+46−41
@@ -17,6 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Application 0.1
1919import Ubuntu.Components 0.1
20+import Ubuntu.Gestures 0.1
2021import LightDM 0.1 as LightDM
2122import "Dash"
2223import "Greeter"
@@ -167,7 +168,14 @@ FocusScope {
167168
168169 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
169170 opacity: 1.0 - disappearingAnimationProgress
170− property real disappearingAnimationProgress: ((greeter.shown) ? greeterRevealer.animatedProgress : stagesRevealer.animatedProgress)
171+ property real disappearingAnimationProgress: {
172+ if (greeter.shown) {
173+ return greeter.showProgress;
174+ } else {
175+ return stagesOuterContainer.showProgress;
176+ }
177+ }
178+
171179 // FIXME: only necessary because stagesRevealer.animatedProgress and
172180 // greeterRevealer.animatedProgress are not animated
173181 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
@@ -176,25 +184,29 @@ FocusScope {
176184
177185
178186 Item {
187+ id: stagesOuterContainer
179188
180189 width: parent.width
181190 height: parent.height
182191 x: launcher.progress
183192 Behavior on x {SmoothedAnimation{velocity: 600}}
184193
194+ property real showProgress:
195+ MathLocal.clamp(1 - (x + stages.x) / shell.width, 0, 1)
185196
186197 Showable {
187198 id: stages
188199
189− property bool fullyShown: shown && stages[stagesRevealer.boundProperty] == stagesRevealer.openedValue
190− && parent.x == 0
191− property bool fullyHidden: !shown && stages[stagesRevealer.boundProperty] == stagesRevealer.closedValue
200+ x: width
201+
202+ property bool fullyShown: shown && x == 0 && parent.x == 0
203+ property bool fullyHidden: !shown && x == width
192204 available: !greeter.shown
193205 hides: [launcher, panel.indicators]
194206 shown: false
195207 opacity: 1.0
196− showAnimation: StandardAnimation { property: "x"; duration: 350; to: stagesRevealer.openedValue; easing.type: Easing.OutCubic }
197− hideAnimation: StandardAnimation { property: "x"; duration: 350; to: stagesRevealer.closedValue; easing.type: Easing.OutCubic }
208+ showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
209+ hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
198210
199211 width: parent.width
200212 height: parent.height
@@ -325,24 +337,19 @@ FocusScope {
325337 height: sideStage.height
326338 orientation: Qt.Horizontal
327339 }
328− }
329− }
330340
341+ DragHandle {
342+ id: stagesRevealer
343+
344+ anchors.top: parent.top
345+ anchors.bottom: parent.bottom
346+ anchors.right: parent.left
331347
332− Revealer {
333− id: stagesRevealer
334−
335− property real animatedProgress: MathLocal.clamp((-dragPosition - launcher.progress) / closedValue, 0, 1)
336− enabled: mainStage.applications.count > 0 || sideStage.applications.count > 0
337− direction: Qt.RightToLeft
338− openedValue: 0
339− hintDisplacement: units.gu(3)
340− handleSize: shell.edgeSize
341− closedValue: width
342− target: stages
343− width: stages.width
344− height: stages.height
345− orientation: Qt.Horizontal
348+ width: shell.edgeSize
349+ direction: Direction.Leftwards
350+ enabled: mainStage.applications.count > 0 || sideStage.applications.count > 0
351+ }
352+ }
346353 }
347354
348355 Lockscreen {
@@ -379,7 +386,7 @@ FocusScope {
379386 } else {
380387 lockscreen.alphaNumeric = true
381388 }
382− lockscreen.placeholderText = i18n.tr("Please enter %1:").arg(text);
389+ lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
383390 lockscreen.show();
384391 }
385392 }
@@ -391,12 +398,13 @@ FocusScope {
391398 available: true
392399 hides: [launcher, panel.indicators, hud]
393400 shown: true
394− showAnimation: StandardAnimation { property: "x"; to: greeterRevealer.openedValue }
395− hideAnimation: StandardAnimation { property: "x"; to: greeterRevealer.closedValue }
401+
396402 y: panel.panelHeight
397403 width: parent.width
398404 height: parent.height - panel.panelHeight
399405
406+ dragHandleWidth: shell.edgeSize
407+
400408 property var previousMainApp: null
401409 property var previousSideApp: null
402410
@@ -431,6 +439,12 @@ FocusScope {
431439 var bgPath = greeter.model.data(uid, LightDM.UserRoles.BackgroundPathRole)
432440 shell.background = bgPath ? bgPath : default_background
433441 }
442+
443+ onLeftTeaserPressedChanged: {
444+ if (leftTeaserPressed) {
445+ launcher.tease();
446+ }
447+ }
434448 }
435449
436450 InputFilterArea {
@@ -438,19 +452,6 @@ FocusScope {
438452 blockInput: greeter.shown || lockscreen.shown
439453 }
440454
441− Revealer {
442− id: greeterRevealer
443−
444− property real animatedProgress: MathLocal.clamp(-dragPosition / closedValue, 0, 1)
445− target: greeter
446− width: greeter.width
447− height: greeter.height
448− handleSize: shell.edgeSize
449− orientation: Qt.Horizontal
450− visible: greeter.shown
451− enabled: !greeter.locked
452− }
453−
454455 Item {
455456 id: overlay
456457
@@ -515,6 +516,8 @@ FocusScope {
515516 theHud: hud
516517 anchors.fill: parent
517518 enabled: !panel.indicators.shown
519+ applicationIsOnForeground: applicationManager.mainStageFocusedApplication
520+ || applicationManager.sideStageFocusedApplication
518521 }
519522
520523 InputFilterArea {
@@ -535,7 +538,6 @@ FocusScope {
535538 width: parent.width
536539 dragAreaWidth: shell.edgeSize
537540 available: !greeter.locked
538− teasing: available && greeter.leftTeaserPressed
539541 onDashItemSelected: {
540542 greeter.hide()
541543 // Animate if moving between application and dash
@@ -547,8 +549,11 @@ FocusScope {
547549 stages.hide();
548550 }
549551 onDash: {
550− dash.setCurrentScope("applications.scope", true, false)
551− stages.hide();
552+ if (stages.shown) {
553+ dash.setCurrentScope("applications.scope", true, false)
554+ stages.hide();
555+ launcher.hide();
556+ }
552557 }
553558 onLauncherApplicationSelected:{
554559 greeter.hide()
build+18−8
@@ -1,10 +1,9 @@
11#!/bin/sh
22
3−PACKAGE=unity8
4−UNITY_BUILD_DIR=$PWD/../unity_build/build
53SETUP=false
64CLEAN=false
75NUM_JOBS=$(( `grep -c ^processor /proc/cpuinfo` + 1 ))
6+CODE_DIR=$( dirname `readlink -f $0` )
87
98usage() {
109 echo "usage: build [OPTIONS] [BUILD_TYPE]\n" >&2
@@ -37,13 +36,26 @@ BUILD_TYPE="debug"
3736[ $# -eq 1 ] && BUILD_TYPE="$1"
3837
3938install_dependencies() {
40− . /etc/lsb-release
4139 [ -f /etc/apt/sources.list.d/phablet-team-desktop-deps-${DISTRIB_CODENAME}.list ] || sudo add-apt-repository ppa:phablet-team/desktop-deps || exit 1
4240 [ -f /etc/apt/sources.list.d/canonical-qt5-edgers-qt5-proper-${DISTRIB_CODENAME}.list ] || sudo add-apt-repository ppa:canonical-qt5-edgers/qt5-proper || exit 2;
4341 [ -f /etc/apt/sources.list.d/ubuntu-sdk-team-ppa-${DISTRIB_CODENAME}.list ] || sudo add-apt-repository ppa:ubuntu-sdk-team/ppa || exit 3
4442 sudo apt-get update || exit 4
4543 echo "Installing Unity 8 dependencies.."
46− sudo apt-get install qtdeclarative5-ubuntu-ui-toolkit-plugin qtdeclarative5-dee-plugin indicators-client indicators-client-plugin-* qtbase5-dev qtbase5-private-dev qtdeclarative5-dev qtdeclarative5-dev-tools qtdeclarative5-test-plugin libdee-qt5-dev libpulse-dev qtdeclarative5-xmllistmodel-plugin unity-lens-mock demo-assets ubuntu-mobile-icons || exit 5
44+ sudo apt-get install devscripts \
45+ equivs \
46+ qtdeclarative5-ubuntu-ui-toolkit-plugin \
47+ qtdeclarative5-dee-plugin \
48+ indicators-client \
49+ indicators-client-plugin-* \
50+ ubuntu-mobile-icons \
51+ unity-notifications-impl-1 \
52+ unity-scope-home \
53+ unity-lens-applications \
54+ || exit 5
55+}
56+
57+mk_build_deps() {
58+ [ ! -f unity8-build-deps*deb -o $CODE_DIR/debian/control -nt unity8-build-deps*deb ] && mk-build-deps --install --root-cmd sudo $CODE_DIR/debian/control
4759}
4860
4961if [ -f "/usr/bin/ninja" ] ; then
@@ -56,13 +68,11 @@ fi
5668
5769if $SETUP; then
5870 install_dependencies
59− ./build_unity --setup || exit 1$?
60− ./build_unity || exit 1$?
6171else
6272 if $CLEAN; then rm -rf builddir; fi
6373 mkdir -p builddir
6474 cd builddir
65− PKG_CONFIG_PATH=$UNITY_BUILD_DIR/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE .. ${GENERATOR} || exit 6
75+ mk_build_deps
76+ cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CODE_DIR ${GENERATOR} || exit 6
6677 ${BUILD_COMMAND} || exit 7
6778fi
68−
build_unitydeleted−158
@@ -1,158 +0,0 @@
1−#!/bin/bash
2−
3−TARGET_DIR=$PWD/../unity_build
4−BUILD_DIR=$TARGET_DIR/build
5−SETUP=false
6−UPDATE=false
7−CLEAN=false
8−NUM_JOBS=$(( `grep -c ^processor /proc/cpuinfo` + 1 ))
9−
10−# verified working revisions
11−LIBUNITY_REV=228
12−UNITY_REV=3343
13−HUD_REV=252
14−
15−usage() {
16− echo "usage: build_unity [OPTIONS]\n"
17− echo "Script to build Unity on Ubuntu 12.10.\n"
18− echo "OPTIONS:"
19− echo " -s, --setup Setup the build environment and branch Unity"
20− echo " -u, --update Update Unity's source code"
21− echo " -c, --clean Clean build trees before building"
22− exit 1
23−}
24−
25−set -- `getopt -n$0 -u -a --longoptions="setup,update,clean,help" "such" "$@"`
26−
27−# FIXME: giving incorrect arguments does not call usage and exit
28−while [ $# -gt 0 ]
29−do
30− case "$1" in
31− -s|--setup) SETUP=true;;
32− -u|--update) UPDATE=true;;
33− -c|--clean) CLEAN=true;;
34− -h|--help) usage;;
35− --) shift;break;;
36− esac
37− shift
38−done
39−
40−install_utils() {
41− echo "Installing build utilities.."
42− sudo apt-get install devscripts equivs || exit 4
43−}
44−
45−mk_build_deps() {
46− echo "Installing build dependencies.."
47− cd $TARGET_DIR
48− sudo mk-build-deps -B -i $TARGET_DIR/libunity/debian/control || exit 5
49− sudo mk-build-deps -B -i $TARGET_DIR/unity/debian/control || exit 6
50− sudo mk-build-deps -B -i $TARGET_DIR/hud/debian/control || exit 7
51−}
52−
53−branch_libunity() {
54− echo "Branching libunity.."
55− bzr branch lp:libunity $TARGET_DIR/libunity || exit 8
56−}
57−
58−branch_unity() {
59− echo "Branching Unity.."
60− bzr branch lp:unity $TARGET_DIR/unity || exit 9
61−}
62−
63−branch_hud() {
64− echo "Branching hud.."
65− bzr branch lp:hud $TARGET_DIR/hud || exit 10
66−}
67−
68−update_unity() {
69− echo "Updating Unity.."
70− bzr pull -d $TARGET_DIR/unity || exit 11
71−}
72−
73−update_libunity() {
74− echo "Updating libunity.."
75− bzr pull -d $TARGET_DIR/libunity || exit 12
76−}
77−
78−update_hud() {
79− echo "Updating hud"
80− bzr pull -d $TARGET_DIR/hud || exit 13
81−}
82−
83−compile_libunity() {
84− echo "Configuring libunity.."
85−
86− if $CLEAN; then bzr clean-tree -d $TARGET_DIR/libunity --quiet --unknown --ignored --force; fi
87−
88− cd $TARGET_DIR/libunity
89− bzr revert --quiet -r $LIBUNITY_REV || exit 14
90−
91− mkdir $TARGET_DIR/libunity/build
92− cd $TARGET_DIR/libunity/build
93−
94− ../autogen.sh --prefix $BUILD_DIR --disable-debug --with-pygi-overrides-dir=$BUILD_DIR/gi-overrides || exit 15
95−
96− echo "Building libunity and installing in " $BUILD_DIR
97− make -j$NUM_JOBS install || exit 16
98−
99−}
100−
101−compile_unity_core() {
102− echo "Configuring Unity.."
103−
104− if $CLEAN; then bzr clean-tree -d $TARGET_DIR/unity --quiet --unknown --ignored --force; fi
105−
106− cd $TARGET_DIR/unity
107− bzr revert --quiet -r $UNITY_REV || exit 17
108−
109− mkdir $TARGET_DIR/unity/build
110− cd $TARGET_DIR/unity/build
111−
112− PKG_CONFIG_PATH=$BUILD_DIR/lib/pkgconfig:$PKG_CONFIG_PATH cmake $TARGET_DIR/unity -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$BUILD_DIR -DCOMPIZ_PLUGIN_INSTALL_TYPE=local -DGSETTINGS_LOCALINSTALL=ON || exit 18
113−
114− echo "Building UnityCore and installing in " $BUILD_DIR
115− cd UnityCore
116− make -j$NUM_JOBS install || exit 19
117−
118−}
119−
120−compile_hud() {
121− echo "Configuring hud.."
122−
123− if $CLEAN; then bzr clean-tree -d $TARGET_DIR/hud --quiet --unknown --ignored --force; fi
124−
125− cd $TARGET_DIR/hud
126− bzr revert -r $HUD_REV || exit 20
127−
128− mkdir $TARGET_DIR/hud/build
129− cd $TARGET_DIR/hud/build
130−
131− cmake $TARGET_DIR/hud/ -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$BUILD_DIR -DCMAKE_INSTALL_LIBDIR=lib -DLOCAL_INSTALL=ON -DENABLE_TESTS=OFF || exit 21
132−
133− echo "Building hud and installing in " $BUILD_DIR
134− make install || exit 22
135−
136−}
137−
138−if $SETUP; then
139− echo "Setting up environment for building Unity.."
140− install_utils
141− mkdir -p $TARGET_DIR
142− branch_libunity
143− branch_unity
144− branch_hud
145− mk_build_deps
146−elif $UPDATE; then
147− update_libunity
148− update_unity
149− update_hud
150− mk_build_deps
151−else
152− if $CLEAN; then rm -Rf $BUILD_DIR; fi
153− mkdir -p $BUILD_DIR
154− compile_libunity
155− compile_unity_core
156− compile_hud
157−fi
158−
debian/changelog+122
@@ -1,3 +1,125 @@
1+unity8 (7.81.3+13.10.20130704ubuntu.unity.next-0ubuntu1) saucy; urgency=low
2+
3+ [ Didier Roche ]
4+ * Clean packaging for entering saucy and following daily release guidelines
5+ * Automatic snapshot from revision 49 (bootstrap)
6+
7+ [ Michał Sawicz ]
8+ * Fix unity8.pot file.
9+ * Support the simplified theming from ubuntu-ui-toolkit.
10+ * Use AbstractButtons instead of Button { color: "transparent" } that
11+ doesn't work.
12+
13+ [ Albert Astals ]
14+ * ListViewWithPageHeader implementation in C++. (LP: #1171918)
15+ * LVWPH: Do not crash on showHeader if we don't have a header .
16+ * Fix bug when setting the same model twice to a QLimitProxyModelQML.
17+ * Add some const & Saves us some microseconds in copying stuff.
18+
19+ [ Daniel d'Andrada ]
20+ * Make Greeter and Stage use the new DragHandle component. So they no
21+ longer use Revealers. Now a directional drag gesture is required to
22+ start the animation that brings back a "minimized" application when
23+ the dash is on foreground. Besides that, now they have the following
24+ feature:  - Action only completes succesfully if you drag through at
25+ least half the    screen width or if your swipe is fast enough. The
26+ shorter the swipe, the faster it has to be for the action to auto-
27+ complete.
28+ * DirectionalDragArea: add touchSceneX, touchSceneY, and sceneDistance
29+ properties.
30+ * DirectionalDragArea: emit draggingChanged() on direct recognition
31+ draggingChanged() should be emited when status change from
32+ WaitingForTouch directly to Recognized.
33+ * update CODING instructions for building & running.
34+ * DragHandle: add stretch and hintDisplacement properties.
35+ * DragHandle: fix hinting Revision 64 had a bad interaction with
36+ revision 66 (that added line was lost in the merge/rebase process).
37+ tst_DragHandle::hintingAnimation() points out the problem (fails on
38+ line 388).
39+ * Make Panel use DragHandles instead of a Revealer - A directional
40+ drag gesture is needed reveal the panel when fullscreen. - better
41+ logic for deciding when to auto-complete the show/hide animation -
42+ hinting animation to close the panel - Tapping on menu bar no longer
43+ opens nearest indicator menu - No closing with handle click.
44+
45+ [ mhall119 ]
46+ * Fix build script error from extra blank line. (LP: #1196322)
47+
48+ [ Nick Dedekind ]
49+ * Changed shellImportPath to return a list of paths. Added
50+ prependImportPaths and changed appendImportPaths to check for
51+ duplicates.
52+
53+ [ Mirco Müller ]
54+ * Added support and tests for expanding snap-decisions with more than
55+ 2 actions passed in.
56+
57+ [ Michael Zanetti ]
58+ * As requested by design, decreasing wobblyness in the
59+ WrongPasswordAnimation.
60+ * improve the bzr commit hook - don't run qmltests in here, it takes
61+ too long - don't abort commit on failed tests, its too annoying -
62+ instead, print a fat warning and backup the commit message to be
63+ reused after uncommitting and fixing the tests.
64+ * edge hinting tweaks - change edge hinting behavior to only happen on
65+ onPressed and immediately snap back - fix edge hinting to not happen
66+ if the Greeter is locked .
67+
68+ [ Michael Terry ]
69+ * Fix "Tap to Unlock" text not appearing when in tablet greeter mode
70+ with only one user.
71+ * Use libusermetrics to provide infographic data.
72+ * Delete builddir/ when running "debuild clean".
73+
74+ [ Pawel Stolowski ]
75+ * Bindings for preview and activation requests.
76+
77+ [ Kevin Gunn ]
78+ * update CODING instructions for building & running.
79+
80+ [ Ubuntu daily release ]
81+ * Automatic snapshot from revision 78 (ubuntu-unity/next)
82+
83+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 04 Jul 2013 12:44:19 +0000
84+
85+unity8 (7.81.3) UNRELEASED; urgency=low
86+
87+ * Choose more appropriate values for edge-drag gestures (LP: #1194150)
88+
89+ -- Daniel d'Andrada <daniel.dandrada@canonical.com> Fri, 28 Jun 2013 16:28:24 -0300
90+
91+unity8 (7.81.2) saucy; urgency=low
92+
93+ * Translation updates.
94+
95+ [ Michał Sawicz ]
96+ * Fix icons in ApplicationsFilterGrid.qml.
97+ * Support flipped image in run_on_device.
98+
99+ [ Michael Zanetti ]
100+ * Don't clear lockscreen when it's fading out.
101+ * Reworked Launcher folding.
102+ * Tweak Launcher revealing.
103+
104+ [ Michal Hruby ]
105+ * Add content_type property to category models.
106+
107+ -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 26 Jun 2013 18:10:39 +0200
108+
109+unity8 (7.81.1) saucy; urgency=low
110+
111+ * Translation updates.
112+
113+ [ Michał Sawicz ]
114+ * Don't limit installed apps.
115+ * Pre-optimize PNGs to speed-up builds.
116+ * Clean up build scripts.
117+
118+ [ Daniel d'Andrada ]
119+ * Use DirectionalDragArea in BottomBar.
120+
121+ -- Michał Sawicz <michal.sawicz@canonical.com> Fri, 21 Jun 2013 17:37:02 +0200
122+
1123unity8 (7.81.0) saucy; urgency=low
2124
3125 * Translation updates.
debian/control+48−48
@@ -1,99 +1,99 @@
11Source: unity8
22Section: x11
3−Priority: extra
3+Priority: optional
44Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
55Build-Depends: cmake,
66 debhelper (>= 9),
7− libc6-dev,
7+ libjson-perl,
88 libdee-qt5-dev (>= 3.0),
99 libgl1-mesa-dev[!armhf] | libgl-dev[!armhf],
1010 libgl1-mesa-dri,
1111 libgles2-mesa-dev[armhf],
1212 libhud-client2-dev,
1313 libpulse-dev,
14+ libqt5v8-5-private-dev,
1415 libunity-core-6.0-dev (<< 7.80),
16+ libunity-dev (>= 7.0.3),
17+ libusermetricsoutput1-dev,
1518 libxcb1-dev,
1619 pkg-config,
1720 python3,
21+ python (>= 2.7),
22+ python-setuptools,
1823 qt5-default,
1924 qtbase5-dev,
2025 qtbase5-private-dev,
2126 qtdeclarative5-dev,
2227 qtdeclarative5-dev-tools,
28+ qtdeclarative5-private-dev,
2329 qtdeclarative5-qtquick2-plugin,
2430 qtdeclarative5-test-plugin,
2531 qtdeclarative5-ubuntu-ui-toolkit-plugin,
2632 qtdeclarative5-xmllistmodel-plugin,
2733 ttf-ubuntu-font-family,
28−Standards-Version: 3.9.3
34+ libunity-scopes-json-def-phone,
35+Standards-Version: 3.9.4
2936Homepage: http://launchpad.net/unity
3037# If you aren't a member of ~unity-team but need to upload
3138# packaging changes, just go ahead. ~unity-team will notice
3239# and sync up the code again.
33−Vcs-Bzr: https://code.launchpad.net/~unity-team/unity/phablet
34−Vcs-Browser: https://bazaar.launchpad.net/~unity-team/unity/phablet/files
40+Vcs-Bzr: https://code.launchpad.net/unity8
41+Vcs-Browser: https://bazaar.launchpad.net/~unity-team/unity8/trunk
3542
3643Package: unity8
37−Replaces: qml-phone-shell (<< 7.80~)
38−Breaks: qml-phone-shell (<< 7.80~)
39−Architecture: amd64 armhf i386
40−Depends: indicators-client (>= 0.6.1),
44+Architecture: any
45+Depends: ${misc:Depends},
46+ ${shlibs:Depends},
47+ unity8-private (= ${binary:Version}),
48+ indicators-client (>= 0.6.1),
4149 qtdeclarative5-dee-plugin,
4250 qtdeclarative5-ubuntu-ui-toolkit-plugin,
4351 qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
4452 unity-notifications-impl-1,
4553 qtdeclarative5-xmllistmodel-plugin,
46− qtubuntu,
47− ${misc:Depends},
48− ${shlibs:Depends},
49−Recommends: indicators-client-plugin-datetime (>= 0.6.1),
54+ unity8-fake-env | qtubuntu-shell,
55+Recommends: ${unity-default-masterscopes},
56+ indicators-client-plugin-datetime (>= 0.6.1),
5057 indicators-client-plugin-messaging (>= 0.6.1),
5158 indicators-client-plugin-network (>= 0.6.1),
5259 indicators-client-plugin-power (>= 0.6.1),
5360 indicators-client-plugin-sound (>= 0.6.1),
54− unity-scope-home,
55− unity-lens-applications,
56−Description: Ubuntu QML shell
57− The Ubuntu QML shell is the primary user interface for Ubuntu devices.
61+Description: Unity 8 shell
62+ The Unity 8 shell is the primary user interface for Ubuntu devices.
5863
59−Package: qml-phone-shell
60−Depends: unity8, ${misc:Depends}
61−Architecture: all
62−Description: transitional dummy package
63− This is a transitional dummy package. It can safely be removed.
64+Package: unity8-private
65+Architecture: any
66+Multi-Arch: same
67+Pre-Depends: ${misc:Pre-Depends}
68+Depends: ${misc:Depends},
69+ ${shlibs:Depends},
70+Description: Unity 8 private libs
71+ The Unity 8 shell is the primary user interface for Ubuntu devices.
72+ .
73+ This package contains the private libraries for QML and other components
74+ only used by the shell.
6475
6576Package: unity8-fake-env
66−Replaces: qml-phone-shell-fake-env (<< 7.80~)
67−Breaks: qml-phone-shell-fake-env (<< 7.80~)
68−Architecture: amd64 armhf i386
69−Depends: ${misc:Depends}, ${shlibs:Depends}
70−Description: Fake environment for running Ubuntu QML shell
71− Provides fake implementations of some QML modules used by Ubuntu QML shell
77+Architecture: any
78+Multi-Arch: same
79+Pre-Depends: ${misc:Pre-Depends}
80+Depends: ${misc:Depends},
81+ ${shlibs:Depends},
82+Provides: qtubuntu-shell,
83+Description: Fake environment for running Unity 8 shell
84+ Provides fake implementations of some QML modules used by Unity 8 shell
7285 (e.g Ubuntu.Application) so that you can run it in a sandboxed environment.
7386
74−Package: qml-phone-shell-fake-env
75−Depends: unity8-fake-env, ${misc:Depends}
76−Architecture: all
77−Description: transitional dummy package
78− This is a transitional dummy package. It can safely be removed.
79−
8087Package: unity8-autopilot
81−Replaces: qml-phone-shell-autopilot (<< 7.80~)
82−Breaks: qml-phone-shell-autopilot (<< 7.80~)
8388Architecture: all
84−Depends: libautopilot-qt,
89+Depends: ${misc:Depends},
90+ ${shlibs:Depends},
91+ ${python:Depends},
92+ libautopilot-qt,
8593 libqt5test5,
8694 libqt5widgets5,
8795 python-evdev,
88− unity8 (= ${source:Version}),
89− unity8-fake-env (= ${source:Version}),
90− ${misc:Depends},
91− ${shlibs:Depends},
92−Description: Test package for the shell
96+ unity8 (>= ${source:Version}),
97+ unity8-fake-env (>= ${source:Version}),
98+Description: Test package for Unity 8 shell
9399 Autopilot tests for the unity8 package
94−
95−Package: qml-phone-shell-autopilot
96−Depends: unity8-autopilot, ${misc:Depends}
97−Architecture: all
98−Description: transitional dummy package
99− This is a transitional dummy package. It can safely be removed.
debian/copyright+13−3
@@ -1,7 +1,9 @@
11Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
2+Upstream-Name: unity8
3+Source: http://launchpad.net/unity
24
35Files: *
4−Copyright: 2013 Canonical Ltd.
6+Copyright: 2011-2013 Canonical Ltd.
57License: GPL-3
68
79License: GPL-3
@@ -20,9 +22,17 @@ License: GPL-3
2022 On Debian systems, the full text of the GNU General Public License
2123 version 3 can be found in the file /usr/share/common-licenses/GPL-3.
2224
23−Files: tests/unittests/plugins/Utils/modeltest.*
25+Files: tests/mocks/LightDM/UsersModel.h tests/mocks/LightDM/Greeter.h
26+Copyright: 2013 Canonical Ltd.
27+ 2010-2011 David Edmundson
28+ 2010-2011 Robert Ancell
29+License: GPL-3
30+
31+Files: plugins/Utils/qvariantlistmodel.*
32+ tests/unittests/plugins/Utils/modeltest.*
33+ tests/plugins/Utils/modeltest.*
2434Copyright: 2013 Digia Plc and/or its subsidiary(-ies).
25−License:
35+License: LGPL-2.1 with Digia Qt LGPL Exception 1.1 or GPL-3
2636 Commercial License Usage
2737 Licensees holding valid commercial Qt licenses may use this file in
2838 accordance with the commercial license agreement provided with the
debian/rules+23−2
@@ -4,12 +4,33 @@
44# Uncomment this to turn on verbose mode.
55#export DH_VERBOSE=1
66export DPKG_GENSYMBOLS_CHECK_LEVEL=4
7+export NO_PNG_PKG_MANGLE=1
8+
9+SCOPES_RECOMMENDS := $(shell perl debian/scopes-recommends-generator /usr/share/unity/client-scopes.json)
710
811%:
9− dh $@ --parallel
12+ dh $@ --parallel --fail-missing --with python2
13+
14+override_dh_auto_clean:
15+ dh_auto_clean
16+ rm -rf builddir
1017
1118override_dh_install:
12− dh_install --fail-missing
19+ # install autopilot tests
20+ cd tests/autopilot; \
21+ set -ex; for python in $(shell pyversions -r); do \
22+ $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \
23+ done; \
24+ cd $(CURDIR)
25+ dh_install -X'*.pyc' --fail-missing
1326
27+# use private lib directories
28+override_dh_makeshlibs:
29+ dh_makeshlibs -Nunity8-private -Nunity8-fake-env
30+
31+# libMockLightDM-qml.so links against liblightdm-qt5-2.so which doesn't exist
1432override_dh_shlibdeps:
1533 dh_shlibdeps -XlibMockLightDM-qml.so
34+
35+override_dh_gencontrol:
36+ dh_gencontrol -- -Vunity-default-masterscopes="$(SCOPES_RECOMMENDS)"
debian/scopes-recommends-generatornew file+27
@@ -0,0 +1,27 @@
1+#!/usr/bin/perl -w
2+
3+use strict;
4+binmode STDOUT, ":utf8";
5+use utf8;
6+
7+use JSON;
8+
9+my $json;
10+{
11+ local $/; #Enable 'slurp' mode
12+ open my $fh, "<", $ARGV[0];
13+ $json = <$fh>;
14+ close $fh;
15+}
16+# get it to a scalar
17+my $j = "[" . $json . "]";
18+
19+my $decoded_json = decode_json( $j );
20+
21+my $recommends_list = "";
22+for my $record ( @$decoded_json ) {
23+ foreach my $key ( keys(%$record) ) {
24+ $recommends_list = $recommends_list . $key . ", ";
25+ }
26+}
27+print $recommends_list;
debian/unity8-autopilot.install+1−1
@@ -1 +1 @@
1−tests/autopilot/unity8/* usr/lib/python2.7/dist-packages/unity8/
1+usr/lib/python*/*/unity*
debian/unity8-fake-env.install+1−1
@@ -1 +1 @@
1−/usr/share/unity8/plugins/mocks/*
1+usr/lib/*/unity8/qml/mocks
debian/unity8-private.installnew file+6
@@ -0,0 +1,6 @@
1+usr/lib/*/unity8/qml/HudClient
2+usr/lib/*/unity8/qml/LightDM
3+usr/lib/*/unity8/qml/ListViewWithPageHeader
4+usr/lib/*/unity8/qml/Ubuntu
5+usr/lib/*/unity8/qml/Unity
6+usr/lib/*/unity8/qml/Utils
debian/unity8.install+15−20
@@ -1,20 +1,15 @@
1−/usr/bin/unity8
2−/usr/share/applications/unity8.desktop
3−/usr/share/locale/*
4−/usr/share/unity8/Applications/*
5−/usr/share/unity8/Bottombar/*
6−/usr/share/unity8/Components/*
7−/usr/share/unity8/Dash/*
8−/usr/share/unity8/Greeter/*
9−/usr/share/unity8/Hud/*
10−/usr/share/unity8/Launcher/*
11−/usr/share/unity8/Notifications/*
12−/usr/share/unity8/Panel/*
13−/usr/share/unity8/Shell.qml
14−/usr/share/unity8/SideStage/*
15−/usr/share/unity8/graphics/*
16−/usr/share/unity8/plugins/HudClient/*
17−/usr/share/unity8/plugins/LightDM/*
18−/usr/share/unity8/plugins/Ubuntu/*
19−/usr/share/unity8/plugins/Unity/*
20−/usr/share/unity8/plugins/Utils/*
1+usr/bin/unity8
2+usr/share/applications/unity8.desktop
3+usr/share/locale
4+usr/share/unity8/Applications
5+usr/share/unity8/Bottombar
6+usr/share/unity8/Components
7+usr/share/unity8/Dash
8+usr/share/unity8/Greeter
9+usr/share/unity8/Hud
10+usr/share/unity8/Launcher
11+usr/share/unity8/Notifications
12+usr/share/unity8/Panel
13+usr/share/unity8/Shell.qml
14+usr/share/unity8/SideStage
15+usr/share/unity8/graphics
graphics/12_10_background_wide@12.png

Binary file not shown.

graphics/applicationIcons/angrybirds@18.png

Binary file not shown.

graphics/applicationIcons/camera@18.png

Binary file not shown.

graphics/applicationIcons/dash@18.png

Binary file not shown.

graphics/applicationIcons/evernote@18.png

Binary file not shown.

graphics/applicationIcons/gallery@18.png

Binary file not shown.

graphics/applicationIcons/map@18.png

Binary file not shown.

graphics/applicationIcons/music@18.png

Binary file not shown.

graphics/applicationIcons/phone-app@18.png

Binary file not shown.

graphics/applicationIcons/pinterest@18.png

Binary file not shown.

graphics/applicationIcons/ski_safari@18.png

Binary file not shown.

graphics/applicationIcons/skype@18.png

Binary file not shown.

graphics/applicationIcons/twitter@18.png

Binary file not shown.

graphics/applicationIcons/youtube@18.png

Binary file not shown.

graphics/avatars/amanda@12.png

Binary file not shown.

graphics/avatars/anna_olsson@12.png

Binary file not shown.

graphics/avatars/funky@12.png

Binary file not shown.

graphics/clock@18.png

Binary file not shown.

main.cpp+26−7
@@ -31,13 +31,33 @@
3131#include "MouseTouchAdaptor.h"
3232
3333namespace {
34+
35+void prependImportPaths(QQmlEngine *engine, const QStringList &paths)
36+{
37+ QStringList importPathList = engine->importPathList();
38+ for (int i = paths.count() -1; i >= 0; i--) {
39+ // don't duplicate
40+ const QString& path = paths[i];
41+ QStringList::iterator iter = qFind(importPathList.begin(), importPathList.end(), path);
42+ if (iter == importPathList.end()) {
43+ engine->addImportPath(path);
44+ }
45+ }
46+}
47+
3448/* When you append and import path to the list of import paths it will be the *last*
3549 place where Qt will search for QML modules.
3650 The usual QQmlEngine::addImportPath() actually prepends the given path.*/
37−void appendImportPath(QQmlEngine *engine, const QString &path)
51+void appendImportPaths(QQmlEngine *engine, const QStringList &paths)
3852{
3953 QStringList importPathList = engine->importPathList();
40− importPathList.append(path);
54+ Q_FOREACH(const QString& path, paths) {
55+ // don't duplicate
56+ QStringList::iterator iter = qFind(importPathList.begin(), importPathList.end(), path);
57+ if (iter == importPathList.end()) {
58+ importPathList.append(path);
59+ }
60+ }
4161 engine->setImportPathList(importPathList);
4262}
4363
@@ -59,7 +79,7 @@ int main(int argc, char** argv)
5979 setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
6080 setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
6181
62− QGuiApplication::setApplicationName("Qml Phone Shell");
82+ QGuiApplication::setApplicationName("Unity 8");
6383 QGuiApplication application(argc, argv);
6484
6585 resolveIconTheme();
@@ -88,7 +108,7 @@ int main(int argc, char** argv)
88108 QQuickView* view = new QQuickView();
89109 view->setResizeMode(QQuickView::SizeRootObjectToView);
90110 view->setTitle("Qml Phone Shell");
91− view->engine()->setBaseUrl(QUrl::fromLocalFile(shellAppDirectory()));
111+ view->engine()->setBaseUrl(QUrl::fromLocalFile(::shellAppDirectory()));
92112 if (args.contains(QLatin1String("-frameless"))) {
93113 view->setFlags(Qt::FramelessWindowHint);
94114 }
@@ -114,9 +134,8 @@ int main(int argc, char** argv)
114134 QObject::connect(view->engine(), SIGNAL(quit()), qApp, SLOT(quit()));
115135
116136 QUrl source("Shell.qml");
117− view->engine()->addImportPath(shellAppDirectory());
118− view->engine()->addImportPath(shellImportPath());
119− appendImportPath(view->engine(), fakePluginsImportPath());
137+ prependImportPaths(view->engine(), ::overrideImportPaths());
138+ appendImportPaths(view->engine(), ::fallbackImportPaths());
120139 view->setSource(source);
121140 view->setColor("transparent");
122141
paths.h.in+16−8
@@ -17,6 +17,9 @@
1717 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1818 */
1919
20+#ifndef PATHS_H
21+#define PATHS_H
22+
2023// Qt
2124#include <QtCore/QCoreApplication>
2225#include <QtCore/QDir>
@@ -43,22 +46,27 @@ inline QString shellAppDirectory() {
4346 }
4447}
4548
46−inline QString shellImportPath() {
47− if (isRunningInstalled()) {
48− return QString("@CMAKE_INSTALL_PREFIX@/@SHELL_APP_DIR@/plugins");
49− } else {
50− return QString("@CMAKE_BINARY_DIR@/plugins/");
49+inline QStringList overrideImportPaths() {
50+ QStringList paths;
51+ if (!isRunningInstalled()) {
52+ paths << QString("@CMAKE_BINARY_DIR@/plugins");
5153 }
54+ return paths;
5255}
5356
54−inline QString fakePluginsImportPath() {
57+inline QStringList fallbackImportPaths() {
58+ QStringList paths;
5559 if (isRunningInstalled()) {
56− return QString("@CMAKE_INSTALL_PREFIX@/@SHELL_APP_DIR@/plugins/mocks");
60+ paths << QString("@CMAKE_INSTALL_PREFIX@/@SHELL_PRIVATE_LIBDIR@/qml");
61+ paths << QString("@CMAKE_INSTALL_PREFIX@/@SHELL_PRIVATE_LIBDIR@/qml/mocks");
5762 } else {
58− return QString("@CMAKE_BINARY_DIR@/tests/mocks");
63+ paths << QString("@CMAKE_BINARY_DIR@/tests/mocks");
5964 }
65+ return paths;
6066}
6167
6268inline QString sourceDirectory() {
6369 return QString("@CMAKE_SOURCE_DIR@/");
6470}
71+
72+#endif
plugins/CMakeLists.txt+1
@@ -3,3 +3,4 @@ add_subdirectory(Utils)
33add_subdirectory(Unity)
44add_subdirectory(HudClient)
55add_subdirectory(LightDM)
6+add_subdirectory(ListViewWithPageHeader)
plugins/HudClient/CMakeLists.txt+2−2
@@ -41,9 +41,9 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
4141 )
4242
4343install(TARGETS HudClientQml
44− DESTINATION ${SHELL_APP_DIR}/plugins/HudClient
44+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/HudClient
4545 )
4646
4747install(FILES qmldir
48− DESTINATION ${SHELL_APP_DIR}/plugins/HudClient
48+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/HudClient
4949 )
plugins/LightDM/CMakeLists.txt+6−3
@@ -1,6 +1,7 @@
11# Dependencies
2+include(FindPkgConfig)
3+pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
24# TODO: Once we split out a separate greeter process, uncomment these lines
3−#include(FindPkgConfig)
45#pkg_check_modules(LIBLIGHTDM REQUIRED liblightdm-qt5-2)
56
67include_directories(
@@ -8,6 +9,7 @@ include_directories(
89 ${CMAKE_CURRENT_BINARY_DIR}
910 ${CMAKE_SOURCE_DIR}/tests/mocks/LightDM
1011 #${LIBLIGHTDM_INCLUDE_DIRS}
12+ ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
1113)
1214
1315set(QMLPLUGIN_SRC
@@ -25,6 +27,7 @@ target_link_libraries(LightDM-qml
2527 MockLightDM-demo
2628# TODO: Once we split out a separate greeter process, uncomment these lines
2729# ${LIBLIGHTDM_LDFLAGS}
30+ ${LIBUSERMETRICSOUTPUT_LDFLAGS}
2831 )
2932
3033qt5_use_modules(LightDM-qml Gui Qml)
@@ -35,9 +38,9 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
3538 )
3639
3740install(TARGETS LightDM-qml
38− DESTINATION ${SHELL_APP_DIR}/plugins/LightDM
41+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/LightDM
3942 )
4043
4144install(FILES qmldir
42− DESTINATION ${SHELL_APP_DIR}/plugins/LightDM
45+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/LightDM
4346 )
plugins/LightDM/Greeter.cpp+6−6
@@ -102,21 +102,21 @@ bool Greeter::startSessionSync(const QString &session)
102102 return d->m_greeter->startSessionSync(session);
103103}
104104
105−void Greeter::showPromptFilter(QString text, QLightDM::Greeter::PromptType type)
105+void Greeter::showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type)
106106{
107107 Q_D(Greeter);
108108 d->wasPrompted = true;
109109
110110 // Strip prompt of any colons at the end
111− text = text.trimmed();
112− if (text.endsWith(":") || text.endsWith(":")) {
113− text.chop(1);
111+ QString trimmedText = text.trimmed();
112+ if (trimmedText.endsWith(":") || trimmedText.endsWith(":")) {
113+ trimmedText.chop(1);
114114 }
115115
116− Q_EMIT showPrompt(text, type == QLightDM::Greeter::PromptTypeSecret);
116+ Q_EMIT showPrompt(trimmedText, type == QLightDM::Greeter::PromptTypeSecret);
117117}
118118
119−void Greeter::showMessageFilter(QString text, QLightDM::Greeter::MessageType type)
119+void Greeter::showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type)
120120{
121121 Q_EMIT showMessage(text, type == QLightDM::Greeter::MessageTypeError);
122122}
plugins/LightDM/Greeter.h+4−4
@@ -51,8 +51,8 @@ public Q_SLOTS:
5151 bool startSessionSync(const QString &session=QString());
5252
5353Q_SIGNALS:
54− void showMessage(QString text, bool isError);
55− void showPrompt(QString text, bool isSecret);
54+ void showMessage(const QString &text, bool isError);
55+ void showPrompt(const QString &text, bool isSecret);
5656 void authenticationComplete();
5757 void promptlessChanged();
5858
@@ -62,8 +62,8 @@ private:
6262 Q_DECLARE_PRIVATE(Greeter)
6363
6464private Q_SLOTS:
65− void showMessageFilter(QString text, QLightDM::Greeter::MessageType type);
66− void showPromptFilter(QString text, QLightDM::Greeter::PromptType type);
65+ void showMessageFilter(const QString &text, QLightDM::Greeter::MessageType type);
66+ void showPromptFilter(const QString &text, QLightDM::Greeter::PromptType type);
6767 void authenticationCompleteFilter();
6868};
6969
plugins/LightDM/plugin.cpp+5−4
@@ -20,8 +20,9 @@
2020#include "plugin.h"
2121#include "Greeter.h"
2222#include "UsersModel.h"
23+#include <libusermetricsoutput/ColorTheme.h>
24+#include <libusermetricsoutput/UserMetrics.h>
2325#include <QLightDM/UsersModel>
24−#include "InfographicModel.h"
2526
2627#include <QtCore/QAbstractItemModel>
2728#include <QtQml>
@@ -44,17 +45,17 @@ static QObject *infographic_provider(QQmlEngine *engine, QJSEngine *scriptEngine
4445{
4546 Q_UNUSED(engine)
4647 Q_UNUSED(scriptEngine)
47− return InfographicModel::getInstance();
48+ return UserMetricsOutput::UserMetrics::getInstance();
4849}
4950
5051void LightDMPlugin::registerTypes(const char *uri)
5152{
5253 qmlRegisterType<QAbstractItemModel>();
53− qmlRegisterType<InfographicColorTheme>();
54+ qmlRegisterType<UserMetricsOutput::ColorTheme>();
5455
5556 Q_ASSERT(uri == QLatin1String("LightDM"));
5657 qmlRegisterSingletonType<Greeter>(uri, 0, 1, "Greeter", greeter_provider);
5758 qmlRegisterSingletonType<UsersModel>(uri, 0, 1, "Users", users_provider);
5859 qmlRegisterUncreatableType<QLightDM::UsersModel>(uri, 0, 1, "UserRoles", "Type is not instantiable");
59− qmlRegisterSingletonType<InfographicModel>(uri, 0, 1, "Infographic", infographic_provider);
60+ qmlRegisterSingletonType<UserMetricsOutput::UserMetrics>(uri, 0, 1, "Infographic", infographic_provider);
6061}
plugins/ListViewWithPageHeader/CMakeLists.txtnew file+44
@@ -0,0 +1,44 @@
1+# There's no cmake var for v8 include path :-/
2+# so create one
3+LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
4+SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
5+
6+include_directories(
7+ ${CMAKE_CURRENT_SOURCE_DIR}
8+ ${CMAKE_CURRENT_BINARY_DIR}
9+ ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
10+ ${Qt5Quick_INCLUDE_DIRS}
11+ ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
12+ ${Qt5V8_PRIVATE_INCLUDE_DIR}
13+)
14+
15+remove_definitions(-DQT_NO_KEYWORDS)
16+
17+set(QMLPLUGIN_SRC
18+ plugin.cpp
19+ listviewwithpageheader.cpp
20+ )
21+
22+add_library(ListViewWithPageHeader-qml MODULE
23+ ${QMLPLUGIN_SRC}
24+ )
25+
26+target_link_libraries(ListViewWithPageHeader-qml
27+ ${Qt5Gui_LIBRARIES}
28+ ${Qt5Quick_LIBRARIES}
29+ )
30+
31+qt5_use_modules(ListViewWithPageHeader-qml Qml Quick)
32+
33+# copy qmldir file into build directory for shadow builds
34+file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
35+ DESTINATION ${CMAKE_CURRENT_BINARY_DIR}
36+ )
37+
38+install(TARGETS ListViewWithPageHeader-qml
39+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/ListViewWithPageHeader
40+ )
41+
42+install(FILES qmldir
43+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/ListViewWithPageHeader
44+ )
plugins/ListViewWithPageHeader/listviewwithpageheader.cppnew file+1062
@@ -0,0 +1,1062 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+/*
18+ * Some documentation on how this thing works:
19+ *
20+ * A flickable has two very important concepts that define the top and
21+ * height of the flickable area.
22+ * The top is returned in minYExtent()
23+ * The height is set using setContentHeight()
24+ * By changing those two values we can make the list grow up or down
25+ * as needed. e.g. if we are in the middle of the list
26+ * and something that is above the viewport grows, since we do not
27+ * want to change the viewport because of that we just adjust the
28+ * minYExtent so that the list grows up.
29+ *
30+ * The implementation on the list relies on the delegateModel doing
31+ * most of the instantiation work. You call createItem() when you
32+ * need to create an item asking for it async or not. If returns null
33+ * it means the item will be created async and the model will call the
34+ * itemCreated slot with the item.
35+ *
36+ * updatePolish is the central point of dispatch for the work of the
37+ * class. It is called by the scene graph just before drawing the class.
38+ * In it we:
39+ * * Make sure all items are positioned correctly
40+ * * Add/Remove items if needed
41+ * * Update the content height if it was dirty
42+ *
43+ * m_visibleItems contains all the items we have created at the moment.
44+ * Actually not all of them are visible since it includes the ones
45+ * in the cache area we create asynchronously to help performance.
46+ * The first item in m_visibleItems has the m_firstVisibleIndex in
47+ * the model. If you actually want to know what is the first
48+ * item in the viewport you have to find the first non culled element
49+ * in m_visibleItems
50+ *
51+ * All the items (except the header) are childs of m_clipItem which
52+ * is a child of the contentItem() of the flickable (The contentItem()
53+ * is what actually 'moves' in a a flickable). This way
54+ * we can implement the clipping needed so we can have the header
55+ * shown in the middle of the list over the items without the items
56+ * leaking under the header in case it is transparent.
57+ *
58+ * The first item of m_visibleItems is the one that defines the
59+ * positions of all the rest of items (see updatePolish()) and
60+ * this is why sometimes we move it even if it's not the item
61+ * that has triggered the function (i.e. in itemGeometryChanged())
62+ *
63+ * m_visibleItems is a list of ListItem. Each ListItem
64+ * will contain a item and potentially a sectionItem. The sectionItem
65+ * is only there when the list is using sectionDelegate+sectionProperty
66+ * and this is the first item of the section. Each ListItem is vertically
67+ * layouted with the sectionItem first and then the item.
68+ *
69+ * For sectioning we also have a section item alone (m_topSectionItem)
70+ * that is used for the cases we need to show the sticky section item at
71+ * the top of the view.
72+ *
73+ * Each delegate item has a context property called heightToClip that is
74+ * used to communicate to the delegate implementation in case it has to
75+ * clip itself because of overlapping with the top sticky section item.
76+ * This is an implementation decision since it has been agreed it
77+ * is easier to implement the clipping in QML with this info than to
78+ * do it at the C++ level.
79+ *
80+ * Note that minYExtent and height are not always totally accurate, since
81+ * we don't have the items created we can't guess their heights
82+ * so we can only guarantee the values are correct when the first/last
83+ * items of the list are visible, otherwise we just live with good enough
84+ * values that make the list scrollable
85+ *
86+ * There are a few things that are not really implemented or tested properly
87+ * which we don't use at the moment like changing the model, changing
88+ * the section delegate, having a section delegate that changes its size, etc.
89+ * The known missing features are marked with TODOs along the code.
90+ */
91+
92+#include "listviewwithpageheader.h"
93+
94+#include <QDebug>
95+#include <qqmlinfo.h>
96+#include <qqmlengine.h>
97+#include <private/qquickvisualdatamodel_p.h>
98+#include <private/qqmlglobal_p.h>
99+#include <private/qquickitem_p.h>
100+#include <private/qquickanimation_p.h>
101+// #include <private/qquickrectangle_p.h>
102+
103+static const qreal bufferRatio = 0.5;
104+
105+qreal ListViewWithPageHeader::ListItem::height() const
106+{
107+ return m_item->height() + (m_sectionItem ? m_sectionItem->height() : 0);
108+}
109+
110+qreal ListViewWithPageHeader::ListItem::y() const
111+{
112+ return m_item->y() - (m_sectionItem ? m_sectionItem->height() : 0);
113+}
114+
115+void ListViewWithPageHeader::ListItem::setY(qreal newY)
116+{
117+ if (m_sectionItem) {
118+ m_sectionItem->setY(newY);
119+ m_item->setY(newY + m_sectionItem->height());
120+ } else {
121+ m_item->setY(newY);
122+ }
123+}
124+
125+bool ListViewWithPageHeader::ListItem::culled() const
126+{
127+ return QQuickItemPrivate::get(m_item)->culled;
128+}
129+
130+void ListViewWithPageHeader::ListItem::setCulled(bool culled)
131+{
132+ QQuickItemPrivate::get(m_item)->setCulled(culled);
133+ if (m_sectionItem)
134+ QQuickItemPrivate::get(m_sectionItem)->setCulled(culled);
135+}
136+
137+ListViewWithPageHeader::ListViewWithPageHeader()
138+ : m_delegateModel(nullptr)
139+ , m_asyncRequestedIndex(-1)
140+ , m_delegateValidated(false)
141+ , m_firstVisibleIndex(-1)
142+ , m_minYExtent(0)
143+ , m_contentHeightDirty(false)
144+ , m_headerItem(nullptr)
145+ , m_previousContentY(0)
146+ , m_headerItemShownHeight(0)
147+ , m_sectionDelegate(nullptr)
148+ , m_topSectionItem(nullptr)
149+ , m_forceNoClip(false)
150+ , m_inLayout(false)
151+{
152+ m_clipItem = new QQuickItem(contentItem());
153+// m_clipItem = new QQuickRectangle(contentItem());
154+// ((QQuickRectangle*)m_clipItem)->setColor(Qt::gray);
155+
156+ m_headerShowAnimation = new QQuickNumberAnimation(this);
157+ m_headerShowAnimation->setEasing(QEasingCurve::OutQuad);
158+ m_headerShowAnimation->setProperty("contentY");
159+ m_headerShowAnimation->setDuration(200);
160+ m_headerShowAnimation->setTargetObject(this);
161+
162+ connect(this, SIGNAL(contentWidthChanged()), this, SLOT(onContentWidthChanged()));
163+ connect(this, SIGNAL(contentHeightChanged()), this, SLOT(onContentHeightChanged()));
164+ connect(this, SIGNAL(heightChanged()), this, SLOT(onHeightChanged()));
165+ connect(m_headerShowAnimation, SIGNAL(stopped()), this, SLOT(onShowHeaderAnimationFinished()));
166+}
167+
168+ListViewWithPageHeader::~ListViewWithPageHeader()
169+{
170+}
171+
172+QAbstractItemModel *ListViewWithPageHeader::model() const
173+{
174+ return m_delegateModel ? m_delegateModel->model().value<QAbstractItemModel *>() : nullptr;
175+}
176+
177+void ListViewWithPageHeader::setModel(QAbstractItemModel *model)
178+{
179+ if (model != this->model()) {
180+ if (!m_delegateModel) {
181+ createDelegateModel();
182+ } else {
183+ disconnect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
184+ }
185+ m_delegateModel->setModel(QVariant::fromValue<QAbstractItemModel *>(model));
186+ connect(m_delegateModel, SIGNAL(modelUpdated(QQuickChangeSet,bool)), this, SLOT(onModelUpdated(QQuickChangeSet,bool)));
187+ Q_EMIT modelChanged();
188+ // TODO?
189+// Q_EMIT contentHeightChanged();
190+// Q_EMIT contentYChanged();
191+ }
192+}
193+
194+QQmlComponent *ListViewWithPageHeader::delegate() const
195+{
196+ return m_delegateModel ? m_delegateModel->delegate() : nullptr;
197+}
198+
199+void ListViewWithPageHeader::setDelegate(QQmlComponent *delegate)
200+{
201+ if (delegate != this->delegate()) {
202+ if (!m_delegateModel) {
203+ createDelegateModel();
204+ }
205+
206+ // Cleanup the existing items
207+ Q_FOREACH(ListItem *item, m_visibleItems)
208+ releaseItem(item);
209+ m_visibleItems.clear();
210+ m_firstVisibleIndex = -1;
211+ adjustMinYExtent();
212+ setContentY(0);
213+ m_clipItem->setY(0);
214+ if (m_topSectionItem) {
215+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
216+ }
217+
218+ m_delegateModel->setDelegate(delegate);
219+
220+ Q_EMIT delegateChanged();
221+ m_delegateValidated = false;
222+ m_contentHeightDirty = true;
223+ polish();
224+ }
225+}
226+
227+QQuickItem *ListViewWithPageHeader::header() const
228+{
229+ return m_headerItem;
230+}
231+
232+void ListViewWithPageHeader::setHeader(QQuickItem *headerItem)
233+{
234+ if (m_headerItem != headerItem) {
235+ qreal oldHeaderHeight = 0;
236+ qreal oldHeaderY = 0;
237+ if (m_headerItem) {
238+ oldHeaderHeight = m_headerItem->height();
239+ oldHeaderY = m_headerItem->y();
240+ m_headerItem->setParentItem(nullptr);
241+ }
242+ m_headerItem = headerItem;
243+ if (m_headerItem) {
244+ m_headerItem->setParentItem(contentItem());
245+ m_headerItem->setZ(1);
246+ }
247+ qreal newHeaderHeight = m_headerItem ? m_headerItem->height() : 0;
248+ if (!m_visibleItems.isEmpty() && newHeaderHeight != oldHeaderHeight) {
249+ headerHeightChanged(newHeaderHeight, oldHeaderHeight, oldHeaderY);
250+ polish();
251+ m_contentHeightDirty = true;
252+ }
253+ Q_EMIT headerChanged();
254+ }
255+}
256+
257+QQmlComponent *ListViewWithPageHeader::sectionDelegate() const
258+{
259+ return m_sectionDelegate;
260+}
261+
262+void ListViewWithPageHeader::setSectionDelegate(QQmlComponent *delegate)
263+{
264+ if (delegate != m_sectionDelegate) {
265+ // TODO clean existing sections
266+
267+ m_sectionDelegate = delegate;
268+
269+ m_topSectionItem = getSectionItem(QString());
270+ m_topSectionItem->setZ(3);
271+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
272+
273+ // TODO create sections for existing items
274+
275+ Q_EMIT sectionDelegateChanged();
276+ }
277+}
278+
279+QString ListViewWithPageHeader::sectionProperty() const
280+{
281+ return m_sectionProperty;
282+}
283+
284+void ListViewWithPageHeader::setSectionProperty(const QString &property)
285+{
286+ if (property != m_sectionProperty) {
287+ m_sectionProperty = property;
288+
289+ updateWatchedRoles();
290+
291+ // TODO recreate sections
292+
293+ Q_EMIT sectionPropertyChanged();
294+ }
295+}
296+
297+bool ListViewWithPageHeader::forceNoClip() const
298+{
299+ return m_forceNoClip;
300+}
301+
302+void ListViewWithPageHeader::setForceNoClip(bool noClip)
303+{
304+ if (noClip != m_forceNoClip) {
305+ m_forceNoClip = noClip;
306+ updateClipItem();
307+ Q_EMIT forceNoClipChanged();
308+ }
309+}
310+
311+void ListViewWithPageHeader::positionAtBeginning()
312+{
313+ qreal headerHeight = (m_headerItem ? m_headerItem->height() : 0);
314+ if (m_firstVisibleIndex != 0) {
315+ // TODO This could be optimized by trying to reuse the interesection
316+ // of items that may end up intersecting between the existing
317+ // m_visibleItems and the items we are creating in the next loop
318+ Q_FOREACH(ListItem *item, m_visibleItems)
319+ releaseItem(item);
320+ m_visibleItems.clear();
321+ m_firstVisibleIndex = -1;
322+
323+ // Create the item 0, it will be already correctly positioned at createItem()
324+ m_clipItem->setY(0);
325+ ListItem *item = createItem(0, false);
326+ // Create the subsequent items
327+ int modelIndex = 1;
328+ qreal pos = item->y() + item->height();
329+ const qreal buffer = height() * bufferRatio;
330+ const qreal bufferTo = height() + buffer;
331+ while (modelIndex < m_delegateModel->count() && pos <= bufferTo) {
332+ if (!(item = createItem(modelIndex, false)))
333+ break;
334+ pos += item->height();
335+ ++modelIndex;
336+ }
337+
338+ m_previousContentY = m_visibleItems.first()->y() - headerHeight;
339+ }
340+ setContentY(m_visibleItems.first()->y() + m_clipItem->y() - headerHeight);
341+}
342+
343+void ListViewWithPageHeader::showHeader()
344+{
345+ if (!m_headerItem)
346+ return;
347+
348+ auto to = qMax(-minYExtent(), contentY() - m_headerItem->height() + m_headerItemShownHeight);
349+ if (to != contentY()) {
350+ m_headerShowAnimation->setTo(to);
351+ m_headerShowAnimation->start();
352+ }
353+}
354+
355+qreal ListViewWithPageHeader::minYExtent() const
356+{
357+// qDebug() << "ListViewWithPageHeader::minYExtent" << m_minYExtent;
358+ return m_minYExtent;
359+}
360+
361+void ListViewWithPageHeader::componentComplete()
362+{
363+ if (m_delegateModel)
364+ m_delegateModel->componentComplete();
365+
366+ QQuickFlickable::componentComplete();
367+
368+ polish();
369+}
370+
371+void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
372+{
373+ QQuickFlickable::viewportMoved(orient);
374+// qDebug() << "ListViewWithPageHeader::viewportMoved" << contentY();
375+ qreal diff = m_previousContentY - contentY();
376+ if (m_headerItem) {
377+ auto oldHeaderItemShownHeight = m_headerItemShownHeight;
378+ if (contentY() < -m_minYExtent) {
379+ // Stick the header item to the top when dragging down
380+ m_headerItem->setY(contentY());
381+ m_headerItem->setHeight(m_headerItem->implicitHeight() + (-m_minYExtent - contentY()));
382+ } else {
383+ m_headerItem->setHeight(m_headerItem->implicitHeight());
384+ // We are going down (but it's not because of the rebound at the end)
385+ // (but the header was not shown by it's own position)
386+ // or the header is partially shown
387+ const bool scrolledUp = m_previousContentY > contentY();
388+ const bool notRebounding = contentY() + height() < contentHeight();
389+ const bool notShownByItsOwn = contentY() + diff > m_headerItem->y() + m_headerItem->height();
390+
391+ if (!scrolledUp && contentY() == -m_minYExtent) {
392+ m_headerItemShownHeight = 0;
393+ m_headerItem->setY(contentY());
394+ } else if ((scrolledUp && notRebounding && notShownByItsOwn) || (m_headerItemShownHeight > 0)) {
395+ m_headerItemShownHeight += diff;
396+ if (contentY() == -m_minYExtent) {
397+ m_headerItemShownHeight = 0;
398+ } else {
399+ m_headerItemShownHeight = qBound(static_cast<qreal>(0.), m_headerItemShownHeight, m_headerItem->height());
400+ }
401+ if (m_headerItemShownHeight > 0) {
402+ m_headerItem->setY(contentY() - m_headerItem->height() + m_headerItemShownHeight);
403+ } else {
404+ m_headerItem->setY(-m_minYExtent);
405+ }
406+ }
407+ }
408+ // We will be changing the clip item, need to accomadate for it
409+ // otherwise we move the firstItem down/up twice (unless the
410+ // show header animation is running, where we want to keep the viewport stable)
411+ if (!m_headerShowAnimation->isRunning()) {
412+ diff += oldHeaderItemShownHeight - m_headerItemShownHeight;
413+ } else {
414+ diff = -diff;
415+ }
416+ }
417+ if (!m_visibleItems.isEmpty()) {
418+ updateClipItem();
419+ ListItem *firstItem = m_visibleItems.first();
420+ firstItem->setY(firstItem->y() + diff);
421+ if (m_headerShowAnimation->isRunning()) {
422+ adjustMinYExtent();
423+ }
424+ }
425+
426+ m_previousContentY = contentY();
427+ layout();
428+ polish();
429+}
430+
431+void ListViewWithPageHeader::createDelegateModel()
432+{
433+ m_delegateModel = new QQuickVisualDataModel(qmlContext(this), this);
434+ connect(m_delegateModel, SIGNAL(createdItem(int,QQuickItem*)), this, SLOT(itemCreated(int,QQuickItem*)));
435+ if (isComponentComplete())
436+ m_delegateModel->componentComplete();
437+ updateWatchedRoles();
438+}
439+
440+void ListViewWithPageHeader::refill()
441+{
442+ if (m_inLayout) {
443+ return;
444+ }
445+ if (!isComponentComplete()) {
446+ return;
447+ }
448+
449+ const qreal buffer = height() * bufferRatio;
450+ const qreal from = contentY();
451+ const qreal to = from + height();
452+ const qreal bufferFrom = from - buffer;
453+ const qreal bufferTo = to + buffer;
454+
455+ bool added = addVisibleItems(from, to, false);
456+ bool removed = removeNonVisibleItems(bufferFrom, bufferTo);
457+ added |= addVisibleItems(bufferFrom, bufferTo, true);
458+
459+ if (added || removed) {
460+ m_contentHeightDirty = true;
461+ }
462+}
463+
464+bool ListViewWithPageHeader::addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous)
465+{
466+ if (!delegate())
467+ return false;
468+
469+ if (m_delegateModel->count() == 0)
470+ return false;
471+
472+ ListItem *item;
473+// qDebug() << "ListViewWithPageHeader::addVisibleItems" << fillFrom << fillTo << asynchronous;
474+
475+ int modelIndex = 0;
476+ qreal pos = 0;
477+ if (!m_visibleItems.isEmpty()) {
478+ modelIndex = m_firstVisibleIndex + m_visibleItems.count();
479+ item = m_visibleItems.last();
480+ pos = item->y() + item->height() + m_clipItem->y();
481+ }
482+ bool changed = false;
483+// qDebug() << (modelIndex < m_delegateModel->count()) << pos << fillTo;
484+ while (modelIndex < m_delegateModel->count() && pos <= fillTo) {
485+// qDebug() << "refill: append item" << modelIndex << "pos" << pos << "asynchronous" << asynchronous;
486+ if (!(item = createItem(modelIndex, asynchronous)))
487+ break;
488+ pos += item->height();
489+ ++modelIndex;
490+ changed = true;
491+ }
492+
493+ modelIndex = 0;
494+ pos = 0;
495+ if (!m_visibleItems.isEmpty()) {
496+ modelIndex = m_firstVisibleIndex - 1;
497+ item = m_visibleItems.first();
498+ pos = item->y() + m_clipItem->y();
499+ }
500+ while (modelIndex >= 0 && pos > fillFrom) {
501+// qDebug() << "refill: prepend item" << modelIndex << "pos" << pos << "fillFrom" << fillFrom << "asynchronous" << asynchronous;
502+ if (!(item = createItem(modelIndex, asynchronous)))
503+ break;
504+ pos -= item->height();
505+ --modelIndex;
506+ changed = true;
507+ }
508+
509+ return changed;
510+}
511+
512+void ListViewWithPageHeader::reallyReleaseItem(ListItem *listItem)
513+{
514+ QQuickItem *item = listItem->m_item;
515+ QQuickVisualModel::ReleaseFlags flags = m_delegateModel->release(item);
516+ if (flags & QQuickVisualModel::Destroyed) {
517+ item->setParentItem(nullptr);
518+ }
519+ delete listItem->m_sectionItem;
520+ delete listItem;
521+}
522+
523+void ListViewWithPageHeader::releaseItem(ListItem *listItem)
524+{
525+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(listItem->m_item);
526+ itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
527+ m_itemsToRelease << listItem;
528+}
529+
530+void ListViewWithPageHeader::updateWatchedRoles()
531+{
532+ if (m_delegateModel) {
533+ QList<QByteArray> roles;
534+ if (!m_sectionProperty.isEmpty())
535+ roles << m_sectionProperty.toUtf8();
536+ m_delegateModel->setWatchedRoles(roles);
537+ }
538+}
539+
540+QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyInserted)
541+{
542+ if (!m_sectionDelegate)
543+ return nullptr;
544+
545+ const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
546+ if (modelIndex > 0) {
547+ const QString prevSection = m_delegateModel->stringValue(modelIndex - 1, m_sectionProperty);
548+ if (section == prevSection)
549+ return nullptr;
550+ }
551+ if (modelIndex + 1 < model()->rowCount() && !alreadyInserted) {
552+ // Already inserted items can't steal next section header
553+ const QString nextSection = m_delegateModel->stringValue(modelIndex + 1, m_sectionProperty);
554+ if (section == nextSection) {
555+ // Steal the section header
556+ ListItem *nextItem = itemAtIndex(modelIndex); // Not +1 since not yet inserted into m_visibleItems
557+ if (nextItem) {
558+ QQuickItem *sectionItem = nextItem->m_sectionItem;
559+ nextItem->m_sectionItem = nullptr;
560+ return sectionItem;
561+ }
562+ }
563+ }
564+
565+ return getSectionItem(section);
566+}
567+
568+QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText)
569+{
570+ QQuickItem *sectionItem = nullptr;
571+
572+ QQmlContext *creationContext = m_sectionDelegate->creationContext();
573+ QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));
574+ context->setContextProperty(QLatin1String("section"), sectionText);
575+ QObject *nobj = m_sectionDelegate->beginCreate(context);
576+ if (nobj) {
577+ QQml_setParent_noEvent(context, nobj);
578+ sectionItem = qobject_cast<QQuickItem *>(nobj);
579+ if (!sectionItem) {
580+ delete nobj;
581+ } else {
582+ sectionItem->setZ(2);
583+ QQml_setParent_noEvent(sectionItem, m_clipItem);
584+ sectionItem->setParentItem(m_clipItem);
585+ }
586+ } else {
587+ delete context;
588+ }
589+ m_sectionDelegate->completeCreate();
590+
591+ // TODO attach to sectionItem so we can accomodate to it changing its height
592+
593+ return sectionItem;
594+}
595+
596+bool ListViewWithPageHeader::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo)
597+{
598+// qDebug() << "ListViewWithPageHeader::removeNonVisibleItems" << bufferFrom << bufferTo;
599+ // Do not remove items if we are overshooting up or down, since we'll come back
600+ // to the "stable" position and delete/create items without any reason
601+ if (contentY() < -m_minYExtent) {
602+ return false;
603+ } else if (contentY() + height() > contentHeight()) {
604+ return false;
605+ }
606+ bool changed = false;
607+
608+ bool foundVisible = false;
609+ int i = 0;
610+ int removedItems = 0;
611+ const auto oldFirstVisibleIndex = m_firstVisibleIndex;
612+ while (i < m_visibleItems.count()) {
613+ ListItem *item = m_visibleItems[i];
614+ const qreal pos = item->y() + m_clipItem->y();
615+// qDebug() << i << pos << (pos + item->height()) << bufferFrom << bufferTo;
616+ if (pos + item->height() < bufferFrom || pos > bufferTo) {
617+// qDebug() << "Releasing" << i << (pos + item->height() < bufferFrom) << pos + item->height() << bufferFrom << (pos > bufferTo) << pos << bufferTo;
618+ releaseItem(item);
619+ m_visibleItems.removeAt(i);
620+ changed = true;
621+ ++removedItems;
622+ } else {
623+ if (!foundVisible) {
624+ foundVisible = true;
625+ const int itemIndex = m_firstVisibleIndex + removedItems + i;
626+ m_firstVisibleIndex = itemIndex;
627+ }
628+ ++i;
629+ }
630+ }
631+ if (m_firstVisibleIndex != oldFirstVisibleIndex) {
632+ adjustMinYExtent();
633+ }
634+
635+ return changed;
636+}
637+
638+ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIndex, bool asynchronous)
639+{
640+// qDebug() << "CREATE ITEM" << modelIndex;
641+ if (asynchronous && m_asyncRequestedIndex != -1)
642+ return nullptr;
643+
644+ m_asyncRequestedIndex = -1;
645+ QQuickItem *item = m_delegateModel->item(modelIndex, asynchronous);
646+ if (!item) {
647+ m_asyncRequestedIndex = modelIndex;
648+ return 0;
649+ } else {
650+// qDebug() << "ListViewWithPageHeader::createItem::We have the item" << modelIndex << item;
651+ ListItem *listItem = new ListItem;
652+ listItem->m_item = item;
653+ listItem->m_sectionItem = getSectionItem(modelIndex, false /*Not yet inserted into m_visibleItems*/);
654+ QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
655+ ListItem *prevItem = itemAtIndex(modelIndex - 1);
656+ bool lostItem = false; // Is an item that we requested async but because of model changes
657+ // it is no longer attached to any of the existing items (has no prev nor next item)
658+ // nor is the first item
659+ if (prevItem) {
660+ listItem->setY(prevItem->y() + prevItem->height());
661+ } else {
662+ ListItem *currItem = itemAtIndex(modelIndex);
663+ if (currItem) {
664+ // There's something already in m_visibleItems at out index, meaning this is an insert, so attach to its top
665+ listItem->setY(currItem->y() - listItem->height());
666+ } else {
667+ ListItem *nextItem = itemAtIndex(modelIndex + 1);
668+ if (nextItem) {
669+ listItem->setY(nextItem->y() - listItem->height());
670+ } else if (modelIndex == 0 && m_headerItem) {
671+ listItem->setY(m_headerItem->height());
672+ } else if (!m_visibleItems.isEmpty()) {
673+ lostItem = true;
674+ }
675+ }
676+ }
677+ if (lostItem) {
678+ releaseItem(listItem);
679+ listItem = nullptr;
680+ } else {
681+ listItem->setCulled(listItem->y() + listItem->height() + m_clipItem->y() < contentY() || listItem->y() + m_clipItem->y() >= contentY() + height());
682+ if (m_visibleItems.isEmpty()) {
683+ m_visibleItems << listItem;
684+ } else {
685+ m_visibleItems.insert(modelIndex - m_firstVisibleIndex, listItem);
686+ }
687+ if (m_firstVisibleIndex < 0 || modelIndex < m_firstVisibleIndex) {
688+ m_firstVisibleIndex = modelIndex;
689+ polish();
690+ }
691+ adjustMinYExtent();
692+ m_contentHeightDirty = true;
693+ }
694+ return listItem;
695+ }
696+}
697+
698+void ListViewWithPageHeader::itemCreated(int modelIndex, QQuickItem *item)
699+{
700+// qDebug() << "ListViewWithPageHeader::itemCreated" << modelIndex << item;
701+
702+ item->setParentItem(m_clipItem);
703+ QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
704+ context->setContextProperty(QLatin1String("ListViewWithPageHeader"), this);
705+ context->setContextProperty(QLatin1String("heightToClip"), QVariant::fromValue<int>(0));
706+ if (modelIndex == m_asyncRequestedIndex) {
707+ createItem(modelIndex, false);
708+ refill();
709+ }
710+}
711+
712+void ListViewWithPageHeader::updateClipItem()
713+{
714+ m_clipItem->setHeight(height() - m_headerItemShownHeight);
715+ m_clipItem->setY(contentY() + m_headerItemShownHeight);
716+ m_clipItem->setClip(!m_forceNoClip && m_headerItemShownHeight > 0);
717+}
718+
719+void ListViewWithPageHeader::onContentHeightChanged()
720+{
721+ updateClipItem();
722+}
723+
724+void ListViewWithPageHeader::onContentWidthChanged()
725+{
726+ m_clipItem->setWidth(contentItem()->width());
727+}
728+
729+void ListViewWithPageHeader::onHeightChanged()
730+{
731+ polish();
732+}
733+
734+void ListViewWithPageHeader::onModelUpdated(const QQuickChangeSet &changeSet, bool /*reset*/)
735+{
736+ // TODO Do something with reset
737+// qDebug() << "ListViewWithPageHeader::onModelUpdated" << changeSet << reset;
738+ const auto oldFirstVisibleIndex = m_firstVisibleIndex;
739+
740+ Q_FOREACH(const QQuickChangeSet::Remove &remove, changeSet.removes()) {
741+// qDebug() << "ListViewWithPageHeader::onModelUpdated Remove" << remove.index << remove.count;
742+ if (remove.index + remove.count > m_firstVisibleIndex && remove.index < m_firstVisibleIndex + m_visibleItems.count()) {
743+ const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
744+ // If all the items we are removing are either not created or culled
745+ // we have to grow down to avoid viewport changing
746+ bool growDown = true;
747+ for (int i = 0; growDown && i < remove.count; ++i) {
748+ const int modelIndex = remove.index + i;
749+ ListItem *item = itemAtIndex(modelIndex);
750+ if (item && !item->culled()) {
751+ growDown = false;
752+ }
753+ }
754+ for (int i = remove.count - 1; i >= 0; --i) {
755+ const int visibleIndex = remove.index + i - m_firstVisibleIndex;
756+ if (visibleIndex >= 0 && visibleIndex < m_visibleItems.count()) {
757+ ListItem *item = m_visibleItems[visibleIndex];
758+ // Pass the section item down if needed
759+ if (item->m_sectionItem && visibleIndex + 1 < m_visibleItems.count()) {
760+ ListItem *nextItem = m_visibleItems[visibleIndex + 1];
761+ if (!nextItem->m_sectionItem) {
762+ nextItem->m_sectionItem = item->m_sectionItem;
763+ item->m_sectionItem = nullptr;
764+ }
765+ }
766+ releaseItem(item);
767+ m_visibleItems.removeAt(visibleIndex);
768+ }
769+ }
770+ if (growDown) {
771+ adjustMinYExtent();
772+ } else if (remove.index <= m_firstVisibleIndex && !m_visibleItems.isEmpty()) {
773+ // We removed the first item that is the one that positions the rest
774+ // position the new first item correctly
775+ m_visibleItems.first()->setY(oldFirstValidIndexPos);
776+ }
777+ } else if (remove.index + remove.count <= m_firstVisibleIndex) {
778+ m_firstVisibleIndex -= remove.count;
779+ }
780+ for (int i = remove.count - 1; i >= 0; --i) {
781+ const int modelIndex = remove.index + i;
782+ if (modelIndex == m_asyncRequestedIndex) {
783+ m_asyncRequestedIndex = -1;
784+ } else if (modelIndex < m_asyncRequestedIndex) {
785+ m_asyncRequestedIndex--;
786+ }
787+ }
788+ }
789+
790+ Q_FOREACH(const QQuickChangeSet::Insert &insert, changeSet.inserts()) {
791+// qDebug() << "ListViewWithPageHeader::onModelUpdated Insert" << insert.index << insert.count;
792+ const bool insertingInValidIndexes = insert.index > m_firstVisibleIndex && insert.index < m_firstVisibleIndex + m_visibleItems.count();
793+ const bool firstItemWithViewOnTop = insert.index == 0 && m_firstVisibleIndex == 0 && m_visibleItems.first()->y() + m_clipItem->y() > contentY();
794+ if (insertingInValidIndexes || firstItemWithViewOnTop)
795+ {
796+ // If the items we are adding won't be really visible
797+ // we grow up instead of down to not change the viewport
798+ bool growUp = false;
799+ if (!firstItemWithViewOnTop) {
800+ for (int i = 0; i < m_visibleItems.count(); ++i) {
801+ if (!m_visibleItems[i]->culled()) {
802+ if (insert.index <= m_firstVisibleIndex + i) {
803+ growUp = true;
804+ }
805+ break;
806+ }
807+ }
808+ }
809+
810+ const qreal oldFirstValidIndexPos = m_visibleItems.first()->y();
811+ for (int i = insert.count - 1; i >= 0; --i) {
812+ const int modelIndex = insert.index + i;
813+ ListItem *item = createItem(modelIndex, false);
814+ if (growUp) {
815+ ListItem *firstItem = m_visibleItems.first();
816+ firstItem->setY(firstItem->y() - item->height());
817+ adjustMinYExtent();
818+ }
819+ // Adding an item may break a "same section" chain, so check
820+ // if we need adding a new section item
821+ if (m_sectionDelegate) {
822+ ListItem *nextItem = itemAtIndex(modelIndex + 1);
823+ if (nextItem && !nextItem->m_sectionItem) {
824+ nextItem->m_sectionItem = getSectionItem(modelIndex + 1, true /* alredy inserted into m_visibleItems*/);
825+ if (growUp && nextItem->m_sectionItem) {
826+ ListItem *firstItem = m_visibleItems.first();
827+ firstItem->setY(firstItem->y() - nextItem->m_sectionItem->height());
828+ adjustMinYExtent();
829+ }
830+ }
831+ }
832+ }
833+ if (firstItemWithViewOnTop) {
834+ ListItem *firstItem = m_visibleItems.first();
835+ firstItem->setY(oldFirstValidIndexPos);
836+ }
837+ } else if (insert.index <= m_firstVisibleIndex) {
838+ m_firstVisibleIndex += insert.count;
839+ }
840+
841+ for (int i = insert.count - 1; i >= 0; --i) {
842+ const int modelIndex = insert.index + i;
843+ if (modelIndex <= m_asyncRequestedIndex) {
844+ m_asyncRequestedIndex++;
845+ }
846+ }
847+ }
848+
849+ if (m_firstVisibleIndex != oldFirstVisibleIndex) {
850+ adjustMinYExtent();
851+ }
852+
853+ layout();
854+ polish();
855+ m_contentHeightDirty = true;
856+}
857+
858+void ListViewWithPageHeader::onShowHeaderAnimationFinished()
859+{
860+ m_contentHeightDirty = true;
861+ polish();
862+}
863+
864+void ListViewWithPageHeader::itemGeometryChanged(QQuickItem * /*item*/, const QRectF &newGeometry, const QRectF &oldGeometry)
865+{
866+ const qreal heightDiff = newGeometry.height() - oldGeometry.height();
867+ if (heightDiff != 0) {
868+ if (oldGeometry.y() + oldGeometry.height() + m_clipItem->y() < contentY() && !m_visibleItems.isEmpty()) {
869+ ListItem *firstItem = m_visibleItems.first();
870+ firstItem->setY(firstItem->y() - heightDiff);
871+ adjustMinYExtent();
872+ layout();
873+ }
874+ refill();
875+ adjustMinYExtent();
876+ polish();
877+ m_contentHeightDirty = true;
878+ }
879+}
880+
881+void ListViewWithPageHeader::headerHeightChanged(qreal newHeaderHeight, qreal oldHeaderHeight, qreal oldHeaderY)
882+{
883+ const qreal heightDiff = newHeaderHeight - oldHeaderHeight;
884+ if (m_headerItemShownHeight > 0) {
885+ // If the header is shown because of the clip
886+ // Change its size
887+ m_headerItemShownHeight += heightDiff;
888+ m_headerItemShownHeight = qBound(static_cast<qreal>(0.), m_headerItemShownHeight, newHeaderHeight);
889+ updateClipItem();
890+ adjustMinYExtent();
891+ } else {
892+ if (oldHeaderY + oldHeaderHeight > contentY()) {
893+ // If the header is shown because its position
894+ // Change its size
895+ ListItem *firstItem = m_visibleItems.first();
896+ firstItem->setY(firstItem->y() + heightDiff);
897+ layout();
898+ } else {
899+ // If the header is not on screen, just change the start of the list
900+ // so the viewport is not changed
901+ adjustMinYExtent();
902+ }
903+ }
904+}
905+
906+
907+void ListViewWithPageHeader::adjustMinYExtent()
908+{
909+ if (m_visibleItems.isEmpty()) {
910+ m_minYExtent = 0;
911+ } else {
912+ qreal nonCreatedHeight = 0;
913+ if (m_firstVisibleIndex != 0) {
914+ // Calculate the average height of items to estimate the position of the list start
915+ const int visibleItems = m_visibleItems.count();
916+ qreal visibleItemsHeight = 0;
917+ Q_FOREACH(ListItem *item, m_visibleItems) {
918+ visibleItemsHeight += item->height();
919+ }
920+ nonCreatedHeight = m_firstVisibleIndex * visibleItemsHeight / visibleItems;
921+// qDebug() << m_firstVisibleIndex << visibleItemsHeight << visibleItems << nonCreatedHeight;
922+ }
923+ m_minYExtent = nonCreatedHeight - m_visibleItems.first()->y() - m_clipItem->y() + (m_headerItem ? m_headerItem->implicitHeight() : 0);
924+ }
925+}
926+
927+ListViewWithPageHeader::ListItem *ListViewWithPageHeader::itemAtIndex(int modelIndex) const
928+{
929+ const int visibleIndexedModelIndex = modelIndex - m_firstVisibleIndex;
930+ if (visibleIndexedModelIndex >= 0 && visibleIndexedModelIndex < m_visibleItems.count())
931+ return m_visibleItems[visibleIndexedModelIndex];
932+
933+ return nullptr;
934+}
935+
936+void ListViewWithPageHeader::layout()
937+{
938+ if (m_inLayout)
939+ return;
940+
941+ m_inLayout = true;
942+ if (!m_visibleItems.isEmpty()) {
943+ const qreal visibleFrom = contentY() - m_clipItem->y() + m_headerItemShownHeight;
944+ const qreal visibleTo = contentY() + height() - m_clipItem->y();
945+
946+ qreal pos = m_visibleItems.first()->y();
947+
948+// qDebug() << "ListViewWithPageHeader::layout Updating positions and heights. contentY" << contentY() << "minYExtent" << minYExtent();
949+ int firstReallyVisibleItem = -1;
950+ int modelIndex = m_firstVisibleIndex;
951+ Q_FOREACH(ListItem *item, m_visibleItems) {
952+ const bool cull = pos + item->height() < visibleFrom || pos >= visibleTo;
953+ item->setCulled(cull);
954+ item->setY(pos);
955+ if (!cull && firstReallyVisibleItem == -1) {
956+ firstReallyVisibleItem = modelIndex;
957+ if (m_topSectionItem) {
958+ // Update the top sticky section header
959+ const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
960+ QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();
961+ context->setContextProperty(QLatin1String("section"), section);
962+
963+ // Positing the top section sticky item is a two step process
964+ // First we set it either we cull it (because it doesn't need to be sticked to the top)
965+ // or stick it to the top
966+ // Then after the loop we'll make sure that if there's another section just below it
967+ // pushed the sticky section up to make it disappear
968+ const qreal topSectionStickPos = m_headerItemShownHeight + contentY() - m_clipItem->y();
969+ if (topSectionStickPos <= pos) {
970+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
971+ if (item->m_sectionItem) {
972+ // This seems it should happen since why would we cull the top section
973+ // if the first visible item has no section header? This only happens briefly
974+ // when increasing the height of a list that is at the bottom, the m_topSectionItem
975+ // gets shown shortly in the next polish call
976+ QQuickItemPrivate::get(item->m_sectionItem)->setCulled(false);
977+ }
978+ } else {
979+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);
980+ m_topSectionItem->setY(topSectionStickPos);
981+ if (item->m_sectionItem) {
982+ QQuickItemPrivate::get(item->m_sectionItem)->setCulled(true);
983+ }
984+ }
985+ }
986+ }
987+ QQmlContext *context = QQmlEngine::contextForObject(item->m_item)->parentContext();
988+ const qreal clipFrom = visibleFrom + (!item->m_sectionItem && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0);
989+ if (!cull && pos < clipFrom) {
990+ context->setContextProperty(QLatin1String("heightToClip"), clipFrom - pos);
991+ } else {
992+ context->setContextProperty(QLatin1String("heightToClip"), QVariant::fromValue<int>(0));
993+ }
994+// qDebug() << "ListViewWithPageHeader::layout" << item->m_item;
995+ pos += item->height();
996+ ++modelIndex;
997+ }
998+
999+ // Second step of section sticky item positioning
1000+ // Look at the next section header, check if it's pushing up the sticky one
1001+ if (m_topSectionItem) {
1002+ if (firstReallyVisibleItem >= 0) {
1003+ for (int i = firstReallyVisibleItem - m_firstVisibleIndex + 1; i < m_visibleItems.count(); ++i) {
1004+ ListItem *item = m_visibleItems[i];
1005+ if (item->m_sectionItem) {
1006+ if (m_topSectionItem->y() + m_topSectionItem->height() > item->y()) {
1007+ m_topSectionItem->setY(item->y() - m_topSectionItem->height());
1008+ }
1009+ break;
1010+ }
1011+ }
1012+ }
1013+ }
1014+ }
1015+ m_inLayout = false;
1016+}
1017+
1018+void ListViewWithPageHeader::updatePolish()
1019+{
1020+ Q_FOREACH(ListItem *item, m_itemsToRelease)
1021+ reallyReleaseItem(item);
1022+ m_itemsToRelease.clear();
1023+
1024+ if (!model())
1025+ return;
1026+
1027+ layout();
1028+
1029+ refill();
1030+
1031+ if (m_contentHeightDirty) {
1032+ qreal contentHeight;
1033+ if (m_visibleItems.isEmpty()) {
1034+ contentHeight = m_headerItem ? m_headerItem->height() : 0;
1035+ } else {
1036+ const int modelCount = model()->rowCount();
1037+ const int visibleItems = m_visibleItems.count();
1038+ const int lastValidIndex = m_firstVisibleIndex + visibleItems - 1;
1039+ qreal nonCreatedHeight = 0;
1040+ if (lastValidIndex != modelCount - 1) {
1041+ const int visibleItems = m_visibleItems.count();
1042+ qreal visibleItemsHeight = 0;
1043+ Q_FOREACH(ListItem *item, m_visibleItems) {
1044+ visibleItemsHeight += item->height();
1045+ }
1046+ const int unknownSizes = modelCount - (m_firstVisibleIndex + visibleItems);
1047+ nonCreatedHeight = unknownSizes * visibleItemsHeight / visibleItems;
1048+ }
1049+ ListItem *item = m_visibleItems.last();
1050+ contentHeight = nonCreatedHeight + item->y() + item->height() + m_clipItem->y();
1051+ if (m_firstVisibleIndex != 0) {
1052+ // Make sure that if we are shrinking we tell the view we still fit
1053+ m_minYExtent = qMax(m_minYExtent, -(contentHeight - height()));
1054+ }
1055+ }
1056+
1057+ m_contentHeightDirty = false;
1058+ setContentHeight(contentHeight);
1059+ }
1060+}
1061+
1062+#include "moc_listviewwithpageheader.cpp"
plugins/ListViewWithPageHeader/listviewwithpageheader.hnew file+180
@@ -0,0 +1,180 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef LISTVIEWWITHPAGEHEADER_H
18+#define LISTVIEWWITHPAGEHEADER_H
19+
20+#include <private/qquickitemchangelistener_p.h>
21+#include <private/qquickflickable_p.h>
22+
23+class QAbstractItemModel;
24+class QQuickChangeSet;
25+class QQuickNumberAnimation;
26+class QQuickVisualDataModel;
27+
28+
29+/**
30+ Note for users of this class
31+
32+ ListViewWithPageHeader already loads delegates async when appropiate so if
33+ your delegate uses a Loader you should not enable the asynchronous feature since
34+ that will need to introduce sizing problems
35+
36+ With the double async it may happen what while we are scrolling down
37+ we reach to a point where given the size of the just created delegate with loader not yet loaded (which will be very close to 0)
38+ we are already "at the end" of the list, but then a few milliseconds later the loader finishes loading and we could
39+ have kept scrolling. This is specially visible at the end of the list where you realize
40+ that scrolling ended a bit before the end of the list but the speed of the flicking was good
41+ to reach the end
42+
43+ By not having the second async we get a better sizing when the delegate is created and things work better
44+*/
45+
46+class ListViewWithPageHeader : public QQuickFlickable, public QQuickItemChangeListener
47+{
48+ Q_OBJECT
49+ Q_PROPERTY(QAbstractItemModel *model READ model WRITE setModel NOTIFY modelChanged)
50+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
51+ Q_PROPERTY(QQuickItem *pageHeader READ header WRITE setHeader NOTIFY headerChanged)
52+ Q_PROPERTY(QQmlComponent *sectionDelegate READ sectionDelegate WRITE setSectionDelegate NOTIFY sectionDelegateChanged)
53+ Q_PROPERTY(QString sectionProperty READ sectionProperty WRITE setSectionProperty NOTIFY sectionPropertyChanged)
54+ Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
55+
56+ friend class ListViewWithPageHeaderTest;
57+ friend class ListViewWithPageHeaderTestSection;
58+
59+public:
60+ ListViewWithPageHeader();
61+ ~ListViewWithPageHeader();
62+
63+ QAbstractItemModel *model() const;
64+ void setModel(QAbstractItemModel *model);
65+
66+ QQmlComponent *delegate() const;
67+ void setDelegate(QQmlComponent *delegate);
68+
69+ QQuickItem *header() const;
70+ void setHeader(QQuickItem *header);
71+
72+ QQmlComponent *sectionDelegate() const;
73+ void setSectionDelegate(QQmlComponent *delegate);
74+
75+ QString sectionProperty() const;
76+ void setSectionProperty(const QString &property);
77+
78+ bool forceNoClip() const;
79+ void setForceNoClip(bool noClip);
80+
81+ Q_INVOKABLE void positionAtBeginning();
82+ Q_INVOKABLE void showHeader();
83+
84+Q_SIGNALS:
85+ void modelChanged();
86+ void delegateChanged();
87+ void headerChanged();
88+ void sectionDelegateChanged();
89+ void sectionPropertyChanged();
90+ void forceNoClipChanged();
91+
92+protected:
93+ void componentComplete();
94+ void viewportMoved(Qt::Orientations orient);
95+ qreal minYExtent() const;
96+ void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry);
97+ void updatePolish();
98+
99+private Q_SLOTS:
100+ void itemCreated(int modelIndex, QQuickItem *item);
101+ void onContentHeightChanged();
102+ void onContentWidthChanged();
103+ void onHeightChanged();
104+ void onModelUpdated(const QQuickChangeSet &changeSet, bool reset);
105+ void onShowHeaderAnimationFinished();
106+
107+private:
108+ class ListItem
109+ {
110+ public:
111+ qreal height() const;
112+
113+ qreal y() const;
114+ void setY(qreal newY);
115+
116+ bool culled() const;
117+ void setCulled(bool culled);
118+
119+ QQuickItem *m_item;
120+ QQuickItem *m_sectionItem;
121+ };
122+
123+ void createDelegateModel();
124+
125+ void layout();
126+ void refill();
127+ bool addVisibleItems(qreal fillFrom, qreal fillTo, bool asynchronous);
128+ bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo);
129+ ListItem *createItem(int modelIndex, bool asynchronous);
130+
131+ void adjustMinYExtent();
132+ void updateClipItem();
133+ void headerHeightChanged(qreal newHeaderHeight, qreal oldHeaderHeight, qreal oldHeaderY);
134+ ListItem *itemAtIndex(int modelIndex) const; // Returns the item at modelIndex if has been created
135+ void releaseItem(ListItem *item);
136+ void reallyReleaseItem(ListItem *item);
137+ void updateWatchedRoles();
138+ QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
139+ QQuickItem *getSectionItem(const QString &sectionText);
140+
141+ QQuickVisualDataModel *m_delegateModel;
142+
143+ // Index we are waiting because we requested it asynchronously
144+ int m_asyncRequestedIndex;
145+
146+ // Used to only give a warning once if the delegate does not return objects
147+ bool m_delegateValidated;
148+
149+ // Visible indexes, [0] is m_firstValidIndex, [0+1] is m_firstValidIndex +1, ...
150+ QList<ListItem *> m_visibleItems;
151+ int m_firstVisibleIndex;
152+
153+ qreal m_minYExtent;
154+
155+ QQuickItem *m_clipItem;
156+
157+ // If any of the heights has changed
158+ // or new items have been added/removed
159+ bool m_contentHeightDirty;
160+
161+ QQuickItem *m_headerItem;
162+ qreal m_previousContentY;
163+ qreal m_headerItemShownHeight; // The height of header shown when the header is shown outside its topmost position
164+ // i.e. it's being shown after dragging down in the middle of the list
165+ QQuickNumberAnimation *m_headerShowAnimation;
166+
167+ QQmlComponent *m_sectionDelegate;
168+ QString m_sectionProperty;
169+ QQuickItem *m_topSectionItem;
170+
171+ bool m_forceNoClip;
172+ bool m_inLayout;
173+
174+ // Qt 5.0 doesn't like releasing the items just after itemCreated
175+ // so we delay the releasing until the next updatePolish
176+ QList<ListItem *> m_itemsToRelease;
177+};
178+
179+
180+#endif
plugins/ListViewWithPageHeader/plugin.cppnew file+29
@@ -0,0 +1,29 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#include "plugin.h"
19+
20+#include "listviewwithpageheader.h"
21+
22+#include <QAbstractItemModel>
23+
24+void ListViewWithPageHeaderPlugin::registerTypes(const char *uri)
25+{
26+ Q_ASSERT(uri == QLatin1String("ListViewWithPageHeader"));
27+ qmlRegisterType<QAbstractItemModel>();
28+ qmlRegisterType<ListViewWithPageHeader>(uri, 0, 1, "ListViewWithPageHeader");
29+}
plugins/ListViewWithPageHeader/plugin.hnew file+33
@@ -0,0 +1,33 @@
1+/*
2+ * Copyright (C) 2012 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ */
17+
18+#ifndef LISTVIEWWITHPAGEHEADER_PLUGIN_H
19+#define LISTVIEWWITHPAGEHEADER_PLUGIN_H
20+
21+#include <QtQml/QQmlEngine>
22+#include <QtQml/QQmlExtensionPlugin>
23+
24+class ListViewWithPageHeaderPlugin : public QQmlExtensionPlugin
25+{
26+ Q_OBJECT
27+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28+
29+public:
30+ void registerTypes(const char *uri);
31+};
32+
33+#endif
plugins/ListViewWithPageHeader/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module ListViewWithPageHeader
2+plugin ListViewWithPageHeader-qml
plugins/Ubuntu/Gestures/AxisVelocityCalculator.cpp+31−16
@@ -21,9 +21,10 @@
2121#include "AxisVelocityCalculator.h"
2222#include <QtCore/QElapsedTimer>
2323
24−class RealTimeSource : public AxisVelocityCalculator::TimeSource {
24+class RealTimeSource : public UbuntuGestures::TimeSource {
2525public:
26− RealTimeSource() {
26+ RealTimeSource()
27+ : UbuntuGestures::TimeSource() {
2728 m_timer.start();
2829 }
2930 virtual qint64 msecsSinceReference() {
@@ -33,23 +34,17 @@ private:
3334 QElapsedTimer m_timer;
3435};
3536
36−
3737AxisVelocityCalculator::AxisVelocityCalculator(QObject *parent)
38− : AxisVelocityCalculator(new RealTimeSource, parent)
39−{
40−}
41−
42−AxisVelocityCalculator::AxisVelocityCalculator(TimeSource *timeSource, QObject *parent)
4338 : QObject(parent)
44− , m_timeSource(timeSource)
39+ , m_timeSource(new RealTimeSource)
4540 , m_trackedPosition(0.0)
4641{
42+ m_timeSource->setParent(this);
4743 reset();
4844}
4945
5046AxisVelocityCalculator::~AxisVelocityCalculator()
5147{
52− delete m_timeSource;
5348}
5449
5550qreal AxisVelocityCalculator::trackedPosition() const
@@ -59,13 +54,17 @@ qreal AxisVelocityCalculator::trackedPosition() const
5954
6055void AxisVelocityCalculator::setTrackedPosition(qreal newPosition)
6156{
62− if (newPosition == m_trackedPosition) {
63− return;
57+ processMovement(newPosition - m_trackedPosition);
58+
59+ if (newPosition != m_trackedPosition) {
60+ m_trackedPosition = newPosition;
61+ Q_EMIT trackedPositionChanged(newPosition);
6462 }
63+}
6564
66− processMovement(newPosition - m_trackedPosition);
67− m_trackedPosition = newPosition;
68− Q_EMIT trackedPositionChanged(newPosition);
65+void AxisVelocityCalculator::updateIdleTime()
66+{
67+ processMovement(0);
6968}
7069
7170void AxisVelocityCalculator::processMovement(qreal movement)
@@ -83,11 +82,12 @@ void AxisVelocityCalculator::processMovement(qreal movement)
8382 m_samplesWrite = (m_samplesWrite + 1) % MAX_SAMPLES;
8483}
8584
86−qreal AxisVelocityCalculator::calculate() const
85+qreal AxisVelocityCalculator::calculate()
8786{
8887 if (numSamples() < MIN_SAMPLES_NEEDED) {
8988 return 0.0;
9089 }
90+ updateIdleTime(); // consider the time elapsed since the last update and now
9191
9292 int lastIndex;
9393 if (m_samplesWrite == 0) {
@@ -141,3 +141,18 @@ int AxisVelocityCalculator::numSamples() const
141141 }
142142 }
143143}
144+
145+void AxisVelocityCalculator::setTimeSource(UbuntuGestures::TimeSource *timeSource)
146+{
147+ if (m_timeSource && m_timeSource->parent() == this)
148+ delete m_timeSource;
149+
150+ m_timeSource = timeSource;
151+
152+ if (numSamples() > 0) {
153+ qWarning("AxisVelocityCalculator: changing time source while there are samples present.");
154+ // Any existent samples are based on the old time source and are, therefore, incompatible
155+ // with this new one.
156+ reset();
157+ }
158+}
plugins/Ubuntu/Gestures/AxisVelocityCalculator.h+31−20
@@ -25,6 +25,19 @@
2525#include <stdint.h>
2626#include <QtCore/QObject>
2727
28+namespace UbuntuGestures {
29+/*
30+ Interface for a time source.
31+ */
32+class UBUNTUGESTURES_EXPORT TimeSource : public QObject {
33+ Q_OBJECT
34+public:
35+ virtual ~TimeSource() {}
36+ /* Returns the current time in milliseconds since some reference time in the past. */
37+ virtual qint64 msecsSinceReference() = 0;
38+};
39+}
40+
2841/*
2942 Estimates the current velocity of a finger based on recent movement along an axis
3043
@@ -59,27 +72,11 @@ class UBUNTUGESTURES_EXPORT AxisVelocityCalculator : public QObject
5972 NOTIFY trackedPositionChanged)
6073public:
6174
62− /*
63− Interface for a time source.
64− */
65− class TimeSource {
66− public:
67− virtual ~TimeSource() {}
68− /* Returns the current time in milliseconds since some reference time in the past. */
69− virtual qint64 msecsSinceReference() = 0;
70− };
71−
7275 /*
7376 Regular constructor
7477 */
7578 AxisVelocityCalculator(QObject *parent = 0);
7679
77− /*
78− Extended constructor useful for testing purposes where you can inject
79− a fake time source implementation.
80− */
81− AxisVelocityCalculator(TimeSource *timeSource, QObject *parent = 0);
82−
8380 virtual ~AxisVelocityCalculator();
8481
8582 qreal trackedPosition() const;
@@ -88,7 +85,7 @@ public:
8885 /*
8986 Calculates the finger velocity, in axis units/millisecond
9087 */
91− Q_INVOKABLE qreal calculate() const;
88+ Q_INVOKABLE qreal calculate();
9289
9390 /*
9491 Removes all stored movements from previous calls to setTrackedPosition()
@@ -97,6 +94,11 @@ public:
9794
9895 int numSamples() const;
9996
97+ /*
98+ Replaces the TimeSource with the given one. Useful for testing purposes.
99+ */
100+ void setTimeSource(UbuntuGestures::TimeSource *timeSource);
101+
100102 /*
101103 The minimum amount of samples needed for a velocity calculation.
102104 */
@@ -105,18 +107,27 @@ public:
105107 /*
106108 Maximum number of movement samples stored
107109 */
108− static const int MAX_SAMPLES = 10;
110+ static const int MAX_SAMPLES = 50;
109111
110112 /*
111113 Age of the oldest sample considered in the velocity calculations, in
112114 milliseconds, compared to the most recent one.
113115 */
114− static const int AGE_OLDEST_SAMPLE = 200;
116+ static const int AGE_OLDEST_SAMPLE = 100;
115117
116118Q_SIGNALS:
117119 void trackedPositionChanged(qreal value);
118120
119121private:
122+
123+ /*
124+ Inform that trackedPosition remained motionless since the time it was
125+ last changed.
126+
127+ It's the same as calling setTrackedPosition(trackedPosition())
128+ */
129+ void updateIdleTime();
130+
120131 /*
121132 How much the finger has moved since processMovement() was last called.
122133 */
@@ -134,7 +145,7 @@ private:
134145 int m_samplesRead; /* index of the oldest sample available. -1 if buffer is empty */
135146 int m_samplesWrite; /* index where the next sample will be written */
136147
137− TimeSource *m_timeSource;
148+ UbuntuGestures::TimeSource *m_timeSource;
138149
139150 qreal m_trackedPosition;
140151};
plugins/Ubuntu/Gestures/CMakeLists.txt+2−2
@@ -27,9 +27,9 @@ add_custom_target(UbuntuGestureQmlDirFile ALL
2727)
2828
2929install(TARGETS UbuntuGestureQml
30− DESTINATION ${SHELL_APP_DIR}/plugins/Ubuntu/Gestures
30+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Ubuntu/Gestures
3131 )
3232
3333install(FILES qmldir
34− DESTINATION ${SHELL_APP_DIR}/plugins/Ubuntu/Gestures
34+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Ubuntu/Gestures
3535 )
plugins/Ubuntu/Gestures/Direction.cpp+5
@@ -25,3 +25,8 @@ bool Direction::isVertical(Direction::Type type)
2525{
2626 return type == Direction::Upwards || type == Direction::Downwards;
2727}
28+
29+bool Direction::isPositive(Direction::Type type)
30+{
31+ return type == Rightwards || type == Downwards;
32+}
plugins/Ubuntu/Gestures/Direction.h+1
@@ -38,6 +38,7 @@ public:
3838
3939 Q_INVOKABLE static bool isHorizontal(Direction::Type type);
4040 Q_INVOKABLE static bool isVertical(Direction::Type type);
41+ Q_INVOKABLE static bool isPositive(Direction::Type type);
4142};
4243
4344#endif // DIRECTION_H
plugins/Ubuntu/Gestures/DirectionalDragArea.cpp+61−10
@@ -141,12 +141,9 @@ void DirectionalDragArea::setRecognitionTimer(UbuntuGestures::AbstractTimer *tim
141141 }
142142}
143143
144−void DirectionalDragArea::setAxisVelocityCalculator(AxisVelocityCalculator *newVelCalc)
144+void DirectionalDragArea::setTimeSource(UbuntuGestures::TimeSource *timeSource)
145145{
146− if (m_velocityCalculator->parent() == this)
147− delete m_velocityCalculator;
148−
149− m_velocityCalculator = newVelCalc;
146+ m_velocityCalculator->setTimeSource(timeSource);
150147}
151148
152149qreal DirectionalDragArea::distance() const
@@ -158,6 +155,15 @@ qreal DirectionalDragArea::distance() const
158155 }
159156}
160157
158+qreal DirectionalDragArea::sceneDistance() const
159+{
160+ if (Direction::isHorizontal(m_direction)) {
161+ return m_previousScenePos.x() - m_startScenePos.x();
162+ } else {
163+ return m_previousScenePos.y() - m_startScenePos.y();
164+ }
165+}
166+
161167qreal DirectionalDragArea::touchX() const
162168{
163169 return m_previousPos.x();
@@ -168,6 +174,16 @@ qreal DirectionalDragArea::touchY() const
168174 return m_previousPos.y();
169175}
170176
177+qreal DirectionalDragArea::touchSceneX() const
178+{
179+ return m_previousScenePos.x();
180+}
181+
182+qreal DirectionalDragArea::touchSceneY() const
183+{
184+ return m_previousScenePos.y();
185+}
186+
171187void DirectionalDragArea::touchEvent(QTouchEvent *event)
172188{
173189 if (!isEnabled() || !isVisible()) {
@@ -195,15 +211,22 @@ void DirectionalDragArea::touchEvent_absent(QTouchEvent *event)
195211{
196212 if ((event->touchPointStates() && (Qt::TouchPointPressed || Qt::TouchPointMoved))
197213 && event->touchPoints().count() == 1) {
198− m_startPos = event->touchPoints()[0].pos();
199− m_touchId = event->touchPoints()[0].id();
214+ const QTouchEvent::TouchPoint &touchPoint = event->touchPoints()[0];
215+ m_startPos = touchPoint.pos();
216+ m_startScenePos = touchPoint.scenePos();
217+ m_touchId = touchPoint.id();
200218 m_dampedPos.reset(m_startPos);
201219 updateVelocityCalculator(m_startPos);
202220 m_velocityCalculator->reset();
203221 m_numSamplesOnLastSpeedCheck = 0;
204222 m_silenceTime = 0;
205223 setPreviousPos(m_startPos);
206− setStatus(Undecided);
224+ setPreviousScenePos(m_startScenePos);
225+
226+ if (m_distanceThreshold > 0)
227+ setStatus(Undecided);
228+ else
229+ setStatus(Recognized);
207230 }
208231}
209232
@@ -241,6 +264,7 @@ void DirectionalDragArea::touchEvent_undecided(QTouchEvent *event)
241264 }
242265
243266 setPreviousPos(touchPos);
267+ setPreviousScenePos(touchPoint->scenePos());
244268
245269 if (movedFarEnough(touchPos)) {
246270 setStatus(Recognized);
@@ -252,6 +276,7 @@ void DirectionalDragArea::touchEvent_recognized(QTouchEvent *event)
252276 const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
253277
254278 setPreviousPos(touchPoint->pos());
279+ setPreviousScenePos(touchPoint->scenePos());
255280
256281 if (touchPoint->state() == Qt::TouchPointReleased) {
257282 setStatus(WaitingForTouch);
@@ -366,6 +391,10 @@ void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus)
366391 m_recognitionTimer->start();
367392 Q_EMIT draggingChanged(true);
368393 break;
394+ case Recognized:
395+ if (oldStatus == WaitingForTouch)
396+ Q_EMIT draggingChanged(true);
397+ break;
369398 case Rejected:
370399 Q_EMIT draggingChanged(false);
371400 break;
@@ -375,7 +404,7 @@ void DirectionalDragArea::setStatus(DirectionalDragArea::Status newStatus)
375404 }
376405}
377406
378−void DirectionalDragArea::setPreviousPos(QPointF point)
407+void DirectionalDragArea::setPreviousPos(const QPointF &point)
379408{
380409 Q_ASSERT(m_status != Rejected);
381410
@@ -397,7 +426,29 @@ void DirectionalDragArea::setPreviousPos(QPointF point)
397426 }
398427}
399428
400−void DirectionalDragArea::updateVelocityCalculator(QPointF point)
429+void DirectionalDragArea::setPreviousScenePos(const QPointF &point)
430+{
431+ Q_ASSERT(m_status != Rejected);
432+
433+ bool xChanged = m_previousScenePos.x() != point.x();
434+ bool yChanged = m_previousScenePos.y() != point.y();
435+
436+ m_previousScenePos = point;
437+
438+ if (xChanged) {
439+ Q_EMIT touchSceneXChanged(point.x());
440+ if (Direction::isHorizontal(m_direction))
441+ Q_EMIT sceneDistanceChanged(sceneDistance());
442+ }
443+
444+ if (yChanged) {
445+ Q_EMIT touchSceneYChanged(point.y());
446+ if (Direction::isVertical(m_direction))
447+ Q_EMIT sceneDistanceChanged(sceneDistance());
448+ }
449+}
450+
451+void DirectionalDragArea::updateVelocityCalculator(const QPointF &point)
401452{
402453 if (Direction::isHorizontal(m_direction)) {
403454 m_velocityCalculator->setTrackedPosition(point.x());
plugins/Ubuntu/Gestures/DirectionalDragArea.h+23−5
@@ -60,10 +60,18 @@ class UBUNTUGESTURES_EXPORT DirectionalDragArea : public QQuickItem {
6060 // DirectionalDragArea's direction.
6161 Q_PROPERTY(qreal distance READ distance NOTIFY distanceChanged)
6262
63− // Position of the touch point performing the drag.
63+ // The distance travelled by the finger along the axis specified by
64+ // DirectionalDragArea's direction in scene coordinates
65+ Q_PROPERTY(qreal sceneDistance READ sceneDistance NOTIFY sceneDistanceChanged)
66+
67+ // Position of the touch point performing the drag relative to this item.
6468 Q_PROPERTY(qreal touchX READ touchX NOTIFY touchXChanged)
6569 Q_PROPERTY(qreal touchY READ touchY NOTIFY touchYChanged)
6670
71+ // Position of the touch point performing the drag, in scene's coordinate system
72+ Q_PROPERTY(qreal touchSceneX READ touchSceneX NOTIFY touchSceneXChanged)
73+ Q_PROPERTY(qreal touchSceneY READ touchSceneY NOTIFY touchSceneYChanged)
74+
6775 // The current status of the directional drag gesture area.
6876 Q_PROPERTY(Status status READ status NOTIFY statusChanged)
6977
@@ -146,10 +154,14 @@ public:
146154 Status status() const { return m_status; }
147155
148156 qreal distance() const;
157+ qreal sceneDistance() const;
149158
150159 qreal touchX() const;
151160 qreal touchY() const;
152161
162+ qreal touchSceneX() const;
163+ qreal touchSceneY() const;
164+
153165 bool dragging() const { return (m_status == Undecided) || (m_status == Recognized); }
154166
155167 qreal maxDeviation() const { return m_dampedPos.maxDelta(); }
@@ -172,14 +184,15 @@ public:
172184 // Useful for providing a fake timer when testing.
173185 void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer);
174186
175− // Useful for testing, where a calculator with a fake time source can be supplied
176− void setAxisVelocityCalculator(AxisVelocityCalculator *velCalc);
187+ // Useful for testing, where a fake time source can be supplied
188+ void setTimeSource(UbuntuGestures::TimeSource *timeSource);
177189
178190Q_SIGNALS:
179191 void directionChanged(Direction::Type direction);
180192 void statusChanged(Status value);
181193 void draggingChanged(bool value);
182194 void distanceChanged(qreal value);
195+ void sceneDistanceChanged(qreal value);
183196 void maxDeviationChanged(qreal value);
184197 void wideningAngleChanged(qreal value);
185198 void distanceThresholdChanged(qreal value);
@@ -187,6 +200,8 @@ Q_SIGNALS:
187200 void maxSilenceTimeChanged(int value);
188201 void touchXChanged(qreal value);
189202 void touchYChanged(qreal value);
203+ void touchSceneXChanged(qreal value);
204+ void touchSceneYChanged(qreal value);
190205
191206protected:
192207 virtual void touchEvent(QTouchEvent *event);
@@ -204,13 +219,16 @@ private:
204219 bool movedFarEnough(const QPointF &point) const;
205220 const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event);
206221 void setStatus(Status newStatus);
207− void setPreviousPos(QPointF point);
208− void updateVelocityCalculator(QPointF point);
222+ void setPreviousPos(const QPointF &point);
223+ void setPreviousScenePos(const QPointF &point);
224+ void updateVelocityCalculator(const QPointF &point);
209225
210226 Status m_status;
211227
212228 QPointF m_startPos;
229+ QPointF m_startScenePos;
213230 QPointF m_previousPos;
231+ QPointF m_previousScenePos;
214232 int m_touchId;
215233
216234 // A movement damper is used in some of the gesture recognition calculations
plugins/Unity/CMakeLists.txt+10−2
@@ -30,6 +30,14 @@ set(QMLPLUGIN_SRC
3030 ratingsfilter.cpp
3131 bottombarvisibilitycommunicatorshell.cpp
3232 launchermodel.cpp
33+ applicationpreview.cpp
34+ genericpreview.cpp
35+ moviepreview.cpp
36+ musicpreview.cpp
37+ preview.cpp
38+ previewaction.cpp
39+ previewinfohint.cpp
40+ variantutils.cpp
3341 )
3442
3543add_library(Unity-qml MODULE
@@ -51,9 +59,9 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
5159 )
5260
5361install(TARGETS Unity-qml
54− DESTINATION ${SHELL_APP_DIR}/plugins/Unity
62+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity
5563 )
5664
5765install(FILES qmldir
58− DESTINATION ${SHELL_APP_DIR}/plugins/Unity
66+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Unity
5967 )
plugins/Unity/applicationpreview.cppnew file+96
@@ -0,0 +1,96 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// local
21+#include "applicationpreview.h"
22+
23+#include <QDebug>
24+
25+ApplicationPreview::ApplicationPreview(QObject *parent):
26+ Preview(parent),
27+ m_unityAppPreview(nullptr)
28+{
29+}
30+
31+QString ApplicationPreview::lastUpdate() const
32+{
33+ if (m_unityAppPreview) {
34+ return QString::fromStdString(m_unityAppPreview->last_update());
35+ } else {
36+ qWarning() << "Preview not set";
37+ }
38+ return QString();
39+}
40+
41+QString ApplicationPreview::copyright() const
42+{
43+ if (m_unityAppPreview) {
44+ return QString::fromStdString(m_unityAppPreview->copyright());
45+ } else {
46+ qWarning() << "Preview not set";
47+ }
48+ return QString();
49+}
50+
51+QString ApplicationPreview::license() const
52+{
53+ if (m_unityAppPreview) {
54+ return QString::fromStdString(m_unityAppPreview->license());
55+ } else {
56+ qWarning() << "Preview not set";
57+ }
58+ return QString();
59+}
60+
61+QString ApplicationPreview::appIcon() const
62+{
63+ if (m_unityAppPreview) {
64+ return QString::fromUtf8(g_icon_to_string(m_unityAppPreview->app_icon()));
65+ } else {
66+ qWarning() << "Preview not set";
67+ }
68+ return QString();
69+}
70+
71+float ApplicationPreview::rating() const
72+{
73+ if (m_unityAppPreview) {
74+ return m_unityAppPreview->rating();
75+ } else {
76+ qWarning() << "Preview not set";
77+ }
78+ return 0.0f;
79+}
80+
81+unsigned int ApplicationPreview::numRatings() const
82+{
83+ if (m_unityAppPreview) {
84+ return m_unityAppPreview->num_ratings();
85+ } else {
86+ qWarning() << "Preview not set";
87+ }
88+ return 0;
89+}
90+
91+void ApplicationPreview::setUnityPreview(unity::dash::Preview::Ptr unityPreview)
92+{
93+ m_unityAppPreview = std::dynamic_pointer_cast<unity::dash::ApplicationPreview>(unityPreview);
94+
95+ Q_EMIT previewChanged();
96+}
plugins/Unity/applicationpreview.hnew file+66
@@ -0,0 +1,66 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef APPLICATIONPREVIEW_H
21+#define APPLICATIONPREVIEW_H
22+
23+// local
24+#include "preview.h"
25+
26+// Qt
27+#include <QObject>
28+#include <QMetaType>
29+
30+// libunity-core
31+#include <UnityCore/ApplicationPreview.h>
32+
33+class Q_DECL_EXPORT ApplicationPreview: public Preview
34+{
35+ Q_OBJECT
36+
37+ Q_PROPERTY(QString lastUpdate READ lastUpdate NOTIFY previewChanged)
38+ Q_PROPERTY(QString copyright READ copyright NOTIFY previewChanged)
39+ Q_PROPERTY(QString license READ license NOTIFY previewChanged)
40+ Q_PROPERTY(QString appIcon READ appIcon NOTIFY previewChanged)
41+ Q_PROPERTY(float rating READ rating NOTIFY previewChanged)
42+ Q_PROPERTY(unsigned int numRatings READ numRatings NOTIFY previewChanged)
43+
44+public:
45+ explicit ApplicationPreview(QObject *parent = 0);
46+
47+ QString lastUpdate() const;
48+ QString copyright() const;
49+ QString license() const;
50+ QString appIcon() const;
51+ float rating() const;
52+ unsigned int numRatings() const;
53+
54+Q_SIGNALS:
55+ void previewChanged();
56+
57+protected:
58+ void setUnityPreview(unity::dash::Preview::Ptr unityPreview) override;
59+
60+private:
61+ unity::dash::ApplicationPreview::Ptr m_unityAppPreview;
62+};
63+
64+Q_DECLARE_METATYPE(ApplicationPreview *)
65+
66+#endif
plugins/Unity/categories.cpp+26−17
@@ -30,6 +30,7 @@ Categories::Categories(QObject* parent)
3030 m_roles[Categories::RoleName] = "name";
3131 m_roles[Categories::RoleIcon] = "icon";
3232 m_roles[Categories::RoleRenderer] = "renderer";
33+ m_roles[Categories::RoleContentType] = "content_type";
3334 m_roles[Categories::RoleHints] = "hints";
3435 m_roles[Categories::RoleResults] = "results";
3536 m_roles[Categories::RoleCount] = "count";
@@ -111,22 +112,30 @@ Categories::data(const QModelIndex& index, int role) const
111112 return QVariant();
112113 }
113114
114− if (role == RoleId) {
115− return QVariant::fromValue(index.row());
116− } else if (role == RoleName) {
117− return QVariant::fromValue(DeeListModel::data(index, 1)); //DISPLAY_NAME
118− } else if (role == RoleIcon) {
119− return QVariant::fromValue(DeeListModel::data(index, 2)); //ICON_HINT
120− } else if (role == RoleRenderer) {
121− return QVariant::fromValue(DeeListModel::data(index, 3)); //RENDERER_NAME
122− } else if (role == RoleHints) {
123− return QVariant::fromValue(DeeListModel::data(index, 4)); //HINTS
124− } else if (role == RoleResults) {
125− return QVariant::fromValue(getFilter(index.row()));
126− } else if (role == RoleCount) {
127− CategoryFilter* filter = getFilter(index.row());
128− return QVariant::fromValue(filter->rowCount());
129− } else {
130− return QVariant();
115+ switch (role) {
116+ case RoleId:
117+ return QVariant::fromValue(index.row());
118+ case RoleName:
119+ return QVariant::fromValue(DeeListModel::data(index, 1)); //DISPLAY_NAME
120+ case RoleIcon:
121+ return QVariant::fromValue(DeeListModel::data(index, 2)); //ICON_HINT
122+ case RoleRenderer:
123+ return QVariant::fromValue(DeeListModel::data(index, 3)); //RENDERER_NAME
124+ case RoleContentType:
125+ {
126+ auto hints = QVariant::fromValue(DeeListModel::data(index, 4)).toHash();
127+ return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
128+ }
129+ case RoleHints:
130+ return QVariant::fromValue(DeeListModel::data(index, 4)); //HINTS
131+ case RoleResults:
132+ return QVariant::fromValue(getFilter(index.row()));
133+ case RoleCount:
134+ {
135+ CategoryFilter* filter = getFilter(index.row());
136+ return QVariant::fromValue(filter->rowCount());
137+ }
138+ default:
139+ return QVariant();
131140 }
132141}
plugins/Unity/categories.h+1
@@ -46,6 +46,7 @@ public:
4646 RoleName,
4747 RoleIcon,
4848 RoleRenderer,
49+ RoleContentType,
4950 RoleHints,
5051 RoleResults,
5152 RoleCount
Notifications/timings.js → plugins/Unity/genericpreview.cpprenamed+9−6
@@ -1,6 +1,9 @@
11/*
22 * Copyright (C) 2013 Canonical, Ltd.
33 *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
47 * This program is free software; you can redistribute it and/or modify
58 * it under the terms of the GNU General Public License as published by
69 * the Free Software Foundation; version 3.
@@ -14,10 +17,10 @@
1417 * along with this program. If not, see <http://www.gnu.org/licenses/>.
1518 */
1619
17−var rhythm = 700;
18−var fastBeat = 0.5 * rhythm;
19−var snapBeat = 0.5 * fastBeat;
20−var slowBeat = rhythm;
21−var sleepyBeat = slowBeat * 2;
20+// local
21+#include "genericpreview.h"
2222
23−var easing = Easing.OutQuint;
23+GenericPreview::GenericPreview(QObject *parent):
24+ Preview(parent)
25+{
26+}
plugins/Unity/genericpreview.hnew file+40
@@ -0,0 +1,40 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef GENERICPREVIEW_H
21+#define GENERICPREVIEW_H
22+
23+// local
24+#include "preview.h"
25+
26+// Qt
27+#include <QObject>
28+#include <QMetaType>
29+
30+class GenericPreview : public Preview
31+{
32+ Q_OBJECT
33+
34+public:
35+ explicit GenericPreview(QObject *parent = 0);
36+};
37+
38+Q_DECLARE_METATYPE(GenericPreview *)
39+
40+#endif
plugins/Unity/moviepreview.cppnew file+67
@@ -0,0 +1,67 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// local
21+#include "moviepreview.h"
22+
23+// Qt
24+#include <QDebug>
25+
26+MoviePreview::MoviePreview(QObject *parent):
27+ Preview(parent),
28+ m_unityMoviePreview(nullptr)
29+{
30+}
31+
32+QString MoviePreview::year() const
33+{
34+ if (m_unityMoviePreview) {
35+ return QString::fromStdString(m_unityMoviePreview->year());
36+ } else {
37+ qWarning() << "Preview not set";
38+ }
39+ return QString();
40+}
41+
42+float MoviePreview::rating() const
43+{
44+ if (m_unityMoviePreview) {
45+ return m_unityMoviePreview->rating();
46+ } else {
47+ qWarning() << "Preview not set";
48+ }
49+ return 0.0f;
50+}
51+
52+unsigned int MoviePreview::numRatings() const
53+{
54+ if (m_unityMoviePreview) {
55+ return m_unityMoviePreview->num_ratings();
56+ } else {
57+ qWarning() << "Preview not set";
58+ }
59+ return 0;
60+}
61+
62+void MoviePreview::setUnityPreview(unity::dash::Preview::Ptr unityPreview)
63+{
64+ m_unityMoviePreview = std::dynamic_pointer_cast<unity::dash::MoviePreview>(unityPreview);
65+
66+ Q_EMIT previewChanged();
67+}
plugins/Unity/moviepreview.hnew file+60
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef MOVIEPREVIEW_H
21+#define MOVIEPREVIEW_H
22+
23+// local
24+#include "preview.h"
25+
26+// Qt
27+#include <QObject>
28+#include <QMetaType>
29+
30+// libunity-core
31+#include <UnityCore/MoviePreview.h>
32+
33+class Q_DECL_EXPORT MoviePreview: public Preview
34+{
35+ Q_OBJECT
36+
37+ Q_PROPERTY(QString year READ year NOTIFY previewChanged)
38+ Q_PROPERTY(float rating READ rating NOTIFY previewChanged)
39+ Q_PROPERTY(unsigned int numRatings READ numRatings NOTIFY previewChanged)
40+
41+public:
42+ explicit MoviePreview(QObject *parent = 0);
43+
44+ QString year() const;
45+ float rating() const;
46+ unsigned int numRatings() const;
47+
48+Q_SIGNALS:
49+ void previewChanged();
50+
51+protected:
52+ void setUnityPreview(unity::dash::Preview::Ptr unityPreview) override;
53+
54+private:
55+ unity::dash::MoviePreview::Ptr m_unityMoviePreview;
56+};
57+
58+Q_DECLARE_METATYPE(MoviePreview *)
59+
60+#endif
plugins/Unity/musicpreview.cppnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#include "musicpreview.h"
21+#include <QDebug>
22+
23+// dee-qt
24+#include "deelistmodel.h"
25+
26+MusicPreview::MusicPreview(QObject *parent):
27+ Preview(parent),
28+ m_unityMusicPreview(nullptr)
29+{
30+ m_tracks = new DeeListModel(this);
31+}
32+
33+void MusicPreview::setUnityPreview(unity::dash::Preview::Ptr unityPreview)
34+{
35+ m_unityMusicPreview = std::dynamic_pointer_cast<unity::dash::MusicPreview>(unityPreview);
36+ m_tracks->setModel(m_unityMusicPreview->GetTracksModel()->model());
37+ m_unityMusicPreview->GetTracksModel()->model.changed.connect(sigc::mem_fun(this, &MusicPreview::onTracksModelChanged));
38+
39+ Q_EMIT previewChanged();
40+ Q_EMIT tracksChanged();
41+}
42+
43+DeeListModel* MusicPreview::tracks() const
44+{
45+ if (m_unityMusicPreview == nullptr) {
46+ qWarning() << "Preview not set";
47+ }
48+ return m_tracks;
49+}
50+
51+void MusicPreview::onTracksModelChanged(unity::glib::Object<DeeModel> /* model */)
52+{
53+ m_tracks->setModel(m_unityMusicPreview->GetTracksModel()->model());
54+}
plugins/Unity/musicpreview.hnew file+62
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef MUSICPREVIEW_H
21+#define MUSICPREVIEW_H
22+
23+// local
24+#include "preview.h"
25+
26+// Qt
27+#include <QObject>
28+#include <QMetaType>
29+
30+// libunity-core
31+#include <UnityCore/MusicPreview.h>
32+
33+class DeeListModel;
34+
35+class Q_DECL_EXPORT MusicPreview: public Preview
36+{
37+ Q_OBJECT
38+
39+ Q_PROPERTY(DeeListModel* tracks READ tracks NOTIFY tracksChanged)
40+
41+public:
42+ explicit MusicPreview(QObject *parent = 0);
43+
44+ DeeListModel* tracks() const;
45+
46+Q_SIGNALS:
47+ void tracksChanged();
48+
49+protected:
50+ void setUnityPreview(unity::dash::Preview::Ptr unityPreview) override;
51+
52+private Q_SLOTS:
53+ void onTracksModelChanged(unity::glib::Object<DeeModel> model);
54+
55+private:
56+ unity::dash::MusicPreview::Ptr m_unityMusicPreview;
57+ DeeListModel *m_tracks;
58+};
59+
60+Q_DECLARE_METATYPE(MusicPreview *)
61+
62+#endif
plugins/Unity/plugin.cpp+6
@@ -24,6 +24,9 @@
2424#include "plugin.h"
2525
2626// local
27+#include "preview.h"
28+#include "previewaction.h"
29+#include "previewinfohint.h"
2730#include "scope.h"
2831#include "scopes.h"
2932#include "categories.h"
@@ -40,6 +43,9 @@ static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommun
4043void UnityPlugin::registerTypes(const char *uri)
4144{
4245 Q_ASSERT(uri == QLatin1String("Unity"));
46+ qmlRegisterUncreatableType<Preview>(uri, 0, 1, "Preview", "Can't create Preview object in QML.");
47+ qmlRegisterUncreatableType<PreviewAction>(uri, 0, 1, "PreviewAction", "Can't create PreviewAction object in QML.");
48+ qmlRegisterUncreatableType<PreviewInfoHint>(uri, 0, 1, "PreviewInfoHint", "Can't create PreviewInfoHint object in QML.");
4349 qmlRegisterType<Scope>(uri, 0, 1, "Scope");
4450 qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
4551 qmlRegisterType<Categories>(uri, 0, 1, "Categories");
plugins/Unity/preview.cppnew file+173
@@ -0,0 +1,173 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// local
21+#include "preview.h"
22+#include "previewaction.h"
23+#include "previewinfohint.h"
24+#include "genericpreview.h"
25+#include "applicationpreview.h"
26+#include "moviepreview.h"
27+#include "musicpreview.h"
28+#include "variantutils.h"
29+
30+// Qt
31+#include <QDebug>
32+#include <QtAlgorithms>
33+
34+#include <UnityCore/GenericPreview.h>
35+#include <UnityCore/ApplicationPreview.h>
36+#include <UnityCore/MoviePreview.h>
37+#include <UnityCore/MusicPreview.h>
38+
39+Preview::Preview(QObject *parent):
40+ QObject(parent),
41+ m_unityPreview(nullptr)
42+{
43+}
44+
45+QString Preview::rendererName() const
46+{
47+ if (m_unityPreview) {
48+ return QString::fromStdString(m_unityPreview->renderer_name());
49+ } else {
50+ qWarning() << "Preview not set";
51+ }
52+ return QString();
53+}
54+
55+QString Preview::title() const
56+{
57+ if (m_unityPreview) {
58+ return QString::fromStdString(m_unityPreview->title());
59+ } else {
60+ qWarning() << "Preview not set";
61+ }
62+ return QString();
63+}
64+
65+QString Preview::subtitle () const
66+{
67+ if (m_unityPreview) {
68+ return QString::fromStdString(m_unityPreview->subtitle());
69+ } else {
70+ qWarning() << "Preview not set";
71+ }
72+ return QString();
73+}
74+
75+QString Preview::description() const
76+{
77+ if (m_unityPreview) {
78+ return QString::fromStdString(m_unityPreview->description());
79+ } else {
80+ qWarning() << "Preview not set";
81+ }
82+ return QString();
83+}
84+
85+QVariant Preview::actions()
86+{
87+ return QVariant::fromValue(m_actions);
88+}
89+
90+QVariant Preview::infoHints()
91+{
92+ return QVariant::fromValue(m_infoHints);
93+}
94+
95+QString Preview::image() const
96+{
97+ if (m_unityPreview) {
98+ return QString::fromUtf8(g_icon_to_string(m_unityPreview->image()));
99+ } else {
100+ qWarning() << "Preview not set";
101+ }
102+ return QString::null;
103+}
104+
105+QString Preview::imageSourceUri() const
106+{
107+ if (m_unityPreview) {
108+ return QString::fromStdString(m_unityPreview->image_source_uri());
109+ } else {
110+ qWarning() << "Preview not set";
111+ }
112+ return QString::null;
113+}
114+
115+Preview* Preview::newFromUnityPreview(unity::dash::Preview::Ptr unityPreview)
116+{
117+ Preview* preview = nullptr;
118+
119+ if (dynamic_cast<unity::dash::GenericPreview *>(unityPreview.get()) != nullptr) {
120+ preview = new GenericPreview();
121+ } else if (dynamic_cast<unity::dash::MusicPreview *>(unityPreview.get()) != nullptr) {
122+ preview = new MusicPreview();
123+ } else if (dynamic_cast<unity::dash::MoviePreview *>(unityPreview.get()) != nullptr) {
124+ preview = new MoviePreview();
125+ } else if (dynamic_cast<unity::dash::ApplicationPreview *>(unityPreview.get()) != nullptr) {
126+ preview = new ApplicationPreview();
127+ } else {
128+ qWarning() << "Unknown preview type: " << typeid(*unityPreview).name();
129+ preview = new GenericPreview();
130+ }
131+
132+ preview->setUnityPreviewBase(unityPreview);
133+ preview->setUnityPreview(unityPreview);
134+
135+ return preview;
136+}
137+
138+void Preview::setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview)
139+{
140+ m_unityPreview = unityPreview;
141+
142+ qDeleteAll(m_infoHints);
143+ m_infoHints.clear();
144+ qDeleteAll(m_actions);
145+ m_actions.clear();
146+
147+ for (auto unityInfoHint: m_unityPreview->GetInfoHints()) {
148+ auto hint = new PreviewInfoHint(this);
149+ hint->setUnityInfoHint(unityInfoHint);
150+ m_infoHints.append(hint);
151+ }
152+
153+ for (auto unityAction: m_unityPreview->GetActions()) {
154+ auto action = new PreviewAction(this);
155+ action->setUnityAction(unityAction);
156+ m_actions.append(action);
157+ }
158+}
159+
160+void Preview::setUnityPreview(unity::dash::Preview::Ptr /* unityPreview */)
161+{
162+ // default implementation does nothing
163+}
164+
165+void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& hints)
166+{
167+ if (m_unityPreview) {
168+ auto unityHints = convertToHintsMap(hints);
169+ m_unityPreview->PerformAction(actionId.toStdString(), unityHints);
170+ } else {
171+ qWarning() << "Preview not set";
172+ }
173+}
plugins/Unity/preview.hnew file+80
@@ -0,0 +1,80 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef PREVIEW_H
21+#define PREVIEW_H
22+
23+// Qt
24+#include <QObject>
25+#include <QString>
26+#include <QMetaType>
27+#include <QList>
28+
29+// libunity-core
30+#include <UnityCore/Preview.h>
31+
32+// local
33+#include "previewaction.h"
34+
35+class Q_DECL_EXPORT Preview : public QObject
36+{
37+ Q_OBJECT
38+
39+ Q_PROPERTY(QString rendererName READ rendererName NOTIFY previewChanged)
40+ Q_PROPERTY(QString title READ title NOTIFY previewChanged)
41+ Q_PROPERTY(QString subtitle READ subtitle NOTIFY previewChanged)
42+ Q_PROPERTY(QString description READ description NOTIFY previewChanged)
43+ Q_PROPERTY(QVariant actions READ actions NOTIFY previewChanged)
44+ Q_PROPERTY(QVariant infoHints READ infoHints NOTIFY previewChanged)
45+ Q_PROPERTY(QString image READ image NOTIFY previewChanged)
46+ Q_PROPERTY(QString imageSourceUri READ imageSourceUri NOTIFY previewChanged)
47+
48+public:
49+ explicit Preview(QObject *parent = 0);
50+ static Preview* newFromUnityPreview(unity::dash::Preview::Ptr unityPreview);
51+
52+ QString rendererName() const;
53+ QString title() const;
54+ QString subtitle() const;
55+ QString description() const;
56+ QVariant actions();
57+ QVariant infoHints();
58+ QString image() const;
59+ QString imageSourceUri() const;
60+
61+ Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
62+
63+Q_SIGNALS:
64+ void previewChanged();
65+
66+protected:
67+ virtual void setUnityPreview(unity::dash::Preview::Ptr unityPreview);
68+
69+ unity::dash::Preview::Ptr m_unityPreview;
70+
71+private:
72+ void setUnityPreviewBase(unity::dash::Preview::Ptr unityPreview);
73+
74+ QList<QObject *> m_actions;
75+ QList<QObject *> m_infoHints;
76+};
77+
78+Q_DECLARE_METATYPE(Preview *)
79+
80+#endif
plugins/Unity/previewaction.cppnew file+75
@@ -0,0 +1,75 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#include "previewaction.h"
21+
22+PreviewAction::PreviewAction(QObject *parent)
23+ : QObject(parent),
24+ m_unityAction(nullptr)
25+{
26+}
27+
28+void PreviewAction::setUnityAction(unity::dash::Preview::ActionPtr unityAction)
29+{
30+ m_unityAction = unityAction;
31+
32+ Q_EMIT previewActionChanged();
33+}
34+
35+QString PreviewAction::id() const
36+{
37+ if (m_unityAction)
38+ return QString::fromStdString(m_unityAction->id);
39+ return QString();
40+}
41+
42+QString PreviewAction::displayName() const
43+{
44+ if (m_unityAction)
45+ return QString::fromStdString(m_unityAction->display_name);
46+ return QString();
47+}
48+
49+QString PreviewAction::iconHint() const
50+{
51+ if (m_unityAction)
52+ return QString::fromStdString(m_unityAction->icon_hint);
53+ return QString();
54+}
55+
56+QString PreviewAction::extraText() const
57+{
58+ if (m_unityAction)
59+ return QString::fromStdString(m_unityAction->extra_text);
60+ return QString();
61+}
62+
63+QString PreviewAction::activationUri() const
64+{
65+ if (m_unityAction)
66+ return QString::fromStdString(m_unityAction->activation_uri);
67+ return QString();
68+}
69+
70+LayoutHint PreviewAction::layoutHint() const
71+{
72+ if (m_unityAction)
73+ return static_cast<LayoutHint>(m_unityAction->layout_hint);
74+ return LayoutHint::None;
75+}
plugins/Unity/previewaction.hnew file+71
@@ -0,0 +1,71 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef PREVIEWACTION_H
21+#define PREVIEWACTION_H
22+
23+// Qt
24+#include <QObject>
25+#include <QList>
26+
27+// libuinity-core
28+#include <UnityCore/Preview.h>
29+
30+enum LayoutHint // keep in sync with unty::dash::LayoutHint
31+{
32+ None,
33+ Left,
34+ Right,
35+ Top,
36+ Bottom
37+};
38+
39+class PreviewAction : public QObject
40+{
41+ Q_OBJECT
42+
43+ Q_PROPERTY(QString id READ id NOTIFY previewActionChanged)
44+ Q_PROPERTY(QString displayName READ displayName NOTIFY previewActionChanged)
45+ Q_PROPERTY(QString iconHint READ iconHint NOTIFY previewActionChanged)
46+ Q_PROPERTY(QString extraText READ extraText NOTIFY previewActionChanged)
47+ Q_PROPERTY(QString activationUri READ activationUri NOTIFY previewActionChanged)
48+ Q_PROPERTY(LayoutHint layoutHint READ layoutHint NOTIFY previewActionChanged)
49+
50+public:
51+ explicit PreviewAction(QObject *parent = 0);
52+ void setUnityAction(unity::dash::Preview::ActionPtr unityAction);
53+
54+ QString id() const;
55+ QString displayName() const;
56+ QString iconHint() const;
57+ QString extraText() const;
58+ QString activationUri() const;
59+ LayoutHint layoutHint() const;
60+
61+Q_SIGNALS:
62+ void previewActionChanged();
63+
64+private:
65+ unity::dash::Preview::ActionPtr m_unityAction;
66+};
67+
68+Q_DECLARE_METATYPE(PreviewAction *)
69+Q_DECLARE_METATYPE(LayoutHint)
70+
71+#endif
plugins/Unity/previewinfohint.cppnew file+67
@@ -0,0 +1,67 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// local
21+#include "previewinfohint.h"
22+#include "variantutils.h"
23+
24+PreviewInfoHint::PreviewInfoHint(QObject *parent):
25+ QObject(parent),
26+ m_unityInfoHint(nullptr)
27+{
28+}
29+
30+void PreviewInfoHint::setUnityInfoHint(unity::dash::Preview::InfoHintPtr unityInfoHint)
31+{
32+ m_unityInfoHint = unityInfoHint;
33+
34+ Q_EMIT previewInfoHintChanged();
35+}
36+
37+QString PreviewInfoHint::id() const
38+{
39+ if (m_unityInfoHint) {
40+ return QString::fromStdString(m_unityInfoHint->id);
41+ }
42+ return QString();
43+}
44+
45+QString PreviewInfoHint::displayName() const
46+{
47+ if (m_unityInfoHint) {
48+ return QString::fromStdString(m_unityInfoHint->display_name);
49+ }
50+ return QString();
51+}
52+
53+QString PreviewInfoHint::iconHint() const
54+{
55+ if (m_unityInfoHint) {
56+ return QString::fromStdString(m_unityInfoHint->icon_hint);
57+ }
58+ return QString();
59+}
60+
61+QVariant PreviewInfoHint::value() const
62+{
63+ if (m_unityInfoHint) {
64+ return QVariantFromGVariant(m_unityInfoHint->value);
65+ }
66+ return QVariant();
67+}
plugins/Unity/previewinfohint.hnew file+58
@@ -0,0 +1,58 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef PREVIEWINFOHINT_H
21+#define PREVIEWINFOHINT_H
22+
23+// Qt
24+#include <QObject>
25+#include <QString>
26+#include <QVariant>
27+
28+// libunity-core
29+#include <UnityCore/Preview.h>
30+
31+class PreviewInfoHint : public QObject
32+{
33+ Q_OBJECT
34+
35+ Q_PROPERTY(QString id READ id NOTIFY previewInfoHintChanged)
36+ Q_PROPERTY(QString displayName READ displayName NOTIFY previewInfoHintChanged)
37+ Q_PROPERTY(QString iconHint READ iconHint NOTIFY previewInfoHintChanged)
38+ Q_PROPERTY(QVariant value READ value NOTIFY previewInfoHintChanged)
39+
40+public:
41+ explicit PreviewInfoHint(QObject *parent = 0);
42+ void setUnityInfoHint(unity::dash::Preview::InfoHintPtr unityInfoHint);
43+
44+ QString id() const;
45+ QString displayName() const;
46+ QString iconHint() const;
47+ QVariant value() const;
48+
49+Q_SIGNALS:
50+ void previewInfoHintChanged();
51+
52+private:
53+ unity::dash::Preview::InfoHintPtr m_unityInfoHint;
54+};
55+
56+Q_DECLARE_METATYPE(PreviewInfoHint *)
57+
58+#endif
plugins/Unity/scope.cpp+79−11
@@ -19,12 +19,19 @@
1919
2020// Self
2121#include "scope.h"
22+
23+// local
2224#include "categories.h"
25+#include "preview.h"
26+#include "variantutils.h"
2327
2428// Qt
2529#include <QUrl>
2630#include <QDebug>
2731#include <QtGui/QDesktopServices>
32+#include <QQmlEngine>
33+
34+#include <UnityCore/Variant.h>
2835
2936#include <libintl.h>
3037
@@ -118,21 +125,80 @@ void Scope::setNoResultsHint(const QString& hint) {
118125 }
119126}
120127
121−void Scope::activate(const QString& /*uri*/)
128+
129+unity::dash::LocalResult Scope::createLocalResult(const QVariant &uri, const QVariant &icon_hint,
130+ const QVariant &category, const QVariant &result_type,
131+ const QVariant &mimetype, const QVariant &title,
132+ const QVariant &comment, const QVariant &dnd_uri,
133+ const QVariant &metadata)
134+{
135+ unity::dash::LocalResult res;
136+ res.uri = uri.toString().toStdString();
137+ res.icon_hint = icon_hint.toString().toStdString();
138+ res.category_index = category.toUInt();
139+ res.result_type = result_type.toUInt();
140+ res.mimetype = mimetype.toString().toStdString();
141+ res.name = title.toString().toStdString();
142+ res.comment = comment.toString().toStdString();
143+ res.dnd_uri = dnd_uri.toString().toStdString();
144+ res.hints = convertToHintsMap(metadata);
145+
146+ return res;
147+}
148+
149+// FIXME: Change to use row index.
150+void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
151+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
152+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
153+{
154+ auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
155+ m_unityScope->Activate(res);
156+}
157+
158+// FIXME: Change to use row index.
159+void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
160+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
161+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
122162{
123− // TODO:
124− // we need to create unity::dash::LocalResult (see UnityCore/Result.h) and pass it to Activate;
125− // this requires entire row from the model, so we need row index rather than uri.
126− // m_unityScope->Activate(QByteArray::fromPercentEncoding(uri.toUtf8()).constData());
163+ auto res = createLocalResult(uri, icon_hint, category, result_type, mimetype, title, comment, dnd_uri, metadata);
164+ m_unityScope->Preview(res);
127165}
128166
129−void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const&)
167+void Scope::onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints)
130168{
131− if (type == unity::dash::NOT_HANDLED) {
132− fallbackActivate(QString::fromStdString(result.uri));
169+ // note: we will not get called on SHOW_PREVIEW, instead UnityCore will signal preview_ready.
170+ switch (type)
171+ {
172+ case unity::dash::NOT_HANDLED:
173+ fallbackActivate(QString::fromStdString(result.uri));
174+ break;
175+ case unity::dash::SHOW_DASH:
176+ Q_EMIT showDash();
177+ break;
178+ case unity::dash::HIDE_DASH:
179+ Q_EMIT hideDash();
180+ break;
181+ case unity::dash::GOTO_DASH_URI:
182+ if (hints.find("goto-uri") != hints.end()) {
183+ Q_EMIT gotoUri(QString::fromStdString(g_variant_get_string(hints.at("goto-uri"), nullptr)));
184+ } else {
185+ qWarning() << "Missing goto-uri hint for GOTO_DASH_URI activation reply";
186+ }
187+ break;
188+ default:
189+ qWarning() << "Unhandled activation response:" << type;
133190 }
134191}
135192
193+void Scope::onPreviewReady(unity::dash::LocalResult const& /* result */, unity::dash::Preview::Ptr const& preview)
194+{
195+ auto prv = Preview::newFromUnityPreview(preview);
196+ // is this the best solution? QML may need to keep more than one preview instance around, so we can't own it.
197+ // passing it by value is not possible.
198+ QQmlEngine::setObjectOwnership(prv, QQmlEngine::JavaScriptOwnership);
199+ Q_EMIT previewReady(prv);
200+}
201+
136202void Scope::fallbackActivate(const QString& uri)
137203{
138204 /* FIXME: stripping all content before the first column because for some
@@ -161,10 +227,10 @@ void Scope::fallbackActivate(const QString& uri)
161227 return;
162228 }
163229
164− qWarning() << "FIXME: Possibly no handler for scheme: " << url.scheme();
165− qWarning() << "Trying to open" << tweakedUri;
230+ qDebug() << "Trying to open" << uri;
231+
166232 /* Try our luck */
167− QDesktopServices::openUrl(url);
233+ QDesktopServices::openUrl(uri); //url?
168234}
169235
170236void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
@@ -204,6 +270,8 @@ void Scope::setUnityScope(const unity::dash::Scope::Ptr& scope)
204270 /* FIXME: signal should be forwarded instead of calling the handler directly */
205271 m_unityScope->activated.connect(sigc::mem_fun(this, &Scope::onActivated));
206272
273+ m_unityScope->preview_ready.connect(sigc::mem_fun(this, &Scope::onPreviewReady));
274+
207275 /* Synchronize local states with m_unityScope right now and whenever
208276 m_unityScope becomes connected */
209277 /* FIXME: should emit change notification signals for all properties */
plugins/Unity/scope.h+20−3
@@ -33,6 +33,7 @@
3333#include "deelistmodel.h"
3434
3535class Categories;
36+class Preview;
3637
3738class Scope : public QObject
3839{
@@ -73,7 +74,12 @@ public:
7374 void setSearchQuery(const QString& search_query);
7475 void setNoResultsHint(const QString& hint);
7576
76− Q_INVOKABLE void activate(const QString& uri);
77+ Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
78+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
79+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
80+ Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
81+ const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
82+ const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
7783 void setUnityScope(const unity::dash::Scope::Ptr& scope);
7884 unity::dash::Scope::Ptr unityScope() const;
7985
@@ -94,6 +100,12 @@ Q_SIGNALS:
94100 void searchQueryChanged();
95101 void noResultsHintChanged();
96102
103+ // signals triggered by activate(..) or preview(..) requests.
104+ void previewReady(Preview *preview);
105+ void showDash();
106+ void hideDash();
107+ void gotoUri(const QString &uri);
108+
97109private Q_SLOTS:
98110 void synchronizeStates();
99111 void onSearchFinished(const std::string &, unity::glib::HintsMap const &);
@@ -105,8 +117,13 @@ private:
105117 void onCategoriesSwarmNameChanged(const std::string&);
106118 void onCategoriesModelChanged(unity::glib::Object<DeeModel>);
107119 void onCategoriesChanged(const unity::dash::Categories::Ptr&);
108−
109− void onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const&);
120+ unity::dash::LocalResult createLocalResult(const QVariant &uri, const QVariant &icon_hint,
121+ const QVariant &category, const QVariant &result_type,
122+ const QVariant &mimetype, const QVariant &title,
123+ const QVariant &comment, const QVariant &dnd_uri,
124+ const QVariant &metadata);
125+ void onActivated(unity::dash::LocalResult const& result, unity::dash::ScopeHandledType type, unity::glib::HintsMap const& hints);
126+ void onPreviewReady(unity::dash::LocalResult const& result, unity::dash::Preview::Ptr const& preview);
110127 void fallbackActivate(const QString& uri);
111128
112129 unity::dash::Scope::Ptr m_unityScope;
plugins/Unity/variantutils.cppnew file+158
@@ -0,0 +1,158 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#include "variantutils.h"
21+
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+
139+unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val)
140+{
141+ unity::glib::HintsMap hintsMap;
142+ QHash<QString, QVariant>::const_iterator it = val.constBegin();
143+ while (it != val.constEnd()) {
144+ hintsMap[it.key().toStdString()] = GVariantFromQVariant(it.value());
145+ ++it;
146+ }
147+ return hintsMap;
148+}
149+
150+unity::glib::HintsMap convertToHintsMap(const QVariant &var)
151+{
152+ if (var.type() == QVariant::Hash) {
153+ unity::glib::HintsMap hintsMap;
154+ const auto hash = var.toHash();
155+ return convertToHintsMap(hash);
156+ }
157+ return unity::glib::HintsMap();
158+}
plugins/Unity/variantutils.hnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Pawel Stolowski <pawel.stolowski@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+#ifndef VARIANTUTILS_H
21+#define VARIANTUTILS_H
22+
23+#include <glib.h>
24+#include <QVariant>
25+
26+// libunity-core
27+#include <UnityCore/Variant.h>
28+
29+GVariant* GVariantFromQVariant(const QVariant &value);
30+QVariant QVariantFromGVariant(GVariant *value);
31+unity::glib::HintsMap convertToHintsMap(const QHash<QString, QVariant> &val);
32+unity::glib::HintsMap convertToHintsMap(const QVariant &var);
33+
34+#endif
plugins/Utils/CMakeLists.txt+2−2
@@ -28,9 +28,9 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
2828 )
2929
3030install(TARGETS Utils-qml
31− DESTINATION ${SHELL_APP_DIR}/plugins/Utils
31+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Utils
3232 )
3333
3434install(FILES qmldir
35− DESTINATION ${SHELL_APP_DIR}/plugins/Utils
35+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/Utils
3636 )
plugins/Utils/qlimitproxymodelqml.cpp+4−4
@@ -39,11 +39,11 @@ QHash<int, QByteArray> QLimitProxyModelQML::roleNames() const
3939void
4040QLimitProxyModelQML::setModel(QAbstractItemModel *itemModel)
4141{
42− if (sourceModel() != NULL) {
43− sourceModel()->disconnect(this);
44− }
45−
4642 if (itemModel != sourceModel()) {
43+ if (sourceModel() != NULL) {
44+ sourceModel()->disconnect(this);
45+ }
46+
4747 setSourceModel(itemModel);
4848
4949 if (sourceModel() != NULL) {
po/ar.po+40−48
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-14 21:09+0000\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-22 16:15+0000\n"
1212"Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n"
1313"Language-Team: Arabic <ar@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "متوفرة للتنزيل"
109109msgid "Apps"
110110msgstr "تطبيقات"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "تطبيقات مألوفة"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "الأشخاص المفضلون"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "أشخاص كانوا على اتصال مؤخرا"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "آخر الصوتيات المشغلة"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "فيديوهات رائجة على الإنترنت"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "الرئيسية"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "موسيقى"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "المفضلات"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "على اتصال موخرا"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "أشخاص جدد"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "A-Z"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "أشخاص"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "الشائع على الإنترنت"
@@ -193,18 +165,18 @@ msgstr "النجوم:"
193165msgid "Author:"
194166msgstr "المؤلف:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "مكالمة طوارئ"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "مرحبا %1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "مرحبًا"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -234,19 +206,39 @@ msgstr "الجهاز"
234206msgid "Flight mode"
235207msgstr "نمط الطيران"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "ابحث"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "عذراً، لا يوجد ما يطابق بحثك."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "الشاشة الرئيسية"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "أشخاص"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "الشاشة الرئيسية"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "الأشخاص المفضلون"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "أشخاص كانوا على اتصال مؤخرا"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "A-Z"
236+
237+#~ msgid "Recently in touch"
238+#~ msgstr "على اتصال موخرا"
239+
240+#~ msgid "New Contacts"
241+#~ msgstr "أشخاص جدد"
242+
243+#~ msgid "Favourites"
244+#~ msgstr "المفضلات"
po/az.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Azerbaijani <az@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Tətbiqlər"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Ev"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Musiqi"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "İnsanlar"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Axtar"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Bağışlayın, amma axtarışınıza heç bir nəticə uyğun gəlmir."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Əsas Ekran"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "İnsanlar"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Əsas Ekran"
po/bg.po+24−44
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-19 15:47+0000\n"
1212"Last-Translator: Miroslav E. Hadzhiev (Хаджиев) "
1313"<miroslav.hadzhiev@gmail.com>\n"
@@ -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-06-20 06:36+0000\n"
19−"X-Generator: Launchpad (build 16673)\n"
18+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
19+"X-Generator: Launchpad (build 16681)\n"
2020
2121#: Applications/applications.js:23
2222msgid "Phone"
@@ -110,27 +110,19 @@ msgstr ""
110110msgid "Apps"
111111msgstr "Приложения"
112112
113−#: Dash/DashHome.qml:43
113+#: Dash/DashHome.qml:40
114114msgid "Frequent Apps"
115115msgstr ""
116116
117−#: Dash/DashHome.qml:46
118−msgid "Favourite People"
119−msgstr ""
120−
121−#: Dash/DashHome.qml:49
122−msgid "People Recently in Touch"
123−msgstr ""
124−
125−#: Dash/DashHome.qml:52
117+#: Dash/DashHome.qml:43
126118msgid "Recent Music"
127119msgstr ""
128120
129−#: Dash/DashHome.qml:55
121+#: Dash/DashHome.qml:46
130122msgid "Videos Popular Online"
131123msgstr ""
132124
133−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
125+#: Dash/DashHome.qml:175
134126msgid "Home"
135127msgstr "Начало"
136128
@@ -154,26 +146,6 @@ msgstr ""
154146msgid "Music"
155147msgstr "Музика"
156148
157−#: Dash/DashPeople.qml:31
158−msgid "Favourites"
159−msgstr "Любими"
160−
161−#: Dash/DashPeople.qml:32
162−msgid "Recently in touch"
163−msgstr ""
164−
165−#: Dash/DashPeople.qml:33
166−msgid "New Contacts"
167−msgstr ""
168−
169−#: Dash/DashPeople.qml:34
170−msgid "A-Z"
171−msgstr "А-Я"
172−
173−#: Dash/DashPeople.qml:123
174−msgid "People"
175−msgstr "Хора"
176−
177149#: Dash/DashVideos.qml:31
178150msgid "Popular Online"
179151msgstr ""
@@ -194,7 +166,7 @@ msgstr ""
194166msgid "Author:"
195167msgstr "Автор:"
196168
197−#: Greeter/Lockscreen.qml:126
169+#: Greeter/Lockscreen.qml:133
198170msgid "Emergency call"
199171msgstr ""
200172
@@ -235,19 +207,27 @@ msgstr "Устройство"
235207msgid "Flight mode"
236208msgstr ""
237209
238−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
210+#: Panel/SearchIndicator.qml:26
239211msgid "Search"
240212msgstr "Търсене"
241213
242−#: plugins/Unity/lens.cpp:333
214+#: plugins/Unity/scope.cpp:268
243215msgid "Sorry, there is nothing that matches your search."
244216msgstr "Съжаляваме, няма нищо, което да отговаря на вашето търсене."
245217
246−#: plugins/Unity/lenses.cpp:39
247−msgid "Home screen"
248−msgstr "Начален екран"
249−
250−#: Shell.qml:380
218+#: Shell.qml:383
251219#, qt-format
252−msgid "Please enter %1:"
220+msgid "Please enter %1"
253221msgstr ""
222+
223+#~ msgid "Favourites"
224+#~ msgstr "Любими"
225+
226+#~ msgid "People"
227+#~ msgstr "Хора"
228+
229+#~ msgid "A-Z"
230+#~ msgstr "А-Я"
231+
232+#~ msgid "Home screen"
233+#~ msgstr "Начален екран"
po/ca.po+24−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Catalan <ca@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Disponibles per baixar"
109109msgid "Apps"
110110msgstr "Aplicacions"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Aplicacions freqüents"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Gent preferida"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Gent amb qui heu parlat"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Música recent"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Vídeos populars en línia"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Inici"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Música"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Gent"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,27 @@ msgstr "Dispositiu"
234206msgid "Flight mode"
235207msgstr "Mode d'avió"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Cerca"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "No hi ha res que coincideixi amb la cerca"
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Pantalla d'inici"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Gent"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Pantalla d'inici"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Gent preferida"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Gent amb qui heu parlat"
po/de.po+42−50
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-15 20:04+0000\n"
12−"Last-Translator: Eduard Gotwig <eduardgotwig@gmail.com>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-29 12:53+0000\n"
12+"Last-Translator: Phillip Sz <Unknown>\n"
1313"Language-Team: German <de@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18+"X-Generator: Launchpad (build 16692)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Zum Herunterladen verfügbar"
109109msgid "Apps"
110110msgstr "Anwendungen"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Häufig genutzte Anwendungen"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Lieblingspersonen"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Zuletzt kontaktierte Personen"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Zuletzt gehörte Musik"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Beliebte Online-Videos"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Start"
135127
@@ -153,26 +145,6 @@ msgstr "Top Tabellenplatz"
153145msgid "Music"
154146msgstr "Musik"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "Favoriten"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "Kürzlich im Gespräch"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "Neue Kontakte"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "A-Z"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Personen"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "Online Beliebt"
@@ -193,18 +165,18 @@ msgstr "Darsteller:"
193165msgid "Author:"
194166msgstr "Autor:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "Notruf"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "Hallo %1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "Hallo"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -234,19 +206,39 @@ msgstr "Gerät"
234206msgid "Flight mode"
235207msgstr "Flugmodus"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Suchen"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Entschuldigung, es wurden keine Treffer erzielt."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Startseite"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
252−msgstr ""
219+msgid "Please enter %1"
220+msgstr "Bitte geben Sie %1 ein"
221+
222+#~ msgid "People"
223+#~ msgstr "Personen"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Startseite"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Lieblingspersonen"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Zuletzt kontaktierte Personen"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "A-Z"
236+
237+#~ msgid "Recently in touch"
238+#~ msgstr "Kürzlich im Gespräch"
239+
240+#~ msgid "New Contacts"
241+#~ msgstr "Neue Kontakte"
242+
243+#~ msgid "Favourites"
244+#~ msgstr "Favoriten"
po/el.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Greek <el@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Εφαρμογές"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Αρχή"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Μουσική"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Πρόσωπα"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Αναζήτηση"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Λυπούμαστε, δεν υπάρχει τίποτα που να ταιριάζει στην αναζήτησή σας."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Αρχική οθόνη"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Πρόσωπα"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Αρχική οθόνη"
po/en_AU.po+36−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-18 20:36+0000\n"
1212"Last-Translator: Jackson Doak <Doak.jackson@gmail.com>\n"
1313"Language-Team: English (Australia) <en_AU@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Available for download"
109109msgid "Apps"
110110msgstr "Apps"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Frequent Apps"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Favourite People"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "People Recently in Touch"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Recent Music"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Videos Popular Online"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Home"
135127
@@ -153,26 +145,6 @@ msgstr "Top Charting"
153145msgid "Music"
154146msgstr "Music"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "Favourites"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "Recently in touch"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "New Contacts"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "A-Z"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "People"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "Popular Online"
@@ -193,7 +165,7 @@ msgstr "Starring:"
193165msgid "Author:"
194166msgstr "Author:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,39 @@ msgstr "Device"
234206msgid "Flight mode"
235207msgstr "Flight mode"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Search"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Sorry, there is nothing that matches your search."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Home screen"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "People"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Home screen"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Favourite People"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "People Recently in Touch"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "A-Z"
236+
237+#~ msgid "Recently in touch"
238+#~ msgstr "Recently in touch"
239+
240+#~ msgid "New Contacts"
241+#~ msgstr "New Contacts"
242+
243+#~ msgid "Favourites"
244+#~ msgstr "Favourites"
po/en_GB.po+41−49
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-14 12:43+0000\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-27 00:22+0000\n"
1212"Last-Translator: Andi Chandler <Unknown>\n"
1313"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Available for download"
109109msgid "Apps"
110110msgstr "Apps"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Frequent Apps"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Favourite People"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "People Recently in Touch"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Recent Music"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Videos Popular Online"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Home"
135127
@@ -153,26 +145,6 @@ msgstr "Top Charting"
153145msgid "Music"
154146msgstr "Music"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "Favourites"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "Recently in touch"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "New Contacts"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "A-Z"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "People"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "Popular Online"
@@ -193,18 +165,18 @@ msgstr "Starring:"
193165msgid "Author:"
194166msgstr "Author:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "Emergency call"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "Hello %1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "Hello"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -234,19 +206,39 @@ msgstr "Device"
234206msgid "Flight mode"
235207msgstr "Flight mode"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Search"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Sorry, there is nothing that matches your search."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Home screen"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
252−msgstr ""
219+msgid "Please enter %1"
220+msgstr "Please enter %1"
221+
222+#~ msgid "Favourite People"
223+#~ msgstr "Favourite People"
224+
225+#~ msgid "People Recently in Touch"
226+#~ msgstr "People Recently in Touch"
227+
228+#~ msgid "People"
229+#~ msgstr "People"
230+
231+#~ msgid "A-Z"
232+#~ msgstr "A-Z"
233+
234+#~ msgid "Recently in touch"
235+#~ msgstr "Recently in touch"
236+
237+#~ msgid "New Contacts"
238+#~ msgstr "New Contacts"
239+
240+#~ msgid "Favourites"
241+#~ msgstr "Favourites"
242+
243+#~ msgid "Home screen"
244+#~ msgstr "Home screen"
po/eo.po+12−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Esperanto <eo@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr ""
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr ""
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr ""
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,15 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr ""
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
po/es.po+36−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-16 23:44+0000\n"
1212"Last-Translator: Adolfo Jayme Barrientos <fitoschido@gmail.com>\n"
1313"Language-Team: Spanish <es@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Disponibles para descargar"
109109msgid "Apps"
110110msgstr "Aplicaciones"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Aplicaciones frecuentes"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Gente favorita"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Gente contactada recientemente"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Música reciente"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Vídeos populares en línea"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Inicio"
135127
@@ -153,26 +145,6 @@ msgstr "Mejor posicionadas"
153145msgid "Music"
154146msgstr "Música"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "Favoritos"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "Contactados recientemente"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "Contactos nuevos"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "A-Z"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Gente"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "Populares en línea"
@@ -193,7 +165,7 @@ msgstr "Protagonistas:"
193165msgid "Author:"
194166msgstr "Autor:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,39 @@ msgstr "Dispositivo"
234206msgid "Flight mode"
235207msgstr "Modo de vuelo"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Buscar"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "No hay nada que coincida con su búsqueda."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Pantalla de inicio"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Gente"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Pantalla de inicio"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Gente favorita"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Gente contactada recientemente"
233+
234+#~ msgid "Recently in touch"
235+#~ msgstr "Contactados recientemente"
236+
237+#~ msgid "Favourites"
238+#~ msgstr "Favoritos"
239+
240+#~ msgid "A-Z"
241+#~ msgstr "A-Z"
242+
243+#~ msgid "New Contacts"
244+#~ msgstr "Contactos nuevos"
po/fi.po+33−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-10 16:19+0000\n"
1212"Last-Translator: Jiri Grönroos <Unknown>\n"
1313"Language-Team: Finnish <fi@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Ladattavissa"
109109msgid "Apps"
110110msgstr "Sovellukset"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Yleisimmät sovellukset"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Suosikkihenkilöt"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Viimeksi yhteydessä olleet henkilöt"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Viimeisin musiikki"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Suositut verkkovideot"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Kotinäyttö"
135127
@@ -153,26 +145,6 @@ msgstr "Nousukiidossa"
153145msgid "Music"
154146msgstr "Musiikki"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "Suosikit"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "Viimeksi yhteydessä"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "Uudet yhteystiedot"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Ihmiset"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "Suosittua verkossa"
@@ -193,7 +165,7 @@ msgstr "Pääosissa:"
193165msgid "Author:"
194166msgstr "Laatinut:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,36 @@ msgstr "Laite"
234206msgid "Flight mode"
235207msgstr "Lentokonetila"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Hae"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Hakuun täsmääviä tuloksia ei löydy."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Kotinäyttö"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Ihmiset"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Kotinäyttö"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Suosikkihenkilöt"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Viimeksi yhteydessä olleet henkilöt"
233+
234+#~ msgid "Favourites"
235+#~ msgstr "Suosikit"
236+
237+#~ msgid "Recently in touch"
238+#~ msgstr "Viimeksi yhteydessä"
239+
240+#~ msgid "New Contacts"
241+#~ msgstr "Uudet yhteystiedot"
po/fo.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Faroese <fo@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Nýtsluskipanir"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Heim"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Tónleikur"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Fólk"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Leita"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Tíanverri er tað einki sum hóskar til tína leiting."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Heimaskíggi"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Fólk"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Heimaskíggi"
po/fr.po+71−82
@@ -7,63 +7,63 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-26 15:11+0000\n"
12+"Last-Translator: Anne <anneonyme017@gmail.com>\n"
1313"Language-Team: French <fr@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
22−msgstr ""
22+msgstr "Téléphone"
2323
2424#: Applications/applications.js:29
2525msgid "Camera"
26−msgstr ""
26+msgstr "Appareil photo"
2727
2828#: Applications/applications.js:35
2929msgid "Gallery"
30−msgstr ""
30+msgstr "Galerie"
3131
3232#: Applications/applications.js:40
3333msgid "Facebook"
34−msgstr ""
34+msgstr "Facebook"
3535
3636#: Applications/applications.js:46
3737msgid "Browser"
38−msgstr ""
38+msgstr "Navigateur"
3939
4040#: Applications/applications.js:51
4141msgid "Twitter"
42−msgstr ""
42+msgstr "Twitter"
4343
4444#: Applications/applications.js:57
4545msgid "GMail"
46−msgstr ""
46+msgstr "GMail"
4747
4848#: Applications/applications.js:62
4949msgid "Weather"
50−msgstr ""
50+msgstr "Météo"
5151
5252#: Applications/applications.js:68
5353msgid "Notepad"
54−msgstr ""
54+msgstr "Bloc-notes"
5555
5656#: Applications/applications.js:74
5757msgid "Calendar"
58−msgstr ""
58+msgstr "Agenda"
5959
6060#: Applications/applications.js:80
6161msgid "Media Player"
62−msgstr ""
62+msgstr "Lecteur multimédia"
6363
6464#: Applications/applications.js:86
6565msgid "Evernote"
66−msgstr ""
66+msgstr "Evernote"
6767
6868#: Applications/applications.js:91
6969msgid "Map"
@@ -71,27 +71,27 @@ msgstr ""
7171
7272#: Applications/applications.js:96
7373msgid "Pinterest"
74−msgstr ""
74+msgstr "Pinterest"
7575
7676#: Applications/applications.js:101
7777msgid "SoundCloud"
78−msgstr ""
78+msgstr "SoundCloud"
7979
8080#: Applications/applications.js:106
8181msgid "Wikipedia"
82−msgstr ""
82+msgstr "Wikipédia"
8383
8484#: Applications/applications.js:111
8585msgid "YouTube"
86−msgstr ""
86+msgstr "YouTube"
8787
8888#: Components/PageHeader.qml:300
8989msgid "Recent searches"
90−msgstr ""
90+msgstr "Recherches récentes"
9191
9292#: Dash/DashApps.qml:65
9393msgid "Running apps"
94−msgstr ""
94+msgstr "Applications en cours d’exécution"
9595
9696#: Dash/DashApps.qml:68
9797msgid "Frequently used"
@@ -99,7 +99,7 @@ msgstr ""
9999
100100#: Dash/DashApps.qml:71
101101msgid "Installed"
102−msgstr ""
102+msgstr "Installées"
103103
104104#: Dash/DashApps.qml:74
105105msgid "Available for download"
@@ -109,29 +109,21 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Applications"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114−msgstr ""
115−
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
114+msgstr "Applications fréquemment utilisées"
119115
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126−msgstr ""
118+msgstr "Musique récente"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130−msgstr ""
122+msgstr "Vidéos populaires en ligne"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134−msgstr ""
126+msgstr "Accueil"
135127
136128#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
137129msgid "Featured"
@@ -143,7 +135,7 @@ msgstr ""
143135
144136#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
145137msgid "New Releases"
146−msgstr ""
138+msgstr "Nouveautés"
147139
148140#: Dash/DashMusic.qml:30
149141msgid "Top Charting"
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Musique"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -183,44 +155,44 @@ msgstr "Vidéos"
183155
184156#: Dash/Video/VideoPreview.qml:98
185157msgid "Directed by:"
186−msgstr ""
158+msgstr "Réalisé par :"
187159
188160#: Dash/Video/VideoPreview.qml:121
189161msgid "Starring:"
190−msgstr ""
162+msgstr "Acteurs :"
191163
192164#: Dash/Video/VideoPreview.qml:144
193165msgid "Author:"
194−msgstr ""
166+msgstr "Auteur :"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "Bonjour %1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "Bonjour"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
211−msgstr ""
183+msgstr "Confirmer"
212184
213185#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
214186msgid "Type or say a command"
215−msgstr ""
187+msgstr "Entrez ou dictez une commande"
216188
217189#: Hud/Hud.qml:84
218190msgid "Loading. Please Wait..."
219−msgstr ""
191+msgstr "Chargement. Veuillez patienter..."
220192
221193#: Hud/Hud.qml:89
222194msgid "Speak Now..."
223−msgstr ""
195+msgstr "Parlez maintenant..."
224196
225197#: Hud/Hud.qml:94
226198msgid "Speaking..."
@@ -232,21 +204,38 @@ msgstr ""
232204
233205#: Panel/Menus/Overview/FlightModeWidget.qml:42
234206msgid "Flight mode"
235−msgstr ""
207+msgstr "Mode avion"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239−msgstr ""
211+msgstr "Rechercher"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243−msgstr ""
244−
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
215+msgstr "Désolé, aucun résultat ne correspond à votre recherche."
248216
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "Home screen"
223+#~ msgstr "Écran d’accueil"
224+
225+#~ msgid "People"
226+#~ msgstr "Contacts"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Contacts favoris"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Contacts récents"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "A-Z"
236+
237+#~ msgid "New Contacts"
238+#~ msgstr "Nouveaux contacts"
239+
240+#~ msgid "Favourites"
241+#~ msgstr "Favoris"
po/gl.po+24−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Galician <gl@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Dispoñíbel para descargar"
109109msgid "Apps"
110110msgstr "Aplicativos"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Aplicativos frecuentes"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Xente favorita"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Xente contactada recentemente"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Música recente"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Vídeos populares en liña"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Cartafol persoal"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Música"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Persoas"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,27 @@ msgstr "Dispositivo"
234206msgid "Flight mode"
235207msgstr "Modo de voo"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Buscar"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Sentímolo, non hai nada que coincida con esta busca."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Pantalla de inicio"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Persoas"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Pantalla de inicio"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Xente favorita"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Xente contactada recentemente"
po/he.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Hebrew <he@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "יישומים"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "בית"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "מוזיקה"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "אנשים"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "חיפוש"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "שום דבר אינו תואם לחיפוש שלך, עמך הסליחה."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "מסך הבית"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "אנשים"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "מסך הבית"
po/hr.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Croatian <hr@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Aplikacije"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Početna"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Glazba"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Osobe"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Pretraživanje"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Nažalost, ne postoji ništa što odgovara vašoj pretrazi."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Početni zaslon"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Osobe"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Početni zaslon"
po/hu.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Hungarian <hu@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Alkalmazások"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Kezdőoldal"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Zene"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Emberek"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr "Eszköz"
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Keresés"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Elnézést, nincs találat a keresésre."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Kezdőképernyő"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Emberek"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Kezdőképernyő"
po/hy.po+24−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-07 12:42+0000\n"
1212"Last-Translator: iAbaS <sosabazyan@yandex.ru>\n"
1313"Language-Team: Armenian <hy@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Հասանելի ծրագրեր"
109109msgid "Apps"
110110msgstr "Ծրագրեր"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Հաճախակի ծրագրերը"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Ֆավորիտներ"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Վերջին մարդիկ"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Վերջին երգերը"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Հայտնի օնլայն վիդեոներ"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Տուն"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Երգեր"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Մարդիկ"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,27 @@ msgstr "Սարք"
234206msgid "Flight mode"
235207msgstr "Անկապ րեժիմ"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Որոնում"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Կներերք, բայց Ձեր հարցումով ոչինչ չկար"
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Տուն"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People Recently in Touch"
223+#~ msgstr "Վերջին մարդիկ"
224+
225+#~ msgid "Favourite People"
226+#~ msgstr "Ֆավորիտներ"
227+
228+#~ msgid "People"
229+#~ msgstr "Մարդիկ"
230+
231+#~ msgid "Home screen"
232+#~ msgstr "Տուն"
po/id.po+12−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Indonesian <id@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr ""
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr ""
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr ""
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,15 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr ""
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
po/it.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Italian <it@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Applicazioni"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Home"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Musica"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Contatti"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Cerca"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Nessun risultato corrispondente alla ricerca."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Home"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Contatti"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Home"
po/ja.po+12−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-15 14:12+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Japanese <ja@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr ""
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr ""
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr ""
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,15 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr ""
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
po/kn.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Kannada <kn@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "ಮನೆ (Home)"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "ಸಂಗೀತ"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "ಜನರು"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "ಹುಡುಕು"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "ಕ್ಷಮಿಸಿ ನಿಮ್ಮ ಶೋಧನೆಗೆ ಸರಿಯಾದ ಹೊಂದಾಣಿಕೆಗಳು ದೊರಕುತ್ತಿಲ್ಲ"
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "ಹೋಮ್ ಸ್ಕ್ರೀನ್"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "ಜನರು"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "ಹೋಮ್ ಸ್ಕ್ರೀನ್"
po/ko.po+12−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Korean <ko@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "내려받을 수 있음"
109109msgid "Apps"
110110msgstr "앱"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "자주 쓰는 앱"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "요즈음 찾는 음악"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr ""
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "음악"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,15 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "찾기"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
po/ky.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Kirghiz <ky@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Тиркемелер"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Үй папкасы"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Музыка"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Адамдар"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Издөө"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Тилекке каршы, сиздин издөөңүзгө эч нерсе дал келген жок."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Башкы экран"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Адамдар"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Башкы экран"
po/lv.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Latvian <lv@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Lietotnes"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Mājas"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Mūzika"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Cilvēki"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Meklēt"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Diemžēl nekas neatbilst jūsu meklētajam."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Mājas ekrāns"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Cilvēki"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Mājas ekrāns"
po/my.po+15−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Burmese <my@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Apps"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "ပင်မ"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "တေးဂီတ"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "လူ"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,18 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "ရှာဖွေ"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "ဆောရီး၊ သင်၏ရှာဖွေမူနှင့်တူညီတာဘာမှမရှိပါ။"
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "လူ"
po/nb.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-17 09:10+0000\n"
1212"Last-Translator: Joakim Langvand <jlangvand@gmail.com>\n"
1313"Language-Team: Norwegian Bokmal <nb@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Tilgjengelig for nedlasting"
109109msgid "Apps"
110110msgstr "Programmer"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Hjem"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Musikk"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Personer"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr "Enhet"
234206msgid "Flight mode"
235207msgstr "Flymodus"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Søk"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Søket ga ingen treff."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Hjemmeskjerm"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Personer"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Hjemmeskjerm"
po/nl.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Dutch <nl@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:15+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Apps"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Hoofdvenster"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Muziek"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Mensen"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Zoeken"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Er is helaas niets dat met uw zoekopdracht overeenkomt."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Startscherm"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Mensen"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Startscherm"
po/pl.po+36−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:43+0000\n"
1212"Last-Translator: Piotr Merski <Unknown>\n"
1313"Language-Team: Polish <pl@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Dostępne do pobrania"
109109msgid "Apps"
110110msgstr "Aplikacje"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Często używane aplikacje"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Ulubione kontakty"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Osoby ostatnio w kontakcie"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Najnowsza muzyka"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Wideo popularne online"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Dom"
135127
@@ -153,26 +145,6 @@ msgstr "Przeboje"
153145msgid "Music"
154146msgstr "Muzyka"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "Ulubione"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "Ostatnio w kontakcie"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "Nowe kontakty"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "A-Z"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Ludzie"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "Popularne w sieci"
@@ -193,7 +165,7 @@ msgstr "Obsada:"
193165msgid "Author:"
194166msgstr "Autor:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,39 @@ msgstr "Urządzenie"
234206msgid "Flight mode"
235207msgstr "Tryb samolotowy"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Szukaj"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Nie znaleziono pasujących wyników."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Ekran domowy"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "Home screen"
223+#~ msgstr "Ekran domowy"
224+
225+#~ msgid "People"
226+#~ msgstr "Ludzie"
227+
228+#~ msgid "People Recently in Touch"
229+#~ msgstr "Osoby ostatnio w kontakcie"
230+
231+#~ msgid "Favourite People"
232+#~ msgstr "Ulubione kontakty"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "A-Z"
236+
237+#~ msgid "Recently in touch"
238+#~ msgstr "Ostatnio w kontakcie"
239+
240+#~ msgid "New Contacts"
241+#~ msgstr "Nowe kontakty"
242+
243+#~ msgid "Favourites"
244+#~ msgstr "Ulubione"
po/pt_BR.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Aplicativos"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Início"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Músicas"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Pessoas"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Pesquisar"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Desculpe, não há nada que corresponda à sua pesquisa."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Tela inicial"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Pessoas"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Tela inicial"
po/ro.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Romanian <ro@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Aplicații"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Acasă"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Muzică"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Persoane"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,20 +206,22 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Căutare"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216"Ne pare rău, nu este nimic care se potrivește căutării dumneavoastră."
245217
246−#: plugins/Unity/lenses.cpp:39
247−msgid "Home screen"
248−msgstr "Ecran principal"
249−
250−#: Shell.qml:380
218+#: Shell.qml:383
251219#, qt-format
252−msgid "Please enter %1:"
220+msgid "Please enter %1"
253221msgstr ""
222+
223+#~ msgid "People"
224+#~ msgstr "Persoane"
225+
226+#~ msgid "Home screen"
227+#~ msgstr "Ecran principal"
po/ru.po+35−52
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-21 10:08+0000\n"
12+"Last-Translator: Andrey Dedikov <iamawesome.ndr@gmail.com>\n"
1313"Language-Team: Russian <ru@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -63,7 +63,7 @@ msgstr ""
6363
6464#: Applications/applications.js:86
6565msgid "Evernote"
66−msgstr ""
66+msgstr "Evernote"
6767
6868#: Applications/applications.js:91
6969msgid "Map"
@@ -71,11 +71,11 @@ msgstr ""
7171
7272#: Applications/applications.js:96
7373msgid "Pinterest"
74−msgstr ""
74+msgstr "Pinterest"
7575
7676#: Applications/applications.js:101
7777msgid "SoundCloud"
78−msgstr ""
78+msgstr "SoundCloud"
7979
8080#: Applications/applications.js:106
8181msgid "Wikipedia"
@@ -109,27 +109,19 @@ msgstr "Доступно для загрузки"
109109msgid "Apps"
110110msgstr "Приложения"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Часто используемые приложения"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Избранные контакты"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Недавние контакты"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Недавно прослушанная музыка"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Популярные видео из сети"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Главная"
135127
@@ -143,7 +135,7 @@ msgstr ""
143135
144136#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
145137msgid "New Releases"
146−msgstr ""
138+msgstr "Новые релизы"
147139
148140#: Dash/DashMusic.qml:30
149141msgid "Top Charting"
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Музыка"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Люди"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -183,17 +155,17 @@ msgstr "Видео"
183155
184156#: Dash/Video/VideoPreview.qml:98
185157msgid "Directed by:"
186−msgstr ""
158+msgstr "Режиссёр"
187159
188160#: Dash/Video/VideoPreview.qml:121
189161msgid "Starring:"
190−msgstr ""
162+msgstr "В главных ролях"
191163
192164#: Dash/Video/VideoPreview.qml:144
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,30 @@ msgstr "Устройство"
234206msgid "Flight mode"
235207msgstr "Режим полета"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Поиск"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Извините, поиск не дал результатов."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Главный экран"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Люди"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Главный экран"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Избранные контакты"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Недавние контакты"
233+
234+#~ msgid "New Contacts"
235+#~ msgstr "Новые контакты"
po/si.po+12−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Sinhalese <si@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr ""
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr ""
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr ""
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,15 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr ""
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
po/sl.po+43−69
@@ -7,83 +7,83 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-09 10:23+0000\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-29 10:26+0000\n"
1212"Last-Translator: Damir Jerovšek <Unknown>\n"
1313"Language-Team: Slovenian <sl@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18+"X-Generator: Launchpad (build 16692)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
22−msgstr ""
22+msgstr "Telefon"
2323
2424#: Applications/applications.js:29
2525msgid "Camera"
26−msgstr ""
26+msgstr "Fotoaparat"
2727
2828#: Applications/applications.js:35
2929msgid "Gallery"
30−msgstr ""
30+msgstr "Galerija"
3131
3232#: Applications/applications.js:40
3333msgid "Facebook"
34−msgstr ""
34+msgstr "Facebook"
3535
3636#: Applications/applications.js:46
3737msgid "Browser"
38−msgstr ""
38+msgstr "Brskalnik"
3939
4040#: Applications/applications.js:51
4141msgid "Twitter"
42−msgstr ""
42+msgstr "Twitter"
4343
4444#: Applications/applications.js:57
4545msgid "GMail"
46−msgstr ""
46+msgstr "GMail"
4747
4848#: Applications/applications.js:62
4949msgid "Weather"
50−msgstr ""
50+msgstr "Vreme"
5151
5252#: Applications/applications.js:68
5353msgid "Notepad"
54−msgstr ""
54+msgstr "Beležnica"
5555
5656#: Applications/applications.js:74
5757msgid "Calendar"
58−msgstr ""
58+msgstr "Koledar"
5959
6060#: Applications/applications.js:80
6161msgid "Media Player"
62−msgstr ""
62+msgstr "Predvajalnik predstavnosti"
6363
6464#: Applications/applications.js:86
6565msgid "Evernote"
66−msgstr ""
66+msgstr "Evernote"
6767
6868#: Applications/applications.js:91
6969msgid "Map"
70−msgstr ""
70+msgstr "Zemljevid"
7171
7272#: Applications/applications.js:96
7373msgid "Pinterest"
74−msgstr ""
74+msgstr "Pinterest"
7575
7676#: Applications/applications.js:101
7777msgid "SoundCloud"
78−msgstr ""
78+msgstr "SoundCloud"
7979
8080#: Applications/applications.js:106
8181msgid "Wikipedia"
82−msgstr ""
82+msgstr "Wikipedija"
8383
8484#: Applications/applications.js:111
8585msgid "YouTube"
86−msgstr ""
86+msgstr "YouTube"
8787
8888#: Components/PageHeader.qml:300
8989msgid "Recent searches"
@@ -109,27 +109,19 @@ msgstr "Na voljo za prejem"
109109msgid "Apps"
110110msgstr "Programi"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Nedavna glasba"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Domov"
135127
@@ -139,11 +131,11 @@ msgstr ""
139131
140132#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
141133msgid "Recent"
142−msgstr ""
134+msgstr "Nedavno"
143135
144136#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
145137msgid "New Releases"
146−msgstr ""
138+msgstr "Nove izdaje"
147139
148140#: Dash/DashMusic.qml:30
149141msgid "Top Charting"
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Glasba"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Ljudje"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -191,20 +163,20 @@ msgstr ""
191163
192164#: Dash/Video/VideoPreview.qml:144
193165msgid "Author:"
194−msgstr ""
166+msgstr "Avtor:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "Klic v sili"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "Pozdravljeni, %1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "Pozdravljeni"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -234,19 +206,21 @@ msgstr "Naprava"
234206msgid "Flight mode"
235207msgstr "Način letenja"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Iskanje"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Nič se ne ujema z vašim iskalnim nizom."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Domači zaslon"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
252−msgstr ""
219+msgid "Please enter %1"
220+msgstr "Vnesite %1"
221+
222+#~ msgid "People"
223+#~ msgstr "Ljudje"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Domači zaslon"
po/sr.po+18−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Serbian <sr@li.org>\n"
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-06-20 06:36+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr "Програми"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Почетна"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "Музика"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Људи"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,21 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Претрага"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Нажалост, претрага није наишла на икакво подударање."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Почетни екран"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Људи"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Почетни екран"
po/sv.po+12−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Swedish <sv@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr ""
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr ""
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr ""
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,15 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr ""
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
po/te.po+12−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Telugu <te@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr ""
109109msgid "Apps"
110110msgstr ""
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr ""
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr ""
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr ""
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr ""
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr ""
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "నివాసం"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "సంగీతం"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr ""
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,15 @@ msgstr ""
234206msgid "Flight mode"
235207msgstr ""
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr ""
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr ""
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr ""
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
po/th.ponew file+220
@@ -0,0 +1,220 @@
1+# Thai translation for unity
2+# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
3+# This file is distributed under the same license as the unity package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-28 15:34+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Thai <th@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18+"X-Generator: Launchpad (build 16692)\n"
19+
20+#: Applications/applications.js:23
21+msgid "Phone"
22+msgstr ""
23+
24+#: Applications/applications.js:29
25+msgid "Camera"
26+msgstr ""
27+
28+#: Applications/applications.js:35
29+msgid "Gallery"
30+msgstr ""
31+
32+#: Applications/applications.js:40
33+msgid "Facebook"
34+msgstr ""
35+
36+#: Applications/applications.js:46
37+msgid "Browser"
38+msgstr ""
39+
40+#: Applications/applications.js:51
41+msgid "Twitter"
42+msgstr ""
43+
44+#: Applications/applications.js:57
45+msgid "GMail"
46+msgstr ""
47+
48+#: Applications/applications.js:62
49+msgid "Weather"
50+msgstr ""
51+
52+#: Applications/applications.js:68
53+msgid "Notepad"
54+msgstr ""
55+
56+#: Applications/applications.js:74
57+msgid "Calendar"
58+msgstr ""
59+
60+#: Applications/applications.js:80
61+msgid "Media Player"
62+msgstr ""
63+
64+#: Applications/applications.js:86
65+msgid "Evernote"
66+msgstr ""
67+
68+#: Applications/applications.js:91
69+msgid "Map"
70+msgstr ""
71+
72+#: Applications/applications.js:96
73+msgid "Pinterest"
74+msgstr ""
75+
76+#: Applications/applications.js:101
77+msgid "SoundCloud"
78+msgstr ""
79+
80+#: Applications/applications.js:106
81+msgid "Wikipedia"
82+msgstr ""
83+
84+#: Applications/applications.js:111
85+msgid "YouTube"
86+msgstr ""
87+
88+#: Components/PageHeader.qml:300
89+msgid "Recent searches"
90+msgstr ""
91+
92+#: Dash/DashApps.qml:65
93+msgid "Running apps"
94+msgstr ""
95+
96+#: Dash/DashApps.qml:68
97+msgid "Frequently used"
98+msgstr ""
99+
100+#: Dash/DashApps.qml:71
101+msgid "Installed"
102+msgstr ""
103+
104+#: Dash/DashApps.qml:74
105+msgid "Available for download"
106+msgstr ""
107+
108+#: Dash/DashApps.qml:178
109+msgid "Apps"
110+msgstr ""
111+
112+#: Dash/DashHome.qml:40
113+msgid "Frequent Apps"
114+msgstr ""
115+
116+#: Dash/DashHome.qml:43
117+msgid "Recent Music"
118+msgstr ""
119+
120+#: Dash/DashHome.qml:46
121+msgid "Videos Popular Online"
122+msgstr ""
123+
124+#: Dash/DashHome.qml:175
125+msgid "Home"
126+msgstr ""
127+
128+#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
129+msgid "Featured"
130+msgstr ""
131+
132+#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
133+msgid "Recent"
134+msgstr ""
135+
136+#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
137+msgid "New Releases"
138+msgstr ""
139+
140+#: Dash/DashMusic.qml:30
141+msgid "Top Charting"
142+msgstr ""
143+
144+#: Dash/DashMusic.qml:99
145+msgid "Music"
146+msgstr ""
147+
148+#: Dash/DashVideos.qml:31
149+msgid "Popular Online"
150+msgstr ""
151+
152+#: Dash/DashVideos.qml:155
153+msgid "Videos"
154+msgstr ""
155+
156+#: Dash/Video/VideoPreview.qml:98
157+msgid "Directed by:"
158+msgstr ""
159+
160+#: Dash/Video/VideoPreview.qml:121
161+msgid "Starring:"
162+msgstr ""
163+
164+#: Dash/Video/VideoPreview.qml:144
165+msgid "Author:"
166+msgstr ""
167+
168+#: Greeter/Lockscreen.qml:133
169+msgid "Emergency call"
170+msgstr ""
171+
172+#: Greeter/PassphraseLockscreen.qml:59
173+#, qt-format
174+msgid "Hello %1"
175+msgstr ""
176+
177+#: Greeter/PassphraseLockscreen.qml:59
178+msgid "Hello"
179+msgstr ""
180+
181+#: Hud/HudParametrizedActionsPage.qml:132
182+msgid "Confirm"
183+msgstr ""
184+
185+#: Hud/Hud.qml:61 Hud/Hud.qml:99 Hud/Hud.qml:372
186+msgid "Type or say a command"
187+msgstr ""
188+
189+#: Hud/Hud.qml:84
190+msgid "Loading. Please Wait..."
191+msgstr ""
192+
193+#: Hud/Hud.qml:89
194+msgid "Speak Now..."
195+msgstr ""
196+
197+#: Hud/Hud.qml:94
198+msgid "Speaking..."
199+msgstr ""
200+
201+#: Panel/MenuContent.qml:192
202+msgid "Device"
203+msgstr ""
204+
205+#: Panel/Menus/Overview/FlightModeWidget.qml:42
206+msgid "Flight mode"
207+msgstr ""
208+
209+#: Panel/SearchIndicator.qml:26
210+msgid "Search"
211+msgstr ""
212+
213+#: plugins/Unity/scope.cpp:268
214+msgid "Sorry, there is nothing that matches your search."
215+msgstr ""
216+
217+#: Shell.qml:383
218+#, qt-format
219+msgid "Please enter %1"
220+msgstr ""
po/tr.po+59−70
@@ -7,59 +7,59 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-05 22:20+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-24 17:24+0000\n"
12+"Last-Translator: Adar Cem EREN <adarcemeren34@gmail.com>\n"
1313"Language-Team: Turkish <tr@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
22−msgstr ""
22+msgstr "Telefon"
2323
2424#: Applications/applications.js:29
2525msgid "Camera"
26−msgstr ""
26+msgstr "Kamera"
2727
2828#: Applications/applications.js:35
2929msgid "Gallery"
30−msgstr ""
30+msgstr "Galeri"
3131
3232#: Applications/applications.js:40
3333msgid "Facebook"
34−msgstr ""
34+msgstr "Facebook"
3535
3636#: Applications/applications.js:46
3737msgid "Browser"
38−msgstr ""
38+msgstr "Tarayıcı"
3939
4040#: Applications/applications.js:51
4141msgid "Twitter"
42−msgstr ""
42+msgstr "Twitter"
4343
4444#: Applications/applications.js:57
4545msgid "GMail"
46−msgstr ""
46+msgstr "GMail"
4747
4848#: Applications/applications.js:62
4949msgid "Weather"
50−msgstr ""
50+msgstr "Hava Durumu"
5151
5252#: Applications/applications.js:68
5353msgid "Notepad"
54−msgstr ""
54+msgstr "Not Defteri"
5555
5656#: Applications/applications.js:74
5757msgid "Calendar"
58−msgstr ""
58+msgstr "Takvim"
5959
6060#: Applications/applications.js:80
6161msgid "Media Player"
62−msgstr ""
62+msgstr "Ortam Oynatıcı"
6363
6464#: Applications/applications.js:86
6565msgid "Evernote"
@@ -67,7 +67,7 @@ msgstr ""
6767
6868#: Applications/applications.js:91
6969msgid "Map"
70−msgstr ""
70+msgstr "Harita"
7171
7272#: Applications/applications.js:96
7373msgid "Pinterest"
@@ -79,15 +79,15 @@ msgstr ""
7979
8080#: Applications/applications.js:106
8181msgid "Wikipedia"
82−msgstr ""
82+msgstr "Vikipedi"
8383
8484#: Applications/applications.js:111
8585msgid "YouTube"
86−msgstr ""
86+msgstr "YouTube"
8787
8888#: Components/PageHeader.qml:300
8989msgid "Recent searches"
90−msgstr "Son aramalar"
90+msgstr "Son Arananlar"
9191
9292#: Dash/DashApps.qml:65
9393msgid "Running apps"
@@ -109,37 +109,29 @@ msgstr "İndirilebilir durumda"
109109msgid "Apps"
110110msgstr "Uygulamalar"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Sıkça Kullanılan Uygulamalar"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Favori Kişiler"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "En Son Konuşulan Kişiler"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "En Son Müzik"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Çevrimiçi Yaygın Videolar"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134−msgstr "Ev"
126+msgstr "Ana Sayfa"
135127
136128#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
137129msgid "Featured"
138−msgstr ""
130+msgstr "Öne Çıkanlar"
139131
140132#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
141133msgid "Recent"
142−msgstr ""
134+msgstr "En Son"
143135
144136#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
145137msgid "New Releases"
@@ -153,29 +145,9 @@ msgstr ""
153145msgid "Music"
154146msgstr "Müzik"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Kişiler"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178−msgstr ""
150+msgstr "Genellikle Çevrimiçi"
179151
180152#: Dash/DashVideos.qml:155
181153msgid "Videos"
@@ -183,7 +155,7 @@ msgstr "Videolar"
183155
184156#: Dash/Video/VideoPreview.qml:98
185157msgid "Directed by:"
186−msgstr ""
158+msgstr "Yönetmen"
187159
188160#: Dash/Video/VideoPreview.qml:121
189161msgid "Starring:"
@@ -191,11 +163,11 @@ msgstr ""
191163
192164#: Dash/Video/VideoPreview.qml:144
193165msgid "Author:"
194−msgstr ""
166+msgstr "Yazar:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "Acil Arama"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
@@ -204,7 +176,7 @@ msgstr ""
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "Merhaba"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -232,21 +204,38 @@ msgstr "Aygıt"
232204
233205#: Panel/Menus/Overview/FlightModeWidget.qml:42
234206msgid "Flight mode"
235−msgstr "Uçak kipi"
207+msgstr "Uçak Modu"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Ara"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Üzgünüz, aramanızla eşleşen hiçbir şey yok."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Başlangıç ekranı"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "Kişiler"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Başlangıç ekranı"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Favori Kişiler"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "En Son Konuşulan Kişiler"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "A-Z"
236+
237+#~ msgid "New Contacts"
238+#~ msgstr "Yeni Kişiler"
239+
240+#~ msgid "Favourites"
241+#~ msgstr "Favoriler"
po/ug.po+59−70
@@ -7,23 +7,23 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-06 07:40+0000\n"
12−"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-28 04:36+0000\n"
12+"Last-Translator: Gheyret T.Kenji <Unknown>\n"
1313"Language-Team: Uyghur <ug@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18+"X-Generator: Launchpad (build 16692)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
22−msgstr ""
22+msgstr "تېلېفون"
2323
2424#: Applications/applications.js:29
2525msgid "Camera"
26−msgstr ""
26+msgstr "كامېرا"
2727
2828#: Applications/applications.js:35
2929msgid "Gallery"
@@ -31,59 +31,59 @@ msgstr ""
3131
3232#: Applications/applications.js:40
3333msgid "Facebook"
34−msgstr ""
34+msgstr "فېيىسبۇك(Facebook)"
3535
3636#: Applications/applications.js:46
3737msgid "Browser"
38−msgstr ""
38+msgstr "توركۆرگۈ"
3939
4040#: Applications/applications.js:51
4141msgid "Twitter"
42−msgstr ""
42+msgstr "تىۋىتتېر(Twitter)"
4343
4444#: Applications/applications.js:57
4545msgid "GMail"
46−msgstr ""
46+msgstr "GMail"
4747
4848#: Applications/applications.js:62
4949msgid "Weather"
50−msgstr ""
50+msgstr "ھاۋا رايى"
5151
5252#: Applications/applications.js:68
5353msgid "Notepad"
54−msgstr ""
54+msgstr "خاتىرە دەپتەر(Notepad)"
5555
5656#: Applications/applications.js:74
5757msgid "Calendar"
58−msgstr ""
58+msgstr "يىلنامە"
5959
6060#: Applications/applications.js:80
6161msgid "Media Player"
62−msgstr ""
62+msgstr "ۋاسىتە قويغۇ"
6363
6464#: Applications/applications.js:86
6565msgid "Evernote"
66−msgstr ""
66+msgstr "Evernote"
6767
6868#: Applications/applications.js:91
6969msgid "Map"
70−msgstr ""
70+msgstr "خەرىتە"
7171
7272#: Applications/applications.js:96
7373msgid "Pinterest"
74−msgstr ""
74+msgstr "Pinterest"
7575
7676#: Applications/applications.js:101
7777msgid "SoundCloud"
78−msgstr ""
78+msgstr "SoundCloud"
7979
8080#: Applications/applications.js:106
8181msgid "Wikipedia"
82−msgstr ""
82+msgstr "ۋىكىپېدىيە"
8383
8484#: Applications/applications.js:111
8585msgid "YouTube"
86−msgstr ""
86+msgstr "YouTube"
8787
8888#: Components/PageHeader.qml:300
8989msgid "Recent searches"
@@ -109,41 +109,33 @@ msgstr "چۈشۈرگىلى بولىدىغانلىرى"
109109msgid "Apps"
110110msgstr "ئەپلەر"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "دائىم ئىشلىتىلىدىغان ئەپلەر"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "ھەمىشە ئالاقە قىلىدىغان كىشىلەر"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "يېقىندا ئالاقە قىلغان كىشىلەر"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "يېقىندا ئاڭلىغان مۇزىكىلار"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "توردىكى ئالقىشقا ئېرىشكەن سىنلار"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "ماكان"
135127
136128#: Dash/DashMusic.qml:27 Dash/DashVideos.qml:28
137129msgid "Featured"
138−msgstr ""
130+msgstr "داڭلىق"
139131
140132#: Dash/DashMusic.qml:28 Dash/DashVideos.qml:29
141133msgid "Recent"
142−msgstr ""
134+msgstr "يېقىنقى"
143135
144136#: Dash/DashMusic.qml:29 Dash/DashVideos.qml:30
145137msgid "New Releases"
146−msgstr ""
138+msgstr "يېڭى ئېلان قىلىنغانلىرى"
147139
148140#: Dash/DashMusic.qml:30
149141msgid "Top Charting"
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "مۇزىكا"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "كىشىلەر"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -191,20 +163,20 @@ msgstr ""
191163
192164#: Dash/Video/VideoPreview.qml:144
193165msgid "Author:"
194−msgstr ""
166+msgstr "ئاپتور:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "جىددىي تېلېفون"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "سالام %1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "سالام"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -234,19 +206,36 @@ msgstr "ئۈسكۈنە"
234206msgid "Flight mode"
235207msgstr "ئايروپىلاندا"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "ئىزدە"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "كەچۈرۈڭ، ئىزدىگىنىڭىزگە ماس نەتىجە تېپىلمىدى."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "ماكان ئېكران"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
252−msgstr ""
219+msgid "Please enter %1"
220+msgstr "%1 نى كىرگۈزۈڭ"
221+
222+#~ msgid "Favourite People"
223+#~ msgstr "ھەمىشە ئالاقە قىلىدىغان كىشىلەر"
224+
225+#~ msgid "People Recently in Touch"
226+#~ msgstr "يېقىندا ئالاقە قىلغان كىشىلەر"
227+
228+#~ msgid "People"
229+#~ msgstr "كىشىلەر"
230+
231+#~ msgid "Home screen"
232+#~ msgstr "ماكان ئېكران"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "A-Z"
236+
237+#~ msgid "Recently in touch"
238+#~ msgstr "يېقىندا ئالاقە قىلغانلار"
239+
240+#~ msgid "New Contacts"
241+#~ msgstr "يېڭى ئالاقەداشلار"
po/uk.po+42−50
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-14 11:26+0000\n"
12−"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-29 14:27+0000\n"
12+"Last-Translator: Roman Koshkin <mar2008m@rambler.ru>\n"
1313"Language-Team: Ukrainian <uk@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-30 07:12+0000\n"
18+"X-Generator: Launchpad (build 16692)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "Доступно до завантаження"
109109msgid "Apps"
110110msgstr "Програми"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "Часто використовувані програми"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "Вибрані контакти"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "Недавні контакти"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "Нещодавно прослухана музика"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "Популярні в мережі відео"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "Домівка"
135127
@@ -153,26 +145,6 @@ msgstr "З високими оцінками"
153145msgid "Music"
154146msgstr "Музика"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "Улюблене"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "Нещодавні контакти"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "Нові контакти"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "А-Я"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "Люди"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "Популярне у мережі"
@@ -193,18 +165,18 @@ msgstr "Актори:"
193165msgid "Author:"
194166msgstr "Автор:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "Екстрений виклик"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "Привіт, %1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "Привіт!"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -234,19 +206,39 @@ msgstr "Пристрій"
234206msgid "Flight mode"
235207msgstr "Автономний режим"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "Пошук"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "Вибачте, для вказаних вами ключових слів нічого не знайдено."
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "Екран домівки"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
252−msgstr ""
219+msgid "Please enter %1"
220+msgstr "Будь ласка, введіть %1"
221+
222+#~ msgid "People"
223+#~ msgstr "Люди"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "Екран домівки"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "Вибрані контакти"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "Недавні контакти"
233+
234+#~ msgid "A-Z"
235+#~ msgstr "А-Я"
236+
237+#~ msgid "New Contacts"
238+#~ msgstr "Нові контакти"
239+
240+#~ msgid "Favourites"
241+#~ msgstr "Улюблене"
242+
243+#~ msgid "Recently in touch"
244+#~ msgstr "Нещодавні контакти"
po/unity8.pot+4−9
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -165,7 +165,7 @@ msgstr ""
165165msgid "Author:"
166166msgstr ""
167167
168−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
169169msgid "Emergency call"
170170msgstr ""
171171
@@ -214,12 +214,7 @@ msgstr ""
214214msgid "Sorry, there is nothing that matches your search."
215215msgstr ""
216216
217−#: Shell.qml:380
217+#: Shell.qml:383
218218#, qt-format
219−msgid "Please enter %1:"
220−msgstr ""
221−
222−#: Shell.qml:380
223−#, qt-format
224−msgid "Please enter %1:"
219+msgid "Please enter %1"
225220msgstr ""
po/zh_CN.po+41−49
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
11−"PO-Revision-Date: 2013-06-13 11:35+0000\n"
12−"Last-Translator: Wylmer Wang <Unknown>\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
11+"PO-Revision-Date: 2013-06-22 21:20+0000\n"
12+"Last-Translator: Anthony Wong <anthony.wong@canonical.com>\n"
1313"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "可供下载"
109109msgid "Apps"
110110msgstr "应用程序"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "常用软件"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "常用联系人"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "近期联系人"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "近期听过的音乐"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "热门在线视频"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "主页"
135127
@@ -153,26 +145,6 @@ msgstr "排行榜图"
153145msgid "Music"
154146msgstr "音乐"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr "最爱"
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr "最近联系"
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr "新建联系人"
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr "A-Z"
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "联系人"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr "经常在线"
@@ -193,18 +165,18 @@ msgstr "主演:"
193165msgid "Author:"
194166msgstr "作者:"
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198−msgstr ""
170+msgstr "紧急呼救"
199171
200172#: Greeter/PassphraseLockscreen.qml:59
201173#, qt-format
202174msgid "Hello %1"
203−msgstr ""
175+msgstr "你好,%1"
204176
205177#: Greeter/PassphraseLockscreen.qml:59
206178msgid "Hello"
207−msgstr ""
179+msgstr "你好"
208180
209181#: Hud/HudParametrizedActionsPage.qml:132
210182msgid "Confirm"
@@ -234,19 +206,39 @@ msgstr "设备"
234206msgid "Flight mode"
235207msgstr "飞行模式"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "搜索"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "对不起,没有找到您想要的结果。"
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "主页"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "Home screen"
223+#~ msgstr "主页"
224+
225+#~ msgid "Favourite People"
226+#~ msgstr "常用联系人"
227+
228+#~ msgid "People Recently in Touch"
229+#~ msgstr "近期联系人"
230+
231+#~ msgid "People"
232+#~ msgstr "联系人"
233+
234+#~ msgid "Recently in touch"
235+#~ msgstr "最近联系"
236+
237+#~ msgid "New Contacts"
238+#~ msgstr "新建联系人"
239+
240+#~ msgid "Favourites"
241+#~ msgstr "最爱"
242+
243+#~ msgid "A-Z"
244+#~ msgstr "A-Z"
po/zh_TW.po+24−44
@@ -7,15 +7,15 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2013-06-19 17:06+0200\n"
10+"POT-Creation-Date: 2013-06-26 22:58+0200\n"
1111"PO-Revision-Date: 2013-06-05 22:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
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-06-20 06:37+0000\n"
18−"X-Generator: Launchpad (build 16673)\n"
17+"X-Launchpad-Export-Date: 2013-06-27 16:16+0000\n"
18+"X-Generator: Launchpad (build 16681)\n"
1919
2020#: Applications/applications.js:23
2121msgid "Phone"
@@ -109,27 +109,19 @@ msgstr "可供下載"
109109msgid "Apps"
110110msgstr "程式"
111111
112−#: Dash/DashHome.qml:43
112+#: Dash/DashHome.qml:40
113113msgid "Frequent Apps"
114114msgstr "常用的程式"
115115
116−#: Dash/DashHome.qml:46
117−msgid "Favourite People"
118−msgstr "喜歡的朋友"
119−
120−#: Dash/DashHome.qml:49
121−msgid "People Recently in Touch"
122−msgstr "最近接觸的朋友"
123−
124−#: Dash/DashHome.qml:52
116+#: Dash/DashHome.qml:43
125117msgid "Recent Music"
126118msgstr "最近聽過的音樂"
127119
128−#: Dash/DashHome.qml:55
120+#: Dash/DashHome.qml:46
129121msgid "Videos Popular Online"
130122msgstr "線上熱門的影片"
131123
132−#: Dash/DashHome.qml:197 plugins/Unity/lenses.cpp:38
124+#: Dash/DashHome.qml:175
133125msgid "Home"
134126msgstr "家屋"
135127
@@ -153,26 +145,6 @@ msgstr ""
153145msgid "Music"
154146msgstr "音樂"
155147
156−#: Dash/DashPeople.qml:31
157−msgid "Favourites"
158−msgstr ""
159−
160−#: Dash/DashPeople.qml:32
161−msgid "Recently in touch"
162−msgstr ""
163−
164−#: Dash/DashPeople.qml:33
165−msgid "New Contacts"
166−msgstr ""
167−
168−#: Dash/DashPeople.qml:34
169−msgid "A-Z"
170−msgstr ""
171−
172−#: Dash/DashPeople.qml:123
173−msgid "People"
174−msgstr "朋友"
175−
176148#: Dash/DashVideos.qml:31
177149msgid "Popular Online"
178150msgstr ""
@@ -193,7 +165,7 @@ msgstr ""
193165msgid "Author:"
194166msgstr ""
195167
196−#: Greeter/Lockscreen.qml:126
168+#: Greeter/Lockscreen.qml:133
197169msgid "Emergency call"
198170msgstr ""
199171
@@ -234,19 +206,27 @@ msgstr "裝置"
234206msgid "Flight mode"
235207msgstr "飛航模式"
236208
237−#: Panel/SearchIndicator.qml:26 plugins/Unity/lenses.cpp:40
209+#: Panel/SearchIndicator.qml:26
238210msgid "Search"
239211msgstr "搜尋"
240212
241−#: plugins/Unity/lens.cpp:333
213+#: plugins/Unity/scope.cpp:268
242214msgid "Sorry, there is nothing that matches your search."
243215msgstr "很抱歉,找不到符合您想搜尋的結果。"
244216
245−#: plugins/Unity/lenses.cpp:39
246−msgid "Home screen"
247−msgstr "家屋畫面"
248−
249−#: Shell.qml:380
217+#: Shell.qml:383
250218#, qt-format
251−msgid "Please enter %1:"
219+msgid "Please enter %1"
252220msgstr ""
221+
222+#~ msgid "People"
223+#~ msgstr "朋友"
224+
225+#~ msgid "Home screen"
226+#~ msgstr "家屋畫面"
227+
228+#~ msgid "Favourite People"
229+#~ msgstr "喜歡的朋友"
230+
231+#~ msgid "People Recently in Touch"
232+#~ msgstr "最近接觸的朋友"
run+3−4
@@ -1,7 +1,6 @@
11#!/bin/sh
22
33QML_PHONE_SHELL_PATH=./builddir/unity8
4−export LD_LIBRARY_PATH=$PWD/../unity_build/build/lib
54GDB=false
65FAKE=false
76PINLOCK=false
@@ -42,17 +41,17 @@ done
4241
4342if $FAKE; then
4443 export QML2_IMPORT_PATH=$PWD/builddir/tests/mocks:$PWD/builddir/plugins
45− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/LightDM/single
44+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single
4645fi
4746
4847if $PINLOCK; then
4948 export QML2_IMPORT_PATH=$PWD/builddir/tests/mocks:$PWD/builddir/plugins
50− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/LightDM/single-pin
49+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-pin
5150fi
5251
5352if $KEYLOCK; then
5453 export QML2_IMPORT_PATH=$PWD/builddir/tests/mocks:$PWD/builddir/plugins
55− export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/LightDM/single-passphrase
54+ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/builddir/tests/mocks/libusermetrics:$PWD/builddir/tests/mocks/LightDM/single-passphrase
5655fi
5756
5857# Force icon theme if running on the desktop, otherwise gnome theme (if running
run_on_device+26−9
@@ -15,6 +15,8 @@ PINLOCK=false
1515KEYLOCK=false
1616SUDO="echo $PASSWORD | sudo -S"
1717NUM_JOBS='$(( `grep -c ^processor /proc/cpuinfo` + 1 ))'
18+FLIPPED=false
19+CHROOT_PREFIX="/data/ubuntu"
1820
1921usage() {
2022 echo "usage: run_on_device [OPTIONS]\n"
@@ -35,7 +37,11 @@ exec_with_ssh() {
3537}
3638
3739exec_with_adb() {
38− adb shell chroot /data/ubuntu /usr/bin/env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin "$@"
40+ if $FLIPPED; then
41+ adb shell $@
42+ else
43+ adb shell chroot /data/ubuntu /usr/bin/env -i PATH=/bin:/usr/bin:/sbin:/usr/sbin:/tools/bin "$@"
44+ fi
3945}
4046
4147adb_root() {
@@ -45,7 +51,7 @@ adb_root() {
4551
4652install_ssh_key() {
4753 ssh-keygen -R $TARGET_IP
48− HOME_DIR=/data/ubuntu/home/phablet
54+ HOME_DIR="${CHROOT_PREFIX}/home/phablet"
4955 adb push ~/.ssh/id_rsa.pub $HOME_DIR/.ssh/authorized_keys
5056 adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh
5157 adb shell chown $USER_ID:$USER_ID $HOME_DIR/.ssh/authorized_keys
@@ -69,7 +75,7 @@ install_dependencies() {
6975sync_code() {
7076 [ -e .bzr ] && bzr export --uncommitted --format=dir /tmp/$CODE_DIR
7177 [ -e .git ] && git checkout-index -a -f --prefix=/tmp/$CODE_DIR/
72− rsync -crlOzv -e "ssh -p $TARGET_SSH_PORT -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" /tmp/$CODE_DIR/ $USER@$TARGET_IP:$CODE_DIR/
78+ rsync -crlOzv --delete --exclude builddir -e "ssh -p $TARGET_SSH_PORT -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" /tmp/$CODE_DIR/ $USER@$TARGET_IP:$CODE_DIR/
7379 rm -rf /tmp/$CODE_DIR
7480}
7581
@@ -79,16 +85,16 @@ build() {
7985}
8086
8187run() {
82− SERVICEFILE="/data/ubuntu/etc/device-services"
83− adb shell "egrep '$BINARY|qml-phone-shell' $SERVICEFILE"
88+ SERVICEFILE="${CHROOT_PREFIX}/etc/device-services"
89+ adb shell "egrep '$BINARY' $SERVICEFILE"
8490 CONTAINS_SHELL=$?
8591 if [ $CONTAINS_SHELL -eq 0 ]; then
8692 echo "Modifying $SERVICEFILE on device. Old contents will be saved in $SERVICEFILE.backup"
8793 adb shell cp $SERVICEFILE $SERVICEFILE.backup
88− adb shell sed -i "/$BINARY\\\\\|qml-phone-shell/d" $SERVICEFILE
89− adb shell "chroot /data/ubuntu /usr/bin/service ubuntu-session restart"
94+ adb shell sed -i "/$BINARY/d" $SERVICEFILE
95+ if $FLIPPED; then exec_with_adb /usr/bin/service ubuntu-touch-session restart
96+ else exec_with_adb /usr/bin/service ubuntu-session restart; fi
9097 fi
91− adb shell pkill qml-phone-shell
9298 adb shell pkill $BINARY
9399 ARGS="--nomousetouch"
94100 if $GDB; then
@@ -106,7 +112,8 @@ run() {
106112 if [ $CONTAINS_SHELL -eq 0 ]; then
107113 echo "Restoring $SERVICEFILE on device from $SERVICEFILE.backup"
108114 adb shell cp $SERVICEFILE.backup $SERVICEFILE
109− adb shell "chroot /data/ubuntu /usr/bin/service ubuntu-session restart"
115+ if $FLIPPED; then exec_with_adb /usr/bin/service ubuntu-touch-session restart
116+ else exec_with_adb /usr/bin/service ubuntu-session restart; fi
110117 fi
111118}
112119
@@ -130,6 +137,16 @@ done
130137adb_root
131138[ "${TARGET_IP}" = "127.0.0.1" ] && setup_adb_forwarding
132139
140+if [ "`adb shell 'grep -q Ubuntu /etc/lsb-release 2> /dev/null && echo -n FLIPPED'`" = "FLIPPED" ]; then
141+ FLIPPED=true
142+ CHROOT_PREFIX=""
143+ if [ "${TARGET_IP}" != "127.0.0.1" ]; then
144+ echo "ERROR: Flipped image detected, adb over TCP/IP isn't supported, yet :/"
145+ echo "Unset TARGET_IP and try again."
146+ exit 2
147+ fi
148+fi
149+
133150if $SETUP; then
134151 echo "Setting up environment for building shell.."
135152 install_ssh_key
tests/autopilot/setup.pynew file+21
@@ -0,0 +1,21 @@
1+#!/usr/bin/python
2+
3+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
4+# Copyright 2013 Canonical
5+#
6+# This program is free software: you can redistribute it and/or modify it
7+# under the terms of the GNU General Public License version 3, as published
8+# by the Free Software Foundation.
9+
10+
11+from distutils.core import setup
12+from setuptools import find_packages
13+
14+setup(
15+ name='unity',
16+ version='8.0',
17+ description='Unity 8 autopilot tests.',
18+ url='https://launchpad.net/unity',
19+ license='GPLv3',
20+ packages=find_packages(),
21+)
tests/autopilot/unity8/tests/__init__.py+6−4
@@ -8,6 +8,7 @@
88"""unity8 autopilot tests."""
99
1010import os.path
11+import sysconfig
1112
1213from autopilot.testcase import AutopilotTestCase
1314from autopilot.matchers import Eventually
@@ -23,6 +24,7 @@ class ShellTestCase(AutopilotTestCase):
2324
2425 """A common test case class that provides several useful methods for shell tests."""
2526
27+ libdir = "/usr/lib/{0}/unity8".format(sysconfig.get_config_var('MULTIARCH'))
2628 lightdm_mock = "full"
2729
2830 def setUp(self, geometry, grid_size):
@@ -39,8 +41,8 @@ class ShellTestCase(AutopilotTestCase):
3941 self.launch_test_local(geometry)
4042
4143 def launch_test_local(self, geometry):
42− os.environ['LD_LIBRARY_PATH'] = "../../../unity_build/build/lib:../../builddir/tests/mocks/LightDM/" + self.lightdm_mock
43− os.environ['QML2_IMPORT_PATH'] = "../../builddir/tests/mocks:../../builddir/plugins"
44+ os.environ['LD_LIBRARY_PATH'] = "../../builddir/tests/mocks/libusermetrics:../../builddir/tests/mocks/LightDM" + self.lightdm_mock
45+ os.environ['QML2_IMPORT_PATH'] = "../../builddir/tests/mocks"
4446 if geometry != "0x0":
4547 self.app = self.launch_test_application(
4648 "../../builddir/unity8", "-geometry", geometry, "-frameless", app_type='qt')
@@ -49,8 +51,8 @@ class ShellTestCase(AutopilotTestCase):
4951 "../../builddir/unity8", "-fullscreen", app_type='qt')
5052
5153 def launch_test_installed(self, geometry):
52− os.environ['LD_LIBRARY_PATH'] = "/usr/share/unity8/plugins/mocks/LightDM/" + self.lightdm_mock
53− os.environ['QML2_IMPORT_PATH'] = "/usr/share/unity8/plugins/mocks:/usr/share/unity8/plugins"
54+ os.environ['LD_LIBRARY_PATH'] = "{0}/qml/mocks/libusermetrics:{0}/qml/mocks/LightDM/{1}".format(self.libdir, self.lightdm_mock)
55+ os.environ['QML2_IMPORT_PATH'] = "{0}/qml/mocks".format(self.libdir)
5456 if model() == 'Desktop' and geometry != "0x0":
5557 self.app = self.launch_test_application(
5658 "unity8", "-geometry", geometry, "-frameless", app_type='qt')
tests/autopilot/unity8/tests/helpers.py+2−1
@@ -98,7 +98,8 @@ class TestShellHelpers(object):
9898 # go to the void for the first time because there's no real way to know what the display has
9999 # painted already. Give it another (max retries) chance.
100100 try:
101− self.assertThat(lambda: getattr(bottombar, "__applicationInFocus"), Eventually(Equals(True)))
101+ self.assertThat(lambda: getattr(bottombar, "applicationIsOnForeground"),
102+ Eventually(Equals(True)))
102103 except:
103104 if retries > 0:
104105 logger.warning("Failed to launch app. Retrying...")
tests/mocks/CMakeLists.txt+3
@@ -1,2 +1,5 @@
1+add_subdirectory(libusermetrics)
12add_subdirectory(LightDM)
23add_subdirectory(Ubuntu)
4+add_subdirectory(Unity)
5+add_subdirectory(HudClient)
tests/qmltests/plugins/HudClient/CMakeLists.txt → tests/mocks/HudClient/CMakeLists.txtrenamed

The content is the same.

tests/qmltests/plugins/HudClient/fake_hud_plugin.cpp → tests/mocks/HudClient/fake_hud_plugin.cpprenamed

The content is the same.

tests/qmltests/plugins/HudClient/fake_hud_plugin.h → tests/mocks/HudClient/fake_hud_plugin.hrenamed

The content is the same.

tests/qmltests/plugins/HudClient/fake_libhud_client.cpp → tests/mocks/HudClient/fake_libhud_client.cpprenamed

The content is the same.

tests/qmltests/plugins/HudClient/libhud_client_stub.cpp → tests/mocks/HudClient/libhud_client_stub.cpprenamed

The content is the same.

tests/qmltests/plugins/HudClient/libhud_client_stub.h → tests/mocks/HudClient/libhud_client_stub.hrenamed

The content is the same.

tests/qmltests/plugins/HudClient/qmldir → tests/mocks/HudClient/qmldirrenamed

The content is the same.

tests/mocks/LightDM/CMakeLists.txt+5−2
@@ -13,6 +13,7 @@ add_subdirectory(single-passphrase)
1313include_directories(
1414 ${CMAKE_CURRENT_SOURCE_DIR}
1515 ${CMAKE_CURRENT_BINARY_DIR}
16+ ${CMAKE_SOURCE_DIR}/tests/mocks/libusermetrics
1617)
1718
1819set(QMLPLUGIN_SRC
@@ -34,6 +35,8 @@ add_dependencies(MockLightDM-qml MockLightDM-full)
3435target_link_libraries(MockLightDM-qml
3536 -L${CMAKE_CURRENT_BINARY_DIR}/full
3637 -llightdm-qt5-2
38+ -L${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics
39+ -lusermetricsoutput
3740 )
3841
3942qt5_use_modules(MockLightDM-qml Gui Qml)
@@ -44,9 +47,9 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/qmldir"
4447 )
4548
4649install(TARGETS MockLightDM-qml
47− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/LightDM
50+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM
4851 )
4952
5053install(FILES qmldir
51− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/LightDM
54+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM
5255 )
tests/mocks/LightDM/InfographicModel.cppdeleted−416
@@ -1,416 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Pete Woods <pete.woods@canonical.com>
17− */
18−
19−#include "InfographicModelPrivate.h"
20−#include "InfographicModel.h"
21−
22−#include <QtCore/QDir>
23−#include <QtCore/QString>
24−#include <QtGui/QIcon>
25−#include <QMultiMap>
26−
27−using namespace QLightDM;
28−
29−namespace QLightDM
30−{
31−
32−class InfographicColorThemePrivate: QObject
33−{
34−public:
35− explicit InfographicColorThemePrivate(InfographicColorTheme *parent = 0);
36−
37− InfographicColorThemePrivate(const QColor &start, const QColor &main,
38− const QColor &end, InfographicColorTheme *parent = 0);
39−
40− ~InfographicColorThemePrivate();
41−
42− InfographicColorTheme * const q_ptr;
43−
44− QColor m_start;
45−
46− QColor m_main;
47−
48− QColor m_end;
49−
50−protected:
51− int calculateLength();
52−
53−private:
54− Q_DECLARE_PUBLIC(InfographicColorTheme)
55−};
56−
57−class InfographicDataPrivate: QObject
58−{
59−public:
60− explicit InfographicDataPrivate(InfographicData *parent);
61−
62− InfographicDataPrivate(const QString &label,
63− const InfographicColorTheme &firstColor,
64− const QVariantList &firstMonth,
65− const InfographicColorTheme &secondColor,
66− const QVariantList &secondMonth, InfographicData *parent);
67−
68− ~InfographicDataPrivate();
69−
70− InfographicData * const q_ptr;
71− QString m_label;
72− InfographicColorTheme m_firstColor;
73− QVariantList m_firstMonth;
74− InfographicColorTheme m_secondColor;
75− QVariantList m_secondMonth;
76− int m_length;
77−
78−protected:
79− int calculateLength();
80−
81−private:
82− Q_DECLARE_PUBLIC(InfographicData)
83−};
84−
85−}
86−
87−InfographicColorThemePrivate::InfographicColorThemePrivate(
88− InfographicColorTheme *parent) :
89− q_ptr(parent)
90−{
91−}
92−
93−InfographicColorThemePrivate::InfographicColorThemePrivate(const QColor &start,
94− const QColor &main, const QColor &end, InfographicColorTheme *parent) :
95− q_ptr(parent), m_start(start), m_main(main), m_end(end)
96−{
97−}
98−
99−InfographicColorThemePrivate::~InfographicColorThemePrivate()
100−{
101−}
102−
103−InfographicColorTheme::InfographicColorTheme(QObject *parent) :
104− QObject(parent), d_ptr(new InfographicColorThemePrivate(this))
105−{
106−}
107−
108−InfographicColorTheme::InfographicColorTheme(QColor &first, QColor &main,
109− QColor &end, QObject *parent) :
110− QObject(parent), d_ptr(
111− new InfographicColorThemePrivate(first, main, end, this))
112−{
113−
114−}
115−
116−InfographicColorTheme & InfographicColorTheme::operator=(
117− const InfographicColorTheme & other)
118−{
119− if (d_ptr->m_start != other.d_ptr->m_start)
120− {
121− d_ptr->m_start = other.d_ptr->m_start;
122− startChanged(d_ptr->m_start);
123− }
124− if (d_ptr->m_main != other.d_ptr->m_main)
125− {
126− d_ptr->m_main = other.d_ptr->m_main;
127− mainChanged(d_ptr->m_main);
128− }
129−
130− if (d_ptr->m_end != other.d_ptr->m_end)
131− {
132− d_ptr->m_end = other.d_ptr->m_end;
133− endChanged(d_ptr->m_end);
134− }
135−
136− return *this;
137−}
138−
139−InfographicColorTheme::~InfographicColorTheme()
140−{
141− delete d_ptr;
142−}
143−
144−QColor InfographicColorTheme::start() const
145−{
146− return d_ptr->m_start;
147−}
148−
149−QColor InfographicColorTheme::main() const
150−{
151− return d_ptr->m_main;
152−}
153−
154−QColor InfographicColorTheme::end() const
155−{
156− return d_ptr->m_end;
157−}
158−
159−InfographicDataPrivate::InfographicDataPrivate(InfographicData *parent) :
160− q_ptr(parent), m_firstColor(this), m_secondColor(this)
161−{
162− m_length = calculateLength();
163−}
164−
165−InfographicDataPrivate::InfographicDataPrivate(const QString &label,
166− const InfographicColorTheme &firstColor, const QVariantList &firstMonth,
167− const InfographicColorTheme &secondColor,
168− const QVariantList &secondMonth, InfographicData *parent) :
169− q_ptr(parent), m_label(label), m_firstColor(this), m_firstMonth(
170− firstMonth), m_secondColor(this), m_secondMonth(secondMonth)
171−{
172− m_length = calculateLength();
173− m_firstColor = firstColor;
174− m_secondColor = secondColor;
175−}
176−
177−InfographicDataPrivate::~InfographicDataPrivate()
178−{
179−}
180−
181−int InfographicDataPrivate::calculateLength()
182−{
183− int day(m_firstMonth.size());
184− auto it = m_firstMonth.end(), end = m_firstMonth.begin();
185− while (it != end)
186− {
187− --it;
188− --day;
189− if (!it->isNull())
190− {
191− return day;
192− }
193− }
194−
195− return -1;
196−}
197−
198−InfographicData::InfographicData(QObject *parent) :
199− QObject(parent), d_ptr(new InfographicDataPrivate(this))
200−{
201−}
202−
203−InfographicData::InfographicData(const QString &label,
204− const InfographicColorTheme &firstColor, const QVariantList &firstMonth,
205− const InfographicColorTheme &secondColor,
206− const QVariantList &secondMonth, QObject* parent) :
207− QObject(parent), d_ptr(
208− new InfographicDataPrivate(label, firstColor, firstMonth,
209− secondColor, secondMonth, this))
210−{
211−}
212−
213−InfographicData::~InfographicData()
214−{
215− delete d_ptr;
216−}
217−
218−const QString & InfographicData::label() const
219−{
220− return d_ptr->m_label;
221−}
222−
223−const InfographicColorTheme & InfographicData::firstColor() const
224−{
225− return d_ptr->m_firstColor;
226−}
227−
228−const QVariantList & InfographicData::firstMonth() const
229−{
230− return d_ptr->m_firstMonth;
231−}
232−
233−const InfographicColorTheme & InfographicData::secondColor() const
234−{
235− return d_ptr->m_secondColor;
236−}
237−
238−const QVariantList & InfographicData::secondMonth() const
239−{
240− return d_ptr->m_secondMonth;
241−}
242−
243−int InfographicData::length() const
244−{
245− return d_ptr->m_length;
246−}
247−
248−InfographicModelPrivate::InfographicModelPrivate(InfographicModel *parent) :
249− q_ptr(parent), m_currentDay(0)
250−{
251− m_fakeData.insert("", InfographicDataPtr(new InfographicData(this)));
252−}
253−
254−InfographicModelPrivate::~InfographicModelPrivate()
255−{
256−}
257−
258−void InfographicModelPrivate::setUsername(const QString &username)
259−{
260− if(m_username == username) {
261− return;
262− }
263−
264− m_username = username;
265−
266− m_dataIndex = m_fakeData.constFind(m_username);
267− if (m_dataIndex == m_fakeData.end())
268− {
269− m_dataIndex = m_fakeData.constFind("");
270− }
271−
272− loadFakeData();
273−
274− q_ptr->usernameChanged(m_username);
275−}
276−
277−void InfographicModelPrivate::loadFakeData()
278−{
279− m_newData = *m_dataIndex;
280−
281− bool oldLabelEmpty = m_label.isEmpty();
282− bool newLabelEmpty = m_newData->label().isEmpty();
283−
284− if (oldLabelEmpty && !newLabelEmpty)
285− {
286− q_ptr->dataAboutToAppear();
287− finishSetFakeData();
288− } else if (!oldLabelEmpty && newLabelEmpty)
289− {
290− q_ptr->dataAboutToDisappear();
291− } else if (!oldLabelEmpty && !newLabelEmpty)
292− {
293− q_ptr->dataAboutToChange();
294− }
295− // we emit no signal if the data has stayed empty
296−}
297−
298−void InfographicModelPrivate::finishSetFakeData()
299−{
300− bool oldLabelEmpty = m_label.isEmpty();
301− bool newLabelEmpty = m_newData->label().isEmpty();
302−
303− m_label = m_newData->label();
304− m_firstColor = m_newData->firstColor();
305− m_firstMonth.setVariantList(m_newData->firstMonth());
306− m_secondColor = m_newData->secondColor();
307− m_secondMonth.setVariantList(m_newData->secondMonth());
308−
309− bool currentDayChanged = m_currentDay != m_newData->length();
310− m_currentDay = m_newData->length();
311−
312− q_ptr->labelChanged(m_label);
313− if (currentDayChanged)
314− {
315− q_ptr->currentDayChanged(m_currentDay);
316− }
317−
318− if (oldLabelEmpty && !newLabelEmpty)
319− {
320− q_ptr->dataAppeared();
321− } else if (!oldLabelEmpty && newLabelEmpty)
322− {
323− q_ptr->dataDisappeared();
324− } else if (!oldLabelEmpty && !newLabelEmpty)
325− {
326− q_ptr->dataChanged();
327− }
328− // we emit no signal if the data has stayed empty
329−}
330−
331−void InfographicModelPrivate::nextFakeData()
332−{
333− ++m_dataIndex;
334− if (m_dataIndex == m_fakeData.end() || m_dataIndex.key() != m_username)
335− {
336− m_dataIndex = m_fakeData.constFind(m_username);
337− }
338−
339− loadFakeData();
340−}
341−
342−InfographicModel::InfographicModel(QObject *parent) :
343− QObject(parent), d_ptr(new InfographicModelPrivate(this))
344−{
345− d_ptr->generateFakeData();
346− setUsername("");
347−
348− connect(this, SIGNAL(nextDataSource()), this, SLOT(nextDataSourceSlot()),
349− Qt::QueuedConnection);
350− connect(this, SIGNAL(readyForDataChange()), this,
351− SLOT(readyForDataChangeSlot()), Qt::QueuedConnection);
352−}
353−
354−InfographicModel::~InfographicModel()
355−{
356− delete d_ptr;
357−}
358−
359−QString InfographicModel::label() const
360−{
361− return d_ptr->m_label;
362−}
363−
364−QString InfographicModel::username() const
365−{
366− return d_ptr->m_username;
367−}
368−
369−void InfographicModel::setUsername(const QString &username)
370−{
371− d_ptr->setUsername(username);
372−}
373−
374−InfographicColorTheme * InfographicModel::firstColor() const
375−{
376− return &d_ptr->m_firstColor;
377−}
378−
379−InfographicColorTheme * InfographicModel::secondColor() const
380−{
381− return &d_ptr->m_secondColor;
382−}
383−
384−QAbstractItemModel * InfographicModel::firstMonth() const
385−{
386− return &d_ptr->m_firstMonth;
387−}
388−
389−QAbstractItemModel * InfographicModel::secondMonth() const
390−{
391− return &d_ptr->m_secondMonth;
392−}
393−
394−int InfographicModel::currentDay() const
395−{
396− return d_ptr->m_currentDay;
397−}
398−
399−void InfographicModel::nextDataSourceSlot()
400−{
401− d_ptr->nextFakeData();
402−}
403−
404−void InfographicModel::readyForDataChangeSlot()
405−{
406− d_ptr->finishSetFakeData();
407−}
408−
409−/**
410− * Factory methods
411− */
412−
413−InfographicModel * InfographicModel::getInstance()
414−{
415− return new InfographicModel();
416−}
tests/mocks/LightDM/InfographicModelPrivate.hdeleted−99
@@ -1,99 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Author: Pete Woods <pete.woods@canonical.com>
17− */
18−
19−#ifndef INFOGRAPHICMODEL_PRIVATE_H
20−#define INFOGRAPHICMODEL_PRIVATE_H
21−
22−#include <QtCore/QSharedPointer>
23−
24−#include "InfographicModel.h"
25−#include "plugins/Utils/qvariantlistmodel.h"
26−
27−namespace QLightDM
28−{
29−class InfographicDataPrivate;
30−
31−class Q_DECL_EXPORT InfographicData: public QObject
32−{
33−public:
34− explicit InfographicData(QObject *parent);
35−
36− InfographicData(const QString &label,
37− const InfographicColorTheme &firstColor,
38− const QVariantList &firstMonth,
39− const InfographicColorTheme &secondColor,
40− const QVariantList &secondMonth, QObject* parent);
41−
42− ~InfographicData();
43−
44−protected:
45− InfographicDataPrivate * const d_ptr;
46−
47−public:
48− const QString & label() const;
49− const InfographicColorTheme & firstColor() const;
50− const QVariantList & firstMonth() const;
51− const InfographicColorTheme & secondColor() const;
52− const QVariantList & secondMonth() const;
53− int length() const;
54−
55−private:
56− Q_DECLARE_PRIVATE(InfographicData)
57−};
58−
59−class InfographicModelPrivate: QObject
60−{
61−
62−public:
63− explicit InfographicModelPrivate(InfographicModel *parent);
64−
65− ~InfographicModelPrivate();
66−
67−public:
68− typedef QSharedPointer<InfographicData> InfographicDataPtr;
69− typedef QMultiMap<QString, InfographicDataPtr> FakeDataMap;
70−
71− InfographicModel * const q_ptr;
72− QString m_label;
73− InfographicColorTheme m_firstColor;
74− QVariantListModel m_firstMonth;
75− InfographicColorTheme m_secondColor;
76− QVariantListModel m_secondMonth;
77− int m_currentDay;
78− QString m_username;
79− FakeDataMap::const_iterator m_dataIndex;
80− InfographicDataPtr m_newData;
81− FakeDataMap m_fakeData;
82−
83− void setUsername(const QString &username);
84−
85−protected:
86− void nextFakeData();
87−
88− void generateFakeData();
89−
90− void loadFakeData();
91−
92− void finishSetFakeData();
93−
94−private:
95− Q_DECLARE_PUBLIC(InfographicModel)
96−};
97−}
98−
99−#endif // INFOGRAPHICMODEL_PRIVATE_H
tests/mocks/LightDM/demo/CMakeLists.txt+11−2
@@ -1,13 +1,22 @@
1+include(FindPkgConfig)
2+pkg_check_modules(LIBUSERMETRICSOUTPUT REQUIRED libusermetricsoutput-1)
3+
14set(LibLightDM_SOURCES
25 ../Greeter.cpp
36 ../UsersModel.cpp
4− ../InfographicModel.cpp
57 GreeterPrivate.cpp
68 UsersModelPrivate.cpp
7− InfographicModelPrivate.cpp
89 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
910 )
1011
1112add_library(MockLightDM-demo STATIC ${LibLightDM_SOURCES})
1213
14+include_directories(
15+ ${LIBUSERMETRICSOUTPUT_INCLUDE_DIRS}
16+)
17+
18+target_link_libraries(MockLightDM-demo
19+ ${LIBUSERMETRICSOUTPUT_LDFLAGS}
20+ )
21+
1322qt5_use_modules(MockLightDM-demo Gui)
tests/mocks/LightDM/demo/UsersModelPrivate.cpp+1−1
@@ -26,7 +26,7 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
2626{
2727 entries =
2828 {
29− { "guest", "Guest", 0, 0, false, false, 0, 0 },
29+ { "single", "Guest", 0, 0, false, false, 0, 0 },
3030 };
3131}
3232
tests/mocks/LightDM/full/CMakeLists.txt+1−3
@@ -1,10 +1,8 @@
11set(LibLightDM_SOURCES
22 ../Greeter.cpp
33 ../UsersModel.cpp
4− ../InfographicModel.cpp
54 GreeterPrivate.cpp
65 UsersModelPrivate.cpp
7− InfographicModelPrivate.cpp
86 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
97 )
108
@@ -16,5 +14,5 @@ set_target_properties(MockLightDM-full PROPERTIES
1614 OUTPUT_NAME lightdm-qt5-2)
1715
1816install(TARGETS MockLightDM-full
19− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/LightDM/full
17+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM/full
2018 )
tests/mocks/LightDM/single-passphrase/CMakeLists.txt+1−3
@@ -1,10 +1,8 @@
11set(LibLightDM_SOURCES
22 ../Greeter.cpp
33 ../UsersModel.cpp
4− ../InfographicModel.cpp
54 GreeterPrivate.cpp
65 UsersModelPrivate.cpp
7− InfographicModelPrivate.cpp
86 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
97 )
108
@@ -17,5 +15,5 @@ set_target_properties(MockLightDM-single-passphrase PROPERTIES
1715 OUTPUT_NAME lightdm-qt5-2)
1816
1917install(TARGETS MockLightDM-single-passphrase
20− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/LightDM/single-passphrase
18+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM/single-passphrase
2119 )
tests/mocks/LightDM/single-passphrase/UsersModelPrivate.cpp+1−1
@@ -26,7 +26,7 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
2626{
2727 entries =
2828 {
29− { "has-pin", "Has PIN", 0, 0, false, false, 0, 0 },
29+ { "single", "Has Passphrase", 0, 0, false, false, 0, 0 },
3030 };
3131}
3232
tests/mocks/LightDM/single-pin/CMakeLists.txt+1−3
@@ -1,10 +1,8 @@
11set(LibLightDM_SOURCES
22 ../Greeter.cpp
33 ../UsersModel.cpp
4− ../InfographicModel.cpp
54 GreeterPrivate.cpp
65 UsersModelPrivate.cpp
7− InfographicModelPrivate.cpp
86 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
97 )
108
@@ -17,5 +15,5 @@ set_target_properties(MockLightDM-single-pin PROPERTIES
1715 OUTPUT_NAME lightdm-qt5-2)
1816
1917install(TARGETS MockLightDM-single-pin
20− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/LightDM/single-pin
18+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM/single-pin
2119 )
tests/mocks/LightDM/single-pin/UsersModelPrivate.cpp+1−1
@@ -26,7 +26,7 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
2626{
2727 entries =
2828 {
29− { "has-pin", "Has PIN", 0, 0, false, false, 0, 0 },
29+ { "single", "Has PIN", 0, 0, false, false, 0, 0 },
3030 };
3131}
3232
tests/mocks/LightDM/single/CMakeLists.txt+1−3
@@ -1,9 +1,7 @@
11set(LibLightDM_SOURCES
22 ../Greeter.cpp
3− ../InfographicModel.cpp
43 ../UsersModel.cpp
54 GreeterPrivate.cpp
6− InfographicModelPrivate.cpp
75 UsersModelPrivate.cpp
86 ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
97 )
@@ -16,5 +14,5 @@ set_target_properties(MockLightDM-single PROPERTIES
1614 OUTPUT_NAME lightdm-qt5-2)
1715
1816install(TARGETS MockLightDM-single
19− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/LightDM/single
17+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/LightDM/single
2018 )
tests/mocks/LightDM/single/UsersModelPrivate.cpp+1−1
@@ -26,7 +26,7 @@ UsersModelPrivate::UsersModelPrivate(UsersModel* parent)
2626{
2727 entries =
2828 {
29− { "one", "Only User", 0, 0, false, false, 0, 0 },
29+ { "single", "Single User", 0, 0, false, false, 0, 0 },
3030 };
3131}
3232
tests/mocks/Ubuntu/Application/CMakeLists.txt+2−2
@@ -27,9 +27,9 @@ add_custom_target(InputFilterAreaQmlFile ALL
2727)
2828
2929install(TARGETS FakeUbuntuApplicationQml
30− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/Ubuntu/Application
30+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Ubuntu/Application
3131 )
3232
3333install(FILES qmldir InputFilterArea.qml
34− DESTINATION ${SHELL_APP_DIR}/plugins/mocks/Ubuntu/Application
34+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/Ubuntu/Application
3535 )
tests/mocks/Ubuntu/CMakeLists.txt+1
@@ -1 +1,2 @@
11add_subdirectory(Application)
2+add_subdirectory(ChewieUI)
tests/qmltests/plugins/Ubuntu/ChewieUI/CMakeLists.txt → tests/mocks/Ubuntu/ChewieUI/CMakeLists.txtrenamed

The content is the same.

tests/qmltests/plugins/Ubuntu/ChewieUI/fake_chewie_plugin.cpp → tests/mocks/Ubuntu/ChewieUI/fake_chewie_plugin.cpprenamed

The content is the same.

tests/qmltests/plugins/Ubuntu/ChewieUI/fake_chewie_plugin.h → tests/mocks/Ubuntu/ChewieUI/fake_chewie_plugin.hrenamed

The content is the same.

tests/qmltests/plugins/Ubuntu/ChewieUI/fake_pluginmodel.cpp → tests/mocks/Ubuntu/ChewieUI/fake_pluginmodel.cpprenamed

The content is the same.

tests/qmltests/plugins/Ubuntu/ChewieUI/fake_pluginmodel.h → tests/mocks/Ubuntu/ChewieUI/fake_pluginmodel.hrenamed

The content is the same.

tests/qmltests/plugins/Ubuntu/ChewieUI/qmldir → tests/mocks/Ubuntu/ChewieUI/qmldirrenamed

The content is the same.

tests/qmltests/plugins/Unity/CMakeLists.txt → tests/mocks/Unity/CMakeLists.txtrenamed

The content is the same.

tests/qmltests/plugins/Unity/Notifications/notification.js → tests/mocks/Unity/Notifications/notification.jsrenamed

The content is the same.

tests/qmltests/plugins/Unity/Notifications/qmldir → tests/mocks/Unity/Notifications/qmldirrenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_launchermodel.cpp → tests/mocks/Unity/fake_launchermodel.cpprenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_launchermodel.h → tests/mocks/Unity/fake_launchermodel.hrenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_scope.cpp → tests/mocks/Unity/fake_scope.cpprenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_scope.h → tests/mocks/Unity/fake_scope.hrenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_scopes.cpp → tests/mocks/Unity/fake_scopes.cpprenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_scopes.h → tests/mocks/Unity/fake_scopes.hrenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_unity_plugin.cpp → tests/mocks/Unity/fake_unity_plugin.cpprenamed

The content is the same.

tests/qmltests/plugins/Unity/fake_unity_plugin.h → tests/mocks/Unity/fake_unity_plugin.hrenamed

The content is the same.

tests/qmltests/plugins/Unity/qmldir → tests/mocks/Unity/qmldirrenamed

The content is the same.

tests/mocks/libusermetrics/CMakeLists.txtnew file+17
@@ -0,0 +1,17 @@
1+set(mock_SOURCES
2+ ColorTheme.cpp
3+ UserMetrics.cpp
4+ ${CMAKE_SOURCE_DIR}/plugins/Utils/qvariantlistmodel.cpp
5+ )
6+
7+add_library(MockUserMetrics SHARED ${mock_SOURCES})
8+
9+qt5_use_modules(MockUserMetrics Gui)
10+
11+set_target_properties(MockUserMetrics PROPERTIES
12+ OUTPUT_NAME usermetricsoutput
13+ VERSION 1)
14+
15+install(TARGETS MockUserMetrics
16+ DESTINATION ${SHELL_PRIVATE_LIBDIR}/qml/mocks/libusermetrics
17+ )
tests/mocks/libusermetrics/ColorTheme.cppnew file+128
@@ -0,0 +1,128 @@
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: Pete Woods <pete.woods@canonical.com>
17+ */
18+
19+#include "ColorTheme.h"
20+
21+#include <QtCore/QDir>
22+#include <QtCore/QString>
23+#include <QtGui/QIcon>
24+#include <QMultiMap>
25+
26+using namespace UserMetricsOutput;
27+
28+namespace UserMetricsOutput
29+{
30+
31+class ColorThemePrivate: QObject
32+{
33+public:
34+ explicit ColorThemePrivate(ColorTheme *parent = 0);
35+
36+ ColorThemePrivate(const QColor &start, const QColor &main,
37+ const QColor &end, ColorTheme *parent = 0);
38+
39+ ~ColorThemePrivate();
40+
41+ ColorTheme * const q_ptr;
42+
43+ QColor m_start;
44+
45+ QColor m_main;
46+
47+ QColor m_end;
48+
49+protected:
50+ int calculateLength();
51+
52+private:
53+ Q_DECLARE_PUBLIC(ColorTheme)
54+};
55+
56+}
57+
58+ColorThemePrivate::ColorThemePrivate(
59+ ColorTheme *parent) :
60+ q_ptr(parent)
61+{
62+}
63+
64+ColorThemePrivate::ColorThemePrivate(const QColor &start,
65+ const QColor &main, const QColor &end, ColorTheme *parent) :
66+ q_ptr(parent), m_start(start), m_main(main), m_end(end)
67+{
68+}
69+
70+ColorThemePrivate::~ColorThemePrivate()
71+{
72+}
73+
74+ColorTheme::ColorTheme(QObject *parent) :
75+ QObject(parent), d_ptr(new ColorThemePrivate(this))
76+{
77+}
78+
79+ColorTheme::ColorTheme(QColor &first, QColor &main,
80+ QColor &end, QObject *parent) :
81+ QObject(parent), d_ptr(
82+ new ColorThemePrivate(first, main, end, this))
83+{
84+
85+}
86+
87+ColorTheme & ColorTheme::operator=(
88+ const ColorTheme & other)
89+{
90+ if (d_ptr->m_start != other.d_ptr->m_start)
91+ {
92+ d_ptr->m_start = other.d_ptr->m_start;
93+ startChanged(d_ptr->m_start);
94+ }
95+ if (d_ptr->m_main != other.d_ptr->m_main)
96+ {
97+ d_ptr->m_main = other.d_ptr->m_main;
98+ mainChanged(d_ptr->m_main);
99+ }
100+
101+ if (d_ptr->m_end != other.d_ptr->m_end)
102+ {
103+ d_ptr->m_end = other.d_ptr->m_end;
104+ endChanged(d_ptr->m_end);
105+ }
106+
107+ return *this;
108+}
109+
110+ColorTheme::~ColorTheme()
111+{
112+ delete d_ptr;
113+}
114+
115+QColor ColorTheme::start() const
116+{
117+ return d_ptr->m_start;
118+}
119+
120+QColor ColorTheme::main() const
121+{
122+ return d_ptr->m_main;
123+}
124+
125+QColor ColorTheme::end() const
126+{
127+ return d_ptr->m_end;
128+}
tests/mocks/libusermetrics/ColorTheme.hnew file+68
@@ -0,0 +1,68 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ *
16+ * Author: Pete Woods <pete.woods@canonical.com>
17+ */
18+
19+#ifndef UNITY_MOCK_COLORTHEME_H
20+#define UNITY_MOCK_COLORTHEME_H
21+
22+#include <QtGui/QColor>
23+
24+namespace UserMetricsOutput
25+{
26+class ColorThemePrivate;
27+
28+class Q_DECL_EXPORT ColorTheme: public QObject
29+{
30+Q_OBJECT
31+
32+Q_PROPERTY(QColor start READ start NOTIFY startChanged FINAL)
33+Q_PROPERTY(QColor main READ main NOTIFY mainChanged FINAL)
34+Q_PROPERTY(QColor end READ end NOTIFY endChanged FINAL)
35+
36+public:
37+ explicit ColorTheme(QObject *parent = 0);
38+
39+ explicit ColorTheme(QColor &first, QColor &main, QColor &end,
40+ QObject *parent = 0);
41+
42+ ColorTheme & operator=(const ColorTheme & other);
43+
44+ ~ColorTheme();
45+
46+ QColor start() const;
47+
48+ QColor main() const;
49+
50+ QColor end() const;
51+
52+Q_SIGNALS:
53+ void startChanged(const QColor &color);
54+
55+ void mainChanged(const QColor &color);
56+
57+ void endChanged(const QColor &color);
58+
59+protected:
60+ ColorThemePrivate * const d_ptr;
61+
62+ Q_DECLARE_PRIVATE(ColorTheme)
63+
64+};
65+
66+}
67+
68+#endif // UNITY_MOCK_COLORTHEME_H
tests/mocks/libusermetrics/UserMetrics.cppnew file+465
@@ -0,0 +1,465 @@
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: Pete Woods <pete.woods@canonical.com>
17+ */
18+
19+#include "UserMetrics.h"
20+#include "plugins/Utils/qvariantlistmodel.h"
21+
22+#include <QtCore/QDir>
23+#include <QtCore/QString>
24+#include <QtGui/QIcon>
25+#include <QMultiMap>
26+
27+using namespace UserMetricsOutput;
28+
29+namespace UserMetricsOutput
30+{
31+class UserMetricsDataPrivate;
32+class UserMetricsPrivate;
33+
34+class Q_DECL_EXPORT UserMetricsData: public QObject
35+{
36+public:
37+ explicit UserMetricsData(QObject *parent);
38+
39+ UserMetricsData(const QString &label,
40+ const ColorTheme &firstColor,
41+ const QVariantList &firstMonth,
42+ const ColorTheme &secondColor,
43+ const QVariantList &secondMonth, QObject* parent);
44+
45+ ~UserMetricsData();
46+
47+protected:
48+ UserMetricsDataPrivate * const d_ptr;
49+
50+public:
51+ const QString & label() const;
52+ const ColorTheme & firstColor() const;
53+ const QVariantList & firstMonth() const;
54+ const ColorTheme & secondColor() const;
55+ const QVariantList & secondMonth() const;
56+ int length() const;
57+
58+private:
59+ Q_DECLARE_PRIVATE(UserMetricsData)
60+};
61+
62+class UserMetricsPrivate: QObject
63+{
64+public:
65+ explicit UserMetricsPrivate(UserMetrics *parent);
66+
67+ ~UserMetricsPrivate();
68+
69+public:
70+ typedef QSharedPointer<UserMetricsData> UserMetricsDataPtr;
71+ typedef QMultiMap<QString, UserMetricsDataPtr> FakeDataMap;
72+
73+ UserMetrics * const q_ptr;
74+ QString m_label;
75+ ColorTheme m_firstColor;
76+ QVariantListModel m_firstMonth;
77+ ColorTheme m_secondColor;
78+ QVariantListModel m_secondMonth;
79+ int m_currentDay;
80+ QString m_username;
81+ FakeDataMap::const_iterator m_dataIndex;
82+ UserMetricsDataPtr m_newData;
83+ FakeDataMap m_fakeData;
84+
85+ void setUsername(const QString &username);
86+
87+protected:
88+ void nextFakeData();
89+
90+ void generateFakeData();
91+
92+ void loadFakeData();
93+
94+ void finishSetFakeData();
95+
96+private:
97+ Q_DECLARE_PUBLIC(UserMetrics)
98+};
99+
100+class UserMetricsDataPrivate: QObject
101+{
102+public:
103+ explicit UserMetricsDataPrivate(UserMetricsData *parent);
104+
105+ UserMetricsDataPrivate(const QString &label,
106+ const ColorTheme &firstColor,
107+ const QVariantList &firstMonth,
108+ const ColorTheme &secondColor,
109+ const QVariantList &secondMonth, UserMetricsData *parent);
110+
111+ ~UserMetricsDataPrivate();
112+
113+ UserMetricsData * const q_ptr;
114+ QString m_label;
115+ ColorTheme m_firstColor;
116+ QVariantList m_firstMonth;
117+ ColorTheme m_secondColor;
118+ QVariantList m_secondMonth;
119+ int m_length;
120+
121+protected:
122+ int calculateLength();
123+
124+private:
125+ Q_DECLARE_PUBLIC(UserMetricsData)
126+};
127+
128+}
129+
130+UserMetricsDataPrivate::UserMetricsDataPrivate(UserMetricsData *parent) :
131+ q_ptr(parent), m_firstColor(this), m_secondColor(this)
132+{
133+ m_length = calculateLength();
134+}
135+
136+UserMetricsDataPrivate::UserMetricsDataPrivate(const QString &label,
137+ const ColorTheme &firstColor, const QVariantList &firstMonth,
138+ const ColorTheme &secondColor,
139+ const QVariantList &secondMonth, UserMetricsData *parent) :
140+ q_ptr(parent), m_label(label), m_firstColor(this), m_firstMonth(
141+ firstMonth), m_secondColor(this), m_secondMonth(secondMonth)
142+{
143+ m_length = calculateLength();
144+ m_firstColor = firstColor;
145+ m_secondColor = secondColor;
146+}
147+
148+UserMetricsDataPrivate::~UserMetricsDataPrivate()
149+{
150+}
151+
152+int UserMetricsDataPrivate::calculateLength()
153+{
154+ int day(m_firstMonth.size());
155+ auto it = m_firstMonth.end(), end = m_firstMonth.begin();
156+ while (it != end)
157+ {
158+ --it;
159+ --day;
160+ if (!it->isNull())
161+ {
162+ return day;
163+ }
164+ }
165+
166+ return -1;
167+}
168+
169+UserMetricsData::UserMetricsData(QObject *parent) :
170+ QObject(parent), d_ptr(new UserMetricsDataPrivate(this))
171+{
172+}
173+
174+UserMetricsData::UserMetricsData(const QString &label,
175+ const ColorTheme &firstColor, const QVariantList &firstMonth,
176+ const ColorTheme &secondColor,
177+ const QVariantList &secondMonth, QObject* parent) :
178+ QObject(parent), d_ptr(
179+ new UserMetricsDataPrivate(label, firstColor, firstMonth,
180+ secondColor, secondMonth, this))
181+{
182+}
183+
184+UserMetricsData::~UserMetricsData()
185+{
186+ delete d_ptr;
187+}
188+
189+const QString & UserMetricsData::label() const
190+{
191+ return d_ptr->m_label;
192+}
193+
194+const ColorTheme & UserMetricsData::firstColor() const
195+{
196+ return d_ptr->m_firstColor;
197+}
198+
199+const QVariantList & UserMetricsData::firstMonth() const
200+{
201+ return d_ptr->m_firstMonth;
202+}
203+
204+const ColorTheme & UserMetricsData::secondColor() const
205+{
206+ return d_ptr->m_secondColor;
207+}
208+
209+const QVariantList & UserMetricsData::secondMonth() const
210+{
211+ return d_ptr->m_secondMonth;
212+}
213+
214+int UserMetricsData::length() const
215+{
216+ return d_ptr->m_length;
217+}
218+
219+UserMetricsPrivate::UserMetricsPrivate(UserMetrics *parent) :
220+ q_ptr(parent), m_firstColor(this), m_secondColor(this)
221+{
222+ m_fakeData.insert("", UserMetricsDataPtr(new UserMetricsData(this)));
223+}
224+
225+UserMetricsPrivate::~UserMetricsPrivate()
226+{
227+}
228+
229+void UserMetricsPrivate::setUsername(const QString &username)
230+{
231+ if (m_username == username) {
232+ return;
233+ }
234+
235+ m_username = username;
236+
237+ m_dataIndex = m_fakeData.constFind(m_username);
238+ if (m_dataIndex == m_fakeData.end())
239+ {
240+ m_dataIndex = m_fakeData.constFind("");
241+ }
242+
243+ loadFakeData();
244+
245+ q_ptr->usernameChanged(m_username);
246+}
247+
248+void UserMetricsPrivate::generateFakeData()
249+{
250+ std::default_random_engine generator;
251+ std::normal_distribution<qreal> distribution(0.5, 0.2);
252+ auto rand = std::bind(distribution, generator);
253+
254+ QVector<QColor> colours;
255+ colours.push_back(QColor::fromRgbF(0.3, 0.27, 0.32));
256+ colours.push_back(QColor::fromRgbF(0.83, 0.49, 0.58));
257+ colours.push_back(QColor::fromRgbF(0.63, 0.51, 0.59));
258+
259+ colours.push_back(QColor::fromRgbF(0.28, 0.26, 0.4));
260+ colours.push_back(QColor::fromRgbF(0.47, 0.38, 0.56));
261+ colours.push_back(QColor::fromRgbF(0.69, 0.65, 0.78));
262+
263+ colours.push_back(QColor::fromRgbF(0.32, 0.21, 0.16));
264+ colours.push_back(QColor::fromRgbF(0.55, 0.45, 0.32));
265+ colours.push_back(QColor::fromRgbF(0.85, 0.74, 0.53));
266+
267+ colours.push_back(QColor::fromRgbF(0.25, 0.31, 0.19));
268+ colours.push_back(QColor::fromRgbF(0.63, 0.53, 0.3));
269+ colours.push_back(QColor::fromRgbF(0.89, 0.56, 0.31));
270+
271+ ColorTheme first(colours[0], colours[1], colours[2]);
272+ ColorTheme second(colours[3], colours[4], colours[5]);
273+ ColorTheme eighth(colours[6], colours[7], colours[8]);
274+ ColorTheme ninth(colours[9], colours[10], colours[11]);
275+
276+ {
277+ QVariantList firstMonth;
278+ while (firstMonth.size() < 17)
279+ firstMonth.push_back(QVariant(rand()));
280+ while (firstMonth.size() < 31)
281+ firstMonth.push_back(QVariant());
282+ QVariantList secondMonth;
283+ while (secondMonth.size() < 31)
284+ secondMonth.push_back(QVariant(rand()));
285+ QSharedPointer<UserMetricsData> data(
286+ new UserMetricsData("<b>52km</b> travelled", first, firstMonth,
287+ ninth, secondMonth, this));
288+ m_fakeData.insert("single", data);
289+ }
290+
291+ {
292+ QVariantList firstMonth;
293+ while (firstMonth.size() < 17)
294+ firstMonth.push_back(QVariant(rand()));
295+ while (firstMonth.size() < 31)
296+ firstMonth.push_back(QVariant());
297+ QVariantList secondMonth;
298+ while (secondMonth.size() < 31)
299+ secondMonth.push_back(QVariant(rand()));
300+ QSharedPointer<UserMetricsData> data(
301+ new UserMetricsData("<b>33</b> messages today", second,
302+ firstMonth, eighth, secondMonth, this));
303+ m_fakeData.insert("single", data);
304+ }
305+
306+ {
307+ QVariantList firstMonth;
308+ while (firstMonth.size() < 17)
309+ firstMonth.push_back(QVariant(rand()));
310+ while (firstMonth.size() < 31)
311+ firstMonth.push_back(QVariant());
312+ QVariantList secondMonth;
313+ while (secondMonth.size() < 31)
314+ secondMonth.push_back(QVariant(rand()));
315+ QSharedPointer<UserMetricsData> data(
316+ new UserMetricsData("<b>19</b> minutes talk time", eighth,
317+ firstMonth, second, secondMonth, this));
318+ m_fakeData.insert("single", data);
319+ // Also use same data for some tablet users
320+ m_fakeData.insert("has-password", data);
321+ m_fakeData.insert("no-password", data);
322+ m_fakeData.insert("empty-name", data);
323+ }
324+}
325+
326+void UserMetricsPrivate::loadFakeData()
327+{
328+ m_newData = *m_dataIndex;
329+
330+ bool oldLabelEmpty = m_label.isEmpty();
331+ bool newLabelEmpty = m_newData->label().isEmpty();
332+
333+ if (oldLabelEmpty && !newLabelEmpty)
334+ {
335+ q_ptr->dataAboutToAppear();
336+ finishSetFakeData();
337+ } else if (!oldLabelEmpty && newLabelEmpty)
338+ {
339+ q_ptr->dataAboutToDisappear();
340+ } else if (!oldLabelEmpty && !newLabelEmpty)
341+ {
342+ q_ptr->dataAboutToChange();
343+ }
344+ // we emit no signal if the data has stayed empty
345+}
346+
347+void UserMetricsPrivate::finishSetFakeData()
348+{
349+ bool oldLabelEmpty = m_label.isEmpty();
350+ bool newLabelEmpty = m_newData->label().isEmpty();
351+
352+ m_label = m_newData->label();
353+ m_firstColor = m_newData->firstColor();
354+ m_firstMonth.setVariantList(m_newData->firstMonth());
355+ m_secondColor = m_newData->secondColor();
356+ m_secondMonth.setVariantList(m_newData->secondMonth());
357+
358+ bool currentDayChanged = m_currentDay != m_newData->length();
359+ m_currentDay = m_newData->length();
360+
361+ q_ptr->labelChanged(m_label);
362+ if (currentDayChanged)
363+ {
364+ q_ptr->currentDayChanged(m_currentDay);
365+ }
366+
367+ if (oldLabelEmpty && !newLabelEmpty)
368+ {
369+ q_ptr->dataAppeared();
370+ } else if (!oldLabelEmpty && newLabelEmpty)
371+ {
372+ q_ptr->dataDisappeared();
373+ } else if (!oldLabelEmpty && !newLabelEmpty)
374+ {
375+ q_ptr->dataChanged();
376+ }
377+ // we emit no signal if the data has stayed empty
378+}
379+
380+void UserMetricsPrivate::nextFakeData()
381+{
382+ ++m_dataIndex;
383+ if (m_dataIndex == m_fakeData.end() || m_dataIndex.key() != m_username)
384+ {
385+ m_dataIndex = m_fakeData.constFind(m_username);
386+ }
387+
388+ loadFakeData();
389+}
390+
391+UserMetrics::UserMetrics(QObject *parent) :
392+ QObject(parent), d_ptr(new UserMetricsPrivate(this))
393+{
394+ d_ptr->generateFakeData();
395+ setUsername("");
396+
397+ connect(this, SIGNAL(nextDataSource()), this, SLOT(nextDataSourceSlot()),
398+ Qt::QueuedConnection);
399+ connect(this, SIGNAL(readyForDataChange()), this,
400+ SLOT(readyForDataChangeSlot()), Qt::QueuedConnection);
401+}
402+
403+UserMetrics::~UserMetrics()
404+{
405+ delete d_ptr;
406+}
407+
408+QString UserMetrics::label() const
409+{
410+ return d_ptr->m_label;
411+}
412+
413+QString UserMetrics::username() const
414+{
415+ return d_ptr->m_username;
416+}
417+
418+void UserMetrics::setUsername(const QString &username)
419+{
420+ d_ptr->setUsername(username);
421+}
422+
423+ColorTheme *UserMetrics::firstColor() const
424+{
425+ return &d_ptr->m_firstColor;
426+}
427+
428+ColorTheme *UserMetrics::secondColor() const
429+{
430+ return &d_ptr->m_secondColor;
431+}
432+
433+QAbstractItemModel *UserMetrics::firstMonth() const
434+{
435+ return &d_ptr->m_firstMonth;
436+}
437+
438+QAbstractItemModel *UserMetrics::secondMonth() const
439+{
440+ return &d_ptr->m_secondMonth;
441+}
442+
443+int UserMetrics::currentDay() const
444+{
445+ return d_ptr->m_currentDay;
446+}
447+
448+void UserMetrics::nextDataSourceSlot()
449+{
450+ d_ptr->nextFakeData();
451+}
452+
453+void UserMetrics::readyForDataChangeSlot()
454+{
455+ d_ptr->finishSetFakeData();
456+}
457+
458+/**
459+ * Factory methods
460+ */
461+
462+UserMetrics * UserMetrics::getInstance()
463+{
464+ return new UserMetrics();
465+}
tests/mocks/LightDM/InfographicModel.h → tests/mocks/libusermetrics/UserMetrics.hrenamed+22−60
@@ -16,74 +16,34 @@
1616 * Author: Pete Woods <pete.woods@canonical.com>
1717 */
1818
19−#ifndef LIGHTDM_INFOGRAPHICMODEL_H
20−#define LIGHTDM_INFOGRAPHICMODEL_H
19+#ifndef UNITY_MOCK_USERMETRICS_H
20+#define UNITY_MOCK_USERMETRICS_H
2121
22+#include "ColorTheme.h"
23+#include <QtCore/QAbstractListModel>
2224#include <QtCore/QString>
23−#include <QtGui/qcolor.h>
24−#include <QAbstractListModel>
25+#include <QtGui/QColor>
2526
26−namespace QLightDM
27+namespace UserMetricsOutput
2728{
28−class InfographicColorThemePrivate;
29+class UserMetricsPrivate;
2930
30−class Q_DECL_EXPORT InfographicColorTheme: public QObject
31−{
32−Q_OBJECT
33−
34−Q_PROPERTY(QColor start READ start NOTIFY startChanged FINAL)
35−Q_PROPERTY(QColor main READ main NOTIFY mainChanged FINAL)
36−Q_PROPERTY(QColor end READ end NOTIFY endChanged FINAL)
37−
38−public:
39− explicit InfographicColorTheme(QObject *parent = 0);
40−
41− explicit InfographicColorTheme(QColor &first, QColor &main, QColor &end,
42− QObject *parent = 0);
43−
44− InfographicColorTheme & operator=(const InfographicColorTheme & other);
45−
46− ~InfographicColorTheme();
47−
48− QColor start() const;
49−
50− QColor main() const;
51−
52− QColor end() const;
53−
54−Q_SIGNALS:
55− void startChanged(const QColor &color);
56−
57− void mainChanged(const QColor &color);
58−
59− void endChanged(const QColor &color);
60−
61−protected:
62− InfographicColorThemePrivate * const d_ptr;
63−
64− Q_DECLARE_PRIVATE(InfographicColorTheme)
65−
66−};
67−
68−class InfographicModelPrivate;
69−
70−class Q_DECL_EXPORT InfographicModel: public QObject
31+class Q_DECL_EXPORT UserMetrics: public QObject
7132{
7233Q_OBJECT
7334
7435Q_PROPERTY(QString label READ label NOTIFY labelChanged FINAL)
7536Q_PROPERTY(QString username READ username WRITE setUsername NOTIFY usernameChanged FINAL)
76−Q_PROPERTY(QLightDM::InfographicColorTheme* firstColor READ firstColor NOTIFY firstColorChanged FINAL)
77−Q_PROPERTY(QLightDM::InfographicColorTheme* secondColor READ secondColor NOTIFY secondColorChanged FINAL)
37+Q_PROPERTY(UserMetricsOutput::ColorTheme* firstColor READ firstColor NOTIFY firstColorChanged FINAL)
38+Q_PROPERTY(UserMetricsOutput::ColorTheme* secondColor READ secondColor NOTIFY secondColorChanged FINAL)
7839Q_PROPERTY(QAbstractItemModel *firstMonth READ firstMonth NOTIFY firstMonthChanged FINAL)
7940Q_PROPERTY(QAbstractItemModel *secondMonth READ secondMonth NOTIFY secondMonthChanged FINAL)
8041Q_PROPERTY(int currentDay READ currentDay NOTIFY currentDayChanged FINAL)
8142
8243public:
83− static InfographicModel *getInstance();
44+ static UserMetrics *getInstance();
8445
85− explicit InfographicModel(QObject *parent = 0);
86− ~InfographicModel();
46+ ~UserMetrics();
8747
8848 QString label() const;
8949
@@ -91,13 +51,13 @@ public:
9151
9252 void setUsername(const QString &username);
9353
94− InfographicColorTheme * firstColor() const;
54+ ColorTheme * firstColor() const;
9555
9656 QAbstractItemModel *firstMonth() const;
9757
9858 int currentDay() const;
9959
100− InfographicColorTheme * secondColor() const;
60+ ColorTheme * secondColor() const;
10161
10262 QAbstractItemModel *secondMonth() const;
10363
@@ -106,13 +66,13 @@ Q_SIGNALS:
10666
10767 void usernameChanged(const QString &username);
10868
109− void firstColorChanged(InfographicColorTheme *color);
69+ void firstColorChanged(ColorTheme *color);
11070
11171 void firstMonthChanged(QAbstractItemModel *firstMonth);
11272
11373 void currentDayChanged(int length);
11474
115− void secondColorChanged(InfographicColorTheme *color);
75+ void secondColorChanged(ColorTheme *color);
11676
11777 void secondMonthChanged(QAbstractItemModel *secondMonth);
11878
@@ -138,13 +98,15 @@ protected Q_SLOTS:
13898 void readyForDataChangeSlot();
13999
140100protected:
141− InfographicModelPrivate * const d_ptr;
101+ UserMetricsPrivate * const d_ptr;
102+
103+ explicit UserMetrics(QObject *parent = 0);
142104
143− Q_DISABLE_COPY(InfographicModel)
144− Q_DECLARE_PRIVATE(InfographicModel)
105+ Q_DISABLE_COPY(UserMetrics)
106+ Q_DECLARE_PRIVATE(UserMetrics)
145107
146108};
147109
148110}
149111
150−#endif // LIGHTDM_INFOGRAPHICMODEL_H
112+#endif // UNITY_MOCK_USERMETRICS_H
tests/mocks/libusermetrics/libusermetricsoutput/ColorTheme.hnew file+1
@@ -0,0 +1 @@
1+../ColorTheme.h
tests/mocks/libusermetrics/libusermetricsoutput/UserMetrics.hnew file+1
@@ -0,0 +1 @@
1+../UserMetrics.h
tests/plugins/CMakeLists.txt+2
@@ -1,2 +1,4 @@
11add_subdirectory(Utils)
22add_subdirectory(Ubuntu)
3+add_subdirectory(Unity)
4+add_subdirectory(ListViewWithPageHeader)
tests/plugins/ListViewWithPageHeader/CMakeLists.txtnew file+31
@@ -0,0 +1,31 @@
1+# There's no cmake var for v8 include path :-/
2+# so create one
3+LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
4+SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
5+
6+include_directories(
7+ ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
8+ ${Qt5Quick_INCLUDE_DIRS}
9+ ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
10+ ${Qt5V8_PRIVATE_INCLUDE_DIR}
11+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/ListViewWithPageHeader
12+ ${CMAKE_CURRENT_BINARY_DIR}
13+ )
14+
15+remove_definitions(-DQT_NO_KEYWORDS)
16+
17+add_definitions(-DLISTVIEWWITHPAGEHEADER_FOLDER="${CMAKE_CURRENT_SOURCE_DIR}")
18+add_definitions(-DBUILT_PLUGINS_DIR="${CMAKE_BINARY_DIR}/plugins")
19+
20+add_executable(listviewwithpageheadertestExec listviewwithpageheadertest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/ListViewWithPageHeader/listviewwithpageheader.cpp)
21+qt5_use_modules(listviewwithpageheadertestExec Test Core Qml)
22+target_link_libraries(listviewwithpageheadertestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
23+add_custom_target(testlistviewwithpageheader ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheader.xml,xunitxml -o -,txt)
24+
25+add_executable(listviewwithpageheadertestsectionExec listviewwithpageheadertestsection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/ListViewWithPageHeader/listviewwithpageheader.cpp)
26+qt5_use_modules(listviewwithpageheadertestsectionExec Test Core Qml)
27+target_link_libraries(listviewwithpageheadertestsectionExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
28+add_custom_target(testlistviewwithpageheadersection ${CMAKE_CURRENT_BINARY_DIR}/listviewwithpageheadertestsectionExec -o ${CMAKE_BINARY_DIR}/testlistviewwithpageheadersection.xml,xunitxml -o -,txt)
29+
30+add_dependencies(qmluitests testlistviewwithpageheader)
31+add_dependencies(qmluitests testlistviewwithpageheadersection)
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertest.cppnew file+1317
@@ -0,0 +1,1317 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "listviewwithpageheader.h"
18+
19+#include <QAbstractItemModel>
20+#include <QQmlEngine>
21+#include <QQuickView>
22+#include <QtTestGui>
23+#include <private/qquicklistmodel_p.h>
24+#include <private/qquickanimation_p.h>
25+#include <private/qquickitem_p.h>
26+
27+class ListViewWithPageHeaderTest : public QObject
28+{
29+ Q_OBJECT
30+
31+private:
32+ void verifyItem(int visibleIndex, qreal pos, qreal height, bool culled)
33+ {
34+ ListViewWithPageHeader::ListItem *item = lvwph->m_visibleItems[visibleIndex];
35+ QTRY_COMPARE(item->y(), pos);
36+ QTRY_COMPARE(item->height(), height);
37+ QCOMPARE(QQuickItemPrivate::get(item->m_item)->culled, culled);
38+ }
39+
40+ void changeContentY(qreal change)
41+ {
42+ const qreal dest = lvwph->contentY() + change;
43+ if (dest > lvwph->contentY()) {
44+ const qreal jump = 25;
45+ while (lvwph->contentY() + jump < dest) {
46+ lvwph->setContentY(lvwph->contentY() + jump);
47+ QTest::qWait(1);
48+ }
49+ } else {
50+ const qreal jump = -25;
51+ while (lvwph->contentY() + jump > dest) {
52+ lvwph->setContentY(lvwph->contentY() + jump);
53+ QTest::qWait(1);
54+ }
55+ }
56+ lvwph->setContentY(dest);
57+ QTest::qWait(1);
58+ }
59+
60+ void scrollToTop()
61+ {
62+ const qreal jump = -25;
63+ while (!lvwph->isAtYBeginning()) {
64+ if (lvwph->contentY() + jump > -lvwph->minYExtent()) {
65+ lvwph->setContentY(lvwph->contentY() + jump);
66+ } else {
67+ lvwph->setContentY(lvwph->contentY() - 1);
68+ }
69+ QTest::qWait(1);
70+ }
71+ }
72+
73+ void scrollToBottom()
74+ {
75+ const qreal jump = 25;
76+ while (!lvwph->isAtYEnd()) {
77+ if (lvwph->contentY() + lvwph->height() + jump < lvwph->contentHeight()) {
78+ lvwph->setContentY(lvwph->contentY() + jump);
79+ } else {
80+ lvwph->setContentY(lvwph->contentY() + 1);
81+ }
82+ QTest::qWait(1);
83+ }
84+ }
85+
86+ void verifyInitialTopPosition()
87+ {
88+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
89+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
90+ verifyItem(0, 50., 150., false);
91+ verifyItem(1, 200., 200., false);
92+ verifyItem(2, 400., 350., false);
93+ verifyItem(3, 750., 350., true);
94+ QCOMPARE(lvwph->m_minYExtent, 0.);
95+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
96+ QCOMPARE(lvwph->m_clipItem->clip(), false);
97+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
98+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
99+ QCOMPARE(lvwph->contentY(), 0.);
100+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
101+ }
102+
103+private Q_SLOTS:
104+
105+ void initTestCase()
106+ {
107+ }
108+
109+ void init()
110+ {
111+ view = new QQuickView();
112+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
113+ view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test.qml"));
114+ lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
115+ model = view->rootObject()->findChild<QQuickListModel*>();
116+ otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
117+ QVERIFY(lvwph);
118+ QVERIFY(model);
119+ QVERIFY(otherDelegate);
120+ view->show();
121+ QTest::qWaitForWindowExposed(view);
122+
123+ verifyInitialTopPosition();
124+ }
125+
126+ void cleanup()
127+ {
128+ delete view;
129+ }
130+
131+ void testCreationDeletion()
132+ {
133+ // Nothing, init/cleanup already tests this
134+ }
135+
136+ void testDrag1PixelUp()
137+ {
138+ lvwph->setContentY(lvwph->contentY() + 1);
139+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
140+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
141+ verifyItem(0, 49., 150., false);
142+ verifyItem(1, 199., 200., false);
143+ verifyItem(2, 399., 350., false);
144+ verifyItem(3, 749., 350., true);
145+ QCOMPARE(lvwph->m_minYExtent, 0.);
146+ QCOMPARE(lvwph->m_clipItem->y(), 1.);
147+ QCOMPARE(lvwph->m_clipItem->clip(), false);
148+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
149+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
150+ QCOMPARE(lvwph->contentY(), 1.);
151+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
152+ }
153+
154+ void testHeaderDetachDragDown()
155+ {
156+ QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 0));
157+ QTest::qWait(100);
158+ QTest::mouseMove(view, QPoint(0, 5));
159+ QTest::qWait(100);
160+ QTest::mouseMove(view, QPoint(0, 10));
161+ QTest::qWait(100);
162+ QTest::mouseMove(view, QPoint(0, 15));
163+ QTest::qWait(100);
164+ QTest::mouseMove(view, QPoint(0, 20));
165+ QTest::qWait(100);
166+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
167+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
168+ verifyItem(0, 55., 150., false);
169+ verifyItem(1, 205., 200., false);
170+ verifyItem(2, 405., 350., false);
171+ verifyItem(3, 755., 350., true);
172+ QCOMPARE(lvwph->m_minYExtent, 0.);
173+ QCOMPARE(lvwph->m_clipItem->y(), -5.);
174+ QCOMPARE(lvwph->m_clipItem->clip(), false);
175+ QCOMPARE(lvwph->m_headerItem->y(), -5.);
176+ QCOMPARE(lvwph->m_headerItem->height(), 55.);
177+ QCOMPARE(lvwph->contentY(), -5.);
178+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
179+
180+ QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 15));
181+
182+ verifyInitialTopPosition();
183+ }
184+
185+ void testDrag375PixelUp()
186+ {
187+ changeContentY(375);
188+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
189+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
190+ verifyItem(0, -325., 150., true);
191+ verifyItem(1, -175, 200., false);
192+ verifyItem(2, 25, 350., false);
193+ verifyItem(3, 375, 350., false);
194+ verifyItem(4, 725, 350., true);
195+ QCOMPARE(lvwph->m_minYExtent, 0.);
196+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
197+ QCOMPARE(lvwph->m_clipItem->clip(), false);
198+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
199+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
200+ QCOMPARE(lvwph->contentY(), 375.);
201+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
202+ }
203+
204+ void testDrag520PixelUp()
205+ {
206+ changeContentY(520);
207+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
208+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
209+ verifyItem(0, -320., 200., true);
210+ verifyItem(1, -120, 350., false);
211+ verifyItem(2, 230, 350., false);
212+ verifyItem(3, 580, 350., true);
213+ // Just here as first check against m_minYExtent when m_firstVisibleIndex is not 0
214+ // We as humans know that m_minYExtent will be 0 but since the first delegate is not there anymore
215+ // we have to estimate its size, the average item height is 312.5 which is 162.5 more than the
216+ // "real" size of 150 and that's why the m_minYExtent has that "peculiar" value
217+ // It's fine since what it means is that we could scroll more up than the original position
218+ // but we will recalculate m_minYExtent when the item 0 is created and set it correctly
219+ QCOMPARE(lvwph->m_minYExtent, 162.5);
220+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
221+ QCOMPARE(lvwph->m_clipItem->clip(), false);
222+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
223+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
224+ QCOMPARE(lvwph->contentY(), 520.);
225+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
226+ }
227+
228+ void testDragHeaderUpThenShow()
229+ {
230+ changeContentY(120);
231+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
232+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
233+ verifyItem(0, -70., 150., false);
234+ verifyItem(1, 80., 200., false);
235+ verifyItem(2, 280., 350., false);
236+ verifyItem(3, 630., 350., true);
237+ QCOMPARE(lvwph->m_minYExtent, 0.);
238+ QCOMPARE(lvwph->m_clipItem->y(), 120.);
239+ QCOMPARE(lvwph->m_clipItem->clip(), false);
240+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
241+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
242+ QCOMPARE(lvwph->contentY(), 120.);
243+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
244+
245+ changeContentY(-30);
246+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
247+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
248+ verifyItem(0, -70., 150., false);
249+ verifyItem(1, 80., 200., false);
250+ verifyItem(2, 280., 350., false);
251+ verifyItem(3, 630., 350., true);
252+ QCOMPARE(lvwph->m_minYExtent, 0.);
253+ QCOMPARE(lvwph->m_clipItem->y(), 120.);
254+ QCOMPARE(lvwph->m_clipItem->clip(), true);
255+ QTRY_COMPARE(lvwph->m_headerItem->y(), 70.);
256+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
257+ QCOMPARE(lvwph->contentY(), 90.);
258+ QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
259+ }
260+
261+ void testDragHeaderUpThenShowWithoutHidingTotally()
262+ {
263+ changeContentY(10);
264+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
265+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
266+ verifyItem(0, 40., 150., false);
267+ verifyItem(1, 190., 200., false);
268+ verifyItem(2, 390., 350., false);
269+ verifyItem(3, 740., 350., true);
270+ QCOMPARE(lvwph->m_minYExtent, 0.);
271+ QCOMPARE(lvwph->m_clipItem->y(), 10.);
272+ QCOMPARE(lvwph->m_clipItem->clip(), false);
273+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
274+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
275+ QCOMPARE(lvwph->contentY(), 10.);
276+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
277+
278+ changeContentY(-1);
279+
280+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
281+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
282+ verifyItem(0, 41., 150., false);
283+ verifyItem(1, 191., 200., false);
284+ verifyItem(2, 391., 350., false);
285+ verifyItem(3, 741., 350., true);
286+ QCOMPARE(lvwph->m_minYExtent, 0.);
287+ QCOMPARE(lvwph->m_clipItem->y(), 9.);
288+ QCOMPARE(lvwph->m_clipItem->clip(), false);
289+ QTRY_COMPARE(lvwph->m_headerItem->y(), 0.);
290+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
291+ QCOMPARE(lvwph->contentY(), 9.);
292+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
293+ }
294+
295+ void testPositionAtBeginningIndex0Visible()
296+ {
297+ changeContentY(375);
298+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
299+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
300+ verifyItem(0, -325., 150., true);
301+ verifyItem(1, -175, 200., false);
302+ verifyItem(2, 25, 350., false);
303+ verifyItem(3, 375, 350., false);
304+ verifyItem(4, 725, 350., true);
305+ QCOMPARE(lvwph->m_minYExtent, 0.);
306+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
307+ QCOMPARE(lvwph->m_clipItem->clip(), false);
308+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
309+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
310+ QCOMPARE(lvwph->contentY(), 375.);
311+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
312+
313+ lvwph->positionAtBeginning();
314+
315+ verifyInitialTopPosition();
316+ }
317+
318+ void testPositionAtBeginningIndex0NotVisible()
319+ {
320+ changeContentY(520);
321+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
322+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
323+ verifyItem(0, -320., 200., true);
324+ verifyItem(1, -120, 350., false);
325+ verifyItem(2, 230, 350., false);
326+ verifyItem(3, 580, 350., true);
327+ QCOMPARE(lvwph->m_minYExtent, 162.5);
328+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
329+ QCOMPARE(lvwph->m_clipItem->clip(), false);
330+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
331+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
332+ QCOMPARE(lvwph->contentY(), 520.);
333+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
334+
335+ lvwph->positionAtBeginning();
336+
337+ verifyInitialTopPosition();
338+ }
339+
340+ void testIndex0GrowOnScreen()
341+ {
342+ model->setProperty(0, "size", 400);
343+
344+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
345+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
346+ verifyItem(0, 50., 400., false);
347+ verifyItem(1, 450., 200., false);
348+ verifyItem(2, 650., 350., true);
349+ QCOMPARE(lvwph->m_minYExtent, 0.);
350+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
351+ QCOMPARE(lvwph->m_clipItem->clip(), false);
352+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
353+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
354+ QCOMPARE(lvwph->contentY(), 0.);
355+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
356+ }
357+
358+ void testIndex0GrowOffScreen()
359+ {
360+ changeContentY(375);
361+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
362+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
363+ verifyItem(0, -325., 150., true);
364+ verifyItem(1, -175, 200., false);
365+ verifyItem(2, 25, 350., false);
366+ verifyItem(3, 375, 350., false);
367+ verifyItem(4, 725, 350., true);
368+ QCOMPARE(lvwph->m_minYExtent, 0.);
369+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
370+ QCOMPARE(lvwph->m_clipItem->clip(), false);
371+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
372+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
373+ QCOMPARE(lvwph->contentY(), 375.);
374+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
375+
376+ model->setProperty(0, "size", 400);
377+
378+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
379+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
380+ verifyItem(0, -575., 400., true);
381+ verifyItem(1, -175, 200., false);
382+ verifyItem(2, 25, 350., false);
383+ verifyItem(3, 375, 350., false);
384+ verifyItem(4, 725, 350., true);
385+ QCOMPARE(lvwph->m_minYExtent, 250.);
386+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
387+ QCOMPARE(lvwph->m_clipItem->clip(), false);
388+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
389+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
390+ QCOMPARE(lvwph->contentY(), 375.);
391+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
392+
393+ scrollToTop();
394+
395+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
396+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
397+ verifyItem(0, 50., 400., false);
398+ verifyItem(1, 450, 200., false);
399+ verifyItem(2, 650, 350., true);
400+ QCOMPARE(lvwph->m_minYExtent, 250.);
401+ QCOMPARE(lvwph->m_clipItem->y(), -250.);
402+ QCOMPARE(lvwph->m_clipItem->clip(), false);
403+ QCOMPARE(lvwph->m_headerItem->y(), -250.);
404+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
405+ QCOMPARE(lvwph->contentY(), -250.);
406+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
407+
408+ changeContentY(30);
409+
410+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
411+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
412+ verifyItem(0, 20., 400., false);
413+ verifyItem(1, 420, 200., false);
414+ verifyItem(2, 620, 350., true);
415+ QCOMPARE(lvwph->m_minYExtent, 250.);
416+ QCOMPARE(lvwph->m_clipItem->y(), -220.);
417+ QCOMPARE(lvwph->m_clipItem->clip(), false);
418+ QCOMPARE(lvwph->m_headerItem->y(), -250.);
419+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
420+ QCOMPARE(lvwph->contentY(), -220.);
421+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
422+ }
423+
424+ void testIndex0GrowNotCreated()
425+ {
426+ changeContentY(520);
427+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
428+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
429+ verifyItem(0, -320., 200., true);
430+ verifyItem(1, -120, 350., false);
431+ verifyItem(2, 230, 350., false);
432+ verifyItem(3, 580, 350., true);
433+ QCOMPARE(lvwph->m_minYExtent, 162.5);
434+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
435+ QCOMPARE(lvwph->m_clipItem->clip(), false);
436+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
437+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
438+ QCOMPARE(lvwph->contentY(), 520.);
439+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
440+
441+ model->setProperty(0, "size", 400);
442+
443+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
444+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
445+ verifyItem(0, -320., 200., true);
446+ verifyItem(1, -120, 350., false);
447+ verifyItem(2, 230, 350., false);
448+ verifyItem(3, 580, 350., true);
449+ QCOMPARE(lvwph->m_minYExtent, 162.5);
450+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
451+ QCOMPARE(lvwph->m_clipItem->clip(), false);
452+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
453+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
454+ QCOMPARE(lvwph->contentY(), 520.);
455+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
456+
457+ scrollToTop();
458+
459+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
460+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
461+ verifyItem(0, 50., 400., false);
462+ verifyItem(1, 450, 200., false);
463+ verifyItem(2, 650, 350., true);
464+ QCOMPARE(lvwph->m_minYExtent, 250.);
465+ QCOMPARE(lvwph->m_clipItem->y(), -250.);
466+ QCOMPARE(lvwph->m_clipItem->clip(), false);
467+ QCOMPARE(lvwph->m_headerItem->y(), -250.);
468+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
469+ QCOMPARE(lvwph->contentY(), -250.);
470+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
471+ }
472+
473+ void testShowHideShowHeaderAtBottom()
474+ {
475+ scrollToBottom();
476+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
477+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
478+ verifyItem(0, -508., 350., true);
479+ verifyItem(1, -158, 350., false);
480+ verifyItem(2, 192, 350., false);
481+ QCOMPARE(lvwph->m_minYExtent, 350.);
482+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
483+ QCOMPARE(lvwph->m_clipItem->clip(), false);
484+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
485+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
486+ QCOMPARE(lvwph->contentY(), 1258.);
487+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
488+
489+ changeContentY(-30);
490+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
491+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
492+ verifyItem(0, -508., 350., true);
493+ verifyItem(1, -158, 350., false);
494+ verifyItem(2, 192, 350., false);
495+ QCOMPARE(lvwph->m_minYExtent, 350.);
496+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
497+ QCOMPARE(lvwph->m_clipItem->clip(), true);
498+ QCOMPARE(lvwph->m_headerItem->y(), 1208.);
499+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
500+ QCOMPARE(lvwph->contentY(), 1228.);
501+ QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
502+
503+ changeContentY(30);
504+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
505+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
506+ verifyItem(0, -508., 350., true);
507+ verifyItem(1, -158, 350., false);
508+ verifyItem(2, 192, 350., false);
509+ QCOMPARE(lvwph->m_minYExtent, 350.);
510+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
511+ QCOMPARE(lvwph->m_clipItem->clip(), false);
512+ QCOMPARE(lvwph->m_headerItem->y(), -350.);
513+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
514+ QCOMPARE(lvwph->contentY(), 1258.);
515+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
516+
517+ changeContentY(-30);
518+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
519+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
520+ verifyItem(0, -508., 350., true);
521+ verifyItem(1, -158, 350., false);
522+ verifyItem(2, 192, 350., false);
523+ QCOMPARE(lvwph->m_minYExtent, 350.);
524+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
525+ QCOMPARE(lvwph->m_clipItem->clip(), true);
526+ QCOMPARE(lvwph->m_headerItem->y(), 1208.);
527+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
528+ QCOMPARE(lvwph->contentY(), 1228.);
529+ QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
530+ }
531+
532+ void testChangeDelegateAtBottom()
533+ {
534+ scrollToBottom();
535+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
536+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
537+ verifyItem(0, -508., 350., true);
538+ verifyItem(1, -158, 350., false);
539+ verifyItem(2, 192, 350., false);
540+ QCOMPARE(lvwph->m_minYExtent, 350.);
541+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
542+ QCOMPARE(lvwph->m_clipItem->clip(), false);
543+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
544+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
545+ QCOMPARE(lvwph->contentY(), 1258.);
546+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
547+
548+ lvwph->setDelegate(otherDelegate);
549+
550+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 6);
551+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
552+ verifyItem(0, 50., 35., false);
553+ verifyItem(1, 85, 35., false);
554+ verifyItem(2, 120, 35., false);
555+ verifyItem(3, 155, 35., false);
556+ verifyItem(4, 190, 35., false);
557+ verifyItem(5, 225, 35., false);
558+ QCOMPARE(lvwph->m_minYExtent, 0.);
559+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
560+ QCOMPARE(lvwph->m_clipItem->clip(), false);
561+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
562+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
563+ QCOMPARE(lvwph->contentY(), 0.);
564+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
565+ }
566+
567+ void testSetEmptyHeaderAtTop()
568+ {
569+ lvwph->setHeader(nullptr);
570+
571+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
572+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
573+ verifyItem(0, 0., 150., false);
574+ verifyItem(1, 150., 200., false);
575+ verifyItem(2, 350., 350., false);
576+ verifyItem(3, 700., 350., true);
577+ QCOMPARE(lvwph->m_minYExtent, 0.);
578+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
579+ QCOMPARE(lvwph->m_clipItem->clip(), false);
580+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
581+ QCOMPARE(lvwph->contentY(), 0.);
582+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
583+ }
584+
585+ void testSetEmptyHeaderAtBottom()
586+ {
587+ scrollToBottom();
588+ lvwph->setHeader(nullptr);
589+
590+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
591+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
592+ verifyItem(0, -508., 350., true);
593+ verifyItem(1, -158, 350., false);
594+ verifyItem(2, 192, 350., false);
595+ QCOMPARE(lvwph->m_minYExtent, 300.);
596+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
597+ QCOMPARE(lvwph->m_clipItem->clip(), false);
598+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
599+ QCOMPARE(lvwph->contentY(), 1258.);
600+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
601+
602+ scrollToTop();
603+
604+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
605+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
606+ verifyItem(0, 0., 150., false);
607+ verifyItem(1, 150., 200., false);
608+ verifyItem(2, 350., 350., false);
609+ verifyItem(3, 700., 350., true);
610+ QCOMPARE(lvwph->m_minYExtent, -50.);
611+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
612+ QCOMPARE(lvwph->m_clipItem->clip(), false);
613+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
614+ QCOMPARE(lvwph->contentY(), 50.);
615+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
616+ }
617+
618+ void testSetEmptyHeaderWhenPartlyShownClipped()
619+ {
620+ scrollToBottom();
621+ changeContentY(-30);
622+ lvwph->setHeader(nullptr);
623+
624+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
625+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
626+ verifyItem(0, -508., 350., true);
627+ verifyItem(1, -158, 350., false);
628+ verifyItem(2, 192, 350., false);
629+ QCOMPARE(lvwph->m_minYExtent, 330.);
630+ QCOMPARE(lvwph->m_clipItem->y(), 1228.);
631+ QCOMPARE(lvwph->m_clipItem->clip(), false);
632+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
633+ QCOMPARE(lvwph->contentY(), 1228.);
634+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
635+ QTRY_VERIFY(lvwph->isAtYEnd());
636+
637+ scrollToTop();
638+
639+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
640+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
641+ verifyItem(0, 0., 150., false);
642+ verifyItem(1, 150., 200., false);
643+ verifyItem(2, 350., 350., false);
644+ verifyItem(3, 700., 350., true);
645+ QCOMPARE(lvwph->m_minYExtent, -20.);
646+ QCOMPARE(lvwph->m_clipItem->y(), 20.);
647+ QCOMPARE(lvwph->m_clipItem->clip(), false);
648+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
649+ QCOMPARE(lvwph->contentY(), 20.);
650+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
651+ }
652+
653+ void testSetEmptyHeaderWhenPartlyShownNotClipped()
654+ {
655+ changeContentY(30);
656+ lvwph->setHeader(nullptr);
657+
658+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
659+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
660+ verifyItem(0, -30., 150., false);
661+ verifyItem(1, 120., 200., false);
662+ verifyItem(2, 320., 350., false);
663+ verifyItem(3, 670., 350., true);
664+ QCOMPARE(lvwph->m_minYExtent, 0.);
665+ QCOMPARE(lvwph->m_clipItem->y(), 30.);
666+ QCOMPARE(lvwph->m_clipItem->clip(), false);
667+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
668+ QCOMPARE(lvwph->contentY(), 30.);
669+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
670+ }
671+
672+ void testSetNullDelegate()
673+ {
674+ lvwph->setDelegate(nullptr);
675+
676+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
677+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
678+ QCOMPARE(lvwph->m_minYExtent, 0.);
679+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
680+ QCOMPARE(lvwph->m_clipItem->clip(), false);
681+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
682+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
683+ QCOMPARE(lvwph->contentY(), 0.);
684+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
685+ QTRY_COMPARE(lvwph->contentHeight(), 50.);
686+ QVERIFY(lvwph->isAtYBeginning());
687+ QVERIFY(lvwph->isAtYEnd());
688+ }
689+
690+ void testInsertItems()
691+ {
692+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100));
693+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125));
694+
695+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
696+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
697+ verifyItem(0, 50., 150., false);
698+ verifyItem(1, 200., 125., false);
699+ verifyItem(2, 325., 100., false);
700+ verifyItem(3, 425., 200., false);
701+ verifyItem(4, 625., 350., true);
702+ QCOMPARE(lvwph->m_minYExtent, 0.);
703+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
704+ QCOMPARE(lvwph->m_clipItem->clip(), false);
705+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
706+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
707+ QCOMPARE(lvwph->contentY(), 0.);
708+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
709+ }
710+
711+ void testInsertItemsOnNotShownPosition()
712+ {
713+ changeContentY(700);
714+
715+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
716+ QTRY_COMPARE(lvwph->m_firstVisibleIndex, 2);
717+ verifyItem(0, -300., 350., false);
718+ verifyItem(1, 50, 350., false);
719+ verifyItem(2, 400, 350., false);
720+ verifyItem(3, 750, 350., true);
721+ QCOMPARE(lvwph->m_minYExtent, 350.);
722+ QCOMPARE(lvwph->m_clipItem->y(), 700.);
723+ QCOMPARE(lvwph->m_clipItem->clip(), false);
724+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
725+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
726+ QCOMPARE(lvwph->contentY(), 700.);
727+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
728+
729+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100));
730+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125));
731+
732+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
733+ QCOMPARE(lvwph->m_firstVisibleIndex, 4);
734+ verifyItem(0, -300., 350., false);
735+ verifyItem(1, 50, 350., false);
736+ verifyItem(2, 400, 350., false);
737+ verifyItem(3, 750, 350., true);
738+ QCOMPARE(lvwph->m_minYExtent, 1050.);
739+ QCOMPARE(lvwph->m_clipItem->y(), 700.);
740+ QCOMPARE(lvwph->m_clipItem->clip(), false);
741+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
742+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
743+ QCOMPARE(lvwph->contentY(), 700.);
744+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
745+
746+ scrollToTop();
747+
748+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
749+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
750+ verifyItem(0, 50., 150., false);
751+ verifyItem(1, 200., 125., false);
752+ verifyItem(2, 325., 100., false);
753+ verifyItem(3, 425., 200., false);
754+ verifyItem(4, 625., 350., true);
755+ QCOMPARE(lvwph->m_minYExtent, 225.);
756+ QCOMPARE(lvwph->m_clipItem->y(), -225.);
757+ QCOMPARE(lvwph->m_clipItem->clip(), false);
758+ QCOMPARE(lvwph->m_headerItem->y(), -225.);
759+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
760+ QCOMPARE(lvwph->contentY(), -225.);
761+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
762+ }
763+
764+ void testInsertItemsAtEndOfViewport()
765+ {
766+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 3), Q_ARG(QVariant, 100));
767+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 3), Q_ARG(QVariant, 125));
768+
769+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
770+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
771+ verifyItem(0, 50., 150., false);
772+ verifyItem(1, 200., 200., false);
773+ verifyItem(2, 400., 350., false);
774+ verifyItem(3, 750., 125., true);
775+ QCOMPARE(lvwph->m_minYExtent, 0.);
776+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
777+ QCOMPARE(lvwph->m_clipItem->clip(), false);
778+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
779+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
780+ QCOMPARE(lvwph->contentY(), 0.);
781+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
782+ }
783+
784+ void testInsertItemsBeforeValidIndex()
785+ {
786+ changeContentY(520);
787+
788+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
789+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
790+ verifyItem(0, -320., 200., true);
791+ verifyItem(1, -120, 350., false);
792+ verifyItem(2, 230, 350., false);
793+ verifyItem(3, 580, 350., true);
794+ QCOMPARE(lvwph->m_minYExtent, 162.5);
795+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
796+ QCOMPARE(lvwph->m_clipItem->clip(), false);
797+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
798+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
799+ QCOMPARE(lvwph->contentY(), 520.);
800+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
801+
802+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100));
803+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125));
804+
805+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
806+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
807+ verifyItem(0, -320., 200., true);
808+ verifyItem(1, -120, 350., false);
809+ verifyItem(2, 230, 350., false);
810+ verifyItem(3, 580, 350., true);
811+ QCOMPARE(lvwph->m_minYExtent, 787.5);
812+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
813+ QCOMPARE(lvwph->m_clipItem->clip(), false);
814+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
815+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
816+ QCOMPARE(lvwph->contentY(), 520.);
817+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
818+ }
819+
820+ void testInsertItemsBeforeViewport()
821+ {
822+ changeContentY(375);
823+
824+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
825+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
826+ verifyItem(0, -325., 150., true);
827+ verifyItem(1, -175, 200., false);
828+ verifyItem(2, 25, 350., false);
829+ verifyItem(3, 375, 350., false);
830+ verifyItem(4, 725, 350., true);
831+ QCOMPARE(lvwph->m_minYExtent, 0.);
832+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
833+ QCOMPARE(lvwph->m_clipItem->clip(), false);
834+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
835+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
836+ QCOMPARE(lvwph->contentY(), 375.);
837+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
838+
839+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100));
840+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125));
841+
842+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
843+ QCOMPARE(lvwph->m_firstVisibleIndex, 2);
844+ verifyItem(0, -275., 100., true);
845+ verifyItem(1, -175, 200., false);
846+ verifyItem(2, 25, 350., false);
847+ verifyItem(3, 375, 350., false);
848+ verifyItem(4, 725, 350., true);
849+ QCOMPARE(lvwph->m_minYExtent, 490.);
850+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
851+ QCOMPARE(lvwph->m_clipItem->clip(), false);
852+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
853+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
854+ QCOMPARE(lvwph->contentY(), 375.);
855+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
856+
857+ scrollToTop();
858+
859+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
860+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
861+ verifyItem(0, 50., 150., false);
862+ verifyItem(1, 200., 125., false);
863+ verifyItem(2, 325., 100., false);
864+ verifyItem(3, 425., 200., false);
865+ verifyItem(4, 625., 350., true);
866+ QCOMPARE(lvwph->m_minYExtent, 225.);
867+ QCOMPARE(lvwph->m_clipItem->y(), -225.);
868+ QCOMPARE(lvwph->m_clipItem->clip(), false);
869+ QCOMPARE(lvwph->m_headerItem->y(), -225.);
870+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
871+ QCOMPARE(lvwph->contentY(), -225.);
872+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
873+ }
874+
875+ void testInsertItemsAtBottom()
876+ {
877+ scrollToBottom();
878+
879+ QVERIFY(lvwph->isAtYEnd());
880+
881+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 100));
882+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 125));
883+
884+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
885+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
886+ verifyItem(0, -508., 350., true);
887+ verifyItem(1, -158, 350., false);
888+ verifyItem(2, 192, 350., false);
889+ verifyItem(3, 542, 125., true);
890+ verifyItem(4, 667, 100., true);
891+ QCOMPARE(lvwph->m_minYExtent, 65.);
892+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
893+ QCOMPARE(lvwph->m_clipItem->clip(), false);
894+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
895+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
896+ QCOMPARE(lvwph->contentY(), 1258.);
897+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
898+ QVERIFY(!lvwph->isAtYEnd());
899+
900+ scrollToBottom();
901+
902+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
903+ QCOMPARE(lvwph->m_firstVisibleIndex, 4);
904+ verifyItem(0, -383., 350., true);
905+ verifyItem(1, -33, 350., false);
906+ verifyItem(2, 317, 125., false);
907+ verifyItem(3, 442, 100., false);
908+ QCOMPARE(lvwph->m_minYExtent, -125.);
909+ QCOMPARE(lvwph->m_clipItem->y(), 1483.);
910+ QCOMPARE(lvwph->m_clipItem->clip(), false);
911+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
912+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
913+ QCOMPARE(lvwph->contentY(), 1483.);
914+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
915+ QVERIFY(lvwph->isAtYEnd());
916+ }
917+
918+ void testInsertItemAtTop()
919+ {
920+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
921+
922+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
923+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
924+ verifyItem(0, 50., 75., false);
925+ verifyItem(1, 125., 150., false);
926+ verifyItem(2, 275., 200., false);
927+ verifyItem(3, 475., 350., false);
928+ QCOMPARE(lvwph->m_minYExtent, 0.);
929+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
930+ QCOMPARE(lvwph->m_clipItem->clip(), false);
931+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
932+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
933+ QCOMPARE(lvwph->contentY(), 0.);
934+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
935+ QVERIFY(lvwph->isAtYBeginning());
936+ }
937+
938+ void testInsertItem10SmallItemsAtTopWhenAtBottom()
939+ {
940+ scrollToBottom();
941+
942+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
943+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
944+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
945+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
946+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
947+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
948+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
949+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
950+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
951+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75));
952+
953+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
954+ QCOMPARE(lvwph->m_firstVisibleIndex, 13);
955+ verifyItem(0, -508., 350., true);
956+ verifyItem(1, -158, 350., false);
957+ verifyItem(2, 192, 350., false);
958+ QCOMPARE(lvwph->m_minYExtent, 3850.);
959+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
960+ QCOMPARE(lvwph->m_clipItem->clip(), false);
961+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
962+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
963+ QCOMPARE(lvwph->contentY(), 1258.);
964+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
965+
966+ changeContentY(-1700);
967+
968+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 12);
969+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
970+ verifyItem(0, -308., 75., true);
971+ verifyItem(1, -233., 75., true);
972+ verifyItem(2, -158., 75., true);
973+ verifyItem(3, -83., 75., true);
974+ verifyItem(4, -8., 75., false);
975+ verifyItem(5, 67., 75., false);
976+ verifyItem(6, 142., 75., false);
977+ verifyItem(7, 217., 75., false);
978+ verifyItem(8, 292., 75., false);
979+ verifyItem(9, 367., 75., false);
980+ verifyItem(10, 442., 150., false);
981+ verifyItem(11, 592., 200., true);
982+ QCOMPARE(lvwph->m_minYExtent, 750.);
983+ QCOMPARE(lvwph->m_clipItem->y(), -392.);
984+ QCOMPARE(lvwph->m_clipItem->clip(), true);
985+ QCOMPARE(lvwph->m_headerItem->y(), -442.);
986+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
987+ QCOMPARE(lvwph->contentY(), -442.);
988+ QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
989+ }
990+
991+ void testRemoveItemsAtTop()
992+ {
993+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
994+
995+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
996+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
997+ verifyItem(0, 50., 350., false);
998+ verifyItem(1, 400., 350., false);
999+ verifyItem(2, 750., 350., true);
1000+ QCOMPARE(lvwph->m_minYExtent, 0.);
1001+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1002+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1003+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1004+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1005+ QCOMPARE(lvwph->contentY(), 0.);
1006+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1007+ QVERIFY(lvwph->isAtYBeginning());
1008+ }
1009+
1010+ void testRemoveNonCreatedItemsAtTopWhenAtBottom()
1011+ {
1012+ scrollToBottom();
1013+
1014+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
1015+
1016+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1017+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1018+ verifyItem(0, -508., 350., true);
1019+ verifyItem(1, -158, 350., false);
1020+ verifyItem(2, 192, 350., false);
1021+ QCOMPARE(lvwph->m_minYExtent, -350.);
1022+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
1023+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1024+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1025+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1026+ QCOMPARE(lvwph->contentY(), 1258.);
1027+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1028+ }
1029+
1030+ void testRemoveLastItemsAtBottom()
1031+ {
1032+ scrollToBottom();
1033+
1034+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 4), Q_ARG(QVariant, 2));
1035+
1036+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1037+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1038+ verifyItem(0, -358., 200., true);
1039+ verifyItem(1, -158, 350., false);
1040+ verifyItem(2, 192, 350., false);
1041+ QCOMPARE(lvwph->m_minYExtent, 150.);
1042+ QCOMPARE(lvwph->m_clipItem->y(), 558.);
1043+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1044+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1045+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1046+ QCOMPARE(lvwph->contentY(), 558.);
1047+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1048+ }
1049+
1050+ void testRemoveItemOutOfViewport()
1051+ {
1052+ changeContentY(520);
1053+
1054+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1055+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1056+ verifyItem(0, -320., 200., true);
1057+ verifyItem(1, -120, 350., false);
1058+ verifyItem(2, 230, 350., false);
1059+ verifyItem(3, 580, 350., true);
1060+ QCOMPARE(lvwph->m_minYExtent, 162.5);
1061+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
1062+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1063+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1064+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1065+ QCOMPARE(lvwph->contentY(), 520.);
1066+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1067+
1068+
1069+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 1), Q_ARG(QVariant, 1));
1070+
1071+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1072+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1073+ verifyItem(0, -270., 150., true);
1074+ verifyItem(1, -120., 350., false);
1075+ verifyItem(2, 230, 350., false);
1076+ verifyItem(3, 580, 350., true);
1077+ QCOMPARE(lvwph->m_minYExtent, -200.);
1078+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
1079+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1080+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1081+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1082+ QCOMPARE(lvwph->contentY(), 520.);
1083+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1084+ }
1085+
1086+ void testMoveFirstItems()
1087+ {
1088+ QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 1), Q_ARG(QVariant, 1));
1089+
1090+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1091+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1092+ verifyItem(0, 50., 200., false);
1093+ verifyItem(1, 250., 150., false);
1094+ verifyItem(2, 400., 350., false);
1095+ verifyItem(3, 750., 350., true);
1096+ QCOMPARE(lvwph->m_minYExtent, 0.);
1097+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1098+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1099+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1100+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1101+ QCOMPARE(lvwph->contentY(), 0.);
1102+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1103+
1104+ }
1105+
1106+ void testMoveFirstOutOfVisibleItems()
1107+ {
1108+ QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 4), Q_ARG(QVariant, 1));
1109+
1110+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1111+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1112+ verifyItem(0, 50., 200., false);
1113+ verifyItem(1, 250., 350., false);
1114+ verifyItem(2, 600., 350., true);
1115+ QCOMPARE(lvwph->m_minYExtent, 0.);
1116+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1117+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1118+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1119+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1120+ QCOMPARE(lvwph->contentY(), 0.);
1121+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1122+
1123+ }
1124+
1125+ void testMoveFirstToLastAtBottom()
1126+ {
1127+ scrollToBottom();
1128+
1129+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1130+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
1131+ verifyItem(0, -508., 350., true);
1132+ verifyItem(1, -158, 350., false);
1133+ verifyItem(2, 192, 350., false);
1134+ QCOMPARE(lvwph->m_minYExtent, 350.);
1135+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
1136+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1137+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1138+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1139+ QCOMPARE(lvwph->contentY(), 1258.);
1140+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1141+
1142+ QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 5), Q_ARG(QVariant, 1));
1143+
1144+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1145+ QCOMPARE(lvwph->m_firstVisibleIndex, 2);
1146+ verifyItem(0, -508., 350., true);
1147+ verifyItem(1, -158, 350., false);
1148+ verifyItem(2, 192, 350., false);
1149+ verifyItem(3, 542, 150., true);
1150+ QCOMPARE(lvwph->m_minYExtent, -100.);
1151+ QCOMPARE(lvwph->m_clipItem->y(), 1258.);
1152+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1153+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1154+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1155+ QCOMPARE(lvwph->contentY(), 1258.);
1156+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1157+ QVERIFY(!lvwph->isAtYEnd());
1158+ }
1159+
1160+ void testChangeSizeVisibleItemNotOnViewport()
1161+ {
1162+ changeContentY(440);
1163+
1164+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1165+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1166+ verifyItem(0, -390., 150., true);
1167+ verifyItem(1, -240., 200., true);
1168+ verifyItem(2, -40, 350., false);
1169+ verifyItem(3, 310, 350., false);
1170+ verifyItem(4, 660, 350., true);
1171+ QCOMPARE(lvwph->m_minYExtent, 0.);
1172+ QCOMPARE(lvwph->m_clipItem->y(), 440.);
1173+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1174+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1175+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1176+ QCOMPARE(lvwph->contentY(), 440.);
1177+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1178+
1179+ model->setProperty(1, "size", 100);
1180+
1181+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1182+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1183+ verifyItem(0, -290., 150., true);
1184+ verifyItem(1, -140., 100., true);
1185+ verifyItem(2, -40, 350., false);
1186+ verifyItem(3, 310, 350., false);
1187+ verifyItem(4, 660, 350., true);
1188+ QCOMPARE(lvwph->m_minYExtent, -100.);
1189+ QCOMPARE(lvwph->m_clipItem->y(), 440.);
1190+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1191+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1192+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1193+ QCOMPARE(lvwph->contentY(), 440.);
1194+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1195+ }
1196+
1197+ void testShowHeaderCloseToTheTop()
1198+ {
1199+ changeContentY(375);
1200+
1201+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1202+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1203+ verifyItem(0, -325., 150., true);
1204+ verifyItem(1, -175, 200., false);
1205+ verifyItem(2, 25, 350., false);
1206+ verifyItem(3, 375, 350., false);
1207+ verifyItem(4, 725, 350., true);
1208+ QCOMPARE(lvwph->m_minYExtent, 0.);
1209+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
1210+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1211+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1212+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1213+ QCOMPARE(lvwph->contentY(), 375.);
1214+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1215+
1216+ lvwph->showHeader();
1217+
1218+ QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1219+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1220+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1221+ verifyItem(0, -375., 150., true);
1222+ verifyItem(1, -225, 200., true);
1223+ verifyItem(2, -25, 350., false);
1224+ verifyItem(3, 325, 350., false);
1225+ verifyItem(4, 675, 350., true);
1226+ QCOMPARE(lvwph->m_minYExtent, 50.);
1227+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
1228+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1229+ QCOMPARE(lvwph->m_headerItem->y(), 325.);
1230+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1231+ QCOMPARE(lvwph->contentY(), 325.);
1232+ QCOMPARE(lvwph->m_headerItemShownHeight, 50.);;
1233+
1234+ scrollToTop();
1235+
1236+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1237+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1238+ verifyItem(0, 50., 150., false);
1239+ verifyItem(1, 200., 200., false);
1240+ verifyItem(2, 400., 350., false);
1241+ verifyItem(3, 750., 350., true);
1242+ QCOMPARE(lvwph->m_minYExtent, 50.);
1243+ QCOMPARE(lvwph->m_clipItem->y(), -50.);
1244+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1245+ QCOMPARE(lvwph->m_headerItem->y(), -50.);
1246+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1247+ QCOMPARE(lvwph->contentY(), -50.);
1248+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1249+ }
1250+
1251+ void testShowHeaderAtBottom()
1252+ {
1253+ scrollToBottom();
1254+
1255+ lvwph->showHeader();
1256+
1257+ QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1258+ QTRY_VERIFY (lvwph->isAtYEnd());
1259+ }
1260+
1261+ void growWindow()
1262+ {
1263+ view->rootObject()->setHeight(850);
1264+
1265+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1266+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1267+ verifyItem(0, 50., 150., false);
1268+ verifyItem(1, 200., 200., false);
1269+ verifyItem(2, 400., 350., false);
1270+ verifyItem(3, 750., 350., false);
1271+ verifyItem(4, 1100., 350., true);
1272+ QCOMPARE(lvwph->m_minYExtent, 0.);
1273+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1274+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1275+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1276+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1277+ QCOMPARE(lvwph->contentY(), 0.);
1278+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1279+ }
1280+
1281+ void growWindowAtBottom()
1282+ {
1283+ scrollToBottom();
1284+
1285+ view->rootObject()->setHeight(850);
1286+
1287+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1288+ QCOMPARE(lvwph->m_firstVisibleIndex, 2);
1289+ verifyItem(0, -550., 350., true);
1290+ verifyItem(1, -200., 350., false);
1291+ verifyItem(2, 150, 350., false);
1292+ verifyItem(3, 500, 350., false);
1293+ QCOMPARE(lvwph->m_minYExtent, 350.);
1294+ QCOMPARE(lvwph->m_clipItem->y(), 950.);
1295+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1296+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1297+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1298+ QCOMPARE(lvwph->contentY(), 950.);
1299+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1300+ }
1301+
1302+ void testCrashShowHeaderWithNoHeader()
1303+ {
1304+ lvwph->setHeader(nullptr);
1305+ lvwph->showHeader();
1306+ }
1307+
1308+private:
1309+ QQuickView *view;
1310+ ListViewWithPageHeader *lvwph;
1311+ QQuickListModel *model;
1312+ QQmlComponent *otherDelegate;
1313+};
1314+
1315+QTEST_MAIN(ListViewWithPageHeaderTest)
1316+
1317+#include "listviewwithpageheadertest.moc"
tests/plugins/ListViewWithPageHeader/listviewwithpageheadertestsection.cppnew file+1567
@@ -0,0 +1,1567 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "listviewwithpageheader.h"
18+
19+#include <QAbstractItemModel>
20+#include <QQmlEngine>
21+#include <QQuickView>
22+#include <QtTestGui>
23+#include <private/qquicklistmodel_p.h>
24+#include <private/qquickanimation_p.h>
25+#include <private/qquickitem_p.h>
26+
27+class ListViewWithPageHeaderTestSection : public QObject
28+{
29+ Q_OBJECT
30+
31+private:
32+ void verifyItem(int visibleIndex, qreal pos, qreal height, bool culled, const QString &sectionHeader, bool sectionHeaderCulled)
33+ {
34+ QTRY_VERIFY(visibleIndex < lvwph->m_visibleItems.count());
35+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->y(), pos);
36+ QTRY_COMPARE(lvwph->m_visibleItems[visibleIndex]->height(), height);
37+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_item)->culled, culled);
38+ QCOMPARE(section(lvwph->m_visibleItems[visibleIndex]->m_sectionItem), sectionHeader);
39+ if (!sectionHeader.isNull()) {
40+ QCOMPARE(QQuickItemPrivate::get(lvwph->m_visibleItems[visibleIndex]->m_sectionItem)->culled, sectionHeaderCulled);
41+ }
42+ }
43+
44+ void changeContentY(qreal change)
45+ {
46+ const qreal dest = lvwph->contentY() + change;
47+ if (dest > lvwph->contentY()) {
48+ const qreal jump = 25;
49+ while (lvwph->contentY() + jump < dest) {
50+ lvwph->setContentY(lvwph->contentY() + jump);
51+ QTest::qWait(1);
52+ }
53+ } else {
54+ const qreal jump = -25;
55+ while (lvwph->contentY() + jump > dest) {
56+ lvwph->setContentY(lvwph->contentY() + jump);
57+ QTest::qWait(1);
58+ }
59+ }
60+ lvwph->setContentY(dest);
61+ QTest::qWait(1);
62+ }
63+
64+ void scrollToTop()
65+ {
66+ const qreal jump = -25;
67+ while (!lvwph->isAtYBeginning()) {
68+ if (lvwph->contentY() + jump > -lvwph->minYExtent()) {
69+ lvwph->setContentY(lvwph->contentY() + jump);
70+ } else {
71+ lvwph->setContentY(lvwph->contentY() - 1);
72+ }
73+ QTest::qWait(1);
74+ }
75+ }
76+
77+ void scrollToBottom()
78+ {
79+ const qreal jump = 25;
80+ while (!lvwph->isAtYEnd()) {
81+ if (lvwph->contentY() + lvwph->height() + jump < lvwph->contentHeight()) {
82+ lvwph->setContentY(lvwph->contentY() + jump);
83+ } else {
84+ lvwph->setContentY(lvwph->contentY() + 1);
85+ }
86+ QTest::qWait(1);
87+ }
88+ }
89+
90+ void verifyInitialTopPosition()
91+ {
92+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
93+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
94+ verifyItem(0, 50., 190., false, "Agressive", false);
95+ verifyItem(1, 240., 240., false, "Regular", false);
96+ verifyItem(2, 480., 390., false, "Mild", false);
97+ QCOMPARE(lvwph->m_minYExtent, 0.);
98+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
99+ QCOMPARE(lvwph->m_clipItem->clip(), false);
100+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
101+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
102+ QCOMPARE(lvwph->contentY(), 0.);
103+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
104+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
105+ }
106+
107+ QString section(QQuickItem *item)
108+ {
109+ return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
110+ }
111+
112+private Q_SLOTS:
113+
114+ void initTestCase()
115+ {
116+ }
117+
118+ void init()
119+ {
120+ view = new QQuickView();
121+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
122+ view->setSource(QUrl::fromLocalFile(LISTVIEWWITHPAGEHEADER_FOLDER "/test_section.qml"));
123+ lvwph = dynamic_cast<ListViewWithPageHeader*>(view->rootObject()->findChild<QQuickFlickable*>());
124+ model = view->rootObject()->findChild<QQuickListModel*>();
125+ otherDelegate = view->rootObject()->findChild<QQmlComponent*>();
126+ QVERIFY(lvwph);
127+ QVERIFY(model);
128+ QVERIFY(otherDelegate);
129+ view->show();
130+ QTest::qWaitForWindowExposed(view);
131+
132+ verifyInitialTopPosition();
133+ }
134+
135+ void cleanup()
136+ {
137+ delete view;
138+ }
139+
140+ void testCreationDeletion()
141+ {
142+ // Nothing, init/cleanup already tests this
143+ }
144+
145+ void testDrag1PixelUp()
146+ {
147+ lvwph->setContentY(lvwph->contentY() + 1);
148+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
149+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
150+ verifyItem(0, 49., 190., false, "Agressive", false);
151+ verifyItem(1, 239., 240., false, "Regular", false);
152+ verifyItem(2, 479., 390., false, "Mild", false);
153+ QCOMPARE(lvwph->m_minYExtent, 0.);
154+ QCOMPARE(lvwph->m_clipItem->y(), 1.);
155+ QCOMPARE(lvwph->m_clipItem->clip(), false);
156+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
157+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
158+ QCOMPARE(lvwph->contentY(), 1.);
159+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
160+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
161+ }
162+
163+ void testHeaderDetachDragDown()
164+ {
165+ QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 0));
166+ QTest::qWait(100);
167+ QTest::mouseMove(view, QPoint(0, 5));
168+ QTest::qWait(100);
169+ QTest::mouseMove(view, QPoint(0, 10));
170+ QTest::qWait(100);
171+ QTest::mouseMove(view, QPoint(0, 15));
172+ QTest::qWait(100);
173+ QTest::mouseMove(view, QPoint(0, 20));
174+ QTest::qWait(100);
175+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
176+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
177+ verifyItem(0, 55., 190., false, "Agressive", false);
178+ verifyItem(1, 245., 240., false, "Regular", false);
179+ verifyItem(2, 485., 390., false, "Mild", false);
180+ QCOMPARE(lvwph->m_minYExtent, 0.);
181+ QCOMPARE(lvwph->m_clipItem->y(), -5.);
182+ QCOMPARE(lvwph->m_clipItem->clip(), false);
183+ QCOMPARE(lvwph->m_headerItem->y(), -5.);
184+ QCOMPARE(lvwph->m_headerItem->height(), 55.);
185+ QCOMPARE(lvwph->contentY(), -5.);
186+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
187+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
188+
189+ QTest::mouseRelease(view, Qt::LeftButton, Qt::NoModifier, QPoint(0, 15));
190+
191+ verifyInitialTopPosition();
192+ }
193+
194+ void testDrag375PixelUp()
195+ {
196+ changeContentY(375);
197+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
198+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
199+ verifyItem(0, -325., 190., true, "Agressive", true);
200+ verifyItem(1, -135, 240., false, "Regular", true);
201+ verifyItem(2, 105, 390., false, "Mild", false);
202+ verifyItem(3, 495, 390., false, "Bold", false);
203+ QCOMPARE(lvwph->m_minYExtent, 0.);
204+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
205+ QCOMPARE(lvwph->m_clipItem->clip(), false);
206+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
207+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
208+ QCOMPARE(lvwph->contentY(), 375.);
209+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
210+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
211+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
212+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
213+ }
214+
215+ void testDrag520PixelUp()
216+ {
217+ changeContentY(520);
218+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
219+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
220+ verifyItem(0, -280., 240., true, "Regular", true);
221+ verifyItem(1, -40, 390., false, "Mild", true);
222+ verifyItem(2, 350, 390., false, "Bold", false);
223+ verifyItem(3, 740, 350., true, QString(), true);
224+ QCOMPARE(lvwph->m_minYExtent, 152.5);
225+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
226+ QCOMPARE(lvwph->m_clipItem->clip(), false);
227+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
228+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
229+ QCOMPARE(lvwph->contentY(), 520.);
230+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
231+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
232+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
233+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
234+ }
235+
236+ void testDragHeaderUpThenShow()
237+ {
238+ changeContentY(120);
239+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
240+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
241+ verifyItem(0, -70., 190., false, "Agressive", true);
242+ verifyItem(1, 120., 240., false, "Regular", false);
243+ verifyItem(2, 360., 390., false, "Mild", false);
244+ verifyItem(3, 750., 390., true, "Bold", true);
245+ QCOMPARE(lvwph->m_minYExtent, 0.);
246+ QCOMPARE(lvwph->m_clipItem->y(), 120.);
247+ QCOMPARE(lvwph->m_clipItem->clip(), false);
248+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
249+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
250+ QCOMPARE(lvwph->contentY(), 120.);
251+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
252+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
253+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
254+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
255+
256+ changeContentY(-30);
257+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
258+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
259+ verifyItem(0, -70., 190., false, "Agressive", true);
260+ verifyItem(1, 120., 240., false, "Regular", false);
261+ verifyItem(2, 360., 390., false, "Mild", false);
262+ verifyItem(3, 750., 390., true, "Bold", true);
263+ QCOMPARE(lvwph->m_minYExtent, 0.);
264+ QCOMPARE(lvwph->m_clipItem->y(), 120.);
265+ QCOMPARE(lvwph->m_clipItem->clip(), true);
266+ QTRY_COMPARE(lvwph->m_headerItem->y(), 70.);
267+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
268+ QCOMPARE(lvwph->contentY(), 90.);
269+ QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
270+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
271+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
272+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
273+ }
274+
275+ void testDragHeaderUpThenShowWithoutHidingTotally()
276+ {
277+ changeContentY(10);
278+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
279+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
280+ verifyItem(0, 40., 190., false, "Agressive", false);
281+ verifyItem(1, 230., 240., false, "Regular", false);
282+ verifyItem(2, 470., 390., false, "Mild", false);
283+ QCOMPARE(lvwph->m_minYExtent, 0.);
284+ QCOMPARE(lvwph->m_clipItem->y(), 10.);
285+ QCOMPARE(lvwph->m_clipItem->clip(), false);
286+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
287+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
288+ QCOMPARE(lvwph->contentY(), 10.);
289+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
290+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
291+
292+ changeContentY(-1);
293+
294+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
295+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
296+ verifyItem(0, 41., 190., false, "Agressive", false);
297+ verifyItem(1, 231., 240., false, "Regular", false);
298+ verifyItem(2, 471., 390., false, "Mild", false);
299+ QCOMPARE(lvwph->m_minYExtent, 0.);
300+ QCOMPARE(lvwph->m_clipItem->y(), 9.);
301+ QCOMPARE(lvwph->m_clipItem->clip(), false);
302+ QTRY_COMPARE(lvwph->m_headerItem->y(), 0.);
303+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
304+ QCOMPARE(lvwph->contentY(), 9.);
305+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
306+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
307+ }
308+
309+ void testPositionAtBeginningIndex0Visible()
310+ {
311+ changeContentY(375);
312+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
313+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
314+ verifyItem(0, -325., 190., true, "Agressive", true);
315+ verifyItem(1, -135, 240., false, "Regular", true);
316+ verifyItem(2, 105, 390., false, "Mild", false);
317+ verifyItem(3, 495, 390., false, "Bold", false);
318+ QCOMPARE(lvwph->m_minYExtent, 0.);
319+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
320+ QCOMPARE(lvwph->m_clipItem->clip(), false);
321+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
322+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
323+ QCOMPARE(lvwph->contentY(), 375.);
324+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
325+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
326+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
327+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
328+
329+ lvwph->positionAtBeginning();
330+
331+ verifyInitialTopPosition();
332+ }
333+
334+ void testPositionAtBeginningIndex0NotVisible()
335+ {
336+ changeContentY(520);
337+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
338+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
339+ verifyItem(0, -280., 240., true, "Regular", true);
340+ verifyItem(1, -40, 390., false, "Mild", true);
341+ verifyItem(2, 350, 390., false, "Bold", false);
342+ verifyItem(3, 740, 350., true, QString(), true);
343+ QCOMPARE(lvwph->m_minYExtent, 152.5);
344+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
345+ QCOMPARE(lvwph->m_clipItem->clip(), false);
346+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
347+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
348+ QCOMPARE(lvwph->contentY(), 520.);
349+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
350+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
351+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
352+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
353+
354+ lvwph->positionAtBeginning();
355+
356+ verifyInitialTopPosition();
357+ }
358+
359+ void testIndex0GrowOnScreen()
360+ {
361+ model->setProperty(0, "size", 400);
362+
363+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
364+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
365+ verifyItem(0, 50., 440., false, "Agressive", false);
366+ verifyItem(1, 490., 240., false, "Regular", false);
367+ verifyItem(2, 730., 390., true, "Mild", true);
368+ QCOMPARE(lvwph->m_minYExtent, 0.);
369+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
370+ QCOMPARE(lvwph->m_clipItem->clip(), false);
371+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
372+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
373+ QCOMPARE(lvwph->contentY(), 0.);
374+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
375+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
376+ }
377+
378+ void testIndex0GrowOffScreen()
379+ {
380+ changeContentY(375);
381+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
382+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
383+ verifyItem(0, -325., 190., true, "Agressive", true);
384+ verifyItem(1, -135, 240., false, "Regular", true);
385+ verifyItem(2, 105, 390., false, "Mild", false);
386+ verifyItem(3, 495, 390., false, "Bold", false);
387+ QCOMPARE(lvwph->m_minYExtent, 0.);
388+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
389+ QCOMPARE(lvwph->m_clipItem->clip(), false);
390+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
391+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
392+ QCOMPARE(lvwph->contentY(), 375.);
393+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
394+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
395+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
396+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
397+
398+ model->setProperty(0, "size", 400);
399+
400+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
401+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
402+ verifyItem(0, -575., 440., true, "Agressive", true);
403+ verifyItem(1, -135, 240., false, "Regular", true);
404+ verifyItem(2, 105, 390., false, "Mild", false);
405+ verifyItem(3, 495, 390., false, "Bold", false);
406+ QCOMPARE(lvwph->m_minYExtent, 250.);
407+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
408+ QCOMPARE(lvwph->m_clipItem->clip(), false);
409+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
410+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
411+ QCOMPARE(lvwph->contentY(), 375.);
412+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
413+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
414+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
415+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
416+
417+ scrollToTop();
418+
419+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
420+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
421+ verifyItem(0, 50., 440., false, "Agressive", false);
422+ verifyItem(1, 490, 240., false, "Regular", false);
423+ verifyItem(2, 730, 390., true, "Mild", true);
424+ QCOMPARE(lvwph->m_minYExtent, 250.);
425+ QCOMPARE(lvwph->m_clipItem->y(), -250.);
426+ QCOMPARE(lvwph->m_clipItem->clip(), false);
427+ QCOMPARE(lvwph->m_headerItem->y(), -250.);
428+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
429+ QCOMPARE(lvwph->contentY(), -250.);
430+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
431+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
432+
433+ changeContentY(30);
434+
435+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
436+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
437+ verifyItem(0, 20., 440., false, "Agressive", false);
438+ verifyItem(1, 460, 240., false, "Regular", false);
439+ verifyItem(2, 700, 390., true, "Mild", true);
440+ QCOMPARE(lvwph->m_minYExtent, 250.);
441+ QCOMPARE(lvwph->m_clipItem->y(), -220.);
442+ QCOMPARE(lvwph->m_clipItem->clip(), false);
443+ QCOMPARE(lvwph->m_headerItem->y(), -250.);
444+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
445+ QCOMPARE(lvwph->contentY(), -220.);
446+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
447+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
448+ }
449+
450+ void testIndex0GrowNotCreated()
451+ {
452+ changeContentY(520);
453+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
454+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
455+ verifyItem(0, -280., 240., true, "Regular", true);
456+ verifyItem(1, -40, 390., false, "Mild", true);
457+ verifyItem(2, 350, 390., false, "Bold", false);
458+ verifyItem(3, 740, 350., true, QString(), true);
459+ QCOMPARE(lvwph->m_minYExtent, 152.5);
460+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
461+ QCOMPARE(lvwph->m_clipItem->clip(), false);
462+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
463+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
464+ QCOMPARE(lvwph->contentY(), 520.);
465+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
466+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
467+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
468+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
469+
470+ model->setProperty(0, "size", 400);
471+
472+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
473+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
474+ verifyItem(0, -280., 240., true, "Regular", true);
475+ verifyItem(1, -40, 390., false, "Mild", true);
476+ verifyItem(2, 350, 390., false, "Bold", false);
477+ verifyItem(3, 740, 350., true, QString(), true);
478+ QCOMPARE(lvwph->m_minYExtent, 152.5);
479+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
480+ QCOMPARE(lvwph->m_clipItem->clip(), false);
481+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
482+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
483+ QCOMPARE(lvwph->contentY(), 520.);
484+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
485+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
486+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
487+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
488+
489+ scrollToTop();
490+
491+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
492+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
493+ verifyItem(0, 50., 440., false, "Agressive", false);
494+ verifyItem(1, 490, 240., false, "Regular", false);
495+ verifyItem(2, 730, 390., true, "Mild", true);
496+ QCOMPARE(lvwph->m_minYExtent, 250.);
497+ QCOMPARE(lvwph->m_clipItem->y(), -250.);
498+ QCOMPARE(lvwph->m_clipItem->clip(), false);
499+ QCOMPARE(lvwph->m_headerItem->y(), -250.);
500+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
501+ QCOMPARE(lvwph->contentY(), -250.);
502+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
503+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
504+ }
505+
506+ void testShowHideShowHeaderAtBottom()
507+ {
508+ scrollToBottom();
509+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
510+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
511+ verifyItem(0, -588., 390., true, "Bold", true);
512+ verifyItem(1, -198, 350., false, QString(), true);
513+ verifyItem(2, 152, 390., false, "Lazy", false);
514+ QCOMPARE(lvwph->m_minYExtent, 310.);
515+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
516+ QCOMPARE(lvwph->m_clipItem->clip(), false);
517+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
518+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
519+ QCOMPARE(lvwph->contentY(), 1458.);
520+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
521+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
522+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
523+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
524+
525+ changeContentY(-30);
526+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
527+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
528+ verifyItem(0, -588., 390., true, "Bold", true);
529+ verifyItem(1, -198, 350., false, QString(), true);
530+ verifyItem(2, 152, 390., false, "Lazy", false);
531+ QCOMPARE(lvwph->m_minYExtent, 310.);
532+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
533+ QCOMPARE(lvwph->m_clipItem->clip(), true);
534+ QCOMPARE(lvwph->m_headerItem->y(), 1408.);
535+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
536+ QCOMPARE(lvwph->contentY(), 1428.);
537+ QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
538+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
539+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
540+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
541+
542+ changeContentY(30);
543+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
544+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
545+ verifyItem(0, -588., 390., true, "Bold", true);
546+ verifyItem(1, -198, 350., false, QString(), true);
547+ verifyItem(2, 152, 390., false, "Lazy", false);
548+ QCOMPARE(lvwph->m_minYExtent, 310.);
549+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
550+ QCOMPARE(lvwph->m_clipItem->clip(), false);
551+ QCOMPARE(lvwph->m_headerItem->y(), -310.);
552+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
553+ QCOMPARE(lvwph->contentY(), 1458.);
554+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
555+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
556+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
557+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
558+
559+ changeContentY(-30);
560+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
561+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
562+ verifyItem(0, -588., 390., true, "Bold", true);
563+ verifyItem(1, -198, 350., false, QString(), true);
564+ verifyItem(2, 152, 390., false, "Lazy", false);
565+ QCOMPARE(lvwph->m_minYExtent, 310.);
566+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
567+ QCOMPARE(lvwph->m_clipItem->clip(), true);
568+ QCOMPARE(lvwph->m_headerItem->y(), 1408.);
569+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
570+ QCOMPARE(lvwph->contentY(), 1428.);
571+ QCOMPARE(lvwph->m_headerItemShownHeight, 30.);
572+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
573+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
574+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
575+ }
576+
577+ void testChangeDelegateAtBottom()
578+ {
579+ scrollToBottom();
580+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
581+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
582+ verifyItem(0, -588., 390., true, "Bold", true);
583+ verifyItem(1, -198, 350., false, QString(), true);
584+ verifyItem(2, 152, 390., false, "Lazy", false);
585+ QCOMPARE(lvwph->m_minYExtent, 310.);
586+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
587+ QCOMPARE(lvwph->m_clipItem->clip(), false);
588+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
589+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
590+ QCOMPARE(lvwph->contentY(), 1458.);
591+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
592+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
593+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
594+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
595+
596+ lvwph->setDelegate(otherDelegate);
597+
598+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 6);
599+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
600+ verifyItem(0, 50., 75., false, "Agressive", false);
601+ verifyItem(1, 125, 75., false, "Regular", false);
602+ verifyItem(2, 200, 75., false, "Mild", false);
603+ verifyItem(3, 275, 75., false, "Bold", false);
604+ verifyItem(4, 350, 35., false, QString(), true);
605+ verifyItem(5, 385, 75., false, "Lazy", false);
606+ QCOMPARE(lvwph->m_minYExtent, 0.);
607+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
608+ QCOMPARE(lvwph->m_clipItem->clip(), false);
609+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
610+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
611+ QCOMPARE(lvwph->contentY(), 0.);
612+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
613+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
614+ }
615+
616+ void testSetEmptyHeaderAtTop()
617+ {
618+ lvwph->setHeader(nullptr);
619+
620+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
621+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
622+ verifyItem(0, 0., 190., false, "Agressive", false);
623+ verifyItem(1, 190., 240., false, "Regular", false);
624+ verifyItem(2, 430., 390., false, "Mild", false);
625+ QCOMPARE(lvwph->m_minYExtent, 0.);
626+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
627+ QCOMPARE(lvwph->m_clipItem->clip(), false);
628+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
629+ QCOMPARE(lvwph->contentY(), 0.);
630+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
631+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
632+ }
633+
634+ void testSetEmptyHeaderAtBottom()
635+ {
636+ scrollToBottom();
637+ lvwph->setHeader(nullptr);
638+
639+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
640+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
641+ verifyItem(0, -588., 390., true, "Bold", true);
642+ verifyItem(1, -198, 350., false, QString(), true);
643+ verifyItem(2, 152, 390., false, "Lazy", false);
644+ QCOMPARE(lvwph->m_minYExtent, 260.);
645+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
646+ QCOMPARE(lvwph->m_clipItem->clip(), false);
647+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
648+ QCOMPARE(lvwph->contentY(), 1458.);
649+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
650+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
651+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
652+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
653+
654+ scrollToTop();
655+
656+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
657+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
658+ verifyItem(0, 0., 190., false, "Agressive", false);
659+ verifyItem(1, 190., 240., false, "Regular", false);
660+ verifyItem(2, 430., 390., false, "Mild", false);
661+ QCOMPARE(lvwph->m_minYExtent, -50.);
662+ QCOMPARE(lvwph->m_clipItem->y(), 50.);
663+ QCOMPARE(lvwph->m_clipItem->clip(), false);
664+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
665+ QCOMPARE(lvwph->contentY(), 50.);
666+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
667+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
668+ }
669+
670+ void testSetEmptyHeaderWhenPartlyShownClipped()
671+ {
672+ scrollToBottom();
673+ changeContentY(-30);
674+ lvwph->setHeader(nullptr);
675+
676+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
677+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
678+ verifyItem(0, -588., 390., true, "Bold", true);
679+ verifyItem(1, -198, 350., false, QString(), true);
680+ verifyItem(2, 152, 390., false, "Lazy", false);
681+ QCOMPARE(lvwph->m_minYExtent, 290.);
682+ QCOMPARE(lvwph->m_clipItem->y(), 1428.);
683+ QCOMPARE(lvwph->m_clipItem->clip(), false);
684+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
685+ QCOMPARE(lvwph->contentY(), 1428.);
686+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
687+ QTRY_VERIFY(lvwph->isAtYEnd());
688+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
689+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
690+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
691+
692+ scrollToTop();
693+
694+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
695+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
696+ verifyItem(0, 0., 190., false, "Agressive", false);
697+ verifyItem(1, 190., 240., false, "Regular", false);
698+ verifyItem(2, 430., 390., false, "Mild", false);
699+ QCOMPARE(lvwph->m_minYExtent, -20.);
700+ QCOMPARE(lvwph->m_clipItem->y(), 20.);
701+ QCOMPARE(lvwph->m_clipItem->clip(), false);
702+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
703+ QCOMPARE(lvwph->contentY(), 20.);
704+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
705+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
706+ }
707+
708+ void testSetEmptyHeaderWhenPartlyShownNotClipped()
709+ {
710+ changeContentY(30);
711+ lvwph->setHeader(nullptr);
712+
713+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
714+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
715+ verifyItem(0, -30., 190., false, "Agressive", true);
716+ verifyItem(1, 160., 240., false, "Regular", false);
717+ verifyItem(2, 400., 390., false, "Mild", false);
718+ QCOMPARE(lvwph->m_minYExtent, 0.);
719+ QCOMPARE(lvwph->m_clipItem->y(), 30.);
720+ QCOMPARE(lvwph->m_clipItem->clip(), false);
721+ QCOMPARE(lvwph->m_headerItem, (QQuickItem*)nullptr);
722+ QCOMPARE(lvwph->contentY(), 30.);
723+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
724+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
725+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
726+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
727+ }
728+
729+ void testSetNullDelegate()
730+ {
731+ lvwph->setDelegate(nullptr);
732+
733+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
734+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
735+ QCOMPARE(lvwph->m_minYExtent, 0.);
736+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
737+ QCOMPARE(lvwph->m_clipItem->clip(), false);
738+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
739+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
740+ QCOMPARE(lvwph->contentY(), 0.);
741+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
742+ QTRY_COMPARE(lvwph->contentHeight(), 50.);
743+ QVERIFY(lvwph->isAtYBeginning());
744+ QVERIFY(lvwph->isAtYEnd());
745+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
746+ }
747+
748+ void testInsertItems()
749+ {
750+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
751+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
752+
753+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
754+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
755+ verifyItem(0, 50., 190., false, "Agressive", false);
756+ verifyItem(1, 240., 165., false, "Regular", false);
757+ verifyItem(2, 405., 140., false, "Agressive", false);
758+ verifyItem(3, 545., 240., true, "Regular", true);
759+ verifyItem(4, 785., 390., true, "Mild", true);
760+ QCOMPARE(lvwph->m_minYExtent, 0.);
761+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
762+ QCOMPARE(lvwph->m_clipItem->clip(), false);
763+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
764+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
765+ QCOMPARE(lvwph->contentY(), 0.);
766+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
767+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
768+ }
769+
770+ void testInsertItemsStealSectionItem()
771+ {
772+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
773+
774+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
775+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
776+ verifyItem(0, 50., 190., false, "Agressive", false);
777+ verifyItem(1, 240., 165., false, "Regular", false);
778+ verifyItem(2, 405., 200., false, QString(), true);
779+ verifyItem(3, 605., 390., true, "Mild", true);
780+ QCOMPARE(lvwph->m_minYExtent, 0.);
781+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
782+ QCOMPARE(lvwph->m_clipItem->clip(), false);
783+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
784+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
785+ QCOMPARE(lvwph->contentY(), 0.);
786+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
787+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
788+ }
789+
790+
791+ void testInsertItemsOnNotShownPosition()
792+ {
793+ changeContentY(800);
794+
795+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
796+ QTRY_COMPARE(lvwph->m_firstVisibleIndex, 2);
797+ verifyItem(0, -320., 390., false, "Mild", true);
798+ verifyItem(1, 70, 390., false, "Bold", false);
799+ verifyItem(2, 460, 350., false, QString(), false);
800+ verifyItem(3, 810, 390., true, "Lazy", true);
801+ QCOMPARE(lvwph->m_minYExtent, 330.);
802+ QCOMPARE(lvwph->m_clipItem->y(), 800.);
803+ QCOMPARE(lvwph->m_clipItem->clip(), false);
804+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
805+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
806+ QCOMPARE(lvwph->contentY(), 800.);
807+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
808+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
809+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
810+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
811+
812+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
813+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
814+
815+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
816+ QCOMPARE(lvwph->m_firstVisibleIndex, 4);
817+ verifyItem(0, -320., 390., false, "Mild", true);
818+ verifyItem(1, 70, 390., false, "Bold", false);
819+ verifyItem(2, 460, 350., false, QString(), false);
820+ verifyItem(3, 810, 390., true, "Lazy", true);
821+ QCOMPARE(lvwph->m_minYExtent, 1090.);
822+ QCOMPARE(lvwph->m_clipItem->y(), 800.);
823+ QCOMPARE(lvwph->m_clipItem->clip(), false);
824+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
825+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
826+ QCOMPARE(lvwph->contentY(), 800.);
827+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
828+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
829+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
830+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
831+
832+ scrollToTop();
833+
834+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
835+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
836+ verifyItem(0, 50., 190., false, "Agressive", false);
837+ verifyItem(1, 240., 165., false, "Regular", false);
838+ verifyItem(2, 405., 140., false, "Agressive", false);
839+ verifyItem(3, 545., 240., true, "Regular", true);
840+ verifyItem(4, 785., 390., true, "Mild", true);
841+ QCOMPARE(lvwph->m_minYExtent, 305.);
842+ QCOMPARE(lvwph->m_clipItem->y(), -305.);
843+ QCOMPARE(lvwph->m_clipItem->clip(), false);
844+ QCOMPARE(lvwph->m_headerItem->y(), -305.);
845+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
846+ QCOMPARE(lvwph->contentY(), -305.);
847+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
848+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
849+ }
850+
851+ void testInsertItemsAtEndOfViewport()
852+ {
853+ changeContentY(60);
854+
855+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
856+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
857+ verifyItem(0, -10., 190., false, "Agressive", true);
858+ verifyItem(1, 180., 240., false, "Regular", false);
859+ verifyItem(2, 420., 390., false, "Mild", false);
860+ verifyItem(3, 810., 390., true, "Bold", true);
861+ QCOMPARE(lvwph->m_minYExtent, 0.);
862+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
863+ QCOMPARE(lvwph->m_clipItem->clip(), false);
864+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
865+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
866+ QCOMPARE(lvwph->contentY(), 60.);
867+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
868+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
869+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
870+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
871+
872+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 3), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
873+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 3), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
874+
875+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
876+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
877+ verifyItem(0, -10., 190., false, "Agressive", true);
878+ verifyItem(1, 180., 240., false, "Regular", false);
879+ verifyItem(2, 420., 390., false, "Mild", false);
880+ verifyItem(3, 810., 165., true, "Regular", true);
881+ QCOMPARE(lvwph->m_minYExtent, 0.);
882+ QCOMPARE(lvwph->m_clipItem->y(), 60.);
883+ QCOMPARE(lvwph->m_clipItem->clip(), false);
884+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
885+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
886+ QCOMPARE(lvwph->contentY(), 60.);
887+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
888+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
889+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Agressive"));
890+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
891+ }
892+
893+ void testInsertItemsBeforeValidIndex()
894+ {
895+ changeContentY(520);
896+
897+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
898+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
899+ verifyItem(0, -280., 240., true, "Regular", true);
900+ verifyItem(1, -40, 390., false, "Mild", true);
901+ verifyItem(2, 350, 390., false, "Bold", false);
902+ verifyItem(3, 740, 350., true, QString(), true);
903+ QCOMPARE(lvwph->m_minYExtent, 152.5);
904+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
905+ QCOMPARE(lvwph->m_clipItem->clip(), false);
906+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
907+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
908+ QCOMPARE(lvwph->contentY(), 520.);
909+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
910+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
911+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
912+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
913+
914+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
915+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
916+
917+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
918+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
919+ verifyItem(0, -280., 240., true, "Regular", true);
920+ verifyItem(1, -40, 390., false, "Mild", true);
921+ verifyItem(2, 350, 390., false, "Bold", false);
922+ verifyItem(3, 740, 350., true, QString(), true);
923+ QCOMPARE(lvwph->m_minYExtent, 837.5);
924+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
925+ QCOMPARE(lvwph->m_clipItem->clip(), false);
926+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
927+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
928+ QCOMPARE(lvwph->contentY(), 520.);
929+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
930+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
931+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
932+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
933+ }
934+
935+ void testInsertItemsBeforeViewport()
936+ {
937+ changeContentY(375);
938+
939+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
940+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
941+ verifyItem(0, -325., 190., true, "Agressive", true);
942+ verifyItem(1, -135, 240., false, "Regular", true);
943+ verifyItem(2, 105, 390., false, "Mild", false);
944+ verifyItem(3, 495, 390., false, "Bold", false);
945+ QCOMPARE(lvwph->m_minYExtent, 0.);
946+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
947+ QCOMPARE(lvwph->m_clipItem->clip(), false);
948+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
949+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
950+ QCOMPARE(lvwph->contentY(), 375.);
951+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
952+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
953+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
954+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
955+
956+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
957+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
958+
959+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
960+ QCOMPARE(lvwph->m_firstVisibleIndex, 2);
961+ verifyItem(0, -275., 140., true, "Agressive", true);
962+ verifyItem(1, -135., 240., false, "Regular", true);
963+ verifyItem(2, 105, 390., false, "Mild", false);
964+ verifyItem(3, 495, 390., false, "Bold", false);
965+ QCOMPARE(lvwph->m_minYExtent, 530.);
966+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
967+ QCOMPARE(lvwph->m_clipItem->clip(), false);
968+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
969+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
970+ QCOMPARE(lvwph->contentY(), 375.);
971+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
972+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
973+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
974+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
975+
976+ scrollToTop();
977+
978+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
979+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
980+ verifyItem(0, 50., 190., false, "Agressive", false);
981+ verifyItem(1, 240., 165., false, "Regular", false);
982+ verifyItem(2, 405., 140., false, "Agressive", false);
983+ verifyItem(3, 545., 240., true, "Regular", true);
984+ verifyItem(4, 785., 390., true, "Mild", true);
985+ QCOMPARE(lvwph->m_minYExtent, 305.);
986+ QCOMPARE(lvwph->m_clipItem->y(), -305.);
987+ QCOMPARE(lvwph->m_clipItem->clip(), false);
988+ QCOMPARE(lvwph->m_headerItem->y(), -305.);
989+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
990+ QCOMPARE(lvwph->contentY(), -305.);
991+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
992+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
993+ }
994+
995+ void testInsertItemsAtBottom()
996+ {
997+ scrollToBottom();
998+
999+ QVERIFY(lvwph->isAtYEnd());
1000+
1001+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 100), Q_ARG(QVariant, "Agressive"));
1002+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 125), Q_ARG(QVariant, "Regular"));
1003+
1004+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1005+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
1006+ verifyItem(0, -588., 390., true, "Bold", true);
1007+ verifyItem(1, -198, 350., false, QString(), true);
1008+ verifyItem(2, 152, 390., false, "Lazy", false);
1009+ verifyItem(3, 542, 165., true, "Regular", true);
1010+ verifyItem(4, 707, 140., true, "Agressive", true);
1011+ QCOMPARE(lvwph->m_minYExtent, 41.);
1012+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
1013+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1014+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1015+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1016+ QCOMPARE(lvwph->contentY(), 1458.);
1017+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1018+ QVERIFY(!lvwph->isAtYEnd());
1019+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1020+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1021+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1022+
1023+ scrollToBottom();
1024+
1025+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1026+ QCOMPARE(lvwph->m_firstVisibleIndex, 4);
1027+ verifyItem(0, -503., 350., true, QString(), true);
1028+ verifyItem(1, -153, 390., false, "Lazy", true);
1029+ verifyItem(2, 237, 165., false, "Regular", false);
1030+ verifyItem(3, 402, 140., false, "Agressive", false);
1031+ QCOMPARE(lvwph->m_minYExtent, -165.);
1032+ QCOMPARE(lvwph->m_clipItem->y(), 1763.);
1033+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1034+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1035+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1036+ QCOMPARE(lvwph->contentY(), 1763.);
1037+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1038+ QVERIFY(lvwph->isAtYEnd());
1039+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1040+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Lazy"));
1041+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1042+ }
1043+
1044+ void testInsertItemAtTop()
1045+ {
1046+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Agressive"));
1047+
1048+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1049+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1050+ verifyItem(0, 50., 115., false, "Agressive", false);
1051+ verifyItem(1, 165., 150., false, QString(), false);
1052+ verifyItem(2, 315., 240., false, "Regular", false);
1053+ verifyItem(3, 555., 390., true, "Mild", true);
1054+ QCOMPARE(lvwph->m_minYExtent, 0.);
1055+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1056+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1057+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1058+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1059+ QCOMPARE(lvwph->contentY(), 0.);
1060+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1061+ QVERIFY(lvwph->isAtYBeginning());
1062+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1063+ }
1064+
1065+ void testInsertItem10SmallItemsAtTopWhenAtBottom()
1066+ {
1067+ scrollToBottom();
1068+
1069+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Agressive"));
1070+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Agressive"));
1071+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Agressive"));
1072+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Regular"));
1073+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Regular"));
1074+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Regular"));
1075+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Agressive"));
1076+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Agressive"));
1077+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Regular"));
1078+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 75), Q_ARG(QVariant, "Agressive"));
1079+
1080+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1081+ QCOMPARE(lvwph->m_firstVisibleIndex, 13);
1082+ verifyItem(0, -588., 390., true, "Bold", true);
1083+ verifyItem(1, -198, 350., false, QString(), true);
1084+ verifyItem(2, 152, 390., false, "Lazy", false);
1085+ QCOMPARE(lvwph->m_minYExtent, 12230./3.);
1086+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
1087+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1088+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1089+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1090+ QCOMPARE(lvwph->contentY(), 1458.);
1091+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1092+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1093+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1094+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1095+
1096+ changeContentY(-1700);
1097+
1098+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 10);
1099+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
1100+ verifyItem(0, -323., 75., true, QString(), true);
1101+ verifyItem(1, -248., 115., true, "Regular", true);
1102+ verifyItem(2, -133., 75., true, QString(), true);
1103+ verifyItem(3, -58., 75., false, QString(), true);
1104+ verifyItem(4, 17., 115., false, "Agressive", false);
1105+ verifyItem(5, 132., 75., false, QString(), true);
1106+ verifyItem(6, 207., 75., false, QString(), true);
1107+ verifyItem(7, 282., 150., false, QString(), true);
1108+ verifyItem(8, 432., 240., false, "Regular", false);
1109+ QCOMPARE(lvwph->m_minYExtent, 980.5);
1110+ QCOMPARE(lvwph->m_clipItem->y(), -192.);
1111+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1112+ QCOMPARE(lvwph->m_headerItem->y(), -242.);
1113+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1114+ QCOMPARE(lvwph->contentY(), -242.);
1115+ QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
1116+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1117+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1118+ QCOMPARE(lvwph->m_topSectionItem->y(), -23.);
1119+ }
1120+
1121+ void testRemoveItemsAtTop()
1122+ {
1123+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
1124+
1125+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 2);
1126+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1127+ verifyItem(0, 50., 390., false, "Mild", false);
1128+ verifyItem(1, 440., 390., false, "Bold", false);
1129+ QCOMPARE(lvwph->m_minYExtent, 0.);
1130+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1131+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1132+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1133+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1134+ QCOMPARE(lvwph->contentY(), 0.);
1135+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1136+ QVERIFY(lvwph->isAtYBeginning());
1137+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1138+ }
1139+
1140+ void testRemoveNonCreatedItemsAtTopWhenAtBottom()
1141+ {
1142+ scrollToBottom();
1143+
1144+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 2));
1145+
1146+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1147+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1148+ verifyItem(0, -588., 390., true, "Bold", true);
1149+ verifyItem(1, -198, 350., false, QString(), true);
1150+ verifyItem(2, 152, 390., false, "Lazy", false);
1151+ QCOMPARE(lvwph->m_minYExtent, -1330./3.);
1152+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
1153+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1154+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1155+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1156+ QCOMPARE(lvwph->contentY(), 1458.);
1157+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1158+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1159+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1160+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1161+ }
1162+
1163+ void testRemoveLastItemsAtBottom()
1164+ {
1165+ scrollToBottom();
1166+
1167+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 4), Q_ARG(QVariant, 2));
1168+
1169+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1170+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1171+ verifyItem(0, -478., 240., true, "Regular", true);
1172+ verifyItem(1, -238, 390., false, "Mild", true);
1173+ verifyItem(2, 152, 390., false, "Bold", false);
1174+ QCOMPARE(lvwph->m_minYExtent, 150.);
1175+ QCOMPARE(lvwph->m_clipItem->y(), 718.);
1176+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1177+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1178+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1179+ QCOMPARE(lvwph->contentY(), 718.);
1180+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1181+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1182+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1183+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1184+ }
1185+
1186+ void testRemoveItemOutOfViewport()
1187+ {
1188+ changeContentY(520);
1189+
1190+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1191+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1192+ verifyItem(0, -280., 240., true, "Regular", true);
1193+ verifyItem(1, -40, 390., false, "Mild", true);
1194+ verifyItem(2, 350, 390., false, "Bold", false);
1195+ verifyItem(3, 740, 350., true, QString(), true);
1196+ QCOMPARE(lvwph->m_minYExtent, 152.5);
1197+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
1198+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1199+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1200+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1201+ QCOMPARE(lvwph->contentY(), 520.);
1202+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1203+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1204+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1205+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1206+
1207+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 1), Q_ARG(QVariant, 1));
1208+
1209+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1210+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1211+ verifyItem(0, -230., 190., true, "Agressive", true);
1212+ verifyItem(1, -40, 390., false, "Mild", true);
1213+ verifyItem(2, 350, 390., false, "Bold", false);
1214+ verifyItem(3, 740, 350., true, QString(), true);
1215+ QCOMPARE(lvwph->m_minYExtent, -240.);
1216+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
1217+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1218+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1219+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1220+ QCOMPARE(lvwph->contentY(), 520.);
1221+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1222+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1223+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1224+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1225+ }
1226+
1227+ void testRemoveFirstOfCategory()
1228+ {
1229+ changeContentY(520);
1230+
1231+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1232+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1233+ verifyItem(0, -280., 240., true, "Regular", true);
1234+ verifyItem(1, -40, 390., false, "Mild", true);
1235+ verifyItem(2, 350, 390., false, "Bold", false);
1236+ verifyItem(3, 740, 350., true, QString(), true);
1237+ QCOMPARE(lvwph->m_minYExtent, 152.5);
1238+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
1239+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1240+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1241+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1242+ QCOMPARE(lvwph->contentY(), 520.);
1243+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1244+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1245+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1246+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1247+
1248+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 3), Q_ARG(QVariant, 1));
1249+
1250+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1251+ QCOMPARE(lvwph->m_firstVisibleIndex, 1);
1252+ verifyItem(0, -280., 240., true, "Regular", true);
1253+ verifyItem(1, -40, 390., false, "Mild", true);
1254+ verifyItem(2, 350, 390., false, "Bold", false);
1255+ verifyItem(3, 740, 390., true, "Lazy", true);
1256+ QCOMPARE(lvwph->m_minYExtent, 162.5);
1257+ QCOMPARE(lvwph->m_clipItem->y(), 520.);
1258+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1259+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1260+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1261+ QCOMPARE(lvwph->contentY(), 520.);
1262+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1263+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1264+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1265+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1266+ }
1267+
1268+ void testAddSecondToCulledCategoryOfTwo()
1269+ {
1270+ // Do some setup
1271+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 25), Q_ARG(QVariant, "Agressive"));
1272+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 25), Q_ARG(QVariant, "Agressive"));
1273+
1274+ changeContentY(200);
1275+
1276+ // Very the items are culled
1277+ verifyItem(0, -150., 65., true, "Agressive", true);
1278+ verifyItem(1, -85, 25., true, QString(), true);
1279+
1280+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 1), Q_ARG(QVariant, 25), Q_ARG(QVariant, "Agressive"));
1281+
1282+ // Very the new item is there correctly
1283+ verifyItem(0, -175., 65., true, "Agressive", true);
1284+ verifyItem(1, -110, 25., true, QString(), true);
1285+ verifyItem(2, -85, 25., true, QString(), true);
1286+ }
1287+
1288+ void testMoveFirstItems()
1289+ {
1290+ QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 1), Q_ARG(QVariant, 1));
1291+
1292+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1293+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1294+ verifyItem(0, 50., 240., false, "Regular", false);
1295+ verifyItem(1, 290., 190., false, "Agressive", false);
1296+ verifyItem(2, 480., 390., false, "Mild", false);
1297+ QCOMPARE(lvwph->m_minYExtent, 0.);
1298+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1299+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1300+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1301+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1302+ QCOMPARE(lvwph->contentY(), 0.);
1303+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1304+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1305+ }
1306+
1307+ void testMoveFirstOutOfVisibleItems()
1308+ {
1309+ QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 4), Q_ARG(QVariant, 1));
1310+
1311+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1312+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1313+ verifyItem(0, 50., 240., false, "Regular", false);
1314+ verifyItem(1, 290., 390., false, "Mild", false);
1315+ verifyItem(2, 680., 390., true, "Bold", true);
1316+ QCOMPARE(lvwph->m_minYExtent, 0.);
1317+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1318+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1319+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1320+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1321+ QCOMPARE(lvwph->contentY(), 0.);
1322+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1323+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1324+ }
1325+
1326+ void testMoveFirstToLastAtBottom()
1327+ {
1328+ scrollToBottom();
1329+
1330+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1331+ QCOMPARE(lvwph->m_firstVisibleIndex, 3);
1332+ verifyItem(0, -588., 390., true, "Bold", true);
1333+ verifyItem(1, -198, 350., false, QString(), true);
1334+ verifyItem(2, 152, 390., false, "Lazy", false);
1335+ QCOMPARE(lvwph->m_minYExtent, 310.);
1336+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
1337+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1338+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1339+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1340+ QCOMPARE(lvwph->contentY(), 1458.);
1341+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1342+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1343+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1344+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1345+
1346+ QMetaObject::invokeMethod(model, "moveItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 5), Q_ARG(QVariant, 1));
1347+
1348+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1349+ QCOMPARE(lvwph->m_firstVisibleIndex, 2);
1350+ verifyItem(0, -588., 390., true, "Bold", true);
1351+ verifyItem(1, -198, 350., false, QString(), true);
1352+ verifyItem(2, 152, 390., false, "Lazy", false);
1353+ verifyItem(3, 542, 190., true, "Agressive", true);
1354+ QCOMPARE(lvwph->m_minYExtent, -160.);
1355+ QCOMPARE(lvwph->m_clipItem->y(), 1458.);
1356+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1357+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1358+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1359+ QCOMPARE(lvwph->contentY(), 1458.);
1360+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1361+ QVERIFY(!lvwph->isAtYEnd());
1362+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1363+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Bold"));
1364+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1365+ }
1366+
1367+ void testChangeSizeVisibleItemNotOnViewport()
1368+ {
1369+ changeContentY(490);
1370+
1371+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1372+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1373+ verifyItem(0, -440., 190., true, "Agressive", true);
1374+ verifyItem(1, -250., 240., true, "Regular", true);
1375+ verifyItem(2, -10, 390., false, "Mild", true);
1376+ verifyItem(3, 380, 390., false, "Bold", false);
1377+ verifyItem(4, 770, 350., true, QString(), true);
1378+ QCOMPARE(lvwph->m_minYExtent, 0.);
1379+ QCOMPARE(lvwph->m_clipItem->y(), 490.);
1380+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1381+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1382+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1383+ QCOMPARE(lvwph->contentY(), 490.);
1384+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1385+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1386+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1387+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1388+
1389+ model->setProperty(1, "size", 100);
1390+
1391+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1392+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1393+ verifyItem(0, -340., 190., true, "Agressive", true);
1394+ verifyItem(1, -150., 140., true, "Regular", true);
1395+ verifyItem(2, -10, 390., false, "Mild", true);
1396+ verifyItem(3, 380, 390., false, "Bold", false);
1397+ verifyItem(4, 770, 350., true, QString(), true);
1398+ QCOMPARE(lvwph->m_minYExtent, -100.);
1399+ QCOMPARE(lvwph->m_clipItem->y(), 490.);
1400+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1401+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1402+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1403+ QCOMPARE(lvwph->contentY(), 490.);
1404+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1405+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1406+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Mild"));
1407+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1408+ }
1409+
1410+ void testShowHeaderCloseToTheTop()
1411+ {
1412+ changeContentY(375);
1413+
1414+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1415+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1416+ verifyItem(0, -325., 190., true, "Agressive", true);
1417+ verifyItem(1, -135, 240., false, "Regular", true);
1418+ verifyItem(2, 105, 390., false, "Mild", false);
1419+ verifyItem(3, 495, 390., false, "Bold", false);
1420+ QCOMPARE(lvwph->m_minYExtent, 0.);
1421+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
1422+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1423+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1424+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1425+ QCOMPARE(lvwph->contentY(), 375.);
1426+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);;
1427+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1428+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1429+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1430+
1431+ lvwph->showHeader();
1432+
1433+ QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1434+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
1435+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1436+ verifyItem(0, -375., 190., true, "Agressive", true);
1437+ verifyItem(1, -185, 240., false, "Regular", true);
1438+ verifyItem(2, 55, 390., false, "Mild", false);
1439+ verifyItem(3, 445, 390., false, "Bold", false);
1440+ QCOMPARE(lvwph->m_minYExtent, 50.);
1441+ QCOMPARE(lvwph->m_clipItem->y(), 375.);
1442+ QCOMPARE(lvwph->m_clipItem->clip(), true);
1443+ QCOMPARE(lvwph->m_headerItem->y(), 325.);
1444+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1445+ QCOMPARE(lvwph->contentY(), 325.);
1446+ QCOMPARE(lvwph->m_headerItemShownHeight, 50.);
1447+ QVERIFY(!QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1448+ QCOMPARE(section(lvwph->m_topSectionItem), QString("Regular"));
1449+ QCOMPARE(lvwph->m_topSectionItem->y(), 0.);
1450+
1451+ scrollToTop();
1452+
1453+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
1454+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1455+ verifyItem(0, 50., 190., false, "Agressive", false);
1456+ verifyItem(1, 240., 240., false, "Regular", false);
1457+ verifyItem(2, 480., 390., false, "Mild", false);
1458+ QCOMPARE(lvwph->m_minYExtent, 50.);
1459+ QCOMPARE(lvwph->m_clipItem->y(), -50.);
1460+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1461+ QCOMPARE(lvwph->m_headerItem->y(), -50.);
1462+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1463+ QCOMPARE(lvwph->contentY(), -50.);
1464+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1465+ QVERIFY(QQuickItemPrivate::get(lvwph->m_topSectionItem)->culled);
1466+ }
1467+
1468+ void testShowHeaderAtBottom()
1469+ {
1470+ scrollToBottom();
1471+
1472+ lvwph->showHeader();
1473+
1474+ QTRY_VERIFY(!lvwph->m_headerShowAnimation->isRunning());
1475+ QTRY_VERIFY (lvwph->isAtYEnd());
1476+ }
1477+
1478+ void growWindow()
1479+ {
1480+ view->rootObject()->setHeight(850);
1481+
1482+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 5);
1483+ QCOMPARE(lvwph->m_firstVisibleIndex, 0);
1484+ verifyItem(0, 50., 190., false, "Agressive", false);
1485+ verifyItem(1, 240., 240., false, "Regular", false);
1486+ verifyItem(2, 480., 390., false, "Mild", false);
1487+ verifyItem(3, 870., 390., true, "Bold", true);
1488+ verifyItem(4, 1260., 350., true, QString(), true);
1489+ QCOMPARE(lvwph->m_minYExtent, 0.);
1490+ QCOMPARE(lvwph->m_clipItem->y(), 0.);
1491+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1492+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1493+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1494+ QCOMPARE(lvwph->contentY(), 0.);
1495+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1496+ }
1497+
1498+ void growWindowAtBottom()
1499+ {
1500+ // Need a bunch small items at the bottom to trigger the problem
1501+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1502+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1503+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1504+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1505+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1506+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1507+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Regular"));
1508+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Regular"));
1509+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Regular"));
1510+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Regular"));
1511+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Regular"));
1512+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Regular"));
1513+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1514+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1515+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1516+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1517+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1518+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1519+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1520+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 6), Q_ARG(QVariant, 50), Q_ARG(QVariant, "Agressive"));
1521+
1522+ scrollToBottom();
1523+
1524+ view->rootObject()->setHeight(850);
1525+
1526+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 21);
1527+ QCOMPARE(lvwph->m_firstVisibleIndex, 5);
1528+ verifyItem(0, -660., 390., true, "Lazy", true);
1529+ verifyItem(1, -270., 90., true, "Agressive", true);
1530+ verifyItem(2, -180, 50., true, QString(), true);
1531+ verifyItem(3, -130, 50., true, QString(), true);
1532+ verifyItem(4, -80, 50., true, QString(), true);
1533+ verifyItem(5, -30, 50., false, QString(), true);
1534+ verifyItem(6, 20, 50., false, QString(), true);
1535+ verifyItem(7, 70, 50., false, QString(), true);
1536+ verifyItem(8, 120, 50., false, QString(), true);
1537+ verifyItem(9, 170, 90., false, "Regular", false);
1538+ verifyItem(10, 260, 50., false, QString(), true);
1539+ verifyItem(11, 310, 50., false, QString(), true);
1540+ verifyItem(12, 360, 50., false, QString(), true);
1541+ verifyItem(13, 410, 50., false, QString(), true);
1542+ verifyItem(14, 460, 50., false, QString(), true);
1543+ verifyItem(15, 510, 90., false, "Agressive", false);
1544+ verifyItem(16, 600, 50., false, QString(), true);
1545+ verifyItem(17, 650, 50., false, QString(), true);
1546+ verifyItem(18, 700, 50., false, QString(), true);
1547+ verifyItem(19, 750, 50., false, QString(), true);
1548+ verifyItem(20, 800, 50., false, QString(), true);
1549+ QCOMPARE(lvwph->m_minYExtent, 5 * 1510./21. + 660 - 1970 + 50);
1550+ QCOMPARE(lvwph->m_clipItem->y(), 1970.);
1551+ QCOMPARE(lvwph->m_clipItem->clip(), false);
1552+ QCOMPARE(lvwph->m_headerItem->y(), 0.);
1553+ QCOMPARE(lvwph->m_headerItem->height(), 50.);
1554+ QCOMPARE(lvwph->contentY(), 1970.);
1555+ QCOMPARE(lvwph->m_headerItemShownHeight, 0.);
1556+ }
1557+
1558+private:
1559+ QQuickView *view;
1560+ ListViewWithPageHeader *lvwph;
1561+ QQuickListModel *model;
1562+ QQmlComponent *otherDelegate;
1563+};
1564+
1565+QTEST_MAIN(ListViewWithPageHeaderTestSection)
1566+
1567+#include "listviewwithpageheadertestsection.moc"
tests/plugins/ListViewWithPageHeader/test.qmlnew file+96
@@ -0,0 +1,96 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import ListViewWithPageHeader 0.1
19+
20+Rectangle {
21+ width: 300
22+ height: 542
23+ color: "lightblue"
24+
25+ ListModel {
26+ id: model
27+
28+ function insertItem(index, size) {
29+ insert(index, { size: size });
30+ }
31+
32+ function removeItems(index, count) {
33+ remove(index, count);
34+ }
35+
36+ function moveItems(indexFrom, indexTo, count) {
37+ move(indexFrom, indexTo, count);
38+ }
39+
40+ ListElement { size: 150 }
41+ ListElement { size: 200 }
42+ ListElement { size: 350 }
43+ ListElement { size: 350 }
44+ ListElement { size: 350 }
45+ ListElement { size: 350 }
46+ }
47+
48+ Component {
49+ id: otherRect
50+ Rectangle {
51+ height: 35
52+ width: parent.width
53+ color: index % 2 == 0 ? "yellow" : "purple"
54+ }
55+ }
56+
57+ ListViewWithPageHeader {
58+ id: listView
59+ width: parent.width
60+ anchors.top: parent.top
61+ anchors.bottom: parent.bottom
62+ model: model
63+ delegate: Rectangle {
64+ property bool timerDone: false
65+ width: parent.width - 20
66+ x: 10
67+ color: index % 2 == 0 ? "red" : "blue"
68+ height: timerDone ? size : 350
69+ Text {
70+ text: index
71+ }
72+ Timer {
73+ id: sizeTimer
74+ interval: 10;
75+ onTriggered: {
76+ timerDone = true
77+ }
78+ }
79+ Component.onCompleted: {
80+ sizeTimer.start()
81+ }
82+ }
83+
84+ pageHeader: Rectangle {
85+ color: "transparent"
86+ width: parent.width
87+ height: 50
88+ implicitHeight: 50
89+ Text {
90+ anchors.fill: parent
91+ text: "APPS"
92+ font.pixelSize: 40
93+ }
94+ }
95+ }
96+}
tests/plugins/ListViewWithPageHeader/test_section.qmlnew file+106
@@ -0,0 +1,106 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import ListViewWithPageHeader 0.1
19+
20+Rectangle {
21+ width: 300
22+ height: 542
23+ color: "lightblue"
24+
25+ ListModel {
26+ id: model
27+
28+ function insertItem(index, size, type) {
29+ insert(index, { size: size, type: type });
30+ }
31+
32+ function removeItems(index, count) {
33+ remove(index, count);
34+ }
35+
36+ function moveItems(indexFrom, indexTo, count) {
37+ move(indexFrom, indexTo, count);
38+ }
39+
40+ ListElement { type: "Agressive"; size: 150 }
41+ ListElement { type: "Regular"; size: 200 }
42+ ListElement { type: "Mild"; size: 350 }
43+ ListElement { type: "Bold"; size: 350 }
44+ ListElement { type: "Bold"; size: 350 }
45+ ListElement { type: "Lazy"; size: 350 }
46+ }
47+
48+ Component {
49+ id: otherRect
50+ Rectangle {
51+ height: 35
52+ width: parent.width
53+ color: index % 2 == 0 ? "yellow" : "purple"
54+ }
55+ }
56+
57+ ListViewWithPageHeader {
58+ id: listView
59+ width: parent.width
60+ anchors.top: parent.top
61+ anchors.bottom: parent.bottom
62+ model: model
63+ delegate: Rectangle {
64+ property bool timerDone: false
65+ width: parent.width - 20
66+ x: 10
67+ color: index % 2 == 0 ? "red" : "blue"
68+ height: timerDone ? size : 350
69+ Text {
70+ text: index
71+ }
72+ Timer {
73+ id: sizeTimer
74+ interval: 10;
75+ onTriggered: {
76+ timerDone = true
77+ }
78+ }
79+ Component.onCompleted: {
80+ sizeTimer.start()
81+ }
82+ }
83+
84+ pageHeader: Rectangle {
85+ color: "transparent"
86+ width: parent.width
87+ height: 50
88+ implicitHeight: 50
89+ Text {
90+ anchors.fill: parent
91+ text: "APPS"
92+ font.pixelSize: 40
93+ }
94+ }
95+
96+ sectionProperty: "type"
97+ sectionDelegate: Component {
98+ Rectangle {
99+ color: "green"
100+ height: 40
101+ Text { text: section; font.pixelSize: 34 }
102+ anchors { left: parent.left; right: parent.right }
103+ }
104+ }
105+ }
106+}
tests/plugins/Ubuntu/Gestures/tst_AxisVelocityCalculator.cpp+40−28
@@ -20,7 +20,7 @@
2020
2121#include <AxisVelocityCalculator.h>
2222
23−class FakeTimeSource : public AxisVelocityCalculator::TimeSource {
23+class FakeTimeSource : public UbuntuGestures::TimeSource {
2424public:
2525 FakeTimeSource() : m_value(0) {}
2626
@@ -44,71 +44,85 @@ class tst_AxisVelocityCalculator : public QObject
4444{
4545 Q_OBJECT
4646private Q_SLOTS:
47+ void init(); // called right before each and every test function is executed
48+ void cleanup(); // called right after each and every test function is executed
49+
4750 void simpleSamples();
4851 void noSamples();
4952 void overflowSamples();
5053 void average();
54+
55+private:
56+ AxisVelocityCalculator *velCalc;
57+ FakeTimeSource *fakeTimeSource;
5158};
5259
60+void tst_AxisVelocityCalculator::init()
61+{
62+ fakeTimeSource = new FakeTimeSource;
63+
64+ velCalc = new AxisVelocityCalculator;
65+ velCalc->setTimeSource(fakeTimeSource);
66+}
67+
68+void tst_AxisVelocityCalculator::cleanup()
69+{
70+ delete velCalc;
71+ delete fakeTimeSource;
72+}
73+
5374void tst_AxisVelocityCalculator::simpleSamples()
5475{
55− FakeTimeSource *fakeTimeSource = new FakeTimeSource;
56− AxisVelocityCalculator velCalc(fakeTimeSource);
5776 qreal pos = 0;
5877
59− velCalc.setTrackedPosition(pos);
60− velCalc.reset();
78+ velCalc->setTrackedPosition(pos);
79+ velCalc->reset();
6180
6281 fakeTimeSource->setMsecsSinceReference(10);
6382 pos += 20;
64− velCalc.setTrackedPosition(pos);
83+ velCalc->setTrackedPosition(pos);
6584
6685 fakeTimeSource->setMsecsSinceReference(20);
6786 pos += 20;
68− velCalc.setTrackedPosition(pos);
87+ velCalc->setTrackedPosition(pos);
6988
7089 fakeTimeSource->setMsecsSinceReference(30);
7190 pos += 20;
72− velCalc.setTrackedPosition(pos);
91+ velCalc->setTrackedPosition(pos);
7392
74− qreal velocity = velCalc.calculate();
93+ qreal velocity = velCalc->calculate();
7594
7695 QCOMPARE(velocity, 2.0f);
7796}
7897
7998void tst_AxisVelocityCalculator::noSamples()
8099{
81− FakeTimeSource *fakeTimeSource = new FakeTimeSource;
82− AxisVelocityCalculator velCalc(fakeTimeSource);
83−
84− float velocity = velCalc.calculate();
100+ float velocity = velCalc->calculate();
85101
86102 QCOMPARE(velocity, 0.0f);
87103}
88104
89105void tst_AxisVelocityCalculator::overflowSamples()
90106{
91− FakeTimeSource *fakeTimeSource = new FakeTimeSource;
92− AxisVelocityCalculator velCalc(fakeTimeSource);
93107 qreal pos = 0;
94108
95− velCalc.setTrackedPosition(pos);
96− velCalc.reset();
109+ velCalc->setTrackedPosition(pos);
110+ velCalc->reset();
97111
98112 for (int i = 0; i < 1000; ++i) {
99113 fakeTimeSource->increaseMsecsSinceReference(10);
100114 pos += 20;
101− velCalc.setTrackedPosition(pos);
115+ velCalc->setTrackedPosition(pos);
102116 }
103117
104118 /* overwrite all existing samples with faster ones */
105119 for (int i = 0; i < AxisVelocityCalculator::MAX_SAMPLES; ++i) {
106120 fakeTimeSource->increaseMsecsSinceReference(10);
107121 pos += 40;
108− velCalc.setTrackedPosition(pos);
122+ velCalc->setTrackedPosition(pos);
109123 }
110124
111− float velocity = velCalc.calculate();
125+ float velocity = velCalc->calculate();
112126
113127 /* check that the calculated velocity correspond to the latest, faster, samples */
114128 QCOMPARE(velocity, 4.0f);
@@ -116,28 +130,26 @@ void tst_AxisVelocityCalculator::overflowSamples()
116130
117131void tst_AxisVelocityCalculator::average()
118132{
119− FakeTimeSource *fakeTimeSource = new FakeTimeSource;
120− AxisVelocityCalculator velCalc(fakeTimeSource);
121133 qreal pos = 0;
122134
123− velCalc.setTrackedPosition(pos);
124− velCalc.reset();
135+ velCalc->setTrackedPosition(pos);
136+ velCalc->reset();
125137
126138 fakeTimeSource->increaseMsecsSinceReference(10);
127139 pos += 20;
128− velCalc.setTrackedPosition(pos);
140+ velCalc->setTrackedPosition(pos);
129141
130142 fakeTimeSource->increaseMsecsSinceReference(10);
131143 pos += 20;
132− velCalc.setTrackedPosition(pos);
144+ velCalc->setTrackedPosition(pos);
133145
134146 /* the last sample is an erratic one and would yield a big velocity if
135147 considered isolatedly */
136148 fakeTimeSource->increaseMsecsSinceReference(10);
137149 pos += 100;
138− velCalc.setTrackedPosition(pos);
150+ velCalc->setTrackedPosition(pos);
139151
140− float velocity = velCalc.calculate();
152+ float velocity = velCalc->calculate();
141153
142154 /* calculated velocity is lower than the one from the last sample */
143155 QVERIFY(velocity < 9.0f);
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+99−11
@@ -38,7 +38,7 @@ private:
3838 int m_duration;
3939};
4040
41−class FakeTimeSource : public AxisVelocityCalculator::TimeSource
41+class FakeTimeSource : public UbuntuGestures::TimeSource
4242{
4343public:
4444 FakeTimeSource() { m_msecsSinceReference = 0; }
@@ -65,6 +65,9 @@ private Q_SLOTS:
6565 void minSpeed_data();
6666 void recognitionTimerUsage();
6767 void maxSilenceTime();
68+ void sceneXAndX();
69+ void sceneYAndY();
70+ void emitDraggingChangedOnDirectRecognition();
6871
6972private:
7073 QQuickView *createView();
@@ -72,7 +75,6 @@ private:
7275 QTouchDevice *device;
7376 FakeTimer *fakeTimer;
7477 FakeTimeSource *fakeTimeSource;
75− AxisVelocityCalculator *velCalcWithFakeTiming;
7678};
7779
7880void tst_DirectionalDragArea::initTestCase()
@@ -101,7 +103,6 @@ void tst_DirectionalDragArea::init()
101103
102104 fakeTimer = new FakeTimer;
103105 fakeTimeSource = new FakeTimeSource;
104− velCalcWithFakeTiming = new AxisVelocityCalculator(fakeTimeSource);
105106}
106107
107108void tst_DirectionalDragArea::cleanup()
@@ -112,10 +113,8 @@ void tst_DirectionalDragArea::cleanup()
112113 delete fakeTimer;
113114 fakeTimer = 0;
114115
115− // will bring fakeTimeSource down with it
116− delete velCalcWithFakeTiming;
116+ delete fakeTimeSource;
117117 fakeTimeSource = 0;
118− velCalcWithFakeTiming = 0;
119118}
120119
121120QQuickView *tst_DirectionalDragArea::createView()
@@ -187,7 +186,7 @@ void tst_DirectionalDragArea::edgeDrag()
187186 view->rootObject()->findChild<DirectionalDragArea*>(dragAreaObjectName);
188187 QVERIFY(edgeDragArea != 0);
189188 edgeDragArea->setRecognitionTimer(fakeTimer);
190− edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
189+ edgeDragArea->setTimeSource(fakeTimeSource);
191190
192191 QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
193192
@@ -292,7 +291,7 @@ void tst_DirectionalDragArea::dragWithShortDirectionChange()
292291 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
293292 QVERIFY(edgeDragArea != 0);
294293 edgeDragArea->setRecognitionTimer(fakeTimer);
295− edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
294+ edgeDragArea->setTimeSource(fakeTimeSource);
296295
297296 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
298297 QPointF touchPoint = initialTouchPos;
@@ -337,7 +336,7 @@ void tst_DirectionalDragArea::minSpeed()
337336 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
338337 QVERIFY(edgeDragArea != 0);
339338 edgeDragArea->setRecognitionTimer(fakeTimer);
340− edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
339+ edgeDragArea->setTimeSource(fakeTimeSource);
341340
342341 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
343342 QPointF touchPoint = initialTouchPos;
@@ -390,7 +389,7 @@ void tst_DirectionalDragArea::recognitionTimerUsage()
390389 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
391390 QVERIFY(edgeDragArea != 0);
392391 edgeDragArea->setRecognitionTimer(fakeTimer);
393− edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
392+ edgeDragArea->setTimeSource(fakeTimeSource);
394393
395394 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
396395 QPointF touchPoint = initialTouchPos;
@@ -431,7 +430,7 @@ void tst_DirectionalDragArea::maxSilenceTime()
431430 view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
432431 QVERIFY(edgeDragArea != 0);
433432 edgeDragArea->setRecognitionTimer(fakeTimer);
434− edgeDragArea->setAxisVelocityCalculator(velCalcWithFakeTiming);
433+ edgeDragArea->setTimeSource(fakeTimeSource);
435434
436435 QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea, view);
437436 QPointF touchPoint = initialTouchPos;
@@ -458,6 +457,95 @@ void tst_DirectionalDragArea::maxSilenceTime()
458457 QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Rejected);
459458}
460459
460+/*
461+ Checks that it informs the X coordinate of the touch point in local and scene coordinates
462+ correctly.
463+ */
464+void tst_DirectionalDragArea::sceneXAndX()
465+{
466+ DirectionalDragArea *edgeDragArea =
467+ view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
468+ QVERIFY(edgeDragArea != 0);
469+ edgeDragArea->setRecognitionTimer(fakeTimer);
470+ edgeDragArea->setTimeSource(fakeTimeSource);
471+
472+ QPointF touchScenePos(view->width() - (edgeDragArea->width()/2.0f), view->height()/2.0f);
473+
474+ fakeTimeSource->m_msecsSinceReference = 0;
475+ QTest::touchEvent(view, device).press(0, touchScenePos.toPoint());
476+
477+ QSignalSpy touchXSpy(edgeDragArea, SIGNAL(touchXChanged(qreal)));
478+ QSignalSpy touchSceneXSpy(edgeDragArea, SIGNAL(touchSceneXChanged(qreal)));
479+
480+ touchScenePos.rx() = view->width() / 2;
481+ QTest::touchEvent(view, device).move(0, touchScenePos.toPoint());
482+
483+ QCOMPARE(touchXSpy.count(), 1);
484+ QCOMPARE(touchSceneXSpy.count(), 1);
485+ QCOMPARE(edgeDragArea->touchX(), touchScenePos.x() - edgeDragArea->x());
486+ QCOMPARE(edgeDragArea->touchSceneX(), touchScenePos.x());
487+}
488+
489+/*
490+ Checks that it informs the Y coordinate of the touch point in local and scene coordinates
491+ correctly.
492+ */
493+void tst_DirectionalDragArea::sceneYAndY()
494+{
495+ DirectionalDragArea *edgeDragArea =
496+ view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
497+ QVERIFY(edgeDragArea != 0);
498+ edgeDragArea->setRecognitionTimer(fakeTimer);
499+ edgeDragArea->setTimeSource(fakeTimeSource);
500+
501+ QPointF touchScenePos(view->width()/2.0f, view->height() - (edgeDragArea->height()/2.0f));
502+
503+ fakeTimeSource->m_msecsSinceReference = 0;
504+ QTest::touchEvent(view, device).press(0, touchScenePos.toPoint());
505+
506+ QSignalSpy touchYSpy(edgeDragArea, SIGNAL(touchYChanged(qreal)));
507+ QSignalSpy touchSceneYSpy(edgeDragArea, SIGNAL(touchSceneYChanged(qreal)));
508+
509+ touchScenePos.ry() = view->height() / 2;
510+ QTest::touchEvent(view, device).move(0, touchScenePos.toPoint());
511+
512+ QCOMPARE(touchYSpy.count(), 1);
513+ QCOMPARE(touchSceneYSpy.count(), 1);
514+ QCOMPARE(edgeDragArea->touchY(), touchScenePos.y() - edgeDragArea->y());
515+ QCOMPARE(edgeDragArea->touchSceneY(), touchScenePos.y());
516+}
517+
518+/*
519+ Emit draggingChanged() when status change from WaitingForTouch directly to Recognized.
520+ This happens when the gesture recognition is effectively disabled (e.g. by setting a
521+ distanceThreshold of zero)
522+ */
523+void tst_DirectionalDragArea::emitDraggingChangedOnDirectRecognition()
524+{
525+ DirectionalDragArea *edgeDragArea =
526+ view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
527+ QVERIFY(edgeDragArea != 0);
528+ edgeDragArea->setRecognitionTimer(fakeTimer);
529+ edgeDragArea->setTimeSource(fakeTimeSource);
530+
531+ QPointF touchPos = calculateInitialTouchPos(edgeDragArea, view);
532+
533+ QSignalSpy draggingSpy(edgeDragArea, SIGNAL(draggingChanged(bool)));
534+
535+ // That will make it completetly skip the recognition phase ("Undecided" status).
536+ edgeDragArea->setDistanceThreshold(0.0);
537+
538+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::WaitingForTouch);
539+ QCOMPARE(edgeDragArea->dragging(), false);
540+
541+ fakeTimeSource->m_msecsSinceReference = 0;
542+ QTest::touchEvent(view, device).press(0, touchPos.toPoint());
543+
544+ QCOMPARE((int)edgeDragArea->status(), (int)DirectionalDragArea::Recognized);
545+ QCOMPARE(draggingSpy.count(), 1);
546+ QCOMPARE(edgeDragArea->dragging(), true);
547+}
548+
461549QTEST_MAIN(tst_DirectionalDragArea)
462550
463551#include "tst_DirectionalDragArea.moc"
tests/plugins/Unity/CMakeLists.txtnew file+38
@@ -0,0 +1,38 @@
1+pkg_check_modules(UNITYCORE REQUIRED unity-core-6.0)
2+pkg_check_modules(LIBUNITYPROTO REQUIRED unity-protocol-private)
3+
4+include_directories(
5+ ${Unity-qml_SOURCE_DIR}
6+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Unity
7+ ${CMAKE_CURRENT_BINARY_DIR}
8+ ${LIBUNITYPROTO_INCLUDE_DIRS}
9+ ${UNITYCORE_INCLUDE_DIRS}
10+ )
11+
12+macro(run_tests)
13+ set(_test_list "")
14+ foreach(_test ${ARGN})
15+ set(testCommand
16+ ${CMAKE_CURRENT_BINARY_DIR}/${_test}Exec
17+ -o ${CMAKE_BINARY_DIR}/${_test}.xml,xunitxml
18+ -o -,txt)
19+ add_test(NAME test${CLASSNAME}${_test} COMMAND ${testCommand})
20+ add_custom_target(${_test} ${testCommand})
21+ add_executable(${_test}Exec ${_test}.cpp previewbindingstest.cpp)
22+ qt5_use_modules(${_test}Exec Test Core Qml)
23+ set_tests_properties(test${CLASSNAME}${_test}
24+ PROPERTIES ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Unity:${LIBUNITYPROTO_LIBRARY_DIRS})
25+
26+ target_link_libraries(${_test}Exec
27+ Unity-qml
28+ ${UNITYCORE_LDFLAGS}
29+ ${LIBUNITYPROTO_LDFLAGS}
30+ )
31+
32+ set(_test_list "${_test_list};${_test}")
33+ endforeach()
34+endmacro(run_tests)
35+
36+run_tests(
37+ previewbindingstest
38+ )
tests/plugins/Unity/previewbindingstest.cppnew file+114
@@ -0,0 +1,114 @@
1+/*
2+ * Copyright (C) 2011, 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "previewbindingstest.h"
18+#include <QTest>
19+
20+#include <UnityCore/Preview.h>
21+#include <UnityCore/GLibWrapper.h>
22+#include <unity-protocol.h>
23+
24+#include "genericpreview.h"
25+#include "applicationpreview.h"
26+#include "moviepreview.h"
27+#include "musicpreview.h"
28+
29+void PreviewBindingsTest::initTestCase()
30+{
31+}
32+
33+void PreviewBindingsTest::testGenericPreview()
34+{
35+ auto raw_preview = (GObject *)unity_protocol_generic_preview_new();
36+ unity_protocol_preview_set_title(UNITY_PROTOCOL_PREVIEW(raw_preview), "Metallica");
37+ unity_protocol_preview_set_subtitle(UNITY_PROTOCOL_PREVIEW(raw_preview), "Ride The Lightning");
38+ unity_protocol_preview_set_description(UNITY_PROTOCOL_PREVIEW(raw_preview), "Lorem ipsum dolor sit amet");
39+ unity::glib::Object<GObject> gen_prv(raw_preview);
40+
41+ auto core_prv = unity::dash::Preview::PreviewForProtocolObject(gen_prv);
42+ auto prv = Preview::newFromUnityPreview(core_prv);
43+
44+ QCOMPARE(prv != nullptr, true);
45+ QCOMPARE(prv->title(), QString("Metallica"));
46+ QCOMPARE(prv->subtitle(), QString("Ride The Lightning"));
47+ QCOMPARE(prv->description(), QString("Lorem ipsum dolor sit amet"));
48+}
49+
50+void PreviewBindingsTest::testApplicationPreview()
51+{
52+ auto raw_preview = (GObject *)unity_protocol_application_preview_new();
53+ unity_protocol_preview_set_title(UNITY_PROTOCOL_PREVIEW(raw_preview), "Firefox");
54+ unity_protocol_preview_set_subtitle(UNITY_PROTOCOL_PREVIEW(raw_preview), "Web Browser");
55+ unity_protocol_preview_set_description(UNITY_PROTOCOL_PREVIEW(raw_preview), "Lorem ipsum dolor sit amet");
56+ unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(raw_preview), "GPL");
57+ unity_protocol_application_preview_set_rating(UNITY_PROTOCOL_APPLICATION_PREVIEW(raw_preview), 0.5f);
58+ unity_protocol_application_preview_set_num_ratings(UNITY_PROTOCOL_APPLICATION_PREVIEW(raw_preview), 4);
59+ unity::glib::Object<GObject> gen_prv(raw_preview);
60+
61+ auto core_prv = unity::dash::Preview::PreviewForProtocolObject(gen_prv);
62+ auto prv = Preview::newFromUnityPreview(core_prv);
63+ auto app_prv = dynamic_cast<ApplicationPreview*>(prv);
64+
65+ QCOMPARE(app_prv != nullptr, true);
66+ QCOMPARE(app_prv->title(), QString("Firefox"));
67+ QCOMPARE(app_prv->subtitle(), QString("Web Browser"));
68+ QCOMPARE(app_prv->description(), QString("Lorem ipsum dolor sit amet"));
69+ QCOMPARE(app_prv->license(), QString("GPL"));
70+ QCOMPARE(app_prv->rating(), 0.5f);
71+ QCOMPARE(app_prv->numRatings(), unsigned (4));
72+}
73+
74+void PreviewBindingsTest::testMoviePreview()
75+{
76+ auto raw_preview = (GObject *)unity_protocol_movie_preview_new();
77+ unity_protocol_preview_set_title(UNITY_PROTOCOL_PREVIEW(raw_preview), "Blade Runner");
78+ unity_protocol_preview_set_subtitle(UNITY_PROTOCOL_PREVIEW(raw_preview), "Ridley Scott");
79+ unity_protocol_preview_set_description(UNITY_PROTOCOL_PREVIEW(raw_preview), "Lorem ipsum dolor sit amet");
80+ unity_protocol_movie_preview_set_year(UNITY_PROTOCOL_MOVIE_PREVIEW(raw_preview), "1982");
81+ unity::glib::Object<GObject> gen_prv(raw_preview);
82+
83+ auto core_prv = unity::dash::Preview::PreviewForProtocolObject(gen_prv);
84+ auto prv = Preview::newFromUnityPreview(core_prv);
85+ auto movie_prv = dynamic_cast<MoviePreview*>(prv);
86+
87+ QCOMPARE(movie_prv != nullptr, true);
88+ QCOMPARE(movie_prv->title(), QString("Blade Runner"));
89+ QCOMPARE(movie_prv->subtitle(), QString("Ridley Scott"));
90+ QCOMPARE(movie_prv->description(), QString("Lorem ipsum dolor sit amet"));
91+ QCOMPARE(movie_prv->year(), QString("1982"));
92+}
93+
94+void PreviewBindingsTest::testMusicPreview()
95+{
96+ auto raw_preview = (GObject *)unity_protocol_music_preview_new();
97+ unity_protocol_preview_set_title(UNITY_PROTOCOL_PREVIEW(raw_preview), "Metallica");
98+ unity_protocol_preview_set_subtitle(UNITY_PROTOCOL_PREVIEW(raw_preview), "Death Magnetic");
99+ unity_protocol_preview_set_description(UNITY_PROTOCOL_PREVIEW(raw_preview), "Lorem ipsum dolor sit amet");
100+ unity::glib::Object<GObject> gen_prv(raw_preview);
101+
102+ auto core_prv = unity::dash::Preview::PreviewForProtocolObject(gen_prv);
103+ auto prv = Preview::newFromUnityPreview(core_prv);
104+ auto music_prv = dynamic_cast<MusicPreview*>(prv);
105+
106+ QCOMPARE(music_prv != nullptr, true);
107+ QCOMPARE(music_prv->title(), QString("Metallica"));
108+ QCOMPARE(music_prv->subtitle(), QString("Death Magnetic"));
109+ QCOMPARE(music_prv->description(), QString("Lorem ipsum dolor sit amet"));
110+}
111+
112+QTEST_MAIN(PreviewBindingsTest)
113+
114+#include "previewbindingstest.moc"
plugins/LightDM/InfographicModel.h → tests/plugins/Unity/previewbindingstest.hrenamed+15−8
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2012,2013 Canonical, Ltd.
2+ * Copyright (C) 2011, 2013 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -12,16 +12,23 @@
1212 *
1313 * You should have received a copy of the GNU General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors: Pete Woods <pete.woods@canonical.com>
1715 */
1816
19−#ifndef INFOGRAPHICMODEL_H
20−#define INFOGRAPHICMODEL_H
17+#ifndef PREVIEWBINDINGSTEST_H
18+#define PREVIEWBINDINGSTEST_H
19+
20+#include <QObject>
2121
22−#include <QLightDM/InfographicModel>
22+class PreviewBindingsTest : public QObject
23+{
24+ Q_OBJECT
2325
24−typedef QLightDM::InfographicModel InfographicModel;
25−typedef QLightDM::InfographicColorTheme InfographicColorTheme;
26+ private Q_SLOTS:
27+ void initTestCase();
28+ void testGenericPreview();
29+ void testApplicationPreview();
30+ void testMoviePreview();
31+ void testMusicPreview();
32+};
2633
2734#endif
tests/plugins/Utils/qlimitproxymodeltest.cpp+15
@@ -446,6 +446,7 @@ private Q_SLOTS:
446446
447447 ModelTest t1(&proxy);
448448 }
449+
449450 void testModelChanged() {
450451 QLimitProxyModelQML proxy;
451452 MockListModel model, model2;
@@ -464,6 +465,20 @@ private Q_SLOTS:
464465 proxy.setModel(&model);
465466 QCOMPARE(spyOnModelChanged.count(), 3);
466467 }
468+
469+ void setSameModelTwice() {
470+ QLimitProxyModelQML proxy;
471+ MockListModel model;
472+
473+ proxy.setModel(&model);
474+ proxy.setModel(&model);
475+
476+ QSignalSpy spyOnCountChanged(&proxy, SIGNAL(countChanged()));
477+
478+ model.insertRows(0, 5);
479+ QCOMPARE(proxy.rowCount(), 5);
480+ QCOMPARE(spyOnCountChanged.count(), 1);
481+ }
467482};
468483
469484QTEST_MAIN(QLimitProxyModelTest)
tests/qmltests/CMakeLists.txt+15−15
@@ -1,11 +1,11 @@
11# add_qml_test macro
22include(QmlTest)
33
4−add_subdirectory(plugins)
4+add_subdirectory(Components)
55
66set(qmltest_DEFAULT_IMPORT_PATHS
7− ${CMAKE_CURRENT_BINARY_DIR}/plugins
87 ${CMAKE_BINARY_DIR}/tests/utils/modules
8+ ${CMAKE_BINARY_DIR}/tests/mocks
99)
1010
1111set(qmltest_DEFAULT_TARGETS qmlunittests)
@@ -25,9 +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+add_manual_qml_test(Components DragHandle IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
2829add_qml_test(Components DraggingArea)
2930add_qml_test(Components FilterGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins)
30−add_qml_test(Components ListViewWithPageHeader)
3131add_qml_test(Components ResponsiveFlowView)
3232add_qml_test(Components ResponsiveGridView)
3333add_qml_test(Components Revealer)
@@ -42,27 +42,27 @@ add_qml_test(Dash DashBar IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRE
4242add_qml_test(Dash DashContent IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS})
4343add_qml_test(Dash DashPreview)
4444add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
45−add_qml_test(Dash ScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_BINARY_DIR}/plugins)
45+add_qml_test(Dash ScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4646add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins
4747 ${CMAKE_BINARY_DIR}/tests/mocks)
4848add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
49−add_qml_test(Greeter Lockscreen IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/tests/mocks
50− PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
51−add_qml_test(Greeter Tablet IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/tests/mocks
52− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
53−add_qml_test(Greeter Phone IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/tests/mocks
54− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
55−add_qml_test(Greeter Infographics IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_BINARY_DIR}/tests/mocks
56− ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
49+add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
50+ PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
51+add_qml_test(Greeter Tablet IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
52+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
53+add_qml_test(Greeter Phone IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
54+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
55+add_qml_test(Greeter Infographics IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
56+ ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
5757add_qml_test(Hud Hud)
5858add_qml_test(Hud Result)
5959add_qml_test(Launcher Launcher IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
60−add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_CURRENT_SOURCE_DIR}/plugins)
60+add_qml_test(Notifications Notifications IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_SOURCE_DIR}/tests/mocks)
6161add_qml_test(Panel IndicatorRow)
62−add_qml_test(Panel Indicators)
62+add_qml_test(Panel Indicators IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
6363add_qml_test(Panel MenuContent)
6464add_qml_test(Panel Overview)
65−add_qml_test(Panel Panel)
65+add_qml_test(Panel Panel IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
6666add_qml_test(Panel SearchIndicator)
6767add_qml_test(Panel/Menus IndicatorMenuWindow IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS})
6868add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
tests/qmltests/Components/CMakeLists.txtnew file+23
@@ -0,0 +1,23 @@
1+########## tst_DragHandle
2+
3+include_directories(
4+ ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
5+ ${CMAKE_CURRENT_BINARY_DIR}
6+ )
7+
8+set(testCommand
9+ LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/plugins/Ubuntu/Gestures
10+ ${CMAKE_CURRENT_BINARY_DIR}/DragHandleTestExec
11+ -o ${CMAKE_BINARY_DIR}/DragHandleTest.xml,xunitxml
12+ -o -,txt)
13+
14+add_custom_target(testDragHandle ${testCommand})
15+add_dependencies(qmluitests testDragHandle)
16+add_dependencies(testDragHandle DragHandleTestExec)
17+
18+add_executable(DragHandleTestExec tst_DragHandle.cpp)
19+qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
20+target_link_libraries(DragHandleTestExec UbuntuGestureQml)
21+
22+add_definitions(-DUBUNTU_GESTURES_PLUGIN_DIR="${CMAKE_BINARY_DIR}/plugins")
23+add_definitions(-DTEST_DIR="${CMAKE_CURRENT_LIST_DIR}")
tests/qmltests/Components/tst_DragHandle.cppnew file+395
@@ -0,0 +1,395 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <functional>
18+#include <QtTest/QtTest>
19+#include <QtCore/QObject>
20+#include <qpa/qwindowsysteminterface.h>
21+#include <QtQuick/QQuickView>
22+#include <QtQml/QQmlEngine>
23+
24+#include <DirectionalDragArea.h>
25+
26+class FakeTimer : public UbuntuGestures::AbstractTimer
27+{
28+ Q_OBJECT
29+public:
30+ FakeTimer(QObject *parent = 0)
31+ : UbuntuGestures::AbstractTimer(parent)
32+ {}
33+
34+ virtual int interval() const { return m_duration; }
35+ virtual void setInterval(int msecs) { m_duration = msecs; }
36+private:
37+ int m_duration;
38+};
39+
40+class FakeTimeSource : public UbuntuGestures::TimeSource
41+{
42+public:
43+ FakeTimeSource() { m_msecsSinceReference = 0; }
44+ virtual qint64 msecsSinceReference() {return m_msecsSinceReference;}
45+ qint64 m_msecsSinceReference;
46+};
47+
48+class tst_DragHandle: public QObject
49+{
50+ Q_OBJECT
51+public:
52+ tst_DragHandle() : m_device(0) { }
53+private Q_SLOTS:
54+ void initTestCase(); // will be called before the first test function is executed
55+ void cleanupTestCase(); // will be called after the last test function was executed.
56+
57+ void init(); // called right before each and every test function is executed
58+ void cleanup(); // called right after each and every test function is executed
59+
60+ void dragThreshold_horizontal();
61+ void dragThreshold_vertical();
62+ void stretch_horizontal();
63+ void stretch_vertical();
64+ void hintingAnimation();
65+
66+private:
67+ void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
68+ DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
69+ qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
70+ void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
71+
72+ QQuickView *createView();
73+ QQuickView *m_view;
74+ QTouchDevice *m_device;
75+ FakeTimer *m_fakeTimer;
76+ FakeTimeSource *m_fakeTimeSource;
77+};
78+
79+
80+void tst_DragHandle::initTestCase()
81+{
82+ if (!m_device) {
83+ m_device = new QTouchDevice;
84+ m_device->setType(QTouchDevice::TouchScreen);
85+ QWindowSystemInterface::registerTouchDevice(m_device);
86+ }
87+
88+ m_view = 0;
89+}
90+
91+void tst_DragHandle::cleanupTestCase()
92+{
93+}
94+
95+void tst_DragHandle::init()
96+{
97+ m_view = createView();
98+ m_view->setSource(QUrl::fromLocalFile(TEST_DIR"/tst_DragHandle.qml"));
99+ m_view->show();
100+ QVERIFY(QTest::qWaitForWindowExposed(m_view));
101+ QVERIFY(m_view->rootObject() != 0);
102+ qApp->processEvents();
103+
104+ m_fakeTimer = new FakeTimer;
105+ m_fakeTimeSource = new FakeTimeSource;
106+}
107+
108+void tst_DragHandle::cleanup()
109+{
110+ delete m_view;
111+ m_view = 0;
112+
113+ delete m_fakeTimer;
114+ m_fakeTimer = 0;
115+
116+ delete m_fakeTimeSource;
117+ m_fakeTimeSource = 0;
118+}
119+
120+QQuickView *tst_DragHandle::createView()
121+{
122+ QQuickView *window = new QQuickView(0);
123+ window->setResizeMode(QQuickView::SizeRootObjectToView);
124+ window->resize(600, 600);
125+ window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
126+ window->engine()->addImportPath(QLatin1String(TEST_DIR));
127+
128+ return window;
129+}
130+
131+void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
132+ qreal expectedValue)
133+{
134+ int waitCount = 0;
135+ while (actualFunc() != expectedValue && waitCount < 100) {
136+ QTest::qWait(50);
137+ ++waitCount;
138+ }
139+ QCOMPARE(actualFunc(), expectedValue);
140+}
141+
142+namespace {
143+QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
144+{
145+
146+ switch (edgeDragArea->direction()) {
147+ case Direction::Upwards:
148+ return QPointF(0, -1);
149+ case Direction::Downwards:
150+ return QPointF(0, 1);
151+ case Direction::Leftwards:
152+ return QPointF(-1, 0);
153+ default: // Direction::Rightwards:
154+ return QPointF(1, 0);
155+ }
156+}
157+}
158+
159+void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
160+ qreal distance)
161+{
162+ QPointF initialTouchPos = dragHandle->mapToScene(
163+ QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
164+ QPointF touchPoint = initialTouchPos;
165+ int numSteps = 10;
166+ qint64 flickTimeMs = 500;
167+ qint64 timeStep = flickTimeMs / numSteps;
168+
169+ QPointF dragDirectionVector = calculateDirectionVector(dragHandle);
170+ QPointF touchMovement = dragDirectionVector * (distance / (qreal)numSteps);
171+
172+ QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
173+
174+ for (int i = 0; i < numSteps; ++i) {
175+ touchPoint += touchMovement;
176+ m_fakeTimeSource->m_msecsSinceReference += timeStep;
177+ QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
178+ }
179+
180+ // Wait for quite a bit before finally releasing to make a very low flick/release
181+ // speed.
182+ m_fakeTimeSource->m_msecsSinceReference += 5000;
183+ QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
184+}
185+
186+DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
187+{
188+ DirectionalDragArea *dragHandle =
189+ m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
190+ Q_ASSERT(dragHandle != 0);
191+ dragHandle->setRecognitionTimer(m_fakeTimer);
192+ dragHandle->setTimeSource(m_fakeTimeSource);
193+
194+ AxisVelocityCalculator *edgeDragEvaluator =
195+ dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
196+ Q_ASSERT(edgeDragEvaluator != 0);
197+ edgeDragEvaluator->setTimeSource(m_fakeTimeSource);
198+
199+ return dragHandle;
200+}
201+
202+qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
203+{
204+ AxisVelocityCalculator *edgeDragEvaluator =
205+ dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
206+ Q_ASSERT(edgeDragEvaluator != 0);
207+
208+ return edgeDragEvaluator->property("dragThreshold").toReal();
209+}
210+
211+/*
212+ Checks that ending a low-speed drag before dragThreshold results in the
213+ Showable getting back to its original position, whereas ending after dragThreshold
214+ results in Showable continuing until reaching its new states (shown or hidden)
215+ */
216+void tst_DragHandle::dragThreshold_horizontal()
217+{
218+ DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
219+
220+ qreal dragThreshold = fetchDragThreshold(dragHandle);
221+
222+ // end before the threshold
223+ flickAndHold(dragHandle, dragThreshold * 0.7);
224+
225+ // should rollback
226+ QQuickItem *parentItem = dragHandle->parentItem();
227+ tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
228+ QCOMPARE(parentItem->property("shown").toBool(), false);
229+
230+ // end after the threshold
231+ flickAndHold(dragHandle, dragThreshold * 1.2);
232+
233+ // should keep going until completion
234+ tryCompare([&](){ return parentItem->x(); }, 0);
235+ QCOMPARE(parentItem->property("shown").toBool(), true);
236+
237+ dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
238+
239+ dragThreshold = fetchDragThreshold(dragHandle);
240+
241+ // end before the threshold
242+ flickAndHold(dragHandle, dragThreshold * 0.7);
243+
244+ // should rollback
245+ tryCompare([&](){ return parentItem->x(); }, 0);
246+ QCOMPARE(parentItem->property("shown").toBool(), true);
247+
248+ // end after the threshold
249+ flickAndHold(dragHandle, dragThreshold * 1.2);
250+
251+ // should keep going until completion
252+ tryCompare([&](){ return parentItem->x(); }, -parentItem->width());
253+ QCOMPARE(parentItem->property("shown").toBool(), false);
254+}
255+
256+void tst_DragHandle::dragThreshold_vertical()
257+{
258+ DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
259+
260+ qreal dragThreshold = fetchDragThreshold(dragHandle);
261+
262+ // end before the threshold
263+ flickAndHold(dragHandle, dragThreshold * 0.7);
264+
265+ // should rollback
266+ QQuickItem *parentItem = dragHandle->parentItem();
267+ tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
268+ QCOMPARE(parentItem->property("shown").toBool(), false);
269+
270+ // end after the threshold
271+ flickAndHold(dragHandle, dragThreshold * 1.2);
272+
273+ // should keep going until completion
274+ tryCompare([&](){ return parentItem->y(); }, 0);
275+ QCOMPARE(parentItem->property("shown").toBool(), true);
276+
277+ dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
278+
279+ dragThreshold = fetchDragThreshold(dragHandle);
280+
281+ // end before the threshold
282+ flickAndHold(dragHandle, dragThreshold * 0.7);
283+
284+ // should rollback
285+ tryCompare([&](){ return parentItem->y(); }, 0);
286+ QCOMPARE(parentItem->property("shown").toBool(), true);
287+
288+ // end after the threshold
289+ flickAndHold(dragHandle, dragThreshold * 1.2);
290+
291+ // should keep going until completion
292+ tryCompare([&](){ return parentItem->y(); }, -parentItem->height());
293+ QCOMPARE(parentItem->property("shown").toBool(), false);
294+}
295+
296+/*
297+ Checks that when the stretch property is true, dragging the DragHandle increases
298+ the width or height (depending on its direction) of its parent Showable
299+ */
300+void tst_DragHandle::stretch_horizontal()
301+{
302+ DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
303+ qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
304+ QQuickItem *parentItem = dragHandle->parentItem();
305+
306+ // enable strech mode
307+ m_view->rootObject()->setProperty("stretch", QVariant(true));
308+
309+ QCOMPARE(parentItem->width(), 0.0);
310+
311+ // flick all the way
312+ flickAndHold(dragHandle, totalDragDistance);
313+
314+ // should keep going until completion
315+ // Parent item should now have its full height
316+ tryCompare([&](){ return parentItem->width(); }, totalDragDistance);
317+ QCOMPARE(parentItem->property("shown").toBool(), true);
318+
319+ dragHandle = fetchAndSetupDragHandle("leftwardsDragHandle");
320+
321+ // flick all the way
322+ flickAndHold(dragHandle, totalDragDistance);
323+
324+ // should keep going until completion
325+ // Parent item should now have its full height
326+ tryCompare([&](){ return parentItem->width(); }, 0.0);
327+ QCOMPARE(parentItem->property("shown").toBool(), false);
328+}
329+
330+void tst_DragHandle::stretch_vertical()
331+{
332+ DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
333+ qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
334+ QQuickItem *parentItem = dragHandle->parentItem();
335+
336+ // enable strech mode
337+ m_view->rootObject()->setProperty("stretch", QVariant(true));
338+
339+ QCOMPARE(parentItem->height(), 0.0);
340+
341+ // flick all the way
342+ flickAndHold(dragHandle, totalDragDistance);
343+
344+ // should keep going until completion
345+ // Parent item should now have its full height
346+ tryCompare([&](){ return parentItem->height(); }, totalDragDistance);
347+ QCOMPARE(parentItem->property("shown").toBool(), true);
348+
349+ dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
350+
351+ // flick all the way
352+ flickAndHold(dragHandle, totalDragDistance);
353+
354+ // should keep going until completion
355+ // Parent item should now have its full height
356+ tryCompare([&](){ return parentItem->height(); }, 0.0);
357+ QCOMPARE(parentItem->property("shown").toBool(), false);
358+}
359+
360+/*
361+ Set DragHandle.hintDisplacement to a value bigger than zero.
362+ Then lay a finger on the DragHandle.
363+ The expected behavior is that it will move or strech its parent Showable
364+ by hintDisplacement pixels.
365+ */
366+void tst_DragHandle::hintingAnimation()
367+{
368+ DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
369+ QQuickItem *parentItem = dragHandle->parentItem();
370+ qreal hintDisplacement = 100.0;
371+
372+ // enable hinting animations and stretch mode
373+ m_view->rootObject()->setProperty("hintDisplacement", QVariant(hintDisplacement));
374+ m_view->rootObject()->setProperty("stretch", QVariant(true));
375+
376+ QCOMPARE(parentItem->height(), 0.0);
377+
378+ QPointF initialTouchPos = dragHandle->mapToScene(
379+ QPointF(dragHandle->width() / 2.0, dragHandle->height() / 2.0));
380+ QPointF touchPoint = initialTouchPos;
381+
382+ // Pressing causes the Showable to be stretched by hintDisplacement pixels
383+ QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
384+ tryCompare([&](){ return parentItem->height(); }, hintDisplacement);
385+
386+ // Releasing causes the Showable to shrink back to 0 pixels.
387+ QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
388+ tryCompare([&](){ return parentItem->height(); }, 0.0);
389+
390+ QCOMPARE(parentItem->property("shown").toBool(), false);
391+}
392+
393+QTEST_MAIN(tst_DragHandle)
394+
395+#include "tst_DragHandle.moc"
tests/qmltests/Components/tst_DragHandle.qmlnew file+146
@@ -0,0 +1,146 @@
1+/*
2+ * Copyright 2013 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../../../Components"
19+import "tst_DragHandle"
20+import Ubuntu.Components 0.1
21+import Ubuntu.Gestures 0.1
22+
23+/*
24+ Two blue fullscreen Showables (a vertical and a horizontal one) with red handles you
25+ can use to drag them away and green handles to drag them in.
26+
27+ A black vertical line marks the point where a drag needs no forward velocity to
28+ achieve auto-completion (i.e., get Showable.show() called after touch release).
29+ */
30+Item {
31+ id: root
32+ width: 700
33+ height: 500
34+
35+ property var dragHandle
36+
37+ property bool stretch: false
38+ property real hintDisplacement: 0
39+
40+ VerticalShowable {
41+ onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
42+ stretch: root.stretch
43+ hintDisplacement: root.hintDisplacement
44+ }
45+
46+ HorizontalShowable {
47+ onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
48+ stretch: root.stretch
49+ hintDisplacement: root.hintDisplacement
50+ }
51+
52+ // Visually mark drag threshold
53+ Rectangle {
54+ color: "black"
55+ width: 2
56+ height: parent.height
57+
58+ visible: dragHandle !== undefined && Direction.isHorizontal(dragHandle.direction)
59+
60+ x: {
61+ if (dragHandle) {
62+ if (dragHandle.direction === Direction.Rightwards) {
63+ dragHandle.edgeDragEvaluator.dragThreshold;
64+ } else {
65+ parent.width - dragHandle.edgeDragEvaluator.dragThreshold;
66+ }
67+ } else {
68+ 0
69+ }
70+ }
71+ }
72+ Rectangle {
73+ color: "black";
74+ height: 2
75+ width: parent.width
76+
77+ visible: dragHandle !== undefined && Direction.isVertical(dragHandle.direction)
78+
79+ y: {
80+ if (dragHandle) {
81+ if (dragHandle.direction === Direction.Downwards) {
82+ dragHandle.edgeDragEvaluator.dragThreshold;
83+ } else {
84+ parent.height - dragHandle.edgeDragEvaluator.dragThreshold;
85+ }
86+ } else {
87+ 0
88+ }
89+ }
90+ }
91+
92+ // Display velocities
93+ Rectangle {
94+ width: childrenRect.width
95+ height: childrenRect.height
96+ color: "white"
97+ opacity: 0.4
98+ Text {
99+ id: velocityText
100+ font.pixelSize: units.gu(2)
101+ text: {
102+ if (dragHandle !== undefined) {
103+ "Velocity: " + (dragHandle.edgeDragEvaluator.velocity * 1000);
104+ } else {
105+ "Velocity: -";
106+ }
107+ }
108+ }
109+ Text {
110+ anchors.top: velocityText.bottom
111+ font.pixelSize: units.gu(2)
112+ text: {
113+ if (dragHandle !== undefined) {
114+ "Minimum velocity: " + (dragHandle.edgeDragEvaluator.minVelocity * 1000);
115+ } else {
116+ "Minimum velocity: -";
117+ }
118+ }
119+ }
120+ }
121+
122+ TestButton {
123+ id: stretchButton
124+ anchors.bottom: parent.bottom
125+ anchors.left: parent.left
126+ anchors.margins: units.gu(1)
127+
128+ text: root.stretch ? "stretch" : "move"
129+ onClicked: { root.stretch = !root.stretch; }
130+ }
131+
132+ TestButton {
133+ anchors.bottom: parent.bottom
134+ anchors.left: stretchButton.right
135+ anchors.margins: units.gu(1)
136+
137+ text: root.hintDisplacement > 0 ? "hint" : "no hint"
138+ onClicked: {
139+ if (root.hintDisplacement > 0) {
140+ root.hintDisplacement = 0;
141+ } else {
142+ root.hintDisplacement = units.gu(6);
143+ }
144+ }
145+ }
146+}
tests/qmltests/Components/tst_DragHandle/HorizontalShowable.qmlnew file+100
@@ -0,0 +1,100 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../../../../Components"
19+import Ubuntu.Components 0.1
20+import Ubuntu.Gestures 0.1
21+
22+Showable {
23+ id: showable
24+ x: stretch ? 0 : -width
25+ width: stretch ? 0 : parent.width
26+ height: parent.height
27+
28+ property bool stretch
29+ property real hintDisplacement
30+
31+ onStretchChanged: {
32+ if (stretch) {
33+ x = 0;
34+ width = 0;
35+ } else {
36+ x = -parent.width;
37+ width = parent.width;
38+ }
39+ }
40+
41+ shown: false
42+
43+ signal dragHandleRecognizedGesture(var dragHandle)
44+
45+ property string animatedProp: stretch ? "width" : "x"
46+ property real propValueWhenShown: stretch ? parent.width : 0
47+ property real propValueWhenHidden: stretch ? 0 : -width
48+
49+ showAnimation: StandardAnimation { property: animatedProp; to: propValueWhenShown }
50+ hideAnimation: StandardAnimation { property: animatedProp; to: propValueWhenHidden }
51+
52+ Image { source: "UnityLogo.png"; anchors.fill: parent }
53+
54+ DragHandle {
55+ objectName: "leftwardsDragHandle"
56+ id: leftwardsDragHandle
57+ anchors.top: parent.top
58+ anchors.bottom: parent.bottom
59+ anchors.right: parent.right
60+
61+ width: units.gu(2)
62+
63+ direction: Direction.Leftwards
64+ stretch: showable.stretch
65+ maxTotalDragDistance: showable.parent.width
66+ hintDisplacement: showable.hintDisplacement
67+
68+ onStatusChanged: {
69+ if (status === DirectionalDragArea.Recognized) {
70+ dragHandleRecognizedGesture(leftwardsDragHandle);
71+ }
72+ }
73+
74+ Rectangle { color: "red"; anchors.fill: parent }
75+ }
76+
77+ DragHandle {
78+ objectName: "rightwardsDragHandle"
79+ id: rightwardsDragHandle
80+ anchors.top: parent.top
81+ anchors.bottom: parent.bottom
82+ anchors.left: parent.right
83+
84+ width: units.gu(2)
85+
86+ direction: Direction.Rightwards
87+ stretch: showable.stretch
88+ maxTotalDragDistance: showable.parent.width
89+ hintDisplacement: showable.hintDisplacement
90+
91+ onStatusChanged: {
92+ if (status === DirectionalDragArea.Recognized) {
93+ dragHandleRecognizedGesture(rightwardsDragHandle);
94+ }
95+ }
96+
97+ Rectangle { color: "green"; anchors.fill: parent }
98+ }
99+
100+}
tests/qmltests/Components/tst_DragHandle/TestButton.qmlnew file+41
@@ -0,0 +1,41 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+
20+Rectangle {
21+ id: rect
22+ width: childrenRect.width
23+ height: childrenRect.height
24+
25+ property alias text: textComponent.text
26+
27+ signal clicked
28+
29+ color: "yellow"
30+ Text {
31+ id: textComponent
32+ font.pixelSize: units.gu(2)
33+ text: root.stretch ? "stretch" : "move"
34+ MouseArea {
35+ anchors.fill: parent
36+ onClicked: {
37+ rect.clicked()
38+ }
39+ }
40+ }
41+}
tests/qmltests/Components/tst_DragHandle/UnityLogo.pngnew file

Binary file not shown.

tests/qmltests/Components/tst_DragHandle/VerticalShowable.qmlnew file+100
@@ -0,0 +1,100 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../../../../Components"
19+import Ubuntu.Components 0.1
20+import Ubuntu.Gestures 0.1
21+
22+Showable {
23+ id: showable
24+ y: stretch ? 0 : -height
25+ width: parent.width
26+ height: stretch ? 0 : parent.height
27+
28+ property bool stretch
29+ property real hintDisplacement
30+
31+ onStretchChanged: {
32+ if (stretch) {
33+ y = 0;
34+ height = 0;
35+ } else {
36+ y = -parent.height;
37+ height = parent.height;
38+ }
39+ }
40+
41+ shown: false
42+
43+ signal dragHandleRecognizedGesture(var dragHandle)
44+
45+ property string animatedProp: stretch ? "height" : "y"
46+ property real propValueWhenShown: stretch ? parent.height : 0
47+ property real propValueWhenHidden: stretch ? 0 : -height
48+
49+ showAnimation: StandardAnimation { property: animatedProp; to: propValueWhenShown }
50+ hideAnimation: StandardAnimation { property: animatedProp; to: propValueWhenHidden }
51+
52+ Image { source: "UnityLogo.png"; anchors.fill: parent }
53+
54+ DragHandle {
55+ objectName: "upwardsDragHandle"
56+ id: upwardsDragHandle
57+ anchors.left: parent.left
58+ anchors.right: parent.right
59+ anchors.bottom: parent.bottom
60+
61+ height: units.gu(2)
62+
63+ direction: Direction.Upwards
64+ stretch: showable.stretch
65+ maxTotalDragDistance: showable.parent.height
66+ hintDisplacement: showable.hintDisplacement
67+
68+ onStatusChanged: {
69+ if (status === DirectionalDragArea.Recognized) {
70+ dragHandleRecognizedGesture(upwardsDragHandle);
71+ }
72+ }
73+
74+ Rectangle { color: "red"; anchors.fill: parent }
75+ }
76+
77+ DragHandle {
78+ objectName: "downwardsDragHandle"
79+ id: downwardsDragHandle
80+ anchors.left: parent.left
81+ anchors.right: parent.right
82+ anchors.top: parent.bottom
83+
84+ height: units.gu(2)
85+
86+ direction: Direction.Downwards
87+ stretch: showable.stretch
88+ maxTotalDragDistance: showable.parent.height
89+ hintDisplacement: showable.hintDisplacement
90+
91+ onStatusChanged: {
92+ if (status === DirectionalDragArea.Recognized) {
93+ dragHandleRecognizedGesture(downwardsDragHandle);
94+ }
95+ }
96+
97+ Rectangle { color: "green"; anchors.fill: parent }
98+ }
99+
100+}
tests/qmltests/Components/tst_ListViewWithPageHeader.qmldeleted−351
@@ -1,351 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import ".."
20−import "../../../Components"
21−import Ubuntu.Components.ListItems 0.1 as ListItem
22−import Ubuntu.Components 0.1
23−import Unity.Test 0.1 as UT
24−
25−Item {
26− id: root
27− width: units.gu(40)
28− height: units.gu(80)
29−
30− ListModel {
31− id: animalsModel
32− ListElement { name: "Parrot"; size: "Small" }
33− ListElement { name: "Guinea pig"; size: "Small" }
34− ListElement { name: "Mouse"; size: "Small" }
35− ListElement { name: "Sparrow"; size: "Small" }
36− ListElement { name: "Dog"; size: "Medium" }
37− ListElement { name: "Cat"; size: "Medium" }
38− ListElement { name: "Dolphin"; size: "Medium" }
39− ListElement { name: "Seal"; size: "Medium" }
40− ListElement { name: "Elephant"; size: "Large" }
41− ListElement { name: "Blue whale"; size: "Large" }
42− ListElement { name: "Rhino"; size: "Large" }
43− ListElement { name: "Ostrich"; size: "Large" }
44− ListElement { name: "Sperm whale"; size: "Large" }
45− ListElement { name: "Giraffe"; size: "Large" }
46− ListElement { name: "Parrot"; size: "Small" }
47− ListElement { name: "Guinea pig"; size: "Small" }
48− ListElement { name: "Mouse"; size: "Small" }
49− ListElement { name: "Sparrow"; size: "Small" }
50− ListElement { name: "Dog"; size: "Medium" }
51− ListElement { name: "Cat"; size: "Medium" }
52− ListElement { name: "Dolphin"; size: "Medium" }
53− ListElement { name: "Seal"; size: "Medium" }
54− ListElement { name: "Elephant"; size: "Large" }
55− ListElement { name: "Blue whale"; size: "Large" }
56− ListElement { name: "Rhino"; size: "Large" }
57− ListElement { name: "Ostrich"; size: "Large" }
58− ListElement { name: "Sperm whale"; size: "Large" }
59− ListElement { name: "Giraffe"; size: "Large" }
60− ListElement { name: "Parrot"; size: "Small" }
61− ListElement { name: "Guinea pig"; size: "Small" }
62− ListElement { name: "Mouse"; size: "Small" }
63− ListElement { name: "Sparrow"; size: "Small" }
64− ListElement { name: "Dog"; size: "Medium" }
65− ListElement { name: "Cat"; size: "Medium" }
66− ListElement { name: "Dolphin"; size: "Medium" }
67− ListElement { name: "Seal"; size: "Medium" }
68− ListElement { name: "Elephant"; size: "Large" }
69− ListElement { name: "Blue whale"; size: "Large" }
70− ListElement { name: "Rhino"; size: "Large" }
71− ListElement { name: "Ostrich"; size: "Large" }
72− ListElement { name: "Sperm whale"; size: "Large" }
73− ListElement { name: "Giraffe"; size: "Large" }
74− ListElement { name: "Parrot"; size: "Small" }
75− ListElement { name: "Guinea pig"; size: "Small" }
76− ListElement { name: "Mouse"; size: "Small" }
77− ListElement { name: "Sparrow"; size: "Small" }
78− ListElement { name: "Dog"; size: "Medium" }
79− ListElement { name: "Cat"; size: "Medium" }
80− ListElement { name: "Dolphin"; size: "Medium" }
81− ListElement { name: "Seal"; size: "Medium" }
82− ListElement { name: "Elephant"; size: "Large" }
83− ListElement { name: "Blue whale"; size: "Large" }
84− ListElement { name: "Rhino"; size: "Large" }
85− ListElement { name: "Ostrich"; size: "Large" }
86− ListElement { name: "Sperm whale"; size: "Large" }
87− ListElement { name: "Giraffe"; size: "Large" }
88− }
89−
90− ListViewWithPageHeader {
91− id: listView
92− anchors.fill: parent
93− model: animalsModel
94−
95− delegate: Item {
96− height: units.gu(6)
97− anchors {
98− left: parent.left
99− right: parent.right
100− }
101−
102− Label {
103− id: label
104− anchors.fill: parent
105− text: name
106− verticalAlignment: Text.AlignVCenter
107− }
108− }
109−
110− sectionProperty: "size"
111− sectionDelegate: Rectangle {
112− anchors {
113− left: (parent) ? parent.left : undefined
114− right: (parent) ? parent.right : undefined
115− }
116− height: units.gu(5)
117− color: "lightsteelblue"
118−
119− Label {
120− id: label
121− anchors.fill: parent
122− text: section
123− verticalAlignment: Text.AlignVCenter
124− }
125− }
126−
127− pageHeader: PageHeader {
128− id: pageHeader
129− anchors {
130− left: parent.left
131− right: parent.right
132− }
133− text: "Animals"
134− }
135− }
136−
137−
138−
139−
140− UT.UnityTestCase {
141− name: "ListViewWithPageHeader"
142− when: windowShown
143−
144− readonly property real xPos: listView.width / 2
145− readonly property real headerHeight: pageHeader.height
146−
147− /**************************** Helper functions ****************************/
148− function listViewFirstSectionHeaderYPosition() {
149− return Math.round(listView.pageHeader.mapToItem(listView).y); //round as using floats
150− }
151−
152− function firstSectionHeaderYPosition() {
153− return Math.round(listView.view.children[0].mapToItem(listView).y);
154− }
155−
156− function cleanup() {
157− listView.positionAtBeginning();
158− // wait for list position to reset
159− tryCompareFunction(listViewFirstSectionHeaderYPosition, 0);
160− tryCompare(listView.view.contentY, 0);
161− }
162−
163− // these functions are hand-crafted to move the Flickable down/up one pixel
164− function swipeDown1Pixel(item) {
165− mousePress(item, xPos, 15);
166− mouseMove(item, xPos, 14, 100);
167− mouseMove(item, xPos, 10, 100);
168− mouseMove(item, xPos, 6, 100);
169− mouseMove(item, xPos, 3, 100);
170− mouseMove(item, xPos, 1, 100);
171− mouseMove(item, xPos, 0, 100);
172− mouseRelease(item, xPos, 0);
173− }
174−
175− function swipeUp1Pixel(item) {
176− mousePress(item, xPos, 0);
177− mouseMove(item, xPos, 1, 100);
178− mouseMove(item, xPos, 5, 100);
179− mouseMove(item, xPos, 9, 100);
180− mouseMove(item, xPos, 12, 100);
181− mouseMove(item, xPos, 14, 100);
182− mouseMove(item, xPos, 15, 100);
183− mouseRelease(item, xPos, 15);
184− }
185−
186− /******************************* Test cases *******************************/
187−
188− /* Check the initial positions of components are correct */
189− function test_initialState() {
190− compare(listViewFirstSectionHeaderYPosition(), 0);
191− compare(listView.view.contentY, 0);
192−
193− // Check that the section delegate is positioned underneath the header
194− // First section delegate is the first child of the view
195− tryCompareFunction(firstSectionHeaderYPosition, headerHeight);
196− }
197−
198− /* Check the header moves up one pixel when the view is moved up by one pixel */
199− function test_headerPositionAfterDownMoveByOnePixel() {
200− swipeDown1Pixel(listView)
201−
202− tryCompareFunction(listViewFirstSectionHeaderYPosition, -1);
203− tryCompareFunction(firstSectionHeaderYPosition, headerHeight - 1);
204− tryCompare(listView.view.contentY, -1);
205− }
206−
207− /* Check the header position is y=0 when view moved up and then down by one pixel */
208− function test_headerPositionAfterDownAndThenUpMoveByOne() {
209− swipeDown1Pixel(listView)
210−
211− tryCompareFunction(listViewFirstSectionHeaderYPosition, -1);
212− tryCompare(listView.view.contentY, -1);
213−
214− // these operations move the Flickabe up one pixel
215− swipeUp1Pixel(listView);
216−
217− tryCompare(listView.view.contentY, 0);
218− // tryCompareFunction(listViewFirstSectionHeaderYPosition, 0) //FIXME - this fails due to bug in LVWPH
219− tryCompareFunction(firstSectionHeaderYPosition, headerHeight)
220− }
221−
222− /* Check after a big flick the header is moved off-screen, with the header bottom
223− placed just above the view */
224− function test_headerPositionAfterDownMove() {
225− // move the Flickabe up to hide header
226− listView.flick(0, -10000);
227−
228− // wait for flick to finish
229− tryCompare(listView.moving, false);
230−
231− tryCompareFunction(listViewFirstSectionHeaderYPosition, -headerHeight);
232− }
233−
234− /* Check when header off-screen, moving down the view by one pixel moves the header
235− down by one pixel */
236− function test_hiddenHeaderPositionAfterUpMoveByOnePixel() {
237− // move the Flickabe up to hide header
238− listView.flick(0, -10000);
239−
240− // wait for flick to fully hide header
241− tryCompareFunction(listViewFirstSectionHeaderYPosition, -headerHeight);
242−
243− swipeUp1Pixel(listView);
244−
245− tryCompareFunction( function() {
246− return Math.floor( listViewFirstSectionHeaderYPosition() ); // need to round to make test more robust
247− }, -headerHeight + 1);
248− }
249−
250− /* Check if up swipe causes list to bounces at the bottom, header stays hidden */
251− function test_upSwipeCausingBounceKeepsHeaderHidden() {
252− // move list to the bottom (will bounce)
253− listView.flick(0, -1000000);
254−
255− // wait for bounce to complete
256− tryCompare(listView.moving, false);
257− tryCompare(listView.view.atYEnd, true);
258−
259− tryCompareFunction(listViewFirstSectionHeaderYPosition, -headerHeight);
260− }
261−
262− /* Check if up swipe causes list to bounces at the bottom, header stays hidden */
263− function test_downSwipeCausingBounceKeepsHeaderVisible() {
264− // move list to the bottom (will bounce)
265− listView.flick(0, -1000000);
266−
267− // wait for bounce to complete
268− tryCompare(listView.moving, false);
269− tryCompare(listView.view.atYBeginning, true);
270−
271− tryCompareFunction(listViewFirstSectionHeaderYPosition, 0);
272− }
273−
274− /* Check if list at top is pulled down further, that the list contents move but the
275− header remains at the top of the view */
276− function test_topDragOverBoundsKeepsHeaderVisible() {
277− // drag list up - but don't release yet
278− mouseFlick(listView,
279− xPos, // from_x
280− 0, // from_y
281− xPos, // to_x
282− 100, true, false, 0.2);
283−
284− // wait for gesture to occur
285− tryCompareFunction(function() { return listView.view.contentY < 20; }, true);
286− tryCompareFunction(listViewFirstSectionHeaderYPosition, 0);
287−
288− mouseRelease(listView, xPos, 400);
289−
290− // ensure list moving to recover from over-bound drag keeps header unchanged
291− tryCompare(listView.view.contentY, 0);
292− tryCompareFunction(listViewFirstSectionHeaderYPosition, 0);
293− }
294−
295− /* Check if list at top is pulled down further, that the list contents move but the
296− header remains at the top of the view */
297− function test_bottomDragOverBoundsKeepsHeaderHidden() {
298− // move list to the bottom (will bounce)
299− listView.flick(0, -1000000);
300−
301− // wait for bounce to complete
302− tryCompare(listView.moving, false);
303− tryCompare(listView.view.atYEnd, true);
304−
305− // drag list up but don't release
306− mouseFlick(listView,
307− xPos, // from_x
308− 0, // from_y
309− xPos, // to_x
310− -listView.height, true, false);
311−
312− tryCompareFunction(listViewFirstSectionHeaderYPosition, -headerHeight);
313−
314− mouseRelease(listView, xPos, -listView.height);
315− // wait for list to reset position
316− tryCompare(listView.moving, false);
317− tryCompare(listView.view.atYEnd, true);
318−
319− // ensure list moving to recover from over-bound drag keeps header unchanged
320− tryCompareFunction(listViewFirstSectionHeaderYPosition, -headerHeight);
321− }
322−
323− /* Check positionAtBeginning() works resets list and header position */
324− function test_positionAtBeginning() {
325− // move the Flickabe up to hide header
326− listView.flick(0, -10000);
327−
328− // wait for gesture to complete
329− tryCompare(listView.moving, false);
330−
331− listView.positionAtBeginning();
332− tryCompareFunction(listViewFirstSectionHeaderYPosition, 0);
333− tryCompare(listView.view.contentY, 0);
334− }
335−
336− /* Check showHeader forces header to appear but list position remains unchanged */
337− function test_showHeader() {
338− // move the Flickabe up to hide header
339− listView.flick(0, -10000);
340−
341− // wait for gesture to complete
342− tryCompare(listView.moving, false);
343−
344− var listContentY = listView.view.contentY;
345−
346− listView.showHeader();
347− tryCompareFunction(listViewFirstSectionHeaderYPosition, 0);
348− tryCompare(listView.view.contentY, listContentY);
349− }
350− }
351−}
tests/qmltests/Components/tst_Stage.qml+1−2
@@ -233,8 +233,7 @@ Rectangle {
233233
234234 var touchX = stage.width - (stage.rightEdgeDraggingAreaWidth / 2)
235235 var touchY = stage.height / 2
236− touchFlick(stage, touchX, touchY,
237− touchX - units.gu(5), touchY)
236+ touchFlick(stage, touchX, touchY, stage.width * 0.25, touchY)
238237
239238 // wait until animations end, if any
240239 tryCompare(stage, "usingScreenshots", false)
tests/qmltests/Greeter/tst_Lockscreen.qml+7−1
@@ -187,8 +187,8 @@ Rectangle {
187187 unlockedCheckBox.checked = false
188188 LightDM.Greeter.authenticate(data.username)
189189
190+ var inputField = findChild(lockscreen, "pinentryField")
190191 if (data.alphanumeric) {
191− var inputField = findChild(lockscreen, "pinentryField")
192192 mouseClick(inputField, units.gu(1), units.gu(1))
193193 typeString(data.password)
194194 keyClick(Qt.Key_Enter)
@@ -200,6 +200,12 @@ Rectangle {
200200 }
201201 }
202202 tryCompare(unlockedCheckBox, "checked", data.unlockedSignal)
203+ if (!data.unlockedSignal) {
204+ // make sure the input is cleared on wrong input
205+ tryCompareFunction(function() {return inputField.text.length == 0}, true)
206+ } else {
207+ tryCompareFunction(function() {return inputField.text.length > 0}, true)
208+ }
203209 }
204210 }
205211}
tests/qmltests/Greeter/tst_Phone.qml+40−1
@@ -28,7 +28,17 @@ Item {
2828
2929 Greeter {
3030 id: greeter
31− anchors.fill: parent
31+ width: parent.width
32+ height: parent.height
33+ x: 0; y: 0
34+
35+ property int minX: 0
36+
37+ onXChanged: {
38+ if (x < minX) {
39+ minX = x;
40+ }
41+ }
3242 }
3343
3444 SignalSpy {
@@ -63,5 +73,34 @@ Item {
6373 tryCompare(greeter, "leftTeaserPressed", false)
6474 tryCompare(greeter, "rightTeaserPressed", false)
6575 }
76+
77+ function test_teaseLockedUnlocked_data() {
78+ return [
79+ {tag: "unlocked", locked: false},
80+ {tag: "locked", locked: true}
81+ ];
82+ }
83+
84+ function test_teaseLockedUnlocked(data) {
85+ tryCompare(greeter, "rightTeaserPressed", false);
86+ tryCompare(greeter, "x", 0);
87+ greeter.locked = data.locked;
88+
89+ mouseClick(greeter, greeter.width - units.gu(5), greeter.height - units.gu(1));
90+ greeter.minX = 0; // This is needed because the transition actually makes x jump once before animating
91+
92+ if (!data.locked) {
93+ // Check if it has been moved over by 2 GUs. Give it a 2 pixel grace area
94+ // because animation duration and teaseTimer are the same duration and
95+ // might cause slight offsets
96+ tryCompareFunction(function() { return greeter.minX <= -units.gu(2) + 2}, true);
97+ } else {
98+ // waiting 100ms to make sure nothing moves
99+ wait(100);
100+ compare(greeter.minX, 0, "Greeter moved even tho its locked");
101+ }
102+ // Wait until we're back to 0
103+ tryCompareFunction(function() { return greeter.x;}, 0);
104+ }
66105 }
67106}
tests/qmltests/Launcher/tst_Launcher.qml+40
@@ -43,6 +43,18 @@ Item {
4343 onDashItemSelected: {
4444 dashItemSelected_count++;
4545 }
46+
47+ property int maxPanelX: 0
48+ }
49+
50+ Connections {
51+ target: testCase.findChild(launcher, "launcherPanel")
52+
53+ onXChanged: {
54+ if (target.x > launcher.maxPanelX) {
55+ launcher.maxPanelX = target.x;
56+ }
57+ }
4658 }
4759
4860 UT.UnityTestCase {
@@ -126,5 +138,33 @@ Item {
126138 var panel = findChild(launcher, "launcherPanel")
127139 tryCompare(panel, "x", -panel.width, 1000)
128140 }
141+
142+
143+ function test_teaseLauncher_data() {
144+ return [
145+ {tag: "available", available: true},
146+ {tag: "not available", available: false}
147+ ];
148+ }
149+
150+ function test_teaseLauncher(data) {
151+ launcher.available = data.available;
152+ launcher.maxPanelX = -launcher.panelWidth;
153+ launcher.tease();
154+
155+ if (data.available) {
156+ // Check if the launcher slides in for units.gu(2). However, as the animation is 200ms
157+ // and the teaseTimer's timeout too, give it a 2 pixels grace distance
158+ tryCompareFunction(
159+ function(){
160+ return launcher.maxPanelX >= -launcher.panelWidth + units.gu(2) - 2;
161+ },
162+ true)
163+ } else {
164+ wait(100)
165+ compare(launcher.maxPanelX, -launcher.panelWidth, "Launcher moved even if it shouldn't")
166+ }
167+ waitUntilLauncherDisappears();
168+ }
129169 }
130170}
tests/qmltests/Notifications/tst_Notifications.qml+48−7
@@ -53,7 +53,10 @@ Row {
5353 icon: "../graphics/avatars/funky.png",
5454 secondaryIcon: "../graphics/applicationIcons/facebook.png",
5555 actions: [{ id: "ok_id", label: "Ok"},
56− { id: "cancel_id", label: "Cancel"}]
56+ { id: "cancel_id", label: "Cancel"},
57+ { id: "notreally_id", label: "Not really"},
58+ { id: "noway_id", label: "No way"},
59+ { id: "nada_id", label: "Nada"}]
5760 }
5861
5962 mockModel.append(n)
@@ -132,7 +135,7 @@ Row {
132135 id: interactiveControls
133136
134137 width: units.gu(30)
135− height: units.gu(71)
138+ height: units.gu(81)
136139 color: "grey"
137140
138141 Column {
@@ -193,7 +196,10 @@ Row {
193196 icon: "../graphics/avatars/funky.png",
194197 secondaryIcon: "../graphics/applicationIcons/facebook.png",
195198 actions: [{ id: "ok_id", label: "Ok"},
196− { id: "cancel_id", label: "Cancel"}],
199+ { id: "cancel_id", label: "Cancel"},
200+ { id: "notreally_id", label: "Not really"},
201+ { id: "noway_id", label: "No way"},
202+ { id: "nada_id", label: "Nada"}],
197203 summaryVisible: true,
198204 bodyVisible: true,
199205 interactiveAreaEnabled: false,
@@ -341,15 +347,50 @@ Row {
341347 var buttonAccept = findChild(buttonRow, "button0")
342348
343349 waitForRendering(notification)
344− mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
345− actionSpy.wait()
346− compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
347− actionSpy.clear()
348350
351+ // only test the left/cancel-button if two actions have been passed in
352+ if (data.actions.length == 2) {
353+ mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
354+ actionSpy.wait()
355+ compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
356+ actionSpy.clear()
357+ }
358+
359+ // click the positive/right button
349360 mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2)
350361 actionSpy.wait()
351362 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action")
352363 actionSpy.clear()
364+
365+ // check if there's more than one negative choice
366+ if (data.actions.length > 2) {
367+ var initialHeight = notification.height
368+
369+ // click to expand
370+ mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
371+ waitForRendering(notification)
372+ actionSpy.clear()
373+ 
374+ // test the additional buttons
375+ for (var i = 2; i < data.actions.length; i++) {
376+ waitForRendering(notification)
377+ var buttonColumn = findChild(notification, "buttonColumn")
378+ var button = findChild(buttonColumn, "button" + i)
379+ mouseClick(button, button.width / 2, button.height / 2)
380+ actionSpy.wait()
381+ compare(actionSpy.signalArguments[0][0], data.actions[i]["id"], "got wrong id for additional negative action")
382+ actionSpy.clear()
383+ }
384+
385+ // click to collapse
386+ mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
387+ waitForRendering(notification)
388+ tryCompare(notification, "height", initialHeight)
389+ } else {
390+ mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
391+ actionSpy.wait()
392+ compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
393+ }
353394 }
354395 }
355396 }
tests/qmltests/Panel/tst_Indicators.qml+34−45

This diff is too big to show here.

tests/qmltests/Panel/tst_Panel.qml+65−113

This diff is too big to show here.

tests/qmltests/plugins/CMakeLists.txtdeleted−3

This diff is too big to show here.

tests/qmltests/plugins/Dee/qmldirdeleted−3

This diff is too big to show here.

tests/qmltests/plugins/Ubuntu/CMakeLists.txtdeleted−1

This diff is too big to show here.