on xenial help sign in
Merge from trunk
3955a4bMichael Terry
tests/autopilot/.project → .projectrenamed+1−1
@@ -1,6 +1,6 @@
1<?xml version="1.0" encoding="UTF-8"?>
1<?xml version="1.0" encoding="UTF-8"?>
2<projectDescription>
2<projectDescription>
3− <name>Unity8 Autopilot</name>
3+ <name>Unity8</name>
4 <comment></comment>
4 <comment></comment>
5 <projects>
5 <projects>
6 </projects>
6 </projects>
tests/autopilot/.pydevproject → .pydevprojectrenamed+3−1
@@ -1,7 +1,9 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<?eclipse-pydev version="1.0"?><pydev_project>
2<?eclipse-pydev version="1.0"?><pydev_project>
3<pydev_pathproperty name="org.python.pydev.PROJECT_SOURCE_PATH">
3<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>
5</pydev_pathproperty>
7</pydev_pathproperty>
6<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
8<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
7<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
9<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+
1unity8 (7.90+14.10.20140723.4-0ubuntu1) utopic; urgency=low
37unity8 (7.90+14.10.20140723.4-0ubuntu1) utopic; urgency=low
2
38
3 [ thomas-voss ]
39 [ thomas-voss ]
debian/control+1−1
@@ -113,7 +113,7 @@ Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
113 unity-application-impl-2,
113 unity-application-impl-2,
114 unity-notifications-impl-3,
114 unity-notifications-impl-3,
115 unity-plugin-scopes | unity-scopes-impl,
115 unity-plugin-scopes | unity-scopes-impl,
116− unity-scopes-impl-0,
116+ unity-scopes-impl-2,
117 unity8-fake-env | unity-application-impl,
117 unity8-fake-env | unity-application-impl,
118 ${misc:Depends},
118 ${misc:Depends},
119Breaks: unity8 (<< 7.86),
119Breaks: unity8 (<< 7.86),
plugins/Dash/ScopeStyle.qml+6
@@ -70,6 +70,12 @@ QtObject {
70 /// Source of the logo image for the header
70 /// Source of the logo image for the header
71 readonly property url headerLogo: "logo" in d.headerStyle ? d.headerStyle["logo"] : ""
71 readonly property url headerLogo: "logo" in d.headerStyle ? d.headerStyle["logo"] : ""
72
72
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+
73 //! @cond
79 //! @cond
74 property var d: QtObject {
80 property var d: QtObject {
75 readonly property real foregroundLuminance: luminance(foreground)
81 readonly property real foregroundLuminance: luminance(foreground)
plugins/Dash/listviewwithpageheader.cpp−5
@@ -141,8 +141,6 @@ void ListViewWithPageHeader::ListItem::setCulled(bool culled)
141void ListViewWithPageHeader::ListItem::setSectionItem(QQuickItem *sectionItem)
141void ListViewWithPageHeader::ListItem::setSectionItem(QQuickItem *sectionItem)
142{
142{
143 m_sectionItem = sectionItem;
143 m_sectionItem = sectionItem;
144− QQmlContext *context = QQmlEngine::contextForObject(m_item)->parentContext();
145− context->setContextProperty(QLatin1String("hasSectionHeader"), QVariant::fromValue<bool>(sectionItem != nullptr));
146}
144}
147
145
148ListViewWithPageHeader::ListViewWithPageHeader()
146ListViewWithPageHeader::ListViewWithPageHeader()
@@ -685,8 +683,6 @@ QQuickItem *ListViewWithPageHeader::getSectionItem(int modelIndex, bool alreadyI
685 return nullptr;
683 return nullptr;
686
684
687 const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
685 const QString section = m_delegateModel->stringValue(modelIndex, m_sectionProperty);
688− if (section.isEmpty())
689− return nullptr;
690
686
691 if (modelIndex > 0) {
687 if (modelIndex > 0) {
692 const QString prevSection = m_delegateModel->stringValue(modelIndex - 1, m_sectionProperty);
688 const QString prevSection = m_delegateModel->stringValue(modelIndex - 1, m_sectionProperty);
@@ -877,7 +873,6 @@ void ListViewWithPageHeader::itemCreated(int modelIndex, QObject *object)
877 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
873 QQmlContext *context = QQmlEngine::contextForObject(item)->parentContext();
878 context->setContextProperty(QLatin1String("ListViewWithPageHeader"), this);
874 context->setContextProperty(QLatin1String("ListViewWithPageHeader"), this);
879 context->setContextProperty(QLatin1String("heightToClip"), QVariant::fromValue<int>(0));
875 context->setContextProperty(QLatin1String("heightToClip"), QVariant::fromValue<int>(0));
880− context->setContextProperty(QLatin1String("hasSectionHeader"), QVariant::fromValue<bool>(false));
881 if (modelIndex == m_asyncRequestedIndex) {
876 if (modelIndex == m_asyncRequestedIndex) {
882 createItem(modelIndex, false);
877 createItem(modelIndex, false);
883 refill();
878 refill();
plugins/Unity/Launcher/launchermodel.cpp+3−2
@@ -141,7 +141,8 @@ void LauncherModel::pin(const QString &appId, int index)
141 beginInsertRows(QModelIndex(), index, index);
141 beginInsertRows(QModelIndex(), index, index);
142 LauncherItem *item = new LauncherItem(appId,
142 LauncherItem *item = new LauncherItem(appId,
143 m_backend->displayName(appId),
143 m_backend->displayName(appId),
144− m_backend->icon(appId));
144+ m_backend->icon(appId),
145+ this);
145 item->setPinned(true);
146 item->setPinned(true);
146 m_list.insert(index, item);
147 m_list.insert(index, item);
147 endInsertRows();
148 endInsertRows();
@@ -326,7 +327,7 @@ void LauncherModel::applicationAdded(const QModelIndex &parent, int row)
326 if (found) {
327 if (found) {
327 // Shall we paint some running/recent app highlight? If yes, do it here.
328 // Shall we paint some running/recent app highlight? If yes, do it here.
328 } else {
329 } 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);
330 item->setRecent(true);
331 item->setRecent(true);
331 item->setFocused(app->focused());
332 item->setFocused(app->focused());
332
333
po/gd.po+3−3
@@ -8,13 +8,13 @@ msgstr ""
8"Project-Id-Version: unity8\n"
8"Project-Id-Version: unity8\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-07-07 12:15+0100\n"
10"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"
12"Last-Translator: GunChleoc <Unknown>\n"
12"Last-Translator: GunChleoc <Unknown>\n"
13"Language-Team: Fòram na Gàidhlig http://www.foramnagaidhlig.net\n"
13"Language-Team: Fòram na Gàidhlig http://www.foramnagaidhlig.net\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"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"
18"X-Generator: Launchpad (build 17114)\n"
18"X-Generator: Launchpad (build 17114)\n"
19"Language: gd\n"
19"Language: gd\n"
20
20
@@ -87,7 +87,7 @@ msgstr "Gairm èiginn"
87
87
88#: qml/Components/Lockscreen.qml:231
88#: qml/Components/Lockscreen.qml:231
89msgid "OK"
89msgid "OK"
90−msgstr "Ceart ma-hà"
90+msgstr "Ceart ma-thà"
91
91
92#: qml/Components/PageHeader.qml:366
92#: qml/Components/PageHeader.qml:366
93msgid "Recent searches"
93msgid "Recent searches"
po/hu.po+11−9
@@ -8,23 +8,23 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-07-07 12:15+0100\n"
10"POT-Creation-Date: 2014-07-07 12:15+0100\n"
11−"PO-Revision-Date: 2014-07-23 10:07+0000\n"
11+"PO-Revision-Date: 2014-07-24 08:19+0000\n"
12−"Last-Translator: Úr Balázs <urbalazs@gmail.com>\n"
12+"Last-Translator: Gabor Kelemen <kelemeng@openscope.org>\n"
13"Language-Team: Hungarian <hu@li.org>\n"
13"Language-Team: Hungarian <hu@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"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"
18"X-Generator: Launchpad (build 17114)\n"
18"X-Generator: Launchpad (build 17114)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
22msgid "Pin shortcut"
22msgid "Pin shortcut"
23−msgstr ""
23+msgstr "Indító rögzítése"
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
26msgid "Unpin shortcut"
26msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "Indító feloldása"
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
@@ -73,6 +73,8 @@ msgid ""
73"You have now mastered the edge gestures and can start using the "
73"You have now mastered the edge gestures and can start using the "
74"phone<br><br>Tap on the screen to start"
74"phone<br><br>Tap on the screen to start"
75msgstr ""
75msgstr ""
76+"Elsajátította a gesztusokat, és megkezdheti a telefon "
77+"használatát.<br><br>Koppintson a képernyőre a kezdéshez."
76
78
77#: qml/Components/Lockscreen.qml:214
79#: qml/Components/Lockscreen.qml:214
78msgid "Emergency Call"
80msgid "Emergency Call"
@@ -105,11 +107,11 @@ msgstr "KÉSZ"
105
107
106#: qml/Components/SeeMore.qml:35
108#: qml/Components/SeeMore.qml:35
107msgid "See more"
109msgid "See more"
108−msgstr ""
110+msgstr "Több"
109
111
110#: qml/Components/SeeMore.qml:58
112#: qml/Components/SeeMore.qml:58
111msgid "See less"
113msgid "See less"
112−msgstr ""
114+msgstr "Kevesebb"
113
115
114#: qml/Dash/DashApps.qml:37
116#: qml/Dash/DashApps.qml:37
115msgid "Recent"
117msgid "Recent"
@@ -137,7 +139,7 @@ msgstr "Küldés"
137
139
138#: qml/Greeter/Greeter.qml:157
140#: qml/Greeter/Greeter.qml:157
139msgid "Swipe to unlock"
141msgid "Swipe to unlock"
140−msgstr ""
142+msgstr "Csúsztasson a feloldáshoz"
141
143
142#: qml/Hud/HudParametrizedActionsPage.qml:132
144#: qml/Hud/HudParametrizedActionsPage.qml:132
143msgid "Confirm"
145msgid "Confirm"
@@ -169,7 +171,7 @@ msgstr "Adja meg a SIM PIN kódját"
169
171
170#: qml/Panel/Indicators/MenuItemFactory.qml:583
172#: qml/Panel/Indicators/MenuItemFactory.qml:583
171msgid "In queue…"
173msgid "In queue…"
172−msgstr ""
174+msgstr "Sorban…"
173
175
174#: qml/Panel/Indicators/MenuItemFactory.qml:587
176#: qml/Panel/Indicators/MenuItemFactory.qml:587
175msgid "Downloading"
177msgid "Downloading"
po/sl.po+11−11
@@ -8,23 +8,23 @@ msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-07-07 12:15+0100\n"
10"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"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
12"Last-Translator: Damir Jerovšek <Unknown>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
13"Language-Team: Slovenian <sl@li.org>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"Content-Transfer-Encoding: 8bit\n"
17−"X-Launchpad-Export-Date: 2014-07-09 06:37+0000\n"
17+"X-Launchpad-Export-Date: 2014-07-25 07:54+0000\n"
18−"X-Generator: Launchpad (build 17100)\n"
18+"X-Generator: Launchpad (build 17114)\n"
19
19
20#: plugins/Unity/Launcher/launcheritem.cpp:43
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
21#: plugins/Unity/Launcher/launcheritem.cpp:73
22msgid "Pin shortcut"
22msgid "Pin shortcut"
23−msgstr ""
23+msgstr "Pripni bližnjico"
24
24
25#: plugins/Unity/Launcher/launcheritem.cpp:73
25#: plugins/Unity/Launcher/launcheritem.cpp:73
26msgid "Unpin shortcut"
26msgid "Unpin shortcut"
27−msgstr ""
27+msgstr "Odpni bližnjico"
28
28
29#: qml/Components/EdgeDemoOverlay.qml:151
29#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
30msgid "Skip intro"
@@ -171,27 +171,27 @@ msgstr "Vnesite PIN kartice SIM"
171
171
172#: qml/Panel/Indicators/MenuItemFactory.qml:583
172#: qml/Panel/Indicators/MenuItemFactory.qml:583
173msgid "In queue…"
173msgid "In queue…"
174−msgstr ""
174+msgstr "V vrsti ..."
175
175
176#: qml/Panel/Indicators/MenuItemFactory.qml:587
176#: qml/Panel/Indicators/MenuItemFactory.qml:587
177msgid "Downloading"
177msgid "Downloading"
178−msgstr ""
178+msgstr "Prejemanje"
179
179
180#: qml/Panel/Indicators/MenuItemFactory.qml:589
180#: qml/Panel/Indicators/MenuItemFactory.qml:589
181msgid "Paused, tap to resume"
181msgid "Paused, tap to resume"
182−msgstr ""
182+msgstr "Premor, tapnite za nadaljevanje"
183
183
184#: qml/Panel/Indicators/MenuItemFactory.qml:591
184#: qml/Panel/Indicators/MenuItemFactory.qml:591
185msgid "Canceled"
185msgid "Canceled"
186−msgstr ""
186+msgstr "Preklicano"
187
187
188#: qml/Panel/Indicators/MenuItemFactory.qml:593
188#: qml/Panel/Indicators/MenuItemFactory.qml:593
189msgid "Finished"
189msgid "Finished"
190−msgstr ""
190+msgstr "Končano"
191
191
192#: qml/Panel/Indicators/MenuItemFactory.qml:595
192#: qml/Panel/Indicators/MenuItemFactory.qml:595
193msgid "Failed, tap to retry"
193msgid "Failed, tap to retry"
194−msgstr ""
194+msgstr "Spodletelo, tapnite za ponovni poskus"
195
195
196#: qml/Panel/SearchIndicator.qml:27
196#: qml/Panel/SearchIndicator.qml:27
197msgid "Search"
197msgid "Search"
po/sv.po+19−18
@@ -1,21 +1,22 @@
1# Swedish translation for unity
1# 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
3# This file is distributed under the same license as the unity package.
3# 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.
5#
5#
6msgid ""
6msgid ""
7msgstr ""
7msgstr ""
8"Project-Id-Version: unity\n"
8"Project-Id-Version: unity\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
9"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
10"POT-Creation-Date: 2014-07-07 12:15+0100\n"
10"POT-Creation-Date: 2014-07-07 12:15+0100\n"
11−"PO-Revision-Date: 2014-07-20 19:14+0000\n"
11+"PO-Revision-Date: 2014-07-24 13:56+0000\n"
12−"Last-Translator: Gunnar Hjalmarsson <Unknown>\n"
12+"Last-Translator: Josef Andersson <Unknown>\n"
13−"Language-Team: Swedish <sv@li.org>\n"
13+"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
14"MIME-Version: 1.0\n"
14"MIME-Version: 1.0\n"
15"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Type: text/plain; charset=UTF-8\n"
16"Content-Transfer-Encoding: 8bit\n"
16"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"
18"X-Generator: Launchpad (build 17114)\n"
18"X-Generator: Launchpad (build 17114)\n"
19+"Language: sv\n"
19
20
20#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:43
21#: plugins/Unity/Launcher/launcheritem.cpp:73
22#: plugins/Unity/Launcher/launcheritem.cpp:73
@@ -28,7 +29,7 @@ msgstr "Släpp genväg"
28
29
29#: qml/Components/EdgeDemoOverlay.qml:151
30#: qml/Components/EdgeDemoOverlay.qml:151
30msgid "Skip intro"
31msgid "Skip intro"
31−msgstr "Skippa intro"
32+msgstr "Hoppa över introduktion"
32
33
33#: qml/Components/EdgeDemo.qml:113
34#: qml/Components/EdgeDemo.qml:113
34msgid "Right edge"
35msgid "Right edge"
@@ -36,7 +37,7 @@ msgstr "Högerkant"
36
37
37#: qml/Components/EdgeDemo.qml:114
38#: qml/Components/EdgeDemo.qml:114
38msgid "Try swiping from the right edge to unlock the phone"
39msgid "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"
40
41
41#: qml/Components/EdgeDemo.qml:145
42#: qml/Components/EdgeDemo.qml:145
42msgid "Top edge"
43msgid "Top edge"
@@ -71,8 +72,8 @@ msgid ""
71"You have now mastered the edge gestures and can start using the "
72"You have now mastered the edge gestures and can start using the "
72"phone<br><br>Tap on the screen to start"
73"phone<br><br>Tap on the screen to start"
73msgstr ""
74msgstr ""
74−"Du har nu bemästrat kantgesterna och kan börja använda telefonen<br><br>Peka "
75+"Du har nu bemästrat kantgesterna och kan börja använda "
75−"på skärmen för att starta"
76+"telefonen<br><br>Tryck på skärmen för att starta"
76
77
77#: qml/Components/Lockscreen.qml:214
78#: qml/Components/Lockscreen.qml:214
78msgid "Emergency Call"
79msgid "Emergency Call"
@@ -117,11 +118,11 @@ msgstr "Senaste"
117
118
118#: qml/Dash/Previews/PreviewActionCombo.qml:34
119#: qml/Dash/Previews/PreviewActionCombo.qml:34
119msgid "More..."
120msgid "More..."
120−msgstr "Mer..."
121+msgstr "Mer…"
121
122
122#: qml/Dash/Previews/PreviewActionCombo.qml:34
123#: qml/Dash/Previews/PreviewActionCombo.qml:34
123msgid "Less..."
124msgid "Less..."
124−msgstr "Mindre..."
125+msgstr "Mindre…"
125
126
126#: qml/Dash/Previews/PreviewRatingInput.qml:82
127#: qml/Dash/Previews/PreviewRatingInput.qml:82
127msgid "Rate this"
128msgid "Rate this"
@@ -149,15 +150,15 @@ msgstr "Skriv eller tala in ett kommando"
149
150
150#: qml/Hud/Hud.qml:84
151#: qml/Hud/Hud.qml:84
151msgid "Loading. Please Wait..."
152msgid "Loading. Please Wait..."
152−msgstr "Laddar. Var god vänta..."
153+msgstr "Läser in. Var god vänta…"
153
154
154#: qml/Hud/Hud.qml:89
155#: qml/Hud/Hud.qml:89
155msgid "Speak Now..."
156msgid "Speak Now..."
156−msgstr "Tala nu..."
157+msgstr "Tala nu…"
157
158
158#: qml/Hud/Hud.qml:94
159#: qml/Hud/Hud.qml:94
159msgid "Speaking..."
160msgid "Speaking..."
160−msgstr "Talar..."
161+msgstr "Talar…"
161
162
162#: qml/Notifications/NotificationMenuItemFactory.qml:91
163#: qml/Notifications/NotificationMenuItemFactory.qml:91
163msgid "Show password"
164msgid "Show password"
@@ -169,7 +170,7 @@ msgstr "Ange SIM PIN-kod"
169
170
170#: qml/Panel/Indicators/MenuItemFactory.qml:583
171#: qml/Panel/Indicators/MenuItemFactory.qml:583
171msgid "In queue…"
172msgid "In queue…"
172−msgstr "I kö..."
173+msgstr "I kö…"
173
174
174#: qml/Panel/Indicators/MenuItemFactory.qml:587
175#: qml/Panel/Indicators/MenuItemFactory.qml:587
175msgid "Downloading"
176msgid "Downloading"
@@ -177,7 +178,7 @@ msgstr "Hämtar"
177
178
178#: qml/Panel/Indicators/MenuItemFactory.qml:589
179#: qml/Panel/Indicators/MenuItemFactory.qml:589
179msgid "Paused, tap to resume"
180msgid "Paused, tap to resume"
180−msgstr "Pausad, peka för att fortsätta"
181+msgstr "Pausad, tryck för att fortsätta"
181
182
182#: qml/Panel/Indicators/MenuItemFactory.qml:591
183#: qml/Panel/Indicators/MenuItemFactory.qml:591
183msgid "Canceled"
184msgid "Canceled"
@@ -189,7 +190,7 @@ msgstr "Klart"
189
190
190#: qml/Panel/Indicators/MenuItemFactory.qml:595
191#: qml/Panel/Indicators/MenuItemFactory.qml:595
191msgid "Failed, tap to retry"
192msgid "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"
193
194
194#: qml/Panel/SearchIndicator.qml:27
195#: qml/Panel/SearchIndicator.qml:27
195msgid "Search"
196msgid "Search"
po/unity8.pot+17−9
@@ -8,7 +8,7 @@ msgid ""
8msgstr ""
8msgstr ""
9"Project-Id-Version: unity8\n"
9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"
10"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"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -80,10 +80,6 @@ msgstr ""
80msgid "OK"
80msgid "OK"
81msgstr ""
81msgstr ""
82
82
83−#: qml/Components/PageHeader.qml:366
84−msgid "Recent searches"
85−msgstr ""
86−
87#: qml/Components/PassphraseLockscreen.qml:60
83#: qml/Components/PassphraseLockscreen.qml:60
88#, qt-format
84#, qt-format
89msgid "Hello %1"
85msgid "Hello %1"
@@ -105,7 +101,7 @@ msgstr ""
105msgid "See more"
101msgid "See more"
106msgstr ""
102msgstr ""
107
103
108−#: qml/Components/SeeMore.qml:58
104+#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
109msgid "See less"
105msgid "See less"
110msgstr ""
106msgstr ""
111
107
@@ -113,6 +109,10 @@ msgstr ""
113msgid "Recent"
109msgid "Recent"
114msgstr ""
110msgstr ""
115
111
112+#: qml/Dash/GenericScopeView.qml:330
113+msgid "See all"
114+msgstr ""
115+
116#: qml/Dash/Previews/PreviewActionCombo.qml:34
116#: qml/Dash/Previews/PreviewActionCombo.qml:34
117msgid "More..."
117msgid "More..."
118msgstr ""
118msgstr ""
@@ -121,15 +121,15 @@ msgstr ""
121msgid "Less..."
121msgid "Less..."
122msgstr ""
122msgstr ""
123
123
124−#: qml/Dash/Previews/PreviewRatingInput.qml:82
124+#: qml/Dash/Previews/PreviewRatingInput.qml:81
125msgid "Rate this"
125msgid "Rate this"
126msgstr ""
126msgstr ""
127
127
128−#: qml/Dash/Previews/PreviewRatingInput.qml:128
128+#: qml/Dash/Previews/PreviewRatingInput.qml:126
129msgid "Add a review"
129msgid "Add a review"
130msgstr ""
130msgstr ""
131
131
132−#: qml/Dash/Previews/PreviewRatingInput.qml:168
132+#: qml/Dash/Previews/PreviewRatingInput.qml:166
133msgid "Send"
133msgid "Send"
134msgstr ""
134msgstr ""
135
135
@@ -165,6 +165,14 @@ msgstr ""
165msgid "Please enter SIM PIN"
165msgid "Please enter SIM PIN"
166msgstr ""
166msgstr ""
167
167
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+
168#: qml/Panel/Indicators/MenuItemFactory.qml:583
176#: qml/Panel/Indicators/MenuItemFactory.qml:583
169msgid "In queue…"
177msgid "In queue…"
170msgstr ""
178msgstr ""
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 @@
1/*
1/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013,2014 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
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
5 * it under the terms of the GNU General Public License as published by
@@ -15,54 +15,45 @@
15 */
15 */
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18+import QtQuick.Layouts 1.1
18import Ubuntu.Components 0.1
19import Ubuntu.Components 0.1
19
20
20Item {
21Item {
21− /*!
22− \preliminary
23− The text that is shown as the header text.
24− \qmlproperty string text
25− */
26 property alias text: label.text
22 property alias text: label.text
27− property alias textColor: label.color
23+ property alias color: label.color
28− property alias image: image.source
24+ property alias iconName: icon.name
29
25
30 signal clicked(variant mouse)
26 signal clicked(variant mouse)
31
27
32 height: units.gu(5)
28 height: units.gu(5)
33
29
34− Item {
30+ RowLayout {
31+ spacing: units.gu(.5)
35 anchors {
32 anchors {
36 left: parent.left
33 left: parent.left
37 right: parent.right
34 right: parent.right
35+ verticalCenter: parent.verticalCenter
38− rightMargin: units.gu(0.5)
36+ margins: units.gu(1)
39− top: parent.top
40− bottom: parent.bottom
41 }
37 }
42
38
43 Label {
39 Label {
44 id: label
40 id: label
45− anchors {
41+ Layout.fillWidth: true
46− left: parent.left
47− leftMargin: units.gu(2)
48− verticalCenter: parent.verticalCenter
49− }
50
42
51− color: "grey" // TODO karni: Update Ubuntu.Compoonents.Themes.Palette.
52 font.family: "Ubuntu"
43 font.family: "Ubuntu"
53 fontSize: "medium"
44 fontSize: "medium"
54 elide: Text.ElideRight
45 elide: Text.ElideRight
46+ maximumLineCount: 1
55 textFormat: Text.PlainText
47 textFormat: Text.PlainText
56− width: parent.width - image.width - image.leftMargin - anchors.leftMargin
48+ width: Math.min(parent.width - units.gu(4), implicitWidth)
57 }
49 }
58
50
59− Image {
51+ Icon {
60− id: image
52+ id: icon
61− readonly property double leftMargin: units.gu(1)
53+ visible: name != ""
62− x: label.x + label.contentWidth + leftMargin
54+ height: units.gu(2)
63− anchors {
55+ width: height
64− verticalCenter: parent.verticalCenter
56+ color: label.color
65− }
66 }
57 }
67 }
58 }
68
59
qml/Components/PageHeader.qml+6−1
@@ -127,6 +127,11 @@ Item {
127 property bool showSearch: false
127 property bool showSearch: false
128 property var popover: null
128 property var popover: null
129
129
130+ Background {
131+ objectName: "headerBackground"
132+ style: scopeStyle.headerBackground
133+ }
134+
130 Behavior on contentY {
135 Behavior on contentY {
131 UbuntuNumberAnimation {
136 UbuntuNumberAnimation {
132 id: openSearchAnimation
137 id: openSearchAnimation
@@ -225,7 +230,7 @@ Item {
225 height: headerContainer.height
230 height: headerContainer.height
226 contentHeight: height
231 contentHeight: height
227 separatorSource: ""
232 separatorSource: ""
228− textColor: root.scopeStyle ? root.scopeStyle.foreground : "grey"
233+ textColor: root.scopeStyle ? root.scopeStyle.headerForeground : "grey"
229 property var styledItem: header
234 property var styledItem: header
230 property string title: root.title
235 property string title: root.title
231 property var config: PageHeadConfiguration {
236 property var config: PageHeadConfiguration {
qml/Components/ResponsiveGridView.qml+2−1
@@ -44,10 +44,11 @@ Item {
44 property alias displayMarginBeginning: gridView.displayMarginBeginning
44 property alias displayMarginBeginning: gridView.displayMarginBeginning
45 property alias displayMarginEnd: gridView.displayMarginEnd
45 property alias displayMarginEnd: gridView.displayMarginEnd
46 property alias highlightIndex: gridView.highlightIndex
46 property alias highlightIndex: gridView.highlightIndex
47+ property alias cacheBuffer: gridView.cacheBuffer
47 readonly property alias currentItem: gridView.currentItem
48 readonly property alias currentItem: gridView.currentItem
48
49
49 function contentHeightForRows(rows) {
50 function contentHeightForRows(rows) {
50− return rows * cellHeight + verticalSpacing
51+ return rows * cellHeight;
51 }
52 }
52
53
53 GridView {
54 GridView {
qml/Dash/CardCarousel.qml+2−7
@@ -21,13 +21,8 @@ import "../Components"
21DashRenderer {
21DashRenderer {
22 id: cardCarousel
22 id: cardCarousel
23
23
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
31
26
32 Carousel {
27 Carousel {
33 id: carousel
28 id: carousel
qml/Dash/CardFilterGrid.qml → qml/Dash/CardGrid.qmlrenamed+22−22
@@ -18,33 +18,33 @@ import QtQuick 2.0
18import "../Components"
18import "../Components"
19
19
20DashRenderer {
20DashRenderer {
21− id: genericFilterGrid
21+ id: root
22
22
23− expandable: filterGrid.expandable
23+ readonly property int collapsedRows: {
24− collapsedHeight: filterGrid.collapsedHeight
24+ if (!cardTool || !cardTool.template || typeof cardTool.template["collapsed-rows"] != "number") return 2;
25− uncollapsedHeight: filterGrid.uncollapsedHeight
25+ return cardTool.template["collapsed-rows"];
26− originY: filterGrid.originY
27− height: filterGrid.height
28− filtered: filterGrid.filtered
29−
30− function setFilter(filter, animate) {
31− filterGrid.setFilter(filter, animate)
32 }
26 }
33
27
34− FilterGrid {
28+ expandedHeight: grid.totalContentHeight
35− id: filterGrid
29+ collapsedHeight: Math.min(grid.contentHeightForRows(collapsedRows), expandedHeight)
36− width: genericFilterGrid.width
30+ collapsedItemCount: collapsedRows * grid.columns
31+ originY: grid.originY
32+
33+ ResponsiveGridView {
34+ id: grid
35+ anchors.fill: parent
37 minimumHorizontalSpacing: units.gu(1)
36 minimumHorizontalSpacing: units.gu(1)
38 delegateWidth: cardTool.cardWidth
37 delegateWidth: cardTool.cardWidth
39 delegateHeight: cardTool.cardHeight
38 delegateHeight: cardTool.cardHeight
40 verticalSpacing: units.gu(1)
39 verticalSpacing: units.gu(1)
41− model: genericFilterGrid.model
40+ model: root.model
42− collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
41+ displayMarginBeginning: root.displayMarginBeginning
43− displayMarginBeginning: genericFilterGrid.displayMarginBeginning
42+ displayMarginEnd: root.displayMarginEnd
44− displayMarginEnd: genericFilterGrid.displayMarginEnd
43+ cacheBuffer: 0
44+ interactive: false
45 delegate: Item {
45 delegate: Item {
46− width: filterGrid.cellWidth
46+ width: grid.cellWidth
47− height: filterGrid.cellHeight
47+ height: grid.cellHeight
48 Loader {
48 Loader {
49 id: loader
49 id: loader
50 sourceComponent: cardTool.cardComponent
50 sourceComponent: cardTool.cardComponent
@@ -58,12 +58,12 @@ DashRenderer {
58 item.template = Qt.binding(function() { return cardTool.template; });
58 item.template = Qt.binding(function() { return cardTool.template; });
59 item.components = Qt.binding(function() { return cardTool.components; });
59 item.components = Qt.binding(function() { return cardTool.components; });
60 item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
60 item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
61− item.scopeStyle = genericFilterGrid.scopeStyle;
61+ item.scopeStyle = root.scopeStyle;
62 }
62 }
63 Connections {
63 Connections {
64 target: loader.item
64 target: loader.item
65− onClicked: genericFilterGrid.clicked(index, result)
65+ onClicked: root.clicked(index, result)
66− onPressAndHold: genericFilterGrid.pressAndHold(index)
66+ onPressAndHold: root.pressAndHold(index)
67 }
67 }
68 }
68 }
69 }
69 }
qml/Dash/CardVerticalJournal.qml+3−21
@@ -23,33 +23,15 @@ DashRenderer {
23
23
24 readonly property double collapseLimit: units.gu(35)
24 readonly property double collapseLimit: units.gu(35)
25
25
26− uncollapsedHeight: cardVerticalJournal.implicitHeight
26+ expandedHeight: Math.max(cardVerticalJournal.implicitHeight, minHeight)
27− collapsedHeight: Math.min(collapseLimit, cardVerticalJournal.implicitHeight)
27+ collapsedHeight: Math.max(Math.min(collapseLimit, cardVerticalJournal.implicitHeight), minHeight)
28− expandable: uncollapsedHeight > collapseLimit
28+ // TODO: implement collapsedItemCount
29
29
30 // This minHeight is used as bootstrapper for the height. Vertical Journal
30 // This minHeight is used as bootstrapper for the height. Vertical Journal
31 // is special by the fact that it doesn't know how to calculate its implicit height unless we give it
31 // is special by the fact that it doesn't know how to calculate its implicit height unless we give it
32 // enough height that it can start creating its children so we make sure it has enough height for that
32 // enough height that it can start creating its children so we make sure it has enough height for that
33 // in case the model is non empty
33 // in case the model is non empty
34 readonly property double minHeight: root.model.count >= 1 ? cardVerticalJournal.rowSpacing + 1 : 0
34 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− }
53
35
54 ResponsiveVerticalJournal {
36 ResponsiveVerticalJournal {
55 id: cardVerticalJournal
37 id: cardVerticalJournal
qml/Dash/DashRenderer.qml+3−10
@@ -17,15 +17,11 @@
17import QtQuick 2.0
17import QtQuick 2.0
18
18
19Item {
19Item {
20− // Can the item be expanded?
20+ property int collapsedHeight
21− property bool expandable: false
22
21
23− // In case it can be expanded, is it filtered
22+ property int expandedHeight
24− property bool filtered: true
25
23
26− property int collapsedHeight: height
24+ property int collapsedItemCount: -1
27−
28− property int uncollapsedHeight: height
29
25
30 property int displayMarginBeginning: 0
26 property int displayMarginBeginning: 0
31
27
@@ -50,7 +46,4 @@ Item {
50 /// Emitted when the user pressed and held on an item
46 /// Emitted when the user pressed and held on an item
51 /// @param index is the index of the held item
47 /// @param index is the index of the held item
52 signal pressAndHold(int index)
48 signal pressAndHold(int index)
53−
54− function setFilter(filter, animate) {
55− }
56}
49}
qml/Dash/GenericScopeView.qml+128−64
@@ -119,6 +119,7 @@ FocusScope {
119
119
120 model: scopeView.categories
120 model: scopeView.categories
121 forceNoClip: previewListView.open
121 forceNoClip: previewListView.open
122+ pixelAligned: true
122
123
123 property string expandedCategoryId: ""
124 property string expandedCategoryId: ""
124
125
@@ -128,11 +129,22 @@ FocusScope {
128 highlightWhenPressed: false
129 highlightWhenPressed: false
129 showDivider: false
130 showDivider: false
130
131
131− readonly property bool expandable: rendererLoader.item ? rendererLoader.item.expandable : false
132+ readonly property bool expandable: {
132− readonly property bool filtered: rendererLoader.item ? rendererLoader.item.filtered : true
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
133 readonly property string category: categoryId
139 readonly property string category: categoryId
140+ readonly property string headerLink: model.headerLink
134 readonly property var item: rendererLoader.item
141 readonly property var item: rendererLoader.item
135
142
143+ function expand(expand, animate) {
144+ heightBehaviour.enabled = animate;
145+ expanded = expand;
146+ }
147+
136 CardTool {
148 CardTool {
137 id: cardTool
149 id: cardTool
138 objectName: "cardTool"
150 objectName: "cardTool"
@@ -142,22 +154,49 @@ FocusScope {
142 viewWidth: parent.width
154 viewWidth: parent.width
143 }
155 }
144
156
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+
145 Loader {
169 Loader {
146 id: rendererLoader
170 id: rendererLoader
147 anchors {
171 anchors {
148 top: parent.top
172 top: parent.top
149 left: parent.left
173 left: parent.left
150 right: parent.right
174 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+ }
152 }
188 }
153
189
190+ readonly property bool expanded: baseItem.expanded || !baseItem.expandable
191+ height: expanded ? item.expandedHeight : item.collapsedHeight
192+
154 source: {
193 source: {
155 switch (cardTool.categoryLayout) {
194 switch (cardTool.categoryLayout) {
156 case "carousel": return "CardCarousel.qml";
195 case "carousel": return "CardCarousel.qml";
157 case "vertical-journal": return "CardVerticalJournal.qml";
196 case "vertical-journal": return "CardVerticalJournal.qml";
158 case "running-apps": return "Apps/RunningApplicationsGrid.qml";
197 case "running-apps": return "Apps/RunningApplicationsGrid.qml";
159 case "grid":
198 case "grid":
160− default: return "CardFilterGrid.qml";
199+ default: return "CardGrid.qml";
161 }
200 }
162 }
201 }
163
202
@@ -176,9 +215,9 @@ FocusScope {
176 }
215 }
177 item.objectName = Qt.binding(function() { return categoryId })
216 item.objectName = Qt.binding(function() { return categoryId })
178 item.scopeStyle = scopeView.scopeStyle;
217 item.scopeStyle = scopeView.scopeStyle;
179− if (item.expandable) {
218+ if (baseItem.expandable) {
180− var shouldFilter = categoryId != categoryView.expandedCategoryId;
219+ var shouldExpand = categoryId === categoryView.expandedCategoryId;
181− item.setFilter(shouldFilter, false /*animate*/);
220+ baseItem.expand(shouldExpand, false /*animate*/);
182 }
221 }
183 updateDelegateCreationRange();
222 updateDelegateCreationRange();
184 item.cardTool = cardTool;
223 item.cardTool = cardTool;
@@ -199,25 +238,22 @@ FocusScope {
199 // so it's not implemented
238 // so it's not implemented
200 scopeView.scope.activate(result)
239 scopeView.scope.activate(result)
201 } else {
240 } else {
202− previewListView.model = target.model;
241+ openPreview(index);
203− previewListView.currentIndex = -1
204− previewListView.currentIndex = index;
205− previewListView.open = true
206 }
242 }
207 }
243 }
208− onPressAndHold: {
244+ onPressAndHold: openPreview(index)
209− previewListView.model = target.model;
245+
210− previewListView.currentIndex = -1
246+ function openPreview(index) {
211− previewListView.currentIndex = index;
247+ if (!rendererLoader.expanded && !seeAllLabel.visible && target.collapsedItemCount > 0) {
212− previewListView.open = true
248+ previewLimitModel.model = target.model;
213− }
249+ previewLimitModel.limit = target.collapsedItemCount;
214− onExpandableChanged: {
250+ previewListView.model = previewLimitModel;
215− // This can happen with the VJ that doesn't know how height it will be on creation
251+ } else {
216− // so doesn't set expandable until a bit too late for onLoaded
252+ previewListView.model = target.model;
217− if (rendererLoader.item.expandable) {
218− var shouldFilter = baseItem.category != categoryView.expandedCategoryId;
219− rendererLoader.item.setFilter(shouldFilter, false /*animate*/);
220 }
253 }
254+ previewListView.currentIndex = -1;
255+ previewListView.currentIndex = index;
256+ previewListView.open = true;
221 }
257 }
222 }
258 }
223 Connections {
259 Connections {
@@ -227,17 +263,17 @@ FocusScope {
227 }
263 }
228 function collapseAllButExpandedCategory() {
264 function collapseAllButExpandedCategory() {
229 var item = rendererLoader.item;
265 var item = rendererLoader.item;
230− if (item.expandable) {
266+ if (baseItem.expandable) {
231− var shouldFilter = categoryId != categoryView.expandedCategoryId;
267+ var shouldExpand = categoryId === categoryView.expandedCategoryId;
232− if (shouldFilter != item.filter) {
268+ if (shouldExpand != baseItem.expanded) {
233 // If the filter animation will be seen start it, otherwise, just flip the switch
269 // If the filter animation will be seen start it, otherwise, just flip the switch
234− var shrinkingVisible = shouldFilter && y + item.collapsedHeight < categoryView.height;
270+ var shrinkingVisible = !shouldExpand && y + item.collapsedHeight + seeAll.height < categoryView.height;
235− var growingVisible = !shouldFilter && y + height < categoryView.height;
271+ var growingVisible = shouldExpand && y + height < categoryView.height;
236− if (!previewListView.open || !shouldFilter) {
272+ if (!previewListView.open || shouldExpand) {
237 var animate = shrinkingVisible || growingVisible;
273 var animate = shrinkingVisible || growingVisible;
238− item.setFilter(shouldFilter, animate)
274+ baseItem.expand(shouldExpand, animate)
239− if (!shouldFilter && !previewListView.open) {
275+ if (shouldExpand && !previewListView.open) {
240− categoryView.maximizeVisibleArea(index, item.uncollapsedHeight);
276+ categoryView.maximizeVisibleArea(index, item.expandedHeight + seeAll.height);
241 }
277 }
242 }
278 }
243 }
279 }
@@ -274,58 +310,82 @@ FocusScope {
274 item.displayMarginEnd = -baseItem.height;
310 item.displayMarginEnd = -baseItem.height;
275 } else {
311 } else {
276 item.displayMarginBeginning = -Math.max(-baseItem.y, 0);
312 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)
278 }
315 }
279 }
316 }
280 }
317 }
318+ }
281
319
282− Image {
320+ AbstractButton {
283− visible: index != 0
321+ id: seeAll
284− anchors {
322+ objectName: "seeAll"
285− top: parent.top
323+ anchors {
286− left: parent.left
324+ top: rendererLoader.bottom
287− right: parent.right
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 = "";
288 }
335 }
289− fillMode: Image.Stretch
290− source: "graphics/dash_divider_top_lightgrad.png"
291− z: -1
292 }
336 }
293
337
294− Image {
338+ Label {
295− // FIXME Should not rely on model.count but view.count, but ListViewWithPageHeader doesn't expose it yet.
339+ id: seeAllLabel
296− visible: index != categoryView.model.count - 1
340+ text: baseItem.expanded ? i18n.tr("See less") : i18n.tr("See all")
297 anchors {
341 anchors {
298− bottom: parent.bottom
342+ centerIn: parent
299− left: parent.left
343+ verticalCenterOffset: units.gu(-0.5)
300− right: parent.right
301 }
344 }
302− fillMode: Image.Stretch
345+ fontSize: "small"
303− source: "graphics/dash_divider_top_darkgrad.png"
346+ font.weight: Font.Bold
304− z: -1
347+ color: scopeStyle ? scopeStyle.foreground : "grey"
348+ visible: baseItem.expandable && !baseItem.headerLink
305 }
349 }
306 }
350 }
307
351
308− onHeightChanged: rendererLoader.updateDelegateCreationRange();
352+ Image {
309− onYChanged: rendererLoader.updateDelegateCreationRange();
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+ }
310 }
376 }
311
377
312 sectionProperty: "name"
378 sectionProperty: "name"
313 sectionDelegate: ListItems.Header {
379 sectionDelegate: ListItems.Header {
314 objectName: "dashSectionHeader" + (delegate ? delegate.category : "")
380 objectName: "dashSectionHeader" + (delegate ? delegate.category : "")
315− property var delegate: categoryView.item(delegateIndex)
381+ readonly property var delegate: categoryView.item(delegateIndex)
316 width: categoryView.width
382 width: categoryView.width
383+ height: section != "" ? units.gu(5) : 0
317 text: section
384 text: section
318− textColor: scopeStyle ? scopeStyle.foreground : "grey"
385+ color: scopeStyle ? scopeStyle.foreground : "grey"
319− image: {
320− if (delegate && delegate.expandable)
386+ iconName: delegate && delegate.headerLink ? "go-next" : ""
321− return delegate.filtered ? "graphics/header_handlearrow.png" : "graphics/header_handlearrow2.png"
322− return "";
323− }
324 onClicked: {
387 onClicked: {
325− if (categoryView.expandedCategoryId != delegate.category)
388+ if (delegate.headerLink) scopeView.scope.performQuery(delegate.headerLink);
326− categoryView.expandedCategoryId = delegate.category;
327− else
328− categoryView.expandedCategoryId = "";
329 }
389 }
330 }
390 }
331
391
@@ -352,6 +412,10 @@ FocusScope {
352 }
412 }
353 }
413 }
354
414
415+ LimitProxyModel {
416+ id: previewLimitModel
417+ }
418+
355 PreviewListView {
419 PreviewListView {
356 id: previewListView
420 id: previewListView
357 objectName: "previewListView"
421 objectName: "previewListView"
src/main.cpp+1−1
@@ -221,7 +221,7 @@ int main(int argc, const char *argv[])
221
221
222 return runWithClient(mirServer, startShell);
222 return runWithClient(mirServer, startShell);
223 } else {
223 } else {
224− if (qgetenv("UPSTART_JOB") == "unity8") {
224+ if (!qgetenv("UNITY_MIR_EMITS_SIGSTOP").isEmpty()) {
225 // Emit SIGSTOP as expected by upstart, under Mir it's unity-mir that will raise it.
225 // Emit SIGSTOP as expected by upstart, under Mir it's unity-mir that will raise it.
226 // see http://upstart.ubuntu.com/cookbook/#expect-stop
226 // see http://upstart.ubuntu.com/cookbook/#expect-stop
227 raise(SIGSTOP);
227 raise(SIGSTOP);
tests/autopilot/unity8/shell/emulators/dash.py+12−6
@@ -18,6 +18,7 @@
18#
18#
19
19
20import logging
20import logging
21+import ubuntuuitoolkit
21
22
22from unity8.shell import emulators
23from unity8.shell import emulators
23
24
@@ -40,7 +41,7 @@ class Dash(emulators.UnityEmulatorBase):
40
41
41 def get_applications_grid(self):
42 def get_applications_grid(self):
42 get_grid = self.get_scope('clickscope').wait_select_single(
43 get_grid = self.get_scope('clickscope').wait_select_single(
43− 'CardFilterGrid', objectName='local')
44+ 'CardGrid', objectName='local')
44 return get_grid
45 return get_grid
45
46
46 def get_application_icon(self, text):
47 def get_application_icon(self, text):
@@ -128,9 +129,9 @@ class Dash(emulators.UnityEmulatorBase):
128 def enter_search_query(self, query):
129 def enter_search_query(self, query):
129 current_header = self._get_current_page_header()
130 current_header = self._get_current_page_header()
130 self.pointing_device.move(current_header.globalRect.x +
131 self.pointing_device.move(current_header.globalRect.x +
131− current_header.width - current_header.height / 2,
132+ current_header.width - current_header.height / 4,
132 current_header.globalRect.y +
133 current_header.globalRect.y +
133− current_header.height / 2)
134+ current_header.height / 4)
134 self.pointing_device.click()
135 self.pointing_device.click()
135 headerContainer = current_header.select_single(objectName="headerContainer")
136 headerContainer = current_header.select_single(objectName="headerContainer")
136 headerContainer.contentY.wait_for(0)
137 headerContainer.contentY.wait_for(0)
@@ -151,6 +152,10 @@ class Dash(emulators.UnityEmulatorBase):
151 return None
152 return None
152
153
153
154
155+class ListViewWithPageHeader(ubuntuuitoolkit.QQuickFlickable):
156+ pass
157+
158+
154class GenericScopeView(emulators.UnityEmulatorBase):
159class GenericScopeView(emulators.UnityEmulatorBase):
155 """Autopilot emulator for generic scopes."""
160 """Autopilot emulator for generic scopes."""
156
161
@@ -196,14 +201,15 @@ class DashApps(GenericScopeView):
196 category_element = self._get_category_element(category)
201 category_element = self._get_category_element(category)
197 application_cards = category_element.select_many('AbstractButton')
202 application_cards = category_element.select_many('AbstractButton')
198
203
199− # sort by y, x
200 application_cards = sorted(
204 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),
202 key=lambda card: (card.globalRect.y, card.globalRect.x))
208 key=lambda card: (card.globalRect.y, card.globalRect.x))
203
209
204 result = []
210 result = []
205 for card in application_cards:
211 for card in application_cards:
206− if card.objectName != 'cardToolCard':
212+ if card.objectName not in ('cardToolCard', 'seeAll'):
207 result.append(card.title)
213 result.append(card.title)
208 return result
214 return result
209
215
tests/autopilot/unity8/shell/tests/test_emulators.py+15−5
@@ -16,6 +16,7 @@
16# You should have received a copy of the GNU General Public License
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/>.
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
18#
19+from unity8.shell.emulators.dash import ListViewWithPageHeader
19
20
20"""Tests for the Dash autopilot emulators.
21"""Tests for the Dash autopilot emulators.
21
22
@@ -182,18 +183,27 @@ class DashAppsEmulatorTestCase(DashBaseTestCase):
182
183
183 def test_get_applications_should_return_correct_applications(self):
184 def test_get_applications_should_return_correct_applications(self):
184 category = '2'
185 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)
185 expected_apps_count = self._get_number_of_application_slots(category)
190 expected_apps_count = self._get_number_of_application_slots(category)
186 expected_applications = self.available_applications[
191 expected_applications = self.available_applications[
187 :expected_apps_count]
192 :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)
188 applications = self.applications_scope.get_applications(category)
198 applications = self.applications_scope.get_applications(category)
189 self.assertEqual(expected_applications, applications)
199 self.assertEqual(expected_applications, applications)
190
200
191 def _get_number_of_application_slots(self, category):
201 def _get_number_of_application_slots(self, category):
192 category_element = self.applications_scope._get_category_element(
202 category_element = self.applications_scope._get_category_element(
193 category)
203 category)
194− grid = category_element.select_single('CardFilterGrid')
204+ cardgrid = category_element.select_single('CardGrid')
195− filtergrid = grid.select_single('FilterGrid')
205+ if (category_element.expanded):
196− if (grid.filtered):
206+ return cardgrid.select_single('QQuickGridView').count
197− return filtergrid.collapsedRowCount * filtergrid.columns
198 else:
207 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 @@
20"""Tests for upstart integration."""
20"""Tests for upstart integration."""
21
21
22import os
22import os
23+import stat
23import signal
24import signal
24import subprocess
25import subprocess
25import time
26import time
@@ -57,6 +58,18 @@ class UpstartIntegrationTests(UnityTestCase):
57
58
58 def _launch_unity(self):
59 def _launch_unity(self):
59 self.patch_environment("QT_LOAD_TESTABILITY", "1")
60 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+
60 self.process = subprocess.Popen(
73 self.process = subprocess.Popen(
61 [get_binary_path()] + self.unity_geometry_args)
74 [get_binary_path()] + self.unity_geometry_args)
62
75
tests/mocks/Ubuntu/Telephony/CMakeLists.txt+1−9
@@ -11,12 +11,4 @@ add_library(FakeUbuntuTelephonyQml MODULE ${FakeUbuntuTelephonyQml_SOURCES})
11
11
12qt5_use_modules(FakeUbuntuTelephonyQml Core Quick)
12qt5_use_modules(FakeUbuntuTelephonyQml Core Quick)
13
13
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
14+add_unity8_mock(Ubuntu.Telephony 0.1 Ubuntu/Telephony TARGETS FakeUbuntuTelephonyQml)
21− DESTINATION ${SHELL_INSTALL_QML}/mocks/Ubuntu/Telephony
22− )
tests/mocks/Unity/fake_categories.cpp+13−1
@@ -145,9 +145,12 @@ Categories::data(const QModelIndex& index, int role) const
145 } else {
145 } else {
146 map["category-layout"] = "carousel";
146 map["category-layout"] = "carousel";
147 map["card-size"] = "medium";
147 map["card-size"] = "medium";
148− map["collapsed-rows"] = 2;
149 map["overlay"] = true;
148 map["overlay"] = true;
150 }
149 }
150+ if (index.row() == 19) {
151+ map["category-layout"] = "grid";
152+ map["collapsed-rows"] = 0;
153+ }
151 map["card-size"] = "small";
154 map["card-size"] = "small";
152 return map;
155 return map;
153 }
156 }
@@ -166,6 +169,9 @@ Categories::data(const QModelIndex& index, int role) const
166 return map;
169 return map;
167 }
170 }
168 case RoleHeaderLink:
171 case RoleHeaderLink:
172+ if (index.row() == 1 || index.row() == 4) {
173+ return QString("scope://query/1");
174+ }
169 return QString();
175 return QString();
170 case RoleResults:
176 case RoleResults:
171 return QVariant::fromValue(resultsModel);
177 return QVariant::fromValue(resultsModel);
@@ -177,3 +183,9 @@ Categories::data(const QModelIndex& index, int role) const
177 }
183 }
178 }
184 }
179}
185}
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:
37 Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) override;
37 Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) override;
38 Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;
38 Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;
39
39
40+ Q_INVOKABLE QVariant data(int row, int role) const;
41+
40private Q_SLOTS:
42private Q_SLOTS:
41 void countChanged();
43 void countChanged();
42
44
tests/mocks/Unity/fake_scope.cpp+8−11
@@ -24,7 +24,7 @@ Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
24{
24{
25}
25}
26
26
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)
28 : unity::shell::scopes::ScopeInterface(parent)
28 : unity::shell::scopes::ScopeInterface(parent)
29 , m_id(id)
29 , m_id(id)
30 , m_name(name)
30 , m_name(name)
@@ -33,7 +33,7 @@ Scope::Scope(QString const& id, QString const& name, bool visible, QObject* pare
33 , m_isActive(false)
33 , m_isActive(false)
34 , m_currentDeparment("root")
34 , m_currentDeparment("root")
35 , m_previewRendererName("preview-generic")
35 , m_previewRendererName("preview-generic")
36− , m_categories(new Categories(20, this))
36+ , m_categories(new Categories(categories, this))
37{
37{
38}
38}
39
39
@@ -182,14 +182,16 @@ bool Scope::hasDepartments() const
182
182
183QVariantMap Scope::customizations() const
183QVariantMap Scope::customizations() const
184{
184{
185− QVariantMap m;
185+ QVariantMap m, h;
186 if (m_id == "clickscope") {
186 if (m_id == "clickscope") {
187+ h["foreground-color"] = "yellow";
187 m["background-color"] = "red";
188 m["background-color"] = "red";
188 m["foreground-color"] = "blue";
189 m["foreground-color"] = "blue";
190+ m["page-header"] = h;
189 } else if (m_id == "MockScope5") {
191 } else if (m_id == "MockScope5") {
190− QVariantMap pageHeader;
192+ h["background"] = "gradient:///lightgrey/grey";
191− pageHeader["logo"] = QUrl("../../../tests/qmltests/Components/tst_PageHeader/logo-ubuntu-orange.svg");
193+ h["logo"] = QUrl("../../../tests/qmltests/Components/tst_PageHeader/logo-ubuntu-orange.svg");
192− m["page-header"] = pageHeader;
194+ m["page-header"] = h;
193 }
195 }
194 return m;
196 return m;
195}
197}
@@ -216,8 +218,3 @@ void Scope::loadDepartment(const QString& id)
216 m_currentDeparment = id;
218 m_currentDeparment = id;
217 Q_EMIT currentDepartmentIdChanged();
219 Q_EMIT currentDepartmentIdChanged();
218}
220}
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
30
30
31public:
31public:
32 Scope(QObject* parent = 0);
32 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);
34
34
35 /* getters */
35 /* getters */
36 QString id() const override;
36 QString id() const override;
@@ -64,7 +64,7 @@ public:
64 bool hasDepartments() const override;
64 bool hasDepartments() const override;
65 Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
65 Q_INVOKABLE unity::shell::scopes::DepartmentInterface* getDepartment(const QString& id) override;
66 Q_INVOKABLE void loadDepartment(const QString& id) override;
66 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;
68
68
69 QVariantMap customizations() const override;
69 QVariantMap customizations() const override;
70
70
tests/mocks/Unity/fake_scopes.cpp+1
@@ -46,6 +46,7 @@ void Scopes::updateScopes()
46 addScope(new Scope("MockScope2", "Music", false, this));
46 addScope(new Scope("MockScope2", "Music", false, this));
47 addScope(new Scope("clickscope", "Apps", true, this));
47 addScope(new Scope("clickscope", "Apps", true, this));
48 addScope(new Scope("MockScope5", "Videos", true, this));
48 addScope(new Scope("MockScope5", "Videos", true, this));
49+ addScope(new Scope("SingleCategoryScope", "Single", true, this, 1));
49
50
50 if (!m_loaded) {
51 if (!m_loaded) {
51 m_loaded = true;
52 m_loaded = true;
tests/plugins/Dash/tst_ScopeStyle.qml+27−2
@@ -36,8 +36,8 @@ Rectangle {
36 property var styles: [
36 property var styles: [
37 {},
37 {},
38 { "foreground-color": "red", "background-color": "black", "page-header": { "logo": "/foo/bar" } },
38 { "foreground-color": "red", "background-color": "black", "page-header": { "logo": "/foo/bar" } },
39− { "foreground-color": "green", "background-color": "white" },
39+ { "foreground-color": "green", "background-color": "white", "page-header": { "foreground-color": "black" } },
40− { "foreground-color": "blue", "background-color": "darkgrey" },
40+ { "foreground-color": "blue", "background-color": "darkgrey", "page-header": { "background": "gradient:///white/blue" } },
41 ]
41 ]
42
42
43 function cleanup() {
43 function cleanup() {
@@ -147,5 +147,30 @@ Rectangle {
147 tool.style = testCase.styles[data.index];
147 tool.style = testCase.styles[data.index];
148 compare(tool.headerLogo, data.headerLogo, "Header logo was incorrect.");
148 compare(tool.headerLogo, data.headerLogo, "Header logo was incorrect.");
149 }
149 }
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+ }
150 }
175 }
151}
176}
tests/qmltests/CMakeLists.txt+1−1
@@ -21,10 +21,10 @@ set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "LC_ALL=C")
21
21
22add_qml_test(. Shell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
22add_qml_test(. Shell ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
23add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single-pin")
23add_qml_test(. ShellWithPin ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single-pin")
24+add_qml_test(Components Background)
24add_qml_test(Components Carousel)
25add_qml_test(Components Carousel)
25add_qml_test(Components DraggingArea)
26add_qml_test(Components DraggingArea)
26add_qml_test(Components EdgeDemoOverlay)
27add_qml_test(Components EdgeDemoOverlay)
27−add_qml_test(Components FilterGrid)
28add_qml_test(Components LazyImage)
28add_qml_test(Components LazyImage)
29add_qml_test(Components Rating)
29add_qml_test(Components Rating)
30add_qml_test(Components ResponsiveFlowView)
30add_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 {
86 tryCompare(dashContentList, "count", 0);
86 tryCompare(dashContentList, "count", 0);
87 scopes.load();
87 scopes.load();
88 tryCompare(scopes, "loaded", true);
88 tryCompare(scopes, "loaded", true);
89− tryCompare(dashContentList, "count", 3);
89+ tryCompare(dashContentList, "count", 4);
90
90
91 verify(dashContentList != undefined);
91 verify(dashContentList != undefined);
92 tryCompare(dashContentList, "currentIndex", data.visualIndex);
92 tryCompare(dashContentList, "currentIndex", data.visualIndex);
tests/qmltests/Dash/tst_DashContent.qml+15−6
@@ -61,6 +61,11 @@ Item {
61 signalName: "movementStarted"
61 signalName: "movementStarted"
62 }
62 }
63
63
64+ SignalSpy {
65+ id: loadedSpy
66+ signalName: "loaded"
67+ }
68+
64 UT.UnityTestCase {
69 UT.UnityTestCase {
65 name: "DashContent"
70 name: "DashContent"
66 when: scopesModel.loaded && windowShown
71 when: scopesModel.loaded && windowShown
@@ -78,6 +83,7 @@ Item {
78
83
79 function cleanup() {
84 function cleanup() {
80 movementStartedSpy.clear();
85 movementStartedSpy.clear();
86+ loadedSpy.clear();
81 dashContent.visible = true;
87 dashContent.visible = true;
82
88
83 var dashContentList = findChild(dashContent, "dashContentList");
89 var dashContentList = findChild(dashContent, "dashContentList");
@@ -116,10 +122,11 @@ Item {
116
122
117 function test_show_header_on_list_movement() {
123 function test_show_header_on_list_movement() {
118 var dashContentList = findChild(dashContent, "dashContentList");
124 var dashContentList = findChild(dashContent, "dashContentList");
119− verify(dashContentList != undefined);
125+ verify(dashContentList !== null);
120− var categoryListView = findChild(dashContentList, "categoryListView");
126+ var scope = findChild(dashContent, "MockScope1 loader");
121− verify(categoryListView != undefined);
127+ waitForRendering(scope);
122
128
129+ var categoryListView = findChild(scope, "categoryListView");
123 waitForRendering(categoryListView);
130 waitForRendering(categoryListView);
124
131
125 categoryListView.contentY = units.gu(15);
132 categoryListView.contentY = units.gu(15);
@@ -133,10 +140,12 @@ Item {
133
140
134 function test_set_current_scope_reset() {
141 function test_set_current_scope_reset() {
135 var dashContentList = findChild(dashContent, "dashContentList");
142 var dashContentList = findChild(dashContent, "dashContentList");
136− verify(dashContentList != undefined);
143+ verify(dashContentList, "Couldn't find dashContentList");
137− var categoryListView = findChild(dashContentList, "categoryListView");
144+ var scope = findChild(dashContent, "MockScope1 loader");
138− verify(categoryListView != undefined);
139
145
146+ tryCompare(scope, "status", Loader.Ready);
147+
148+ var categoryListView = findChild(dashContentList, "categoryListView");
140 categoryListView.contentY = units.gu(10);
149 categoryListView.contentY = units.gu(10);
141
150
142 compare(dashContentList.currentItem.item.objectName, "MockScope1")
151 compare(dashContentList.currentItem.item.objectName, "MockScope1")
tests/qmltests/Dash/tst_GenericScopeView.qml+137−49
@@ -39,6 +39,10 @@ Item {
39 id: scopes
39 id: scopes
40 }
40 }
41
41
42+ SignalSpy {
43+ id: spy
44+ }
45+
42 property Item applicationManager: Item {
46 property Item applicationManager: Item {
43 signal sideStageFocusedApplicationChanged()
47 signal sideStageFocusedApplicationChanged()
44 signal mainStageFocusedApplicationChanged()
48 signal mainStageFocusedApplicationChanged()
@@ -54,12 +58,20 @@ Item {
54 when: scopes.loaded && windowShown
58 when: scopes.loaded && windowShown
55
59
56 property Item previewListView: findChild(genericScopeView, "previewListView")
60 property Item previewListView: findChild(genericScopeView, "previewListView")
61+ property Item header: findChild(genericScopeView, "scopePageHeader")
57
62
58 function init() {
63 function init() {
59 genericScopeView.scope = scopes.getScope(1)
64 genericScopeView.scope = scopes.getScope(1)
60 shell.width = units.gu(120)
65 shell.width = units.gu(120)
61 genericScopeView.categoryView.positionAtBeginning();
66 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 = "";
63 }
75 }
64
76
65 function test_isActive() {
77 function test_isActive() {
@@ -104,90 +116,146 @@ Item {
104 tryCompare(genericScopeView.scope, "searchQuery", "test")
116 tryCompare(genericScopeView.scope, "searchQuery", "test")
105 }
117 }
106
118
107− function test_filter_expand_collapse() {
119+ function test_expand_collapse() {
108− // wait for the item to be there
109− waitForRendering(genericScopeView);
110 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0") != null; }, true);
120 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader0") != null; }, true);
111
121
112− var header = findChild(genericScopeView, "dashSectionHeader0")
113 var category = findChild(genericScopeView, "dashCategory0")
122 var category = findChild(genericScopeView, "dashCategory0")
123+ var seeAll = findChild(category, "seeAll")
114
124
115− waitForRendering(header);
125+ waitForRendering(seeAll);
116 verify(category.expandable);
126 verify(category.expandable);
117− verify(category.filtered);
127+ verify(!category.expanded);
118
128
119 var initialHeight = category.height;
129 var initialHeight = category.height;
120− var middleHeight;
121− mouseClick(header, header.width / 2, header.height / 2);
130+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
131+ verify(category.expanded);
122− tryCompareFunction(function() { middleHeight = category.height; return category.height > initialHeight; }, true);
132+ tryCompareFunction(function() { return category.height > initialHeight; }, true);
123− tryCompare(category, "filtered", false);
124− tryCompareFunction(function() { return category.height > middleHeight; }, true);
125
133
126− mouseClick(header, header.width / 2, header.height / 2);
134+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
127− verify(category.expandable);
135+ verify(!category.expanded);
128− tryCompare(category, "filtered", true);
129 }
136 }
130
137
131− function test_filter_expand_expand_collapse() {
138+ function test_expand_expand_collapse() {
132 // wait for the item to be there
139 // wait for the item to be there
133 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader2") != null; }, true);
140 tryCompareFunction(function() { return findChild(genericScopeView, "dashSectionHeader2") != null; }, true);
134
141
135 var categoryListView = findChild(genericScopeView, "categoryListView");
142 var categoryListView = findChild(genericScopeView, "categoryListView");
136 categoryListView.contentY = categoryListView.height;
143 categoryListView.contentY = categoryListView.height;
137
144
138− var header2 = findChild(genericScopeView, "dashSectionHeader2")
139 var category2 = findChild(genericScopeView, "dashCategory2")
145 var category2 = findChild(genericScopeView, "dashCategory2")
140− var category2FilterGrid = category2.children[1].children[2];
146+ var seeAll2 = findChild(category2, "seeAll")
141− verify(UT.Util.isInstanceOf(category2FilterGrid, "CardFilterGrid"));
142
147
143− waitForRendering(header2);
148+ waitForRendering(seeAll2);
144 verify(category2.expandable);
149 verify(category2.expandable);
145− verify(category2.filtered);
150+ verify(!category2.expanded);
146
151
147− mouseClick(header2, header2.width / 2, header2.height / 2);
152+ mouseClick(seeAll2, seeAll2.width / 2, seeAll2.height / 2);
148− tryCompare(category2, "filtered", false);
153+ tryCompare(category2, "expanded", true);
149− tryCompare(category2FilterGrid, "filtered", false);
150
154
151 categoryListView.positionAtBeginning();
155 categoryListView.positionAtBeginning();
152
156
153− var header0 = findChild(genericScopeView, "dashSectionHeader0")
154 var category0 = findChild(genericScopeView, "dashCategory0")
157 var category0 = findChild(genericScopeView, "dashCategory0")
158+ var seeAll0 = findChild(category0, "seeAll")
155− mouseClick(header0, header0.width / 2, header0.height / 2);
159+ mouseClick(seeAll0, seeAll0.width / 2, seeAll0.height / 2);
156− tryCompare(category0, "filtered", false);
160+ tryCompare(category0, "expanded", true);
157− tryCompare(category2, "filtered", true);
161+ tryCompare(category2, "expanded", false);
158− tryCompare(category2FilterGrid, "filtered", true);
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+
159− mouseClick(header0, header0.width / 2, header0.height / 2);
174+ mouseClick(header, header.width / 2, header.height / 2);
160− tryCompare(category0, "filtered", true);
175+
161− tryCompare(category2, "filtered", true);
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.");
162 }
200 }
163
201
164 function test_narrow_delegate_ranges_expand() {
202 function test_narrow_delegate_ranges_expand() {
165− tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") != undefined; }, true);
203+ tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") !== null; }, true);
166 var category = findChild(genericScopeView, "dashCategory0")
204 var category = findChild(genericScopeView, "dashCategory0")
167− tryCompare(category, "filtered", true);
205+ tryCompare(category, "expanded", false);
168
206
169 shell.width = units.gu(20)
207 shell.width = units.gu(20)
170 var categoryListView = findChild(genericScopeView, "categoryListView");
208 var categoryListView = findChild(genericScopeView, "categoryListView");
171 categoryListView.contentY = units.gu(20);
209 categoryListView.contentY = units.gu(20);
172− var header0 = findChild(genericScopeView, "dashSectionHeader0")
210+ var seeAll = findChild(category, "seeAll")
173− mouseClick(header0, header0.width / 2, header0.height / 2);
211+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
174− tryCompare(category, "filtered", false);
212+ tryCompare(category, "expanded", true);
175 tryCompareFunction(function() { return category.item.height == genericScopeView.height - category.item.displayMarginBeginning - category.item.displayMarginEnd; }, true);
213 tryCompareFunction(function() { return category.item.height == genericScopeView.height - category.item.displayMarginBeginning - category.item.displayMarginEnd; }, true);
176− mouseClick(header0, header0.width / 2, header0.height / 2);
214+ mouseClick(seeAll, seeAll.width / 2, seeAll.height / 2);
177− tryCompare(category, "filtered", true);
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");
178 }
244 }
179
245
180− function openPreview() {
246+ function openPreview(category, delegate) {
247+ if (category === undefined) category = 0;
248+ if (delegate === undefined) delegate = 0;
181 tryCompareFunction(function() {
249 tryCompareFunction(function() {
182− var filterGrid = findChild(genericScopeView, "0");
250+ var cardGrid = findChild(genericScopeView, category);
183− if (filterGrid != null) {
251+ if (cardGrid != null) {
184− var tile = findChild(filterGrid, "delegate0");
252+ var tile = findChild(cardGrid, "delegate"+delegate);
185 return tile != null;
253 return tile != null;
186 }
254 }
187 return false;
255 return false;
188 },
256 },
189 true);
257 true);
190− var tile = findChild(findChild(genericScopeView, "0"), "delegate0");
258+ var tile = findChild(findChild(genericScopeView, category), "delegate"+delegate);
191 mouseClick(tile, tile.width / 2, tile.height / 2);
259 mouseClick(tile, tile.width / 2, tile.height / 2);
192 tryCompare(testCase.previewListView, "open", true);
260 tryCompare(testCase.previewListView, "open", true);
193 tryCompare(testCase.previewListView, "x", 0);
261 tryCompare(testCase.previewListView, "x", 0);
@@ -257,13 +325,33 @@ Item {
257 closePreview();
325 closePreview();
258 }
326 }
259
327
260− function test_haeder_logo() {
328+ function test_header_style_data() {
261− genericScopeView.scope = scopes.getScope(3);
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+ }
262
336
263− var image = findChild(genericScopeView, "titleImage");
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");
264− verify(image, "Could not find the title image");
343+ verify(innerHeader, "Could not find the inner header");
265− compare(image.source, Qt.resolvedUrl("../Components/tst_PageHeader/logo-ubuntu-orange.svg"), "Title image has the wrong source");
344+ verify(Qt.colorEqual(innerHeader.textColor, data.foreground),
345+ "Foreground color not equal: %1 != %2".arg(innerHeader.textColor).arg(data.foreground));
266
346
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");
267 }
355 }
268 }
356 }
269 }
357 }