on xenial help sign in
Bring Card and CardHeader over from new-scopes.

Approved by PS Jenkins bot, Michael Zanetti.

commit11ac636fb3ea8aad96854a710d3a72539c6e8ee2 authorMichał Sawicz <michal.sawicz@canonical.com> dateFri 10 Jan 2014, 14:28 (13 years ago) parent1663e5c3142c97
8 files changed+747
qml/Dash/Card.qml+83 qml/Dash/CardHeader.qml+112 tests/qmltests/CMakeLists.txt+2 tests/qmltests/Dash/CardHelpers.js+75 tests/qmltests/Dash/artwork/avatar@12.png tests/qmltests/Dash/artwork/music-player-design.png tests/qmltests/Dash/tst_Card.qml+337 tests/qmltests/Dash/tst_CardHeader.qml+138
qml/Dash/Card.qmlnew file+83
@@ -0,0 +1,83 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+
20+Item {
21+ id: root
22+ property var template
23+ property var components
24+ property var cardData
25+
26+ width: {
27+ if (template !== undefined) {
28+ if (template["card-layout"] === "horizontal") return units.gu(38);
29+ switch (template['card-size']) {
30+ case "small": return units.gu(12);
31+ case "large": return units.gu(38);
32+ }
33+ }
34+ return units.gu(18.5);
35+ }
36+ height: childrenRect.height
37+
38+ UbuntuShape {
39+ id: artShape
40+ objectName: "artShape"
41+ width: image.fillMode === Image.PreserveAspectCrop || aspect < image.aspect ? image.width : height * image.aspect
42+ height: image.fillMode === Image.PreserveAspectCrop || aspect > image.aspect ? image.height : width / image.aspect
43+ anchors.horizontalCenter: template && template["card-layout"] === "horizontal" ? undefined : parent.horizontalCenter
44+
45+ property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1
46+
47+ image: Image {
48+ width: template && template["card-layout"] === "horizontal" ? height * artShape.aspect : root.width
49+ height: template && template["card-layout"] === "horizontal" ? header.height : width / artShape.aspect
50+ objectName: "artImage"
51+ source: cardData && cardData["art"] || ""
52+ // FIXME uncomment when having investigated / fixed the crash
53+ //sourceSize.width: width > height ? width : 0
54+ //sourceSize.height: height > width ? height : 0
55+ fillMode: components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop
56+
57+ property real aspect: implicitWidth / implicitHeight
58+ }
59+ }
60+
61+ CardHeader {
62+ id: header
63+ objectName: "cardHeader"
64+ anchors {
65+ top: template && template["card-layout"] === "horizontal" ? artShape.top : artShape.bottom
66+ left: template && template["card-layout"] === "horizontal" ? artShape.right : parent.left
67+ right: parent.right
68+ }
69+
70+ mascot: cardData && cardData["mascot"] || ""
71+ title: cardData && cardData["title"] || ""
72+ subtitle: cardData && cardData["subtitle"] || ""
73+ }
74+
75+ Label {
76+ objectName: "summaryLabel"
77+ anchors { top: header.bottom; left: parent.left; right: parent.right }
78+ wrapMode: Text.Wrap
79+ maximumLineCount: 5
80+ elide: Text.ElideRight
81+ text: cardData && cardData["summary"] || ""
82+ }
83+}
qml/Dash/CardHeader.qmlnew file+112
@@ -0,0 +1,112 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+
20+Item {
21+ id: root
22+ property alias mascot: mascotImage.source
23+ property alias title: titleLabel.text
24+ property alias subtitle: subtitleLabel.text
25+ property alias price: priceLabel.text
26+ property alias oldPrice: oldPriceLabel.text
27+ property alias altPrice: altPriceLabel.text
28+
29+ visible: mascotImage.status === Image.Ready || title || price
30+ height: row.height > 0 ? row.height + row.spacing * 2 : 0
31+
32+ Row {
33+ id: row
34+ objectName: "outerRow"
35+
36+ anchors { top: parent.top; left: parent.left; right: parent.right; margins: spacing }
37+ spacing: units.gu(1)
38+
39+ UbuntuShape {
40+ id: mascotShape
41+ objectName: "mascotShape"
42+
43+ width: units.gu(8)
44+ height: units.gu(8)
45+ visible: image.status === Image.Ready
46+
47+ image: Image {
48+ id: mascotImage
49+ sourceSize { width: mascotShape.width; height: mascotShape.height }
50+ }
51+ }
52+
53+ Column {
54+ objectName: "column"
55+ width: parent.width - x
56+
57+ Label {
58+ id: titleLabel
59+ anchors { left: parent.left; right: parent.right }
60+ elide: Text.ElideRight
61+ objectName: "titleLabel"
62+ font.weight: Font.DemiBold
63+ wrapMode: Text.Wrap
64+ maximumLineCount: 2
65+ }
66+
67+ Label {
68+ id: subtitleLabel
69+ anchors { left: parent.left; right: parent.right }
70+ elide: Text.ElideRight
71+ visible: titleLabel.text && text
72+ }
73+
74+ Row {
75+ id: prices
76+ objectName: "prices"
77+ anchors { left: parent.left; right: parent.right }
78+
79+ property int labels: {
80+ var labels = 1; // price always visible
81+ if (oldPriceLabel.text !== "") labels += 1;
82+ if (altPriceLabel.text !== "") labels += 1;
83+ return labels;
84+ }
85+ property real labelWidth: width / labels
86+
87+ Label {
88+ id: priceLabel
89+ width: parent.labelWidth
90+ elide: Text.ElideRight
91+ font.weight: Font.DemiBold
92+ color: Theme.palette.selected.foreground
93+ }
94+
95+ Label {
96+ id: oldPriceLabel
97+ objectName: "oldPriceLabel"
98+ width: parent.labelWidth
99+ elide: Text.ElideRight
100+ horizontalAlignment: parent.labels === 3 ? Text.AlignHCenter : Text.AlignRight
101+ }
102+
103+ Label {
104+ id: altPriceLabel
105+ width: parent.labelWidth
106+ elide: Text.ElideRight
107+ horizontalAlignment: Text.AlignRight
108+ }
109+ }
110+ }
111+ }
112+}
tests/qmltests/CMakeLists.txt+2
@@ -42,6 +42,8 @@ add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAUL
4242add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4343add_qml_test(Dash DashPreview)
4444add_qml_test(Dash GenericPreview)
45+add_qml_test(Dash Card)
46+add_qml_test(Dash CardHeader)
4547add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
4648add_qml_test(Dash FilterGrids IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins
4749 ${CMAKE_BINARY_DIR}/tests/mocks)
tests/qmltests/Dash/CardHelpers.jsnew file+75
@@ -0,0 +1,75 @@
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+.pragma library
18+
19+var components = ["title", "art", "subtitle", "mascot", "emblem", "old-price", "price", "alt-price", "rating", "alt-rating", "summary"]
20+
21+function tryParse(json, errorLabel) {
22+ var o = undefined;
23+ if (errorLabel !== undefined) {
24+ errorLabel.text = "";
25+ }
26+ try {
27+ o = JSON.parse(json)
28+ } catch(err) {
29+ if (errorLabel !== undefined) {
30+ errorLabel.text = err + "";
31+ } else {
32+ console.debug(err);
33+ }
34+ }
35+ return o;
36+}
37+
38+function mapData(json, layout, errorLabel) {
39+ var o = tryParse(json, errorLabel);
40+ var d = undefined;
41+
42+ if (o !== undefined) {
43+ d = Object();
44+ for (var k in components) {
45+ try {
46+ if (typeof layout[components[k]] == "object") {
47+ d[components[k]] = o[layout[components[k]]['field']];
48+ } else {
49+ d[components[k]] = o[layout[components[k]]];
50+ }
51+ } catch(err) {
52+ d[components[k]] = undefined;
53+ }
54+ }
55+ }
56+ return d;
57+}
58+
59+function update(object, overrides) {
60+ for (var k in overrides) {
61+ if (typeof object[k] == "string" && typeof overrides[k] == "object") {
62+ if (!overrides[k].hasOwnProperty('field')) overrides[k]['field'] = object[k];
63+ }
64+ if (object[k] === null) {
65+ object[k] = overrides[k];
66+ } else if (typeof object[k] == "object" && typeof overrides[k] == "string") {
67+ object[k]['field'] = overrides[k];
68+ } else if (typeof object[k] == "object") {
69+ update(object[k], overrides[k]);
70+ } else {
71+ object[k] = overrides[k];
72+ }
73+ }
74+ return object;
75+}
tests/qmltests/Dash/artwork/avatar@12.pngnew file

Binary file not shown.

tests/qmltests/Dash/artwork/music-player-design.pngnew file

Binary file not shown.

tests/qmltests/Dash/tst_Card.qmlnew file+337
@@ -0,0 +1,337 @@
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 QtTest 1.0
19+import Ubuntu.Components 0.1
20+import Unity.Test 0.1 as UT
21+import "../../../qml/Dash"
22+import "CardHelpers.js" as Helpers
23+
24+Rectangle {
25+ id: root
26+ width: units.gu(80)
27+ height: units.gu(72)
28+ color: "#88FFFFFF"
29+
30+ property string defaultLayout: '
31+ {
32+ "schema-version": 1,
33+ "template": {
34+ "category-layout": "grid",
35+ "card-layout": "vertical",
36+ "card-size": "medium",
37+ "overlay-mode": null,
38+ "collapsed-rows": 2
39+ },
40+ "components": {
41+ "title": null,
42+ "art": {
43+ "aspect-ratio": 1.0,
44+ "fill-mode": "crop"
45+ },
46+ "subtitle": null,
47+ "mascot": null,
48+ "emblem": null,
49+ "old-price": null,
50+ "price": null,
51+ "alt-price": null,
52+ "rating": {
53+ "type": "stars",
54+ "range": [0, 5],
55+ "full": "image://theme/rating-star-full",
56+ "half": "image://theme/rating-star-half",
57+ "empty": "image://theme/rating-star-empty"
58+ },
59+ "alt-rating": null,
60+ "summary": null
61+ },
62+ "resources": {}
63+ }'
64+
65+ property string cardData: '
66+ {
67+ "art": "../../tests/qmltests/Dash/artwork/music-player-design.png",
68+ "mascot": "../../tests/qmltests/Dash/artwork/avatar.png",
69+ "title": "foo",
70+ "subtitle": "bar",
71+ "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
72+ }'
73+
74+ property string fullMapping: '
75+ {
76+ "title": "title",
77+ "art": "art",
78+ "subtitle": "subtitle",
79+ "mascot": "mascot",
80+ "summary": "summary"
81+ }'
82+
83+ property var cardsModel: [
84+ {
85+ "name": "Art, header, summary - vertical",
86+ "layout": { "components": JSON.parse(fullMapping) }
87+ },
88+ {
89+ "name": "Art, header, summary - vertical, small",
90+ "layout": { "template": { "card-size": "small" }, "components": JSON.parse(fullMapping) }
91+ },
92+ {
93+ "name": "Art, header, summary - vertical, large",
94+ "layout": { "template": { "card-size": "large" }, "components": JSON.parse(fullMapping) }
95+ },
96+ {
97+ "name": "Art, header, summary - vertical, wide",
98+ "layout": { "components": Helpers.update(JSON.parse(root.fullMapping), { "art": { "aspect-ratio": 2 } }) }
99+ },
100+ {
101+ "name": "Art, title - vertical, fitted",
102+ "layout": { "components": Helpers.update(JSON.parse(root.fullMapping), { "art": { "fill-mode": "fit" } }) }
103+ },
104+ {
105+ "name": "Art, header, summary - horizontal",
106+ "layout": { "template": { "card-layout": "horizontal" },
107+ "components": JSON.parse(fullMapping) }
108+ },
109+ ]
110+
111+ Card {
112+ id: card
113+ anchors { top: parent.top; left: parent.left; margins: units.gu(1) }
114+
115+ template: Helpers.update(JSON.parse(root.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template'];
116+ components: Helpers.update(JSON.parse(root.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components'];
117+ cardData: Helpers.mapData(dataArea.text, components, dataError)
118+ }
119+
120+ Rectangle {
121+ anchors { top: parent.top; bottom: parent.bottom; right: parent.right}
122+ width: units.gu(40)
123+ color: "lightgrey"
124+
125+ Column {
126+ anchors { fill: parent; margins: units.gu(1) }
127+ spacing: units.gu(1)
128+
129+ OptionSelector {
130+ id: selector
131+ model: cardsModel
132+ delegate: OptionSelectorDelegate { text: modelData.name }
133+ onSelectedIndexChanged: updateAreas()
134+ Component.onCompleted: updateAreas()
135+
136+ function updateAreas() {
137+ var element = cardsModel[selectedIndex];
138+ if (element) {
139+ layoutArea.text = JSON.stringify(element.layout, undefined, 2) || "{}";
140+ // FIXME: don't overwrite data
141+ var data = JSON.parse(root.cardData);
142+ Helpers.update(data, element.data);
143+ dataArea.text = JSON.stringify(data, undefined, 2) || "{}";
144+ } else {
145+ layoutArea.text = "";
146+ dataArea.text = "";
147+ }
148+
149+ }
150+ }
151+
152+ TextArea {
153+ id: layoutArea
154+ anchors { left: parent.left; right: parent.right }
155+ height: units.gu(25)
156+ }
157+
158+ Label {
159+ id: layoutError
160+ anchors { left: parent.left; right: parent.right }
161+ height: units.gu(4)
162+ color: "orange"
163+ }
164+
165+ TextArea {
166+ id: dataArea
167+ anchors { left: parent.left; right: parent.right }
168+ height: units.gu(25)
169+ }
170+
171+ Label {
172+ id: dataError
173+ anchors { left: parent.left; right: parent.right }
174+ height: units.gu(4)
175+ color: "orange"
176+ }
177+ }
178+ }
179+
180+ UT.UnityTestCase {
181+ id: testCase
182+ name: "Card"
183+
184+ when: windowShown
185+
186+ property Item header: findChild(card, "cardHeader")
187+ property Item art: findChild(card, "artShape")
188+ property Item artImage: findChild(card, "artImage")
189+ property Item summary: findChild(card, "summaryLabel")
190+
191+ function initTestCase() {
192+ verify(testCase.header !== undefined, "Couldn't find header object.");
193+ }
194+
195+ function cleanup() {
196+ selector.selectedIndex = -1;
197+ }
198+
199+
200+ function test_header_binding_data() {
201+ return [
202+ { tag: "Mascot", property: "mascot", value: Qt.resolvedUrl("artwork/avatar.png"), index: 0 },
203+ { tag: "Title", property: "title", value: "foo", index: 0 },
204+ { tag: "Subtitle", property: "subtitle", value: "bar", index: 0 },
205+ ];
206+ }
207+
208+ function test_header_binding(data) {
209+ selector.selectedIndex = data.index;
210+ tryCompare(testCase.header, data.property, data.value);
211+ }
212+
213+ function test_card_binding_data() {
214+ return [
215+ { tag: "Art", object: artImage, property: "source", value: Qt.resolvedUrl("artwork/music-player-design.png"), index: 0 },
216+ { tag: "Summary", object: summary, property: "text", field: "summary", index: 0 },
217+ { tag: "Fit", object: art, fill: Image.PreserveAspectFit, index: 4 },
218+ ];
219+ }
220+
221+ function test_card_binding(data) {
222+ selector.selectedIndex = data.index;
223+
224+ if (data.hasOwnProperty('value')) {
225+ tryCompare(data.object, data.property, data.value);
226+ }
227+
228+ if (data.hasOwnProperty('field')) {
229+ tryCompare(data.object, data.property, card.cardData[data.field]);
230+ }
231+ }
232+
233+ function test_card_size_data() {
234+ return [
235+ { tag: "Medium", width: units.gu(18.5), index: 0 },
236+ { tag: "Small", width: units.gu(12), size: "small", index: 0 },
237+ { tag: "Large", width: units.gu(38), size: "large", index: 0 },
238+ { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
239+ { tag: "Horizontal", width: units.gu(38), index: 5 },
240+ ]
241+ }
242+
243+ function test_card_size(data) {
244+ selector.selectedIndex = data.index;
245+
246+ if (data.hasOwnProperty("size")) {
247+ card.template['card-size'] = data.size;
248+ card.templateChanged();
249+ }
250+
251+ if (data.hasOwnProperty("aspect")) {
252+ card.components['art']['aspect-ratio'] = data.aspect;
253+ card.componentsChanged();
254+ }
255+
256+ if (data.hasOwnProperty("width")) {
257+ tryCompare(card, "width", data.width);
258+ }
259+
260+ if (data.hasOwnProperty("height")) {
261+ tryCompare(card, "height", data.height);
262+ }
263+ }
264+
265+ function test_art_size_data() {
266+ return [
267+ { tag: "Medium", width: units.gu(18.5), fill: Image.PreserveAspectCrop, index: 0 },
268+ { tag: "Small", width: units.gu(12), index: 1 },
269+ { tag: "Large", width: units.gu(38), index: 2 },
270+ { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
271+ { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
272+ { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
273+ { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
274+ { tag: "HorizontalWidth", width: function() { return header.x }, index: 5 },
275+ ]
276+ }
277+
278+ function test_art_size(data) {
279+ selector.selectedIndex = data.index;
280+
281+ if (data.hasOwnProperty("size")) {
282+ card.template['card-size'] = data.size;
283+ card.templateChanged();
284+ }
285+
286+ if (data.hasOwnProperty("aspect")) {
287+ card.components['art']['aspect-ratio'] = data.aspect;
288+ card.componentsChanged();
289+ }
290+
291+ if (data.hasOwnProperty("width")) {
292+ if (typeof data.width === "function") {
293+ tryCompareFunction(function() { return art.width === data.width() }, true);
294+ } else tryCompare(art, "width", data.width);
295+ }
296+
297+ if (data.hasOwnProperty("height")) {
298+ if (typeof data.height === "function") {
299+ tryCompareFunction(function() { return art.height === data.height() }, true);
300+ } else tryCompare(art, "height", data.height);
301+ }
302+
303+ if (data.hasOwnProperty("fill")) {
304+ tryCompare(artImage, "fillMode", data.fill);
305+ }
306+ }
307+
308+ function test_art_layout_data() {
309+ return [
310+ { tag: "Vertical", left: function() { return 0 }, index: 0},
311+ { tag: "Horizontal", left: function() { return art.width }, index: 5 }
312+ ];
313+ }
314+
315+ function test_art_layout(data) {
316+ selector.selectedIndex = data.index;
317+
318+ tryCompare(testCase.header, "x", data.left());
319+ }
320+
321+ function test_header_layout_data() {
322+ return [
323+ { tag: "Vertical", top: function() { return art.y + art.height },
324+ left: function() { return art.x }, index: 0 },
325+ { tag: "Horizontal", top: function() { return art.y },
326+ left: function() { return art.x + art.width }, index: 5 }
327+ ]
328+ }
329+
330+ function test_header_layout(data) {
331+ selector.selectedIndex = data.index;
332+
333+ tryCompareFunction(function() { return testCase.header.y === data.top() }, true);
334+ tryCompareFunction(function() { return testCase.header.x === data.left() }, true);
335+ }
336+ }
337+}
tests/qmltests/Dash/tst_CardHeader.qmlnew file+138
@@ -0,0 +1,138 @@
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 QtTest 1.0
19+import Ubuntu.Components 0.1
20+import Unity.Test 0.1 as UT
21+import "../../../qml/Dash"
22+
23+
24+Rectangle {
25+ width: units.gu(40)
26+ height: units.gu(72)
27+ color: "lightgrey"
28+
29+ CardHeader {
30+ id: cardHeader
31+ anchors { left: parent.left; right: parent.right }
32+ }
33+
34+ Rectangle {
35+ anchors.fill: cardHeader
36+ color: "lightblue"
37+ opacity: 0.5
38+ }
39+
40+ UT.UnityTestCase {
41+ id: testCase
42+ name: "CardHeader"
43+
44+ when: windowShown
45+
46+ property Item mascot: findChild(cardHeader, "mascotShape")
47+ property Item titleLabel: findChild(cardHeader, "titleLabel")
48+ property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
49+ property Item prices: findChild(cardHeader, "prices")
50+ property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
51+ property Item outerRow: findChild(cardHeader, "outerRow")
52+ property Item column: findChild(cardHeader, "column")
53+
54+ function initTestCase() {
55+ verify(testCase.mascot !== undefined, "Couldn't find mascot object.");
56+ verify(testCase.titleLabel !== undefined, "Couldn't find titleLabel object.");
57+ verify(testCase.subtitleLabel !== undefined, "Couldn't find subtitleLabel object.");
58+ verify(testCase.prices !== undefined, "Couldn't find prices object.");
59+ verify(testCase.oldPriceLabel !== undefined, "Couldn't find oldPriceLabel object.");
60+ }
61+
62+ function cleanup() {
63+ cardHeader.mascot = "";
64+ cardHeader.title = "";
65+ cardHeader.subtitle = "";
66+ cardHeader.price = "";
67+ cardHeader.oldPrice = "";
68+ cardHeader.altPrice = "";
69+ }
70+
71+ function test_mascot_data() {
72+ return [
73+ { tag: "Empty", source: "", visible: false },
74+ { tag: "Invalid", source: "bad_path", visible: false },
75+ { tag: "Valid", source: Qt.resolvedUrl("artwork/avatar.png"), visible: true },
76+ ]
77+ }
78+
79+ function test_mascot(data) {
80+ cardHeader.mascot = data.source;
81+ tryCompare(testCase.mascot, "visible", data.visible);
82+ }
83+
84+ function test_labels_data() {
85+ return [
86+ { tag: "Empty", visible: false },
87+ { tag: "Title only", title: "Foo", visible: true },
88+ { tag: "Subtitle only", subtitle: "Bar", visible: false },
89+ { tag: "Both", title: "Foo", subtitle: "Bar", visible: true }
90+ ]
91+ }
92+
93+ function test_labels(data) {
94+ cardHeader.title = data.title !== undefined ? data.title : "";
95+ cardHeader.subtitle = data.subtitle !== undefined ? data.subtitle : "";
96+ tryCompare(cardHeader, "visible", data.visible);
97+ }
98+
99+ function test_prices_data() {
100+ return [
101+ { tag: "Main", main: "$1.25", visible: true },
102+ { tag: "Alt", alt: "€1.00", visible: false },
103+ { tag: "Old", old: "€2.00", visible: false },
104+ { tag: "Main and Alt", main: "$1.25", alt: "€1.00", visible: true },
105+ { tag: "Main and Old", main: "$1.25", old: "$2.00", visible: true, oldAlign: Text.AlignRight },
106+ { tag: "Alt and Old", alt: "€1.00", old: "$2.00", visible: false },
107+ { tag: "All", main: "$1.25", alt: "€1.00", old: "$2.00", visible: true, oldAlign: Text.AlignHCenter }
108+ ]
109+ }
110+
111+ function test_prices(data) {
112+ cardHeader.price = data.main !== undefined ? data.main : "";
113+ cardHeader.oldPrice = data.old !== undefined ? data.old : "";
114+ cardHeader.altPrice = data.alt !== undefined ? data.alt : "";
115+ tryCompare(cardHeader, "visible", data.visible);
116+ if (data.hasOwnProperty("oldAlign")) {
117+ compare(testCase.oldPriceLabel.horizontalAlignment, data.oldAlign, "Old price label is aligned wrong.")
118+ }
119+ }
120+
121+ function test_dimensions_data() {
122+ return [
123+ { tag: "Column width", object: column, width: cardHeader.width - testCase.outerRow.spacing * 2 },
124+ { tag: "Column width", object: column, width: cardHeader.width - mascot.width - testCase.outerRow.spacing * 3, mascot: "artwork/avatar.png" }
125+ ]
126+ }
127+
128+ function test_dimensions(data) {
129+ if (data.hasOwnProperty("mascot")) {
130+ cardHeader.mascot = data.mascot;
131+ }
132+
133+ if (data.hasOwnProperty("width")) {
134+ tryCompare(data.object, "width", data.width);
135+ }
136+ }
137+ }
138+}