Merge lp:~unity-team/unity8/ota9.5 into lp:unity8/stable

Proposed by Michał Sawicz
Status: Merged
Approved by: Michał Sawicz
Approved revision: 2142
Merged at revision: 2140
Proposed branch: lp:~unity-team/unity8/ota9.5
Merge into: lp:unity8/stable
Diff against target: 755 lines (+464/-66)
13 files modified
plugins/Dash/CardCreator.js (+34/-30)
plugins/Dash/CardCreatorCache.qml (+1/-1)
plugins/Dash/listviewwithpageheader.cpp (+18/-9)
plugins/Dash/listviewwithpageheader.h (+1/-0)
tests/plugins/Dash/cardcreator/10.res (+142/-0)
tests/plugins/Dash/cardcreator/10.tst (+2/-1)
tests/plugins/Dash/cardcreator/11.res (+217/-0)
tests/plugins/Dash/cardcreator/11.tst (+3/-0)
tests/plugins/Dash/cardcreator/3.res (+1/-1)
tests/plugins/Dash/cardcreator/6.res (+1/-1)
tests/plugins/Dash/cardcreatortest.cpp (+21/-22)
tests/plugins/Dash/listviewwithpageheadertest.cpp (+23/-0)
tests/plugins/Dash/listviewwithpageheadertest.qml (+0/-1)
To merge this branch: bzr merge lp:~unity-team/unity8/ota9.5
Reviewer Review Type Date Requested Status
Michał Sawicz code Approve
Review via email: mp+285731@code.launchpad.net

Commit message

[r2175] LVWPH: Reset to initial values when list is empty
[r2166] Better attempt at sanitization
[r2162] Do not use the same filepath parameter for all the card creator createQmlObject calls

To post a comment you must log in.
Revision history for this message
Michał Sawicz (saviq) wrote :

Verified the diff is sane for the cherry-picks.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Dash/CardCreator.js'
2--- plugins/Dash/CardCreator.js 2016-01-21 22:33:46 +0000
3+++ plugins/Dash/CardCreator.js 2016-02-11 14:27:32 +0000
4@@ -16,9 +16,9 @@
5
6 .pragma library
7
8-// %1 is the template["card-background"] string
9-// %2 is the template["card-background"]["elements"][0]
10-// %3 is the template["card-background"]["elements"][1]
11+// %1 is the template["card-background"]["elements"][0]
12+// %2 is the template["card-background"]["elements"][1]
13+// %3 is the template["card-background"] string
14 var kBackgroundLoaderCode = 'Loader {\n\
15 id: backgroundLoader; \n\
16 objectName: "backgroundLoader"; \n\
17@@ -46,14 +46,14 @@
18 objectName: "backgroundImage"; \n\
19 source: { \n\
20 if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\
21- else return "%1"; \n\
22+ else return %3; \n\
23 } \n\
24 } \n\
25 function getColor(index) { \n\
26 if (cardData && typeof cardData["background"] === "object" \n\
27 && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) { \n\
28 return cardData["background"]["elements"][index]; \n\
29- } else return index === 0 ? %2 : %3; \n\
30+ } else return index === 0 ? %1 : %2; \n\
31 } \n\
32 } \n\
33 }\n';
34@@ -373,27 +373,21 @@
35 color: %3; \n\
36 }';
37
38-function evil_param(object) {
39- for (var x in object) {
40- if (typeof object[x] === "object" && evil_param(object[x]))
41- return true;
42-
43- if (typeof object[x] === "string" && object[x].match(/"(?:[^"\\]|\\.)*"/) != null)
44- return true;
45+function sanitizeColor(colorString) {
46+ if (colorString !== undefined) {
47+ if (colorString.match(/^[#a-z0-9]*$/i) === null) {
48+ // This is not the perfect regexp for color
49+ // but what we're trying to do here is just protect
50+ // against injection so it's ok
51+ return "";
52+ }
53 }
54-
55- return false;
56+ return colorString;
57 }
58
59 function cardString(template, components) {
60 var code;
61
62- if (evil_param(template))
63- return "";
64-
65- if (evil_param(components))
66- return "";
67-
68 var templateInteractive = (template == null ? true : (template["non-interactive"] !== undefined ? !template["non-interactive"] : true)) ? "true" : "false";
69
70 code = 'AbstractButton { \n\
71@@ -442,18 +436,26 @@
72 }
73
74 if (hasBackground) {
75- var templateCardBackground = (template && typeof template["card-background"] === "string") ? template["card-background"] : "";
76+ var templateCardBackground;
77+ if (template && typeof template["card-background"] === "string") {
78+ templateCardBackground = 'decodeURI("' + encodeURI(template["card-background"]) + '")';
79+ } else {
80+ templateCardBackground = '""';
81+ }
82+
83 var backgroundElements0;
84 var backgroundElements1;
85 if (template && typeof template["card-background"] === "object" && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
86- if (template["card-background"]["elements"][0] !== undefined) {
87- backgroundElements0 = '"%1"'.arg(template["card-background"]["elements"][0]);
88+ var element0 = sanitizeColor(template["card-background"]["elements"][0]);
89+ var element1 = sanitizeColor(template["card-background"]["elements"][1]);
90+ if (element0 !== undefined) {
91+ backgroundElements0 = '"%1"'.arg(element0);
92 }
93- if (template["card-background"]["elements"][1] !== undefined) {
94- backgroundElements1 = '"%1"'.arg(template["card-background"]["elements"][1]);
95+ if (element1 !== undefined) {
96+ backgroundElements1 = '"%1"'.arg(element1);
97 }
98 }
99- code += kBackgroundLoaderCode.arg(templateCardBackground).arg(backgroundElements0).arg(backgroundElements1);
100+ code += kBackgroundLoaderCode.arg(backgroundElements0).arg(backgroundElements1).arg(templateCardBackground);
101 }
102
103 if (hasArt) {
104@@ -479,9 +481,10 @@
105 }
106
107 var fallback = components["art"] && components["art"]["fallback"] || "";
108+ fallback = encodeURI(fallback);
109 var fallbackCode = "";
110 if (fallback !== "") {
111- fallbackCode += 'onStatusChanged: if (status === Image.Error) source = "%1";'.arg(fallback);
112+ fallbackCode += 'onStatusChanged: if (status === Image.Error) source = decodeURI("%1");'.arg(fallback);
113 }
114 code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode).arg(fallbackCode);
115 } else {
116@@ -576,9 +579,10 @@
117
118 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
119 var fallback = components["mascot"] && components["mascot"]["fallback"] || "";
120+ fallback = encodeURI(fallback);
121 var fallbackCode = "";
122 if (fallback !== "") {
123- fallbackCode += 'onStatusChanged: if (status === Image.Error) source = "%1";'.arg(fallback);
124+ fallbackCode += 'onStatusChanged: if (status === Image.Error) source = decodeURI("%1");'.arg(fallback);
125 }
126 mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible).arg(fallbackCode);
127 }
128@@ -825,7 +829,7 @@
129 return code;
130 }
131
132-function createCardComponent(parent, template, components) {
133+function createCardComponent(parent, template, components, identifier) {
134 var imports = 'import QtQuick 2.4; \n\
135 import Ubuntu.Components 1.3; \n\
136 import Ubuntu.Settings.Components 0.1; \n\
137@@ -835,7 +839,7 @@
138 var code = imports + 'Component {\n' + card + '}\n';
139
140 try {
141- return Qt.createQmlObject(code, parent, "createCardComponent");
142+ return Qt.createQmlObject(code, parent, identifier);
143 } catch (e) {
144 console.error("ERROR: Invalid component created.");
145 console.error("Template:");
146
147=== modified file 'plugins/Dash/CardCreatorCache.qml'
148--- plugins/Dash/CardCreatorCache.qml 2015-07-15 15:07:19 +0000
149+++ plugins/Dash/CardCreatorCache.qml 2016-02-11 14:27:32 +0000
150@@ -32,7 +32,7 @@
151 var allString = tString + cString;
152 var component = cache[allString];
153 if (component === undefined) {
154- component = CardCreator.createCardComponent(root, template, components);
155+ component = CardCreator.createCardComponent(root, template, components, allString);
156 cache[allString] = component;
157 }
158 return component;
159
160=== modified file 'plugins/Dash/listviewwithpageheader.cpp'
161--- plugins/Dash/listviewwithpageheader.cpp 2016-01-05 09:24:58 +0000
162+++ plugins/Dash/listviewwithpageheader.cpp 2016-02-11 14:27:32 +0000
163@@ -219,13 +219,7 @@
164 Q_FOREACH(ListItem *item, m_visibleItems)
165 releaseItem(item);
166 m_visibleItems.clear();
167- m_firstVisibleIndex = -1;
168- adjustMinYExtent();
169- setContentY(0);
170- m_clipItem->setY(0);
171- if (m_topSectionItem) {
172- QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
173- }
174+ initializeValuesForEmptyList();
175
176 m_delegateModel->setDelegate(delegate);
177
178@@ -236,6 +230,17 @@
179 }
180 }
181
182+void ListViewWithPageHeader::initializeValuesForEmptyList()
183+{
184+ m_firstVisibleIndex = -1;
185+ adjustMinYExtent();
186+ setContentY(0);
187+ m_clipItem->setY(0);
188+ if (m_topSectionItem) {
189+ QQuickItemPrivate::get(m_topSectionItem)->setCulled(true);
190+ }
191+}
192+
193 QQuickItem *ListViewWithPageHeader::header() const
194 {
195 return m_headerItem;
196@@ -835,7 +840,7 @@
197 }
198 }
199 if (!foundVisible) {
200- m_firstVisibleIndex = -1;
201+ initializeValuesForEmptyList();
202 }
203 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
204 adjustMinYExtent();
205@@ -1092,7 +1097,11 @@
206 }
207
208 if (m_firstVisibleIndex != oldFirstVisibleIndex) {
209- adjustMinYExtent();
210+ if (m_visibleItems.isEmpty()) {
211+ initializeValuesForEmptyList();
212+ } else {
213+ adjustMinYExtent();
214+ }
215 }
216
217 for (int i = 0; i < m_visibleItems.count(); ++i) {
218
219=== modified file 'plugins/Dash/listviewwithpageheader.h'
220--- plugins/Dash/listviewwithpageheader.h 2015-11-26 13:50:56 +0000
221+++ plugins/Dash/listviewwithpageheader.h 2016-02-11 14:27:32 +0000
222@@ -168,6 +168,7 @@
223 QQuickItem *getSectionItem(int modelIndex, bool alreadyInserted);
224 QQuickItem *getSectionItem(const QString &sectionText);
225 void updateSectionItem(int modelIndex);
226+ void initializeValuesForEmptyList();
227
228 QQmlDelegateModel *m_delegateModel;
229
230
231=== added directory 'plugins/UInput'
232=== added file 'tests/plugins/Dash/cardcreator/10.res'
233--- tests/plugins/Dash/cardcreator/10.res 1970-01-01 00:00:00 +0000
234+++ tests/plugins/Dash/cardcreator/10.res 2016-02-11 14:27:32 +0000
235@@ -0,0 +1,142 @@
236+AbstractButton {
237+ id: root;
238+ property var components;
239+ property var cardData;
240+ property string artShapeStyle: "inset";
241+ property string backgroundShapeStyle: "inset";
242+ property real fontScale: 1.0;
243+ property var scopeStyle: null;
244+ property int titleAlignment: Text.AlignLeft;
245+ property int fixedHeaderHeight: -1;
246+ property size fixedArtShapeSize: Qt.size(-1, -1);
247+ readonly property string title: cardData && cardData["title"] || "";
248+ property bool asynchronous: true;
249+ property bool showHeader: true;
250+ implicitWidth: childrenRect.width;
251+ enabled: true;
252+
253+Loader {
254+ id: backgroundLoader;
255+ objectName: "backgroundLoader";
256+ anchors.fill: parent;
257+ asynchronous: root.asynchronous;
258+ visible: status == Loader.Ready;
259+ sourceComponent: UbuntuShape {
260+ objectName: "background";
261+ radius: "medium";
262+ aspect: {
263+ switch (root.backgroundShapeStyle) {
264+ case "inset": return UbuntuShape.Inset;
265+ case "shadow": return UbuntuShape.DropShadow;
266+ default:
267+ case "flat": return UbuntuShape.Flat;
268+ }
269+ }
270+ backgroundColor: getColor(0) || "white";
271+ secondaryBackgroundColor: getColor(1) || backgroundColor;
272+ backgroundMode: UbuntuShape.VerticalGradient;
273+ anchors.fill: parent;
274+ source: backgroundImage.source ? backgroundImage : null;
275+ property real luminance: Style.luminance(backgroundColor);
276+ property Image backgroundImage: Image {
277+ objectName: "backgroundImage";
278+ source: {
279+ if (cardData && typeof cardData["background"] === "string") return cardData["background"];
280+ else return "";
281+ }
282+ }
283+ function getColor(index) {
284+ if (cardData && typeof cardData["background"] === "object"
285+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
286+ return cardData["background"]["elements"][index];
287+ } else return index === 0 ? "" : "";
288+ }
289+ }
290+ }
291+readonly property size artShapeSize: Qt.size(-1, -1);
292+readonly property int headerHeight: row.height;
293+Row {
294+ id: row;
295+ objectName: "outerRow";
296+ property real margins: units.gu(1);
297+ spacing: margins;
298+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
299+ anchors { top: parent.top;
300+ topMargin: units.gu(1);
301+left: parent.left;
302+ }
303+ anchors.right: parent.right;
304+ anchors.margins: margins;
305+ anchors.rightMargin: 0;
306+ data: [
307+ CroppedImageMinimumSourceSize {
308+ id: mascotImage;
309+ objectName: "mascotImage";
310+ anchors { verticalCenter: parent.verticalCenter; }
311+ source: cardData && cardData["mascot"] || "";
312+ width: units.gu(6);
313+ height: units.gu(5.625);
314+ horizontalAlignment: Image.AlignHCenter;
315+ verticalAlignment: Image.AlignVCenter;
316+ visible: showHeader;
317+
318+ }
319+,Item {
320+ id: headerTitleContainer;
321+ anchors { verticalCenter: parent.verticalCenter; }
322+ width: parent.width - x;
323+ implicitHeight: titleLabel.height + subtitleLabel.height;
324+ data: [
325+ Label {
326+ id: titleLabel;
327+ objectName: "titleLabel";
328+ anchors { right: parent.right;
329+rightMargin: units.gu(1);
330+left: parent.left;
331+ top: parent.top; }
332+ elide: Text.ElideRight;
333+ fontSize: "small";
334+ wrapMode: Text.Wrap;
335+ maximumLineCount: 2;
336+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
337+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white");
338+ visible: showHeader ;
339+ width: undefined;
340+ text: root.title;
341+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
342+ horizontalAlignment: root.titleAlignment;
343+ }
344+,Label {
345+ id: subtitleLabel;
346+ objectName: "subtitleLabel";
347+ anchors { right: parent.right;
348+ left: parent.left;
349+rightMargin: units.gu(1);
350+top: titleLabel.bottom;
351+ }
352+ anchors.topMargin: units.dp(2);
353+ elide: Text.ElideRight;
354+ maximumLineCount: 1;
355+ fontSize: "x-small";
356+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
357+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white");
358+ visible: titleLabel.visible && titleLabel.text;
359+ text: cardData && cardData["subtitle"] || "";
360+ font.weight: Font.Light;
361+ }
362+
363+ ]
364+ }
365+
366+ ]
367+ }
368+UbuntuShape {
369+ id: touchdown;
370+ objectName: "touchdown";
371+ anchors { fill: backgroundLoader }
372+ visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
373+ radius: "medium";
374+ borderSource: "radius_pressed.sci"
375+ }
376+implicitHeight: row.y + row.height + units.gu(1);
377+}
378
379=== modified file 'tests/plugins/Dash/cardcreator/10.tst'
380--- tests/plugins/Dash/cardcreator/10.tst 2016-01-21 22:33:46 +0000
381+++ tests/plugins/Dash/cardcreator/10.tst 2016-02-11 14:27:32 +0000
382@@ -1,2 +1,3 @@
383-template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2, "card-background": { "type": "color", "elements": [ "\" : \"\";} Item { } function moo() { return true ? \"" ] } }
384+template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2, "card-background": { "type": "color", "elements": [ "\\", ": 3; } Item { } function moo () { \"" ] } }
385 components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{}}
386+result: 10.res
387\ No newline at end of file
388
389=== added file 'tests/plugins/Dash/cardcreator/11.res'
390--- tests/plugins/Dash/cardcreator/11.res 1970-01-01 00:00:00 +0000
391+++ tests/plugins/Dash/cardcreator/11.res 2016-02-11 14:27:32 +0000
392@@ -0,0 +1,217 @@
393+AbstractButton {
394+ id: root;
395+ property var components;
396+ property var cardData;
397+ property string artShapeStyle: "inset";
398+ property string backgroundShapeStyle: "inset";
399+ property real fontScale: 1.0;
400+ property var scopeStyle: null;
401+ property int titleAlignment: Text.AlignLeft;
402+ property int fixedHeaderHeight: -1;
403+ property size fixedArtShapeSize: Qt.size(-1, -1);
404+ readonly property string title: cardData && cardData["title"] || "";
405+ property bool asynchronous: true;
406+ property bool showHeader: true;
407+ implicitWidth: childrenRect.width;
408+ enabled: true;
409+
410+Loader {
411+ id: backgroundLoader;
412+ objectName: "backgroundLoader";
413+ anchors.fill: parent;
414+ asynchronous: root.asynchronous;
415+ visible: status == Loader.Ready;
416+ sourceComponent: UbuntuShape {
417+ objectName: "background";
418+ radius: "medium";
419+ aspect: {
420+ switch (root.backgroundShapeStyle) {
421+ case "inset": return UbuntuShape.Inset;
422+ case "shadow": return UbuntuShape.DropShadow;
423+ default:
424+ case "flat": return UbuntuShape.Flat;
425+ }
426+ }
427+ backgroundColor: getColor(0) || "white";
428+ secondaryBackgroundColor: getColor(1) || backgroundColor;
429+ backgroundMode: UbuntuShape.VerticalGradient;
430+ anchors.fill: parent;
431+ source: backgroundImage.source ? backgroundImage : null;
432+ property real luminance: Style.luminance(backgroundColor);
433+ property Image backgroundImage: Image {
434+ objectName: "backgroundImage";
435+ source: {
436+ if (cardData && typeof cardData["background"] === "string") return cardData["background"];
437+ else return "";
438+ }
439+ }
440+ function getColor(index) {
441+ if (cardData && typeof cardData["background"] === "object"
442+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
443+ return cardData["background"]["elements"][index];
444+ } else return index === 0 ? "#E9E9E9" : undefined;
445+ }
446+ }
447+ }
448+readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
449+Item {
450+ id: artShapeHolder;
451+ height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
452+ width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
453+ anchors { horizontalCenter: parent.horizontalCenter; }
454+ Loader {
455+ id: artShapeLoader;
456+ objectName: "artShapeLoader";
457+ active: cardData && cardData["art"] || false;
458+ asynchronous: root.asynchronous;
459+ visible: status == Loader.Ready;
460+ sourceComponent: Item {
461+ id: artShape;
462+ objectName: "artShape";
463+ readonly property bool doShapeItem: components["art"]["conciergeMode"] !== true;
464+ visible: image.status == Image.Ready;
465+ readonly property alias image: artImage;
466+ ShaderEffectSource {
467+ id: artShapeSource;
468+ sourceItem: artImage;
469+ anchors.centerIn: parent;
470+ width: 1;
471+ height: 1;
472+ hideSource: doShapeItem;
473+ }
474+ Loader {
475+ anchors.fill: parent;
476+ visible: artShape.doShapeItem;
477+ sourceComponent: root.artShapeStyle === "icon" ? artShapeIconComponent : artShapeShapeComponent;
478+ Component {
479+ id: artShapeShapeComponent;
480+ UbuntuShape {
481+ source: artShapeSource;
482+ sourceFillMode: UbuntuShape.PreserveAspectCrop;
483+ radius: "medium";
484+ aspect: {
485+ switch (root.artShapeStyle) {
486+ case "inset": return UbuntuShape.Inset;
487+ case "shadow": return UbuntuShape.DropShadow;
488+ default:
489+ case "flat": return UbuntuShape.Flat;
490+ }
491+ }
492+ }
493+ }
494+ Component {
495+ id: artShapeIconComponent;
496+ ProportionalShape { source: artShapeSource; aspect: UbuntuShape.DropShadow; }
497+ }
498+ }
499+ readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
500+ readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
501+ Component.onCompleted: { updateWidthHeightBindings(); }
502+ Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
503+ function updateWidthHeightBindings() {
504+ if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
505+ width = root.fixedArtShapeSize.width;
506+ height = root.fixedArtShapeSize.height;
507+ } else {
508+ width = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.width });
509+ height = Qt.binding(function() { return image.status !== Image.Ready ? 0 : image.height });
510+ }
511+ }
512+ CroppedImageMinimumSourceSize {
513+ id: artImage;
514+ objectName: "artImage";
515+ source: cardData && cardData["art"] || "";
516+ asynchronous: root.asynchronous;
517+ width: root.width;
518+ height: width / artShape.aspect;
519+ onStatusChanged: if (status === Image.Error) source = decodeURI("%5C");
520+ }
521+ }
522+ }
523+ }
524+readonly property int headerHeight: row.height;
525+Row {
526+ id: row;
527+ objectName: "outerRow";
528+ property real margins: units.gu(1);
529+ spacing: margins;
530+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
531+ anchors { top: artShapeHolder.bottom;
532+ topMargin: units.gu(1);
533+left: parent.left;
534+ }
535+ anchors.right: parent.right;
536+ anchors.margins: margins;
537+ anchors.rightMargin: 0;
538+ data: [
539+ CroppedImageMinimumSourceSize {
540+ id: mascotImage;
541+ objectName: "mascotImage";
542+ anchors { verticalCenter: parent.verticalCenter; }
543+ source: cardData && cardData["mascot"] || "";
544+ width: units.gu(6);
545+ height: units.gu(5.625);
546+ horizontalAlignment: Image.AlignHCenter;
547+ verticalAlignment: Image.AlignVCenter;
548+ visible: showHeader;
549+ onStatusChanged: if (status === Image.Error) source = decodeURI("%22");
550+ }
551+,Item {
552+ id: headerTitleContainer;
553+ anchors { verticalCenter: parent.verticalCenter; }
554+ width: parent.width - x;
555+ implicitHeight: titleLabel.height + subtitleLabel.height;
556+ data: [
557+ Label {
558+ id: titleLabel;
559+ objectName: "titleLabel";
560+ anchors { right: parent.right;
561+rightMargin: units.gu(1);
562+left: parent.left;
563+ top: parent.top; }
564+ elide: Text.ElideRight;
565+ fontSize: "small";
566+ wrapMode: Text.Wrap;
567+ maximumLineCount: 2;
568+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
569+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white");
570+ visible: showHeader ;
571+ width: undefined;
572+ text: root.title;
573+ font.weight: cardData && cardData["subtitle"] ? Font.DemiBold : Font.Normal;
574+ horizontalAlignment: root.titleAlignment;
575+ }
576+,Label {
577+ id: subtitleLabel;
578+ objectName: "subtitleLabel";
579+ anchors { right: parent.right;
580+ left: parent.left;
581+rightMargin: units.gu(1);
582+top: titleLabel.bottom;
583+ }
584+ anchors.topMargin: units.dp(2);
585+ elide: Text.ElideRight;
586+ maximumLineCount: 1;
587+ fontSize: "x-small";
588+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
589+ color: backgroundLoader.active && backgroundLoader.item && root.scopeStyle ? root.scopeStyle.getTextColor(backgroundLoader.item.luminance) : (backgroundLoader.item && backgroundLoader.item.luminance > 0.7 ? theme.palette.normal.baseText : "white");
590+ visible: titleLabel.visible && titleLabel.text;
591+ text: cardData && cardData["subtitle"] || "";
592+ font.weight: Font.Light;
593+ }
594+
595+ ]
596+ }
597+
598+ ]
599+ }
600+UbuntuShape {
601+ id: touchdown;
602+ objectName: "touchdown";
603+ anchors { fill: backgroundLoader }
604+ visible: root.artShapeStyle != "shadow" && root.artShapeStyle != "icon" && root.pressed;
605+ radius: "medium";
606+ borderSource: "radius_pressed.sci"
607+ }
608+implicitHeight: row.y + row.height + units.gu(1);
609+}
610
611=== added file 'tests/plugins/Dash/cardcreator/11.tst'
612--- tests/plugins/Dash/cardcreator/11.tst 1970-01-01 00:00:00 +0000
613+++ tests/plugins/Dash/cardcreator/11.tst 2016-02-11 14:27:32 +0000
614@@ -0,0 +1,3 @@
615+template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2 }
616+components: {"art":{"aspect-ratio":1,"field":"art","fallback":"\\"},"background":{"field":"background"},"mascot":{"field":"icon","fallback":"\""},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{}}
617+result: 11.res
618\ No newline at end of file
619
620=== modified file 'tests/plugins/Dash/cardcreator/3.res'
621--- tests/plugins/Dash/cardcreator/3.res 2016-01-21 22:44:41 +0000
622+++ tests/plugins/Dash/cardcreator/3.res 2016-02-11 14:27:32 +0000
623@@ -86,7 +86,7 @@
624 asynchronous: root.asynchronous;
625 width: root.width;
626 height: width / artShape.aspect;
627- onStatusChanged: if (status === Image.Error) source = "IHAVE\"ESCAPED\"QUOTES\"";
628+ onStatusChanged: if (status === Image.Error) source = decodeURI("IHAVE%5C%22ESCAPED%5C%22QUOTES%5C%22");
629 }
630 }
631 }
632
633=== modified file 'tests/plugins/Dash/cardcreator/6.res'
634--- tests/plugins/Dash/cardcreator/6.res 2015-11-20 16:33:38 +0000
635+++ tests/plugins/Dash/cardcreator/6.res 2016-02-11 14:27:32 +0000
636@@ -42,7 +42,7 @@
637 objectName: "backgroundImage";
638 source: {
639 if (cardData && typeof cardData["background"] === "string") return cardData["background"];
640- else return "http://assets.ubuntu.com/sites/ubuntu/latest/u/img/logos/logo-ubuntu-grey.png";
641+ else return decodeURI("http://assets.ubuntu.com/sites/ubuntu/latest/u/img/logos/logo-ubuntu-grey.png");
642 }
643 }
644 function getColor(index) {
645
646=== modified file 'tests/plugins/Dash/cardcreatortest.cpp'
647--- tests/plugins/Dash/cardcreatortest.cpp 2016-01-21 22:33:46 +0000
648+++ tests/plugins/Dash/cardcreatortest.cpp 2016-02-11 14:27:32 +0000
649@@ -63,6 +63,7 @@
650
651 QVERIFY(lines[0].startsWith(templateString));
652 QVERIFY(lines[1].startsWith(componentsString));
653+ QVERIFY(lines[2].startsWith(resultString));
654
655 const QString templateJSON = lines[0].mid(templateString.length());
656 const QString componentsJSON = lines[1].mid(componentsString.length());
657@@ -71,32 +72,30 @@
658 QVariant cardStringResult;
659 QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
660
661- if (!resultFileName.isEmpty()) {
662- QFile testResultFile(testDirPath + resultFileName);
663- QVERIFY(testResultFile.open(QIODevice::ReadOnly));
664- QTextStream ts2(&testResultFile);
665-
666- // Record failed results to /tmp
667- const QString executedResult = cardStringResult.toString();
668- QTemporaryFile tmpFile(QDir::tempPath() + QDir::separator() + "testCardCreatorFailedResultXXXXXX");
669- tmpFile.open();
670- tmpFile.setAutoRemove(false);
671- tmpFile.write(executedResult.toUtf8().constData());
672-
673- // Line by line comparison
674- const QStringList expectedLines = ts2.readAll().trimmed().replace(QRegExp("\n\\s*\n"),"\n").split("\n");
675- const QStringList cardStringResultLines = cardStringResult.toString().trimmed().replace(QRegExp("\n\\s*\n"),"\n").split("\n");
676- for (int i = 0; i < expectedLines.size(); ++i) {
677- QCOMPARE(cardStringResultLines[i].simplified(), expectedLines[i].simplified());
678- }
679-
680- // Remove the result if it passed
681- tmpFile.setAutoRemove(true);
682+ QFile testResultFile(testDirPath + resultFileName);
683+ QVERIFY(testResultFile.open(QIODevice::ReadOnly));
684+ QTextStream ts2(&testResultFile);
685+
686+ // Record failed results to /tmp
687+ const QString executedResult = cardStringResult.toString();
688+ QTemporaryFile tmpFile(QDir::tempPath() + QDir::separator() + "testCardCreatorFailedResultXXXXXX");
689+ tmpFile.open();
690+ tmpFile.setAutoRemove(false);
691+ tmpFile.write(executedResult.toUtf8().constData());
692+
693+ // Line by line comparison
694+ const QStringList expectedLines = ts2.readAll().trimmed().replace(QRegExp("\n\\s*\n"),"\n").split("\n");
695+ const QStringList cardStringResultLines = cardStringResult.toString().trimmed().replace(QRegExp("\n\\s*\n"),"\n").split("\n");
696+ for (int i = 0; i < expectedLines.size(); ++i) {
697+ QCOMPARE(cardStringResultLines[i].simplified(), expectedLines[i].simplified());
698 }
699
700+ // Remove the result if it passed
701+ tmpFile.setAutoRemove(true);
702+
703 QVariant createCardComponentResult;
704 QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
705- QCOMPARE(createCardComponentResult.toBool(), !resultFileName.isEmpty());
706+ QVERIFY(createCardComponentResult.toBool());
707 }
708 }
709
710
711=== modified file 'tests/plugins/Dash/listviewwithpageheadertest.cpp'
712--- tests/plugins/Dash/listviewwithpageheadertest.cpp 2015-09-02 08:04:41 +0000
713+++ tests/plugins/Dash/listviewwithpageheadertest.cpp 2016-02-11 14:27:32 +0000
714@@ -1954,6 +1954,29 @@
715 QCOMPARE(lvwph->m_firstVisibleIndex, 0);
716 }
717
718+ void testBug1540490()
719+ {
720+ lvwph->header()->setImplicitHeight(150);
721+ verifyItem(0, 150., 150., false);
722+
723+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 3), Q_ARG(QVariant, 3));
724+ model->setProperty(0, "size", 400);
725+ model->setProperty(1, "size", 600);
726+ model->setProperty(2, "size", 300);
727+
728+ scrollToBottom();
729+ changeContentY(-200);
730+
731+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 1), Q_ARG(QVariant, 2));
732+ model->setProperty(0, "size", 100);
733+ QMetaObject::invokeMethod(model, "removeItems", Q_ARG(QVariant, 0), Q_ARG(QVariant, 1));
734+ lvwph->header()->setImplicitHeight(50);
735+ QMetaObject::invokeMethod(model, "insertItem", Q_ARG(QVariant, 0), Q_ARG(QVariant, 200));
736+
737+ QTRY_COMPARE(lvwph->m_visibleItems.count(), 1);
738+ verifyItem(0, 50., 200., false);
739+ }
740+
741 private:
742 QQuickView *view;
743 ListViewWithPageHeader *lvwph;
744
745=== modified file 'tests/plugins/Dash/listviewwithpageheadertest.qml'
746--- tests/plugins/Dash/listviewwithpageheadertest.qml 2015-07-15 15:07:19 +0000
747+++ tests/plugins/Dash/listviewwithpageheadertest.qml 2016-02-11 14:27:32 +0000
748@@ -85,7 +85,6 @@
749 pageHeader: Rectangle {
750 color: "transparent"
751 width: parent.width
752- height: 50
753 implicitHeight: 50
754 Text {
755 anchors.fill: parent

Subscribers

People subscribed via source and target branches

to all changes: