on xenial help sign in
Merge from trunk
commit3955a4b26523e37562a320b96654e52bfb3194ee authorMichael Terry <michael.terry@canonical.com> dateFri 25 Jul 2014, 09:37 (12 years ago) parent6381ad93d1d3f0
41 files changed+738−620
tests/autopilot/.project → .project+1−1 tests/autopilot/.pydevproject → .pydevproject+3−1 .settings/Autopilot List.launch+14 .settings/Autopilot Run.launch+14 debian/changelog+36 debian/control+1−1 plugins/Dash/ScopeStyle.qml+6 plugins/Dash/listviewwithpageheader.cpp−5 plugins/Unity/Launcher/launchermodel.cpp+3−2 po/gd.po+3−3 po/hu.po+11−9 po/sl.po+11−11 po/sv.po+19−18 po/unity8.pot+17−9 qml/Components/Background.qml+77 qml/Components/FilterGrid.qml−124 qml/Components/ListItems/Header.qml+17−26 qml/Components/PageHeader.qml+6−1 qml/Components/ResponsiveGridView.qml+2−1 qml/Dash/CardCarousel.qml+2−7 qml/Dash/CardFilterGrid.qml → qml/Dash/CardGrid.qml+22−22 qml/Dash/CardVerticalJournal.qml+3−21 qml/Dash/DashRenderer.qml+3−10 qml/Dash/GenericScopeView.qml+128−64 src/main.cpp+1−1 tests/autopilot/unity8/shell/emulators/dash.py+12−6 tests/autopilot/unity8/shell/tests/test_emulators.py+15−5 tests/autopilot/unity8/shell/tests/test_upstart.py+13 tests/mocks/Ubuntu/Telephony/CMakeLists.txt+1−9 tests/mocks/Unity/fake_categories.cpp+13−1 tests/mocks/Unity/fake_categories.h+2 tests/mocks/Unity/fake_scope.cpp+8−11 tests/mocks/Unity/fake_scope.h+2−2 tests/mocks/Unity/fake_scopes.cpp+1 tests/plugins/Dash/tst_ScopeStyle.qml+27−2 tests/qmltests/CMakeLists.txt+1−1 tests/qmltests/Components/tst_Background.qml+90 tests/qmltests/Components/tst_FilterGrid.qml−190 tests/qmltests/Dash/tst_Dash.qml+1−1 tests/qmltests/Dash/tst_DashContent.qml+15−6 tests/qmltests/Dash/tst_GenericScopeView.qml+137−49
tests/autopilot/.project → .projectrenamed+1−1
@@ -1,6 +1,6 @@
11<?xml version="1.0" encoding="UTF-8"?>
22<projectDescription>
3− <name>Unity8 Autopilot</name>
3+ <name>Unity8</name>
44 <comment></comment>
55 <projects>
66 </projects>
tests/autopilot/.pydevproject → .pydevprojectrenamed+3−1
@@ -1,7 +1,9 @@
11<?xml version="1.0" encoding="UTF-8" standalone="no"?>
22<?eclipse-pydev version="1.0"?><pydev_project>
33<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
4−<path>/Unity8 Autopilot</path>
4+<path>/Unity8/tests/autopilot</path>
5+<path>/Unity8/.bazaar</path>
6+<path>/Unity8/tests/whitespace</path>
57</pydev_pathproperty>
68<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
79<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
.settings/Autopilot List.launchnew file+14
@@ -0,0 +1,14 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
3+<stringAttribute key="bad_container_name" value="/Unity8/.pyd"/>
4+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"/>
5+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"/>
6+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
7+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
8+</listAttribute>
9+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/autopilot"/>
10+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
11+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="list unity8"/>
12+<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
13+<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Unity8"/>
14+</launchConfiguration>
.settings/Autopilot Run.launchnew file+14
@@ -0,0 +1,14 @@
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2+<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
3+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"/>
4+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"/>
5+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
6+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
7+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
8+</listAttribute>
9+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="/usr/bin/autopilot"/>
10+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value=""/>
11+<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="run ${string_prompt:the test suite to run:unity8}"/>
12+<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
13+<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Unity8"/>
14+</launchConfiguration>
debian/changelog+36
@@ -1,3 +1,39 @@
1+unity8 (7.90+14.10.20140724.1-0ubuntu1) utopic; urgency=low
2+
3+ [ Michael Zanetti ]
4+ * properly parent launcher items (LP: #1347902)
5+
6+ [ Michał Sawicz ]
7+ * Move the PyDev project files to the root, supporting .py scripts
8+ outside of tests/autopilot. Add Autopilot Run and List launch
9+ configurations to easily support debugging in Eclipse. Use
10+ add_unity8_mock macro in the Telephony plugin.
11+ * Drop FilterGrid and refactor height animations in GenericScopeView.
12+ Also implement forced category expansion. (LP: #1326470)
13+ * Move expansion button from section header to category footer. (LP:
14+ #1261300)
15+ * Fix expect-sigstop enviroment variable name. (LP: #1346819)
16+ * Make headerless categories easier Instead of having no header
17+ category (which is a bit confusing since the LVWPH code was designed
18+ so that when a category has no header it is because it shares the
19+ category with the previous one) what we have for headerless
20+ categories is a header of height 0, this way everything works as it
21+ should and results in cleaner code in the LVWPH and in
22+ GenericScopeView
23+ * Add support for header links.
24+ * Add dash PageHeader styling.
25+
26+ [ Albert Astals ]
27+ * Make headerless categories easier Instead of having no header
28+ category (which is a bit confusing since the LVWPH code was designed
29+ so that when a category has no header it is because it shares the
30+ category with the previous one) what we have for headerless
31+ categories is a header of height 0, this way everything works as it
32+ should and results in cleaner code in the LVWPH and in
33+ GenericScopeView
34+
35+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 24 Jul 2014 20:41:29 +0000
36+
137unity8 (7.90+14.10.20140723.4-0ubuntu1) utopic; urgency=low
238
339 [ thomas-voss ]
debian/control+1−1
@@ -113,7 +113,7 @@ Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
113113 unity-application-impl-2,
114114 unity-notifications-impl-3,
115115 unity-plugin-scopes | unity-scopes-impl,
116− unity-scopes-impl-0,
116+ unity-scopes-impl-2,
117117 unity8-fake-env | unity-application-impl,
118118 ${misc:Depends},
119119Breaks: unity8 (<< 7.86),
plugins/Dash/ScopeStyle.qml+6
@@ -70,6 +70,12 @@ QtObject {
7070 /// Source of the logo image for the header
7171 readonly property url headerLogo: "logo" in d.headerStyle ? d.headerStyle["logo"] : ""
7272
73+ /// Background style for the header
74+ readonly property url headerBackground: "background" in d.headerStyle ? d.headerStyle["background"] : ""
75+
76+ /// Foreground color for the header
77+ readonly property color headerForeground: "foreground-color" in d.headerStyle ? d.headerStyle["foreground-color"] : foreground
78+
7379 //! @cond
7480 property var d: QtObject {
7581 readonly property real foregroundLuminance: luminance(foreground)
plugins/Dash/listviewwithpageheader.cpp−5
@@ -141,8 +141,6 @@ void ListViewWithPageHeader::ListItem::setCulled(bool culled)
141141void ListViewWithPageHeader::ListItem::setSectionItem(QQuickItem *sectionItem)
142142{
143143 m_sectionItem = sectionItem;
144− QQmlContext *context = QQmlEngine::contextForObject(m_item)->parentContext();
145− context->setContextProperty(QLatin1String("hasSectionHeader"), QVariant::fromValue<bool>(sectionItem != nullptr));
146144}
147145
148146ListViewWithPageHeader::ListViewWithPageHeader()
@@ -685,8 +683,6 @@ QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyI
685683 return nullptr;
686684
687685 const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
688− if (section.isEmpty())
689− return nullptr;
690686
691687 if (modelIndex > 0) {
692688 const QString prevSection = m_delegateModel->stringValue(modelIndex - 1, m_sectionProperty);
@@ -877,7 +873,6 @@ void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
877873 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
878874 context->setContextProperty(QLatin1String("ListViewWithPageHeader"), this);
879875 context->setContextProperty(QLatin1String("heightToClip"), QVariant::fromValue<int>(0));
880− context->setContextProperty(QLatin1String("hasSectionHeader"), QVariant::fromValue<bool>(false));
881876 if (modelIndex == m_asyncRequestedIndex) {
882877 createItem(modelIndex, false);
883878 refill();
plugins/Unity/Launcher/launchermodel.cpp+3−2
@@ -141,7 +141,8 @@ void LauncherModel::pin(const QString &appId, int index)
141141 beginInsertRows(QModelIndex(), index, index);
142142 LauncherItem *item = new LauncherItem(appId,
143143 m_backend->displayName(appId),
144− m_backend->icon(appId));
144+ m_backend->icon(appId),
145+ this);
145146 item->setPinned(true);
146147 m_list.insert(index, item);
147148 endInsertRows();
@@ -326,7 +327,7 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
326327 if (found) {
327328 // Shall we paint some running/recent app highlight? If yes, do it here.
328329 } else {
329− LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString());
330+ LauncherItem *item = new LauncherItem(app->appId(), app->name(), app->icon().toString(), this);
330331 item->setRecent(true);
331332 item->setFocused(app->focused());
332333
po/gd.po+3−3
@@ -8,13 +8,13 @@ msgstr ""
88"Project-Id-Version: unity8\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-07-07 12:15+0100\n"
11−"PO-Revision-Date: 2014-07-16 14:48+0000\n"
11+"PO-Revision-Date: 2014-07-24 22:26+0000\n"
1212"Last-Translator: GunChleoc <Unknown>\n"
1313"Language-Team: Fòram na Gàidhlig http://www.foramnagaidhlig.net\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-17 06:38+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-25 07:54+0000\n"
1818"X-Generator: Launchpad (build 17114)\n"
1919"Language: gd\n"
2020
@@ -87,7 +87,7 @@ msgstr "Gairm èiginn"
8787
8888#: qml/Components/Lockscreen.qml:231
8989msgid "OK"
90−msgstr "Ceart ma-hà"
90+msgstr "Ceart ma-thà"
9191
9292#: qml/Components/PageHeader.qml:366
9393msgid "Recent searches"
po/hu.po+11−9
@@ -8,23 +8,23 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-07-07 12:15+0100\n"
11−"PO-Revision-Date: 2014-07-23 10:07+0000\n"
12−"Last-Translator: Úr Balázs <urbalazs@gmail.com>\n"
11+"PO-Revision-Date: 2014-07-24 08:19+0000\n"
12+"Last-Translator: Gabor Kelemen <kelemeng@openscope.org>\n"
1313"Language-Team: Hungarian <hu@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-24 06:32+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-25 07:54+0000\n"
1818"X-Generator: Launchpad (build 17114)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
2222msgid "Pin shortcut"
23−msgstr ""
23+msgstr "Indító rögzítése"
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:73
2626msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "Indító feloldása"
2828
2929#: qml/Components/EdgeDemoOverlay.qml:151
3030msgid "Skip intro"
@@ -73,6 +73,8 @@ msgid ""
7373"You have now mastered the edge gestures and can start using the "
7474"phone<br><br>Tap on the screen to start"
7575msgstr ""
76+"Elsajátította a gesztusokat, és megkezdheti a telefon "
77+"használatát.<br><br>Koppintson a képernyőre a kezdéshez."
7678
7779#: qml/Components/Lockscreen.qml:214
7880msgid "Emergency Call"
@@ -105,11 +107,11 @@ msgstr "KÉSZ"
105107
106108#: qml/Components/SeeMore.qml:35
107109msgid "See more"
108−msgstr ""
110+msgstr "Több"
109111
110112#: qml/Components/SeeMore.qml:58
111113msgid "See less"
112−msgstr ""
114+msgstr "Kevesebb"
113115
114116#: qml/Dash/DashApps.qml:37
115117msgid "Recent"
@@ -137,7 +139,7 @@ msgstr "Küldés"
137139
138140#: qml/Greeter/Greeter.qml:157
139141msgid "Swipe to unlock"
140−msgstr ""
142+msgstr "Csúsztasson a feloldáshoz"
141143
142144#: qml/Hud/HudParametrizedActionsPage.qml:132
143145msgid "Confirm"
@@ -169,7 +171,7 @@ msgstr "Adja meg a SIM PIN kódját"
169171
170172#: qml/Panel/Indicators/MenuItemFactory.qml:583
171173msgid "In queue…"
172−msgstr ""
174+msgstr "Sorban…"
173175
174176#: qml/Panel/Indicators/MenuItemFactory.qml:587
175177msgid "Downloading"
po/sl.po+11−11
@@ -8,23 +8,23 @@ msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-07-07 12:15+0100\n"
11−"PO-Revision-Date: 2014-06-23 09:29+0000\n"
11+"PO-Revision-Date: 2014-07-24 09:01+0000\n"
1212"Last-Translator: Damir Jerovšek <Unknown>\n"
1313"Language-Team: Slovenian <sl@li.org>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-09 06:37+0000\n"
18−"X-Generator: Launchpad (build 17100)\n"
17+"X-Launchpad-Export-Date: 2014-07-25 07:54+0000\n"
18+"X-Generator: Launchpad (build 17114)\n"
1919
2020#: plugins/Unity/Launcher/launcheritem.cpp:43
2121#: plugins/Unity/Launcher/launcheritem.cpp:73
2222msgid "Pin shortcut"
23−msgstr ""
23+msgstr "Pripni bližnjico"
2424
2525#: plugins/Unity/Launcher/launcheritem.cpp:73
2626msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "Odpni bližnjico"
2828
2929#: qml/Components/EdgeDemoOverlay.qml:151
3030msgid "Skip intro"
@@ -171,27 +171,27 @@ msgstr "Vnesite PIN kartice SIM"
171171
172172#: qml/Panel/Indicators/MenuItemFactory.qml:583
173173msgid "In queue…"
174−msgstr ""
174+msgstr "V vrsti ..."
175175
176176#: qml/Panel/Indicators/MenuItemFactory.qml:587
177177msgid "Downloading"
178−msgstr ""
178+msgstr "Prejemanje"
179179
180180#: qml/Panel/Indicators/MenuItemFactory.qml:589
181181msgid "Paused, tap to resume"
182−msgstr ""
182+msgstr "Premor, tapnite za nadaljevanje"
183183
184184#: qml/Panel/Indicators/MenuItemFactory.qml:591
185185msgid "Canceled"
186−msgstr ""
186+msgstr "Preklicano"
187187
188188#: qml/Panel/Indicators/MenuItemFactory.qml:593
189189msgid "Finished"
190−msgstr ""
190+msgstr "Končano"
191191
192192#: qml/Panel/Indicators/MenuItemFactory.qml:595
193193msgid "Failed, tap to retry"
194−msgstr ""
194+msgstr "Spodletelo, tapnite za ponovni poskus"
195195
196196#: qml/Panel/SearchIndicator.qml:27
197197msgid "Search"
po/sv.po+19−18
@@ -1,21 +1,22 @@
11# Swedish translation for unity
2−# Copyright (c) 2013 Rosetta Contributors and Canonical Ltd 2013
2+# Copyright © 2013-2014 Rosetta Contributors and Canonical Ltd 2013-2014
33# This file is distributed under the same license as the unity package.
4−# FIRST AUTHOR <EMAIL@ADDRESS>, 2013.
4+# Josef Andersson <josef.andersson@fripost.org>, 2014.
55#
66msgid ""
77msgstr ""
88"Project-Id-Version: unity\n"
99"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
1010"POT-Creation-Date: 2014-07-07 12:15+0100\n"
11−"PO-Revision-Date: 2014-07-20 19:14+0000\n"
12−"Last-Translator: Gunnar Hjalmarsson <Unknown>\n"
13−"Language-Team: Swedish <sv@li.org>\n"
11+"PO-Revision-Date: 2014-07-24 13:56+0000\n"
12+"Last-Translator: Josef Andersson <Unknown>\n"
13+"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
1414"MIME-Version: 1.0\n"
1515"Content-Type: text/plain; charset=UTF-8\n"
1616"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-21 07:05+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-25 07:54+0000\n"
1818"X-Generator: Launchpad (build 17114)\n"
19+"Language: sv\n"
1920
2021#: plugins/Unity/Launcher/launcheritem.cpp:43
2122#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -28,7 +29,7 @@ msgstr "Släpp genväg"
2829
2930#: qml/Components/EdgeDemoOverlay.qml:151
3031msgid "Skip intro"
31−msgstr "Skippa intro"
32+msgstr "Hoppa över introduktion"
3233
3334#: qml/Components/EdgeDemo.qml:113
3435msgid "Right edge"
@@ -36,7 +37,7 @@ msgstr "Högerkant"
3637
3738#: qml/Components/EdgeDemo.qml:114
3839msgid "Try swiping from the right edge to unlock the phone"
39−msgstr "Dra med fingret från höger för att låsa upp telefonen"
40+msgstr "Svep från höger för att låsa upp telefonen"
4041
4142#: qml/Components/EdgeDemo.qml:145
4243msgid "Top edge"
@@ -71,8 +72,8 @@ msgid ""
7172"You have now mastered the edge gestures and can start using the "
7273"phone<br><br>Tap on the screen to start"
7374msgstr ""
74−"Du har nu bemästrat kantgesterna och kan börja använda telefonen<br><br>Peka "
75−"på skärmen för att starta"
75+"Du har nu bemästrat kantgesterna och kan börja använda "
76+"telefonen<br><br>Tryck på skärmen för att starta"
7677
7778#: qml/Components/Lockscreen.qml:214
7879msgid "Emergency Call"
@@ -117,11 +118,11 @@ msgstr "Senaste"
117118
118119#: qml/Dash/Previews/PreviewActionCombo.qml:34
119120msgid "More..."
120−msgstr "Mer..."
121+msgstr "Mer…"
121122
122123#: qml/Dash/Previews/PreviewActionCombo.qml:34
123124msgid "Less..."
124−msgstr "Mindre..."
125+msgstr "Mindre…"
125126
126127#: qml/Dash/Previews/PreviewRatingInput.qml:82
127128msgid "Rate this"
@@ -149,15 +150,15 @@ msgstr "Skriv eller tala in ett kommando"
149150
150151#: qml/Hud/Hud.qml:84
151152msgid "Loading. Please Wait..."
152−msgstr "Laddar. Var god vänta..."
153+msgstr "Läser in. Var god vänta…"
153154
154155#: qml/Hud/Hud.qml:89
155156msgid "Speak Now..."
156−msgstr "Tala nu..."
157+msgstr "Tala nu…"
157158
158159#: qml/Hud/Hud.qml:94
159160msgid "Speaking..."
160−msgstr "Talar..."
161+msgstr "Talar…"
161162
162163#: qml/Notifications/NotificationMenuItemFactory.qml:91
163164msgid "Show password"
@@ -169,7 +170,7 @@ msgstr "Ange SIM PIN-kod"
169170
170171#: qml/Panel/Indicators/MenuItemFactory.qml:583
171172msgid "In queue…"
172−msgstr "I kö..."
173+msgstr "I kö…"
173174
174175#: qml/Panel/Indicators/MenuItemFactory.qml:587
175176msgid "Downloading"
@@ -177,7 +178,7 @@ msgstr "Hämtar"
177178
178179#: qml/Panel/Indicators/MenuItemFactory.qml:589
179180msgid "Paused, tap to resume"
180−msgstr "Pausad, peka för att fortsätta"
181+msgstr "Pausad, tryck för att fortsätta"
181182
182183#: qml/Panel/Indicators/MenuItemFactory.qml:591
183184msgid "Canceled"
@@ -189,7 +190,7 @@ msgstr "Klart"
189190
190191#: qml/Panel/Indicators/MenuItemFactory.qml:595
191192msgid "Failed, tap to retry"
192−msgstr "Misslyckades, peka för att försöka igen"
193+msgstr "Misslyckades, tryck för att försöka igen"
193194
194195#: qml/Panel/SearchIndicator.qml:27
195196msgid "Search"
po/unity8.pot+17−9
@@ -8,7 +8,7 @@ msgid ""
88msgstr ""
99"Project-Id-Version: unity8\n"
1010"Report-Msgid-Bugs-To: \n"
11−"POT-Creation-Date: 2014-07-07 12:15+0100\n"
11+"POT-Creation-Date: 2014-07-11 14:59+0200\n"
1212"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -80,10 +80,6 @@ msgstr ""
8080msgid "OK"
8181msgstr ""
8282
83−#: qml/Components/PageHeader.qml:366
84−msgid "Recent searches"
85−msgstr ""
86−
8783#: qml/Components/PassphraseLockscreen.qml:60
8884#, qt-format
8985msgid "Hello %1"
@@ -105,7 +101,7 @@ msgstr ""
105101msgid "See more"
106102msgstr ""
107103
108−#: qml/Components/SeeMore.qml:58
104+#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
109105msgid "See less"
110106msgstr ""
111107
@@ -113,6 +109,10 @@ msgstr ""
113109msgid "Recent"
114110msgstr ""
115111
112+#: qml/Dash/GenericScopeView.qml:330
113+msgid "See all"
114+msgstr ""
115+
116116#: qml/Dash/Previews/PreviewActionCombo.qml:34
117117msgid "More..."
118118msgstr ""
@@ -121,15 +121,15 @@ msgstr ""
121121msgid "Less..."
122122msgstr ""
123123
124−#: qml/Dash/Previews/PreviewRatingInput.qml:82
124+#: qml/Dash/Previews/PreviewRatingInput.qml:81
125125msgid "Rate this"
126126msgstr ""
127127
128−#: qml/Dash/Previews/PreviewRatingInput.qml:128
128+#: qml/Dash/Previews/PreviewRatingInput.qml:126
129129msgid "Add a review"
130130msgstr ""
131131
132−#: qml/Dash/Previews/PreviewRatingInput.qml:168
132+#: qml/Dash/Previews/PreviewRatingInput.qml:166
133133msgid "Send"
134134msgstr ""
135135
@@ -165,6 +165,14 @@ msgstr ""
165165msgid "Please enter SIM PIN"
166166msgstr ""
167167
168+#: qml/Panel/ActiveCallHint.qml:77
169+msgid "Tap to return to call..."
170+msgstr ""
171+
172+#: qml/Panel/ActiveCallHint.qml:90
173+msgid "Conference"
174+msgstr ""
175+
168176#: qml/Panel/Indicators/MenuItemFactory.qml:583
169177msgid "In queue…"
170178msgstr ""
qml/Components/Background.qmlnew file+77
@@ -0,0 +1,77 @@
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+
19+Loader {
20+ id: root
21+ anchors.fill: parent
22+
23+ property url style
24+ readonly property var parsedStyle: String(style)
25+ .match(/^(color|gradient):\/\/\/(?:(#(?:[0-9a-f]{3,4}){1,2}|[a-z]{3,}))(?:\/(#(?:[0-9a-f]{3,4}){1,2}|[a-z]{3,}))?\/?$/i)
26+
27+ sourceComponent: {
28+ if (style == "") return null;
29+ if (!parsedStyle) return image;
30+ if (parsedStyle[1] === "color") return solid
31+ if (parsedStyle[1] === "gradient") return gradient
32+ }
33+
34+ onLoaded: if (item.hasOwnProperty("parsedStyle")) {
35+ item.parsedStyle = Qt.binding(function() { return root.parsedStyle } );
36+ }
37+
38+ Component {
39+ id: solid
40+
41+ Rectangle {
42+ objectName: "solid"
43+
44+ property var parsedStyle
45+
46+ color: parsedStyle ? parsedStyle[2] : "#ffffff"
47+ }
48+ }
49+
50+ Component {
51+ id: gradient
52+
53+ Rectangle {
54+ objectName: "gradient"
55+
56+ property var parsedStyle
57+
58+ gradient: Gradient {
59+ GradientStop { position: 0; color: parsedStyle ? parsedStyle[2] : "#000000" }
60+ GradientStop { position: 1; color: parsedStyle ? parsedStyle[3] : "#000000" }
61+ }
62+ }
63+ }
64+
65+ Component {
66+ id: image
67+
68+ Image {
69+ objectName: "image"
70+
71+ source: width > 0 && height > 0 && root.style
72+
73+ sourceSize.width: width
74+ sourceSize.height: height
75+ }
76+ }
77+}
qml/Components/FilterGrid.qmldeleted−124
@@ -1,124 +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−
22−/*
23− A ResponsiveGridView that can optionally have the number of rows being displayed
24− reduced to collapsedRowCount, in which case a button saying "View all (123)"
25− will be shown at the bottom. If clicked, FilterGrid will them expand vertically
26− to display all rows.
27− */
28−Item {
29− id: root
30−
31− /* Whether, when collapsed, a button should be displayed enabling the user to expand
32− the grid to its full size. */
33− readonly property bool expandable: model.count > rowsWhenCollapsed * iconTileGrid.columns
34−
35− property var model: null
36−
37− /* Maximum number of rows to be show when filter=true. */
38− property int collapsedRowCount: 2
39− property int uncollapsedRowCount: Math.ceil(model.count / columns)
40− /* Never show more rows than model would fill up. */
41− readonly property int rowsWhenCollapsed: Math.min(collapsedRowCount, uncollapsedRowCount)
42− readonly property int collapsedHeight: iconTileGrid.contentHeightForRows(rowsWhenCollapsed)
43− readonly property int uncollapsedHeight: iconTileGrid.contentHeightForRows(uncollapsedRowCount)
44−
45− property alias minimumHorizontalSpacing: iconTileGrid.minimumHorizontalSpacing
46− property alias maximumNumberOfColumns: iconTileGrid.maximumNumberOfColumns
47− property alias columns: iconTileGrid.columns
48− property alias delegateWidth: iconTileGrid.delegateWidth
49− property alias delegateHeight: iconTileGrid.delegateHeight
50− property alias verticalSpacing: iconTileGrid.verticalSpacing
51− readonly property alias margins: iconTileGrid.margins
52− property alias delegate: iconTileGrid.delegate
53− property alias cellWidth: iconTileGrid.cellWidth
54− property alias cellHeight: iconTileGrid.cellHeight
55− property alias displayMarginBeginning: iconTileGrid.displayMarginBeginning
56− property alias displayMarginEnd: iconTileGrid.displayMarginEnd
57− readonly property alias originY: iconTileGrid.originY
58− readonly property alias flicking: iconTileGrid.flicking
59− readonly property alias moving: iconTileGrid.moving
60− readonly property alias pressDelay: iconTileGrid.pressDelay
61− property alias highlightIndex: iconTileGrid.highlightIndex
62− readonly property alias currentItem: iconTileGrid.currentItem
63− readonly property alias filtered: d.filter
64−
65− QtObject {
66− id: d
67− // We do have filter and collapsed properties because we need to decouple
68− // the real filtering with the animation since the closing animation
69− // i.e. setFilter(false. true) we still need to not be filtering until
70− // the animation finishes otherwise we hide the items when the animation
71− // is still running
72− property bool filter: true
73− property bool collapsed: true
74− }
75−
76− height: d.collapsed ? root.collapsedHeight : root.uncollapsedHeight
77− clip: filterAnimation.running
78−
79− Behavior on height {
80− id: heightBehaviour
81− enabled: false
82− NumberAnimation {
83− id: filterAnimation
84− // Duration and easing here match the ListViewWithPageHeader::m_contentYAnimation
85− // otherwise since both animations can run at the same time you'll get
86− // some visual weirdness.
87− duration: 200
88− easing.type: Easing.InOutQuad
89− onRunningChanged: {
90− if (!running) {
91− d.filter = d.collapsed;
92− }
93− heightBehaviour.enabled = false;
94− }
95− }
96− }
97−
98− function setFilter(filter, animate) {
99− heightBehaviour.enabled = animate;
100− d.collapsed = filter;
101− if (!animate || !filter) {
102− d.filter = filter;
103− }
104− }
105−
106− ResponsiveGridView {
107− id: iconTileGrid
108−
109− anchors { left: parent.left; right: parent.right }
110− height: totalContentHeight
111− interactive: false
112−
113− minimumHorizontalSpacing: units.gu(0.5)
114− maximumNumberOfColumns: 6
115− delegateWidth: units.gu(11)
116− delegateHeight: units.gu(9.5)
117− verticalSpacing: units.gu(2)
118−
119− model: LimitProxyModel {
120− model: root.model
121− limit: d.filter ? rowsWhenCollapsed * iconTileGrid.columns : -1
122− }
123− }
124−}
qml/Components/ListItems/Header.qml+17−26
@@ -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
@@ -15,54 +15,45 @@
1515 */
1616
1717import QtQuick 2.0
18+import QtQuick.Layouts 1.1
1819import Ubuntu.Components 0.1
1920
2021Item {
21− /*!
22− \preliminary
23− The text that is shown as the header text.
24− \qmlproperty string text
25− */
2622 property alias text: label.text
27− property alias textColor: label.color
28− property alias image: image.source
23+ property alias color: label.color
24+ property alias iconName: icon.name
2925
3026 signal clicked(variant mouse)
3127
3228 height: units.gu(5)
3329
34− Item {
30+ RowLayout {
31+ spacing: units.gu(.5)
3532 anchors {
3633 left: parent.left
3734 right: parent.right
38− rightMargin: units.gu(0.5)
39− top: parent.top
40− bottom: parent.bottom
35+ verticalCenter: parent.verticalCenter
36+ margins: units.gu(1)
4137 }
4238
4339 Label {
4440 id: label
45− anchors {
46− left: parent.left
47− leftMargin: units.gu(2)
48− verticalCenter: parent.verticalCenter
49− }
41+ Layout.fillWidth: true
5042
51− color: "grey" // TODO karni: Update Ubuntu.Compoonents.Themes.Palette.
5243 font.family: "Ubuntu"
5344 fontSize: "medium"
5445 elide: Text.ElideRight
46+ maximumLineCount: 1
5547 textFormat: Text.PlainText
56− width: parent.width - image.width - image.leftMargin - anchors.leftMargin
48+ width: Math.min(parent.width - units.gu(4), implicitWidth)
5749 }
5850
59− Image {
60− id: image
61− readonly property double leftMargin: units.gu(1)
62− x: label.x + label.contentWidth + leftMargin
63− anchors {
64− verticalCenter: parent.verticalCenter
65− }
51+ Icon {
52+ id: icon
53+ visible: name != ""
54+ height: units.gu(2)
55+ width: height
56+ color: label.color
6657 }
6758 }
6859
qml/Components/PageHeader.qml+6−1
@@ -127,6 +127,11 @@ Item {
127127 property bool showSearch: false
128128 property var popover: null
129129
130+ Background {
131+ objectName: "headerBackground"
132+ style: scopeStyle.headerBackground
133+ }
134+
130135 Behavior on contentY {
131136 UbuntuNumberAnimation {
132137 id: openSearchAnimation
@@ -225,7 +230,7 @@ Item {
225230 height: headerContainer.height
226231 contentHeight: height
227232 separatorSource: ""
228− textColor: root.scopeStyle ? root.scopeStyle.foreground : "grey"
233+ textColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
229234 property var styledItem: header
230235 property string title: root.title
231236 property var config: PageHeadConfiguration {
qml/Components/ResponsiveGridView.qml+2−1
@@ -44,10 +44,11 @@ Item {
4444 property alias displayMarginBeginning: gridView.displayMarginBeginning
4545 property alias displayMarginEnd: gridView.displayMarginEnd
4646 property alias highlightIndex: gridView.highlightIndex
47+ property alias cacheBuffer: gridView.cacheBuffer
4748 readonly property alias currentItem: gridView.currentItem
4849
4950 function contentHeightForRows(rows) {
50− return rows * cellHeight + verticalSpacing
51+ return rows * cellHeight;
5152 }
5253
5354 GridView {
qml/Dash/CardCarousel.qml+2−7
@@ -21,13 +21,8 @@ import "../Components"
2121DashRenderer {
2222 id: cardCarousel
2323
24− property alias cacheBuffer: carousel.cacheBuffer
25− property alias itemComponent: carousel.itemComponent
26− property alias minimumTileWidth: carousel.minimumTileWidth
27− property alias selectedItemScaleFactor: carousel.selectedItemScaleFactor
28− property alias tileAspectRatio: carousel.tileAspectRatio
29−
30− height: carousel.implicitHeight + units.gu(6)
24+ expandedHeight: carousel.implicitHeight + units.gu(6)
25+ collapsedHeight: expandedHeight
3126
3227 Carousel {
3328 id: carousel
qml/Dash/CardFilterGrid.qml → qml/Dash/CardGrid.qmlrenamed+22−22
@@ -18,33 +18,33 @@ import QtQuick 2.0
1818import "../Components"
1919
2020DashRenderer {
21− id: genericFilterGrid
21+ id: root
2222
23− expandable: filterGrid.expandable
24− collapsedHeight: filterGrid.collapsedHeight
25− uncollapsedHeight: filterGrid.uncollapsedHeight
26− originY: filterGrid.originY
27− height: filterGrid.height
28− filtered: filterGrid.filtered
29−
30− function setFilter(filter, animate) {
31− filterGrid.setFilter(filter, animate)
23+ readonly property int collapsedRows: {
24+ if (!cardTool || !cardTool.template || typeof cardTool.template["collapsed-rows"] != "number") return 2;
25+ return cardTool.template["collapsed-rows"];
3226 }
3327
34− FilterGrid {
35− id: filterGrid
36− width: genericFilterGrid.width
28+ expandedHeight: grid.totalContentHeight
29+ collapsedHeight: Math.min(grid.contentHeightForRows(collapsedRows), expandedHeight)
30+ collapsedItemCount: collapsedRows * grid.columns
31+ originY: grid.originY
32+
33+ ResponsiveGridView {
34+ id: grid
35+ anchors.fill: parent
3736 minimumHorizontalSpacing: units.gu(1)
3837 delegateWidth: cardTool.cardWidth
3938 delegateHeight: cardTool.cardHeight
4039 verticalSpacing: units.gu(1)
41− model: genericFilterGrid.model
42− collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
43− displayMarginBeginning: genericFilterGrid.displayMarginBeginning
44− displayMarginEnd: genericFilterGrid.displayMarginEnd
40+ model: root.model
41+ displayMarginBeginning: root.displayMarginBeginning
42+ displayMarginEnd: root.displayMarginEnd
43+ cacheBuffer: 0
44+ interactive: false
4545 delegate: Item {
46− width: filterGrid.cellWidth
47− height: filterGrid.cellHeight
46+ width: grid.cellWidth
47+ height: grid.cellHeight
4848 Loader {
4949 id: loader
5050 sourceComponent: cardTool.cardComponent
@@ -58,12 +58,12 @@ DashRenderer {
5858 item.template = Qt.binding(function() { return cardTool.template; });
5959 item.components = Qt.binding(function() { return cardTool.components; });
6060 item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
61− item.scopeStyle = genericFilterGrid.scopeStyle;
61+ item.scopeStyle = root.scopeStyle;
6262 }
6363 Connections {
6464 target: loader.item
65− onClicked: genericFilterGrid.clicked(index, result)
66− onPressAndHold: genericFilterGrid.pressAndHold(index)
65+ onClicked: root.clicked(index, result)
66+ onPressAndHold: root.pressAndHold(index)
6767 }
6868 }
6969 }
qml/Dash/CardVerticalJournal.qml+3−21
@@ -23,33 +23,15 @@ DashRenderer {
2323
2424 readonly property double collapseLimit: units.gu(35)
2525
26− uncollapsedHeight: cardVerticalJournal.implicitHeight
27− collapsedHeight: Math.min(collapseLimit, cardVerticalJournal.implicitHeight)
28− expandable: uncollapsedHeight > collapseLimit
26+ expandedHeight: Math.max(cardVerticalJournal.implicitHeight, minHeight)
27+ collapsedHeight: Math.max(Math.min(collapseLimit, cardVerticalJournal.implicitHeight), minHeight)
28+ // TODO: implement collapsedItemCount
2929
3030 // This minHeight is used as bootstrapper for the height. Vertical Journal
3131 // is special by the fact that it doesn't know how to calculate its implicit height unless we give it
3232 // enough height that it can start creating its children so we make sure it has enough height for that
3333 // in case the model is non empty
3434 readonly property double minHeight: root.model.count >= 1 ? cardVerticalJournal.rowSpacing + 1 : 0
35− height: filtered ? Math.max(collapsedHeight, minHeight) : uncollapsedHeight
36−
37− Behavior on height {
38− id: heightBehaviour
39− enabled: false
40− animation: UbuntuNumberAnimation {
41− onRunningChanged: {
42− if (!running) {
43− heightBehaviour.enabled = false
44− }
45− }
46− }
47− }
48−
49− function setFilter(filter, animate) {
50− heightBehaviour.enabled = animate;
51− filtered = filter;
52− }
5335
5436 ResponsiveVerticalJournal {
5537 id: cardVerticalJournal
qml/Dash/DashRenderer.qml+3−10
@@ -17,15 +17,11 @@
1717import QtQuick 2.0
1818
1919Item {
20− // Can the item be expanded?
21− property bool expandable: false
20+ property int collapsedHeight
2221
23− // In case it can be expanded, is it filtered
24− property bool filtered: true
22+ property int expandedHeight
2523
26− property int collapsedHeight: height
27−
28− property int uncollapsedHeight: height
24+ property int collapsedItemCount: -1
2925
3026 property int displayMarginBeginning: 0
3127
@@ -50,7 +46,4 @@ Item {
5046 /// Emitted when the user pressed and held on an item
5147 /// @param index is the index of the held item
5248 signal pressAndHold(int index)
53−
54− function setFilter(filter, animate) {
55− }
5649}
qml/Dash/GenericScopeView.qml+128−64
@@ -119,6 +119,7 @@ FocusScope {
119119
120120 model: scopeView.categories
121121 forceNoClip: previewListView.open
122+ pixelAligned: true
122123
123124 property string expandedCategoryId: ""
124125
@@ -128,11 +129,22 @@ FocusScope {
128129 highlightWhenPressed: false
129130 showDivider: false
130131
131− readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
132− readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filtered : true
132+ readonly property bool expandable: {
133+ if (categoryView.model.count === 1) return false;
134+ if (cardTool.template && cardTool.template["collapsed-rows"] === 0) return false;
135+ if (item && item.expandedHeight > item.collapsedHeight) return true;
136+ return false;
137+ }
138+ property bool expanded: false
133139 readonly property string category: categoryId
140+ readonly property string headerLink: model.headerLink
134141 readonly property var item: rendererLoader.item
135142
143+ function expand(expand, animate) {
144+ heightBehaviour.enabled = animate;
145+ expanded = expand;
146+ }
147+
136148 CardTool {
137149 id: cardTool
138150 objectName: "cardTool"
@@ -142,22 +154,49 @@ FocusScope {
142154 viewWidth: parent.width
143155 }
144156
157+ onExpandableChanged: {
158+ // This can happen with the VJ that doesn't know how height it will be on creation
159+ // so doesn't set expandable until a bit too late for onLoaded
160+ if (expandable) {
161+ var shouldExpand = baseItem.category === categoryView.expandedCategoryId;
162+ baseItem.expand(shouldExpand, false /*animate*/);
163+ }
164+ }
165+
166+ onHeightChanged: rendererLoader.updateDelegateCreationRange();
167+ onYChanged: rendererLoader.updateDelegateCreationRange();
168+
145169 Loader {
146170 id: rendererLoader
147171 anchors {
148172 top: parent.top
149173 left: parent.left
150174 right: parent.right
151− topMargin: hasSectionHeader ? 0 : units.gu(2)
175+ topMargin: name != "" ? 0 : units.gu(2)
176+ }
177+
178+ Behavior on height {
179+ id: heightBehaviour
180+ enabled: false
181+ animation: UbuntuNumberAnimation {
182+ onRunningChanged: {
183+ if (!running) {
184+ heightBehaviour.enabled = false
185+ }
186+ }
187+ }
152188 }
153189
190+ readonly property bool expanded: baseItem.expanded || !baseItem.expandable
191+ height: expanded ? item.expandedHeight : item.collapsedHeight
192+
154193 source: {
155194 switch (cardTool.categoryLayout) {
156195 case "carousel": return "CardCarousel.qml";
157196 case "vertical-journal": return "CardVerticalJournal.qml";
158197 case "running-apps": return "Apps/RunningApplicationsGrid.qml";
159198 case "grid":
160− default: return "CardFilterGrid.qml";
199+ default: return "CardGrid.qml";
161200 }
162201 }
163202
@@ -176,9 +215,9 @@ FocusScope {
176215 }
177216 item.objectName = Qt.binding(function() { return categoryId })
178217 item.scopeStyle = scopeView.scopeStyle;
179− if (item.expandable) {
180− var shouldFilter = categoryId != categoryView.expandedCategoryId;
181− item.setFilter(shouldFilter, false /*animate*/);
218+ if (baseItem.expandable) {
219+ var shouldExpand = categoryId === categoryView.expandedCategoryId;
220+ baseItem.expand(shouldExpand, false /*animate*/);
182221 }
183222 updateDelegateCreationRange();
184223 item.cardTool = cardTool;
@@ -199,25 +238,22 @@ FocusScope {
199238 // so it's not implemented
200239 scopeView.scope.activate(result)
201240 } else {
202− previewListView.model = target.model;
203− previewListView.currentIndex = -1
204− previewListView.currentIndex = index;
205− previewListView.open = true
241+ openPreview(index);
206242 }
207243 }
208− onPressAndHold: {
209− previewListView.model = target.model;
210− previewListView.currentIndex = -1
211− previewListView.currentIndex = index;
212− previewListView.open = true
213− }
214− onExpandableChanged: {
215− // This can happen with the VJ that doesn't know how height it will be on creation
216− // so doesn't set expandable until a bit too late for onLoaded
217− if (rendererLoader.item.expandable) {
218− var shouldFilter = baseItem.category != categoryView.expandedCategoryId;
219− rendererLoader.item.setFilter(shouldFilter, false /*animate*/);
244+ onPressAndHold: openPreview(index)
245+
246+ function openPreview(index) {
247+ if (!rendererLoader.expanded && !seeAllLabel.visible && target.collapsedItemCount > 0) {
248+ previewLimitModel.model = target.model;
249+ previewLimitModel.limit = target.collapsedItemCount;
250+ previewListView.model = previewLimitModel;
251+ } else {
252+ previewListView.model = target.model;
220253 }
254+ previewListView.currentIndex = -1;
255+ previewListView.currentIndex = index;
256+ previewListView.open = true;
221257 }
222258 }
223259 Connections {
@@ -227,17 +263,17 @@ FocusScope {
227263 }
228264 function collapseAllButExpandedCategory() {
229265 var item = rendererLoader.item;
230− if (item.expandable) {
231− var shouldFilter = categoryId != categoryView.expandedCategoryId;
232− if (shouldFilter != item.filter) {
266+ if (baseItem.expandable) {
267+ var shouldExpand = categoryId === categoryView.expandedCategoryId;
268+ if (shouldExpand != baseItem.expanded) {
233269 // If the filter animation will be seen start it, otherwise, just flip the switch
234− var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
235− var growingVisible = !shouldFilter && y + height < categoryView.height;
236− if (!previewListView.open || !shouldFilter) {
270+ var shrinkingVisible = !shouldExpand && y + item.collapsedHeight + seeAll.height < categoryView.height;
271+ var growingVisible = shouldExpand && y + height < categoryView.height;
272+ if (!previewListView.open || shouldExpand) {
237273 var animate = shrinkingVisible || growingVisible;
238− item.setFilter(shouldFilter, animate)
239− if (!shouldFilter && !previewListView.open) {
240− categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
274+ baseItem.expand(shouldExpand, animate)
275+ if (shouldExpand && !previewListView.open) {
276+ categoryView.maximizeVisibleArea(index, item.expandedHeight + seeAll.height);
241277 }
242278 }
243279 }
@@ -274,58 +310,82 @@ FocusScope {
274310 item.displayMarginEnd = -baseItem.height;
275311 } else {
276312 item.displayMarginBeginning = -Math.max(-baseItem.y, 0);
277− item.displayMarginEnd = -Math.max(baseItem.height - categoryView.height + baseItem.y, 0)
313+ item.displayMarginEnd = -Math.max(baseItem.height - seeAll.height
314+ - categoryView.height + baseItem.y, 0)
278315 }
279316 }
280317 }
318+ }
281319
282− Image {
283− visible: index != 0
284− anchors {
285− top: parent.top
286− left: parent.left
287− right: parent.right
320+ AbstractButton {
321+ id: seeAll
322+ objectName: "seeAll"
323+ anchors {
324+ top: rendererLoader.bottom
325+ left: parent.left
326+ right: parent.right
327+ }
328+ height: seeAllLabel.visible ? seeAllLabel.font.pixelSize + units.gu(6) : 0
329+
330+ onClicked: {
331+ if (categoryView.expandedCategoryId != baseItem.category) {
332+ categoryView.expandedCategoryId = baseItem.category;
333+ } else {
334+ categoryView.expandedCategoryId = "";
288335 }
289− fillMode: Image.Stretch
290− source: "graphics/dash_divider_top_lightgrad.png"
291− z: -1
292336 }
293337
294− Image {
295− // FIXME Should not rely on model.count but view.count, but ListViewWithPageHeader doesn't expose it yet.
296− visible: index != categoryView.model.count - 1
338+ Label {
339+ id: seeAllLabel
340+ text: baseItem.expanded ? i18n.tr("See less") : i18n.tr("See all")
297341 anchors {
298− bottom: parent.bottom
299− left: parent.left
300− right: parent.right
342+ centerIn: parent
343+ verticalCenterOffset: units.gu(-0.5)
301344 }
302− fillMode: Image.Stretch
303− source: "graphics/dash_divider_top_darkgrad.png"
304− z: -1
345+ fontSize: "small"
346+ font.weight: Font.Bold
347+ color: scopeStyle ? scopeStyle.foreground : "grey"
348+ visible: baseItem.expandable && !baseItem.headerLink
305349 }
306350 }
307351
308− onHeightChanged: rendererLoader.updateDelegateCreationRange();
309− onYChanged: rendererLoader.updateDelegateCreationRange();
352+ Image {
353+ visible: index != 0
354+ anchors {
355+ top: parent.top
356+ left: parent.left
357+ right: parent.right
358+ }
359+ fillMode: Image.Stretch
360+ source: "graphics/dash_divider_top_lightgrad.png"
361+ z: -1
362+ }
363+
364+ Image {
365+ // FIXME Should not rely on model.count but view.count, but ListViewWithPageHeader doesn't expose it yet.
366+ visible: index != categoryView.model.count - 1
367+ anchors {
368+ bottom: seeAll.bottom
369+ left: parent.left
370+ right: parent.right
371+ }
372+ fillMode: Image.Stretch
373+ source: "graphics/dash_divider_top_darkgrad.png"
374+ z: -1
375+ }
310376 }
311377
312378 sectionProperty: "name"
313379 sectionDelegate: ListItems.Header {
314380 objectName: "dashSectionHeader" + (delegate ? delegate.category : "")
315− property var delegate: categoryView.item(delegateIndex)
381+ readonly property var delegate: categoryView.item(delegateIndex)
316382 width: categoryView.width
383+ height: section != "" ? units.gu(5) : 0
317384 text: section
318− textColor: scopeStyle ? scopeStyle.foreground : "grey"
319− image: {
320− if (delegate && delegate.expandable)
321− return delegate.filtered ? "graphics/header_handlearrow.png" : "graphics/header_handlearrow2.png"
322− return "";
323− }
385+ color: scopeStyle ? scopeStyle.foreground : "grey"
386+ iconName: delegate && delegate.headerLink ? "go-next" : ""
324387 onClicked: {
325− if (categoryView.expandedCategoryId != delegate.category)
326− categoryView.expandedCategoryId = delegate.category;
327− else
328− categoryView.expandedCategoryId = "";
388+ if (delegate.headerLink) scopeView.scope.performQuery(delegate.headerLink);
329389 }
330390 }
331391
@@ -352,6 +412,10 @@ FocusScope {
352412 }
353413 }
354414
415+ LimitProxyModel {
416+ id: previewLimitModel
417+ }
418+
355419 PreviewListView {
356420 id: previewListView
357421 objectName: "previewListView"
src/main.cpp+1−1
@@ -221,7 +221,7 @@ int main(int argc, const char *argv[])
221221
222222 return runWithClient(mirServer, startShell);
223223 } else {
224− if (qgetenv("UPSTART_JOB") == "unity8") {
224+ if (!qgetenv("UNITY_MIR_EMITS_SIGSTOP").isEmpty()) {
225225 // Emit SIGSTOP as expected by upstart, under Mir it's unity-mir that will raise it.
226226 // see http://upstart.ubuntu.com/cookbook/#expect-stop
227227 raise(SIGSTOP);
tests/autopilot/unity8/shell/emulators/dash.py+12−6
@@ -18,6 +18,7 @@
1818#
1919
2020import logging
21+import ubuntuuitoolkit
2122
2223from unity8.shell import emulators
2324
@@ -40,7 +41,7 @@ class Dash(emulators.UnityEmulatorBase):
4041
4142 def get_applications_grid(self):
4243 get_grid = self.get_scope('clickscope').wait_select_single(
43− 'CardFilterGrid', objectName='local')
44+ 'CardGrid', objectName='local')
4445 return get_grid
4546
4647 def get_application_icon(self, text):
@@ -128,9 +129,9 @@ class Dash(emulators.UnityEmulatorBase):
128129 def enter_search_query(self, query):
129130 current_header = self._get_current_page_header()
130131 self.pointing_device.move(current_header.globalRect.x +
131− current_header.width - current_header.height / 2,
132+ current_header.width - current_header.height / 4,
132133 current_header.globalRect.y +
133− current_header.height / 2)
134+ current_header.height / 4)
134135 self.pointing_device.click()
135136 headerContainer = current_header.select_single(objectName="headerContainer")
136137 headerContainer.contentY.wait_for(0)
@@ -151,6 +152,10 @@ class Dash(emulators.UnityEmulatorBase):
151152 return None
152153
153154
155+class ListViewWithPageHeader(ubuntuuitoolkit.QQuickFlickable):
156+ pass
157+
158+
154159class GenericScopeView(emulators.UnityEmulatorBase):
155160 """Autopilot emulator for generic scopes."""
156161
@@ -196,14 +201,15 @@ class DashApps(GenericScopeView):
196201 category_element = self._get_category_element(category)
197202 application_cards = category_element.select_many('AbstractButton')
198203
199− # sort by y, x
200204 application_cards = sorted(
201− application_cards,
205+ (card for card in application_cards
206+ if card.globalRect.y
207+ < category_element.globalRect.y + category_element.height),
202208 key=lambda card: (card.globalRect.y, card.globalRect.x))
203209
204210 result = []
205211 for card in application_cards:
206− if card.objectName != 'cardToolCard':
212+ if card.objectName not in ('cardToolCard', 'seeAll'):
207213 result.append(card.title)
208214 return result
209215
tests/autopilot/unity8/shell/tests/test_emulators.py+15−5
@@ -16,6 +16,7 @@
1616# You should have received a copy of the GNU General Public License
1717# along with this program. If not, see <http://www.gnu.org/licenses/>.
1818#
19+from unity8.shell.emulators.dash import ListViewWithPageHeader
1920
2021"""Tests for the Dash autopilot emulators.
2122
@@ -182,18 +183,27 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
182183
183184 def test_get_applications_should_return_correct_applications(self):
184185 category = '2'
186+ category_element = self.applications_scope._get_category_element(
187+ category)
188+ list_view = self.dash.get_scope('clickscope')\
189+ .select_single(ListViewWithPageHeader)
185190 expected_apps_count = self._get_number_of_application_slots(category)
186191 expected_applications = self.available_applications[
187192 :expected_apps_count]
193+ x_center = list_view.globalRect.x + list_view.width / 2
194+ y_center = list_view.globalRect.y + list_view.height / 2
195+ y_diff = category_element.y - list_view.height + category_element.height
196+ list_view._slow_drag(x_center, x_center,
197+ y_center, y_center - y_diff)
188198 applications = self.applications_scope.get_applications(category)
189199 self.assertEqual(expected_applications, applications)
190200
191201 def _get_number_of_application_slots(self, category):
192202 category_element = self.applications_scope._get_category_element(
193203 category)
194− grid = category_element.select_single('CardFilterGrid')
195− filtergrid = grid.select_single('FilterGrid')
196− if (grid.filtered):
197− return filtergrid.collapsedRowCount * filtergrid.columns
204+ cardgrid = category_element.select_single('CardGrid')
205+ if (category_element.expanded):
206+ return cardgrid.select_single('QQuickGridView').count
198207 else:
199− return filtergrid.uncollapsedRowCount * filtergrid.columns
208+ return cardgrid.collapsedRows \
209+ * cardgrid.select_single('ResponsiveGridView').columns
tests/autopilot/unity8/shell/tests/test_upstart.py+13
@@ -20,6 +20,7 @@
2020"""Tests for upstart integration."""
2121
2222import os
23+import stat
2324import signal
2425import subprocess
2526import time
@@ -57,6 +58,18 @@ class UpstartIntegrationTests(UnityTestCase):
5758
5859 def _launch_unity(self):
5960 self.patch_environment("QT_LOAD_TESTABILITY", "1")
61+
62+ try:
63+ host_socket = os.getenv("MIR_SOCKET", "/run/mir_socket")
64+ if stat.S_ISSOCK(os.stat(host_socket).st_mode):
65+ self.patch_environment("MIR_SERVER_HOST_SOCKET",
66+ host_socket)
67+ socket = os.path.join(os.getenv("XDG_RUNTIME_DIR", "/tmp"),
68+ "mir_socket")
69+ self.patch_environment("MIR_SERVER_FILE", socket)
70+ except OSError:
71+ pass
72+
6073 self.process = subprocess.Popen(
6174 [get_binary_path()] + self.unity_geometry_args)
6275
tests/mocks/Ubuntu/Telephony/CMakeLists.txt+1−9
@@ -11,12 +11,4 @@ add_library(FakeUbuntuTelephonyQml MODULE ${FakeUbuntuTelephonyQml_SOURCES})
1111
1212qt5_use_modules(FakeUbuntuTelephonyQml Core Quick)
1313
14−# copy files into build directory for shadow builds
15−add_custom_target(UbuntuTelephonyQmlDirFile ALL
16− COMMAND cp "${CMAKE_CURRENT_SOURCE_DIR}/qmldir" ${CMAKE_CURRENT_BINARY_DIR}
17− DEPENDS qmldir
18−)
19−
20−install(TARGETS FakeUbuntuTelephonyQml
21− DESTINATION ${SHELL_INSTALL_QML}/mocks/Ubuntu/Telephony
22− )
14+add_unity8_mock(Ubuntu.Telephony 0.1 Ubuntu/Telephony TARGETS FakeUbuntuTelephonyQml)
tests/mocks/Unity/fake_categories.cpp+13−1
@@ -145,9 +145,12 @@ Categories::data(const QModelIndex& index, int role) const
145145 } else {
146146 map["category-layout"] = "carousel";
147147 map["card-size"] = "medium";
148− map["collapsed-rows"] = 2;
149148 map["overlay"] = true;
150149 }
150+ if (index.row() == 19) {
151+ map["category-layout"] = "grid";
152+ map["collapsed-rows"] = 0;
153+ }
151154 map["card-size"] = "small";
152155 return map;
153156 }
@@ -166,6 +169,9 @@ Categories::data(const QModelIndex& index, int role) const
166169 return map;
167170 }
168171 case RoleHeaderLink:
172+ if (index.row() == 1 || index.row() == 4) {
173+ return QString("scope://query/1");
174+ }
169175 return QString();
170176 case RoleResults:
171177 return QVariant::fromValue(resultsModel);
@@ -177,3 +183,9 @@ Categories::data(const QModelIndex& index, int role) const
177183 }
178184 }
179185}
186+
187+QVariant
188+Categories::data(int row, int role) const
189+{
190+ return data(index(row, 0), role);
191+}
tests/mocks/Unity/fake_categories.h+2
@@ -37,6 +37,8 @@ public:
3737 Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) override;
3838 Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;
3939
40+ Q_INVOKABLE QVariant data(int row, int role) const;
41+
4042private Q_SLOTS:
4143 void countChanged();
4244
tests/mocks/Unity/fake_scope.cpp+8−11
@@ -24,7 +24,7 @@ Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
2424{
2525}
2626
27−Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent)
27+Scope::Scope(QString const& id, QString const& name, bool visible, QObject* parent, int categories)
2828 : unity::shell::scopes::ScopeInterface(parent)
2929 , m_id(id)
3030 , m_name(name)
@@ -33,7 +33,7 @@ Scope::Scope(QString const& id, QString const& name, bool visible, QObject* pare
3333 , m_isActive(false)
3434 , m_currentDeparment("root")
3535 , m_previewRendererName("preview-generic")
36− , m_categories(new Categories(20, this))
36+ , m_categories(new Categories(categories, this))
3737{
3838}
3939
@@ -182,14 +182,16 @@ bool Scope::hasDepartments() const
182182
183183QVariantMap Scope::customizations() const
184184{
185− QVariantMap m;
185+ QVariantMap m, h;
186186 if (m_id == "clickscope") {
187+ h["foreground-color"] = "yellow";
187188 m["background-color"] = "red";
188189 m["foreground-color"] = "blue";
190+ m["page-header"] = h;
189191 } else if (m_id == "MockScope5") {
190− QVariantMap pageHeader;
191− pageHeader["logo"] = QUrl("../../../tests/qmltests/Components/tst_PageHeader/logo-ubuntu-orange.svg");
192− m["page-header"] = pageHeader;
192+ h["background"] = "gradient:///lightgrey/grey";
193+ h["logo"] = QUrl("../../../tests/qmltests/Components/tst_PageHeader/logo-ubuntu-orange.svg");
194+ m["page-header"] = h;
193195 }
194196 return m;
195197}
@@ -216,8 +218,3 @@ void Scope::loadDepartment(const QString& id)
216218 m_currentDeparment = id;
217219 Q_EMIT currentDepartmentIdChanged();
218220}
219−
220−void Scope::performQuery(const QString& query)
221−{
222− Q_UNUSED(query);
223−}
tests/mocks/Unity/fake_scope.h+2−2
@@ -30,7 +30,7 @@ class Scope : public unity::shell::scopes::ScopeInterface
3030
3131public:
3232 Scope(QObject* parent = 0);
33− Scope(QString const& id, QString const& name, bool visible, QObject* parent = 0);
33+ Scope(QString const& id, QString const& name, bool visible, QObject* parent = 0, int categories = 20);
3434
3535 /* getters */
3636 QString id() const override;
@@ -64,7 +64,7 @@ public:
6464 bool hasDepartments() const override;
6565 Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
6666 Q_INVOKABLE void loadDepartment(const QString& id) override;
67− Q_INVOKABLE void performQuery(const QString& query) override;
67+ Q_SIGNAL void performQuery(const QString& query) override;
6868
6969 QVariantMap customizations() const override;
7070
tests/mocks/Unity/fake_scopes.cpp+1
@@ -46,6 +46,7 @@ void Scopes::updateScopes()
4646 addScope(new Scope("MockScope2", "Music", false, this));
4747 addScope(new Scope("clickscope", "Apps", true, this));
4848 addScope(new Scope("MockScope5", "Videos", true, this));
49+ addScope(new Scope("SingleCategoryScope", "Single", true, this, 1));
4950
5051 if (!m_loaded) {
5152 m_loaded = true;
tests/plugins/Dash/tst_ScopeStyle.qml+27−2
@@ -36,8 +36,8 @@ Rectangle {
3636 property var styles: [
3737 {},
3838 { "foreground-color": "red", "background-color": "black", "page-header": { "logo": "/foo/bar" } },
39− { "foreground-color": "green", "background-color": "white" },
40− { "foreground-color": "blue", "background-color": "darkgrey" },
39+ { "foreground-color": "green", "background-color": "white", "page-header": { "foreground-color": "black" } },
40+ { "foreground-color": "blue", "background-color": "darkgrey", "page-header": { "background": "gradient:///white/blue" } },
4141 ]
4242
4343 function cleanup() {
@@ -147,5 +147,30 @@ Rectangle {
147147 tool.style = testCase.styles[data.index];
148148 compare(tool.headerLogo, data.headerLogo, "Header logo was incorrect.");
149149 }
150+
151+ function test_headerForeground_data() {
152+ return [
153+ { tag: "default", index: 0, headerForeground: "grey" },
154+ { tag: "black", index: 2, headerForeground: "black" },
155+ ];
156+ }
157+
158+ function test_headerForeground(data) {
159+ tool.style = testCase.styles[data.index];
160+ verify(Qt.colorEqual(tool.headerForeground, data.headerForeground),
161+ "Header foreground not equal: %1 != %2".arg(tool.headerForeground).arg(data.headerForeground));
162+ }
163+
164+ function test_headerBackground_data() {
165+ return [
166+ { tag: "default", index: 0, headerBackground: "" },
167+ { tag: "black", index: 3, headerBackground: "gradient:///white/blue" },
168+ ];
169+ }
170+
171+ function test_headerBackground(data) {
172+ tool.style = testCase.styles[data.index];
173+ compare(tool.headerBackground, data.headerBackground, "Header background was incorrect.");
174+ }
150175 }
151176}
tests/qmltests/CMakeLists.txt+1−1
@@ -21,10 +21,10 @@ set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
2121
2222add_qml_test(. Shell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
2323add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single-pin")
24+add_qml_test(Components Background)
2425add_qml_test(Components Carousel)
2526add_qml_test(Components DraggingArea)
2627add_qml_test(Components EdgeDemoOverlay)
27−add_qml_test(Components FilterGrid)
2828add_qml_test(Components LazyImage)
2929add_qml_test(Components Rating)
3030add_qml_test(Components ResponsiveFlowView)
tests/qmltests/Components/tst_Background.qmlnew file+90
@@ -0,0 +1,90 @@
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.2
18+import QtTest 1.0
19+import Unity.Test 0.1
20+
21+import "../../../qml/Components"
22+
23+Rectangle {
24+ width: units.gu(40)
25+ height: units.gu(71)
26+
27+ Background {
28+ id: background
29+ }
30+
31+ UnityTestCase {
32+ id: testCase
33+ name: "Background"
34+ when: windowShown
35+
36+ SignalSpy {
37+ id: loadedSpy
38+ target: background
39+ signalName: "loaded"
40+ }
41+
42+ function cleanup() {
43+ background.style = "";
44+ loadedSpy.clear();
45+ }
46+
47+ function test_style_data() {
48+ return [
49+ { tag: "empty", style: "" },
50+ { tag: "solid", style: "color:///black" },
51+ { tag: "gradient", style: "gradient:///black/red" },
52+ { tag: "image", style: "/some/path" },
53+ ];
54+ }
55+
56+ function test_style(data) {
57+ background.style = data.style;
58+ expectFail("empty", "Empty style should not create a background.");
59+ loadedSpy.wait();
60+ compare(background.item.objectName, data.tag, "Background should be %1".arg(data.style));
61+ }
62+
63+ function test_solid() {
64+ background.style = "color:///black";
65+ loadedSpy.wait();
66+
67+ verify(Qt.colorEqual(background.item.color, "black"),
68+ "Solid color not equal: %1 != black".arg(background.item.color));
69+ }
70+
71+ function test_gradient() {
72+ background.style = "gradient:///black/red";
73+ loadedSpy.wait();
74+
75+ var stops = background.item.gradient.stops;
76+
77+ verify(Qt.colorEqual(stops[0].color, "black"),
78+ "Top gradient color not equal: %1 != black".arg(stops[0].color));
79+ verify(Qt.colorEqual(stops[1].color, "red"),
80+ "Bottom gradient color not equal: %1 != black".arg(stops[1].color));
81+ }
82+
83+ function test_image() {
84+ background.style = "/some/path";
85+ loadedSpy.wait();
86+
87+ compare(background.item.source, Qt.resolvedUrl("/some/path"), "Image path is incorrect.");
88+ }
89+ }
90+}
tests/qmltests/Components/tst_FilterGrid.qmldeleted−190
@@ -1,190 +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−import Ubuntu.Components.ListItems 0.1 as ListItem
21−import Ubuntu.Components 0.1
22−import Unity.Test 0.1 as UT
23−import Utils 0.1
24−
25−/*
26− You should see 6 green squares (from "A" to "F") and a button "View all (12)".
27− Once you press that button other 6 green squares (from "G" to "L") should show up.
28−*/
29−Rectangle {
30− width: gridRect.width + controls.width
31− height: units.gu(50)
32− color: "white"
33−
34− Column {
35− id: controls
36− width: units.gu(30)
37− height: parent.height
38− anchors.top: parent.top
39− anchors.right: parent.right
40− ListItem.ValueSelector {
41− id: collapsedRowCountSelector
42− text: "collapsedRowCount"
43− values: [1,2,3,4]
44− selectedIndex: 1
45− }
46− Row {
47− spacing: units.gu(1)
48− Label { anchors.verticalCenter: parent.verticalCenter
49− text: "Filter" }
50− CheckBox {
51− id: filterCheckBox
52− checked: true
53− onCheckedChanged: filterGrid.setFilter(checked, false /*animate*/)
54− }
55− }
56− }
57−
58− ListModel {
59− id: fakeModel
60− ListElement { name: "A" }
61− ListElement { name: "B" }
62− ListElement { name: "C" }
63− ListElement { name: "D" }
64− ListElement { name: "E" }
65− ListElement { name: "F" }
66− ListElement { name: "G" }
67− ListElement { name: "H" }
68− ListElement { name: "I" }
69− ListElement { name: "J" }
70− ListElement { name: "K" }
71− ListElement { name: "L" }
72− }
73−
74− ListModel {
75− id: fakeModelTwoItems
76− ListElement { name: "A" }
77− ListElement { name: "B" }
78− }
79−
80− ListModel {
81− id: fakeModelFourItems
82− ListElement { name: "A" }
83− ListElement { name: "B" }
84− ListElement { name: "C" }
85− ListElement { name: "D" }
86− }
87−
88− Rectangle {
89− id: gridRect
90− width: units.gu(30)
91− height: parent.height
92− color: "grey"
93− anchors.top: parent.top
94− anchors.left: parent.left
95−
96− FilterGrid {
97− id: filterGrid
98− anchors.fill: parent
99− model: fakeModel
100− maximumNumberOfColumns: 3
101− collapsedRowCount:
102− collapsedRowCountSelector.values[collapsedRowCountSelector.selectedIndex]
103− minimumHorizontalSpacing: units.gu(1)
104− delegateWidth: units.gu(6)
105− delegateHeight: units.gu(6)
106− verticalSpacing: units.gu(1)
107−
108− delegate: Rectangle {
109− // So that it can be identified by countVisibleDelegates()
110− property bool isGridDelegate: true
111−
112− color: "green"
113− width: units.gu(6)
114− height: units.gu(6)
115− Text {
116− anchors.centerIn: parent
117− text: name
118− }
119− }
120− }
121− }
122−
123− UT.UnityTestCase {
124− name: "FilterGrid"
125− when: windowShown
126−
127− function init() {
128− filterGrid.model = fakeModel
129− }
130−
131− function cleanup() {
132− filterCheckBox.checked = true
133− collapsedRowCountSelector.selectedIndex = 1
134− }
135−
136− function test_turningFilterOffShowsAllElements() {
137− tryCompareFunction(countVisibleDelegates, 6)
138−
139− filterCheckBox.checked = false
140−
141− tryCompareFunction(countVisibleDelegates, 12)
142− }
143−
144− function test_collapsedRowCount() {
145− for (var i = 0; i < 4; ++i) {
146− collapsedRowCountSelector.selectedIndex = i
147− // We have 3 elements per row.
148− // row count == index + 1
149− tryCompareFunction(countVisibleDelegates, 3*(i+1))
150− }
151− }
152−
153− function test_modelSizeAffectsCollapsedRowCount_data() {
154− return [
155− { tag: "2 items, collapsedRows 1", model: fakeModelTwoItems, collapsedRowCountIndex: 0,
156− rowsWhenCollapsed: 1, visibleDelegates: 2 },
157− { tag: "2 items, collapsedRows 2", model: fakeModelTwoItems, collapsedRowCountIndex: 1,
158− rowsWhenCollapsed: 1, visibleDelegates: 2 },
159− { tag: "4 items, collapsedRows 1", model: fakeModelFourItems, collapsedRowCountIndex: 0,
160− rowsWhenCollapsed: 1, visibleDelegates: 3 },
161− { tag: "4 items, collapsedRows 2", model: fakeModelFourItems, collapsedRowCountIndex: 1,
162− rowsWhenCollapsed: 2, visibleDelegates: 4 },
163− ]
164− }
165−
166− function test_modelSizeAffectsCollapsedRowCount(data) {
167− filterGrid.model = data.model
168− collapsedRowCountSelector.selectedIndex = data.collapsedRowCountIndex
169−
170− tryCompare(filterGrid, "rowsWhenCollapsed", data.rowsWhenCollapsed)
171− tryCompareFunction(countVisibleDelegates, data.visibleDelegates)
172− }
173−
174− function countVisibleDelegates() {
175− return __countVisibleDelegates(filterGrid.visibleChildren, 0)
176− }
177−
178− function __countVisibleDelegates(objList, total) {
179− for (var i = 0; i < objList.length; ++i) {
180− var child = objList[i];
181− if (child.isGridDelegate !== undefined) {
182− ++total;
183− } else {
184− total = __countVisibleDelegates(child.visibleChildren, total)
185− }
186− }
187− return total
188− }
189− }
190−}
tests/qmltests/Dash/tst_Dash.qml+1−1
@@ -86,7 +86,7 @@ Item {
8686 tryCompare(dashContentList, "count", 0);
8787 scopes.load();
8888 tryCompare(scopes, "loaded", true);
89− tryCompare(dashContentList, "count", 3);
89+ tryCompare(dashContentList, "count", 4);
9090
9191 verify(dashContentList != undefined);
9292 tryCompare(dashContentList, "currentIndex", data.visualIndex);
tests/qmltests/Dash/tst_DashContent.qml+15−6
@@ -61,6 +61,11 @@ Item {
6161 signalName: "movementStarted"
6262 }
6363
64+ SignalSpy {
65+ id: loadedSpy
66+ signalName: "loaded"
67+ }
68+
6469 UT.UnityTestCase {
6570 name: "DashContent"
6671 when: scopesModel.loaded && windowShown
@@ -78,6 +83,7 @@ Item {
7883
7984 function cleanup() {
8085 movementStartedSpy.clear();
86+ loadedSpy.clear();
8187 dashContent.visible = true;
8288
8389 var dashContentList = findChild(dashContent, "dashContentList");
@@ -116,10 +122,11 @@ Item {
116122
117123 function test_show_header_on_list_movement() {
118124 var dashContentList = findChild(dashContent, "dashContentList");
119− verify(dashContentList != undefined);
120− var categoryListView = findChild(dashContentList, "categoryListView");
121− verify(categoryListView != undefined);
125+ verify(dashContentList !== null);
126+ var scope = findChild(dashContent, "MockScope1 loader");
127+ waitForRendering(scope);
122128
129+ var categoryListView = findChild(scope, "categoryListView");
123130 waitForRendering(categoryListView);
124131
125132 categoryListView.contentY = units.gu(15);
@@ -133,10 +140,12 @@ Item {
133140
134141 function test_set_current_scope_reset() {
135142 var dashContentList = findChild(dashContent, "dashContentList");
136− verify(dashContentList != undefined);
137− var categoryListView = findChild(dashContentList, "categoryListView");
138− verify(categoryListView != undefined);
143+ verify(dashContentList, "Couldn't find dashContentList");
144+ var scope = findChild(dashContent, "MockScope1 loader");
139145
146+ tryCompare(scope, "status", Loader.Ready);
147+
148+ var categoryListView = findChild(dashContentList, "categoryListView");
140149 categoryListView.contentY = units.gu(10);
141150
142151 compare(dashContentList.currentItem.item.objectName, "MockScope1")
tests/qmltests/Dash/tst_GenericScopeView.qml+137−49
@@ -39,6 +39,10 @@ Item {
3939 id: scopes
4040 }
4141
42+ SignalSpy {
43+ id: spy
44+ }
45+
4246 property Item applicationManager: Item {
4347 signal sideStageFocusedApplicationChanged()
4448 signal mainStageFocusedApplicationChanged()
@@ -54,12 +58,20 @@ Item {
5458 when: scopes.loaded && windowShown
5559
5660 property Item previewListView: findChild(genericScopeView, "previewListView")
61+ property Item header: findChild(genericScopeView, "scopePageHeader")
5762
5863 function init() {
5964 genericScopeView.scope = scopes.getScope(1)
6065 shell.width = units.gu(120)
6166 genericScopeView.categoryView.positionAtBeginning();
62− tryCompare(genericScopeView.categoryView, "contentY", 0)
67+ waitForRendering(genericScopeView.categoryView);
68+ }
69+
70+ function cleanup() {
71+ genericScopeView.scope = null;
72+ spy.clear();
73+ spy.target = null;
74+ spy.signalName = "";
6375 }
6476
6577 function test_isActive() {
@@ -104,90 +116,146 @@ Item {
104116 tryCompare(genericScopeView.scope, "searchQuery", "test")
105117 }
106118
107− function test_filter_expand_collapse() {
108− // wait for the item to be there
109− waitForRendering(genericScopeView);
119+ function test_expand_collapse() {
110120 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0") != null; }, true);
111121
112− var header = findChild(genericScopeView, "dashSectionHeader0")
113122 var category = findChild(genericScopeView, "dashCategory0")
123+ var seeAll = findChild(category, "seeAll")
114124
115− waitForRendering(header);
125+ waitForRendering(seeAll);
116126 verify(category.expandable);
117− verify(category.filtered);
127+ verify(!category.expanded);
118128
119129 var initialHeight = category.height;
120− var middleHeight;
121− mouseClick(header, header.width / 2, header.height / 2);
122− tryCompareFunction(function() { middleHeight = category.height; return category.height > initialHeight; }, true);
123− tryCompare(category, "filtered", false);
124− tryCompareFunction(function() { return category.height > middleHeight; }, true);
130+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
131+ verify(category.expanded);
132+ tryCompareFunction(function() { return category.height > initialHeight; }, true);
125133
126− mouseClick(header, header.width / 2, header.height / 2);
127− verify(category.expandable);
128− tryCompare(category, "filtered", true);
134+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
135+ verify(!category.expanded);
129136 }
130137
131− function test_filter_expand_expand_collapse() {
138+ function test_expand_expand_collapse() {
132139 // wait for the item to be there
133140 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader2") != null; }, true);
134141
135142 var categoryListView = findChild(genericScopeView, "categoryListView");
136143 categoryListView.contentY = categoryListView.height;
137144
138− var header2 = findChild(genericScopeView, "dashSectionHeader2")
139145 var category2 = findChild(genericScopeView, "dashCategory2")
140− var category2FilterGrid = category2.children[1].children[2];
141− verify(UT.Util.isInstanceOf(category2FilterGrid, "CardFilterGrid"));
146+ var seeAll2 = findChild(category2, "seeAll")
142147
143− waitForRendering(header2);
148+ waitForRendering(seeAll2);
144149 verify(category2.expandable);
145− verify(category2.filtered);
150+ verify(!category2.expanded);
146151
147− mouseClick(header2, header2.width / 2, header2.height / 2);
148− tryCompare(category2, "filtered", false);
149− tryCompare(category2FilterGrid, "filtered", false);
152+ mouseClick(seeAll2, seeAll2.width / 2, seeAll2.height / 2);
153+ tryCompare(category2, "expanded", true);
150154
151155 categoryListView.positionAtBeginning();
152156
153− var header0 = findChild(genericScopeView, "dashSectionHeader0")
154157 var category0 = findChild(genericScopeView, "dashCategory0")
155− mouseClick(header0, header0.width / 2, header0.height / 2);
156− tryCompare(category0, "filtered", false);
157− tryCompare(category2, "filtered", true);
158− tryCompare(category2FilterGrid, "filtered", true);
159− mouseClick(header0, header0.width / 2, header0.height / 2);
160− tryCompare(category0, "filtered", true);
161− tryCompare(category2, "filtered", true);
158+ var seeAll0 = findChild(category0, "seeAll")
159+ mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
160+ tryCompare(category0, "expanded", true);
161+ tryCompare(category2, "expanded", false);
162+ mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
163+ tryCompare(category0, "expanded", false);
164+ tryCompare(category2, "expanded", false);
165+ }
166+
167+ function test_headerLink() {
168+ tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader1") != null; }, true);
169+ var header = findChild(genericScopeView, "dashSectionHeader1");
170+
171+ spy.target = genericScopeView.scope;
172+ spy.signalName = "performQuery";
173+
174+ mouseClick(header, header.width / 2, header.height / 2);
175+
176+ spy.wait();
177+ compare(spy.signalArguments[0][0], genericScopeView.scope.categories.data(1, Categories.RoleHeaderLink));
178+ }
179+
180+ function test_headerLink_disable_expansion() {
181+ var categoryListView = findChild(genericScopeView, "categoryListView");
182+ waitForRendering(categoryListView);
183+
184+ categoryListView.contentY = categoryListView.height * 2;
185+
186+ // wait for the item to be there
187+ tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader4") != null; }, true);
188+
189+ var categoryView = findChild(genericScopeView, "dashCategory4");
190+ verify(categoryView, "Can't find the category view.");
191+
192+ var seeAll = findChild(categoryView, "seeAll");
193+ verify(seeAll, "Can't find the seeAll element");
194+
195+ compare(seeAll.height, 0, "SeeAll should be 0-height.");
196+
197+ openPreview(4, 0);
198+
199+ compare(testCase.previewListView.count, 12, "There should only be 12 items in preview.");
162200 }
163201
164202 function test_narrow_delegate_ranges_expand() {
165− tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") != undefined; }, true);
203+ tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") !== null; }, true);
166204 var category = findChild(genericScopeView, "dashCategory0")
167− tryCompare(category, "filtered", true);
205+ tryCompare(category, "expanded", false);
168206
169207 shell.width = units.gu(20)
170208 var categoryListView = findChild(genericScopeView, "categoryListView");
171209 categoryListView.contentY = units.gu(20);
172− var header0 = findChild(genericScopeView, "dashSectionHeader0")
173− mouseClick(header0, header0.width / 2, header0.height / 2);
174− tryCompare(category, "filtered", false);
210+ var seeAll = findChild(category, "seeAll")
211+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
212+ tryCompare(category, "expanded", true);
175213 tryCompareFunction(function() { return category.item.height == genericScopeView.height - category.item.displayMarginBeginning - category.item.displayMarginEnd; }, true);
176− mouseClick(header0, header0.width / 2, header0.height / 2);
177− tryCompare(category, "filtered", true);
214+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
215+ tryCompare(category, "expanded", false);
216+ }
217+
218+ function test_forced_category_expansion() {
219+ tryCompareFunction(function() {
220+ mouseFlick(genericScopeView, genericScopeView.width/2, genericScopeView.height,
221+ genericScopeView.width/2, genericScopeView.y)
222+ return findChild(genericScopeView, "dashCategory19") !== null;
223+ }, true);
224+ var category = findChild(genericScopeView, "dashCategory19")
225+ compare(category.expandable, false, "Category with collapsed-rows: 0 should not be expandable");
226+
227+ var grid = findChild(category, "19");
228+ verify(grid, "Could not find the category renderer.");
229+
230+ compare(grid.height, grid.expandedHeight, "Category with collapsed-rows: 0 should always be expanded.");
231+ }
232+
233+ function test_single_category_expansion() {
234+ genericScopeView.scope = scopes.getScope(4);
235+
236+ tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") != undefined; }, true);
237+ var category = findChild(genericScopeView, "dashCategory0")
238+ compare(category.expandable, false, "Only category should not be expandable.");
239+
240+ var grid = findChild(category, "0");
241+ verify(grid, "Could not find the category renderer.");
242+
243+ compare(grid.height, grid.expandedHeight, "Only category should always be expanded");
178244 }
179245
180− function openPreview() {
246+ function openPreview(category, delegate) {
247+ if (category === undefined) category = 0;
248+ if (delegate === undefined) delegate = 0;
181249 tryCompareFunction(function() {
182− var filterGrid = findChild(genericScopeView, "0");
183− if (filterGrid != null) {
184− var tile = findChild(filterGrid, "delegate0");
250+ var cardGrid = findChild(genericScopeView, category);
251+ if (cardGrid != null) {
252+ var tile = findChild(cardGrid, "delegate"+delegate);
185253 return tile != null;
186254 }
187255 return false;
188256 },
189257 true);
190− var tile = findChild(findChild(genericScopeView, "0"), "delegate0");
258+ var tile = findChild(findChild(genericScopeView, category), "delegate"+delegate);
191259 mouseClick(tile, tile.width / 2, tile.height / 2);
192260 tryCompare(testCase.previewListView, "open", true);
193261 tryCompare(testCase.previewListView, "x", 0);
@@ -257,13 +325,33 @@ Item {
257325 closePreview();
258326 }
259327
260− function test_haeder_logo() {
261− genericScopeView.scope = scopes.getScope(3);
328+ function test_header_style_data() {
329+ return [
330+ { tag: "Default", index: 0, foreground: "grey", background: "", logo: "" },
331+ { tag: "Foreground", index: 2, foreground: "yellow", background: "", logo: "" },
332+ { tag: "Logo+Background", index: 3, foreground: "grey", background: "gradient:///lightgrey/grey",
333+ logo: Qt.resolvedUrl("../Components/tst_PageHeader/logo-ubuntu-orange.svg") },
334+ ];
335+ }
262336
263− var image = findChild(genericScopeView, "titleImage");
264− verify(image, "Could not find the title image");
265− compare(image.source, Qt.resolvedUrl("../Components/tst_PageHeader/logo-ubuntu-orange.svg"), "Title image has the wrong source");
337+ function test_header_style(data) {
338+ genericScopeView.scope = scopes.getScope(data.index);
339+ waitForRendering(genericScopeView);
340+ verify(header, "Could not find the header.");
341+
342+ var innerHeader = findChild(header, "innerPageHeader");
343+ verify(innerHeader, "Could not find the inner header");
344+ verify(Qt.colorEqual(innerHeader.textColor, data.foreground),
345+ "Foreground color not equal: %1 != %2".arg(innerHeader.textColor).arg(data.foreground));
266346
347+ var background = findChild(header, "headerBackground");
348+ verify(background, "Could not find the background");
349+ compare(background.style, data.background);
350+
351+ var image = findChild(genericScopeView, "titleImage");
352+ if (data.logo == "") expectFail(data.tag, "Title image should not exist.");
353+ verify(image, "Could not find the title image.");
354+ compare(image.source, data.logo, "Title image has the wrong source");
267355 }
268356 }
269357 }