on xenial help sign in
Merge
commit4f6e054839509225b7cd158b21ab380796bd9da6 authorAlbert Astals <albert.astals@canonical.com> dateTue 25 Mar 2014, 10:18 (13 years ago) parent864085505d4a33
220 files changed+2172−5974
data/unity8.conf+9 debian/changelog+114 debian/control+3−3 debian/rules−5 debian/scopes-recommends-generator−27 plugins/DashViews/listviewwithpageheader.cpp+46−12 plugins/Unity/Indicators/qml/MenuItemFactory.qml+7−1 po/am.po+2−2 po/ar.po+2−2 po/ast.po+2−2 po/az.po+2−2 po/bg.po+2−2 po/bs.po+2−2 po/ca.po+2−2 po/ckb.po+2−2 po/cs.po+2−2 po/da.po+2−2 po/de.po+2−2 po/el.po+2−2 po/en_AU.po+2−2 po/en_GB.po+2−2 po/eo.po+2−2 po/es.po+2−2 po/eu.po+32−30 po/fa.po+2−2 po/fi.po+2−2 po/fo.po+2−2 po/fr.po+2−2 po/gd.po+2−2 po/gl.po+2−2 po/he.po+2−2 po/hi.po+2−2 po/hr.po+2−2 po/hu.po+2−2 po/hy.po+2−2 po/id.po+2−2 po/is.po+2−2 po/it.po+2−2 po/ja.po+2−2 po/km.po+2−2 po/kn.po+2−2 po/ko.po+2−2 po/ky.po+2−2 po/lo.po+2−2 po/lt.po+2−2 po/lv.po+2−2 po/ml.po+2−2 po/mr.po+2−2 po/ms.po+2−2 po/my.po+2−2 po/nb.po+2−2 po/nl.po+2−2 po/pl.po+2−2 po/pt.po+2−2 po/pt_BR.po+2−2 po/ro.po+2−2 po/ru.po+2−2 po/shn.po+2−2 po/si.po+2−2 po/sl.po+2−2 po/sq.po+2−2 po/sr.po+2−2 po/sv.po+2−2 po/sw.po+2−2 po/ta.po+2−2 po/te.po+2−2 po/tr.po+2−2 po/ug.po+2−2 po/uk.po+2−2 po/vi.po+2−2 po/xh.po+2−2 po/zh_CN.po+2−2 po/zh_HK.po+2−2 po/zh_TW.po+2−2 qml/Components/ListItems/Header.qml+2−14 qml/Components/OpenEffect.qml−138 qml/Components/PageHeader.qml+27−2 qml/Components/RatingStars.qml−41 qml/Components/ResponsiveGridView.qml−1 qml/Components/SeeMore.qml+4−2 qml/Components/Stage.qml+17−9 qml/Components/Tile.qml−39 qml/Components/TileStyle.qml−81 qml/Components/VolumeControl.qml+6−2 qml/Components/graphics/headerback@27.png qml/Dash/Apps/AppPreview.qml−167 qml/Dash/Apps/DashPluginFilterGrid.qml−47 qml/Dash/Apps/FrequentlyUsedAppsModel.qml−110 qml/Dash/Apps/RunningApplicationTile.qml+2−3 qml/Dash/Card.qml+11−2 qml/Dash/DashCarousel.qml → qml/Dash/CardCarousel.qml+30−8 qml/Dash/CardFilterGrid.qml+76 qml/Dash/CardHeader.qml+32−60 qml/Dash/CardTool.qml+47−9 qml/Dash/Dash.qml+57−4 qml/Dash/DashApps.qml+4−19 qml/Dash/DashContent.qml+62−43 qml/Dash/DashContentOpenEffect.qml−57 qml/Dash/DashContentTabBarStyle.qml+3 qml/Dash/DashFilterGrid.qml−65 qml/Dash/DashHome.qml−39 qml/Dash/DashPreview.qml−208 qml/Dash/DashPreviewPlaceholder.qml−25 qml/Dash/DashRenderer.qml+5−3 qml/Dash/Generic/FlatTileStyle.qml−79 qml/Dash/Generic/GenericCarousel.qml−53 qml/Dash/Generic/GenericFilterGrid.qml−46 qml/Dash/Generic/GenericFilterGridPotrait.qml−28 qml/Dash/Generic/GenericPreview.qml−197 qml/Dash/Generic/WeatherFilterGrid.qml−47 qml/Dash/GenericScopeView.qml+66−125 qml/Dash/Movie/MoviePreview.qml−71 qml/Dash/Music/CarouselDelegateMusic.qml−42 qml/Dash/Music/MusicCarousel.qml−34 qml/Dash/Music/MusicFilterGrid.qml−48 qml/Dash/Music/MusicPreview.qml−203 qml/Dash/Music/MusicTileStyle.qml−102 qml/Dash/PreviewDelegateMapper.qml−38 qml/Dash/PreviewListView.qml+52−133 qml/Dash/Previews/Header.qml−109 qml/Dash/Previews/Preview.qml+17−23 qml/Dash/Previews/PreviewActions.qml+1−1 qml/Dash/Previews/PreviewAudioPlayback.qml+4−3 qml/Dash/Previews/PreviewHeader.qml+5−1 qml/Dash/Previews/PreviewImageGallery.qml+19 qml/Dash/Previews/PreviewRatingInput.qml+1−1 qml/Dash/Previews/PreviewTextSummary.qml+6−3 qml/Dash/Previews/PreviewWidgetFactory.qml+1−1 qml/Dash/Previews/Reviews.qml−194 qml/Dash/ScopeDelegateMapper.qml+1−3 qml/Dash/ScopeItem.qml+94 qml/Dash/SearchableResultModel.qml−44 qml/Dash/Video/CarouselDelegateVideo.qml−42 qml/Dash/Video/VideoCarousel.qml−34 qml/Dash/Video/VideoFilterGrid.qml−47 qml/Dash/Video/VideoTileStyle.qml−87 qml/Dash/Video/graphics/icon_button_amazon@20.png qml/Dash/Video/graphics/icon_button_u1@20.png qml/Dash/Video/graphics/movie_icon_holder@27.png qml/Dash/graphics/dash_divider_top_darkgrad@27.png qml/Dash/graphics/dash_divider_top_lightgrad@27.png qml/Dash/graphics/header_handlearrow2@20.png qml/Dash/graphics/header_handlearrow2@27.png qml/Dash/graphics/header_handlearrow@20.png qml/Dash/graphics/header_handlearrow@27.png qml/Dash/graphics/paper_landscape@27.png qml/Dash/graphics/paper_portrait@27.png qml/Dash/graphics/tabbarchevron@27.png qml/Launcher/Launcher.qml−1 qml/Launcher/LauncherPanel.qml−1 qml/Panel/IndicatorRow.qml+1−1 qml/ScopeTool.qml+9−1 qml/Shell.qml+11−33 tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+5−40 tests/autopilot/unity8/shell/emulators/dash.py+23−52 tests/autopilot/unity8/shell/emulators/main_window.py−4 tests/autopilot/unity8/shell/tests/__init__.py+1−1 tests/autopilot/unity8/shell/tests/test_emulators.py+26−52 tests/autopilot/unity8/shell/tests/test_greeter.py−38 tests/autopilot/unity8/shell/tests/test_notifications.py+1−1 tests/mocks/Unity/CMakeLists.txt+4−4 tests/mocks/Unity/categoryresults.cpp−121 tests/mocks/Unity/categoryresults.h−68 tests/mocks/Unity/fake_applications_scope.cpp−76 tests/mocks/Unity/fake_applications_scope.h−33 tests/mocks/Unity/fake_categories.cpp+109−194 tests/mocks/Unity/fake_categories.h+25−29 tests/mocks/Unity/fake_preview.cpp−73 tests/mocks/Unity/fake_preview.h−65 tests/mocks/Unity/fake_previewmodel.cpp+86 tests/mocks/Unity/fake_previewmodel.h+67 tests/mocks/Unity/fake_previewstack.cpp+76 tests/mocks/Unity/fake_previewstack.h+61 tests/mocks/Unity/scopes-ng/fake_preview_model.cpp → tests/mocks/Unity/fake_previewwidgetmodel.cpp+6−16 tests/mocks/Unity/scopes-ng/fake_preview_model.h → tests/mocks/Unity/fake_previewwidgetmodel.h+6−18 tests/mocks/Unity/fake_resultsmodel.cpp+117 tests/mocks/Unity/fake_resultsmodel.h+80 tests/mocks/Unity/fake_scope.cpp+18−118 tests/mocks/Unity/fake_scope.h+17−18 tests/mocks/Unity/fake_scopes.cpp+1−5 tests/mocks/Unity/fake_unity_plugin.cpp+10−13 tests/plugins/DashViews/listviewwithpageheadertest.cpp+24−6 tests/plugins/DashViews/listviewwithpageheadertestsection.cpp−3 tests/plugins/DashViews/organicgridtest.cpp+2−1 tests/plugins/DashViews/verticaljournaltest.cpp+2−1 tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+8 tests/qmltests/CMakeLists.txt−10 tests/qmltests/Components/tst_DragHandle.cpp−1 tests/qmltests/Components/tst_LazyImage.qml+1−1 tests/qmltests/Components/tst_OpenEffect.qml−71 tests/qmltests/Components/tst_PageHeaderLabel.qml+1−1 tests/qmltests/Components/tst_RatingStars.qml−62 tests/qmltests/Components/tst_Tile.qml−71 tests/qmltests/Dash/Apps/tst_AppPreview.qml−276 tests/qmltests/Dash/Movie/tst_MoviePreview.qml−86 tests/qmltests/Dash/Music/tst_MusicPreview.qml−174 tests/qmltests/Dash/Previews/tst_Preview.qml+4−18 tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml+1−1 tests/qmltests/Dash/Previews/tst_PreviewVideoPlayback.qml−6 tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+3−4 tests/qmltests/Dash/qml/FakeScopeView.qml+1−1 tests/qmltests/Dash/qml/fake_scopeView1.qml+1−1 tests/qmltests/Dash/qml/fake_scopeView2.qml+1−1 tests/qmltests/Dash/qml/fake_scopeView3.qml+1−1 tests/qmltests/Dash/tst_Card.qml+49 tests/qmltests/Dash/tst_CardHeader.qml+1−28 tests/qmltests/Dash/tst_CardTool.qml+21−1 tests/qmltests/Dash/tst_Dash.qml+14−6 tests/qmltests/Dash/tst_DashContent.qml+117−35 tests/qmltests/Dash/tst_DashPreview.qml−202 tests/qmltests/Dash/tst_FilterGrids.qml−143 tests/qmltests/Dash/tst_GenericPreview.qml−125 tests/qmltests/Dash/tst_GenericScopeView.qml+25−247 tests/qmltests/Launcher/tst_Launcher.qml+6−4 tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+47−6 tests/qmltests/tst_Shell.qml+24−27 tests/utils/modules/Unity/Test/UnityTestCase.qml+10−16 tools/registry-tracker.cpp+19−4 tools/registry-tracker.h+7−2 tools/scopetool.cpp+27−8
data/unity8.conf+9
@@ -1,6 +1,8 @@
11description "Unity Shell v8"
22author "Ricardo Mendoza <ricmm@ubuntu.com>"
33
4+emits scope-ui-starting
5+
46start on ((xsession SESSION=ubuntu-touch) or (xsession SESSION=ubuntu-touch-surfaceflinger)) and started dbus
57stop on desktop-end
68
@@ -29,10 +31,17 @@ pre-start script
2931 gdbus call --session --dest org.freedesktop.DBus --object-path /org/freedesktop/DBus --method org.freedesktop.DBus.UpdateActivationEnvironment "@a{ss} {'MIR_SOCKET': '$MIR_SERVER_FILE'}"
3032 fi
3133
34+ if [ -z "$UNITY_SCOPES_LIST" ]; then
35+ # FIXME: remove once we have this in dconf
36+ initctl set-env UNITY_SCOPES_LIST="scopes;clickscope;musicaggregator;videoaggregator"
37+ fi
38+
3239 # Remove the socket if still there
3340 if [ -S "$MIR_SERVER_FILE" ]; then
3441 rm "$MIR_SERVER_FILE"
3542 fi
43+
44+ initctl emit scope-ui-starting
3645end script
3746
3847exec ${BINARY:-unity8} $ARGS
debian/changelog+114
@@ -1,3 +1,117 @@
1+unity8 (7.84+14.04.20140324.4-0ubuntu1) trusty; urgency=low
2+
3+ [ Michal Hruby ]
4+ * Change and extend the way non-installed scopes are started with the
5+ scope-tool.
6+ * Switch to new scope backend and apply required visual adaptations.
7+ (LP: #1294294)
8+
9+ [ Gerry Boland ]
10+ * Switch to new scope backend and apply required visual adaptations.
11+ (LP: #1294294)
12+
13+ [ Michał Sawicz ]
14+ * Fix rating input action to always be "rated", not dynamic. Based on
15+ http://developer.ubuntu.com/api/devel/ubuntu-14.04/cplusplus/unity-
16+ scopes/previewwidgets.html#rating-input
17+ * Switch to new scope backend and apply required visual adaptations.
18+ (LP: #1294294)
19+
20+ [ Kevin Gunn ]
21+ * Switch to new scope backend and apply required visual adaptations.
22+ (LP: #1294294)
23+
24+ [ Albert Astals ]
25+ * Switch to new scope backend and apply required visual adaptations.
26+ (LP: #1294294)
27+ * LVWPH: cull lost items lost items will be released on the next
28+ updatePolish cycle but meanwhile don't let them be visible
29+
30+ [ Daniel d'Andrada ]
31+ * Switch to new scope backend and apply required visual adaptations.
32+ (LP: #1294294)
33+
34+ [ Michał Karnicki ]
35+ * Switch to new scope backend and apply required visual adaptations.
36+ (LP: #1294294)
37+
38+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 24 Mar 2014 16:10:24 +0000
39+
40+unity8 (7.84+14.04.20140319.1-0ubuntu1) trusty; urgency=low
41+
42+ [ Michał Sawicz ]
43+ * Work around bug #1293478 - make sure to send ints, not doubles for
44+ volume control. (LP: #1293478)
45+
46+ [ Nick Dedekind ]
47+ * Fixed binding being cleared when manually changing slider value
48+ (lp#1283191). (LP: #1283191)
49+
50+ [ Albert Astals ]
51+ * Fix indicators highlight position on 5.2 We need to take into
52+ account the list originX if we're using the list delegates x outside
53+ the list itself
54+ * LVWPH: Make sure m_firstVisibleIndex is correctly set on
55+ removeNonVisibleItems
56+
57+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 19 Mar 2014 16:40:20 +0000
58+
59+unity8 (7.84+14.04.20140317.2-0ubuntu1) trusty; urgency=low
60+
61+ [ CI bot ]
62+ * Resync trunk
63+
64+ [ Michał Sawicz ]
65+ * Revert disable-hud, we weren't ready to land it yet.
66+
67+ [ Mirco Müller ]
68+ * The snap-decision AP-test for "incoming call"-case used the wrong
69+ objectName "notification0". It has to be "notification1".
70+
71+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 17 Mar 2014 15:54:39 +0000
72+
73+unity8 (7.84+14.04.20140314-0ubuntu1) trusty; urgency=low
74+
75+ [ Michał Sawicz ]
76+ * Fix tests under Qt 5.2.
77+ * CardHeader improvements depending on background. Also drop prices,
78+ they need to be reworked into attributes.
79+ * Bring Cards closer to design
80+ * Add back the workaround for not being able scroll the image gallery
81+ Taken from AppPreview.qml (LP: #1281709)
82+ * Only allow searching when preview isn't open. (LP: #1282475)
83+ * Adds carousel dynamic switch
84+
85+ [ Leo Arias ]
86+ * Update the url dispatcher test to use the fake app fixture from the
87+ toolkit.
88+
89+ [ Albert Astals ]
90+ * Fix tests under Qt 5.2.
91+ * Workaround compiz/unity7 behaviour change/bug
92+
93+ [ Michael Zanetti ]
94+ * Fix tests under Qt 5.2.
95+ * Disable HUD from the bottom edge.
96+
97+ [ Andrea Cimitan ]
98+ * Adds carousel dynamic switch
99+
100+ [ CI bot ]
101+ * Resync trunk
102+
103+ [ Michał Karnicki ]
104+ * CardHeader improvements depending on background. Also drop prices,
105+ they need to be reworked into attributes.
106+
107+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 14 Mar 2014 15:46:10 +0000
108+
109+unity8 (7.84+14.04.20140307-0ubuntu1) trusty; urgency=low
110+
111+ * New rebuild forced
112+
113+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 07 Mar 2014 10:54:33 +0000
114+
1115unity8 (7.84+14.04.20140306-0ubuntu1) trusty; urgency=low
2116
3117 [ Bill Filler ]
debian/control+3−3
@@ -13,14 +13,12 @@ Build-Depends: cmake,
1313 libgles2-mesa-dev[armhf],
1414 libgsettings-qt-dev,
1515 libhud-client2-dev,
16− libjson-perl,
1716 libnih-dbus-dev,
1817 libnih-dev,
1918 libpulse-dev,
2019 libqmenumodel-dev (>= 0.2.7),
2120 libunity-api-dev (>= 7.80.4),
2221 libunity-mir-dev,
23− libunity-scopes-json-def-phone,
2422 libupstart-dev,
2523 libusermetricsoutput1-dev,
2624 libxcb1-dev,
@@ -96,7 +94,9 @@ Depends: gsettings-desktop-schemas,
9694 libcap2-bin,
9795 ${misc:Depends},
9896 ${shlibs:Depends},
99−Recommends: ${unity-default-masterscopes},
97+Recommends: unity-scope-click,
98+ unity-scope-mediascanner2,
99+ unity-scope-scopes,
100100Breaks: indicator-network (<< 0.5.1)
101101Replaces: ubuntu-touch-session (<< 0.82~)
102102Description: Unity 8 shell
debian/rules−5
@@ -6,8 +6,6 @@
66export DPKG_GENSYMBOLS_CHECK_LEVEL=4
77export NO_PNG_PKG_MANGLE=1
88
9−SCOPES_RECOMMENDS := $(shell perl debian/scopes-recommends-generator /usr/share/unity/client-scopes.json)
10−
119.PHONY: build
1210build %:
1311 dh $@ --parallel --fail-missing --with python2,python3
@@ -41,6 +39,3 @@ override_dh_makeshlibs:
4139# libMockLightDM-qml.so links against liblightdm-qt5-2.so which doesn't exist
4240override_dh_shlibdeps:
4341 dh_shlibdeps -XlibMockLightDM-qml.so
44−
45−override_dh_gencontrol:
46− dh_gencontrol -- -Vunity-default-masterscopes="$(SCOPES_RECOMMENDS)"
debian/scopes-recommends-generatordeleted−27
@@ -1,27 +0,0 @@
1−#!/usr/bin/perl -w
2−
3−use strict;
4−binmode STDOUT, ":utf8";
5−use utf8;
6−
7−use JSON;
8−
9−my $json;
10−{
11− local $/; #Enable 'slurp' mode
12− open my $fh, "<", $ARGV[0];
13− $json = <$fh>;
14− close $fh;
15−}
16−# get it to a scalar
17−my $j = "[" . $json . "]";
18−
19−my $decoded_json = decode_json( $j );
20−
21−my $recommends_list = "";
22−for my $record ( @$decoded_json ) {
23− foreach my $key ( keys(%$record) ) {
24− $recommends_list = $recommends_list . $key . ", ";
25− }
26−}
27−print $recommends_list;
plugins/DashViews/listviewwithpageheader.cpp+46−12
@@ -91,6 +91,7 @@
9191
9292#include "listviewwithpageheader.h"
9393
94+#include <QCoreApplication>
9495#include <QDebug>
9596#include <qqmlinfo.h>
9697#include <qqmlengine.h>
@@ -366,6 +367,18 @@ void ListViewWithPageHeader::positionAtBeginning()
366367 m_previousContentY = m_visibleItems.first()->y() - headerHeight;
367368 }
368369 setContentY(m_visibleItems.first()->y() + m_clipItem->y() - headerHeight);
370+ if (m_headerItem) {
371+ // TODO This should not be needed and the code that adjust the m_headerItem position
372+ // in viewportMoved() should be enough but in some cases we have not found a way to reproduce
373+ // yet the code of viewportMoved() fails so here we make sure that at least if we are calling
374+ // positionAtBeginning the header item will be correctly positioned
375+ m_headerItem->setY(-m_minYExtent);
376+ }
377+}
378+
379+static inline bool uFuzzyCompare(qreal r1, qreal r2)
380+{
381+ return qFuzzyCompare(r1, r2) || (qFuzzyIsNull(r1) && qFuzzyIsNull(r2));
369382}
370383
371384void ListViewWithPageHeader::showHeader()
@@ -373,8 +386,8 @@ void ListViewWithPageHeader::showHeader()
373386 if (!m_headerItem)
374387 return;
375388
376− auto to = qMax(-minYExtent(), contentY() - m_headerItem->height() + m_headerItemShownHeight);
377− if (to != contentY()) {
389+ const auto to = qMax(-minYExtent(), contentY() - m_headerItem->height() + m_headerItemShownHeight);
390+ if (!uFuzzyCompare(to, contentY())) {
378391 const bool headerShownByItsOwn = contentY() < m_headerItem->y() + m_headerItem->height();
379392 if (headerShownByItsOwn && m_headerItemShownHeight == 0) {
380393 // We are not clipping since we are just at the top of the viewport
@@ -491,11 +504,7 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
491504 const bool showHeaderAnimationRunning = m_contentYAnimation->isRunning() && contentYAnimationType == ContentYAnimationShowHeader;
492505 if (m_headerItem) {
493506 const auto oldHeaderItemShownHeight = m_headerItemShownHeight;
494− if (contentY() < -m_minYExtent) {
495− // Stick the header item to the top when dragging down
496− m_headerItem->setY(contentY());
497− m_headerItem->setHeight(m_headerItem->implicitHeight() + (-m_minYExtent - contentY()));
498− } else {
507+ if (uFuzzyCompare(contentY(), -m_minYExtent) || contentY() > -m_minYExtent) {
499508 m_headerItem->setHeight(m_headerItem->implicitHeight());
500509 // We are going down (but it's not because of the rebound at the end)
501510 // (but the header was not shown by it's own position)
@@ -509,21 +518,32 @@ void ListViewWithPageHeader::viewportMoved(Qt::Orientations orient)
509518 m_headerItemShownHeight = 0;
510519 m_headerItem->setY(-m_minYExtent);
511520 } else if ((scrolledUp && notRebounding && notShownByItsOwn && !maximizeVisibleAreaRunning) || (m_headerItemShownHeight > 0) || m_inContentHeightKeepHeaderShown) {
512− if (maximizeVisibleAreaRunning && diff > 0) // If we are maximizing and the header was shown, make sure we hide it
521+ if (maximizeVisibleAreaRunning && diff > 0) {
522+ // If we are maximizing and the header was shown, make sure we hide it
513523 m_headerItemShownHeight -= diff;
514− else
524+ } else {
515525 m_headerItemShownHeight += diff;
516− if (contentY() == -m_minYExtent) {
526+ }
527+ if (uFuzzyCompare(contentY(), -m_minYExtent)) {
517528 m_headerItemShownHeight = 0;
518529 } else {
519530 m_headerItemShownHeight = qBound(static_cast<qreal>(0.), m_headerItemShownHeight, m_headerItem->height());
520531 }
521532 if (m_headerItemShownHeight > 0) {
522− m_headerItem->setY(contentY() - m_headerItem->height() + m_headerItemShownHeight);
533+ if (uFuzzyCompare(m_headerItem->height(), m_headerItemShownHeight)) {
534+ m_headerItem->setY(contentY());
535+ m_headerItemShownHeight = m_headerItem->height();
536+ } else {
537+ m_headerItem->setY(contentY() - m_headerItem->height() + m_headerItemShownHeight);
538+ }
523539 } else {
524540 m_headerItem->setY(-m_minYExtent);
525541 }
526542 }
543+ } else {
544+ // Stick the header item to the top when dragging down
545+ m_headerItem->setY(contentY());
546+ m_headerItem->setHeight(m_headerItem->implicitHeight() + (-m_minYExtent - contentY()));
527547 }
528548 // We will be changing the clip item, need to accomadate for it
529549 // otherwise we move the firstItem down/up twice (unless the
@@ -759,6 +779,9 @@ bool ListViewWithPageHeader::removeNonVisibleItems(qreal bufferFrom, qreal buffe
759779 ++i;
760780 }
761781 }
782+ if (!foundVisible) {
783+ m_firstVisibleIndex = -1;
784+ }
762785 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
763786 adjustMinYExtent();
764787 }
@@ -824,6 +847,7 @@ ListViewWithPageHeader::ListItem *ListViewWithPageHeader::createItem(int modelIn
824847 }
825848 }
826849 if (lostItem) {
850+ listItem->setCulled(true);
827851 releaseItem(listItem);
828852 listItem = nullptr;
829853 } else {
@@ -1128,7 +1152,12 @@ void ListViewWithPageHeader::adjustMinYExtent()
11281152 nonCreatedHeight = m_firstVisibleIndex * visibleItemsHeight / visibleItems;
11291153// qDebug() << m_firstVisibleIndex << visibleItemsHeight << visibleItems << nonCreatedHeight;
11301154 }
1131− m_minYExtent = nonCreatedHeight - m_visibleItems.first()->y() - m_clipItem->y() + (m_headerItem ? m_headerItem->implicitHeight() : 0);
1155+ const qreal headerHeight = (m_headerItem ? m_headerItem->implicitHeight() : 0);
1156+ m_minYExtent = nonCreatedHeight - m_visibleItems.first()->y() - m_clipItem->y() + headerHeight;
1157+ if (m_minYExtent != 0 && qFuzzyIsNull(m_minYExtent)) {
1158+ m_minYExtent = 0;
1159+ m_visibleItems.first()->setY(nonCreatedHeight - m_clipItem->y() + headerHeight);
1160+ }
11321161 }
11331162}
11341163
@@ -1264,6 +1293,11 @@ void ListViewWithPageHeader::updatePolish()
12641293 refill();
12651294
12661295 if (m_contentHeightDirty) {
1296+ // We need to make sure all bindings have updated otherwise
1297+ // we may end up with bindings updating when we call setContentHeight
1298+ // and then everything gets out of sync, i.e. testHeaderPositionBug1240118
1299+ QCoreApplication::instance()->processEvents();
1300+
12671301 qreal contentHeight;
12681302 if (m_visibleItems.isEmpty()) {
12691303 contentHeight = m_headerItem ? m_headerItem->height() : 0;
plugins/Unity/Indicators/qml/MenuItemFactory.qml+7−1
@@ -77,6 +77,7 @@ Item {
7777 property var menuModel: menuFactory.menuModel
7878 property int menuIndex: -1
7979 property var extendedData: menuData && menuData.ext || undefined
80+ property var serverValue: getExtendedProperty(menuData, "actionState", undefined)
8081
8182 text: menuData && menuData.label || ""
8283 iconSource: menuData && menuData.icon || ""
@@ -91,7 +92,6 @@ Item {
9192 }
9293 return maximum;
9394 }
94− value: menuData && menuData.actionState || 0.0
9595 enabled: menuData && menuData.sensitive || false
9696
9797 onMenuModelChanged: {
@@ -100,6 +100,12 @@ Item {
100100 onMenuIndexChanged: {
101101 loadAttributes();
102102 }
103+ onServerValueChanged: {
104+ // value can be changed by slider, so a binding won't work.
105+ if (serverValue !== undefined) {
106+ value = serverValue;
107+ }
108+ }
103109 onUpdated: {
104110 menuModel.changeState(menuIndex, value);
105111 }
po/am.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ar.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n % 100 >= "
1818"3 && n % 100 <= 10 ? 3 : n % 100 >= 11 && n % 100 <= 99 ? 4 : 5;\n"
19−"X-Launchpad-Export-Date: 2014-02-22 07:40+0000\n"
20−"X-Generator: Launchpad (build 16926)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ast.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-03-02 05:30+0000\n"
19−"X-Generator: Launchpad (build 16948)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/az.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/bg.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/bs.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ca.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ckb.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/cs.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/da.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/de.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/el.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-27 06:34+0000\n"
19−"X-Generator: Launchpad (build 16935)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/en_AU.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/en_GB.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-03-08 06:57+0000\n"
19−"X-Generator: Launchpad (build 16948)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/eo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/es.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-21 06:42+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/eu.po+32−30
@@ -8,24 +8,24 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-02-13 18:37+0000\n"
11−"PO-Revision-Date: 2014-02-03 22:04+0000\n"
11+"PO-Revision-Date: 2014-03-17 20:56+0000\n"
1212"Last-Translator: Ibai Oihanguren Sala <Unknown>\n"
1313"Language-Team: Basque <eu@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: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
2323msgid "Lock to Launcher"
24−msgstr ""
24+msgstr "Lotu abiarazlera"
2525
2626#: plugins/Unity/Launcher/launcheritem.cpp:73
2727msgid "Unlock from Launcher"
28−msgstr ""
28+msgstr "Askatu abiarazletik"
2929
3030#: qml/Components/EdgeDemoOverlay.qml:151
3131msgid "Skip intro"
@@ -74,107 +74,109 @@ msgid ""
7474"You have now mastered the edge gestures and can start using the "
7575"phone<br><br>Tap on the screen to start"
7676msgstr ""
77+"Jadanik ezagutzen dituzu ertzetako keinuak, eta mugikorra erabiltzen has "
78+"zaitezke<br><br>Ukitu pantaila hasteko"
7779
7880#: qml/Components/PageHeader.qml:340
7981msgid "Recent searches"
80−msgstr ""
82+msgstr "Azken bilaketak"
8183
8284#: qml/Components/SeeMore.qml:35
8385msgid "See more"
84−msgstr ""
86+msgstr "Ikusi gehiago"
8587
8688#: qml/Components/SeeMore.qml:57
8789msgid "See less"
88−msgstr ""
90+msgstr "Ikusi gutxiago"
8991
9092#: qml/Dash/Apps/AppPreview.qml:136 qml/Dash/Previews/PreviewRating.qml:70
9193msgid "Rate this"
92−msgstr ""
94+msgstr "Puntuatu hau"
9395
9496#. TRANSLATORS: Number of persons who rated this app/video/whatever
9597#: qml/Dash/Previews/Header.qml:93
9698#, qt-format
9799msgid "(%1)"
98−msgstr ""
100+msgstr "(%1)"
99101
100102#. TRANSLATORS: Number of persons who wrote reviews for this app/video/whatever
101103#: qml/Dash/Previews/Header.qml:105
102104#, qt-format
103105msgid "%1 review"
104106msgid_plural "%1 reviews"
105−msgstr[0] ""
106−msgstr[1] ""
107+msgstr[0] "kritika %1"
108+msgstr[1] "%1 kritika"
107109
108110#: qml/Dash/Previews/PreviewActionCombo.qml:34
109111msgid "More..."
110−msgstr ""
112+msgstr "Gehiago..."
111113
112114#: qml/Dash/Previews/PreviewActionCombo.qml:34
113115msgid "Less..."
114−msgstr ""
116+msgstr "Gutxiago..."
115117
116118#: qml/Dash/Previews/PreviewRating.qml:114 qml/Dash/Previews/Reviews.qml:74
117119msgid "Add a review"
118−msgstr ""
120+msgstr "Gehitu kritika"
119121
120122#: qml/Dash/Previews/PreviewRating.qml:153 qml/Dash/Previews/Reviews.qml:121
121123msgid "Send"
122−msgstr ""
124+msgstr "Bidali"
123125
124126#: qml/Dash/Previews/Reviews.qml:86
125127msgid "Review"
126−msgstr ""
128+msgstr "Egin kritika"
127129
128130#: qml/Dash/Previews/Reviews.qml:139
129131msgid "Comments:"
130−msgstr ""
132+msgstr "Iruzkinak:"
131133
132134#: qml/Greeter/Lockscreen.qml:149
133135msgid "Emergency Call"
134−msgstr ""
136+msgstr "Larrialdi-deia"
135137
136138#: qml/Greeter/PassphraseLockscreen.qml:59
137139#, qt-format
138140msgid "Hello %1"
139−msgstr ""
141+msgstr "Kaixo %1"
140142
141143#: qml/Greeter/PassphraseLockscreen.qml:59
142144msgid "Hello"
143−msgstr ""
145+msgstr "Kaixo"
144146
145147#: qml/Hud/HudParametrizedActionsPage.qml:132
146148msgid "Confirm"
147−msgstr ""
149+msgstr "Baieztatu"
148150
149151#: qml/Hud/Hud.qml:61 qml/Hud/Hud.qml:99 qml/Hud/Hud.qml:372
150152msgid "Type or say a command"
151−msgstr ""
153+msgstr "Idatzi edo esan agindu bat"
152154
153155#: qml/Hud/Hud.qml:84
154156msgid "Loading. Please Wait..."
155−msgstr ""
157+msgstr "Kargatzen. Itxaron, mesedez..."
156158
157159#: qml/Hud/Hud.qml:89
158160msgid "Speak Now..."
159−msgstr ""
161+msgstr "Hitz egin orain..."
160162
161163#: qml/Hud/Hud.qml:94
162164msgid "Speaking..."
163−msgstr ""
165+msgstr "Hitz egiten..."
164166
165167#: qml/Notifications/NotificationMenuItemFactory.qml:91
166168msgid "Show password"
167−msgstr ""
169+msgstr "Erakutsi pasahitza"
168170
169171#: qml/Notifications/NotificationMenuItemFactory.qml:103
170172msgid "Please enter SIM PIN"
171−msgstr ""
173+msgstr "Sartu SIMaren PINa"
172174
173175#: qml/Panel/SearchIndicator.qml:27
174176msgid "Search"
175−msgstr ""
177+msgstr "Bilatu"
176178
177179#: qml/Shell.qml:440
178180#, qt-format
179181msgid "Please enter %1"
180−msgstr ""
182+msgstr "Sartu %1"
po/fa.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/fi.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-03-10 06:11+0000\n"
19−"X-Generator: Launchpad (build 16948)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/fo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/fr.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/gd.po+2−2
@@ -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: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/gl.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-03-09 06:08+0000\n"
19−"X-Generator: Launchpad (build 16948)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/he.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/hi.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/hr.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/hu.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/hy.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/id.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/is.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/it.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ja.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/km.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-03-04 08:33+0000\n"
19−"X-Generator: Launchpad (build 16948)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/kn.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ko.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ky.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/lo.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/lt.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"(n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/lv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ml.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/mr.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ms.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/my.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/nb.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/nl.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/pl.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
1818"|| n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/pt.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/pt_BR.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n > 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ro.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=(n == 1 ? 0: (((n % 100 > 19) || ((n % 100 "
1818"== 0) && (n != 0))) ? 2: 1));\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ru.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/shn.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=(n == 1) ? 0 : 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/si.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/sl.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
1818"n%100==4 ? 3 : 0);\n"
19−"X-Launchpad-Export-Date: 2014-02-22 07:40+0000\n"
20−"X-Generator: Launchpad (build 16926)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/sq.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:25+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/sr.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/sv.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/sw.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ta.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020"Language: ta\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
po/te.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/tr.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-03-06 06:19+0000\n"
19−"X-Generator: Launchpad (build 16948)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/ug.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/uk.po+2−2
@@ -16,8 +16,8 @@ msgstr ""
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
1818"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
19−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
20−"X-Generator: Launchpad (build 16916)\n"
19+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
20+"X-Generator: Launchpad (build 16963)\n"
2121
2222#: plugins/Unity/Launcher/launcheritem.cpp:43
2323#: plugins/Unity/Launcher/launcheritem.cpp:73
po/vi.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/xh.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=2; plural=n != 1;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/zh_CN.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/zh_HK.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
po/zh_TW.po+2−2
@@ -15,8 +15,8 @@ msgstr ""
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
1717"Plural-Forms: nplurals=1; plural=0;\n"
18−"X-Launchpad-Export-Date: 2014-02-19 05:44+0000\n"
19−"X-Generator: Launchpad (build 16916)\n"
18+"X-Launchpad-Export-Date: 2014-03-18 06:26+0000\n"
19+"X-Generator: Launchpad (build 16963)\n"
2020
2121#: plugins/Unity/Launcher/launcheritem.cpp:43
2222#: plugins/Unity/Launcher/launcheritem.cpp:73
qml/Components/ListItems/Header.qml+2−14
@@ -36,7 +36,7 @@ Item {
3636 right: parent.right
3737 rightMargin: units.gu(0.5)
3838 top: parent.top
39− bottom: bottomBorder.top
39+ bottom: parent.bottom
4040 }
4141
4242 Label {
@@ -47,14 +47,11 @@ Item {
4747 verticalCenter: parent.verticalCenter
4848 }
4949
50− color: Theme.palette.selected.backgroundText //at 60%
51− opacity: 0.6
50+ color: "grey" // TODO karni: Update Ubuntu.Compoonents.Themes.Palette.
5251 font.family: "Ubuntu"
5352 fontSize: "medium"
5453 elide: Text.ElideRight
5554 textFormat: Text.PlainText
56− style: Text.Raised
57− styleColor: "black"
5855 width: parent.width - image.width - image.leftMargin - anchors.leftMargin
5956 }
6057
@@ -68,15 +65,6 @@ Item {
6865 }
6966 }
7067
71− ThinDivider {
72− id: bottomBorder
73− anchors {
74− left: parent.left
75− right: parent.right
76− bottom: parent.bottom
77− }
78− }
79−
8068 MouseArea {
8169 anchors.fill: parent
8270 onClicked: parent.clicked(mouse)
qml/Components/OpenEffect.qmldeleted−138
@@ -1,138 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−Item {
20− id: effect
21− property bool enabled: topGapPx != positionPx || bottomGapPx != positionPx
22− property alias live: effectSource.live
23− property Item sourceItem
24− property ShaderEffectSource source: ShaderEffectSource {
25− id: effectSource
26− sourceItem: effect.enabled ? effect.sourceItem : null
27− hideSource: effect.enabled
28− live: false
29− sourceRect: {
30− if (effect.enabled) {
31− Qt.rect(0, -effect.topOverflow, sourceItem.width, sourceItem.height + effect.topOverflow + effect.bottomOverflow)
32− } else {
33− Qt.rect(0, 0, 0, 0)
34− }
35− }
36− }
37−
38− onEnabledChanged: if (!live && enabled) scheduleUpdate()
39−
40− /*!
41− \qmlproperty real positionPx
42− The y coordinate of where to perform the split.
43−
44− \qmlproperty real topGapPx
45− Gap's top edge.
46−
47− \qmlproperty real bottomGapPx
48− Gap's bottom edge.
49−
50− \qmlproperty real topOverflow
51− How much of the sourceItem should be sourced above its bounds.
52−
53− \qmlproperty real bottomOverflow
54− How much of the sourceItem should be sourced below its bounds.
55− */
56−
57− property real positionPx: 0
58− property real topGapPx: 0
59− property real bottomGapPx: height
60− property real topOverflow: 0.0
61− property real bottomOverflow: 0.0
62− property real topOpacity: 1.0
63− property real bottomOpacity: 1.0
64−
65− property real __roundedPositionPx: Math.round(positionPx)
66−
67− function scheduleUpdate() {
68− source.scheduleUpdate();
69− }
70−
71− ShaderEffect {
72− id: top
73− visible: effect.enabled
74− opacity: topOpacity
75− property ShaderEffectSource source: effect.source
76− property real positionPx: __roundedPositionPx
77− property real factor: effect.height / height
78−
79− clip: true
80−
81− anchors {
82− top: parent.top
83− left: parent.left
84− right: parent.right
85− topMargin: -topOverflow - positionPx + topGapPx
86− }
87− height: topOverflow + positionPx
88−
89− vertexShader: "
90− uniform highp mat4 qt_Matrix;
91− attribute highp vec4 qt_Vertex;
92− attribute highp vec2 qt_MultiTexCoord0;
93− varying highp vec2 qt_TexCoord0;
94− uniform highp float factor;
95−
96− void main() {
97− highp vec4 pos = qt_Vertex;
98− pos.y *= factor;
99− gl_Position = qt_Matrix * pos;
100− qt_TexCoord0 = qt_MultiTexCoord0;
101− }
102− "
103− }
104−
105− ShaderEffect {
106− id: bottom
107− visible: effect.enabled
108− opacity: bottomOpacity
109− property ShaderEffectSource source: effect.source
110− property real offset: effect.topOverflow + __roundedPositionPx
111− property real factor: effect.height / height
112−
113− clip: true
114−
115− anchors {
116− left: parent.left
117− right: parent.right
118− }
119− y: topOverflow + bottomGapPx
120− height: sourceItem.height - positionPx + bottomOverflow
121−
122− vertexShader: "
123− uniform highp mat4 qt_Matrix;
124− attribute highp vec4 qt_Vertex;
125− attribute highp vec2 qt_MultiTexCoord0;
126− varying highp vec2 qt_TexCoord0;
127− uniform highp float factor;
128− uniform highp float offset;
129−
130− void main() {
131− highp vec4 pos = qt_Vertex;
132− pos.y = (pos.y * factor) - offset;
133− gl_Position = qt_Matrix * pos;
134− qt_TexCoord0 = qt_MultiTexCoord0;
135− }
136− "
137− }
138−}
qml/Components/PageHeader.qml+27−2
@@ -18,7 +18,7 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Ubuntu.Components.Popups 0.1
2020import Ubuntu.Components.ListItems 0.1 as ListItem
21−import Unity 0.1
21+import Unity 0.2
2222
2323Item {
2424 id: root
@@ -27,6 +27,9 @@ Item {
2727 property ListModel searchHistory
2828 property Scope scope
2929 property alias childItem: itemContainer.children
30+ property alias showBackButton: backButton.visible
31+
32+ signal backClicked
3033
3134 height: units.gu(8.5)
3235 implicitHeight: units.gu(8.5)
@@ -69,11 +72,33 @@ Item {
6972
7073 Behavior on contentY { NumberAnimation { duration: 200; easing.type: Easing.OutQuad } }
7174
75+ AbstractButton {
76+ id: backButton
77+ objectName: root.objectName + "_backButton"
78+ visible: false
79+ height: header.height
80+ y: header.contentY
81+ anchors {
82+ left: parent.left
83+ leftMargin: visible ? units.gu(2) : 0
84+ }
85+ width: visible ? image.width + units.gu(2) : 0
86+ onClicked: root.backClicked();
87+ Image {
88+ id: image
89+ anchors.centerIn: parent
90+ source: "graphics/headerback.png"
91+ }
92+ }
93+
7294 // FIXME this could potentially be simplified to avoid all the containers
7395 Item {
7496 id: headerContainer
7597
76− width: parent.width
98+ anchors {
99+ left: backButton.right
100+ right: parent.right
101+ }
77102 height: childrenRect.height
78103
79104 Item {
qml/Components/RatingStars.qmldeleted−41
@@ -1,41 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−Row {
20− id: root
21− property int rating
22− property int maximumRating: 5
23− property int starCount: 5
24− height: childrenRect.height
25− width: childrenRect.width
26−
27− readonly property int effectiveRating: Math.max(0, Math.min(root.starCount * root.rating / root.maximumRating, root.maximumRating))
28−
29− Repeater {
30− model: root.effectiveRating
31− Image {
32− source: "graphics/icon_star_on.png"
33− }
34− }
35− Repeater {
36− model: root.starCount - root.effectiveRating
37− Image {
38− source: "graphics/icon_star_off.png"
39− }
40− }
41−}
qml/Components/ResponsiveGridView.qml−1
@@ -56,7 +56,6 @@ Item {
5656 fill: parent
5757 leftMargin: margin/2
5858 rightMargin: margin/2
59− topMargin: verticalSpacing
6059 }
6160 clip: parent.height != totalContentHeight
6261
qml/Components/SeeMore.qml+4−2
@@ -34,7 +34,8 @@ Item {
3434 objectName: "seeMoreLabel"
3535 text: i18n.tr("See more")
3636 opacity: !more ? 0.8 : 0.4
37− color: Theme.palette.selected.backgroundText
37+ // TODO: Fix requiring Palette update
38+ color: "grey" //Theme.palette.selected.backgroundText
3839 font.weight: Font.Bold
3940
4041 MouseArea {
@@ -56,7 +57,8 @@ Item {
5657 objectName: "seeLessLabel"
5758 text: i18n.tr("See less")
5859 opacity: more ? 0.8 : 0.4
59− color: Theme.palette.selected.backgroundText
60+ // TODO: Fix requiring Palette update
61+ color: "grey" //Theme.palette.selected.backgroundText
6062 font.weight: Font.Bold
6163
6264 MouseArea {
qml/Components/Stage.qml+17−9
@@ -65,7 +65,9 @@ Showable {
6565
6666 function activateApplication(desktopFile, addDelay) {
6767 var application = applicationManager.getApplicationFromDesktopFile(desktopFile, stage.type);
68− if (application != null && application == stage.focusedApplication) {
68+ if (application == null) {
69+ return;
70+ } else if (application == stage.focusedApplication) {
6971 stage.show();
7072 return;
7173 }
@@ -142,6 +144,14 @@ Showable {
142144 }
143145 }
144146
147+ Timer {
148+ id: hideScreenshotsAfterBriefDelay
149+ // Since Mir & Qt have independent event loops, Mir often applies a focus request a frame later than when Qt
150+ // asks for it. To work around, delay removing the screenshots a touch so Mir has definitely shown the app.
151+ interval: 10
152+ onTriggered: stage.__hideScreenshots();
153+ }
154+
145155 function __hideScreenshots() {
146156 newApplicationScreenshot.clearApplication();
147157 oldApplicationScreenshot.clearApplication();
@@ -177,7 +187,7 @@ Showable {
177187 applicationManager.focusApplication(application);
178188 }
179189 if (!delayedHideScreenshots.running) {
180− stage.__hideScreenshots();
190+ hideScreenshotsAfterBriefDelay.start();
181191 }
182192 } else {
183193 /* FIXME: calling ApplicationManager::focusApplication does not focus
@@ -252,7 +262,7 @@ Showable {
252262 delayedHideScreenshots.start();
253263 } else {
254264 stage.focusedApplicationWhenUsingScreenshots = null;
255− stage.__hideScreenshots();
265+ hideScreenshotsAfterBriefDelay.start();
256266 }
257267 }
258268 }
@@ -329,13 +339,11 @@ Showable {
329339
330340 ScriptAction {
331341 script: {
332− if (!stage.focusedApplicationWhenUsingScreenshots) {
333− // FIXME: only here to support case where application does
334− // not exist yet but is about to
335− return;
342+ // FIXME: only here to support case where application does
343+ // not exist yet but is about to
344+ if (stage.focusedApplicationWhenUsingScreenshots) {
345+ stage.__focusApplication(stage.focusedApplicationWhenUsingScreenshots);
336346 }
337−
338− stage.__focusApplication(stage.focusedApplicationWhenUsingScreenshots);
339347 }
340348 }
341349 }
qml/Components/Tile.qmldeleted−39
@@ -1,39 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−AbstractButton {
21− property url source
22− property int fillMode: Image.PreserveAspectCrop
23− property int horizontalAlignment: Text.AlignHCenter
24− property string text
25− property int imageWidth
26− property int imageHeight
27− property int maximumLineCount: 1
28−
29− readonly property int center: (index % GridView.view.columns * width) + (width / 2)
30−
31− opacity: GridView.view.highlightIndex === -1 ? 1 :
32− GridView.view.highlightIndex === index ? 0.6 : 0.2
33−
34− Behavior on opacity {
35− UbuntuNumberAnimation {}
36− }
37−
38− style: TileStyle {}
39−}
qml/Components/TileStyle.qmldeleted−81
@@ -1,81 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: tile
22−
23− anchors.fill: parent
24−
25− UbuntuShape {
26− id: icon
27− anchors {
28− top: parent.top
29− horizontalCenter: parent.horizontalCenter
30− }
31− radius: "medium"
32− width: styledItem.imageWidth
33− height: styledItem.imageHeight
34− image: Image {
35− id: image
36− objectName: "image"
37− sourceSize { width: icon.width; height: icon.height }
38− asynchronous: true
39− cache: false
40− source: styledItem.source
41− fillMode: styledItem.fillMode
42− horizontalAlignment: Image.AlignHCenter
43− verticalAlignment: Image.AlignVCenter
44− }
45− }
46−
47− UbuntuShape {
48− id: borderPressed
49− objectName: "borderPressed"
50−
51− anchors.fill: icon
52− radius: "medium"
53− borderSource: "radius_pressed.sci"
54− opacity: styledItem.pressed ? 1.0 : 0.0
55− Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
56− }
57−
58− Label {
59− id: label
60− objectName: "label"
61− anchors {
62− baseline: icon.bottom
63− baselineOffset: units.gu(2)
64− left: parent.left
65− right: parent.right
66− leftMargin: units.gu(1)
67− rightMargin: units.gu(1)
68− }
69−
70− color: Theme.palette.selected.backgroundText
71− opacity: 0.9
72− style: Text.Raised
73− styleColor: "black"
74− fontSize: "small"
75− elide: Text.ElideMiddle
76− horizontalAlignment: styledItem.horizontalAlignment
77− text: styledItem.text
78− wrapMode: Text.Wrap
79− maximumLineCount: styledItem.maximumLineCount
80− }
81−}
qml/Components/VolumeControl.qml+6−2
@@ -22,6 +22,10 @@ Item {
2222 objectName: "volumeControl"
2323 visible: false
2424
25+ // TODO Work around http://pad.lv/1293478 until qmenumodel knows to cast
26+ readonly property int stepUp: 1
27+ readonly property int stepDown: -1
28+
2529 QDBusActionGroup {
2630 id: actionGroup
2731 busType: 1
@@ -32,11 +36,11 @@ Item {
3236 }
3337
3438 function volumeUp() {
35− actionGroup.actionObject.activate(1);
39+ actionGroup.actionObject.activate(stepUp);
3640 }
3741
3842 function volumeDown() {
39− actionGroup.actionObject.activate(-1);
43+ actionGroup.actionObject.activate(stepDown);
4044 }
4145
4246 Component.onCompleted: actionGroup.start()
qml/Components/graphics/headerback@27.pngnew file

Binary file not shown.

qml/Dash/Apps/AppPreview.qmldeleted−167
@@ -1,167 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import Ubuntu.Components.ListItems 0.1 as ListItems
20−import ".."
21−import "../Generic"
22−import "../Previews"
23−import "../../Components"
24−
25−GenericPreview {
26− id: root
27−
28− signal sendUserReview(string review)
29−
30− previewImages: previewImagesComponent
31− description: descriptionComponent
32− header: headerComponent
33−
34− // TODO: Ratings are not yet complete... enable this once they work
35− //ratings: ratingsComponent
36−
37− Component {
38− id: previewImagesComponent
39− ListView {
40− id: previewImageListView
41− spacing: units.gu(1)
42− orientation: ListView.Horizontal
43− height: units.gu(22)
44− model: previewData.infoMap["more-screenshots"] != null ? previewData.infoMap["more-screenshots"].value : [previewData.image]
45− cacheBuffer: width * 3
46−
47− // FIXME: Because of ListViews inside ListViews inside Flickables inside ListViews (and some more)
48− // we finally reached the point where this ListView doesn't correctly get swipe input any more but
49− // instead the parent ListView is the one that is swiped. This MouseArea sort of creates a blocking
50− // layer to make sure this ListView can be swiped, regardless of what's behind it.
51− MouseArea {
52− anchors.fill: parent
53− enabled: parent.contentWidth > parent.width
54− }
55−
56− LazyImage {
57− objectName: "placeholderScreenshot"
58− anchors {
59− top: parent.top
60− bottom: parent.bottom
61− }
62− scaleTo: "height"
63− source: "broken_image"
64− initialWidth: units.gu(13)
65− visible: previewImageListView.count == 0
66− }
67−
68− delegate: LazyImage {
69− id: shape
70− anchors {
71− top: parent.top
72− bottom: parent.bottom
73− }
74− source: modelData ? modelData : ""
75− scaleTo: "height"
76− initialWidth: units.gu(13)
77− }
78− }
79− }
80−
81− Component {
82− id: headerComponent
83− Header {
84− objectName: "previewHeader"
85− title: previewData.title
86− icon: previewData.appIcon
87− subtitle: root.previewData.infoMap["publisher"] ? root.previewData.infoMap["publisher"].value : ""
88− rating: Math.round(root.previewData.rating * 10)
89− reviews: root.previewData.numRatings
90− rated: root.previewData.infoMap["rated"] ? root.previewData.infoMap["rated"].value : 0
91− }
92− }
93−
94− Component {
95− id: descriptionComponent
96− Column {
97− spacing: units.gu(1)
98−
99− Label {
100− objectName: "descriptionLabel"
101− anchors { left: parent.left; right: parent.right }
102− text: root.previewData.description
103− fontSize: "medium"
104− color: Theme.palette.selected.backgroundText
105− opacity: .6
106− wrapMode: Text.WordWrap
107− style: Text.Raised
108− styleColor: "black"
109− }
110− }
111− }
112−
113− Component {
114− id: ratingsComponent
115− Column {
116− id: columnReviewRating
117− objectName: "columnReviewRating"
118− visible: root.previewData.rating >= 0
119−
120− spacing: units.gu(1)
121− height: childrenRect.height
122−
123− ListItems.ThinDivider { }
124−
125− Item {
126− anchors { left: parent.left; right: parent.right }
127− height: rateLabel.height
128−
129− Label {
130− id: rateLabel
131− fontSize: "medium"
132− color: "white"
133− style: Text.Raised
134− styleColor: "black"
135− opacity: .9
136− text: i18n.tr("Rate this")
137−
138− anchors.left: parent.left
139− anchors.verticalCenter: parent.verticalCenter
140− }
141−
142− // FIXME these need to be made interactive and connected to the scope
143− RatingStars {
144− anchors.right: parent.right
145− anchors.verticalCenter: parent.verticalCenter
146− }
147− }
148−
149− ListItems.ThinDivider { }
150−
151− Reviews {
152− id: appReviews
153− objectName: "appReviews"
154−
155− anchors { left: parent.left; right: parent.right }
156−
157− model: root.previewData.infoMap["comments"] ? root.previewData.infoMap["comments"].value : undefined
158−
159− onSendReview: root.sendUserReview(review);
160−
161− onEditing: {
162− root.ensureVisible(appReviews.textArea);
163− }
164− }
165− }
166− }
167−}
qml/Dash/Apps/DashPluginFilterGrid.qmldeleted−47
@@ -1,47 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−import "../Generic"
21−
22−GenericFilterGrid {
23− id: filtergrid
24−
25− delegate: Tile {
26− id: tile
27− objectName: "delegate" + index
28− width: filtergrid.cellWidth
29− height: filtergrid.cellHeight
30− text: model.title
31− imageWidth: filtergrid.iconWidth
32− imageHeight: filtergrid.iconHeight
33− source: model.icon
34−
35− style: FlatTileStyle {
36− disabled: model.rendererHints['scope_disabled'] === 1;
37− }
38−
39− onClicked: {
40− filtergrid.clicked(index, tile.y)
41− }
42−
43− onPressAndHold: {
44− filtergrid.pressAndHold(index, tile.y)
45− }
46− }
47−}
qml/Dash/Apps/FrequentlyUsedAppsModel.qmldeleted−110
@@ -1,110 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−ListModel {
20− ListElement {
21− uri: "application://dialer-app.desktop"
22− icon: "../../graphics/applicationIcons/phone-app.png"
23− category: 0
24− mimetype: "application/x-desktop"
25− title: "Dialer"
26− comment: ""
27− dndUri: "file:///usr/share/applications/dialer-app.desktop"
28− metadata: "subscope:applications.scope/applications-non-click.scope"
29− }
30− ListElement {
31− uri: "application://messaging-app.desktop"
32− icon: "../../graphics/applicationIcons/messages-app.png"
33− category: 0
34− mimetype: "application/x-desktop"
35− title: "Messaging"
36− comment: ""
37− dndUri: "file:///usr/share/applications/messaging-app.desktop"
38− metadata: "subscope:applications.scope/applications-non-click.scope"
39− }
40− ListElement {
41− uri: "application://address-book-app.desktop"
42− icon: "../../graphics/applicationIcons/contacts-app.png"
43− category: 0
44− mimetype: "application/x-desktop"
45− title: "Contacts"
46− comment: ""
47− dndUri: "file:///usr/share/applications/address-book-app.desktop"
48− metadata: "subscope:applications.scope/applications-non-click.scope"
49− }
50− ListElement {
51− uri: "appid://com.ubuntu.camera/camera/current-user-version"
52− icon: "../../graphics/applicationIcons/camera.png"
53− category: 0
54− mimetype: "application/x-desktop"
55− title: "Camera"
56− comment: ""
57− dndUri: "appid://com.ubuntu.camera/camera/current-user-version"
58− metadata: "subscope:applications.scope/applications-click.scope?app_id=com.ubuntu.camera"
59− }
60− ListElement {
61− uri: "appid://com.ubuntu.gallery/gallery/current-user-version"
62− icon: "../../graphics/applicationIcons/gallery.png"
63− category: 0
64− mimetype: "application/x-desktop"
65− title: "Gallery"
66− comment: ""
67− dndUri: "appid://com.ubuntu.gallery/gallery/current-user-version"
68− metadata: "subscope:applications.scope/applications-click.scope?app_id=com.ubuntu.gallery"
69− }
70− ListElement {
71− uri: "appid://com.ubuntu.developer.webapps.webapp-facebook/webapp-facebook/current-user-version"
72− icon: "../../graphics/applicationIcons/facebook.png"
73− category: 0
74− mimetype: "application/x-desktop"
75− title: "Facebook"
76− comment: ""
77− dndUri: "appid://com.ubuntu.developer.webapps.webapp-facebook/webapp-facebook/current-user-version"
78− metadata: "subscope:applications.scope/applications-click.scope?app_id=com.ubuntu.developer.webapps.webapp-facebook"
79− }
80− ListElement {
81− uri: "application://webbrowser-app.desktop"
82− icon: "../../graphics/applicationIcons/browser.png"
83− category: 0
84− mimetype: "application/x-desktop"
85− title: "Browser"
86− comment: ""
87− dndUri: "file:///usr/share/applications/webbrowser-app.desktop"
88− metadata: "subscope:applications.scope/applications-non-click.scope"
89− }
90− ListElement {
91− uri: "appid://com.ubuntu.developer.webapps.webapp-gmail/webapp-gmail/current-user-version"
92− icon: "../../graphics/applicationIcons/gmail.png"
93− category: 0
94− mimetype: "application/x-desktop"
95− title: "GMail"
96− comment: ""
97− dndUri: "appid://com.ubuntu.developer.webapps.webapp-gmail/webapp-gmail/current-user-version"
98− metadata: "subscope:applications.scope/applications-click.scope?app_id=com.ubuntu.developer.webapps.webapp-gmail"
99− }
100− ListElement {
101− uri: "application://ubuntu-system-settings.desktop"
102− icon: "../../graphics/applicationIcons/system-settings.png"
103− category: 0
104− mimetype: "application/x-desktop"
105− title: "System Settings"
106− comment: ""
107− dndUri: "file:///usr/share/applications/ubuntu-system-settings.desktop"
108− metadata: "subscope:applications.scope/applications-non-click.scope"
109− }
110−}
qml/Dash/Apps/RunningApplicationTile.qml+2−3
@@ -108,10 +108,9 @@ AbstractButton {
108108 }
109109 text: (application) ? application.name : ""
110110
111− color: Theme.palette.selected.backgroundText
111+ // TODO karni: Update Ubuntu.Components.Themes.Palette and use theme color instead
112+ color: "grey"
112113 opacity: 0.9
113− style: Text.Raised
114− styleColor: "black"
115114 fontSize: "small"
116115 elide: Text.ElideMiddle
117116 horizontalAlignment: Text.AlignHCenter
qml/Dash/Card.qml+11−2
@@ -17,7 +17,7 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919
20−Item {
20+AbstractButton {
2121 id: root
2222 property var template
2323 property var components
@@ -25,7 +25,8 @@ Item {
2525
2626 property alias fontScale: header.fontScale
2727 property alias headerAlignment: header.headerAlignment
28− readonly property alias headerHeight: header.height
28+ property alias headerHeight: header.height
29+ readonly property alias title: header.title
2930
3031 property bool showHeader: true
3132
@@ -44,6 +45,8 @@ Item {
4445 anchors.fill: parent
4546 image: backgroundImage.source ? backgroundImage : null
4647
48+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
49+
4750 property Image backgroundImage: Image {
4851 objectName: "backgroundImage"
4952 source: {
@@ -87,6 +90,7 @@ Item {
8790 height: template && template["card-layout"] === "horizontal" ? header.height : width / artShape.aspect
8891 objectName: "artImage"
8992 source: cardData && cardData["art"] || ""
93+ cache: true
9094 // FIXME uncomment when having investigated / fixed the crash
9195 //sourceSize.width: width > height ? width : 0
9296 //sourceSize.height: height > width ? height : 0
@@ -163,6 +167,9 @@ Item {
163167 titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
164168
165169 opacity: showHeader ? 1 : 0
170+ inOverlay: root.template && root.template["overlay"] === true
171+ fontColor: inOverlay ? "white" : summary.color
172+ useMascotShape: !background.visible && !inOverlay
166173
167174 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
168175 }
@@ -183,5 +190,7 @@ Item {
183190 text: cardData && cardData["summary"] || ""
184191 height: text ? implicitHeight : 0
185192 fontSize: "small"
193+ // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
194+ color: background.visible && background.luminance < 0.7 ? "white" : "grey"
186195 }
187196}
qml/Dash/DashCarousel.qml → qml/Dash/CardCarousel.qmlrenamed+30−8
@@ -18,8 +18,9 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import "../Components"
2020
21+
2122DashRenderer {
22− id: dashCarousel
23+ id: cardCarousel
2324
2425 property alias cacheBuffer: carousel.cacheBuffer
2526 property alias itemComponent: carousel.itemComponent
@@ -34,14 +35,35 @@ DashRenderer {
3435 Carousel {
3536 id: carousel
3637 anchors.fill: parent
37− tileAspectRatio: 198 / 288
38− minimumTileWidth: units.gu(13)
39− selectedItemScaleFactor: 1.14
38+ tileAspectRatio: cardCarousel.components && cardCarousel.components["art"]["aspect-ratio"] || 1.0
39+ // FIXME we need to "reverse" the carousel to make the selected item the size
40+ // and push others back.
41+ minimumTileWidth: cardTool.cardWidth / selectedItemScaleFactor
42+ selectedItemScaleFactor: cardTool.carouselSelectedItemScaleFactor
4043 cacheBuffer: 1404 // 18px * 13gu * 6
41− model: dashCarousel.model
42− highlightIndex: dashCarousel.highlightIndex
44+ model: cardCarousel.model
45+
46+ onClicked: cardCarousel.clicked(index, itemY)
47+ onPressAndHold: cardCarousel.pressAndHold(index, itemY)
48+
49+ property real fontScale: 1 / selectedItemScaleFactor
50+ property real headerHeight: cardTool.headerHeight / selectedItemScaleFactor
51+
52+ itemComponent: Card {
53+ id: card
54+ objectName: "carouselDelegate" + index
55+ headerHeight: carousel.headerHeight
56+ cardData: model
57+ template: cardTool.template
58+ components: cardTool.components
59+
60+ property bool explicitlyScaled
61+ property var model
62+
63+ enabled: false
64+ showHeader: explicitlyScaled
4365
44− onClicked: dashCarousel.clicked(index, itemY)
45− onPressAndHold: dashCarousel.pressAndHold(index, itemY)
66+ fontScale: carousel.fontScale
67+ }
4668 }
4769}
qml/Dash/CardFilterGrid.qmlnew file+76
@@ -0,0 +1,76 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import "../Components"
19+
20+DashRenderer {
21+ id: genericFilterGrid
22+
23+ expandable: filterGrid.expandable
24+ collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
25+ collapsedHeight: filterGrid.collapsedHeight
26+ columns: filterGrid.columns
27+ rows: filter ? collapsedRowCount : uncollapsedRowCount
28+ margins: filterGrid.margins
29+ uncollapsedHeight: filterGrid.uncollapsedHeight
30+ verticalSpacing: units.gu(1)
31+ currentItem: filterGrid.currentItem
32+ height: filterGrid.height
33+
34+ function startFilterAnimation(filter) {
35+ filterGrid.startFilterAnimation(filter)
36+ }
37+
38+ FilterGrid {
39+ id: filterGrid
40+ width: genericFilterGrid.width
41+ minimumHorizontalSpacing: units.gu(1)
42+ delegateWidth: cardTool.cardWidth
43+ delegateHeight: cardTool.cardHeight
44+ verticalSpacing: genericFilterGrid.verticalSpacing
45+ model: genericFilterGrid.model
46+ filter: genericFilterGrid.filter
47+ collapsedRowCount: genericFilterGrid.collapsedRowCount
48+ delegateCreationBegin: genericFilterGrid.delegateCreationBegin
49+ delegateCreationEnd: genericFilterGrid.delegateCreationEnd
50+ delegate: Item {
51+ width: filterGrid.cellWidth
52+ height: filterGrid.cellHeight
53+ Card {
54+ id: card
55+ width: cardTool.cardWidth
56+ height: cardTool.cardHeight
57+ headerHeight: cardTool.headerHeight
58+ anchors.horizontalCenter: parent.horizontalCenter
59+ objectName: "delegate" + index
60+ cardData: model
61+ template: cardTool.template
62+ components: cardTool.components
63+
64+ headerAlignment: cardTool.headerAlignment
65+
66+ onClicked: genericFilterGrid.clicked(index, card.y)
67+ onPressAndHold: genericFilterGrid.pressAndHold(index, card.y)
68+ }
69+ }
70+
71+ onFilterChanged: {
72+ genericFilterGrid.filter = filter
73+ filter = Qt.binding(function() { return genericFilterGrid.filter })
74+ }
75+ }
76+}
qml/Dash/CardHeader.qml+32−60
@@ -22,18 +22,20 @@ Item {
2222 property alias mascot: mascotImage.source
2323 property alias title: titleLabel.text
2424 property alias subtitle: subtitleLabel.text
25− property alias price: priceLabel.text
26− property alias oldPrice: oldPriceLabel.text
27− property alias altPrice: altPriceLabel.text
2825
2926 property alias titleWeight: titleLabel.font.weight
27+ property alias titleSize: titleLabel.fontSize
3028
3129 // FIXME: Saviq, used to scale fonts down in Carousel
3230 property real fontScale: 1.0
3331
3432 property alias headerAlignment: titleLabel.horizontalAlignment
3533
36− visible: mascotImage.status === Image.Ready || title || price
34+ property bool inOverlay: false
35+ property bool useMascotShape: true
36+ property color fontColor: Theme.palette.selected.backgroundText
37+
38+ visible: mascotImage.status === Image.Ready || title
3739 height: row.height > 0 ? row.height + row.margins * 2 : 0
3840
3941 Row {
@@ -42,13 +44,13 @@ Item {
4244
4345 property real margins: units.gu(1)
4446
47+ spacing: mascotShape.visible || mascotImage.visible || inOverlay ? margins : 0
4548 anchors {
4649 top: parent.top; left: parent.left; right: parent.right
4750 margins: margins
4851 leftMargin: spacing
4952 rightMargin: spacing
5053 }
51− spacing: mascotShape.visible || (template && template["overlay"]) ? margins : 0
5254
5355 UbuntuShape {
5456 id: mascotShape
@@ -57,35 +59,45 @@ Item {
5759 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
5860 width: units.gu(6)
5961 height: units.gu(5.625)
60− visible: image.status === Image.Ready
61− readonly property int maxSize: Math.max(width, height)
62+ anchors.verticalCenter: parent.verticalCenter
63+ visible: useMascotShape && image && image.status === Image.Ready
64+ readonly property int maxSize: Math.max(width, height) * 4
6265
63− image: Image {
64− id: mascotImage
66+ image: useMascotShape ? mascotImage : null
67+ }
6568
66− sourceSize { width: mascotShape.maxSize; height: mascotShape.maxSize }
67− fillMode: Image.PreserveAspectCrop
68− horizontalAlignment: Image.AlignHCenter
69− verticalAlignment: Image.AlignVCenter
70− }
69+ Image {
70+ id: mascotImage
71+ objectName: "mascotImage"
72+
73+ width: source ? mascotShape.width : 0
74+ height: mascotShape.height
75+ anchors.verticalCenter: parent.verticalCenter
76+ visible: !useMascotShape && status === Image.Ready
77+
78+ sourceSize { width: mascotShape.maxSize; height: mascotShape.maxSize }
79+ fillMode: Image.PreserveAspectCrop
80+ horizontalAlignment: Image.AlignHCenter
81+ verticalAlignment: Image.AlignVCenter
7182 }
7283
7384 Column {
7485 objectName: "column"
7586 width: parent.width - x
76− spacing: units.gu(0.5)
87+ spacing: units.dp(2)
88+ anchors.verticalCenter: parent.verticalCenter
7789
7890 Label {
7991 id: titleLabel
8092 objectName: "titleLabel"
8193 anchors { left: parent.left; right: parent.right }
8294 elide: Text.ElideRight
83− font.weight: Font.DemiBold
95+ font.weight: Font.Normal
96+ fontSize: "small"
8497 wrapMode: Text.Wrap
8598 maximumLineCount: 2
86− fontSize: "small"
8799 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
88− color: template["overlay"] === true ? "white" : Theme.palette.selected.backgroundText
100+ color: fontColor
89101 }
90102
91103 Label {
@@ -93,51 +105,11 @@ Item {
93105 objectName: "subtitleLabel"
94106 anchors { left: parent.left; right: parent.right }
95107 elide: Text.ElideRight
108+ fontSize: "small"
96109 font.weight: Font.Light
97110 visible: titleLabel.text && text
98− fontSize: "x-small"
99111 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
100− color: template["overlay"] === true ? "white" : Theme.palette.selected.backgroundText
101− }
102−
103− Row {
104− id: prices
105− objectName: "prices"
106− anchors { left: parent.left; right: parent.right }
107−
108− property int labels: {
109− var labels = 1; // price always visible
110− if (oldPriceLabel.text !== "") labels += 1;
111− if (altPriceLabel.text !== "") labels += 1;
112− return labels;
113− }
114− property real labelWidth: width / labels
115−
116− Label {
117− id: priceLabel
118− width: parent.labelWidth
119− elide: Text.ElideRight
120− font.weight: Font.DemiBold
121− color: Theme.palette.selected.foreground
122− visible: text
123− }
124−
125− Label {
126− id: oldPriceLabel
127− objectName: "oldPriceLabel"
128− width: parent.labelWidth
129− elide: Text.ElideRight
130− horizontalAlignment: parent.labels === 3 ? Text.AlignHCenter : Text.AlignRight
131− visible: text
132− }
133−
134− Label {
135− id: altPriceLabel
136− width: parent.labelWidth
137− elide: Text.ElideRight
138− horizontalAlignment: Text.AlignRight
139− visible: text
140− }
112+ color: fontColor
141113 }
142114 }
143115 }
qml/Dash/CardTool.qml+47−9
@@ -28,6 +28,22 @@ import QtQuick 2.0
2828
2929Item {
3030 id: cardTool
31+
32+ /*!
33+ \brief Number of cards.
34+ */
35+ property int count
36+
37+ /*!
38+ \brief Width of the category view.
39+ */
40+ property real viewWidth
41+
42+ /*!
43+ \brief Scaling factor of selected Carousel item.
44+ */
45+ readonly property real carouselSelectedItemScaleFactor: 1.38 // XXX assuming 1.38 carousel scaling factor for cards
46+
3147 /*!
3248 \brief Template supplied for the category.
3349 */
@@ -39,9 +55,15 @@ Item {
3955 property var components
4056
4157 /*!
42− \brief Width of the view, based on which carousel width is calculated.
58+ \brief The category layout for this card tool.
4359 */
44− property var viewWidth
60+ property string categoryLayout: {
61+ var layout = template["category-layout"];
62+
63+ // carousel fallback mode to grid
64+ if (layout === "carousel" && count <= Math.ceil(carouselTool.realPathItemCount)) layout = "grid";
65+ return layout;
66+ }
4567
4668 // FIXME: Saviq
4769 // Only way for the card below to actually be laid out completely.
@@ -56,7 +78,7 @@ Item {
5678 If undefined, should use implicit width of the actual card.
5779 */
5880 readonly property var cardWidth: {
59− switch (template !== undefined && template["category-layout"]) {
81+ switch (categoryLayout) {
6082 case "grid":
6183 case "vertical-journal":
6284 if (template["card-layout"] === "horizontal") return units.gu(38);
@@ -66,10 +88,7 @@ Item {
6688 }
6789 return units.gu(18.5);
6890 case "carousel":
69− if (viewWidth === undefined) return undefined
70− if (viewWidth <= units.gu(40)) return units.gu(18)
71− if (viewWidth >= units.gu(128)) return units.gu(26)
72− return units.gu(18 + Math.round((viewWidth - units.gu(40))/ units.gu(11)))
91+ return carouselTool.minimumTileWidth;
7392 case undefined:
7493 case "organic-grid":
7594 case "journal":
@@ -84,7 +103,7 @@ Item {
84103 If undefined, should use implicit height of the actual card.
85104 */
86105 readonly property var cardHeight: {
87− switch (template !== undefined && template["category-layout"]) {
106+ switch (categoryLayout) {
88107 case "journal":
89108 if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]);
90109 return units.gu(18.5);
@@ -123,9 +142,28 @@ Item {
123142 return (template["card-layout"] === "horizontal") ? Text.AlignLeft : Text.AlignHCenter;
124143 }
125144
145+ QtObject {
146+ id: carouselTool
147+
148+ property real minimumTileWidth: {
149+ if (cardTool.viewWidth === undefined) return undefined;
150+ if (cardTool.viewWidth <= units.gu(40)) return units.gu(18);
151+ if (cardTool.viewWidth >= units.gu(128)) return units.gu(26);
152+ return units.gu(18 + Math.round((cardTool.viewWidth - units.gu(40)) / units.gu(11)));
153+ }
154+
155+ readonly property real pathItemCount: 4.8457 /// (848 / 175) reference values
156+
157+ property real realPathItemCount: {
158+ var scaledMinimumTileWidth = minimumTileWidth / cardTool.carouselSelectedItemScaleFactor;
159+ var tileWidth = Math.max(cardTool.viewWidth / pathItemCount, scaledMinimumTileWidth);
160+ return Math.min(cardTool.viewWidth / tileWidth, pathItemCount);
161+ }
162+ }
163+
126164 Card {
127165 id: card
128− objectName: "card"
166+ objectName: "cardToolCard"
129167 template: cardTool.template
130168 components: cardTool.components
131169
qml/Dash/Dash.qml+57−4
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013, 2014 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
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19−import Unity 0.1
19+import Unity 0.2
2020import Utils 0.1
2121import "../Components"
2222
@@ -27,8 +27,9 @@ Showable {
2727 visible: shown
2828
2929 property ListModel searchHistory: SearchHistoryModel {}
30+ property bool searchable: !dashContent.previewOpen && !scopeItem.previewOpen
3031
31− property string showScopeOnLoaded: "home.scope"
32+ property string showScopeOnLoaded: "clickscope"
3233 property real contentScale: 1.0
3334
3435 function setCurrentScope(scopeId, animate, reset) {
@@ -39,6 +40,10 @@ Showable {
3940 return
4041 }
4142
43+ closeOverlayScope();
44+
45+ dashContent.closePreview();
46+
4247 if (scopeIndex == dashContent.currentIndex && !reset) {
4348 // the scope is already the current one
4449 return
@@ -47,6 +52,12 @@ Showable {
4752 dashContent.setCurrentScopeAtIndex(scopeIndex, animate, reset)
4853 }
4954
55+ function closeOverlayScope() {
56+ if (dashContent.x != 0) {
57+ dashContent.x = 0;
58+ }
59+ }
60+
5061 SortFilterProxyModel {
5162 id: filteredScopes
5263 model: Scopes {
@@ -61,10 +72,19 @@ Showable {
6172 DashContent {
6273 id: dashContent
6374 objectName: "dashContent"
64− anchors.fill: parent
75+ width: parent.width
76+ height: parent.height
6577 model: filteredScopes
6678 scopes: scopes
6779 searchHistory: dash.searchHistory
80+ visible: x != -width
81+ onGotoScope: {
82+ dash.setCurrentScope(scopeId, true, false);
83+ }
84+ onOpenScope: {
85+ scopeItem.scope = scope;
86+ x = -width;
87+ }
6888 onScopeLoaded: {
6989 if (scopeId == dash.showScopeOnLoaded) {
7090 dash.setCurrentScope(scopeId, false, false)
@@ -72,6 +92,39 @@ Showable {
7292 }
7393 }
7494 scale: dash.contentScale
95+ clip: scale != 1.0 || scopeItem.visible
96+ Behavior on x {
97+ UbuntuNumberAnimation {
98+ onRunningChanged: {
99+ if (!running && dashContent.x == 0) {
100+ dashContent.closeScope(scopeItem.scope);
101+ scopeItem.scope = null;
102+ }
103+ }
104+ }
105+ }
106+ }
107+
108+ ScopeItem {
109+ id: scopeItem
110+ anchors.left: dashContent.right
111+ width: parent.width
112+ height: parent.height
113+ searchHistory: dash.searchHistory
114+ scale: dash.contentScale
75115 clip: scale != 1.0
116+ visible: scope != null
117+ onBack: {
118+ closeOverlayScope();
119+ }
120+ onGotoScope: {
121+ // TODO
122+ console.log("gotoScope from an openScope scope is not implemented");
123+ }
124+ onOpenScope: {
125+ // TODO
126+ console.log("openScope from an openScope scope is not implemented");
127+ }
128+
76129 }
77130}
qml/Dash/DashApps.qml+4−19
@@ -29,28 +29,13 @@ GenericScopeView {
2929 property var mainStageApplicationsModel: shell.applicationManager.mainStageApplications
3030 property var sideStageApplicationModel: shell.applicationManager.sideStageApplications
3131
32− ListModel {
33− id: dummyVisibilityModifier
34−
35− ListElement { name: "running-apps" }
36− }
37−
38− SortFilterProxyModel {
39− id: runningApplicationsModel
40−
41− property var firstModel: mainStageApplicationsModel
42− property var secondModel: sideStageApplicationModel
43− property bool canEnableTerminationMode: scopeView.isCurrent
44−
45− model: dummyVisibilityModifier
46− filterRole: 0
47− filterRegExp: invertMatch ? ((mainStageApplicationsModel.count === 0 &&
48− sideStageApplicationModel.count === 0) ? RegExp("running-apps") : RegExp("")) : RegExp("disabled")
49− invertMatch: scopeView.scope.searchQuery.length == 0
32+ QtObject {
33+ id: countObject
34+ property int count: scopeView.scope.searchQuery.length == 0 ? (mainStageApplicationsModel.count + sideStageApplicationModel.count) : 0
5035 }
5136
5237 onScopeChanged: {
53− scopeView.scope.categories.overrideResults("recent", runningApplicationsModel);
38+ scopeView.scope.categories.addSpecialCategory("running.apps.category", "Recent", "", "{ \"template\": { \"category-layout\": \"running-apps\" } }", countObject);
5439 enableHeightBehaviorOnNextCreation = (mainStageApplicationsModel.count + sideStageApplicationModel.count == 0)
5540 }
5641}
qml/Dash/DashContent.qml+62−43
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013, 2014 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
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19−import Unity 0.1
19+import Unity 0.2
2020import Utils 0.1
2121import "../Components"
2222
@@ -25,7 +25,8 @@ Item {
2525
2626 property var model: null
2727 property var scopes: null
28− property alias currentIndex: dashContentList.currentIndex
28+ readonly property alias currentIndex: dashContentList.currentIndex
29+ property alias previewOpen: previewListView.open
2930
3031 property ScopeDelegateMapper scopeMapper : ScopeDelegateMapper {}
3132 property ListModel searchHistory
@@ -34,6 +35,8 @@ Item {
3435 signal movementEnded()
3536 signal scopeLoaded(string scopeId)
3637 signal positionedAtBeginning()
38+ signal gotoScope(string scopeId)
39+ signal openScope(var scope)
3740
3841 // If we set the current scope index before the scopes have been added,
3942 // then we need to wait until the loaded signals gets emitted from the scopes
@@ -49,6 +52,12 @@ Item {
4952 }
5053
5154 function setCurrentScopeAtIndex(index, animate, reset) {
55+ // if the scopes haven't loaded yet, then wait until they are.
56+ if (!scopes.loaded) {
57+ set_current_index = [ index, animate, reset ]
58+ return;
59+ }
60+
5261 var storedMoveDuration = dashContentList.highlightMoveDuration
5362 var storedMoveSpeed = dashContentList.highlightMoveVelocity
5463 if (!animate) {
@@ -56,11 +65,6 @@ Item {
5665 dashContentList.highlightMoveDuration = 0
5766 }
5867
59− // if the scopes haven't loaded yet, then wait until they are.
60− if (!scopes.loaded) {
61− set_current_index = [ index, animate, reset ]
62− return;
63− }
6468 set_current_index = undefined;
6569
6670 if (dashContentList.count > index)
@@ -78,15 +82,27 @@ Item {
7882 }
7983 }
8084
85+ function closeScope(scope) {
86+ dashContentList.currentItem.theScope.closeScope(scope)
87+ }
88+
89+ function closePreview() {
90+ previewListView.open = false;
91+ }
92+
8193 Item {
8294 id: dashContentListHolder
83− anchors.fill: parent
95+
96+ x: previewListView.open ? -width : 0
97+ Behavior on x { UbuntuNumberAnimation { } }
98+ width: parent.width
99+ height: parent.height
84100
85101 ListView {
86102 id: dashContentList
87103 objectName: "dashContentList"
88104
89− interactive: dashContent.scopes.loaded && !previewListView.onScreen && !currentItem.moving
105+ interactive: dashContent.scopes.loaded && !previewListView.open && currentItem && !currentItem.moving
90106
91107 anchors.fill: parent
92108 model: dashContent.model
@@ -101,6 +117,7 @@ Item {
101117 cacheBuffer: 1073741823
102118 onMovementStarted: dashContent.movementStarted()
103119 onMovementEnded: dashContent.movementEnded()
120+ clip: parent.x != 0
104121
105122 // If the number of items is less than the current index, then need to reset to another item.
106123 onCountChanged: {
@@ -109,7 +126,7 @@ Item {
109126 dashContent.setCurrentScopeAtIndex(count-1, true, true)
110127 } else if (currentIndex < 0) {
111128 // setting currentIndex directly, cause we don't want to loose set_current_index
112− dashContent.currentIndex = 0
129+ dashContentList.currentIndex = 0
113130 }
114131 }
115132 }
@@ -132,35 +149,44 @@ Item {
132149 readonly property bool isLoaded: status == Loader.Ready
133150
134151 onLoaded: {
152+ item.objectName = scope.id
153+ item.pageHeader = dashPageHeader;
154+ item.previewListView = previewListView;
135155 item.scope = Qt.binding(function() { return scope })
136156 item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
137− item.tabBarHeight = pageHeader.implicitHeight;
138− item.pageHeader = pageHeader;
139− item.openEffect = openEffect;
140− item.previewListView = previewListView;
157+ item.tabBarHeight = dashPageHeader.implicitHeight;
141158 dashContentList.movementStarted.connect(item.movementStarted)
142159 dashContent.positionedAtBeginning.connect(item.positionedAtBeginning)
143160 dashContent.scopeLoaded(item.scope.id)
144161 }
162+ Connections {
163+ target: isCurrent ? scope : null
164+ onGotoScope: {
165+ // Note here scopeId is the signal parameter and not the loader property
166+ dashContent.gotoScope(scopeId);
167+ }
168+ onOpenScope: {
169+ dashContent.openScope(scope);
170+ }
171+ }
145172
146173 Component.onDestruction: active = false
147174 }
148175 }
149176
150177 PageHeader {
151− id: pageHeader
178+ id: dashPageHeader
152179 objectName: "pageHeader"
153180 width: parent.width
154181 searchEntryEnabled: true
155182 searchHistory: dashContent.searchHistory
156− scope: dashContentList.currentItem.theScope
183+ scope: dashContentList.currentItem && dashContentList.currentItem.theScope
157184
158185 childItem: TabBar {
159186 id: tabBar
160187 objectName: "tabbar"
161− height: units.gu(7)
188+ height: units.gu(6.5)
162189 width: parent.width
163− selectionMode: false
164190 style: DashContentTabBarStyle {}
165191
166192 SortFilterProxyModel {
@@ -170,6 +196,13 @@ Item {
170196
171197 property int selectedIndex: -1
172198 onSelectedIndexChanged: {
199+ if (dashContentList.currentIndex == -1 && tabBar.selectedIndex != -1) {
200+ // TODO This together with the Timer below
201+ // are a workaround for the first tab sometimes not showing the text.
202+ // But Tabs are going away in the future so not sure if makes
203+ // sense invetigating what's the problem at this stage
204+ selectionModeTimer.restart();
205+ }
173206 dashContentList.currentIndex = selectedIndex;
174207 }
175208 }
@@ -183,37 +216,23 @@ Item {
183216 }
184217 }
185218
186− Connections {
187− target: model
188− onCountChanged: {
189− if (tabBarModel.selectedIndex < 0 && tabBarModel.count > 0)
190− tabBarModel.selectedIndex = 0;
191− }
192− }
193−
194− Component.onCompleted: {
195− __styleInstance.headerTextStyle = Text.Raised
196− __styleInstance.headerTextStyleColor = "black"
219+ Timer {
220+ id: selectionModeTimer
221+ interval: 1
222+ onTriggered: tabBar.selectionMode = false
197223 }
198224 }
199225 }
200226 }
201227
202− DashContentOpenEffect {
203− id: openEffect
204− anchors {
205− fill: parent
206− bottomMargin: -bottomOverflow
207− }
208− sourceItem: dashContentListHolder
209− previewListView: previewListView
210− }
211−
212228 PreviewListView {
213229 id: previewListView
214− openEffect: openEffect
215− categoryView: dashContentList.currentItem ? dashContentList.currentItem.categoryView : null
230+ objectName: "dashContentPreviewList"
231+ visible: x != width
216232 scope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
217− anchors.fill: parent
233+ pageHeader: dashPageHeader
234+ width: parent.width
235+ height: parent.height
236+ anchors.left: dashContentListHolder.right
218237 }
219238}
qml/Dash/DashContentOpenEffect.qmldeleted−57
@@ -1,57 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../Components"
20−
21−OpenEffect {
22− property PreviewListView previewListView: null
23−
24− objectName: "openEffect"
25− anchors {
26− fill: parent
27− bottomMargin: -bottomOverflow
28− }
29−
30− enabled: gap > 0.0
31−
32− topGapPx: (1 - gap) * positionPx
33− topOpacity: (1 - gap * 1.2)
34− bottomGapPx: positionPx + gap * (targetBottomGapPx - positionPx)
35− bottomOverflow: units.gu(20)
36− live: !expansionAnimation.running
37−
38− property int targetBottomGapPx: height - units.gu(8) - bottomOverflow
39− property real gap: previewListView.open ? 1.0 : 0.0
40−
41− Behavior on gap {
42− NumberAnimation {
43− id: expansionAnimation
44− duration: 200
45− easing.type: Easing.InOutQuad
46− onRunningChanged: {
47− if (!previewListView.open && !running) {
48− previewListView.onScreen = false
49− }
50− }
51− }
52− }
53− Behavior on positionPx {
54− enabled: previewListView.open
55− UbuntuNumberAnimation {}
56− }
57−}
qml/Dash/DashContentTabBarStyle.qml+3
@@ -18,4 +18,7 @@ import Ubuntu.Components.Themes.Ambiance 0.1
1818
1919TabBarStyle {
2020 indicatorImageSource: "graphics/tabbarchevron.png"
21+ // TODO karni: These should come from updated Ubuntu Palette.
22+ headerTextColor: "#88888888"
23+ headerTextSelectedColor: "#888888"
2124}
qml/Dash/DashFilterGrid.qmldeleted−65
@@ -1,65 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import "../Components"
19−import ".."
20−
21−DashRenderer {
22− id: dashFilterGrid
23−
24− property alias cellWidth: filterGrid.cellWidth
25− property alias cellHeight: filterGrid.cellHeight
26− property alias delegate: filterGrid.delegate
27− property alias delegateWidth: filterGrid.delegateWidth
28− property alias delegateHeight: filterGrid.delegateHeight
29− property alias maximumNumberOfColumns: filterGrid.maximumNumberOfColumns
30− property alias minimumHorizontalSpacing: filterGrid.minimumHorizontalSpacing
31−
32− collapsedHeight: filterGrid.collapsedHeight
33− collapsedRowCount: filterGrid.collapsedRowCount
34− columns: filterGrid.columns
35− rows: filter ? filterGrid.collapsedRowCount : filterGrid.uncollapsedRowCount
36− currentItem: filterGrid.currentItem
37− expandable: filterGrid.expandable
38− height: filterGrid.height
39− margins: filterGrid.margins
40− uncollapsedHeight: filterGrid.uncollapsedHeight
41− verticalSpacing: filterGrid.verticalSpacing
42−
43− function startFilterAnimation(filter) {
44− filterGrid.startFilterAnimation(filter)
45− }
46−
47− FilterGrid {
48− id: filterGrid
49− width: dashFilterGrid.width
50− minimumHorizontalSpacing: units.gu(0.5)
51− delegateWidth: units.gu(11)
52− delegateHeight: units.gu(9.5)
53− verticalSpacing: units.gu(2)
54− model: dashFilterGrid.model
55− filter: dashFilterGrid.filter
56− highlightIndex: dashFilterGrid.highlightIndex
57− delegateCreationBegin: dashFilterGrid.delegateCreationBegin
58− delegateCreationEnd: dashFilterGrid.delegateCreationEnd
59−
60− onFilterChanged: {
61− dashFilterGrid.filter = filter
62− filter = Qt.binding(function() { return dashFilterGrid.filter })
63− }
64− }
65−}
qml/Dash/DashHome.qmldeleted−39
@@ -1,39 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import Utils 0.1
20−import "../Components"
21−import "../Components/ListItems"
22−import "Apps"
23−
24−GenericScopeView {
25− id: root
26− objectName: "DashHome"
27−
28− SearchableResultModel {
29− id: appsModel
30−
31− model: FrequentlyUsedAppsModel {}
32− filterRole: 3
33− searchQuery: root.scope.searchQuery
34− }
35−
36− onScopeChanged: {
37− root.scope.categories.overrideResults("applications.scope", appsModel);
38− }
39−}
qml/Dash/DashPreview.qmldeleted−208
@@ -1,208 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: root
22−
23− property int keyboardSize: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
24− property var previewData
25− property alias showProcessingAction: waitingForActionMouseArea.enabled
26−
27− property real previewWidthRatio: 0.5
28− property bool isCurrent: false
29−
30− property Component previewImages
31− property Component header
32− property Component actions
33− property Component description
34− property Component ratings
35−
36− readonly property bool narrowMode: width <= height * 1.5
37− readonly property int columnWidth: narrowMode ? contentRow.width : (contentRow.width / 3) - contentRow.spacing
38− readonly property int contentSpacing: units.gu(3)
39−
40− clip: true
41−
42− function ensureVisible(item) {
43− var o = leftFlickable.mapFromItem(item, 0, 0, item.width, item.height);
44− var keyboardY = shell.height - root.keyboardSize;
45− if ((o.y + o.height) > keyboardY) {
46− leftFlickable.contentY += o.y + o.height - keyboardY;
47− }
48− }
49−
50− Connections {
51− target: shell.applicationManager
52− onMainStageFocusedApplicationChanged: {
53− root.close();
54− }
55− onSideStageFocusedApplicationChanged: {
56− root.close();
57− }
58− }
59−
60− onPreviewDataChanged: showProcessingAction = false
61−
62− MouseArea {
63− anchors.fill: parent
64− }
65−
66− Row {
67− id: contentRow
68− anchors {
69− left: parent.left
70− top: parent.top
71− right: parent.right
72− bottom: parent.bottom
73− topMargin: root.contentSpacing
74− leftMargin: root.contentSpacing
75− rightMargin: root.contentSpacing
76− }
77− height: childrenRect.height
78−
79− spacing: units.gu(2)
80−
81−
82− Flickable {
83− id: leftFlickable
84− objectName: "leftFlickable"
85− anchors {
86− top: parent.top
87− bottom: parent.bottom
88− }
89− width: root.columnWidth
90− contentHeight: leftColumn.height + root.contentSpacing
91− anchors.bottomMargin: root.keyboardSize
92− clip: true
93−
94− Behavior on contentY { NumberAnimation { duration: 300 } }
95−
96− Column {
97− id: leftColumn
98− objectName: "leftColumn"
99− height: childrenRect.height
100− spacing: root.contentSpacing
101− anchors {
102− left: parent.left
103− right: parent.right
104− }
105− }
106− }
107−
108− Flickable {
109− id: centerFlickable
110− anchors {
111− top: parent.top
112− bottom: parent.bottom
113− }
114− width: root.columnWidth
115− contentHeight: centerColumn.height
116− clip: true
117−
118− Column {
119− id: centerColumn
120− objectName: "centerColumn"
121− height: childrenRect.height
122− anchors {
123− left: parent.left
124− right: parent.right
125− }
126− spacing: root.contentSpacing
127− }
128− }
129−
130− Flickable {
131− id: rightFlickable
132− anchors {
133− top: parent.top
134− bottom: parent.bottom
135− }
136− width: root.columnWidth
137− contentHeight: rightColumn.height
138− clip: true
139−
140− Column {
141− id: rightColumn
142− objectName: "rightColumn"
143− height: childrenRect.height
144− anchors {
145− left: parent.left
146− right: parent.right
147− }
148− }
149− }
150− }
151−
152− Loader {
153− id: previewImageLoader
154− parent: leftColumn
155− sourceComponent: root.previewImages
156− anchors {
157− left: parent.left
158− right: parent.right
159− }
160− }
161−
162− Loader {
163− id: ratingsLoader
164− parent: root.narrowMode ? leftColumn : rightColumn
165− anchors {
166− left: parent.left
167− right: parent.right
168− }
169− sourceComponent: root.ratings
170− }
171−
172− Loader {
173− id: descriptionLoader
174− parent: root.narrowMode ? leftColumn : centerColumn
175− anchors {
176− left: parent.left
177− right: parent.right
178− }
179− sourceComponent: root.description
180− }
181−
182− Loader {
183− id: actionsLoader
184− parent: root.narrowMode ? leftColumn : centerColumn
185− anchors {
186− left: parent.left
187− right: parent.right
188− }
189− sourceComponent: root.actions
190− }
191−
192− Loader {
193− id: headerLoader
194− parent: root.narrowMode ? leftColumn : centerColumn
195− anchors {
196− left: parent.left
197− right: parent.right
198− }
199− sourceComponent: root.header
200− }
201−
202− MouseArea {
203− id: waitingForActionMouseArea
204− objectName: "waitingForActionMouseArea"
205− anchors.fill: parent
206− enabled: false
207− }
208−}
qml/Dash/DashPreviewPlaceholder.qmldeleted−25
@@ -1,25 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−DashPreview {
21− ActivityIndicator {
22− anchors.centerIn: parent
23− running: true
24− }
25−}
qml/Dash/DashRenderer.qml+5−3
@@ -31,9 +31,6 @@ Item {
3131
3232 property int rows: 1
3333
34− // Index of the highlighted item
35− property int highlightIndex: -1
36−
3734 property int margins: 0
3835
3936 property int uncollapsedHeight: height
@@ -50,6 +47,11 @@ Item {
5047 // The model to renderer
5148 property var model
5249
50+ /*!
51+ \brief CardTool component.
52+ */
53+ property var cardTool: undefined
54+
5355 /// Emitted when the user clicked on an item
5456 /// @param index is the index of the clicked item
5557 /// @param itemY is y of the clicked delegate
qml/Dash/Generic/FlatTileStyle.qmldeleted−79
@@ -1,79 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: tile
22−
23− property bool disabled: false
24−
25− anchors.fill: parent
26−
27− Image {
28− id: icon
29− objectName: "image"
30− width: styledItem.imageWidth
31− height: styledItem.imageHeight
32−
33− anchors.horizontalCenter: parent.horizontalCenter
34−
35− sourceSize { width: width; height: height }
36− asynchronous: true
37− cache: false
38− source: styledItem.source
39− fillMode: styledItem.fillMode
40− opacity: tile.disabled ? 0.3 : 1.0
41− horizontalAlignment: Image.AlignHCenter
42− verticalAlignment: Image.AlignVCenter
43− }
44−
45− UbuntuShape {
46− id: borderPressed
47− objectName: "borderPressed"
48−
49− anchors.fill: icon
50− radius: "medium"
51− borderSource: "radius_pressed.sci"
52− opacity: styledItem.pressed ? 1.0 : 0.0
53− Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
54− }
55−
56− Label {
57− id: label
58− objectName: "label"
59− anchors {
60− baseline: icon.bottom
61− baselineOffset: units.gu(2)
62− left: parent.left
63− right: parent.right
64− leftMargin: units.gu(1)
65− rightMargin: units.gu(1)
66− }
67−
68− color: Theme.palette.selected.backgroundText
69− opacity: 0.9
70− style: Text.Raised
71− styleColor: "black"
72− fontSize: "small"
73− elide: Text.ElideMiddle
74− horizontalAlignment: styledItem.horizontalAlignment
75− text: styledItem.text
76− wrapMode: Text.Wrap
77− maximumLineCount: styledItem.maximumLineCount
78− }
79−}
qml/Dash/Generic/GenericCarousel.qmldeleted−53
@@ -1,53 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−import ".."
21−
22−DashCarousel {
23− id: genericCarousel
24− itemComponent: carouselDelegateGeneric
25−
26− Component {
27− id: carouselDelegateGeneric
28−
29− BaseCarouselDelegate {
30− id: item
31− objectName: "carouselDelegate"
32−
33− UbuntuShape {
34− anchors.fill: parent
35− radius: "medium"
36− borderSource: ""
37− image: Image {
38− asynchronous: true
39− sourceSize { width: item.width; height: item.height }
40− source: model ? model.icon : ""
41− }
42− }
43−
44− BorderImage {
45− anchors.centerIn: parent
46− opacity: 0.6
47− source: "../../Components/graphics/non-selected.sci"
48− width: parent.width + units.gu(1.5)
49− height: parent.height + units.gu(1.5)
50− }
51− }
52− }
53−}
qml/Dash/Generic/GenericFilterGrid.qmldeleted−46
@@ -1,46 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−import ".."
21−
22−DashFilterGrid {
23− id: genericFilterGrid
24−
25− property int iconWidth: units.gu(8)
26− property int iconHeight: units.gu(7.5)
27−
28− minimumHorizontalSpacing: units.gu(0.5)
29− delegateWidth: units.gu(11)
30− delegateHeight: units.gu(9.5)
31− verticalSpacing: units.gu(2)
32−
33− delegate: Tile {
34− id: tile
35− objectName: "delegate" + index
36− width: genericFilterGrid.cellWidth
37− height: genericFilterGrid.cellHeight
38− text: model.title
39− imageWidth: genericFilterGrid.iconWidth
40− imageHeight: genericFilterGrid.iconHeight
41− source: model.icon
42−
43− onClicked: genericFilterGrid.clicked(index, tile.y)
44− onPressAndHold: genericFilterGrid.pressAndHold(index, tile.y)
45− }
46−}
qml/Dash/Generic/GenericFilterGridPotrait.qmldeleted−28
@@ -1,28 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−
21−GenericFilterGrid {
22− minimumHorizontalSpacing: units.gu(0.5)
23− delegateWidth: units.gu(11)
24− delegateHeight: units.gu(18)
25− verticalSpacing: units.gu(2)
26− iconWidth: (width / columns) * 0.8
27− iconHeight: iconWidth * 16 / 11
28−}
qml/Dash/Generic/GenericPreview.qmldeleted−197
@@ -1,197 +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−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import Ubuntu.Components.ListItems 0.1 as ListItems
20−import Ubuntu.DownloadDaemonListener 0.1
21−import "../../Components"
22−import ".."
23−import "../Previews"
24−
25−DashPreview {
26− id: genericPreview
27−
28− previewImages: previewImagesComponent
29− header: headerComponent
30− actions: (previewData.infoMap !== undefined && previewData.infoMap["show_progressbar"]) ? progressComponent : actionsComponent
31− description: descriptionComponent
32−
33− Component {
34− id: previewImagesComponent
35−
36− LazyImage {
37− objectName: "genericPreviewImage"
38− anchors {
39− left: parent.left
40− right: parent.right
41− }
42− scaleTo: "width"
43− source: genericPreview.previewData.image
44− initialHeight: width
45− }
46− }
47−
48− Component {
49− id: headerComponent
50− Header {
51− title: previewData.title
52− subtitle: previewData.subtitle
53− }
54− }
55−
56− Component {
57− id: actionsComponent
58−
59− Column {
60− id: buttonList
61− spacing: units.gu(1)
62− Repeater {
63− objectName: "buttonList"
64− model: previewData.actions
65−
66− delegate: Button {
67− objectName: "button" + index
68− width: parent.width
69− height: buttonList.buttonHeight
70− color: Theme.palette.selected.foreground
71− text: modelData.displayName
72− iconSource: modelData.iconHint
73− iconPosition: "right"
74− onClicked: {
75− previewData.execute(modelData.id, { })
76− genericPreview.showProcessingAction = true;
77− }
78− }
79− }
80− }
81− }
82−
83− Component {
84− id: progressComponent
85−
86− ProgressBar {
87− id: progressBar
88− objectName: "progressBar"
89− value: 0
90− maximumValue: 100
91− height: units.gu(5)
92−
93− property var model: previewData.actions
94−
95− DownloadTracker {
96− service: "com.canonical.applications.Downloader"
97− dbusPath: previewData.infoMap["progressbar_source"] ? previewData.infoMap["progressbar_source"].value : ""
98−
99− onProgress: {
100− var percentage = parseInt(received * 100 / total);
101− progressBar.value = percentage;
102− }
103−
104− onFinished: {
105− previewData.execute(progressBar.model[0].id, { })
106− }
107−
108− onError: {
109− previewData.execute(progressBar.model[1].id, { "error": error });
110− }
111− }
112−
113− }
114− }
115−
116− Component {
117− id: descriptionComponent
118− Column {
119− spacing: units.gu(2)
120−
121− Label {
122− id: descriptionLabel
123− objectName: "descriptionLabel"
124− anchors { left: parent.left; right: parent.right }
125− visible: text != ""
126− fontSize: "small"
127− opacity: 0.6
128− color: "white"
129− text: previewData.description.replace(/[\r\n]/g, "<br />")
130− style: Text.Raised
131− styleColor: "black"
132− wrapMode: Text.WordWrap
133− textFormat: Text.RichText
134− // FIXME: workaround for https://bugreports.qt-project.org/browse/QTBUG-33020
135− onWidthChanged: { wrapMode = Text.NoWrap; wrapMode = Text.WordWrap }
136− }
137−
138− Column {
139− objectName: "infoHintColumn"
140− anchors {
141− left: parent.left
142− right: parent.right
143− }
144− Repeater {
145− objectName: "infoHintRepeater"
146− model: previewData.infoHints
147−
148− delegate: Item {
149− objectName: "infoHintItem" + index
150− width: parent.width
151− height: units.gu(5)
152− Row {
153− width: parent.width
154− spacing: units.gu(1)
155− property int columnWidth: (width - spacing) / 2
156− anchors.verticalCenter: parent.verticalCenter
157−
158− Label {
159− objectName: "displayNameLabel"
160− visible: valueLabel.visible
161− fontSize: "small"
162− opacity: 0.9
163− color: "white"
164− horizontalAlignment: Text.AlignLeft
165− width: parent.columnWidth
166− text: modelData.displayName
167− style: Text.Raised
168− styleColor: "black"
169− }
170− Label {
171− id: valueLabel
172− objectName: "valueLabel"
173− visible: modelData.value != ""
174− fontSize: "small"
175− opacity: 0.6
176− color: "white"
177− horizontalAlignment: Text.AlignRight
178− width: parent.columnWidth
179− text: modelData.value ? modelData.value : ""
180− style: Text.Raised
181− styleColor: "black"
182− wrapMode: Text.WordWrap
183− }
184− }
185− ListItems.ThinDivider {
186− anchors {
187− left: parent.left
188− bottom: parent.bottom
189− right: parent.right
190− }
191− }
192− }
193− }
194− }
195− }
196− }
197−}
qml/Dash/Generic/WeatherFilterGrid.qmldeleted−47
@@ -1,47 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−
21−GenericFilterGrid {
22− id: filtergrid
23−
24− delegateHeight: units.gu(11.5)
25−
26− delegate: Tile {
27− id: tile
28− objectName: "delegate" + index
29− width: filtergrid.cellWidth
30− height: filtergrid.cellHeight
31− text: model.title
32− imageWidth: filtergrid.iconWidth
33− imageHeight: filtergrid.iconHeight
34− source: model.icon
35− maximumLineCount: 2
36−
37− style: FlatTileStyle {}
38−
39− onClicked: {
40− filtergrid.clicked(index, tile.y)
41− }
42−
43− onPressAndHold: {
44− filtergrid.pressAndHold(index, tile.y)
45− }
46− }
47−}
qml/Dash/GenericScopeView.qml+66−125
@@ -17,20 +17,19 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Utils 0.1
20−import Unity 0.1
20+import Unity 0.2
2121import "../Components"
2222import "../Components/ListItems" as ListItems
2323
2424FocusScope {
2525 id: scopeView
2626
27− property Scope scope
27+ property Scope scope: null
2828 property SortFilterProxyModel categories: categoryFilter
29− property bool isCurrent
29+ property bool isCurrent: false
3030 property alias moving: categoryView.moving
3131 property int tabBarHeight: 0
3232 property PageHeader pageHeader: null
33− property OpenEffect openEffect: null
3433 property Item previewListView: null
3534
3635 signal movementStarted
@@ -55,7 +54,7 @@ FocusScope {
5554 Binding {
5655 target: scope
5756 property: "isActive"
58− value: isCurrent && !previewListView.onScreen
57+ value: isCurrent && !previewListView.open
5958 }
6059
6160 Timer {
@@ -92,7 +91,7 @@ FocusScope {
9291 Binding {
9392 target: pageHeader
9493 property: "searchQuery"
95− value: scopeView.scope.searchQuery
94+ value: scopeView.scope ? scopeView.scope.searchQuery : ""
9695 when: isCurrent
9796 }
9897
@@ -115,30 +114,34 @@ FocusScope {
115114 objectName: "categoryListView"
116115 anchors.fill: parent
117116 model: scopeView.categories
118− forceNoClip: previewListView.onScreen
117+ forceNoClip: previewListView.open
119118
120119 property string expandedCategoryId: ""
121− signal correctExpandedCategory();
122120
123121 onContentYChanged: pageHeader.positionRealHeader();
124122 onOriginYChanged: pageHeader.positionRealHeader();
125123 onContentHeightChanged: pageHeader.positionRealHeader();
126124
127− Behavior on contentY {
128− enabled: previewListView.open
129− UbuntuNumberAnimation {}
130− }
131−
132125 delegate: ListItems.Base {
133126 id: baseItem
134127 objectName: "dashCategory" + category
135128 highlightWhenPressed: false
129+ showDivider: false
136130
137131 readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
138132 readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filter : true
139133 readonly property string category: categoryId
140134 readonly property var item: rendererLoader.item
141135
136+ CardTool {
137+ id: cardTool
138+
139+ count: results.count
140+ template: model.renderer
141+ components: model.components
142+ viewWidth: parent.width
143+ }
144+
142145 Loader {
143146 id: rendererLoader
144147 anchors {
@@ -147,7 +150,14 @@ FocusScope {
147150 right: parent.right
148151 }
149152
150− source: getRenderer(model.renderer, model.contentType, model.rendererHint, results)
153+ source: {
154+ switch (cardTool.categoryLayout) {
155+ case "carousel": return "CardCarousel.qml";
156+ case "running-apps": return "Apps/RunningApplicationsGrid.qml";
157+ case "grid":
158+ default: return "CardFilterGrid.qml";
159+ }
160+ }
151161
152162 onLoaded: {
153163 if (item.enableHeightBehavior !== undefined && item.enableHeightBehaviorOnNextCreation !== undefined) {
@@ -155,9 +165,10 @@ FocusScope {
155165 scopeView.enableHeightBehaviorOnNextCreation = false;
156166 }
157167 if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) {
158− // TODO: the running apps grid doesn't support standard scope results model yet
159− item.firstModel = Qt.binding(function() { return results.firstModel })
160− item.secondModel = Qt.binding(function() { return results.secondModel })
168+ // TODO: this is still a kludge :D Ideally add some kind of hook so that we
169+ // can do this from DashApps.qml or think a better way that needs no special casing
170+ item.firstModel = Qt.binding(function() { return mainStageApplicationsModel })
171+ item.secondModel = Qt.binding(function() { return sideStageApplicationModel })
161172 item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent })
162173 } else {
163174 item.model = Qt.binding(function() { return results })
@@ -170,6 +181,7 @@ FocusScope {
170181 }
171182 }
172183 updateDelegateCreationRange();
184+ item.cardTool = cardTool;
173185 }
174186
175187 Component.onDestruction: {
@@ -181,39 +193,24 @@ FocusScope {
181193 Connections {
182194 target: rendererLoader.item
183195 onClicked: {
184− // Prepare the preview in case activate() triggers a preview only
185− openEffect.positionPx = Math.max(mapToItem(categoryView, 0, itemY).y, pageHeader.height + categoryView.stickyHeaderHeight);
186− previewListView.categoryId = categoryId
187− previewListView.categoryDelegate = rendererLoader.item
188− previewListView.model = target.model;
189− previewListView.init = true;
190− previewListView.currentIndex = index;
191−
192− var item = target.model.get(index);
193−
194− if ((scopeView.scope.id == "applications.scope" && categoryId == "installed")
195− || (scopeView.scope.id == "home.scope" && categoryId == "applications.scope")) {
196− scopeView.scope.activate(item.uri, item.icon, item.category, 0, item.mimetype, item.title,
197− item.comment, item.dndUri, item.metadata)
196+ if (scopeView.scope.id === "scopes" || (scopeView.scope.id == "clickscope" && categoryId == "local")) {
197+ // TODO Technically it is possible that calling activate() will make the scope emit
198+ // previewRequested so that we show a preview but there's no scope that does that yet
199+ // so it's not implemented
200+ var item = target.model.get(index);
201+ scopeView.scope.activate(item.result)
198202 } else {
203+ previewListView.model = target.model;
204+ previewListView.currentIndex = -1
205+ previewListView.currentIndex = index;
199206 previewListView.open = true
200−
201− scopeView.scope.preview(item.uri, item.icon, item.category, 0, item.mimetype, item.title,
202− item.comment, item.dndUri, item.metadata)
203207 }
204208 }
205209 onPressAndHold: {
206− openEffect.positionPx = Math.max(mapToItem(categoryView, 0, itemY).y, pageHeader.height + categoryView.stickyHeaderHeight);
207− previewListView.categoryId = categoryId
208− previewListView.categoryDelegate = rendererLoader.item
209210 previewListView.model = target.model;
210− previewListView.init = true;
211+ previewListView.currentIndex = -1
211212 previewListView.currentIndex = index;
212213 previewListView.open = true
213−
214− var item = target.model.get(index)
215− scopeView.scope.preview(item.uri, item.icon, item.category, 0, item.mimetype, item.title,
216− item.comment, item.dndUri, item.metadata)
217214 }
218215 }
219216 Connections {
@@ -221,9 +218,6 @@ FocusScope {
221218 onExpandedCategoryIdChanged: {
222219 collapseAllButExpandedCategory();
223220 }
224− onCorrectExpandedCategory: {
225− collapseAllButExpandedCategory();
226− }
227221 function collapseAllButExpandedCategory() {
228222 var item = rendererLoader.item;
229223 if (item.expandable) {
@@ -275,6 +269,31 @@ FocusScope {
275269 }
276270 }
277271 }
272+
273+ Image {
274+ visible: index != 0
275+ anchors {
276+ top: parent.top
277+ left: parent.left
278+ right: parent.right
279+ }
280+ fillMode: Image.Stretch
281+ source: "graphics/dash_divider_top_lightgrad.png"
282+ z: -1
283+ }
284+
285+ Image {
286+ // FIXME Should not rely on model.count but view.count, but ListViewWithPageHeader doesn't expose it yet.
287+ visible: index != categoryView.model.count - 1
288+ anchors {
289+ bottom: parent.bottom
290+ left: parent.left
291+ right: parent.right
292+ }
293+ fillMode: Image.Stretch
294+ source: "graphics/dash_divider_top_darkgrad.png"
295+ z: -1
296+ }
278297 }
279298
280299 onHeightChanged: rendererLoader.updateDelegateCreationRange();
@@ -302,95 +321,17 @@ FocusScope {
302321 pageHeader: Item {
303322 implicitHeight: scopeView.tabBarHeight
304323 onHeightChanged: {
305− if (scopeView.pageHeader) {
324+ if (scopeView.pageHeader && scopeView.isCurrent) {
306325 scopeView.pageHeader.height = height;
307326 }
308327 }
309328 onYChanged: positionRealHeader();
310329
311330 function positionRealHeader() {
312− if (scopeView.pageHeader) {
331+ if (scopeView.pageHeader && scopeView.isCurrent) {
313332 scopeView.pageHeader.y = y + parent.y;
314333 }
315334 }
316335 }
317336 }
318−
319− function getDefaultRendererId(contentType) {
320− switch (contentType) {
321− default: return "grid";
322− }
323− }
324−
325− function getRenderer(rendererId, contentType, rendererHint, results) {
326− if (rendererId == "default") {
327− rendererId = getDefaultRendererId(contentType);
328− }
329− if (rendererId == "carousel") {
330− // Selectively disable carousel, 6 is fixed for now, should change on the form factor
331− if (results.count <= 6)
332− rendererId = "grid"
333− }
334− switch (rendererId) {
335− case "carousel": {
336− switch (contentType) {
337− case "music": return "Music/MusicCarousel.qml";
338− case "video": return "Video/VideoCarousel.qml";
339− default: return "Generic/GenericCarousel.qml";
340− }
341− }
342− case "grid": {
343− switch (contentType) {
344− case "apps": {
345− if (rendererHint == "toggled")
346− return "Apps/DashPluginFilterGrid.qml";
347− else
348− return "Generic/GenericFilterGrid.qml";
349− }
350− case "music": return "Music/MusicFilterGrid.qml";
351− case "video": return "Video/VideoFilterGrid.qml";
352− case "weather": return "Generic/WeatherFilterGrid.qml";
353− default: return "Generic/GenericFilterGrid.qml";
354− }
355− }
356− case "special": {
357− switch (contentType) {
358− case "apps": return "Apps/RunningApplicationsGrid.qml";
359− default: return "Generic/GenericFilterGrid.qml";
360− }
361− }
362− default: return "Generic/GenericFilterGrid.qml";
363− }
364− }
365−
366− Connections {
367− target: scopeView.scope
368− onPreviewReady: {
369− if (previewListView.init) {
370− // Preview was triggered because of a click on the item. Need to expand now.
371− if (!previewListView.open) {
372− previewListView.open = true
373− }
374−
375− var index = previewListView.currentIndex
376− previewListView.currentIndex = -1
377− previewListView.currentIndex = index
378− previewListView.init = false
379− }
380− previewListView.currentItem.previewData = preview
381− }
382− }
383−
384− // TODO: Move as InverseMouseArea to DashPreview
385− MouseArea {
386− objectName: "closePreviewMouseArea"
387− enabled: previewListView.onScreen
388− anchors {
389− fill: parent
390− topMargin: openEffect.bottomGapPx
391− }
392− onClicked: {
393− previewListView.open = false;
394− }
395− }
396337}
qml/Dash/Movie/MoviePreview.qmldeleted−71
@@ -1,71 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import ".."
20−import "../Generic"
21−import "../../Components"
22−import "../Previews"
23−
24−GenericPreview {
25− id: root
26−
27− property bool ready: previewData ? true : false
28− property url url: ready ? previewData.image : ""
29−
30− previewImages: previewImageComponent
31− header: headerComponent
32−
33− Component {
34− id: previewImageComponent
35− LazyImage {
36− anchors.left: parent.left
37− anchors.right: parent.right
38− scaleTo: "width"
39− visible: height > 0
40− source: root.url
41− initialHeight: width * 10 / 16
42−
43− Image {
44− objectName: "playButton"
45− anchors.centerIn: parent
46− readonly property bool bigButton: parent.width > units.gu(40)
47− width: bigButton ? units.gu(8) : units.gu(4.5)
48− height: width
49− source: "../graphics/play_button%1%2.png".arg(previewImageMouseArea.pressed ? "_active" : "").arg(bigButton ? "_big" : "")
50− }
51−
52− MouseArea {
53− id: previewImageMouseArea
54− anchors.fill: parent
55− onClicked: {
56− Qt.openUrlExternally(previewData.result.uri);
57− }
58− }
59− }
60− }
61−
62− Component {
63− id: headerComponent
64− Header {
65− title: previewData.title
66− rating: Math.round(previewData.rating * 10)
67− reviews: previewData.numRatings
68− rated: previewData.infoMap["rated"] ? previewData.infoMap["rated"].value : 0
69− }
70− }
71−}
qml/Dash/Music/CarouselDelegateMusic.qmldeleted−42
@@ -1,42 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−
21−BaseCarouselDelegate {
22− id: item
23−
24− UbuntuShape {
25− anchors.fill: parent
26− radius: "medium"
27− borderSource: ""
28− image: Image {
29− asynchronous: true
30− sourceSize { width: item.width; height: item.height }
31− source: model ? model.icon : ""
32− }
33− }
34−
35− BorderImage {
36− anchors.centerIn: parent
37− opacity: 0.6
38− source: "../../Components/graphics/non-selected.sci"
39− width: parent.width + units.gu(1.5)
40− height: parent.height + units.gu(1.5)
41− }
42−}
qml/Dash/Music/MusicCarousel.qmldeleted−34
@@ -1,34 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import "../../Components"
19−import ".."
20−
21−DashCarousel {
22− id: musicCarousel
23− tileAspectRatio: 1
24− minimumTileWidth: units.gu(13)
25− itemComponent: carouselDelegateMusic
26− selectedItemScaleFactor: 1.2
27− cacheBuffer: 1404 // 18px * 13gu * 6
28−
29− Component {
30− id: carouselDelegateMusic
31− CarouselDelegateMusic {
32− }
33− }
34−}
qml/Dash/Music/MusicFilterGrid.qmldeleted−48
@@ -1,48 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import "../../Components"
19−import "../Generic"
20−
21−GenericFilterGrid {
22− id: musicFilterGrid
23−
24− delegateWidth: units.gu(11)
25− delegateHeight: units.gu(16)
26− iconWidth: units.gu(11)
27− iconHeight: units.gu(11)
28−
29− delegate: Tile {
30− id: tile
31− objectName: "delegate" + index
32− width: musicFilterGrid.cellWidth
33− height: musicFilterGrid.cellHeight
34− text: model.comment
35− imageWidth: musicFilterGrid.iconWidth
36− imageHeight: musicFilterGrid.iconHeight
37− source: model.icon
38− maximumLineCount: 2
39− horizontalAlignment: Text.AlignLeft
40−
41− style: MusicTileStyle {
42− artist: model.title
43− }
44−
45− onClicked: musicFilterGrid.clicked(index, tile.y)
46− onPressAndHold: musicFilterGrid.pressAndHold(index, tile.y)
47− }
48−}
qml/Dash/Music/MusicPreview.qmldeleted−203
@@ -1,203 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtMultimedia 5.0
19−import Ubuntu.Components 0.1
20−import Ubuntu.Components.ListItems 0.1
21−import ".."
22−import "../Generic"
23−import "../../Components"
24−import "../Previews"
25−
26−GenericPreview {
27− id: root
28−
29− previewImages: previewImageComponent
30− header: headerComponent
31− description: descriptionComponent
32−
33− Component {
34− id: previewImageComponent
35− LazyImage {
36− height: units.gu(22)
37− scaleTo: "height"
38− source: previewData ? previewData.image : ""
39− initialHeight: height
40− initialWidth: height
41− }
42− }
43−
44− Component {
45− id: headerComponent
46− Header {
47− title: previewData.title
48− subtitle: previewData.subtitle
49− }
50− }
51−
52− Component {
53− id: descriptionComponent
54−
55− Item {
56− height: childrenRect.height
57− Audio {
58− id: audioPlayer
59− objectName: "audioPlayer"
60− property real progress: audioPlayer.position / audioPlayer.duration
61−
62− property Item playingItem
63−
64− Component.onDestruction: {
65− audioPlayer.stop();
66− }
67−
68− onErrorStringChanged: console.warn("Audio player error:", errorString)
69−
70− }
71−
72− Connections {
73− target: root
74− onIsCurrentChanged: {
75− if (!root.isCurrent) {
76− audioPlayer.stop();
77− }
78− }
79− }
80−
81− Column {
82− anchors { left: parent.left; right: parent.right }
83− visible: trackRepeater.count > 0
84−
85− ThinDivider {
86− objectName: "topDivider"
87− anchors { left: parent.left; right: parent.right }
88− }
89−
90− Repeater {
91− id: trackRepeater
92− objectName: "trackRepeater"
93−
94− model: previewData.tracks
95−
96− delegate: Item {
97− id: trackItem
98− objectName: "trackItem" + index
99− anchors { left: parent.left; right: parent.right }
100− height: units.gu(5)
101− property bool isPlayingItem: audioPlayer.playingItem == trackItem
102−
103− function play() {
104− audioPlayer.stop();
105− // Make sure we change the source, even if two items point to the same uri location
106− audioPlayer.source = "";
107− audioPlayer.source = model.uri;
108− audioPlayer.playingItem = trackItem;
109− audioPlayer.play();
110− }
111−
112− Row {
113− id: trackRow
114− width: parent.width
115− spacing: units.gu(1)
116− property int column1Width: units.gu(3)
117− property int column2Width: width - (2 * spacing) - column1Width - column3Width
118− property int column3Width: units.gu(4)
119− anchors.verticalCenter: parent.verticalCenter
120−
121− Button {
122− objectName: "playButton"
123− width: trackRow.column1Width
124− height: width
125− iconSource: audioPlayer.playbackState == Audio.PlayingState && trackItem.isPlayingItem ? "image://theme/media-playback-pause" : "image://theme/media-playback-start"
126−
127− // Can't be "transparent" or "#00xxxxxx" as the button optimizes away the surrounding shape
128− // FIXME when this is resolved: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1251685
129− color: "#01000000"
130−
131− onClicked: {
132− if (trackItem.isPlayingItem) {
133− if (audioPlayer.playbackState == Audio.PlayingState) {
134− audioPlayer.pause();
135− } else if (audioPlayer.playbackState == Audio.PausedState){
136− audioPlayer.play();
137− }
138− } else {
139− trackItem.play();
140− }
141− }
142− }
143−
144− Label {
145− objectName: "trackTitleLabel"
146− fontSize: "small"
147− opacity: 0.9
148− color: "white"
149− horizontalAlignment: Text.AlignLeft
150− anchors.verticalCenter: parent.verticalCenter
151− width: parent.column2Width
152− text: title
153− style: Text.Raised
154− styleColor: "black"
155− elide: Text.ElideRight
156−
157− UbuntuShape {
158− id: progressBarFill
159− objectName: "progressBarFill"
160− color: UbuntuColors.orange
161− anchors.left: progressBarImage.left
162− anchors.right: progressBarImage.right
163− anchors.verticalCenter: progressBarImage.verticalCenter
164− height: units.dp(2)
165− anchors.margins: units.dp(2)
166− anchors.rightMargin: maxWidth - (maxWidth * audioPlayer.progress) + units.dp(2)
167− visible: progressBarImage.visible
168− property int maxWidth: progressBarImage.width - units.dp(4)
169− }
170−
171− Image {
172− id: progressBarImage
173− anchors { left: parent.left; top: parent.bottom; right: parent.right }
174− height: units.dp(6)
175− visible: audioPlayer.playbackState != Audio.StoppedState && trackItem.isPlayingItem && model.length.length > 0
176− source: "graphics/music_progress_bg.png"
177− }
178− }
179−
180− Label {
181− id: valueLabel
182− objectName: "timeLabel"
183− fontSize: "small"
184− opacity: 0.9
185− color: "white"
186− anchors.verticalCenter: parent.verticalCenter
187− horizontalAlignment: Text.AlignRight
188− width: parent.column3Width
189− text: length
190− style: Text.Raised
191− styleColor: "black"
192− }
193− }
194−
195− ThinDivider {
196− anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
197− }
198− }
199− }
200− }
201− }
202− }
203−}
qml/Dash/Music/MusicTileStyle.qmldeleted−102
@@ -1,102 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: tile
22−
23− property alias artist: artistLabel.text
24−
25− anchors.fill: parent
26−
27− UbuntuShape {
28− id: icon
29− anchors {
30− top: parent.top
31− horizontalCenter: parent.horizontalCenter
32− }
33− radius: "medium"
34− width: styledItem.imageWidth
35− height: styledItem.imageHeight
36− image: Image {
37− id: image
38− objectName: "image"
39− sourceSize { width: icon.width; height: icon.height }
40− asynchronous: true
41− cache: false
42− source: styledItem.source
43− fillMode: styledItem.fillMode
44− horizontalAlignment: Image.AlignHCenter
45− verticalAlignment: Image.AlignVCenter
46− }
47− }
48−
49− UbuntuShape {
50− id: borderPressed
51− objectName: "borderPressed"
52−
53− anchors.fill: icon
54− radius: "medium"
55− borderSource: "radius_pressed.sci"
56− opacity: styledItem.pressed ? 1.0 : 0.0
57− Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
58− }
59−
60− Label {
61− id: label
62− objectName: "label"
63− anchors {
64− baseline: icon.bottom
65− baselineOffset: units.gu(2)
66− left: icon.left
67− right: parent.right
68− rightMargin: units.gu(1)
69− leftMargin: units.dp(2)
70− }
71−
72− color: Theme.palette.selected.backgroundText
73− opacity: 0.9
74− style: Text.Raised
75− styleColor: "black"
76− fontSize: "small"
77− font.weight: Font.Bold
78− elide: Text.ElideRight
79− horizontalAlignment: styledItem.horizontalAlignment
80− text: styledItem.text
81− wrapMode: Text.Wrap
82− maximumLineCount: styledItem.maximumLineCount
83− }
84−
85− Label {
86− id: artistLabel
87− anchors {
88− top: label.bottom
89− left: label.left
90− right: label.right
91− rightMargin: units.gu(1)
92− }
93−
94− color: Theme.palette.selected.backgroundText
95− opacity: 0.9
96− style: Text.Raised
97− styleColor: "black"
98− fontSize: "x-small"
99− elide: Text.ElideMiddle
100− horizontalAlignment: styledItem.horizontalAlignment
101− }
102−}
qml/Dash/PreviewDelegateMapper.qmldeleted−38
@@ -1,38 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−
19−QtObject {
20− property var d: QtObject {
21− readonly property string genericPreview: "Generic/GenericPreview.qml"
22− readonly property string appPreview: "Apps/AppPreview.qml"
23− property var previewDelegateMapping: {"preview-generic": genericPreview,
24− "preview-application": appPreview,
25− "preview-movie": "Movie/MoviePreview.qml",
26− "preview-music": "Music/MusicPreview.qml",
27− }
28− }
29−
30− function map(rendererName) {
31− var customPreview = d.previewDelegateMapping[rendererName]
32− if (customPreview != undefined) {
33− return customPreview
34− }
35− console.debug("Renderer "+rendererName+" not found, using preview-generic")
36− return d.genericPreview
37− }
38−}
qml/Dash/PreviewListView.qml+52−133
@@ -16,53 +16,55 @@
1616
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
19−import Unity 0.1
19+import Unity 0.2
2020import "../Components"
21+import "Previews" as Previews
2122
2223Item {
23− property OpenEffect openEffect: null
24− property ScopeListView categoryView: null
24+ id: root
25+
2526 property Scope scope: null
27+ property var pageHeader: null
2628
2729 property alias open: previewListView.open
28− property alias onScreen: previewListView.onScreen
29− property alias categoryId: previewListView.categoryId
30− property alias categoryDelegate: previewListView.categoryDelegate
31− property alias init: previewListView.init
3230 property alias model: previewListView.model
3331 property alias currentIndex: previewListView.currentIndex
3432 property alias currentItem: previewListView.currentItem
3533 property alias count: previewListView.count
3634
37− Image {
38− objectName: "pointerArrow"
39− anchors {
40− top: previewListView.bottom
41− left: parent.left
42− leftMargin: previewListView.categoryDelegate !== undefined && previewListView.categoryDelegate.currentItem ?
43− previewListView.categoryDelegate.currentItem.center + (-width + margins) / 2 : 0
44−
45− Behavior on leftMargin {
46− SmoothedAnimation {
47− duration: UbuntuAnimation.FastDuration
48− }
35+ PageHeader {
36+ id: header
37+ objectName: root.objectName + "_pageHeader"
38+ width: parent.width
39+ searchEntryEnabled: false
40+ scope: root.scope
41+ height: units.gu(8.5)
42+ showBackButton: true
43+ onBackClicked: root.open = false
44+
45+ childItem: Label {
46+ id: label
47+ anchors {
48+ left: parent.left
49+ right: parent.right
50+ verticalCenter: parent.verticalCenter
4951 }
52+ text: scope ? i18n.tr("%1 Preview").arg(scope.name) : ""
53+ // TODO Saviq: These should come from updated Ubuntu Palette.
54+ color: "#888888"
55+ font.family: "Ubuntu"
56+ font.weight: Font.Light
57+ fontSize: "x-large"
58+ elide: Text.ElideRight
5059 }
51− height: units.gu(1)
52− width: units.gu(2)
53− property int margins: previewListView.categoryDelegate ? previewListView.categoryDelegate.margins : 0
54− opacity: previewListView.open ? .5 : 0
55−
56− source: "graphics/tooltip_arrow.png"
5760 }
5861
5962 ListView {
6063 id: previewListView
61− objectName: "previewListView"
62− height: openEffect.bottomGapPx - openEffect.topGapPx
64+ objectName: root.objectName + "_listView"
6365 anchors {
64− top: parent.top
65− topMargin: openEffect.topGapPx
66+ top: header.bottom
67+ bottom: parent.bottom
6668 left: parent.left
6769 right: parent.right
6870 }
@@ -77,140 +79,57 @@ Item {
7779
7880 // To be set before opening the preview
7981 property string categoryId: ""
80− property var categoryDelegate
8182
8283 // because the ListView is built asynchronous, setting the
8384 // currentIndex directly won't work. We need to refresh it
8485 // when the first preview is ready to be displayed.
8586 property bool init: true
8687
87− PreviewDelegateMapper {
88− id: previewDelegateMapper
89− }
90−
91− onCurrentIndexChanged: positionListView();
92−
93− function positionListView() {
94− if (!open) {
95− return;
96− }
97−
98− var row = Math.floor(currentIndex / categoryDelegate.columns);
99− if (categoryDelegate.collapsedRowCount <= row) {
100− categoryView.expandedCategoryId = categoryId
101− }
102−
103− categoryDelegate.highlightIndex = currentIndex
104−
105− if (!init && model !== undefined) {
106− var item = model.get(currentIndex)
107− scope.preview(item.uri, item.icon, item.category, 0, item.mimetype, item.title, item.comment, item.dndUri, item.metadata)
108− }
109−
110− // Adjust contentY in case we need to change to it to show the next row
111− if (categoryDelegate.rows > 1) {
112− var itemY = categoryView.contentItem.mapFromItem(categoryDelegate.currentItem).y;
113−
114− // Find new contentY and effect.postionPx
115− var newContentY = itemY - openEffect.positionPx - categoryDelegate.verticalSpacing;
116−
117− // Make sure the item is not covered by a header. Move the effect split down if necessary
118− var headerHeight = pageHeader.height + categoryView.stickyHeaderHeight;
119− var effectAdjust = Math.max(openEffect.positionPx, headerHeight);
120−
121− // Make sure we don't overscroll the listview. If yes, adjust effect position
122− if (newContentY < 0) {
123− effectAdjust += newContentY;
124− newContentY = 0;
125− }
126− if (newContentY > Math.max(0, categoryView.contentHeight - categoryView.height)) {
127− effectAdjust += -(categoryView.contentHeight - categoryView.height) + newContentY
128− newContentY = categoryView.contentHeight - categoryView.height;
129− }
130−
131− openEffect.positionPx = effectAdjust;
132− categoryView.contentY = newContentY;
133− }
134− }
135−
13688 property bool open: false
137− property bool onScreen: false
13889
13990 onOpenChanged: {
14091 if (open) {
141− onScreen = true;
142− categoryDelegate.highlightIndex = currentIndex;
14392 pageHeader.unfocus();
144− positionListView();
14593 } else {
14694 // Cancel any pending preview requests or actions
147− if (previewListView.currentItem.previewData !== undefined) {
95+ if (previewListView.currentItem && previewListView.currentItem.previewData !== undefined) {
14896 previewListView.currentItem.previewData.cancelAction();
14997 }
15098 scope.cancelActivation();
15199 model = undefined;
152− categoryView.correctExpandedCategory();
153− categoryDelegate.highlightIndex = -1;
154100 }
155101 }
156102
157− Rectangle {
158− anchors.fill: parent
159− color: Qt.rgba(0, 0, 0, .3)
160− z: -1
161− }
162−
163− delegate: Loader {
164− id: previewLoader
165− objectName: "previewLoader" + index
103+ delegate: Item {
104+ objectName: "previewItem" + index
166105 height: previewListView.height
167106 width: previewListView.width
168− asynchronous: true
169− source: previewListView.onScreen ?
170− (previewData !== undefined ? previewDelegateMapper.map(previewData.rendererName) : "DashPreviewPlaceholder.qml") : ""
171107
172− onPreviewDataChanged: {
173− if (previewData !== undefined && source.toString().indexOf("DashPreviewPlaceholder.qml") != -1) {
174− previewLoader.opacity = 0;
175− }
176− }
177−
178− onSourceChanged: {
179− if (previewData !== undefined) {
180− fadeIn.start()
181− }
182− }
108+ readonly property bool ready: preview.previewModel.loaded
183109
184− PropertyAnimation {
185− id: fadeIn
186− target: previewLoader
187− property: "opacity"
188− from: 0.0
189− to: 1.0
190− duration: UbuntuAnimation.BriskDuration
191− }
110+ Previews.Preview {
111+ id: preview
112+ objectName: "preview" + index
113+ anchors.fill: parent
192114
193− property var previewData
194− property bool valid: item !== null
115+ isCurrent: parent.ListView.isCurrentItem
195116
196− onLoaded: {
197− if (previewListView.onScreen && previewData !== undefined) {
198− item.previewData = Qt.binding(function() { return previewData })
199− item.isCurrent = Qt.binding(function() { return ListView.isCurrentItem })
117+ previewModel: {
118+ var previewStack = root.scope.preview(result);
119+ return previewStack.get(0);
200120 }
201121 }
202122
203− Connections {
204− ignoreUnknownSignals: true
205− target: item
206− onClose: {
207− previewListView.open = false
208− }
209− }
123+ MouseArea {
124+ id: processingMouseArea
125+ objectName: "processingMouseArea"
126+ anchors.fill: parent
127+ enabled: !preview.previewModel.loaded || preview.previewModel.processingAction
210128
211− function closePreviewSpinner() {
212− if (item) {
213− item.showProcessingAction = false;
129+ ActivityIndicator {
130+ anchors.centerIn: parent
131+ visible: root.open && parent.enabled
132+ running: visible
214133 }
215134 }
216135 }
qml/Dash/Previews/Header.qmldeleted−109
@@ -1,109 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−
21−Row {
22− id: root
23− property alias icon: image.source
24− property alias title: titleLabel.text
25− property alias subtitle: subtitleLabel.text
26− property alias rating: ratingStars.rating
27− property int rated: 0
28− property int reviews: 0
29−
30− spacing: units.gu(2)
31− height: imageShape.visible ? imageShape.height : contentColumn.height
32−
33− UbuntuShape {
34− id: imageShape
35− width: height
36− height: Math.max(units.gu(6), contentColumn.height)
37− visible: image.source.toString().length > 0
38− image: Image {
39− id: image
40− sourceSize { width: imageShape.width; height: imageShape.height }
41− asynchronous: true
42− fillMode: Image.PreserveAspectFit
43− }
44− }
45−
46− Column {
47− id: contentColumn
48− spacing: units.gu(1)
49− width: parent.width - x
50−
51− Label {
52− id: titleLabel
53− objectName: "titleLabel"
54− fontSize: "large"
55− color: "white"
56− style: Text.Raised
57− styleColor: "black"
58− opacity: .9
59− width: parent.width
60− elide: Text.ElideRight
61− }
62−
63− Label {
64− id: subtitleLabel
65− objectName: "subtitleLabel"
66− fontSize: "medium"
67− color: "white"
68− style: Text.Raised
69− styleColor: "black"
70− opacity: .6
71− visible: text.length > 0
72− }
73−
74− Row {
75− visible: root.rating >= 0
76− spacing: units.gu(1)
77−
78− RatingStars {
79− id: ratingStars
80− maximumRating: 10
81− rating: -1
82− }
83−
84− Label {
85− id: ratedLabel
86− objectName: "ratedLabel"
87− fontSize: "medium"
88− color: "white"
89− style: Text.Raised
90− styleColor: "black"
91− opacity: .6
92− //TRANSLATORS: Number of persons who rated this app/video/whatever
93− text: i18n.tr("(%1)").arg(root.rated)
94− }
95−
96− Label {
97− id: reviewsLabel
98− objectName: "reviewsLabel"
99− fontSize: "medium"
100− color: "white"
101− style: Text.Raised
102− styleColor: "black"
103− opacity: .6
104− //TRANSLATORS: Number of persons who wrote reviews for this app/video/whatever
105− text: i18n.tr("%1 review", "%1 reviews", root.reviews).arg(root.reviews)
106− }
107− }
108− }
109−}
qml/Dash/Previews/Preview.qml+17−23
@@ -38,18 +38,12 @@ Item {
3838
3939 clip: true
4040
41− Connections {
42− target: shell.applicationManager
43− onMainStageFocusedApplicationChanged: {
44− root.close();
45− }
46− onSideStageFocusedApplicationChanged: {
47− root.close();
48− }
41+ Binding {
42+ target: previewModel
43+ property: "widgetColumnCount"
44+ value: row.columns
4945 }
5046
51− onPreviewModelChanged: processingMouseArea.enabled = false
52−
5347 MouseArea {
5448 anchors.fill: parent
5549 }
@@ -60,18 +54,21 @@ Item {
6054 spacing: units.gu(1)
6155 anchors { fill: parent; margins: spacing }
6256
57+ property int columns: width >= units.gu(80) ? 2 : 1
58+ property real columnWidth: width / columns
59+
6360 Repeater {
64− model: 1
61+ model: previewModel
6562
6663 delegate: ListView {
6764 id: column
6865 anchors { top: parent.top; bottom: parent.bottom }
69− width: row.width
66+ width: row.columnWidth
7067 spacing: row.spacing
7168 bottomMargin: Qt.inputMethod.visible ? Qt.inputMethod.keyboardRectangle.height : 0
7269
73− model: previewModel
74− cacheBuffer: units.gu(40)
70+ model: columnModel
71+ cacheBuffer: height
7572
7673 Behavior on contentY { UbuntuNumberAnimation { } }
7774
@@ -80,10 +77,14 @@ Item {
8077 widgetType: model.type
8178 widgetData: model.properties
8279 isCurrentPreview: root.isCurrent
83− anchors { left: parent.left; right: parent.right }
80+ anchors {
81+ left: parent.left
82+ right: parent.right
83+ leftMargin: units.gu(1)
84+ rightMargin: units.gu(1)
85+ }
8486
8587 onTriggered: {
86− processingMouseArea.enabled = true;
8788 previewModel.triggered(widgetId, actionId, data);
8889 }
8990
@@ -94,11 +95,4 @@ Item {
9495 }
9596 }
9697 }
97−
98− MouseArea {
99− id: processingMouseArea
100− objectName: "processingMouseArea"
101− anchors.fill: parent
102− enabled: false
103− }
10498}
qml/Dash/Previews/PreviewActions.qml+1−1
@@ -24,7 +24,7 @@ import QtQuick 2.1
2424PreviewWidget {
2525 id: root
2626
27− height: row.height
27+ height: row.height + units.gu(1)
2828
2929 Row {
3030 id: row
qml/Dash/Previews/PreviewAudioPlayback.qml+4−3
@@ -139,7 +139,7 @@ PreviewWidget {
139139 objectName: "trackTitleLabel"
140140 anchors { top: parent.top; left: parent.left; right: parent.right }
141141 opacity: 0.9
142− color: Theme.palette.selected.backgroundText
142+ color: "grey"//Theme.palette.selected.backgroundText // TODO karni: Use updated Palette.
143143 fontSize: "small"
144144 horizontalAlignment: Text.AlignLeft
145145 text: modelData["title"]
@@ -152,7 +152,8 @@ PreviewWidget {
152152 anchors { top: trackTitleLabel.bottom; left: parent.left; right: parent.right }
153153 visible: text !== ""
154154 opacity: 0.9
155− color: Theme.palette.selected.backgroundText
155+ color: "grey"//Theme.palette.selected.backgroundText // TODO karni: Use updated Palette.
156+ font.weight: Font.Light
156157 fontSize: "small"
157158 horizontalAlignment: Text.AlignLeft
158159 text: modelData["subtitle"] || ""
@@ -192,7 +193,7 @@ PreviewWidget {
192193 anchors.verticalCenter: parent.verticalCenter
193194 width: parent.column3Width
194195 opacity: 0.9
195− color: Theme.palette.selected.backgroundText
196+ color: "grey"//Theme.palette.selected.backgroundText // TODO karni: Use updated Palette.
196197 fontSize: "small"
197198 horizontalAlignment: Text.AlignRight
198199 text: audio.lengthToString(modelData["length"])
qml/Dash/Previews/PreviewHeader.qml+5−1
@@ -34,5 +34,9 @@ PreviewWidget {
3434 title: root.widgetData["title"] || ""
3535 subtitle: root.widgetData["subtitle"] || ""
3636 width: parent.width
37+
38+ titleSize: "large"
39+ // TODO Change "grey" to Ubuntu.Components.Palette color once updated.
40+ fontColor: "grey"
3741 }
38−}
42+}
qml/Dash/Previews/PreviewImageGallery.qml+19
@@ -32,6 +32,25 @@ PreviewWidget {
3232 orientation: ListView.Horizontal
3333 cacheBuffer: width * 3
3434 model: root.widgetData["sources"]
35+ clip: true
36+
37+ // FIXME: Because of ListViews inside ListViews inside Flickables inside ListViews (and some more)
38+ // we finally reached the point where this ListView doesn't correctly get swipe input any more but
39+ // instead the parent ListView is the one that is swiped. This MouseArea sort of creates a blocking
40+ // layer to make sure this ListView can be swiped, regardless of what's behind it.
41+ MouseArea {
42+ anchors.fill: parent
43+ enabled: parent.contentWidth > parent.width
44+ }
45+
46+ // FIXME: Because of ListViews inside ListViews inside Flickables inside ListViews (and some more)
47+ // we finally reached the point where this ListView doesn't correctly get swipe input any more but
48+ // instead the parent ListView is the one that is swiped. This MouseArea sort of creates a blocking
49+ // layer to make sure this ListView can be swiped, regardless of what's behind it.
50+ MouseArea {
51+ anchors.fill: parent
52+ enabled: parent.contentWidth > parent.width
53+ }
3554
3655 LazyImage {
3756 objectName: "placeholderScreenshot"
qml/Dash/Previews/PreviewRatingInput.qml+1−1
@@ -58,7 +58,7 @@ PreviewWidget {
5858 reviewTextArea.text === "")) return;
5959
6060 var data = {"rating": rating.value, "review": reviewTextArea.text, "author": null};
61− triggered(root.widgetId, widgetData["required"], data);
61+ triggered(root.widgetId, "rated", data);
6262 }
6363
6464 Item {
qml/Dash/Previews/PreviewTextSummary.qml+6−3
@@ -38,7 +38,8 @@ PreviewWidget {
3838 right: parent.right
3939 }
4040 fontSize: "large"
41− color: Theme.palette.selected.backgroundText
41+ // TODO karni: Yet another fix requiring Palette update.
42+ color: "grey" //Theme.palette.selected.backgroundText
4243 visible: text !== ""
4344 opacity: .8
4445 text: widgetData["title"] || ""
@@ -58,8 +59,10 @@ PreviewWidget {
5859 }
5960 height: (!seeMore.visible || seeMore.more) ? contentHeight : contentHeight / lineCount * (maximumCollapsedLineCount - 2)
6061 clip: true
61− fontSize: "medium"
62− color: Theme.palette.selected.backgroundText
62+ fontSize: "small"
63+ lineHeight: 1.2
64+ // TODO karni: Yet another fix requiring Palette update.
65+ color: "grey" //Theme.palette.selected.backgroundText
6366 opacity: .8
6467 text: widgetData["text"]
6568 wrapMode: Text.Wrap
qml/Dash/Previews/PreviewWidgetFactory.qml+1−1
@@ -46,7 +46,7 @@ Loader {
4646 case "audio": return "PreviewAudioPlayback.qml";
4747 case "gallery": return "PreviewImageGallery.qml";
4848 case "header": return "PreviewHeader.qml";
49− case "image": return "PreviewZoomableImage.qml"
49+ case "image": return "PreviewZoomableImage.qml";
5050 case "progress": return "PreviewProgress.qml";
5151 case "rating-input": return "PreviewRatingInput.qml";
5252 case "reviews": return "PreviewRatingDisplay.qml";
qml/Dash/Previews/Reviews.qmldeleted−194
@@ -1,194 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import Ubuntu.Components.ListItems 0.1 as ListItem
20−import "../../Components"
21−
22−Column {
23− id: root
24−
25− property var model
26− property alias textArea: reviewField
27−
28− signal sendReview(string review)
29− signal editing
30−
31− spacing: units.gu(2)
32− state: ""
33−
34− states: [
35− State {
36− name: ""
37− PropertyChanges { target: reviewField; width: root.width }
38− PropertyChanges { target: sendButton; opacity: 0 }
39− PropertyChanges { target: inverseArea; enabled: false }
40− },
41− State {
42− name: "editing"
43− PropertyChanges { target: reviewField; width: (root.width - row.spacing - sendButton.width) }
44− PropertyChanges { target: sendButton; opacity: 1 }
45− PropertyChanges { target: inverseArea; enabled: true }
46− }
47− ]
48−
49− transitions: [
50− Transition {
51− from: ""
52− to: "editing"
53− SequentialAnimation {
54− UbuntuNumberAnimation { target: reviewField; properties: "width"; duration: UbuntuAnimation.SlowDuration }
55− UbuntuNumberAnimation { target: sendButton; properties: "opacity"; duration: UbuntuAnimation.SlowDuration }
56− }
57− },
58− Transition {
59− from: "editing"
60− to: ""
61− SequentialAnimation {
62− UbuntuNumberAnimation { target: sendButton; properties: "opacity"; duration: UbuntuAnimation.SlowDuration }
63− UbuntuNumberAnimation { target: reviewField; properties: "width"; duration: UbuntuAnimation.SlowDuration }
64− }
65− }
66− ]
67−
68− Label {
69− fontSize: "medium"
70− color: "white"
71− style: Text.Raised
72− styleColor: "black"
73− opacity: .9
74− text: i18n.tr("Add a review")
75− }
76−
77− Row {
78− id: row
79− spacing: units.gu(1)
80− width: root.width
81−
82− // FIXME: needs to react to Qt.inputMethod geometry
83− TextArea {
84− id: reviewField
85− objectName: "reviewField"
86− placeholderText: i18n.tr("Review")
87− width: parent.width
88− verticalAlignment: Text.AlignVCenter
89− autoSize: true
90− maximumLineCount: 5
91−
92− Behavior on height { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
93−
94− onFocusChanged: {
95− if(reviewField.focus){
96− root.state = "editing";
97− reviewField.selectAll();
98− root.editing();
99− }
100− }
101−
102− // FIXME: not active when in wide mode
103− InverseMouseArea {
104− id: inverseArea
105− anchors.fill: parent
106− enabled: false
107− onPressed: {
108− reviewField.focus = false;
109− root.state = "";
110− }
111− }
112− }
113−
114− Button {
115− id: sendButton
116− objectName: "sendButton"
117− width: units.gu(10)
118− height: units.gu(4)
119− anchors.bottom: reviewField.bottom
120− color: Theme.palette.selected.foreground
121− text: i18n.tr("Send")
122− opacity: 0
123−
124− onClicked: {
125− root.sendReview(reviewField.text);
126− reviewField.text = ""
127− }
128− }
129− }
130−
131− ListItem.ThinDivider {}
132−
133− Label {
134− fontSize: "medium"
135− color: "white"
136− style: Text.Raised
137− styleColor: "black"
138− opacity: .9
139− text: i18n.tr("Comments:")
140− }
141−
142− Repeater {
143− objectName: "commentsArea"
144− model: root.model
145−
146− Column {
147− anchors { left: parent.left; right: parent.right }
148−
149− Column {
150− anchors { left: parent.left; right: parent.right }
151−
152− Label {
153− anchors { left: parent.left; right: parent.right }
154− text: modelData[0]
155− fontSize: "medium"
156− color: "white"
157− opacity: .8
158− wrapMode: Text.WordWrap
159− style: Text.Raised
160− styleColor: "black"
161− }
162−
163− Row {
164− spacing: units.gu(1)
165−
166− RatingStars {
167− maximumRating: 10
168− rating: modelData[1]
169− }
170−
171− Label {
172− text: modelData[2]
173− fontSize: "medium"
174− color: Theme.palette.selected.backgroundText
175− opacity: .6
176− style: Text.Raised
177− styleColor: "black"
178− }
179− }
180− }
181−
182− Label {
183− anchors { left: parent.left; right: parent.right }
184− text: modelData[3]
185− fontSize: "medium"
186− color: Theme.palette.selected.backgroundText
187− opacity: .6
188− wrapMode: Text.WordWrap
189− style: Text.Raised
190− styleColor: "black"
191− }
192− }
193− }
194−}
qml/Dash/ScopeDelegateMapper.qml+1−3
@@ -17,9 +17,7 @@
1717import QtQuick 2.0
1818
1919QtObject {
20− property var scopeDelegateMapping: {"applications.scope": "DashApps.qml",
21− "home.scope": "DashHome.qml"
22− }
20+ property var scopeDelegateMapping: {"clickscope": "DashApps.qml"}
2321 property string genericScope: "GenericScopeView.qml"
2422
2523 function map(scopeId) {
qml/Dash/ScopeItem.qmlnew file+94
@@ -0,0 +1,94 @@
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 QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Unity 0.2
20+import "../Components"
21+
22+Item {
23+ id: root
24+
25+ property alias scope: scopeView.scope
26+ property alias previewOpen: previewListView.open
27+
28+ property ListModel searchHistory
29+
30+ signal back
31+ signal gotoScope(string scopeId)
32+ signal openScope(var scope)
33+
34+ Item {
35+ id: scopeViewHolder
36+
37+ x: previewListView.open ? -width : 0
38+ Behavior on x { UbuntuNumberAnimation { } }
39+ width: parent.width
40+ height: parent.height
41+
42+ GenericScopeView {
43+ id: scopeView
44+ width: parent.width
45+ height: parent.height
46+ isCurrent: scope != null
47+ tabBarHeight: scopeItemPageHeader.implicitHeight
48+ pageHeader: scopeItemPageHeader
49+ previewListView: previewListView
50+
51+ Connections {
52+ target: scopeView.isCurrent ? scope : null
53+ onGotoScope: root.gotoScope(scopeId);
54+ onOpenScope: root.openScope(scope);
55+ }
56+ }
57+
58+ PageHeader {
59+ id: scopeItemPageHeader
60+ width: parent.width
61+ searchEntryEnabled: true
62+ searchHistory: root.searchHistory
63+ scope: root.scope
64+ height: units.gu(8.5)
65+ showBackButton: true
66+ onBackClicked: root.back();
67+
68+ childItem: Label {
69+ id: label
70+ anchors {
71+ left: parent.left
72+ right: parent.right
73+ verticalCenter: parent.verticalCenter
74+ }
75+ text: scope ? scope.name : ""
76+ color: "#888888"
77+ font.family: "Ubuntu"
78+ font.weight: Font.Light
79+ fontSize: "x-large"
80+ elide: Text.ElideRight
81+ }
82+ }
83+ }
84+
85+ PreviewListView {
86+ id: previewListView
87+ visible: x != width
88+ pageHeader: scopeItemPageHeader
89+ scope: root.scope
90+ width: parent.width
91+ height: parent.height
92+ anchors.left: scopeViewHolder.right
93+ }
94+}
qml/Dash/SearchableResultModel.qmldeleted−44
@@ -1,44 +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 Utils 0.1
18−import Unity 0.1
19−
20−SortFilterProxyModel {
21− id: root
22−
23− property string searchQuery: ""
24− property bool hideOnSearch: false
25−
26− filterRole: CategoryResults.RoleTitle
27−
28− function get(index) {
29− return model.get(mapToSource(index))
30− }
31−
32− onSearchQueryChanged: {
33− if (searchQuery.length == 0) {
34− filterRegExp = RegExp("");
35− filterCaseSensitivity = Qt.CaseInsensitive;
36− } else if (!hideOnSearch) {
37− setFilterWildcard(searchQuery);
38− filterCaseSensitivity = Qt.CaseInsensitive;
39− } else {
40− filterRegExp = /^$/;
41− filterCaseSensitivity = Qt.CaseInsensitive;
42− }
43− }
44−}
qml/Dash/Video/CarouselDelegateVideo.qmldeleted−42
@@ -1,42 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−
21−BaseCarouselDelegate {
22− id: item
23−
24− UbuntuShape {
25− anchors.fill: parent
26− radius: "medium"
27− borderSource: ""
28− image: Image {
29− asynchronous: true
30− sourceSize { width: item.width; height: item.height }
31− source: model ? model.icon : ""
32− }
33− }
34−
35− BorderImage {
36− anchors.centerIn: parent
37− opacity: 0.6
38− source: "../../Components/graphics/non-selected.sci"
39− width: parent.width + units.gu(1.5)
40− height: parent.height + units.gu(1.5)
41− }
42−}
qml/Dash/Video/VideoCarousel.qmldeleted−34
@@ -1,34 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import "../../Components"
19−import ".."
20−
21−DashCarousel {
22− id: videosCarousel
23− tileAspectRatio: 198 / 288
24− minimumTileWidth: units.gu(13)
25− itemComponent: carouselDelegateVideo
26− selectedItemScaleFactor: 1.14
27− cacheBuffer: 1404 // 18px * 13gu * 6
28−
29− Component {
30− id: carouselDelegateVideo
31− CarouselDelegateVideo {
32− }
33− }
34−}
qml/Dash/Video/VideoFilterGrid.qmldeleted−47
@@ -1,47 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−import "../../Components"
20−import "../Generic"
21−
22−GenericFilterGrid {
23− id: videoFilterGrid
24−
25− delegateWidth: units.gu(11)
26− delegateHeight: units.gu(15)
27− iconWidth: units.gu(11)
28− iconHeight: units.gu(11)
29−
30− delegate: Tile {
31− id: tile
32− objectName: "delegate" + index
33− width: videoFilterGrid.cellWidth
34− height: videoFilterGrid.cellHeight
35− text: model.title
36− imageWidth: videoFilterGrid.iconWidth
37− imageHeight: videoFilterGrid.iconHeight
38− source: model.icon
39− maximumLineCount: 2
40− horizontalAlignment: Text.AlignLeft
41−
42− style: VideoTileStyle {}
43−
44− onClicked: videoFilterGrid.clicked(index, tile.y)
45− onPressAndHold: videoFilterGrid.pressAndHold(index, tile.y)
46− }
47−}
qml/Dash/Video/VideoTileStyle.qmldeleted−87
@@ -1,87 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import Ubuntu.Components 0.1
19−
20−Item {
21− id: tile
22−
23− anchors.fill: parent
24−
25− Image {
26− id: icon
27− anchors {
28− top: parent.top
29− horizontalCenter: parent.horizontalCenter
30− }
31− width: styledItem.imageWidth
32− height: styledItem.imageHeight
33− source: "graphics/movie_icon_holder.png"
34−
35− Image {
36− id: image
37− objectName: "image"
38− anchors {
39− fill: parent;
40− topMargin: units.gu(2);
41− bottomMargin: units.gu(2)
42− }
43− sourceSize { width: icon.width; height: icon.height }
44− asynchronous: true
45− cache: false
46− source: styledItem.source
47− fillMode: styledItem.fillMode
48− horizontalAlignment: Image.AlignHCenter
49− verticalAlignment: Image.AlignVCenter
50− }
51− }
52−
53− UbuntuShape {
54− id: borderPressed
55− objectName: "borderPressed"
56−
57− anchors.fill: icon
58− radius: "medium"
59− borderSource: "radius_pressed.sci"
60− opacity: styledItem.pressed ? 1.0 : 0.0
61− Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.OutQuint } }
62− }
63−
64− Label {
65− id: label
66− objectName: "label"
67− anchors {
68− baseline: icon.bottom
69− baselineOffset: units.gu(2)
70− left: icon.left
71− right: parent.right
72− rightMargin: units.gu(1)
73− leftMargin: units.dp(2)
74− }
75−
76− color: Theme.palette.selected.backgroundText
77− opacity: 0.9
78− style: Text.Raised
79− styleColor: "black"
80− fontSize: "small"
81− elide: Text.ElideRight
82− horizontalAlignment: styledItem.horizontalAlignment
83− text: styledItem.text
84− wrapMode: Text.Wrap
85− maximumLineCount: styledItem.maximumLineCount
86− }
87−}
qml/Dash/Video/graphics/icon_button_amazon@20.pngdeleted

Binary file not shown.

qml/Dash/Video/graphics/icon_button_u1@20.pngdeleted

Binary file not shown.

qml/Dash/Video/graphics/movie_icon_holder@27.pngdeleted

Binary file not shown.

qml/Dash/graphics/dash_divider_top_darkgrad@27.pngnew file

Binary file not shown.

qml/Dash/graphics/dash_divider_top_lightgrad@27.pngnew file

Binary file not shown.

qml/Dash/graphics/header_handlearrow2@20.pngdeleted

Binary file not shown.

qml/Dash/graphics/header_handlearrow2@27.pngnew file

Binary file not shown.

qml/Dash/graphics/header_handlearrow@20.pngdeleted

Binary file not shown.

qml/Dash/graphics/header_handlearrow@27.pngnew file

Binary file not shown.

qml/Dash/graphics/paper_landscape@27.pngnew file

Binary file not shown.

qml/Dash/graphics/paper_portrait@27.pngnew file

Binary file not shown.

qml/Dash/graphics/tabbarchevron@27.png

Binary file not shown.

qml/Launcher/Launcher.qml−1
@@ -18,7 +18,6 @@ import QtQuick 2.0
1818import "../Components"
1919import Ubuntu.Components 0.1
2020import Ubuntu.Gestures 0.1
21−import Unity 0.1
2221import Unity.Launcher 0.1
2322
2423Item {
qml/Launcher/LauncherPanel.qml−1
@@ -17,7 +17,6 @@
1717import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Ubuntu.Components.ListItems 0.1 as ListItems
20−import Unity 0.1
2120import Unity.Launcher 0.1
2221import Ubuntu.Components.Popups 0.1
2322import "../Components/ListItems"
qml/Panel/IndicatorRow.qml+1−1
@@ -137,7 +137,7 @@ Item {
137137 anchors.top: row.bottom
138138 visible: indicatorRow.currentItem != null
139139
140− property real intendedX: row.x + (indicatorRow.currentItem != null ? indicatorRow.currentItem.x + centerOffset : 0)
140+ property real intendedX: row.x + (indicatorRow.currentItem != null ? (indicatorRow.currentItem.x - row.originX) + centerOffset : 0)
141141 x: intendedX >= row.x ? (intendedX + width <= row.x + row.width ? intendedX : row.x + row.width - width) : row.x // listview boundaries
142142 width: indicatorRow.currentItem != null ? indicatorRow.currentItem.width : 0
143143
qml/ScopeTool.qml+9−1
@@ -18,7 +18,7 @@ import QtQuick 2.0
1818import Ubuntu.Components 0.1
1919import Ubuntu.Components.Popups 0.1
2020import Utils 0.1
21−import Unity 0.1
21+import Unity 0.2
2222import "Components"
2323import "Dash"
2424
@@ -61,6 +61,14 @@ Rectangle {
6161 color: "#FCFCFC"
6262 }
6363
64+ Image {
65+ anchors.fill: dashContent
66+ source: root.width > root.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
67+ fillMode: Image.PreserveAspectCrop
68+ horizontalAlignment: Image.AlignRight
69+ verticalAlignment: Image.AlignTop
70+ }
71+
6472 DashContent {
6573 id: dashContent
6674
qml/Shell.qml+11−33
@@ -125,27 +125,6 @@ FocusScope {
125125 shell.background = gSettingsPicture
126126 }
127127
128− // This is a dummy image that is needed to determine if the picture url
129− // in backgroundSettings points to a valid picture file.
130− // We can't do this with the real background image because setting a
131− // new source in onStatusChanged triggers a binding loop detection
132− // inside Image, which causes it not to render even though a valid source
133− // would be set. We don't mind about this image staying black and just
134− // use it for verification to populate the source for the real
135− // background image.
136− Image {
137− source: shell.background
138− height: 0
139− width: 0
140− sourceSize.height: 0
141− sourceSize.width: 0
142− onStatusChanged: {
143− if (status == Image.Error && source != shell.defaultBackground) {
144− shell.background = defaultBackground
145− }
146− }
147− }
148−
149128 VolumeControl {
150129 id: volumeControl
151130 }
@@ -174,21 +153,20 @@ FocusScope {
174153 // through the translucent parts of the shell surface.
175154 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
176155
177− CrossFadeImage {
178− id: backgroundImage
179− objectName: "backgroundImage"
180−
181− anchors.fill: parent
182− source: shell.background
183− fillMode: Image.PreserveAspectCrop
184− }
185−
186156 Rectangle {
187157 anchors.fill: parent
188158 color: "black"
189159 opacity: dash.disappearingAnimationProgress
190160 }
191161
162+ Image {
163+ anchors.fill: dash
164+ source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png"
165+ fillMode: Image.PreserveAspectCrop
166+ horizontalAlignment: Image.AlignRight
167+ verticalAlignment: Image.AlignTop
168+ }
169+
192170 Dash {
193171 id: dash
194172 objectName: "dash"
@@ -571,7 +549,7 @@ FocusScope {
571549 function showHome() {
572550 var animate = !greeter.shown && !stages.shown
573551 greeter.hide()
574− dash.setCurrentScope("home.scope", animate, false)
552+ dash.setCurrentScope("clickscope", animate, false)
575553 stages.hide()
576554 }
577555
@@ -594,7 +572,7 @@ FocusScope {
594572 contentEnabled: edgeDemo.panelContentEnabled
595573 }
596574 fullscreenMode: shell.fullscreenMode
597− searchVisible: !greeter.shown && !lockscreen.shown && dash.shown
575+ searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable
598576
599577 InputFilterArea {
600578 anchors {
@@ -682,7 +660,7 @@ FocusScope {
682660 launcher.hide();
683661 }
684662 }
685− onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("applications.scope", false, true)
663+ onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true)
686664 onLauncherApplicationSelected:{
687665 if (edgeDemo.running)
688666 return;
tests/autopilot/unity8/application_lifecycle/tests/test_url_dispatcher.py+5−40
@@ -20,12 +20,11 @@
2020"""Test the integration with the URL dispatcher service."""
2121
2222import os
23−import tempfile
2423
2524from autopilot import platform
2625from autopilot.matchers import Eventually
2726from testtools.matchers import Equals
28−from ubuntuuitoolkit import base as toolkit_base
27+from ubuntuuitoolkit import fixture_setup
2928
3029from unity8 import process_helpers
3130from unity8.shell import tests
@@ -47,13 +46,6 @@ MainView {
4746 text: 'Test application.'
4847 }
4948}
50−""")
51−
52− desktop_file_contents = ("""[Desktop Entry]
53−Type=Application
54−Name=test
55−Exec={qmlscene} {qml_file_path}
56−Icon=Not important
5749""")
5850
5951 def setUp(self):
@@ -66,37 +58,10 @@ Icon=Not important
6658 process_helpers.unlock_unity(unity_proxy)
6759
6860 def create_test_application(self):
69− # FIXME most of this code is duplicated in the toolkit. We should
70− # create a fixture on the toolkit for other projects to use.
71− # http://pad.lv/1277334 --elopio - 2014-02-06
72− qml_file_path = self._write_test_qml_file()
73− self.addCleanup(os.remove, qml_file_path)
74− desktop_file_path = self._write_test_desktop_file(qml_file_path)
75− self.addCleanup(os.remove, desktop_file_path)
76− return qml_file_path, desktop_file_path
77−
78− def _write_test_qml_file(self):
79− qml_file = tempfile.NamedTemporaryFile(suffix='.qml', delete=False)
80− qml_file.write(self.test_qml.encode('utf-8'))
81− qml_file.close()
82− return qml_file.name
83−
84− def _write_test_desktop_file(self, qml_file_path):
85− desktop_file_dir = self._get_local_desktop_file_directory()
86− if not os.path.exists(desktop_file_dir):
87− os.makedirs(desktop_file_dir)
88− desktop_file = tempfile.NamedTemporaryFile(
89− suffix='.desktop', dir=desktop_file_dir, delete=False)
90− contents = self.desktop_file_contents.format(
91− qmlscene=toolkit_base.get_qmlscene_launch_command(),
92− qml_file_path=qml_file_path)
93− desktop_file.write(contents.encode('utf-8'))
94− desktop_file.close()
95− return desktop_file.name
96−
97− def _get_local_desktop_file_directory(self):
98− return os.path.join(
99− os.environ.get('HOME'), '.local', 'share', 'applications')
61+ fake_application = fixture_setup.FakeApplication(self.test_qml)
62+ self.useFixture(fake_application)
63+ return (
64+ fake_application.qml_file_path, fake_application.desktop_file_path)
10065
10166 def test_swipe_out_application_started_by_url_dispatcher(self):
10267 _, desktop_file_path = self.create_test_application()
tests/autopilot/unity8/shell/emulators/dash.py+23−52
@@ -36,11 +36,9 @@ class Dash(emulators.UnityEmulatorBase):
3636 self.dash_content_list = self.wait_select_single(
3737 'QQuickListView', objectName='dashContentList')
3838
39− def get_home_applications_grid(self):
40− get_grid = self.get_scope('home').wait_select_single(
41− "GenericFilterGrid",
42− objectName="applications.scope"
43− )
39+ def get_applications_grid(self):
40+ get_grid = self.get_scope('clickscope').wait_select_single(
41+ 'CardFilterGrid', objectName='local')
4442 return get_grid
4543
4644 def get_application_icon(self, text):
@@ -50,24 +48,22 @@ class Dash(emulators.UnityEmulatorBase):
5048 :param text: String containing the text of the icon to search for.
5149
5250 """
53− app_grid = self.get_home_applications_grid()
51+ app_grid = self.get_applications_grid()
5452 resp_grid = app_grid.wait_select_single('ResponsiveGridView')
5553 return resp_grid.select_single('Tile', text=text)
5654
57− def get_scope(self, scope_name='home'):
58− scope_id = "%s.scope" % scope_name
55+ def get_scope(self, scope_name='clickscope'):
5956 return self.dash_content_list.select_single(
60− 'QQuickLoader', scopeId=scope_id)
57+ 'QQuickLoader', scopeId=scope_name)
6158
6259 @autopilot_logging.log_action(logger.info)
63− def open_scope(self, scope_name):
60+ def open_scope(self, scope_id):
6461 """Open a dash scope.
6562
66− :parameter scope_name: The name of the scope.
63+ :parameter scope_id: The id of the scope.
6764 :return: The scope.
6865
6966 """
70− scope_id = "%s.scope" % scope_name
7167 scope_loader = self._get_scope_loader(scope_id)
7268 if scope_loader.isCurrent:
7369 logger.info('The scope is already open.')
@@ -84,7 +80,7 @@ class Dash(emulators.UnityEmulatorBase):
8480 'No scope found with id {0}'.format(scope_id))
8581
8682 def _get_scope_from_loader(self, loader):
87− if loader.scopeId == 'applications.scope':
83+ if loader.scopeId == 'clickscope':
8884 return loader.select_single(DashApps)
8985 else:
9086 return loader.select_single(GenericScopeView)
@@ -115,7 +111,7 @@ class Dash(emulators.UnityEmulatorBase):
115111 original_index = self.dash_content_list.currentIndex
116112 # Scroll on the border of the page header, because some scopes have
117113 # contents that can be scrolled horizontally.
118− page_header = self.select_single('PageHeader')
114+ page_header = self._get_page_header()
119115 border = page_header.select_single('QQuickBorderImage')
120116 start_x = border.width / 3
121117 stop_x = border.width / 3 * 2
@@ -123,12 +119,15 @@ class Dash(emulators.UnityEmulatorBase):
123119 self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
124120 self.dash_content_list.currentIndex.wait_for(original_index - 1)
125121
122+ def _get_page_header(self):
123+ return self.select_single('PageHeader', objectName='pageHeader')
124+
126125 @autopilot_logging.log_action(logger.info)
127126 def _scroll_to_right_scope(self):
128127 original_index = self.dash_content_list.currentIndex
129128 # Scroll on the border of the page header, because some scopes have
130129 # contents that can be scrolled horizontally.
131− page_header = self.select_single('PageHeader')
130+ page_header = self._get_page_header()
132131 border = page_header.select_single('QQuickBorderImage')
133132 start_x = border.width / 3 * 2
134133 stop_x = border.width / 3
@@ -137,24 +136,9 @@ class Dash(emulators.UnityEmulatorBase):
137136 self.dash_content_list.currentIndex.wait_for(original_index + 1)
138137
139138
140−class DashPreview(emulators.UnityEmulatorBase):
141− """Autopilot emulator for the generic preview."""
142−
143− def get_details(self):
144− """Return the details of the open preview."""
145− title = self.select_single('Label', objectName='titleLabel').text
146− subtitle = self.select_single(
147− 'Label', objectName='subtitleLabel').text
148− description = self.select_single(
149− 'Label', objectName='descriptionLabel').text
150− return dict(title=title, subtitle=subtitle, description=description)
151−
152−
153139class GenericScopeView(emulators.UnityEmulatorBase):
154140 """Autopilot emulator for generic scopes."""
155141
156− preview_class = DashPreview
157−
158142 @autopilot_logging.log_action(logger.info)
159143 def open_preview(self, category, app_name):
160144 """Open the preview of an application.
@@ -164,15 +148,13 @@ class GenericScopeView(emulators.UnityEmulatorBase):
164148
165149 """
166150 category_element = self._get_category_element(category)
167− icon = category_element.select_single('Tile', text=app_name)
151+ icon = category_element.select_single('Card', title=app_name)
168152 # FIXME some categories need a long press in order to see the preview.
169153 # Some categories do not show previews, like recent apps.
170154 # --elopio - 2014-1-14
171155 self.pointing_device.click_object(icon)
172− preview = self.get_root_instance().wait_select_single(
173− self.preview_class, isCurrent=True)
174− preview.showProcessingAction.wait_for(False)
175− return preview
156+ return self.get_root_instance().wait_select_single(
157+ 'PreviewListView', objectName='dashContentPreviewList')
176158
177159 def _get_category_element(self, category):
178160 try:
@@ -183,24 +165,9 @@ class GenericScopeView(emulators.UnityEmulatorBase):
183165 'No category found with name {}'.format(category))
184166
185167
186−class AppPreview(DashPreview):
187− """Autopilot emulator for the application preview."""
188−
189− def get_details(self):
190− """Return the details of the application showed in its preview."""
191− details = super(AppPreview, self).get_details()
192− # TODO return screenshots, icon, rating and reviews.
193− # --elopio - 2014-1-15
194− return dict(
195− title=details.get('title'), publisher=details.get('subtitle'),
196− description=details.get('description'))
197−
198−
199168class DashApps(GenericScopeView):
200169 """Autopilot emulator for the applications scope."""
201170
202− preview_class = AppPreview
203−
204171 def get_applications(self, category):
205172 """Return the list of applications on a category.
206173
@@ -208,7 +175,11 @@ class DashApps(GenericScopeView):
208175
209176 """
210177 category_element = self._get_category_element(category)
211− application_tiles = category_element.select_many('Tile')
178+ application_tiles = category_element.select_many('Card')
212179 # TODO return them on the same order they are displayed.
213180 # --elopio - 2014-1-15
214− return [tile.text for tile in application_tiles]
181+ result = []
182+ for card in application_tiles:
183+ if card.objectName != 'cardToolCard':
184+ result.append(card)
185+ return result
tests/autopilot/unity8/shell/emulators/main_window.py−4
@@ -42,10 +42,6 @@ class QQuickView(emulators.UnityEmulatorBase):
4242 objectName="greeterContentLoader"
4343 )
4444
45− def get_greeter_background(self):
46− return self.select_single(
47− "CrossFadeImage", objectName="greeterBackground")
48−
4945 def get_login_loader(self):
5046 return self.select_single("QQuickLoader", objectName="loginLoader")
5147
tests/autopilot/unity8/shell/tests/__init__.py+1−1
@@ -376,7 +376,7 @@ class UnityTestCase(AutopilotTestCase):
376376
377377 def assertUnityReady(self):
378378 dash = self.get_dash()
379− home_scope = dash.get_scope('home')
379+ home_scope = dash.get_scope('clickscope')
380380
381381 # FIXME! There is a huge timeout here for when we're doing CI on
382382 # VMs. See lp:1203715
tests/autopilot/unity8/shell/tests/test_emulators.py+26−52
@@ -60,14 +60,13 @@ class DashEmulatorTestCase(DashBaseTestCase):
6060 self.dash.open_scope, scope_name)
6161
6262 self.assertEqual(
63− 'No scope found with id unexisting.scope', str(exception))
63+ 'No scope found with id unexisting', str(exception))
6464 self.assertFalse(mock_pointer.called)
6565
6666 def test_open_already_opened_scope(self):
6767 scope_id = self._get_current_scope_id()
6868 with mock.patch.object(self.dash, 'pointing_device') as mock_pointer:
69− scope = self.dash.open_scope(self._get_scope_name_from_id(
70− scope_id))
69+ scope = self.dash.open_scope(scope_id)
7170
7271 self.assertFalse(mock_pointer.called)
7372 self._assert_scope_is_opened(scope, scope_id)
@@ -83,12 +82,11 @@ class DashEmulatorTestCase(DashBaseTestCase):
8382 return scope.scopeId
8483
8584 def test_open_scope_to_the_right(self):
86− leftmost_scope = self._get_scope_name_from_id(
87− self._get_leftmost_scope_id())
85+ leftmost_scope = self._get_leftmost_scope_id()
8886 self.dash.open_scope(leftmost_scope)
8987
9088 scope_id = self._get_rightmost_scope_id()
91− scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
89+ scope = self.dash.open_scope(scope_id)
9290 self._assert_scope_is_opened(scope, scope_id)
9391
9492 def _get_leftmost_scope_id(self):
@@ -104,10 +102,6 @@ class DashEmulatorTestCase(DashBaseTestCase):
104102 'QQuickItem')[0]
105103 return item.get_children_by_type('QQuickLoader')
106104
107− def _get_scope_name_from_id(self, scope_id):
108− if scope_id.endswith('.scope'):
109− return scope_id[:-6]
110−
111105 def _get_rightmost_scope_id(self):
112106 scope_loaders = self._get_scope_loaders()
113107 rightmost_scope_loader = scope_loaders[0]
@@ -117,23 +111,22 @@ class DashEmulatorTestCase(DashBaseTestCase):
117111 return rightmost_scope_loader.scopeId
118112
119113 def test_open_scope_to_the_left(self):
120− rightmost_scope = self._get_scope_name_from_id(
121− self._get_rightmost_scope_id())
114+ rightmost_scope = self._get_rightmost_scope_id()
122115 self.dash.open_scope(rightmost_scope)
123116
124117 scope_id = self._get_leftmost_scope_id()
125− scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
118+ scope = self.dash.open_scope(scope_id)
126119 self._assert_scope_is_opened(scope, scope_id)
127120
128121 def test_open_generic_scope(self):
129− scope_id = 'home.scope'
130− scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
122+ scope_id = 'scopes'
123+ scope = self.dash.open_scope(scope_id)
131124 self._assert_scope_is_opened(scope, scope_id)
132125 self.assertIsInstance(scope, dash_emulators.GenericScopeView)
133126
134127 def test_open_applications_scope(self):
135− scope_id = 'applications.scope'
136− scope = self.dash.open_scope(self._get_scope_name_from_id(scope_id))
128+ scope_id = 'clickscope'
129+ scope = self.dash.open_scope(scope_id)
137130 self._assert_scope_is_opened(scope, scope_id)
138131 self.assertIsInstance(scope, dash_emulators.DashApps)
139132
@@ -144,36 +137,24 @@ class GenericScopeViewEmulatorTestCase(DashBaseTestCase):
144137 # Set up the fake scopes before launching unity.
145138 self.useFixture(fixture_setup.FakeScopes())
146139 super(GenericScopeViewEmulatorTestCase, self).setUp()
147− self.home_scope = self.dash.open_scope('home')
140+ self.generic_scope = self.dash.open_scope('MockScope1')
148141
149142 def test_open_preview(self):
150− preview = self.home_scope.open_preview('0', 'Title.0')
151− self.assertIsInstance(preview, dash_emulators.DashPreview)
152− self.assertTrue(preview.isCurrent)
153− self.assertFalse(preview.showProcessingAction)
154−
155− def test_get_details(self):
156− expected_details = dict(
157− title='Title', subtitle='Subtitle', description='Description')
158−
159− preview = self.home_scope.open_preview('0', 'Title.0')
160− details = preview.get_details()
161−
162− self.assertEqual(expected_details, details)
163−
143+ preview = self.generic_scope.open_preview('0', 'Title.0.0')
144+ preview.x.wait_for(0)
164145
165146class DashAppsEmulatorTestCase(DashBaseTestCase):
166147
167148 available_applications = [
168− 'Title.1', 'Title.21', 'Title.41', 'Title.61', 'Title.81',
169− 'Title.101', 'Title.121', 'Title.141', 'Title.161', 'Title.181',
170− 'Title.201', 'Title.221', 'Title.241', 'Title.261', 'Title.281']
149+ 'Title.2.0', 'Title.2.1', 'Title.2.2', 'Title.2.3', 'Title.2.4',
150+ 'Title.2.5', 'Title.2.6', 'Title.2.7', 'Title.2.8', 'Title.2.9',
151+ 'Title.2.9', 'Title.2.10', 'Title.2.11']
171152
172153 def setUp(self):
173154 # Set up the fake scopes before launching unity.
174155 self.useFixture(fixture_setup.FakeScopes())
175156 super(DashAppsEmulatorTestCase, self).setUp()
176− self.applications_scope = self.dash.open_scope('applications')
157+ self.applications_scope = self.dash.open_scope('clickscope')
177158
178159 def test_get_applications_with_unexisting_category(self):
179160 exception = self.assertRaises(
@@ -185,34 +166,27 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
185166 'No category found with name unexisting category', str(exception))
186167
187168 def test_get_applications_should_return_list_with_names(self):
188− category = 'installed'
169+ category = '2'
189170 expected_apps_count = self._get_number_of_application_slots(category)
190171 expected_applications = self.available_applications[
191172 :expected_apps_count]
192173
193174 applications = self.applications_scope.get_applications(category)
175+ applications_titles = []
176+ for application in applications:
177+ cardHeader = application.select_single('CardHeader')
178+ applications_titles.append(cardHeader.title)
194179
195180 self.assertThat(applications, HasLength(expected_apps_count))
196181 for expected in expected_applications:
197− self.assertThat(applications, Contains(expected))
182+ self.assertThat(applications_titles, Contains(expected))
198183
199184 def _get_number_of_application_slots(self, category):
200185 category_element = self.applications_scope._get_category_element(
201186 category)
202− grid = category_element.select_single('GenericFilterGrid')
187+ grid = category_element.select_single('CardFilterGrid')
203188 return grid.columns * grid.rows
204189
205190 def test_open_preview(self):
206− preview = self.applications_scope.open_preview('installed', 'Title.1')
207− self.assertIsInstance(preview, dash_emulators.AppPreview)
208− self.assertTrue(preview.isCurrent)
209− self.assertFalse(preview.showProcessingAction)
210−
211− def test_get_details(self):
212− expected_details = dict(
213− title='Title', publisher='', description='Description')
214−
215− preview = self.applications_scope.open_preview('installed', 'Title.1')
216− details = preview.get_details()
217−
218− self.assertEqual(expected_details, details)
191+ preview = self.applications_scope.open_preview('2', 'Title.2.1')
192+ preview.x.wait_for(0)
tests/autopilot/unity8/shell/tests/test_greeter.pydeleted−38
@@ -1,38 +0,0 @@
1−# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2−#
3−# Unity Autopilot Test Suite
4−# Copyright (C) 2012-2013 Canonical
5−#
6−# This program is free software: you can redistribute it and/or modify
7−# it under the terms of the GNU General Public License as published by
8−# the Free Software Foundation, either version 3 of the License, or
9−# (at your option) any later version.
10−#
11−# This program is distributed in the hope that it will be useful,
12−# but WITHOUT ANY WARRANTY; without even the implied warranty of
13−# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14−# GNU General Public License for more details.
15−#
16−# You should have received a copy of the GNU General Public License
17−# along with this program. If not, see <http://www.gnu.org/licenses/>.
18−#
19−
20−from unity8.shell.tests import UnityTestCase, _get_device_emulation_scenarios
21−
22−from testtools.matchers import Equals
23−
24−class TestGreeter(UnityTestCase):
25−
26− """Tests the Shell Greeter."""
27−
28− scenarios = _get_device_emulation_scenarios()
29−
30− def test_greeter_background(self):
31− """Test that the background of the greeter and the background of the shell are placed correctly
32−
33− """
34− self.launch_unity()
35− self.main_window.get_greeter()
36− greeter_background = self.main_window.get_greeter_background()
37− shell_background = self.main_window.get_shell_background()
38− self.assertThat(greeter_background.globalRect, Equals(shell_background.globalRect))
tests/autopilot/unity8/shell/tests/test_notifications.py+1−1
@@ -194,7 +194,7 @@ class InteractiveNotificationBase(NotificationsBase):
194194
195195 notify_list = self._get_notifications_list()
196196 get_notification = lambda: notify_list.wait_select_single(
197− 'Notification', objectName='notification0')
197+ 'Notification', objectName='notification1')
198198 notification = get_notification()
199199 self._assert_notification(notification, None, None, True, True, 1.0)
200200 initial_height = notification.height
tests/mocks/Unity/CMakeLists.txt+4−4
@@ -18,14 +18,14 @@ include_directories(
1818add_definitions(-DQT_NO_KEYWORDS)
1919
2020set(UnityQML_SOURCES
21− categoryresults.cpp
2221 iconutils.cpp
23− fake_applications_scope.cpp
24− fake_preview.cpp
2522 fake_scope.cpp
2623 fake_scopes.cpp
2724 fake_categories.cpp
28− scopes-ng/fake_preview_model.cpp
25+ fake_resultsmodel.cpp
26+ fake_previewmodel.cpp
27+ fake_previewstack.cpp
28+ fake_previewwidgetmodel.cpp
2929 fake_unity_plugin.cpp
3030)
3131
tests/mocks/Unity/categoryresults.cppdeleted−121
@@ -1,121 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Michal Hruby <michal.hruby@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−// self
21−#include "categoryresults.h"
22−#include "iconutils.h"
23−
24−// TODO: use something from libunity once it's public
25−enum ResultsColumn {
26− URI,
27− ICON_HINT,
28− CATEGORY,
29− RESULT_TYPE,
30− MIMETYPE,
31− TITLE,
32− COMMENT,
33− DND_URI,
34− METADATA
35−};
36−
37−CategoryResults::CategoryResults(QObject* parent)
38− : DeeListModel(parent)
39− , m_categoryIndex(-1)
40−{
41− m_roles[CategoryResults::RoleUri] = "uri";
42− m_roles[CategoryResults::RoleIconHint] = "icon";
43− m_roles[CategoryResults::RoleCategory] = "category";
44− m_roles[CategoryResults::RoleMimetype] = "mimetype";
45− m_roles[CategoryResults::RoleTitle] = "title";
46− m_roles[CategoryResults::RoleComment] = "comment";
47− m_roles[CategoryResults::RoleDndUri] = "dndUri";
48− m_roles[CategoryResults::RoleMetadata] = "metadata";
49− m_roles[CategoryResults::RoleRendererHints] = "rendererHints";
50−}
51−
52−int CategoryResults::categoryIndex() const
53−{
54− return m_categoryIndex;
55−}
56−
57−void CategoryResults::setCategoryIndex(int index)
58−{
59− if (m_categoryIndex != index) {
60− m_categoryIndex = index;
61− Q_EMIT categoryIndexChanged(m_categoryIndex);
62− }
63−}
64−
65−QHash<int, QByteArray>
66−CategoryResults::roleNames() const
67−{
68− return m_roles;
69−}
70−
71−QVariant
72−CategoryResults::data(const QModelIndex& index, int role) const
73−{
74− if (!index.isValid()) {
75− return QVariant();
76− }
77−
78− switch (role) {
79− case RoleUri:
80− return DeeListModel::data(index, ResultsColumn::URI);
81− case RoleIconHint: {
82− QString giconString(DeeListModel::data(index, ResultsColumn::ICON_HINT).toString());
83− if (giconString.isEmpty()) {
84− QString mimetype(DeeListModel::data(index, ResultsColumn::MIMETYPE).toString());
85− QString uri(DeeListModel::data(index, ResultsColumn::URI).toString());
86− QString thumbnailerUri(uriToThumbnailerProviderString(uri, mimetype, DeeListModel::data(index, ResultsColumn::METADATA).toHash()));
87− if (!thumbnailerUri.isNull()) {
88− return QVariant::fromValue(thumbnailerUri);
89− }
90− }
91− return QVariant::fromValue(gIconToDeclarativeImageProviderString(giconString));
92− }
93− case RoleCategory:
94− return DeeListModel::data(index, ResultsColumn::CATEGORY);
95− case RoleMimetype:
96− return DeeListModel::data(index, ResultsColumn::MIMETYPE);
97− case RoleTitle:
98− return DeeListModel::data(index, ResultsColumn::TITLE);
99− case RoleComment:
100− return DeeListModel::data(index, ResultsColumn::COMMENT);
101− case RoleDndUri:
102− return DeeListModel::data(index, ResultsColumn::DND_URI);
103− case RoleMetadata:
104− return DeeListModel::data(index, ResultsColumn::METADATA);
105− case RoleRendererHints:
106− {
107− QVariantHash hash(DeeListModel::data(index, ResultsColumn::METADATA).toHash());
108− if (hash.contains("content")) {
109− QVariantMap hints;
110− QVariantHash innerHash(hash["content"].toHash());
111− if (innerHash.contains("scope_disabled")) {
112− hints["scope_disabled"] = innerHash["scope_disabled"];
113− }
114− return hints.empty() ? QVariant() : QVariant::fromValue(hints);
115− }
116− return QVariant();
117− }
118− default:
119− return QVariant();
120− }
121−}
tests/mocks/Unity/categoryresults.hdeleted−68
@@ -1,68 +0,0 @@
1−/*
2− * Copyright (C) 2013 Canonical, Ltd.
3− *
4− * Authors:
5− * Michal Hruby <michal.hruby@canonical.com>
6− *
7− * This program is free software; you can redistribute it and/or modify
8− * it under the terms of the GNU General Public License as published by
9− * the Free Software Foundation; version 3.
10− *
11− * This program is distributed in the hope that it will be useful,
12− * but WITHOUT ANY WARRANTY; without even the implied warranty of
13− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14− * GNU General Public License for more details.
15− *
16− * You should have received a copy of the GNU General Public License
17− * along with this program. If not, see <http://www.gnu.org/licenses/>.
18− */
19−
20−
21−#ifndef CATEGORY_RESULTS_H
22−#define CATEGORY_RESULTS_H
23−
24−// dee-qt
25−#include "deelistmodel.h"
26−
27−class Q_DECL_EXPORT CategoryResults : public DeeListModel
28−{
29− Q_OBJECT
30−
31− Q_ENUMS(Roles)
32−
33− Q_PROPERTY(int categoryIndex READ categoryIndex WRITE setCategoryIndex NOTIFY categoryIndexChanged)
34−
35−public:
36− explicit CategoryResults(QObject* parent = 0);
37−
38− enum Roles {
39− RoleUri,
40− RoleIconHint,
41− RoleCategory,
42− RoleMimetype,
43− RoleTitle,
44− RoleComment,
45− RoleDndUri,
46− RoleMetadata,
47− RoleRendererHints
48− };
49−
50− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
51−
52− QHash<int, QByteArray> roleNames() const;
53−
54− /* getters */
55− int categoryIndex() const;
56−
57− /* setters */
58− void setCategoryIndex(int index);
59−
60−Q_SIGNALS:
61− void categoryIndexChanged(int index);
62−
63−private:
64− QHash<int, QByteArray> m_roles;
65− int m_categoryIndex;
66−};
67−
68−#endif // CATEGORY_RESULTS_H
tests/mocks/Unity/fake_applications_scope.cppdeleted−76
@@ -1,76 +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−#include "fake_applications_scope.h"
18−
19−static const gchar * categories_model_schema[] = {
20− "s", //ID
21− "s", // DISPLAY_NAME
22− "s", // ICON_HINT
23− "s", // RENDERER_NAME
24− "a{sv}" // HINTS
25−};
26−
27−ApplicationsScope::ApplicationsScope(bool visible, QObject* parent)
28− : Scope(parent)
29−{
30− m_id = "applications.scope";
31− m_name = "Applications";
32− m_visible = visible;
33− m_previewRendererName = "preview-application";
34− m_categories->setModel(createCategoriesModel());
35−}
36−
37−DeeModel* ApplicationsScope::createCategoriesModel()
38−{
39− DeeModel* category_model = dee_sequence_model_new();
40− dee_model_set_schema_full(category_model, categories_model_schema, G_N_ELEMENTS(categories_model_schema));
41− GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
42−
43− GVariant* children[1];
44− children[0] = g_variant_new_dict_entry(g_variant_new_string("content-type"),
45− g_variant_new_variant(g_variant_new_string("apps")));
46− GVariant* recentHints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), children, 1);
47− dee_model_append(category_model,
48− "recent",
49− "Recent",
50− "gtk-apply",
51− "special",
52− recentHints);
53−
54− dee_model_append(category_model,
55− "installed",
56− "Installed",
57− "gtk-apply",
58− "grid",
59− hints);
60−
61− dee_model_append(category_model,
62− "suggested",
63− "Suggested",
64− "gtk-apply",
65− "grid",
66− hints);
67−
68− dee_model_append(category_model,
69− "outdated",
70− "Outdaded",
71− "gtk-apply",
72− "grid",
73− hints);
74−
75− return category_model;
76−}
tests/mocks/Unity/fake_applications_scope.hdeleted−33
@@ -1,33 +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 FAKE_APPLICATIONS_SCOPE_H
18−#define FAKE_APPLICATIONS_SCOPE_H
19−
20−#include "fake_scope.h"
21−
22−class ApplicationsScope : public Scope
23−{
24− Q_OBJECT
25−
26−public:
27− ApplicationsScope(bool visible, QObject* parent = 0);
28−
29−private:
30− DeeModel* createCategoriesModel();
31−};
32−
33−#endif // FAKE_APPLICATIONS_SCOPE_H
tests/mocks/Unity/fake_categories.cpp+109−194
@@ -19,100 +19,21 @@
1919// self
2020#include "fake_categories.h"
2121
22−// local
23−#include "categoryresults.h"
22+#include "fake_resultsmodel.h"
2423
25−#define CATEGORY_COLUMN 2
26−
27−// TODO: use something from libunity once it's public
28−enum CategoryColumn {
29− ID,
30− DISPLAY_NAME,
31− ICON_HINT,
32− RENDERER_NAME,
33− HINTS
34−};
35−
36−Categories::Categories(QObject* parent)
37− : DeeListModel(parent)
24+Categories::Categories(int category_count, QObject* parent)
25+ : QAbstractListModel(parent)
26+ , m_category_count(category_count)
3827{
39− // FIXME: need to clean up unused filters on countChanged
4028 m_roles[Categories::RoleCategoryId] = "categoryId";
4129 m_roles[Categories::RoleName] = "name";
4230 m_roles[Categories::RoleIcon] = "icon";
31+ m_roles[Categories::RoleRawRendererTemplate] = "rawRendererTemplate";
4332 m_roles[Categories::RoleRenderer] = "renderer";
44− m_roles[Categories::RoleContentType] = "contentType";
45− m_roles[Categories::RoleRendererHint] = "rendererHint";
46− m_roles[Categories::RoleHints] = "hints";
33+ m_roles[Categories::RoleComponents] = "components";
34+ m_roles[Categories::RoleProgressSource] = "progressSource";
4735 m_roles[Categories::RoleResults] = "results";
4836 m_roles[Categories::RoleCount] = "count";
49−
50− // TODO This should not be needed but accumulatting the count changes
51− // makes the visualization more stable and also makes crashes on fast
52− // change of the search term harder to reproduce
53− m_timer.setSingleShot(true);
54− m_timer.setInterval(50);
55− connect(&m_timer, SIGNAL(timeout()), this, SLOT(onEmitCountChanged()));
56−}
57−
58−DeeListModel*
59−Categories::getFilter(int index) const
60−{
61− if (!m_filters.contains(index)) {
62− auto results = new CategoryResults ();
63− results->setCategoryIndex(index);
64− connect(results, SIGNAL(countChanged()), this, SLOT(onCountChanged()));
65−
66− unsigned cat_index = static_cast<unsigned>(index);
67− auto model = getResultsForCategory(cat_index);
68− results->setModel(model);
69−
70− m_filters.insert(index, results);
71− }
72−
73− return m_filters[index];
74−}
75−
76−void
77−Categories::onCountChanged()
78−{
79− DeeListModel* filter = qobject_cast<DeeListModel*>(sender());
80− if (filter) {
81− m_timerFilters << filter;
82− m_timer.start();
83− }
84−}
85−
86−void Categories::onRowCountChanged()
87−{
88− QAbstractItemModel* model = qobject_cast<QAbstractItemModel*>(sender());
89− // find the corresponding category index
90− for (auto iter = m_overriddenCategories.begin(); iter != m_overriddenCategories.end(); ++iter) {
91− if (iter.value() == model) {
92− for (int i = 0; i < rowCount(); i++) {
93− auto id = data(index(i), RoleCategoryId).toString();
94− if (id != iter.key()) continue;
95− QVector<int> roles;
96− roles.append(RoleCount);
97− QModelIndex changedIndex = index(i);
98− Q_EMIT dataChanged(changedIndex, changedIndex, roles);
99− break;
100− }
101− }
102− }
103−}
104−
105−void
106−Categories::onEmitCountChanged()
107−{
108− QVector<int> roles;
109− roles.append(Categories::RoleCount);
110− Q_FOREACH(DeeListModel* results, m_timerFilters) {
111− auto cat_results = qobject_cast<CategoryResults*>(results);
112− QModelIndex changedIndex = index(cat_results->categoryIndex());
113− Q_EMIT dataChanged(changedIndex, changedIndex, roles);
114− }
115− m_timerFilters.clear();
11637}
11738
11839QHash<int, QByteArray>
@@ -121,94 +42,46 @@ Categories::roleNames() const
12142 return m_roles;
12243}
12344
124−void Categories::onOverrideModelDestroyed()
45+int Categories::rowCount(const QModelIndex& /*parent*/) const
12546{
126− QObject* model = sender();
127− auto iter = m_overriddenCategories.begin();
128− while (iter != m_overriddenCategories.end()) {
129− if (iter.value() == model) {
130− iter = m_overriddenCategories.erase(iter);
131− continue;
132− }
133− ++iter;
134− }
47+ return m_category_count + m_specialCategories.count();
13548}
13649
137−void Categories::overrideResults(const QString& categoryId, QAbstractItemModel* model)
50+void Categories::addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject)
13851{
139− m_overriddenCategories[categoryId] = model;
140− // watch the model
141− connect(model, &QObject::destroyed, this, &Categories::onOverrideModelDestroyed);
142− connect(model, &QAbstractItemModel::rowsInserted, this, &Categories::onRowCountChanged);
143− connect(model, &QAbstractItemModel::rowsRemoved, this, &Categories::onRowCountChanged);
144− connect(model, &QAbstractItemModel::modelReset, this, &Categories::onRowCountChanged);
145−
146− // emit the dataChanged signal if the category is already in the model
147− for (int i = 0; i < rowCount(); i++) {
148− auto id = data(index(i), RoleCategoryId).toString();
149− if (id != categoryId) continue;
150− QVector<int> roles;
151− roles.append(RoleCount);
152− roles.append(RoleResults);
153− QModelIndex changedIndex = index(i);
154− Q_EMIT dataChanged(changedIndex, changedIndex, roles);
155− break;
52+ CategoryData catData;
53+ catData.categoryId = categoryId;
54+ catData.name = name;
55+ catData.icon = icon;
56+ catData.rawTemplate = rawTemplate;
57+ catData.countObject = countObject;
58+
59+ beginInsertRows(QModelIndex(), 0, 0);
60+ m_specialCategories.prepend(catData);
61+ endInsertRows();
62+
63+ if (countObject) {
64+ connect(countObject, SIGNAL(countChanged()), this, SLOT(countChanged()));
15665 }
15766}
15867
159−void Categories::setResultModel(DeeModel* model)
68+void Categories::countChanged()
16069{
161− // FIXME: should ref it
162− m_dee_results = model;
163−}
164−
70+ QObject* countObject = sender();
16571
166−static void category_filter_map_func (DeeModel* orig_model,
167− DeeFilterModel* filter_model,
168− gpointer user_data)
169−{
170− DeeModelIter* iter;
171− DeeModelIter* end;
172− unsigned index = GPOINTER_TO_UINT(user_data);
72+ for (int i = 0; i < m_specialCategories.count(); ++i) {
73+ const CategoryData &catData = m_specialCategories.at(i);
74+ if (catData.countObject == countObject) {
75+ QVector<int> roles;
76+ roles.append(RoleCount);
17377
174− iter = dee_model_get_first_iter(orig_model);
175− end = dee_model_get_last_iter(orig_model);
176− while (iter != end) {
177− unsigned category_index = dee_model_get_uint32(orig_model, iter, CATEGORY_COLUMN);
178− if (index == category_index) {
179− dee_filter_model_append_iter(filter_model, iter);
78+ QModelIndex changedIndex(index(i));
79+ dataChanged(changedIndex, changedIndex, roles);
80+ break;
18081 }
181− iter = dee_model_next(orig_model, iter);
18282 }
18383}
18484
185−static gboolean category_filter_notify_func (DeeModel* orig_model,
186− DeeModelIter* orig_iter,
187− DeeFilterModel* filter_model,
188− gpointer user_data)
189−{
190− unsigned index = GPOINTER_TO_UINT(user_data);
191− unsigned category_index = dee_model_get_uint32(orig_model, orig_iter, CATEGORY_COLUMN);
192−
193− if (index != category_index)
194− return FALSE;
195−
196− dee_filter_model_insert_iter_with_original_order(filter_model, orig_iter);
197− return TRUE;
198−}
199−
200−DeeModel* Categories::getResultsForCategory(unsigned cat_index) const
201−{
202− DeeFilter filter;
203− filter.map_func = category_filter_map_func;
204− filter.map_notify = category_filter_notify_func;
205− filter.destroy = nullptr;
206− filter.userdata = GUINT_TO_POINTER(cat_index);
207−
208− DeeModel* filtered_model = dee_filter_model_new(m_dee_results, &filter);
209− return filtered_model;
210−}
211−
21285QVariant
21386Categories::data(const QModelIndex& index, int role) const
21487{
@@ -216,44 +89,86 @@ Categories::data(const QModelIndex& index, int role) const
21689 return QVariant();
21790 }
21891
219− switch (role) {
220− case RoleCategoryId:
221− return DeeListModel::data(index, CategoryColumn::ID);
222− case RoleName:
223− return DeeListModel::data(index, CategoryColumn::DISPLAY_NAME);
224− case RoleIcon:
225− return DeeListModel::data(index, CategoryColumn::ICON_HINT);
226− case RoleRenderer:
227− return DeeListModel::data(index, CategoryColumn::RENDERER_NAME);
228− case RoleContentType:
229− {
230− auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
231− return hints.contains("content-type") ? hints["content-type"] : QVariant(QString("default"));
232− }
233− case RoleRendererHint:
234− {
235− auto hints = DeeListModel::data(index, CategoryColumn::HINTS).toHash();
236− return hints.contains("renderer-hint") ? hints["renderer-hint"] : QVariant(QString());
92+ ResultsModel *resultsModel = m_resultsModels[index.row()];
93+ if (!resultsModel) {
94+ resultsModel = new ResultsModel(15, index.row());
95+ m_resultsModels[index.row()] = resultsModel;
96+ }
97+ if (index.row() < m_specialCategories.count()) {
98+ const CategoryData &catData = m_specialCategories.at(index.row());
99+ switch (role) {
100+ case RoleCategoryId:
101+ return catData.categoryId;
102+ case RoleName:
103+ return catData.name;
104+ case RoleIcon:
105+ return catData.icon;
106+ case RoleRawRendererTemplate:
107+ return catData.rawTemplate;
108+ case RoleRenderer:
109+ {
110+ QVariantMap map;
111+ map["category-layout"] = index.row() % 2 == 0 ? "grid" : "carousel";
112+ map["card-size"] = "small";
113+ return map;
114+ }
115+ case RoleComponents:
116+ {
117+ QVariantMap map, artMap;
118+ artMap["aspect-ratio"] = "1.0";
119+ artMap["field"] = "art";
120+ map["art"] = artMap;
121+ map["title"] = "HOLA";
122+ return map;
123+ }
124+ case RoleProgressSource:
125+ qFatal("Using un-implemented RoleProgressSource Categories role");
126+ return QVariant();
127+ case RoleResults:
128+ return QVariant();
129+ case RoleCount:
130+ return catData.countObject->property("count");
131+ default:
132+ qFatal("Using un-implemented Categories role");
133+ return QVariant();
237134 }
238− case RoleHints:
239− return DeeListModel::data(index, CategoryColumn::HINTS);
240− case RoleResults:
241− if (m_overriddenCategories.size() > 0)
135+ } else {
136+ switch (role) {
137+ case RoleCategoryId:
138+ return QString("%1").arg(index.row());
139+ case RoleName:
140+ return QString("Category %1").arg(index.row());
141+ case RoleIcon:
142+ return "gtk-apply";
143+ case RoleRawRendererTemplate:
144+ qFatal("Using un-implemented RoleRawRendererTemplate Categories role");
145+ return QVariant();
146+ case RoleRenderer:
242147 {
243− auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
244− if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
245− return QVariant::fromValue(m_overriddenCategories[id]);
148+ QVariantMap map;
149+ map["category-layout"] = index.row() % 2 == 0 ? "grid" : "carousel";
150+ map["card-size"] = "small";
151+ return map;
246152 }
247− return QVariant::fromValue(getFilter(index.row()));
248− case RoleCount:
249− if (m_overriddenCategories.size() > 0)
153+ case RoleComponents:
250154 {
251− auto id = DeeListModel::data(index, CategoryColumn::ID).toString();
252− if (m_overriddenCategories.find(id) != m_overriddenCategories.end())
253− return QVariant::fromValue(m_overriddenCategories[id]->rowCount());
155+ QVariantMap map, artMap;
156+ artMap["aspect-ratio"] = "1.0";
157+ artMap["field"] = "art";
158+ map["art"] = artMap;
159+ map["title"] = "HOLA";
160+ return map;
254161 }
255− return QVariant::fromValue(getFilter(index.row())->rowCount());
256− default:
257− return QVariant();
162+ case RoleProgressSource:
163+ qFatal("Using un-implemented RoleProgressSource Categories role");
164+ return QVariant();
165+ case RoleResults:
166+ return QVariant::fromValue(resultsModel);
167+ case RoleCount:
168+ return resultsModel->rowCount();
169+ default:
170+ qFatal("Using un-implemented Categories role");
171+ return QVariant();
172+ }
258173 }
259174}
tests/mocks/Unity/fake_categories.h+25−29
@@ -18,58 +18,54 @@
1818#define FAKE_CATEGORIES_H
1919
2020// Qt
21−#include <QObject>
22−#include <QSet>
23−#include <QTimer>
21+#include <QAbstractListModel>
22+#include <QList>
2423
25−#include <dee.h>
26−#include <deelistmodel.h>
24+class ResultsModel;
2725
28−class Categories : public DeeListModel
26+class Categories : public QAbstractListModel
2927{
3028 Q_OBJECT
3129
3230 Q_ENUMS(Roles)
3331
3432public:
35− Categories(QObject* parent = 0);
33+ Categories(int category_count, QObject* parent = 0);
3634 enum Roles {
3735 RoleCategoryId,
3836 RoleName,
3937 RoleIcon,
38+ RoleRawRendererTemplate,
4039 RoleRenderer,
41− RoleContentType,
42− RoleRendererHint,
43− RoleHints,
40+ RoleComponents,
41+ RoleProgressSource, // maybe
4442 RoleResults,
4543 RoleCount
4644 };
4745
48− Q_INVOKABLE void overrideResults(const QString& categoryId, QAbstractItemModel* model);
46+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
47+ QHash<int, QByteArray> roleNames() const override;
48+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
4949
50− QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
51−
52− QHash<int, QByteArray> roleNames() const;
53−
54− /* setters */
55− void setResultModel(DeeModel* model);
50+ Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject);
5651
5752private Q_SLOTS:
58− void onCountChanged();
59− void onRowCountChanged();
60− void onEmitCountChanged();
61− void onOverrideModelDestroyed();
53+ void countChanged();
6254
6355private:
64− DeeModel* getResultsForCategory(unsigned index) const;
65− DeeListModel* getFilter(int index) const;
66−
67− DeeModel* m_dee_results;
68− QTimer m_timer;
69− QSet<DeeListModel*> m_timerFilters;
56+ mutable QHash<int, ResultsModel*> m_resultsModels;
7057 QHash<int, QByteArray> m_roles;
71− QMap<QString, QAbstractItemModel*> m_overriddenCategories;
72− mutable QMap<int, DeeListModel*> m_filters;
58+ int m_category_count;
59+
60+ struct CategoryData {
61+ QString categoryId;
62+ QString name;
63+ QString icon;
64+ QString rawTemplate;
65+ QObject* countObject;
66+ };
67+
68+ QList<CategoryData> m_specialCategories;
7369};
7470
7571#endif // FAKE_CATEGORIES_H
tests/mocks/Unity/fake_preview.cppdeleted−73
@@ -1,73 +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−#include "fake_preview.h"
18−
19−Preview::Preview(const QString &rendererName, QObject *parent):
20− QObject(parent),
21− m_rendererName(rendererName)
22−{
23−}
24−
25−QString Preview::rendererName() const
26−{
27− return m_rendererName;
28−}
29−
30−QString Preview::title() const
31−{
32− return "Title";
33−}
34−
35−QString Preview::subtitle() const
36−{
37− return "Subtitle";
38−}
39−
40−QString Preview::description() const
41−{
42− return "Description";
43−}
44−
45−QVariant Preview::actions()
46−{
47− return QVariant();
48−}
49−
50−QVariant Preview::infoHints()
51−{
52− return QVariant();
53−}
54−
55−QVariantMap Preview::infoHintsHash() const
56−{
57− return QVariantMap();
58−}
59−
60−QString Preview::image() const
61−{
62− return "";
63−}
64−
65−void Preview::execute(const QString& actionId, const QHash<QString, QVariant>& hints)
66−{
67− Q_UNUSED(actionId);
68− Q_UNUSED(hints);
69−}
70−
71−void Preview::cancelAction()
72−{
73−}
tests/mocks/Unity/fake_preview.hdeleted−65
@@ -1,65 +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 FAKE_PREVIEW_H
18−#define FAKE_PREVIEW_H
19−
20−// Qt
21−#include <QObject>
22−#include <QString>
23−#include <QMetaType>
24−#include <QList>
25−#include <QVariantMap>
26−
27−class Q_DECL_EXPORT Preview : public QObject
28−{
29− Q_OBJECT
30−
31− Q_PROPERTY(QString rendererName READ rendererName NOTIFY previewChanged)
32− Q_PROPERTY(QString title READ title NOTIFY previewChanged)
33− Q_PROPERTY(QString subtitle READ subtitle NOTIFY previewChanged)
34− Q_PROPERTY(QString description READ description NOTIFY previewChanged)
35− Q_PROPERTY(QVariant actions READ actions NOTIFY previewChanged)
36− Q_PROPERTY(QVariant infoHints READ infoHints NOTIFY previewChanged)
37− Q_PROPERTY(QVariantMap infoMap READ infoHintsHash NOTIFY previewChanged)
38− Q_PROPERTY(QString image READ image NOTIFY previewChanged)
39−
40−public:
41− explicit Preview(const QString &rendererName, QObject *parent = 0);
42−
43− QString rendererName() const;
44− QString title() const;
45− QString subtitle() const;
46− QString description() const;
47− QVariant actions();
48− QVariant infoHints();
49− QVariantMap infoHintsHash() const;
50− QString image() const;
51−
52− Q_INVOKABLE void execute(const QString& actionId, const QHash<QString, QVariant>& hints);
53−
54− Q_INVOKABLE void cancelAction();
55−
56−Q_SIGNALS:
57− void previewChanged();
58−
59−private:
60− QString m_rendererName;
61−};
62−
63−Q_DECLARE_METATYPE(Preview *)
64−
65−#endif // FAKE_PREVIEW_H
tests/mocks/Unity/fake_previewmodel.cppnew file+86
@@ -0,0 +1,86 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michał Sawicz <michal.sawicz@canonical.com>
6+ * Michal Hruby <michal.hruby@canonical.com>
7+ *
8+ * This program is free software; you can redistribute it and/or modify
9+ * it under the terms of the GNU General Public License as published by
10+ * the Free Software Foundation; version 3.
11+ *
12+ * This program is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ * GNU General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU General Public License
18+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19+ */
20+
21+// self
22+#include "fake_previewmodel.h"
23+
24+// local
25+#include "fake_previewwidgetmodel.h"
26+
27+// Qt
28+#include <QDebug>
29+
30+PreviewModel::PreviewModel(QObject* parent) : QAbstractListModel(parent)
31+{
32+ // we have one column by default
33+ PreviewWidgetModel* columnModel = new PreviewWidgetModel(this);
34+ m_previewWidgetModels.append(columnModel);
35+}
36+
37+QHash<int, QByteArray> PreviewModel::roleNames() const
38+{
39+ QHash<int, QByteArray> roles;
40+
41+ roles[Roles::RoleColumnModel] = "columnModel";
42+
43+ return roles;
44+}
45+
46+void PreviewModel::setWidgetColumnCount(int count)
47+{
48+ if (count != 1) {
49+ qWarning("PreviewModel::setWidgetColumnCount != 1 not implemented");
50+ }
51+}
52+
53+int PreviewModel::widgetColumnCount() const
54+{
55+ return 1;
56+}
57+
58+bool PreviewModel::loaded() const
59+{
60+ return true;
61+}
62+
63+bool PreviewModel::processingAction() const
64+{
65+ return false;
66+}
67+
68+void PreviewModel::setProcessingAction(bool /*processing*/)
69+{
70+ qFatal("PreviewModel::setProcessingAction not implemented");
71+}
72+
73+int PreviewModel::rowCount(const QModelIndex&) const
74+{
75+ return m_previewWidgetModels.size();
76+}
77+
78+QVariant PreviewModel::data(const QModelIndex& index, int role) const
79+{
80+ switch (role) {
81+ case RoleColumnModel:
82+ return QVariant::fromValue(m_previewWidgetModels.at(index.row()));
83+ default:
84+ return QVariant();
85+ }
86+}
tests/mocks/Unity/fake_previewmodel.hnew file+67
@@ -0,0 +1,67 @@
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+
18+#ifndef FAKE_PREVIEWMODEL_H
19+#define FAKE_PREVIEWMODEL_H
20+
21+#include <QAbstractListModel>
22+#include <QSharedPointer>
23+#include <QVariantMap>
24+
25+class PreviewWidgetModel;
26+
27+class PreviewModel : public QAbstractListModel
28+{
29+ Q_OBJECT
30+
31+ Q_ENUMS(Roles)
32+
33+ Q_PROPERTY(int widgetColumnCount READ widgetColumnCount WRITE setWidgetColumnCount NOTIFY widgetColumnCountChanged)
34+ Q_PROPERTY(bool loaded READ loaded NOTIFY loadedChanged)
35+ Q_PROPERTY(bool processingAction READ processingAction NOTIFY processingActionChanged)
36+
37+public:
38+ explicit PreviewModel(QObject* parent = 0);
39+
40+ enum Roles {
41+ RoleColumnModel
42+ };
43+
44+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
45+ QHash<int, QByteArray> roleNames() const override;
46+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
47+
48+ void setWidgetColumnCount(int count);
49+ int widgetColumnCount() const;
50+ bool loaded() const;
51+ bool processingAction() const;
52+ void setProcessingAction(bool processing);
53+
54+Q_SIGNALS:
55+ void widgetColumnCountChanged();
56+ void loadedChanged();
57+ void processingActionChanged();
58+ void triggered(QString const&, QString const&, QVariantMap const&);
59+
60+private:
61+ QHash<int, QByteArray> m_roles;
62+ QList<PreviewWidgetModel*> m_previewWidgetModels;
63+};
64+
65+Q_DECLARE_METATYPE(PreviewModel*)
66+
67+#endif // FAKE_PREVIEWMODEL_H
tests/mocks/Unity/fake_previewstack.cppnew file+76
@@ -0,0 +1,76 @@
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+// self
18+#include "fake_previewstack.h"
19+
20+// local
21+#include "fake_previewmodel.h"
22+#include "fake_scope.h"
23+
24+PreviewStack::PreviewStack(QObject* parent) : QAbstractListModel(parent)
25+{
26+ m_previews << new PreviewModel(this);
27+}
28+
29+PreviewStack::~PreviewStack()
30+{
31+}
32+
33+QHash<int, QByteArray> PreviewStack::roleNames() const
34+{
35+ QHash<int, QByteArray> roles;
36+
37+ roles[Roles::RolePreviewModel] = "previewModel";
38+
39+ return roles;
40+}
41+
42+void PreviewStack::setWidgetColumnCount(int columnCount)
43+{
44+ if (columnCount != 1) {
45+ qFatal("PreviewStack::setWidgetColumnCount != 1 not implemented");
46+ }
47+}
48+
49+int PreviewStack::widgetColumnCount() const
50+{
51+ return 1;
52+}
53+
54+int PreviewStack::rowCount(const QModelIndex&) const
55+{
56+ return m_previews.size();
57+}
58+
59+PreviewModel* PreviewStack::get(int index) const
60+{
61+ if (index >= m_previews.size()) {
62+ return nullptr;
63+ }
64+
65+ return m_previews.at(index);
66+}
67+
68+QVariant PreviewStack::data(const QModelIndex& index, int role) const
69+{
70+ switch (role) {
71+ case RolePreviewModel:
72+ return QVariant::fromValue(m_previews.at(index.row()));
73+ default:
74+ return QVariant();
75+ }
76+}
tests/mocks/Unity/fake_previewstack.hnew file+61
@@ -0,0 +1,61 @@
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+
18+#ifndef FAKE_PREVIEWSTACK_H
19+#define FAKE_PREVIEWSTACK_H
20+
21+#include <QAbstractListModel>
22+#include <QSharedPointer>
23+#include <QVariantMap>
24+
25+class PreviewModel;
26+
27+class PreviewStack : public QAbstractListModel
28+{
29+ Q_OBJECT
30+
31+ Q_ENUMS(Roles)
32+
33+ Q_PROPERTY(int widgetColumnCount READ widgetColumnCount WRITE setWidgetColumnCount NOTIFY widgetColumnCountChanged)
34+
35+public:
36+ explicit PreviewStack(QObject* parent = 0);
37+ virtual ~PreviewStack();
38+
39+ enum Roles {
40+ RolePreviewModel
41+ };
42+
43+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
44+ QHash<int, QByteArray> roleNames() const override;
45+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
46+
47+ Q_INVOKABLE PreviewModel* get(int index) const;
48+
49+ void setWidgetColumnCount(int columnCount);
50+ int widgetColumnCount() const;
51+
52+Q_SIGNALS:
53+ void widgetColumnCountChanged();
54+
55+private:
56+ QList<PreviewModel*> m_previews;
57+};
58+
59+Q_DECLARE_METATYPE(PreviewStack*)
60+
61+#endif // FAKE_PREVIEWSTACK_H
tests/mocks/Unity/scopes-ng/fake_preview_model.cpp → tests/mocks/Unity/fake_previewwidgetmodel.cpprenamed+6−16
@@ -19,14 +19,11 @@
1919 */
2020
2121// self
22−#include "fake_preview_model.h"
22+#include "fake_previewwidgetmodel.h"
2323
2424// Qt
2525#include <QVariantMap>
2626
27−namespace scopes_ng
28−{
29−
3027struct PreviewData
3128{
3229 QString id;
@@ -38,7 +35,7 @@ struct PreviewData
3835 }
3936};
4037
41−PreviewModel::PreviewModel(QObject* parent) : QAbstractListModel(parent)
38+PreviewWidgetModel::PreviewWidgetModel(QObject* parent) : QAbstractListModel(parent)
4239{
4340 m_roles[Roles::RoleWidgetId] = "widgetId";
4441 m_roles[Roles::RoleType] = "type";
@@ -47,7 +44,7 @@ PreviewModel::PreviewModel(QObject* parent) : QAbstractListModel(parent)
4744 populateWidgets();
4845}
4946
50−void PreviewModel::populateWidgets()
47+void PreviewWidgetModel::populateWidgets()
5148{
5249 beginResetModel();
5350 m_previewWidgets.clear();
@@ -63,22 +60,17 @@ void PreviewModel::populateWidgets()
6360
6461}
6562
66−void PreviewModel::triggered(QString widgetId, QString actionId, QVariantMap data)
67−{
68− Q_EMIT actionTriggered(widgetId, actionId, data);
69−}
70−
71−QHash<int, QByteArray> PreviewModel::roleNames() const
63+QHash<int, QByteArray> PreviewWidgetModel::roleNames() const
7264{
7365 return m_roles;
7466}
7567
76−int PreviewModel::rowCount(const QModelIndex&) const
68+int PreviewWidgetModel::rowCount(const QModelIndex&) const
7769{
7870 return m_previewWidgets.size();
7971}
8072
81−QVariant PreviewModel::data(const QModelIndex& index, int role) const
73+QVariant PreviewWidgetModel::data(const QModelIndex& index, int role) const
8274{
8375 auto widget_data = m_previewWidgets.at(index.row());
8476 switch (role) {
@@ -92,5 +84,3 @@ QVariant PreviewModel::data(const QModelIndex& index, int role) const
9284 return QVariant();
9385 }
9486}
95−
96−} // namespace scopes_ng
tests/mocks/Unity/scopes-ng/fake_preview_model.h → tests/mocks/Unity/fake_previewwidgetmodel.hrenamed+6−18
@@ -15,26 +15,23 @@
1515 */
1616
1717
18−#ifndef NG_FAKE_PREVIEW_H
19−#define NG_FAKE_PREVIEW_H
18+#ifndef FAKE_PREVIEWWIDGETMODEL_H
19+#define FAKE_PREVIEWWIDGETMODEL_H
2020
2121#include <QAbstractListModel>
2222#include <QSharedPointer>
2323#include <QVariantMap>
2424
25−namespace scopes_ng
26−{
27−
2825class PreviewData;
2926
30−class Q_DECL_EXPORT PreviewModel : public QAbstractListModel
27+class PreviewWidgetModel : public QAbstractListModel
3128{
3229 Q_OBJECT
3330
3431 Q_ENUMS(Roles)
3532
3633public:
37− explicit PreviewModel(QObject* parent = 0);
34+ explicit PreviewWidgetModel(QObject* parent = 0);
3835
3936 enum Roles {
4037 RoleWidgetId,
@@ -46,12 +43,6 @@ public:
4643 QHash<int, QByteArray> roleNames() const override;
4744 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
4845
49−Q_SIGNALS:
50− void actionTriggered(QString widgetId, QString actionId, QVariantMap data);
51−
52−public Q_SLOTS:
53− void triggered(QString widgetId, QString actionId, QVariantMap data);
54−
5546private:
5647 QHash<int, QByteArray> m_roles;
5748 QList<QSharedPointer<PreviewData>> m_previewWidgets;
@@ -60,9 +51,6 @@ private:
6051
6152};
6253
63−} // namespace scopes_ng
64−
65−
66−Q_DECLARE_METATYPE(scopes_ng::PreviewModel*)
54+Q_DECLARE_METATYPE(PreviewWidgetModel*)
6755
68−#endif // NG_FAKE_PREVIW_H
56+#endif // FAKE_PREVIEWWIDGETMODEL_H
tests/mocks/Unity/fake_resultsmodel.cppnew file+117
@@ -0,0 +1,117 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// self
21+#include "fake_resultsmodel.h"
22+
23+#include <paths.h>
24+
25+ResultsModel::ResultsModel(int result_count, int categoryId, QObject* parent)
26+ : QAbstractListModel(parent)
27+ , m_result_count(result_count)
28+ , m_categoryId(categoryId)
29+{
30+ m_roles[ResultsModel::RoleUri] = "uri";
31+ m_roles[ResultsModel::RoleCategoryId] = "categoryId";
32+ m_roles[ResultsModel::RoleDndUri] = "dndUri";
33+ m_roles[ResultsModel::RoleResult] = "result";
34+ m_roles[ResultsModel::RoleTitle] = "title";
35+ m_roles[ResultsModel::RoleArt] = "art";
36+ m_roles[ResultsModel::RoleSubtitle] = "subtitle";
37+ m_roles[ResultsModel::RoleMascot] = "mascot";
38+ m_roles[ResultsModel::RoleEmblem] = "emblem";
39+ m_roles[ResultsModel::RoleOldPrice] = "oldPrice";
40+ m_roles[ResultsModel::RolePrice] = "price";
41+ m_roles[ResultsModel::RoleAltPrice] = "altPrice";
42+ m_roles[ResultsModel::RoleRating] = "rating";
43+ m_roles[ResultsModel::RoleAltRating] = "altRating";
44+ m_roles[ResultsModel::RoleSummary] = "summary";
45+}
46+
47+QString ResultsModel::categoryId() const
48+{
49+ return QString::number(m_categoryId);
50+}
51+
52+void ResultsModel::setCategoryId(QString const& /*id*/)
53+{
54+ qFatal("Calling un-implemented ResultsModel::setCategoryId");
55+}
56+
57+QHash<int, QByteArray>
58+ResultsModel::roleNames() const
59+{
60+ return m_roles;
61+}
62+
63+int ResultsModel::rowCount(const QModelIndex& parent) const
64+{
65+ Q_UNUSED(parent);
66+
67+ return m_result_count;
68+}
69+
70+int ResultsModel::count() const
71+{
72+ return rowCount();
73+}
74+
75+QVariant ResultsModel::get(int row) const
76+{
77+ if (row >= m_result_count || row < 0) return QVariantMap();
78+
79+ QVariantMap result;
80+ QModelIndex modelIndex(index(row));
81+ QHashIterator<int, QByteArray> it(roleNames());
82+ while (it.hasNext()) {
83+ it.next();
84+ QVariant val(data(modelIndex, it.key()));
85+ if (val.isNull()) continue;
86+ result[it.value()] = val;
87+ }
88+
89+ return result;
90+}
91+
92+QVariant
93+ResultsModel::data(const QModelIndex& index, int role) const
94+{
95+ switch (role) {
96+ case RoleUri:
97+ case RoleCategoryId:
98+ case RoleDndUri:
99+ case RoleResult:
100+ return QString();
101+ case RoleTitle:
102+ return QString("Title.%1.%2").arg(m_categoryId).arg(index.row());
103+ case RoleArt:
104+ return qmlDirectory() + "graphics/applicationIcons/dash.png";
105+ case RoleSubtitle:
106+ case RoleMascot:
107+ case RoleEmblem:
108+ case RoleOldPrice:
109+ case RolePrice:
110+ case RoleAltPrice:
111+ case RoleRating:
112+ case RoleAltRating:
113+ case RoleSummary:
114+ default:
115+ return QVariant();
116+ }
117+}
tests/mocks/Unity/fake_resultsmodel.hnew file+80
@@ -0,0 +1,80 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+
21+#ifndef FAKE_RESULTS_MODEL_H
22+#define FAKE_RESULTS_MODEL_H
23+
24+#include <QAbstractListModel>
25+
26+class ResultsModel : public QAbstractListModel
27+{
28+ Q_OBJECT
29+
30+ Q_ENUMS(Roles)
31+
32+ Q_PROPERTY(QString categoryId READ categoryId WRITE setCategoryId NOTIFY categoryIdChanged)
33+ Q_PROPERTY(int count READ count NOTIFY countChanged)
34+
35+public:
36+ explicit ResultsModel(int result_count, int categoryId, QObject* parent = 0);
37+
38+ enum Roles {
39+ RoleUri,
40+ RoleCategoryId,
41+ RoleDndUri,
42+ RoleResult,
43+ // card components
44+ RoleTitle,
45+ RoleArt,
46+ RoleSubtitle,
47+ RoleMascot,
48+ RoleEmblem,
49+ RoleOldPrice,
50+ RolePrice,
51+ RoleAltPrice,
52+ RoleRating,
53+ RoleAltRating,
54+ RoleSummary
55+ };
56+
57+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
58+ QHash<int, QByteArray> roleNames() const override;
59+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
60+
61+ Q_INVOKABLE QVariant get(int row) const;
62+
63+ /* getters */
64+ QString categoryId() const;
65+ int count() const;
66+
67+ /* setters */
68+ void setCategoryId(QString const& id);
69+
70+Q_SIGNALS:
71+ void categoryIdChanged();
72+ void countChanged();
73+
74+private:
75+ QHash<int, QByteArray> m_roles;
76+ int m_result_count;
77+ int m_categoryId;
78+};
79+
80+#endif // FAKE_RESULTS_MODEL_H
tests/mocks/Unity/fake_scope.cpp+18−118
@@ -15,15 +15,7 @@
1515 */
1616
1717#include "fake_scope.h"
18−#include "fake_preview.h"
19−#include <paths.h>
20−
21−#include <dee.h>
22−
23−static DeeModel* create_categories_model(unsigned category_count);
24−static DeeModel* create_results_model(unsigned category_count, unsigned result_count);
25−
26−// TODO: Implement remaining pieces
18+#include "fake_resultsmodel.h"
2719
2820Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
2921{
@@ -37,20 +29,8 @@ Scope::Scope(QString const& id, QString const& name, bool visible, QObject* pare
3729 , m_searching(false)
3830 , m_isActive(false)
3931 , m_previewRendererName("preview-generic")
40− , m_categories(new Categories(this))
41− , m_results(new DeeListModel(this))
32+ , m_categories(new Categories(20, this))
4233{
43− DeeModel* results_model = create_results_model(20, 300);
44− m_categories->setResultModel(results_model);
45− m_categories->setModel(create_categories_model(20));
46− m_results->setModel(results_model);
47−
48− m_timer.setInterval(1000);
49− m_timer.setSingleShot(true);
50− connect(&m_timer, &QTimer::timeout, [this]() {
51− Preview *p = new Preview(m_previewRendererName, this);
52− Q_EMIT previewReady(p);
53− });
5434}
5535
5636QString Scope::id() const {
@@ -133,7 +113,7 @@ void Scope::setFormFactor(const QString &str) {
133113void Scope::setActive(const bool active) {
134114 if (active != m_isActive) {
135115 m_isActive = active;
136− Q_EMIT isActiveChanged();
116+ Q_EMIT isActiveChanged(active);
137117 }
138118}
139119
@@ -151,105 +131,25 @@ void Scope::setNoResultsHint(const QString& str) {
151131 }
152132}
153133
154−void Scope::activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
155− const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
156− const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
134+void Scope::activate(QVariant const& result)
157135{
158− Q_UNUSED(icon_hint);
159− Q_UNUSED(category);
160− Q_UNUSED(result_type);
161− Q_UNUSED(mimetype);
162− Q_UNUSED(title);
163− Q_UNUSED(comment);
164− Q_UNUSED(dnd_uri);
165− Q_UNUSED(metadata);
166−
167− if (uri != "uri://result.2")
168− m_timer.start();
169−}
170−
171−void Scope::preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
172− const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
173− const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata)
136+ Q_UNUSED(result);
137+}
138+
139+PreviewStack* Scope::preview(QVariant const& result)
174140{
175− Q_UNUSED(uri);
176− Q_UNUSED(icon_hint);
177− Q_UNUSED(category);
178− Q_UNUSED(result_type);
179− Q_UNUSED(mimetype);
180− Q_UNUSED(title);
181− Q_UNUSED(comment);
182− Q_UNUSED(dnd_uri);
183− Q_UNUSED(metadata);
184−
185− m_timer.start();
186−}
187−
188−static const gchar * categories_model_schema[] = {
189− "s", //ID
190− "s", // DISPLAY_NAME
191− "s", // ICON_HINT
192− "s", // RENDERER_NAME
193− "a{sv}" // HINTS
194−};
195−
196−
197−DeeModel* create_categories_model(unsigned category_count) {
198− DeeModel* category_model = dee_sequence_model_new();
199− dee_model_set_schema_full(category_model, categories_model_schema, G_N_ELEMENTS(categories_model_schema));
200− GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
201−
202− for(unsigned i = 0; i < category_count; ++i)
203− {
204− dee_model_append(category_model,
205− (i == 2) ? "applications.scope" : std::to_string(i).c_str(),
206− ("Category "+std::to_string(i)).c_str(),
207− "gtk-apply",
208− i % 2 == 0 ? "grid" : "carousel",
209− hints);
210− }
211− return category_model;
212−}
213−
214−
215−/* Schema that is used in the DeeModel representing
216− the results */
217−static const gchar * results_model_schema[] = {
218− "s", // URI
219− "s", // ICON_HINT
220− "u", // CATEGORY
221− "u", // RESULT_TYPE
222− "s", // MIMETYPE
223− "s", // TITLE
224− "s", // COMMENT
225− "s", // DND_URI
226− "a{sv}" // METADATA
227−};
228−
229−DeeModel* create_results_model(unsigned category_count, unsigned result_count) {
230− DeeModel* results_model = dee_sequence_model_new();
231− dee_model_set_schema_full(results_model, results_model_schema, G_N_ELEMENTS(results_model_schema));
232− GVariant* hints = g_variant_new_array(g_variant_type_element(G_VARIANT_TYPE_VARDICT), NULL, 0);
233−
234− for(unsigned i = 0; i < result_count; ++i)
235− {
236− unsigned category = i % category_count;
237−
238− dee_model_append(results_model,
239− ("uri://result."+std::to_string(i)).c_str(),
240− (qmlDirectory() + "graphics/applicationIcons/dash.png").toLatin1().data(),
241− category,
242− 0,
243− "application/x-desktop",
244− ("Title."+std::to_string(i)).c_str(),
245− ("Comment."+std::to_string(i)).c_str(),
246− ("uri://result."+std::to_string(i)).c_str(),
247− hints);
248− }
249− return results_model;
141+ Q_UNUSED(result);
142+
143+ // This probably leaks, do we don't care
144+ // it's a test after all
145+ return new PreviewStack;
250146}
251147
252148void Scope::cancelActivation()
253149{
254− m_timer.stop();
150+}
151+
152+void Scope::closeScope(Scope* /*scope*/)
153+{
154+ qFatal("Scope::closeScope is not implemented");
255155}
tests/mocks/Unity/fake_scope.h+17−18
@@ -18,9 +18,10 @@
1818#define FAKE_SCOPE_H
1919
2020#include "fake_categories.h"
21+#include "fake_previewstack.h"
2122
2223#include <QObject>
23−#include <QDebug>
24+#include <QTimer>
2425
2526class Preview;
2627
@@ -33,12 +34,12 @@ class Scope : public QObject
3334 Q_PROPERTY(QString iconHint READ iconHint NOTIFY iconHintChanged)
3435 Q_PROPERTY(QString description READ description NOTIFY descriptionChanged)
3536 Q_PROPERTY(QString searchHint READ searchHint NOTIFY searchHintChanged)
37+ Q_PROPERTY(bool searchInProgress READ searchInProgress WRITE setSearchInProgress NOTIFY searchInProgressChanged)
3638 Q_PROPERTY(bool visible READ visible NOTIFY visibleChanged)
3739 Q_PROPERTY(QString shortcut READ shortcut NOTIFY shortcutChanged)
38− Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
3940 Q_PROPERTY(Categories* categories READ categories NOTIFY categoriesChanged)
41+ //Q_PROPERTY(Filters* filters READ filters NOTIFY filtersChanged)
4042
41− Q_PROPERTY(bool searchInProgress READ searchInProgress WRITE setSearchInProgress NOTIFY searchInProgressChanged)
4243 Q_PROPERTY(QString searchQuery READ searchQuery WRITE setSearchQuery NOTIFY searchQueryChanged)
4344 Q_PROPERTY(QString noResultsHint READ noResultsHint WRITE setNoResultsHint NOTIFY noResultsHintChanged)
4445 Q_PROPERTY(QString formFactor READ formFactor WRITE setFormFactor NOTIFY formFactorChanged)
@@ -72,17 +73,13 @@ public:
7273 void setActive(const bool);
7374 void setSearchInProgress(const bool inProg);
7475
75− Q_INVOKABLE void activate(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
76− const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
77− const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
78− Q_INVOKABLE void preview(const QVariant &uri, const QVariant &icon_hint, const QVariant &category,
79− const QVariant &result_type, const QVariant &mimetype, const QVariant &title,
80− const QVariant &comment, const QVariant &dnd_uri, const QVariant &metadata);
81−
76+ Q_INVOKABLE void activate(QVariant const& result);
77+ Q_INVOKABLE PreviewStack* preview(QVariant const& result);
8278 Q_INVOKABLE void cancelActivation();
79+ Q_INVOKABLE void closeScope(Scope* scope);
8380
8481Q_SIGNALS:
85− void idChanged(const QString&);
82+ void idChanged();
8683 void nameChanged(const QString&);
8784 void iconHintChanged(const QString&);
8885 void descriptionChanged(const QString&);
@@ -90,18 +87,23 @@ Q_SIGNALS:
9087 void searchInProgressChanged();
9188 void visibleChanged(bool);
9289 void shortcutChanged(const QString&);
93− void connectedChanged(bool);
9490 void categoriesChanged();
91+ //void filtersChanged();
9592 void searchQueryChanged();
9693 void noResultsHintChanged();
9794 void formFactorChanged();
98− void isActiveChanged();
95+ void isActiveChanged(bool);
9996
10097 // signals triggered by activate(..) or preview(..) requests.
101− void previewReady(Preview *preview);
102− void activateApplication(const QString &desktop);
10398 void showDash();
10499 void hideDash();
100+ void gotoUri(const QString &uri);
101+ void activated();
102+ void previewRequested(QVariant const& result);
103+ void gotoScope(QString const& scopeId);
104+ void openScope(Scope* scope);
105+
106+ void activateApplication(const QString &desktop);
105107
106108protected:
107109
@@ -119,9 +121,6 @@ protected:
119121 QString m_previewRendererName;
120122
121123 Categories* m_categories;
122− DeeListModel* m_results;
123−
124− QTimer m_timer;
125124};
126125
127126#endif // FAKE_SCOPE_H
tests/mocks/Unity/fake_scopes.cpp+1−5
@@ -19,9 +19,6 @@
1919// Self
2020#include "fake_scopes.h"
2121
22−// Local
23−#include "fake_applications_scope.h"
24−
2522// TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
2623
2724// Qt
@@ -56,8 +53,7 @@ void Scopes::updateScopes()
5653 clear();
5754 addScope(new Scope("MockScope1", "People", true, this));
5855 addScope(new Scope("MockScope2", "Music", false, this));
59− addScope(new Scope("home.scope", "Home", true, this));
60− addScope(new ApplicationsScope(true, this));
56+ addScope(new Scope("clickscope", "Apps", true, this));
6157 addScope(new Scope("MockScope5", "Videos", true, this));
6258
6359 if (!m_loaded) {
tests/mocks/Unity/fake_unity_plugin.cpp+10−13
@@ -22,11 +22,9 @@
2222// local
2323#include "fake_scopes.h"
2424#include "fake_categories.h"
25−#include "fake_preview.h"
26−#include "categoryresults.h"
27−
28−// scopes-ng
29−#include "scopes-ng/fake_preview_model.h"
25+#include "fake_previewmodel.h"
26+#include "fake_previewwidgetmodel.h"
27+#include "fake_resultsmodel.h"
3028
3129// External
3230#include <glib-object.h>
@@ -41,12 +39,11 @@ void FakeUnityPlugin::registerTypes(const char *uri)
4139
4240 Q_ASSERT(uri == QLatin1String("Unity"));
4341
44− qmlRegisterUncreatableType<Preview>(uri, 0, 1, "Preview", "Can't create Preview object in QML.");
45− qmlRegisterType<Scopes>(uri, 0, 1, "Scopes");
46− qmlRegisterType<Scope>(uri, 0, 1, "Scope");
47− qmlRegisterType<Categories>(uri, 0, 1, "Categories");
48− qmlRegisterUncreatableType<CategoryResults>(uri, 0, 1, "CategoryResults", "Can't create");
49− qmlRegisterType<DeeListModel>(uri, 0, 1, "DeeListModel");
50−
51− qmlRegisterType<scopes_ng::PreviewModel>(uri, 0, 1, "FakePreviewModel");
42+ qmlRegisterType<Scopes>(uri, 0, 2, "Scopes");
43+ qmlRegisterType<Scope>(uri, 0, 2, "Scope");
44+ qmlRegisterUncreatableType<Categories>(uri, 0, 2, "Categories", "Can't create Categories object in QML.");
45+ qmlRegisterUncreatableType<ResultsModel>(uri, 0, 2, "ResultsModel", "Can't create ResultsModel object in QML.");
46+ qmlRegisterType<PreviewModel>(uri, 0, 2, "FakePreviewModel");
47+ qmlRegisterUncreatableType<PreviewWidgetModel>(uri, 0, 2, "PreviewWidgetModel", "Can't create new PreviewWidgetModel in QML. Get them from PreviewModel instance.");
48+ qmlRegisterUncreatableType<PreviewStack>(uri, 0, 2, "PreviewStack", "Can't create new PreviewStack in QML. Get them from Scope instance.");
5249}
tests/plugins/DashViews/listviewwithpageheadertest.cpp+24−6
@@ -32,6 +32,10 @@
3232#include <private/qquickitem_p.h>
3333#pragma GCC diagnostic pop
3434
35+// TODO Think on how doing a test for lost items
36+// particullary making sure that lost items are culled
37+// and then removed in the next updatePolish cycle
38+
3539class ListViewWithPageHeaderTest : public QObject
3640{
3741 Q_OBJECT
@@ -1281,9 +1285,6 @@ private Q_SLOTS:
12811285
12821286 void testShowHeaderHalfShown()
12831287 {
1284−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1285− QSKIP("This test is extremely unstable in 5.0.x");
1286−#endif
12871288 changeContentY(20);
12881289
12891290 QTRY_COMPARE(lvwph->m_visibleItems.count(), 4);
@@ -1860,9 +1861,6 @@ private Q_SLOTS:
18601861 model->setProperty(4, "size", 10);
18611862 model->setProperty(5, "size", 10);
18621863 model->setProperty(6, "size", 10);
1863−#if (QT_VERSION > QT_VERSION_CHECK(5, 0, 3))
1864− QTRY_COMPARE(lvwph->m_minYExtent, 210.);
1865−#endif
18661864 QTRY_COMPARE(lvwph->m_headerItem->y(), -lvwph->m_minYExtent);
18671865 }
18681866
@@ -1893,6 +1891,26 @@ private Q_SLOTS:
18931891 QTRY_COMPARE(lvwph->m_visibleItems.count(), 1);
18941892 }
18951893
1894+ void testResizeScrolledBigItem()
1895+ {
1896+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 6));
1897+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 0);
1898+
1899+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 10000));
1900+ changeContentY(8000);
1901+
1902+ // Pretend the list is busy requesting some other index
1903+ lvwph->m_asyncRequestedIndex = 4;
1904+
1905+ lvwph->m_visibleItems[0]->m_item->setHeight(100);
1906+ // This resize makes the item go outside the viewport so its deleted
1907+ QCOMPARE(lvwph->m_visibleItems.count(), 0);
1908+ QCOMPARE(lvwph->m_firstVisibleIndex, -1);
1909+ // On the next polish the item will be readded
1910+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 1);
1911+ QTRY_COMPARE(lvwph->m_firstVisibleIndex, 0);
1912+ }
1913+
18961914private:
18971915 QQuickView *view;
18981916 ListViewWithPageHeader *lvwph;
tests/plugins/DashViews/listviewwithpageheadertestsection.cpp−3
@@ -1486,9 +1486,6 @@ private Q_SLOTS:
14861486
14871487 void testShowHeaderHalfShown()
14881488 {
1489−#if (QT_VERSION < QT_VERSION_CHECK(5, 1, 0))
1490− QSKIP("This test is extremely unstable in 5.0.x");
1491−#endif
14921489 changeContentY(20);
14931490
14941491 QTRY_COMPARE(lvwph->m_visibleItems.count(), 3);
tests/plugins/DashViews/organicgridtest.cpp+2−1
@@ -134,11 +134,12 @@ private Q_SLOTS:
134134 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/organicgridtest.qml"));
135135
136136 view->show();
137− view->resize(470, 400);
138137 QTest::qWaitForWindowExposed(view);
138+ view->resize(470, 400);
139139
140140 grid = dynamic_cast<OrganicGrid*>(view->rootObject()->findChild<QObject*>("grid"));
141141 grid->setModel(model);
142+ QTRY_COMPARE(grid->width(), 470.);
142143
143144 checkInitialPositions();
144145 }
tests/plugins/DashViews/verticaljournaltest.cpp+2−1
@@ -135,11 +135,12 @@ private Q_SLOTS:
135135 view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/verticaljournaltest.qml"));
136136
137137 view->show();
138− view->resize(470, 400);
139138 QTest::qWaitForWindowExposed(view);
139+ view->resize(470, 400);
140140
141141 vj = dynamic_cast<VerticalJournal*>(view->rootObject()->findChild<QObject*>("vj"));
142142 vj->setModel(model);
143+ QTRY_COMPARE(vj->width(), 470.);
143144
144145 checkInitialPositions();
145146 }
tests/plugins/Ubuntu/Gestures/tst_DirectionalDragArea.cpp+8
@@ -103,6 +103,14 @@ void tst_DirectionalDragArea::init()
103103{
104104 GestureTest::init();
105105
106+ // We shouldn't need the three lines below, but a compiz/unity7
107+ // regression means we don't pass the test without them because
108+ // the window doesn't have the proper size. Can be removed in the
109+ // future if the regression is fixed and tests pass again
110+ m_view->resize(m_view->rootObject()->width(), m_view->rootObject()->height());
111+ QTRY_COMPARE(m_view->width(), (int)m_view->rootObject()->width());
112+ QTRY_COMPARE(m_view->height(), (int)m_view->rootObject()->height());
113+
106114 fakeTimeSource.reset(new FakeTimeSource);
107115 fakeTimer = new FakeTimer(fakeTimeSource);
108116}
tests/qmltests/CMakeLists.txt−10
@@ -13,8 +13,6 @@ set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
1313set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
1414add_qml_test(Components AnimationControllerWithSignals)
1515add_qml_test(Components Carousel)
16−add_qml_test(Components OpenEffect)
17−add_qml_test(Components RatingStars)
1816add_qml_test(Panel IndicatorItem)
1917add_qml_test(utils/Unity/Test UnityTest)
2018
@@ -38,24 +36,16 @@ add_qml_test(Components Showable)
3836add_qml_test(Components Stage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
3937 ${CMAKE_BINARY_DIR}/tests/mocks
4038 ${CMAKE_BINARY_DIR}/plugins)
41−add_qml_test(Components Tile)
4239add_qml_test(Components PageHeaderLabel)
4340add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4441add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
45−add_qml_test(Dash DashPreview)
46−add_qml_test(Dash GenericPreview)
4742add_qml_test(Dash Card)
4843add_qml_test(Dash CardHeader)
4944add_qml_test(Dash CardTool)
5045add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
51−add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins
52− ${CMAKE_BINARY_DIR}/tests/mocks)
5346add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS}
5447 ${CMAKE_BINARY_DIR}/tests/mocks
5548 ${CMAKE_BINARY_DIR}/plugins)
56−add_qml_test(Dash/Apps AppPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
57−add_qml_test(Dash/Movie MoviePreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
58−add_qml_test(Dash/Music MusicPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
5949add_qml_test(Dash/Previews Preview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
6050add_qml_test(Dash/Previews PreviewActions IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
6151add_qml_test(Dash/Previews PreviewAudioPlayback IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
tests/qmltests/Components/tst_DragHandle.cpp−1
@@ -126,7 +126,6 @@ QQuickView *tst_DragHandle::createView()
126126{
127127 QQuickView *window = new QQuickView(0);
128128 window->setResizeMode(QQuickView::SizeRootObjectToView);
129− window->resize(600, 600);
130129 window->engine()->addImportPath(QLatin1String(UBUNTU_GESTURES_PLUGIN_DIR));
131130 window->engine()->addImportPath(QLatin1String(TEST_DIR));
132131
tests/qmltests/Components/tst_LazyImage.qml+1−1
@@ -155,7 +155,7 @@ Rectangle {
155155
156156 if (data.transition) {
157157 // wait for the transition to complete
158− var transition = findInvisibleChild(data.image, data.transition);
158+ var transition = findChildIn(data.image, "transitions", data.transition);
159159 tryCompare(transition, "running", true);
160160 tryCompare(transition, "running", false);
161161 }
tests/qmltests/Components/tst_OpenEffect.qmldeleted−71
@@ -1,71 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../qml/Components"
20−
21−TestCase {
22− name: "OpenEffectTest"
23−
24− function test_openeffect_enabled() {
25− compare(openEffect1.enabled, true, "OpenEffect should be enabled if gap is greather than 0.0")
26− }
27−
28− function test_openeffect_shadereffectsource() {
29− compare(openEffect1.source.hideSource, true, "OpenEffect ShaderEffectSource is incorrect")
30− compare(openEffect1.source.sourceItem, rectangle2, "OpenEffect ShaderEffectSource is incorrect")
31− compare(openEffect1.source.live, false, "OpenEffect ShaderEffectSource is incorrect")
32− compare(openEffect1.source.sourceRect.x, 0, "OpenEffect ShaderEffectSource is incorrect")
33− compare(openEffect1.source.sourceRect.y, 0, "OpenEffect ShaderEffectSource is incorrect")
34− compare(openEffect1.source.sourceRect.width, 50, "OpenEffect ShaderEffectSource is incorrect")
35− compare(openEffect1.source.sourceRect.height, 71, "OpenEffect ShaderEffectSource is incorrect")
36− openEffect1.gap=2.0
37− compare(openEffect1.source.sourceRect.x, 0, "OpenEffect ShaderEffectSource is incorrect")
38− compare(openEffect1.source.sourceRect.y, 0, "OpenEffect ShaderEffectSource is incorrect")
39− compare(openEffect1.source.sourceRect.width, 50, "OpenEffect ShaderEffectSource is incorrect")
40− compare(openEffect1.source.sourceRect.height, 72, "OpenEffect ShaderEffectSource is incorrect")
41− }
42−
43− Rectangle {
44− id: rectangle1
45−
46− width: 100; height: 100
47−
48− Rectangle {
49− id: rectangle2
50− width: 50; height: 50
51− }
52−
53− OpenEffect {
54− id: openEffect1
55− anchors {
56− fill: parent
57− }
58−
59− property real gap: 1.0
60−
61− topGapPx: (1 - gap) * positionPx
62− topOpacity: (1 - gap * 1.2)
63− bottomGapPx: positionPx + gap * 10
64− bottomOverflow: 20 + gap
65− bottomOpacity: 1 - (gap * 0.8)
66−
67− positionPx: gap
68− sourceItem: rectangle2
69− }
70− }
71−}
tests/qmltests/Components/tst_PageHeaderLabel.qml+1−1
@@ -19,7 +19,7 @@ import QtTest 1.0
1919import ".."
2020import "../../../qml/Components"
2121import Ubuntu.Components 0.1
22−import Unity 0.1
22+import Unity 0.2
2323import Unity.Test 0.1 as UT
2424
2525Item {
tests/qmltests/Components/tst_RatingStars.qmldeleted−62
@@ -1,62 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../qml/Components"
20−
21−TestCase {
22− name: "RatingStars"
23−
24− property int maximumRating: 5
25− property int rating: 3
26− property alias effectiveRating: ratingStars.effectiveRating
27−
28− RatingStars {
29− id: ratingStars
30− maximumRating: parent.maximumRating
31− rating: parent.rating
32− }
33−
34− function test_rating_init() {
35− compare(effectiveRating, rating, "EffectiveRating not initialized properly")
36− }
37−
38− function test_rating_negative() {
39− rating = -3
40− compare(effectiveRating, 0, "EffectiveRating not calculated correctly")
41− }
42−
43− function test_rating_set_ok() {
44− rating = 2
45− compare(effectiveRating, rating, "EffectiveRating not calculated correctly")
46− }
47−
48− function test_rating_set_too_big() {
49− rating = 200
50− compare(effectiveRating, maximumRating, "EffectiveRating not calculated correctly")
51− }
52−
53− function test_rating_set_min() {
54− rating = 0
55− compare(effectiveRating, 0, "EffectiveRating not calculated correctly")
56− }
57−
58− function test_rating_set_max() {
59− rating = maximumRating
60− compare(effectiveRating, maximumRating, "EffectiveRating not calculated correctly")
61− }
62−}
tests/qmltests/Components/tst_Tile.qmldeleted−71
@@ -1,71 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import ".."
20−import "../../../qml/Components"
21−import Ubuntu.Components 0.1
22−import Unity.Test 0.1 as UT
23−
24−Item {
25− id: root
26− width: units.gu(20)
27− height: units.gu(24)
28−
29− property bool helper: false
30−
31− Tile {
32− id: tile
33− anchors.fill: parent
34− source: "../../../graphics/clock@18.png"
35− text: "Testing rocks, debugging sucks!"
36− imageWidth: width
37− imageHeight: width
38− }
39−
40− UT.UnityTestCase {
41− name: "Tile"
42− when: windowShown
43−
44− function test_click_highlight() {
45− var border = findChild(tile, "borderPressed")
46− compare(border.opacity, 0)
47− mousePress(root, 1, 1)
48− tryCompare(border, "opacity", 1)
49− mouseRelease(root, 1, 1)
50− tryCompare(border, "opacity", 0)
51− }
52−
53− function test_resize_image_data() {
54− return [
55− {tag: "small", w: 1, h: 1, click: true},
56− {tag: "large", w: units.gu(20), h: units.gu(20), click: true},
57− // If image is too large to fit, text will be moved outside of the scene and click should fail
58− {tag: "too large", w: units.gu(40), h: units.gu(40), click: false}
59− ]
60− }
61−
62− function test_resize_image(data) {
63− tile.imageWidth = data.w
64− tile.imageHeight = data.h
65− var label = findChild(tile, "label")
66− mousePress(label, 1, 1)
67− tryCompare(tile, "pressed", data.click)
68− mouseRelease(label, 1, 1)
69− }
70− }
71−}
tests/qmltests/Dash/Apps/tst_AppPreview.qmldeleted−276
@@ -1,276 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import Ubuntu.Components 0.1
20−import "../../../../qml/Dash/Apps"
21−import Unity.Test 0.1 as UT
22−
23−Item {
24− id: root
25− width: units.gu(60)
26− height: units.gu(80)
27−
28− // Fake shell
29− QtObject { id: shell; property int height: appPreview.height }
30−
31− property var calls: []
32−
33− SignalSpy {
34− id: sendPreviewSpy
35− target: appPreview
36− signalName: "sendUserReview"
37− }
38−
39− property string commentary: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus a mi vitae augue rhoncus lobortis ut rutrum metus. Curabitur tortor leo, tristique sed mollis quis, condimentum venenatis nibh.";
40− QtObject { id: screenshots; property var value: ["fake_image1.png", "fake_image2.png", "fake_image3.png"] }
41− QtObject { id: rating; property real value: 0.8 }
42− QtObject { id: rated; property int value: 120 }
43− QtObject { id: reviews; property int value: 8 }
44− QtObject { id: progress; property string value: "source" }
45− QtObject { id: publisher; property string value: "Ubuntu Developer" }
46− QtObject { id: comments; property var value: [
47− ["Unity User", 4, "08/20/2013", root.commentary],
48− ["Unity User", 8, "01/15/2013", root.commentary],
49− ["Unity User", 10, "10/02/2013", root.commentary],
50− ]
51− }
52− QtObject { id: showProgress; property bool value: true }
53− QtObject { id: progressSource; property string value: "service" }
54−
55− QtObject {
56− id: data
57− property string title: "Unity App"
58− property string appIcon: "fake_image.png"
59− property string description: "This is an Application description"
60− property real rating: rating.value
61− property int numRatings: reviews.value
62− property var execute: root.fake_call
63− property var infoMap: {
64− "more-screenshots": screenshots,
65− "rated": rated,
66− "comments": comments,
67− "publisher": publisher
68− }
69− property var actions: [
70− { "id": 123, "displayName": "action1" },
71− { "id": 456, "displayName": "action2" },
72− { "id": 789, "displayName": "action3" },
73− ]
74− }
75−
76− QtObject {
77− id: dataProgress
78− property string title: "Unity App"
79− property string appIcon: "fake_image.png"
80− property string description: "This is an Application description"
81− property real rating: rating.value
82− property int numRatings: reviews.value
83− property var execute: root.fake_call
84− property var infoMap: {
85− "show_progressbar": showProgress,
86− "more-screenshots": screenshots,
87− "rated": rated,
88− "comments": comments,
89− "publisher": publisher,
90− "progressbar_source": progressSource
91− }
92− property var actions: [
93− { "id": 123, "displayName": "action1" },
94− { "id": 456, "displayName": "action2" },
95− { "id": 789, "displayName": "action3" },
96− ]
97− }
98−
99− function fake_call(id, data){
100− root.calls[root.calls.length] = [id, data];
101− }
102−
103− // The component under test
104− AppPreview {
105− id: appPreview
106− anchors.fill: parent
107−
108− previewData: data
109− }
110−
111− UT.UnityTestCase {
112− name: "AppPreview"
113− when: windowShown
114−
115− function init() {
116− waitForRendering(appPreview)
117− }
118−
119− function cleanup() {
120− root.calls = new Array();
121− sendPreviewSpy.clear();
122− // TODO: This doesn't work right now as Reviews are disabled
123− //var reviewField = findChild(appPreview, "reviewField");
124− //reviewField.focus = false;
125− //reviewField.text = "";
126− //data.rating = rating.value;
127− dataProgress.infoMap["progressbar_source"].value = "service";
128− //var appReviews = findChild(appPreview, "appReviews");
129− //appReviews.visible = false;
130− //appPreview.keyboardSize = 0;
131− }
132−
133− function test_actions() {
134− var buttons = findChild(appPreview, "buttonList");
135− compare(buttons.count, 3, "Not the proper amount of actions detected.");
136−
137− for(var i = 0; i < buttons.count; i++) {
138− var button = findChild(appPreview, "button" + i);
139− mouseClick(button, 1, 1);
140− appPreview.showProcessingAction = false;
141− }
142−
143− var actions = data.actions;
144− for(var j = 0; j < actions.length; j++) {
145− compare(root.calls[j][0], actions[j].id, "Id of action not found.");
146− }
147− }
148−
149− function test_check_app_info() {
150− var appInfo = findChild(appPreview, "previewHeader");
151− var titleLabel = findChild(appInfo, "titleLabel");
152− var subtitleLabel = findChild(appInfo, "subtitleLabel");
153− compare(titleLabel.text, data.title, "App Title doesn't match.");
154− compare(subtitleLabel.text, publisher.value, "Publisher name doesn't match.");
155− }
156−
157− function test_rated() {
158− var rated = findChild(appPreview, "ratedLabel");
159− compare(rated.text, "(120)", "Rates not equal");
160− }
161−
162− function test_reviews() {
163− var rated = findChild(appPreview, "reviewsLabel");
164− compare(rated.text, "8 reviews", "Reviews don't match");
165− }
166−
167− // TODO: Disabled as reviewing and commenting is currently disabled
168− function test_send_review() {
169− skip();
170− var appReviews = findChild(appPreview, "appReviews");
171− appReviews.sendReview("review");
172− sendPreviewSpy.wait();
173− }
174−
175− function test_review_focus() {
176− skip();
177− var columnReviewRating = findChild(appPreview, "columnReviewRating");
178− columnReviewRating.visible = true;
179− var appReviews = findChild(appPreview, "appReviews");
180− appReviews.visible = true;
181− var sendButton = findChild(appReviews, "sendButton");
182− var reviewField = findChild(appReviews, "reviewField");
183−
184− compare(reviewField.focus, false, "ReviewField shouldn't have focus");
185− compare(appReviews.state, "", "State should be empty");
186−
187− mouseClick(reviewField, reviewField.width/2, reviewField.height/2);
188− compare(reviewField.focus, true, "Review Field should have focus");
189− compare(appReviews.state, "editing", "State should be 'editing'");
190− }
191−
192− function test_comments() {
193− skip();
194− var commentsArea = findChild(appPreview, "commentsArea");
195− compare(commentsArea.count, 3);
196− for(var i = 0; i < 3; i++) {
197− var username = commentsArea.itemAt(i).children[0].children[0].text
198− var rate = commentsArea.itemAt(i).children[0].children[1].children[0].rating
199− var date = commentsArea.itemAt(i).children[0].children[1].children[1].text
200− var comment = commentsArea.itemAt(i).children[1].text
201− compare(username, comments.value[i][0], "Username don't match");
202− compare(rate, comments.value[i][1], "Rating don't match");
203− compare(date, comments.value[i][2], "Date don't match");
204− compare(comment, comments.value[i][3], "Comment don't match");
205− }
206− }
207−
208− function test_negative_rating() {
209− skip();
210− data.rating = -1.0;
211− var rated = findChild(appPreview, "reviewsLabel");
212− verify(rated.visible == false);
213− var commentsArea = findChild(appPreview, "commentsArea");
214− verify(commentsArea.visible == false);
215− var appReviews = findChild(appPreview, "appReviews");
216− verify(appReviews.visible == false);
217− var buttons = findChild(appPreview, "gridButtons");
218− verify(buttons.visible == true);
219− }
220−
221− function test_automatic_scroll_on_keyboard_shown() {
222− skip();
223− waitForRendering(appPreview);
224− var appReviews = findChild(appPreview, "appReviews");
225− appReviews.visible = true;
226−
227− var leftFlickable = findChild(appPreview, "leftFlickable");
228− leftFlickable.contentY = leftFlickable.contentHeight;
229− var reviewField = findChild(appReviews, "reviewField");
230− appPreview.keyboardSize = 400;
231− appReviews.editing(reviewField);
232− var newFlickPos = leftFlickable.contentY;
233− var keyboardY = shell.height - appPreview.keyboardSize;
234− verify(newFlickPos < keyboardY);
235− }
236−
237− function test_progress_show() {
238− appPreview.previewData = dataProgress;
239− var progress = findChild(appPreview, "progressBar");
240− verify(progress.visible == true);
241− }
242−
243− function test_progress_download_finish() {
244− appPreview.previewData = dataProgress;
245− var progress = findChild(appPreview, "progressBar");
246− dataProgress.infoMap["progressbar_source"].value = "finish";
247−
248− var actions = dataProgress.actions;
249− compare(root.calls[0][0], actions[0].id, "Id of action not found.");
250− compare(root.calls[0][1], {}, "Data of action not found.");
251− }
252−
253− function test_progress_download_error() {
254− appPreview.previewData = dataProgress;
255− var progress = findChild(appPreview, "progressBar");
256− dataProgress.infoMap["progressbar_source"].value = "error";
257−
258− var actions = dataProgress.actions;
259− compare(root.calls[0][0], actions[1].id, "Id of action not found.");
260− compare(root.calls[0][1], {"error": "DOWNLOAD ERROR"}, "Data of action not found.");
261− }
262−
263− function test_placeholderScreenshot() {
264− var placeholderScreenshot = findChild(appPreview, "placeholderScreenshot");
265− compare(placeholderScreenshot.visible, false);
266−
267− data.infoMap["more-screenshots"] = [];
268− appPreview.previewData = data;
269− tryCompare(placeholderScreenshot, "visible", true);
270−
271− data.infoMap["more-screenshots"] = screenshots;
272− appPreview.previewData = data;
273− tryCompare(placeholderScreenshot, "visible", false);
274− }
275− }
276−}
tests/qmltests/Dash/Movie/tst_MoviePreview.qmldeleted−86
@@ -1,86 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../../qml/Dash/Movie"
20−import Unity.Test 0.1 as UT
21−
22−Item {
23− id: root
24− width: units.gu(60)
25− height: units.gu(80)
26−
27− property var calls: []
28− property int counter: 0
29−
30− function get_actions_data() {
31− return [
32− { id: 123, displayName: "Play", iconHint: "image://theme/search" },
33− { id: 456, displayName: "Buy", iconHint: "image://theme/search" },
34− { id: 789, displayName: "Delete", iconHint: "image//theme/search" }
35− ]
36− }
37−
38− function fake_callback(id, data){
39− root.calls[root.calls.length] = id;
40− }
41−
42− // The component under test
43− MoviePreview {
44− id: moviePreview
45− anchors.fill: parent
46−
47− previewData: QtObject {
48− property string rendererName: "preview-movie"
49− property string title: "Unity Movie"
50− property string subtitle: "Subtitle"
51− property string description: "This is the description"
52− property string image: "../../tests/qmltests/Components/tst_LazyImage/square.png"
53− property var actions: get_actions_data()
54− property string year: "2013"
55− property real rating: 0.3
56− property int numRatings: 1
57− property var execute: fake_callback
58− }
59− }
60−
61− UT.UnityTestCase {
62− name: "MoviePreviewTest"
63− when: windowShown
64−
65− function init() {
66− waitForRendering(moviePreview);
67− root.calls = new Array();
68− }
69−
70− function test_actions() {
71− var buttons = findChild(moviePreview, "buttonList");
72− compare(buttons.count, 3);
73−
74− for(var i = 0; i < buttons.count; i++) {
75− var button = findChild(moviePreview, "button" + i);
76− mouseClick(button, 1, 1);
77− moviePreview.showProcessingAction = false;
78− }
79−
80− var actions = get_actions_data();
81− for(var i = 0; i < actions.length; i++) {
82− compare(root.calls[i], actions[i].id);
83− }
84− }
85− }
86−}
tests/qmltests/Dash/Music/tst_MusicPreview.qmldeleted−174
@@ -1,174 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../../qml/Dash/Music"
20−import Unity.Test 0.1 as UT
21−import QtMultimedia 5.0
22−
23−Rectangle {
24− id: root
25− width: units.gu(60)
26− height: units.gu(80)
27− color: "lightgrey"
28−
29− MusicPreview {
30− id: musicPreview
31− anchors.fill: parent
32− isCurrent: true
33−
34− previewData: QtObject {
35− property string rendererName: "preview-music"
36− property string title: "Music Preview"
37− property string subtitle: "Subtitle"
38− property string description: "This is the description"
39− property string image: "../../tests/qmltests/Components/tst_LazyImage/square.png"
40− property var actions: [
41− { id: 123, displayName: "Play"},
42− { id: 456, displayName: "Show in folder"}
43− ]
44− property var tracks: tracksModel2
45− }
46− }
47−
48− ListModel {
49− id: tracksModel0
50− }
51− ListModel {
52− id: tracksModel1
53− ListElement { uri: "../../tests/qmltests/Dash/Music/data/testsound1.ogg"; trackNo: 1; title: "Some track name"; length: "0:30"}
54− }
55− ListModel {
56− id: tracksModel2
57− ListElement { uri: "../../tests/qmltests/Dash/Music/data/testsound1.ogg"; trackNo: 1; title: "Some track name"; length: "0:30"}
58− ListElement { uri: "../../tests/qmltests/Dash/Music/data/testsound1.ogg"; trackNo: 2; title: "Some track name"; length: "0:30"}
59− ListElement { uri: "../../tests/qmltests/Dash/Music/data/testsound2.ogg"; trackNo: 3; title: "Some other track name"; length: "1:23"}
60− ListElement { uri: "../../tests/qmltests/Dash/Music/data/testsound3.ogg"; trackNo: 4; title: "And another one"; length: "123:45"}
61− }
62−
63− UT.UnityTestCase {
64− name: "MusicPreviewTest"
65− when: windowShown
66−
67− function init() {
68− waitForRendering(musicPreview);
69− }
70−
71− function test_tracks_data() {
72− return [
73− {tag: "0 tracks", tracksModel: tracksModel0, dividerVisible: false},
74− {tag: "1 track", tracksModel: tracksModel1, dividerVisible: true},
75− {tag: "4 track", tracksModel: tracksModel2, dividerVisible: true}
76− ];
77− }
78−
79− function test_tracks(data) {
80− musicPreview.previewData.tracks = data.tracksModel;
81− waitForRendering(musicPreview);
82−
83− var trackRepeater = findChild(musicPreview, "trackRepeater");
84− compare(trackRepeater.count, data.tracksModel.count)
85−
86− var topDivider = findChild(musicPreview, "topDivider");
87− compare(topDivider.visible, data.dividerVisible);
88−
89− for (var i = 0; i < data.tracksModel.count; ++i) {
90− var trackItem = findChild(musicPreview, "trackItem" + i);
91− var titleLabel = findChild(trackItem, "trackTitleLabel");
92− compare(titleLabel.text, data.tracksModel.get(i).title)
93− var timeLabel = findChild(trackItem, "timeLabel");
94− compare(timeLabel.text, data.tracksModel.get(i).length)
95− }
96− }
97−
98− function checkPlayerUri(index) {
99− var modelFilename = musicPreview.previewData.tracks.get(index).uri.replace(/^.*[\\\/]/, '');
100− var playerFilename = findInvisibleChild(musicPreview, "audioPlayer").source.toString().replace(/^.*[\\\/]/, '');
101−
102− compare(modelFilename, playerFilename, "Player source is not set correctly.");
103− }
104−
105− function test_playback() {
106− musicPreview.previewData.tracks = tracksModel2;
107− waitForRendering(musicPreview);
108−
109− var track0Item = findChild(musicPreview, "trackItem0");
110− var track1Item = findChild(musicPreview, "trackItem1");
111− var track2Item = findChild(musicPreview, "trackItem2");
112−
113− var track0ProgressBar = findChild(track0Item, "progressBarFill");
114− var track1ProgressBar = findChild(track1Item, "progressBarFill");
115− var track2ProgressBar = findChild(track2Item, "progressBarFill");
116−
117− var track0PlayButton = findChild(track0Item, "playButton");
118− var track1PlayButton = findChild(track1Item, "playButton");
119− var track2PlayButton = findChild(track2Item, "playButton");
120−
121− var audioPlayer = findInvisibleChild(musicPreview, "audioPlayer");
122−
123− // All progress bars must be hidden in the beginning
124− compare(track0ProgressBar.visible, false);
125− compare(track1ProgressBar.visible, false);
126− compare(track2ProgressBar.visible, false);
127−
128− // Playing track 0 should make progress bar 0 visible
129− mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
130−
131− tryCompare(audioPlayer, "playbackState", Audio.PlayingState);
132− checkPlayerUri(0);
133−
134− tryCompare(track0ProgressBar, "visible", true);
135− tryCompare(track1ProgressBar, "visible", false);
136− tryCompare(track2ProgressBar, "visible", false);
137−
138− // Clicking the button again should pause it. The progress bar should stay visible
139− mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
140− tryCompare(audioPlayer, "playbackState", Audio.PausedState);
141− checkPlayerUri(0);
142− tryCompare(track0ProgressBar, "visible", true);
143−
144− // Continue playback
145− mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
146− tryCompare(audioPlayer, "playbackState", Audio.PlayingState);
147− checkPlayerUri(0);
148−
149− // Playing track 1 should make progress bar 1 visible and hide progress bar 0 again
150− mouseClick(track1PlayButton, track1PlayButton.width / 2, track1PlayButton.height / 2);
151−
152− tryCompare(audioPlayer, "playbackState", Audio.PlayingState);
153− checkPlayerUri(1);
154−
155− tryCompare(track0ProgressBar, "visible", false);
156− tryCompare(track1ProgressBar, "visible", true);
157− tryCompare(track2ProgressBar, "visible", false);
158−
159− // Playing track 2 should make progress bar 1 visible and hide progress bar 0 again
160− mouseClick(track2PlayButton, track2PlayButton.width / 2, track2PlayButton.height / 2);
161−
162− tryCompare(audioPlayer, "playbackState", Audio.PlayingState);
163− checkPlayerUri(2);
164−
165− tryCompare(track0ProgressBar, "visible", false);
166− tryCompare(track1ProgressBar, "visible", false);
167− tryCompare(track2ProgressBar, "visible", true);
168−
169− // Switching away from this preview should make all players shut up!
170− musicPreview.isCurrent = false
171− tryCompare(audioPlayer, "playbackState", Audio.StoppedState);
172− }
173− }
174−}
tests/qmltests/Dash/Previews/tst_Preview.qml+4−18
@@ -18,7 +18,7 @@ import QtQuick 2.0
1818import QtTest 1.0
1919import "../../../../qml/Dash/Previews"
2020import Unity.Test 0.1 as UT
21−import Unity 0.1 as Unity
21+import Unity 0.2 as Unity
2222
2323Rectangle {
2424 id: root
@@ -47,7 +47,7 @@ Rectangle {
4747 SignalSpy {
4848 id: triggeredSpy
4949 target: mockPreviewModel
50− signalName: "actionTriggered"
50+ signalName: "triggered"
5151 }
5252
5353 UT.UnityTestCase {
@@ -60,9 +60,9 @@ Rectangle {
6060
6161 compare(typeof widget, "object", "Could not find the widget object.");
6262
63+ compare(triggeredSpy.count, 0)
6364 widget.triggered(widget.widgetId, "mockAction", {"mock": "data"});
64−
65− triggeredSpy.wait();
65+ compare(triggeredSpy.count, 1)
6666
6767 var args = triggeredSpy.signalArguments[0];
6868
@@ -71,20 +71,6 @@ Rectangle {
7171 compare(args[2]["mock"], "data", "Data not passed correctly.");
7272 }
7373
74− function test_showProcessing() {
75− waitForRendering(preview);
76− var widget = findChild(preview, "widget-3");
77− widget.triggered(widget.widgetId, "mockAction", {"mock": "data"});
78−
79− var processing = findChild(preview, "processingMouseArea");
80−
81− tryCompare(processing, "enabled", true);
82−
83− preview.previewModelChanged();
84−
85− tryCompare(processing, "enabled", false);
86− }
87−
8874 function test_containOnFocus() {
8975 waitForRendering(preview);
9076 tryCompareFunction(function () { return findChild(preview, "widget-9") != null }, true);
tests/qmltests/Dash/Previews/tst_PreviewRatingInput.qml+1−1
@@ -174,7 +174,7 @@ Rectangle {
174174 compare(spy.count, 1);
175175 var args = spy.signalArguments[0];
176176 compare(args[0], previewRatingInput.widgetId);
177− compare(args[1], data.widgetData["required"]);
177+ compare(args[1], "rated");
178178 compare(args[2]["rating"], data.triggeredData["rating"]);
179179 compare(args[2]["review"], data.triggeredData["review"]);
180180 verify(args[2]["author"]); // Just verifying it exists now
tests/qmltests/Dash/Previews/tst_PreviewVideoPlayback.qml−6
@@ -53,12 +53,6 @@ Rectangle {
5353 function test_loadScreenshot() {
5454 var screenshot = findChild(videoPlayback, "screenshot");
5555
56− videoPlayback.widgetData = widgetData0;
57− tryCompare(screenshot.visible, false);
58−
59− videoPlayback.widgetData = widgetData1;
60− tryCompare(screenshot.visible, true);
61−
6256 videoPlayback.widgetData = widgetData2;
6357 var screenshotSource = screenshot.source
6458 verify(screenshotSource.toString().indexOf("image://thumbnailer/") === 0)
tests/qmltests/Dash/Previews/tst_PreviewZoomableImage.qml+3−4
@@ -30,14 +30,13 @@ Rectangle {
3030 }
3131
3232 property var widgetData1: {
33− "source": "../../graphics/phone_background.jpg",
33+ "source": Qt.resolvedUrl("../artwork/checkers.png"),
3434 "zoomable": false
3535 }
3636
3737 PreviewZoomableImage {
3838 id: zoomableImage
3939 width: parent.width
40− widgetData: widgetData1
4140 }
4241
4342 UT.UnityTestCase {
@@ -48,10 +47,10 @@ Rectangle {
4847 var image = findChild(zoomableImage, "image");
4948
5049 zoomableImage.widgetData = widgetData0;
51− tryCompare(image.state, "default");
50+ tryCompare(image, "state", "default");
5251
5352 zoomableImage.widgetData = widgetData1;
54− tryCompare(image.state, "ready");
53+ tryCompare(image, "state", "ready");
5554 }
5655 }
5756}
tests/qmltests/Dash/qml/FakeScopeView.qml+1−1
@@ -15,7 +15,7 @@
1515 */
1616
1717import QtQuick 2.0
18−import Unity 0.1
18+import Unity 0.2
1919
2020import "../../../../qml/Dash"
2121
tests/qmltests/Dash/qml/fake_scopeView1.qml+1−1
@@ -20,5 +20,5 @@ FakeScopeView {
2020 id: fake_scopeView1
2121 objectName: "fake_scopeView1"
2222
23− backColor: "#909090"
23+ backColor: "#90E090"
2424}
tests/qmltests/Dash/qml/fake_scopeView2.qml+1−1
@@ -20,5 +20,5 @@ FakeScopeView {
2020 id: fake_scopeView2
2121 objectName: "fake_scopeView2"
2222
23− backColor: "#A0A0A0"
23+ backColor: "#A0D0A0"
2424}
tests/qmltests/Dash/qml/fake_scopeView3.qml+1−1
@@ -20,5 +20,5 @@ FakeScopeView {
2020 id: fake_scopeView3
2121 objectName: "fake_scopeView3"
2222
23− backColor: "#B0B0B0"
23+ backColor: "#B0C0B0"
2424}
tests/qmltests/Dash/tst_Card.qml+49
@@ -427,5 +427,54 @@ Rectangle {
427427
428428 tryCompare(testCase.title.font, "weight", data.weight);
429429 }
430+
431+ function test_fontColor_data() {
432+ return [
433+ { tag: "#ffffff", dark: true },
434+ { tag: "#fdfdfd", dark: true },
435+ { tag: "#f9f9f9", dark: true },
436+ { tag: "#000000", dark: false },
437+ { tag: "#ef814c", dark: false },
438+ { tag: "#312f2c", dark: false },
439+ { tag: "#be332d", dark: false },
440+ { tag: "#52ace4", dark: false },
441+ { tag: "#3a5897", dark: false },
442+ { tag: "#1caeeb", dark: false },
443+ { tag: "#87c341", dark: false },
444+ { tag: "#50893b", dark: false },
445+ ];
446+ }
447+
448+ function test_fontColor(data) {
449+ selector.selectedIndex = 10;
450+
451+ background.color = data.tag;
452+
453+ var fontColor = data.dark ? "grey" : "white";
454+
455+ tryCompareFunction(function() { return Qt.colorEqual(summary.color, fontColor); }, true);
456+ tryCompareFunction(function() { return Qt.colorEqual(header.fontColor, fontColor); }, true);
457+ }
458+
459+ function test_mascotShape_data() {
460+ return [
461+ { tag: "Art and summary", shape: false, index: 0 },
462+ { tag: "No Summary", shape: true, index: 6 },
463+ { tag: "With background", shape: false, index: 10 },
464+ ];
465+ }
466+
467+ function test_mascotShape(data) {
468+ selector.selectedIndex = data.index;
469+
470+ var shape = findChild(card, "mascotShape");
471+ var image = findChild(card, "mascotImage");
472+
473+ verify(shape, "Could not find shape.");
474+ verify(image, "Could not find image.");
475+
476+ tryCompare(shape, "visible", data.shape);
477+ tryCompare(image, "visible", !data.shape);
478+ }
430479 }
431480}
tests/qmltests/Dash/tst_CardHeader.qml+1−28
@@ -46,7 +46,6 @@ Rectangle {
4646 property Item mascot: findChild(cardHeader, "mascotShape")
4747 property Item titleLabel: findChild(cardHeader, "titleLabel")
4848 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
49− property Item prices: findChild(cardHeader, "prices")
5049 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
5150 property Item outerRow: findChild(cardHeader, "outerRow")
5251 property Item column: findChild(cardHeader, "column")
@@ -55,7 +54,6 @@ Rectangle {
5554 verify(typeof testCase.mascot === "object", "Couldn't find mascot object.");
5655 verify(typeof testCase.titleLabel === "object", "Couldn't find titleLabel object.");
5756 verify(typeof testCase.subtitleLabel === "object", "Couldn't find subtitleLabel object.");
58− verify(typeof testCase.prices === "object", "Couldn't find prices object.");
5957 verify(typeof testCase.oldPriceLabel === "object", "Couldn't find oldPriceLabel object.");
6058 }
6159
@@ -63,9 +61,6 @@ Rectangle {
6361 cardHeader.mascot = "";
6462 cardHeader.title = "";
6563 cardHeader.subtitle = "";
66− cardHeader.price = "";
67− cardHeader.oldPrice = "";
68− cardHeader.altPrice = "";
6964 }
7065
7166 function test_mascot_data() {
@@ -96,33 +91,11 @@ Rectangle {
9691 tryCompare(cardHeader, "visible", data.visible);
9792 }
9893
99− function test_prices_data() {
100− return [
101− { tag: "Main", main: "$1.25", visible: true },
102− { tag: "Alt", alt: "€1.00", visible: false },
103− { tag: "Old", old: "€2.00", visible: false },
104− { tag: "Main and Alt", main: "$1.25", alt: "€1.00", visible: true },
105− { tag: "Main and Old", main: "$1.25", old: "$2.00", visible: true, oldAlign: Text.AlignRight },
106− { tag: "Alt and Old", alt: "€1.00", old: "$2.00", visible: false },
107− { tag: "All", main: "$1.25", alt: "€1.00", old: "$2.00", visible: true, oldAlign: Text.AlignHCenter },
108− ]
109− }
110−
111− function test_prices(data) {
112− cardHeader.price = data.main !== undefined ? data.main : "";
113− cardHeader.oldPrice = data.old !== undefined ? data.old : "";
114− cardHeader.altPrice = data.alt !== undefined ? data.alt : "";
115− tryCompare(cardHeader, "visible", data.visible);
116− if (data.hasOwnProperty("oldAlign")) {
117− compare(testCase.oldPriceLabel.horizontalAlignment, data.oldAlign, "Old price label is aligned wrong.")
118− }
119− }
120−
12194 function test_dimensions_data() {
12295 return [
12396 { tag: "Column width", object: column, width: cardHeader.width },
12497 { tag: "Column width with mascot", object: column, width: cardHeader.width - mascot.width - outerRow.margins * 3, mascot: "artwork/avatar.png" },
125− { tag: "Header height", object: cardHeader, height: function() { return subtitleLabel.y + subtitleLabel.height + outerRow.margins * 2 } },
98+ { tag: "Header height", object: cardHeader, height: function() { return outerRow.height + outerRow.margins * 2 } },
12699 ]
127100 }
128101
tests/qmltests/Dash/tst_CardTool.qml+21−1
@@ -93,6 +93,7 @@ Rectangle {
9393 CardTool {
9494 id: cardTool
9595
96+ count: 8
9697 template: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template'];
9798 components: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components'];
9899 viewWidth: units.gu(Math.round(widthSlider.value))
@@ -256,7 +257,7 @@ Rectangle {
256257 id: testCase
257258 name: "Card"
258259
259− property Card internalCard: findChild(cardTool, "card")
260+ property Card internalCard: findChild(cardTool, "cardToolCard")
260261
261262 when: windowShown
262263
@@ -343,5 +344,24 @@ Rectangle {
343344 tryCompare(cardTool, data.property, data.value);
344345 }
345346 }
347+
348+ function test_categoryLayout_data() {
349+ return [
350+ { tag: "Default Grid", layout_index: 0, count: 2, viewWidth: units.gu(40), layout: "grid" },
351+ { tag: "Long carousel", layout_index: 4, count: 6, viewWidth: units.gu(140), layout: "carousel" },
352+ { tag: "Long carousel fallback", layout_index: 4, count: 5, viewWidth: units.gu(140), layout: "grid" },
353+ { tag: "Short carousel", layout_index: 4, count: 4, viewWidth: units.gu(30), layout: "carousel" },
354+ { tag: "Short carousel fallback", layout_index: 4, count: 3, viewWidth: units.gu(30), layout: "grid" },
355+ { tag: "Journal", layout_index: 2, count: 8, viewWidth: units.gu(30), layout: "journal" }
356+ ]
357+ }
358+
359+ function test_categoryLayout(data) {
360+ selector.selectedIndex = 0;
361+ layoutSelector.selectedIndex = data.layout_index;
362+ cardTool.viewWidth = data.viewWidth;
363+ cardTool.count = data.count;
364+ compare(cardTool.categoryLayout, data.layout);
365+ }
346366 }
347367}
tests/qmltests/Dash/tst_Dash.qml+14−6
@@ -20,11 +20,21 @@ import "../../../qml/Dash"
2020import Ubuntu.Components 0.1
2121import Unity.Test 0.1 as UT
2222
23+// TODO We don't have any tests for the overlay scope functionality.
24+
2325Item {
2426 id: shell
2527 width: units.gu(40)
2628 height: units.gu(80)
2729
30+ // BEGIN To reduce warnings
31+ // TODO I think it we should pass down these variables
32+ // as needed instead of hoping they will be globally around
33+ property var greeter: null
34+ property var panel: null
35+ // BEGIN To reduce warnings
36+
37+
2838 Dash {
2939 id: dash
3040 anchors.fill: parent
@@ -36,8 +46,7 @@ Item {
3646 scopeDelegateMapping: {
3747 "MockScope1": Qt.resolvedUrl("qml/fake_scopeView1.qml"),
3848 "MockScope2": Qt.resolvedUrl("qml/fake_scopeView2.qml"),
39− "home.scope": Qt.resolvedUrl("qml/fake_scopeView3.qml"),
40− "applications.scope": Qt.resolvedUrl("qml/fake_scopeView4.qml")
49+ "clickscope": Qt.resolvedUrl("qml/fake_scopeView3.qml")
4150 }
4251 genericScope: Qt.resolvedUrl("qml/fake_generic_scopeView.qml")
4352 }
@@ -67,9 +76,8 @@ Item {
6776 return [
6877 { tag: "MockScope1", visualIndex: 0, shouldBeVisible: true },
6978 { tag: "MockScope2", visualIndex: -1, shouldBeVisible: false },
70− { tag: "home.scope", visualIndex: 1, shouldBeVisible: true },
71− { tag: "applications.scope", visualIndex: 2, shouldBeVisible: true },
72− { tag: "MockScope5", visualIndex: 3, shouldBeVisible: true },
79+ { tag: "clickscope", visualIndex: 1, shouldBeVisible: true },
80+ { tag: "MockScope5", visualIndex: 2, shouldBeVisible: true },
7381 ]
7482 }
7583
@@ -107,7 +115,7 @@ Item {
107115 tryCompare(dashContentList, "count", 0);
108116 scopes.load();
109117 tryCompare(scopes, "loaded", true);
110− tryCompare(dashContentList, "count", 4);
118+ tryCompare(dashContentList, "count", 3);
111119
112120 verify(dashContentList != undefined);
113121 tryCompare(dashContentList, "currentIndex", data.visualIndex);
tests/qmltests/Dash/tst_DashContent.qml+117−35
@@ -19,7 +19,7 @@ import QtTest 1.0
1919import "../../../qml/Dash"
2020import "../../../qml/Components"
2121import Ubuntu.Components 0.1
22−import Unity 0.1
22+import Unity 0.2
2323import Unity.Test 0.1 as UT
2424import Utils 0.1
2525
@@ -28,23 +28,17 @@ Item {
2828 width: units.gu(40)
2929 height: units.gu(80)
3030
31− Item {
32− // Fake. Make a few components less noisy
33− id: greeter
34− signal shownChanged
35− }
36−
37− Item {
38− // Fake. Make a few components less noisy
39− id: panel
40− signal searchClicked
41− }
31+ // BEGIN To reduce warnings
32+ // TODO I think it we should pass down these variables
33+ // as needed instead of hoping they will be globally around
34+ property var greeter: null
35+ property var panel: null
36+ // BEGIN To reduce warnings
4237
4338 property var scopeStatus: {
4439 'MockScope1': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
4540 'MockScope2': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
46− 'home.scope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
47− 'applications.scope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
41+ 'clickscope': { 'movementStarted': 0, 'positionedAtBeginning': 0 },
4842 'MockScope5': { 'movementStarted': 0, 'positionedAtBeginning': 0 }
4943 }
5044
@@ -70,8 +64,7 @@ Item {
7064 scopeDelegateMapping: {
7165 "MockScope1": Qt.resolvedUrl("qml/fake_scopeView1.qml"),
7266 "MockScope2": Qt.resolvedUrl("qml/fake_scopeView2.qml"),
73− "home.scope": Qt.resolvedUrl("qml/fake_scopeView3.qml"),
74− "applications.scope": Qt.resolvedUrl("qml/fake_scopeView4.qml")
67+ "clickscope": Qt.resolvedUrl("qml/fake_scopeView3.qml"),
7568 }
7669 genericScope: Qt.resolvedUrl("qml/fake_generic_scopeView.qml")
7770 }
@@ -83,11 +76,8 @@ Item {
8376 scopeStatus["MockScope2"].movementStarted = 0;
8477 scopeStatus["MockScope2"].positionedAtBeginning = 0;
8578
86− scopeStatus["home.scope"].movementStarted = 0;
87− scopeStatus["home.scope"].positionedAtBeginning = 0;
88−
89− scopeStatus["applications.scope"].movementStarted = 0;
90− scopeStatus["applications.scope"].positionedAtBeginning = 0;
79+ scopeStatus["clickscope"].movementStarted = 0;
80+ scopeStatus["clickscope"].positionedAtBeginning = 0;
9181
9282 scopeStatus["MockScope5"].movementStarted = 0;
9383 scopeStatus["MockScope5"].positionedAtBeginning = 0;
@@ -113,7 +103,7 @@ Item {
113103 scopesModel.clear();
114104 scopeLoadedSpy.clear();
115105 scopesModel.load();
116− tryCompare(scopeLoadedSpy, "count", 5);
106+ tryCompare(scopeLoadedSpy, "count", 4);
117107 }
118108
119109 function cleanup() {
@@ -138,7 +128,7 @@ Item {
138128
139129 scopeLoadedSpy.clear();
140130 scopesModel.load();
141− tryCompare(scopeLoadedSpy, "count", 5);
131+ tryCompare(scopeLoadedSpy, "count", 4);
142132
143133 verify(dashContentList.currentIndex >= 0);
144134 }
@@ -154,7 +144,7 @@ Item {
154144
155145 scopeLoadedSpy.clear();
156146 scopesModel.load();
157− tryCompare(scopeLoadedSpy, "count", 5);
147+ tryCompare(scopeLoadedSpy, "count", 4);
158148
159149 verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
160150 }
@@ -170,8 +160,7 @@ Item {
170160 compare(movementStartedSpy.count, 1, "DashContent should have emitted movementStarted signal when content list did.");
171161 compare(scopeStatus["MockScope1"].movementStarted, 1, "MockScope1 should have emitted movementStarted signal when content list did.");
172162 compare(scopeStatus["MockScope2"].movementStarted, 1, "MockScope2 should have emitted movementStarted signal when content list did.");
173− compare(scopeStatus["home.scope"].movementStarted, 1, "home.scope should have emitted movementStarted signal when content list did.");
174− compare(scopeStatus["applications.scope"].movementStarted, 1, "applications.scope should have emitted movementStarted signal when content list did.");
163+ compare(scopeStatus["clickscope"].movementStarted, 1, "clickscope should have emitted movementStarted signal when content list did.");
175164 compare(scopeStatus["MockScope5"].movementStarted, 1, "MockScope5 should have emitted movementStarted signal when content list did.");
176165 }
177166
@@ -181,8 +170,7 @@ Item {
181170 dashContent.positionedAtBeginning();
182171 compare(scopeStatus["MockScope1"].positionedAtBeginning, 1, "MockScope1 should have emitted positionedAtBeginning signal when DashContent did.");
183172 compare(scopeStatus["MockScope2"].positionedAtBeginning, 1, "MockScope2 should have emitted positionedAtBeginning signal when DashContent did.");
184− compare(scopeStatus["home.scope"].positionedAtBeginning, 1, "home.scope should have emitted positionedAtBeginning signal when DashContent did.");
185− compare(scopeStatus["applications.scope"].positionedAtBeginning, 1, "applications.scope should have emitted positionedAtBeginning signal when DashContent did.");
173+ compare(scopeStatus["clickscope"].positionedAtBeginning, 1, "clickscope should have emitted positionedAtBeginning signal when DashContent did.");
186174 compare(scopeStatus["MockScope5"].positionedAtBeginning, 1, "MockScope5 should have emitted positionedAtBeginning signal when DashContent did.");
187175 }
188176
@@ -220,11 +208,10 @@ Item {
220208
221209 function test_scope_mapping_data() {
222210 return [
223− {tag: "index0", index: 0, objectName: "fake_scopeView1"},
224− {tag: "index1", index: 1, objectName: "fake_scopeView2"},
225− {tag: "index2", index: 2, objectName: "fake_scopeView3"},
226− {tag: "index3", index: 3, objectName: "fake_scopeView4"},
227− {tag: "index4", index: 4, objectName: "fake_generic_scopeView"}
211+ {tag: "index0", index: 0, objectName: "MockScope1"},
212+ {tag: "index1", index: 1, objectName: "MockScope2"},
213+ {tag: "index2", index: 2, objectName: "clickscope"},
214+ {tag: "index3", index: 3, objectName: "MockScope5"}
228215 ]
229216 }
230217
@@ -284,7 +271,7 @@ Item {
284271 tryCompare(scopesModel, "loaded", true);
285272 var tabbar = findChild(dashContent, "tabbar");
286273
287− compare(dashContent.currentIndex, 0);
274+ tryCompare(dashContent, "currentIndex", 0);
288275 tryCompare(tabbar, "selectedIndex", 0);
289276 tryCompare(tabbar, "selectionMode", false);
290277
@@ -298,6 +285,7 @@ Item {
298285 tryCompareFunction(function() { button = findMusicButton(); return button != undefined; }, true);
299286 waitForRendering(button);
300287
288+ tryCompareFunction(function() { return button.opacity > 0; }, true);
301289 mouseClick(button, button.width / 2, button.height / 2)
302290
303291 tryCompare(tabbar, "selectionMode", false);
@@ -309,7 +297,8 @@ Item {
309297 var tabbar = findChild(dashContent, "tabbar");
310298 tryCompare(dashContent, "currentIndex", 0);
311299 compare(tabbar.selectedIndex, 0);
312− dashContent.currentIndex = 1;
300+ var dashContentList = findChild(dashContent, "dashContentList");
301+ dashContentList.currentIndex = 1;
313302 compare(tabbar.selectedIndex, 1);
314303 }
315304
@@ -334,5 +323,98 @@ Item {
334323
335324 tryCompareFunction(checkFlickMovingAndNotInteractive, true);
336325 }
326+
327+ function openPreview() {
328+ tryCompareFunction(function() {
329+ var filterGrid = findChild(dashContent, "0");
330+ if (filterGrid != null) {
331+ var tile = findChild(filterGrid, "delegate0");
332+ return tile != null;
333+ }
334+ return false;
335+ },
336+ true);
337+ var tile = findChild(findChild(dashContent, "0"), "delegate0");
338+ mouseClick(tile, tile.width / 2, tile.height / 2);
339+ var previewListView = findChild(dashContent, "dashContentPreviewList");
340+ tryCompare(previewListView, "open", true);
341+ tryCompare(previewListView, "x", 0);
342+ }
343+
344+ function closePreview() {
345+ var closePreviewMouseArea = findChild(dashContent, "dashContentPreviewList_pageHeader_backButton");
346+ mouseClick(closePreviewMouseArea, closePreviewMouseArea.width / 2, closePreviewMouseArea.height / 2);
347+
348+ var previewListView = findChild(dashContent, "dashContentPreviewList");
349+ tryCompare(previewListView, "open", false);
350+ }
351+
352+ function test_previewOpenClose() {
353+ tryCompare(scopeLoadedSpy, "count", 4);
354+
355+ var previewListView = findChild(dashContent, "dashContentPreviewList");
356+ tryCompare(previewListView, "open", false);
357+
358+ var categoryListView = findChild(dashContent, "categoryListView");
359+ categoryListView.positionAtBeginning();
360+
361+ openPreview();
362+ closePreview();
363+ }
364+
365+ function test_showPreviewCarousel() {
366+ tryCompareFunction(function() {
367+ var scope = findChild(dashContent, "MockScope1 loader");
368+ if (scope != null) {
369+ var dashCategory1 = findChild(scope, "dashCategory1");
370+ if (dashCategory1 != null) {
371+ var tile = findChild(dashCategory1, "carouselDelegate1");
372+ return tile != null;
373+ }
374+ }
375+ return false;
376+ },
377+ true);
378+
379+ tryCompare(scopeLoadedSpy, "count", 4);
380+
381+ var previewListView = findChild(dashContent, "dashContentPreviewList");
382+ tryCompare(previewListView, "open", false);
383+
384+ var scope = findChild(dashContent, "MockScope1 loader");
385+ var dashCategory1 = findChild(scope, "dashCategory1");
386+ var tile = findChild(dashCategory1, "carouselDelegate1");
387+ mouseClick(tile, tile.width / 2, tile.height / 2);
388+ tryCompare(previewListView, "open", true);
389+ tryCompare(previewListView, "x", 0);
390+
391+ closePreview();
392+ }
393+
394+ function test_previewCycle() {
395+ tryCompare(scopeLoadedSpy, "count", 4);
396+
397+ var categoryListView = findChild(dashContent, "categoryListView");
398+ categoryListView.positionAtBeginning();
399+
400+ var previewListView = findChild(dashContent, "dashContentPreviewList");
401+ tryCompare(previewListView, "open", false);
402+ var previewListViewList = findChild(dashContent, "dashContentPreviewList_listView");
403+
404+ openPreview();
405+
406+ // flick to the next previews
407+ tryCompare(previewListView, "count", 15);
408+ for (var i = 1; i < previewListView.count; ++i) {
409+ mouseFlick(previewListView, previewListView.width - units.gu(1),
410+ previewListView.height / 2,
411+ units.gu(2),
412+ previewListView.height / 2);
413+ tryCompare(previewListViewList, "moving", false);
414+ tryCompare(previewListView.currentItem, "objectName", "previewItem" + i);
415+
416+ }
417+ closePreview();
418+ }
337419 }
338420}
tests/qmltests/Dash/tst_DashPreview.qmldeleted−202
@@ -1,202 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import ".."
20−import "../../../qml/Dash"
21−import Ubuntu.Components 0.1
22−import Unity.Test 0.1 as UT
23−
24−Item {
25− id: root
26− width: units.gu(120)
27− height: units.gu(80)
28−
29− property bool helper: false
30−
31− DashPreview {
32− id: preview
33− anchors.fill: parent
34−
35− previewImages: Rectangle {
36− width: parent.width
37− height: units.gu(20)
38− color: "honeydew"
39− Label {
40− anchors.centerIn: parent
41− text: "Preview images"
42− }
43− }
44−
45− header: Rectangle {
46− width: parent.width
47− height: units.gu(10)
48− color: "papayawhip"
49− Label {
50− anchors.centerIn: parent
51− text: "Caption label"
52− }
53− }
54−
55− actions: Row {
56− width: parent.width
57− height: units.gu(5)
58− Rectangle {
59− width: parent.width / 3
60− height: parent.height
61− color: "blue"
62− Label {
63− anchors.centerIn: parent
64− text: "Button 1"
65− }
66− MouseArea {
67− id: buttonMouseArea
68− objectName: "buttonMouseArea"
69− anchors.fill: parent
70− onClicked: root.helper = true
71− }
72− }
73− Rectangle {
74− width: parent.width / 3
75− height: parent.height
76− color: "green"
77− Label {
78− anchors.centerIn: parent
79− text: "Button 2"
80− }
81−
82− }
83− }
84−
85− description: Column {
86− id: testContent
87− objectName: "testContent"
88− width: parent.width
89− height: units.gu(50)
90− Rectangle {
91− width: parent.width
92− height: parent.height / 3
93− color: "green"
94− Label {
95− anchors.centerIn: parent
96− text: "Description part 1"
97− }
98− }
99− Rectangle {
100− width: parent.width
101− height: parent.height / 3
102− color: "red"
103− Label {
104− anchors.centerIn: parent
105− text: "Description part 2"
106− }
107− }
108− Rectangle {
109− width: parent.width
110− height: parent.height / 3
111− color: "blue"
112− Label {
113− anchors.centerIn: parent
114− text: "Description part 3"
115− }
116− }
117− }
118−
119− ratings: Rectangle {
120− objectName: "ratings"
121− width: parent.width
122− height: units.gu(20)
123− Label {
124− anchors.centerIn: parent
125− text: "Ratings"
126− }
127− }
128− }
129−
130− SignalSpy {
131− id: closeSpy
132− target: preview
133− signalName: "close"
134− }
135−
136− SignalSpy {
137− id: previewClickedSpy
138− target: preview
139− signalName: "previewImageClicked"
140− }
141−
142− UT.UnityTestCase {
143− name: "DashPreview"
144− when: windowShown
145−
146− function test_columns_data() {
147− return [
148− {tag: "1 columns", width: units.gu(5), height: units.gu(10), columns: 1},
149− {tag: "3 columns", width: units.gu(50), height: units.gu(10), columns: 3}
150− ]
151− }
152−
153− function test_columns(data) {
154− var leftCol = findChild(preview, "leftColumn")
155− var centerCol = findChild(preview, "centerColumn")
156− var rightCol = findChild(preview, "rightColumn")
157−
158− root.width = data.width
159− root.height = data.height
160−
161− // there are 3 columns in DashPreview. On portrait form factors
162− // only the left one is used and the center and right ones should be empty.
163− // To find out if the content is in the correct column, we get a
164− // reference to the column objects and search only the subtree
165− // to see if the content is in the correct column.
166− // 1 colum -> all content should be in leftColumn
167− // 3 colums -> content should be in centerColumn, rating in rightColumn
168−
169− switch(data.columns) {
170− case 1:
171− var testContent = findChild(leftCol, "testContent")
172− compare(testContent.objectName, "testContent")
173− testContent = findChild(leftCol, "ratings")
174− compare(testContent.objectName, "ratings")
175− break
176− case 3:
177− var testContent = findChild(centerCol, "testContent")
178− compare(testContent.objectName, "testContent")
179− testContent = findChild(rightCol, "ratings")
180− compare(testContent.objectName, "ratings")
181− break
182− }
183−
184− // reset to initial values to not disturb other tests
185− root.width = units.gu(120)
186− root.height = units.gu(80)
187− }
188−
189− // This test just checks if Components assigned to the
190− // "buttons" property are actually put somewhere on the
191− // screen. the mouseClick would fail if they are not used/painted
192− function test_ensure_buttons_visible() {
193− waitForRendering(preview)
194−
195− var button = findChild(preview, "buttonMouseArea")
196− mouseClick(button, 1, 1)
197− tryCompare(root, "helper", true)
198− // reset to false in case any other test wants to use it
199− root.helper = false
200− }
201− }
202−}
tests/qmltests/Dash/tst_FilterGrids.qmldeleted−143
@@ -1,143 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../qml/Dash/Video"
20−import Ubuntu.Components.ListItems 0.1 as ListItem
21−import Ubuntu.Components 0.1
22−import Unity.Test 0.1 as UT
23−import "../"
24−
25−Rectangle {
26− id: shell
27− width: gridRect.width + controls.width
28− height: units.gu(50)
29− color: "white"
30−
31− Column {
32− id: controls
33− width: units.gu(30)
34− height: parent.height
35− anchors.top: parent.top
36− anchors.right: parent.right
37− spacing: units.gu(1)
38− Label {
39− id: spyLabel
40− color: "blue"
41− text: "Clicked item: [none]"
42− anchors {left: parent.left; right: parent.right; margins: units.gu(1) }
43− }
44− Repeater {
45− model: testCase.test_clicked_signal_data()
46− Button {
47− anchors {left: parent.left; right: parent.right; margins: units.gu(1) }
48− text: testCase.test_clicked_signal_data()[index].tag
49− onClicked: gridLoader.source = "../../../qml/Dash/" + testCase.test_clicked_signal_data()[index].component
50− }
51− }
52− }
53−
54− ListModel {
55− id: fakeModel
56− ListElement { icon: "../../graphics/clock.png"; title: "Item0"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
57− ListElement { icon: "../../graphics/clock.png"; title: "Item1"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
58− ListElement { icon: "../../graphics/clock.png"; title: "Item2"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
59− ListElement { icon: "../../graphics/clock.png"; title: "Item3"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
60− ListElement { icon: "../../graphics/clock.png"; title: "Item4"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
61− ListElement { icon: "../../graphics/clock.png"; title: "Item5"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
62− ListElement { icon: "../../graphics/clock.png"; title: "Item6"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
63− ListElement { icon: "../../graphics/clock.png"; title: "Item7"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
64− ListElement { icon: "../../graphics/clock.png"; title: "Item8"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
65− ListElement { icon: "../../graphics/clock.png"; title: "Item9"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
66− ListElement { icon: "../../graphics/clock.png"; title: "Item10"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
67− ListElement { icon: "../../graphics/clock.png"; title: "Item11"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
68− ListElement { icon: "../../graphics/clock.png"; title: "Item12"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
69− ListElement { icon: "../../graphics/clock.png"; title: "Item13"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
70− ListElement { icon: "../../graphics/clock.png"; title: "Item14"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
71− ListElement { icon: "../../graphics/clock.png"; title: "Item15"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
72− ListElement { icon: "../../graphics/clock.png"; title: "Item16"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
73− ListElement { icon: "../../graphics/clock.png"; title: "Item17"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
74− ListElement { icon: "../../graphics/clock.png"; title: "Item18"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
75− ListElement { icon: "../../graphics/clock.png"; title: "Item19"; comment: ""; uri: "dummy.desktop"; dndUri: "dummy.desktop" }
76− }
77−
78− Rectangle {
79− id: gridRect
80− width: units.gu(50)
81− height: parent.height
82− color: "grey"
83− anchors.top: parent.top
84− anchors.left: parent.left
85−
86− Loader {
87− id: gridLoader
88− anchors.fill: parent
89−
90− onProgressChanged: {
91− if (progress == 1) {
92− item.model = fakeModel
93− }
94− }
95− }
96−
97− Connections {
98− target: gridLoader.item
99− onClicked: spyLabel.text = "Clicked index: " + index
100− }
101− }
102−
103− UT.UnityTestCase {
104− id: testCase
105− name: "FilterGrids"
106− when: windowShown
107−
108− function test_clicked_signal_data() {
109− return [
110− {tag: "VideoFilterGrid", component: "Video/VideoFilterGrid.qml"},
111− {tag: "MusicFilterGrid", component: "Music/MusicFilterGrid.qml"}
112− ]
113− }
114−
115− function test_clicked_signal(data) {
116− gridLoader.source = "";
117− gridLoader.source = "../../../qml/Dash/" + data.component;
118−
119− // Wait until the FilterGrid is loaded by the loader
120− tryCompare(gridLoader, "status", Loader.Ready);
121−
122− // Wait until the GridView inside the model has finished rendering
123− var gridView = findChild(gridLoader, "responsiveGridViewGrid");
124− gridView.forceLayout();
125− waitForRendering(gridView);
126−
127− // Click item 1
128− var tile1 = findChild(gridLoader.item, "delegate1");
129− verify(tile1 !== undefined, "delegate1 wasn't found");
130− clickedSpy.clear()
131− mouseClick(tile1, tile1.width/2, tile1.height/2);
132−
133− // Check emission of clicked() signal with the according index as argument
134− compare(clickedSpy.signalArguments[0][0], 1, "Clicked index is not the same as the one actually clicked")
135− }
136− }
137−
138− SignalSpy {
139− id: clickedSpy
140− signalName: "clicked"
141− target: gridLoader.item
142− }
143−}
tests/qmltests/Dash/tst_GenericPreview.qmldeleted−125
@@ -1,125 +0,0 @@
1−/*
2− * Copyright 2013 Canonical Ltd.
3− *
4− * This program is free software; you can redistribute it and/or modify
5− * it under the terms of the GNU General Public License as published by
6− * the Free Software Foundation; version 3.
7− *
8− * This program is distributed in the hope that it will be useful,
9− * but WITHOUT ANY WARRANTY; without even the implied warranty of
10− * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11− * GNU General Public License for more details.
12− *
13− * You should have received a copy of the GNU General Public License
14− * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− */
16−
17−import QtQuick 2.0
18−import QtTest 1.0
19−import "../../../qml/Dash/Generic"
20−import Unity.Test 0.1 as UT
21−
22−Item {
23− id: root
24− width: units.gu(60)
25− height: units.gu(80)
26−
27− property var calls: []
28− property int counter: 0
29−
30− function get_actions_data() {
31− return [
32− { id: 123, displayName: "Button 1", iconHint: "image://theme/search" },
33− { id: 456, displayName: "Button 2", iconHint: "image://theme/search" },
34− { id: 789, displayName: "Button 3", iconHint: "image://theme/search" }
35− ]
36− }
37−
38− function fake_callback(id, data){
39− root.calls[root.calls.length] = id;
40− }
41−
42− // The component under test
43− GenericPreview {
44− id: genericPreview
45− anchors.fill: parent
46−
47− previewData: QtObject {
48− id: dataObject
49− property string rendererName: "preview-generic"
50− property string title: "Unity Generic Preview"
51− property string subtitle: "Subtitle"
52− property string description: "This is the description"
53− property string image: "../../tests/qmltests/Components/tst_LazyImage/square.png"
54− property var actions: get_actions_data()
55− property string year: "2013"
56− property var execute: fake_callback
57− property var infoHints: [{displayName: "info 1", value: "value 1"},
58− {displayName: "info 2", value: "value 2"}
59− ]
60− }
61− }
62−
63− UT.UnityTestCase {
64− name: "GenericPreviewTest"
65− when: windowShown
66−
67− function init() {
68− waitForRendering(genericPreview)
69− root.calls = new Array();
70− }
71−
72− function test_actions() {
73− var buttons = findChild(genericPreview, "buttonList");
74− compare(buttons.count, 3);
75−
76− for(var i = 0; i < buttons.count; i++) {
77− var button = findChild(genericPreview, "button" + i);
78− mouseClick(button, 1, 1);
79− genericPreview.showProcessingAction = false;
80− }
81−
82− var actions = get_actions_data();
83− for(var i = 0; i < actions.length; i++) {
84− compare(root.calls[i], actions[i].id);
85− }
86− }
87−
88− function test_title() {
89− var titleLabel = findChild(genericPreview, "titleLabel");
90− compare(titleLabel.text, dataObject.title)
91− }
92−
93− function test_subtitle() {
94− var subtitleLabel = findChild(genericPreview, "subtitleLabel");
95− compare(subtitleLabel.text, dataObject.subtitle)
96− }
97−
98− function test_image() {
99− var image = findChild(genericPreview, "genericPreviewImage");
100− tryCompare(image, "height", genericPreview.width - units.gu(6))
101− }
102−
103− function test_infoHints() {
104− var infoHintColumn = findChild(genericPreview, "infoHintColumn")
105− var infoHintRepeater = findChild(genericPreview, "infoHintRepeater")
106− compare(infoHintRepeater.count, dataObject.infoHints.length)
107−
108− for (var i = 0; i < dataObject.infoHints.length; ++i) {
109− var infoItem = findChild(infoHintColumn, "infoHintItem" + i)
110− var displayName = findChild(infoItem, "displayNameLabel")
111− compare(displayName.text, dataObject.infoHints[i].displayName)
112− var value = findChild(infoItem, "valueLabel")
113− compare(value.text, dataObject.infoHints[i].value)
114− }
115− }
116−
117− function test_showProcessing() {
118− var button = findChild(genericPreview, "button1");
119− mouseClick(button, 1, 1);
120− tryCompare(genericPreview, "showProcessingAction", true);
121− genericPreview.previewDataChanged();
122− tryCompare(genericPreview, "showProcessingAction", false);
123− }
124− }
125−}
tests/qmltests/Dash/tst_GenericScopeView.qml+25−247
@@ -16,7 +16,7 @@
1616
1717import QtQuick 2.0
1818import QtTest 1.0
19−import Unity 0.1
19+import Unity 0.2
2020import ".."
2121import "../../../qml/Dash"
2222import "../../../qml/Components"
@@ -26,7 +26,14 @@ import Unity.Test 0.1 as UT
2626Item {
2727 id: shell
2828 width: units.gu(120)
29− height: units.gu(80)
29+ height: units.gu(100)
30+
31+ // BEGIN To reduce warnings
32+ // TODO I think it we should pass down these variables
33+ // as needed instead of hoping they will be globally around
34+ property var greeter: null
35+ property var panel: null
36+ // BEGIN To reduce warnings
3037
3138 Scopes {
3239 id: scopes
@@ -41,24 +48,19 @@ Item {
4148 signal mainStageFocusedApplicationChanged()
4249 }
4350
44− DashContentOpenEffect {
45− id: openEffect
46− previewListView: previewListView
47− sourceItem: genericScopeView
48− }
49−
5051 PageHeaderLabel {
51− id: pageHeader
52+ id: testPageHeader
5253 searchHistory: SearchHistoryModel {}
54+ text: genericScopeView.scope ? genericScopeView.scope.name : ""
55+ width: parent.width
5356 }
5457
5558 GenericScopeView {
5659 id: genericScopeView
5760 anchors.fill: parent
5861 previewListView: previewListView
59− openEffect: openEffect
60− pageHeader: pageHeader
61− tabBarHeight: pageHeader.implicitHeight
62+ pageHeader: testPageHeader
63+ tabBarHeight: testPageHeader.implicitHeight
6264
6365 UT.UnityTestCase {
6466 name: "GenericScopeView"
@@ -67,15 +69,15 @@ Item {
6769 function init() {
6870 shell.width = units.gu(120)
6971 genericScopeView.categoryView.positionAtBeginning();
70− tryCompare(genericScopeView.categoryView.contentY, 0)
72+ tryCompare(genericScopeView.categoryView, "contentY", 0)
7173 }
7274
7375 function test_isCurrent() {
7476 genericScopeView.isCurrent = true
75− pageHeader.searchQuery = "test"
77+ testPageHeader.searchQuery = "test"
7678 previewListView.open = true
7779 genericScopeView.isCurrent = false
78− tryCompare(pageHeader, "searchQuery", "")
80+ tryCompare(testPageHeader, "searchQuery", "")
7981 tryCompare(previewListView, "open", false);
8082 }
8183
@@ -93,181 +95,14 @@ Item {
9395
9496 function test_showDash() {
9597 previewListView.open = true;
96− tryCompare(openEffect, "live", true);
9798 scopes.get(2).showDash();
9899 tryCompare(previewListView, "open", false);
99− tryCompare(openEffect, "live", true);
100100 }
101101
102102 function test_hideDash() {
103103 previewListView.open = true;
104104 scopes.get(2).hideDash();
105105 tryCompare(previewListView, "open", false);
106− tryCompare(openEffect, "gap", 0);
107− }
108−
109− function openPreview(filterGridName, willOpen) {
110− if (filterGridName === undefined)
111− filterGridName = "0";
112− if (willOpen === undefined)
113− willOpen = true;
114− tryCompareFunction(function() {
115− var filterGrid = findChild(genericScopeView, filterGridName);
116− if (filterGrid != null) {
117− var tile = findChild(filterGrid, "delegate0");
118− return tile != null;
119− }
120− return false;
121− },
122− true);
123− var tile = findChild(findChild(genericScopeView, filterGridName), "delegate0");
124− mouseClick(tile, tile.width / 2, tile.height / 2);
125− tryCompare(previewListView, "open", willOpen);
126− tryCompare(openEffect, "gap", willOpen ? 1 : 0);
127− }
128−
129− function checkArrowPosition(index) {
130− tryCompareFunction(function() {
131− var tile = findChild(findChild(genericScopeView, "0"), "delegate" + index);
132− return tile != null;
133− },
134− true);
135− var tile = findChild(findChild(genericScopeView, "0"), "delegate" + index);
136− var tileCenter = tile.x + tile.width/2;
137− var pointerArrow = findChild(previewListView, "pointerArrow");
138− var pointerArrowCenter = pointerArrow.x + pointerArrow.width/2;
139− compare(pointerArrowCenter, tileCenter, "Pointer did not move to tile");
140− }
141−
142− function closePreview() {
143− var closePreviewMouseArea = findChild(genericScopeView, "closePreviewMouseArea");
144− mouseClick(closePreviewMouseArea, closePreviewMouseArea.width / 2, closePreviewMouseArea.height / 2);
145−
146− tryCompare(previewListView, "open", false);
147− tryCompare(openEffect, "gap", 0);
148−
149− var categoryListView = findChild(genericScopeView, "categoryListView");
150− categoryListView.flick(0, units.gu(200));
151− tryCompare(categoryListView, "flicking", false);
152− }
153−
154− function test_previewOpenClose() {
155− tryCompare(previewListView, "open", false);
156− var categoryListView = findChild(genericScopeView, "categoryListView");
157− categoryListView.positionAtBeginning();
158−
159− openPreview();
160−
161− // check for it opening successfully
162− var currentPreviewItem = findChild(previewListView, "previewLoader0");
163− tryCompareFunction(function() {
164− var parts = currentPreviewItem.source.toString().split("/");
165− var name = parts[parts.length - 1];
166− return name == "DashPreviewPlaceholder.qml";
167− },
168− true);
169− tryCompareFunction(function() {
170− var parts = currentPreviewItem.source.toString().split("/");
171− var name = parts[parts.length - 1];
172− return name == "GenericPreview.qml";
173− },
174− true);
175− tryCompare(currentPreviewItem, "progress", 1);
176− tryCompare(previewListView, "open", true);
177−
178− closePreview();
179− tryCompare(previewListView, "open", false);
180− }
181−
182− function test_hiddenPreviewOpen() {
183− var categoryListView = findChild(genericScopeView, "categoryListView");
184− categoryListView.positionAtBeginning();
185− waitForRendering(categoryListView);
186− categoryListView.flick(0, -units.gu(60));
187− tryCompare(categoryListView.flicking, false);
188−
189− var tile = findChild(findChild(genericScopeView, "0"), "delegate0");
190− mouseClick(tile, tile.width / 2, tile.height - 1);
191− tryCompare(openEffect, "gap", 1);
192−
193− verify(openEffect.positionPx >= pageHeader.height + categoryListView.stickyHeaderHeight);
194− }
195−
196− function test_previewCycle() {
197− var categoryListView = findChild(genericScopeView, "categoryListView");
198− categoryListView.positionAtBeginning();
199−
200− tryCompare(previewListView, "open", false);
201− tryCompare(openEffect, "gap", 0);
202−
203− openPreview();
204−
205− // wait for it to be loaded
206− var currentPreviewItem = findChild(previewListView, "previewLoader0");
207− tryCompareFunction(function() {
208− var parts = currentPreviewItem.source.toString().split("/");
209− var name = parts[parts.length - 1];
210− return name == "GenericPreview.qml";
211− },
212− true);
213− tryCompare(currentPreviewItem, "progress", 1);
214− waitForRendering(currentPreviewItem);
215−
216− checkArrowPosition(0);
217−
218− // flick to the next previews
219− tryCompare(previewListView, "count", 15);
220− for (var i = 1; i < previewListView.count; ++i) {
221−
222− mouseFlick(previewListView, previewListView.width - units.gu(1),
223− previewListView.height / 2,
224− units.gu(2),
225− previewListView.height / 2);
226−
227− // wait for it to be loaded
228− var nextPreviewItem = findChild(previewListView, "previewLoader" + i);
229− tryCompareFunction(function() {
230− var parts = nextPreviewItem.source.toString().split("/");
231− var name = parts[parts.length - 1];
232− return name == "GenericPreview.qml";
233− },
234− true);
235− tryCompare(nextPreviewItem, "progress", 1);
236− waitForRendering(nextPreviewItem);
237− tryCompareFunction(function() {return nextPreviewItem.item !== null}, true);
238−
239− checkArrowPosition(i);
240−
241− // Make sure only the new one has isCurrent set to true
242− compare(nextPreviewItem.item.isCurrent, true);
243−
244− if (currentPreviewItem.item !== undefined && currentPreviewItem.item !== null) {
245− compare(currentPreviewItem.item.isCurrent, false);
246− }
247−
248− currentPreviewItem = nextPreviewItem;
249− }
250− closePreview();
251− }
252−
253− function test_show_spinner() {
254− var categoryListView = findChild(genericScopeView, "categoryListView");
255− waitForRendering(categoryListView);
256− categoryListView.contentY = units.gu(13);
257− openPreview();
258− var previewLoader = findChild(previewListView, "previewLoader0");
259− compare(previewLoader.source.toString().split("/").pop(), "DashPreviewPlaceholder.qml");
260− compare(categoryListView.contentY, 0)
261− tryCompare(previewLoader, "progress", 1.0);
262− tryCompareFunction(function() { return previewLoader.item != undefined; }, true);
263−
264− previewLoader.item.showProcessingAction = true;
265− var waitingForAction = findChild(previewListView, "waitingForActionMouseArea");
266− tryCompare(waitingForAction, "enabled", true);
267− previewLoader.closePreviewSpinner();
268− tryCompare(waitingForAction, "enabled", false);
269−
270− closePreview();
271106 }
272107
273108 function test_changeScope() {
@@ -300,59 +135,17 @@ Item {
300135 tryCompare(category, "filtered", true);
301136 }
302137
303− function test_getRendererCarouselGridFallback() {
304− var rendererId = "carousel"
305− var contentType = ""
306− var rendererHint = ""
307− var results = new Object()
308−
309− results.count = 7
310− var renderer = genericScopeView.getRenderer(rendererId, contentType, rendererHint, results)
311− compare(renderer, "Generic/GenericCarousel.qml")
312−
313− results.count = 6
314− renderer = genericScopeView.getRenderer(rendererId, contentType, rendererHint, results)
315− compare(renderer, "Generic/GenericFilterGrid.qml")
316− }
317−
318− function test_showPreviewCarousel() {
319− tryCompareFunction(function() { return findChild(genericScopeView, "carouselDelegate") != null; }, true);
320− var tile = findChild(genericScopeView, "carouselDelegate");
321− mouseClick(tile, tile.width / 2, tile.height / 2);
322− tryCompare(openEffect, "gap", 1);
323−
324− // check for it opening successfully
325− var currentPreviewItem = findChild(previewListView, "previewLoader0");
326− tryCompareFunction(function() {
327− var parts = currentPreviewItem.source.toString().split("/");
328− var name = parts[parts.length - 1];
329− return name == "DashPreviewPlaceholder.qml";
330− },
331− true);
332− tryCompareFunction(function() {
333− var parts = currentPreviewItem.source.toString().split("/");
334− var name = parts[parts.length - 1];
335− return name == "GenericPreview.qml";
336− },
337− true);
338− tryCompare(currentPreviewItem, "progress", 1);
339− tryCompare(previewListView, "open", true);
340−
341− closePreview();
342− tryCompare(previewListView, "open", false);
343− }
344−
345138 function test_filter_expand_expand_collapse() {
346139 // wait for the item to be there
347− tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeaderapplications.scope") != null; }, true);
140+ tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader2") != null; }, true);
348141
349142 var categoryListView = findChild(genericScopeView, "categoryListView");
350143 categoryListView.contentY = categoryListView.height;
351144
352− var header2 = findChild(genericScopeView, "dashSectionHeaderapplications.scope")
353− var category2 = findChild(genericScopeView, "dashCategoryapplications.scope")
354− var category2FilterGrid = category2.children[0].children[0].children[0];
355− verify(UT.Util.isInstanceOf(category2FilterGrid, "FilterGrid"));
145+ var header2 = findChild(genericScopeView, "dashSectionHeader2")
146+ var category2 = findChild(genericScopeView, "dashCategory2")
147+ var category2FilterGrid = category2.children[1].children[2];
148+ verify(UT.Util.isInstanceOf(category2FilterGrid, "CardFilterGrid"));
356149
357150 waitForRendering(header2);
358151 verify(category2.expandable);
@@ -368,7 +161,7 @@ Item {
368161 tryCompareFunction(
369162 function() {
370163 var header0 = findChild(genericScopeView, "dashSectionHeader0")
371− return header0.y == pageHeader.height;
164+ return header0.y == testPageHeader.height;
372165 },
373166 true);
374167
@@ -383,21 +176,6 @@ Item {
383176 tryCompare(category2, "filtered", true);
384177 }
385178
386− function test_bug1271676_no_move_y_no_preview() {
387− waitForRendering(genericScopeView);
388− var categoryListView = findChild(genericScopeView, "categoryListView");
389− waitForRendering(categoryListView);
390− tryCompareFunction(function() { return findChild(genericScopeView, "dashCategoryapplications.scope") != null; }, true);
391− var category = findChild(genericScopeView, "dashCategoryapplications.scope")
392− categoryListView.contentY = category.y;
393− waitForRendering(categoryListView);
394− var contentYBefore = categoryListView.contentY
395− openPreview("applications.scope", false); // This actually doesn't open anything because we
396− // have code so that the item of installed
397− // does activate instead of preview and never shows a preview
398− compare(categoryListView.contentY, contentYBefore);
399− }
400−
401179 function test_narrow_delegate_ranges_expand() {
402180 tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") != undefined; }, true);
403181 var category = findChild(genericScopeView, "dashCategory0")
@@ -419,8 +197,8 @@ Item {
419197 PreviewListView {
420198 id: previewListView
421199 anchors.fill: parent
422− openEffect: openEffect
423− categoryView: genericScopeView.categoryView
200+ visible: false
201+ pageHeader: testPageHeader
424202 scope: genericScopeView.scope
425203 }
426204}
tests/qmltests/Launcher/tst_Launcher.qml+6−4
@@ -121,8 +121,7 @@ Item {
121121 revealer.dragLauncherIntoView()
122122
123123 var listView = findChild(launcher, "launcherListView");
124− listView.flick(0, units.gu(500));
125− tryCompare(listView, "flicking", false);
124+ listView.positionViewAtEnd();
126125
127126 var appIcon = findChild(launcher, "launcherDelegate0")
128127
@@ -397,8 +396,11 @@ Item {
397396
398397 // Position launcher to where we need it
399398 var listView = findChild(launcher, "launcherListView");
400− listView.flick(0, units.gu(200) * (data.flickTo === "top" ? 1 : -1));
401− tryCompare(listView, "flicking", false);
399+ if (data.flickTo == "top") {
400+ listView.positionViewAtEnd();
401+ } else {
402+ listView.positionViewAtBeginning();
403+ }
402404
403405 // Doing longpress
404406 mousePress(draggedItem, draggedItem.width / 2, draggedItem.height / 2)
tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml+47−6
@@ -148,14 +148,14 @@ Item {
148148
149149 function test_create_sliderMenu_data() {
150150 return [
151− {label: "testLabel1", enabled: false, minValue: 0, maxValue: 100, value: 10.5 },
152− {label: "testLabel2", enabled: true, minValue: 0, maxValue: 100, value: 100 },
151+ {tag: "disabled", enabled: false, minValue: 0, maxValue: 100, value1: 10.5, value2: 22 },
152+ {tag: "enabled", enabled: true, minValue: 0, maxValue: 100, value1: 100, value2: 50 },
153153 ];
154154 }
155155
156156 function test_create_sliderMenu(data) {
157157 menuData.type = "com.canonical.indicator.slider"
158− menuData.label = data.label;
158+ menuData.label = data.tag;
159159 menuData.sensitive = data.enabled;
160160 menuData.ext = {
161161 'minIcon': "file:///testMinIcon",
@@ -163,20 +163,61 @@ Item {
163163 'minValue': data.minValue,
164164 'maxValue': data.maxValue
165165 };
166− menuData.actionState = data.value;
166+ menuData.actionState = data.value1;
167167
168168 loader.data = menuData;
169169 loader.sourceComponent = factory.load(menuData);
170170 tryCompareFunction(function() { return loader.item != undefined; }, true);
171171 compare(loader.item.objectName, "sliderMenu", "Should have created a slider menu");
172172
173− compare(loader.item.text, data.label, "Label does not match data");
173+ compare(loader.item.text, data.tag, "Label does not match data");
174174 compare(loader.item.minIcon, "file:///testMinIcon", "MinIcon does not match data");
175175 compare(loader.item.maxIcon, "file:///testMaxIcon", "MaxIcon does not match data");
176176 compare(loader.item.minimumValue, data.minValue, "MinValue does not match data");
177177 compare(loader.item.maximumValue, data.maxValue, "MaxValue does not match data");
178− compare(loader.item.value, data.value, "Value does not match data");
179178 compare(loader.item.enabled, data.enabled, "Enabled does not match data");
179+ compare(loader.item.value, data.value1, "Value does not match data");
180+
181+ menuData.actionState = data.value2;
182+ compare(loader.item.value, data.value2, "Value does not match new data");
183+ }
184+
185+ function test_create_sliderMenu_lp1283191_data() {
186+ return [
187+ {tag: "disabled", enabled: false, minValue: 0, maxValue: 100, value1: 10.5, value2: 22, manualValue: 0 },
188+ {tag: "enabled", enabled: true, minValue: 0, maxValue: 100, value1: 100, value2: 50, manualValue: 30 },
189+ {tag: "test-zero", enabled: true, minValue: 0, maxValue: 100, value1: 10, value2: 0, manualValue: 20 },
190+ ];
191+ }
192+
193+ function test_create_sliderMenu_lp1283191(data) {
194+ menuData.type = "com.canonical.indicator.slider"
195+ menuData.label = data.tag;
196+ menuData.sensitive = data.enabled;
197+ menuData.ext = {
198+ 'minIcon': "file:///testMinIcon",
199+ 'maxIcon': "file:///testMaxIcon",
200+ 'minValue': data.minValue,
201+ 'maxValue': data.maxValue
202+ };
203+ menuData.actionState = data.value1;
204+
205+ loader.data = menuData;
206+ loader.sourceComponent = factory.load(menuData);
207+ tryCompareFunction(function() { return loader.item != undefined; }, true);
208+ compare(loader.item.value, data.value1, "Value does not match data");
209+
210+ var slider = findChild(loader.item, "slider");
211+ verify(slider !== null);
212+
213+ slider.value = data.manualValue;
214+ compare(loader.item.value, data.manualValue, "Slider value does not match manual set value");
215+
216+ menuData.actionState = data.value2;
217+ compare(loader.item.value, data.value2, "Value does not match new data");
218+
219+ menuData.actionState = undefined;
220+ compare(loader.item.value, data.value2, "Undefined state should not update slider value");
180221 }
181222
182223 function test_create_buttonMenu_data() {
tests/qmltests/tst_Shell.qml+24−27
@@ -68,13 +68,10 @@ Item {
6868 do {
6969 var dashContentList = findChild(shell, "dashContentList");
7070 waitForRendering(dashContentList);
71− var homeLoader = findChild(dashContentList, "home.scope loader");
71+ var homeLoader = findChild(dashContentList, "clickscope loader");
7272 ok = homeLoader !== null
7373 && homeLoader.item !== undefined;
7474
75− var dashHome = findChild(shell, "DashHome");
76− ok &= dashHome !== null;
77−
7875 var greeter = findChild(shell, "greeter");
7976 ok &= greeter !== null;
8077
@@ -106,7 +103,10 @@ Item {
106103 // kill all (fake) running apps
107104 killApps(ApplicationManager);
108105
109− var dashHome = findChild(shell, "DashHome");
106+ var dashContent = findChild(shell, "dashContent");
107+ dashContent.previewOpen = false;
108+
109+ var dashHome = findChild(shell, "clickscope loader");
110110 swipeUntilScopeViewIsReached(dashHome);
111111
112112 hideIndicators();
@@ -235,8 +235,8 @@ Item {
235235
236236 var dash = findChild(shell, "dash");
237237 // check that dash has normal scale and opacity
238− tryCompare(dash.contentScale, 1.0);
239− tryCompare(dash.opacity, 1.0);
238+ tryCompare(dash, "contentScale", 1.0);
239+ tryCompare(dash, "opacity", 1.0);
240240
241241 touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY,
242242 true /* beginTouch */, false /* endTouch */);
@@ -298,8 +298,7 @@ Item {
298298 - apps lens shown and Running Apps visible on screen
299299 */
300300 function test_minimizingAppTakesToRunningApps() {
301− var dashApps = findChild(shell, "DashApps");
302−
301+ var dashApps = findChild(shell, "clickscope");
303302 swipeUntilScopeViewIsReached(dashApps);
304303
305304 // swipe finger up until the running/recent apps section (which we assume
@@ -337,7 +336,7 @@ Item {
337336
338337 verify(itemIsOnScreen(dashApps));
339338
340− var runningApplicationsGrid = findChild(appsCategoryListView, "recent");
339+ var runningApplicationsGrid = findChild(appsCategoryListView, "running.apps.category");
341340 verify(runningApplicationsGrid);
342341 verify(itemIsOnScreen(runningApplicationsGrid));
343342 }
@@ -418,13 +417,13 @@ Item {
418417 }
419418
420419 function swipeLeftFromCenter() {
421− var touchStartX = shell.width / 2;
420+ var touchStartX = shell.width * 3 / 4;
422421 var touchStartY = shell.height / 2;
423422 touchFlick(shell, touchStartX, touchStartY, 0, touchStartY);
424423 }
425424
426425 function swipeRightFromCenter() {
427− var touchStartX = shell.width / 2;
426+ var touchStartX = shell.width * 3 / 4;
428427 var touchStartY = shell.height / 2;
429428 touchFlick(shell, touchStartX, touchStartY, shell.width, touchStartY);
430429 }
@@ -476,21 +475,6 @@ Item {
476475 ]
477476 }
478477
479− function test_background(data) {
480− var backgroundImage = findChild(shell, "backgroundImage")
481− GSettingsController.setPictureUri(data.url)
482− tryCompareFunction(function() { return backgroundImage.source.toString().indexOf(data.expectedUrl) !== -1; }, true)
483− tryCompare(backgroundImage, "status", Image.Ready)
484− }
485−
486− function test_lockscreen_background() {
487− var backgroundImage = findChild(shell, "backgroundImage")
488− var lockscreen = findChild(shell, "lockscreen")
489− var lockscreenBackground = findChild(lockscreen, "lockscreenBackground")
490− var lockscreenBackgroundMapped = lockscreenBackground.mapToItem(shell, 0, 0)
491− compare(backgroundImage.y, lockscreenBackgroundMapped.y)
492− }
493−
494478 function test_DashShown_data() {
495479 return [
496480 {tag: "in focus", greeter: false, app: false, launcher: false, indicators: false, expectedShown: true},
@@ -549,5 +533,18 @@ Item {
549533 tryCompare(greeter, "shown", true)
550534 tryCompare(searchIndicator, "opacity", 0)
551535 }
536+
537+ function test_searchIndicatorHideOnPreviewShown() {
538+ var searchIndicator = findChild(shell, "container");
539+ var dashContent = findChild(shell, "dashContent");
540+
541+ verify(dashContent != null);
542+
543+ tryCompare(searchIndicator, "opacity", 1);
544+
545+ dashContent.previewOpen = true;
546+
547+ tryCompare(searchIndicator, "opacity", 0);
548+ }
552549 }
553550}
tests/utils/modules/Unity/Test/UnityTestCase.qml+10−16
@@ -71,19 +71,8 @@ TestCase {
7171
7272
7373 // Find an object with the given name in the children tree of "obj"
74− function findChild(obj,objectName) {
75− var childs = new Array(0);
76− childs.push(obj)
77− while (childs.length > 0) {
78− if (childs[0].objectName == objectName) {
79− return childs[0]
80− }
81− for (var i in childs[0].children) {
82− childs.push(childs[0].children[i])
83− }
84− childs.splice(0, 1);
85− }
86− return null;
74+ function findChild(obj, objectName) {
75+ return findChildIn(obj, "children", objectName);
8776 }
8877
8978 // Find an object with the given name in the children tree of "obj"
@@ -91,15 +80,20 @@ TestCase {
9180 // Note: you should use findChild if you're not sure you need this
9281 // as this tree is much bigger and might contain stuff that goes
9382 // away randomly.
94− function findInvisibleChild(obj,objectName) {
83+ function findInvisibleChild(obj, objectName) {
84+ return findChildIn(obj, "data", objectName);
85+ }
86+
87+ // Find a child in the named property
88+ function findChildIn(obj, prop, objectName) {
9589 var childs = new Array(0);
9690 childs.push(obj)
9791 while (childs.length > 0) {
9892 if (childs[0].objectName == objectName) {
9993 return childs[0]
10094 }
101− for (var i in childs[0].data) {
102− childs.push(childs[0].data[i])
95+ for (var i in childs[0][prop]) {
96+ childs.push(childs[0][prop][i])
10397 }
10498 childs.splice(0, 1);
10599 }
tools/registry-tracker.cpp+19−4
@@ -25,8 +25,10 @@
2525#include "registry-tracker.h"
2626
2727
28−RegistryTracker::RegistryTracker(QString const& scope_dir):
29− m_scopeDir(scope_dir),
28+RegistryTracker::RegistryTracker(QStringList const& scopes, bool systemScopes, bool serverScopes):
29+ m_scopes(scopes),
30+ m_systemScopes(systemScopes),
31+ m_serverScopes(serverScopes),
3032 m_registry(nullptr),
3133 m_endpoints_dir(QDir::temp().filePath("scope-dev-endpoints.XXXXXX"))
3234{
@@ -56,7 +58,8 @@ RegistryTracker::~RegistryTracker()
5658"Zmq.EndpointDir = %2\n" \
5759"Zmq.ConfigFile = %3\n" \
5860"Scope.InstallDir = %4\n" \
59−"Scoperunner.Path = %5\n"
61+"Scoperunner.Path = %5\n" \
62+"%6"
6063
6164#define MW_CONFIG \
6265"[Zmq]\n" \
@@ -95,7 +98,17 @@ void RegistryTracker::runRegistry()
9598 QString scopeRunnerPath = QDir(scopesLibdir).filePath("scoperunner/scoperunner");
9699
97100 QString runtime_ini = QString(RUNTIME_CONFIG).arg(m_registry_config.fileName()).arg(m_mw_config.fileName());
98− QString registry_ini = QString(REGISTRY_CONFIG).arg(m_endpoints_dir.path()).arg(m_endpoints_dir.path()).arg(m_mw_config.fileName()).arg(m_scopeDir).arg(scopeRunnerPath);
101+ // FIXME: keep in sync with the SSRegistry config
102+ QString serverRegistryConfig(m_serverScopes ? "SS.Registry.Identity = SSRegistry\nSS.Registry.Endpoint = ipc:///tmp/SSRegistry" : "");
103+ QString scopeInstallDir(scopesLibdir + "/unity-scopes");
104+ if (!m_systemScopes) {
105+ m_scopeInstallDir.reset(new QTemporaryDir(tmp.filePath("scopes.XXXXXX")));
106+ if (!m_scopeInstallDir->isValid()) {
107+ qWarning("Unable to create temporary scopes directory!");
108+ }
109+ scopeInstallDir = m_scopeInstallDir->path();
110+ }
111+ QString registry_ini = QString(REGISTRY_CONFIG).arg(m_endpoints_dir.path()).arg(m_endpoints_dir.path()).arg(m_mw_config.fileName()).arg(scopeInstallDir).arg(scopeRunnerPath).arg(serverRegistryConfig);
99112 QString mw_ini = QString(MW_CONFIG).arg(m_endpoints_dir.path()).arg(m_endpoints_dir.path());
100113
101114 m_runtime_config.write(runtime_ini.toUtf8());
@@ -111,6 +124,8 @@ void RegistryTracker::runRegistry()
111124 QString registryBin(QDir(scopesLibdir).filePath("scoperegistry/scoperegistry"));
112125 QStringList arguments;
113126 arguments << m_runtime_config.fileName();
127+ arguments << m_scopes;
114128
129+ m_registry.setProcessChannelMode(QProcess::ForwardedChannels);
115130 m_registry.start(registryBin, arguments);
116131}
tools/registry-tracker.h+7−2
@@ -22,12 +22,14 @@
2222#include <QTemporaryFile>
2323#include <QTemporaryDir>
2424#include <QDebug>
25+#include <QStringList>
26+#include <QScopedPointer>
2527
2628
2729class RegistryTracker
2830{
2931public:
30− RegistryTracker(QString const&);
32+ RegistryTracker(QStringList const&, bool, bool);
3133 ~RegistryTracker();
3234
3335 QProcess* registry() const;
@@ -35,10 +37,13 @@ public:
3537private:
3638 void runRegistry();
3739
38− QString m_scopeDir;
40+ QStringList m_scopes;
41+ bool m_systemScopes;
42+ bool m_serverScopes;
3943 QProcess m_registry;
4044 QTemporaryDir m_endpoints_dir;
4145 QTemporaryFile m_runtime_config;
4246 QTemporaryFile m_registry_config;
4347 QTemporaryFile m_mw_config;
48+ QScopedPointer<QTemporaryDir> m_scopeInstallDir;
4449};
tools/scopetool.cpp+27−8
@@ -24,6 +24,8 @@
2424#include <QtQml/QQmlContext>
2525#include <QScopedPointer>
2626#include <QDebug>
27+#include <QCommandLineParser>
28+#include <QCommandLineOption>
2729#include <libintl.h>
2830
2931
@@ -46,16 +48,33 @@ int main(int argc, char *argv[])
4648 QGuiApplication *application;
4749 application = new QGuiApplication(argc, argv);
4850
49− QStringList arguments = application->arguments();
50− QString scopesDir;
51− if (arguments.contains("--scope-dir")) {
52− int idx = arguments.indexOf("--scope-dir");
53− scopesDir = arguments[idx+1];
54− }
51+ QCommandLineParser parser;
52+ parser.setApplicationDescription("Unity Scope Tool\n\n"
53+ "This tool allows development and testing of scopes. Running it without\n"
54+ "any arguments will open a session to all scopes available on the system.\n"
55+ "Otherwise passing a path to a scope config file will open a session with\n"
56+ "only that scope (assuming that the binary implementing the scope can be\n"
57+ "found in the same directory as the config file).");
58+ parser.addHelpOption();
59+ parser.addPositionalArgument("scopes", "Paths to scope config files to spawn, optionally.", "[scopes...]");
60+
61+ QCommandLineOption includeSystemScopes("include-system-scopes",
62+ "Initialize the registry with scopes installed on this system");
63+ QCommandLineOption includeServerScopes("include-server-scopes",
64+ "Initialize the registry with scopes on the default server");
65+
66+ parser.addOption(includeServerScopes);
67+ parser.addOption(includeSystemScopes);
68+
69+ parser.process(*application);
70+
71+ QStringList extraScopes = parser.positionalArguments();
5572
5673 QScopedPointer<RegistryTracker> tracker;
57− if (!scopesDir.isEmpty()) {
58− tracker.reset(new RegistryTracker(scopesDir));
74+ if (!extraScopes.isEmpty()) {
75+ bool systemScopes = parser.isSet(includeSystemScopes);
76+ bool serverScopes = parser.isSet(includeServerScopes);
77+ tracker.reset(new RegistryTracker(extraScopes, systemScopes, serverScopes));
5978 }
6079
6180 resolveIconTheme();