on xenial help sign in
Untested merge from trunk
commit936045a203a36fcc308d9e0858082531f2043f36 authorMichael Terry <michael.terry@canonical.com> dateWed 1 Jun 2016, 16:09 (10 years ago) parent547c7ff4e8f79f
340 files changed+3720−7921
CMakeLists.txt+13−2 debian/changelog+85 debian/control+5−3 debian/unity8-private.install−1 libs/CMakeLists.txt−1 libs/UbuntuGestures/CMakeLists.txt−41 libs/UbuntuGestures/CandidateInactivityTimer.cpp−46 libs/UbuntuGestures/CandidateInactivityTimer.h−51 libs/UbuntuGestures/DebugHelpers.cpp−95 libs/UbuntuGestures/DebugHelpers.h−31 libs/UbuntuGestures/Pool.h−124 libs/UbuntuGestures/TimeSource.cpp−49 libs/UbuntuGestures/TimeSource.h−64 libs/UbuntuGestures/Timer.cpp−152 libs/UbuntuGestures/Timer.h−122 libs/UbuntuGestures/TouchOwnershipEvent.cpp−35 libs/UbuntuGestures/TouchOwnershipEvent.h−50 libs/UbuntuGestures/TouchRegistry.cpp−553 libs/UbuntuGestures/TouchRegistry.h−201 libs/UbuntuGestures/UbuntuGesturesGlobal.h−23 libs/UbuntuGestures/UnownedTouchEvent.cpp−39 libs/UbuntuGestures/UnownedTouchEvent.h−45 plugins/Cursor/CMakeLists.txt+2−1 plugins/Cursor/Cursor.qml+21−5 plugins/Cursor/Cursor.qmltypes−78 plugins/Cursor/CursorImageInfo.cpp+106 plugins/Cursor/CursorImageInfo.h+76 plugins/Cursor/CursorImageProvider.cpp+50−21 plugins/Cursor/CursorImageProvider.h+12−4 plugins/Cursor/MousePointer.cpp+29−24 plugins/Cursor/MousePointer.h+5−6 plugins/Cursor/plugin.cpp+4−2 plugins/Cursor/qmldir+1−1 plugins/Dash/AudioProgressBar.qml+1−1 plugins/Dash/CardCreator.js+64−48 plugins/Dash/CardCreatorCache.qml+2−2 plugins/Dash/ScopeStyle.qml+1−1 plugins/Dash/listviewwithpageheader.cpp+14−17 plugins/Ubuntu/Gestures/AxisVelocityCalculator.h+1−1 plugins/Ubuntu/Gestures/CMakeLists.txt+9−4 plugins/Ubuntu/Gestures/Damper.cpp−24 plugins/Ubuntu/Gestures/Damper.h−89 plugins/Ubuntu/Gestures/Direction.h+1 plugins/Ubuntu/Gestures/DirectionalDragArea.cpp−932 plugins/Ubuntu/Gestures/DirectionalDragArea.h−143 plugins/Ubuntu/Gestures/DirectionalDragArea_p.h−169 plugins/Ubuntu/Gestures/FloatingFlickable.cpp−150 plugins/Ubuntu/Gestures/FloatingFlickable.h−86 plugins/Ubuntu/Gestures/Gestures.qmltypes−132 plugins/Ubuntu/Gestures/MouseEventGenerator.cpp+64 plugins/Ubuntu/Gestures/MouseEventGenerator.h+48 plugins/Ubuntu/Gestures/PressedOutsideNotifier.h+1−1 plugins/Ubuntu/Gestures/TouchGate.cpp+2−2 plugins/Ubuntu/Gestures/TouchGestureArea.cpp+9−6 plugins/Ubuntu/Gestures/TouchGestureArea.h+2−3 plugins/Ubuntu/Gestures/plugin.cpp+3−5 plugins/Unity/InputInfo/plugin.h+1−1 plugins/Unity/InputInfo/qdeclarativeinputdevicemodel_p.h+3−3 plugins/Unity/Session/dbusunitysessionservice.cpp+7 plugins/Utils/WindowInputMonitor.cpp+8−8 plugins/Utils/WindowInputMonitor.h+8−2 plugins/Utils/windowstatestorage.h+13−3 po/aa.po+4−4 po/am.po+4−4 po/ar.po+4−4 po/ast.po+4−4 po/az.po+4−4 po/be.po+4−4 po/bg.po+4−4 po/bn.po+4−4 po/br.po+4−4 po/bs.po+4−4 po/ca.po+4−4 po/ca@valencia.po+4−4 po/ce.po+4−4 po/ckb.po+4−4 po/co.po+736 po/cs.po+4−4 po/cy.po+4−4 po/da.po+4−4 po/de.po+4−4 po/el.po+4−4 po/en_AU.po+4−4 po/en_GB.po+4−4 po/eo.po+4−4 po/es.po+4−4 po/eu.po+4−4 po/fa.po+4−4 po/fi.po+8−6 po/fo.po+4−4 po/fr.po+9−9 po/ga.po+4−4 po/gd.po+4−4 po/gl.po+4−4 po/gv.po+4−4 po/he.po+4−4 po/hi.po+4−4 po/hr.po+4−4 po/hu.po+4−4 po/hy.po+4−4 po/ia.po+4−4 po/id.po+4−4 po/is.po+4−4 po/it.po+4−4 po/ja.po+4−4 po/km.po+4−4 po/kn.po+4−4 po/ko.po+4−4 po/ku.po+4−4 po/ky.po+4−4 po/lo.po+4−4 po/lt.po+4−4 po/lv.po+4−4 po/ml.po+4−4 po/mr.po+4−4 po/ms.po+94−73 po/my.po+4−4 po/nb.po+4−4 po/ne.po+4−4 po/nl.po+4−4 po/nn.po+4−4 po/oc.po+4−4 po/or.po+4−4 po/pa.po+4−4 po/pl.po+4−4 po/pt.po+7−7 po/pt_BR.po+4−4 po/ro.po+4−4 po/ru.po+30−26 po/shn.po+4−4 po/si.po+4−4 po/sk.po+4−4 po/sl.po+4−4 po/sq.po+4−4 po/sr.po+4−4 po/sv.po+4−4 po/sw.po+4−4 po/ta.po+4−4 po/te.po+4−4 po/th.po+4−4 po/tr.po+4−4 po/ug.po+4−4 po/uk.po+4−4 po/unity8.pot+23−23 po/ur.po+4−4 po/uz.po+4−4 po/vi.po+4−4 po/wo.po+4−4 po/xh.po+4−4 po/zh_CN.po+4−4 po/zh_HK.po+4−4 po/zh_TW.po+4−4 qml/Components/Dialogs.qml+2−2 qml/Components/DragHandle.qml+43−25 qml/Components/FloatingFlickable.qml+59 qml/Components/Header.qml−28 qml/Components/InputMethod.qml+2−2 qml/Components/ModeSwitchWarningDialog.qml+1−1 qml/Components/PanelState/PanelState.qml+3−3 qml/Components/Rating.qml+1 qml/Components/RatingStyle.qml+3 qml/Components/WindowControlButtons.qml+18−7 qml/Dash/CardCarousel.qml−1 qml/Dash/CardGrid.qml−2 qml/Dash/CardTool.qml+6−2 qml/Dash/Dash.qml+3−3 qml/Dash/DashApplication.qml−3 qml/Dash/DashCategoryBase.qml+3−11 qml/Dash/DashPageHeader.qml+31−36 qml/Dash/Filters/FilterOptionSelector.qml+4 qml/Dash/Filters/FilterWidgetFactory.qml+8 qml/Dash/GenericScopeView.qml+14−4 qml/Dash/PageHeaderExtraPanel.qml+34−10 qml/Dash/Previews/PreviewActions.qml+1−1 qml/Dash/Previews/PreviewPayments.qml+1−1 qml/Dash/Previews/PreviewRatingInput.qml+41−42 qml/Dash/ScopesList.qml+1−13 qml/DisabledScreenNotice.qml+7 qml/Launcher/Launcher.qml+16−24 qml/Launcher/LauncherDelegate.qml+2−2 qml/Notifications/Notification.qml+20−5 qml/Notifications/NotificationMenuItemFactory.qml+4 qml/Notifications/Notifications.qml+18−9 qml/Panel/Indicators/MenuItemFactory.qml+2−2 qml/Panel/Indicators/MessageMenuItemFactory.qml+1−5 qml/Panel/IndicatorsMenu.qml+17−13 qml/Panel/Panel.qml+21−20 qml/Shell.qml+4−3 qml/Stages/DecoratedWindow.qml+11−7 qml/Stages/DesktopSpread.qml+1−1 qml/Stages/DesktopSpreadDelegate.qml+1−1 qml/Stages/DesktopStage.qml+55−43 qml/Stages/PhoneStage.qml+4−4 qml/Stages/SideStage.qml+1−2 qml/Stages/Splash.qml+6−17 qml/Stages/SpreadDelegate.qml+1−1 qml/Stages/SurfaceContainer.qml+3 qml/Stages/TabletStage.qml+8−7 qml/Stages/WindowDecoration.qml+12−8 qml/Stages/WindowResizeArea.qml+25−5 qml/Tutorial/TutorialBottom.qml+3−3 qml/Wizard/Pages/50-timezone.qml+5−2 src/CMakeLists.txt+1−4 src/Dash/CMakeLists.txt+1 src/Dash/main.cpp+6 tools/unix-signal-handler.cpp → src/UnixSignalHandler.cpp+1−1 tools/unix-signal-handler.h → src/UnixSignalHandler.h src/main.cpp+6 tests/CMakeLists.txt−1 tests/autopilot/unity8/dash.py+2−3 tests/libs/CMakeLists.txt−1 tests/libs/UbuntuGestures/CMakeLists.txt−20 tests/libs/UbuntuGestures/tst_TouchRegistry.cpp−974 tests/mocks/Cursor/qmldir+1−1 tests/mocks/GSettings.1.0/fake_gsettings.cpp+1 tests/mocks/GSettings.1.0/fake_gsettings.h+2−2 tests/mocks/IntegratedLightDM/liblightdm/GreeterPrivate.h−1 tests/mocks/QtMultimedia/audio.cpp+3−3 tests/mocks/QtMultimedia/audio.h+12−6 tests/mocks/Ubuntu/Payments/MockPayments.cpp+1 tests/mocks/Ubuntu/SystemSettings/TimeDate/CMakeLists.txt+1−1 tests/mocks/Ubuntu/SystemSettings/TimeDate/MockTimeDate.qml+15−3 tests/mocks/Ubuntu/SystemSettings/TimeDate/qmldir+1−1 tests/mocks/Unity/Application/ApplicationInfo.h+1−1 tests/mocks/Unity/Application/MirSurface.h+2−2 tests/mocks/Unity/Application/MirSurfaceItem.cpp+17−7 tests/mocks/Unity/Application/MirSurfaceItem.h+1−1 tests/mocks/Unity/InputInfo/plugin.h+1−1 tests/mocks/Unity/Screens/plugin.h+1−1 tests/mocks/Unity/fake_scope.cpp+6−3 tests/mocks/Unity/fake_scope.h+1−1 tests/mocks/Unity/fake_scopes.cpp+11 tests/mocks/Utils/plugin.h+1−1 tests/mocks/Utils/windowstatestorage.cpp+1 tests/mocks/Utils/windowstatestorage.h+17−3 tests/mocks/libusermetrics/UserMetrics.cpp+1−1 tests/plugins/CMakeLists.txt+2−1 tests/plugins/Cursor/CMakeLists.txt+8 tests/plugins/Cursor/TextEntry.qml+34 tests/plugins/Cursor/tst_Cursor.qml+144 tests/plugins/Dash/cardcreator/1.res+8−26 tests/plugins/Dash/cardcreator/1.res.cardcreator+8−26 tests/plugins/Dash/cardcreator/1.tst+1 tests/plugins/Dash/cardcreator/10.res−9 tests/plugins/Dash/cardcreator/10.res.cardcreator−9 tests/plugins/Dash/cardcreator/10.tst+1 tests/plugins/Dash/cardcreator/11.res+11−29 tests/plugins/Dash/cardcreator/11.res.cardcreator+10−28 tests/plugins/Dash/cardcreator/11.tst+1 tests/plugins/Dash/cardcreator/12.res+8−26 tests/plugins/Dash/cardcreator/12.res.cardcreator+10−28 tests/plugins/Dash/cardcreator/12.tst+1 tests/plugins/Dash/cardcreator/2.res−9 tests/plugins/Dash/cardcreator/2.res.cardcreator−9 tests/plugins/Dash/cardcreator/2.tst+1 tests/plugins/Dash/cardcreator/3.res+5−33 tests/plugins/Dash/cardcreator/3.res.cardcreator+5−33 tests/plugins/Dash/cardcreator/3.tst+1 tests/plugins/Dash/cardcreator/4.res+1−2 tests/plugins/Dash/cardcreator/4.res.cardcreator+1−2 tests/plugins/Dash/cardcreator/4.tst+1 tests/plugins/Dash/cardcreator/5.res+2−35 tests/plugins/Dash/cardcreator/5.res.cardcreator+2−35 tests/plugins/Dash/cardcreator/5.tst+1 tests/plugins/Dash/cardcreator/6.res+1−2 tests/plugins/Dash/cardcreator/6.res.cardcreator+1−2 tests/plugins/Dash/cardcreator/6.tst+1 tests/plugins/Dash/cardcreator/7.res−9 tests/plugins/Dash/cardcreator/7.res.cardcreator−9 tests/plugins/Dash/cardcreator/7.tst+1 tests/plugins/Dash/cardcreator/8.res+1−2 tests/plugins/Dash/cardcreator/8.res.cardcreator+1−2 tests/plugins/Dash/cardcreator/8.tst+1 tests/plugins/Dash/cardcreator/9.res+1−2 tests/plugins/Dash/cardcreator/9.res.cardcreator+1−2 tests/plugins/Dash/cardcreator/9.tst+1 tests/plugins/Dash/cardcreatortest.cpp+9−6 tests/plugins/Dash/cardcreatortest.qml+4−4 tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp+2−2 tests/plugins/Dash/listviewwithpageheadersectiontest.cpp+2−2 tests/plugins/Dash/listviewwithpageheadertest.cpp+5 tests/plugins/Dash/listviewwithpageheadertestsection.qml+3−2 tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml+2−1 tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml+4−2 tests/plugins/Dash/tst_ScopeStyle.qml+1−1 tests/plugins/Ubuntu/Gestures/CMakeLists.txt+4−4 tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qml−72 tests/plugins/Ubuntu/Gestures/GestureTest.cpp+2−2 tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qml−76 tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qml−76 tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qml−76 tests/plugins/Ubuntu/Gestures/tst_Damper.cpp−40 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp−1250 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qml−76 tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.cpp+25−18 tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml+1 tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+1−1 tests/plugins/Unity/Indicators/MenuContentActivatorTest.cpp+1 tests/plugins/Unity/Session/sessionbackendtest.cpp−15 tests/plugins/Utils/WindowInputMonitorTest.cpp+52−11 tests/qmltests/Components/CMakeLists.txt+6−3 tests/qmltests/Components/tst_DragHandle.cpp+28−24 tests/qmltests/Components/tst_DragHandle.qml+22−4 tests/qmltests/Components/tst_DragHandle/BottomEdgeShowable.qml+108 tests/qmltests/Components/tst_DragHandle/HorizontalShowable.qml → tests/qmltests/Components/tst_DragHandle/LeftEdgeShowable.qml tests/qmltests/Components/tst_DragHandle/RightEdgeShowable.qml+108 tests/qmltests/Components/tst_DragHandle/VerticalShowable.qml → tests/qmltests/Components/tst_DragHandle/TopEdgeShowable.qml+7−7 tests/qmltests/Components/tst_EdgeDragEvaluator.cpp+1−1 tests/qmltests/Dash/Previews/tst_Preview.qml−1 tests/qmltests/Dash/Previews/tst_PreviewRatingEdit.qml+5−1 tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml+18−6 tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+1−1 tests/qmltests/Dash/tst_Card.qml+22−10 tests/qmltests/Dash/tst_CardTool.qml+1−1 tests/qmltests/Dash/tst_Dash.qml+76−62 tests/qmltests/Dash/tst_DashContent.qml+63−4 tests/qmltests/Dash/tst_DashPageHeader.qml−24 tests/qmltests/Dash/tst_DashShell.qml+1−1 tests/qmltests/Dash/tst_GenericScopeView.qml+2−2 tests/qmltests/Dash/tst_PreviewView.qml+3−3 tests/qmltests/Greeter/tst_Greeter.qml+1−1 tests/qmltests/Greeter/tst_NarrowView.qml+1−1 tests/qmltests/Greeter/tst_WideView.qml+1−1 tests/qmltests/Launcher/tst_Launcher.qml+13−1 tests/qmltests/Notifications/tst_Notifications.qml+89 tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml+1 tests/qmltests/Stages/tst_DesktopStage.qml+31−1 tests/qmltests/Stages/tst_TabletStage.qml+66−2 tests/qmltests/Stages/tst_WindowResizeArea.qml+16−5 tests/qmltests/Tutorial/tst_Tutorial.qml+2−2 tests/qmltests/Wizard/tst_Wizard.qml+7−15 tests/qmltests/tst_OrientedShell.qml+1−1 tests/qmltests/tst_Shell.qml+32−5 tests/qmltests/tst_ShellWithPin.qml+1−1 tests/uqmlscene/main.cpp−1 tests/utils/modules/Unity/Test/CMakeLists.txt+4−2 tests/utils/modules/Unity/Test/UnityTestCase.qml+31−12 tests/utils/modules/Unity/Test/testutil.cpp+2−2 tools/CMakeLists.txt+1−1 tools/scopetool.cpp+1−1
CMakeLists.txt+13−2
@@ -57,12 +57,24 @@ find_package(Qt5DBus 5.4 REQUIRED)
5757find_package(Qt5Concurrent 5.4 REQUIRED)
5858find_package(Qt5Sql 5.4 REQUIRED)
5959
60−pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=16)
60+pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=17)
6161pkg_check_modules(GEONAMES REQUIRED geonames>=0.2)
6262pkg_check_modules(GIO REQUIRED gio-2.0>=2.32)
6363pkg_check_modules(GLIB REQUIRED glib-2.0>=2.32)
6464pkg_check_modules(QMENUMODEL REQUIRED qmenumodel)
6565
66+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
67+
68+### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them
69+find_path(UBUNTUGESTUREPRIV
70+ NAMES UbuntuGestures/private/damper_p.h UbuntuGestures/private/ucswipearea_p.h UbuntuGestures/private/ucswipearea_p_p.h
71+ PATHS ${UBUNTUGESTURES_INCLUDEDIR}/UbuntuGestures/${UBUNTUGESTURES_VERSION}
72+ NO_DEFAULT_PATH)
73+if (${UBUNTUGESTUREPRIV} STREQUAL UBUNTUGESTUREPRIV-NOTFOUND)
74+ message(FATAL_ERROR "UbuntuGestures private headers not found.")
75+endif()
76+# end of UbuntuGesture private headers check
77+
6678# Standard install paths
6779include(GNUInstallDirs)
6880
@@ -144,7 +156,6 @@ endif()
144156
145157# add subdirectories to build
146158add_subdirectory(include)
147−add_subdirectory(libs)
148159add_subdirectory(src)
149160add_subdirectory(tools)
150161add_subdirectory(qml)
debian/changelog+85
@@ -1,3 +1,88 @@
1+unity8 (8.12+16.10.20160527-0ubuntu1) yakkety; urgency=medium
2+
3+ [ Albert Astals Cid ]
4+ * Activate on click for SimpleMessages (LP: #1421696)
5+ * Add override
6+ * Change the art back to the cardData value if it changes from broken
7+ to valid image (LP: #1533577)
8+ * Concierge mode generated code optimization
9+ * Don't use context properties but properties of the delegates
10+ * Listen to contentItem::widthChanged instead of
11+ Flickable::contentWidthChanged (LP: #1565763)
12+ * Make some AP code faster
13+ * Make tests a bit more stable
14+ * Make unity8 and unity8-dash handle termination signals
15+ * Remove workaround not needed anymore (LP: #1475643)
16+ * Resolve cardArtStyle on compile time
17+ * Set the theme earlier (LP: #1574048)
18+
19+ [ Albert Astals Cid, Daniel d'Andrada ]
20+ * Remove DirectionalDragArea and libs/UbuntuGestures and port to SDK
21+ equivalents
22+
23+ [ Andrea Cimitan ]
24+ * Hide the preview review input field when a rating is required (LP:
25+ #1541971)
26+
27+ [ CI Train Bot ]
28+ * Resync trunk.
29+
30+ [ Daniel d'Andrada ]
31+ * Fix DragHandle so it works in all directions
32+ * Support animated cursors
33+ * WindowInputMonitor - also map Qt::Key_HomePage to our home key
34+ * plugins/Cursor: properly register to the screen's QPlatformCursor
35+ when screen changes (LP: #1579742)
36+
37+ [ Josh Arenson ]
38+ * Close the PageHeaderExtraPanel when a filter option is selected (LP:
39+ #1569498)
40+ * Wrap primaryFilter in a flickable to make it behave nicely. (LP:
41+ #1569492)
42+
43+ [ Lukáš Tinkl ]
44+ * First snap decision should always be expanded, unless user decides
45+ otherwise (LP: #1580090, #1575045)
46+ * Fullscreen notification bug fixes (LP: #1583944, #1581498, #1422711)
47+ * Implement maximizing windows horizontally/vertically
48+ * Lock the session when putting the laptop into sleep (LP: #1581063)
49+
50+ [ Lukáš Tinkl, Michael Terry ]
51+ * With a maximized window, "dragging" the panel down should restore it
52+
53+ [ Michael Terry ]
54+ * Change some dash button colors from orange to green. (LP: #1581047)
55+ * Use PageHeader instead Ambiance's PageHeadStyle
56+ * Use new setTimeZone method to set user-friendly timezone name in the
57+ wizard. (LP: #1566295)
58+
59+ [ Michael Zanetti ]
60+ * Remove the background dimming when the launcher is revealed by a
61+ drag (LP: #1575137)
62+ * reenable or drop disabled tests
63+
64+ -- Michael Terry <michael.terry@canonical.com> Fri, 27 May 2016 13:54:44 +0000
65+
66+unity8 (8.12+16.10.20160520.1-0ubuntu1) yakkety; urgency=medium
67+
68+ [ Lukáš Tinkl ]
69+ * Don't dim screen when the indicators are open (LP: #1564342)
70+ * Fix upcoming alarms ETA labels (LP: #1576741)
71+ * Stabilize flaky wizard tests (LP: #1582994)
72+
73+ [ Michael Zanetti ]
74+ * fix the SIM PIN darkening after it got removed accidentally (LP:
75+ #1577147)
76+
77+ [ Michał Sawicz, Nick Dedekind ]
78+ * Fixed saving current stage and loss of surface focus when switching
79+ stages
80+
81+ [ Nick Dedekind ]
82+ * Fixed incorrect osk surface item resizing the surface.
83+
84+ -- Michał Sawicz <michal.sawicz@canonical.com> Fri, 20 May 2016 08:44:19 +0000
85+
186unity8 (8.12+16.04.20160518.1-0ubuntu1) xenial; urgency=medium
287
388 [ CI Train Bot ]
debian/control+5−3
@@ -30,8 +30,10 @@ Build-Depends: cmake,
3030 libqt5svg5-dev,
3131 libqt5xmlpatterns5-dev,
3232 libsystemsettings-dev,
33+ libubuntugestures5-dev,
34+ libubuntugestures5-private-dev,
3335 libudev-dev,
34− libunity-api-dev (>= 7.112),
36+ libunity-api-dev (>= 7.113),
3537 libusermetricsoutput1-dev,
3638# Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
3739 libx11-dev[!armhf],
@@ -108,7 +110,7 @@ Depends: dmz-cursor-theme,
108110 qtdeclarative5-qtmir-plugin (>= 0.4.8),
109111 qtdeclarative5-ubuntu-telephony0.1,
110112 qtdeclarative5-ubuntu-web-plugin,
111− ubuntu-system-settings,
113+ ubuntu-system-settings (>= 0.4),
112114 unity-launcher-impl-7,
113115 unity8-common (= ${source:Version}),
114116 unity8-private (= ${binary:Version}),
@@ -135,7 +137,7 @@ Depends: qml-module-qtquick-layouts,
135137 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 1.3.1845) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 1.3.1845),
136138 qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
137139 ubuntu-thumbnailer-impl-0,
138− unity-application-impl-16,
140+ unity-application-impl-17,
139141 unity-notifications-impl-3,
140142 unity-plugin-scopes | unity-scopes-impl,
141143 unity-scopes-impl-12,
debian/unity8-private.install−1
@@ -1,5 +1,4 @@
11usr/lib/*/libunity8-private.*
2−usr/lib/*/unity8/libUbuntuGestures*
32usr/lib/*/unity8/qml/AccountsService
43usr/lib/*/unity8/qml/Cursor
54usr/lib/*/unity8/qml/Dash
libs/CMakeLists.txtdeleted−1
@@ -1 +0,0 @@
1−add_subdirectory(UbuntuGestures)
libs/UbuntuGestures/CMakeLists.txtdeleted−41
@@ -1,41 +0,0 @@
1−# in order to include Qt's private headers
2−remove_definitions(-DQT_NO_KEYWORDS)
3−
4−set(UbuntuGestures_SOURCES
5− CandidateInactivityTimer.cpp
6− DebugHelpers.cpp
7− Timer.cpp
8− TimeSource.cpp
9− TouchOwnershipEvent.cpp
10− TouchRegistry.cpp
11− UnownedTouchEvent.cpp
12−)
13−
14−add_definitions(-DUBUNTUGESTURES_LIBRARY)
15−
16−add_library(UbuntuGestures SHARED ${UbuntuGestures_SOURCES})
17−
18−qt5_use_modules(UbuntuGestures Core Quick)
19−
20−# So that Foo.cpp can #include "Foo.moc"
21−include_directories(${CMAKE_CURRENT_BINARY_DIR})
22−
23−install(TARGETS UbuntuGestures
24− DESTINATION ${SHELL_PRIVATE_LIBDIR})
25−
26−
27−# There's no cmake var for v8 include path :-/ so create one
28−LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
29−if(${Qt5Core_VERSION_STRING} VERSION_LESS "5.1.0")
30− SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/../QtV8/${Qt5Core_VERSION_STRING}/QtV8)
31−else()
32− SET(Qt5V8_PRIVATE_INCLUDE_DIR ${QtCoreDir0}/QtV8/${Qt5Core_VERSION_STRING}/QtV8)
33−endif()
34−
35−# DANGER! DANGER! Using Qt's private API!
36−include_directories(
37− ${Qt5Qml_PRIVATE_INCLUDE_DIRS}
38− ${Qt5Quick_INCLUDE_DIRS}
39− ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
40− ${Qt5V8_PRIVATE_INCLUDE_DIR}
41−)
libs/UbuntuGestures/CandidateInactivityTimer.cppdeleted−46
@@ -1,46 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 "CandidateInactivityTimer.h"
18−
19−namespace UbuntuGestures {
20−
21−CandidateInactivityTimer::CandidateInactivityTimer(int touchId, QQuickItem *candidate,
22− AbstractTimer *timer, QObject *parent)
23− : QObject(parent)
24− , m_timer(timer)
25− , m_touchId(touchId)
26− , m_candidate(candidate)
27−{
28− connect(m_timer, &AbstractTimer::timeout,
29− this, &CandidateInactivityTimer::onTimeout);
30− m_timer->setInterval(durationMs);
31− m_timer->setSingleShot(true);
32− m_timer->start();
33−}
34−
35−CandidateInactivityTimer::~CandidateInactivityTimer()
36−{
37− delete m_timer;
38−}
39−
40−void CandidateInactivityTimer::onTimeout()
41−{
42− qWarning("[TouchRegistry] Candidate for touch %d defaulted!", m_touchId);
43− Q_EMIT candidateDefaulted(m_touchId, m_candidate);
44−}
45−
46−} // namespace UbuntuGestures
libs/UbuntuGestures/CandidateInactivityTimer.hdeleted−51
@@ -1,51 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
18−#define UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
19−
20−#include <QObject>
21−
22−class QQuickItem;
23−
24−#include "Timer.h"
25−
26−namespace UbuntuGestures {
27−
28−class UBUNTUGESTURES_EXPORT CandidateInactivityTimer : public QObject {
29− Q_OBJECT
30−public:
31− CandidateInactivityTimer(int touchId, QQuickItem *candidate,
32− AbstractTimer *timer,
33− QObject *parent = nullptr);
34−
35− virtual ~CandidateInactivityTimer();
36−
37− const int durationMs = 1000;
38−
39−Q_SIGNALS:
40− void candidateDefaulted(int touchId, QQuickItem *candidate);
41−private Q_SLOTS:
42− void onTimeout();
43−private:
44− AbstractTimer *m_timer;
45− int m_touchId;
46− QQuickItem *m_candidate;
47−};
48−
49−} // namespace UbuntuGestures
50−
51−#endif // UBUNTUGESTURES_CANDIDATE_INACTIVITY_TIMER_H
libs/UbuntuGestures/DebugHelpers.cppdeleted−95
@@ -1,95 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 "DebugHelpers.h"
18−#include <QTouchEvent>
19−#include <QMouseEvent>
20−
21−QString touchPointStateToString(Qt::TouchPointState state)
22−{
23− switch (state) {
24− case Qt::TouchPointPressed:
25− return QStringLiteral("pressed");
26− case Qt::TouchPointMoved:
27− return QStringLiteral("moved");
28− case Qt::TouchPointStationary:
29− return QStringLiteral("stationary");
30− case Qt::TouchPointReleased:
31− return QStringLiteral("released");
32− default:
33− return QStringLiteral("INVALID_STATE");
34− }
35−}
36−
37−QString touchEventToString(const QTouchEvent *ev)
38−{
39− QString message;
40−
41− switch (ev->type()) {
42− case QEvent::TouchBegin:
43− message.append("TouchBegin ");
44− break;
45− case QEvent::TouchUpdate:
46− message.append("TouchUpdate ");
47− break;
48− case QEvent::TouchEnd:
49− message.append("TouchEnd ");
50− break;
51− case QEvent::TouchCancel:
52− message.append("TouchCancel ");
53− break;
54− default:
55− message.append("INVALID_TOUCH_EVENT_TYPE ");
56− }
57−
58− foreach(const QTouchEvent::TouchPoint& touchPoint, ev->touchPoints()) {
59− message.append(
60− QStringLiteral("(id:%1, state:%2, scenePos:(%3,%4)) ")
61− .arg(touchPoint.id())
62− .arg(touchPointStateToString(touchPoint.state()))
63− .arg(touchPoint.scenePos().x())
64− .arg(touchPoint.scenePos().y())
65− );
66− }
67−
68− return message;
69−}
70−
71−QString mouseEventToString(const QMouseEvent *ev)
72−{
73− QString message;
74−
75− switch (ev->type()) {
76− case QEvent::MouseButtonPress:
77− message.append("MouseButtonPress ");
78− break;
79− case QEvent::MouseButtonRelease:
80− message.append("MouseButtonRelease ");
81− break;
82− case QEvent::MouseButtonDblClick:
83− message.append("MouseButtonDblClick ");
84− break;
85− case QEvent::MouseMove:
86− message.append("MouseMove ");
87− break;
88− default:
89− message.append("INVALID_MOUSE_EVENT_TYPE ");
90− }
91−
92− message.append(QStringLiteral("pos(%1, %2)").arg(ev->x()).arg(ev->y()));
93−
94− return message;
95−}
libs/UbuntuGestures/DebugHelpers.hdeleted−31
@@ -1,31 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 UBUNTUGESTURES_DEBUG_HELPER_H
18−#define UBUNTUGESTURES_DEBUG_HELPER_H
19−
20−#include <QString>
21−
22−#include "UbuntuGesturesGlobal.h"
23−
24−class QMouseEvent;
25−class QTouchEvent;
26−
27−UBUNTUGESTURES_EXPORT QString touchPointStateToString(Qt::TouchPointState state);
28−UBUNTUGESTURES_EXPORT QString touchEventToString(const QTouchEvent *ev);
29−UBUNTUGESTURES_EXPORT QString mouseEventToString(const QMouseEvent *ev);
30−
31−#endif // UBUNTUGESTURES_DEBUG_HELPER_H
libs/UbuntuGestures/Pool.hdeleted−124
@@ -1,124 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 UBUNTUGESTURES_POOL_H
18−#define UBUNTUGESTURES_POOL_H
19−
20−#include <QVector>
21−
22−#include "UbuntuGesturesGlobal.h"
23−
24−/*
25− An object pool.
26− Avoids unnecessary creations/initializations and deletions/destructions of items. Useful
27− in a scenario where items are created and destroyed very frequently but the total number
28− of items at any given time remains small. They're stored in a unordered fashion.
29−
30− To be used in Pool, ItemType needs to have the following methods:
31−
32− - ItemType();
33−
34− A constructor that takes no parameters. An object contructed with it must return false if
35− isValid() is called.
36−
37− - bool isValid() const;
38−
39− Returns wheter the object holds a valid , "filled" state or is empty.
40− Used by Pool to check if the slot occupied by this object is actually available.
41−
42− - void reset();
43−
44− Resets the object to its initial, empty, state. After calling this method, isValid() must
45− return false.
46− */
47−template <class ItemType> class Pool
48−{
49−public:
50− Pool() : m_lastUsedIndex(-1) {
51− }
52−
53− class Iterator {
54− public:
55− Iterator() : index(-1), item(nullptr) {}
56− Iterator(int index, ItemType *item)
57− : index(index), item(item) {}
58−
59− ItemType *operator->() const { return item; }
60− ItemType &operator*() const { return *item; }
61− ItemType &value() const { return *item; }
62−
63− operator bool() const { return item != nullptr; }
64−
65− int index;
66− ItemType *item;
67− };
68−
69− ItemType &getEmptySlot() {
70− Q_ASSERT(m_lastUsedIndex < m_slots.size());
71−
72− // Look for an in-between vacancy first
73− for (int i = 0; i < m_lastUsedIndex; ++i) {
74− ItemType &item = m_slots[i];
75− if (!item.isValid()) {
76− return item;
77− }
78− }
79−
80− ++m_lastUsedIndex;
81− if (m_lastUsedIndex >= m_slots.size()) {
82− m_slots.resize(m_lastUsedIndex + 1);
83− }
84−
85− return m_slots[m_lastUsedIndex];
86− }
87−
88− void freeSlot(Iterator &iterator) {
89− m_slots[iterator.index].reset();
90− if (iterator.index == m_lastUsedIndex) {
91− do {
92− --m_lastUsedIndex;
93− } while (m_lastUsedIndex >= 0 && !m_slots.at(m_lastUsedIndex).isValid());
94− }
95− }
96−
97− // Iterates through all valid items (i.e. the occupied slots)
98− // calling the given function, with the option of ending the loop early.
99− //
100− // bool Func(Iterator& item)
101− //
102− // Returning true means it wants to continue the "for" loop, false
103− // terminates the loop.
104− template<typename Func> void forEach(Func func) {
105− Iterator it;
106− for (it.index = 0; it.index <= m_lastUsedIndex; ++it.index) {
107− it.item = &m_slots[it.index];
108− if (!it.item->isValid())
109− continue;
110−
111− if (!func(it))
112− break;
113− }
114− }
115−
116− bool isEmpty() const { return m_lastUsedIndex == -1; }
117−
118−
119−private:
120− QVector<ItemType> m_slots;
121− int m_lastUsedIndex;
122−};
123−
124−#endif // UBUNTUGESTURES_POOL_H
libs/UbuntuGestures/TimeSource.cppdeleted−49
@@ -1,49 +0,0 @@
1−/*
2− * Copyright (C) 2013 - Canonical Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it
5− * under the terms of the GNU Lesser General Public License, as
6− * published by the Free Software Foundation; either version 2.1 or 3.0
7− * of the License.
8− *
9− * This program is distributed in the hope that it will be useful, but
10− * WITHOUT ANY WARRANTY; without even the implied warranties of
11− * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12− * PURPOSE. See the applicable version of the GNU Lesser General Public
13− * License for more details.
14− *
15− * You should have received a copy of both the GNU Lesser General Public
16− * License along with this program. If not, see <http://www.gnu.org/licenses/>
17− *
18− * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19− */
20−
21−#include "TimeSource.h"
22−
23−#include <QElapsedTimer>
24−
25−namespace UbuntuGestures {
26−class RealTimeSourcePrivate {
27−public:
28− QElapsedTimer timer;
29−};
30−}
31−
32−using namespace UbuntuGestures;
33−
34−RealTimeSource::RealTimeSource()
35− : UbuntuGestures::TimeSource()
36− , d(new RealTimeSourcePrivate)
37−{
38− d->timer.start();
39−}
40−
41−RealTimeSource::~RealTimeSource()
42−{
43− delete d;
44−}
45−
46−qint64 RealTimeSource::msecsSinceReference()
47−{
48− return d->timer.elapsed();
49−}
libs/UbuntuGestures/TimeSource.hdeleted−64
@@ -1,64 +0,0 @@
1−/*
2− * Copyright (C) 2013,2015 Canonical Ltd.
3− *
4− * This program is free software: you can redistribute it and/or modify it
5− * under the terms of the GNU Lesser General Public License, as
6− * published by the Free Software Foundation; either version 2.1 or 3.0
7− * of the License.
8− *
9− * This program is distributed in the hope that it will be useful, but
10− * WITHOUT ANY WARRANTY; without even the implied warranties of
11− * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12− * PURPOSE. See the applicable version of the GNU Lesser General Public
13− * License for more details.
14− *
15− * You should have received a copy of both the GNU Lesser General Public
16− * License along with this program. If not, see <http://www.gnu.org/licenses/>
17− *
18− * Authored by: Daniel d'Andrada <daniel.dandrada@canonical.com>
19− */
20−
21−#ifndef UBUNTUGESTURES_TIMESOURCE_H
22−#define UBUNTUGESTURES_TIMESOURCE_H
23−
24−#include "UbuntuGesturesGlobal.h"
25−#include <QSharedPointer>
26−
27−namespace UbuntuGestures {
28−/*
29− Interface for a time source.
30− */
31−class UBUNTUGESTURES_EXPORT TimeSource {
32−public:
33− virtual ~TimeSource() {}
34− /* Returns the current time in milliseconds since some reference time in the past. */
35− virtual qint64 msecsSinceReference() = 0;
36−};
37−typedef QSharedPointer<TimeSource> SharedTimeSource;
38−
39−/*
40− Implementation of a time source
41− */
42−class RealTimeSourcePrivate;
43−class UBUNTUGESTURES_EXPORT RealTimeSource : public TimeSource {
44−public:
45− RealTimeSource();
46− virtual ~RealTimeSource();
47− qint64 msecsSinceReference() override;
48−private:
49− RealTimeSourcePrivate *d;
50−};
51−
52−/*
53− A fake time source, useful for tests
54− */
55−class FakeTimeSource : public TimeSource {
56−public:
57− FakeTimeSource() { m_msecsSinceReference = 0; }
58− qint64 msecsSinceReference() override { return m_msecsSinceReference; }
59− qint64 m_msecsSinceReference;
60−};
61−
62−} // namespace UbuntuGestures
63−
64−#endif // UBUNTUGESTURES_TIMESOURCE_H
libs/UbuntuGestures/Timer.cppdeleted−152
@@ -1,152 +0,0 @@
1−/*
2− * Copyright (C) 2014-2015 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 "Timer.h"
18−
19−namespace UbuntuGestures {
20−
21−Timer::Timer(QObject *parent) : AbstractTimer(parent)
22−{
23− m_timer.setSingleShot(false);
24− connect(&m_timer, &QTimer::timeout, this, &AbstractTimer::timeout);
25−}
26−
27−int Timer::interval() const
28−{
29− return m_timer.interval();
30−}
31−
32−void Timer::setInterval(int msecs)
33−{
34− m_timer.setInterval(msecs);
35−}
36−
37−void Timer::start()
38−{
39− m_timer.start();
40− AbstractTimer::start();
41−}
42−
43−void Timer::stop()
44−{
45− m_timer.stop();
46− AbstractTimer::stop();
47−}
48−
49−bool Timer::isSingleShot() const
50−{
51− return m_timer.isSingleShot();
52−}
53−
54−void Timer::setSingleShot(bool value)
55−{
56− m_timer.setSingleShot(value);
57−}
58−
59−/////////////////////////////////// FakeTimer //////////////////////////////////
60−
61−FakeTimer::FakeTimer(const SharedTimeSource &timeSource, QObject *parent)
62− : UbuntuGestures::AbstractTimer(parent)
63− , m_interval(0)
64− , m_singleShot(false)
65− , m_timeSource(timeSource)
66−{
67−}
68−
69−void FakeTimer::update()
70−{
71− if (!isRunning()) {
72− return;
73− }
74−
75− if (m_nextTimeoutTime <= m_timeSource->msecsSinceReference()) {
76− if (isSingleShot()) {
77− stop();
78− } else {
79− m_nextTimeoutTime += interval();
80− }
81− Q_EMIT timeout();
82− }
83−}
84−
85−void FakeTimer::start()
86−{
87− AbstractTimer::start();
88− m_nextTimeoutTime = m_timeSource->msecsSinceReference() + (qint64)interval();
89−}
90−
91−int FakeTimer::interval() const
92−{
93− return m_interval;
94−}
95−
96−void FakeTimer::setInterval(int msecs)
97−{
98− m_interval = msecs;
99−}
100−
101−bool FakeTimer::isSingleShot() const
102−{
103− return m_singleShot;
104−}
105−
106−void FakeTimer::setSingleShot(bool value)
107−{
108− m_singleShot = value;
109−}
110−
111−/////////////////////////////////// FakeTimerFactory //////////////////////////////////
112−
113−FakeTimerFactory::FakeTimerFactory()
114−{
115− m_timeSource.reset(new FakeTimeSource);
116−}
117−
118−void FakeTimerFactory::updateTime(qint64 targetTime)
119−{
120− qint64 minTimeoutTime = targetTime;
121−
122− for (int i = 0; i < timers.count(); ++i) {
123− FakeTimer *timer = timers[i].data();
124− if (timer && timer->isRunning() && timer->nextTimeoutTime() < minTimeoutTime) {
125− minTimeoutTime = timer->nextTimeoutTime();
126− }
127− }
128−
129− m_timeSource->m_msecsSinceReference = minTimeoutTime;
130−
131− for (int i = 0; i < timers.count(); ++i) {
132− FakeTimer *timer = timers[i].data();
133− if (timer) {
134− timer->update();
135− }
136− }
137−
138− if (m_timeSource->msecsSinceReference() < targetTime) {
139− updateTime(targetTime);
140− }
141−}
142−
143−AbstractTimer *FakeTimerFactory::createTimer(QObject *parent)
144−{
145− FakeTimer *fakeTimer = new FakeTimer(m_timeSource, parent);
146−
147− timers.append(fakeTimer);
148−
149− return fakeTimer;
150−}
151−
152−} // namespace UbuntuGestures
libs/UbuntuGestures/Timer.hdeleted−122
@@ -1,122 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 UBUNTUGESTURES_TIMER_H
18−#define UBUNTUGESTURES_TIMER_H
19−
20−#include "UbuntuGesturesGlobal.h"
21−#include "TimeSource.h"
22−
23−#include <QObject>
24−#include <QPointer>
25−#include <QTimer>
26−
27−namespace UbuntuGestures {
28−
29−/* Defines an interface for a Timer. Useful for tests. */
30−class UBUNTUGESTURES_EXPORT AbstractTimer : public QObject
31−{
32− Q_OBJECT
33−public:
34− AbstractTimer(QObject *parent) : QObject(parent), m_isRunning(false) {}
35− virtual int interval() const = 0;
36− virtual void setInterval(int msecs) = 0;
37− virtual void start() { m_isRunning = true; }
38− virtual void start(int msecs)
39− {
40− setInterval(msecs);
41− start();
42− }
43− virtual void stop() { m_isRunning = false; }
44− bool isRunning() const { return m_isRunning; }
45− virtual bool isSingleShot() const = 0;
46− virtual void setSingleShot(bool value) = 0;
47−Q_SIGNALS:
48− void timeout();
49−private:
50− bool m_isRunning;
51−};
52−
53−/* Essentially a QTimer wrapper */
54−class UBUNTUGESTURES_EXPORT Timer : public AbstractTimer
55−{
56− Q_OBJECT
57−public:
58− Timer(QObject *parent = nullptr);
59−
60− int interval() const override;
61− void setInterval(int msecs) override;
62− void start() override;
63− void stop() override;
64− bool isSingleShot() const override;
65− void setSingleShot(bool value) override;
66−private:
67− QTimer m_timer;
68−};
69−
70−/* For tests */
71−class UBUNTUGESTURES_EXPORT FakeTimer : public AbstractTimer
72−{
73− Q_OBJECT
74−public:
75− FakeTimer(const SharedTimeSource &timeSource, QObject *parent = nullptr);
76−
77− void update();
78− qint64 nextTimeoutTime() const { return m_nextTimeoutTime; }
79−
80− int interval() const override;
81− void setInterval(int msecs) override;
82− void start() override;
83− bool isSingleShot() const override;
84− void setSingleShot(bool value) override;
85−private:
86− int m_interval;
87− bool m_singleShot;
88− SharedTimeSource m_timeSource;
89− qint64 m_nextTimeoutTime;
90−};
91−
92−class UBUNTUGESTURES_EXPORT AbstractTimerFactory
93−{
94−public:
95− virtual ~AbstractTimerFactory() {}
96− virtual AbstractTimer *createTimer(QObject *parent = nullptr) = 0;
97−};
98−
99−class UBUNTUGESTURES_EXPORT TimerFactory : public AbstractTimerFactory
100−{
101−public:
102− AbstractTimer *createTimer(QObject *parent = nullptr) override { return new Timer(parent); }
103−};
104−
105−class UBUNTUGESTURES_EXPORT FakeTimerFactory : public AbstractTimerFactory
106−{
107−public:
108− FakeTimerFactory();
109− virtual ~FakeTimerFactory() {}
110−
111− void updateTime(qint64 msecsSinceReference);
112− QSharedPointer<TimeSource> timeSource() { return m_timeSource; }
113−
114− AbstractTimer *createTimer(QObject *parent = nullptr) override;
115− QList<QPointer<FakeTimer>> timers;
116−private:
117− QSharedPointer<FakeTimeSource> m_timeSource;
118−};
119−
120−} // namespace UbuntuGestures
121−
122−#endif // UBUNTUGESTURES_TIMER_H
libs/UbuntuGestures/TouchOwnershipEvent.cppdeleted−35
@@ -1,35 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 "TouchOwnershipEvent.h"
18−
19−QEvent::Type TouchOwnershipEvent::m_touchOwnershipType = (QEvent::Type)-1;
20−
21−TouchOwnershipEvent::TouchOwnershipEvent(int touchId, bool gained)
22− : QEvent(touchOwnershipEventType())
23− , m_touchId(touchId)
24− , m_gained(gained)
25−{
26−}
27−
28−QEvent::Type TouchOwnershipEvent::touchOwnershipEventType()
29−{
30− if (m_touchOwnershipType == (QEvent::Type)-1) {
31− m_touchOwnershipType = (QEvent::Type)registerEventType();
32− }
33−
34− return m_touchOwnershipType;
35−}
libs/UbuntuGestures/TouchOwnershipEvent.hdeleted−50
@@ -1,50 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 UBUNTU_TOUCHOWNERSHIPEVENT_H
18−#define UBUNTU_TOUCHOWNERSHIPEVENT_H
19−
20−#include <QEvent>
21−#include "UbuntuGesturesGlobal.h"
22−
23−/*
24− When an item get an ownership event for a touch it can grab/steal that touch
25− with a clean conscience.
26− */
27−class UBUNTUGESTURES_EXPORT TouchOwnershipEvent : public QEvent
28−{
29−public:
30− TouchOwnershipEvent(int touchId, bool gained);
31−
32− static Type touchOwnershipEventType();
33−
34− /*
35− Whether ownership was gained (true) or lost (false)
36− */
37− bool gained() const { return m_gained; }
38−
39− /*
40− Id of the touch whose ownership was granted.
41− */
42− int touchId() const { return m_touchId; }
43−
44−private:
45− static Type m_touchOwnershipType;
46− int m_touchId;
47− bool m_gained;
48−};
49−
50−#endif // UBUNTU_TOUCHOWNERSHIPEVENT_H
libs/UbuntuGestures/TouchRegistry.cppdeleted−553
@@ -1,553 +0,0 @@
1−/*
2− * Copyright (C) 2014-2015 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 "TouchRegistry.h"
18−
19−#include <QCoreApplication>
20−#include <QDebug>
21−
22−#pragma GCC diagnostic push
23−#pragma GCC diagnostic ignored "-pedantic"
24−#include <private/qquickitem_p.h>
25−#pragma GCC diagnostic pop
26−
27−#include "CandidateInactivityTimer.h"
28−#include "Timer.h"
29−#include "TouchOwnershipEvent.h"
30−#include "UnownedTouchEvent.h"
31−
32−#define TOUCHREGISTRY_DEBUG 0
33−
34−#if TOUCHREGISTRY_DEBUG
35− #include "DebugHelpers.h"
36− #define UG_DEBUG qDebug() << "[TouchRegistry]"
37−#endif // TOUCHREGISTRY_DEBUG
38−
39−using namespace UbuntuGestures;
40−
41−TouchRegistry *TouchRegistry::m_instance = nullptr;
42−
43−TouchRegistry::TouchRegistry(QObject *parent)
44− : QObject(parent)
45− , m_inDispatchLoop(false)
46− , m_timerFactory(new TimerFactory)
47−{
48−}
49−
50−TouchRegistry::~TouchRegistry()
51−{
52− Q_ASSERT(m_instance != nullptr);
53− m_instance = nullptr;
54− delete m_timerFactory;
55−}
56−
57−TouchRegistry *TouchRegistry::instance()
58−{
59− if (m_instance == nullptr) {
60− m_instance = new TouchRegistry;
61− }
62− return m_instance;
63−}
64−
65−void TouchRegistry::setTimerFactory(AbstractTimerFactory *timerFactory)
66−{
67− delete m_timerFactory;
68− m_timerFactory = timerFactory;
69−}
70−
71−void TouchRegistry::update(const QTouchEvent *event)
72−{
73− #if TOUCHREGISTRY_DEBUG
74− UG_DEBUG << "got" << qPrintable(touchEventToString(event));
75− #endif
76−
77− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
78− for (int i = 0; i < touchPoints.count(); ++i) {
79− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
80− if (touchPoint.state() == Qt::TouchPointPressed) {
81− TouchInfo &touchInfo = m_touchInfoPool.getEmptySlot();
82− touchInfo.init(touchPoint.id());
83− } else if (touchPoint.state() == Qt::TouchPointReleased) {
84− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchPoint.id());
85−
86− touchInfo->physicallyEnded = true;
87− }
88− }
89−
90− deliverTouchUpdatesToUndecidedCandidatesAndWatchers(event);
91−
92− freeEndedTouchInfos();
93−}
94−
95−void TouchRegistry::deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event)
96−{
97− // TODO: Look into how we could optimize this whole thing.
98− // Although it's not really a problem as we should have at most two candidates
99− // for each point and there should not be many active points at any given moment.
100− // But having three nested for-loops does scare.
101−
102− const QList<QTouchEvent::TouchPoint> &updatedTouchPoints = event->touchPoints();
103−
104− // Maps an item to the touches in this event he should be informed about.
105− // E.g.: a QTouchEvent might have three touches but a given item might be interested in only
106− // one of them. So he will get a UnownedTouchEvent from this QTouchEvent containing only that
107− // touch point.
108− QHash<QQuickItem*, QList<int>> touchIdsForItems;
109−
110− // Build touchIdsForItems
111− m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) {
112− if (touchInfo->isOwned() && touchInfo->watchers.isEmpty())
113− return true;
114−
115− for (int j = 0; j < updatedTouchPoints.count(); ++j) {
116− if (updatedTouchPoints[j].id() == touchInfo->id) {
117− if (!touchInfo->isOwned()) {
118− for (int i = 0; i < touchInfo->candidates.count(); ++i) {
119− CandidateInfo &candidate = touchInfo->candidates[i];
120− Q_ASSERT(!candidate.item.isNull());
121− if (candidate.state != CandidateInfo::InterimOwner) {
122− touchIdsForItems[candidate.item.data()].append(touchInfo->id);
123− }
124− }
125− }
126−
127− const QList<QPointer<QQuickItem>> &watchers = touchInfo->watchers;
128− for (int i = 0; i < watchers.count(); ++i) {
129− if (!watchers[i].isNull()) {
130− touchIdsForItems[watchers[i].data()].append(touchInfo->id);
131− }
132− }
133−
134− return true;
135− }
136− }
137−
138− return true;
139− });
140−
141− // TODO: Consider what happens if an item calls any of TouchRegistry's public methods
142− // from the event handler callback.
143− m_inDispatchLoop = true;
144− auto it = touchIdsForItems.constBegin();
145− while (it != touchIdsForItems.constEnd()) {
146− QQuickItem *item = it.key();
147− const QList<int> &touchIds = it.value();
148− dispatchPointsToItem(event, touchIds, item);
149− ++it;
150− };
151− m_inDispatchLoop = false;
152−}
153−
154−void TouchRegistry::freeEndedTouchInfos()
155−{
156− m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &touchInfo) {
157− if (touchInfo->ended()) {
158− m_touchInfoPool.freeSlot(touchInfo);
159− }
160− return true;
161− });
162−}
163−
164−/*
165− Extracts the touches with the given touchIds from event and send them in a
166− UnownedTouchEvent to the given item
167− */
168−void TouchRegistry::dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds,
169− QQuickItem *item)
170−{
171− Qt::TouchPointStates touchPointStates = 0;
172− QList<QTouchEvent::TouchPoint> touchPoints;
173−
174− const QList<QTouchEvent::TouchPoint> &allTouchPoints = event->touchPoints();
175−
176− QTransform windowToCandidateTransform = QQuickItemPrivate::get(item)->windowToItemTransform();
177− QMatrix4x4 windowToCandidateMatrix(windowToCandidateTransform);
178−
179− for (int i = 0; i < allTouchPoints.count(); ++i) {
180− const QTouchEvent::TouchPoint &originalTouchPoint = allTouchPoints[i];
181− if (touchIds.contains(originalTouchPoint.id())) {
182− QTouchEvent::TouchPoint touchPoint = originalTouchPoint;
183−
184− translateTouchPointFromScreenToWindowCoords(touchPoint);
185−
186− // Set the point's local coordinates to that of the item
187− touchPoint.setRect(windowToCandidateTransform.mapRect(touchPoint.sceneRect()));
188− touchPoint.setStartPos(windowToCandidateTransform.map(touchPoint.startScenePos()));
189− touchPoint.setLastPos(windowToCandidateTransform.map(touchPoint.lastScenePos()));
190− touchPoint.setVelocity(windowToCandidateMatrix.mapVector(touchPoint.velocity()).toVector2D());
191−
192− touchPoints.append(touchPoint);
193− touchPointStates |= touchPoint.state();
194− }
195− }
196−
197− QTouchEvent *eventForItem = new QTouchEvent(event->type(),
198− event->device(),
199− event->modifiers(),
200− touchPointStates,
201− touchPoints);
202− eventForItem->setWindow(event->window());
203− eventForItem->setTimestamp(event->timestamp());
204− eventForItem->setTarget(event->target());
205−
206− UnownedTouchEvent unownedTouchEvent(eventForItem);
207−
208− #if TOUCHREGISTRY_DEBUG
209− UG_DEBUG << "Sending unowned" << qPrintable(touchEventToString(eventForItem))
210− << "to" << item;
211− #endif
212−
213− QCoreApplication::sendEvent(item, &unownedTouchEvent);
214−}
215−
216−void TouchRegistry::translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint)
217−{
218− touchPoint.setScreenRect(touchPoint.sceneRect());
219− touchPoint.setStartScreenPos(touchPoint.startScenePos());
220− touchPoint.setLastScreenPos(touchPoint.lastScenePos());
221−
222− touchPoint.setSceneRect(touchPoint.rect());
223− touchPoint.setStartScenePos(touchPoint.startPos());
224− touchPoint.setLastScenePos(touchPoint.lastPos());
225−}
226−
227−bool TouchRegistry::eventFilter(QObject *watched, QEvent *event)
228−{
229− Q_UNUSED(watched);
230−
231− switch (event->type()) {
232− case QEvent::TouchBegin:
233− case QEvent::TouchUpdate:
234− case QEvent::TouchEnd:
235− case QEvent::TouchCancel:
236− update(static_cast<QTouchEvent*>(event));
237− break;
238− default:
239− // do nothing
240− break;
241− }
242−
243− // Do not filter out the event. i.e., let it be handled further as
244− // we're just monitoring events
245− return false;
246−}
247−
248−void TouchRegistry::addCandidateOwnerForTouch(int id, QQuickItem *candidate)
249−{
250− #if TOUCHREGISTRY_DEBUG
251− UG_DEBUG << "addCandidateOwnerForTouch id" << id << "candidate" << candidate;
252− #endif
253−
254− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
255− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
256−
257− if (touchInfo->isOwned()) {
258− qWarning("TouchRegistry: trying to add candidate owner for a touch that's already owned");
259− return;
260− }
261−
262− // TODO: Check if candidate already exists
263−
264− CandidateInfo candidateInfo;
265− candidateInfo.state = CandidateInfo::Undecided;
266− candidateInfo.item = candidate;
267− candidateInfo.inactivityTimer = new CandidateInactivityTimer(id, candidate,
268− m_timerFactory->createTimer(),
269− this);
270− connect(candidateInfo.inactivityTimer, &CandidateInactivityTimer::candidateDefaulted,
271− this, &TouchRegistry::rejectCandidateOwnerForTouch);
272−
273− touchInfo->candidates.append(candidateInfo);
274−
275− connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
276−}
277−
278−void TouchRegistry::addTouchWatcher(int touchId, QQuickItem *watcher)
279−{
280− #if TOUCHREGISTRY_DEBUG
281− UG_DEBUG << "addTouchWatcher id" << touchId << "watcher" << watcher;
282− #endif
283−
284− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
285− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
286−
287− // TODO: Check if watcher already exists
288−
289− touchInfo->watchers.append(watcher);
290−}
291−
292−void TouchRegistry::removeCandidateOwnerForTouch(int id, QQuickItem *candidate)
293−{
294− #if TOUCHREGISTRY_DEBUG
295− UG_DEBUG << "removeCandidateOwnerForTouch id" << id << "candidate" << candidate;
296− #endif
297−
298− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
299− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
300−
301−
302− // TODO: check if the candidate is in fact the owner of the touch
303−
304− bool removed = false;
305− for (int i = 0; i < touchInfo->candidates.count() && !removed; ++i) {
306− if (touchInfo->candidates[i].item == candidate) {
307− removeCandidateOwnerForTouchByIndex(touchInfo, i);
308− removed = true;
309− }
310− }
311−}
312−
313−void TouchRegistry::pruneNullCandidatesForTouch(int touchId)
314−{
315− #if TOUCHREGISTRY_DEBUG
316− UG_DEBUG << "pruneNullCandidatesForTouch touchId" << touchId;
317− #endif
318−
319− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(touchId);
320− if (!touchInfo) {
321− // doesn't matter as touch is already gone.
322− return;
323− }
324−
325− int i = 0;
326− while (i < touchInfo->candidates.count()) {
327− if (touchInfo->candidates[i].item.isNull()) {
328− removeCandidateOwnerForTouchByIndex(touchInfo, i);
329− } else {
330− ++i;
331− }
332− }
333−}
334−
335−void TouchRegistry::removeCandidateOwnerForTouchByIndex(Pool<TouchRegistry::TouchInfo>::Iterator &touchInfo,
336− int candidateIndex)
337−{
338− // TODO: check if the candidate is in fact the owner of the touch
339−
340− Q_ASSERT(candidateIndex < touchInfo->candidates.count());
341−
342− if (candidateIndex == 0 && touchInfo->candidates[candidateIndex].state != CandidateInfo::Undecided) {
343− qCritical("TouchRegistry: touch owner is being removed.");
344− }
345− removeCandidateHelper(touchInfo, candidateIndex);
346−
347− if (candidateIndex == 0) {
348− // the top candidate has been removed. if the new top candidate
349− // wants the touch let him know he's now the owner.
350− if (touchInfo->isOwned()) {
351− touchInfo->notifyCandidatesOfOwnershipResolution();
352− }
353− }
354−
355− if (!m_inDispatchLoop && touchInfo->ended()) {
356− m_touchInfoPool.freeSlot(touchInfo);
357− }
358−}
359−
360−void TouchRegistry::requestTouchOwnership(int id, QQuickItem *candidate)
361−{
362− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
363− if (!touchInfo) { qFatal("TouchRegistry: Failed to find TouchInfo"); }
364−
365− Q_ASSERT(!touchInfo->isOwned());
366−
367− int candidateIndex = -1;
368− for (int i = 0; i < touchInfo->candidates.count(); ++i) {
369− CandidateInfo &candidateInfo = touchInfo->candidates[i];
370− if (candidateInfo.item == candidate) {
371− candidateInfo.state = CandidateInfo::Requested;
372− delete candidateInfo.inactivityTimer;
373− candidateInfo.inactivityTimer = nullptr;
374− candidateIndex = i;
375− break;
376− }
377− }
378− #if TOUCHREGISTRY_DEBUG
379− UG_DEBUG << "requestTouchOwnership id " << id << "candidate" << candidate << "index: " << candidateIndex;
380− #endif
381−
382− // add it as a candidate if not present yet
383− if (candidateIndex < 0) {
384− CandidateInfo candidateInfo;
385− candidateInfo.state = CandidateInfo::InterimOwner;
386− candidateInfo.item = candidate;
387− candidateInfo.inactivityTimer = nullptr;
388− touchInfo->candidates.append(candidateInfo);
389− // it's the last one
390− candidateIndex = touchInfo->candidates.count() - 1;
391− connect(candidate, &QObject::destroyed, this, [=](){ pruneNullCandidatesForTouch(id); });
392− }
393−
394− // If it's the top candidate it means it's now the owner. Let
395− // it know about it.
396− if (candidateIndex == 0) {
397− touchInfo->notifyCandidatesOfOwnershipResolution();
398− }
399−}
400−
401−Pool<TouchRegistry::TouchInfo>::Iterator TouchRegistry::findTouchInfo(int id)
402−{
403− Pool<TouchInfo>::Iterator touchInfo;
404−
405− m_touchInfoPool.forEach([&](Pool<TouchInfo>::Iterator &someTouchInfo) -> bool {
406− if (someTouchInfo->id == id) {
407− touchInfo = someTouchInfo;
408− return false;
409− } else {
410− return true;
411− }
412− });
413−
414− return touchInfo;
415−}
416−
417−
418−void TouchRegistry::rejectCandidateOwnerForTouch(int id, QQuickItem *candidate)
419−{
420− // NB: It's technically possible that candidate is a dangling pointer at this point.
421− // Although that would most likely be due to a bug in our code.
422− // In any case, only dereference it after it's confirmed that it indeed exists.
423−
424− #if TOUCHREGISTRY_DEBUG
425− UG_DEBUG << "rejectCandidateOwnerForTouch id" << id << "candidate" << (void*)candidate;
426− #endif
427−
428− Pool<TouchInfo>::Iterator touchInfo = findTouchInfo(id);
429− if (!touchInfo) {
430− #if TOUCHREGISTRY_DEBUG
431− UG_DEBUG << "Failed to find TouchInfo for id" << id;
432− #endif
433− return;
434− }
435−
436− int rejectedCandidateIndex = -1;
437−
438− // Check if the given candidate is valid and still undecided
439− for (int i = 0; i < touchInfo->candidates.count() && rejectedCandidateIndex == -1; ++i) {
440− CandidateInfo &candidateInfo = touchInfo->candidates[i];
441− if (candidateInfo.item == candidate) {
442− Q_ASSERT(i > 0 || candidateInfo.state == CandidateInfo::Undecided);
443− if (i == 0 && candidateInfo.state != CandidateInfo::Undecided) {
444− qCritical() << "TouchRegistry: Can't reject item (" << (void*)candidate
445− << ") as it already owns touch" << id;
446− return;
447− } else {
448− // we found the guy and it's all fine.
449− rejectedCandidateIndex = i;
450− }
451− }
452− }
453−
454− // If we reached this point it's because the given candidate exists and is indeed undecided.
455−
456− Q_ASSERT(rejectedCandidateIndex >= 0 && rejectedCandidateIndex < touchInfo->candidates.size());
457−
458− {
459− TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/);
460− QCoreApplication::sendEvent(candidate, &lostOwnershipEvent);
461− }
462−
463− removeCandidateHelper(touchInfo, rejectedCandidateIndex);
464−
465− if (rejectedCandidateIndex == 0) {
466− // the top candidate has been removed. if the new top candidate
467− // wants the touch let him know he's now the owner.
468− if (touchInfo->isOwned()) {
469− touchInfo->notifyCandidatesOfOwnershipResolution();
470− }
471− }
472−}
473−
474−void TouchRegistry::removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex)
475−{
476− {
477− CandidateInfo &candidateInfo = touchInfo->candidates[candidateIndex];
478−
479− delete candidateInfo.inactivityTimer;
480− candidateInfo.inactivityTimer = nullptr;
481−
482− if (candidateInfo.item) {
483− disconnect(candidateInfo.item.data(), nullptr, this, nullptr);
484− }
485− }
486− touchInfo->candidates.removeAt(candidateIndex);
487−}
488−
489−////////////////////////////////////// TouchRegistry::TouchInfo ////////////////////////////////////
490−
491−TouchRegistry::TouchInfo::TouchInfo(int id)
492−{
493− init(id);
494−}
495−
496−void TouchRegistry::TouchInfo::reset()
497−{
498− id = -1;
499−
500− for (int i = 0; i < candidates.count(); ++i) {
501− CandidateInfo &candidate = candidates[i];
502− delete candidate.inactivityTimer;
503− candidate.inactivityTimer.clear(); // shoundn't be needed but anyway...
504− }
505−}
506−
507−void TouchRegistry::TouchInfo::init(int id)
508−{
509− this->id = id;
510− physicallyEnded = false;
511− candidates.clear();
512− watchers.clear();
513−}
514−
515−bool TouchRegistry::TouchInfo::isOwned() const
516−{
517− return !candidates.isEmpty() && candidates.first().state != CandidateInfo::Undecided;
518−}
519−
520−bool TouchRegistry::TouchInfo::ended() const
521−{
522− Q_ASSERT(isValid());
523− return physicallyEnded && (isOwned() || candidates.isEmpty());
524−}
525−
526−void TouchRegistry::TouchInfo::notifyCandidatesOfOwnershipResolution()
527−{
528− Q_ASSERT(isOwned());
529−
530− #if TOUCHREGISTRY_DEBUG
531− UG_DEBUG << "sending TouchOwnershipEvent(id =" << id
532− << " gained) to candidate" << candidates[0].item;
533− #endif
534−
535− // need to take a copy of the item list in case
536− // we call back in to remove candidate during the lost ownership event.
537− QList<QPointer<QQuickItem>> items;
538− Q_FOREACH(const CandidateInfo& info, candidates) {
539− items << info.item;
540− }
541−
542− TouchOwnershipEvent gainedOwnershipEvent(id, true /*gained*/);
543− QCoreApplication::sendEvent(items[0], &gainedOwnershipEvent);
544−
545− TouchOwnershipEvent lostOwnershipEvent(id, false /*gained*/);
546− for (int i = 1; i < items.count(); ++i) {
547− #if TOUCHREGISTRY_DEBUG
548− UG_DEBUG << "sending TouchOwnershipEvent(id =" << id << " lost) to candidate"
549− << items[i];
550− #endif
551− QCoreApplication::sendEvent(items[i], &lostOwnershipEvent);
552− }
553−}
libs/UbuntuGestures/TouchRegistry.hdeleted−201
@@ -1,201 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 UNITY_TOUCHREGISTRY_H
18−#define UNITY_TOUCHREGISTRY_H
19−
20−#include <QQuickItem>
21−#include <QObject>
22−#include <QPointer>
23−#include <QTouchEvent>
24−#include <QVector>
25−
26−#include "UbuntuGesturesGlobal.h"
27−#include "CandidateInactivityTimer.h"
28−#include "Timer.h"
29−#include "Pool.h"
30−
31−namespace UbuntuGestures {
32− class AbstractTimerFactory;
33−}
34−
35−/*
36− Where the ownership of touches is registered.
37−
38− Singleton used for adding a touch point ownership model analogous to the one
39− described in the XInput 2.2 protocol[1] on top of the existing input dispatch logic in QQuickWindow.
40−
41− It provides a much more flexible and powerful way of dealing with pointer ownership than the existing
42− mechanisms in Qt. Namely QQuickItem::grabTouchPoints, QuickItem::keepTouchGrab,
43− QQuickItem::setFiltersChildMouseEvents, QQuickItem::ungrabTouchPoints and QQuickItem::touchUngrabEvent.
44−
45− Usage:
46−
47− 1- An item receives a a new touch point. If he's not sure whether he wants it yet, he calls:
48− TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, this);
49− touchEvent->ignore();
50− Ignoring the event is crucial so that it can be seen by other interested parties, which will
51− behave similarly.
52−
53− 2- That item will then start receiving UnownedTouchEvents for that touch from step 1. Once he's
54− made a decision he calls either:
55− TouchRegistry::instance()->requestTouchOwnership(touchId, this);
56− If he wants the touch point or:
57− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, this);
58−  if he does not want it.
59−
60− Candidates are put in a priority queue. The first one to call addCandidateOwnerForTouch() will
61− take precedence over the others for receiving ownership over the touch point (from now on called
62− simply top-candidate).
63−
64− If the top-candidate calls requestTouchOwnership() he will immediately receive a
65− TouchOwnershipEvent(gained=true) for that touch point. He can then safely call
66− QQuickItem::grabTouchPoints to actually get the owned touch points. The other candidates
67− will receive TouchOwnershipEvent(gained=false) and will no longer receive UnownedTouchEvents
68− for that touch point. They will have to undo whatever action they were performing with that
69− touch point.
70−
71− But if the top-candidate calls removeCandidateOwnerForTouch() instead, he's popped from the
72− candidacy queue and ownership is given to the new top-most candidate if he has already
73− made his decision, that is.
74−
75− The TouchRegistry cannot enforce the results of this pointer ownership negotiation (i.e.,
76− who gets to grab the touch points) as that would clash with QQuickWindow's input event
77− dispatching logic. The candidates have to respect the decision and grab the touch points
78− themselves.
79−
80− If an item wants ownership over touches as soon as he receives the TouchBegin for them, his step 1
81− would be instead:
82− TouchRegistry::instance()->requestTouchOwnership(touchId, this);
83− touchEvent->accept();
84− He won't get any UnownedTouchEvent for that touch as he is already the interim owner (ie, QQuickWindow
85− will keep sending touch updates to him already). Eventually he will be notified once ownership has
86− been granted to him (from TouchRegistry perspective), from which point onwards he could safely assume
87− other TouchRegistry users wouldn't snatch this touch away from him.
88−
89− Items oblivious to TouchRegistry will lose their touch points without warning, just like in plain Qt.
90−
91− [1] - http://www.x.org/releases/X11R7.7/doc/inputproto/XI2proto.txt (see multitouch-ownership)
92− */
93−class UBUNTUGESTURES_EXPORT TouchRegistry : public QObject
94−{
95− Q_OBJECT
96−public:
97− virtual ~TouchRegistry();
98−
99− // Returns a pointer to the application's TouchRegistry instance.
100− static TouchRegistry *instance();
101−
102− void update(const QTouchEvent *event);
103−
104− // Calls update() if the given event is a QTouchEvent
105− bool eventFilter(QObject *watched, QEvent *event) override;
106−
107− // An item that might later request ownership over the given touch point.
108− // He will be kept informed about that touch point through UnownedTouchEvents
109− // All candidates must eventually decide whether they want to own the touch point
110− // or not. That decision is informed through requestTouchOwnership() or
111− // removeCandidateOwnerForTouch()
112− void addCandidateOwnerForTouch(int id, QQuickItem *candidate);
113−
114− // The same as rejecting ownership of a touch
115− void removeCandidateOwnerForTouch(int id, QQuickItem *candidate);
116−
117− // The candidate object wants to be the owner of the touch with the given id.
118− // If he's currently the oldest/top-most candidate, he will get an ownership
119− // event immediately. If not, he will get ownership if (or once) he becomes the
120− // top-most candidate.
121− void requestTouchOwnership(int id, QQuickItem *candidate);
122−
123− // An item that has no interest (effective or potential) in owning a touch point
124− // but would nonetheless like to be kept up-to-date on its state.
125− void addTouchWatcher(int touchId, QQuickItem *watcherItem);
126−
127− // Useful for tests, where you should use fake timers
128− void setTimerFactory(UbuntuGestures::AbstractTimerFactory *timerFactory);
129−
130−private Q_SLOTS:
131− void rejectCandidateOwnerForTouch(int id, QQuickItem *candidate);
132−
133−private:
134− // Only instance() can cronstruct one
135− TouchRegistry(QObject *parent = nullptr);
136−
137− class CandidateInfo {
138− public:
139− enum {
140− // A candidate owner that doesn't yet know for sure whether he wants the touch point
141− // (gesture recognition is stilll going on)
142− Undecided = 0,
143− // A candidate owner that wants the touch but hasn't been granted it yet,
144− // most likely because there's an undecided candidate with higher priority
145− Requested = 1,
146− // An item that is the interim owner of the touch, receiving QTouchEvents of it
147− // from QQuickWindow. Ie, it's the actual touch owner from Qt's point of view.
148− // It wants to keep its touch ownership but hasn't been granted it by TouchRegistry
149− // yet because of undecided candidates higher up.
150− InterimOwner = 2
151− } state;
152− QPointer<QQuickItem> item;
153− QPointer<UbuntuGestures::CandidateInactivityTimer> inactivityTimer;
154− };
155−
156− class TouchInfo {
157− public:
158− TouchInfo() : id(-1) {}
159− TouchInfo(int id);
160− bool isValid() const { return id >= 0; }
161− void reset();
162− void init(int id);
163− int id;
164− bool physicallyEnded;
165− bool isOwned() const;
166− bool ended() const;
167− void notifyCandidatesOfOwnershipResolution();
168−
169− // TODO optimize storage (s/QList/Pool)
170− QList<CandidateInfo> candidates;
171− QList<QPointer<QQuickItem>> watchers;
172− };
173−
174− void pruneNullCandidatesForTouch(int touchId);
175− void removeCandidateOwnerForTouchByIndex(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex);
176− void removeCandidateHelper(Pool<TouchInfo>::Iterator &touchInfo, int candidateIndex);
177−
178− Pool<TouchInfo>::Iterator findTouchInfo(int id);
179−
180− void deliverTouchUpdatesToUndecidedCandidatesAndWatchers(const QTouchEvent *event);
181−
182− static void translateTouchPointFromScreenToWindowCoords(QTouchEvent::TouchPoint &touchPoint);
183−
184− static void dispatchPointsToItem(const QTouchEvent *event, const QList<int> &touchIds,
185− QQuickItem *item);
186− void freeEndedTouchInfos();
187−
188− Pool<TouchInfo> m_touchInfoPool;
189−
190− // the singleton instance
191− static TouchRegistry *m_instance;
192−
193− bool m_inDispatchLoop;
194−
195− UbuntuGestures::AbstractTimerFactory *m_timerFactory;
196−
197− friend class tst_TouchRegistry;
198− friend class tst_DirectionalDragArea;
199−};
200−
201−#endif // UNITY_TOUCHREGISTRY_H
libs/UbuntuGestures/UbuntuGesturesGlobal.hdeleted−23
@@ -1,23 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 <QtCore/QtGlobal>
18−
19−#if defined(UBUNTUGESTURES_LIBRARY)
20−# define UBUNTUGESTURES_EXPORT Q_DECL_EXPORT
21−#else
22−# define UBUNTUGESTURES_EXPORT Q_DECL_IMPORT
23−#endif
libs/UbuntuGestures/UnownedTouchEvent.cppdeleted−39
@@ -1,39 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 "UnownedTouchEvent.h"
18−
19−QEvent::Type UnownedTouchEvent::m_unownedTouchEventType = (QEvent::Type)-1;
20−
21−UnownedTouchEvent::UnownedTouchEvent(QTouchEvent *touchEvent)
22− : QEvent(unownedTouchEventType())
23− , m_touchEvent(touchEvent)
24−{
25−}
26−
27−QEvent::Type UnownedTouchEvent::unownedTouchEventType()
28−{
29− if (m_unownedTouchEventType == (QEvent::Type)-1) {
30− m_unownedTouchEventType = (QEvent::Type)registerEventType();
31− }
32−
33− return m_unownedTouchEventType;
34−}
35−
36−QTouchEvent *UnownedTouchEvent::touchEvent()
37−{
38− return m_touchEvent.data();
39−}
libs/UbuntuGestures/UnownedTouchEvent.hdeleted−45
@@ -1,45 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 UBUNTU_UNOWNEDTOUCHEVENT_H
18−#define UBUNTU_UNOWNEDTOUCHEVENT_H
19−
20−#include <QTouchEvent>
21−#include <QScopedPointer>
22−#include "UbuntuGesturesGlobal.h"
23−
24−/*
25− A touch event with touch points that do not belong the item receiving it.
26−
27− See TouchRegistry::addCandidateOwnerForTouch and TouchRegistry::addTouchWatcher
28− */
29−class UBUNTUGESTURES_EXPORT UnownedTouchEvent : public QEvent
30−{
31−public:
32− UnownedTouchEvent(QTouchEvent *touchEvent);
33− static Type unownedTouchEventType();
34−
35− // TODO: It might be cleaner to store the information directly in UnownedTouchEvent
36− // instead of carrying around a synthesized QTouchEvent. But the latter option
37− // is very convenient.
38− QTouchEvent *touchEvent();
39−
40−private:
41− static Type m_unownedTouchEventType;
42− QScopedPointer<QTouchEvent> m_touchEvent;
43−};
44−
45−#endif // UBUNTU_UNOWNEDTOUCHEVENT_H
plugins/Cursor/CMakeLists.txt+2−1
@@ -8,8 +8,9 @@ include_directories(
88
99set(QMLPLUGIN_SRC
1010 plugin.cpp
11− MousePointer.cpp
11+ CursorImageInfo.cpp
1212 CursorImageProvider.cpp
13+ MousePointer.cpp
1314 # We need to run moc on this header
1415 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirMousePointerInterface.h
1516 )
plugins/Cursor/Cursor.qml+21−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 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
@@ -15,14 +15,30 @@
1515 */
1616
1717import QtQuick 2.4
18−import Cursor 1.0 // For MousePointer
18+import Cursor 1.1
1919
2020MousePointer {
2121 id: mousePointer
2222
23− Image {
24− x: -mousePointer.hotspotX
25− y: -mousePointer.hotspotY
23+ CursorImageInfo {
24+ id: imageInfo
25+ themeName: mousePointer.themeName
26+ cursorName: mousePointer.cursorName
27+ }
28+
29+ AnimatedSprite {
30+ x: -imageInfo.hotspot.x
31+ y: -imageInfo.hotspot.y
2632 source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
33+
34+ interpolate: false
35+
36+ width: imageInfo.frameWidth
37+ height: imageInfo.frameHeight
38+
39+ frameCount: imageInfo.frameCount
40+ frameDuration: imageInfo.frameDuration
41+ frameWidth: imageInfo.frameWidth
42+ frameHeight: imageInfo.frameHeight
2743 }
2844}
plugins/Cursor/Cursor.qmltypesdeleted−78
@@ -1,78 +0,0 @@
1−import QtQuick.tooling 1.1
2−
3−// This file describes the plugin-supplied types contained in the library.
4−// It is used for QML tooling purposes only.
5−//
6−// This file was auto-generated by:
7−// 'qmlplugindump -notrelocatable Cursor 1.0 plugins'
8−
9−Module {
10− Component {
11− name: "MirMousePointerInterface"
12− defaultProperty: "data"
13− prototype: "QQuickItem"
14− Property { name: "cursorName"; type: "string"; isReadonly: true }
15− Property { name: "themeName"; type: "string"; isReadonly: true }
16− Property { name: "hotspotX"; type: "double"; isReadonly: true }
17− Property { name: "hotspotY"; type: "double"; isReadonly: true }
18− Signal {
19− name: "cursorNameChanged"
20− Parameter { name: "name"; type: "string" }
21− }
22− Signal {
23− name: "themeNameChanged"
24− Parameter { name: "name"; type: "string" }
25− }
26− Signal {
27− name: "hotspotXChanged"
28− Parameter { name: "value"; type: "double" }
29− }
30− Signal {
31− name: "hotspotYChanged"
32− Parameter { name: "value"; type: "double" }
33− }
34− Method {
35− name: "handleMouseEvent"
36− Parameter { name: "timestamp"; type: "ulong" }
37− Parameter { name: "movement"; type: "QPointF" }
38− Parameter { name: "buttons"; type: "Qt::MouseButtons" }
39− Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
40− }
41− Method {
42− name: "handleWheelEvent"
43− Parameter { name: "timestamp"; type: "ulong" }
44− Parameter { name: "angleDelta"; type: "QPoint" }
45− Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
46− }
47− }
48− Component {
49− name: "MousePointer"
50− defaultProperty: "data"
51− prototype: "MirMousePointerInterface"
52− exports: ["Cursor/MousePointer 1.0"]
53− exportMetaObjectRevisions: [0]
54− Signal {
55− name: "pushedLeftBoundary"
56− Parameter { name: "amount"; type: "double" }
57− Parameter { name: "buttons"; type: "Qt::MouseButtons" }
58− }
59− Signal {
60− name: "pushedRightBoundary"
61− Parameter { name: "amount"; type: "double" }
62− Parameter { name: "buttons"; type: "Qt::MouseButtons" }
63− }
64− Method {
65− name: "handleMouseEvent"
66− Parameter { name: "timestamp"; type: "ulong" }
67− Parameter { name: "movement"; type: "QPointF" }
68− Parameter { name: "buttons"; type: "Qt::MouseButtons" }
69− Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
70− }
71− Method {
72− name: "handleWheelEvent"
73− Parameter { name: "timestamp"; type: "ulong" }
74− Parameter { name: "angleDelta"; type: "QPoint" }
75− Parameter { name: "modifiers"; type: "Qt::KeyboardModifiers" }
76− }
77− }
78−}
plugins/Cursor/CursorImageInfo.cppnew file+106
@@ -0,0 +1,106 @@
1+/*
2+ * Copyright (C) 2016 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 "CursorImageInfo.h"
18+
19+CursorImageInfo::CursorImageInfo(QObject *parent)
20+ : QObject(parent)
21+{
22+ m_updateTimer.setInterval(0);
23+ m_updateTimer.setSingleShot(true);
24+ connect(&m_updateTimer, &QTimer::timeout, this, &CursorImageInfo::update);
25+}
26+
27+void CursorImageInfo::setCursorName(const QString &cursorName)
28+{
29+ if (cursorName != m_cursorName) {
30+ m_cursorName = cursorName;
31+ Q_EMIT cursorNameChanged();
32+ scheduleUpdate();
33+ }
34+}
35+
36+void CursorImageInfo::setThemeName(const QString &themeName)
37+{
38+ if (m_themeName != themeName) {
39+ m_themeName = themeName;
40+ Q_EMIT themeNameChanged();
41+ scheduleUpdate();
42+ }
43+}
44+
45+void CursorImageInfo::scheduleUpdate()
46+{
47+ if (!m_updateTimer.isActive()) {
48+ m_updateTimer.start();
49+ }
50+}
51+
52+void CursorImageInfo::update()
53+{
54+ m_cursorImage = CursorImageProvider::instance()->fetchCursor(m_themeName, m_cursorName);
55+
56+ Q_EMIT hotspotChanged();
57+ Q_EMIT frameWidthChanged();
58+ Q_EMIT frameHeightChanged();
59+ Q_EMIT frameCountChanged();
60+ Q_EMIT frameDurationChanged();
61+}
62+
63+QPoint CursorImageInfo::hotspot() const
64+{
65+ if (m_cursorImage) {
66+ return m_cursorImage->hotspot;
67+ } else {
68+ return QPoint();
69+ }
70+}
71+
72+qreal CursorImageInfo::frameWidth() const
73+{
74+ if (m_cursorImage) {
75+ return m_cursorImage->frameWidth;
76+ } else {
77+ return 0;
78+ }
79+}
80+
81+qreal CursorImageInfo::frameHeight() const
82+{
83+ if (m_cursorImage) {
84+ return m_cursorImage->frameHeight;
85+ } else {
86+ return 0;
87+ }
88+}
89+
90+int CursorImageInfo::frameCount() const
91+{
92+ if (m_cursorImage) {
93+ return m_cursorImage->frameCount;
94+ } else {
95+ return 0;
96+ }
97+}
98+
99+int CursorImageInfo::frameDuration() const
100+{
101+ if (m_cursorImage) {
102+ return m_cursorImage->frameDuration;
103+ } else {
104+ return 0;
105+ }
106+}
plugins/Cursor/CursorImageInfo.hnew file+76
@@ -0,0 +1,76 @@
1+/*
2+ * Copyright (C) 2016 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 CURSOR_IMAGE_INFO_H
18+#define CURSOR_IMAGE_INFO_H
19+
20+#include "CursorImageProvider.h"
21+
22+#include <QObject>
23+#include <QString>
24+#include <QTimer>
25+
26+class CursorImageInfo : public QObject
27+{
28+ Q_OBJECT
29+
30+ Q_PROPERTY(QString themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged)
31+ Q_PROPERTY(QString cursorName READ cursorName WRITE setCursorName NOTIFY cursorNameChanged)
32+
33+ Q_PROPERTY(QPoint hotspot READ hotspot NOTIFY hotspotChanged)
34+ Q_PROPERTY(qreal frameWidth READ frameWidth NOTIFY frameWidthChanged)
35+ Q_PROPERTY(qreal frameHeight READ frameHeight NOTIFY frameHeightChanged)
36+ Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged)
37+ Q_PROPERTY(int frameDuration READ frameDuration NOTIFY frameDurationChanged)
38+
39+public:
40+ CursorImageInfo(QObject *parent = nullptr);
41+
42+ QString themeName() const { return m_themeName; }
43+ void setThemeName(const QString &);
44+
45+ QString cursorName() const { return m_cursorName; }
46+ void setCursorName(const QString &);
47+
48+ QPoint hotspot() const;
49+ qreal frameWidth() const;
50+ qreal frameHeight() const;
51+ int frameCount() const;
52+ int frameDuration() const;
53+
54+Q_SIGNALS:
55+ void themeNameChanged();
56+ void cursorNameChanged();
57+ void hotspotChanged();
58+ void frameWidthChanged();
59+ void frameHeightChanged();
60+ void frameCountChanged();
61+ void frameDurationChanged();
62+
63+private Q_SLOTS:
64+ void update();
65+
66+private:
67+ void scheduleUpdate();
68+ QTimer m_updateTimer;
69+
70+ QString m_themeName;
71+ QString m_cursorName;
72+
73+ CursorImage *m_cursorImage{nullptr};
74+};
75+
76+#endif // CURSOR_IMAGE_INFO_H
plugins/Cursor/CursorImageProvider.cpp+50−21
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 Canonical, Ltd.
33 *
44 * This program is free software: you can redistribute it and/or modify it under
55 * the terms of the GNU Lesser General Public License version 3, as published by
@@ -46,6 +46,9 @@ BuiltInCursorImage::BuiltInCursorImage()
4646 qimage.fill(Qt::transparent);
4747 QPainter imagePainter(&qimage);
4848
49+ frameWidth = qimage.width();
50+ frameHeight = qimage.height();
51+
4952 QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
5053 svgRenderer->render(&imagePainter);
5154 delete svgRenderer;
@@ -59,6 +62,8 @@ BlankCursorImage::BlankCursorImage()
5962{
6063 qimage = QImage(1, 1, QImage::Format_ARGB32);
6164 qimage.fill(Qt::transparent);
65+ frameWidth = qimage.width();
66+ frameHeight = qimage.height();
6267}
6368
6469/////
@@ -69,40 +74,74 @@ CustomCursorImage::CustomCursorImage(const QCursor &cursor)
6974{
7075 qimage = cursor.pixmap().toImage();
7176 hotspot = cursor.hotSpot();
77+ frameWidth = qimage.width();
78+ frameHeight = qimage.height();
7279}
7380
7481/////
7582// XCursorImage
7683
7784XCursorImage::XCursorImage(const QString &theme, const QString &file)
78− : xcursorImages(nullptr)
7985{
8086 // TODO: Consider grid unit value
8187 // Hardcoding to a medium size for now
8288 int preferredCursorHeightPx = 32;
8389
84− xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),
90+ XcursorImages *xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),
8591 preferredCursorHeightPx);
86− if (!xcursorImages) {
92+ if (!xcursorImages || xcursorImages->nimage == 0) {
8793 return;
8894 }
8995
90− // Just take the first one. It will have multiple images in case of an animated cursor.
91− // TODO: Support animated cursors
92− if ( xcursorImages->nimage > 0) {
93− XcursorImage *xcursorImage = xcursorImages->images[0];
96+ frameCount = xcursorImages->nimage;
9497
95− qimage = QImage((uchar*)xcursorImage->pixels,
96− xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
98+ for (int i = 0; i < xcursorImages->nimage; ++i) {
99+ XcursorImage *xcursorImage = xcursorImages->images[0];
100+ if (frameWidth < (int)xcursorImage->width) {
101+ frameWidth = xcursorImage->width;
102+ }
103+ if (frameHeight < (int)xcursorImage->height) {
104+ frameHeight = xcursorImage->height;
105+ }
106+ if (i == 0) {
107+ frameDuration = (int)xcursorImage->delay;
108+ } else {
109+ if (frameDuration != (int)xcursorImage->delay) {
110+ qWarning().nospace() << "CursorImageProvider: XCursorImage("<<theme<<","<<file<<") has"
111+ " varying delays in its animation. Animation won't look right.";
112+ }
113+ }
114+ }
97115
116+ {
117+ // Assume that the hotspot position does not animate
118+ XcursorImage *xcursorImage = xcursorImages->images[0];
98119 hotspot.setX(xcursorImage->xhot);
99120 hotspot.setY(xcursorImage->yhot);
100121 }
122+
123+ // Build the sprite as a single row of frames
124+ qimage = QImage(frameWidth*frameCount, frameHeight, QImage::Format_ARGB32);
125+ qimage.fill(Qt::transparent);
126+
127+ {
128+ QPainter painter(&qimage);
129+
130+ for (int i = 0; i < xcursorImages->nimage; ++i) {
131+ XcursorImage *xcursorImage = xcursorImages->images[i];
132+
133+ auto frameImage = QImage((uchar*)xcursorImage->pixels,
134+ xcursorImage->width, xcursorImage->height, QImage::Format_ARGB32);
135+
136+ painter.drawImage(QPoint(i*frameWidth, 0), frameImage);
137+ }
138+ }
139+
140+ XcursorImagesDestroy(xcursorImages);
101141}
102142
103143XCursorImage::~XCursorImage()
104144{
105− XcursorImagesDestroy(xcursorImages);
106145}
107146
108147/////
@@ -205,16 +244,6 @@ QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSiz
205244 return cursorImage->qimage;
206245}
207246
208−QPoint CursorImageProvider::hotspot(const QString &themeName, const QString &cursorName)
209−{
210− CursorImage *cursorImage = fetchCursor(themeName, cursorName);
211− if (cursorImage) {
212− return cursorImage->hotspot;
213− } else {
214− return QPoint(0,0);
215− }
216−}
217−
218247CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
219248{
220249 QString themeName;
plugins/Cursor/CursorImageProvider.h+12−4
@@ -31,15 +31,23 @@ public:
3131 virtual ~CursorImage() {}
3232
3333 QImage qimage;
34+
35+ // TODO: consider if there's a need to animate the hotspot
36+ // ie, if there's a need to make it an array of points, one for each frame.
37+ // Maybe no single xcursor (or at least the ones we know of or use)
38+ // vary its hotspot position through its animation.
3439 QPoint hotspot;
40+
41+ int frameWidth{0};
42+ int frameHeight{0};
43+ int frameCount{1};
44+ int frameDuration{40};
3545};
3646
3747class XCursorImage : public CursorImage {
3848public:
3949 XCursorImage(const QString &theme, const QString &file);
4050 virtual ~XCursorImage();
41−
42− XcursorImages *xcursorImages;
4351};
4452
4553class BuiltInCursorImage : public CursorImage {
@@ -68,16 +76,16 @@ public:
6876
6977 QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override;
7078
71− QPoint hotspot(const QString &themeName, const QString &cursorName);
79+ CursorImage *fetchCursor(const QString &themeName, const QString &cursorName);
7280
7381 void setCustomCursor(const QCursor &customCursor);
7482
7583private:
7684 CursorImage *fetchCursor(const QString &cursorThemeAndName);
77− CursorImage *fetchCursor(const QString &themeName, const QString &cursorName);
7885 CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName);
7986
8087 // themeName -> (cursorName -> cursorImage)
88+ // TODO: discard old, unused, cursors
8189 QMap<QString, QMap<QString, CursorImage*> > m_cursors;
8290
8391 QScopedPointer<CursorImage> m_builtInCursorImage;
plugins/Cursor/MousePointer.cpp+29−24
@@ -29,10 +29,7 @@ MousePointer::MousePointer(QQuickItem *parent)
2929 : MirMousePointerInterface(parent)
3030 , m_cursorName(QStringLiteral("left_ptr"))
3131 , m_themeName(QStringLiteral("default"))
32− , m_hotspotX(0)
33− , m_hotspotY(0)
3432{
35− updateHotspot();
3633}
3734
3835void MousePointer::handleMouseEvent(ulong timestamp, QPointF movement, Qt::MouseButtons buttons,
@@ -89,8 +86,32 @@ void MousePointer::itemChange(ItemChange change, const ItemChangeData &value)
8986
9087void MousePointer::registerWindow(QWindow *window)
9188{
92− if (m_registeredWindow && window != m_registeredWindow) {
93− auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredWindow->screen()->handle()->cursor());
89+ if (window == m_registeredWindow) {
90+ return;
91+ }
92+
93+ if (m_registeredWindow) {
94+ m_registeredWindow->disconnect(this);
95+ }
96+
97+ m_registeredWindow = window;
98+
99+ if (m_registeredWindow) {
100+ connect(window, &QWindow::screenChanged, this, &MousePointer::registerScreen);
101+ registerScreen(window->screen());
102+ } else {
103+ registerScreen(nullptr);
104+ }
105+}
106+
107+void MousePointer::registerScreen(QScreen *screen)
108+{
109+ if (m_registeredScreen == screen) {
110+ return;
111+ }
112+
113+ if (m_registeredScreen) {
114+ auto previousCursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
94115 if (previousCursor) {
95116 previousCursor->setMousePointer(nullptr);
96117 } else {
@@ -98,10 +119,10 @@ void MousePointer::registerWindow(QWindow *window)
98119 }
99120 }
100121
101− m_registeredWindow = window;
122+ m_registeredScreen = screen;
102123
103− if (m_registeredWindow) {
104− auto cursor = dynamic_cast<MirPlatformCursor*>(window->screen()->handle()->cursor());
124+ if (m_registeredScreen) {
125+ auto cursor = dynamic_cast<MirPlatformCursor*>(m_registeredScreen->handle()->cursor());
105126 if (cursor) {
106127 cursor->setMousePointer(this);
107128 } else {
@@ -115,22 +136,6 @@ void MousePointer::setCursorName(const QString &cursorName)
115136 if (cursorName != m_cursorName) {
116137 m_cursorName = cursorName;
117138 Q_EMIT cursorNameChanged(m_cursorName);
118− updateHotspot();
119− }
120−}
121−
122−void MousePointer::updateHotspot()
123−{
124− QPoint newHotspot = CursorImageProvider::instance()->hotspot(m_themeName, m_cursorName);
125−
126− if (m_hotspotX != newHotspot.x()) {
127− m_hotspotX = newHotspot.x();
128− Q_EMIT hotspotXChanged(m_hotspotX);
129− }
130−
131− if (m_hotspotY != newHotspot.y()) {
132− m_hotspotY = newHotspot.y();
133− Q_EMIT hotspotYChanged(m_hotspotY);
134139 }
135140}
136141
plugins/Cursor/MousePointer.h+5−6
@@ -20,6 +20,7 @@
2020// Qt
2121#include <QPointer>
2222#include <QWindow>
23+#include <QScreen>
2324
2425// Unity API
2526#include <unity/shell/application/MirMousePointerInterface.h>
@@ -35,9 +36,6 @@ public:
3536 void setThemeName(const QString &themeName) override;
3637 QString themeName() const override { return m_themeName; }
3738
38− qreal hotspotX() const override { return m_hotspotX; }
39− qreal hotspotY() const override { return m_hotspotY; }
40−
4139 void setCustomCursor(const QCursor &) override;
4240
4341public Q_SLOTS:
@@ -53,15 +51,16 @@ Q_SIGNALS:
5351protected:
5452 void itemChange(ItemChange change, const ItemChangeData &value) override;
5553
54+private Q_SLOTS:
55+ void registerScreen(QScreen *screen);
56+
5657private:
5758 void registerWindow(QWindow *window);
58− void updateHotspot();
5959
6060 QPointer<QWindow> m_registeredWindow;
61+ QPointer<QScreen> m_registeredScreen;
6162 QString m_cursorName;
6263 QString m_themeName;
63− int m_hotspotX;
64− int m_hotspotY;
6564};
6665
6766#endif // MOUSEPOINTER_H
plugins/Cursor/plugin.cpp+4−2
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 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
@@ -22,13 +22,15 @@
2222#include "plugin.h"
2323
2424// local
25+#include "CursorImageInfo.h"
2526#include "CursorImageProvider.h"
2627#include "MousePointer.h"
2728
2829void CursorPlugin::registerTypes(const char *uri)
2930{
3031 Q_ASSERT(uri == QLatin1String("Cursor"));
31− qmlRegisterType<MousePointer>(uri, 1, 0, "MousePointer");
32+ qmlRegisterType<CursorImageInfo>(uri, 1, 1, "CursorImageInfo");
33+ qmlRegisterType<MousePointer>(uri, 1, 1, "MousePointer");
3234}
3335
3436void CursorPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
plugins/Cursor/qmldir+1−1
@@ -1,3 +1,3 @@
11module Cursor
22plugin Cursor-qml
3−Cursor 1.0 Cursor.qml
3+Cursor 1.1 Cursor.qml
plugins/Dash/AudioProgressBar.qml+1−1
@@ -49,6 +49,6 @@ Item {
4949 rightMargin: maxWidth - (maxWidth * root.progress)
5050 }
5151 height: units.dp(2)
52− backgroundColor: UbuntuColors.orange
52+ backgroundColor: theme.palette.normal.activity
5353 }
5454}
plugins/Dash/CardCreator.js+64−48
@@ -59,14 +59,30 @@ var kBackgroundLoaderCode = 'Loader {\n\
5959 } \n\
6060 }\n';
6161
62+// %1 is the aspect of the UbuntuShape
63+var kArtUbuntuShapeCode = 'UbuntuShape { \n\
64+ anchors.fill: parent; \n\
65+ source: artImage; \n\
66+ sourceFillMode: UbuntuShape.PreserveAspectCrop; \n\
67+ radius: "medium"; \n\
68+ aspect: %1; \n\
69+ }';
70+
71+var kArtProportionalShapeCode = 'ProportionalShape { \n\
72+ anchors.fill: parent; \n\
73+ source: artImage; \n\
74+ aspect: UbuntuShape.DropShadow; \n\
75+ }';
76+
6277// %1 is used as anchors of artShapeHolder
6378// %2 is used as image width
6479// %3 is used as image height
65−// %4 is whether the image or the Loader with the UbuntuShape/ProportionalShape should be visible
80+// %4 is whether the image should be visible
6681// %5 is used as aspect ratio fallback
6782// %6 is whether the loader should be asynchronous or not
68−// %7 is injected as code to artImage
69−// %8 is used as image fallback
83+// %7 is the shape code we want to use
84+// %8 is injected as code to artImage
85+// %9 is used as image fallback
7086var kArtShapeHolderCode = 'Item { \n\
7187 id: artShapeHolder; \n\
7288 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\
@@ -75,7 +91,8 @@ var kArtShapeHolderCode = 'Item { \n\
7591 Loader { \n\
7692 id: artShapeLoader; \n\
7793 objectName: "artShapeLoader"; \n\
78− readonly property string cardArt: cardData && cardData["art"] || %8; \n\
94+ readonly property string cardArt: cardData && cardData["art"] || %9; \n\
95+ onCardArtChanged: { if (item) { item.image.source = cardArt; } } \n\
7996 active: cardArt != ""; \n\
8097 asynchronous: %6; \n\
8198 visible: status == Loader.Ready; \n\
@@ -84,31 +101,7 @@ var kArtShapeHolderCode = 'Item { \n\
84101 objectName: "artShape"; \n\
85102 visible: image.status == Image.Ready; \n\
86103 readonly property alias image: artImage; \n\
87− Loader { \n\
88− anchors.fill: parent; \n\
89− visible: %4; \n\
90− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent; \n\
91− Component { \n\
92− id: artShapeShapeComponent; \n\
93− UbuntuShape { \n\
94− source: artImage; \n\
95− sourceFillMode: UbuntuShape.PreserveAspectCrop; \n\
96− radius: "medium"; \n\
97− aspect: { \n\
98− switch (root.artShapeStyle) { \n\
99− case "inset": return UbuntuShape.Inset; \n\
100− case "shadow": return UbuntuShape.DropShadow; \n\
101− default: \n\
102− case "flat": return UbuntuShape.Flat; \n\
103− } \n\
104− } \n\
105− } \n\
106− } \n\
107− Component { \n\
108− id: artShapeIconComponent; \n\
109− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; } \n\
110− } \n\
111− } \n\
104+ %7 \n\
112105 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1; \n\
113106 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : %5; \n\
114107 Component.onCompleted: { updateWidthHeightBindings(); } \n\
@@ -127,10 +120,10 @@ var kArtShapeHolderCode = 'Item { \n\
127120 objectName: "artImage"; \n\
128121 source: artShapeLoader.cardArt; \n\
129122 asynchronous: %6; \n\
130− visible: !%4; \n\
123+ visible: %4; \n\
131124 width: %2; \n\
132125 height: %3; \n\
133− %7 \n\
126+ %8 \n\
134127 } \n\
135128 } \n\
136129 } \n\
@@ -318,7 +311,7 @@ var kTouchdownCode = 'UbuntuShape { \n\
318311 id: touchdown; \n\
319312 objectName: "touchdown"; \n\
320313 anchors { %1 } \n\
321− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed; \n\
314+ visible: root.pressed; \n\
322315 radius: "medium"; \n\
323316 borderSource: "radius_pressed.sci" \n\
324317 }\n';
@@ -412,7 +405,7 @@ function sanitizeColor(colorString) {
412405 return colorString;
413406}
414407
415−function cardString(template, components, isCardTool) {
408+function cardString(template, components, isCardTool, artShapeStyle) {
416409 var code;
417410
418411 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
@@ -420,7 +413,6 @@ function cardString(template, components, isCardTool) {
420413 code = 'AbstractButton { \n\
421414 id: root; \n\
422415 property var cardData; \n\
423− property string artShapeStyle: "inset"; \n\
424416 property string backgroundShapeStyle: "inset"; \n\
425417 property real fontScale: 1.0; \n\
426418 property var scopeStyle: null; \n\
@@ -519,17 +511,35 @@ function cardString(template, components, isCardTool) {
519511 var fallbackStatusCode = "";
520512 var fallbackURICode = '""';
521513 if (fallback !== "") {
522− // fallbackStatusCode has %6 in it because we want to substitute it for fallbackURICode
523− // which in kArtShapeHolderCode is %8
524− fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %8;';
514+ // fallbackStatusCode has %9 in it because we want to substitute it for fallbackURICode
515+ // which in kArtShapeHolderCode is %9
516+ fallbackStatusCode += 'onStatusChanged: if (status === Image.Error) source = %9;';
525517 fallbackURICode = 'decodeURI("%1")'.arg(fallback);
526518 }
519+ var artShapeHolderShapeCode;
520+ if (!isConciergeMode) {
521+ if (artShapeStyle === "icon") {
522+ artShapeHolderShapeCode = kArtProportionalShapeCode;
523+ } else {
524+ var artShapeHolderShapeAspect;
525+ switch (artShapeStyle) {
526+ case "inset": artShapeHolderShapeAspect = "UbuntuShape.Inset"; break;
527+ case "shadow": artShapeHolderShapeAspect = "UbuntuShape.DropShadow"; break;
528+ default:
529+ case "flat": artShapeHolderShapeAspect = "UbuntuShape.Flat"; break;
530+ }
531+ artShapeHolderShapeCode = kArtUbuntuShapeCode.arg(artShapeHolderShapeAspect);
532+ }
533+ } else {
534+ artShapeHolderShapeCode = "";
535+ }
527536 code += kArtShapeHolderCode.arg(artAnchors)
528537 .arg(widthCode)
529538 .arg(heightCode)
530− .arg(isConciergeMode ? "false" : "true")
539+ .arg(isConciergeMode ? "true" : "false")
531540 .arg(aspectRatio)
532541 .arg(asynchronous)
542+ .arg(artShapeHolderShapeCode)
533543 .arg(fallbackStatusCode)
534544 .arg(fallbackURICode);
535545 } else {
@@ -854,6 +864,10 @@ function cardString(template, components, isCardTool) {
854864 code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);
855865 }
856866
867+// <<<<<<< TREE
868+// if (artShapeStyle != "shadow" && artShapeStyle != "icon") {
869+// var touchdownAnchors;
870+// =======
857871 if (hasSocialActions) {
858872 var socialAnchors;
859873 var socialTopAnchor;
@@ -882,15 +896,17 @@ function cardString(template, components, isCardTool) {
882896 code += kSocialActionsRowCode.arg(socialAnchors).arg(socialColor);
883897 }
884898
885− var touchdownAnchors;
886− if (hasBackground) {
887− touchdownAnchors = 'fill: backgroundLoader';
888− } else if (touchdownOnArtShape) {
889− touchdownAnchors = 'fill: artShapeHolder';
890− } else {
891− touchdownAnchors = 'fill: root'
899+ if (artShapeStyle != "shadow" && artShapeStyle != "icon") {
900+ var touchdownAnchors;
901+ if (hasBackground) {
902+ touchdownAnchors = 'fill: backgroundLoader';
903+ } else if (touchdownOnArtShape) {
904+ touchdownAnchors = 'fill: artShapeHolder';
905+ } else {
906+ touchdownAnchors = 'fill: root'
907+ }
908+ code += kTouchdownCode.arg(touchdownAnchors);
892909 }
893− code += kTouchdownCode.arg(touchdownAnchors);
894910
895911 var implicitHeight = 'implicitHeight: ';
896912 if (hasSocialActions) {
@@ -925,13 +941,13 @@ function cardString(template, components, isCardTool) {
925941 return code;
926942}
927943
928−function createCardComponent(parent, template, components, isCardTool, identifier) {
944+function createCardComponent(parent, template, components, isCardTool, artShapeStyle, identifier) {
929945 var imports = 'import QtQuick 2.4; \n\
930946 import Ubuntu.Components 1.3; \n\
931947 import Ubuntu.Settings.Components 0.1; \n\
932948 import Dash 0.1;\n\
933949 import Utils 0.1;\n';
934− var card = cardString(template, components, isCardTool);
950+ var card = cardString(template, components, isCardTool, artShapeStyle);
935951 var code = imports + 'Component {\n' + card + '}\n';
936952
937953 try {
plugins/Dash/CardCreatorCache.qml+2−2
@@ -23,7 +23,7 @@ QtObject {
2323
2424 property var cache: new Object();
2525
26− function getCardComponent(template, components, isCardTool) {
26+ function getCardComponent(template, components, isCardTool, artShapeStyle) {
2727 if (template === undefined || components === undefined)
2828 return undefined;
2929
@@ -32,7 +32,7 @@ QtObject {
3232 var allString = tString + cString + isCardTool;
3333 var component = cache[allString];
3434 if (component === undefined) {
35− component = CardCreator.createCardComponent(root, template, components, isCardTool, allString);
35+ component = CardCreator.createCardComponent(root, template, components, isCardTool, artShapeStyle, allString);
3636 cache[allString] = component;
3737 }
3838 return component;
plugins/Dash/ScopeStyle.qml+1−1
@@ -70,7 +70,7 @@ QtObject {
7070 readonly property url navigationBackground: "navigation-background" in d.headerStyle ? d.headerStyle["navigation-background"] : "color:///#f5f5f5"
7171
7272 /// Color of the primary preview button
73− readonly property color previewButtonColor: "preview-button-color" in style ? style["preview-button-color"] : UbuntuColors.orange
73+ readonly property color previewButtonColor: "preview-button-color" in style ? style["preview-button-color"] : theme.palette.normal.positive
7474
7575 //! @cond
7676 property var d: QtObject {
plugins/Dash/listviewwithpageheader.cpp+14−17
@@ -97,6 +97,7 @@
9797#include <qqmlengine.h>
9898#pragma GCC diagnostic push
9999#pragma GCC diagnostic ignored "-pedantic"
100+#include <private/qqmlcontext_p.h>
100101#include <private/qqmldelegatemodel_p.h>
101102#include <private/qqmlglobal_p.h>
102103#include <private/qquickitem_p.h>
@@ -168,7 +169,7 @@ ListViewWithPageHeader::ListViewWithPageHeader()
168169 m_contentYAnimation->setDuration(200);
169170 m_contentYAnimation->setTargetObject(this);
170171
171− connect(this, &ListViewWithPageHeader::contentWidthChanged, this, &ListViewWithPageHeader::onContentWidthChanged);
172+ connect(contentItem(), &QQuickItem::widthChanged, this, &ListViewWithPageHeader::onContentWidthChanged);
172173 connect(this, &ListViewWithPageHeader::contentHeightChanged, this, &ListViewWithPageHeader::onContentHeightChanged);
173174 connect(this, &ListViewWithPageHeader::heightChanged, this, &ListViewWithPageHeader::onHeightChanged);
174175 connect(m_contentYAnimation, &QQuickNumberAnimation::runningChanged, this, &ListViewWithPageHeader::contentYAnimationRunningChanged);
@@ -757,8 +758,6 @@ QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText, b
757758
758759 QQmlContext *creationContext = m_sectionDelegate->creationContext();
759760 QQmlContext *context = new QQmlContext(creationContext ? creationContext : qmlContext(this));
760− context->setContextProperty(QStringLiteral("section"), sectionText);
761− context->setContextProperty(QStringLiteral("delegateIndex"), -1);
762761 QObject *nobj = m_sectionDelegate->beginCreate(context);
763762 if (nobj) {
764763 QQml_setParent_noEvent(context, nobj);
@@ -766,6 +765,8 @@ QQuickItem *ListViewWithPageHeader::getSectionItem(const QString &sectionText, b
766765 if (!sectionItem) {
767766 delete nobj;
768767 } else {
768+ sectionItem->setProperty("text", sectionText);
769+ sectionItem->setProperty("delegateIndex", -1);
769770 sectionItem->setZ(2);
770771 QQml_setParent_noEvent(sectionItem, m_clipItem);
771772 sectionItem->setParentItem(m_clipItem);
@@ -801,8 +802,7 @@ void ListViewWithPageHeader::updateSectionItem(int modelIndex)
801802 if (!item->sectionItem()) {
802803 item->setSectionItem(getSectionItem(sectionText));
803804 } else {
804− QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext();
805− context->setContextProperty(QStringLiteral("section"), sectionText);
805+ item->sectionItem()->setProperty("text", sectionText);
806806 }
807807 } else {
808808 if (item->sectionItem()) {
@@ -923,8 +923,7 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
923923 polish();
924924 }
925925 if (listItem->sectionItem()) {
926− QQmlContext *context = QQmlEngine::contextForObject(listItem->sectionItem())->parentContext();
927− context->setContextProperty(QStringLiteral("delegateIndex"), modelIndex);
926+ listItem->sectionItem()->setProperty("delegateIndex", modelIndex);
928927 }
929928 adjustMinYExtent();
930929 m_contentHeightDirty = true;
@@ -948,9 +947,10 @@ void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
948947 return;
949948
950949 item->setParentItem(m_clipItem);
950+ // FIXME Why do we need the refreshExpressions call?
951951 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
952− context->setContextProperty(QStringLiteral("ListViewWithPageHeader"), this);
953− context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0));
952+ QQmlContextPrivate::get(context)->data->refreshExpressions();
953+ item->setProperty("heightToClip", QVariant::fromValue<int>(0));
954954 if (modelIndex == m_asyncRequestedIndex) {
955955 createItem(modelIndex, false);
956956 refill();
@@ -1116,8 +1116,7 @@ void ListViewWithPageHeader::onModelUpdated(const QQmlChangeSet &changeSet, bool
11161116 for (int i = 0; i < m_visibleItems.count(); ++i) {
11171117 ListItem *item = m_visibleItems[i];
11181118 if (item->sectionItem()) {
1119− QQmlContext *context = QQmlEngine::contextForObject(item->sectionItem())->parentContext();
1120− context->setContextProperty(QStringLiteral("delegateIndex"), m_firstVisibleIndex + i);
1119+ item->sectionItem()->setProperty("delegateIndex", m_firstVisibleIndex + i);
11211120 }
11221121 }
11231122
@@ -1287,8 +1286,7 @@ void ListViewWithPageHeader::layout()
12871286 } else {
12881287 // Update the top sticky section header
12891288 const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
1290− QQmlContext *context = QQmlEngine::contextForObject(m_topSectionItem)->parentContext();
1291− context->setContextProperty(QStringLiteral("section"), section);
1289+ m_topSectionItem->setProperty("text", section);
12921290
12931291 QQuickItemPrivate::get(m_topSectionItem)->setCulled(false);
12941292 m_topSectionItem->setY(topSectionStickPos);
@@ -1300,19 +1298,18 @@ void ListViewWithPageHeader::layout()
13001298 break;
13011299 delegateIndex--;
13021300 }
1303− context->setContextProperty(QStringLiteral("delegateIndex"), delegateIndex);
1301+ m_topSectionItem->setProperty("delegateIndex", delegateIndex);
13041302 if (item->sectionItem()) {
13051303 QQuickItemPrivate::get(item->sectionItem())->setCulled(true);
13061304 }
13071305 }
13081306 }
13091307 }
1310− QQmlContext *context = QQmlEngine::contextForObject(item->m_item)->parentContext();
13111308 const qreal clipFrom = visibleFrom + (!item->sectionItem() && m_topSectionItem && !QQuickItemPrivate::get(m_topSectionItem)->culled ? m_topSectionItem->height() : 0);
13121309 if (!cull && pos < clipFrom) {
1313− context->setContextProperty(QStringLiteral("heightToClip"), clipFrom - pos);
1310+ item->m_item->setProperty("heightToClip", clipFrom - pos);
13141311 } else {
1315− context->setContextProperty(QStringLiteral("heightToClip"), QVariant::fromValue<int>(0));
1312+ item->m_item->setProperty("heightToClip", QVariant::fromValue<int>(0));
13161313 }
13171314// qDebug() << "ListViewWithPageHeader::layout" << item->m_item;
13181315 pos += item->height();
plugins/Ubuntu/Gestures/AxisVelocityCalculator.h+1−1
@@ -24,7 +24,7 @@
2424#include "UbuntuGesturesQmlGlobal.h"
2525#include <stdint.h>
2626#include <QtCore/QObject>
27−#include "TimeSource.h"
27+#include <TimeSource>
2828
2929/*
3030 Estimates the current velocity of a finger based on recent movement along an axis
plugins/Ubuntu/Gestures/CMakeLists.txt+9−4
@@ -4,27 +4,32 @@ remove_definitions(-DQT_NO_KEYWORDS)
44set(UbuntuGesturesQml_SOURCES
55 plugin.cpp
66 AxisVelocityCalculator.cpp
7− Damper.cpp
87 Direction.cpp
9− DirectionalDragArea.cpp
10− FloatingFlickable.cpp
8+ MouseEventGenerator.cpp
119 PressedOutsideNotifier.cpp
1210 TouchDispatcher.cpp
1311 TouchGate.cpp
1412 TouchGestureArea.cpp
1513)
1614
15+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
16+
1717add_definitions(-DUBUNTUGESTURESQML_LIBRARY)
1818
19+<<<<<<< TREE
1920add_library(UbuntuGesturesQml SHARED ${UbuntuGesturesQml_SOURCES})
2021target_link_libraries(UbuntuGesturesQml UbuntuGestures)
22+=======
23+add_library(UbuntuGesturesQml MODULE ${UbuntuGesturesQml_SOURCES})
24+target_link_libraries(UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
25+>>>>>>> MERGE-SOURCE
2126
2227qt5_use_modules(UbuntuGesturesQml Core Quick)
2328
2429# So that Foo.cpp can #include "Foo.moc"
2530include_directories(${CMAKE_CURRENT_BINARY_DIR})
2631
27−include_directories(${CMAKE_SOURCE_DIR}/libs/UbuntuGestures)
32+include_directories(${UBUNTUGESTURES_INCLUDE_DIRS})
2833
2934# There's no cmake var for v8 include path :-/ so create one
3035LIST(GET Qt5Core_INCLUDE_DIRS 0 QtCoreDir0)
plugins/Ubuntu/Gestures/Damper.cppdeleted−24
@@ -1,24 +0,0 @@
1−/*
2− * Copyright (C) 2015 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 "Damper.h"
18−#include <QDebug>
19−
20−QDebug operator<<(QDebug dbg, const DampedPointF &p)
21−{
22− dbg.nospace() << "(" << p.x() << ", " << p.y() << ")";
23− return dbg.space();
24−}
plugins/Ubuntu/Gestures/Damper.hdeleted−89
@@ -1,89 +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−#ifndef UBUNTU_GESTURES_DAMPER_H
18−#define UBUNTU_GESTURES_DAMPER_H
19−
20−#include <QtCore/QPointF>
21−
22−/*
23− Decreases the oscillations of a value along an axis.
24− */
25−template <class Type> class Damper {
26−public:
27− Damper() : m_value(0), m_maxDelta(0) { }
28−
29− // Maximum delta between the raw value and its dampened counterpart.
30− void setMaxDelta(Type maxDelta) {
31− if (maxDelta < 0) qFatal("Damper::maxDelta must be a positive number.");
32− m_maxDelta = maxDelta;
33− }
34− Type maxDelta() const { return m_maxDelta; }
35−
36− void reset(Type value) {
37− m_value = value;
38− }
39−
40− Type update(Type value) {
41− Type delta = value - m_value;
42− if (delta > 0 && delta > m_maxDelta) {
43− m_value += delta - m_maxDelta;
44− } else if (delta < 0 && delta < -m_maxDelta) {
45− m_value += delta + m_maxDelta;
46− }
47−
48− return m_value;
49− }
50−
51− Type value() const { return m_value; }
52−
53−private:
54− Type m_value;
55− Type m_maxDelta;
56−};
57−
58−/*
59− A point that has its movement dampened.
60− */
61−class DampedPointF {
62−public:
63− void setMaxDelta(qreal maxDelta) {
64− m_x.setMaxDelta(maxDelta);
65− m_y.setMaxDelta(maxDelta);
66− }
67−
68− qreal maxDelta() const { return m_x.maxDelta(); }
69−
70− void reset(const QPointF point) {
71− m_x.reset(point.x());
72− m_y.reset(point.y());
73− }
74−
75− void update(const QPointF point) {
76− m_x.update(point.x());
77− m_y.update(point.y());
78− }
79−
80− qreal x() const { return m_x.value(); }
81− qreal y() const { return m_y.value(); }
82−private:
83− Damper<qreal> m_x;
84− Damper<qreal> m_y;
85−};
86−
87−QDebug operator<<(QDebug dbg, const DampedPointF &p);
88−
89−#endif // UBUNTU_GESTURES_DAMPER_H
plugins/Ubuntu/Gestures/Direction.h+1
@@ -29,6 +29,7 @@ class UBUNTUGESTURESQML_EXPORT Direction : public QObject {
2929 Q_ENUMS(Type)
3030
3131public:
32+ // Make sure it is kept synchronized with SDK UCSwipeArea::Direction
3233 enum Type {
3334 Rightwards, // Along the positive direction of the X axis
3435 Leftwards, // Along the negative direction of the X axis
plugins/Ubuntu/Gestures/DirectionalDragArea.cppdeleted−932
@@ -1,932 +0,0 @@
1−/*
2− * Copyright (C) 2013-2015 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−#define ACTIVETOUCHESINFO_DEBUG 0
18−#define DIRECTIONALDRAGAREA_DEBUG 0
19−
20−#include "DirectionalDragArea.h"
21−
22−#include <QQuickWindow>
23−#include <QtCore/qmath.h>
24−#include <QScreen>
25−#include <QDebug>
26−
27−#pragma GCC diagnostic push
28−#pragma GCC diagnostic ignored "-pedantic"
29−#include <private/qquickwindow_p.h>
30−#pragma GCC diagnostic pop
31−
32−// local
33−#include "TouchOwnershipEvent.h"
34−#include "TouchRegistry.h"
35−#include "UnownedTouchEvent.h"
36−
37−#include "DirectionalDragArea_p.h"
38−
39−using namespace UbuntuGestures;
40−
41−#if DIRECTIONALDRAGAREA_DEBUG
42−#define ddaDebug(params) qDebug().nospace() << "[DDA(" << qPrintable(objectName()) << ")] " << params
43−#include "DebugHelpers.h"
44−
45−namespace {
46−const char *statusToString(DirectionalDragAreaPrivate::Status status)
47−{
48− if (status == DirectionalDragAreaPrivate::WaitingForTouch) {
49− return "WaitingForTouch";
50− } else if (status == DirectionalDragAreaPrivate::Undecided) {
51− return "Undecided";
52− } else {
53− return "Recognized";
54− }
55−}
56−
57−} // namespace {
58−#else // DIRECTIONALDRAGAREA_DEBUG
59−#define ddaDebug(params) ((void)0)
60−#endif // DIRECTIONALDRAGAREA_DEBUG
61−
62−DirectionalDragArea::DirectionalDragArea(QQuickItem *parent)
63− : QQuickItem(parent)
64− , d(new DirectionalDragAreaPrivate(this))
65−{
66− d->setRecognitionTimer(new Timer(this));
67− d->recognitionTimer->setInterval(d->maxTime);
68− d->recognitionTimer->setSingleShot(true);
69−
70− connect(this, &QQuickItem::enabledChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible);
71− connect(this, &QQuickItem::visibleChanged, d, &DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible);
72−}
73−
74−Direction::Type DirectionalDragArea::direction() const
75−{
76− return d->direction;
77−}
78−
79−void DirectionalDragArea::setDirection(Direction::Type direction)
80−{
81− if (direction != d->direction) {
82− d->direction = direction;
83− Q_EMIT directionChanged(d->direction);
84− }
85−}
86−
87−void DirectionalDragAreaPrivate::setDistanceThreshold(qreal value)
88−{
89− if (distanceThreshold != value) {
90− distanceThreshold = value;
91− distanceThresholdSquared = distanceThreshold * distanceThreshold;
92− }
93−}
94−
95−void DirectionalDragAreaPrivate::setMaxTime(int value)
96−{
97− if (maxTime != value) {
98− maxTime = value;
99− recognitionTimer->setInterval(maxTime);
100− }
101−}
102−
103−void DirectionalDragAreaPrivate::setRecognitionTimer(UbuntuGestures::AbstractTimer *timer)
104−{
105− int interval = 0;
106− bool timerWasRunning = false;
107− bool wasSingleShot = false;
108−
109− // can be null when called from the constructor
110− if (recognitionTimer) {
111− interval = recognitionTimer->interval();
112− timerWasRunning = recognitionTimer->isRunning();
113− if (recognitionTimer->parent() == this) {
114− delete recognitionTimer;
115− }
116− }
117−
118− recognitionTimer = timer;
119− timer->setInterval(interval);
120− timer->setSingleShot(wasSingleShot);
121− connect(timer, &UbuntuGestures::AbstractTimer::timeout,
122− this, &DirectionalDragAreaPrivate::rejectGesture);
123− if (timerWasRunning) {
124− recognitionTimer->start();
125− }
126−}
127−
128−void DirectionalDragAreaPrivate::setTimeSource(const SharedTimeSource &timeSource)
129−{
130− this->timeSource = timeSource;
131− activeTouches.m_timeSource = timeSource;
132−}
133−
134−qreal DirectionalDragArea::distance() const
135−{
136− if (Direction::isHorizontal(d->direction)) {
137− return d->publicPos.x() - d->startPos.x();
138− } else {
139− return d->publicPos.y() - d->startPos.y();
140− }
141−}
142−
143−void DirectionalDragAreaPrivate::updateSceneDistance()
144−{
145− QPointF totalMovement = publicScenePos - startScenePos;
146− sceneDistance = projectOntoDirectionVector(totalMovement);
147−}
148−
149−qreal DirectionalDragArea::sceneDistance() const
150−{
151− return d->sceneDistance;
152−}
153−
154−qreal DirectionalDragArea::touchX() const
155−{
156− return d->publicPos.x();
157−}
158−
159−qreal DirectionalDragArea::touchY() const
160−{
161− return d->publicPos.y();
162−}
163−
164−qreal DirectionalDragArea::touchSceneX() const
165−{
166− return d->publicScenePos.x();
167−}
168−
169−qreal DirectionalDragArea::touchSceneY() const
170−{
171− return d->publicScenePos.y();
172−}
173−
174−bool DirectionalDragArea::dragging() const
175−{
176− return d->status == DirectionalDragAreaPrivate::Recognized;
177−}
178−
179−bool DirectionalDragArea::pressed() const
180−{
181− return d->status != DirectionalDragAreaPrivate::WaitingForTouch;
182−}
183−
184−bool DirectionalDragArea::immediateRecognition() const
185−{
186− return d->immediateRecognition;
187−}
188−
189−void DirectionalDragArea::setImmediateRecognition(bool enabled)
190−{
191− if (d->immediateRecognition != enabled) {
192− d->immediateRecognition = enabled;
193− Q_EMIT immediateRecognitionChanged(enabled);
194− }
195−}
196−
197−bool DirectionalDragArea::monitorOnly() const
198−{
199− return d->monitorOnly;
200−}
201−
202−void DirectionalDragArea::setMonitorOnly(bool monitorOnly)
203−{
204− if (d->monitorOnly != monitorOnly) {
205− d->monitorOnly = monitorOnly;
206−
207− if (monitorOnly && d->status == DirectionalDragAreaPrivate::Undecided) {
208− TouchRegistry::instance()->removeCandidateOwnerForTouch(d->touchId, this);
209− // We still wanna know when it ends for keeping the composition time window up-to-date
210− TouchRegistry::instance()->addTouchWatcher(d->touchId, this);
211− }
212−
213− Q_EMIT monitorOnlyChanged(monitorOnly);
214− }
215−}
216−
217−void DirectionalDragArea::removeTimeConstraints()
218−{
219− d->setMaxTime(60 * 60 * 1000);
220− d->compositionTime = 0;
221− ddaDebug("removed time constraints");
222−}
223−
224−bool DirectionalDragArea::event(QEvent *event)
225−{
226− if (event->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
227− d->touchOwnershipEvent(static_cast<TouchOwnershipEvent *>(event));
228− return true;
229− } else if (event->type() == UnownedTouchEvent::unownedTouchEventType()) {
230− d->unownedTouchEvent(static_cast<UnownedTouchEvent *>(event));
231− return true;
232− } else {
233− return QQuickItem::event(event);
234− }
235−}
236−
237−void DirectionalDragAreaPrivate::touchOwnershipEvent(TouchOwnershipEvent *event)
238−{
239− if (event->gained()) {
240− QVector<int> ids;
241− ids.append(event->touchId());
242− ddaDebug("grabbing touch");
243− q->grabTouchPoints(ids);
244−
245− // Work around for Qt bug. If we grab a touch that is being used for mouse pointer
246− // emulation it will cause the emulation logic to go nuts.
247− // Thus we have to also grab the mouse in this case.
248− //
249− // The fix for this bug has landed in Qt 5.4 (https://codereview.qt-project.org/96887)
250− // TODO: Remove this workaround once we start using Qt 5.4
251− if (q->window()) {
252− QQuickWindowPrivate *windowPrivate = QQuickWindowPrivate::get(q->window());
253− if (windowPrivate->touchMouseId == event->touchId() && q->window()->mouseGrabberItem()) {
254− ddaDebug("removing mouse grabber");
255− q->window()->mouseGrabberItem()->ungrabMouse();
256− }
257− }
258− } else {
259− // We still wanna know when it ends for keeping the composition time window up-to-date
260− TouchRegistry::instance()->addTouchWatcher(touchId, q);
261−
262− setStatus(WaitingForTouch);
263− }
264−}
265−
266−void DirectionalDragAreaPrivate::unownedTouchEvent(UnownedTouchEvent *unownedTouchEvent)
267−{
268− QTouchEvent *event = unownedTouchEvent->touchEvent();
269−
270− Q_ASSERT(!event->touchPointStates().testFlag(Qt::TouchPointPressed));
271−
272− ddaDebug("Unowned " << timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
273−
274− switch (status) {
275− case WaitingForTouch:
276− // do nothing
277− break;
278− case Undecided:
279− Q_ASSERT(q->isEnabled() && q->isVisible());
280− unownedTouchEvent_undecided(unownedTouchEvent);
281− break;
282− default: // Recognized:
283− if (monitorOnly) {
284− // Treat unowned event as if we owned it, but we are really just watching it
285− touchEvent_recognized(event);
286− }
287− break;
288− }
289−
290− activeTouches.update(event);
291−}
292−
293−void DirectionalDragAreaPrivate::unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent)
294−{
295− const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(unownedTouchEvent->touchEvent());
296− if (!touchPoint) {
297− qCritical() << "DirectionalDragArea[status=Undecided]: touch " << touchId
298− << "missing from UnownedTouchEvent without first reaching state Qt::TouchPointReleased. "
299− "Considering it as released.";
300−
301− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
302− setStatus(WaitingForTouch);
303− return;
304− }
305−
306− const QPointF &touchScenePos = touchPoint->scenePos();
307−
308− if (touchPoint->state() == Qt::TouchPointReleased) {
309− // touch has ended before recognition concluded
310− ddaDebug("Touch has ended before recognition concluded");
311− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
312− setStatus(WaitingForTouch);
313− return;
314− }
315−
316− previousDampedScenePos.setX(dampedScenePos.x());
317− previousDampedScenePos.setY(dampedScenePos.y());
318− dampedScenePos.update(touchScenePos);
319−
320− if (!movingInRightDirection()) {
321− ddaDebug("Rejecting gesture because touch point is moving in the wrong direction.");
322− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
323− // We still wanna know when it ends for keeping the composition time window up-to-date
324− TouchRegistry::instance()->addTouchWatcher(touchId, q);
325− setStatus(WaitingForTouch);
326− return;
327− }
328−
329− if (isWithinTouchCompositionWindow()) {
330− // There's still time for some new touch to appear and ruin our party as it would be combined
331− // with our touchId one and therefore deny the possibility of a single-finger gesture.
332− ddaDebug("Sill within composition window. Let's wait more.");
333− return;
334− }
335−
336− if (movedFarEnoughAlongGestureAxis()) {
337− if (!monitorOnly) {
338− TouchRegistry::instance()->requestTouchOwnership(touchId, q);
339− }
340− setStatus(Recognized);
341− setPublicPos(touchPoint->pos());
342− setPublicScenePos(touchScenePos);
343− } else if (isPastMaxDistance()) {
344− ddaDebug("Rejecting gesture because it went farther than maxDistance without getting recognized.");
345− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
346− // We still wanna know when it ends for keeping the composition time window up-to-date
347− TouchRegistry::instance()->addTouchWatcher(touchId, q);
348− setStatus(WaitingForTouch);
349− } else {
350− ddaDebug("Didn't move far enough yet. Let's wait more.");
351− }
352−}
353−
354−void DirectionalDragArea::touchEvent(QTouchEvent *event)
355−{
356− // TODO: Consider when more than one touch starts in the same event (although it's not possible
357− // with Mir's android-input). Have to track them all. Consider it a plus/bonus.
358−
359− ddaDebug(d->timeSource->msecsSinceReference() << " " << qPrintable(touchEventToString(event)));
360−
361− if (!isEnabled() || !isVisible()) {
362− QQuickItem::touchEvent(event);
363− return;
364− }
365−
366− switch (d->status) {
367− case DirectionalDragAreaPrivate::WaitingForTouch:
368− d->touchEvent_absent(event);
369− break;
370− case DirectionalDragAreaPrivate::Undecided:
371− d->touchEvent_undecided(event);
372− break;
373− default: // Recognized:
374− d->touchEvent_recognized(event);
375− break;
376− }
377−
378− d->activeTouches.update(event);
379−}
380−
381−void DirectionalDragAreaPrivate::touchEvent_absent(QTouchEvent *event)
382−{
383− // TODO: accept/reject is for the whole event, not per touch id. See how that affects us.
384−
385− if (!event->touchPointStates().testFlag(Qt::TouchPointPressed)) {
386− // Nothing to see here. No touch starting in this event.
387− return;
388− }
389−
390− // to be proven wrong, if that's the case
391− bool allGood = true;
392−
393− if (isWithinTouchCompositionWindow()) {
394− // too close to the last touch start. So we consider them as starting roughly at the same time.
395− // Can't be a single-touch gesture.
396− ddaDebug("A new touch point came in but we're still within time composition window. Ignoring it.");
397− allGood = false;
398− }
399−
400− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
401−
402− const QTouchEvent::TouchPoint *newTouchPoint = nullptr;
403− for (int i = 0; i < touchPoints.count() && allGood; ++i) {
404− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
405− if (touchPoint.state() == Qt::TouchPointPressed) {
406− if (newTouchPoint) {
407− // more than one touch starting in this QTouchEvent. Can't be a single-touch gesture
408− allGood = false;
409− } else {
410− // that's our candidate
411− newTouchPoint = &touchPoint;
412− }
413− }
414− }
415−
416− if (allGood) {
417− allGood = sanityCheckRecognitionProperties();
418− if (!allGood) {
419− qWarning("DirectionalDragArea: recognition properties are wrongly set. Gesture recognition"
420− " is impossible");
421− }
422− }
423−
424− if (allGood) {
425− Q_ASSERT(newTouchPoint);
426−
427− startPos = newTouchPoint->pos();
428− startScenePos = newTouchPoint->scenePos();
429− touchId = newTouchPoint->id();
430− dampedScenePos.reset(startScenePos);
431− setPublicPos(startPos);
432−
433− setPublicScenePos(startScenePos);
434− updateSceneDirectionVector();
435−
436− if (recognitionIsDisabled()) {
437− // Behave like a dumb TouchArea
438− ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately.");
439− setStatus(Recognized);
440− if (monitorOnly) {
441− watchPressedTouchPoints(touchPoints);
442− event->ignore();
443− } else {
444− TouchRegistry::instance()->requestTouchOwnership(touchId, q);
445− event->accept();
446− }
447− } else {
448− // just monitor the touch points for now.
449− if (monitorOnly) {
450− watchPressedTouchPoints(touchPoints);
451− } else {
452− TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q);
453− }
454−
455− setStatus(Undecided);
456− // Let the item below have it. We will monitor it and grab it later if a gesture
457− // gets recognized.
458− event->ignore();
459− }
460− } else {
461− watchPressedTouchPoints(touchPoints);
462− event->ignore();
463− }
464−}
465−
466−void DirectionalDragAreaPrivate::touchEvent_undecided(QTouchEvent *event)
467−{
468− Q_ASSERT(fetchTargetTouchPoint(event) == nullptr);
469−
470− // We're not interested in new touch points. We already have our candidate (touchId).
471− // But we do want to know when those new touches end for keeping the composition time
472− // window up-to-date
473− event->ignore();
474− watchPressedTouchPoints(event->touchPoints());
475−
476− if (event->touchPointStates().testFlag(Qt::TouchPointPressed) && isWithinTouchCompositionWindow()) {
477− // multi-finger drags are not accepted
478− ddaDebug("Multi-finger drags are not accepted");
479−
480− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
481− // We still wanna know when it ends for keeping the composition time window up-to-date
482− TouchRegistry::instance()->addTouchWatcher(touchId, q);
483−
484− setStatus(WaitingForTouch);
485− }
486−}
487−
488−void DirectionalDragAreaPrivate::touchEvent_recognized(QTouchEvent *event)
489−{
490− const QTouchEvent::TouchPoint *touchPoint = fetchTargetTouchPoint(event);
491−
492− if (!touchPoint) {
493− qCritical() << "DirectionalDragArea[status=Recognized]: touch " << touchId
494− << "missing from QTouchEvent without first reaching state Qt::TouchPointReleased. "
495− "Considering it as released.";
496− setStatus(WaitingForTouch);
497− } else {
498− setPublicPos(touchPoint->pos());
499− setPublicScenePos(touchPoint->scenePos());
500−
501− if (touchPoint->state() == Qt::TouchPointReleased) {
502− setStatus(WaitingForTouch);
503− }
504− }
505−}
506−
507−void DirectionalDragAreaPrivate::watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints)
508−{
509− for (int i = 0; i < touchPoints.count(); ++i) {
510− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
511− if (touchPoint.state() == Qt::TouchPointPressed) {
512− TouchRegistry::instance()->addTouchWatcher(touchPoint.id(), q);
513− }
514− }
515−}
516−
517−bool DirectionalDragAreaPrivate::recognitionIsDisabled() const
518−{
519− return immediateRecognition || (distanceThreshold <= 0 && compositionTime <= 0);
520−}
521−
522−bool DirectionalDragAreaPrivate::sanityCheckRecognitionProperties()
523−{
524− return recognitionIsDisabled()
525− || (distanceThreshold < maxDistance && compositionTime < maxTime);
526−}
527−
528−const QTouchEvent::TouchPoint *DirectionalDragAreaPrivate::fetchTargetTouchPoint(QTouchEvent *event)
529−{
530− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
531− const QTouchEvent::TouchPoint *touchPoint = 0;
532− for (int i = 0; i < touchPoints.size(); ++i) {
533− if (touchPoints.at(i).id() == touchId) {
534− touchPoint = &touchPoints.at(i);
535− break;
536− }
537− }
538− return touchPoint;
539−}
540−
541−bool DirectionalDragAreaPrivate::movingInRightDirection() const
542−{
543− if (direction == Direction::Horizontal || direction == Direction::Vertical) {
544− return true;
545− } else {
546− QPointF movementVector(dampedScenePos.x() - previousDampedScenePos.x(),
547− dampedScenePos.y() - previousDampedScenePos.y());
548−
549− qreal scalarProjection = projectOntoDirectionVector(movementVector);
550−
551− return scalarProjection >= 0.;
552− }
553−}
554−
555−bool DirectionalDragAreaPrivate::movedFarEnoughAlongGestureAxis() const
556−{
557− if (distanceThreshold <= 0.) {
558− // distance threshold check is disabled
559− return true;
560− } else {
561− QPointF totalMovement(dampedScenePos.x() - startScenePos.x(),
562− dampedScenePos.y() - startScenePos.y());
563−
564− qreal scalarProjection = projectOntoDirectionVector(totalMovement);
565−
566− ddaDebug(" movedFarEnoughAlongGestureAxis: scalarProjection=" << scalarProjection
567− << ", distanceThreshold=" << distanceThreshold);
568−
569− if (direction == Direction::Horizontal || direction == Direction::Vertical) {
570− return qAbs(scalarProjection) > distanceThreshold;
571− } else {
572− return scalarProjection > distanceThreshold;
573− }
574− }
575−}
576−
577−bool DirectionalDragAreaPrivate::isPastMaxDistance() const
578−{
579− QPointF totalMovement(dampedScenePos.x() - startScenePos.x(),
580− dampedScenePos.y() - startScenePos.y());
581−
582− qreal squaredDistance = totalMovement.x()*totalMovement.x() + totalMovement.y()*totalMovement.y();
583− return squaredDistance > maxDistance*maxDistance;
584−}
585−
586−void DirectionalDragAreaPrivate::giveUpIfDisabledOrInvisible()
587−{
588− if (!q->isEnabled() || !q->isVisible()) {
589− if (status == Undecided) {
590− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
591− // We still wanna know when it ends for keeping the composition time window up-to-date
592− TouchRegistry::instance()->addTouchWatcher(touchId, q);
593− }
594−
595− if (status != WaitingForTouch) {
596− ddaDebug("Resetting status because got disabled or made invisible");
597− setStatus(WaitingForTouch);
598− }
599− }
600−}
601−
602−void DirectionalDragAreaPrivate::rejectGesture()
603−{
604− if (status == Undecided) {
605− ddaDebug("Rejecting gesture because it's taking too long to drag beyond the threshold.");
606−
607− TouchRegistry::instance()->removeCandidateOwnerForTouch(touchId, q);
608− // We still wanna know when it ends for keeping the composition time window up-to-date
609− TouchRegistry::instance()->addTouchWatcher(touchId, q);
610−
611− setStatus(WaitingForTouch);
612− }
613−}
614−
615−void DirectionalDragAreaPrivate::setStatus(Status newStatus)
616−{
617− if (newStatus == status)
618− return;
619−
620− Status oldStatus = status;
621−
622− if (oldStatus == Undecided) {
623− recognitionTimer->stop();
624− }
625−
626− status = newStatus;
627− Q_EMIT statusChanged(status);
628−
629− ddaDebug(statusToString(oldStatus) << " -> " << statusToString(newStatus));
630−
631− switch (newStatus) {
632− case WaitingForTouch:
633− if (oldStatus == Recognized) {
634− Q_EMIT q->draggingChanged(false);
635− }
636− Q_EMIT q->pressedChanged(false);
637− break;
638− case Undecided:
639− recognitionTimer->start();
640− Q_EMIT q->pressedChanged(true);
641− break;
642− case Recognized:
643− if (oldStatus == WaitingForTouch) { // for immediate recognition
644− Q_EMIT q->pressedChanged(true);
645− }
646− Q_EMIT q->draggingChanged(true);
647− break;
648− default:
649− // no-op
650− break;
651− }
652−}
653−
654−void DirectionalDragAreaPrivate::setPublicPos(const QPointF point)
655−{
656− bool xChanged = publicPos.x() != point.x();
657− bool yChanged = publicPos.y() != point.y();
658−
659− // Public position should not get updated while the gesture is still being recognized
660− // (ie, Undecided status).
661− Q_ASSERT(status == WaitingForTouch || status == Recognized);
662−
663− if (status == Recognized && !recognitionIsDisabled()) {
664− // When the gesture finally gets recognized, the finger will likely be
665− // reasonably far from the edge. If we made the contentX immediately
666− // follow the finger position it would be visually unpleasant as it
667− // would appear right next to the user's finger out of nowhere (ie,
668− // it would jump). Instead, we make contentX go towards the user's
669− // finger in several steps. ie., in an animated way.
670− QPointF delta = point - publicPos;
671− // the trick is not to go all the way (1.0) as it would cause a sudden jump
672− publicPos.rx() += 0.4 * delta.x();
673− publicPos.ry() += 0.4 * delta.y();
674− } else {
675− // no smoothing when initializing or if gesture recognition was immediate as there will
676− // be no jump.
677− publicPos = point;
678− }
679−
680− if (xChanged) {
681− Q_EMIT q->touchXChanged(publicPos.x());
682− if (Direction::isHorizontal(direction))
683− Q_EMIT q->distanceChanged(q->distance());
684− }
685−
686− if (yChanged) {
687− Q_EMIT q->touchYChanged(publicPos.y());
688− if (Direction::isVertical(direction))
689− Q_EMIT q->distanceChanged(q->distance());
690− }
691−}
692−
693−void DirectionalDragAreaPrivate::setPublicScenePos(const QPointF point)
694−{
695− bool xChanged = publicScenePos.x() != point.x();
696− bool yChanged = publicScenePos.y() != point.y();
697−
698− if (!xChanged && !yChanged)
699− return;
700−
701− // Public position should not get updated while the gesture is still being recognized
702− // (ie, Undecided status).
703− Q_ASSERT(status == WaitingForTouch || status == Recognized);
704−
705− qreal oldSceneDistance = sceneDistance;
706−
707− if (status == Recognized && !recognitionIsDisabled()) {
708− // When the gesture finally gets recognized, the finger will likely be
709− // reasonably far from the edge. If we made the contentX immediately
710− // follow the finger position it would be visually unpleasant as it
711− // would appear right next to the user's finger out of nowhere (ie,
712− // it would jump). Instead, we make contentX go towards the user's
713− // finger in several steps. ie., in an animated way.
714− QPointF delta = point - publicScenePos;
715− // the trick is not to go all the way (1.0) as it would cause a sudden jump
716− publicScenePos.rx() += 0.4 * delta.x();
717− publicScenePos.ry() += 0.4 * delta.y();
718− } else {
719− // no smoothing when initializing or if gesture recognition was immediate as there will
720− // be no jump.
721− publicScenePos = point;
722− }
723−
724− updateSceneDistance();
725−
726− if (oldSceneDistance != sceneDistance) {
727− Q_EMIT q->sceneDistanceChanged(sceneDistance);
728− }
729−
730− if (xChanged) {
731− Q_EMIT q->touchSceneXChanged(publicScenePos.x());
732− }
733−
734− if (yChanged) {
735− Q_EMIT q->touchSceneYChanged(publicScenePos.y());
736− }
737−}
738−
739−bool DirectionalDragAreaPrivate::isWithinTouchCompositionWindow()
740−{
741− return
742− compositionTime > 0 &&
743− !activeTouches.isEmpty() &&
744− timeSource->msecsSinceReference() <=
745− activeTouches.mostRecentStartTime() + (qint64)compositionTime;
746−}
747−
748−void DirectionalDragArea::itemChange(ItemChange change, const ItemChangeData &value)
749−{
750− if (change == QQuickItem::ItemSceneChange) {
751− if (value.window != nullptr) {
752− value.window->installEventFilter(TouchRegistry::instance());
753−
754− // TODO: Handle window->screen() changes (ie window changing screens)
755−
756− qreal pixelsPerInch = value.window->screen()->physicalDotsPerInch();
757− if (pixelsPerInch < 0) {
758− // It can return garbage when run in a XVFB server (Virtual Framebuffer 'fake' X server)
759− pixelsPerInch = 72;
760− }
761−
762− d->setPixelsPerMm(pixelsPerInch / 25.4);
763− }
764− }
765−}
766−
767−void DirectionalDragAreaPrivate::setPixelsPerMm(qreal pixelsPerMm)
768−{
769− dampedScenePos.setMaxDelta(1. * pixelsPerMm);
770− setDistanceThreshold(4. * pixelsPerMm);
771− maxDistance = 10. * pixelsPerMm;
772−}
773−
774−//************************** ActiveTouchesInfo **************************
775−
776−ActiveTouchesInfo::ActiveTouchesInfo(const SharedTimeSource &timeSource)
777− : m_timeSource(timeSource)
778−{
779−}
780−
781−void ActiveTouchesInfo::update(QTouchEvent *event)
782−{
783− if (!(event->touchPointStates() & (Qt::TouchPointPressed | Qt::TouchPointReleased))) {
784− // nothing to update
785− #if ACTIVETOUCHESINFO_DEBUG
786− qDebug("[DDA::ActiveTouchesInfo] Nothing to Update");
787− #endif
788− return;
789− }
790−
791− const QList<QTouchEvent::TouchPoint> &touchPoints = event->touchPoints();
792− for (int i = 0; i < touchPoints.count(); ++i) {
793− const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
794− if (touchPoint.state() == Qt::TouchPointPressed) {
795− addTouchPoint(touchPoint.id());
796− } else if (touchPoint.state() == Qt::TouchPointReleased) {
797− removeTouchPoint(touchPoint.id());
798− }
799− }
800−}
801−
802−#if ACTIVETOUCHESINFO_DEBUG
803−QString ActiveTouchesInfo::toString()
804−{
805− QString string = "(";
806−
807− {
808− QTextStream stream(&string);
809− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
810− stream << "(id=" << touchInfo->id << ",startTime=" << touchInfo->startTime << ")";
811− return true;
812− });
813− }
814−
815− string.append(")");
816−
817− return string;
818−}
819−#endif // ACTIVETOUCHESINFO_DEBUG
820−
821−void ActiveTouchesInfo::addTouchPoint(int touchId)
822−{
823− ActiveTouchInfo &activeTouchInfo = m_touchInfoPool.getEmptySlot();
824− activeTouchInfo.id = touchId;
825− activeTouchInfo.startTime = m_timeSource->msecsSinceReference();
826−
827− #if ACTIVETOUCHESINFO_DEBUG
828− qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString());
829− #endif
830−}
831−
832−qint64 ActiveTouchesInfo::touchStartTime(int touchId)
833−{
834− qint64 result = -1;
835−
836− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
837− if (touchId == touchInfo->id) {
838− result = touchInfo->startTime;
839− return false;
840− } else {
841− return true;
842− }
843− });
844−
845− Q_ASSERT(result != -1);
846− return result;
847−}
848−
849−void ActiveTouchesInfo::removeTouchPoint(int touchId)
850−{
851− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &touchInfo) {
852− if (touchId == touchInfo->id) {
853− m_touchInfoPool.freeSlot(touchInfo);
854− return false;
855− } else {
856− return true;
857− }
858− });
859−
860− #if ACTIVETOUCHESINFO_DEBUG
861− qDebug() << "[DDA::ActiveTouchesInfo]" << qPrintable(toString());
862− #endif
863−}
864−
865−qint64 ActiveTouchesInfo::mostRecentStartTime()
866−{
867− Q_ASSERT(!m_touchInfoPool.isEmpty());
868−
869− qint64 highestStartTime = -1;
870−
871− m_touchInfoPool.forEach([&](Pool<ActiveTouchInfo>::Iterator &activeTouchInfo) {
872− if (activeTouchInfo->startTime > highestStartTime) {
873− highestStartTime = activeTouchInfo->startTime;
874− }
875− return true;
876− });
877−
878− return highestStartTime;
879−}
880−
881−void DirectionalDragAreaPrivate::updateSceneDirectionVector()
882−{
883− QPointF localOrigin(0., 0.);
884− QPointF localDirection;
885− switch (direction) {
886− case Direction::Upwards:
887− localDirection.rx() = 0.;
888− localDirection.ry() = -1.;
889− break;
890− case Direction::Downwards:
891− case Direction::Vertical:
892− localDirection.rx() = 0.;
893− localDirection.ry() = 1;
894− break;
895− case Direction::Leftwards:
896− localDirection.rx() = -1.;
897− localDirection.ry() = 0.;
898− break;
899− default: // Direction::Rightwards || Direction.Horizontal
900− localDirection.rx() = 1.;
901− localDirection.ry() = 0.;
902− break;
903− }
904− QPointF sceneOrigin = q->mapToScene(localOrigin);
905− QPointF sceneDirection = q->mapToScene(localDirection);
906− sceneDirectionVector = sceneDirection - sceneOrigin;
907−}
908−
909−qreal DirectionalDragAreaPrivate::projectOntoDirectionVector(const QPointF sceneVector) const
910−{
911− // same as dot product as sceneDirectionVector is a unit vector
912− return sceneVector.x() * sceneDirectionVector.x() +
913− sceneVector.y() * sceneDirectionVector.y();
914−}
915−
916−DirectionalDragAreaPrivate::DirectionalDragAreaPrivate(DirectionalDragArea *q)
917− : q(q)
918− , status(WaitingForTouch)
919− , sceneDistance(0)
920− , touchId(-1)
921− , direction(Direction::Rightwards)
922− , distanceThreshold(0)
923− , distanceThresholdSquared(0.)
924− , maxTime(400)
925− , compositionTime(60)
926− , immediateRecognition(false)
927− , recognitionTimer(nullptr)
928− , timeSource(new RealTimeSource)
929− , activeTouches(timeSource)
930− , monitorOnly(false)
931−{
932−}
plugins/Ubuntu/Gestures/DirectionalDragArea.hdeleted−143
@@ -1,143 +0,0 @@
1−/*
2− * Copyright (C) 2013,2014 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 DIRECTIONAL_DRAG_AREA_H
18−#define DIRECTIONAL_DRAG_AREA_H
19−
20−#include <QtQuick/QQuickItem>
21−#include "UbuntuGesturesQmlGlobal.h"
22−#include "Damper.h"
23−#include "Direction.h"
24−
25−// lib UbuntuGestures
26−#include <Pool.h>
27−#include <Timer.h>
28−
29−class TouchOwnershipEvent;
30−class UnownedTouchEvent;
31−class DirectionalDragAreaPrivate;
32−
33−/*
34− An area that detects axis-aligned single-finger drag gestures
35−
36− If a drag deviates too much from the components' direction recognition will
37− fail. It will also fail if the drag or flick is too short. E.g. a noisy or
38− fidgety click
39−
40− See doc/DirectionalDragArea.svg
41− */
42−class UBUNTUGESTURESQML_EXPORT DirectionalDragArea : public QQuickItem {
43− Q_OBJECT
44−
45− // The direction in which the gesture should move in order to be recognized.
46− Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)
47−
48− // The distance travelled by the finger along the axis specified by
49− // DirectionalDragArea's direction.
50− Q_PROPERTY(qreal distance READ distance NOTIFY distanceChanged)
51−
52− // The distance travelled by the finger along the axis specified by
53− // DirectionalDragArea's direction in scene coordinates
54− Q_PROPERTY(qreal sceneDistance READ sceneDistance NOTIFY sceneDistanceChanged)
55−
56− // Position of the touch point performing the drag relative to this item.
57− Q_PROPERTY(qreal touchX READ touchX NOTIFY touchXChanged)
58− Q_PROPERTY(qreal touchY READ touchY NOTIFY touchYChanged)
59−
60− // Position of the touch point performing the drag, in scene's coordinate system
61− Q_PROPERTY(qreal touchSceneX READ touchSceneX NOTIFY touchSceneXChanged)
62− Q_PROPERTY(qreal touchSceneY READ touchSceneY NOTIFY touchSceneYChanged)
63−
64− // Whether a drag gesture is taking place
65− Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged)
66−
67− // Whether the drag area is pressed.
68− Q_PROPERTY(bool pressed READ pressed NOTIFY pressedChanged)
69−
70− // Whether a gesture should be Recognized as soon a touch lands on the area.
71− // With this property enabled it will work pretty much like a MultiPointTouchArea,
72− // just with a different API.
73− //
74− // It's false by default. In most cases you will not want that enabled.
75− Q_PROPERTY(bool immediateRecognition
76− READ immediateRecognition
77− WRITE setImmediateRecognition
78− NOTIFY immediateRecognitionChanged)
79−
80− // Whether we are merely monitoring touch events (in which case, we don't
81− // claim ownership of the touch).
82− Q_PROPERTY(bool monitorOnly READ monitorOnly WRITE setMonitorOnly NOTIFY monitorOnlyChanged)
83−
84− Q_ENUMS(Direction)
85−public:
86− DirectionalDragArea(QQuickItem *parent = 0);
87−
88− Direction::Type direction() const;
89− void setDirection(Direction::Type);
90−
91− qreal distance() const;
92− qreal sceneDistance() const;
93−
94− qreal touchX() const;
95− qreal touchY() const;
96−
97− qreal touchSceneX() const;
98− qreal touchSceneY() const;
99−
100− bool dragging() const;
101−
102− bool pressed() const;
103−
104− bool immediateRecognition() const;
105− void setImmediateRecognition(bool enabled);
106−
107− bool monitorOnly() const;
108− void setMonitorOnly(bool monitorOnly);
109−
110− bool event(QEvent *e) override;
111−
112− /*
113− In qmltests, sequences of touch events are sent all at once, unlike in "real life".
114− Also qmltests might run really slowly, e.g. when run from inside virtual machines.
115− Thus to remove a variable that qmltests cannot really control, namely time, this
116− function removes all constraints that are sensible to elapsed time.
117−
118− This effectively makes the DirectionalDragArea easier to fool.
119− */
120− Q_INVOKABLE void removeTimeConstraints();
121−
122−Q_SIGNALS:
123− void directionChanged(Direction::Type direction);
124− void draggingChanged(bool value);
125− void pressedChanged(bool value);
126− void distanceChanged(qreal value);
127− void sceneDistanceChanged(qreal value);
128− void touchXChanged(qreal value);
129− void touchYChanged(qreal value);
130− void touchSceneXChanged(qreal value);
131− void touchSceneYChanged(qreal value);
132− void immediateRecognitionChanged(bool value);
133− void monitorOnlyChanged(bool value);
134−
135−protected:
136− void touchEvent(QTouchEvent *event) override;
137− void itemChange(ItemChange change, const ItemChangeData &value) override;
138−
139−public: // so tests can access it
140− DirectionalDragAreaPrivate *d;
141−};
142−
143−#endif // DIRECTIONAL_DRAG_AREA_H
plugins/Ubuntu/Gestures/DirectionalDragArea_p.hdeleted−169
@@ -1,169 +0,0 @@
1−/*
2− * Copyright (C) 2015 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 DIRECTIONAL_DRAG_AREA_PRIV_H
18−#define DIRECTIONAL_DRAG_AREA_PRIV_H
19−
20−// Information about an active touch point
21−struct UBUNTUGESTURESQML_EXPORT ActiveTouchInfo {
22− ActiveTouchInfo() : id(-1), startTime(-1) {}
23− bool isValid() const { return id != -1; }
24− void reset() { id = -1; }
25− int id;
26− qint64 startTime;
27−};
28−class UBUNTUGESTURESQML_EXPORT ActiveTouchesInfo {
29−public:
30− ActiveTouchesInfo(const UbuntuGestures::SharedTimeSource &timeSource);
31− void update(QTouchEvent *event);
32− qint64 touchStartTime(int id);
33− bool isEmpty() const { return m_touchInfoPool.isEmpty(); }
34− qint64 mostRecentStartTime();
35− UbuntuGestures::SharedTimeSource m_timeSource;
36−private:
37− void addTouchPoint(int touchId);
38− void removeTouchPoint(int touchId);
39− #if ACTIVETOUCHESINFO_DEBUG
40− QString toString();
41− #endif
42−
43− Pool<ActiveTouchInfo> m_touchInfoPool;
44−};
45−
46−class UBUNTUGESTURESQML_EXPORT DirectionalDragAreaPrivate : public QObject {
47− Q_OBJECT
48−
49− Q_ENUMS(Status)
50−public:
51− DirectionalDragAreaPrivate(DirectionalDragArea *q);
52−
53−public Q_SLOTS:
54− void giveUpIfDisabledOrInvisible();
55− void rejectGesture();
56−
57−public:
58− // Describes the state of the directional drag gesture.
59− enum Status {
60− // Waiting for a new touch point to land on this area. No gesture is being processed
61− // or tracked.
62− WaitingForTouch,
63−
64− // A touch point has landed on this area but it's not know yet whether it is
65− // performing a drag in the correct direction.
66− // If it's decided that the touch point is not performing a directional drag gesture,
67− // it will be rejected/ignored and status will return to WaitingForTouch.
68− Undecided, //Recognizing,
69−
70− // There's a touch point in this area and it performed a drag in the correct
71− // direction.
72− //
73− // Once recognized, the gesture state will move back to WaitingForTouch only once
74− // that touch point ends. The gesture will remain in the Recognized state even if
75− // the touch point starts moving in other directions or halts.
76− Recognized,
77− };
78−
79− void touchEvent_absent(QTouchEvent *event);
80− void touchEvent_undecided(QTouchEvent *event);
81− void touchEvent_recognized(QTouchEvent *event);
82− bool movingInRightDirection() const;
83− bool movedFarEnoughAlongGestureAxis() const;
84− bool isPastMaxDistance() const;
85− const QTouchEvent::TouchPoint *fetchTargetTouchPoint(QTouchEvent *event);
86− void setStatus(Status newStatus);
87− void setPublicPos(const QPointF point);
88− void setPublicScenePos(const QPointF point);
89− bool isWithinTouchCompositionWindow();
90− void updateSceneDirectionVector();
91− // returns the scalar projection between the given vector (in scene coordinates)
92− // and m_sceneDirectionVector
93− qreal projectOntoDirectionVector(const QPointF sceneVector) const;
94− void touchOwnershipEvent(TouchOwnershipEvent *event);
95− void unownedTouchEvent(UnownedTouchEvent *event);
96− void unownedTouchEvent_undecided(UnownedTouchEvent *unownedTouchEvent);
97− void watchPressedTouchPoints(const QList<QTouchEvent::TouchPoint> &touchPoints);
98− bool recognitionIsDisabled() const;
99− bool sanityCheckRecognitionProperties();
100− void updateSceneDistance();
101− void setMaxTime(int value);
102− void setDistanceThreshold(qreal value);
103− void setPixelsPerMm(qreal pixelsPerMm);
104− QString objectName() const { return q->objectName(); }
105−
106− // Replaces the existing Timer with the given one.
107− //
108− // Useful for providing a fake timer when testing.
109− void setRecognitionTimer(UbuntuGestures::AbstractTimer *timer);
110−
111− // Useful for testing, where a fake time source can be supplied
112− void setTimeSource(const UbuntuGestures::SharedTimeSource &timeSource);
113−
114− DirectionalDragArea *q;
115−
116− // The current status of the directional drag gesture area.
117− Status status;
118−
119− QPointF startPos;
120− QPointF startScenePos;
121− qreal sceneDistance;
122− int touchId;
123−
124− // The touch position exposed in the public API.
125− // It only starts to move once the gesture gets recognized.
126− QPointF publicPos;
127− QPointF publicScenePos;
128−
129− // A movement damper is used in some of the gesture recognition calculations
130− // to get rid of noise or small oscillations in the touch position.
131− DampedPointF dampedScenePos;
132− QPointF previousDampedScenePos;
133−
134− // Unit vector in scene coordinates describing the direction of the gesture recognition
135− QPointF sceneDirectionVector;
136−
137− Direction::Type direction;
138−
139− // How far a touch point has to move from its initial position along the gesture axis in order
140− // for it to be recognized as a directional drag.
141− qreal distanceThreshold;
142− qreal distanceThresholdSquared; // it's pow(distanceThreshold, 2)
143−
144− // Maximum time (in milliseconds) the gesture can take to go beyond the distance threshold
145− int maxTime;
146−
147− // Maximum distance the gesture can go without crossing the axis-aligned distance threshold
148− qreal maxDistance;
149−
150− // Maximum time (in milliseconds) after the start of a given touch point where
151− // subsequent touch starts are grouped with the first one into an N-touches gesture
152− // (e.g. a two-fingers tap or drag).
153− int compositionTime;
154−
155− bool immediateRecognition;
156−
157− UbuntuGestures::AbstractTimer *recognitionTimer;
158−
159− UbuntuGestures::SharedTimeSource timeSource;
160−
161− ActiveTouchesInfo activeTouches;
162−
163− bool monitorOnly;
164−
165−Q_SIGNALS:
166− void statusChanged(Status value);
167−};
168−
169−#endif // DIRECTIONAL_DRAG_AREA_PRIV_H
plugins/Ubuntu/Gestures/FloatingFlickable.cppdeleted−150
@@ -1,150 +0,0 @@
1−/*
2− * Copyright (C) 2015 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 "FloatingFlickable.h"
18−
19−#include <private/qquickflickable_p.h>
20−#include "DirectionalDragArea.h"
21−
22−#include <QDebug>
23−
24−FloatingFlickable::FloatingFlickable(QQuickItem *parent)
25− : QQuickItem(parent)
26− , m_mousePressed(false)
27−{
28− m_dragArea = new DirectionalDragArea(this);
29− m_dragArea->setWidth(width());
30− m_dragArea->setHeight(height());
31− m_dragArea->setDirection(Direction::Horizontal);
32− connect(m_dragArea, &DirectionalDragArea::touchXChanged,
33− this, &FloatingFlickable::onDragAreaTouchPosChanged);
34− connect(m_dragArea, &DirectionalDragArea::touchYChanged,
35− this, &FloatingFlickable::onDragAreaTouchPosChanged);
36− connect(m_dragArea, &DirectionalDragArea::draggingChanged,
37− this, &FloatingFlickable::onDragAreaDraggingChanged);
38− connect(m_dragArea, &DirectionalDragArea::directionChanged, this, &FloatingFlickable::directionChanged);
39−
40− m_flickable = new QQuickFlickable(this);
41− m_flickable->setEnabled(false);
42− m_flickable->setWidth(width());
43− m_flickable->setHeight(height());
44− connect(m_flickable, &QQuickFlickable::contentWidthChanged, this, &FloatingFlickable::contentWidthChanged);
45− connect(m_flickable, &QQuickFlickable::contentHeightChanged, this, &FloatingFlickable::contentHeightChanged);
46− connect(m_flickable, &QQuickFlickable::contentXChanged, this, &FloatingFlickable::contentXChanged);
47− connect(m_flickable, &QQuickFlickable::contentYChanged, this, &FloatingFlickable::contentYChanged);
48−
49− connect(this, &QQuickItem::widthChanged, this, &FloatingFlickable::updateChildrenWidth);
50− connect(this, &QQuickItem::heightChanged, this, &FloatingFlickable::updateChildrenHeight);
51−}
52−
53−qreal FloatingFlickable::contentWidth() const
54−{
55− return m_flickable->contentWidth();
56−}
57−
58−void FloatingFlickable::setContentWidth(qreal contentWidth)
59−{
60− m_flickable->setContentWidth(contentWidth);
61−}
62−
63−qreal FloatingFlickable::contentHeight() const
64−{
65− return m_flickable->contentHeight();
66−}
67−
68−void FloatingFlickable::setContentHeight(qreal contentHeight)
69−{
70− m_flickable->setContentHeight(contentHeight);
71−}
72−
73−qreal FloatingFlickable::contentX() const
74−{
75− return m_flickable->contentX();
76−}
77−
78−void FloatingFlickable::setContentX(qreal contentX)
79−{
80− m_flickable->setContentX(contentX);
81−}
82−
83−qreal FloatingFlickable::contentY() const
84−{
85− return m_flickable->contentY();
86−}
87−
88−void FloatingFlickable::setContentY(qreal contentY)
89−{
90− m_flickable->setContentY(contentY);
91−}
92−
93−Direction::Type FloatingFlickable::direction() const
94−{
95− return m_dragArea->direction();
96−}
97−
98−void FloatingFlickable::setDirection(Direction::Type direction)
99−{
100− m_dragArea->setDirection(direction);
101− if (Direction::isHorizontal(direction)) {
102− m_flickable->setFlickableDirection(QQuickFlickable::HorizontalFlick);
103− } else {
104− m_flickable->setFlickableDirection(QQuickFlickable::VerticalFlick);
105− }
106−}
107−
108−void FloatingFlickable::updateChildrenWidth()
109−{
110− m_dragArea->setWidth(width());
111− m_flickable->setWidth(width());
112−}
113−
114−void FloatingFlickable::updateChildrenHeight()
115−{
116− m_dragArea->setHeight(height());
117− m_flickable->setHeight(height());
118−}
119−
120−void FloatingFlickable::onDragAreaTouchPosChanged(qreal)
121−{
122− if (m_mousePressed) {
123− QMouseEvent mouseEvent(QEvent::MouseMove,
124− QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
125− Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
126−
127− QCoreApplication::sendEvent(m_flickable, &mouseEvent);
128−
129− }
130−}
131−
132−void FloatingFlickable::onDragAreaDraggingChanged(bool dragging)
133−{
134− if (dragging && !m_mousePressed) {
135− QMouseEvent mouseEvent(QEvent::MouseButtonPress,
136− QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
137− Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
138−
139− QCoreApplication::sendEvent(m_flickable, &mouseEvent);
140− m_mousePressed = true;
141−
142− } else if (!dragging && m_mousePressed) {
143− QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
144− QPointF(m_dragArea->touchX(),m_dragArea->touchY()),
145− Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
146−
147− QCoreApplication::sendEvent(m_flickable, &mouseEvent);
148− m_mousePressed = false;
149− }
150−}
plugins/Ubuntu/Gestures/FloatingFlickable.hdeleted−86
@@ -1,86 +0,0 @@
1−/*
2− * Copyright (C) 2015 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 FLOATING_FLICKABLE_H
18−#define FLOATING_FLICKABLE_H
19−
20−#include <QQuickItem>
21−#include "UbuntuGesturesQmlGlobal.h"
22−#include "Direction.h"
23−
24−class DirectionalDragArea;
25−class QQuickFlickable;
26−
27−/*
28− A Flickable that can be put in front of the item to be flicked and
29− still have the item-to-be-flicked receive input events that are not flicks.
30−
31− Ie, it's a Flickable that, input-wise, is transparent to non-flick gestures.
32−
33− With a regular Flickable you would have to make the item-to-be-flicked a child
34− of Flicakble to achieve the same result. FloatingFlickable has no such requirement
35− or limitation.
36− */
37−class UBUNTUGESTURESQML_EXPORT FloatingFlickable : public QQuickItem {
38− Q_OBJECT
39−
40− Q_PROPERTY(qreal contentWidth READ contentWidth WRITE setContentWidth NOTIFY contentWidthChanged)
41− Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged)
42− Q_PROPERTY(qreal contentX READ contentX WRITE setContentX NOTIFY contentXChanged)
43− Q_PROPERTY(qreal contentY READ contentY WRITE setContentY NOTIFY contentYChanged)
44−
45− Q_PROPERTY(Direction::Type direction READ direction WRITE setDirection NOTIFY directionChanged)
46−
47−Q_SIGNALS:
48− void contentWidthChanged();
49− void contentHeightChanged();
50− void contentXChanged();
51− void contentYChanged();
52− void directionChanged();
53−
54−public:
55− FloatingFlickable(QQuickItem *parent = nullptr);
56−
57− qreal contentWidth() const;
58− void setContentWidth(qreal contentWidth);
59−
60− qreal contentHeight() const;
61− void setContentHeight(qreal contentHeight);
62−
63− qreal contentX() const;
64− void setContentX(qreal contentX);
65−
66− qreal contentY() const;
67− void setContentY(qreal contentY);
68−
69− Direction::Type direction() const;
70− void setDirection(Direction::Type);
71−
72−private Q_SLOTS:
73− void updateChildrenWidth();
74− void updateChildrenHeight();
75− void onDragAreaTouchPosChanged(qreal);
76− void onDragAreaDraggingChanged(bool value);
77−
78−private:
79− DirectionalDragArea *m_dragArea;
80− QQuickFlickable *m_flickable;
81− bool m_mousePressed;
82−
83− friend class tst_FloatingFlickable;
84−};
85−
86−#endif // FLOATING_FLICKABLE_H
plugins/Ubuntu/Gestures/Gestures.qmltypes−132
@@ -54,88 +54,6 @@ Module {
5454 Parameter { name: "type"; type: "Direction::Type" }
5555 }
5656 }
57− Component {
58− name: "DirectionalDragArea"
59− defaultProperty: "data"
60− prototype: "QQuickItem"
61− exports: ["Ubuntu.Gestures/DirectionalDragArea 0.1"]
62− exportMetaObjectRevisions: [0]
63− Property { name: "direction"; type: "Direction::Type" }
64− Property { name: "distance"; type: "double"; isReadonly: true }
65− Property { name: "sceneDistance"; type: "double"; isReadonly: true }
66− Property { name: "touchX"; type: "double"; isReadonly: true }
67− Property { name: "touchY"; type: "double"; isReadonly: true }
68− Property { name: "touchSceneX"; type: "double"; isReadonly: true }
69− Property { name: "touchSceneY"; type: "double"; isReadonly: true }
70− Property { name: "dragging"; type: "bool"; isReadonly: true }
71− Property { name: "pressed"; type: "bool"; isReadonly: true }
72− Property { name: "immediateRecognition"; type: "bool" }
73− Signal {
74− name: "directionChanged"
75− Parameter { name: "direction"; type: "Direction::Type" }
76− }
77− Signal {
78− name: "draggingChanged"
79− Parameter { name: "value"; type: "bool" }
80− }
81− Signal {
82− name: "pressedChanged"
83− Parameter { name: "value"; type: "bool" }
84− }
85− Signal {
86− name: "distanceChanged"
87− Parameter { name: "value"; type: "double" }
88− }
89− Signal {
90− name: "sceneDistanceChanged"
91− Parameter { name: "value"; type: "double" }
92− }
93− Signal {
94− name: "touchXChanged"
95− Parameter { name: "value"; type: "double" }
96− }
97− Signal {
98− name: "touchYChanged"
99− Parameter { name: "value"; type: "double" }
100− }
101− Signal {
102− name: "touchSceneXChanged"
103− Parameter { name: "value"; type: "double" }
104− }
105− Signal {
106− name: "touchSceneYChanged"
107− Parameter { name: "value"; type: "double" }
108− }
109− Signal {
110− name: "immediateRecognitionChanged"
111− Parameter { name: "value"; type: "bool" }
112− }
113− Method { name: "removeTimeConstraints" }
114− }
115− Component {
116− name: "FloatingFlickable"
117− defaultProperty: "data"
118− prototype: "QQuickItem"
119− exports: ["Ubuntu.Gestures/FloatingFlickable 0.1"]
120− exportMetaObjectRevisions: [0]
121− Property { name: "contentWidth"; type: "double" }
122− Property { name: "contentHeight"; type: "double" }
123− Property { name: "contentX"; type: "double" }
124− Property { name: "contentY"; type: "double" }
125− Property { name: "direction"; type: "Direction::Type" }
126− }
127− Component {
128− name: "GestureTouchPoint"
129− prototype: "QObject"
130− exports: ["Ubuntu.Gestures/GestureTouchPoint 0.1"]
131− isCreatable: false
132− exportMetaObjectRevisions: [0]
133− Property { name: "pointId"; type: "int"; isReadonly: true }
134− Property { name: "pressed"; type: "bool"; isReadonly: true }
135− Property { name: "x"; type: "double"; isReadonly: true }
136− Property { name: "y"; type: "double"; isReadonly: true }
137− Property { name: "dragging"; type: "bool"; isReadonly: true }
138− }
13957 Component {
14058 name: "PressedOutsideNotifier"
14159 defaultProperty: "data"
@@ -156,54 +74,4 @@ Module {
15674 Parameter { name: "item"; type: "QQuickItem"; isPointer: true }
15775 }
15876 }
159− Component {
160− name: "TouchGestureArea"
161− defaultProperty: "data"
162− prototype: "QQuickItem"
163− exports: ["Ubuntu.Gestures/TouchGestureArea 0.1"]
164− exportMetaObjectRevisions: [0]
165− Enum {
166− name: "Status"
167− values: {
168− "WaitingForTouch": 0,
169− "Undecided": 1,
170− "Recognized": 2,
171− "Rejected": 3
172− }
173− }
174− Property { name: "touchPoints"; type: "GestureTouchPoint"; isList: true; isReadonly: true }
175− Property { name: "dragging"; type: "bool"; isReadonly: true }
176− Property { name: "minimumTouchPoints"; type: "int" }
177− Property { name: "maximumTouchPoints"; type: "int" }
178− Signal {
179− name: "statusChanged"
180− Parameter { name: "status"; type: "Status" }
181− }
182− Signal { name: "touchPointsUpdated" }
183− Signal {
184− name: "draggingChanged"
185− Parameter { name: "dragging"; type: "bool" }
186− }
187− Signal {
188− name: "minimumTouchPointsChanged"
189− Parameter { name: "value"; type: "bool" }
190− }
191− Signal {
192− name: "maximumTouchPointsChanged"
193− Parameter { name: "value"; type: "bool" }
194− }
195− Signal {
196− name: "pressed"
197− Parameter { name: "points"; type: "QList<QObject*>" }
198− }
199− Signal {
200− name: "released"
201− Parameter { name: "points"; type: "QList<QObject*>" }
202− }
203− Signal {
204− name: "updated"
205− Parameter { name: "points"; type: "QList<QObject*>" }
206− }
207− Signal { name: "clicked" }
208− }
20977}
plugins/Ubuntu/Gestures/MouseEventGenerator.cppnew file+64
@@ -0,0 +1,64 @@
1+/*
2+ * Copyright (C) 2015-2016 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 "MouseEventGenerator.h"
18+
19+#include <QCoreApplication>
20+#include <QMouseEvent>
21+#include <QQuickItem>
22+
23+MouseEventGenerator::MouseEventGenerator(QObject *parent)
24+ : QObject(parent)
25+{
26+}
27+
28+void MouseEventGenerator::move(const QPointF position)
29+{
30+ if (!m_mousePressed || !m_targetItem) {
31+ return;
32+ }
33+
34+ QMouseEvent mouseEvent(QEvent::MouseMove,
35+ QPointF(position.x(), position.y()), Qt::NoButton, Qt::LeftButton, Qt::NoModifier);
36+
37+ QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
38+}
39+
40+void MouseEventGenerator::press(const QPointF position)
41+{
42+ if (m_mousePressed || !m_targetItem) {
43+ return;
44+ }
45+
46+ QMouseEvent mouseEvent(QEvent::MouseButtonPress,
47+ QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
48+
49+ QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
50+ m_mousePressed = true;
51+}
52+
53+void MouseEventGenerator::release(const QPointF position)
54+{
55+ if (!m_mousePressed || !m_targetItem) {
56+ return;
57+ }
58+
59+ QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
60+ QPointF(position.x(), position.y()), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
61+
62+ QCoreApplication::sendEvent(m_targetItem, &mouseEvent);
63+ m_mousePressed = false;
64+}
plugins/Ubuntu/Gestures/MouseEventGenerator.hnew file+48
@@ -0,0 +1,48 @@
1+/*
2+ * Copyright (C) 2015-2016 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 MOUSEEVENTGENERATOR_H
18+#define MOUSEEVENTGENERATOR_H
19+
20+#include <QObject>
21+#include <QPointF>
22+
23+#include "UbuntuGesturesQmlGlobal.h"
24+
25+class QQuickItem;
26+
27+class UBUNTUGESTURESQML_EXPORT MouseEventGenerator : public QObject {
28+ Q_OBJECT
29+ Q_PROPERTY(QQuickItem* targetItem MEMBER m_targetItem NOTIFY targetItemChanged)
30+
31+public:
32+ MouseEventGenerator(QObject *parent = nullptr);
33+
34+ Q_INVOKABLE void move(const QPointF position);
35+ Q_INVOKABLE void press(const QPointF position);
36+ Q_INVOKABLE void release(const QPointF position);
37+
38+Q_SIGNALS:
39+ void targetItemChanged(QQuickItem *);
40+
41+private:
42+ bool m_mousePressed {false};
43+ QQuickItem *m_targetItem {nullptr};
44+
45+ friend class tst_FloatingFlickable;
46+};
47+
48+#endif // MOUSEEVENTGENERATOR_H
plugins/Ubuntu/Gestures/PressedOutsideNotifier.h+1−1
@@ -23,7 +23,7 @@
2323#include <QPointer>
2424#include <QTimer>
2525
26−#include "UbuntuGesturesGlobal.h"
26+#include <ubuntugesturesglobal.h>
2727
2828/*
2929 Notifies when a point, mouse or touch, is pressed outside its area.
plugins/Ubuntu/Gestures/TouchGate.cpp+2−2
@@ -20,8 +20,8 @@
2020#include <QDebug>
2121#include <QQuickWindow>
2222
23−#include <TouchOwnershipEvent.h>
24−#include <TouchRegistry.h>
23+#include <TouchOwnershipEvent>
24+#include <TouchRegistry>
2525
2626#if TOUCHGATE_DEBUG
2727#define ugDebug(params) qDebug().nospace() << "[TouchGate(" << (void*)this << ")] " << params
plugins/Ubuntu/Gestures/TouchGestureArea.cpp+9−6
@@ -16,10 +16,11 @@
1616
1717#include "TouchGestureArea.h"
1818
19−// local
20−#include "TouchOwnershipEvent.h"
21−#include "TouchRegistry.h"
22−#include "UnownedTouchEvent.h"
19+#include <UbuntuGestures/TouchOwnershipEvent>
20+#include <UbuntuGestures/TouchRegistry>
21+#include <UbuntuGestures/UnownedTouchEvent>
22+// #include "TouchRegistry.h"
23+// #include "UnownedTouchEvent.h"
2324
2425#include <QGuiApplication>
2526#include <QStyleHints>
@@ -588,13 +589,15 @@ void TouchGestureArea::setInternalStatus(uint newStatus)
588589 resyncCachedTouchPoints();
589590 break;
590591 case InternalStatus::WaitingForMoreTouches:
591− m_recognitionTimer->start(m_recognitionPeriod);
592+ m_recognitionTimer->setInterval(m_recognitionPeriod);
593+ m_recognitionTimer->start();
592594 break;
593595 case InternalStatus::Recognized:
594596 resyncCachedTouchPoints();
595597 break;
596598 case InternalStatus::WaitingForRejection:
597− m_recognitionTimer->start(m_releaseRejectPeriod);
599+ m_recognitionTimer->setInterval(m_releaseRejectPeriod);
600+ m_recognitionTimer->start();
598601 break;
599602 case InternalStatus::Rejected:
600603 resyncCachedTouchPoints();
plugins/Ubuntu/Gestures/TouchGestureArea.h+2−3
@@ -21,8 +21,7 @@
2121
2222#include <QQuickItem>
2323
24−// lib UbuntuGestures
25−#include <Timer.h>
24+#include <UbuntuGestures/Timer>
2625
2726class TouchOwnershipEvent;
2827class UnownedTouchEvent;
@@ -176,7 +175,7 @@ Q_SIGNALS:
176175 void clicked();
177176
178177protected:
179− void itemChange(ItemChange change, const ItemChangeData &value);
178+ void itemChange(ItemChange change, const ItemChangeData &value) override;
180179
181180private Q_SLOTS:
182181 void rejectGesture();
plugins/Ubuntu/Gestures/plugin.cpp+3−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013,2015 Canonical, Ltd.
2+ * Copyright (C) 2013,2015,2016 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
@@ -17,8 +17,7 @@
1717#include "plugin.h"
1818#include "AxisVelocityCalculator.h"
1919#include "Direction.h"
20−#include "DirectionalDragArea.h"
21−#include "FloatingFlickable.h"
20+#include "MouseEventGenerator.h"
2221#include "PressedOutsideNotifier.h"
2322#include "TouchGate.h"
2423#include "TouchGestureArea.h"
@@ -34,9 +33,8 @@ static QObject* directionSingleton(QQmlEngine* engine, QJSEngine* scriptEngine)
3433void UbuntuGesturesQmlPlugin::registerTypes(const char *uri)
3534{
3635 qmlRegisterSingletonType<Direction>(uri, 0, 1, "Direction", directionSingleton);
37− qmlRegisterType<DirectionalDragArea>(uri, 0, 1, "DirectionalDragArea");
3836 qmlRegisterType<AxisVelocityCalculator>(uri, 0, 1, "AxisVelocityCalculator");
39− qmlRegisterType<FloatingFlickable>(uri, 0, 1, "FloatingFlickable");
37+ qmlRegisterType<MouseEventGenerator>(uri, 0, 1, "MouseEventGenerator");
4038 qmlRegisterType<PressedOutsideNotifier>(uri, 0, 1, "PressedOutsideNotifier");
4139 qmlRegisterType<TouchGate>(uri, 0, 1, "TouchGate");
4240 qmlRegisterType<TouchGestureArea>(uri, 0, 1, "TouchGestureArea");
plugins/Unity/InputInfo/plugin.h+1−1
@@ -24,7 +24,7 @@ class InputInfoPlugin : public QQmlExtensionPlugin
2424 Q_OBJECT
2525 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
2626public:
27− void registerTypes(const char *uri);
27+ void registerTypes(const char *uri) override;
2828};
2929
3030#endif // INPUTINFO_PLUGIN_H
plugins/Unity/InputInfo/qdeclarativeinputdevicemodel_p.h+3−3
@@ -69,8 +69,8 @@ public:
6969 explicit QDeclarativeInputDeviceModel(QObject *parent = 0);
7070 virtual ~QDeclarativeInputDeviceModel();
7171
72− QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
73− int rowCount(const QModelIndex &parent = QModelIndex()) const;
72+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
73+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
7474
7575 void setDeviceFilter(QInputDevice::InputType filter);
7676 QInputDevice::InputType deviceFilter();
@@ -78,7 +78,7 @@ public:
7878 Q_INVOKABLE int indexOf(const QString &devicePath) const;
7979
8080 Q_INVOKABLE QInputDevice *get(int index) const;
81− QHash<int, QByteArray> roleNames() const;
81+ QHash<int, QByteArray> roleNames() const override;
8282
8383Q_SIGNALS:
8484 void deviceAdded(const QString &devicePath);
plugins/Unity/Session/dbusunitysessionservice.cpp+7
@@ -227,11 +227,14 @@ private Q_SLOTS:
227227 {
228228 if (!active) {
229229 setupSystemdInhibition();
230+ } else {
231+ Q_EMIT prepareForSleep();
230232 }
231233 }
232234
233235Q_SIGNALS:
234236 void screensaverActiveChanged(bool active);
237+ void prepareForSleep();
235238};
236239
237240Q_GLOBAL_STATIC(DBusUnitySessionServicePrivate, d)
@@ -245,6 +248,7 @@ DBusUnitySessionService::DBusUnitySessionService()
245248 // ... and our Unlocked() signal to the logind's session Unlock() signal
246249 // (lightdm handles the unlocking by calling logind's Unlock method which in turn emits this signal we connect to)
247250 QDBusConnection::systemBus().connect(LOGIN1_SERVICE, d->logindSessionPath, LOGIN1_SESSION_IFACE, QStringLiteral("Unlock"), this, SIGNAL(Unlocked()));
251+ connect(d, &DBusUnitySessionServicePrivate::prepareForSleep, this, &DBusUnitySessionService::PromptLock);
248252 } else {
249253 qWarning() << "Failed to connect to logind's session Lock/Unlock signals";
250254 }
@@ -390,16 +394,19 @@ void DBusUnitySessionService::Shutdown()
390394
391395void DBusUnitySessionService::Suspend()
392396{
397+ PromptLock();
393398 d->makeLogin1Call(QStringLiteral("Suspend"), {false});
394399}
395400
396401void DBusUnitySessionService::Hibernate()
397402{
403+ PromptLock();
398404 d->makeLogin1Call(QStringLiteral("Hibernate"), {false});
399405}
400406
401407void DBusUnitySessionService::HybridSleep()
402408{
409+ PromptLock();
403410 d->makeLogin1Call(QStringLiteral("HybridSleep"), {false});
404411}
405412
plugins/Utils/WindowInputMonitor.cpp+8−8
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 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
@@ -30,7 +30,6 @@ WindowInputMonitor::WindowInputMonitor(UnityUtil::AbstractTimer *timer,
3030 QQuickItem *parent)
3131 : QQuickItem(parent)
3232 , m_windowBeingTouched(false)
33− , m_homeKeyPressed(false)
3433 , m_windowLastTouchedTimer(elapsedTimer)
3534 , m_activationTimer(timer)
3635{
@@ -42,6 +41,7 @@ WindowInputMonitor::WindowInputMonitor(UnityUtil::AbstractTimer *timer,
4241 connect(m_activationTimer, &UnityUtil::AbstractTimer::timeout,
4342 this, &WindowInputMonitor::emitActivatedIfNoTouchesAround);
4443 m_activationTimer->setInterval(msecsWithoutTouches);
44+ m_activationTimer->setSingleShot(true);
4545}
4646
4747WindowInputMonitor::~WindowInputMonitor()
@@ -67,19 +67,19 @@ void WindowInputMonitor::update(QEvent *event)
6767 if (event->type() == QEvent::KeyPress) {
6868 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
6969
70− m_homeKeyPressed = true;
71−
72− if (keyEvent->key() == Qt::Key_Super_L && !keyEvent->isAutoRepeat()
70+ if (m_pressedHomeKey == 0 && m_homeKeys.contains(keyEvent->key()) && !keyEvent->isAutoRepeat()
71+ && !m_activationTimer->isRunning()
7372 && !m_windowBeingTouched
7473 && m_windowLastTouchedTimer->elapsed() >= msecsWithoutTouches) {
74+ m_pressedHomeKey = keyEvent->key();
7575 m_activationTimer->start();
7676 }
7777
7878 } else if (event->type() == QEvent::KeyRelease) {
7979 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
8080
81− if (keyEvent->key() == Qt::Key_Super_L) {
82− m_homeKeyPressed = false;
81+ if (keyEvent->key() == m_pressedHomeKey) {
82+ m_pressedHomeKey = 0;
8383 }
8484
8585 } else if (event->type() == QEvent::TouchBegin) {
@@ -116,7 +116,7 @@ void WindowInputMonitor::setupFilterOnWindow(QQuickWindow *window)
116116
117117void WindowInputMonitor::emitActivatedIfNoTouchesAround()
118118{
119− if (!m_homeKeyPressed && !m_windowBeingTouched &&
119+ if (m_pressedHomeKey == 0 && !m_windowBeingTouched &&
120120 (m_windowLastTouchedTimer->elapsed() > msecsWithoutTouches)) {
121121 Q_EMIT homeKeyActivated();
122122 }
plugins/Utils/WindowInputMonitor.h+8−2
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 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
@@ -18,6 +18,7 @@
1818#define UNITY_WINDOWINPUTMONITOR_H
1919
2020#include <QQuickItem>
21+#include <QList>
2122#include <QPointer>
2223
2324#include "Timer.h"
@@ -83,9 +84,14 @@ private Q_SLOTS:
8384private:
8485 QPointer<QQuickWindow> m_filteredWindow;
8586 bool m_windowBeingTouched;
86− bool m_homeKeyPressed;
8787 UnityUtil::AbstractElapsedTimer *m_windowLastTouchedTimer;
8888 UnityUtil::AbstractTimer *m_activationTimer;
89+
90+ // Qt::Keys that are mapped to our "home" key.
91+ QList<int> m_homeKeys{Qt::Key_Super_L, Qt::Key_HomePage};
92+ // Which Qt::Key from m_homeKeys is currently pressed.
93+ // 0 if none
94+ int m_pressedHomeKey{0};
8995};
9096
9197#endif // UNITY_WINDOWINPUTMONITOR_H
plugins/Utils/windowstatestorage.h+13−3
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2015 Canonical Ltd.
2+ * Copyright 2015-2016 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -25,9 +25,19 @@ class WindowStateStorage: public QObject
2525 Q_ENUMS(WindowState)
2626public:
2727 enum WindowState {
28− WindowStateNormal,
29− WindowStateMaximized
28+ WindowStateNormal = 1 << 0,
29+ WindowStateMaximized = 1 << 1,
30+ WindowStateMinimized = 1 << 2,
31+ WindowStateFullscreen = 1 << 3,
32+ WindowStateMaximizedLeft = 1 << 4,
33+ WindowStateMaximizedRight = 1 << 5,
34+ WindowStateMaximizedHorizontally = 1 << 6,
35+ WindowStateMaximizedVertically = 1 << 7
3036 };
37+ Q_DECLARE_FLAGS(WindowStates, WindowState)
38+#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
39+ Q_FLAG(WindowStates)
40+#endif
3141
3242 WindowStateStorage(QObject *parent = 0);
3343 virtual ~WindowStateStorage();
po/aa.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-02-12 10:18+0000\n"
1212"Last-Translator: Charif AYFARAH <ayfarah@ymail.com>\n"
1313"Language-Team: Afar <aa@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr "Dabqi"
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/am.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-03-24 19:07+0000\n"
1212"Last-Translator: samson <Unknown>\n"
1313"Language-Team: Amharic <am@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr "ቤት"
258258msgid "Also installed"
259259msgstr "እንዲሁም የተገጠሙ"
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/ar.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-29 09:41+0000\n"
1212"Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n"
1313"Language-Team: Arabic <ar@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
1818"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -265,7 +265,7 @@ msgstr "الرئيسية"
265265msgid "Also installed"
266266msgstr "أيضا تم تثبيت"
267267
268−#: qml/DisabledScreenNotice.qml:104
268+#: qml/DisabledScreenNotice.qml:109
269269msgid ""
270270"Your device is now connected to an external display. Use this screen as a "
271271"touch pad to interact with the pointer."
po/ast.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-05-16 14:07+0000\n"
1212"Last-Translator: Xuacu Saturio <xuacusk8@gmail.com>\n"
1313"Language-Team: Asturian <ast@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -259,7 +259,7 @@ msgstr "Aniciu"
259259msgid "Also installed"
260260msgstr "Tamién instalaos"
261261
262−#: qml/DisabledScreenNotice.qml:104
262+#: qml/DisabledScreenNotice.qml:109
263263msgid ""
264264"Your device is now connected to an external display. Use this screen as a "
265265"touch pad to interact with the pointer."
po/az.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-09-03 16:39+0000\n"
1212"Last-Translator: Nicat Məmmədov <n1c4t97@gmail.com>\n"
1313"Language-Team: Azerbaijani <az@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/be.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-12-13 13:12+0000\n"
1212"Last-Translator: Mikhail_SaTuRn <mikhail_saturn@tut.by>\n"
1313"Language-Team: Belarusian <be@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Хатняя папка"
263263msgid "Also installed"
264264msgstr "Таксама ўсталявана"
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
po/bg.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-04-12 14:43+0000\n"
1212"Last-Translator: George Karavasilev <kokoto-java@ubuntu.com>\n"
1313"Language-Team: Bulgarian <bg@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr ""
258258msgid "Also installed"
259259msgstr ""
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/bn.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-11-27 19:38+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Bengali <bn@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr ""
258258msgid "Also installed"
259259msgstr "আরও ইন্সটল করা রয়েছে..."
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/br.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-04-27 12:20+0000\n"
1212"Last-Translator: Fohanno Thierry <thierry.fohanno@ofis-bzh.org>\n"
1313"Language-Team: Breton <br@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -265,7 +265,7 @@ msgstr "Er gêr"
265265msgid "Also installed"
266266msgstr "Staliet ivez"
267267
268−#: qml/DisabledScreenNotice.qml:104
268+#: qml/DisabledScreenNotice.qml:109
269269msgid ""
270270"Your device is now connected to an external display. Use this screen as a "
271271"touch pad to interact with the pointer."
po/bs.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-12-01 20:06+0000\n"
1212"Last-Translator: Kenan Gutić <Unknown>\n"
1313"Language-Team: Bosnian <bs@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -262,7 +262,7 @@ msgstr "Početna"
262262msgid "Also installed"
263263msgstr "Također instalirano"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
po/ca.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-04 09:48+0000\n"
1212"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
1313"Language-Team: Catalan <ca@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -262,7 +262,7 @@ msgstr "Inici"
262262msgid "Also installed"
263263msgstr "També instal·lat"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
po/ca@valencia.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-02-22 15:22+0000\n"
1212"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
1313"Language-Team: Catalan <ca@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -262,7 +262,7 @@ msgstr "Inici"
262262msgid "Also installed"
263263msgstr "També instal·lat"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
po/ce.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-02-15 04:01+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Chechen <ce@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/ckb.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-01-21 11:05+0000\n"
1212"Last-Translator: Aras <aras.noori@gmail.com>\n"
1313"Language-Team: Kurdish (Sorani) <ckb@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/co.ponew file+736
@@ -0,0 +1,736 @@
1+# Corsican translation for unity8
2+# Copyright (c) 2016 Rosetta Contributors and Canonical Ltd 2016
3+# This file is distributed under the same license as the unity8 package.
4+# FIRST AUTHOR <EMAIL@ADDRESS>, 2016.
5+#
6+msgid ""
7+msgstr ""
8+"Project-Id-Version: unity8\n"
9+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
11+"PO-Revision-Date: 2016-05-24 10:40+0000\n"
12+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13+"Language-Team: Corsican <co@li.org>\n"
14+"MIME-Version: 1.0\n"
15+"Content-Type: text/plain; charset=UTF-8\n"
16+"Content-Transfer-Encoding: 8bit\n"
17+"Plural-Forms: nplurals=2; plural=n != 1;\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
20+
21+#: plugins/IntegratedLightDM/Greeter.cpp:112
22+msgid "Password: "
23+msgstr ""
24+
25+#: plugins/Unity/Launcher/launcheritem.cpp:48
26+#: plugins/Unity/Launcher/launcheritem.cpp:107
27+msgid "Pin shortcut"
28+msgstr ""
29+
30+#: plugins/Unity/Launcher/launcheritem.cpp:53
31+msgid "Quit"
32+msgstr ""
33+
34+#: plugins/Unity/Launcher/launcheritem.cpp:107
35+msgid "Unpin shortcut"
36+msgstr ""
37+
38+#: qml/Components/DelayedLockscreen.qml:49
39+msgid "Device Locked"
40+msgstr ""
41+
42+#: qml/Components/DelayedLockscreen.qml:64
43+msgid "You have been locked out due to too many failed passphrase attempts."
44+msgstr ""
45+
46+#: qml/Components/DelayedLockscreen.qml:65
47+msgid "You have been locked out due to too many failed passcode attempts."
48+msgstr ""
49+
50+#: qml/Components/DelayedLockscreen.qml:74
51+#, qt-format
52+msgid "Please wait %1 minute and then try again…"
53+msgid_plural "Please wait %1 minutes and then try again…"
54+msgstr[0] ""
55+msgstr[1] ""
56+
57+#: qml/Components/Dialogs.qml:144
58+msgctxt "Title: Lock/Log out dialog"
59+msgid "Log out"
60+msgstr ""
61+
62+#: qml/Components/Dialogs.qml:145
63+msgid "Are you sure you want to log out?"
64+msgstr ""
65+
66+#: qml/Components/Dialogs.qml:147
67+msgctxt "Button: Lock the system"
68+msgid "Lock"
69+msgstr ""
70+
71+#: qml/Components/Dialogs.qml:154
72+msgctxt "Button: Log out from the system"
73+msgid "Log Out"
74+msgstr ""
75+
76+#: qml/Components/Dialogs.qml:161 qml/Components/Dialogs.qml:217
77+#: qml/Dash/DashPageHeader.qml:298 qml/Wizard/Pages/passcode-confirm.qml:32
78+#: qml/Wizard/Pages/passcode-set.qml:32
79+msgid "Cancel"
80+msgstr ""
81+
82+#: qml/Components/Dialogs.qml:173
83+msgctxt "Title: Reboot dialog"
84+msgid "Reboot"
85+msgstr ""
86+
87+#: qml/Components/Dialogs.qml:174
88+msgid "Are you sure you want to reboot?"
89+msgstr ""
90+
91+#: qml/Components/Dialogs.qml:176
92+msgid "No"
93+msgstr ""
94+
95+#: qml/Components/Dialogs.qml:182
96+msgid "Yes"
97+msgstr ""
98+
99+#: qml/Components/Dialogs.qml:197
100+msgctxt "Title: Power off/Restart dialog"
101+msgid "Power"
102+msgstr ""
103+
104+#: qml/Components/Dialogs.qml:198
105+msgid ""
106+"Are you sure you would like\n"
107+"to power off?"
108+msgstr ""
109+
110+#: qml/Components/Dialogs.qml:200
111+msgctxt "Button: Power off the system"
112+msgid "Power off"
113+msgstr ""
114+
115+#: qml/Components/Dialogs.qml:209
116+msgctxt "Button: Restart the system"
117+msgid "Restart"
118+msgstr ""
119+
120+#: qml/Components/Lockscreen.qml:231
121+msgid "Return to Call"
122+msgstr ""
123+
124+#: qml/Components/Lockscreen.qml:231
125+msgid "Emergency Call"
126+msgstr ""
127+
128+#: qml/Components/Lockscreen.qml:263
129+msgid "OK"
130+msgstr ""
131+
132+#: qml/Components/ModeSwitchWarningDialog.qml:32
133+msgid "Apps may have unsaved data:"
134+msgstr ""
135+
136+#: qml/Components/ModeSwitchWarningDialog.qml:57
137+msgctxt ""
138+"Re-dock means connect the device again to an external screen/mouse/keyboard"
139+msgid "Re-dock, save your work and close these apps to continue."
140+msgstr ""
141+
142+#: qml/Components/ModeSwitchWarningDialog.qml:63
143+msgid "Or force close now (unsaved data will be lost)."
144+msgstr ""
145+
146+#: qml/Components/ModeSwitchWarningDialog.qml:75
147+msgid "OK, I will reconnect"
148+msgstr ""
149+
150+#: qml/Components/ModeSwitchWarningDialog.qml:76
151+msgid "Reconnect now!"
152+msgstr ""
153+
154+#: qml/Components/ModeSwitchWarningDialog.qml:88
155+msgid "Close all"
156+msgstr ""
157+
158+#: qml/Dash/DashPageHeader.qml:337
159+msgctxt "Button: Open the Ubuntu Store"
160+msgid "Store"
161+msgstr ""
162+
163+#: qml/Dash/DashPageHeader.qml:344
164+msgctxt "Button: Start a search in the current dash scope"
165+msgid "Search"
166+msgstr ""
167+
168+#: qml/Dash/DashPageHeader.qml:354
169+msgctxt "Button: Show the current dash scope settings"
170+msgid "Settings"
171+msgstr ""
172+
173+#: qml/Dash/DashPageHeader.qml:361
174+msgid "Remove from Favorites"
175+msgstr ""
176+
177+#: qml/Dash/DashPageHeader.qml:361
178+msgid "Add to Favorites"
179+msgstr ""
180+
181+#: qml/Dash/FiltersPopover.qml:60
182+msgid "Refine your results"
183+msgstr ""
184+
185+#: qml/Dash/FiltersPopover.qml:69
186+msgid "Reset"
187+msgstr ""
188+
189+#: qml/Dash/GenericScopeView.qml:579 qml/Dash/GenericScopeView.qml:764
190+msgid "Show less"
191+msgstr ""
192+
193+#: qml/Dash/GenericScopeView.qml:579
194+msgid "Show all"
195+msgstr ""
196+
197+#: qml/Dash/GenericScopeView.qml:636
198+msgctxt "Label: Hint for dash search line edit"
199+msgid "Search"
200+msgstr ""
201+
202+#: qml/Dash/PageHeaderExtraPanel.qml:55
203+msgid "Recent Searches"
204+msgstr ""
205+
206+#: qml/Dash/PageHeaderExtraPanel.qml:66
207+msgid "Clear All"
208+msgstr ""
209+
210+#: qml/Dash/Previews/PreviewActionCombo.qml:35
211+msgid "More..."
212+msgstr ""
213+
214+#: qml/Dash/Previews/PreviewActionCombo.qml:35
215+msgid "Less..."
216+msgstr ""
217+
218+#: qml/Dash/Previews/PreviewCommentInput.qml:68
219+#: qml/Dash/Previews/PreviewRatingInput.qml:174
220+msgid "Send"
221+msgstr ""
222+
223+#: qml/Dash/Previews/PreviewRatingInput.qml:84
224+msgid "Rate this"
225+msgstr ""
226+
227+#: qml/Dash/Previews/PreviewRatingInput.qml:129
228+msgid "Add a review"
229+msgstr ""
230+
231+#: qml/Dash/Previews/PreviewSharing.qml:66
232+msgid "Preview Share Item"
233+msgstr ""
234+
235+#: qml/Dash/PullToRefreshScopeStyle.qml:55
236+msgid "Pull to refresh…"
237+msgstr ""
238+
239+#: qml/Dash/PullToRefreshScopeStyle.qml:60
240+msgid "Release to refresh…"
241+msgstr ""
242+
243+#: qml/Dash/ScopeSettings/ScopeSettingBoolean.qml:43
244+msgid "Enable location data"
245+msgstr ""
246+
247+#: qml/Dash/ScopesList.qml:67
248+msgid "Manage"
249+msgstr ""
250+
251+#: qml/Dash/ScopesList.qml:113
252+msgid "Home"
253+msgstr ""
254+
255+#: qml/Dash/ScopesList.qml:114
256+msgid "Also installed"
257+msgstr ""
258+
259+#: qml/DisabledScreenNotice.qml:109
260+msgid ""
261+"Your device is now connected to an external display. Use this screen as a "
262+"touch pad to interact with the pointer."
263+msgstr ""
264+
265+#: qml/Greeter/CoverPage.qml:118
266+msgid "Unlock"
267+msgstr ""
268+
269+#: qml/Greeter/LoginList.qml:239
270+msgid "Retry"
271+msgstr ""
272+
273+#: qml/Greeter/LoginList.qml:240
274+msgid "Tap to unlock"
275+msgstr ""
276+
277+#: qml/Greeter/NarrowView.qml:54
278+msgid "Sorry, incorrect passphrase."
279+msgstr ""
280+
281+#: qml/Greeter/NarrowView.qml:55
282+msgid "Sorry, incorrect passcode."
283+msgstr ""
284+
285+#: qml/Greeter/NarrowView.qml:56
286+msgid "This will be your last attempt."
287+msgstr ""
288+
289+#: qml/Greeter/NarrowView.qml:58
290+msgid ""
291+"If passphrase is entered incorrectly, your phone will conduct a factory "
292+"reset and all personal data will be deleted."
293+msgstr ""
294+
295+#: qml/Greeter/NarrowView.qml:59
296+msgid ""
297+"If passcode is entered incorrectly, your phone will conduct a factory reset "
298+"and all personal data will be deleted."
299+msgstr ""
300+
301+#: qml/Greeter/NarrowView.qml:116
302+#, qt-format
303+msgid "Enter %1"
304+msgstr ""
305+
306+#: qml/Greeter/NarrowView.qml:117
307+msgid "Enter passphrase"
308+msgstr ""
309+
310+#: qml/Greeter/NarrowView.qml:118
311+msgid "Enter passcode"
312+msgstr ""
313+
314+#: qml/Greeter/NarrowView.qml:119
315+#, qt-format
316+msgid "Sorry, incorrect %1"
317+msgstr ""
318+
319+#: qml/Greeter/NarrowView.qml:120
320+msgid "Sorry, incorrect passphrase"
321+msgstr ""
322+
323+#: qml/Greeter/NarrowView.qml:121
324+msgctxt "passphrase"
325+msgid "Please re-enter"
326+msgstr ""
327+
328+#: qml/Greeter/NarrowView.qml:122
329+msgid "Sorry, incorrect passcode"
330+msgstr ""
331+
332+#: qml/Notifications/NotificationMenuItemFactory.qml:124
333+msgid "Show password"
334+msgstr ""
335+
336+#: qml/Panel/ActiveCallHint.qml:79
337+msgid "Tap to return to call..."
338+msgstr ""
339+
340+#: qml/Panel/ActiveCallHint.qml:92
341+msgid "Conference"
342+msgstr ""
343+
344+#: qml/Panel/Indicators/MenuItemFactory.qml:762
345+msgid "Nothing is playing"
346+msgstr ""
347+
348+#: qml/Panel/Indicators/MenuItemFactory.qml:891
349+#, qt-format
350+msgid "%1 hour"
351+msgid_plural "%1 hours"
352+msgstr[0] ""
353+msgstr[1] ""
354+
355+#: qml/Panel/Indicators/MenuItemFactory.qml:895
356+#, qt-format
357+msgid "%1 minute"
358+msgid_plural "%1 minutes"
359+msgstr[0] ""
360+msgstr[1] ""
361+
362+#: qml/Panel/Indicators/MenuItemFactory.qml:900
363+#, qt-format
364+msgid "%1 second"
365+msgid_plural "%1 seconds"
366+msgstr[0] ""
367+msgstr[1] ""
368+
369+#: qml/Panel/Indicators/MenuItemFactory.qml:903
370+msgid "0 seconds"
371+msgstr ""
372+
373+#. Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
374+#: qml/Panel/Indicators/MenuItemFactory.qml:905
375+#, qt-format
376+msgid "%1 remaining"
377+msgstr ""
378+
379+#: qml/Panel/Indicators/MenuItemFactory.qml:911
380+msgid "In queue…"
381+msgstr ""
382+
383+#: qml/Panel/Indicators/MenuItemFactory.qml:915
384+msgid "Downloading"
385+msgstr ""
386+
387+#: qml/Panel/Indicators/MenuItemFactory.qml:917
388+msgid "Paused, tap to resume"
389+msgstr ""
390+
391+#: qml/Panel/Indicators/MenuItemFactory.qml:919
392+msgid "Canceled"
393+msgstr ""
394+
395+#: qml/Panel/Indicators/MenuItemFactory.qml:921
396+msgid "Finished"
397+msgstr ""
398+
399+#: qml/Panel/Indicators/MenuItemFactory.qml:923
400+msgid "Failed, tap to retry"
401+msgstr ""
402+
403+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:155
404+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:214
405+msgctxt "Button: Send a reply message"
406+msgid "Send"
407+msgstr ""
408+
409+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:156
410+msgctxt "Label: Hint in message indicator line edit"
411+msgid "Reply"
412+msgstr ""
413+
414+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:213
415+msgctxt "Button: Call back on phone"
416+msgid "Call back"
417+msgstr ""
418+
419+#: qml/Stages/SideStage.qml:76
420+msgid "Drag using 3 fingers any application from one window to the other"
421+msgstr ""
422+
423+#: qml/Tutorial/TutorialBottom.qml:78
424+msgid "Swipe up to add a contact"
425+msgstr ""
426+
427+#: qml/Tutorial/TutorialBottom.qml:80
428+msgid "Swipe up for favorite calculations"
429+msgstr ""
430+
431+#: qml/Tutorial/TutorialBottom.qml:82
432+msgid "Swipe up for recent calls"
433+msgstr ""
434+
435+#: qml/Tutorial/TutorialBottom.qml:84
436+msgid "Swipe up to create a message"
437+msgstr ""
438+
439+#: qml/Tutorial/TutorialBottom.qml:85
440+msgid "Swipe up to manage the app"
441+msgstr ""
442+
443+#: qml/Tutorial/TutorialLeftLong.qml:47
444+msgid "Long swipe from the left edge to open the Today scope"
445+msgstr ""
446+
447+#: qml/Tutorial/TutorialLeft.qml:47
448+msgid "Swipe from the left edge to open the launcher"
449+msgstr ""
450+
451+#: qml/Tutorial/TutorialRight.qml:55
452+msgid "Push your mouse against the right edge to view your open apps"
453+msgstr ""
454+
455+#: qml/Tutorial/TutorialRight.qml:56
456+msgid "Short or long swipe from the right edge to view your open apps"
457+msgstr ""
458+
459+#: qml/Tutorial/TutorialTop.qml:53
460+msgid "Swipe from the top right edge to open the notification bar"
461+msgstr ""
462+
463+#: qml/Tutorial/TutorialTop.qml:54
464+msgid "Swipe from the top edge to open the notification bar"
465+msgstr ""
466+
467+#: qml/Wizard/Page.qml:54
468+msgctxt "Button: Go back one page in the Wizard"
469+msgid "Back"
470+msgstr ""
471+
472+#: qml/Wizard/Pages/10-welcome.qml:27
473+msgid "Language"
474+msgstr ""
475+
476+#: qml/Wizard/Pages/10-welcome.qml:156 qml/Wizard/Pages/30-wifi.qml:206
477+#: qml/Wizard/Pages/40-location.qml:271 qml/Wizard/Pages/50-timezone.qml:267
478+#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/70-passwd-type.qml:144
479+#: qml/Wizard/Pages/75-report-check.qml:84
480+#: qml/Wizard/Pages/passcode-desktop.qml:124
481+#: qml/Wizard/Pages/password-set.qml:141
482+msgid "Next"
483+msgstr ""
484+
485+#: qml/Wizard/Pages/30-wifi.qml:29
486+msgid "Connect to Wi‑Fi"
487+msgstr ""
488+
489+#: qml/Wizard/Pages/30-wifi.qml:130
490+msgid "Connected"
491+msgstr ""
492+
493+#: qml/Wizard/Pages/30-wifi.qml:163
494+msgid "Available Wi-Fi networks"
495+msgstr ""
496+
497+#: qml/Wizard/Pages/30-wifi.qml:164
498+msgid "No available Wi-Fi networks"
499+msgstr ""
500+
501+#: qml/Wizard/Pages/30-wifi.qml:206 qml/Wizard/Pages/60-account.qml:65
502+#: qml/Wizard/Pages/sim.qml:101
503+msgid "Skip"
504+msgstr ""
505+
506+#: qml/Wizard/Pages/40-location.qml:27
507+msgid "Location Services"
508+msgstr ""
509+
510+#: qml/Wizard/Pages/40-location.qml:83
511+msgid ""
512+"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
513+"(recommended)"
514+msgstr ""
515+
516+#: qml/Wizard/Pages/40-location.qml:105
517+#, qt-format
518+msgid "By selecting this option you agree to the Nokia HERE %1."
519+msgstr ""
520+
521+#: qml/Wizard/Pages/40-location.qml:106
522+msgctxt "part of: Nokia HERE terms and conditions"
523+msgid "terms and conditions"
524+msgstr ""
525+
526+#: qml/Wizard/Pages/40-location.qml:160
527+msgid "GPS only"
528+msgstr ""
529+
530+#: qml/Wizard/Pages/40-location.qml:214
531+msgid "Don't use my location"
532+msgstr ""
533+
534+#: qml/Wizard/Pages/40-location.qml:260
535+msgid "You can change it later in System Settings."
536+msgstr ""
537+
538+#: qml/Wizard/Pages/50-timezone.qml:29
539+msgid "Time Zone"
540+msgstr ""
541+
542+#: qml/Wizard/Pages/50-timezone.qml:178
543+msgid "Enter your city"
544+msgstr ""
545+
546+#: qml/Wizard/Pages/60-account.qml:24
547+msgid "Personalize Your Device"
548+msgstr ""
549+
550+#: qml/Wizard/Pages/60-account.qml:48
551+msgid "Preferred Name"
552+msgstr ""
553+
554+#: qml/Wizard/Pages/70-passwd-type.qml:39
555+msgid "Lock Screen"
556+msgstr ""
557+
558+#: qml/Wizard/Pages/70-passwd-type.qml:101
559+msgctxt "Label: Type of security method"
560+msgid "Create new password"
561+msgstr ""
562+
563+#: qml/Wizard/Pages/70-passwd-type.qml:103
564+msgctxt "Label: Type of security method"
565+msgid "Create passcode (numbers only)"
566+msgstr ""
567+
568+#: qml/Wizard/Pages/70-passwd-type.qml:105
569+msgctxt "Label: Type of security method"
570+msgid "No lock code"
571+msgstr ""
572+
573+#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
574+msgid "Privacy Policy"
575+msgstr ""
576+
577+#: qml/Wizard/Pages/75-report-check.qml:26
578+msgid "Help Us Improve"
579+msgstr ""
580+
581+#: qml/Wizard/Pages/75-report-check.qml:59
582+msgid "Improve system performance by sending us crashes and error reports."
583+msgstr ""
584+
585+#: qml/Wizard/Pages/75-report-check.qml:60
586+msgid "Privacy policy"
587+msgstr ""
588+
589+#: qml/Wizard/Pages/80-finished.qml:89
590+msgid "Welcome to Ubuntu"
591+msgstr ""
592+
593+#: qml/Wizard/Pages/80-finished.qml:104
594+msgid "You are ready to use your device now"
595+msgstr ""
596+
597+#: qml/Wizard/Pages/80-finished.qml:124
598+msgid "Get Started"
599+msgstr ""
600+
601+#: qml/Wizard/Pages/here-terms.qml:25
602+msgid "Terms & Conditions"
603+msgstr ""
604+
605+#: qml/Wizard/Pages/here-terms.qml:69
606+msgid "Your device uses positioning technologies provided by HERE."
607+msgstr ""
608+
609+#: qml/Wizard/Pages/here-terms.qml:81
610+msgid ""
611+"To provide you with positioning services and to improve their quality, HERE "
612+"collects information about nearby cell towers and Wi-Fi hotspots around your "
613+"current location whenever your position is being found."
614+msgstr ""
615+
616+#: qml/Wizard/Pages/here-terms.qml:93
617+msgid ""
618+"The information collected is used to analyze the service and to improve the "
619+"use of service, but not to identify you personally."
620+msgstr ""
621+
622+#: qml/Wizard/Pages/here-terms.qml:106
623+#, qt-format
624+msgid "By continuing, you agree to the HERE platform %1 and %2."
625+msgstr ""
626+
627+#: qml/Wizard/Pages/here-terms.qml:107
628+msgid "Service Terms"
629+msgstr ""
630+
631+#: qml/Wizard/Pages/passcode-confirm.qml:43
632+#: qml/Wizard/Pages/passcode-desktop.qml:80
633+msgid "Confirm passcode"
634+msgstr ""
635+
636+#: qml/Wizard/Pages/passcode-confirm.qml:45
637+msgid "Incorrect passcode."
638+msgstr ""
639+
640+#: qml/Wizard/Pages/passcode-confirm.qml:45
641+msgctxt "Enter the passcode again"
642+msgid "Please re-enter."
643+msgstr ""
644+
645+#: qml/Wizard/Pages/passcode-desktop.qml:30
646+msgid "Lock Screen Passcode"
647+msgstr ""
648+
649+#: qml/Wizard/Pages/passcode-desktop.qml:56
650+msgid "Enter 4 numbers to setup your passcode"
651+msgstr ""
652+
653+#: qml/Wizard/Pages/passcode-desktop.qml:65
654+#: qml/Wizard/Pages/passcode-set.qml:54
655+msgid "Choose passcode"
656+msgstr ""
657+
658+#: qml/Wizard/Pages/passcode-desktop.qml:105
659+msgid "Passcode too short"
660+msgstr ""
661+
662+#: qml/Wizard/Pages/passcode-desktop.qml:107
663+msgid "Passcodes match"
664+msgstr ""
665+
666+#: qml/Wizard/Pages/passcode-desktop.qml:109
667+msgid "Passcodes do not match"
668+msgstr ""
669+
670+#: qml/Wizard/Pages/passcode-set.qml:62
671+msgid "Passcode must be 4 characters long"
672+msgstr ""
673+
674+#: qml/Wizard/Pages/password-set.qml:30
675+msgid "Lock Screen Password"
676+msgstr ""
677+
678+#: qml/Wizard/Pages/password-set.qml:61
679+msgid "Enter at least 8 characters"
680+msgstr ""
681+
682+#: qml/Wizard/Pages/password-set.qml:73
683+msgid "Choose password"
684+msgstr ""
685+
686+#: qml/Wizard/Pages/password-set.qml:103
687+msgid "Confirm password"
688+msgstr ""
689+
690+#: qml/Wizard/Pages/sim.qml:27
691+msgid "No SIM card installed"
692+msgstr ""
693+
694+#: qml/Wizard/Pages/sim.qml:54
695+msgid "SIM card added"
696+msgstr ""
697+
698+#: qml/Wizard/Pages/sim.qml:55
699+msgid "You must restart the device to access the mobile network."
700+msgstr ""
701+
702+#: qml/Wizard/Pages/sim.qml:59
703+msgid "Restart"
704+msgstr ""
705+
706+#: qml/Wizard/Pages/sim.qml:78
707+msgid "You won’t be able to make calls or use text messaging without a SIM."
708+msgstr ""
709+
710+#: qml/Wizard/Pages/sim.qml:90
711+msgid "To proceed with no SIM tap Skip."
712+msgstr ""
713+
714+#: qml/Wizard/PasswordMeter.qml:87
715+msgid "Passwords match"
716+msgstr ""
717+
718+#: qml/Wizard/PasswordMeter.qml:89
719+msgid "Passwords do not match"
720+msgstr ""
721+
722+#: qml/Wizard/PasswordMeter.qml:93
723+msgid "Strong password"
724+msgstr ""
725+
726+#: qml/Wizard/PasswordMeter.qml:95
727+msgid "Fair password"
728+msgstr ""
729+
730+#: qml/Wizard/PasswordMeter.qml:97
731+msgid "Weak password"
732+msgstr ""
733+
734+#: qml/Wizard/PasswordMeter.qml:99
735+msgid "Very weak password"
736+msgstr ""
po/cs.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-07 10:44+0000\n"
1212"Last-Translator: Vojtěch Daněk <vdanek@outlook.com>\n"
1313"Language-Team: Czech <cs@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020"Language: cs\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -262,7 +262,7 @@ msgstr "Domů"
262262msgid "Also installed"
263263msgstr "Také nainstalováno"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
po/cy.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-31 13:21+0000\n"
1212"Last-Translator: Owen Llywelyn <owen.llywelyn@gmail.com>\n"
1313"Language-Team: Welsh <cy@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=n==1 ? 0 : n==2 ? 1 : (n != 8 && n != 11) ? "
1818"2 : 3;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Cartref"
263263msgid "Also installed"
264264msgstr "Hefyd wedi gosod"
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
po/da.po+4−4
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
11−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
11+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1212"PO-Revision-Date: 2015-07-06 12:05+0000\n"
1313"Last-Translator: Folmer Fredslund <Unknown>\n"
1414"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
1818"Plural-Forms: nplurals=2; plural=n != 1;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Hjem"
263263msgid "Also installed"
264264msgstr "Også installeret"
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
po/de.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-05-10 19:23+0000\n"
1212"Last-Translator: Torsten Franz <Unknown>\n"
1313"Language-Team: German <de@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -264,7 +264,7 @@ msgstr "Startseite"
264264msgid "Also installed"
265265msgstr "Ebenfalls installiert"
266266
267−#: qml/DisabledScreenNotice.qml:104
267+#: qml/DisabledScreenNotice.qml:109
268268msgid ""
269269"Your device is now connected to an external display. Use this screen as a "
270270"touch pad to interact with the pointer."
po/el.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-04-25 16:24+0000\n"
1212"Last-Translator: Aggelos Arnaoutis <angelosarn@hotmail.com>\n"
1313"Language-Team: Greek <el@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -264,7 +264,7 @@ msgstr "Αρχή"
264264msgid "Also installed"
265265msgstr "Επίσης εγκατεστημένα"
266266
267−#: qml/DisabledScreenNotice.qml:104
267+#: qml/DisabledScreenNotice.qml:109
268268msgid ""
269269"Your device is now connected to an external display. Use this screen as a "
270270"touch pad to interact with the pointer."
po/en_AU.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-03-27 10:09+0000\n"
1212"Last-Translator: Jared Norris <jarednorris@ubuntu.com>\n"
1313"Language-Team: English (Australia) <en_AU@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr "Home"
258258msgid "Also installed"
259259msgstr "Also installed"
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/en_GB.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-05-10 10:10+0000\n"
1212"Last-Translator: Andi Chandler <Unknown>\n"
1313"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr "Home"
258258msgid "Also installed"
259259msgstr "Also installed"
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/eo.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-06-06 23:37+0000\n"
1212"Last-Translator: Eliovir <Unknown>\n"
1313"Language-Team: Esperanto <eo@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr "Hejmo"
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/es.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-03-25 12:02+0000\n"
1212"Last-Translator: Adolfo Jayme <fitoschido@gmail.com>\n"
1313"Language-Team: Spanish <es@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Inicio"
263263msgid "Also installed"
264264msgstr "También instalados"
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
po/eu.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-13 23:29+0000\n"
1212"Last-Translator: Ibai Oihanguren Sala <Unknown>\n"
1313"Language-Team: Basque <eu@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -259,7 +259,7 @@ msgstr "Hasiera"
259259msgid "Also installed"
260260msgstr "Hau ere instalatuta"
261261
262−#: qml/DisabledScreenNotice.qml:104
262+#: qml/DisabledScreenNotice.qml:109
263263msgid ""
264264"Your device is now connected to an external display. Use this screen as a "
265265"touch pad to interact with the pointer."
po/fa.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-03-30 14:29+0000\n"
1212"Last-Translator: Danial Behzadi <dani.behzi@gmail.com>\n"
1313"Language-Team: Persian <fa@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -259,7 +259,7 @@ msgstr "خانه"
259259msgid "Also installed"
260260msgstr "هم‌چنین نصب شده"
261261
262−#: qml/DisabledScreenNotice.qml:104
262+#: qml/DisabledScreenNotice.qml:109
263263msgid ""
264264"Your device is now connected to an external display. Use this screen as a "
265265"touch pad to interact with the pointer."
po/fi.po+8−6
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-04 18:32+0000\n"
1212"Last-Translator: Jiri Grönroos <Unknown>\n"
1313"Language-Team: Finnish <fi@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -194,11 +194,11 @@ msgstr "Palauta"
194194
195195#: qml/Dash/GenericScopeView.qml:579 qml/Dash/GenericScopeView.qml:764
196196msgid "Show less"
197−msgstr ""
197+msgstr "Näytä vähemmän"
198198
199199#: qml/Dash/GenericScopeView.qml:579
200200msgid "Show all"
201−msgstr ""
201+msgstr "Näytä kaikki"
202202
203203#: qml/Dash/GenericScopeView.qml:636
204204msgctxt "Label: Hint for dash search line edit"
@@ -262,7 +262,7 @@ msgstr "Koti"
262262msgid "Also installed"
263263msgstr "Myös asennettu"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
@@ -463,6 +463,8 @@ msgstr "Vedä vasemmasta reunasta avataksesi käynnistimen"
463463#: qml/Tutorial/TutorialRight.qml:55
464464msgid "Push your mouse against the right edge to view your open apps"
465465msgstr ""
466+"Työnnä oikeaa reunaa hiiren osoittimella nähdäksesi avoinna olevat "
467+"sovellukset"
466468
467469#: qml/Tutorial/TutorialRight.qml:56
468470msgid "Short or long swipe from the right edge to view your open apps"
po/fo.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-01-14 20:08+0000\n"
1212"Last-Translator: Jógvan Olsen <jeggy@jebster.net>\n"
1313"Language-Team: Faroese <fo@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/fr.po+9−9
@@ -7,16 +7,16 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
11−"PO-Revision-Date: 2016-05-01 09:09+0000\n"
12−"Last-Translator: Anne <anneonyme017@gmail.com>\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
11+"PO-Revision-Date: 2016-05-19 21:22+0000\n"
12+"Last-Translator: Ubuntu-QC-1 <Unknown>\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"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -37,13 +37,13 @@ msgstr "Détacher le raccourci"
3737
3838#: qml/Components/DelayedLockscreen.qml:49
3939msgid "Device Locked"
40−msgstr "Périphérique verrouillé"
40+msgstr "Appareil verrouillé"
4141
4242#: qml/Components/DelayedLockscreen.qml:64
4343msgid "You have been locked out due to too many failed passphrase attempts."
4444msgstr ""
45−"Vous avez été bloqué suite à un trop grand nombre de tentatives de saisie "
46−"d'une phrase de passe erronée."
45+"L'appareil a été verrouillé suite à un trop grand nombre de tentatives de "
46+"saisie d'une phrase de passe erronée."
4747
4848#: qml/Components/DelayedLockscreen.qml:65
4949msgid "You have been locked out due to too many failed passcode attempts."
@@ -266,7 +266,7 @@ msgstr "Accueil"
266266msgid "Also installed"
267267msgstr "Également installées"
268268
269−#: qml/DisabledScreenNotice.qml:104
269+#: qml/DisabledScreenNotice.qml:109
270270msgid ""
271271"Your device is now connected to an external display. Use this screen as a "
272272"touch pad to interact with the pointer."
po/ga.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-01-25 11:33+0000\n"
1212"Last-Translator: Joshua Kiley <Unknown>\n"
1313"Language-Team: Irish <ga@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -257,7 +257,7 @@ msgstr "Baile"
257257msgid "Also installed"
258258msgstr ""
259259
260−#: qml/DisabledScreenNotice.qml:104
260+#: qml/DisabledScreenNotice.qml:109
261261msgid ""
262262"Your device is now connected to an external display. Use this screen as a "
263263"touch pad to interact with the pointer."
po/gd.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-04-08 18:34+0000\n"
1212"Last-Translator: Akerbeltz <fios@akerbeltz.org>\n"
1313"Language-Team: Fòram na Gàidhlig\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=(n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : "
1818"(n > 2 && n < 20) ? 2 : 3;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121"Language: gd\n"
2222
2323#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -268,7 +268,7 @@ msgstr "Dhachaigh"
268268msgid "Also installed"
269269msgstr "Air a stàladh cuideachd"
270270
271−#: qml/DisabledScreenNotice.qml:104
271+#: qml/DisabledScreenNotice.qml:109
272272msgid ""
273273"Your device is now connected to an external display. Use this screen as a "
274274"touch pad to interact with the pointer."
po/gl.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-01-15 14:56+0000\n"
1212"Last-Translator: Marcos Lans <Unknown>\n"
1313"Language-Team: Galician <gl@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr "Persoal"
258258msgid "Also installed"
259259msgstr "Tamén instalado"
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/gv.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-04-02 14:24+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Manx <gv@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : (n == 2 ? 1 : 2);\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Balley"
263263msgid "Also installed"
264264msgstr ""
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
po/he.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-12 08:47+0000\n"
1212"Last-Translator: Yaron <sh.yaron@gmail.com>\n"
1313"Language-Team: Hebrew <he@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr "בית"
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/hi.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-01-15 01:49+0000\n"
1212"Last-Translator: Siddhanathan Shanmugam <Unknown>\n"
1313"Language-Team: Hindi <hi@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/hr.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-05-04 17:52+0000\n"
1212"Last-Translator: gogo <trebelnik2@gmail.com>\n"
1313"Language-Team: Croatian <hr@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -262,7 +262,7 @@ msgstr "Naslovnica"
262262msgid "Also installed"
263263msgstr "Također instalirano"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
po/hu.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-03-24 09:19+0000\n"
1212"Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n"
1313"Language-Team: Hungarian <hu@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -260,7 +260,7 @@ msgstr "Kezdőlapon"
260260msgid "Also installed"
261261msgstr "Telepítve"
262262
263−#: qml/DisabledScreenNotice.qml:104
263+#: qml/DisabledScreenNotice.qml:109
264264msgid ""
265265"Your device is now connected to an external display. Use this screen as a "
266266"touch pad to interact with the pointer."
po/hy.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-10-28 06:34+0000\n"
1212"Last-Translator: Vahan Harutyunyan <Unknown>\n"
1313"Language-Team: Armenian <hy@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -260,7 +260,7 @@ msgstr ""
260260msgid "Also installed"
261261msgstr ""
262262
263−#: qml/DisabledScreenNotice.qml:104
263+#: qml/DisabledScreenNotice.qml:109
264264msgid ""
265265"Your device is now connected to an external display. Use this screen as a "
266266"touch pad to interact with the pointer."
po/ia.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-08-25 19:31+0000\n"
1212"Last-Translator: karm <melo@carmu.com>\n"
1313"Language-Team: Interlingua <ia@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -260,7 +260,7 @@ msgstr "A domo"
260260msgid "Also installed"
261261msgstr "Ja installate"
262262
263−#: qml/DisabledScreenNotice.qml:104
263+#: qml/DisabledScreenNotice.qml:109
264264msgid ""
265265"Your device is now connected to an external display. Use this screen as a "
266266"touch pad to interact with the pointer."
po/id.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-06-26 22:35+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Indonesian <id@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -259,7 +259,7 @@ msgstr "Beranda"
259259msgid "Also installed"
260260msgstr "Juga terpasang"
261261
262−#: qml/DisabledScreenNotice.qml:104
262+#: qml/DisabledScreenNotice.qml:109
263263msgid ""
264264"Your device is now connected to an external display. Use this screen as a "
265265"touch pad to interact with the pointer."
po/is.po+4−4
@@ -9,7 +9,7 @@ msgid ""
99msgstr ""
1010"Project-Id-Version: po_unity8-is\n"
1111"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
12−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
12+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1313"PO-Revision-Date: 2014-11-13 09:32+0000\n"
1414"Last-Translator: Sveinn í Felli <sv1@fellsnet.is>\n"
1515"Language-Team: Icelandic <translation-team-is@lists.sourceforge.net>\n"
@@ -17,8 +17,8 @@ msgstr ""
1717"Content-Type: text/plain; charset=UTF-8\n"
1818"Content-Transfer-Encoding: 8bit\n"
1919"Plural-Forms: nplurals=2; plural=n != 1;\n"
20−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
21−"X-Generator: Launchpad (build 18025)\n"
20+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
21+"X-Generator: Launchpad (build 18053)\n"
2222"Language: is\n"
2323
2424#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -265,7 +265,7 @@ msgstr ""
265265msgid "Also installed"
266266msgstr ""
267267
268−#: qml/DisabledScreenNotice.qml:104
268+#: qml/DisabledScreenNotice.qml:109
269269msgid ""
270270"Your device is now connected to an external display. Use this screen as a "
271271"touch pad to interact with the pointer."
po/it.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-04-03 16:08+0000\n"
1212"Last-Translator: Milo Casagrande <milo.casagrande@gmail.com>\n"
1313"Language-Team: Italian <it@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -264,7 +264,7 @@ msgstr "Home"
264264msgid "Also installed"
265265msgstr "Installato anche"
266266
267−#: qml/DisabledScreenNotice.qml:104
267+#: qml/DisabledScreenNotice.qml:109
268268msgid ""
269269"Your device is now connected to an external display. Use this screen as a "
270270"touch pad to interact with the pointer."
po/ja.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-10-05 10:05+0000\n"
1212"Last-Translator: Kentaro Kazuhama <Unknown>\n"
1313"Language-Team: Japanese <ja@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -255,7 +255,7 @@ msgstr ""
255255msgid "Also installed"
256256msgstr ""
257257
258−#: qml/DisabledScreenNotice.qml:104
258+#: qml/DisabledScreenNotice.qml:109
259259msgid ""
260260"Your device is now connected to an external display. Use this screen as a "
261261"touch pad to interact with the pointer."
po/km.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-08-20 02:48+0000\n"
1212"Last-Translator: Sophea Sok <sksophea@gmail.com>\n"
1313"Language-Team: Khmer <km@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr "ផ្ទះ"
258258msgid "Also installed"
259259msgstr ""
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/kn.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-06-27 05:43+0000\n"
1212"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Kannada <kn@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/ko.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-08-19 13:02+0000\n"
1212"Last-Translator: MinSik CHO <Unknown>\n"
1313"Language-Team: Korean <ko@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -255,7 +255,7 @@ msgstr "홈"
255255msgid "Also installed"
256256msgstr "설치함"
257257
258−#: qml/DisabledScreenNotice.qml:104
258+#: qml/DisabledScreenNotice.qml:109
259259msgid ""
260260"Your device is now connected to an external display. Use this screen as a "
261261"touch pad to interact with the pointer."
po/ku.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-09-10 13:14+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Kurdish <ku@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr ""
258258msgid "Also installed"
259259msgstr ""
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/ky.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-06-27 06:17+0000\n"
1212"Last-Translator: Michał Sawicz <michal.sawicz@canonical.com>\n"
1313"Language-Team: Kirghiz <ky@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/lo.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-10-02 10:00+0000\n"
1212"Last-Translator: Anousak <anousak@gmail.com>\n"
1313"Language-Team: Lao <lo@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/lt.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-05-19 17:15+0000\n"
1212"Last-Translator: Mantas Kriaučiūnas <mantas@akl.lt>\n"
1313"Language-Team: Lithuanian <lt@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"(n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -257,7 +257,7 @@ msgstr ""
257257msgid "Also installed"
258258msgstr ""
259259
260−#: qml/DisabledScreenNotice.qml:104
260+#: qml/DisabledScreenNotice.qml:109
261261msgid ""
262262"Your device is now connected to an external display. Use this screen as a "
263263"touch pad to interact with the pointer."
po/lv.po+4−4
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity\n"
1010"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
11−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
11+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1212"PO-Revision-Date: 2015-11-22 19:13+0000\n"
1313"Last-Translator: Klavs Anson <anson.klavs@gmail.com>\n"
1414"Language-Team: Latvian <lata-l10n@googlegroups.com>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Type: text/plain; charset=UTF-8\n"
1717"Content-Transfer-Encoding: 8bit\n"
1818"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121"Language: lv\n"
2222
2323#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -261,7 +261,7 @@ msgstr "Mājas"
261261msgid "Also installed"
262262msgstr "Arī instalēja"
263263
264−#: qml/DisabledScreenNotice.qml:104
264+#: qml/DisabledScreenNotice.qml:109
265265msgid ""
266266"Your device is now connected to an external display. Use this screen as a "
267267"touch pad to interact with the pointer."
po/ml.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-11-23 11:44+0000\n"
1212"Last-Translator: ST Alfas <Unknown>\n"
1313"Language-Team: Malayalam <ml@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/mr.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-01-14 19:54+0000\n"
1212"Last-Translator: Rohan Deshmukh <Unknown>\n"
1313"Language-Team: Marathi <mr@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/ms.po+94−73
@@ -7,16 +7,16 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
11−"PO-Revision-Date: 2014-01-17 09:05+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
11+"PO-Revision-Date: 2016-05-24 01:36+0000\n"
1212"Last-Translator: abuyop <Unknown>\n"
1313"Language-Team: Malay <ms@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -125,7 +125,7 @@ msgstr "Kembali ke Panggilan"
125125
126126#: qml/Components/Lockscreen.qml:231
127127msgid "Emergency Call"
128−msgstr "panggilan Kecemasan"
128+msgstr "Panggilan Kecemasan"
129129
130130#: qml/Components/Lockscreen.qml:263
131131msgid "OK"
@@ -139,7 +139,7 @@ msgstr "Apl mungkin mempunyai data tidak disimpan:"
139139msgctxt ""
140140"Re-dock means connect the device again to an external screen/mouse/keyboard"
141141msgid "Re-dock, save your work and close these apps to continue."
142−msgstr ""
142+msgstr "Labuh-semula, simpan kerja anda dan tutup apl ini untuk teruskan."
143143
144144#: qml/Components/ModeSwitchWarningDialog.qml:63
145145msgid "Or force close now (unsaved data will be lost)."
@@ -182,19 +182,19 @@ msgstr "Tambah ke Kegemaran"
182182
183183#: qml/Dash/FiltersPopover.qml:60
184184msgid "Refine your results"
185−msgstr ""
185+msgstr "Takrif keputusan anda"
186186
187187#: qml/Dash/FiltersPopover.qml:69
188188msgid "Reset"
189−msgstr ""
189+msgstr "Tetap Semula"
190190
191191#: qml/Dash/GenericScopeView.qml:579 qml/Dash/GenericScopeView.qml:764
192192msgid "Show less"
193−msgstr ""
193+msgstr "Tunjuk sedikit"
194194
195195#: qml/Dash/GenericScopeView.qml:579
196196msgid "Show all"
197−msgstr ""
197+msgstr "Tunjuk semua"
198198
199199#: qml/Dash/GenericScopeView.qml:636
200200msgctxt "Label: Hint for dash search line edit"
@@ -203,11 +203,11 @@ msgstr "Gelintar"
203203
204204#: qml/Dash/PageHeaderExtraPanel.qml:55
205205msgid "Recent Searches"
206−msgstr ""
206+msgstr "Gelintar Baru-baru Ini"
207207
208208#: qml/Dash/PageHeaderExtraPanel.qml:66
209209msgid "Clear All"
210−msgstr ""
210+msgstr "Kosongkan Semua"
211211
212212#: qml/Dash/Previews/PreviewActionCombo.qml:35
213213msgid "More..."
@@ -258,11 +258,13 @@ msgstr "Rumah"
258258msgid "Also installed"
259259msgstr "Juga dipasang"
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
265265msgstr ""
266+"Peranti anda kini bersambung dengan paparan luar. Guna skrin ini sebagai pad "
267+"sentuh untuk berinteraksi dengan penuding."
266268
267269#: qml/Greeter/CoverPage.qml:118
268270msgid "Unlock"
@@ -392,7 +394,7 @@ msgstr "Memuat turun"
392394
393395#: qml/Panel/Indicators/MenuItemFactory.qml:917
394396msgid "Paused, tap to resume"
395−msgstr "Dijeda, ketuk untuk sambung semula"
397+msgstr "Dijeda, ketik untuk sambung semula"
396398
397399#: qml/Panel/Indicators/MenuItemFactory.qml:919
398400msgid "Canceled"
@@ -404,7 +406,7 @@ msgstr "Selesai"
404406
405407#: qml/Panel/Indicators/MenuItemFactory.qml:923
406408msgid "Failed, tap to retry"
407−msgstr "Gagal, ketuk untuk cuba lagi"
409+msgstr "Gagal, ketik untuk cuba lagi"
408410
409411#: qml/Panel/Indicators/MessageMenuItemFactory.qml:155
410412#: qml/Panel/Indicators/MessageMenuItemFactory.qml:214
@@ -425,50 +427,56 @@ msgstr "Panggilan semula"
425427#: qml/Stages/SideStage.qml:76
426428msgid "Drag using 3 fingers any application from one window to the other"
427429msgstr ""
430+"Seret menggunakan 3 jari pada mana-mana aplik dari satu tetingkap ke "
431+"tetingkap yang lain"
428432
429433#: qml/Tutorial/TutorialBottom.qml:78
430434msgid "Swipe up to add a contact"
431−msgstr ""
435+msgstr "Leret ke atas untuk menambah kenalan"
432436
433437#: qml/Tutorial/TutorialBottom.qml:80
434438msgid "Swipe up for favorite calculations"
435−msgstr ""
439+msgstr "Leret ke atas untuk pengiraan kegemaran"
436440
437441#: qml/Tutorial/TutorialBottom.qml:82
438442msgid "Swipe up for recent calls"
439−msgstr ""
443+msgstr "Leret ke atas untuk panggilan baru-baru ini"
440444
441445#: qml/Tutorial/TutorialBottom.qml:84
442446msgid "Swipe up to create a message"
443−msgstr ""
447+msgstr "Leret ke atas untuk cipta satu mesej"
444448
445449#: qml/Tutorial/TutorialBottom.qml:85
446450msgid "Swipe up to manage the app"
447−msgstr ""
451+msgstr "Leret ke atas untuk mengurus apl"
448452
449453#: qml/Tutorial/TutorialLeftLong.qml:47
450454msgid "Long swipe from the left edge to open the Today scope"
451−msgstr ""
455+msgstr "Leret panjang dari pinggir kiri untuk membuka skop Hari Ini"
452456
453457#: qml/Tutorial/TutorialLeft.qml:47
454458msgid "Swipe from the left edge to open the launcher"
455−msgstr ""
459+msgstr "Leret dari pinggir kiri untuk membuka pelancar"
456460
457461#: qml/Tutorial/TutorialRight.qml:55
458462msgid "Push your mouse against the right edge to view your open apps"
459463msgstr ""
464+"Tolak penuding tetikus anda ke pinggir kanan untuk melihat apl yang telah "
465+"dibuka"
460466
461467#: qml/Tutorial/TutorialRight.qml:56
462468msgid "Short or long swipe from the right edge to view your open apps"
463469msgstr ""
470+"Leret pendek atau panjang dari pinggir kanan untuk melihat apl yang telah "
471+"dibuka"
464472
465473#: qml/Tutorial/TutorialTop.qml:53
466474msgid "Swipe from the top right edge to open the notification bar"
467−msgstr ""
475+msgstr "Leret dari pinggir kanan atas untuk membuka palang pemberitahuan"
468476
469477#: qml/Tutorial/TutorialTop.qml:54
470478msgid "Swipe from the top edge to open the notification bar"
471−msgstr ""
479+msgstr "Leret dari pinggir atas untuk membuka palang pemberitahuan"
472480
473481#: qml/Wizard/Page.qml:54
474482msgctxt "Button: Go back one page in the Wizard"
@@ -477,7 +485,7 @@ msgstr "Kembali"
477485
478486#: qml/Wizard/Pages/10-welcome.qml:27
479487msgid "Language"
480−msgstr ""
488+msgstr "Bahasa"
481489
482490#: qml/Wizard/Pages/10-welcome.qml:156 qml/Wizard/Pages/30-wifi.qml:206
483491#: qml/Wizard/Pages/40-location.qml:271 qml/Wizard/Pages/50-timezone.qml:267
@@ -486,7 +494,7 @@ msgstr ""
486494#: qml/Wizard/Pages/passcode-desktop.qml:124
487495#: qml/Wizard/Pages/password-set.qml:141
488496msgid "Next"
489−msgstr ""
497+msgstr "Berikutnya"
490498
491499#: qml/Wizard/Pages/30-wifi.qml:29
492500msgid "Connect to Wi‑Fi"
@@ -494,15 +502,15 @@ msgstr "Sambung ke Wi-Fi"
494502
495503#: qml/Wizard/Pages/30-wifi.qml:130
496504msgid "Connected"
497−msgstr ""
505+msgstr "Bersambung"
498506
499507#: qml/Wizard/Pages/30-wifi.qml:163
500508msgid "Available Wi-Fi networks"
501−msgstr ""
509+msgstr "Rangkaian Wi-Fi tersedia"
502510
503511#: qml/Wizard/Pages/30-wifi.qml:164
504512msgid "No available Wi-Fi networks"
505−msgstr ""
513+msgstr "Tiada rangkaian Wi-Fi tersedia"
506514
507515#: qml/Wizard/Pages/30-wifi.qml:206 qml/Wizard/Pages/60-account.qml:65
508516#: qml/Wizard/Pages/sim.qml:101
@@ -511,98 +519,101 @@ msgstr "Langkau"
511519
512520#: qml/Wizard/Pages/40-location.qml:27
513521msgid "Location Services"
514−msgstr ""
522+msgstr "Perkhidmatan Lokasi"
515523
516524#: qml/Wizard/Pages/40-location.qml:83
517525msgid ""
518526"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
519527"(recommended)"
520528msgstr ""
529+"Guna GPS, hotspot Wi-Fi dan rangkaian mudah alih secara awanama untuk "
530+"mengesan lokasi (disarankan)"
521531
522532#: qml/Wizard/Pages/40-location.qml:105
523533#, qt-format
524534msgid "By selecting this option you agree to the Nokia HERE %1."
525−msgstr ""
535+msgstr "Dengan memilih pilihan ini anda bersetuju dengan Nokia HERE %1."
526536
527537#: qml/Wizard/Pages/40-location.qml:106
528538msgctxt "part of: Nokia HERE terms and conditions"
529539msgid "terms and conditions"
530−msgstr ""
540+msgstr "terma dan syarat"
531541
532542#: qml/Wizard/Pages/40-location.qml:160
533543msgid "GPS only"
534−msgstr ""
544+msgstr "GPS sahaja"
535545
536546#: qml/Wizard/Pages/40-location.qml:214
537547msgid "Don't use my location"
538−msgstr ""
548+msgstr "Jangan guna lokasi saya"
539549
540550#: qml/Wizard/Pages/40-location.qml:260
541551msgid "You can change it later in System Settings."
542−msgstr ""
552+msgstr "Anda boleh mengubahnya kemudian di dalam Tetapan Sistem."
543553
544554#: qml/Wizard/Pages/50-timezone.qml:29
545555msgid "Time Zone"
546−msgstr ""
556+msgstr "Zon Waktu"
547557
548558#: qml/Wizard/Pages/50-timezone.qml:178
549559msgid "Enter your city"
550−msgstr ""
560+msgstr "Masukkan bandar anda"
551561
552562#: qml/Wizard/Pages/60-account.qml:24
553563msgid "Personalize Your Device"
554−msgstr ""
564+msgstr "Peribadikan Peranti Anda"
555565
556566#: qml/Wizard/Pages/60-account.qml:48
557567msgid "Preferred Name"
558−msgstr ""
568+msgstr "Nama Digemari"
559569
560570#: qml/Wizard/Pages/70-passwd-type.qml:39
561571msgid "Lock Screen"
562−msgstr ""
572+msgstr "Skrin Kunci"
563573
564574#: qml/Wizard/Pages/70-passwd-type.qml:101
565575msgctxt "Label: Type of security method"
566576msgid "Create new password"
567−msgstr ""
577+msgstr "Cipta kata laluan baharu"
568578
569579#: qml/Wizard/Pages/70-passwd-type.qml:103
570580msgctxt "Label: Type of security method"
571581msgid "Create passcode (numbers only)"
572−msgstr ""
582+msgstr "Cipta kod laluan (nombor sahaja)"
573583
574584#: qml/Wizard/Pages/70-passwd-type.qml:105
575585msgctxt "Label: Type of security method"
576586msgid "No lock code"
577−msgstr ""
587+msgstr "Tiada kod kunci"
578588
579589#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
580590msgid "Privacy Policy"
581−msgstr ""
591+msgstr "Dasar Kerahsiaan"
582592
583593#: qml/Wizard/Pages/75-report-check.qml:26
584594msgid "Help Us Improve"
585−msgstr ""
595+msgstr "Bantu Kami"
586596
587597#: qml/Wizard/Pages/75-report-check.qml:59
588598msgid "Improve system performance by sending us crashes and error reports."
589599msgstr ""
600+"Tambah baik prestasi sistem dengan menghantar laporan kerosakan dan ralat."
590601
591602#: qml/Wizard/Pages/75-report-check.qml:60
592603msgid "Privacy policy"
593−msgstr ""
604+msgstr "Dasar kerahsiaan"
594605
595606#: qml/Wizard/Pages/80-finished.qml:89
596607msgid "Welcome to Ubuntu"
597−msgstr ""
608+msgstr "Selamat datang ke Ubuntu"
598609
599610#: qml/Wizard/Pages/80-finished.qml:104
600611msgid "You are ready to use your device now"
601−msgstr ""
612+msgstr "Anda boleh gunakan peranti sekarang"
602613
603614#: qml/Wizard/Pages/80-finished.qml:124
604615msgid "Get Started"
605−msgstr ""
616+msgstr "Membiasakan Diri"
606617
607618#: qml/Wizard/Pages/here-terms.qml:25
608619msgid "Terms & Conditions"
@@ -611,6 +622,8 @@ msgstr "Terma & Syarat"
611622#: qml/Wizard/Pages/here-terms.qml:69
612623msgid "Your device uses positioning technologies provided by HERE."
613624msgstr ""
625+"Peranti anda menggunakan teknologi menentukan lokasi yang disediakan oleh "
626+"HERE."
614627
615628#: qml/Wizard/Pages/here-terms.qml:81
616629msgid ""
@@ -618,21 +631,27 @@ msgid ""
618631"collects information about nearby cell towers and Wi-Fi hotspots around your "
619632"current location whenever your position is being found."
620633msgstr ""
634+"Untuk menyediakan perkhidmatan penentuan lokasi dan menambahbaik kualiti, "
635+"HERE mengutip maklumat berkenaan menara telekomunikasi berhampiran dan "
636+"hotspot Wi-Fi disekitar anda bilamana kedudukan anda ditemui."
621637
622638#: qml/Wizard/Pages/here-terms.qml:93
623639msgid ""
624640"The information collected is used to analyze the service and to improve the "
625641"use of service, but not to identify you personally."
626642msgstr ""
643+"Maklumat tersebut digunakan untuk menganalisis perkhidmatan dan menambahbaik "
644+"penggunaan perkhidmatan, walaubagaimanapun tidak mengenalpasti anda secara "
645+"peribadi."
627646
628647#: qml/Wizard/Pages/here-terms.qml:106
629648#, qt-format
630649msgid "By continuing, you agree to the HERE platform %1 and %2."
631−msgstr ""
650+msgstr "Jika diteruskan, anda menyetujui HERE platform %1 dan %2."
632651
633652#: qml/Wizard/Pages/here-terms.qml:107
634653msgid "Service Terms"
635−msgstr ""
654+msgstr "Terma Perkhidmatan"
636655
637656#: qml/Wizard/Pages/passcode-confirm.qml:43
638657#: qml/Wizard/Pages/passcode-desktop.qml:80
@@ -641,69 +660,70 @@ msgstr "Sahkan kod laluan"
641660
642661#: qml/Wizard/Pages/passcode-confirm.qml:45
643662msgid "Incorrect passcode."
644−msgstr ""
663+msgstr "Kod laluan tidak betul."
645664
646665#: qml/Wizard/Pages/passcode-confirm.qml:45
647666msgctxt "Enter the passcode again"
648667msgid "Please re-enter."
649−msgstr ""
668+msgstr "Sila masukkan sekali lagi."
650669
651670#: qml/Wizard/Pages/passcode-desktop.qml:30
652671msgid "Lock Screen Passcode"
653−msgstr ""
672+msgstr "Kod Laluan Skrin Kunci"
654673
655674#: qml/Wizard/Pages/passcode-desktop.qml:56
656675msgid "Enter 4 numbers to setup your passcode"
657−msgstr ""
676+msgstr "Masukkan 4 nombor untuk persediaan kod laluan anda"
658677
659678#: qml/Wizard/Pages/passcode-desktop.qml:65
660679#: qml/Wizard/Pages/passcode-set.qml:54
661680msgid "Choose passcode"
662−msgstr ""
681+msgstr "Pilih kod laluan"
663682
664683#: qml/Wizard/Pages/passcode-desktop.qml:105
665684msgid "Passcode too short"
666−msgstr ""
685+msgstr "Kod laluan terlalu pendek"
667686
668687#: qml/Wizard/Pages/passcode-desktop.qml:107
669688msgid "Passcodes match"
670−msgstr ""
689+msgstr "Kod laluan sepadan"
671690
672691#: qml/Wizard/Pages/passcode-desktop.qml:109
673692msgid "Passcodes do not match"
674−msgstr ""
693+msgstr "Kod laluan tidak sepadan"
675694
676695#: qml/Wizard/Pages/passcode-set.qml:62
677696msgid "Passcode must be 4 characters long"
678−msgstr ""
697+msgstr "Kod laluan mestilah 4 aksara panjang"
679698
680699#: qml/Wizard/Pages/password-set.qml:30
681700msgid "Lock Screen Password"
682−msgstr ""
701+msgstr "Kata Laluan Skrin Kunci"
683702
684703#: qml/Wizard/Pages/password-set.qml:61
685704msgid "Enter at least 8 characters"
686−msgstr ""
705+msgstr "Masukkan sekurang-kurangnya 8 aksara"
687706
688707#: qml/Wizard/Pages/password-set.qml:73
689708msgid "Choose password"
690−msgstr ""
709+msgstr "Pilih kata laluan"
691710
692711#: qml/Wizard/Pages/password-set.qml:103
693712msgid "Confirm password"
694−msgstr ""
713+msgstr "Sahkan kata laluan"
695714
696715#: qml/Wizard/Pages/sim.qml:27
697716msgid "No SIM card installed"
698−msgstr ""
717+msgstr "Tiada kad SIM terpasang"
699718
700719#: qml/Wizard/Pages/sim.qml:54
701720msgid "SIM card added"
702−msgstr ""
721+msgstr "Kad SIM ditambah"
703722
704723#: qml/Wizard/Pages/sim.qml:55
705724msgid "You must restart the device to access the mobile network."
706725msgstr ""
726+"Anda mesti mulakan semula peranti supaya dapat mencapai rangkaian mudah alih."
707727
708728#: qml/Wizard/Pages/sim.qml:59
709729msgid "Restart"
@@ -712,34 +732,35 @@ msgstr "Mula Semula"
712732#: qml/Wizard/Pages/sim.qml:78
713733msgid "You won’t be able to make calls or use text messaging without a SIM."
714734msgstr ""
735+"Anda tidak dapat membuat panggilan atau guna pemesejan teks tanpa SIM."
715736
716737#: qml/Wizard/Pages/sim.qml:90
717738msgid "To proceed with no SIM tap Skip."
718−msgstr ""
739+msgstr "Untuk teruskan tanpa SIM ketik Langkau."
719740
720741#: qml/Wizard/PasswordMeter.qml:87
721742msgid "Passwords match"
722−msgstr ""
743+msgstr "Kata laluan sepadan"
723744
724745#: qml/Wizard/PasswordMeter.qml:89
725746msgid "Passwords do not match"
726−msgstr ""
747+msgstr "Kata laluan tidak sepadan"
727748
728749#: qml/Wizard/PasswordMeter.qml:93
729750msgid "Strong password"
730−msgstr ""
751+msgstr "Kata laluan kuat"
731752
732753#: qml/Wizard/PasswordMeter.qml:95
733754msgid "Fair password"
734−msgstr ""
755+msgstr "Kata laluan sederhana"
735756
736757#: qml/Wizard/PasswordMeter.qml:97
737758msgid "Weak password"
738−msgstr ""
759+msgstr "Kata laluan lemah"
739760
740761#: qml/Wizard/PasswordMeter.qml:99
741762msgid "Very weak password"
742−msgstr ""
763+msgstr "Kata laluan sangat lemah"
743764
744765#~ msgid "Top edge"
745766#~ msgstr "Pinggir atas"
po/my.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-12-12 11:12+0000\n"
1212"Last-Translator: Pyae Sone <Unknown>\n"
1313"Language-Team: Burmese <my@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr "ပင်မ"
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/nb.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-03-29 08:56+0000\n"
1212"Last-Translator: Åka Sikrom <Unknown>\n"
1313"Language-Team: Norwegian Bokmal <nb@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -262,7 +262,7 @@ msgstr "Hjem"
262262msgid "Also installed"
263263msgstr "Også installert"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
po/ne.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-12-06 15:11+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Nepali <ne@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/nl.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-07 07:14+0000\n"
1212"Last-Translator: Hannie Dumoleyn <Unknown>\n"
1313"Language-Team: Dutch <nl@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -265,7 +265,7 @@ msgstr "Thuis"
265265msgid "Also installed"
266266msgstr "Ook geïnstalleerd"
267267
268−#: qml/DisabledScreenNotice.qml:104
268+#: qml/DisabledScreenNotice.qml:109
269269msgid ""
270270"Your device is now connected to an external display. Use this screen as a "
271271"touch pad to interact with the pointer."
po/nn.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-05-12 11:32+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Norwegian Nynorsk <nn@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/oc.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-02-05 20:35+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Occitan (post 1500) <oc@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -265,7 +265,7 @@ msgstr "Acuèlh"
265265msgid "Also installed"
266266msgstr "Tanben installadas"
267267
268−#: qml/DisabledScreenNotice.qml:104
268+#: qml/DisabledScreenNotice.qml:109
269269msgid ""
270270"Your device is now connected to an external display. Use this screen as a "
271271"touch pad to interact with the pointer."
po/or.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-03-21 05:28+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Oriya <or@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n!=1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/pa.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-04-24 04:29+0000\n"
1212"Last-Translator: Gursharnjit_Singh <ubuntuser13@gmail.com>\n"
1313"Language-Team: Punjabi <pa@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr "ਘਰ"
258258msgid "Also installed"
259259msgstr "ਨਾਲ ਇੰਸਟਾਲ ਹੋਇਆ"
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/pl.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-05-05 13:36+0000\n"
1212"Last-Translator: dawidd6 <dawidd0811@gmail.com>\n"
1313"Language-Team: Polish <pl@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
1818"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -259,7 +259,7 @@ msgstr "Pulpit"
259259msgid "Also installed"
260260msgstr "Również zainstalowane"
261261
262−#: qml/DisabledScreenNotice.qml:104
262+#: qml/DisabledScreenNotice.qml:109
263263msgid ""
264264"Your device is now connected to an external display. Use this screen as a "
265265"touch pad to interact with the pointer."
po/pt.po+7−7
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-02-18 01:11+0000\n"
1212"Last-Translator: Ivo Xavier <ivoxavier.8@gmail.com>\n"
1313"Language-Team: Portuguese <pt@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Página inicial"
263263msgid "Also installed"
264264msgstr "Também instalado"
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
@@ -300,8 +300,8 @@ msgid ""
300300"If passphrase is entered incorrectly, your phone will conduct a factory "
301301"reset and all personal data will be deleted."
302302msgstr ""
303−"Se a palavra-passe for introduzida incorretamente, o seu telemóvel apagará "
304−"toda a sua informação pessoal."
303+"Se a palavra-passe for introduzida incorretamente, a sua informação pessoal "
304+"será eliminada."
305305
306306#: qml/Greeter/NarrowView.qml:59
307307msgid ""
@@ -309,7 +309,7 @@ msgid ""
309309"and all personal data will be deleted."
310310msgstr ""
311311"Se o código for introduzido incorretamente, todos os dados pessoais serão "
312−"apagados."
312+"eliminados"
313313
314314#: qml/Greeter/NarrowView.qml:116
315315#, qt-format
po/pt_BR.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-08-05 04:40+0000\n"
1212"Last-Translator: Julio Alexander Sieg <julio.sieg@gmail.com>\n"
1313"Language-Team: Brazilian Portuguese <pt_BR@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -260,7 +260,7 @@ msgstr "Início"
260260msgid "Also installed"
261261msgstr "Instalado também"
262262
263−#: qml/DisabledScreenNotice.qml:104
263+#: qml/DisabledScreenNotice.qml:109
264264msgid ""
265265"Your device is now connected to an external display. Use this screen as a "
266266"touch pad to interact with the pointer."
po/ro.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-06 17:47+0000\n"
1212"Last-Translator: Meriuță Cornel <meriutacornel@neacornel.eu>\n"
1313"Language-Team: Romanian <ro@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
1818"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Acasă"
263263msgid "Also installed"
264264msgstr "Alte programe instalate"
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
po/ru.po+30−26
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-06 05:33+0000\n"
1212"Last-Translator: ☠Jay ZDLin☠ <Unknown>\n"
1313"Language-Team: Russian <ru@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -186,7 +186,7 @@ msgstr "Добавить в избранное"
186186
187187#: qml/Dash/FiltersPopover.qml:60
188188msgid "Refine your results"
189−msgstr ""
189+msgstr "Уточнить результаты"
190190
191191#: qml/Dash/FiltersPopover.qml:69
192192msgid "Reset"
@@ -262,7 +262,7 @@ msgstr "Домой"
262262msgid "Also installed"
263263msgstr "Также установлено"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
@@ -507,11 +507,11 @@ msgstr "Подключено"
507507
508508#: qml/Wizard/Pages/30-wifi.qml:163
509509msgid "Available Wi-Fi networks"
510−msgstr ""
510+msgstr "Доступные Wi-Fi сети"
511511
512512#: qml/Wizard/Pages/30-wifi.qml:164
513513msgid "No available Wi-Fi networks"
514−msgstr ""
514+msgstr "Нет доступных Wi-Fi сетей"
515515
516516#: qml/Wizard/Pages/30-wifi.qml:206 qml/Wizard/Pages/60-account.qml:65
517517#: qml/Wizard/Pages/sim.qml:101
@@ -520,13 +520,15 @@ msgstr "Пропустить"
520520
521521#: qml/Wizard/Pages/40-location.qml:27
522522msgid "Location Services"
523−msgstr ""
523+msgstr "Службы геолокации"
524524
525525#: qml/Wizard/Pages/40-location.qml:83
526526msgid ""
527527"Use GPS, Wi-Fi hotspots and mobile network anonymously to detect location "
528528"(recommended)"
529529msgstr ""
530+"Использовать анонимно GPS, точки доступа Wi-Fi и мобильную сеть для "
531+"определения местоположения (рекомендуется)"
530532
531533#: qml/Wizard/Pages/40-location.qml:105
532534#, qt-format
@@ -536,7 +538,7 @@ msgstr ""
536538#: qml/Wizard/Pages/40-location.qml:106
537539msgctxt "part of: Nokia HERE terms and conditions"
538540msgid "terms and conditions"
539−msgstr ""
541+msgstr "условия и соглашения"
540542
541543#: qml/Wizard/Pages/40-location.qml:160
542544msgid "GPS only"
@@ -564,11 +566,11 @@ msgstr ""
564566
565567#: qml/Wizard/Pages/60-account.qml:48
566568msgid "Preferred Name"
567−msgstr ""
569+msgstr "Предпочитаемое имя"
568570
569571#: qml/Wizard/Pages/70-passwd-type.qml:39
570572msgid "Lock Screen"
571−msgstr ""
573+msgstr "Заблокировать экран"
572574
573575#: qml/Wizard/Pages/70-passwd-type.qml:101
574576msgctxt "Label: Type of security method"
@@ -578,16 +580,16 @@ msgstr "Создать новый пароль"
578580#: qml/Wizard/Pages/70-passwd-type.qml:103
579581msgctxt "Label: Type of security method"
580582msgid "Create passcode (numbers only)"
581−msgstr ""
583+msgstr "Создать парольный код (только цифры)"
582584
583585#: qml/Wizard/Pages/70-passwd-type.qml:105
584586msgctxt "Label: Type of security method"
585587msgid "No lock code"
586−msgstr ""
588+msgstr "Без кода разблокировки"
587589
588590#: qml/Wizard/Pages/75-report-check.qml:26 qml/Wizard/Pages/here-terms.qml:108
589591msgid "Privacy Policy"
590−msgstr ""
592+msgstr "Политика конфиденциальности"
591593
592594#: qml/Wizard/Pages/75-report-check.qml:26
593595msgid "Help Us Improve"
@@ -599,7 +601,7 @@ msgstr ""
599601
600602#: qml/Wizard/Pages/75-report-check.qml:60
601603msgid "Privacy policy"
602−msgstr ""
604+msgstr "Политика конфиденциальности"
603605
604606#: qml/Wizard/Pages/80-finished.qml:89
605607msgid "Welcome to Ubuntu"
@@ -607,11 +609,11 @@ msgstr "Добро пожаловать в Ubuntu"
607609
608610#: qml/Wizard/Pages/80-finished.qml:104
609611msgid "You are ready to use your device now"
610−msgstr ""
612+msgstr "Теперь устройство готово к использованию"
611613
612614#: qml/Wizard/Pages/80-finished.qml:124
613615msgid "Get Started"
614−msgstr ""
616+msgstr "Приступая к работе"
615617
616618#: qml/Wizard/Pages/here-terms.qml:25
617619msgid "Terms & Conditions"
@@ -619,7 +621,7 @@ msgstr "Условия использования"
619621
620622#: qml/Wizard/Pages/here-terms.qml:69
621623msgid "Your device uses positioning technologies provided by HERE."
622−msgstr ""
624+msgstr "Ваше устройство использует HERE для определения местоположения"
623625
624626#: qml/Wizard/Pages/here-terms.qml:81
625627msgid ""
@@ -633,6 +635,8 @@ msgid ""
633635"The information collected is used to analyze the service and to improve the "
634636"use of service, but not to identify you personally."
635637msgstr ""
638+"Собираемая информация используется для анализа и улучшения сервиса, а не для "
639+"идентификации вашей личности."
636640
637641#: qml/Wizard/Pages/here-terms.qml:106
638642#, qt-format
@@ -659,11 +663,11 @@ msgstr "Введите заново."
659663
660664#: qml/Wizard/Pages/passcode-desktop.qml:30
661665msgid "Lock Screen Passcode"
662−msgstr ""
666+msgstr "Код блокировки экрана"
663667
664668#: qml/Wizard/Pages/passcode-desktop.qml:56
665669msgid "Enter 4 numbers to setup your passcode"
666−msgstr ""
670+msgstr "Введите код блокировки из 4 цифр"
667671
668672#: qml/Wizard/Pages/passcode-desktop.qml:65
669673#: qml/Wizard/Pages/passcode-set.qml:54
@@ -672,15 +676,15 @@ msgstr ""
672676
673677#: qml/Wizard/Pages/passcode-desktop.qml:105
674678msgid "Passcode too short"
675−msgstr ""
679+msgstr "Код слишком короткий"
676680
677681#: qml/Wizard/Pages/passcode-desktop.qml:107
678682msgid "Passcodes match"
679−msgstr ""
683+msgstr "Коды совпадают"
680684
681685#: qml/Wizard/Pages/passcode-desktop.qml:109
682686msgid "Passcodes do not match"
683−msgstr ""
687+msgstr "Коды не совпадают"
684688
685689#: qml/Wizard/Pages/passcode-set.qml:62
686690msgid "Passcode must be 4 characters long"
@@ -688,7 +692,7 @@ msgstr "Код должен содержать 4 символа"
688692
689693#: qml/Wizard/Pages/password-set.qml:30
690694msgid "Lock Screen Password"
691−msgstr ""
695+msgstr "Пароль блокировки экрана"
692696
693697#: qml/Wizard/Pages/password-set.qml:61
694698msgid "Enter at least 8 characters"
@@ -737,11 +741,11 @@ msgstr "Пароли не совпадают"
737741
738742#: qml/Wizard/PasswordMeter.qml:93
739743msgid "Strong password"
740−msgstr ""
744+msgstr "Сильный пароль"
741745
742746#: qml/Wizard/PasswordMeter.qml:95
743747msgid "Fair password"
744−msgstr ""
748+msgstr "Неплохой пароль"
745749
746750#: qml/Wizard/PasswordMeter.qml:97
747751msgid "Weak password"
po/shn.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-11-10 12:09+0000\n"
1212"Last-Translator: Rockworld <sumoisrock@gmail.com>\n"
1313"Language-Team: Shan <shn@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=(n == 1) ? 0 : 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/si.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-06-26 22:36+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Sinhalese <si@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr ""
258258msgid "Also installed"
259259msgstr ""
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/sk.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-05-02 10:43+0000\n"
1212"Last-Translator: P_E_T_O <Unknown>\n"
1313"Language-Team: Slovak <sk@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020"Language: sk\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -265,7 +265,7 @@ msgstr "Domov"
265265msgid "Also installed"
266266msgstr "Tiež nainštalované"
267267
268−#: qml/DisabledScreenNotice.qml:104
268+#: qml/DisabledScreenNotice.qml:109
269269msgid ""
270270"Your device is now connected to an external display. Use this screen as a "
271271"touch pad to interact with the pointer."
po/sl.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-01-31 18:34+0000\n"
1212"Last-Translator: Bernard Banko <Unknown>\n"
1313"Language-Team: Slovenian <sl@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
1818"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -263,7 +263,7 @@ msgstr "Domov"
263263msgid "Also installed"
264264msgstr "Tudi nameščeno"
265265
266−#: qml/DisabledScreenNotice.qml:104
266+#: qml/DisabledScreenNotice.qml:109
267267msgid ""
268268"Your device is now connected to an external display. Use this screen as a "
269269"touch pad to interact with the pointer."
po/sq.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-04-21 06:03+0000\n"
1212"Last-Translator: Indrit Bashkimi <indrit.bashkimi@gmail.com>\n"
1313"Language-Team: sq\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:49+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:08+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020"Language: sq\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -257,7 +257,7 @@ msgstr "Shtëpia"
257257msgid "Also installed"
258258msgstr ""
259259
260−#: qml/DisabledScreenNotice.qml:104
260+#: qml/DisabledScreenNotice.qml:109
261261msgid ""
262262"Your device is now connected to an external display. Use this screen as a "
263263"touch pad to interact with the pointer."
po/sr.po+4−4
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity\n"
1010"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
11−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
11+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1212"PO-Revision-Date: 2016-05-04 19:50+0000\n"
1313"Last-Translator: Bojan Bogdanović <Unknown>\n"
1414"Language-Team: српски <xfce4@xfce4.org>\n"
@@ -17,8 +17,8 @@ msgstr ""
1717"Content-Transfer-Encoding: 8bit\n"
1818"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1919"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
20−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
21−"X-Generator: Launchpad (build 18025)\n"
20+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
21+"X-Generator: Launchpad (build 18053)\n"
2222"Language: sr\n"
2323
2424#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -262,7 +262,7 @@ msgstr "Почетна"
262262msgid "Also installed"
263263msgstr "Такође инсталиран"
264264
265−#: qml/DisabledScreenNotice.qml:104
265+#: qml/DisabledScreenNotice.qml:109
266266msgid ""
267267"Your device is now connected to an external display. Use this screen as a "
268268"touch pad to interact with the pointer."
po/sv.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-03-25 05:01+0000\n"
1212"Last-Translator: Josef Andersson <Unknown>\n"
1313"Language-Team: Swedish\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020"Language: sv\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -260,7 +260,7 @@ msgstr "Hem"
260260msgid "Also installed"
261261msgstr "Även installerat"
262262
263−#: qml/DisabledScreenNotice.qml:104
263+#: qml/DisabledScreenNotice.qml:109
264264msgid ""
265265"Your device is now connected to an external display. Use this screen as a "
266266"touch pad to interact with the pointer."
po/sw.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-17 20:02+0000\n"
1212"Last-Translator: Valentine <mwangi_valentino@yahoo.com>\n"
1313"Language-Team: Swahili <sw@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -258,7 +258,7 @@ msgstr "Nyumbani"
258258msgid "Also installed"
259259msgstr ""
260260
261−#: qml/DisabledScreenNotice.qml:104
261+#: qml/DisabledScreenNotice.qml:109
262262msgid ""
263263"Your device is now connected to an external display. Use this screen as a "
264264"touch pad to interact with the pointer."
po/ta.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-10-24 11:36+0000\n"
1212"Last-Translator: Arun Kumar - அருண் குமார் <thangam.arunx@gmail.com>\n"
1313"Language-Team: Ubuntu Tamil Team/Free Tamil Computing/Thamizha\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020"Language: ta\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -257,7 +257,7 @@ msgstr ""
257257msgid "Also installed"
258258msgstr ""
259259
260−#: qml/DisabledScreenNotice.qml:104
260+#: qml/DisabledScreenNotice.qml:109
261261msgid ""
262262"Your device is now connected to an external display. Use this screen as a "
263263"touch pad to interact with the pointer."
po/te.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-07-19 10:04+0000\n"
1212"Last-Translator: Praveen Illa <mail2ipn@gmail.com>\n"
1313"Language-Team: Telugu <te@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/th.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-10-02 04:55+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Thai <th@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/tr.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-03-22 15:56+0000\n"
1212"Last-Translator: Arda Ünlü <aarda.uunlu@gmail.com>\n"
1313"Language-Team: Turkish <tr@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr "Ev"
256256msgid "Also installed"
257257msgstr "Ayrıca kurulan"
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/ug.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-12-01 07:37+0000\n"
1212"Last-Translator: Eltikin <eltikinuyghur@hotmail.com>\n"
1313"Language-Team: Uyghur Computer Science Association <UKIJ@yahoogroups.com>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -257,7 +257,7 @@ msgstr "ماكان"
257257msgid "Also installed"
258258msgstr "قايتىدىن ئورنات"
259259
260−#: qml/DisabledScreenNotice.qml:104
260+#: qml/DisabledScreenNotice.qml:109
261261msgid ""
262262"Your device is now connected to an external display. Use this screen as a "
263263"touch pad to interact with the pointer."
po/uk.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-04-01 17:32+0000\n"
1212"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
1313"Language-Team: Ukrainian <uk@li.org>\n"
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
20−"X-Generator: Launchpad (build 18025)\n"
19+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
20+"X-Generator: Launchpad (build 18053)\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
2323msgid "Password: "
@@ -266,7 +266,7 @@ msgstr "Домівка"
266266msgid "Also installed"
267267msgstr "Також встановлено"
268268
269−#: qml/DisabledScreenNotice.qml:104
269+#: qml/DisabledScreenNotice.qml:109
270270msgid ""
271271"Your device is now connected to an external display. Use this screen as a "
272272"touch pad to interact with the pointer."
po/unity8.pot+23−23
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
11+"POT-Creation-Date: 2016-05-27 13:54+0000\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"
@@ -74,7 +74,7 @@ msgid "Log Out"
7474msgstr ""
7575
7676#: qml/Components/Dialogs.qml:161 qml/Components/Dialogs.qml:217
77−#: qml/Dash/DashPageHeader.qml:298 qml/Wizard/Pages/passcode-confirm.qml:32
77+#: qml/Dash/DashPageHeader.qml:295 qml/Wizard/Pages/passcode-confirm.qml:32
7878#: qml/Wizard/Pages/passcode-set.qml:32
7979msgid "Cancel"
8080msgstr ""
@@ -155,26 +155,26 @@ msgstr ""
155155msgid "Close all"
156156msgstr ""
157157
158−#: qml/Dash/DashPageHeader.qml:337
158+#: qml/Dash/DashPageHeader.qml:333
159159msgctxt "Button: Open the Ubuntu Store"
160160msgid "Store"
161161msgstr ""
162162
163−#: qml/Dash/DashPageHeader.qml:344
163+#: qml/Dash/DashPageHeader.qml:340
164164msgctxt "Button: Start a search in the current dash scope"
165165msgid "Search"
166166msgstr ""
167167
168−#: qml/Dash/DashPageHeader.qml:354
168+#: qml/Dash/DashPageHeader.qml:350
169169msgctxt "Button: Show the current dash scope settings"
170170msgid "Settings"
171171msgstr ""
172172
173−#: qml/Dash/DashPageHeader.qml:361
173+#: qml/Dash/DashPageHeader.qml:357
174174msgid "Remove from Favorites"
175175msgstr ""
176176
177−#: qml/Dash/DashPageHeader.qml:361
177+#: qml/Dash/DashPageHeader.qml:357
178178msgid "Add to Favorites"
179179msgstr ""
180180
@@ -186,7 +186,7 @@ msgstr ""
186186msgid "Reset"
187187msgstr ""
188188
189−#: qml/Dash/GenericScopeView.qml:579 qml/Dash/GenericScopeView.qml:764
189+#: qml/Dash/GenericScopeView.qml:579 qml/Dash/GenericScopeView.qml:774
190190msgid "Show less"
191191msgstr ""
192192
@@ -199,11 +199,11 @@ msgctxt "Label: Hint for dash search line edit"
199199msgid "Search"
200200msgstr ""
201201
202−#: qml/Dash/PageHeaderExtraPanel.qml:55
202+#: qml/Dash/PageHeaderExtraPanel.qml:56
203203msgid "Recent Searches"
204204msgstr ""
205205
206−#: qml/Dash/PageHeaderExtraPanel.qml:66
206+#: qml/Dash/PageHeaderExtraPanel.qml:67
207207msgid "Clear All"
208208msgstr ""
209209
@@ -216,15 +216,15 @@ msgid "Less..."
216216msgstr ""
217217
218218#: qml/Dash/Previews/PreviewCommentInput.qml:68
219−#: qml/Dash/Previews/PreviewRatingInput.qml:174
219+#: qml/Dash/Previews/PreviewRatingInput.qml:175
220220msgid "Send"
221221msgstr ""
222222
223−#: qml/Dash/Previews/PreviewRatingInput.qml:84
223+#: qml/Dash/Previews/PreviewRatingInput.qml:82
224224msgid "Rate this"
225225msgstr ""
226226
227−#: qml/Dash/Previews/PreviewRatingInput.qml:129
227+#: qml/Dash/Previews/PreviewRatingInput.qml:157
228228msgid "Add a review"
229229msgstr ""
230230
@@ -244,19 +244,19 @@ msgstr ""
244244msgid "Enable location data"
245245msgstr ""
246246
247−#: qml/Dash/ScopesList.qml:67
247+#: qml/Dash/ScopesList.qml:55
248248msgid "Manage"
249249msgstr ""
250250
251−#: qml/Dash/ScopesList.qml:113
251+#: qml/Dash/ScopesList.qml:101
252252msgid "Home"
253253msgstr ""
254254
255−#: qml/Dash/ScopesList.qml:114
255+#: qml/Dash/ScopesList.qml:102
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
@@ -400,18 +400,18 @@ msgstr ""
400400msgid "Failed, tap to retry"
401401msgstr ""
402402
403−#: qml/Panel/Indicators/MessageMenuItemFactory.qml:155
404−#: qml/Panel/Indicators/MessageMenuItemFactory.qml:214
403+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:151
404+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:210
405405msgctxt "Button: Send a reply message"
406406msgid "Send"
407407msgstr ""
408408
409−#: qml/Panel/Indicators/MessageMenuItemFactory.qml:156
409+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:152
410410msgctxt "Label: Hint in message indicator line edit"
411411msgid "Reply"
412412msgstr ""
413413
414−#: qml/Panel/Indicators/MessageMenuItemFactory.qml:213
414+#: qml/Panel/Indicators/MessageMenuItemFactory.qml:209
415415msgctxt "Button: Call back on phone"
416416msgid "Call back"
417417msgstr ""
@@ -474,7 +474,7 @@ msgid "Language"
474474msgstr ""
475475
476476#: qml/Wizard/Pages/10-welcome.qml:156 qml/Wizard/Pages/30-wifi.qml:206
477−#: qml/Wizard/Pages/40-location.qml:271 qml/Wizard/Pages/50-timezone.qml:267
477+#: qml/Wizard/Pages/40-location.qml:271 qml/Wizard/Pages/50-timezone.qml:270
478478#: qml/Wizard/Pages/60-account.qml:65 qml/Wizard/Pages/70-passwd-type.qml:144
479479#: qml/Wizard/Pages/75-report-check.qml:84
480480#: qml/Wizard/Pages/passcode-desktop.qml:124
@@ -539,7 +539,7 @@ msgstr ""
539539msgid "Time Zone"
540540msgstr ""
541541
542−#: qml/Wizard/Pages/50-timezone.qml:178
542+#: qml/Wizard/Pages/50-timezone.qml:181
543543msgid "Enter your city"
544544msgstr ""
545545
po/ur.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-05-05 03:12+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Urdu <ur@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/uz.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-07-04 16:03+0000\n"
1212"Last-Translator: Learner <muzaffar.habibullayev@yandex.ru>\n"
1313"Language-Team: Uzbek <uz@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/vi.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-01-15 01:19+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Vietnamese <vi@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/wo.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2015-10-29 11:16+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Wolof <wo@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr "Njëlbeen"
256256msgid "Also installed"
257257msgstr "Yiñ samp tamit"
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/xh.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2013-09-28 13:20+0000\n"
1212"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313"Language-Team: Xhosa <xh@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/zh_CN.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-04-13 06:27+0000\n"
1212"Last-Translator: YunQiang Su <wzssyqa@gmail.com>\n"
1313"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -257,7 +257,7 @@ msgstr "首页"
257257msgid "Also installed"
258258msgstr "已安装"
259259
260−#: qml/DisabledScreenNotice.qml:104
260+#: qml/DisabledScreenNotice.qml:109
261261msgid ""
262262"Your device is now connected to an external display. Use this screen as a "
263263"touch pad to interact with the pointer."
po/zh_HK.po+4−4
@@ -7,7 +7,7 @@ msgid ""
77msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10−"POT-Creation-Date: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2014-08-10 11:45+0000\n"
1212"Last-Translator: Daniel Cheung <daniel.2345@hotmail.com>\n"
1313"Language-Team: Chinese (Hong Kong) <zh_HK@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020
2121#: plugins/IntegratedLightDM/Greeter.cpp:112
2222msgid "Password: "
@@ -256,7 +256,7 @@ msgstr ""
256256msgid "Also installed"
257257msgstr ""
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
po/zh_TW.po+4−4
@@ -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: 2016-05-18 11:19+0000\n"
10+"POT-Creation-Date: 2016-05-20 08:44+0000\n"
1111"PO-Revision-Date: 2016-02-24 04:40+0000\n"
1212"Last-Translator: Po-Hsu Lin <po-hsu.lin@canonical.com>\n"
1313"Language-Team: Chinese (Traditional) <zh_TW@li.org>\n"
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2016-05-19 05:50+0000\n"
19−"X-Generator: Launchpad (build 18025)\n"
18+"X-Launchpad-Export-Date: 2016-05-25 06:09+0000\n"
19+"X-Generator: Launchpad (build 18053)\n"
2020"Language: zh_TW\n"
2121
2222#: plugins/IntegratedLightDM/Greeter.cpp:112
@@ -256,7 +256,7 @@ msgstr "家屋"
256256msgid "Also installed"
257257msgstr "也有安裝"
258258
259−#: qml/DisabledScreenNotice.qml:104
259+#: qml/DisabledScreenNotice.qml:109
260260msgid ""
261261"Your device is now connected to an external display. Use this screen as a "
262262"touch pad to interact with the pointer."
qml/Components/Dialogs.qml+2−2
@@ -185,7 +185,7 @@ Item {
185185 unitySessionService.reboot();
186186 rebootDialog.hide();
187187 }
188− color: UbuntuColors.red
188+ color: theme.palette.normal.negative
189189 }
190190 }
191191 }
@@ -203,7 +203,7 @@ Item {
203203 powerDialog.hide();
204204 root.powerOffClicked();
205205 }
206− color: UbuntuColors.red
206+ color: theme.palette.normal.negative
207207 }
208208 Button {
209209 text: i18n.ctr("Button: Restart the system", "Restart")
qml/Components/DragHandle.qml+43−25
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013,2016 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
@@ -38,12 +38,12 @@ import Ubuntu.Gestures 0.1
3838 anchors.bottom: parent.bottom
3939 width: units.gu(2)
4040
41− direction: DirectionalDragArea::Leftwards
41+ direction: SwipeArea::Leftwards
4242 }
4343 }
4444
4545 */
46−DirectionalDragArea {
46+SwipeArea {
4747 id: dragArea
4848
4949 property bool stretch: false
@@ -70,15 +70,16 @@ DirectionalDragArea {
7070 property: "targetValue"
7171 duration: 150
7272 velocity: -1
73− to: Direction.isPositive(direction) ? d.startValue + hintDisplacement
74− : d.startValue - hintDisplacement
73+
74+ to: d.incrementTargetProp ? d.startValue + hintDisplacement
75+ : d.startValue - hintDisplacement
7576 property real targetValue
7677 onTargetValueChanged: {
7778 if (!running) {
7879 return;
7980 }
8081
81− if (Direction.isPositive(direction)) {
82+ if (d.incrementTargetProp) {
8283 if (parent[d.targetProp] < targetValue) {
8384 parent[d.targetProp] = targetValue;
8485 }
@@ -93,19 +94,24 @@ DirectionalDragArea {
9394 // Private stuff
9495 QtObject {
9596 id: d
97+
98+ // Whether movement along the designated direction will increment the value of the target property
99+ readonly property bool incrementTargetProp: (Direction.isPositive(direction) && !dragArea.stretch)
100+ || (dragArea.stretch && !d.dragParent.shown)
101+
96102 property real startValue
97103 property real minValue: {
98104 if (direction == Direction.Horizontal) {
99105 return startValue - maxTotalDragDistance;
100− } else if (Direction.isPositive(direction)) {
106+ } else if (incrementTargetProp) {
101107 return startValue;
102108 } else {
103109 return startValue - maxTotalDragDistance;
104110 }
105111 }
106112
107− property real maxValue: Direction.isPositive(direction) ? startValue + maxTotalDragDistance
108− : startValue
113+ property real maxValue: incrementTargetProp ? startValue + maxTotalDragDistance
114+ : startValue;
109115
110116 property var dragParent: dragArea.parent
111117
@@ -118,26 +124,26 @@ DirectionalDragArea {
118124 }
119125 }
120126
121− function limitMovement(inputStep) {
122− var targetValue = MathUtils.clamp(dragParent[targetProp] + inputStep, minValue, maxValue);
123− var step = targetValue - dragParent[targetProp];
127+ function limitMovement(distance) {
128+ var targetValue = MathUtils.clamp(d.startValue + distance, minValue, maxValue);
129+ var diff = targetValue - d.startValue;
124130
125131 if (hintDisplacement == 0) {
126− return step;
132+ return diff;
127133 }
128134
129135 // we should not go behind hintingAnimation's current value
130− if (Direction.isPositive(direction)) {
131− if (dragParent[targetProp] + step < hintingAnimation.targetValue) {
132− step = hintingAnimation.targetValue - dragParent[targetProp];
136+ if (d.incrementTargetProp) {
137+ if (d.startValue + diff < hintingAnimation.targetValue) {
138+ diff = hintingAnimation.targetValue - d.startValue;
133139 }
134140 } else {
135− if (dragParent[targetProp] + step > hintingAnimation.targetValue) {
136− step = hintingAnimation.targetValue - dragParent[targetProp];
141+ if (d.startValue + diff > hintingAnimation.targetValue) {
142+ diff = hintingAnimation.targetValue - d.startValue;
137143 }
138144 }
139145
140− return step;
146+ return diff;
141147 }
142148
143149 function onFinishedRecognizedGesture() {
@@ -171,19 +177,31 @@ DirectionalDragArea {
171177 objectName: "edgeDragEvaluator"
172178 id: dragEvaluator
173179 // Effectively convert distance into the drag position projected onto the gesture direction axis
174− trackedPosition: Direction.isPositive(dragArea.direction) ? sceneDistance : -sceneDistance
180+ trackedPosition: Direction.isPositive(dragArea.direction) ? distance : -distance
175181 maxDragDistance: maxTotalDragDistance
176182 direction: dragArea.direction
177183 }
178184
179185 onDistanceChanged: {
180186 if (dragging) {
181− // don't go the whole distance in order to smooth out the movement
182− var step = distance * 0.3;
183−
184− step = d.limitMovement(step);
187+ if (!Direction.isPositive(direction))
188+ distance = -distance;
189+
190+ if (dragArea.stretch &&
191+ ((!Direction.isPositive(direction) && !d.dragParent.shown)
192+ ||
193+ (Direction.isPositive(direction) && d.dragParent.shown))
194+ )
195+ {
196+ // This happens when you have a stretching showable being shown from the right or
197+ // top edge (and consequently being hidden when dragged towards the right/top edge)
198+ // In those situations, dimension expansion/retraction happens in the opposite
199+ // sign of the axis direction
200+ distance = -distance;
201+ }
185202
186− parent[d.targetProp] += step;
203+ var toAdd = d.limitMovement(distance);
204+ parent[d.targetProp] = d.startValue + toAdd;
187205 }
188206 }
189207
qml/Components/FloatingFlickable.qmlnew file+59
@@ -0,0 +1,59 @@
1+/*
2+ * Copyright (C) 2015-2016 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.4
18+import Ubuntu.Components 1.3
19+import Ubuntu.Gestures 0.1
20+
21+/*
22+ A Flickable that can be put in front of the item to be flicked and
23+ still have the item-to-be-flicked receive input events that are not flicks.
24+
25+ Ie, it's a Flickable that, input-wise, is transparent to non-flick gestures.
26+
27+ With a regular Flickable you would have to make the item-to-be-flicked a child
28+ of Flicakble to achieve the same result. FloatingFlickable has no such requirement
29+ or limitation.
30+ */
31+Item {
32+ property alias contentWidth: flickable.contentWidth
33+ property alias contentHeight: flickable.contentHeight
34+ property alias contentX: flickable.contentX
35+ property alias contentY: flickable.contentY
36+ property alias direction: swipeArea.direction
37+
38+ MouseEventGenerator {
39+ id: mouseEventGenerator
40+ targetItem: flickable
41+ }
42+
43+ Flickable {
44+ id: flickable
45+ enabled: false
46+ anchors.fill: parent
47+ flickableDirection: Direction.isHorizontal(swipeArea.direction) ? Flickable.HorizontalFlick : Flickable.VerticalFlick
48+ }
49+
50+ SwipeArea {
51+ id: swipeArea
52+ anchors.fill: parent
53+ direction: Direction.Horizontal
54+
55+ onTouchPositionChanged: mouseEventGenerator.move(touchPosition);
56+ onDraggingChanged: dragging ? mouseEventGenerator.press(touchPosition)
57+ : mouseEventGenerator.release(touchPosition)
58+ }
59+}
qml/Components/Header.qmldeleted−28
@@ -1,28 +0,0 @@
1−/*
2− * Copyright (C) 2014 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 Ubuntu.Components 1.3
18−import Ubuntu.Components.Themes.Ambiance 1.3
19−
20−PageHeadStyle {
21− // FIXME: Don't use this but PageHeader from Ubuntu.Components 1.3.
22− id: root
23−
24− property var styledItem: root
25− property string title
26− property var config: PageHeadConfiguration {}
27− property var contents: null
28−}
qml/Components/InputMethod.qml+2−2
@@ -30,8 +30,8 @@ Item {
3030
3131 consumesInput: true
3232
33− surfaceWidth: width
34− surfaceHeight: height
33+ surfaceWidth: root.enabled ? width : -1
34+ surfaceHeight: root.enabled ? height : -1
3535 surface: SurfaceManager.inputMethodSurface
3636
3737 onLiveChanged: {
qml/Components/ModeSwitchWarningDialog.qml+1−1
@@ -86,7 +86,7 @@ ShellDialog {
8686 Button {
8787 objectName: "forceCloseButton"
8888 text: i18n.tr("Close all")
89− color: UbuntuColors.red
89+ color: theme.palette.normal.negative
9090 onClicked: {
9191 root.forceClose();
9292 }
qml/Components/PanelState/PanelState.qml+3−3
@@ -26,8 +26,8 @@ QtObject {
2626 property bool dropShadow: false
2727 property int panelHeight: 0
2828
29− signal close()
30− signal minimize()
31− signal maximize()
29+ signal closeClicked()
30+ signal minimizeClicked()
31+ signal restoreClicked()
3232 signal focusMaximizedApp()
3333}
qml/Components/Rating.qml+1
@@ -21,6 +21,7 @@ import Ubuntu.Components 1.3
2121
2222StyledItem {
2323 id: root
24+ implicitHeight: units.gu(2)
2425
2526 //! True if it accepts user input.
2627 property bool interactive: true
qml/Components/RatingStyle.qml+3
@@ -36,6 +36,9 @@ Row {
3636 property url urlIconHalf: styledItem.urlIconHalf || "graphics/icon_star_half.png"
3737
3838 Image {
39+ height: parent.height
40+ fillMode: Image.PreserveAspectFit
41+ sourceSize.height: height
3942 opacity: styledItem.value < 0 ? 0.4 : 1 // Let's make the stars look inactive for a not-set value
4043 source: {
4144 if (index === repeater.indexHalfValue) return repeater.urlIconHalf;
qml/Components/WindowControlButtons.qml+18−7
@@ -25,9 +25,11 @@ Row {
2525 property bool active: false
2626 property bool closeButtonShown: true
2727
28− signal close()
29− signal minimize()
30− signal maximize()
28+ signal closeClicked()
29+ signal minimizeClicked()
30+ signal maximizeClicked()
31+ signal maximizeVerticallyClicked()
32+ signal maximizeHorizontallyClicked()
3133
3234 MouseArea {
3335 id: closeWindowButton
@@ -35,7 +37,7 @@ Row {
3537 hoverEnabled: true
3638 height: parent.height
3739 width: height
38− onClicked: root.close()
40+ onClicked: root.closeClicked()
3941 visible: root.closeButtonShown
4042
4143 Rectangle {
@@ -43,7 +45,7 @@ Row {
4345 width: units.gu(2)
4446 height: units.gu(2)
4547 radius: height / 2
46− color: UbuntuColors.red
48+ color: theme.palette.normal.negative
4749 visible: parent.containsMouse
4850 }
4951 Icon {
@@ -62,7 +64,7 @@ Row {
6264 hoverEnabled: true
6365 height: parent.height
6466 width: height
65− onClicked: root.minimize()
67+ onClicked: root.minimizeClicked()
6668
6769 Rectangle {
6870 anchors.centerIn: parent
@@ -88,7 +90,16 @@ Row {
8890 hoverEnabled: true
8991 height: parent.height
9092 width: height
91− onClicked: root.maximize()
93+ acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
94+ onClicked: {
95+ if (mouse.button == Qt.LeftButton) {
96+ root.maximizeClicked();
97+ } else if (mouse.button == Qt.RightButton) {
98+ root.maximizeHorizontallyClicked();
99+ } else if (mouse.button == Qt.MiddleButton) {
100+ root.maximizeVerticallyClicked();
101+ }
102+ }
92103
93104 Rectangle {
94105 anchors.centerIn: parent
qml/Dash/CardCarousel.qml−1
@@ -66,7 +66,6 @@ DashRenderer {
6666 item.cardData = Qt.binding(function() { return model; });
6767 item.fontScale = Qt.binding(function() { return carousel.fontScale; });
6868 item.showHeader = Qt.binding(function() { return loader.explicitlyScaled; });
69− item.artShapeStyle = "shadow";
7069 item.scopeStyle = cardCarousel.scopeStyle;
7170 }
7271 }
qml/Dash/CardGrid.qml−2
@@ -25,7 +25,6 @@ DashRenderer {
2525 if (!cardTool || !cardTool.template || typeof cardTool.template["collapsed-rows"] != "number") return 2;
2626 return cardTool.template["collapsed-rows"];
2727 }
28− property string artShapeStyle: "inset";
2928 property string backgroundShapeStyle: "inset";
3029 property alias minimumHorizontalSpacing: grid.minimumHorizontalSpacing
3130
@@ -71,7 +70,6 @@ DashRenderer {
7170 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
7271 item.cardData = Qt.binding(function() { return model; });
7372 item.scopeStyle = root.scopeStyle;
74− item.artShapeStyle = root.artShapeStyle;
7573 item.backgroundShapeStyle = root.backgroundShapeStyle;
7674 }
7775 Connections {
qml/Dash/CardTool.qml+6−2
@@ -66,7 +66,11 @@ Item {
6666 return layout;
6767 }
6868
69− property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, false);
69+
70+ // Not readonly because gets overwritten from GenericScopeView in some cases
71+ property string artShapeStyle: categoryLayout === "carousel" ? "shadow" : "inset"
72+
73+ property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, false, artShapeStyle);
7074
7175 // FIXME: Saviq
7276 // Only way for the card below to actually be laid out completely.
@@ -208,7 +212,7 @@ Item {
208212 "attributes": attributesModel.model,
209213 "socialActions": socialActionsModel.model
210214 }
211− sourceComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true);
215+ sourceComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components, true, artShapeStyle);
212216 onLoaded: {
213217 item.objectName = "cardToolCard";
214218 item.width = Qt.binding(function() { return cardTool.cardWidth !== -1 ? cardTool.cardWidth : item.implicitWidth; });
qml/Dash/Dash.qml+3−3
@@ -349,7 +349,7 @@ Showable {
349349 }
350350 }
351351
352− DirectionalDragArea {
352+ SwipeArea {
353353 id: overviewDragHandle
354354 objectName: "overviewDragHandle"
355355 z: 1
@@ -364,10 +364,10 @@ Showable {
364364 anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
365365 height: units.gu(2)
366366
367− onSceneDistanceChanged: {
367+ onDistanceChanged: {
368368 if (dragging) {
369369 bottomEdgeController.enableAnimation = false;
370− bottomEdgeController.progress = Math.max(0, Math.min(1, sceneDistance / fullMovement));
370+ bottomEdgeController.progress = Math.max(0, Math.min(1, distance / fullMovement));
371371 }
372372 }
373373
qml/Dash/DashApplication.qml−3
@@ -22,9 +22,6 @@ MainView {
2222 implicitWidth: units.gu(40)
2323 implicitHeight: units.gu(68)
2424
25− // Workaround bug #1475643
26− headerColor: Qt.rgba(0, 0, 0, 0)
27−
2825 Dash {
2926 anchors.fill: parent
3027 }
qml/Dash/DashCategoryBase.qml+3−11
@@ -24,17 +24,9 @@ Item {
2424 /* Relevant really only for ListViewWithPageHeader case: specify how many pixels we can overlap with the section header */
2525 readonly property int allowedOverlap: units.dp(1)
2626
27− property real __heightToClip: {
28− // Check this is in position where clipping is needed
29− if (typeof ListViewWithPageHeader !== 'undefined') {
30− if (typeof heightToClip !== 'undefined') {
31− if (heightToClip >= allowedOverlap) {
32− return heightToClip - allowedOverlap;
33− }
34− }
35− }
36− return 0;
37− }
27+ property real heightToClip: 0
28+ readonly property real __heightToClip: heightToClip >= allowedOverlap ? heightToClip - allowedOverlap : 0
29+
3830
3931 /*!
4032 \internal
qml/Dash/DashPageHeader.qml+31−36
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.4
1818import Ubuntu.Components 1.3
19−import Ubuntu.Components.Themes.Ambiance 1.3
19+import Ubuntu.Components.Popups 1.3
2020import Ubuntu.Components.ListItems 1.3
2121import "../Components"
2222
@@ -78,13 +78,13 @@ Item {
7878 }
7979 }
8080
81− function closePopup(keepFocus) {
81+ function closePopup(keepFocus, keepSearch) {
8282 if (extraPanel.visible) {
8383 extraPanel.visible = false;
8484 } else if (!keepFocus) {
85− unfocus();
85+ unfocus(keepSearch);
8686 }
87− if (!searchTextField.text && !root.navigationTag && searchHistory.count == 0) {
87+ if (!keepSearch && !searchTextField.text && !root.navigationTag && searchHistory.count == 0) {
8888 headerContainer.showSearch = false;
8989 }
9090 }
@@ -97,9 +97,9 @@ Item {
9797 closePopup(keepFocus);
9898 }
9999
100− function unfocus() {
100+ function unfocus(keepSearch) {
101101 searchTextField.focus = false;
102− if (!searchTextField.text && !root.navigationTag) {
102+ if (!keepSearch && !searchTextField.text && !root.navigationTag) {
103103 headerContainer.showSearch = false;
104104 }
105105 }
@@ -142,7 +142,7 @@ Item {
142142 objectName: "headerContainer"
143143 clip: contentY < height
144144 anchors { left: parent.left; top: parent.top; right: parent.right }
145− height: header.contentHeight
145+ height: header.__styleInstance.contentHeight
146146 contentHeight: headersColumn.height
147147 interactive: false
148148 contentY: showSearch ? 0 : height
@@ -173,22 +173,18 @@ Item {
173173 id: headersColumn
174174 anchors { left: parent.left; right: parent.right }
175175
176− PageHeadStyle {
177− // FIXME: Replace PageHeadStyle from the Ambiance theme by the new PageHeader from Ubuntu.Components 1.3.
176+ PageHeader {
178177 id: searchHeader
179178 anchors { left: parent.left; right: parent.right }
180179 opacity: headerContainer.clip || headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
181− __separator_visible: false
182− // Required to keep PageHeadStyle noise down as it expects the Page's properties around.
183− property var styledItem: searchHeader
184− property color dividerColor: "transparent" // Doesn't matter as we don't have PageHeadSections
185− property color panelColor: background.topColor
186− panelForegroundColor: config.foregroundColor
187− backgroundColor: "transparent"
188− config: PageHeadConfiguration {
180+
181+ StyleHints {
189182 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
183+ backgroundColor: "transparent"
184+ dividerColor: "transparent"
190185 }
191− property var contents: Item {
186+
187+ contents: Item {
192188 anchors.fill: parent
193189
194190 TextField {
@@ -273,7 +269,7 @@ Item {
273269 anchors.fill: parent
274270 anchors.margins: units.gu(2)
275271 name: "filters"
276− color: root.activeFiltersCount > 0 ? UbuntuColors.orange : header.config.foregroundColor
272+ color: root.activeFiltersCount > 0 ? theme.palette.normal.positive : header.__styleInstance.foregroundColor
277273 }
278274
279275 onClicked: {
@@ -283,6 +279,7 @@ Item {
283279
284280 AbstractButton {
285281 id: cancelButton
282+ objectName: "cancelButton"
286283 width: cancelLabel.width + cancelLabel.anchors.rightMargin + cancelLabel.anchors.leftMargin
287284 anchors {
288285 top: parent.top
@@ -296,7 +293,7 @@ Item {
296293 Label {
297294 id: cancelLabel
298295 text: i18n.tr("Cancel")
299− color: header.panelForegroundColor
296+ color: header.__styleInstance.foregroundColor
300297 verticalAlignment: Text.AlignVCenter
301298 anchors {
302299 verticalCenter: parent.verticalCenter
@@ -309,28 +306,27 @@ Item {
309306 }
310307 }
311308
312− PageHeadStyle {
313− // FIXME: Replace PageHeadStyle from the Ambiance theme by the new PageHeader from Ubuntu.Components 1.3.
309+ PageHeader {
314310 id: header
315311 objectName: "innerPageHeader"
316312 anchors { left: parent.left; right: parent.right }
317313 height: headerContainer.height
318314 opacity: headerContainer.clip || !headerContainer.showSearch ? 1 : 0 // setting visible false cause column to relayout
319− __separator_visible: false
320− property var styledItem: header
321− property color dividerColor: "transparent" // Doesn't matter as we don't have PageHeadSections
322− property color panelColor: background.topColor
323− panelForegroundColor: config.foregroundColor
324− backgroundColor: "transparent"
325− config: PageHeadConfiguration {
326− title: root.title
315+ title: root.title
316+
317+ StyleHints {
327318 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : theme.palette.normal.baseText
328− backAction: Action {
329− iconName: backIsClose ? "close" : "back"
330− visible: root.showBackButton
331− onTriggered: root.backClicked()
332− }
319+ backgroundColor: "transparent"
320+ dividerColor: "transparent"
321+ }
322+
323+ leadingActionBar.actions: Action {
324+ iconName: backIsClose ? "close" : "back"
325+ visible: root.showBackButton
326+ onTriggered: root.backClicked()
327+ }
333328
329+ trailingActionBar {
334330 actions: [
335331 Action {
336332 objectName: "store"
@@ -366,7 +362,6 @@ Item {
366362 ]
367363 }
368364
369− property var contents: null
370365 Component.onCompleted: root.refreshLogo()
371366
372367 Component {
qml/Dash/Filters/FilterOptionSelector.qml+4
@@ -25,6 +25,8 @@ FilterWidget {
2525
2626 implicitHeight: expandingItem.height
2727
28+ signal filterSelected()
29+
2830 ListItems.Expandable {
2931 id: expandingItem
3032 objectName: "expandingItem"
@@ -67,6 +69,7 @@ FilterWidget {
6769 width: parent.width
6870 Repeater {
6971 model: widgetData.options
72+ objectName: "optionsRepeater"
7073
7174 ListItems.Standard {
7275 text: label
@@ -83,6 +86,7 @@ FilterWidget {
8386
8487 onClicked: {
8588 widgetData.options.setChecked(index, !checked);
89+ root.filterSelected()
8690 }
8791 }
8892 }
qml/Dash/Filters/FilterWidgetFactory.qml+8
@@ -31,6 +31,9 @@ Item {
3131 //! Widget data, forwarded to the widget as is.
3232 property var widgetData: null
3333
34+ // Emitted iff filter type is FilterOptionSelector
35+ signal singleSelectionFilterSelected()
36+
3437 implicitHeight: title.height + title.anchors.topMargin + loader.height
3538
3639 Label {
@@ -77,5 +80,10 @@ Item {
7780 item.widgetId = Qt.binding(function() { return root.widgetId } )
7881 item.widgetData = Qt.binding(function() { return root.widgetData } )
7982 }
83+
84+ Connections {
85+ target: widgetType == Filters.OptionSelectorFilter ? loader.item : null
86+ onFilterSelected: root.singleSelectionFilterSelected()
87+ }
8088 }
8189}
qml/Dash/GenericScopeView.qml+14−4
@@ -345,10 +345,10 @@ FocusScope {
345345 if (scope && scope.id === "clickscope") {
346346 if (categoryId === "predefined" || categoryId === "local") {
347347 cardTool.artShapeSize = Qt.binding(function() { return Qt.size(units.gu(8), units.gu(7.5)) });
348− item.artShapeStyle = "icon";
348+ cardTool.artShapeStyle = "icon";
349349 } else {
350350 // Should be ubuntu store icon
351− item.artShapeStyle = "flat";
351+ cardTool.artShapeStyle = "flat";
352352 item.backgroundShapeStyle = "shadow";
353353 }
354354 }
@@ -616,10 +616,10 @@ FocusScope {
616616 sectionProperty: "name"
617617 sectionDelegate: ListItems.Header {
618618 objectName: "dashSectionHeader" + (delegate ? delegate.category : "")
619+ property int delegateIndex: -1
619620 readonly property var delegate: categoryView.item(delegateIndex)
620621 width: categoryView.width
621− height: section != "" ? units.gu(5) : 0
622− text: section
622+ height: text != "" ? units.gu(5) : 0
623623 color: scopeStyle ? scopeStyle.foreground : theme.palette.normal.baseText
624624 iconName: delegate && delegate.headerLink ? "go-next" : ""
625625 onClicked: {
@@ -662,6 +662,10 @@ FocusScope {
662662 onShowFiltersPopup: { // item
663663 extraPanel.visible = false;
664664 scopeView.filtersPopover = PopupUtils.open(Qt.resolvedUrl("FiltersPopover.qml"), item, { "contentWidth": scopeView.width - units.gu(2) } );
665+ scopeView.filtersPopover.Component.onDestruction.connect(function () {
666+ categoryView.pageHeader.closePopup(false, true);
667+ categoryView.pageHeader.unfocus(true); // remove the focus from the search field
668+ })
665669 }
666670 }
667671
@@ -683,12 +687,18 @@ FocusScope {
683687 onHistoryItemClicked: {
684688 SearchHistoryModel.addQuery(text);
685689 categoryView.pageHeader.searchQuery = text;
690+ categoryView.pageHeader.unfocus();
686691 }
687692
688693 onDashNavigationLeafClicked: {
689694 categoryView.pageHeader.closePopup();
690695 categoryView.pageHeader.unfocus();
691696 }
697+
698+ onExtraPanelOptionSelected: {
699+ categoryView.pageHeader.closePopup();
700+ categoryView.pageHeader.unfocus();
701+ }
692702 }
693703 }
694704
qml/Dash/PageHeaderExtraPanel.qml+34−10
@@ -24,7 +24,7 @@ Item {
2424
2525 readonly property real searchesHeight: recentSearchesRepeater.count > 0 ? searchColumn.height + recentSearchesLabels.height + recentSearchesLabels.anchors.topMargin : 0
2626
27− implicitHeight: searchesHeight + dashNavigation.implicitHeight + dashNavigation.anchors.topMargin + primaryFilter.height + primaryFilter.anchors.topMargin
27+ implicitHeight: searchesHeight + dashNavigation.implicitHeight + dashNavigation.anchors.topMargin + primaryFilterContainer.height + primaryFilterContainer.anchors.topMargin
2828
2929 // Set by parent
3030 property ListModel searchHistory
@@ -36,6 +36,7 @@ Item {
3636
3737 signal historyItemClicked(string text)
3838 signal dashNavigationLeafClicked()
39+ signal extraPanelOptionSelected()
3940
4041 function resetNavigation() {
4142 dashNavigation.resetNavigation();
@@ -124,7 +125,7 @@ Item {
124125 color: "#888888"
125126 }
126127
127− divider.visible: index != repeater.count - 1 || (scope && scope.hasNavigation) || primaryFilter.active
128+ divider.visible: index != recentSearchesRepeater.count - 1 || (scope && scope.hasNavigation) || primaryFilter.active
128129
129130 onClicked: root.historyItemClicked(query)
130131 }
@@ -145,22 +146,45 @@ Item {
145146 onLeafClicked: root.dashNavigationLeafClicked();
146147 }
147148
148− Filters.FilterWidgetFactory {
149− id: primaryFilter
150− active: scope && !scope.hasNavigation
149+ Flickable {
150+ id: primaryFilterContainer
151+ objectName: "primaryFilterContainer"
152+
153+ height: {
154+ if (!primaryFilter.active) {
155+ return 0;
156+ } else if (contentHeight > dashNavigation.availableHeight) {
157+ return dashNavigation.availableHeight;
158+ } else {
159+ return contentHeight;
160+ }
161+ }
151162
152− property var filter: active ? scope.primaryNavigationFilter : null
163+ clip: true
164+ contentHeight: primaryFilter.implicitHeight
153165
154166 anchors {
155167 top: recentSearchesRepeater.count > 0 ? searchColumn.bottom : parent.top
156− topMargin: active && recentSearchesRepeater.count > 0 ? units.gu(2) : 0
168+ topMargin: primaryFilter.active && recentSearchesRepeater.count > 0 ? units.gu(2) : 0
157169 left: parent.left
158170 right: parent.right
159171 }
160172
161− widgetId: filter ? filter.filterId : ""
162− widgetType: filter ? filter.filterType : -1
163− widgetData: filter
173+ Filters.FilterWidgetFactory {
174+ id: primaryFilter
175+ objectName: "primaryFilter"
176+
177+ active: scope && !scope.hasNavigation
178+
179+ anchors.fill: parent
180+ property var filter: active ? scope.primaryNavigationFilter : null
181+
182+ widgetId: filter ? filter.filterId : ""
183+ widgetType: filter ? filter.filterType : -1
184+ widgetData: filter
185+
186+ onSingleSelectionFilterSelected: extraPanelOptionSelected()
187+ }
164188 }
165189
166190 // This is outside the item
qml/Dash/Previews/PreviewActions.qml+1−1
@@ -66,7 +66,7 @@ PreviewWidget {
6666 visible: root.actions && root.actions.length > 0
6767 onTriggeredAction: root.triggered(root.widgetId, actionData.id, actionData)
6868 width: (root.width - units.gu(1)) / 2
69− color: root.scopeStyle ? root.scopeStyle.previewButtonColor : UbuntuColors.orange
69+ color: root.scopeStyle ? root.scopeStyle.previewButtonColor : theme.palette.normal.positive
7070 }
7171 }
7272}
qml/Dash/Previews/PreviewPayments.qml+1−1
@@ -35,7 +35,7 @@ PreviewWidget {
3535 id: paymentButton
3636 objectName: "paymentButton"
3737
38− color: UbuntuColors.orange
38+ color: theme.palette.normal.positive
3939 text: paymentClient.formattedPrice
4040 onClicked: {
4141 paymentClient.start();
qml/Dash/Previews/PreviewRatingInput.qml+41−42
@@ -40,14 +40,16 @@ PreviewWidget {
4040 switch(widgetData["visible"]) {
4141 default:
4242 case "both":
43− return ratingLabelAndWidgetContainer.implicitHeight + reviewContainer.implicitHeight;
43+ return ratingLabelAndWidgetContainer.implicitHeight + (reviewContainer.visible ? reviewContainer.implicitHeight : 0);
4444 case "rating":
4545 return ratingLabelAndWidgetContainer.implicitHeight;
4646 case "review":
4747 return reviewContainer.implicitHeight;
48− }
48+ }
4949 }
5050
51+ clip: reviewContainer.visible
52+
5153 property alias ratingValue: rating.value
5254 property alias reviewText: reviewTextArea.text
5355
@@ -64,21 +66,17 @@ PreviewWidget {
6466 triggered(root.widgetId, "rated", data);
6567 }
6668
67− Item {
69+ Column {
6870 id: ratingLabelAndWidgetContainer
69− anchors {
70− left: parent.left
71− right: parent.right
72− }
73− implicitHeight: rating.height
71+ anchors { left: parent.left; right: parent.right; }
72+ spacing: units.gu(0.5)
7473 visible: widgetData["visible"] !== "review"
7574
7675 Label {
76+ id: ratingLabel
7777 objectName: "ratingLabel"
78− anchors {
79− verticalCenter: parent.verticalCenter
80− left: parent.left
81− }
78+ anchors { left: parent.left; right: parent.right; }
79+ fontSize: "large"
8280 color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText
8381 opacity: .8
8482 text: widgetData["rating-label"] || i18n.tr("Rate this")
@@ -87,23 +85,22 @@ PreviewWidget {
8785 Rating {
8886 id: rating
8987 objectName: "rating"
90− anchors {
91− verticalCenter: parent.verticalCenter
92− right: parent.right
93− }
88+ anchors.left: parent.left
9489 size: 5
90+ height: units.gu(4)
9591 onValueChanged: {
9692 if (widgetData["visible"] === "rating") root.submit();
9793 }
9894
99− property var urlIconEmpty: widgetData["rating-icon-empty"]
100− property var urlIconFull: widgetData["rating-icon-full"]
95+ property var urlIconEmpty: widgetData["rating-icon-empty"] || "image://theme/non-starred"
96+ property var urlIconFull: widgetData["rating-icon-full"] || "image://theme/starred"
10197 }
10298 }
10399
104100 Item {
105101 id: reviewContainer
106− implicitHeight: reviewLabel.implicitHeight + reviewSubmitContainer.implicitHeight + anchors.topMargin
102+ objectName: "reviewContainer"
103+ implicitHeight: visible ? reviewSubmitContainer.implicitHeight + anchors.topMargin : 0
107104
108105 readonly property real innerMargin: units.gu(1)
109106
@@ -112,32 +109,31 @@ PreviewWidget {
112109 right: parent.right
113110 top: ratingLabelAndWidgetContainer.visible ? ratingLabelAndWidgetContainer.bottom : parent.top
114111 bottom: parent.bottom
115− topMargin: ratingLabelAndWidgetContainer.visible ? reviewContainer.innerMargin : 0
112+ topMargin: ratingLabelAndWidgetContainer.visible ? innerMargin : 0
113+ }
114+ visible: {
115+ switch(widgetData["visible"]) {
116+ default:
117+ case "both":
118+ return widgetData["required"] === "review" || rating.value > 0;
119+ case "rating":
120+ return false;
121+ case "review":
122+ return true;
123+ }
116124 }
117− visible: widgetData["visible"] !== "rating"
118125
119− Label {
120− objectName: "reviewLabel"
121− id: reviewLabel
122− anchors {
123− top: parent.top
124− left: parent.left
125− right: parent.right
126+ Behavior on implicitHeight {
127+ UbuntuNumberAnimation {
128+ duration: UbuntuAnimation.FastDuration
129+ easing.type: Easing.OutCubic
126130 }
127− color: root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText
128− opacity: .8
129− text: widgetData["review-label"] || i18n.tr("Add a review")
130131 }
131132
132133 Item {
133134 id: reviewSubmitContainer
134− anchors {
135− top: reviewLabel.bottom
136− left: parent.left
137− right: parent.right
138− bottom: parent.bottom
139− topMargin: reviewContainer.innerMargin
140− }
135+ objectName: "reviewSubmitContainer"
136+ anchors.fill: parent
141137 implicitHeight: reviewTextArea.implicitHeight + anchors.topMargin
142138
143139 TextArea {
@@ -148,12 +144,17 @@ PreviewWidget {
148144 if(inputMethodVisible && activeFocus)
149145 root.makeSureVisible(reviewTextArea);
150146 }
147+ onVisibleChanged: {
148+ if (visible && widgetData["visible"] !== "review")
149+ focus = true;
150+ }
151151 anchors {
152152 top: parent.top
153153 left: parent.left
154154 right: submitButton.left
155155 rightMargin: reviewContainer.innerMargin
156156 }
157+ placeholderText: widgetData["review-label"] || i18n.tr("Add a review")
157158 }
158159
159160 Button {
@@ -170,11 +171,9 @@ PreviewWidget {
170171 top: parent.top
171172 right: parent.right
172173 }
173− color: readyToSubmit ? theme.palette.selected.base : theme.palette.normal.base
174+ enabled: readyToSubmit
174175 text: widgetData["submit-label"] || i18n.tr("Send")
175− onClicked: {
176− if (readyToSubmit) root.submit()
177− }
176+ onClicked: root.submit()
178177 }
179178 }
180179 }
qml/Dash/ScopesList.qml+1−13
@@ -49,18 +49,6 @@ Item {
4949 anchors.fill: parent
5050 }
5151
52− Binding {
53− target: root.scope
54− property: "searchQuery"
55− value: header.searchQuery
56− }
57−
58− Binding {
59− target: header
60− property: "searchQuery"
61− value: root.scope ? root.scope.searchQuery : ""
62− }
63−
6452 DashPageHeader {
6553 id: header
6654 objectName: "pageHeader"
@@ -70,7 +58,7 @@ Item {
7058 showBackButton: true
7159 backIsClose: root.state == "edit"
7260 storeEntryEnabled: root.state == "browse"
73− searchEntryEnabled: false // Disable search for now
61+ searchEntryEnabled: false
7462 scopeStyle: root.scopeStyle
7563 onBackClicked: {
7664 if (backIsClose) {
qml/DisabledScreenNotice.qml+7
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import QtQuick.Layouts 1.1
1919import Ubuntu.Components 1.3
2020import Unity.Session 0.1
21+import Unity.Screens 0.1
2122import QtQuick.Window 2.2
2223import "Components"
2324
@@ -35,6 +36,10 @@ Item {
3536 name: applicationArguments.deviceName
3637 }
3738
39+ Screens {
40+ id: screens
41+ }
42+
3843 Item {
3944 id: contentContainer
4045 objectName: "contentContainer"
@@ -119,6 +124,8 @@ Item {
119124
120125 InputMethod {
121126 id: inputMethod
127+ // Don't resize when there is only one screen to avoid resize clashing with the InputMethod in the Shell.
128+ enabled: screens.count > 1
122129 objectName: "inputMethod"
123130 anchors.fill: parent
124131 }
qml/Launcher/Launcher.qml+16−24
@@ -31,14 +31,14 @@ FocusScope {
3131 property int panelWidth: units.gu(10)
3232 property int dragAreaWidth: units.gu(1)
3333 property int minimizeDistance: units.gu(26)
34− property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
35− (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0
34+ property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
35+ (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
3636
3737 property bool superPressed: false
3838 property bool superTabPressed: false
3939
4040 readonly property bool dragging: dragArea.dragging
41− readonly property real dragDistance: dragArea.dragging ? dragArea.touchX : 0
41+ readonly property real dragDistance: dragArea.dragging ? dragArea.touchPosition.x : 0
4242 readonly property real visibleWidth: panel.width + panel.x
4343
4444 readonly property bool shown: panel.x > -panel.width
@@ -273,6 +273,18 @@ FocusScope {
273273 }
274274 }
275275
276+ InverseMouseArea {
277+ id: closeMouseArea
278+ anchors.fill: panel
279+ enabled: root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)
280+ visible: enabled
281+ onPressed: {
282+ mouse.accepted = false;
283+ panel.highlightIndex = -2;
284+ root.hide();
285+ }
286+ }
287+
276288 MouseArea {
277289 id: launcherDragArea
278290 enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary") && !root.lockedVisible
@@ -293,26 +305,6 @@ FocusScope {
293305 }
294306 }
295307
296− InverseMouseArea {
297− id: closeMouseArea
298− anchors.fill: panel
299− enabled: root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)
300− visible: enabled
301− onPressed: {
302− panel.highlightIndex = -2
303− root.hide();
304− }
305− }
306−
307− Rectangle {
308− id: backgroundShade
309− anchors.fill: parent
310− color: "black"
311− opacity: root.state == "visible" && !root.lockedVisible ? 0.6 : 0
312−
313− Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
314− }
315−
316308 EdgeBarrier {
317309 id: edgeBarrier
318310 edge: Qt.LeftEdge
@@ -400,7 +392,7 @@ FocusScope {
400392 }
401393 }
402394
403− DirectionalDragArea {
395+ SwipeArea {
404396 id: dragArea
405397 objectName: "launcherDragArea"
406398
qml/Launcher/LauncherDelegate.qml+2−2
@@ -164,7 +164,7 @@ Item {
164164 }
165165 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
166166 height: units.gu(2)
167− backgroundColor: UbuntuColors.green
167+ backgroundColor: theme.palette.normal.positive
168168 visible: root.countVisible
169169 aspect: UbuntuShape.Flat
170170
@@ -207,7 +207,7 @@ Item {
207207 top: parent.top
208208 bottom: parent.bottom
209209 }
210− backgroundColor: UbuntuColors.blue
210+ backgroundColor: theme.palette.normal.activity
211211 borderSource: "none"
212212 width: progressOverlay.width
213213 }
qml/Notifications/Notification.qml+20−5
@@ -55,11 +55,13 @@ StyledItem {
5555 name: "Ubuntu.Components.Themes.Ambiance"
5656 }
5757
58+ signal dismissed()
59+
5860 readonly property bool expanded: {
5961 var result = false;
6062
6163 if (type === Notification.SnapDecision) {
62− if (ListView.view.currentIndex === index) {
64+ if (ListView.view.currentIndex === index || fullscreen) {
6365 result = true;
6466 } else {
6567 if (ListView.view.count > 2) {
@@ -99,10 +101,15 @@ StyledItem {
99101 }
100102
101103 function closeNotification() {
102− if (notification.actions.count > 1) { // perform the "reject" action
103− notification.notification.invokeAction(notification.actions.data(1, ActionModel.RoleActionId));
104+ if (index === ListView.view.currentIndex) { // reset to get the 1st snap decision expanded
105+ ListView.view.currentIndex = -1;
104106 }
107+
108+ // perform the "reject" action
109+ notification.notification.invokeAction(notification.actions.data(1, ActionModel.RoleActionId));
110+
105111 notification.notification.close();
112+ notification.dismissed()
106113 }
107114
108115 Behavior on x {
@@ -115,6 +122,12 @@ StyledItem {
115122 }
116123 }
117124
125+ onFullscreenChanged: {
126+ if (fullscreen) {
127+ notification.notification.urgency = Notification.Critical;
128+ }
129+ }
130+
118131 Behavior on height {
119132 UbuntuNumberAnimation {
120133 duration: UbuntuAnimation.SnapDuration
@@ -188,6 +201,7 @@ StyledItem {
188201 onNameOwnerChanged: {
189202 if (lastNameOwner !== "" && nameOwner === "" && notification.notification !== undefined) {
190203 notification.notification.close()
204+ notification.dismissed()
191205 }
192206 lastNameOwner = nameOwner
193207 }
@@ -199,7 +213,7 @@ StyledItem {
199213 anchors.fill: parent
200214 objectName: "interactiveArea"
201215
202− drag.target: notification
216+ drag.target: !fullscreen ? notification : undefined
203217 drag.axis: Drag.XAxis
204218 drag.minimumX: -notification.width
205219 drag.maximumX: notification.width
@@ -382,7 +396,7 @@ StyledItem {
382396 objectName: "dialogListView"
383397 spacing: notification.margins
384398
385− visible: count > 0
399+ visible: count > 0 && (notification.expanded || notification.fullscreen)
386400
387401 anchors {
388402 left: parent.left
@@ -413,6 +427,7 @@ StyledItem {
413427 }
414428 onAccepted: {
415429 notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
430+ notification.dismissed()
416431 }
417432 }
418433 }
qml/Notifications/NotificationMenuItemFactory.qml+4
@@ -146,19 +146,23 @@ Loader {
146146 errorText: errorAction.valid ? errorAction.state : ""
147147 retryText: notification.body
148148 background: menuFactory.background
149+ darkenBackground: 0.4
149150
150151 onEntered: {
151152 menuModel.changeState(menuIndex, passphrase);
152153 clear(false);
154+ notification.dismissed()
153155 }
154156
155157 onCancel: {
156158 menuModel.activate(menuIndex, false);
159+ notification.dismissed()
157160 }
158161
159162 onEmergencyCall: {
160163 shell.startLockedApp("dialer-app");
161164 menuModel.activate(menuIndex, false);
165+ notification.dismissed()
162166 }
163167
164168 property var extendedData: menuData && menuData.ext || undefined
qml/Notifications/Notifications.qml+18−9
@@ -41,18 +41,25 @@ ListView {
4141 filterRegExp: RegExp(UnityNotifications.Notification.SnapDecision)
4242 }
4343
44− property bool topmostIsFullscreen: false
44+ readonly property bool topmostIsFullscreen: fullscreenIndex != -1
4545 spacing: topmostIsFullscreen ? 0 : units.gu(1)
4646
4747 currentIndex: count > 1 ? 1 : -1
4848
49+ property int fullscreenIndex: -1
50+ onFullscreenIndexChanged: {
51+ if (fullscreenIndex != -1) {
52+ positionViewAtIndex(fullscreenIndex, ListView.Beginning);
53+ }
54+ }
55+
4956 delegate: Notification {
5057 objectName: "notification" + index
5158 width: parent.width
5259 type: model.type
5360 hints: model.hints
5461 iconSource: model.icon
55− secondaryIconSource: model.secondaryIcon
62+ secondaryIconSource: model.secondaryIcon ? model.secondaryIcon : ""
5663 summary: model.summary
5764 body: model.body
5865 value: model.value ? model.value : -1
@@ -69,16 +76,18 @@ ListView {
6976 // FIXME: disabled all transitions because of LP: #1354406 workaround
7077 //layer.enabled: add.running || remove.running || populate.running
7178
72− Component.onCompleted: {
73− if (index == 1) {
74− notificationList.topmostIsFullscreen = fullscreen
79+ onFullscreenChanged: updateListTopMostIsFullscreen();
80+
81+ function updateListTopMostIsFullscreen() {
82+ if (fullscreen) {
83+ fullscreenIndex = index;
7584 }
7685 }
7786
78− onFullscreenChanged: {
79− // index 1 because 0 is the PlaceHolder...
80− if (index == 1) {
81− notificationList.topmostIsFullscreen = fullscreen
87+ onDismissed: {
88+ if (fullscreenIndex == index) {
89+ fullscreenIndex = -1;
90+ notificationList.positionViewAtBeginning();
8291 }
8392 }
8493 }
qml/Panel/Indicators/MenuItemFactory.qml+2−2
@@ -377,11 +377,11 @@ Item {
377377 property int menuIndex: -1
378378 property var extendedData: menuData && menuData.ext || undefined
379379
380− property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
380+ readonly property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
381381 LiveTimer {
382382 frequency: LiveTimer.Relative
383383 relativeTime: alarmItem.serverTime
384− onTrigger: alarmItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
384+ onTrigger: alarmItem.time = i18n.relativeDateTime(alarmItem.serverTime)
385385 }
386386
387387 text: menuData && menuData.label || ""
qml/Panel/Indicators/MessageMenuItemFactory.qml+1−5
@@ -123,11 +123,7 @@ Loader {
123123 menuModel.activate(menuIndex, false);
124124 }
125125 onTriggered: {
126− if (selected) {
127− menuDeselected();
128− } else {
129− menuSelected();
130− }
126+ menuModel.activate(menuIndex, true);
131127 }
132128 }
133129 }
qml/Panel/IndicatorsMenu.qml+17−13
@@ -39,7 +39,7 @@ Showable {
3939 property bool showOnClick: true
4040 property color panelColor: theme.palette.normal.background
4141
42− signal showTapped(point position)
42+ signal showTapped()
4343
4444 // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
4545 // use its own values. Need to ask design about this.
@@ -204,7 +204,7 @@ Showable {
204204 } else {
205205 var touchReleaseTime = new Date().getTime();
206206 if (touchReleaseTime - touchPressTime <= 300) {
207− root.showTapped(Qt.point(touchSceneX, touchSceneY));
207+ root.showTapped();
208208 }
209209 }
210210 }
@@ -233,10 +233,10 @@ Showable {
233233 stretch: true
234234 maxTotalDragDistance: openedHeight - expandedPanelHeight - handle.height
235235
236− onTouchSceneXChanged: {
236+ onTouchPositionChanged: {
237237 if (root.state === "locked") {
238− d.xDisplacementSinceLock += (touchSceneX - d.lastHideTouchSceneX)
239− d.lastHideTouchSceneX = touchSceneX;
238+ d.xDisplacementSinceLock += (touchPosition.x - d.lastHideTouchX)
239+ d.lastHideTouchX = touchPosition.x;
240240 }
241241 }
242242 }
@@ -244,7 +244,11 @@ Showable {
244244 PanelVelocityCalculator {
245245 id: yVelocityCalculator
246246 velocityThreshold: d.hasCommitted ? 0.1 : 0.3
247− trackedValue: d.activeDragHandle ? d.activeDragHandle.touchSceneY : 0
247+ trackedValue: d.activeDragHandle ?
248+ (Direction.isPositive(d.activeDragHandle.direction) ?
249+ d.activeDragHandle.distance :
250+ -d.activeDragHandle.distance)
251+ : 0
248252
249253 onVelocityAboveThresholdChanged: d.updateState()
250254 }
@@ -271,13 +275,13 @@ Showable {
271275 id: d
272276 property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
273277 property bool hasCommitted: false
274− property real lastHideTouchSceneX: 0
278+ property real lastHideTouchX: 0
275279 property real xDisplacementSinceLock: 0
276280 onXDisplacementSinceLockChanged: d.updateState()
277281
278282 property real rowMappedLateralPosition: {
279283 if (!d.activeDragHandle) return -1;
280− return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchX, 0).x;
284+ return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchPosition.x, 0).x;
281285 }
282286
283287 function updateState() {
@@ -305,7 +309,7 @@ Showable {
305309 script: {
306310 yVelocityCalculator.reset();
307311 // initial item selection
308− if (!d.hasCommitted) bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchX : -1);
312+ if (!d.hasCommitted) bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchPosition.x : -1);
309313 d.hasCommitted = false;
310314 }
311315 }
@@ -323,7 +327,7 @@ Showable {
323327 target: leftScroller
324328 lateralPosition: {
325329 if (!d.activeDragHandle) return -1;
326− var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchX, 0);
330+ var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchPosition.x, 0);
327331 return mapped.x;
328332 }
329333 }
@@ -332,7 +336,7 @@ Showable {
332336 target: rightScroller
333337 lateralPosition: {
334338 if (!d.activeDragHandle) return -1;
335− var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchX, 0);
339+ var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchPosition.x, 0);
336340 return mapped.x;
337341 }
338342 }
@@ -342,7 +346,7 @@ Showable {
342346 StateChangeScript {
343347 script: {
344348 d.xDisplacementSinceLock = 0;
345− d.lastHideTouchSceneX = hideDragHandle.touchSceneX;
349+ d.lastHideTouchX = hideDragHandle.touchPosition.x;
346350 }
347351 }
348352 PropertyChanges { target: bar; expanded: true }
@@ -354,7 +358,7 @@ Showable {
354358 PropertyChanges {
355359 target: d;
356360 hasCommitted: true
357− lastHideTouchSceneX: 0
361+ lastHideTouchX: 0
358362 xDisplacementSinceLock: 0
359363 restoreEntryValues: false
360364 }
qml/Panel/Panel.qml+21−20
@@ -30,22 +30,13 @@ Item {
3030 property real indicatorAreaShowProgress: 1.0
3131 property bool locked: false
3232
33− Rectangle {
34− id: darkenedArea
35− property real darkenedOpacity: 0.6
36− anchors {
37− fill: parent
38− topMargin: panelHeight
39− }
40− color: "black"
41− opacity: indicators.unitProgress * darkenedOpacity
33+ MouseArea {
34+ anchors.fill: parent
35+ anchors.topMargin: panelHeight
4236 visible: !indicators.fullyClosed
43−
44− MouseArea {
45− anchors.fill: parent
46− onClicked: if (indicators.fullyOpened) indicators.hide();
47− hoverEnabled: true // should also eat hover events, otherwise they will pass through
48− }
37+ enabled: visible
38+ onClicked: if (indicators.fullyOpened) indicators.hide();
39+ hoverEnabled: true // should also eat hover events, otherwise they will pass through
4940 }
5041
5142 Binding {
@@ -89,7 +80,7 @@ Item {
8980
9081 Rectangle {
9182 id: indicatorAreaBackground
92− color: callHint.visible ? UbuntuColors.green : theme.palette.normal.background
83+ color: callHint.visible ? theme.palette.normal.positive : theme.palette.normal.background
9384 anchors {
9485 top: parent.top
9586 left: parent.left
@@ -101,6 +92,7 @@ Item {
10192 }
10293
10394 MouseArea {
95+ objectName: "windowControlArea"
10496 anchors {
10597 top: parent.top
10698 left: parent.left
@@ -109,7 +101,16 @@ Item {
109101 height: indicators.minimizedPanelHeight
110102 hoverEnabled: true
111103 onClicked: callHint.visible ? callHint.showLiveCall() : PanelState.focusMaximizedApp()
112− onDoubleClicked: PanelState.maximize()
104+ onDoubleClicked: PanelState.restoreClicked()
105+
106+ property bool mouseWasPressed: false
107+ onPressed: mouseWasPressed = containsPress
108+ onMouseYChanged: {
109+ if (mouseWasPressed && mouseY > panelHeight) {
110+ PanelState.restoreClicked(); // restore the window when "dragging" the panel down
111+ mouseWasPressed = false;
112+ }
113+ }
113114
114115 // WindowControlButtons inside the mouse area, otherwise QML doesn't grok nested hover events :/
115116 // cf. https://bugreports.qt.io/browse/QTBUG-32909
@@ -126,10 +127,10 @@ Item {
126127 height: indicators.minimizedPanelHeight - anchors.topMargin - anchors.bottomMargin
127128 visible: PanelState.buttonsVisible && parent.containsMouse && !root.locked && !callHint.visible
128129 active: PanelState.buttonsVisible
130+ onCloseClicked: PanelState.closeClicked()
131+ onMinimizeClicked: PanelState.minimizeClicked()
132+ onMaximizeClicked: PanelState.restoreClicked()
129133 closeButtonShown: PanelState.closeButtonShown
130− onClose: PanelState.close()
131− onMinimize: PanelState.minimize()
132− onMaximize: PanelState.maximize()
133134 }
134135 }
135136
qml/Shell.qml+4−3
@@ -41,13 +41,15 @@ import Unity.Notifications 1.0 as NotificationBackend
4141import Unity.Session 0.1
4242import Unity.DashCommunicator 0.1
4343import Unity.Indicators 0.1 as Indicators
44−import Cursor 1.0
44+import Cursor 1.1
4545import WindowManager 0.1
4646
4747
48−Item {
48+StyledItem {
4949 id: shell
5050
51+ theme.name: "Ubuntu.Components.Themes.SuruDark"
52+
5153 // to be set from outside
5254 property int orientationAngle: 0
5355 property int orientation
@@ -171,7 +173,6 @@ Item {
171173 }
172174
173175 Component.onCompleted: {
174− theme.name = "Ubuntu.Components.Themes.SuruDark"
175176 finishStartUpTimer.start();
176177 }
177178
qml/Stages/DecoratedWindow.qml+11−7
@@ -46,9 +46,11 @@ FocusScope {
4646 property alias widthIncrement: applicationWindow.widthIncrement
4747 property alias heightIncrement: applicationWindow.heightIncrement
4848
49− signal close()
50− signal maximize()
51− signal minimize()
49+ signal closeClicked()
50+ signal maximizeClicked()
51+ signal maximizeHorizontallyClicked()
52+ signal maximizeVerticallyClicked()
53+ signal minimizeClicked()
5254 signal decorationPressed()
5355
5456 Rectangle {
@@ -62,7 +64,7 @@ FocusScope {
6264 Rectangle {
6365 anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
6466 height: units.dp(2)
65− color: UbuntuColors.orange
67+ color: theme.palette.normal.focus
6668 visible: highlightShown
6769 }
6870
@@ -86,9 +88,11 @@ FocusScope {
8688 title: applicationWindow.title
8789 visible: root.decorationShown
8890
89− onClose: root.close();
90− onMaximize: { root.decorationPressed(); root.maximize(); }
91− onMinimize: root.minimize();
91+ onCloseClicked: root.closeClicked();
92+ onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
93+ onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
94+ onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
95+ onMinimizeClicked: root.minimizeClicked();
9296 onPressed: root.decorationPressed();
9397 }
9498
qml/Stages/DesktopSpread.qml+1−1
@@ -494,7 +494,7 @@ FocusScope {
494494 // Rectangle {
495495 // anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
496496 // height: units.dp(2)
497− // color: UbuntuColors.orange
497+ // color: theme.palette.normal.focus
498498 // visible: index == 0 // TODO: should be active workspace index
499499 // }
500500 }
qml/Stages/DesktopSpreadDelegate.qml+1−1
@@ -83,7 +83,7 @@ Item {
8383 Rectangle {
8484 anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
8585 height: units.dp(2)
86− color: UbuntuColors.orange
86+ color: theme.palette.normal.focus
8787 visible: root.highlightShown
8888 antialiasing: true
8989 }
qml/Stages/DesktopStage.qml+55−43
@@ -90,7 +90,8 @@ AbstractStage {
9090 GlobalShortcut {
9191 id: minimizeRestoreShortcut
9292 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
93− onTriggered: priv.focusedAppDelegate.maximized || priv.focusedAppDelegate.maximizedLeft || priv.focusedAppDelegate.maximizedRight
93+ onTriggered: priv.focusedAppDelegate.maximized || priv.focusedAppDelegate.maximizedLeft || priv.focusedAppDelegate.maximizedRight ||
94+ priv.focusedAppDelegate.maximizedHorizontally || priv.focusedAppDelegate.maximizedVertically
9495 ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
9596 active: priv.focusedAppDelegate !== null
9697 }
@@ -159,9 +160,9 @@ AbstractStage {
159160
160161 Connections {
161162 target: PanelState
162− onClose: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
163− onMinimize: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.minimize(); } }
164− onMaximize: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.restoreFromMaximized(); } }
163+ onCloseClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.close(); } }
164+ onMinimizeClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.minimize(); } }
165+ onRestoreClicked: { if (priv.focusedAppDelegate) { priv.focusedAppDelegate.restoreFromMaximized(); } }
165166 onFocusMaximizedApp: {
166167 if (priv.foregroundMaximizedAppDelegate) {
167168 priv.foregroundMaximizedAppDelegate.focus = true;
@@ -276,19 +277,16 @@ AbstractStage {
276277 property alias widthIncrement: decoratedWindow.widthIncrement
277278 property alias heightIncrement: decoratedWindow.heightIncrement
278279
279− QtObject {
280− id: appDelegatePrivate
281− property bool maximized: false
282− property bool maximizedLeft: false
283− property bool maximizedRight: false
284− property bool minimized: false
285− }
286− readonly property alias maximized: appDelegatePrivate.maximized
287− readonly property alias maximizedLeft: appDelegatePrivate.maximizedLeft
288− readonly property alias maximizedRight: appDelegatePrivate.maximizedRight
289− readonly property alias minimized: appDelegatePrivate.minimized
280+ readonly property bool maximized: windowState & WindowStateStorage.WindowStateMaximized
281+ readonly property bool maximizedLeft: windowState & WindowStateStorage.WindowStateMaximizedLeft
282+ readonly property bool maximizedRight: windowState & WindowStateStorage.WindowStateMaximizedRight
283+ readonly property bool maximizedHorizontally: windowState & WindowStateStorage.WindowStateMaximizedHorizontally
284+ readonly property bool maximizedVertically: windowState & WindowStateStorage.WindowStateMaximizedVertically
285+ readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
290286 readonly property alias fullscreen: decoratedWindow.fullscreen
291287
288+ property int windowState: WindowStateStorage.WindowStateNormal
289+
292290 readonly property var application: model.application
293291 property bool animationsEnabled: true
294292 property alias title: decoratedWindow.title
@@ -386,43 +384,45 @@ AbstractStage {
386384
387385 function maximize(animated) {
388386 animationsEnabled = (animated === undefined) || animated;
389− appDelegatePrivate.minimized = false;
390− appDelegatePrivate.maximized = true;
391− appDelegatePrivate.maximizedLeft = false;
392− appDelegatePrivate.maximizedRight = false;
387+ windowState = WindowStateStorage.WindowStateMaximized;
388+ }
389+ function maximizeLeft(animated) {
390+ animationsEnabled = (animated === undefined) || animated;
391+ windowState = WindowStateStorage.WindowStateMaximizedLeft;
392+ }
393+ function maximizeRight(animated) {
394+ animationsEnabled = (animated === undefined) || animated;
395+ windowState = WindowStateStorage.WindowStateMaximizedRight;
393396 }
394− function maximizeLeft() {
395− appDelegatePrivate.minimized = false;
396− appDelegatePrivate.maximized = false;
397− appDelegatePrivate.maximizedLeft = true;
398− appDelegatePrivate.maximizedRight = false;
397+ function maximizeHorizontally(animated) {
398+ animationsEnabled = (animated === undefined) || animated;
399+ windowState = WindowStateStorage.WindowStateMaximizedHorizontally;
399400 }
400− function maximizeRight() {
401− appDelegatePrivate.minimized = false;
402− appDelegatePrivate.maximized = false;
403− appDelegatePrivate.maximizedLeft = false;
404− appDelegatePrivate.maximizedRight = true;
401+ function maximizeVertically(animated) {
402+ animationsEnabled = (animated === undefined) || animated;
403+ windowState = WindowStateStorage.WindowStateMaximizedVertically;
405404 }
406405 function minimize(animated) {
407406 animationsEnabled = (animated === undefined) || animated;
408− appDelegatePrivate.minimized = true;
407+ windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
409408 }
410409 function restoreFromMaximized(animated) {
411410 animationsEnabled = (animated === undefined) || animated;
412− appDelegatePrivate.minimized = false;
413− appDelegatePrivate.maximized = false;
414− appDelegatePrivate.maximizedLeft = false;
415− appDelegatePrivate.maximizedRight = false;
411+ windowState = WindowStateStorage.WindowStateNormal;
416412 }
417413 function restore(animated) {
418414 animationsEnabled = (animated === undefined) || animated;
419− appDelegatePrivate.minimized = false;
415+ windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
420416 if (maximized)
421417 maximize();
422418 else if (maximizedLeft)
423419 maximizeLeft();
424420 else if (maximizedRight)
425421 maximizeRight();
422+ else if (maximizedHorizontally)
423+ maximizeHorizontally();
424+ else if (maximizedVertically)
425+ maximizeVertically();
426426
427427 focus = true;
428428 }
@@ -453,8 +453,7 @@ AbstractStage {
453453 },
454454 State {
455455 name: "normal";
456− when: !appDelegate.maximized && !appDelegate.minimized
457− && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
456+ when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
458457 PropertyChanges {
459458 target: appDelegate;
460459 visuallyMinimized: false;
@@ -502,13 +501,23 @@ AbstractStage {
502501 requestedHeight: appContainer.height - PanelState.panelHeight
503502 }
504503 },
504+ State {
505+ name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
506+ PropertyChanges { target: appDelegate; x: root.leftMargin }
507+ PropertyChanges { target: decoratedWindow; requestedWidth: appContainer.width - root.leftMargin }
508+ },
509+ State {
510+ name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
511+ PropertyChanges { target: appDelegate; y: PanelState.panelHeight }
512+ PropertyChanges { target: decoratedWindow; requestedHeight: appContainer.height - PanelState.panelHeight }
513+ },
505514 State {
506515 name: "minimized"; when: appDelegate.minimized
507516 PropertyChanges {
508517 target: appDelegate;
509518 x: -appDelegate.width / 2;
510519 scale: units.gu(5) / appDelegate.width;
511− opacity: 0
520+ opacity: 0;
512521 visuallyMinimized: true;
513522 visuallyMaximized: false
514523 }
@@ -611,10 +620,13 @@ AbstractStage {
611620 requestedWidth: appDelegate.requestedWidth
612621 requestedHeight: appDelegate.requestedHeight
613622
614− onClose: { appDelegate.close(); }
615− onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
616− ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
617− onMinimize: appDelegate.minimize()
623+ onCloseClicked: { appDelegate.close(); }
624+ onMaximizeClicked: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
625+ || appDelegate.maximizedHorizontally || appDelegate.maximizedVertically
626+ ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
627+ onMaximizeHorizontallyClicked: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
628+ onMaximizeVerticallyClicked: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
629+ onMinimizeClicked: appDelegate.minimize()
618630 onDecorationPressed: { appDelegate.focus = true; }
619631 }
620632
@@ -650,7 +662,7 @@ AbstractStage {
650662 }
651663 }
652664
653− DirectionalDragArea {
665+ SwipeArea {
654666 direction: Direction.Leftwards
655667 anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
656668 width: units.gu(1)
qml/Stages/PhoneStage.qml+4−4
@@ -713,7 +713,7 @@ AbstractStage {
713713 enabled: spreadDragArea.dragging
714714 }
715715
716− DirectionalDragArea {
716+ SwipeArea {
717717 id: spreadDragArea
718718 objectName: "spreadDragArea"
719719 direction: Direction.Leftwards
@@ -724,10 +724,10 @@ AbstractStage {
724724
725725 property var gesturePoints: new Array()
726726
727− onTouchXChanged: {
727+ onTouchPositionChanged: {
728728 if (dragging) {
729729 // Gesture recognized. Let's move the spreadView with the finger
730− var dragX = Math.min(touchX + width, width); // Prevent dragging rightwards
730+ var dragX = Math.min(touchPosition.x + width, width); // Prevent dragging rightwards
731731 dragX = -dragX + spreadDragArea.width - spreadView.shift;
732732 // Don't allow dragging further than the animation crossing with phase2's animation
733733 var maxMovement = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
@@ -739,7 +739,7 @@ AbstractStage {
739739 spreadView.contentX = -spreadView.shift;
740740 }
741741
742− gesturePoints.push(touchX);
742+ gesturePoints.push(touchPosition.x);
743743 }
744744
745745 onDraggingChanged: {
qml/Stages/SideStage.qml+1−2
@@ -98,8 +98,7 @@ Showable {
9898 id: hideSideStageDragArea
9999 objectName: "hideSideStageDragArea"
100100
101− direction: Direction.Leftwards
102− rotation: 180
101+ direction: Direction.Rightwards
103102 enabled: root.shown
104103 anchors.right: root.left
105104 width: sideStageDragHandle.width
qml/Stages/Splash.qml+6−17
@@ -29,7 +29,7 @@ Item {
2929 property color footerColor: d.undefinedColor
3030 property alias imageSource: overlaidImage.source
3131 property url icon
32− property alias title: headerConfig.title
32+ property alias title: header.title
3333 property alias showHeader: header.visible
3434
3535 Ambiance.Palette {
@@ -75,25 +75,14 @@ Item {
7575 style: Component { MainViewStyle {theme: styledItem.fakeTheme} }
7676 }
7777
78− Ambiance.PageHeadStyle {
79− // FIXME: Replace PageHeadStyle by PageHeader from Ubuntu.Components 1.3.
78+ PageHeader {
8079 id: header
81− anchors {
82− left: parent.left;
83− right: parent.right
84− }
85− property var styledItem: header
86− // FIXME Keep in sync with SDK's MainView.qml values of these two colors
87− property color dividerColor: Qt.darker(styledItem.backgroundColor, 1.1)
88− property color panelColor: Qt.lighter(styledItem.backgroundColor, 1.1)
89− panelForegroundColor: config.foregroundColor
90− backgroundColor: "transparent"
91− config: PageHeadConfiguration {
92− id: headerConfig
80+ anchors { left: parent.left; right: parent.right }
81+ StyleHints {
9382 foregroundColor: styledItem.fakeTheme.palette.normal.backgroundText
83+ backgroundColor: "transparent"
84+ dividerColor: styledItem.fakeTheme.palette.normal.base
9485 }
95−
96− property var contents: null
9786 }
9887
9988 Image {
qml/Stages/SpreadDelegate.qml+1−1
@@ -286,7 +286,7 @@ FocusScope {
286286 Rectangle {
287287 anchors { left: selectionHighlight.left; right: selectionHighlight.right; bottom: selectionHighlight.bottom; }
288288 height: units.dp(2)
289− color: UbuntuColors.orange
289+ color: theme.palette.normal.focus
290290 visible: root.highlightShown
291291 antialiasing: true
292292 }
qml/Stages/SurfaceContainer.qml+3
@@ -34,6 +34,9 @@ FocusScope {
3434 property int surfaceOrientationAngle: 0
3535 property bool resizeSurface: true
3636 property bool isPromptSurface: false
37+ // FIME - dont export, use interactive property. Need to fix qtmir to handle consumesInputChanged
38+ // to update surface activeFocus. See mock MirSurfaceItem.
39+ property alias consumesInput: surfaceItem.consumesInput
3740
3841 onSurfaceChanged: {
3942 // Not a binding because animations might remove the surface from the surfaceItem
qml/Stages/TabletStage.qml+8−7
@@ -752,7 +752,7 @@ AbstractStage {
752752
753753 readonly property bool wantsMainStage: stage == ApplicationInfoInterface.MainStage
754754
755− readonly property bool isDash: model.application.appId == "unity8-dash"
755+ readonly property bool isDash: application.appId == "unity8-dash"
756756
757757 onFocusChanged: {
758758 if (focus && !spreadRepeater.startingUp) {
@@ -768,7 +768,7 @@ AbstractStage {
768768 onFocusRequested: spreadTile.focus = true;
769769 }
770770 Connections {
771− target: model.application
771+ target: spreadTile.application
772772 onFocusRequested: {
773773 if (!model.surface) {
774774 // when an app has no surfaces, we assume there's only one entry representing it:
@@ -844,7 +844,7 @@ AbstractStage {
844844 _constructing = false;
845845 }
846846 Component.onDestruction: {
847− WindowStateStorage.saveStage(model.application.appId, stage);
847+ WindowStateStorage.saveStage(application.appId, stage);
848848 }
849849
850850 function refreshStage() {
@@ -1073,6 +1073,7 @@ AbstractStage {
10731073
10741074 surface: spreadDelegate ? spreadDelegate.surface : null
10751075
1076+ consumesInput: false
10761077 interactive: false
10771078 resizeSurface: false
10781079 focus: false
@@ -1105,7 +1106,7 @@ AbstractStage {
11051106 enabled: spreadDragArea.dragging
11061107 }
11071108
1108− DirectionalDragArea {
1109+ SwipeArea {
11091110 id: spreadDragArea
11101111 objectName: "spreadDragArea"
11111112 x: parent.width - root.dragAreaWidth
@@ -1116,18 +1117,18 @@ AbstractStage {
11161117
11171118 property var gesturePoints: new Array()
11181119
1119− onTouchXChanged: {
1120+ onTouchPositionChanged: {
11201121 if (!dragging) {
11211122 spreadView.phase = 0;
11221123 spreadView.contentX = -spreadView.shift;
11231124 }
11241125
11251126 if (dragging) {
1126− var dragX = -touchX + spreadDragArea.width - spreadView.shift;
1127+ var dragX = -touchPosition.x + spreadDragArea.width - spreadView.shift;
11271128 var maxDrag = spreadView.width * spreadView.positionMarker4 - spreadView.shift;
11281129 spreadView.contentX = Math.min(dragX, maxDrag);
11291130 }
1130− gesturePoints.push(touchX);
1131+ gesturePoints.push(touchPosition.x);
11311132 }
11321133
11331134 onDraggingChanged: {
qml/Stages/WindowDecoration.qml+12−8
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 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
@@ -29,11 +29,13 @@ MouseArea {
2929 property bool active: false
3030 hoverEnabled: true
3131
32− signal close()
33− signal minimize()
34− signal maximize()
32+ signal closeClicked()
33+ signal minimizeClicked()
34+ signal maximizeClicked()
35+ signal maximizeHorizontallyClicked()
36+ signal maximizeVerticallyClicked()
3537
36− onDoubleClicked: root.maximize()
38+ onDoubleClicked: root.maximizeClicked()
3739
3840 QtObject {
3941 id: priv
@@ -84,10 +86,12 @@ MouseArea {
8486 id: buttons
8587 height: parent.height
8688 active: root.active
89+ onCloseClicked: root.closeClicked();
90+ onMinimizeClicked: root.minimizeClicked();
91+ onMaximizeClicked: root.maximizeClicked();
92+ onMaximizeHorizontallyClicked: root.maximizeHorizontallyClicked();
93+ onMaximizeVerticallyClicked: root.maximizeVerticallyClicked();
8794 closeButtonShown: root.target.application.appId !== "unity8-dash"
88− onClose: root.close();
89− onMinimize: root.minimize();
90− onMaximize: root.maximize();
9195 }
9296
9397 Label {
qml/Stages/WindowResizeArea.qml+25−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 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
@@ -81,15 +81,35 @@ MouseArea {
8181 target.y = Qt.binding(function() { return Math.max(Math.min(windowGeometry.y, root.screenHeight - target.requestedHeight), PanelState.panelHeight); });
8282
8383 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
84− if (windowState === WindowStateStorage.WindowStateMaximized) {
85− target.maximize(false)
84+ switch (windowState) {
85+ case WindowStateStorage.WindowStateNormal:
86+ break;
87+ case WindowStateStorage.WindowStateMaximized:
88+ target.maximize(false);
89+ break;
90+ case WindowStateStorage.WindowStateMaximizedLeft:
91+ target.maximizeLeft(false);
92+ break;
93+ case WindowStateStorage.WindowStateMaximizedRight:
94+ target.maximizeRight(false);
95+ break;
96+ case WindowStateStorage.WindowStateMaximizedHorizontally:
97+ target.maximizeHorizontally(false);
98+ break;
99+ case WindowStateStorage.WindowStateMaximizedVertically:
100+ target.maximizeVertically(false);
101+ break;
102+ default:
103+ console.warn("Unsupported window state");
104+ break;
86105 }
106+
87107 priv.updateNormalGeometry();
88108 }
89109
90110 function saveWindowState() {
91− windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
92− windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
111+ windowStateStorage.saveState(root.windowId, target.windowState & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
112+ windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight));
93113 }
94114
95115 QtObject {
qml/Tutorial/TutorialBottom.qml+3−3
@@ -51,7 +51,7 @@ TutorialPage {
5151 readonly property real dragAreaHeight: units.gu(3) // based on PageWithBottomEdge.qml
5252 readonly property real targetDistance: height * 0.2 + dragAreaHeight // based on PageWithBottomEdge.qml
5353
54− opacityOverride: dragArea.dragging ? 1 - (-dragArea.distance / targetDistance) : 1
54+ opacityOverride: dragArea.dragging ? 1 - (dragArea.distance / targetDistance) : 1
5555
5656 mouseArea {
5757 anchors.bottomMargin: root.dragAreaHeight
@@ -95,9 +95,9 @@ TutorialPage {
9595
9696 // Watches drag events but does not intercept them, so that the app beneath
9797 // will still drag the bottom edge up.
98− DirectionalDragArea {
98+ SwipeArea {
9999 id: dragArea
100− monitorOnly: true
100+ grabGesture: false
101101 direction: Direction.Upwards
102102 anchors.left: parent.left
103103 anchors.right: parent.right
qml/Wizard/Pages/50-timezone.qml+5−2
@@ -18,7 +18,7 @@ import QtQuick 2.4
1818import QtQuick.Layouts 1.1
1919import Ubuntu.Components 1.3
2020import Wizard 0.1
21−import Ubuntu.SystemSettings.TimeDate 1.0
21+import Ubuntu.SystemSettings.TimeDate 1.1
2222import Utils 0.1 as Utils
2323import ".." as LocalComponents
2424
@@ -30,6 +30,7 @@ LocalComponents.Page {
3030 forwardButtonSourceComponent: forwardButton
3131
3232 property string selectedTimeZone: ""
33+ property string selectedTimeZoneName: ""
3334 readonly property bool showingMap: wideMode && width >= units.gu(110)
3435
3536 // for testing
@@ -67,6 +68,7 @@ LocalComponents.Page {
6768
6869 function resetViews() {
6970 selectedTimeZone = ""
71+ selectedTimeZoneName = ""
7072 tzList.currentIndex = -1
7173 highlightImage.source = ""
7274 pinImage.x = 0;
@@ -144,6 +146,7 @@ LocalComponents.Page {
144146 highlightTimezone(offset);
145147 ListView.view.currentIndex = index;
146148 selectedTimeZone = timeZone;
149+ selectedTimeZoneName = city;
147150 //print("Clicked at city with coords:", longitude, latitude);
148151 //print("Clicked on TZ:", timeZone);
149152 //print("Highlight at (x,y):", longitudeToX(longitude, map.width), latitudeToY(latitude, map.height));
@@ -267,7 +270,7 @@ LocalComponents.Page {
267270 text: i18n.tr("Next")
268271 enabled: selectedTimeZone != ""
269272 onClicked: {
270− timeDatePanel.timeZone = selectedTimeZone;
273+ timeDatePanel.setTimeZone(selectedTimeZone, selectedTimeZoneName);
271274 pageStack.next();
272275 }
273276 }
src/CMakeLists.txt+1−4
@@ -2,7 +2,6 @@ pkg_check_modules(CONNECTIVITY REQUIRED connectivity-qt1)
22
33include_directories(
44 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
5− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
65 ${CONNECTIVITY_INCLUDE_DIRS}
76)
87
@@ -24,6 +23,7 @@ set(SOURCE_FILES
2423 ShellApplication.cpp
2524 ShellView.cpp
2625 UnityCommandLineParser.cpp
26+ UnixSignalHandler.cpp
2727 ${QML_FILES} # This is to make qml and image files appear in the IDE's project tree
2828)
2929
@@ -44,9 +44,6 @@ if (ENABLE_TOUCH_EMULATION)
4444 target_link_libraries(${SHELL_APP} ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
4545endif()
4646
47−# For it to find libUbuntuGestures.so
48−set_target_properties(${SHELL_APP} PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}")
49−
5047# install binaries
5148install(TARGETS ${SHELL_APP}
5249 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
src/Dash/CMakeLists.txt+1
@@ -1,6 +1,7 @@
11set(DASH_SRCS
22 main.cpp
33 ../CachingNetworkManagerFactory.cpp
4+ ../UnixSignalHandler.cpp
45)
56
67if (ENABLE_TOUCH_EMULATION)
src/Dash/main.cpp+6
@@ -32,6 +32,7 @@
3232 #include "../MouseTouchAdaptor.h"
3333#endif
3434#include "../CachingNetworkManagerFactory.h"
35+#include "../UnixSignalHandler.h"
3536
3637int main(int argc, const char *argv[])
3738{
@@ -116,6 +117,11 @@ int main(int argc, const char *argv[])
116117 view->setSource(source);
117118 view->show();
118119
120+ UnixSignalHandler signalHandler([]{
121+ QGuiApplication::exit(0);
122+ });
123+ signalHandler.setupUnixSignalHandlers();
124+
119125 int result = application->exec();
120126
121127 delete view;
tools/unix-signal-handler.cpp → src/UnixSignalHandler.cpprenamed+1−1
@@ -16,7 +16,7 @@
1616 * Author: Marcus Tomlinson <marcus.tomlinson@canonical.com>
1717 */
1818
19−#include "unix-signal-handler.h"
19+#include "UnixSignalHandler.h"
2020
2121#include <QDebug>
2222
tools/unix-signal-handler.h → src/UnixSignalHandler.hrenamed

The content is the same.

src/main.cpp+6
@@ -17,6 +17,7 @@
1717// local
1818#include "ShellApplication.h"
1919#include "qmldebuggerutils.h"
20+#include "UnixSignalHandler.h"
2021
2122int main(int argc, const char *argv[])
2223{
@@ -32,6 +33,11 @@ int main(int argc, const char *argv[])
3233
3334 ShellApplication *application = new ShellApplication(argc, (char**)argv, isMirServer);
3435
36+ UnixSignalHandler signalHandler([]{
37+ QGuiApplication::exit(0);
38+ });
39+ signalHandler.setupUnixSignalHandlers();
40+
3541 int result = application->exec();
3642
3743 application->destroyResources();
tests/CMakeLists.txt−1
@@ -135,7 +135,6 @@ install(DIRECTORY data graphics
135135
136136
137137# Actual test definitions
138−add_subdirectory(libs)
139138add_subdirectory(plugins)
140139add_subdirectory(qmltests)
141140add_subdirectory(whitespace)
tests/autopilot/unity8/dash.py+2−3
@@ -175,9 +175,8 @@ class Dash(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
175175 return page_header.select_single(objectName='searchTextField')
176176
177177 def _get_current_page_header(self):
178− dashContentList = self.select_single(objectName="dashContentList")
179− all_headers = dashContentList.select_many("QQuickLoader")
180− for i in all_headers:
178+ all_scopes = self.dash_content_list.select_many("GenericScopeView")
179+ for i in all_scopes:
181180 if i.isCurrent:
182181 return i.select_single(objectName="scopePageHeader")
183182 return None
tests/libs/CMakeLists.txtdeleted−1
@@ -1 +0,0 @@
1−add_subdirectory(UbuntuGestures)
tests/libs/UbuntuGestures/CMakeLists.txtdeleted−20
@@ -1,20 +0,0 @@
1−include_directories(
2− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
3− ${CMAKE_CURRENT_BINARY_DIR}
4− )
5−
6−macro(add_gesture_test CLASSNAME)
7− add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp)
8− qt5_use_modules(${CLASSNAME}TestExec Test Core Gui Quick)
9− target_link_libraries(${CLASSNAME}TestExec UbuntuGestures)
10− install(TARGETS ${CLASSNAME}TestExec
11− DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/libs/UbuntuGestures"
12− )
13− set_target_properties(${CLASSNAME}TestExec PROPERTIES
14− INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${SHELL_PRIVATE_LIBDIR}"
15− )
16−
17− add_unity8_unittest(${CLASSNAME} ${CLASSNAME}TestExec)
18−endmacro(add_gesture_test)
19−
20−add_gesture_test(TouchRegistry)
tests/libs/UbuntuGestures/tst_TouchRegistry.cppdeleted−974
@@ -1,974 +0,0 @@
1−/*
2− * Copyright (C) 2014-2015 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 <QtTest>
18−#include <QSet>
19−#include <QTouchEvent>
20−
21−#include <Timer.h>
22−#include <TouchOwnershipEvent.h>
23−#include <TouchRegistry.h>
24−#include <UnownedTouchEvent.h>
25−
26−using namespace UbuntuGestures;
27−
28−class TouchMemento {
29−public:
30− TouchMemento(const QTouchEvent *touchEvent);
31− Qt::TouchPointStates touchPointStates;
32− QList<QTouchEvent::TouchPoint> touchPoints;
33−
34− bool containsTouchWithId(int touchId) const;
35−};
36−
37−class DummyCandidate : public QQuickItem
38−{
39− Q_OBJECT
40−public:
41− bool event(QEvent *e) override;
42− QSet<int> ownedTouches;
43− QSet<int> lostTouches;
44− QList<TouchMemento> unownedTouchEvents;
45−
46−Q_SIGNALS:
47− void gainedOwnership();
48− void lostOwnership();
49−};
50−
51−class tst_TouchRegistry : public QObject
52−{
53− Q_OBJECT
54−public:
55− tst_TouchRegistry() : QObject(0) { }
56−private Q_SLOTS:
57− void initTestCase() {} // will be called before the first test function is executed
58− void cleanupTestCase() {} // will be called after the last test function was executed.
59−
60− void init(); // called right before each and every test function is executed
61− void cleanup(); // called right after each and every test function is executed
62−
63− void requestWithNoCandidates();
64− void lateCandidateRequestGetsNothing();
65− void lateCandidateGestOwnershipOnceEarlyCandidateQuits();
66− void dispatchesTouchEventsToCandidates();
67− void dispatchesTouchEventsToWatchers();
68− void keepDispatchingToWatchersAfterLastCandidateGivesUp();
69− void candidatesAndWatchers_1();
70− void candidatesAndWatchers_2();
71− void rejectingTouchfterItsEnd();
72− void removeOldUndecidedCandidates();
73− void interimOwnerWontGetUnownedTouchEvents();
74− void candidateVanishes();
75− void candicateOwnershipReentrace();
76−
77−private:
78− TouchRegistry *touchRegistry;
79−};
80−
81−void tst_TouchRegistry::init()
82−{
83− touchRegistry = TouchRegistry::instance();
84−}
85−
86−void tst_TouchRegistry::cleanup()
87−{
88− delete touchRegistry;
89−}
90−
91−void tst_TouchRegistry::requestWithNoCandidates()
92−{
93− DummyCandidate candidate;
94−
95− {
96− QList<QTouchEvent::TouchPoint> touchPoints;
97− touchPoints.append(QTouchEvent::TouchPoint(0));
98− touchPoints[0].setState(Qt::TouchPointPressed);
99− QTouchEvent touchEvent(QEvent::TouchBegin,
100− 0 /* device */,
101− Qt::NoModifier,
102− Qt::TouchPointPressed,
103− touchPoints);
104− touchRegistry->update(&touchEvent);
105− }
106−
107− touchRegistry->requestTouchOwnership(0, &candidate);
108−
109− QVERIFY(candidate.ownedTouches.contains(0));
110−}
111−
112−void tst_TouchRegistry::lateCandidateRequestGetsNothing()
113−{
114− DummyCandidate earlyCandidate;
115− earlyCandidate.setObjectName("early");
116− DummyCandidate lateCandidate;
117− lateCandidate.setObjectName("late");
118−
119− {
120− QList<QTouchEvent::TouchPoint> touchPoints;
121− touchPoints.append(QTouchEvent::TouchPoint(0));
122− touchPoints[0].setState(Qt::TouchPointPressed);
123− QTouchEvent touchEvent(QEvent::TouchBegin,
124− 0 /* device */,
125− Qt::NoModifier,
126− Qt::TouchPointPressed,
127− touchPoints);
128− touchRegistry->update(&touchEvent);
129− }
130−
131− touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
132− touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
133−
134− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
135− QVERIFY(lateCandidate.ownedTouches.isEmpty());
136−
137− touchRegistry->requestTouchOwnership(0, &lateCandidate);
138−
139− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
140− QVERIFY(lateCandidate.ownedTouches.isEmpty());
141−
142− touchRegistry->requestTouchOwnership(0, &earlyCandidate);
143−
144− QVERIFY(earlyCandidate.ownedTouches.contains(0));
145− QVERIFY(lateCandidate.ownedTouches.isEmpty());
146−}
147−
148−void tst_TouchRegistry::lateCandidateGestOwnershipOnceEarlyCandidateQuits()
149−{
150− DummyCandidate earlyCandidate;
151− DummyCandidate lateCandidate;
152−
153− {
154− QList<QTouchEvent::TouchPoint> touchPoints;
155− touchPoints.append(QTouchEvent::TouchPoint(0));
156− touchPoints[0].setState(Qt::TouchPointPressed);
157− QTouchEvent touchEvent(QEvent::TouchBegin,
158− 0 /* device */,
159− Qt::NoModifier,
160− Qt::TouchPointPressed,
161− touchPoints);
162− touchRegistry->update(&touchEvent);
163− }
164−
165− touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
166− touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
167−
168− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
169− QVERIFY(lateCandidate.ownedTouches.isEmpty());
170−
171− touchRegistry->requestTouchOwnership(0, &lateCandidate);
172−
173− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
174− QVERIFY(lateCandidate.ownedTouches.isEmpty());
175−
176− touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
177−
178− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
179− QVERIFY(lateCandidate.ownedTouches.contains(0));
180−}
181−
182−void tst_TouchRegistry::dispatchesTouchEventsToCandidates()
183−{
184− QQuickItem rootItem;
185−
186− DummyCandidate candidate0;
187− candidate0.setObjectName("0");
188− candidate0.setParentItem(&rootItem);
189− candidate0.setX(1);
190− candidate0.setY(2);
191−
192− DummyCandidate candidate1;
193− candidate1.setObjectName("1");
194− candidate0.setParentItem(&rootItem);
195− candidate1.setX(3);
196− candidate1.setY(4);
197−
198− {
199− QList<QTouchEvent::TouchPoint> touchPoints;
200− touchPoints.append(QTouchEvent::TouchPoint(0));
201− touchPoints[0].setState(Qt::TouchPointPressed);
202− touchPoints[0].setRect(QRect(10, 10, 0, 0));
203− QTouchEvent touchEvent(QEvent::TouchBegin,
204− 0 /* device */,
205− Qt::NoModifier,
206− Qt::TouchPointPressed,
207− touchPoints);
208− touchRegistry->update(&touchEvent);
209− }
210−
211− touchRegistry->addCandidateOwnerForTouch(0, &candidate0);
212−
213− {
214− QList<QTouchEvent::TouchPoint> touchPoints;
215− touchPoints.append(QTouchEvent::TouchPoint(0));
216− touchPoints[0].setState(Qt::TouchPointMoved);
217− touchPoints[0].setRect(QRect(11, 11, 0, 0));
218− touchPoints.append(QTouchEvent::TouchPoint(1));
219− touchPoints[1].setState(Qt::TouchPointPressed);
220− touchPoints[1].setRect(QRect(20, 20, 0, 0));
221− QTouchEvent touchEvent(QEvent::TouchUpdate,
222− 0 /* device */,
223− Qt::NoModifier,
224− Qt::TouchPointPressed | Qt::TouchPointMoved,
225− touchPoints);
226− touchRegistry->update(&touchEvent);
227− }
228−
229− // candidate0 should have received an update on the touch he's interested on.
230− QCOMPARE(candidate0.unownedTouchEvents.count(), 1);
231− // make sure only touch 0 is there (i.e. no mention of touch 1)
232− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints.count(), 1);
233− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].id(), 0);
234− // Check that the points local coordinates have been mapped to candidate0's coordinate system.
235− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - candidate0.x());
236− QCOMPARE(candidate0.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - candidate0.y());
237−
238− touchRegistry->addCandidateOwnerForTouch(1, &candidate1);
239−
240− {
241− QList<QTouchEvent::TouchPoint> touchPoints;
242− touchPoints.append(QTouchEvent::TouchPoint(0));
243− touchPoints[0].setState(Qt::TouchPointMoved);
244− touchPoints[0].setRect(QRect(12, 12, 0, 0));
245− touchPoints.append(QTouchEvent::TouchPoint(1));
246− touchPoints[1].setState(Qt::TouchPointMoved);
247− touchPoints[1].setRect(QRect(21, 21, 0, 0));
248− QTouchEvent touchEvent(QEvent::TouchUpdate,
249− 0 /* device */,
250− Qt::NoModifier,
251− Qt::TouchPointPressed | Qt::TouchPointMoved,
252− touchPoints);
253− touchRegistry->update(&touchEvent);
254− }
255−
256− // candidate0 gets updates only for touch 0 and
257− // candidate1 gets updates only for touch 1
258−
259− QCOMPARE(candidate0.unownedTouchEvents.count(), 2);
260− QCOMPARE(candidate0.unownedTouchEvents[1].touchPoints.count(), 1);
261− QCOMPARE(candidate0.unownedTouchEvents[1].touchPoints[0].id(), 0);
262−
263− QCOMPARE(candidate1.unownedTouchEvents.count(), 1);
264− QCOMPARE(candidate1.unownedTouchEvents[0].touchPoints.count(), 1);
265− QCOMPARE(candidate1.unownedTouchEvents[0].touchPoints[0].id(), 1);
266−}
267−
268−void tst_TouchRegistry::dispatchesTouchEventsToWatchers()
269−{
270− QQuickItem rootItem;
271−
272− DummyCandidate watcher;
273− watcher.setObjectName("watcher");
274− watcher.setParentItem(&rootItem);
275− watcher.setX(1);
276− watcher.setY(2);
277−
278− {
279− QList<QTouchEvent::TouchPoint> touchPoints;
280− touchPoints.append(QTouchEvent::TouchPoint(0));
281− touchPoints[0].setState(Qt::TouchPointPressed);
282− touchPoints[0].setRect(QRect(10, 10, 0, 0));
283− QTouchEvent touchEvent(QEvent::TouchBegin,
284− 0 /* device */,
285− Qt::NoModifier,
286− Qt::TouchPointPressed,
287− touchPoints);
288− touchRegistry->update(&touchEvent);
289− }
290−
291− touchRegistry->addTouchWatcher(0, &watcher);
292−
293− {
294− QList<QTouchEvent::TouchPoint> touchPoints;
295− touchPoints.append(QTouchEvent::TouchPoint(0));
296− touchPoints[0].setState(Qt::TouchPointMoved);
297− touchPoints[0].setRect(QRect(11, 11, 0, 0));
298− touchPoints.append(QTouchEvent::TouchPoint(1));
299− touchPoints[1].setState(Qt::TouchPointPressed);
300− touchPoints[1].setRect(QRect(20, 20, 0, 0));
301− QTouchEvent touchEvent(QEvent::TouchUpdate,
302− 0 /* device */,
303− Qt::NoModifier,
304− Qt::TouchPointPressed | Qt::TouchPointMoved,
305− touchPoints);
306− touchRegistry->update(&touchEvent);
307− }
308−
309− // watcher should have received an update on the touch he's interested on.
310− QCOMPARE(watcher.unownedTouchEvents.count(), 1);
311− // make sure only touch 0 is there (i.e. no mention of touch 1)
312− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints.count(), 1);
313− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].id(), 0);
314− // Check that the points local coordinates have been mapped to watcher's coordinate system.
315− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].rect().x(), 11 - watcher.x());
316− QCOMPARE(watcher.unownedTouchEvents[0].touchPoints[0].rect().y(), 11 - watcher.y());
317−
318− {
319− QList<QTouchEvent::TouchPoint> touchPoints;
320− touchPoints.append(QTouchEvent::TouchPoint(0));
321− touchPoints[0].setState(Qt::TouchPointMoved);
322− touchPoints[0].setRect(QRect(12, 12, 0, 0));
323− touchPoints.append(QTouchEvent::TouchPoint(1));
324− touchPoints[1].setState(Qt::TouchPointMoved);
325− touchPoints[1].setRect(QRect(21, 21, 0, 0));
326− QTouchEvent touchEvent(QEvent::TouchUpdate,
327− 0 /* device */,
328− Qt::NoModifier,
329− Qt::TouchPointPressed | Qt::TouchPointMoved,
330− touchPoints);
331− touchRegistry->update(&touchEvent);
332− }
333−
334− // watcher gets updates only for touch 0
335−
336− QCOMPARE(watcher.unownedTouchEvents.count(), 2);
337− QCOMPARE(watcher.unownedTouchEvents[1].touchPoints.count(), 1);
338− QCOMPARE(watcher.unownedTouchEvents[1].touchPoints[0].id(), 0);
339−}
340−
341−void tst_TouchRegistry::keepDispatchingToWatchersAfterLastCandidateGivesUp()
342−{
343− DummyCandidate item;
344−
345− {
346− QList<QTouchEvent::TouchPoint> touchPoints;
347− touchPoints.append(QTouchEvent::TouchPoint(0));
348− touchPoints[0].setState(Qt::TouchPointPressed);
349− QTouchEvent touchEvent(QEvent::TouchBegin,
350− 0 /* device */,
351− Qt::NoModifier,
352− Qt::TouchPointPressed,
353− touchPoints);
354− touchRegistry->update(&touchEvent);
355− }
356−
357− touchRegistry->addCandidateOwnerForTouch(0, &item);
358−
359− {
360− QList<QTouchEvent::TouchPoint> touchPoints;
361− touchPoints.append(QTouchEvent::TouchPoint(0));
362− touchPoints[0].setState(Qt::TouchPointMoved);
363− touchPoints.append(QTouchEvent::TouchPoint(1));
364− touchPoints[1].setState(Qt::TouchPointPressed);
365− QTouchEvent touchEvent(QEvent::TouchUpdate,
366− 0 /* device */,
367− Qt::NoModifier,
368− Qt::TouchPointPressed | Qt::TouchPointMoved,
369− touchPoints);
370− touchRegistry->update(&touchEvent);
371− }
372−
373− QCOMPARE(item.unownedTouchEvents.count(), 1);
374− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 1);
375− QCOMPARE(item.unownedTouchEvents[0].touchPoints[0].id(), 0);
376− item.unownedTouchEvents.clear();
377−
378− touchRegistry->addTouchWatcher(1, &item);
379−
380− {
381− QList<QTouchEvent::TouchPoint> touchPoints;
382− touchPoints.append(QTouchEvent::TouchPoint(0));
383− touchPoints[0].setState(Qt::TouchPointMoved);
384− touchPoints.append(QTouchEvent::TouchPoint(1));
385− touchPoints[1].setState(Qt::TouchPointMoved);
386− QTouchEvent touchEvent(QEvent::TouchUpdate,
387− 0 /* device */,
388− Qt::NoModifier,
389− Qt::TouchPointMoved,
390− touchPoints);
391− touchRegistry->update(&touchEvent);
392− }
393−
394− QCOMPARE(item.unownedTouchEvents.count(), 1);
395− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 2);
396− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(0));
397− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
398− item.unownedTouchEvents.clear();
399−
400− {
401− QList<QTouchEvent::TouchPoint> touchPoints;
402− touchPoints.append(QTouchEvent::TouchPoint(0));
403− touchPoints[0].setState(Qt::TouchPointReleased);
404− touchPoints.append(QTouchEvent::TouchPoint(1));
405− touchPoints[1].setState(Qt::TouchPointMoved);
406− QTouchEvent touchEvent(QEvent::TouchUpdate,
407− 0 /* device */,
408− Qt::NoModifier,
409− Qt::TouchPointReleased | Qt::TouchPointMoved,
410− touchPoints);
411− touchRegistry->update(&touchEvent);
412− }
413−
414− QCOMPARE(item.unownedTouchEvents.count(), 1);
415− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 2);
416− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(0));
417− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
418− item.unownedTouchEvents.clear();
419−
420− touchRegistry->removeCandidateOwnerForTouch(0, &item);
421−
422− {
423− QList<QTouchEvent::TouchPoint> touchPoints;
424− touchPoints.append(QTouchEvent::TouchPoint(1));
425− touchPoints[0].setState(Qt::TouchPointReleased);
426− QTouchEvent touchEvent(QEvent::TouchEnd,
427− 0 /* device */,
428− Qt::NoModifier,
429− Qt::TouchPointReleased,
430− touchPoints);
431− touchRegistry->update(&touchEvent);
432− }
433−
434− QCOMPARE(item.unownedTouchEvents.count(), 1);
435− QCOMPARE(item.unownedTouchEvents[0].touchPoints.count(), 1);
436− QVERIFY(item.unownedTouchEvents[0].containsTouchWithId(1));
437− item.unownedTouchEvents.clear();
438−
439− QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
440−}
441−
442−/*
443− Regression test that reproduces a problematic scenario that came up during manual testing.
444− It reproduces the interaction between TouchRegistry and a DirectionalDragArea
445− */
446−void tst_TouchRegistry::candidatesAndWatchers_1()
447−{
448− DummyCandidate item;
449−
450− {
451− QList<QTouchEvent::TouchPoint> touchPoints;
452− touchPoints.append(QTouchEvent::TouchPoint(0));
453− touchPoints[0].setState(Qt::TouchPointPressed);
454− QTouchEvent touchEvent(QEvent::TouchBegin,
455− 0 /* device */,
456− Qt::NoModifier,
457− Qt::TouchPointPressed,
458− touchPoints);
459− touchRegistry->update(&touchEvent);
460− }
461−
462− touchRegistry->addCandidateOwnerForTouch(0, &item);
463−
464− {
465− QList<QTouchEvent::TouchPoint> touchPoints;
466− touchPoints.append(QTouchEvent::TouchPoint(0));
467− touchPoints[0].setState(Qt::TouchPointMoved);
468− touchPoints.append(QTouchEvent::TouchPoint(1));
469− touchPoints[1].setState(Qt::TouchPointPressed);
470− QTouchEvent touchEvent(QEvent::TouchUpdate,
471− 0 /* device */,
472− Qt::NoModifier,
473− Qt::TouchPointPressed | Qt::TouchPointMoved,
474− touchPoints);
475− touchRegistry->update(&touchEvent);
476− }
477−
478− touchRegistry->addTouchWatcher(1, &item);
479−
480− touchRegistry->removeCandidateOwnerForTouch(0, &item);
481−
482− touchRegistry->addTouchWatcher(0, &item);
483−
484− {
485− QList<QTouchEvent::TouchPoint> touchPoints;
486− touchPoints.append(QTouchEvent::TouchPoint(0));
487− touchPoints[0].setState(Qt::TouchPointReleased);
488− touchPoints.append(QTouchEvent::TouchPoint(1));
489− touchPoints[1].setState(Qt::TouchPointMoved);
490− QTouchEvent touchEvent(QEvent::TouchUpdate,
491− 0 /* device */,
492− Qt::NoModifier,
493− Qt::TouchPointReleased | Qt::TouchPointMoved,
494− touchPoints);
495− touchRegistry->update(&touchEvent);
496− }
497−
498− {
499− QList<QTouchEvent::TouchPoint> touchPoints;
500− touchPoints.append(QTouchEvent::TouchPoint(1));
501− touchPoints[0].setState(Qt::TouchPointReleased);
502− QTouchEvent touchEvent(QEvent::TouchEnd,
503− 0 /* device */,
504− Qt::NoModifier,
505− Qt::TouchPointReleased,
506− touchPoints);
507− touchRegistry->update(&touchEvent);
508− }
509−
510− QVERIFY(touchRegistry->m_touchInfoPool.isEmpty());
511−
512− item.unownedTouchEvents.clear();
513−
514− {
515− QList<QTouchEvent::TouchPoint> touchPoints;
516− touchPoints.append(QTouchEvent::TouchPoint(0));
517− touchPoints[0].setState(Qt::TouchPointPressed);
518− QTouchEvent touchEvent(QEvent::TouchBegin,
519− 0 /* device */,
520− Qt::NoModifier,
521− Qt::TouchPointPressed,
522− touchPoints);
523− touchRegistry->update(&touchEvent);
524− }
525−
526− // Haven't made any subscription for that new touch 0.
527− QCOMPARE(item.unownedTouchEvents.count(), 0);
528−}
529−
530−/*
531− Regression test that reproduces a problematic scenario that came up during manual testing.
532− It reproduces the interaction between TouchRegistry, DirectionalDragArea and a TouchGate.
533− */
534−void tst_TouchRegistry::candidatesAndWatchers_2()
535−{
536− DummyCandidate directionalDragArea;
537− directionalDragArea.setObjectName("DirectionalDragArea");
538−
539− DummyCandidate touchGate;
540− touchGate.setObjectName("TouchGate");
541−
542− // [DDA] 1298 TouchBegin (id:0, state:pressed, scenePos:(147,1023))
543− {
544− QList<QTouchEvent::TouchPoint> touchPoints;
545− touchPoints.append(QTouchEvent::TouchPoint(0));
546− touchPoints[0].setState(Qt::TouchPointPressed);
547− QTouchEvent touchEvent(QEvent::TouchBegin,
548− 0 /* device */,
549− Qt::NoModifier,
550− Qt::TouchPointPressed,
551− touchPoints);
552− touchRegistry->update(&touchEvent);
553− }
554−
555− // [TouchRegistry] addCandidateOwnerForTouch id 0 candidate DirectionalDragArea
556− touchRegistry->addCandidateOwnerForTouch(0, &directionalDragArea);
557−
558− // [TouchRegistry] requestTouchOwnership id 0 candidate TouchGate
559− touchRegistry->requestTouchOwnership(0, &touchGate);
560−
561− //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(147,1023)) (id:1, state:pressed, scenePos:(327,792))
562− {
563− QList<QTouchEvent::TouchPoint> touchPoints;
564− touchPoints.append(QTouchEvent::TouchPoint(0));
565− touchPoints[0].setState(Qt::TouchPointMoved);
566− touchPoints.append(QTouchEvent::TouchPoint(1));
567− touchPoints[1].setState(Qt::TouchPointPressed);
568− QTouchEvent touchEvent(QEvent::TouchUpdate,
569− 0 /* device */,
570− Qt::NoModifier,
571− Qt::TouchPointPressed | Qt::TouchPointMoved,
572− touchPoints);
573− touchRegistry->update(&touchEvent);
574− }
575−
576− // [TouchRegistry] addTouchWatcher id 1 watcher DirectionalDragArea
577− touchRegistry->addTouchWatcher(1, &directionalDragArea);
578−
579− // [TouchRegistry] removeCandidateOwnerForTouch id 0 candidate DirectionalDragArea
580− touchRegistry->removeCandidateOwnerForTouch(0, &directionalDragArea);
581−
582− //[TouchRegistry] sending TouchWonershipEvent(id = 0 gained) to candidate TouchGate
583− QCOMPARE(touchGate.ownedTouches.count(), 1);
584− QVERIFY(touchGate.ownedTouches.contains(0));
585−
586− // [TouchRegistry] addTouchWatcher id 0 watcher DirectionalDragArea
587− touchRegistry->addTouchWatcher(0, &directionalDragArea);
588−
589− // [TouchRegistry] requestTouchOwnership id 1 candidate TouchGate
590− touchRegistry->requestTouchOwnership(1, &touchGate);
591−
592− //[TouchRegistry] sending TouchWonershipEvent(id = 1 gained) to candidate TouchGate
593− QCOMPARE(touchGate.ownedTouches.count(), 2);
594− QVERIFY(touchGate.ownedTouches.contains(1));
595−
596− directionalDragArea.unownedTouchEvents.clear();
597− touchGate.unownedTouchEvents.clear();
598−
599− //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(148,1025)) (id:1, state:moved, scenePos:(329,795))
600− {
601− QList<QTouchEvent::TouchPoint> touchPoints;
602− touchPoints.append(QTouchEvent::TouchPoint(0));
603− touchPoints[0].setState(Qt::TouchPointMoved);
604− touchPoints.append(QTouchEvent::TouchPoint(1));
605− touchPoints[1].setState(Qt::TouchPointMoved);
606− QTouchEvent touchEvent(QEvent::TouchUpdate,
607− 0 /* device */,
608− Qt::NoModifier,
609− Qt::TouchPointMoved,
610− touchPoints);
611− touchRegistry->update(&touchEvent);
612− }
613−
614− //vvvvv DDA Watchers are being ignored from now on vvvvvvv
615−
616− QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
617− QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 2);
618− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
619− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(1));
620−
621− QVERIFY(touchGate.unownedTouchEvents.isEmpty());
622−
623− directionalDragArea.unownedTouchEvents.clear();
624−
625− //[TouchRegistry] got TouchUpdate (id:0, state:moved, scenePos:(151,1029)) (id:1, state:released, scenePos:(329,795))
626− {
627− QList<QTouchEvent::TouchPoint> touchPoints;
628− touchPoints.append(QTouchEvent::TouchPoint(0));
629− touchPoints[0].setState(Qt::TouchPointMoved);
630− touchPoints.append(QTouchEvent::TouchPoint(1));
631− touchPoints[1].setState(Qt::TouchPointReleased);
632− QTouchEvent touchEvent(QEvent::TouchUpdate,
633− 0 /* device */,
634− Qt::NoModifier,
635− Qt::TouchPointMoved | Qt::TouchPointReleased,
636− touchPoints);
637− touchRegistry->update(&touchEvent);
638− }
639−
640− QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
641− QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 2);
642− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
643− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(1));
644−
645− QVERIFY(touchGate.unownedTouchEvents.isEmpty());
646−
647− directionalDragArea.unownedTouchEvents.clear();
648−
649− //[TouchRegistry] got TouchEnd (id:0, state:released, scenePos:(157,1034))
650− {
651− QList<QTouchEvent::TouchPoint> touchPoints;
652− touchPoints.append(QTouchEvent::TouchPoint(0));
653− touchPoints[0].setState(Qt::TouchPointReleased);
654− QTouchEvent touchEvent(QEvent::TouchEnd,
655− 0 /* device */,
656− Qt::NoModifier,
657− Qt::TouchPointReleased,
658− touchPoints);
659− touchRegistry->update(&touchEvent);
660− }
661−
662− QCOMPARE(directionalDragArea.unownedTouchEvents.count(), 1);
663− QCOMPARE(directionalDragArea.unownedTouchEvents.first().touchPoints.count(), 1);
664− QVERIFY(directionalDragArea.unownedTouchEvents.first().containsTouchWithId(0));
665−
666− QVERIFY(touchGate.unownedTouchEvents.isEmpty());
667−}
668−
669−void tst_TouchRegistry::rejectingTouchfterItsEnd()
670−{
671− DummyCandidate earlyCandidate;
672− DummyCandidate lateCandidate;
673−
674− {
675− QList<QTouchEvent::TouchPoint> touchPoints;
676− touchPoints.append(QTouchEvent::TouchPoint(0));
677− touchPoints[0].setState(Qt::TouchPointPressed);
678− QTouchEvent touchEvent(QEvent::TouchBegin,
679− 0 /* device */,
680− Qt::NoModifier,
681− Qt::TouchPointPressed,
682− touchPoints);
683− touchRegistry->update(&touchEvent);
684− }
685−
686− touchRegistry->addCandidateOwnerForTouch(0, &earlyCandidate);
687− touchRegistry->addCandidateOwnerForTouch(0, &lateCandidate);
688−
689− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
690− QVERIFY(lateCandidate.ownedTouches.isEmpty());
691−
692− touchRegistry->requestTouchOwnership(0, &lateCandidate);
693−
694− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
695− QVERIFY(lateCandidate.ownedTouches.isEmpty());
696−
697− {
698− QList<QTouchEvent::TouchPoint> touchPoints;
699− touchPoints.append(QTouchEvent::TouchPoint(0));
700− touchPoints[0].setState(Qt::TouchPointReleased);
701− QTouchEvent touchEvent(QEvent::TouchEnd,
702− 0 /* device */,
703− Qt::NoModifier,
704− Qt::TouchPointPressed,
705− touchPoints);
706− touchRegistry->update(&touchEvent);
707− }
708−
709− QVERIFY(earlyCandidate.ownedTouches.isEmpty());
710− QVERIFY(lateCandidate.ownedTouches.isEmpty());
711−
712− touchRegistry->removeCandidateOwnerForTouch(0, &earlyCandidate);
713−
714− QCOMPARE(lateCandidate.ownedTouches.count(), 1);
715− QVERIFY(lateCandidate.ownedTouches.contains(0));
716−
717− // Check that there's no trace left of touch 0 as we no longer need to keep tabs on it.
718− QVERIFY(!touchRegistry->findTouchInfo(0));
719−}
720−
721−void tst_TouchRegistry::removeOldUndecidedCandidates()
722−{
723− FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
724− touchRegistry->setTimerFactory(fakeTimerFactory);
725−
726− DummyCandidate undecidedCandidate;
727− undecidedCandidate.setObjectName("undecided");
728−
729− DummyCandidate candidateThatWantsTouch;
730− candidateThatWantsTouch.setObjectName("wantsTouch");
731−
732− {
733− QList<QTouchEvent::TouchPoint> touchPoints;
734− touchPoints.append(QTouchEvent::TouchPoint(0));
735− touchPoints[0].setState(Qt::TouchPointPressed);
736− QTouchEvent touchEvent(QEvent::TouchBegin,
737− 0 /* device */,
738− Qt::NoModifier,
739− Qt::TouchPointPressed,
740− touchPoints);
741− touchRegistry->update(&touchEvent);
742− }
743−
744− touchRegistry->addCandidateOwnerForTouch(0, &undecidedCandidate);
745−
746− touchRegistry->requestTouchOwnership(0, &candidateThatWantsTouch);
747−
748− QVERIFY(undecidedCandidate.ownedTouches.isEmpty());
749− QVERIFY(undecidedCandidate.lostTouches.isEmpty());
750− QVERIFY(candidateThatWantsTouch.ownedTouches.isEmpty());
751− QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
752−
753− // Simulate that enough time has passed to cause the CandidateInactivityTimer to timeout,
754− // making TouchRegistry consider that undecidedCantidate defaulted.
755− fakeTimerFactory->updateTime(10000);
756−
757− QVERIFY(undecidedCandidate.ownedTouches.isEmpty());
758− QVERIFY(undecidedCandidate.lostTouches.contains(0));
759− QVERIFY(candidateThatWantsTouch.ownedTouches.contains(0));
760− QVERIFY(candidateThatWantsTouch.lostTouches.isEmpty());
761−}
762−
763−/*
764− An item that calls requestTouchOwnership() without first having called addCandidateOwnerForTouch()
765− is assumed to be the interim owner of the touch point, thus there's no point in sending
766− UnownedTouchEvents to him as he already gets proper QTouchEvents from QQuickWindow because
767− he didn't ignore the first QTouchEvent with that touch point.
768− */
769−void tst_TouchRegistry::interimOwnerWontGetUnownedTouchEvents()
770−{
771− FakeTimerFactory *fakeTimerFactory = new FakeTimerFactory;
772− touchRegistry->setTimerFactory(fakeTimerFactory);
773−
774− DummyCandidate undecidedCandidate;
775− undecidedCandidate.setObjectName("undecided");
776−
777− DummyCandidate interimOwner;
778− interimOwner.setObjectName("interimOwner");
779−
780− {
781− QList<QTouchEvent::TouchPoint> touchPoints;
782− touchPoints.append(QTouchEvent::TouchPoint(0));
783− touchPoints[0].setState(Qt::TouchPointPressed);
784− QTouchEvent touchEvent(QEvent::TouchBegin,
785− 0 /* device */,
786− Qt::NoModifier,
787− Qt::TouchPointPressed,
788− touchPoints);
789− touchRegistry->update(&touchEvent);
790− }
791−
792− touchRegistry->addCandidateOwnerForTouch(0, &undecidedCandidate);
793− touchRegistry->requestTouchOwnership(0, &interimOwner);
794−
795− {
796− QList<QTouchEvent::TouchPoint> touchPoints;
797− touchPoints.append(QTouchEvent::TouchPoint(0));
798− touchPoints[0].setState(Qt::TouchPointMoved);
799− QTouchEvent touchEvent(QEvent::TouchUpdate,
800− 0 /* device */,
801− Qt::NoModifier,
802− Qt::TouchPointMoved,
803− touchPoints);
804− touchRegistry->update(&touchEvent);
805− }
806−
807− QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 1);
808− QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
809−
810− {
811− QList<QTouchEvent::TouchPoint> touchPoints;
812− touchPoints.append(QTouchEvent::TouchPoint(0));
813− touchPoints[0].setState(Qt::TouchPointMoved);
814− QTouchEvent touchEvent(QEvent::TouchUpdate,
815− 0 /* device */,
816− Qt::NoModifier,
817− Qt::TouchPointMoved,
818− touchPoints);
819− touchRegistry->update(&touchEvent);
820− }
821−
822− QCOMPARE(undecidedCandidate.unownedTouchEvents.count(), 2);
823− QCOMPARE(interimOwner.unownedTouchEvents.count(), 0);
824−}
825−
826−/*
827− Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1473492
828−
829− Bug caused by candidates getting deleted before ownership resolution
830− */
831−void tst_TouchRegistry::candidateVanishes()
832−{
833− DummyCandidate mainCandidate;
834− DummyCandidate *missingCandidate = new DummyCandidate;
835−
836− {
837− QList<QTouchEvent::TouchPoint> touchPoints;
838− touchPoints.append(QTouchEvent::TouchPoint(0));
839− touchPoints[0].setState(Qt::TouchPointPressed);
840− QTouchEvent touchEvent(QEvent::TouchBegin,
841− 0 /* device */,
842− Qt::NoModifier,
843− Qt::TouchPointPressed,
844− touchPoints);
845− touchRegistry->update(&touchEvent);
846− }
847−
848− touchRegistry->addCandidateOwnerForTouch(0, &mainCandidate);
849− touchRegistry->addCandidateOwnerForTouch(0, missingCandidate);
850−
851− {
852− QList<QTouchEvent::TouchPoint> touchPoints;
853− touchPoints.append(QTouchEvent::TouchPoint(0));
854− touchPoints[0].setState(Qt::TouchPointMoved);
855− QTouchEvent touchEvent(QEvent::TouchUpdate,
856− 0 /* device */,
857− Qt::NoModifier,
858− Qt::TouchPointMoved,
859− touchPoints);
860− touchRegistry->update(&touchEvent);
861− }
862−
863− // This candidate suddenly disappears without having removed its candidacy.
864− delete missingCandidate;
865− missingCandidate = nullptr;
866−
867− touchRegistry->requestTouchOwnership(0, &mainCandidate);
868−
869− QVERIFY(mainCandidate.ownedTouches.contains(0));
870−}
871−
872−/*
873− Regression test for canidate reentrance
874−
875− Bug caused by candidates getting removed during ownership resolution
876− */
877−void tst_TouchRegistry::candicateOwnershipReentrace()
878−{
879− DummyCandidate mainCandidate;
880− DummyCandidate candicate2;
881− DummyCandidate candicate3;
882−
883− {
884− QList<QTouchEvent::TouchPoint> touchPoints;
885− touchPoints.append(QTouchEvent::TouchPoint(0));
886− touchPoints[0].setState(Qt::TouchPointPressed);
887− QTouchEvent touchEvent(QEvent::TouchBegin,
888− 0 /* device */,
889− Qt::NoModifier,
890− Qt::TouchPointPressed,
891− touchPoints);
892− touchRegistry->update(&touchEvent);
893− }
894−
895− // Re-entrance!
896− connect(&candicate2, &DummyCandidate::lostOwnership, this, [&]() {
897− touchRegistry->removeCandidateOwnerForTouch(0, &candicate2);
898− });
899−
900− touchRegistry->addCandidateOwnerForTouch(0, &mainCandidate);
901− touchRegistry->addCandidateOwnerForTouch(0, &candicate2);
902− touchRegistry->addCandidateOwnerForTouch(0, &candicate3);
903−
904− {
905− QList<QTouchEvent::TouchPoint> touchPoints;
906− touchPoints.append(QTouchEvent::TouchPoint(0));
907− touchPoints[0].setState(Qt::TouchPointMoved);
908− QTouchEvent touchEvent(QEvent::TouchUpdate,
909− 0 /* device */,
910− Qt::NoModifier,
911− Qt::TouchPointMoved,
912− touchPoints);
913− touchRegistry->update(&touchEvent);
914− }
915−
916− touchRegistry->requestTouchOwnership(0, &mainCandidate);
917−
918− QCOMPARE(mainCandidate.ownedTouches.count(), 1);
919− QCOMPARE(candicate2.lostTouches.count(), 1);
920− QCOMPARE(candicate3.lostTouches.count(), 1);
921−}
922−
923−
924−////////////// TouchMemento //////////
925−
926−TouchMemento::TouchMemento(const QTouchEvent *touchEvent)
927− : touchPointStates(touchEvent->touchPointStates()), touchPoints(touchEvent->touchPoints())
928−{
929−}
930−
931−bool TouchMemento::containsTouchWithId(int touchId) const
932−{
933− for (int i = 0; i < touchPoints.count(); ++i) {
934− if (touchPoints.at(i).id() == touchId) {
935− return true;
936− }
937− }
938− return false;
939−}
940−
941−////////////// DummyCandidate //////////
942−
943−bool DummyCandidate::event(QEvent *e)
944−{
945− if (e->type() == TouchOwnershipEvent::touchOwnershipEventType()) {
946− TouchOwnershipEvent *touchOwnershipEvent = static_cast<TouchOwnershipEvent *>(e);
947−
948− // NB: Cannot use QVERIFY here because the macro doesn't return a boolean and is
949− // meant for use only directly in the body of a test function
950− if (ownedTouches.contains(touchOwnershipEvent->touchId()))
951− qFatal("Sent ownership event for a touch that is already owned.");
952− if (lostTouches.contains(touchOwnershipEvent->touchId()))
953− qFatal("Sent ownership event for a touch that has already been lost.");
954−
955− if (touchOwnershipEvent->gained()) {
956− ownedTouches.insert(touchOwnershipEvent->touchId());
957− Q_EMIT gainedOwnership();
958− } else {
959− lostTouches.insert(touchOwnershipEvent->touchId());
960− Q_EMIT lostOwnership();
961− }
962− return true;
963− } else if (e->type() == UnownedTouchEvent::unownedTouchEventType()) {
964− UnownedTouchEvent *unownedTouchEvent = static_cast<UnownedTouchEvent *>(e);
965− unownedTouchEvents.append(TouchMemento(unownedTouchEvent->touchEvent()));
966− return true;
967− } else {
968− return QObject::event(e);
969− }
970−}
971−
972−QTEST_GUILESS_MAIN(tst_TouchRegistry)
973−
974−#include "tst_TouchRegistry.moc"
tests/mocks/Cursor/qmldir+1−1
@@ -1,2 +1,2 @@
11module Cursor
2−Cursor 1.0 Cursor.qml
2+Cursor 1.1 Cursor.qml
tests/mocks/GSettings.1.0/fake_gsettings.cpp+1
@@ -22,6 +22,7 @@ GSettingsControllerQml* GSettingsControllerQml::s_controllerInstance = 0;
2222
2323GSettingsControllerQml::GSettingsControllerQml()
2424 : m_disableHeight(false)
25+ , m_lockedOutTime(0)
2526 , m_usageMode("Staged")
2627 , m_autohideLauncher(false)
2728 , m_launcherWidth(8)
tests/mocks/GSettings.1.0/fake_gsettings.h+2−2
@@ -61,8 +61,8 @@ class GSettingsQml: public QObject, public QQmlParserStatus
6161public:
6262 GSettingsQml(QObject *parent = nullptr);
6363
64− void classBegin();
65− void componentComplete();
64+ void classBegin() override;
65+ void componentComplete() override;
6666
6767 GSettingsSchemaQml * schema() const;
6868 QVariant disableHeight() const;
tests/mocks/IntegratedLightDM/liblightdm/GreeterPrivate.h−1
@@ -41,7 +41,6 @@ public:
4141 void handleRespond(const QString &response);
4242
4343protected:
44− GreeterImpl *m_impl; // if the backend needs more private data
4544 Greeter * const q_ptr;
4645
4746private:
tests/mocks/QtMultimedia/audio.cpp+3−3
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013, 2015 Canonical, Ltd.
2+ * Copyright (C) 2013-2016 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
@@ -21,7 +21,7 @@
2121Audio::Audio(QObject* parent):
2222 QObject(parent),
2323 m_playbackState(StoppedState),
24− m_playlist(0)
24+ m_playlist(nullptr)
2525{
2626 qsrand(time(nullptr));
2727 m_timer.setInterval(1000);
@@ -109,7 +109,7 @@ void Audio::timerEvent()
109109
110110Audio::AudioRole Audio::audioRole() const
111111{
112− return Audio::multimedia;
112+ return Audio::MusicRole;
113113}
114114
115115void Audio::setAudioRole(Audio::AudioRole audioRole)
tests/mocks/QtMultimedia/audio.h+12−6
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2012, 2013, 2015 Canonical, Ltd.
2+ * Copyright (C) 2012-2016 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
@@ -44,13 +44,19 @@ public:
4444 };
4545
4646 enum AudioRole {
47− alarm,
48− alert,
49− multimedia,
50− phone
47+ UnknownRole,
48+ MusicRole,
49+ VideoRole,
50+ VoiceCommunicationRole,
51+ AlarmRole,
52+ NotificationRole,
53+ RingtoneRole,
54+ AccessibilityRole,
55+ SonificationRole,
56+ GameRole
5157 };
5258
53− explicit Audio(QObject *parent = 0);
59+ explicit Audio(QObject *parent = nullptr);
5460
5561 QUrl source() const;
5662 void setSource(const QUrl &source);
tests/mocks/Ubuntu/Payments/MockPayments.cpp+1
@@ -21,6 +21,7 @@
2121
2222MockPayments::MockPayments(QObject *parent)
2323 : QObject(parent)
24+ , m_price(0)
2425{
2526}
2627
tests/mocks/Ubuntu/SystemSettings/TimeDate/CMakeLists.txt+1−1
@@ -1 +1 @@
1−add_unity8_mock(Ubuntu.SystemSettings.TimeDate 1.0 Ubuntu/SystemSettings/TimeDate)
1+add_unity8_mock(Ubuntu.SystemSettings.TimeDate 1.1 Ubuntu/SystemSettings/TimeDate)
tests/mocks/Ubuntu/SystemSettings/TimeDate/MockTimeDate.qml+15−3
@@ -18,8 +18,20 @@ import QtQuick 2.4
1818
1919Item {
2020 id: root
21− property string timeZone: "Europe/Prague"
22− onTimeZoneChanged: root.timeZoneChangedCalled(root.timeZone);
21+ readonly property alias timeZone: d.timeZone
22+ readonly property alias timeZoneName: d.timeZoneName
2323
24− signal timeZoneChangedCalled(string tz);
24+ signal timeZoneChangedCalled(string tz, string name) // only in mock
25+
26+ function setTimeZone(tz, name) {
27+ d.timeZone = tz;
28+ d.timeZoneName = name;
29+ timeZoneChangedCalled(tz, name);
30+ }
31+
32+ QtObject {
33+ id: d
34+ property string timeZone: "Europe/Prague"
35+ property string timeZoneName: "Prague"
36+ }
2537}
tests/mocks/Ubuntu/SystemSettings/TimeDate/qmldir+1−1
@@ -1,2 +1,2 @@
11module Ubuntu.SystemSettings.TimeDate
2−UbuntuTimeDatePanel 1.0 MockTimeDate.qml
2+UbuntuTimeDatePanel 1.1 MockTimeDate.qml
tests/mocks/Unity/Application/ApplicationInfo.h+1−1
@@ -67,7 +67,7 @@ public:
6767
6868 QUrl icon() const override { return m_icon; }
6969
70− Q_INVOKABLE void setStage(Stage value); // invokable only for mock
70+ Q_INVOKABLE void setStage(Stage value) override; // invokable only for mock
7171 Stage stage() const override { return m_stage; }
7272
7373 Q_INVOKABLE void setState(State value);
tests/mocks/Unity/Application/MirSurface.h+2−2
@@ -96,8 +96,8 @@ public:
9696 int widthIncrement() const override { return m_widthIncrement; }
9797 int heightIncrement() const override { return m_heightIncrement; }
9898
99− virtual void setKeymap(const QString &);
100− virtual QString keymap() const;
99+ void setKeymap(const QString &) override;
100+ QString keymap() const override;
101101
102102 Mir::ShellChrome shellChrome() const override;
103103
tests/mocks/Unity/Application/MirSurfaceItem.cpp+17−7
@@ -40,6 +40,7 @@ using namespace unity::shell::application;
4040MirSurfaceItem::MirSurfaceItem(QQuickItem *parent)
4141 : MirSurfaceItemInterface(parent)
4242 , m_qmlSurface(nullptr)
43+ , m_qmlContentComponent(nullptr)
4344 , m_qmlItem(nullptr)
4445 , m_consumesInput(false)
4546 , m_surfaceWidth(0)
@@ -56,7 +57,11 @@ MirSurfaceItem::MirSurfaceItem(QQuickItem *parent)
5657 Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
5758 Qt::ExtraButton12 | Qt::ExtraButton13);
5859
60+ connect(this, &QQuickItem::activeFocusChanged, this, &MirSurfaceItem::updateMirSurfaceActiveFocus);
5961 connect(this, &QQuickItem::visibleChanged, this, &MirSurfaceItem::updateMirSurfaceVisibility);
62+ connect(this, &MirSurfaceItem::consumesInputChanged, this, [this]() {
63+ updateMirSurfaceActiveFocus(hasActiveFocus());
64+ });
6065}
6166
6267MirSurfaceItem::~MirSurfaceItem()
@@ -234,6 +239,10 @@ void MirSurfaceItem::setSurface(MirSurfaceInterface* surface)
234239 delete m_qmlContentComponent;
235240 m_qmlContentComponent = nullptr;
236241
242+ if (hasActiveFocus() && m_consumesInput && m_qmlSurface->live()) {
243+ m_qmlSurface->setActiveFocus(false);
244+ }
245+
237246 disconnect(m_qmlSurface, nullptr, this, nullptr);
238247 m_qmlSurface->unregisterView((qintptr)this);
239248 }
@@ -243,8 +252,6 @@ void MirSurfaceItem::setSurface(MirSurfaceInterface* surface)
243252 if (m_qmlSurface) {
244253 m_qmlSurface->registerView((qintptr)this);
245254
246− m_qmlSurface->setActiveFocus(hasActiveFocus());
247−
248255 updateSurfaceSize();
249256 updateMirSurfaceVisibility();
250257
@@ -277,17 +284,20 @@ void MirSurfaceItem::setSurface(MirSurfaceInterface* surface)
277284 default:
278285 qFatal("MirSurfaceItem: Unhandled component status");
279286 }
287+
288+ if (m_consumesInput) {
289+ m_qmlSurface->setActiveFocus(hasActiveFocus());
290+ }
280291 }
281292
282293 Q_EMIT surfaceChanged(m_qmlSurface);
283294}
284295
285−void MirSurfaceItem::itemChange(ItemChange change, const ItemChangeData & value)
296+
297+void MirSurfaceItem::updateMirSurfaceActiveFocus(bool focused)
286298{
287− if (change == QQuickItem::ItemActiveFocusHasChanged) {
288− if (m_qmlSurface) {
289− m_qmlSurface->setActiveFocus(value.boolValue);
290− }
299+ if (m_qmlSurface && m_consumesInput && m_qmlSurface->live()) {
300+ m_qmlSurface->setActiveFocus(focused);
291301 }
292302}
293303
tests/mocks/Unity/Application/MirSurfaceItem.h+1−1
@@ -98,12 +98,12 @@ protected:
9898 void mousePressEvent(QMouseEvent * event) override;
9999 void mouseMoveEvent(QMouseEvent * event) override;
100100 void mouseReleaseEvent(QMouseEvent * event) override;
101− void itemChange(ItemChange change, const ItemChangeData & value) override;
102101
103102private Q_SLOTS:
104103 void onComponentStatusChanged(QQmlComponent::Status status);
105104 void updateScreenshot(QUrl screenshot);
106105 void updateMirSurfaceVisibility();
106+ void updateMirSurfaceActiveFocus(bool focused);
107107
108108private:
109109 void createQmlContentItem();
tests/mocks/Unity/InputInfo/plugin.h+1−1
@@ -24,7 +24,7 @@ class InputInfoPlugin : public QQmlExtensionPlugin
2424 Q_OBJECT
2525 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
2626public:
27− void registerTypes(const char *uri);
27+ void registerTypes(const char *uri) override;
2828};
2929
3030#endif // INPUTINFO_PLUGIN_H
tests/mocks/Unity/Screens/plugin.h+1−1
@@ -21,5 +21,5 @@ class UnityScreensPlugin : public QQmlExtensionPlugin {
2121 Q_OBJECT
2222 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
2323public:
24− virtual void registerTypes(const char* uri);
24+ void registerTypes(const char* uri) override;
2525};
tests/mocks/Unity/fake_scope.cpp+6−3
@@ -32,7 +32,7 @@ Scope::Scope(Scopes* parent) : Scope("MockScope5", "Mock Scope", false, parent)
3232{
3333}
3434
35−Scope::Scope(QString const& id, QString const& name, bool favorite, Scopes* parent, int categories, bool returnNullPreview)
35+Scope::Scope(QString const& id, QString const& name, bool favorite, Scopes* parent, int categories, bool returnNullPreview, const QStringList primaryNavigationFilterOptionLabels)
3636 : unity::shell::scopes::ScopeInterface(parent)
3737 , m_id(id)
3838 , m_name(name)
@@ -49,10 +49,11 @@ Scope::Scope(QString const& id, QString const& name, bool favorite, Scopes* pare
4949 , m_filters(new Filters(this))
5050 , m_returnNullPreview(returnNullPreview)
5151{
52+ m_primaryNavigationFilter = new FakeOptionSelectorFilter("OSF3", "PFTag", "Which food you like More", false, primaryNavigationFilterOptionLabels, this);
5253 m_filters->addFakeFilters();
53−
54− m_primaryNavigationFilter = new FakeOptionSelectorFilter("OSF3", "PFTag", "Which food you like More", false, QStringList() << "meat" << "vegetables", this);
5554 connect(m_filters, &Filters::activeFiltersCountChanged, this, &Scope::activeFiltersCountChanged);
55+ connect(m_primaryNavigationFilter, &FakeOptionSelectorFilter::isActiveChanged,
56+ this, &unity::shell::scopes::ScopeInterface::primaryNavigationTagChanged);
5657}
5758
5859QString Scope::id() const
@@ -326,6 +327,8 @@ unity::shell::scopes::FiltersInterface* Scope::filters() const
326327
327328QString Scope::primaryNavigationTag() const
328329{
330+ if (m_hasPrimaryFilter && m_primaryNavigationFilter->isActive())
331+ return m_primaryNavigationFilter->filterTag();
329332 if (m_currentNavigationId == "root")
330333 return QString();
331334 else
tests/mocks/Unity/fake_scope.h+1−1
@@ -34,7 +34,7 @@ class Scope : public unity::shell::scopes::ScopeInterface
3434
3535public:
3636 Scope(Scopes* parent = 0);
37− Scope(QString const& id, QString const& name, bool favorite, Scopes* parent = 0, int categories = 20, bool returnNullPreview = false);
37+ Scope(QString const& id, QString const& name, bool favorite, Scopes* parent = 0, int categories = 20, bool returnNullPreview = false, const QStringList primaryNavigationFilterOptionLabels = QStringList() << "meat" << "vegetables");
3838
3939 /* getters */
4040 QString id() const override;
tests/mocks/Unity/fake_scopes.cpp+11
@@ -60,6 +60,17 @@ void Scopes::updateScopes()
6060 addScope(new Scope("MockScope7", "MS7", false, this));
6161 addScope(new Scope("MockScope8", "MS8", false, this));
6262 addScope(new Scope("MockScope9", "MS9", false, this));
63+
64+ Scope *longNavigationScope = new Scope(
65+ "LongPrimaryNavigation", "LongPrimaryNavigation", true, this, 1, false,
66+ QStringList() << "Meat" << "Vegetables" << "BBQ" << "Burritos"
67+ << "Pasta" << "Pancakes" << "Seafood" << "Soup" << "Bugs"
68+ << "Pudding" << "Chocolate" << "Gluten-Free" << "Hamburgers"
69+ << "Pho" << "Panang Curry" << "Lumpia" << "Sushi");
70+
71+ longNavigationScope->setHasNavigation(false);
72+ addScope(longNavigationScope);
73+
6374 addScope(new Scope("NullPreviewScope", "NPS", false, this, 1, true));
6475 m_scopesOverview = new ScopesOverview(this);
6576
tests/mocks/Utils/plugin.h+1−1
@@ -26,7 +26,7 @@ class FakeUtilsPlugin : public QQmlExtensionPlugin
2626 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
2727
2828public:
29− void registerTypes(const char *uri);
29+ void registerTypes(const char *uri) override;
3030};
3131
3232#endif
tests/mocks/Utils/windowstatestorage.cpp+1
@@ -50,6 +50,7 @@ QRect WindowStateStorage::getGeometry(const QString &windowId, const QRect &defa
5050void WindowStateStorage::saveStage(const QString &appId, int stage)
5151{
5252 m_stage[appId] = stage;
53+ Q_EMIT stageSaved(appId, stage);
5354}
5455
5556int WindowStateStorage::getStage(const QString &appId) const
tests/mocks/Utils/windowstatestorage.h+17−3
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2015 Canonical Ltd.
2+ * Copyright 2015-2016 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -25,9 +25,20 @@ class WindowStateStorage: public QObject
2525 Q_ENUMS(WindowState)
2626public:
2727 enum WindowState {
28− WindowStateNormal,
29− WindowStateMaximized
28+ WindowStateNormal = 1 << 0,
29+ WindowStateMaximized = 1 << 1,
30+ WindowStateMinimized = 1 << 2,
31+ WindowStateFullscreen = 1 << 3,
32+ WindowStateMaximizedLeft = 1 << 4,
33+ WindowStateMaximizedRight = 1 << 5,
34+ WindowStateMaximizedHorizontally = 1 << 6,
35+ WindowStateMaximizedVertically = 1 << 7
3036 };
37+ Q_DECLARE_FLAGS(WindowStates, WindowState)
38+#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
39+ Q_FLAG(WindowStates)
40+#endif
41+
3142 WindowStateStorage(QObject *parent = 0);
3243
3344 Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
@@ -45,6 +56,9 @@ public:
4556Q_SIGNALS:
4657 void geometryChanged(const QVariantMap& geometry);
4758
59+ // For testing.
60+ void stageSaved(const QString& appId, int stage);
61+
4862private:
4963 void setGeometry(const QVariantMap& geometry);
5064 QVariantMap geometry() const;
tests/mocks/libusermetrics/UserMetrics.cpp+1−1
@@ -220,7 +220,7 @@ int UserMetricsData::length() const
220220}
221221
222222UserMetricsPrivate::UserMetricsPrivate(UserMetrics *parent) :
223− q_ptr(parent), m_firstColor(this), m_secondColor(this)
223+ q_ptr(parent), m_firstColor(this), m_secondColor(this), m_currentDay(0)
224224{
225225 m_fakeData.insert("", UserMetricsDataPtr(new UserMetricsData(this)));
226226}
tests/plugins/CMakeLists.txt+2−1
@@ -1,8 +1,9 @@
11add_subdirectory(AccountsService)
2+add_subdirectory(Cursor)
3+add_subdirectory(Dash)
24add_subdirectory(GlobalShortcut)
35add_subdirectory(Greeter)
46add_subdirectory(IntegratedLightDM)
5−add_subdirectory(Dash)
67add_subdirectory(Ubuntu)
78add_subdirectory(Unity)
89add_subdirectory(Utils)
tests/plugins/Cursor/CMakeLists.txtnew file+8
@@ -0,0 +1,8 @@
1+include(QmlTest)
2+
3+set(UNITY_IMPORT_PATHS
4+ ${CMAKE_BINARY_DIR}/tests/utils/modules
5+ ${UNITY_PLUGINPATH}
6+)
7+
8+add_manual_qml_test(. Cursor IMPORT_PATHS ${UNITY_IMPORT_PATHS})
tests/plugins/Cursor/TextEntry.qmlnew file+34
@@ -0,0 +1,34 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+
19+Column {
20+ property alias name: entryText.text
21+ property alias value: textInput.text
22+ Text { id: entryText }
23+ Rectangle {
24+ color: "white"
25+ width: parent.width - 20
26+ height: 40
27+ TextInput {
28+ id: textInput
29+ anchors.fill: parent
30+ verticalAlignment: TextInput.AlignVCenter
31+ selectByMouse: true
32+ }
33+ }
34+}
tests/plugins/Cursor/tst_Cursor.qmlnew file+144
@@ -0,0 +1,144 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+
18+import QtQuick 2.4
19+import Cursor 1.1
20+
21+Rectangle {
22+ id: root
23+ color: "blue"
24+ width: 400
25+ height: 600
26+
27+ property string themeName: "default"
28+ property string cursorName: "left_ptr"
29+
30+ CursorImageInfo {
31+ id: imageInfo
32+ themeName: root.themeName
33+ cursorName: root.cursorName
34+ }
35+
36+ Item {
37+ id: cursor
38+ x: (200 - animatedSprite.width) / 2
39+ y: (root.height - animatedSprite.height) / 2
40+
41+ AnimatedSprite {
42+ id: animatedSprite
43+
44+ x: -imageInfo.hotspot.x
45+ y: -imageInfo.hotspot.y
46+ source: "image://cursor/" + root.themeName + "/" + root.cursorName
47+
48+ interpolate: false
49+
50+ width: imageInfo.frameWidth
51+ height: imageInfo.frameHeight
52+
53+ frameCount: imageInfo.frameCount
54+ frameDuration: imageInfo.frameDuration
55+ frameWidth: imageInfo.frameWidth
56+ frameHeight: imageInfo.frameHeight
57+ }
58+ }
59+
60+ Rectangle {
61+ id: hotspotCrossH
62+ color: "red"
63+ width: 200
64+ height: 1
65+ anchors.top: cursor.top
66+ opacity: 0.6
67+ }
68+ Rectangle {
69+ id: hotspotCrossV
70+ color: "red"
71+ width: 1
72+ anchors.left: cursor.left
73+ anchors.top: parent.top
74+ anchors.bottom: parent.bottom
75+ opacity: 0.6
76+ }
77+ MouseArea {
78+ anchors.top: parent.top
79+ anchors.bottom: parent.bottom
80+ anchors.left: parent.left
81+ anchors.right: controls.left
82+ onClicked: {
83+ if (hotspotCrossH.visible) {
84+ hotspotCrossH.visible = false;
85+ hotspotCrossV.visible = false;
86+ } else {
87+ hotspotCrossH.visible = true;
88+ hotspotCrossV.visible = true;
89+ }
90+ }
91+ }
92+
93+ Rectangle {
94+ id: controls
95+ color: "lightgrey"
96+ anchors.right: parent.right
97+ anchors.top: parent.top
98+ anchors.bottom: parent.bottom
99+ width: root.width - 200
100+
101+ Column {
102+ anchors.fill: parent
103+ anchors.margins: 10
104+
105+ TextEntry { id: themeNameEntry; name: "themeName"; value: "default" }
106+
107+ Item {width: 10; height: 20}
108+
109+ TextEntry { id: cursorNameEntry; name: "cursorName"; value: "left_ptr" }
110+
111+ Item {width: 10; height: 40}
112+
113+ Rectangle {
114+ color: applyMouseArea.pressed ? "green" : "lightslategray"
115+ width: parent.width - 20
116+ height: 40
117+ Text { anchors.centerIn: parent; text: "Apply" }
118+ MouseArea {
119+ id: applyMouseArea
120+ anchors.fill: parent
121+ onClicked: {
122+ root.themeName = themeNameEntry.value;
123+ root.cursorName = cursorNameEntry.value;
124+ }
125+ }
126+ }
127+
128+ Item {width: 10; height: 10}
129+ Rectangle {
130+ color: "black"
131+ height: 2
132+ anchors.left: parent.left
133+ anchors.right: parent.right
134+ }
135+ Item {width: 10; height: 10}
136+
137+ Text { text: "frameWidth: " + imageInfo.frameWidth }
138+ Text { text: "frameHeight: " + imageInfo.frameHeight }
139+ Text { text: "frameCount: " + imageInfo.frameCount }
140+ Text { text: "frameDuration: " + imageInfo.frameDuration }
141+ Text { text: "currentFrame: " + animatedSprite.currentFrame }
142+ }
143+ }
144+}
tests/plugins/Dash/cardcreator/1.res+8−26
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -22,6 +21,7 @@ Item {
2221 id: artShapeLoader;
2322 objectName: "artShapeLoader";
2423 readonly property string cardArt: cardData && cardData["art"] || "";
24+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2525 active: cardArt != "";
2626 asynchronous: true;
2727 visible: status == Loader.Ready;
@@ -30,30 +30,12 @@ Item {
3030 objectName: "artShape";
3131 visible: image.status == Image.Ready;
3232 readonly property alias image: artImage;
33− Loader {
33+ UbuntuShape {
3434 anchors.fill: parent;
35− visible: true;
36− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
37− Component {
38− id: artShapeShapeComponent;
39− UbuntuShape {
40− source: artImage;
41− sourceFillMode: UbuntuShape.PreserveAspectCrop;
42− radius: "medium";
43− aspect: {
44− switch (root.artShapeStyle) {
45− case "inset": return UbuntuShape.Inset;
46− case "shadow": return UbuntuShape.DropShadow;
47− default:
48− case "flat": return UbuntuShape.Flat;
49− }
50− }
51− }
52− }
53− Component {
54− id: artShapeIconComponent;
55− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
56− }
35+ source: artImage;
36+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
37+ radius: "medium";
38+ aspect: UbuntuShape.Inset;
5739 }
5840 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5941 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 1.6;
@@ -73,7 +55,7 @@ Item {
7355 objectName: "artImage";
7456 source: artShapeLoader.cardArt;
7557 asynchronous: true;
76− visible: !true;
58+ visible: false;
7759 width: root.width;
7860 height: width / artShape.aspect;
7961 }
@@ -105,7 +87,7 @@ UbuntuShape {
10587 id: touchdown;
10688 objectName: "touchdown";
10789 anchors { fill: artShapeHolder }
108− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
90+ visible: root.pressed;
10991 radius: "medium";
11092 borderSource: "radius_pressed.sci"
11193}
tests/plugins/Dash/cardcreator/1.res.cardcreator+8−26
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -21,6 +20,7 @@ Item {
2120 id: artShapeLoader;
2221 objectName: "artShapeLoader";
2322 readonly property string cardArt: cardData && cardData["art"] || "";
23+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2424 active: cardArt != "";
2525 asynchronous: false;
2626 visible: status == Loader.Ready;
@@ -29,30 +29,12 @@ Item {
2929 objectName: "artShape";
3030 visible: image.status == Image.Ready;
3131 readonly property alias image: artImage;
32− Loader {
32+ UbuntuShape {
3333 anchors.fill: parent;
34− visible: true;
35− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
36− Component {
37− id: artShapeShapeComponent;
38− UbuntuShape {
39− source: artImage;
40− sourceFillMode: UbuntuShape.PreserveAspectCrop;
41− radius: "medium";
42− aspect: {
43− switch (root.artShapeStyle) {
44− case "inset": return UbuntuShape.Inset;
45− case "shadow": return UbuntuShape.DropShadow;
46− default:
47− case "flat": return UbuntuShape.Flat;
48− }
49− }
50− }
51− }
52− Component {
53− id: artShapeIconComponent;
54− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
55− }
34+ source: artImage;
35+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
36+ radius: "medium";
37+ aspect: UbuntuShape.Inset;
5638 }
5739 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5840 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 1.6;
@@ -72,7 +54,7 @@ Item {
7254 objectName: "artImage";
7355 source: artShapeLoader.cardArt;
7456 asynchronous: false;
75− visible: !true;
57+ visible: false;
7658 width: root.width;
7759 height: width / artShape.aspect;
7860 }
@@ -104,7 +86,7 @@ UbuntuShape {
10486 id: touchdown;
10587 objectName: "touchdown";
10688 anchors { fill: artShapeHolder }
107− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
89+ visible: root.pressed;
10890 radius: "medium";
10991 borderSource: "radius_pressed.sci"
11092}
tests/plugins/Dash/cardcreator/1.tst+1
@@ -1,3 +1,4 @@
11template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
22components: {"art":{"aspect-ratio":1.6,"field":"art"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: inset
34result: 1.res
tests/plugins/Dash/cardcreator/10.res−9
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -127,13 +126,5 @@ top: titleLabel.bottom;
127126
128127 ]
129128 }
130−UbuntuShape {
131− id: touchdown;
132− objectName: "touchdown";
133− anchors { fill: backgroundLoader }
134− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
135− radius: "medium";
136− borderSource: "radius_pressed.sci"
137− }
138129implicitHeight: row.y + row.height + units.gu(1);
139130}
tests/plugins/Dash/cardcreator/10.res.cardcreator−9
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -125,13 +124,5 @@ top: titleLabel.bottom;
125124
126125 ]
127126 }
128−UbuntuShape {
129− id: touchdown;
130− objectName: "touchdown";
131− anchors { fill: backgroundLoader }
132− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
133− radius: "medium";
134− borderSource: "radius_pressed.sci"
135− }
136127implicitHeight: row.y + row.height + units.gu(1);
137128}
tests/plugins/Dash/cardcreator/10.tst+1
@@ -1,3 +1,4 @@
11template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2, "card-background": { "type": "color", "elements": [ "\\", ": 3; } Item { } function moo () { \"" ] } }
22components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: shadow
34result: 10.res
tests/plugins/Dash/cardcreator/11.res+11−29
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -60,6 +59,7 @@ Item {
6059 id: artShapeLoader;
6160 objectName: "artShapeLoader";
6261 readonly property string cardArt: cardData && cardData["art"] || decodeURI("%5C");
62+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
6363 active: cardArt != "";
6464 asynchronous: true;
6565 visible: status == Loader.Ready;
@@ -68,32 +68,14 @@ Item {
6868 objectName: "artShape";
6969 visible: image.status == Image.Ready;
7070 readonly property alias image: artImage;
71− Loader {
72− anchors.fill: parent;
73− visible: true;
74− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
75− Component {
76− id: artShapeShapeComponent;
77− UbuntuShape {
78− source: artImage;
79− sourceFillMode: UbuntuShape.PreserveAspectCrop;
80− radius: "medium";
81− aspect: {
82− switch (root.artShapeStyle) {
83− case "inset": return UbuntuShape.Inset;
84− case "shadow": return UbuntuShape.DropShadow;
85− default:
86− case "flat": return UbuntuShape.Flat;
87− }
88− }
89− }
90− }
91− Component {
92− id: artShapeIconComponent;
93− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
94− }
95− }
96− readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
71+ UbuntuShape {
72+ anchors.fill: parent;
73+ source: artImage;
74+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
75+ radius: "medium";
76+ aspect: UbuntuShape.Flat;
77+ }
78+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
9779 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 1;
9880 Component.onCompleted: { updateWidthHeightBindings(); }
9981 Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
@@ -111,7 +93,7 @@ Item {
11193 objectName: "artImage";
11294 source: artShapeLoader.cardArt;
11395 asynchronous: true;
114− visible: !true;
96+ visible: false;
11597 width: root.width;
11698 height: width / artShape.aspect;
11799 onStatusChanged: if (status === Image.Error) source = decodeURI("%5C");
@@ -199,7 +181,7 @@ UbuntuShape {
199181 id: touchdown;
200182 objectName: "touchdown";
201183 anchors { fill: backgroundLoader }
202− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
184+ visible: root.pressed;
203185 radius: "medium";
204186 borderSource: "radius_pressed.sci"
205187 }
tests/plugins/Dash/cardcreator/11.res.cardcreator+10−28
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -59,6 +58,7 @@ Item {
5958 id: artShapeLoader;
6059 objectName: "artShapeLoader";
6160 readonly property string cardArt: cardData && cardData["art"] || "";
61+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
6262 active: cardArt != "";
6363 asynchronous: false;
6464 visible: status == Loader.Ready;
@@ -67,31 +67,13 @@ Item {
6767 objectName: "artShape";
6868 visible: image.status == Image.Ready;
6969 readonly property alias image: artImage;
70− Loader {
71− anchors.fill: parent;
72− visible: true;
73− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
74− Component {
75− id: artShapeShapeComponent;
76− UbuntuShape {
77− source: artImage;
78− sourceFillMode: UbuntuShape.PreserveAspectCrop;
79− radius: "medium";
80− aspect: {
81− switch (root.artShapeStyle) {
82− case "inset": return UbuntuShape.Inset;
83− case "shadow": return UbuntuShape.DropShadow;
84− default:
85− case "flat": return UbuntuShape.Flat;
86− }
87− }
88− }
89− }
90− Component {
91− id: artShapeIconComponent;
92− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
93− }
94− }
70+ UbuntuShape {
71+ anchors.fill: parent;
72+ source: artImage;
73+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
74+ radius: "medium";
75+ aspect: UbuntuShape.Flat;
76+ }
9577 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
9678 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 1;
9779 Component.onCompleted: { updateWidthHeightBindings(); }
@@ -110,7 +92,7 @@ Item {
11092 objectName: "artImage";
11193 source: artShapeLoader.cardArt;
11294 asynchronous: false;
113− visible: !true;
95+ visible: false;
11496 width: root.width;
11597 height: width / artShape.aspect;
11698 }
@@ -195,7 +177,7 @@ UbuntuShape {
195177 id: touchdown;
196178 objectName: "touchdown";
197179 anchors { fill: backgroundLoader }
198− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
180+ visible: root.pressed;
199181 radius: "medium";
200182 borderSource: "radius_pressed.sci"
201183 }
tests/plugins/Dash/cardcreator/11.tst+1
@@ -1,3 +1,4 @@
11template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2 }
22components: {"art":{"aspect-ratio":1,"field":"art","fallback":"\\"},"background":{"field":"background"},"mascot":{"field":"icon","fallback":"\""},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: flat
34result: 11.res
tests/plugins/Dash/cardcreator/12.res+8−26
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -22,6 +21,7 @@ Item {
2221 id: artShapeLoader;
2322 objectName: "artShapeLoader";
2423 readonly property string cardArt: cardData && cardData["art"] || "";
24+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2525 active: cardArt != "";
2626 asynchronous: true;
2727 visible: status == Loader.Ready;
@@ -30,30 +30,12 @@ Item {
3030 objectName: "artShape";
3131 visible: image.status == Image.Ready;
3232 readonly property alias image: artImage;
33− Loader {
33+ UbuntuShape {
3434 anchors.fill: parent;
35− visible: true;
36− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
37− Component {
38− id: artShapeShapeComponent;
39− UbuntuShape {
40− source: artImage;
41− sourceFillMode: UbuntuShape.PreserveAspectCrop;
42− radius: "medium";
43− aspect: {
44− switch (root.artShapeStyle) {
45− case "inset": return UbuntuShape.Inset;
46− case "shadow": return UbuntuShape.DropShadow;
47− default:
48− case "flat": return UbuntuShape.Flat;
49− }
50− }
51− }
52− }
53− Component {
54− id: artShapeIconComponent;
55− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
56− }
35+ source: artImage;
36+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
37+ radius: "medium";
38+ aspect: UbuntuShape.Flat;
5739 }
5840 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5941 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 0.75;
@@ -73,7 +55,7 @@ Item {
7355 objectName: "artImage";
7456 source: artShapeLoader.cardArt;
7557 asynchronous: true;
76− visible: !true;
58+ visible: false;
7759 width: root.width;
7860 height: width / artShape.aspect;
7961 }
@@ -131,7 +113,7 @@ UbuntuShape {
131113 id: touchdown;
132114 objectName: "touchdown";
133115 anchors { fill: artShapeHolder }
134− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
116+ visible: root.pressed;
135117 radius: "medium";
136118 borderSource: "radius_pressed.sci"
137119}
tests/plugins/Dash/cardcreator/12.res.cardcreator+10−28
@@ -1,7 +1,6 @@
1−AbstractButton {
1+AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -17,10 +16,11 @@ Item {
1716 height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
1817 width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
1918 anchors { horizontalCenter: parent.horizontalCenter; }
20− Loader {
19+ Loader {
2120 id: artShapeLoader;
2221 objectName: "artShapeLoader";
2322 readonly property string cardArt: cardData && cardData["art"] || "";
23+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2424 active: cardArt != "";
2525 asynchronous: false;
2626 visible: status == Loader.Ready;
@@ -29,30 +29,12 @@ Item {
2929 objectName: "artShape";
3030 visible: image.status == Image.Ready;
3131 readonly property alias image: artImage;
32− Loader {
32+ UbuntuShape {
3333 anchors.fill: parent;
34− visible: true;
35− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
36− Component {
37− id: artShapeShapeComponent;
38− UbuntuShape {
39− source: artImage;
40− sourceFillMode: UbuntuShape.PreserveAspectCrop;
41− radius: "medium";
42− aspect: {
43− switch (root.artShapeStyle) {
44− case "inset": return UbuntuShape.Inset;
45− case "shadow": return UbuntuShape.DropShadow;
46− default:
47− case "flat": return UbuntuShape.Flat;
48− }
49− }
50− }
51− }
52− Component {
53− id: artShapeIconComponent;
54− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
55− }
34+ source: artImage;
35+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
36+ radius: "medium";
37+ aspect: UbuntuShape.Flat;
5638 }
5739 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5840 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 0.75;
@@ -72,7 +54,7 @@ Item {
7254 objectName: "artImage";
7355 source: artShapeLoader.cardArt;
7456 asynchronous: false;
75− visible: !true;
57+ visible: false;
7658 width: root.width;
7759 height: width / artShape.aspect;
7860 }
@@ -130,7 +112,7 @@ UbuntuShape {
130112 id: touchdown;
131113 objectName: "touchdown";
132114 anchors { fill: artShapeHolder }
133− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
115+ visible: root.pressed;
134116 radius: "medium";
135117 borderSource: "radius_pressed.sci"
136118}
tests/plugins/Dash/cardcreator/12.tst+1
@@ -1,3 +1,4 @@
11template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
22components: {"art":{"aspect-ratio":0.75,"field":"art"},"subtitle":{"field":"price"},"title":{"field":"title"},"attributes":{},"social-actions":{}}
3+artShapeStyle: flat
34result: 12.res
tests/plugins/Dash/cardcreator/2.res−9
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -126,13 +125,5 @@ CroppedImageMinimumSourceSize {
126125
127126 ]
128127 }
129−UbuntuShape {
130− id: touchdown;
131− objectName: "touchdown";
132− anchors { fill: backgroundLoader }
133− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
134− radius: "medium";
135− borderSource: "radius_pressed.sci"
136−}
137128implicitHeight: row.y + row.height + units.gu(1);
138129}
tests/plugins/Dash/cardcreator/2.res.cardcreator−9
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -124,13 +123,5 @@ CroppedImageMinimumSourceSize {
124123
125124 ]
126125 }
127−UbuntuShape {
128− id: touchdown;
129− objectName: "touchdown";
130− anchors { fill: backgroundLoader }
131− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
132− radius: "medium";
133− borderSource: "radius_pressed.sci"
134−}
135126implicitHeight: row.y + row.height + units.gu(1);
136127}
tests/plugins/Dash/cardcreator/2.tst+1
@@ -1,3 +1,4 @@
11template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
22components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: icon
34result: 2.res
tests/plugins/Dash/cardcreator/3.res+5−33
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -22,6 +21,7 @@ Item {
2221 id: artShapeLoader;
2322 objectName: "artShapeLoader";
2423 readonly property string cardArt: cardData && cardData["art"] || decodeURI("IHAVE%5C%22ESCAPED%5C%22QUOTES%5C%22");
24+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2525 active: cardArt != "";
2626 asynchronous: true;
2727 visible: status == Loader.Ready;
@@ -30,30 +30,10 @@ Item {
3030 objectName: "artShape";
3131 visible: image.status == Image.Ready;
3232 readonly property alias image: artImage;
33− Loader {
33+ ProportionalShape {
3434 anchors.fill: parent;
35− visible: true;
36− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
37− Component {
38− id: artShapeShapeComponent;
39− UbuntuShape {
40− source: artImage;
41− sourceFillMode: UbuntuShape.PreserveAspectCrop;
42− radius: "medium";
43− aspect: {
44− switch (root.artShapeStyle) {
45− case "inset": return UbuntuShape.Inset;
46− case "shadow": return UbuntuShape.DropShadow;
47− default:
48− case "flat": return UbuntuShape.Flat;
49− }
50− }
51− }
52− }
53− Component {
54− id: artShapeIconComponent;
55− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
56− }
35+ source: artImage;
36+ aspect: UbuntuShape.DropShadow;
5737 }
5838 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5939 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 0.75;
@@ -73,7 +53,7 @@ Item {
7353 objectName: "artImage";
7454 source: artShapeLoader.cardArt;
7555 asynchronous: true;
76− visible: !true;
56+ visible: false;
7757 width: root.width;
7858 height: width / artShape.aspect;
7959 onStatusChanged: if (status === Image.Error) source = decodeURI("IHAVE%5C%22ESCAPED%5C%22QUOTES%5C%22");
@@ -120,13 +100,5 @@ Label {
120100 text: cardData && cardData["subtitle"] || "";
121101 font.weight: Font.Light;
122102 }
123−UbuntuShape {
124− id: touchdown;
125− objectName: "touchdown";
126− anchors { fill: artShapeHolder }
127− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
128− radius: "medium";
129− borderSource: "radius_pressed.sci"
130−}
131103implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
132104}
tests/plugins/Dash/cardcreator/3.res.cardcreator+5−33
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -21,6 +20,7 @@ Item {
2120 id: artShapeLoader;
2221 objectName: "artShapeLoader";
2322 readonly property string cardArt: cardData && cardData["art"] || "";
23+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2424 active: cardArt != "";
2525 asynchronous: false;
2626 visible: status == Loader.Ready;
@@ -29,30 +29,10 @@ Item {
2929 objectName: "artShape";
3030 visible: image.status == Image.Ready;
3131 readonly property alias image: artImage;
32− Loader {
32+ ProportionalShape {
3333 anchors.fill: parent;
34− visible: true;
35− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
36− Component {
37− id: artShapeShapeComponent;
38− UbuntuShape {
39− source: artImage;
40− sourceFillMode: UbuntuShape.PreserveAspectCrop;
41− radius: "medium";
42− aspect: {
43− switch (root.artShapeStyle) {
44− case "inset": return UbuntuShape.Inset;
45− case "shadow": return UbuntuShape.DropShadow;
46− default:
47− case "flat": return UbuntuShape.Flat;
48− }
49− }
50− }
51− }
52− Component {
53− id: artShapeIconComponent;
54− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
55− }
34+ source: artImage;
35+ aspect: UbuntuShape.DropShadow;
5636 }
5737 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5838 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 0.75;
@@ -72,7 +52,7 @@ Item {
7252 objectName: "artImage";
7353 source: artShapeLoader.cardArt;
7454 asynchronous: false;
75− visible: !true;
55+ visible: false;
7656 width: root.width;
7757 height: width / artShape.aspect;
7858 }
@@ -118,13 +98,5 @@ Label {
11898 text: cardData && cardData["subtitle"] || "";
11999 font.weight: Font.Light;
120100 }
121−UbuntuShape {
122− id: touchdown;
123− objectName: "touchdown";
124− anchors { fill: artShapeHolder }
125− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
126− radius: "medium";
127− borderSource: "radius_pressed.sci"
128−}
129101implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);
130102}
tests/plugins/Dash/cardcreator/3.tst+1
@@ -1,3 +1,4 @@
11template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
22components: {"art":{"aspect-ratio":0.75,"field":"art","fallback":"IHAVE\\\"ESCAPED\\\"QUOTES\\\""},"subtitle":{"field":"price"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: icon
34result: 3.res
tests/plugins/Dash/cardcreator/4.res+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -103,7 +102,7 @@ UbuntuShape {
103102 id: touchdown;
104103 objectName: "touchdown";
105104 anchors { fill: root }
106− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
105+ visible: root.pressed;
107106 radius: "medium";
108107 borderSource: "radius_pressed.sci"
109108}
tests/plugins/Dash/cardcreator/4.res.cardcreator+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -101,7 +100,7 @@ UbuntuShape {
101100 id: touchdown;
102101 objectName: "touchdown";
103102 anchors { fill: root }
104− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
103+ visible: root.pressed;
105104 radius: "medium";
106105 borderSource: "radius_pressed.sci"
107106}
tests/plugins/Dash/cardcreator/4.tst+1
@@ -1,3 +1,4 @@
11template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2}
22components: {"art":{"aspect-ratio":1},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: flat
34result: 4.res
tests/plugins/Dash/cardcreator/5.res+2−35
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -22,6 +21,7 @@ Item {
2221 id: artShapeLoader;
2322 objectName: "artShapeLoader";
2423 readonly property string cardArt: cardData && cardData["art"] || "";
24+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2525 active: cardArt != "";
2626 asynchronous: true;
2727 visible: status == Loader.Ready;
@@ -30,31 +30,6 @@ Item {
3030 objectName: "artShape";
3131 visible: image.status == Image.Ready;
3232 readonly property alias image: artImage;
33− Loader {
34− anchors.fill: parent;
35− visible: false;
36− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
37− Component {
38− id: artShapeShapeComponent;
39− UbuntuShape {
40− source: artImage;
41− sourceFillMode: UbuntuShape.PreserveAspectCrop;
42− radius: "medium";
43− aspect: {
44− switch (root.artShapeStyle) {
45− case "inset": return UbuntuShape.Inset;
46− case "shadow": return UbuntuShape.DropShadow;
47− default:
48− case "flat": return UbuntuShape.Flat;
49− }
50− }
51− }
52− }
53− Component {
54− id: artShapeIconComponent;
55− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
56− }
57− }
5833 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5934 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 1;
6035 Component.onCompleted: { updateWidthHeightBindings(); }
@@ -73,7 +48,7 @@ Item {
7348 objectName: "artImage";
7449 source: artShapeLoader.cardArt;
7550 asynchronous: true;
76− visible: !false;
51+ visible: true;
7752 width: root.width;
7853 height: width / artShape.aspect;
7954 }
@@ -138,13 +113,5 @@ Label {
138113 text: cardData && cardData["subtitle"] || "";
139114 font.weight: Font.Light;
140115 }
141−UbuntuShape {
142− id: touchdown;
143− objectName: "touchdown";
144− anchors { fill: artShapeHolder }
145− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
146− radius: "medium";
147− borderSource: "radius_pressed.sci"
148−}
149116implicitHeight: artShapeHolder.height;
150117}
tests/plugins/Dash/cardcreator/5.res.cardcreator+2−35
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -21,6 +20,7 @@ Item {
2120 id: artShapeLoader;
2221 objectName: "artShapeLoader";
2322 readonly property string cardArt: cardData && cardData["art"] || "";
23+ onCardArtChanged: { if (item) { item.image.source = cardArt; } }
2424 active: cardArt != "";
2525 asynchronous: false;
2626 visible: status == Loader.Ready;
@@ -29,31 +29,6 @@ Item {
2929 objectName: "artShape";
3030 visible: image.status == Image.Ready;
3131 readonly property alias image: artImage;
32− Loader {
33− anchors.fill: parent;
34− visible: false;
35− sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
36− Component {
37− id: artShapeShapeComponent;
38− UbuntuShape {
39− source: artImage;
40− sourceFillMode: UbuntuShape.PreserveAspectCrop;
41− radius: "medium";
42− aspect: {
43− switch (root.artShapeStyle) {
44− case "inset": return UbuntuShape.Inset;
45− case "shadow": return UbuntuShape.DropShadow;
46− default:
47− case "flat": return UbuntuShape.Flat;
48− }
49− }
50− }
51− }
52− Component {
53− id: artShapeIconComponent;
54− ProportionalShape { source: artImage; aspect: UbuntuShape.DropShadow; }
55− }
56− }
5732 readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
5833 readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : 1;
5934 Component.onCompleted: { updateWidthHeightBindings(); }
@@ -72,7 +47,7 @@ Item {
7247 objectName: "artImage";
7348 source: artShapeLoader.cardArt;
7449 asynchronous: false;
75− visible: !false;
50+ visible: true;
7651 width: root.width;
7752 height: width / artShape.aspect;
7853 }
@@ -137,13 +112,5 @@ Label {
137112 text: cardData && cardData["subtitle"] || "";
138113 font.weight: Font.Light;
139114 }
140−UbuntuShape {
141− id: touchdown;
142− objectName: "touchdown";
143− anchors { fill: artShapeHolder }
144− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
145− radius: "medium";
146− borderSource: "radius_pressed.sci"
147−}
148115implicitHeight: artShapeHolder.height;
149116}
tests/plugins/Dash/cardcreator/5.tst+1
@@ -1,3 +1,4 @@
11template: {"non-interactive":true,"card-layout":"vertical","card-size":"medium","category-layout":"carousel","collapsed-rows":2,"overlay":true}
22components: {"art":{"aspect-ratio":1,"field":"art","conciergeMode":true},"subtitle":{"field":"artist"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: shadow
34result: 5.res
tests/plugins/Dash/cardcreator/6.res+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -119,7 +118,7 @@ UbuntuShape {
119118 id: touchdown;
120119 objectName: "touchdown";
121120 anchors { fill: backgroundLoader }
122− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
121+ visible: root.pressed;
123122 radius: "medium";
124123 borderSource: "radius_pressed.sci"
125124}
tests/plugins/Dash/cardcreator/6.res.cardcreator+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -118,7 +117,7 @@ UbuntuShape {
118117 id: touchdown;
119118 objectName: "touchdown";
120119 anchors { fill: backgroundLoader }
121− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
120+ visible: root.pressed;
122121 radius: "medium";
123122 borderSource: "radius_pressed.sci"
124123}
tests/plugins/Dash/cardcreator/6.tst+1
@@ -1,3 +1,4 @@
11template: {"card-background":"http://assets.ubuntu.com/sites/ubuntu/latest/u/img/logos/logo-ubuntu-grey.png","card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
22components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"subtitle":{"field":"author"},"title":{"field":"title"},"emblem":{"field":"source"},"attributes":{}}
3+artShapeStyle: inset
34result: 6.res
tests/plugins/Dash/cardcreator/7.res−9
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -139,13 +138,5 @@ CroppedImageMinimumSourceSize {
139138
140139 ]
141140 }
142−UbuntuShape {
143− id: touchdown;
144− objectName: "touchdown";
145− anchors { fill: backgroundLoader }
146− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
147− radius: "medium";
148− borderSource: "radius_pressed.sci"
149−}
150141implicitHeight: row.y + row.height + units.gu(1);
151142}
tests/plugins/Dash/cardcreator/7.res.cardcreator−9
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -137,13 +136,5 @@ CroppedImageMinimumSourceSize {
137136
138137 ]
139138 }
140−UbuntuShape {
141− id: touchdown;
142− objectName: "touchdown";
143− anchors { fill: backgroundLoader }
144− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
145− radius: "medium";
146− borderSource: "radius_pressed.sci"
147−}
148139implicitHeight: row.y + row.height + units.gu(1);
149140}
tests/plugins/Dash/cardcreator/7.tst+1
@@ -1,3 +1,4 @@
11template: {"card-background":{"elements":["#E9E9E9","#E9AAE9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
22components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{"field":"attributes","max-count":2}}
3+artShapeStyle: icon
34result: 7.res
tests/plugins/Dash/cardcreator/8.res+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -101,7 +100,7 @@ UbuntuShape {
101100 id: touchdown;
102101 objectName: "touchdown";
103102 anchors { fill: backgroundLoader }
104− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
103+ visible: root.pressed;
105104 radius: "medium";
106105 borderSource: "radius_pressed.sci"
107106}
tests/plugins/Dash/cardcreator/8.res.cardcreator+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -99,7 +98,7 @@ UbuntuShape {
9998 id: touchdown;
10099 objectName: "touchdown";
101100 anchors { fill: backgroundLoader }
102− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
101+ visible: root.pressed;
103102 radius: "medium";
104103 borderSource: "radius_pressed.sci"
105104}
tests/plugins/Dash/cardcreator/8.tst+1
@@ -1,3 +1,4 @@
11template: {"card-background":{"elements":["#E9E9E9","#E9AAE9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
22components: {"background":{"field":"background"},"mascot":{"field":"icon"},"title":{"field":"title"},"attributes":{}}
3+artShapeStyle: inset
34result: 8.res
tests/plugins/Dash/cardcreator/9.res+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -112,7 +111,7 @@ CardAudioProgress {
112111 id: touchdown;
113112 objectName: "touchdown";
114113 anchors { fill: root }
115− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
114+ visible: root.pressed;
116115 radius: "medium";
117116 borderSource: "radius_pressed.sci"
118117 }
tests/plugins/Dash/cardcreator/9.res.cardcreator+1−2
@@ -1,7 +1,6 @@
11AbstractButton {
22 id: root;
33 property var cardData;
4− property string artShapeStyle: "inset";
54 property string backgroundShapeStyle: "inset";
65 property real fontScale: 1.0;
76 property var scopeStyle: null;
@@ -111,7 +110,7 @@ CardAudioProgress {
111110 id: touchdown;
112111 objectName: "touchdown";
113112 anchors { fill: root }
114− visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
113+ visible: root.pressed;
115114 radius: "medium";
116115 borderSource: "radius_pressed.sci"
117116 }
tests/plugins/Dash/cardcreator/9.tst+1
@@ -1,3 +1,4 @@
11template: {"card-layout":"horizontal","card-size":"medium","category-layout":"grid","collapsed-rows":2,"quick-preview-type": "audio"}
22components: {"art":{"aspect-ratio":1},"subtitle":{"field":"author"},"title":{"field":"title"}, "quickPreviewData": "quickPreviewData"}
3+artShapeStyle: inset
34result: 9.res
tests/plugins/Dash/cardcreatortest.cpp+9−6
@@ -78,6 +78,7 @@ private Q_SLOTS:
7878 {
7979 const QString templateString("template: ");
8080 const QString componentsString("components: ");
81+ const QString artShapeStyleString("artShapeStyle: ");
8182 const QString resultString("result: ");
8283
8384 const QString testDirPath = testDataDir() + "/" TEST_DIR "/cardcreator/";
@@ -92,24 +93,26 @@ private Q_SLOTS:
9293
9394 QVERIFY(lines[0].startsWith(templateString));
9495 QVERIFY(lines[1].startsWith(componentsString));
95− QVERIFY(lines[2].startsWith(resultString));
96+ QVERIFY(lines[2].startsWith(artShapeStyleString));
97+ QVERIFY(lines[3].startsWith(resultString));
9698
9799 const QString templateJSON = lines[0].mid(templateString.length());
98100 const QString componentsJSON = lines[1].mid(componentsString.length());
99− const QString resultFileName = lines[2].mid(resultString.length());
101+ const QString artShapeStyle = lines[2].mid(artShapeStyleString.length());
102+ const QString resultFileName = lines[3].mid(resultString.length());
100103 QVariant cardStringResult;
101104 QVariant createCardComponentResult;
102105
103− QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, false));
106+ QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, false), Q_ARG(QVariant, artShapeStyle));
104107 compareFileContents(testDirPath + resultFileName, cardStringResult.toString());
105108
106− QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, true));
109+ QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, true), Q_ARG(QVariant, artShapeStyle));
107110 compareFileContents(testDirPath + resultFileName + ".cardcreator", cardStringResult.toString());
108111
109− QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, false));
112+ QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, false), Q_ARG(QVariant, artShapeStyle));
110113 QVERIFY(createCardComponentResult.toBool());
111114
112− QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, true));
115+ QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON), Q_ARG(QVariant, true), Q_ARG(QVariant, artShapeStyle));
113116 QVERIFY(createCardComponentResult.toBool());
114117 }
115118 }
tests/plugins/Dash/cardcreatortest.qml+4−4
@@ -19,11 +19,11 @@ import "../../../plugins/Dash/CardCreator.js" as CardCreator
1919
2020Item {
2121 id: root
22− function cardString(template, components, isCardCreator) {
23− return CardCreator.cardString(JSON.parse(template), JSON.parse(components), isCardCreator);
22+ function cardString(template, components, isCardCreator, artShapeStyle) {
23+ return CardCreator.cardString(JSON.parse(template), JSON.parse(components), isCardCreator, artShapeStyle);
2424 }
2525
26− function createCardComponent(template, components, isCardCreator) {
27− return CardCreator.createCardComponent(root, JSON.parse(template), JSON.parse(components), isCardCreator) !== null;
26+ function createCardComponent(template, components, isCardCreator, artShapeStyle) {
27+ return CardCreator.createCardComponent(root, JSON.parse(template), JSON.parse(components), isCardCreator, artShapeStyle) !== null;
2828 }
2929}
tests/plugins/Dash/listviewwithpageheadersectionexternalmodeltest.cpp+2−2
@@ -153,12 +153,12 @@ private:
153153
154154 QString section(QQuickItem *item)
155155 {
156− return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
156+ return item ? item->property("text").toString() : QString();
157157 }
158158
159159 int sectionDelegateIndex(QQuickItem *item)
160160 {
161− return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
161+ return item ? item->property("delegateIndex").toInt() : -1;
162162 }
163163
164164private Q_SLOTS:
tests/plugins/Dash/listviewwithpageheadersectiontest.cpp+2−2
@@ -118,12 +118,12 @@ private:
118118
119119 QString section(QQuickItem *item) const
120120 {
121− return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("section")).toString() : QString();
121+ return item ? item->property("text").toString() : QString();
122122 }
123123
124124 int sectionDelegateIndex(QQuickItem *item) const
125125 {
126− return item ? QQmlEngine::contextForObject(item)->parentContext()->contextProperty(QLatin1String("delegateIndex")).toInt() : -1;
126+ return item ? item->property("delegateIndex").toInt() : -1;
127127 }
128128
129129private Q_SLOTS:
tests/plugins/Dash/listviewwithpageheadertest.cpp+5
@@ -47,6 +47,11 @@ private:
4747 QTRY_COMPARE(item->y(), pos);
4848 QTRY_COMPARE(item->height(), height);
4949 QCOMPARE(QQuickItemPrivate::get(item->m_item)->culled, culled);
50+ if (lvwph->delegate() == otherDelegate) {
51+ QCOMPARE(item->m_item->width(), lvwph->width());
52+ } else {
53+ QCOMPARE(item->m_item->width(), lvwph->width() - 20);
54+ }
5055 }
5156
5257 void changeContentY(qreal change)
tests/plugins/Dash/listviewwithpageheadertestsection.qml+3−2
@@ -97,9 +97,10 @@ Rectangle {
9797 sectionProperty: "type"
9898 sectionDelegate: Component {
9999 Rectangle {
100+ property alias text: theText.text
100101 color: "green"
101− height: section === "" ? 0 : section != "halfheight" ? 40 : 20;
102− Text { text: section; font.pixelSize: 34 }
102+ height: text === "" ? 0 : text != "halfheight" ? 40 : 20;
103+ Text { id: theText; font.pixelSize: 34 }
103104 anchors { left: parent.left; right: parent.right }
104105 }
105106 }
tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml+2−1
@@ -65,9 +65,10 @@ Rectangle {
6565 sectionProperty: "type"
6666 sectionDelegate: Component {
6767 Rectangle {
68+ property alias text: theText.text
6869 color: "green"
6970 height: 40
70− Text { text: section; font.pixelSize: 34 }
71+ Text { id: theText; font.pixelSize: 34 }
7172 anchors { left: parent.left; right: parent.right }
7273 }
7374 }
tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml+4−2
@@ -81,9 +81,10 @@ Rectangle {
8181 sectionDelegate: Component {
8282 id: sectionHeaderComponent
8383 Rectangle {
84+ property alias text: theText.text
8485 color: "green"
8586 height: listView.sectionHeaderHeight
86− Text { text: section; font.pixelSize: 34 }
87+ Text { id: theText; font.pixelSize: 34 }
8788 anchors { left: parent.left; right: parent.right }
8889 }
8990 }
@@ -92,9 +93,10 @@ Rectangle {
9293 Component {
9394 id: otherSectionHeaderComponent
9495 Rectangle {
96+ property alias text: theText.text
9597 color: "green"
9698 height: 50
97− Text { text: section; font.pixelSize: 34 }
99+ Text { id: theText; font.pixelSize: 34 }
98100 anchors { left: parent.left; right: parent.right }
99101 }
100102 }
tests/plugins/Dash/tst_ScopeStyle.qml+1−1
@@ -174,7 +174,7 @@ Rectangle {
174174
175175 function test_previewButtonColor_data() {
176176 return [
177− { tag: "default", index: 0, previewButtonColor: UbuntuColors.orange },
177+ { tag: "default", index: 0, previewButtonColor: theme.palette.normal.positive },
178178 { tag: "red", index: 1, previewButtonColor: "red" },
179179 ];
180180 }
tests/plugins/Ubuntu/Gestures/CMakeLists.txt+4−4
@@ -1,5 +1,7 @@
11include(QmlTest)
22
3+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
4+
35# DANGER! DANGER! Using Qt's private API!
46include_directories(
57 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
@@ -7,7 +9,7 @@ include_directories(
79
810include_directories(
911 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
10− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
12+ ${UBUNTUGESTURES_INCLUDE_DIRS}
1113 ${CMAKE_CURRENT_BINARY_DIR}
1214 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
1315 )
@@ -19,7 +21,7 @@ export_qmlfiles(UbuntuGesturesTest .
1921macro(build_gesture_test CLASSNAME)
2022 add_executable(${CLASSNAME}TestExec tst_${CLASSNAME}.cpp GestureTest.cpp TestItem.cpp)
2123 qt5_use_modules(${CLASSNAME}TestExec Test Core Qml Gui Quick)
22− target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml UbuntuGestures)
24+ target_link_libraries(${CLASSNAME}TestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
2325 install(TARGETS ${CLASSNAME}TestExec
2426 DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/plugins/Ubuntu/Gestures"
2527 )
@@ -51,11 +53,9 @@ macro(add_gesture_ui_test CLASSNAME)
5153 add_manual_qml_test(. ${CLASSNAME} IMPORT_PATHS ${UNITY_IMPORT_PATHS})
5254endmacro()
5355
54−add_gesture_ui_test(DirectionalDragArea)
5556add_gesture_ui_test(FloatingFlickable)
5657add_gesture_ui_test(PressedOutsideNotifier)
5758add_gesture_ui_test(TouchDispatcher)
5859add_gesture_ui_test(TouchGate)
59−add_gesture_unit_test(Damper)
6060add_gesture_unit_test(AxisVelocityCalculator)
6161add_gesture_ui_test(TouchGestureArea)
tests/plugins/Ubuntu/Gestures/DownwardsLauncher.qmldeleted−72
@@ -1,72 +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.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22−
23− function reset() { launcher.y = -launcher.height }
24−
25− Rectangle {
26− id: launcher
27− color: "blue"
28− width: parent.width
29− height: units.gu(15)
30− x: 0
31− y: followDragArea()
32−
33− function followDragArea() {
34− return dragArea.distance < height ? -height + dragArea.distance : 0
35− }
36− }
37−
38− Rectangle {
39− id: dragAreaRect
40− opacity: dragArea.dragging ? 0.5 : 0.0
41− color: "green"
42− anchors.fill: dragArea
43− }
44−
45− DirectionalDragArea {
46− id: dragArea
47− objectName: "vpDragArea"
48−
49− height: units.gu(5)
50−
51− direction: Direction.Downwards
52−
53− onDraggingChanged: {
54− if (dragging) {
55− launcher.y = Qt.binding(launcher.followDragArea)
56− }
57− }
58−
59− anchors {
60− left: parent.left
61− right: parent.right
62− top: parent.top
63− }
64− }
65−
66− Label {
67− text: "Downwards"
68− anchors.top: parent.top
69− anchors.horizontalCenter: parent.horizontalCenter
70− anchors.topMargin: units.gu(1)
71− }
72−}
tests/plugins/Ubuntu/Gestures/GestureTest.cpp+2−2
@@ -22,8 +22,8 @@
2222#include <QQuickView>
2323#include <QtTest>
2424
25−#include <Timer.h>
26−#include <TouchRegistry.h>
25+#include <Timer>
26+#include <TouchRegistry>
2727#include <paths.h>
2828
2929using namespace UbuntuGestures;
tests/plugins/Ubuntu/Gestures/LeftwardsLauncher.qmldeleted−76
@@ -1,76 +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.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22− id: root
23−
24− function reset() { launcher.x = Qt.binding(function(){return root.width;}); }
25−
26− Rectangle {
27− id: launcher
28− color: "blue"
29− width: units.gu(15)
30− height: parent.height
31− x: root.width
32− y: 0
33−
34− function followDragArea() {
35− return dragArea.distance > -width ?
36− root.width + dragArea.distance
37− :
38− root.width - width
39− }
40− }
41−
42− Rectangle {
43− id: dragAreaRect
44− opacity: dragArea.dragging ? 0.5 : 0.0
45− color: "green"
46− anchors.fill: dragArea
47− }
48−
49− DirectionalDragArea {
50− id: dragArea
51− objectName: "hnDragArea"
52−
53− width: units.gu(5)
54−
55− direction: Direction.Leftwards
56−
57− onDraggingChanged: {
58− if (dragging) {
59− launcher.x = Qt.binding(launcher.followDragArea)
60− }
61− }
62−
63− anchors {
64− right: parent.right
65− top: parent.top
66− bottom: parent.bottom
67− }
68− }
69−
70− Label {
71− text: "Leftwards"
72− anchors.right: parent.right
73− anchors.verticalCenter: parent.verticalCenter
74− anchors.rightMargin: units.gu(1)
75− }
76−}
tests/plugins/Ubuntu/Gestures/RightwardsLauncher.qmldeleted−76
@@ -1,76 +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.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22− objectName: "rightwardsLauncher"
23−
24− function reset() { launcher.x = -launcher.width }
25−
26− Rectangle {
27− id: launcher
28− color: "blue"
29− width: units.gu(15)
30− height: parent.height
31− x: followDragArea()
32− y: 0
33−
34− function followDragArea() {
35− return dragArea.distance < width ? -width + dragArea.distance : 0
36− }
37− }
38−
39− Rectangle {
40− id: dragAreaRect
41− opacity: dragArea.dragging ? 0.5 : 0.0
42− color: "green"
43− anchors.fill: dragArea
44− }
45−
46− DirectionalDragArea {
47− id: dragArea
48− objectName: "hpDragArea"
49−
50− // give some room for items to be dynamically stacked right behind him
51− z: 10.0
52−
53− width: units.gu(5)
54−
55− direction: Direction.Rightwards
56−
57− onDraggingChanged: {
58− if (dragging) {
59− launcher.x = Qt.binding(launcher.followDragArea)
60− }
61− }
62−
63− anchors {
64− left: parent.left
65− top: parent.top
66− bottom: parent.bottom
67− }
68− }
69−
70− Label {
71− text: "Rightwards"
72− anchors.left: parent.left
73− anchors.verticalCenter: parent.verticalCenter
74− anchors.leftMargin: units.gu(1)
75− }
76−}
tests/plugins/Ubuntu/Gestures/UpwardsLauncher.qmldeleted−76
@@ -1,76 +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.4
18−import Ubuntu.Gestures 0.1
19−import Ubuntu.Components 1.3
20−
21−Item {
22− id: root
23−
24− function reset() { launcher.y = Qt.binding(function(){return root.height;}); }
25−
26− Rectangle {
27− id: launcher
28− color: "blue"
29− width: parent.width
30− height: units.gu(15)
31− x: 0
32− y: root.height
33−
34− function followDragArea() {
35− return dragArea.distance > -height ?
36− root.height + dragArea.distance
37− :
38− root.height - height
39− }
40− }
41−
42− Rectangle {
43− id: dragAreaRect
44− opacity: dragArea.dragging ? 0.5 : 0.0
45− color: "green"
46− anchors.fill: dragArea
47− }
48−
49− DirectionalDragArea {
50− id: dragArea
51− objectName: "vnDragArea"
52−
53− height: units.gu(5)
54−
55− direction: Direction.Upwards
56−
57− onDraggingChanged: {
58− if (dragging) {
59− launcher.y = Qt.binding(launcher.followDragArea)
60− }
61− }
62−
63− anchors {
64− left: parent.left
65− right: parent.right
66− bottom: parent.bottom
67− }
68− }
69−
70− Label {
71− text: "Upwards"
72− anchors.bottom: parent.bottom
73− anchors.horizontalCenter: parent.horizontalCenter
74− anchors.bottomMargin: units.gu(1)
75− }
76−}
tests/plugins/Ubuntu/Gestures/tst_Damper.cppdeleted−40
@@ -1,40 +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−#include <QtTest/QtTest>
18−
19−#include <Damper.h>
20−
21−class tst_Damper : public QObject
22−{
23− Q_OBJECT
24−private Q_SLOTS:
25− void negativeMovement();
26−};
27−
28−void tst_Damper::negativeMovement()
29−{
30− Damper<qreal> damper;
31−
32− damper.setMaxDelta(3.0);
33− damper.reset(0.0);
34− damper.update(-5.0);
35− QCOMPARE(damper.value(), -2.0);
36−}
37−
38−QTEST_MAIN(tst_Damper)
39−
40−#include "tst_Damper.moc"
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cppdeleted−1250
@@ -1,1250 +0,0 @@
1−/*
2− * Copyright (C) 2013-2015 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 <QtTest/QtTest>
18−#include <QtCore/QObject>
19−#include <QtQuick/QQuickView>
20−#include <QtQml/QQmlEngine>
21−#include <QPointer>
22−#include <private/qquickmousearea_p.h>
23−
24−
25−#include <DirectionalDragArea.h>
26−#include <DirectionalDragArea_p.h>
27−#include <TouchRegistry.h>
28−
29−#include "GestureTest.h"
30−
31−using namespace UbuntuGestures;
32−
33−// Because QSignalSpy(directionalDragArea, SIGNAL(DirectionalDragArea::Status)) simply
34−// doesn't work
35−class StatusSpy : public QObject {
36− Q_OBJECT
37−public:
38− StatusSpy(DirectionalDragArea *edgeDragArea) {
39− m_recognized = false;
40− connect(edgeDragArea->d, &DirectionalDragAreaPrivate::statusChanged,
41− this, &StatusSpy::onStatusChanged);
42− }
43− bool recognized() {
44− return m_recognized;
45− }
46−
47−private Q_SLOTS:
48− void onStatusChanged(DirectionalDragAreaPrivate::Status status) {
49− m_recognized |= status == DirectionalDragAreaPrivate::Recognized;
50− }
51−
52−private:
53− bool m_recognized;
54−};
55−
56−/*
57− QQuickMouseArea::canceled() signal is not registered in the meta object system.
58− So using a QSignalSpy to track it won't work. Thus the only way to connect to it
59− is using its method address directly.
60− */
61−class MouseAreaSpy : public QObject
62−{
63− Q_OBJECT
64−public:
65− MouseAreaSpy(QQuickMouseArea *mouseArea)
66− : canceledCount(0)
67− {
68− connect(mouseArea, &QQuickMouseArea::canceled,
69− this, &MouseAreaSpy::onMouseAreaCanceled);
70− }
71−
72− int canceledCount;
73−
74−private Q_SLOTS:
75− void onMouseAreaCanceled() {
76− ++canceledCount;
77− }
78−};
79−
80−class tst_DirectionalDragArea: public GestureTest
81−{
82− Q_OBJECT
83−public:
84− tst_DirectionalDragArea();
85−private Q_SLOTS:
86− void init() override; // called right before each and every test function is executed
87−
88− void dragWithShortDirectionChange();
89− void recognitionTimerUsage();
90− void sceneXAndX();
91− void sceneYAndY();
92− void twoFingerTap();
93− void movingDDA();
94− void ignoreOldFinger();
95− void rotated();
96− void sceneDistance();
97− void sceneDistance_data();
98− void disabledWhileDragging();
99− void oneFingerDownFollowedByLateSecondFingerDown();
100− void givesUpWhenLosesTouch();
101− void threeFingerDrag();
102− void immediateRecognitionWhenConstraintsDisabled();
103− void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition();
104− void withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data();
105− void gettingTouchOwnershipMakesMouseAreaBehindGetCanceled();
106− void interleavedTouches();
107− void makoRightEdgeDrag();
108− void makoRightEdgeDrag_verticalDownwards();
109− void makoLeftEdgeDrag_slowStart();
110− void makoLeftEdgeDrag_movesSlightlyBackwardsOnStart();
111−};
112−
113−tst_DirectionalDragArea::tst_DirectionalDragArea()
114− : GestureTest(QStringLiteral("tst_DirectionalDragArea.qml"))
115−{
116−}
117−
118−void tst_DirectionalDragArea::init()
119−{
120− GestureTest::init();
121−
122− // We shouldn't need the three lines below, but a compiz/unity7
123− // regression means we don't pass the test without them because
124− // the window doesn't have the proper size. Can be removed in the
125− // future if the regression is fixed and tests pass again
126− m_view->resize(m_view->rootObject()->width(), m_view->rootObject()->height());
127− QTRY_COMPARE(m_view->width(), (int)m_view->rootObject()->width());
128− QTRY_COMPARE(m_view->height(), (int)m_view->rootObject()->height());
129−}
130−
131−namespace {
132−QPointF calculateInitialTouchPos(DirectionalDragArea *edgeDragArea)
133−{
134− QPointF localCenter(edgeDragArea->width() / 2., edgeDragArea->height() / 2.);
135− return edgeDragArea->mapToScene(localCenter);
136−}
137−}
138−
139−/*
140− A directional drag should still be recognized if there is a momentaneous, small,
141− change in the direction of a drag. That should be accounted as input noise and
142− therefore ignored.
143− */
144−void tst_DirectionalDragArea::dragWithShortDirectionChange()
145−{
146− DirectionalDragArea *edgeDragArea =
147− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
148− QVERIFY(edgeDragArea != 0);
149− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
150− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
151−
152− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
153− QPointF touchPoint = initialTouchPos;
154−
155− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0;
156− QPointF dragDirectionVector(1.0, 0.0);
157− qreal touchStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
158− // make sure we are above maximum time
159− int touchStepTimeMs = edgeDragArea->d->maxTime / 20. ;
160− QPointF touchMovement = dragDirectionVector * touchStepDistance;
161−
162− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
163−
164− // Move a bit in the proper direction
165− for (int i=0; i < 3; ++i) {
166− touchPoint += touchMovement;
167− passTime(touchStepTimeMs);
168− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
169− }
170−
171− // Then a sudden and small movement to the opposite direction
172− touchPoint -= touchMovement*0.2;
173− passTime(touchStepTimeMs*0.2);
174− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
175−
176− // And then resume movment in the correct direction until it crosses the distance and time
177− // thresholds.
178− do {
179− touchPoint += touchMovement;
180− passTime(touchStepTimeMs);
181− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
182− } while ((touchPoint - initialTouchPos).manhattanLength() < desiredDragDistance
183− || m_fakeTimerFactory->timeSource()->msecsSinceReference() < (edgeDragArea->d->compositionTime * 1.5f));
184−
185− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
186−
187− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
188−}
189−
190−/*
191− Checks that the recognition timer is started and stopped appropriately.
192− I.e., check that it's running only while gesture recognition is taking place
193− (status == Undecided)
194− */
195−void tst_DirectionalDragArea::recognitionTimerUsage()
196−{
197− DirectionalDragArea *edgeDragArea =
198− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
199− QVERIFY(edgeDragArea != 0);
200− AbstractTimer *fakeTimer = m_fakeTimerFactory->createTimer();
201− edgeDragArea->d->setRecognitionTimer(fakeTimer);
202− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
203−
204− int timeStepMs = 5; // some arbitrary small value.
205−
206− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
207− QPointF touchPoint = initialTouchPos;
208−
209− QPointF dragDirectionVector(1.0, 0.0);
210− QPointF touchMovement = dragDirectionVector * (edgeDragArea->d->distanceThreshold * 0.2f);
211−
212− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
213− QVERIFY(!fakeTimer->isRunning());
214−
215− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
216−
217− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
218− QVERIFY(fakeTimer->isRunning());
219−
220− // Move beyond distance threshold and composition time to ensure recognition
221− while (m_fakeTimerFactory->timeSource()->msecsSinceReference() <= edgeDragArea->d->compositionTime ||
222− (touchPoint - initialTouchPos).manhattanLength() <= edgeDragArea->d->distanceThreshold) {
223−
224− QCOMPARE(edgeDragArea->d->status == DirectionalDragAreaPrivate::Undecided, fakeTimer->isRunning());
225−
226− touchPoint += touchMovement;
227− passTime(timeStepMs);
228− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
229− }
230−
231− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
232− QVERIFY(!fakeTimer->isRunning());
233−}
234−
235−/*
236− Checks that it informs the X coordinate of the touch point in local and scene coordinates
237− correctly.
238− */
239−void tst_DirectionalDragArea::sceneXAndX()
240−{
241− DirectionalDragArea *edgeDragArea =
242− m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
243− QVERIFY(edgeDragArea != 0);
244− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
245− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
246− edgeDragArea->setImmediateRecognition(true);
247−
248− QPointF touchScenePos(m_view->width() - (edgeDragArea->width()/2.0f), m_view->height()/2.0f);
249−
250− sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
251−
252− QSignalSpy touchXSpy(edgeDragArea, &DirectionalDragArea::touchXChanged);
253− QSignalSpy touchSceneXSpy(edgeDragArea, &DirectionalDragArea::touchSceneXChanged);
254−
255− touchScenePos.rx() = m_view->width() / 2;
256− sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
257−
258− QCOMPARE(touchXSpy.count(), 1);
259− QCOMPARE(touchSceneXSpy.count(), 1);
260− QCOMPARE(edgeDragArea->touchX(), touchScenePos.x() - edgeDragArea->x());
261− QCOMPARE(edgeDragArea->touchSceneX(), touchScenePos.x());
262−}
263−
264−/*
265− Checks that it informs the Y coordinate of the touch point in local and scene coordinates
266− correctly.
267− */
268−void tst_DirectionalDragArea::sceneYAndY()
269−{
270− DirectionalDragArea *edgeDragArea =
271− m_view->rootObject()->findChild<DirectionalDragArea*>("vnDragArea");
272− QVERIFY(edgeDragArea != 0);
273− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
274− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
275− edgeDragArea->setImmediateRecognition(true);
276−
277− QPointF touchScenePos(m_view->width()/2.0f, m_view->height() - (edgeDragArea->height()/2.0f));
278−
279− sendTouchPress(0 /* timestamp */, 0 /* id */, touchScenePos);
280−
281− QSignalSpy touchYSpy(edgeDragArea, &DirectionalDragArea::touchYChanged);
282− QSignalSpy touchSceneYSpy(edgeDragArea, &DirectionalDragArea::touchSceneYChanged);
283−
284− touchScenePos.ry() = m_view->height() / 2;
285− sendTouchUpdate(50 /* timestamp */, 0 /* id */, touchScenePos);
286−
287− QCOMPARE(touchYSpy.count(), 1);
288− QCOMPARE(touchSceneYSpy.count(), 1);
289− QCOMPARE(edgeDragArea->touchY(), touchScenePos.y() - edgeDragArea->y());
290− QCOMPARE(edgeDragArea->touchSceneY(), touchScenePos.y());
291−}
292−
293−/*
294− Regression test for https://bugs.launchpad.net/bugs/1228336
295−
296− Perform a quick two-finger double-tap and check that DirectionalDragArea properly
297− rejects those touch points. In the bug above it got confused and crashed.
298− */
299−void tst_DirectionalDragArea::twoFingerTap()
300−{
301− DirectionalDragArea *edgeDragArea =
302− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
303− QVERIFY(edgeDragArea != 0);
304− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
305− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
306−
307− // Make touches evenly spaced along the edgeDragArea
308− QPoint touchAPos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
309− QPoint touchBPos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
310−
311− qint64 timeStepMsecs = 5; // some arbitrary, small value
312−
313− // Perform the first two-finger tap
314− // NB: using move() instead of stationary() becasue in the latter you cannot provide
315− // the touch position and therefore it's left with some garbage numbers.
316− QTest::touchEvent(m_view, m_device)
317− .press(0, touchAPos);
318−
319− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
320−
321− passTime(timeStepMsecs);
322− QTest::touchEvent(m_view, m_device)
323− .move(0, touchAPos)
324− .press(1, touchBPos);
325−
326− // A second touch point appeared during recognition, reject immediately as this
327− // can't be a single-touch gesture anymore.
328− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
329−
330− passTime(timeStepMsecs);
331− QTest::touchEvent(m_view, m_device)
332− .release(0, touchAPos)
333− .move(1, touchBPos);
334−
335− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
336−
337− passTime(timeStepMsecs);
338− QTest::touchEvent(m_view, m_device)
339− .release(1, touchBPos);
340−
341− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
342−
343− // Perform the second two-finger tap
344−
345− passTime(timeStepMsecs);
346− QTest::touchEvent(m_view, m_device)
347− .press(0, touchAPos);
348−
349− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
350−
351− passTime(timeStepMsecs);
352− QTest::touchEvent(m_view, m_device)
353− .move(0, touchAPos)
354− .press(1, touchBPos);
355−
356− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
357−
358− passTime(timeStepMsecs);
359− QTest::touchEvent(m_view, m_device)
360− .release(0, touchAPos)
361− .move(1, touchBPos);
362−
363− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
364−
365− passTime(timeStepMsecs);
366− QTest::touchEvent(m_view, m_device)
367− .release(1, touchBPos);
368−
369− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
370−}
371−
372−/*
373− Tests that gesture recognition works normally even if the DirectionalDragArea moves
374− during recognition.
375− This effectively means that we have to do gesture recognition with scene coordinates
376− instead of local item coordinates.
377− */
378−void tst_DirectionalDragArea::movingDDA()
379−{
380− QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
381− Q_ASSERT(rightwardsLauncher != 0);
382−
383− DirectionalDragArea *edgeDragArea =
384− rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
385− Q_ASSERT(edgeDragArea != 0);
386− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
387− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
388−
389− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
390− QPointF touchPoint = initialTouchPos;
391−
392− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
393− QPointF dragDirectionVector(1.0f, 0.0f);
394−
395− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
396− QPointF touchMovement = dragDirectionVector * movementStepDistance;
397− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
398− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
399−
400− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
401−
402− // Move it far ahead along the direction of the gesture
403− // rightwardsLauncher is a parent of our DirectionalDragArea. So moving it will move our DDA
404− rightwardsLauncher->setX(rightwardsLauncher->x() + edgeDragArea->d->distanceThreshold * 5.0f);
405−
406− for (int i = 0; i < totalMovementSteps; ++i) {
407− touchPoint += touchMovement;
408− passTime(movementTimeStepMs);
409− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
410− }
411−
412− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
413−
414− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
415−}
416−
417−/*
418− The presence of and old, rejected, touch point lying on the DirectionalDragArea
419− shouldn't impede the recognition of a gesture from a new touch point.
420− */
421−void tst_DirectionalDragArea::ignoreOldFinger()
422−{
423− DirectionalDragArea *edgeDragArea =
424− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
425− Q_ASSERT(edgeDragArea != 0);
426− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
427− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
428−
429− // Make touches evenly spaced along the edgeDragArea
430− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
431− QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
432−
433− QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
434−
435− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
436−
437− // leave it lying around for some time
438− passTime(edgeDragArea->d->maxTime * 10);
439−
440− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
441−
442− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
443− QPointF dragDirectionVector(1.0f, 0.0f);
444−
445− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
446− QPointF touchMovement = dragDirectionVector * movementStepDistance;
447− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
448− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
449−
450− QTest::touchEvent(m_view, m_device)
451− .move(0, touch0Pos)
452− .press(1, touch1Pos);
453−
454− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
455−
456− for (int i = 0; i < totalMovementSteps; ++i) {
457− touch1Pos += touchMovement.toPoint();
458− passTime(movementTimeStepMs);
459− QTest::touchEvent(m_view, m_device)
460− .move(0, touch0Pos)
461− .move(1, touch1Pos);
462− }
463−
464− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
465−
466− QTest::touchEvent(m_view, m_device)
467− .move(0, touch0Pos)
468− .release(1, touch1Pos);
469−
470− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
471−}
472−
473−/*
474− A Rightwards DDA that is rotated 90 degrees clockwise should recognize gestures
475− that are done downwards in scene coordinates. I.e. the gesture recognition direction
476− should be in local coordinates, not scene coordinates.
477− */
478−void tst_DirectionalDragArea::rotated()
479−{
480− QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
481− baseItem->setRotation(90.);
482−
483− QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
484− Q_ASSERT(rightwardsLauncher != 0);
485−
486− DirectionalDragArea *edgeDragArea =
487− rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
488− Q_ASSERT(edgeDragArea != 0);
489− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
490− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
491−
492− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
493− QPointF touchPoint = initialTouchPos;
494−
495− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
496− QPointF dragDirectionVector(0.0f, 1.0f);
497−
498− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
499− QPointF touchMovement = dragDirectionVector * movementStepDistance;
500− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
501− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
502−
503− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
504−
505− for (int i = 0; i < totalMovementSteps; ++i) {
506− touchPoint += touchMovement;
507− passTime(movementTimeStepMs);
508− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
509− }
510−
511− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
512−
513− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
514−}
515−
516−void tst_DirectionalDragArea::sceneDistance()
517−{
518− QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
519− QFETCH(qreal, rotation);
520− QFETCH(QPointF, dragDirectionVector);
521− baseItem->setRotation(rotation);
522−
523− QQuickItem *rightwardsLauncher = m_view->rootObject()->findChild<QQuickItem*>("rightwardsLauncher");
524− Q_ASSERT(rightwardsLauncher != 0);
525−
526− DirectionalDragArea *edgeDragArea =
527− rightwardsLauncher->findChild<DirectionalDragArea*>("hpDragArea");
528− Q_ASSERT(edgeDragArea != 0);
529− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
530− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
531−
532− // to disable the position smoothing so that we can more easily check sceneDistance values
533− edgeDragArea->setImmediateRecognition(true);
534−
535− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
536− QPointF touchPoint = initialTouchPos;
537−
538− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
539−
540− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
541− QPointF touchMovement = dragDirectionVector * movementStepDistance;
542− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
543− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
544−
545− qint64 timestamp = 0;
546−
547− sendTouchPress(timestamp, 0, touchPoint);
548−
549− for (int i = 0; i < totalMovementSteps; ++i) {
550− touchPoint += touchMovement;
551− timestamp += movementTimeStepMs;
552− sendTouchUpdate(timestamp, 0, touchPoint);
553− }
554−
555− qreal actualDragDistance = ((qreal)totalMovementSteps) * movementStepDistance;
556−
557− // DirectionalDragArea::sceneDistance() must match the actual drag distance as the
558− // drag was aligned with the gesture direction
559− // NB: qFuzzyCompare(), used internally by QCOMPARE(), is broken.
560− QVERIFY(qAbs(edgeDragArea->sceneDistance() - actualDragDistance) < 0.001);
561−
562− timestamp += movementTimeStepMs;
563− sendTouchRelease(timestamp, 0, touchPoint);
564−}
565−
566−void tst_DirectionalDragArea::sceneDistance_data()
567−{
568− QTest::addColumn<qreal>("rotation");
569− QTest::addColumn<QPointF>("dragDirectionVector");
570−
571− QTest::newRow("not rotated") << 0. << QPointF(1., 0.);
572− QTest::newRow("rotated by 90 degrees") << 90. << QPointF(0., 1.);
573−}
574−
575−/*
576− Regression test for https://bugs.launchpad.net/unity8/+bug/1276122
577−
578− The bug:
579− If setting "enabled: false" while the DirectionalDragArea's (DDA) dragging
580− property is true, the DDA stays in that state and doesn't recover any more.
581−*/
582−void tst_DirectionalDragArea::disabledWhileDragging()
583−{
584− DirectionalDragArea *edgeDragArea =
585− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
586− Q_ASSERT(edgeDragArea != 0);
587− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
588− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
589−
590− QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
591−
592− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2.0f;
593− QPointF dragDirectionVector(1., 0.); // horizontal positive
594−
595− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
596− QPointF touchMovement = dragDirectionVector * movementStepDistance;
597− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
598− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
599−
600− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
601−
602− for (int i = 0; i < totalMovementSteps; ++i) {
603− touchPoint += touchMovement;
604− passTime(movementTimeStepMs);
605− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
606− }
607−
608− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
609− QCOMPARE(edgeDragArea->dragging(), true);
610−
611− // disable the dragArea while it's being dragged.
612− edgeDragArea->setEnabled(false);
613−
614− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
615− QCOMPARE(edgeDragArea->dragging(), false);
616−
617− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
618−}
619−
620−void tst_DirectionalDragArea::oneFingerDownFollowedByLateSecondFingerDown()
621−{
622− DirectionalDragArea *edgeDragArea =
623− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
624− Q_ASSERT(edgeDragArea != 0);
625− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
626− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
627−
628− // Disable some constraints we're not interested in
629− edgeDragArea->d->setMaxTime(60 * 1000);
630−
631− // And ensure others have the values we want
632− edgeDragArea->d->compositionTime = 60;
633−
634− // Put an item right behind edgeDragArea to receive the touches ignored by it
635− DummyItem *dummyItem = new DummyItem;
636− dummyItem->setParentItem(edgeDragArea->parentItem());
637− dummyItem->setX(edgeDragArea->x());
638− dummyItem->setY(edgeDragArea->y());
639− dummyItem->setZ(edgeDragArea->z() - 1.0);
640− dummyItem->setWidth(edgeDragArea->width());
641− dummyItem->setHeight(edgeDragArea->height());
642−
643− // Make touches evenly spaced along the edgeDragArea
644− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.33f);
645− QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.66f);
646−
647− QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
648−
649− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
650−
651− // We are now going to be way beyond compositionTime
652− passTime(edgeDragArea->d->compositionTime*3);
653−
654− QTest::touchEvent(m_view, m_device)
655− .move(0, touch0Pos)
656− .press(1, touch1Pos);
657−
658− // A new touch has come, but as it can't be composed with touch 0, it should be
659− // ignored/rejected by the DirectionalDragArea
660− // Therefore the last event received by dummyItem must have both touch points (0 and 1)
661− {
662− TouchMemento &touchMemento = dummyItem->touchEvents.last();
663− QCOMPARE(touchMemento.touchPoints.count(), 2);
664− QVERIFY(touchMemento.containsTouchWithId(0));
665− QVERIFY(touchMemento.containsTouchWithId(1));
666− }
667−
668− passTime(30);
669−
670− QTest::touchEvent(m_view, m_device)
671− .move(0, touch0Pos)
672− .move(1, touch1Pos);
673−
674− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
675−
676− passTime(5);
677−
678− QTest::touchEvent(m_view, m_device)
679− .release(0, touch0Pos)
680− .move(1, touch1Pos);
681−
682− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
683−
684− passTime(5);
685−
686− QTest::touchEvent(m_view, m_device)
687− .release(1, touch1Pos);
688−
689− // Shouldn't be keepping info about touches that no longer exist or interest us
690− QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
691−
692− delete dummyItem;
693−}
694−
695−void tst_DirectionalDragArea::givesUpWhenLosesTouch()
696−{
697− DirectionalDragArea *edgeDragArea =
698− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
699− Q_ASSERT(edgeDragArea != 0);
700− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
701− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
702−
703− // Disable some constraints we're not interested in
704− edgeDragArea->d->setMaxTime(60 * 1000);
705−
706− // Put an item right in front of edgeDragArea
707− DummyItem *dummyItem = new DummyItem(edgeDragArea->parentItem());
708− dummyItem->setX(edgeDragArea->x());
709− dummyItem->setY(edgeDragArea->y());
710− dummyItem->setZ(edgeDragArea->z() + 1.0);
711− dummyItem->setWidth(edgeDragArea->width());
712− dummyItem->setHeight(edgeDragArea->height());
713−
714− QPoint touchPos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
715−
716− dummyItem->touchEventHandler = [&](QTouchEvent *event) {
717− m_touchRegistry->addCandidateOwnerForTouch(0, dummyItem);
718− event->ignore();
719− };
720−
721− QTest::touchEvent(m_view, m_device).press(0, touchPos);
722−
723− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
724−
725− m_touchRegistry->requestTouchOwnership(0, dummyItem);
726−
727− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
728−
729− dummyItem->grabTouchPoints({0});
730− dummyItem->touchEventHandler = [&](QTouchEvent *event) { event->accept(); };
731−
732− passTime(5);
733− QTest::touchEvent(m_view, m_device).release(0, touchPos);
734−
735− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
736−
737− QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
738−}
739−
740−void tst_DirectionalDragArea::threeFingerDrag()
741−{
742− DirectionalDragArea *edgeDragArea =
743− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
744− Q_ASSERT(edgeDragArea != 0);
745− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
746− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
747−
748− // Disable some constraints we're not interested in
749− edgeDragArea->d->setMaxTime(60 * 1000);
750−
751− // And ensure others have the values we want
752− edgeDragArea->d->compositionTime = 60;
753−
754− // Make touches evenly spaced along the edgeDragArea
755− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()*0.25f);
756− QPoint touch1Pos(edgeDragArea->width()/2.0f, m_view->height()*0.50f);
757− QPoint touch2Pos(edgeDragArea->width()/2.0f, m_view->height()*0.75f);
758−
759− QTest::touchEvent(m_view, m_device)
760− .press(0, touch0Pos);
761−
762− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
763−
764− passTime(5);
765− QTest::touchEvent(m_view, m_device)
766− .move(0, touch0Pos)
767− .press(1, touch1Pos);
768−
769− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
770−
771− passTime(5);
772− QTest::touchEvent(m_view, m_device)
773− .move(0, touch0Pos)
774− .move(1, touch1Pos)
775− .press(2, touch2Pos);
776−
777− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
778−
779− passTime(10);
780− QTest::touchEvent(m_view, m_device)
781− .move(0, touch0Pos)
782− .move(1, touch1Pos)
783− .move(2, touch2Pos);
784−
785− passTime(200);
786− QTest::touchEvent(m_view, m_device)
787− .move(0, touch0Pos)
788− .release(1, touch1Pos)
789− .move(2, touch2Pos);
790−
791− passTime(10);
792− QTest::touchEvent(m_view, m_device)
793− .move(0, touch0Pos)
794− .release(2, touch2Pos);
795−
796− passTime(5);
797− QTest::touchEvent(m_view, m_device)
798− .release(0, touch0Pos);
799−
800− // Shouldn't be keepping info about touches that no longer exist or interest us
801− QVERIFY(edgeDragArea->d->activeTouches.isEmpty());
802−}
803−
804−/*
805− If all the relevant gesture recognition constraints/parameters have been disabled,
806− it means that the gesture recognition itself has been disabled and DirectionalDragArea
807− will therefore work like a simple touch area, merely reporting touch movement.
808− */
809−void tst_DirectionalDragArea::immediateRecognitionWhenConstraintsDisabled()
810−{
811− DirectionalDragArea *edgeDragArea =
812− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
813− Q_ASSERT(edgeDragArea != 0);
814− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
815− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
816−
817− // Disable the minimum amount of constraints to ensure immediate recognition
818− edgeDragArea->d->setDistanceThreshold(0);
819− edgeDragArea->d->compositionTime = 0;
820−
821− // Put an item right behind edgeDragArea to receive the touches ignored by it
822− DummyItem *dummyItem = new DummyItem;
823− dummyItem->setParentItem(edgeDragArea->parentItem());
824− dummyItem->setX(edgeDragArea->x());
825− dummyItem->setY(edgeDragArea->y());
826− dummyItem->setZ(edgeDragArea->z() - 1.0);
827− dummyItem->setWidth(edgeDragArea->width());
828− dummyItem->setHeight(edgeDragArea->height());
829−
830− QPoint touch0Pos(edgeDragArea->width()/2.0f, m_view->height()/2.0f);
831−
832− QTest::touchEvent(m_view, m_device).press(0, touch0Pos);
833−
834− // check for immediate recognition
835− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
836−
837− // and therefore it should have immediately grabbed the touch point,
838− // not letting it leak to items behind him.
839− QCOMPARE(dummyItem->touchEvents.count(), 0);
840−}
841−
842−void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition()
843−{
844− DirectionalDragArea *edgeDragArea =
845− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
846− Q_ASSERT(edgeDragArea != 0);
847− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
848− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
849−
850− QPointF touchPoint = calculateInitialTouchPos(edgeDragArea);
851−
852− // Move less than the minimum needed for the drag gesture recognition
853− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 0.5f;
854− QPointF dragDirectionVector(1., 0.); // horizontal positive
855−
856− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
857− QPointF touchMovement = dragDirectionVector * movementStepDistance;
858− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
859− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 0.8f) / totalMovementSteps;
860−
861− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
862−
863− for (int i = 0; i < totalMovementSteps; ++i) {
864− touchPoint += touchMovement;
865− passTime(movementTimeStepMs);
866− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
867− }
868−
869− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
870−
871− // edgeDragArea should be an undecided candidate
872− {
873− auto touchInfo = m_touchRegistry->findTouchInfo(0);
874− QCOMPARE(touchInfo->candidates.size(), 1);
875− QCOMPARE(touchInfo->candidates.at(0).item.data(), edgeDragArea);
876− QCOMPARE(touchInfo->candidates.at(0).state, TouchRegistry::CandidateInfo::Undecided);
877− }
878−
879− // disable the dragArea while it's still recognizing a possible drag gesture.
880− QFETCH(bool, disable);
881− if (disable) {
882− edgeDragArea->setEnabled(false);
883− } else {
884− edgeDragArea->setVisible(false);
885− }
886−
887− // edgeDragArea should no longer be a candidate
888− {
889− auto touchInfo = m_touchRegistry->findTouchInfo(0);
890− QCOMPARE(touchInfo->candidates.size(), 0);
891− }
892−
893− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
894−
895− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
896−}
897−
898−void tst_DirectionalDragArea::withdrawTouchOwnershipCandidacyIfDisabledDuringRecognition_data()
899−{
900− QTest::addColumn<bool>("disable");
901−
902− QTest::newRow("disabled") << true;
903− QTest::newRow("invisible") << false;
904−}
905−
906−void tst_DirectionalDragArea::gettingTouchOwnershipMakesMouseAreaBehindGetCanceled()
907−{
908− DirectionalDragArea *edgeDragArea =
909− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
910− QVERIFY(edgeDragArea != nullptr);
911− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
912− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
913−
914− QQuickMouseArea *mouseArea =
915− m_view->rootObject()->findChild<QQuickMouseArea*>("mouseArea");
916− QVERIFY(mouseArea != nullptr);
917−
918− MouseAreaSpy mouseAreaSpy(mouseArea);
919−
920− QPointF initialTouchPos = calculateInitialTouchPos(edgeDragArea);
921− QPointF touchPoint = initialTouchPos;
922−
923− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
924− QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
925− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
926− QPointF touchMovement = dragDirectionVector * movementStepDistance;
927− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
928− int movementTimeStepMs = (edgeDragArea->d->compositionTime * 1.5f) / totalMovementSteps;
929−
930− QCOMPARE(mouseArea->pressed(), false);
931−
932− QTest::touchEvent(m_view, m_device).press(0, touchPoint.toPoint());
933−
934− // The TouchBegin passes through the DirectionalDragArea and reaches the MouseArea behind it,
935− // where it's converted to a MouseEvent by QQuickWindow and sent to the MouseArea which then
936− // accepts it. Making it get pressed.
937− QCOMPARE(mouseArea->pressed(), true);
938− QCOMPARE(mouseAreaSpy.canceledCount, 0);
939−
940− for (int i = 0; i < totalMovementSteps; ++i) {
941− touchPoint += touchMovement;
942− passTime(movementTimeStepMs);
943− QTest::touchEvent(m_view, m_device).move(0, touchPoint.toPoint());
944− }
945−
946− // As the DirectionalDragArea recognizes the gesture, it grabs the touch from the MouseArea,
947− // which should make the MouseArea get a cancelation event, which will then cause it to
948− // reset its state (going back to "unpressed"/"released").
949− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
950− QCOMPARE(mouseArea->pressed(), false);
951− QCOMPARE(mouseAreaSpy.canceledCount, 1);
952−
953− QTest::touchEvent(m_view, m_device).release(0, touchPoint.toPoint());
954−}
955−
956−void tst_DirectionalDragArea::interleavedTouches()
957−{
958− DirectionalDragArea *edgeDragArea =
959− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
960− QVERIFY(edgeDragArea != 0);
961− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
962− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
963−
964− QPointF touch0 = edgeDragArea->mapToScene(
965− QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.3));
966−
967− qreal desiredDragDistance = edgeDragArea->d->distanceThreshold * 2;
968− QPointF dragDirectionVector(1.0f, 0.0f); // rightwards
969− qreal movementStepDistance = edgeDragArea->d->distanceThreshold * 0.1f;
970− QPointF touchMovement = dragDirectionVector * movementStepDistance;
971− int totalMovementSteps = qCeil(desiredDragDistance / movementStepDistance);
972− int movementTimeStepMs = (edgeDragArea->d->maxTime * 0.4f) / totalMovementSteps;
973−
974− QTest::touchEvent(m_view, m_device).press(0, touch0.toPoint());
975− for (int i = 0; i < totalMovementSteps; ++i) {
976− touch0 += touchMovement;
977− passTime(movementTimeStepMs);
978− QTest::touchEvent(m_view, m_device).move(0, touch0.toPoint());
979− }
980− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
981−
982− QPointF touch1 = edgeDragArea->mapToScene(
983− QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.6));
984−
985− QTest::touchEvent(m_view, m_device)
986− .move(0, touch0.toPoint())
987− .press(1, touch1.toPoint());
988−
989− touch1 += touchMovement;
990− passTime(movementTimeStepMs);
991− QTest::touchEvent(m_view, m_device)
992− .move(0, touch0.toPoint())
993− .move(1, touch1.toPoint());
994−
995− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Recognized);
996−
997− QTest::touchEvent(m_view, m_device)
998− .release(0, touch0.toPoint())
999− .move(1, touch1.toPoint());
1000−
1001− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1002−
1003− touch1 += touchMovement;
1004− passTime(movementTimeStepMs);
1005− QTest::touchEvent(m_view, m_device)
1006− .move(1, touch1.toPoint());
1007−
1008− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1009−
1010− QPointF touch2 = edgeDragArea->mapToScene(
1011− QPointF(edgeDragArea->width()*0.5, edgeDragArea->height()*0.9));
1012−
1013− passTime(edgeDragArea->d->compositionTime + movementTimeStepMs);
1014− QTest::touchEvent(m_view, m_device)
1015− .move(1, touch1.toPoint())
1016− .press(2, touch2.toPoint());
1017−
1018− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::Undecided);
1019− QCOMPARE(edgeDragArea->d->touchId, 2);
1020−
1021− touch2 += touchMovement;
1022− passTime(movementTimeStepMs);
1023− QTest::touchEvent(m_view, m_device)
1024− .move(1, touch1.toPoint())
1025− .move(2, touch2.toPoint());
1026−
1027− touch1 += touchMovement;
1028− passTime(movementTimeStepMs);
1029− QTest::touchEvent(m_view, m_device)
1030− .move(1, touch1.toPoint())
1031− .move(2, touch2.toPoint());
1032−
1033− passTime(movementTimeStepMs);
1034− QTest::touchEvent(m_view, m_device)
1035− .release(1, touch1.toPoint())
1036− .move(2, touch2.toPoint());
1037−
1038− passTime(movementTimeStepMs);
1039− QTest::touchEvent(m_view, m_device)
1040− .release(2, touch2.toPoint());
1041−
1042− QCOMPARE((int)edgeDragArea->d->status, (int)DirectionalDragAreaPrivate::WaitingForTouch);
1043−}
1044−
1045−/*
1046− A valid right-edge drag performed on mako
1047− */
1048−void tst_DirectionalDragArea::makoRightEdgeDrag()
1049−{
1050− m_view->resize(768, 1280);
1051− QTest::qWait(300);
1052−
1053− DirectionalDragArea *edgeDragArea =
1054− m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1055− QVERIFY(edgeDragArea != nullptr);
1056− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1057− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1058−
1059− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1060−
1061− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1062−
1063− sendTouchPress(319744, 0, QPointF(767.001, 719.719));
1064− sendTouchUpdate(319765, 0, QPointF(765.744,729.973));
1065− sendTouchUpdate(319784, 0, QPointF(740.879,752.182));
1066− sendTouchUpdate(319803, 0, QPointF(689.698,795.795));
1067− sendTouchUpdate(319826, 0, QPointF(616.978,856.212));
1068− sendTouchUpdate(319845, 0, QPointF(558.769,906.157));
1069− sendTouchUpdate(319859, 0, QPointF(513.219,945.266));
1070− sendTouchUpdate(319878, 0, QPointF(481.31,975.496));
1071− sendTouchUpdate(319902, 0, QPointF(460.016,997.439));
1072− sendTouchUpdate(319920, 0, QPointF(449.761,1008.6));
1073− sendTouchUpdate(319929, 0, QPointF(445.891,1012.42));
1074− sendTouchUpdate(319947, 0, QPointF(444.884,1013.93));
1075− sendTouchUpdate(319965, 0, QPointF(444.461,1014.35));
1076− sendTouchUpdate(320057, 0, QPointF(444.71,1013.56));
1077− sendTouchUpdate(320138, 0, QPointF(445.434,1013.6));
1078− sendTouchUpdate(320154, 0, QPointF(446.338,1012.98));
1079− sendTouchUpdate(320171, 0, QPointF(447.232,1012.08));
1080− sendTouchRelease(320171, 0, QPointF(447.232,1012.08));
1081−
1082− QCOMPARE(statusSpy->recognized(), true);
1083−
1084− delete statusSpy;
1085−}
1086−
1087−/*
1088− A vertical, downwards swipe performed on mako near its right edge.
1089−
1090− The DirectionalDragArea on the right edge must not recognize this
1091− gesture.
1092− */
1093−void tst_DirectionalDragArea::makoRightEdgeDrag_verticalDownwards()
1094−{
1095− m_view->resize(768, 1280);
1096− QTest::qWait(300);
1097−
1098− DirectionalDragArea *edgeDragArea =
1099− m_view->rootObject()->findChild<DirectionalDragArea*>("hnDragArea");
1100− QVERIFY(edgeDragArea != nullptr);
1101− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1102− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1103−
1104− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1105−
1106− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1107−
1108− sendTouchPress(12012445, 26, QPointF(767.001,461.82));
1109− sendTouchUpdate(12012472, 26, QPointF(767.001,462.569));
1110− sendTouchUpdate(12012528, 26, QPointF(767.001,463.334));
1111− sendTouchUpdate(12012546, 26, QPointF(767.001,466.856));
1112− sendTouchUpdate(12012571, 26, QPointF(767.001,473.291));
1113− sendTouchUpdate(12012587, 26, QPointF(767.001,487.31));
1114− sendTouchUpdate(12012604, 26, QPointF(765.364,507.521));
1115− sendTouchUpdate(12012618, 26, QPointF(765.364,507.521));
1116− sendTouchUpdate(12012627, 26, QPointF(762.642,534.317));
1117− sendTouchUpdate(12012655, 26, QPointF(760.846,573.406));
1118− sendTouchUpdate(12012667, 26, QPointF(759.838,625.295));
1119− sendTouchUpdate(12012675, 26, QPointF(758.875,703.207));
1120− sendTouchUpdate(12012696, 26, QPointF(761.52,777.015));
1121− sendTouchUpdate(12012713, 26, QPointF(765.659,835.591));
1122− sendTouchUpdate(12012731, 26, QPointF(766.778,883.206));
1123− sendTouchUpdate(12012748, 26, QPointF(767.001,922.937));
1124− sendTouchUpdate(12012779, 26, QPointF(767.001,967.558));
1125− sendTouchUpdate(12012798, 26, QPointF(767.001,1006.12));
1126− sendTouchUpdate(12012809, 26, QPointF(767.001,1033.1));
1127− sendTouchRelease(12012810, 26, QPointF(767.001,1033.1));
1128−
1129− QCOMPARE(statusSpy->recognized(), false);
1130−
1131− delete statusSpy;
1132−}
1133−
1134−/*
1135− A valid left-edge drag performed on mako. This one starts a bit slow than speeds up
1136− */
1137−void tst_DirectionalDragArea::makoLeftEdgeDrag_slowStart()
1138−{
1139− m_view->resize(768, 1280);
1140− QTest::qWait(300);
1141−
1142− DirectionalDragArea *edgeDragArea =
1143− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1144− QVERIFY(edgeDragArea != nullptr);
1145− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1146− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1147−
1148− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1149−
1150− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1151−
1152− sendTouchPress(4002267, 77, QPointF(0,885.154));
1153− sendTouchUpdate(4002275, 77, QPointF(0,886.214));
1154− sendTouchUpdate(4002311, 77, QPointF(1.09568,887.75));
1155− sendTouchUpdate(4002329, 77, QPointF(3.53647,890.191));
1156− sendTouchUpdate(4002347, 77, QPointF(7.87434,892.879));
1157− sendTouchUpdate(4002366, 77, QPointF(12.3036,895.075));
1158− sendTouchUpdate(4002384, 77, QPointF(15.8885,896.849));
1159− sendTouchUpdate(4002406, 77, QPointF(18.4504,897.88));
1160− sendTouchUpdate(4002420, 77, QPointF(20.2429,898.149));
1161− sendTouchUpdate(4002439, 77, QPointF(20.9945,898.149));
1162− sendTouchUpdate(4002457, 77, QPointF(21.8819,898.149));
1163− sendTouchUpdate(4002480, 77, QPointF(22.7454,897.389));
1164− sendTouchUpdate(4002493, 77, QPointF(23.5456,896.589));
1165− sendTouchUpdate(4002511, 77, QPointF(24.5435,895.031));
1166− sendTouchUpdate(4002529, 77, QPointF(25.4271,892.32));
1167− sendTouchUpdate(4002548, 77, QPointF(26.3145,889.658));
1168− sendTouchUpdate(4002566, 77, QPointF(27.2004,886.999));
1169− sendTouchUpdate(4002584, 77, QPointF(28.035,885.048));
1170− sendTouchUpdate(4002603, 77, QPointF(29.9684,883.167));
1171− sendTouchUpdate(4002620, 77, QPointF(33.3591,881.403));
1172− sendTouchUpdate(4002639, 77, QPointF(44.1017,879.642));
1173− sendTouchUpdate(4002657, 77, QPointF(64.828,878.502));
1174− sendTouchUpdate(4002675, 77, QPointF(87.9486,878.157));
1175− sendTouchUpdate(4002693, 77, QPointF(112.96,877.742));
1176− sendTouchUpdate(4002711, 77, QPointF(138.903,877.157));
1177− sendTouchUpdate(4002729, 77, QPointF(163.204,877.157));
1178− sendTouchUpdate(4002747, 77, QPointF(182.127,877.157));
1179− sendTouchUpdate(4002765, 77, QPointF(194.478,877.657));
1180− sendTouchUpdate(4002785, 77, QPointF(201.474,878.508));
1181− sendTouchUpdate(4002803, 77, QPointF(204.855,879.401));
1182− sendTouchUpdate(4002822, 77, QPointF(206.616,880.281));
1183− sendTouchUpdate(4002839, 77, QPointF(207.115,880.906));
1184− sendTouchUpdate(4002894, 77, QPointF(206.865,881.184));
1185− sendTouchUpdate(4002912, 77, QPointF(206.865,882.143));
1186− sendTouchUpdate(4002930, 77, QPointF(206.865,883.106));
1187− sendTouchUpdate(4002949, 77, QPointF(206.526,883.994));
1188− sendTouchUpdate(4002967, 77, QPointF(205.866,884.88));
1189− sendTouchUpdate(4002985, 77, QPointF(205.866,885.766));
1190− sendTouchUpdate(4003005, 77, QPointF(205.866,886.654));
1191− sendTouchUpdate(4003021, 77, QPointF(205.366,887.537));
1192− sendTouchUpdate(4003039, 77, QPointF(204.592,888.428));
1193− sendTouchUpdate(4003050, 77, QPointF(204.367,888.653));
1194− sendTouchRelease(4003050, 77, QPointF(204.367,888.653));
1195−
1196− QCOMPARE(statusSpy->recognized(), true);
1197−
1198− delete statusSpy;
1199−}
1200−
1201−void tst_DirectionalDragArea::makoLeftEdgeDrag_movesSlightlyBackwardsOnStart()
1202−{
1203− m_view->resize(768, 1280);
1204− QTest::qWait(300);
1205−
1206− DirectionalDragArea *edgeDragArea =
1207− m_view->rootObject()->findChild<DirectionalDragArea*>("hpDragArea");
1208− QVERIFY(edgeDragArea != nullptr);
1209− edgeDragArea->d->setRecognitionTimer(m_fakeTimerFactory->createTimer(edgeDragArea));
1210− edgeDragArea->d->setTimeSource(m_fakeTimerFactory->timeSource());
1211−
1212− edgeDragArea->d->setPixelsPerMm(320.0 /*mako ppi*/ * 0.03937 /* inches per mm*/);
1213−
1214− StatusSpy *statusSpy = new StatusSpy(edgeDragArea);
1215−
1216− sendTouchPress(41097, 24, QPointF(13.9909,827.177));
1217− sendTouchUpdate(41120, 24, QPointF(19.2375,825.677));
1218− sendTouchUpdate(41138, 24, QPointF(18.4057,826.177));
1219− sendTouchUpdate(41161, 24, QPointF(20.1067,825.867));
1220− sendTouchUpdate(41177, 24, QPointF(21.8869,824.977));
1221− sendTouchUpdate(41193, 24, QPointF(24.7603,823.494));
1222− sendTouchUpdate(41211, 24, QPointF(28.3889,821.725));
1223− sendTouchUpdate(41229, 24, QPointF(32.2909,819.955));
1224− sendTouchUpdate(41247, 24, QPointF(38.2251,817.431));
1225− sendTouchUpdate(41266, 24, QPointF(52.4182,814.223));
1226− sendTouchUpdate(41284, 24, QPointF(85.8465,809.483));
1227− sendTouchUpdate(41302, 24, QPointF(126.091,802.741));
1228− sendTouchUpdate(41320, 24, QPointF(153.171,797.977));
1229− sendTouchUpdate(41338, 24, QPointF(170.565,795.077));
1230− sendTouchUpdate(41356, 24, QPointF(178.685,794.101));
1231− sendTouchUpdate(41375, 24, QPointF(183.706,793.225));
1232− sendTouchUpdate(41393, 24, QPointF(186.112,793.19));
1233− sendTouchUpdate(41411, 24, QPointF(187.634,793.19));
1234− sendTouchUpdate(41429, 24, QPointF(188.505,793.19));
1235− sendTouchUpdate(41532, 24, QPointF(187.816,793.19));
1236− sendTouchUpdate(41538, 24, QPointF(186.902,793.19));
1237− sendTouchUpdate(41557, 24, QPointF(186.01,793.19));
1238− sendTouchUpdate(41575, 24, QPointF(185.125,793.444));
1239− sendTouchUpdate(41593, 24, QPointF(184.229,793.69));
1240− sendTouchUpdate(41605, 24, QPointF(183.88,793.69));
1241− sendTouchRelease(41607, 24, QPointF(183.88,793.69));
1242−
1243− QCOMPARE(statusSpy->recognized(), true);
1244−
1245− delete statusSpy;
1246−}
1247−
1248−QTEST_MAIN(tst_DirectionalDragArea)
1249−
1250−#include "tst_DirectionalDragArea.moc"
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.qmldeleted−76
@@ -1,76 +0,0 @@
1−/*
2− * Copyright (C) 2013,2015 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.4
18−import Ubuntu.Components 1.3
19−import Unity.Test 0.1
20−
21−Rectangle {
22− width: units.gu(60)
23− height: units.gu(60)
24− color: "white"
25−
26− Binding {
27− target: MouseTouchAdaptor
28− property: "enabled"
29− value: true
30− }
31−
32− MouseArea {
33− id: mouseArea
34− objectName: "mouseArea"
35− anchors.fill: parent
36− onClicked: {
37− hpLauncher.reset()
38− hnLauncher.reset()
39− vpLauncher.reset()
40− vnLauncher.reset()
41− }
42− }
43−
44− Item {
45− id: baseItem
46− objectName: "baseItem"
47− width: parent.width
48− height: parent.height
49−
50− // NB: Do not anchor it as we will move it programmatically from the test
51− RightwardsLauncher {
52− id: hpLauncher;
53− width: parent.width
54− height: parent.height
55− }
56−
57− LeftwardsLauncher { id: hnLauncher; anchors.fill: parent }
58− DownwardsLauncher { id: vpLauncher; anchors.fill: parent }
59− UpwardsLauncher { id: vnLauncher; anchors.fill: parent }
60− }
61−
62− Button {
63− anchors.bottom: parent.bottom
64− anchors.left: parent.left
65− anchors.margins: units.gu(1)
66−
67− text: "rotation: " + baseItem.rotation
68− onClicked: {
69− if (baseItem.rotation === 0.0) {
70− baseItem.rotation = 90.0
71− } else {
72− baseItem.rotation = 0.0
73− }
74− }
75− }
76−}
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.cpp+25−18
@@ -17,12 +17,9 @@
1717#include <QtTest>
1818#include <QQuickView>
1919
20−// Ubuntu.Gestures plugin
21−#include <DirectionalDragArea.h>
22−#include <FloatingFlickable.h>
23−
2420#include "GestureTest.h"
2521#include "TestItem.h"
22+#include "Direction.h"
2623
2724using namespace UbuntuGestures;
2825
@@ -44,8 +41,8 @@ tst_FloatingFlickable::tst_FloatingFlickable()
4441
4542void tst_FloatingFlickable::tapGoesThrough()
4643{
47− FloatingFlickable *floatingFlickable =
48− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
44+ QQuickItem *floatingFlickable =
45+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
4946 QVERIFY(floatingFlickable != nullptr);
5047
5148 TestItem *testItem = new TestItem;
@@ -62,16 +59,26 @@ void tst_FloatingFlickable::tapGoesThrough()
6259 QCOMPARE(testItem->touchEventsReceived.count(), 1);
6360}
6461
62+static void removeTimeConstraints(QQuickItem *floatingFlickable)
63+{
64+ auto children = floatingFlickable->findChildren<QObject*>();
65+ Q_FOREACH(QObject *child, children) {
66+ if (child->metaObject()->className() == QByteArray("UCSwipeAreaPrivate")) {
67+ QMetaObject::invokeMethod(child, "setMaxTime", Q_ARG(int, 60 * 60 * 1000));
68+ QMetaObject::invokeMethod(child, "setCompositionTime", Q_ARG(int, 0));
69+ }
70+ }
71+}
72+
6573void tst_FloatingFlickable::flickChangesContentX()
6674{
6775 QSKIP("This fails due to bug #1564571");
68− FloatingFlickable *floatingFlickable =
69− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
76+ QQuickItem *floatingFlickable =
77+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
7078 QVERIFY(floatingFlickable != nullptr);
79+ removeTimeConstraints(floatingFlickable);
7180
72− floatingFlickable->m_dragArea->removeTimeConstraints();
73−
74− qreal startContentX = floatingFlickable->contentX();
81+ qreal startContentX = floatingFlickable->property("contentX").toReal();
7582
7683 QPoint startPos(floatingFlickable->width() - 5, 10);
7784 int stepCount = 20;
@@ -87,20 +94,20 @@ void tst_FloatingFlickable::flickChangesContentX()
8794 QTest::qWait(10);
8895 QTest::touchEvent(m_view, m_device).release(0, QPoint(5, 10));
8996
90− QVERIFY(floatingFlickable->contentX() > (startContentX + floatingFlickable->width()/2));
97+ QVERIFY(floatingFlickable->property("contentX").toReal() > (startContentX + floatingFlickable->width()/2));
9198}
9299
93100void tst_FloatingFlickable::flickChangesContentY()
94101{
95102 QSKIP("This fails due to bug #1564571");
96− FloatingFlickable *floatingFlickable =
97− m_view->rootObject()->findChild<FloatingFlickable*>("floatingFlickable");
103+ QQuickItem *floatingFlickable =
104+ m_view->rootObject()->findChild<QQuickItem*>("floatingFlickable");
98105 QVERIFY(floatingFlickable != nullptr);
99106
100− floatingFlickable->setDirection(Direction::Vertical);
101− floatingFlickable->m_dragArea->removeTimeConstraints();
107+ floatingFlickable->setProperty("direction", Direction::Vertical);
108+ removeTimeConstraints(floatingFlickable);
102109
103− qreal startContentY = floatingFlickable->contentY();
110+ qreal startContentY = floatingFlickable->property("contentY").toReal();
104111
105112 QPoint startPos(10, floatingFlickable->height() - 5);
106113 int stepCount = 20;
@@ -116,7 +123,7 @@ void tst_FloatingFlickable::flickChangesContentY()
116123 QTest::qWait(10);
117124 QTest::touchEvent(m_view, m_device).release(0, QPoint(10, 5));
118125
119− QVERIFY(floatingFlickable->contentY() > (startContentY + floatingFlickable->height()/2));
126+ QVERIFY(floatingFlickable->property("contentY").toReal() > (startContentY + floatingFlickable->height()/2));
120127}
121128
122129QTEST_MAIN(tst_FloatingFlickable)
tests/plugins/Ubuntu/Gestures/tst_FloatingFlickable.qml+1
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import Ubuntu.Components 1.3
1919import Ubuntu.Gestures 0.1
2020import Unity.Test 0.1
21+import "../../../../../qml/Components"
2122
2223Rectangle {
2324 id: root
tests/plugins/Ubuntu/Gestures/tst_TouchGate.cpp+1−1
@@ -25,7 +25,7 @@
2525#include <functional>
2626
2727#include <TouchGate.h>
28−#include <TouchRegistry.h>
28+#include <TouchRegistry>
2929
3030#include "TestItem.h"
3131
tests/plugins/Unity/Indicators/MenuContentActivatorTest.cpp+1
@@ -28,6 +28,7 @@ class FakeTimer : public UnityIndicators::AbstractTimer
2828public:
2929 FakeTimer(QObject *parent = 0)
3030 : UnityIndicators::AbstractTimer(parent)
31+ , m_duration(0)
3132 {}
3233
3334 int interval() const override { return m_duration; }
tests/plugins/Unity/Session/sessionbackendtest.cpp−15
@@ -148,21 +148,6 @@ private Q_SLOTS:
148148 }
149149 }
150150
151− void testLogin1Capabilities() {
152− QSKIP("This test talks to real logind backend, it will fail depending on how the machine is set up");
153− DBusUnitySessionService dbusUnitySessionService;
154− QDBusInterface login1face("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", QDBusConnection::systemBus());
155− QCoreApplication::processEvents(); // to let the services register on DBus
156−
157− if (login1face.isValid()) {
158− QCOMPARE(dbusUnitySessionService.CanHibernate(), (login1face.call("CanHibernate").arguments().first().toString() != "no"));
159− QCOMPARE(dbusUnitySessionService.CanSuspend(), (login1face.call("CanSuspend").arguments().first().toString() != "no"));
160− QCOMPARE(dbusUnitySessionService.CanReboot(), (login1face.call("CanReboot").arguments().first().toString() != "no"));
161− QCOMPARE(dbusUnitySessionService.CanShutdown(), (login1face.call("CanPowerOff").arguments().first().toString() != "no"));
162− QCOMPARE(dbusUnitySessionService.CanHybridSleep(), (login1face.call("CanHybridSleep").arguments().first().toString() != "no"));
163− }
164− }
165−
166151private:
167152 QDBusInterface *dbusUnitySession;
168153};
tests/plugins/Utils/WindowInputMonitorTest.cpp+52−11
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2015-2016 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
@@ -71,6 +71,8 @@ public:
7171
7272using namespace UnityUtil;
7373
74+Q_DECLARE_METATYPE(Qt::Key) // because of QTest::addColumn<Qt::Key>
75+
7476class WindowInputMonitorTest : public QObject {
7577 Q_OBJECT
7678private Q_SLOTS:
@@ -81,6 +83,7 @@ private Q_SLOTS:
8183 void touchTapTouch();
8284
8385 void tapWhileTouching();
86+ void multipleHomeKeys();
8487
8588private:
8689 void passTime(qint64 timeSpanMs);
@@ -112,13 +115,15 @@ void WindowInputMonitorTest::touchTapTouch_data()
112115 QTest::addColumn<int>("tapDuration");
113116 QTest::addColumn<int>("silenceAfterTap");
114117 QTest::addColumn<int>("expectedActivatedCount");
115−
116− QTest::newRow("tap followed by touch") << 2000 << 50 << 10 << 0;
117− QTest::newRow("touch, tap and touch") << 10 << 50 << 10 << 0;
118− QTest::newRow("touch followed by tap") << 10 << 50 << 2000 << 0;
119− QTest::newRow("touch followed by long tap") << 10 << 500 << 2000 << 0;
120− QTest::newRow("isolated tap") << 1000 << 50 << 1000 << 1;
121− QTest::newRow("isolated long press") << 1000 << 200 << 1000 << 0;
118+ QTest::addColumn<Qt::Key>("key");
119+
120+ QTest::newRow("tap followed by touch") << 2000 << 50 << 10 << 0 << Qt::Key_Super_L;
121+ QTest::newRow("touch, tap and touch") << 10 << 50 << 10 << 0 << Qt::Key_Super_L;
122+ QTest::newRow("touch followed by tap") << 10 << 50 << 2000 << 0 << Qt::Key_Super_L;
123+ QTest::newRow("touch followed by long tap") << 10 << 500 << 2000 << 0 << Qt::Key_Super_L;
124+ QTest::newRow("isolated tap, Super_L") << 1000 << 50 << 1000 << 1 << Qt::Key_Super_L;
125+ QTest::newRow("isolated tap, HomePage") << 1000 << 50 << 1000 << 1 << Qt::Key_HomePage;
126+ QTest::newRow("isolated long press") << 1000 << 200 << 1000 << 0 << Qt::Key_Super_L;
122127}
123128
124129void WindowInputMonitorTest::touchTapTouch()
@@ -127,6 +132,7 @@ void WindowInputMonitorTest::touchTapTouch()
127132 QFETCH(int, tapDuration);
128133 QFETCH(int, silenceAfterTap);
129134 QFETCH(int, expectedActivatedCount);
135+ QFETCH(Qt::Key, key);
130136 WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
131137 QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
132138 QVERIFY(activatedSpy.isValid());
@@ -149,7 +155,7 @@ void WindowInputMonitorTest::touchTapTouch()
149155 passTime(silenceBeforeTap);
150156
151157 {
152− QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
158+ QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier);
153159 homeKeyWatcher.update(&keyEvent);
154160 }
155161 int tapTime = 0;
@@ -157,10 +163,10 @@ void WindowInputMonitorTest::touchTapTouch()
157163 passTime(10);
158164 tapTime += 10;
159165 if (tapTime + 10 >= tapDuration) {
160− QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
166+ QKeyEvent keyEvent(QEvent::KeyRelease, key, Qt::NoModifier);
161167 homeKeyWatcher.update(&keyEvent);
162168 } else {
163− QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier, QString(), true /*autorepeat*/);
169+ QKeyEvent keyEvent(QEvent::KeyPress, key, Qt::NoModifier, QString(), true /*autorepeat*/);
164170 homeKeyWatcher.update(&keyEvent);
165171 }
166172 }
@@ -217,6 +223,41 @@ void WindowInputMonitorTest::tapWhileTouching()
217223 QCOMPARE(activatedSpy.count(), 0);
218224}
219225
226+/*
227+ Press multiple of the mapped home keys roughly at the same time.
228+ The first pressed will be recognized and the other ignored
229+ */
230+void WindowInputMonitorTest::multipleHomeKeys()
231+{
232+ WindowInputMonitor homeKeyWatcher(m_fakeTimerFactory->create(), new FakeElapsedTimer);
233+ QSignalSpy activatedSpy(&homeKeyWatcher, &WindowInputMonitor::homeKeyActivated);
234+ QVERIFY(activatedSpy.isValid());
235+
236+ passTime(1000);
237+ {
238+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_HomePage, Qt::NoModifier);
239+ homeKeyWatcher.update(&keyEvent);
240+ }
241+ passTime(50);
242+ {
243+ QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Super_L, Qt::NoModifier);
244+ homeKeyWatcher.update(&keyEvent);
245+ }
246+ passTime(50);
247+ {
248+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_HomePage, Qt::NoModifier);
249+ homeKeyWatcher.update(&keyEvent);
250+ }
251+ passTime(10);
252+ {
253+ QKeyEvent keyEvent(QEvent::KeyRelease, Qt::Key_Super_L, Qt::NoModifier);
254+ homeKeyWatcher.update(&keyEvent);
255+ }
256+ passTime(1000);
257+
258+ QCOMPARE(activatedSpy.count(), 1);
259+}
260+
220261/////////////////////////////////// FakeTimer //////////////////////////////////
221262
222263FakeTimer::FakeTimer(QObject *parent)
tests/qmltests/Components/CMakeLists.txt+6−3
@@ -1,18 +1,21 @@
11add_definitions(-DTEST_DIR="qmltests/Components")
22
3+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
4+
35########## tst_DragHandle
46
57include_directories(
68 ${CMAKE_SOURCE_DIR}/plugins/Ubuntu/Gestures
7− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
9+ ${UBUNTUGESTURES_INCLUDE_DIRS}
810 ${CMAKE_CURRENT_BINARY_DIR}
911 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
1012 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
13+ ${UBUNTUGESTURES_INCLUDEDIR}/UbuntuGestures/${UBUNTUGESTURES_VERSION}
1114 )
1215
1316add_executable(DragHandleTestExec tst_DragHandle.cpp)
1417qt5_use_modules(DragHandleTestExec Test Core Qml Gui Quick)
15−target_link_libraries(DragHandleTestExec UbuntuGesturesQml UbuntuGestures)
18+target_link_libraries(DragHandleTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
1619install(TARGETS DragHandleTestExec
1720 DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/qmltests/Components"
1821 )
@@ -28,7 +31,7 @@ add_unity8_qmltest_data(. tst_DragHandle)
2831########## tst_EdgeDragEvaluator
2932add_executable(EdgeDragEvaluatorTestExec tst_EdgeDragEvaluator.cpp)
3033qt5_use_modules(EdgeDragEvaluatorTestExec Test Core Qml Gui Quick)
31−target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml UbuntuGestures)
34+target_link_libraries(EdgeDragEvaluatorTestExec UbuntuGesturesQml ${UBUNTUGESTURES_LIBRARIES})
3235install(TARGETS EdgeDragEvaluatorTestExec
3336 DESTINATION "${SHELL_PRIVATE_LIBDIR}/tests/qmltests/Components"
3437 )
tests/qmltests/Components/tst_DragHandle.cpp+28−24
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013-2014 Canonical, Ltd.
2+ * Copyright (C) 2013-2014,2016 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
@@ -21,11 +21,11 @@
2121#include <QtQuick/QQuickView>
2222#include <QtQml/QQmlEngine>
2323#include <private/qquickwindow_p.h>
24+#include <UbuntuGestures/private/ucswipearea_p_p.h>
2425
2526#include <AxisVelocityCalculator.h>
26−#include <DirectionalDragArea.h>
27−#include <DirectionalDragArea_p.h>
28−#include <Timer.h>
27+#include <Timer>
28+#include "Direction.h"
2929
3030#include <paths.h>
3131
@@ -53,11 +53,11 @@ private Q_SLOTS:
5353 void hintingAnimation_dontRestartAfterFinishedAndStillPressed();
5454
5555private:
56− void flickAndHold(DirectionalDragArea *dragHandle, qreal distance);
56+ void flickAndHold(QQuickItem *dragHandle, qreal distance);
5757 void drag(QPointF &touchPoint, const QPointF& direction, qreal distance,
5858 int numSteps, qint64 timeMs = 500);
59− DirectionalDragArea *fetchAndSetupDragHandle(const char *objectName);
60− qreal fetchDragThreshold(DirectionalDragArea *dragHandle);
59+ QQuickItem *fetchAndSetupDragHandle(const char *objectName);
60+ qreal fetchDragThreshold(QQuickItem *dragHandle);
6161 void tryCompare(std::function<qreal ()> actualFunc, qreal expectedValue);
6262
6363 QQuickView *createView();
@@ -132,11 +132,11 @@ void tst_DragHandle::tryCompare(std::function<qreal ()> actualFunc,
132132}
133133
134134namespace {
135−QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
135+QPointF calculateDirectionVector(QQuickItem *edgeDragArea)
136136{
137137 QPointF localOrigin(0., 0.);
138138 QPointF localDirection;
139− switch (edgeDragArea->direction()) {
139+ switch (edgeDragArea->property("direction").toInt()) {
140140 case Direction::Upwards:
141141 localDirection.rx() = 0.;
142142 localDirection.ry() = -1.;
@@ -160,7 +160,7 @@ QPointF calculateDirectionVector(DirectionalDragArea *edgeDragArea)
160160}
161161}
162162
163−void tst_DragHandle::flickAndHold(DirectionalDragArea *dragHandle,
163+void tst_DragHandle::flickAndHold(QQuickItem *dragHandle,
164164 qreal distance)
165165{
166166 QPointF initialTouchPos = dragHandle->mapToScene(
@@ -198,13 +198,17 @@ void tst_DragHandle::drag(QPointF &touchPoint, const QPointF& direction, qreal d
198198 }
199199}
200200
201−DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
201+QQuickItem *tst_DragHandle::fetchAndSetupDragHandle(const char *objectName)
202202{
203− DirectionalDragArea *dragHandle =
204− m_view->rootObject()->findChild<DirectionalDragArea*>(objectName);
203+ QQuickItem *dragHandle =
204+ m_view->rootObject()->findChild<QQuickItem*>(objectName);
205205 Q_ASSERT(dragHandle != 0);
206− dragHandle->d->setRecognitionTimer(m_fakeTimer);
207− dragHandle->d->setTimeSource(m_fakeTimeSource);
206+ UCSwipeArea *swipeArea = dynamic_cast<UCSwipeArea*>(dragHandle);
207+ if (swipeArea) {
208+ UCSwipeAreaPrivate *swipeAreaPrivate = dynamic_cast<UCSwipeAreaPrivate *>(QQuickItemPrivate::get(swipeArea));
209+ swipeAreaPrivate->setRecognitionTimer(m_fakeTimer);
210+ swipeAreaPrivate->setTimeSource(m_fakeTimeSource);
211+ }
208212
209213 AxisVelocityCalculator *edgeDragEvaluator =
210214 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
@@ -214,7 +218,7 @@ DirectionalDragArea *tst_DragHandle::fetchAndSetupDragHandle(const char *objectN
214218 return dragHandle;
215219}
216220
217−qreal tst_DragHandle::fetchDragThreshold(DirectionalDragArea *dragHandle)
221+qreal tst_DragHandle::fetchDragThreshold(QQuickItem *dragHandle)
218222{
219223 AxisVelocityCalculator *edgeDragEvaluator =
220224 dragHandle->findChild<AxisVelocityCalculator*>("edgeDragEvaluator");
@@ -235,7 +239,7 @@ void tst_DragHandle::dragThreshold_horizontal()
235239 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
236240 baseItem->setRotation(rotation);
237241
238− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
242+ QQuickItem *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
239243 QQuickItem *parentItem = dragHandle->parentItem();
240244
241245 qreal dragThreshold = fetchDragThreshold(dragHandle);
@@ -288,7 +292,7 @@ void tst_DragHandle::dragThreshold_vertical()
288292 QQuickItem *baseItem = m_view->rootObject()->findChild<QQuickItem*>("baseItem");
289293 baseItem->setRotation(rotation);
290294
291− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
295+ QQuickItem *dragHandle = fetchAndSetupDragHandle("topEdgeShowDragHandle");
292296
293297 qreal dragThreshold = fetchDragThreshold(dragHandle);
294298
@@ -307,7 +311,7 @@ void tst_DragHandle::dragThreshold_vertical()
307311 tryCompare([&](){ return parentItem->y(); }, 0);
308312 QCOMPARE(parentItem->property("shown").toBool(), true);
309313
310− dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
314+ dragHandle = fetchAndSetupDragHandle("topEdgeHideDragHandle");
311315
312316 dragThreshold = fetchDragThreshold(dragHandle);
313317
@@ -340,7 +344,7 @@ void tst_DragHandle::dragThreshold_vertical_data()
340344 */
341345void tst_DragHandle::stretch_horizontal()
342346{
343− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
347+ QQuickItem *dragHandle = fetchAndSetupDragHandle("rightwardsDragHandle");
344348 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
345349 QQuickItem *parentItem = dragHandle->parentItem();
346350
@@ -370,7 +374,7 @@ void tst_DragHandle::stretch_horizontal()
370374
371375void tst_DragHandle::stretch_vertical()
372376{
373− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
377+ QQuickItem *dragHandle = fetchAndSetupDragHandle("topEdgeShowDragHandle");
374378 qreal totalDragDistance = dragHandle->property("maxTotalDragDistance").toReal();
375379 QQuickItem *parentItem = dragHandle->parentItem();
376380
@@ -387,7 +391,7 @@ void tst_DragHandle::stretch_vertical()
387391 tryCompare([&](){ return parentItem->height(); }, totalDragDistance);
388392 QCOMPARE(parentItem->property("shown").toBool(), true);
389393
390− dragHandle = fetchAndSetupDragHandle("upwardsDragHandle");
394+ dragHandle = fetchAndSetupDragHandle("topEdgeHideDragHandle");
391395
392396 // flick all the way
393397 flickAndHold(dragHandle, totalDragDistance);
@@ -406,7 +410,7 @@ void tst_DragHandle::stretch_vertical()
406410 */
407411void tst_DragHandle::hintingAnimation()
408412{
409− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
413+ QQuickItem *dragHandle = fetchAndSetupDragHandle("topEdgeShowDragHandle");
410414 QQuickItem *parentItem = dragHandle->parentItem();
411415 qreal hintDisplacement = 100.0;
412416
@@ -447,7 +451,7 @@ void tst_DragHandle::hintingAnimation()
447451 */
448452void tst_DragHandle::hintingAnimation_dontRestartAfterFinishedAndStillPressed()
449453{
450− DirectionalDragArea *dragHandle = fetchAndSetupDragHandle("downwardsDragHandle");
454+ QQuickItem *dragHandle = fetchAndSetupDragHandle("topEdgeShowDragHandle");
451455 QQuickItem *parentItem = dragHandle->parentItem();
452456 qreal hintDisplacement = 100.0;
453457
tests/qmltests/Components/tst_DragHandle.qml+22−4
@@ -64,15 +64,33 @@ Rectangle {
6464 onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
6565 }
6666
67− VerticalShowable {
68− visible: !root.bidirectional
67+ TopEdgeShowable {
68+ id: topEdgeShowable
69+ visible: !root.bidirectional && !bottomEdgeShowable.shown
6970 onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
7071 stretch: root.stretch
7172 hintDisplacement: root.hintDisplacement
7273 }
7374
74− HorizontalShowable {
75− visible: !root.bidirectional
75+ BottomEdgeShowable {
76+ id: bottomEdgeShowable
77+ visible: !root.bidirectional && !topEdgeShowable.shown
78+ onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
79+ stretch: root.stretch
80+ hintDisplacement: root.hintDisplacement
81+ }
82+
83+ LeftEdgeShowable {
84+ id: leftEdgeShowable
85+ visible: !root.bidirectional && !rightEdgeShowable.shown
86+ onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
87+ stretch: root.stretch
88+ hintDisplacement: root.hintDisplacement
89+ }
90+
91+ RightEdgeShowable {
92+ id: rightEdgeShowable
93+ visible: !root.bidirectional && !leftEdgeShowable.shown
7694 onDragHandleRecognizedGesture: { root.dragHandle = dragHandle }
7795 stretch: root.stretch
7896 hintDisplacement: root.hintDisplacement
tests/qmltests/Components/tst_DragHandle/BottomEdgeShowable.qmlnew file+108
@@ -0,0 +1,108 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import "../../../../qml/Components"
19+import Ubuntu.Components 1.3
20+import Ubuntu.Gestures 0.1
21+
22+Showable {
23+ id: root
24+ y: height
25+ width: parent.width
26+ height: parent.height
27+
28+ property bool stretch
29+ property real hintDisplacement
30+
31+ Binding {
32+ when: stretch
33+ target: root
34+ property: "y"
35+ value: root.parent.height - root.height
36+ }
37+
38+ onStretchChanged: {
39+ // reset
40+ shown = false;
41+ if (stretch) {
42+ height = 0;
43+ } else {
44+ y = parent.height;
45+ height = parent.height;
46+ }
47+ }
48+
49+ shown: false
50+
51+ signal dragHandleRecognizedGesture(var dragHandle)
52+
53+ property string animatedProp: stretch ? "height" : "y"
54+ property real propValueWhenShown: stretch ? parent.height : 0
55+ property real propValueWhenHidden: stretch ? 0 : height
56+
57+ showAnimation: StandardAnimation { property: animatedProp; to: propValueWhenShown }
58+ hideAnimation: StandardAnimation { property: animatedProp; to: propValueWhenHidden }
59+
60+ Image { source: "../../UnityLogo.png"; anchors.fill: parent }
61+
62+ DragHandle {
63+ objectName: "topEdgeHideDragHandle"
64+ id: hideDragHandle
65+ anchors.left: parent.left
66+ anchors.right: parent.right
67+ anchors.top: parent.top
68+
69+ height: units.gu(2)
70+
71+ direction: Direction.Downwards
72+ stretch: root.stretch
73+ maxTotalDragDistance: root.parent.height
74+ hintDisplacement: root.hintDisplacement
75+
76+ onDraggingChanged: {
77+ if (dragging) {
78+ dragHandleRecognizedGesture(hideDragHandle);
79+ }
80+ }
81+
82+ Rectangle { color: "red"; anchors.fill: parent }
83+ }
84+
85+ DragHandle {
86+ objectName: "topEdgeShowDragHandle"
87+ id: showDragHandle
88+ anchors.left: parent.left
89+ anchors.right: parent.right
90+ anchors.bottom: parent.top
91+
92+ height: units.gu(2)
93+
94+ direction: Direction.Upwards
95+ stretch: root.stretch
96+ maxTotalDragDistance: root.parent.height
97+ hintDisplacement: root.hintDisplacement
98+
99+ onDraggingChanged: {
100+ if (dragging) {
101+ dragHandleRecognizedGesture(showDragHandle);
102+ }
103+ }
104+
105+ Rectangle { color: "green"; anchors.fill: parent }
106+ }
107+
108+}
tests/qmltests/Components/tst_DragHandle/HorizontalShowable.qml → tests/qmltests/Components/tst_DragHandle/LeftEdgeShowable.qmlrenamed

The content is the same.

tests/qmltests/Components/tst_DragHandle/RightEdgeShowable.qmlnew file+108
@@ -0,0 +1,108 @@
1+/*
2+ * Copyright (C) 2016 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.4
18+import "../../../../qml/Components"
19+import Ubuntu.Components 1.3
20+import Ubuntu.Gestures 0.1
21+
22+Showable {
23+ id: root
24+ x: parent.width
25+ width: parent.width
26+ height: parent.height
27+
28+ property bool stretch
29+ property real hintDisplacement
30+
31+ Binding {
32+ when: stretch
33+ target: root
34+ property: "x"
35+ value: root.parent.width - root.width
36+ }
37+
38+ onStretchChanged: {
39+ // reset
40+ shown = false;
41+ if (stretch) {
42+ width = 0;
43+ } else {
44+ x = parent.width;
45+ width = parent.width;
46+ }
47+ }
48+
49+ shown: false
50+
51+ signal dragHandleRecognizedGesture(var dragHandle)
52+
53+ property string animatedProp: stretch ? "width" : "x"
54+ property real propValueWhenShown: stretch ? parent.width : 0
55+ property real propValueWhenHidden: stretch ? 0 : parent.width
56+
57+ showAnimation: StandardAnimation { property: animatedProp; to: propValueWhenShown }
58+ hideAnimation: StandardAnimation { property: animatedProp; to: propValueWhenHidden }
59+
60+ Image { source: "../../UnityLogo.png"; anchors.fill: parent }
61+
62+ DragHandle {
63+ objectName: "rightEdgeHideDragHandle"
64+ id: hideDragHandle
65+ anchors.top: parent.top
66+ anchors.bottom: parent.bottom
67+ anchors.left: parent.left
68+
69+ width: units.gu(2)
70+
71+ direction: Direction.Rightwards
72+ stretch: root.stretch
73+ maxTotalDragDistance: root.parent.width
74+ hintDisplacement: root.hintDisplacement
75+
76+ onDraggingChanged: {
77+ if (dragging) {
78+ dragHandleRecognizedGesture(hideDragHandle);
79+ }
80+ }
81+
82+ Rectangle { color: "red"; anchors.fill: parent }
83+ }
84+
85+ DragHandle {
86+ objectName: "rightEdgeShowDragHandle"
87+ id: showDragHandle
88+ anchors.top: parent.top
89+ anchors.bottom: parent.bottom
90+ anchors.right: parent.left
91+
92+ width: units.gu(2)
93+
94+ direction: Direction.Leftwards
95+ stretch: root.stretch
96+ maxTotalDragDistance: root.parent.width
97+ hintDisplacement: root.hintDisplacement
98+
99+ onDraggingChanged: {
100+ if (dragging) {
101+ dragHandleRecognizedGesture(showDragHandle);
102+ }
103+ }
104+
105+ Rectangle { color: "green"; anchors.fill: parent }
106+ }
107+
108+}
tests/qmltests/Components/tst_DragHandle/VerticalShowable.qml → tests/qmltests/Components/tst_DragHandle/TopEdgeShowable.qmlrenamed+7−7
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013,2016 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
@@ -52,8 +52,8 @@ Showable {
5252 Image { source: "../../UnityLogo.png"; anchors.fill: parent }
5353
5454 DragHandle {
55− objectName: "upwardsDragHandle"
56− id: upwardsDragHandle
55+ objectName: "topEdgeHideDragHandle"
56+ id: hideDragHandle
5757 anchors.left: parent.left
5858 anchors.right: parent.right
5959 anchors.bottom: parent.bottom
@@ -67,7 +67,7 @@ Showable {
6767
6868 onDraggingChanged: {
6969 if (dragging) {
70− dragHandleRecognizedGesture(upwardsDragHandle);
70+ dragHandleRecognizedGesture(hideDragHandle);
7171 }
7272 }
7373
@@ -75,8 +75,8 @@ Showable {
7575 }
7676
7777 DragHandle {
78− objectName: "downwardsDragHandle"
79− id: downwardsDragHandle
78+ objectName: "topEdgeShowDragHandle"
79+ id: showDragHandle
8080 anchors.left: parent.left
8181 anchors.right: parent.right
8282 anchors.top: parent.bottom
@@ -90,7 +90,7 @@ Showable {
9090
9191 onDraggingChanged: {
9292 if (dragging) {
93− dragHandleRecognizedGesture(downwardsDragHandle);
93+ dragHandleRecognizedGesture(showDragHandle);
9494 }
9595 }
9696
tests/qmltests/Components/tst_EdgeDragEvaluator.cpp+1−1
@@ -24,7 +24,7 @@
2424// Ubuntu.Gestures plugin
2525#include <AxisVelocityCalculator.h>
2626#include <Direction.h>
27−#include <Timer.h>
27+#include <Timer>
2828
2929#include <paths.h>
3030
tests/qmltests/Dash/Previews/tst_Preview.qml−1
@@ -109,7 +109,6 @@ Rectangle {
109109 }
110110
111111 function test_comboEnsureVisible() {
112− skip("Flaky in adt but can't reproduce locally. Given the deadline I won't risk this getting stuck in proposed.");
113112 waitForRendering(preview);
114113
115114 // Scroll down
tests/qmltests/Dash/Previews/tst_PreviewRatingEdit.qml+5−1
@@ -50,7 +50,8 @@ Rectangle {
5050
5151 var authorLabel = findChild(previewRatingEdit, "authorLabel");
5252 var reviewTextArea = findChild(previewRatingEdit, "reviewTextArea");
53− var inputRating = findChild(findChild(previewRatingEdit, "input"), "rating");
53+ var ratingInput = findChild(previewRatingEdit, "input");
54+ var inputRating = findChild(ratingInput, "rating");
5455 verify(authorLabel.visible)
5556 verify(!reviewTextArea.visible)
5657
@@ -65,6 +66,9 @@ Rectangle {
6566 reviewTextArea.text = "Ho Ho";
6667 inputRating.value = 3;
6768
69+ var reviewContainer = findChild(ratingInput, "reviewContainer");
70+ var reviewSubmitContainer = findChild(ratingInput, "reviewSubmitContainer");
71+ tryCompare(reviewContainer, "implicitHeight", reviewSubmitContainer.implicitHeight + reviewContainer.anchors.topMargin);
6872 var submitButton = findChild(previewRatingEdit, "submitButton")
6973 mouseClick(submitButton);
7074
tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml+18−6
@@ -73,11 +73,10 @@ Rectangle {
7373
7474 function test_labels() {
7575 var ratingLabel = findChild(previewRatingInput, "ratingLabel");
76− var reviewLabel = findChild(previewRatingInput, "reviewLabel");
7776
7877 previewRatingInput.widgetData = widgetDataNewLabels;
7978 compare(ratingLabel.text, widgetDataNewLabels["rating-label"]);
80− compare(reviewLabel.text, widgetDataNewLabels["review-label"]);
79+ compare(reviewTextArea.placeholderText, widgetDataNewLabels["review-label"]);
8180 compare(submitButton.text, widgetDataNewLabels["submit-label"]);
8281 }
8382
@@ -120,10 +119,17 @@ Rectangle {
120119
121120 previewRatingInput.widgetData = data.widgetData;
122121
122+ if (data.widgetData["visible"] === "both" && data.widgetData["required"] === "both")
123+ compare(reviewTextArea.visible, false);
124+
123125 if (data.widgetData["visible"] !== "review") {
124− verify(rating.visible === true);
126+ compare(rating.visible, true);
125127
126128 rating.value = data.inputRating;
129+
130+ if (data.inputRating > 0 && data.widgetData["visible"] === "both")
131+ compare(reviewTextArea.visible, true);
132+
127133 if (data.widgetData["required"] !== "rating" ||
128134 data.widgetData["visible"] !== "rating" ||
129135 data.inputRating < 0) {
@@ -132,13 +138,19 @@ Rectangle {
132138 compare(spy.count, 1);
133139 }
134140 } else {
135− verify(rating.visible === false);
141+ compare(rating.visible, false);
136142 }
137143
138144 if (data.widgetData["visible"] !== "rating") {
139− verify(reviewTextArea.visible === true);
145+ if (data.widgetData["visible"] === "review" || data.widgetData["required"] === "review")
146+ compare(reviewTextArea.visible, true);
140147
141148 reviewTextArea.text = data.inputText;
149+ var reviewContainer = findChild(previewRatingInput, "reviewContainer");
150+ if (reviewContainer.visible) {
151+ var reviewSubmitContainer = findChild(previewRatingInput, "reviewSubmitContainer");
152+ tryCompare(reviewContainer, "implicitHeight", reviewSubmitContainer.implicitHeight + reviewContainer.anchors.topMargin);
153+ }
142154 mouseClick(submitButton);
143155 switch (data.widgetData["required"]) {
144156 case "rating": {
@@ -164,7 +176,7 @@ Rectangle {
164176 }
165177 }
166178 } else {
167− verify(reviewTextArea.visible === false);
179+ compare(reviewTextArea.visible, false);
168180 }
169181
170182 compare(spy.count === 1, data.emitted);
tests/qmltests/Dash/Previews/tst_PreviewWidgetFactory.qml+1−1
@@ -43,7 +43,7 @@ Rectangle {
4343 name: "PreviewWidgetFactory"
4444 when: windowShown
4545
46− property Item mockWidget: findChild(factory, "mockPreviewWidget")
46+ property Item mockWidget: findChild(factory, "mockPreviewWidget", 0 /*timeout*/)
4747
4848 function cleanup() {
4949 factory.source = Qt.binding(function() { return factory.widgetSource });
tests/qmltests/Dash/tst_Card.qml+22−10
@@ -226,16 +226,16 @@ Rectangle {
226226
227227 when: windowShown
228228
229− property Item title: findChild(loader, "titleLabel")
230− property Item subtitle: findChild(loader, "subtitleLabel")
231− property var headerRow: findChild(loader, "outerRow")
232− property var art: findChild(loader, "artShape")
233− property Item artImage: findChild(loader, "artImage")
234− property Item summary: findChild(loader, "summaryLabel")
235− property Item background: findChild(loader, "background")
236− property Item backgroundLoader: findChild(loader, "backgroundLoader")
237− property Item backgroundImage: findChild(loader, "backgroundImage")
238− property Item mascotImage: findChild(loader, "mascotImage");
229+ property Item title: findChild(loader, "titleLabel", 0 /*timeout*/)
230+ property Item subtitle: findChild(loader, "subtitleLabel", 0 /*timeout*/)
231+ property var headerRow: findChild(loader, "outerRow", 0 /*timeout*/)
232+ property var art: findChild(loader, "artShape", 0 /*timeout*/)
233+ property Item artImage: findChild(loader, "artImage", 0 /*timeout*/)
234+ property Item summary: findChild(loader, "summaryLabel", 0 /*timeout*/)
235+ property Item background: findChild(loader, "background", 0 /*timeout*/)
236+ property Item backgroundLoader: findChild(loader, "backgroundLoader", 0 /*timeout*/)
237+ property Item backgroundImage: findChild(loader, "backgroundImage", 0 /*timeout*/)
238+ property Item mascotImage: findChild(loader, "mascotImage", 0 /*timeout*/)
239239
240240 function init() {
241241 cardTool.components = Qt.binding(function() { return Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components']; });
@@ -496,6 +496,18 @@ Rectangle {
496496 tryCompare(art, "visible", true);
497497 compare(artImage.source, Qt.resolvedUrl("artwork/checkers.png"));
498498
499+ card.cardData["art"] = "somethingbroken";
500+ card.cardDataChanged();
501+ waitForRendering(card);
502+ tryCompare(art, "visible", true);
503+ compare(artImage.source, Qt.resolvedUrl("artwork/checkers.png"));
504+
505+ card.cardData["art"] = Qt.resolvedUrl("artwork/music-player-design.png");
506+ card.cardDataChanged();
507+ waitForRendering(card);
508+ tryCompare(art, "visible", true);
509+ compare(artImage.source, Qt.resolvedUrl("artwork/music-player-design.png"));
510+
499511 card.cardData["mascot"] = "somethingbroken2";
500512 card.cardDataChanged();
501513 compare(mascotImage.status, Image.Error);
tests/qmltests/Dash/tst_CardTool.qml+1−1
@@ -240,7 +240,7 @@ Rectangle {
240240 id: testCase
241241 name: "CardTool"
242242
243− property var internalCard: findChild(cardTool, "cardToolCard")
243+ property var internalCard: findChild(cardTool, "cardToolCard", 0 /*timeout*/)
244244
245245 when: windowShown
246246
tests/qmltests/Dash/tst_Dash.qml+76−62
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import QtTest 1.0
1919import "../../../qml/Dash"
2020import Ubuntu.Components 1.3
21+import Unity 0.2 // Access the Filters enum
2122import Unity.Test 0.1 as UT
2223
2324Item {
@@ -57,7 +58,7 @@ Item {
5758 tryCompare(dashContentList, "count", 0);
5859 scopes.load();
5960 tryCompare(dashContentList, "currentIndex", 0);
60− tryCompare(dashContentList, "count", 6);
61+ tryCompare(dashContentList, "count", 7);
6162 tryCompare(scopes, "loaded", true);
6263 tryCompareFunction(function() {
6364 var mockScope1Loader = findChild(dash, "scopeLoader0");
@@ -106,6 +107,72 @@ Item {
106107 mouseClick(tile);
107108 }
108109
110+ function test_longNavigationFilterList() {
111+ // Select the scope with long navigation
112+ dash.setCurrentScope("LongPrimaryNavigation")
113+ var dashContent = findChild(dash, "dashContent")
114+ tryCompare(dashContent.currentScope, "id", "LongPrimaryNavigation")
115+
116+ var dashContentList = findChild(dashContent, "dashContentList")
117+ var searchButton = findChild(dashContentList.currentItem, "search_button")
118+ var extraPanel = findChild(dashContentList.currentItem, "peExtraPanel")
119+ tryCompare(extraPanel, "visible", false)
120+
121+ // Open the primaryNavigationFilter
122+ dashContent.currentScope.setHasNavigation(false)
123+ mouseClick(searchButton)
124+ tryCompare(extraPanel, "visible", true)
125+
126+ var primaryFilterContainer = findChild(extraPanel, "primaryFilterContainer")
127+ verify(primaryFilterContainer)
128+
129+ var primaryFilter = findChild(extraPanel, "primaryFilter")
130+ verify(primaryFilter)
131+ tryCompare(primaryFilter, "widgetType", Filters.OptionSelectorFilter)
132+
133+ var genericScopeView = dashContentList.currentItem;
134+ var categoryListView = findChild(genericScopeView, "categoryListView")
135+ verify(categoryListView)
136+ tryCompare(categoryListView, "atYBeginning", true)
137+
138+ var expandingItem = findChild(primaryFilter, "expandingItem")
139+ verify(expandingItem)
140+ expandingItem.expanded = true
141+
142+ // Flick the navigation list and ensure the underlying scope didn't move
143+ tryCompareFunction(function() { return expandingItem.height == expandingItem.expandedHeight; }, true);
144+ flickToYEnd(primaryFilterContainer)
145+
146+ tryCompare(categoryListView, "atYBeginning", true)
147+ }
148+
149+ function test_navigationFilterPopupClosesWhenOptionSelected() {
150+ dash.setCurrentScope("LongPrimaryNavigation")
151+
152+ var dashContentList = findChild(dashContent, "dashContentList")
153+ var searchButton = findChild(dashContentList.currentItem, "search_button")
154+ verify(searchButton)
155+ var extraPanel = findChild(dashContentList.currentItem, "peExtraPanel")
156+ verify(extraPanel)
157+
158+ var primaryFilter = findChild(extraPanel, "primaryFilter")
159+ var expandingItem = findChild(primaryFilter, "expandingItem")
160+ verify(expandingItem)
161+ tryCompare(expandingItem, "expanded", false)
162+
163+ mouseClick(searchButton)
164+ expandingItem.expanded = true
165+ tryCompare(expandingItem, "expanded", true)
166+ tryCompareFunction(function() { return expandingItem.height == expandingItem.expandedHeight; }, true);
167+
168+ var optionsRepeater = findChild(expandingItem, "optionsRepeater")
169+ verify(optionsRepeater)
170+ verify(optionsRepeater.itemAt(0))
171+ tryCompare(optionsRepeater.itemAt(0), "visible", true)
172+ mouseClick(optionsRepeater.itemAt(0))
173+ tryCompare(expandingItem, "visible", false)
174+ }
175+
109176 function test_manage_dash_clickscope_unfavoritable() {
110177 // Show the manage dash
111178 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
@@ -125,7 +192,7 @@ Item {
125192 // Go back
126193 var scopesList = findChild(dash, "scopesList");
127194 var scopesListPageHeader = findChild(scopesList, "pageHeader");
128− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
195+ var backButton = findChild(scopesListPageHeader, "innerPageHeader").leadingActionBar;
129196 mouseClick(backButton);
130197 tryCompare(bottomEdgeController, "progress", 0);
131198 }
@@ -200,60 +267,7 @@ Item {
200267
201268 // Go back
202269 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
203− var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "customBackButton");
204− mouseClick(backButton);
205−
206− // Check temp scope is gone
207− tryCompare(dashTempScopeItem, "x", dash.width);
208− tryCompare(dashTempScopeItem, "visible", false);
209−
210− // Original list is still on 0
211− var dashContentList = findChild(dash, "dashContentList");
212− compare(dashContentList.currentIndex, 0);
213− }
214−
215− function test_manage_dash_search_temp_scope() {
216− // TODO Search is disabled for now in manage dash
217− skip();
218−
219− // Show the manage dash
220− touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
221− var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
222− tryCompare(bottomEdgeController, "progress", 1);
223−
224− // Do a search
225− var scopesList = findChild(dash, "scopesList");
226− var scopesListPageHeader = findChild(scopesList, "pageHeader");
227− var searchButton = findChild(scopesListPageHeader, "search_header_button");
228− mouseClick(searchButton);
229−
230− // Type something
231− keyClick(Qt.Key_H);
232−
233− // Click on a temp scope in the search
234− tryCompareFunction( function() { return findChild(scopesList, "scopesListCategorysearchA") != null; }, true);
235− var dashCategorysearchA = findChild(scopesList, "scopesListCategorysearchA");
236− tryCompareFunction( function() { return findChild(dashCategorysearchA, "delegate2") != null; }, true);
237− var cardTempScope = findChild(dashCategorysearchA, "delegate2");
238−
239− waitForRendering(cardTempScope);
240− mouseClick(cardTempScope);
241−
242− // Check the bottom edge (overview) is disabled from temp scope
243− var overviewDragHandle = findChild(dash, "overviewDragHandle");
244− compare(overviewDragHandle.enabled, false);
245−
246− // Check temp scope is there
247− var dashTempScopeItem = findChild(dash, "dashTempScopeItem");
248− tryCompare(dashTempScopeItem, "x", 0);
249− tryCompare(dashTempScopeItem, "visible", true);
250−
251− // Check the manage dash is gone
252− tryCompare(bottomEdgeController, "progress", 0);
253−
254− // Go back
255− var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
256− var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "customBackButton");
270+ var backButton = findChild(dashTempScopeItemHeader, "innerPageHeader").leadingActionBar;
257271 mouseClick(backButton);
258272
259273 // Check temp scope is gone
@@ -279,7 +293,7 @@ Item {
279293 // Go back
280294 var scopesList = findChild(dash, "scopesList");
281295 var scopesListPageHeader = findChild(scopesList, "pageHeader");
282− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
296+ var backButton = findChild(scopesListPageHeader, "innerPageHeader").leadingActionBar;
283297 mouseClick(backButton);
284298 tryCompare(bottomEdgeController, "progress", 0);
285299 }
@@ -391,7 +405,7 @@ Item {
391405 // Exit edit mode and go back
392406 var scopesList = findChild(dash, "scopesList");
393407 var scopesListPageHeader = findChild(scopesList, "pageHeader");
394− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
408+ var backButton = findChild(scopesListPageHeader, "innerPageHeader").leadingActionBar;
395409 mouseClick(backButton);
396410 mouseClick(backButton);
397411 tryCompare(bottomEdgeController, "progress", 0);
@@ -436,7 +450,7 @@ Item {
436450 // Exit edit mode
437451 var scopesList = findChild(dash, "scopesList");
438452 var scopesListPageHeader = findChild(scopesList, "pageHeader");
439− var backButton = findChild(findChild(scopesListPageHeader, "innerPageHeader"), "customBackButton");
453+ var backButton = findChild(scopesListPageHeader, "innerPageHeader").leadingActionBar;
440454 mouseClick(backButton);
441455
442456 // Click on third scope
@@ -546,7 +560,7 @@ Item {
546560
547561 // Go back
548562 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
549− var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "customBackButton");
563+ var backButton = findChild(dashTempScopeItemHeader, "innerPageHeader").leadingActionBar;
550564 mouseClick(backButton);
551565
552566 // Check temp scope is gone
@@ -614,7 +628,7 @@ Item {
614628
615629 // Go back
616630 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
617− var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "customBackButton");
631+ var backButton = findChild(dashTempScopeItemHeader, "innerPageHeader").leadingActionBar;
618632 mouseClick(backButton);
619633
620634 // Check temp scope is gone
@@ -646,7 +660,7 @@ Item {
646660
647661 // Go back
648662 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
649− var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "customBackButton");
663+ var backButton = findChild(dashTempScopeItemHeader, "innerPageHeader").leadingActionBar;
650664 mouseClick(backButton);
651665
652666 // Check temp scope is gone
tests/qmltests/Dash/tst_DashContent.qml+63−4
@@ -124,7 +124,7 @@ Item {
124124
125125 loadScopes();
126126
127− compare(dashContentList.count, 6);
127+ compare(dashContentList.count, 7);
128128 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < dashContentList.count);
129129 }
130130
@@ -215,7 +215,7 @@ Item {
215215 verify(pageHeader, "Could not find the scope page header.");
216216 var innerHeader = findChild(pageHeader, "innerPageHeader");
217217 verify(innerHeader, "Could not find the scope page header.");
218− compare(innerHeader.config.title, scopesModel.getScope(data.index).name);
218+ compare(innerHeader.title, scopesModel.getScope(data.index).name);
219219 }
220220
221221 function test_is_active_data() {
@@ -515,10 +515,18 @@ Item {
515515 }
516516
517517 function test_navigationShowFilterPopup() {
518− goToSecondLevel();
519−
520518 var dashContentList = findChild(dashContent, "dashContentList");
519+ var pageHeader = findChild(dashContentList.currentItem, "scopePageHeader")
521520 var settingsButton = findChild(dashContentList.currentItem, "settingsButton");
521+ var searchButton = findChild(dashContentList.currentItem, "search_button");
522+ var cancelButton = findChild(dashContentList.currentItem, "cancelButton");
523+ var searchTextField = findChild(pageHeader, "searchTextField");
524+ var peExtraPanel = findChild(dashContentList.currentItem, "peExtraPanel");
525+ var headerContainer = findChild(pageHeader, "headerContainer");
526+
527+ // test that closing the filters popover without a search unfocuses and removes the navigation
528+ mouseClick(searchButton);
529+ tryCompare(peExtraPanel, "visible", true);
522530
523531 var filtersPopover = findChild(shell, "filtersPopover")
524532 verify(!filtersPopover);
@@ -526,8 +534,33 @@ Item {
526534 mouseClick(settingsButton);
527535
528536 filtersPopover = findChild(shell, "filtersPopover")
537+ verify(filtersPopover);
529538
539+ mouseClick(shell, shell.width - 1, shell.height - 1);
540+
541+ tryCompare(pageHeader.extraPanel, "visible", false);
542+ tryCompare(headerContainer, "showSearch", true);
543+ tryCompare(searchTextField, "focus", false);
544+
545+ mouseClick(cancelButton);
546+ tryCompare(headerContainer, "showSearch", false);
547+ tryCompare(headerContainer, "contentY", headerContainer.height);
548+
549+ // test within a navigation
550+ goToSecondLevel();
551+
552+ filtersPopover = findChild(shell, "filtersPopover")
553+ verify(!filtersPopover);
554+
555+ mouseClick(settingsButton);
556+
557+ filtersPopover = findChild(shell, "filtersPopover")
530558 verify(filtersPopover);
559+
560+ mouseClick(shell, shell.width - 1, shell.height - 1);
561+
562+ tryCompare(pageHeader.extraPanel, "visible", false);
563+ tryCompare(headerContainer, "showSearch", true);
531564 }
532565
533566 function test_primaryFilter() {
@@ -625,5 +658,31 @@ Item {
625658 tryCompareFunction(function() { return dashContentList.currentItem.item.scope.id == nextScopeId; }, true);
626659 compare(dashContentList.currentIndex, 0);
627660 }
661+
662+ function test_extraPanel() {
663+ var dashContentList = findChild(dashContent, "dashContentList");
664+ var pageHeader = findChild(dashContentList.currentItem, "scopePageHeader")
665+ pageHeader.searchEntryEnabled = true;
666+ pageHeader.searchHistory.clear();
667+
668+ pageHeader.searchHistory.addQuery("Search1");
669+ pageHeader.searchHistory.addQuery("Search2");
670+
671+ pageHeader.triggerSearch();
672+ tryCompare(pageHeader.extraPanel, "visible", true);
673+
674+ var searchTextField = findChild(pageHeader, "searchTextField");
675+ compare(searchTextField.focus, true);
676+
677+ var recentSearches = findChild(pageHeader.extraPanel, "recentSearchesRepeater");
678+ verify(recentSearches, "Could not find recent searches");
679+
680+ waitForRendering(recentSearches);
681+
682+ mouseClick(recentSearches.itemAt(0));
683+ compare(pageHeader.searchQuery, "Search2");
684+ tryCompare(pageHeader.extraPanel, "visible", false);
685+ compare(searchTextField.focus, false);
686+ }
628687 }
629688}
tests/qmltests/Dash/tst_DashPageHeader.qml−24
@@ -147,30 +147,6 @@ Item {
147147 doResetSearch();
148148 }
149149
150− function test_extraPanel() {
151− searchEnabled = true;
152− pageHeader.searchHistory.clear();
153−
154− pageHeader.searchHistory.addQuery("Search1");
155− pageHeader.searchHistory.addQuery("Search2");
156−
157− pageHeader.triggerSearch();
158−
159− tryCompare(pageHeader.extraPanel, "visible", true);
160−
161− var searchTextField = findChild(pageHeader, "searchTextField");
162− compare(searchTextField.focus, true);
163−
164− var recentSearches = findChild(pageHeader.extraPanel, "recentSearchesRepeater");
165− verify(recentSearches, "Could not find recent searches");
166− waitForRendering(recentSearches);
167− mouseClick(recentSearches.itemAt(0));
168−
169− compare(pageHeader.searchQuery, "Search2");
170− tryCompare(pageHeader.extraPanel, "visible", false);
171− compare(searchTextField.focus, false);
172− }
173−
174150 function test_popup_closing_data() {
175151 return [
176152 { tag: "with search text", searchText: "foobar", hideSearch: false },
tests/qmltests/Dash/tst_DashShell.qml+1−1
@@ -60,7 +60,7 @@ Item {
6060 tryCompare(dashContentList, "count", 0);
6161 scopes.load();
6262 tryCompare(dashContentList, "currentIndex", 0);
63− tryCompare(dashContentList, "count", 6);
63+ tryCompare(dashContentList, "count", 7);
6464 tryCompare(scopes, "loaded", true);
6565 tryCompareFunction(function() {
6666 var mockScope1Loader = findChild(dash, "scopeLoader0");
tests/qmltests/Dash/tst_GenericScopeView.qml+2−2
@@ -442,8 +442,8 @@ Item {
442442
443443 var innerHeader = findChild(header, "innerPageHeader");
444444 verify(innerHeader, "Could not find the inner header");
445− verify(Qt.colorEqual(innerHeader.config.foregroundColor, data.foreground),
446− "Foreground color not equal: %1 != %2".arg(innerHeader.config.foregroundColor).arg(data.foreground));
445+ verify(Qt.colorEqual(innerHeader.__styleInstance.foregroundColor, data.foreground),
446+ "Foreground color not equal: %1 != %2".arg(innerHeader.__styleInstance.foregroundColor).arg(data.foreground));
447447
448448 var background = findChild(header, "headerBackground");
449449 verify(background, "Could not find the background");
tests/qmltests/Dash/tst_PreviewView.qml+3−3
@@ -98,7 +98,7 @@ Rectangle {
9898 var header = findChild(view, "innerPageHeader");
9999 verify(header, "Could not find the preview header");
100100
101− compare(header.config.title, "Mock Scope");
101+ compare(header.title, "Mock Scope");
102102 }
103103
104104 function test_header_style() {
@@ -107,8 +107,8 @@ Rectangle {
107107
108108 var innerHeader = findChild(header, "innerPageHeader");
109109 verify(innerHeader, "Could not find the inner header");
110− verify(Qt.colorEqual(innerHeader.config.foregroundColor, UbuntuColors.darkGrey),
111− "Foreground color not equal: %1 != %2".arg(innerHeader.config.foregroundColor).arg(UbuntuColors.darkGrey));
110+ verify(Qt.colorEqual(innerHeader.__styleInstance.foregroundColor, UbuntuColors.darkGrey),
111+ "Foreground color not equal: %1 != %2".arg(innerHeader.__styleInstance.foregroundColor).arg(UbuntuColors.darkGrey));
112112
113113 var background = findChild(header, "headerBackground");
114114 verify(background, "Could not find the background");
tests/qmltests/Greeter/tst_Greeter.qml+1−1
@@ -166,7 +166,7 @@ Item {
166166 tryCompare(loader, "itemDestroyed", true);
167167 loader.active = true;
168168 tryCompare(loader, "status", Loader.Ready);
169− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
169+ removeTimeConstraintsFromSwipeAreas(loader.item);
170170 }
171171
172172 function getIndexOf(name) {
tests/qmltests/Greeter/tst_NarrowView.qml+1−1
@@ -302,7 +302,7 @@ Item {
302302 tryCompare(loader, "itemDestroyed", true);
303303 loader.active = true;
304304 tryCompare(loader, "status", Loader.Ready);
305− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
305+ removeTimeConstraintsFromSwipeAreas(loader.item);
306306 }
307307
308308 function swipeAwayCover(toTheRight) {
tests/qmltests/Greeter/tst_WideView.qml+1−1
@@ -330,7 +330,7 @@ Item {
330330 tryCompare(loader, "itemDestroyed", true);
331331 loader.active = true;
332332 tryCompare(loader, "status", Loader.Ready);
333− removeTimeConstraintsFromDirectionalDragAreas(loader.item);
333+ removeTimeConstraintsFromSwipeAreas(loader.item);
334334 }
335335
336336 function getIndexOf(name) {
tests/qmltests/Launcher/tst_Launcher.qml+13−1
@@ -34,6 +34,14 @@ Rectangle {
3434
3535 Component.onCompleted: theme.name = "Ubuntu.Components.Themes.SuruDark"
3636
37+ MouseArea {
38+ id: clickThroughTester
39+ anchors.fill: parent
40+ // SignalSpy does not seem to want to connect to the pressed signal. let's count them ourselves.
41+ property int pressCount: 0
42+ onPressed: pressCount++;
43+ }
44+
3745 Loader {
3846 id: launcherLoader
3947 anchors.fill: parent
@@ -254,7 +262,7 @@ Rectangle {
254262 // Now do check that snapping is in fact enabled
255263 compare(listView.snapMode, ListView.SnapToItem, "Snapping is not enabled");
256264
257− removeTimeConstraintsFromDirectionalDragAreas(root);
265+ removeTimeConstraintsFromSwipeAreas(root);
258266 }
259267
260268 function dragLauncherIntoView() {
@@ -836,16 +844,20 @@ Rectangle {
836844 dragLauncherIntoView();
837845 verify(launcher.state == "visible");
838846
847+ clickThroughTester.pressCount = 0;
839848 mouseClick(root, root.width / 2, units.gu(1));
840849 waitUntilLauncherDisappears();
841850 verify(launcher.state == "");
851+ compare(clickThroughTester.pressCount, 1);
842852
843853 // and repeat, as a test for regression in lpbug#1531339
844854 dragLauncherIntoView();
845855 verify(launcher.state == "visible");
856+ clickThroughTester.pressCount = 0;
846857 mouseClick(root, root.width / 2, units.gu(1));
847858 waitUntilLauncherDisappears();
848859 verify(launcher.state == "");
860+ compare(clickThroughTester.pressCount, 1);
849861 }
850862
851863 function test_quicklist_positioning_data() {
tests/qmltests/Notifications/tst_Notifications.qml+89
@@ -725,6 +725,95 @@ Item {
725725 tryCompare(mockModel, "count", before - 1)
726726 }
727727
728+ function expansionLogic_data() {
729+ return [{
730+ tag: "Snap Decision without secondary icon and no button-tint",
731+ n: nlist[3],
732+ summaryVisible: true,
733+ bodyVisible: true,
734+ iconVisible: true,
735+ centeredIconVisible: false,
736+ shaped: true,
737+ secondaryIconVisible: false,
738+ buttonRowVisible: true,
739+ buttonTinted: false,
740+ hasSound: true,
741+ valueVisible: false,
742+ valueLabelVisible: false,
743+ valueTinted: false
744+ },
745+ {
746+ tag: "2-over-1 Snap Decision with button-tint",
747+ n: nlist[8],
748+ summaryVisible: true,
749+ bodyVisible: true,
750+ iconVisible: false,
751+ centeredIconVisible: false,
752+ shaped: false,
753+ secondaryIconVisible: false,
754+ buttonRowVisible: false,
755+ buttonTinted: true,
756+ hasSound: false,
757+ valueVisible: false,
758+ valueLabelVisible: false,
759+ valueTinted: false
760+ },
761+ {
762+ tag: "Snap Decision without secondary icon and no button-tint",
763+ n: nlist[3],
764+ summaryVisible: true,
765+ bodyVisible: true,
766+ iconVisible: true,
767+ centeredIconVisible: false,
768+ shaped: true,
769+ secondaryIconVisible: false,
770+ buttonRowVisible: true,
771+ buttonTinted: false,
772+ hasSound: true,
773+ valueVisible: false,
774+ valueLabelVisible: false,
775+ valueTinted: false
776+ }
777+ ]
778+ }
779+
780+ function test_expansionLogic() {
781+ var data = expansionLogic_data();
782+
783+ // fill the model
784+ data.forEach(function(notification) {
785+ mockModel.append(notification.n);
786+ notification.n.completed.connect(mockModel.onCompleted)
787+ })
788+
789+ // make sure the view is properly updated before going on
790+ notifications.forceLayout();
791+ waitForRendering(notifications);
792+
793+ // first one should be expanded by default
794+ var notification1 = findChild(notifications, "notification1") // 0 is placeholder...
795+ verify(!!notification1, "notification wasn't found");
796+ waitForRendering(notification1);
797+ verify(notification1.expanded);
798+
799+ // click the 2nd one, verify it's now expanded
800+ var notification2 = findChild(notifications, "notification2") // 0 is placeholder...
801+ verify(!!notification2, "notification wasn't found");
802+ waitForRendering(notification2);
803+ mouseClick(notification2);
804+ verify(notification2.expanded);
805+ verify(!notification1.expanded);
806+
807+ // now close the 2nd one, verify 1st is again expanded, 2nd is gone
808+ var dragStart = notification2.width * 0.25;
809+ var dragEnd = notification2.width;
810+ var dragY = notification2.height / 2;
811+ touchFlick(notification2, dragStart, dragY, dragEnd, dragY);
812+ waitForRendering(notifications);
813+ tryCompareFunction(function() { return notification1.expanded; }, true);
814+ tryCompareFunction(function() { return notification2.expanded; }, undefined);
815+ }
816+
728817 function cleanupTestCase() {
729818 notifications.hasMouse = false;
730819 }
tests/qmltests/Panel/Indicators/tst_MessageMenuItemFactory.qml+1
@@ -30,6 +30,7 @@ Item {
3030 id: factory
3131 menuModel: UnityMenuModel {}
3232 menuIndex: 0
33+ width: parent.width
3334 }
3435
3536 UT.UnityTestCase {
tests/qmltests/Stages/tst_DesktopStage.qml+31−1
@@ -462,6 +462,36 @@ Item {
462462 verify(topSurfaceList.indexForId(dialerSurfaceId) === -1);
463463 }
464464
465+ function test_windowMaximizeHorizontally() {
466+ var dialerDelegate = startApplication("dialer-app");
467+
468+ var dialerMaximizeButton = findChild(dialerDelegate, "maximizeWindowButton");
469+ verify(dialerMaximizeButton);
470+
471+ // RMB to maximize horizontally
472+ mouseClick(dialerMaximizeButton, dialerMaximizeButton.width/2, dialerMaximizeButton.height/2, Qt.RightButton);
473+ tryCompare(dialerDelegate, "windowState", WindowStateStorage.WindowStateMaximizedHorizontally);
474+
475+ // click again to restore
476+ mouseClick(dialerMaximizeButton);
477+ tryCompare(dialerDelegate, "windowState", WindowStateStorage.WindowStateNormal);
478+ }
479+
480+ function test_windowMaximizeVertically() {
481+ var dialerDelegate = startApplication("dialer-app");
482+
483+ var dialerMaximizeButton = findChild(dialerDelegate, "maximizeWindowButton");
484+ verify(dialerMaximizeButton);
485+
486+ // MMB to maximize vertically
487+ mouseClick(dialerMaximizeButton, dialerMaximizeButton.width/2, dialerMaximizeButton.height/2, Qt.MiddleButton);
488+ tryCompare(dialerDelegate, "windowState", WindowStateStorage.WindowStateMaximizedVertically);
489+
490+ // click again to restore
491+ mouseClick(dialerMaximizeButton);
492+ tryCompare(dialerDelegate, "windowState", WindowStateStorage.WindowStateNormal);
493+ }
494+
465495 function test_smashCursorKeys() {
466496 var apps = ["dialer-app", "gmail-webapp"];
467497 apps.forEach(startApplication);
@@ -483,7 +513,7 @@ Item {
483513 verify(decoratedWindow);
484514
485515 tryCompare(dashSurface, "visible", true);
486− decoratedWindow.minimize();
516+ decoratedWindow.minimizeClicked();
487517 tryCompare(dashSurface, "visible", false);
488518 }
489519
tests/qmltests/Stages/tst_TabletStage.qml+66−2
@@ -129,6 +129,12 @@ Rectangle {
129129 }
130130 }
131131
132+ SignalSpy {
133+ id: stageSaver
134+ target: WindowStateStorage
135+ signalName: "stageSaved"
136+ }
137+
132138 UnityTestCase {
133139 id: testCase
134140 name: "TabletStage"
@@ -138,6 +144,7 @@ Rectangle {
138144 property Item sideStage: tabletStage ? findChild(tabletStage, "sideStage") : null
139145
140146 function init() {
147+ stageSaver.clear();
141148 tabletStageLoader.active = true;
142149 tryCompare(tabletStageLoader, "status", Loader.Ready);
143150
@@ -510,7 +517,35 @@ Rectangle {
510517 tryCompare(stagesPriv, "sideStageAppId", data.sideStageAppId);
511518 }
512519
513− function test_loadSideStageByDragginFromMainStage() {
520+ function test_applicationSavesLastStage_data() {
521+ return [
522+ { tag: "MainStage", stage: ApplicationInfoInterface.MainStage},
523+ { tag: "SideStage", stage: ApplicationInfoInterface.SideStage},
524+ ];
525+ }
526+
527+ function test_applicationSavesLastStage(data) {
528+ WindowStateStorage.saveStage(webbrowserCheckBox.appId, data.stage);
529+ stageSaver.clear();
530+
531+ var stagesPriv = findInvisibleChild(tabletStage, "stagesPriv");
532+ verify(stagesPriv);
533+
534+ tryCompare(stagesPriv, "mainStageAppId", "unity8-dash");
535+ tryCompare(stagesPriv, "sideStageAppId", "");
536+
537+ var webbrowserSurfaceId = topSurfaceList.nextId;
538+ webbrowserCheckBox.checked = true;
539+ waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
540+
541+ webbrowserCheckBox.checked = false;
542+
543+ tryCompare(stageSaver, "count", 1);
544+ compare(stageSaver.signalArguments[0][0], "webbrowser-app")
545+ compare(stageSaver.signalArguments[0][1], data.stage)
546+ }
547+
548+ function test_loadSideStageByDraggingFromMainStage() {
514549 sideStage.showNow();
515550 var webbrowserSurfaceId = topSurfaceList.nextId;
516551 webbrowserCheckBox.checked = true;
@@ -538,7 +573,7 @@ Rectangle {
538573 tryCompare(appDelegate, "stage", ApplicationInfoInterface.SideStage);
539574 }
540575
541− function test_unloadSideStageByDragginFromStageStage() {
576+ function test_unloadSideStageByDraggingFromStageStage() {
542577 sideStage.showNow();
543578 WindowStateStorage.saveStage(webbrowserCheckBox.appId, ApplicationInfoInterface.SideStage)
544579 var webbrowserSurfaceId = topSurfaceList.nextId;
@@ -690,5 +725,34 @@ Rectangle {
690725 // only unity8-dash surface is left
691726 compare(topSurfaceList.count, 1);
692727 }
728+
729+ function test_draggingSurfaceKeepsSurfaceFocus() {
730+ var webbrowserSurfaceId = topSurfaceList.nextId;
731+ webbrowserCheckBox.checked = true;
732+ waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
733+
734+ var appDelegate = findChild(tabletStage, "spreadDelegate_" + webbrowserSurfaceId);
735+ verify(appDelegate);
736+ compare(appDelegate.stage, ApplicationInfoInterface.MainStage);
737+
738+ tryCompare(appDelegate.surface, "activeFocus", true);
739+
740+ var pos = tabletStage.width - sideStage.width - (tabletStage.width - sideStage.width) / 2;
741+ var end_pos = tabletStage.width - sideStage.width / 2;
742+
743+ multiTouchDragUntil([0,1,2],
744+ tabletStage,
745+ pos,
746+ tabletStage.height / 2,
747+ units.gu(3),
748+ 0,
749+ function() {
750+ pos += units.gu(3);
751+ return sideStage.shown && !sideStage.showAnimation.running &&
752+ pos >= end_pos;
753+ });
754+
755+ tryCompare(appDelegate.surface, "activeFocus", true);
756+ }
693757 }
694758}
tests/qmltests/Stages/tst_WindowResizeArea.qml+16−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2014-2015 Canonical Ltd.
2+ * Copyright 2014-2016 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
@@ -24,6 +24,7 @@ import "../../../qml/Stages"
2424import Ubuntu.Components 1.3
2525import Ubuntu.Components.ListItems 1.3 as ListItem
2626import Unity.Application 0.1
27+import Utils 0.1
2728
2829Item {
2930 id: root
@@ -55,10 +56,20 @@ Item {
5556 property real maximumHeight: 0
5657 property real widthIncrement: 0
5758 property real heightIncrement: 0
58− state: "normal"
59+
60+ property int windowState: WindowStateStorage.WindowStateNormal
61+
62+ states: [
63+ State { name: "normal"; when: windowState == WindowStateStorage.WindowStateNormal },
64+ State { name: "maximized"; when: windowState == WindowStateStorage.WindowStateMaximized }
65+ ]
5966
6067 function maximize() {
61− state = "maximized"
68+ windowState = WindowStateStorage.WindowStateMaximized
69+ }
70+
71+ function restoreFromMaximized() {
72+ windowState = WindowStateStorage.WindowStateNormal
6273 }
6374
6475 WindowResizeArea {
@@ -346,7 +357,7 @@ Item {
346357 fakeWindow.y = initialWindowY + moveDelta
347358
348359 // Now change the state to maximized. The window should not keep updating the stored values
349− fakeWindow.state = "maximized"
360+ fakeWindow.maximize()
350361 fakeWindow.x = 31415 // 0 is too risky to pass the test even when broken
351362 fakeWindow.y = 31415
352363
@@ -363,7 +374,7 @@ Item {
363374 tryCompare(fakeWindow, "state", "maximized")
364375
365376 // clean up
366− fakeWindow.state = "normal"
377+ fakeWindow.restoreFromMaximized()
367378 }
368379
369380 function test_restoreMovesIntoBounds_data() {
tests/qmltests/Tutorial/tst_Tutorial.qml+2−2
@@ -261,7 +261,7 @@ Rectangle {
261261 shellLoader.active = true;
262262
263263 tryCompare(shellLoader, "status", Loader.Ready);
264− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
264+ removeTimeConstraintsFromSwipeAreas(shellLoader.item);
265265 }
266266
267267 function prepareShell() {
@@ -465,7 +465,7 @@ Rectangle {
465465 // compare opacity with a bound rather than hard 0.6 because progress doesn't
466466 // always match the drag perfectly (takes a moment for drag to kick in)
467467 tryCompareFunction(function() {
468− return tutorialTop.opacity >= 0.6 && tutorialTop.opacity < 0.7;
468+ return tutorialTop.opacity >= 0.5 && tutorialTop.opacity < 0.7;
469469 }, true);
470470 touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, false, true);
471471
tests/qmltests/Wizard/tst_Wizard.qml+7−15
@@ -21,7 +21,7 @@ import MeeGo.QOfono 0.2
2121import QMenuModel 0.1
2222import Ubuntu.Components 1.3
2323import Ubuntu.SystemSettings.SecurityPrivacy 1.0
24−import Ubuntu.SystemSettings.TimeDate 1.0
24+import Ubuntu.SystemSettings.TimeDate 1.1
2525import Unity.Test 0.1 as UT
2626import Wizard 0.1
2727import "../../../qml/Wizard"
@@ -144,7 +144,9 @@ Item {
144144 var pages = findChild(wizard, "wizardPages");
145145 var stack = findChild(pages, "pageStack");
146146 // don't simply call tryCompare here, because stack.currentPage will be swapped out itself
147− tryCompareFunction(function() { return stack.currentPage.objectName; }, name);
147+ tryCompareFunction(function() { return stack.currentPage.objectName; }, name, 15000);
148+ var contentAnimation = findInvisibleChild(stack.currentPage, "contentAnimation");
149+ tryCompareFunction(function() { return contentAnimation.running; }, false);
148150 tryCompare(stack.currentPage, "opacity", 1.0);
149151 tryCompare(stack.currentPage, "enabled", true);
150152 tryCompare(stack.currentPage, "skipValid", true);
@@ -153,17 +155,6 @@ Item {
153155 return stack.currentPage;
154156 }
155157
156− function verifyPageIsBlocked(name) {
157− var pages = findChild(wizard, "wizardPages");
158− var stack = findChild(pages, "pageStack");
159− // don't simply call tryCompare here, because stack.currentPage will be swapped out itself
160− tryCompareFunction(function() { return stack.currentPage.objectName; }, name);
161− tryCompare(stack.currentPage, "enabled", false);
162− tryCompare(stack.currentPage, "skipValid", false);
163− waitForRendering(stack.currentPage);
164− return stack.currentPage;
165− }
166−
167158 function goToPage(name, skipSim, skipLocation, skipReporting) {
168159 if (skipSim === undefined) {
169160 skipSim = false;
@@ -464,7 +455,7 @@ Item {
464455 var tzFilter = findChild(page, "tzFilter");
465456 verify(tzFilter);
466457 tap(tzFilter);
467− typeString("London");
458+ typeString("Belfa");
468459
469460 var tzList = findChild(page, "tzList");
470461 verify(tzList);
@@ -478,7 +469,8 @@ Item {
478469 // go next and verify the (mock) signal got fired
479470 tap(findChild(page, "forwardButton"));
480471 tryCompare(timezoneSpy, "count", 1);
481− tryCompare(page.tdModule, "timeZone", timezoneSpy.signalArguments[0][0]);
472+ compare(timezoneSpy.signalArguments[0][0], "Europe/London");
473+ compare(timezoneSpy.signalArguments[0][1], "Belfast");
482474 }
483475
484476 function test_accountPage() {
tests/qmltests/tst_OrientedShell.qml+1−1
@@ -1551,7 +1551,7 @@ Rectangle {
15511551 orientedShellLoader.active = true;
15521552
15531553 tryCompare(orientedShellLoader, "status", Loader.Ready);
1554− removeTimeConstraintsFromDirectionalDragAreas(orientedShellLoader.item);
1554+ removeTimeConstraintsFromSwipeAreas(orientedShellLoader.item);
15551555
15561556 shell = findChild(orientedShell, "shell");
15571557
tests/qmltests/tst_Shell.qml+32−5
@@ -436,7 +436,7 @@ Rectangle {
436436 shellLoader.state = formFactor;
437437 shellLoader.active = true;
438438 tryCompare(shellLoader, "status", Loader.Ready);
439− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item);
439+ removeTimeConstraintsFromSwipeAreas(shellLoader.item);
440440 tryCompare(shell, "enabled", true); // enabled by greeter when ready
441441
442442 sessionSpy.target = findChild(shell, "greeter")
@@ -749,8 +749,9 @@ Rectangle {
749749 // greeter unloads its internal components when hidden
750750 // and reloads them when shown. Thus we have to do this
751751 // again before interacting with it otherwise any
752− // DirectionalDragAreas in there won't be easily fooled by
752+ // SwipeAreas in there won't be easily fooled by
753753 // fake swipes.
754+ removeTimeConstraintsFromSwipeAreas(greeter);
754755 swipeAwayGreeter();
755756
756757 compare(mainApp.requestedState, ApplicationInfoInterface.RequestedRunning);
@@ -761,7 +762,7 @@ Rectangle {
761762 var greeter = findChild(shell, "greeter");
762763 tryCompare(greeter, "fullyShown", true);
763764 waitForGreeterToStabilize();
764− removeTimeConstraintsFromDirectionalDragAreas(greeter);
765+ removeTimeConstraintsFromSwipeAreas(greeter);
765766
766767 var touchX = shell.width - (shell.edgeSize / 2);
767768 var touchY = shell.height / 2;
@@ -1069,9 +1070,9 @@ Rectangle {
10691070 // greeter unloads its internal components when hidden
10701071 // and reloads them when shown. Thus we have to do this
10711072 // again before interacting with it otherwise any
1072− // DirectionalDragAreas in there won't be easily fooled by
1073+ // SwipeAreas in there won't be easily fooled by
10731074 // fake swipes.
1074− removeTimeConstraintsFromDirectionalDragAreas(greeter);
1075+ removeTimeConstraintsFromSwipeAreas(greeter);
10751076 }
10761077
10771078 function revealLauncherByEdgePushWithMouse() {
@@ -2203,6 +2204,7 @@ Rectangle {
22032204 compare(ApplicationManager.focusedApplicationId, "unity8-dash");
22042205
22052206 // Use Super + Tab Tab to cycle to the first entry in the launcher
2207+ wait(1000);
22062208 keyPress(Qt.Key_Super_L, Qt.MetaModifier);
22072209 keyClick(Qt.Key_Tab);
22082210 tryCompare(launcher, "state", "visible");
@@ -2427,5 +2429,30 @@ Rectangle {
24272429 ApplicationManager.requestFocusApplication("calendar-app");
24282430 tryCompare(app2Surface, "keymap", "fr");
24292431 }
2432+
2433+ function test_dragPanelToRestoreMaximizedWindow() {
2434+ loadShell("desktop");
2435+ shell.usageScenario = "desktop";
2436+ waitForRendering(shell);
2437+ var panel = findChild(shell, "windowControlArea");
2438+ verify(panel);
2439+
2440+ var appSurfaceId = topLevelSurfaceList.nextId;
2441+ var app = ApplicationManager.startApplication("dialer-app")
2442+ waitUntilAppWindowIsFullyLoaded(appSurfaceId);
2443+
2444+ // start dialer, maximize it
2445+ var appContainer = findChild(shell, "appContainer");
2446+ var appDelegate = findChild(appContainer, "appDelegate_" + appSurfaceId);
2447+ verify(appDelegate);
2448+ appDelegate.maximize();
2449+ tryCompare(appDelegate, "state", "maximized");
2450+
2451+ mousePress(panel);
2452+ mouseMove(shell, shell.width/2, shell.height/2);
2453+ mouseRelease(shell);
2454+
2455+ tryCompare(appDelegate, "state", "normal");
2456+ }
24302457 }
24312458}
tests/qmltests/tst_ShellWithPin.qml+1−1
@@ -194,7 +194,7 @@ Item {
194194 shellLoader.active = true
195195
196196 tryCompare(shellLoader, "status", Loader.Ready)
197− removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item)
197+ removeTimeConstraintsFromSwipeAreas(shellLoader.item)
198198 }
199199
200200 function swipeAwayGreeter(waitForCoverPage) {
tests/uqmlscene/main.cpp−1
@@ -159,7 +159,6 @@ struct Options
159159 bool maximized;
160160 bool fullscreen;
161161 bool transparent;
162− bool scenegraphOnGraphicsview;
163162 bool clip;
164163 bool versionDetection;
165164 bool quitImmediately;
tests/utils/modules/Unity/Test/CMakeLists.txt+4−2
@@ -2,10 +2,12 @@ include(QmlPlugins)
22
33add_definitions(-DQT_NO_KEYWORDS)
44
5+pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures)
6+
57include_directories(
68 ${Qt5Gui_PRIVATE_INCLUDE_DIRS}
79 ${Qt5Quick_PRIVATE_INCLUDE_DIRS}
8− ${CMAKE_SOURCE_DIR}/libs/UbuntuGestures
10+ ${UBUNTUGESTURES_INCLUDE_DIRS}
911 ${CMAKE_SOURCE_DIR}/src
1012)
1113
@@ -20,7 +22,7 @@ if (ENABLE_TOUCH_EMULATION)
2022endif()
2123
2224add_library(UnityTestQml MODULE ${UnityTestQML_SOURCES})
23−target_link_libraries(UnityTestQml UbuntuGestures)
25+target_link_libraries(UnityTestQml ${UBUNTUGESTURES_LIBRARIES})
2426
2527if (ENABLE_TOUCH_EMULATION)
2628 target_link_libraries(UnityTestQml ${MOUSETOUCHADAPTOR_LIBS_LDFLAGS})
tests/utils/modules/Unity/Test/UnityTestCase.qml+31−12
@@ -18,6 +18,7 @@ import QtQuick 2.4
1818import QtTest 1.0
1919import Unity.Application 0.1
2020import Ubuntu.Components 1.3
21+import Ubuntu.Test 1.0 as UbuntuTest
2122import Unity.Test 0.1 as UT
2223import Utils 0.1
2324
@@ -175,11 +176,11 @@ TestCase {
175176
176177
177178 // Find an object with the given name in the children tree of "obj"
178− function findChild(obj, objectName) {
179+ function findChild(obj, objectName, timeout) {
179180 if (!obj)
180181 qtest_fail("no obj given", 1);
181182
182− return findChildIn(obj, "children", objectName);
183+ return findChildInWithTimeout(obj, "children", objectName, timeout);
183184 }
184185
185186 // Find an object with the given name in the children tree of "obj"
@@ -187,11 +188,30 @@ TestCase {
187188 // Note: you should use findChild if you're not sure you need this
188189 // as this tree is much bigger and might contain stuff that goes
189190 // away randomly.
190− function findInvisibleChild(obj, objectName) {
191+ function findInvisibleChild(obj, objectName, timeout) {
191192 if (!obj)
192193 qtest_fail("no obj given", 1);
193194
194− return findChildIn(obj, "data", objectName);
195+ return findChildInWithTimeout(obj, "data", objectName, timeout);
196+ }
197+
198+ // Find a child in the named property with timeout
199+ function findChildInWithTimeout(obj, prop, objectName, timeout) {
200+ if (!obj)
201+ qtest_fail("no obj given", 1);
202+
203+ var timeSpent = 0
204+ if (timeout === undefined)
205+ timeout = 5000;
206+
207+ var child = findChildIn(obj, prop, objectName);
208+
209+ while (timeSpent < timeout && !child) {
210+ wait(50)
211+ timeSpent += 50
212+ child = findChildIn(obj, prop, objectName);
213+ }
214+ return child;
195215 }
196216
197217 // Find a child in the named property
@@ -572,28 +592,27 @@ TestCase {
572592 while (rootItem.parent != undefined) {
573593 rootItem = rootItem.parent;
574594 }
575− removeTimeConstraintsFromDirectionalDragAreas(rootItem);
595+ removeTimeConstraintsFromSwipeAreas(rootItem);
576596 }
577597
578598 /*
579599 In qmltests, sequences of touch events are sent all at once, unlike in "real life".
580600 Also qmltests might run really slowly, e.g. when run from inside virtual machines.
581601 Thus to remove a variable that qmltests cannot really control, namely time, this
582− function removes all constraints from DirectionalDragAreas that are sensible to
602+ function removes all constraints from SwipeAreas that are sensible to
583603 elapsed time.
584604
585− This effectively makes DirectionalDragAreas easier to fool.
605+ This effectively makes SwipeAreas easier to fool.
586606 */
587− function removeTimeConstraintsFromDirectionalDragAreas(item) {
607+ function removeTimeConstraintsFromSwipeAreas(item) {
588608 if (!item)
589609 qtest_fail("no item given", 1);
590610
591− // use duck-typing to identify a DirectionalDragArea
592− if (item.removeTimeConstraints != undefined) {
593− item.removeTimeConstraints();
611+ if (UT.Util.isInstanceOf(item, "UCSwipeArea")) {
612+ UbuntuTest.TestExtras.removeTimeConstraintsFromSwipeArea(item);
594613 } else {
595614 for (var i in item.children) {
596− removeTimeConstraintsFromDirectionalDragAreas(item.children[i]);
615+ removeTimeConstraintsFromSwipeAreas(item.children[i]);
597616 }
598617 }
599618 }
tests/utils/modules/Unity/Test/testutil.cpp+2−2
@@ -22,8 +22,8 @@
2222#include <QQuickView>
2323
2424// UbuntuGestures lib
25−#include <TouchRegistry.h>
26−#include <Timer.h>
25+#include <TouchRegistry>
26+#include <Timer>
2727
2828using namespace UbuntuGestures;
2929
tools/CMakeLists.txt+1−1
@@ -1,7 +1,7 @@
11add_executable(${SCOPE_TOOL}
22 scopetool.cpp
33 registry-tracker.cpp
4− unix-signal-handler.cpp
4+ ../src/UnixSignalHandler.cpp
55 )
66
77qt5_use_modules(${SCOPE_TOOL} Qml Quick)
tools/scopetool.cpp+1−1
@@ -32,7 +32,7 @@
3232// local
3333#include <paths.h>
3434#include "registry-tracker.h"
35−#include "unix-signal-handler.h"
35+#include "../src/UnixSignalHandler.h"
3636
3737
3838int main(int argc, char *argv[])