on xenial help sign in
Improve Card creation time by adding loaders that make sure only what's needed is loaded
ab4e43dAlbert Astals
cmake/modules/QmlTest.cmake+16−1
@@ -58,7 +58,15 @@ macro(add_manual_qml_test SUBPATH COMPONENT_NAME)
58
58
59endmacro(add_manual_qml_test)
59endmacro(add_manual_qml_test)
60
60
61+macro(add_qml_benchmark SUBPATH COMPONENT_NAME ITERATIONS)
62+ add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} ${ITERATIONS})
63+endmacro(add_qml_benchmark)
64+
61macro(add_qml_test SUBPATH COMPONENT_NAME)
65macro(add_qml_test SUBPATH COMPONENT_NAME)
66+ add_qml_test_internal(${SUBPATH} ${COMPONENT_NAME} 0)
67+endmacro(add_qml_test)
68+
69+macro(add_qml_test_internal SUBPATH COMPONENT_NAME ITERATIONS)
62 set(options NO_ADD_TEST NO_TARGETS)
70 set(options NO_ADD_TEST NO_TARGETS)
63 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)
71 set(multi_value_keywords IMPORT_PATHS TARGETS PROPERTIES ENVIRONMENT)
64
72
@@ -88,10 +96,17 @@ macro(add_qml_test SUBPATH COMPONENT_NAME)
88 set(function_ARGS "")
96 set(function_ARGS "")
89 endif()
97 endif()
90
98
99+ if (${ITERATIONS} GREATER 0)
100+ set(ITERATIONS_STRING "-iterations" ${ITERATIONS})
101+ else()
102+ set(ITERATIONS_STRING "")
103+ endif()
104+
91 set(qmltest_command
105 set(qmltest_command
92 env ${qmltest_ENVIRONMENT}
106 env ${qmltest_ENVIRONMENT}
93 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
107 ${qmltestrunner_exe} -input ${CMAKE_CURRENT_SOURCE_DIR}/${qmltest_FILE}.qml
94 ${qmltestrunner_imports}
108 ${qmltestrunner_imports}
109+ ${ITERATIONS_STRING}
95 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
110 -o ${CMAKE_BINARY_DIR}/${qmltest_TARGET}.xml,xunitxml
96 -o -,txt
111 -o -,txt
97 ${function_ARGS}
112 ${function_ARGS}
@@ -114,7 +129,7 @@ macro(add_qml_test SUBPATH COMPONENT_NAME)
114 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})
129 add_qmltest_target(${qmltest_TARGET} "${qmltest_command}" TRUE ${qmltest_NO_ADD_TEST})
115 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)
130 add_qmltest_target(${qmltest_xvfb_TARGET} "${qmltest_xvfb_command}" ${qmltest_NO_TARGETS} TRUE)
116 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
131 add_manual_qml_test(${SUBPATH} ${COMPONENT_NAME} ${ARGN})
117−endmacro(add_qml_test)
132+endmacro(add_qml_test_internal)
118
133
119macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
134macro(add_binary_qml_test CLASS_NAME LD_PATH DEPS)
120 set(testCommand
135 set(testCommand
qml/Dash/Card.qml+99−79
@@ -25,47 +25,53 @@ AbstractButton {
25 property var components
25 property var components
26 property var cardData
26 property var cardData
27
27
28− property alias fontScale: header.fontScale
28+ property real fontScale: 1.0
29− property alias headerAlignment: header.headerAlignment
29+ property int headerAlignment: Text.AlignLeft
30− property alias headerHeight: header.height
30+ readonly property int headerHeight: headerLoader.item ? headerLoader.item.height : 0
31+ property int fixedHeaderHeight: -1
31− readonly property alias title: header.title
32+ readonly property string title: cardData && cardData["title"] || ""
32
33
33 property bool showHeader: true
34 property bool showHeader: true
34
35
35 implicitWidth: childrenRect.width
36 implicitWidth: childrenRect.width
36− implicitHeight: summary.y + summary.height + (summary.text && background.visible ? units.gu(1) : 0)
37+ implicitHeight: summary.y + summary.height + (summary.text && backgroundLoader.active ? units.gu(1) : 0)
37
38
38− UbuntuShape {
39+ Loader {
39− id: background
40+ id: backgroundLoader
40− objectName: "background"
41+ objectName: "backgroundLoader"
41− radius: "medium"
42− visible: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"]
43− || artAndSummary)
44− property bool artAndSummary: components["art"]["field"] && components["summary"] || false
45− color: getColor(0) || "white"
46− gradientColor: getColor(1) || color
47− anchors.fill: parent
48− image: backgroundImage.source ? backgroundImage : null
49
42
50− property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
43+ readonly property bool artAndSummary: components["art"]["field"] && components["summary"] || false
44+ active: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"] || artAndSummary)
45+ anchors.fill: parent
51
46
47+ sourceComponent: UbuntuShape {
48+ objectName: "background"
49+ radius: "medium"
50+ color: getColor(0) || "white"
51+ gradientColor: getColor(1) || color
52+ anchors.fill: parent
53+ image: backgroundImage.source ? backgroundImage : null
54+
55+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b
56+
52− property Image backgroundImage: Image {
57+ property Image backgroundImage: Image {
53− objectName: "backgroundImage"
58+ objectName: "backgroundImage"
54− source: {
59+ source: {
55− if (cardData && typeof cardData["background"] === "string") return cardData["background"]
60+ if (cardData && typeof cardData["background"] === "string") return cardData["background"]
56− else if (template && typeof template["card-background"] === "string") return template["card-background"]
61+ else if (template && typeof template["card-background"] === "string") return template["card-background"]
57− else return ""
62+ else return ""
63+ }
58 }
64 }
59− }
60
65
61− function getColor(index) {
66+ function getColor(index) {
62− if (cardData && typeof cardData["background"] === "object"
67+ if (cardData && typeof cardData["background"] === "object"
63− && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
68+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
64− return cardData["background"]["elements"][index];
69+ return cardData["background"]["elements"][index];
65− } else if (template && typeof template["card-background"] === "object"
70+ } else if (template && typeof template["card-background"] === "object"
66− && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
71+ && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
67− return template["card-background"]["elements"][index];
72+ return template["card-background"]["elements"][index];
68− } else return undefined;
73+ } else return undefined;
74+ }
69 }
75 }
70 }
76 }
71
77
@@ -111,7 +117,7 @@ AbstractButton {
111 function updateWidthHeightBindings() {
117 function updateWidthHeightBindings() {
112 if (isHorizontal) {
118 if (isHorizontal) {
113 width = Qt.binding(function() { return height * artShape.aspect });
119 width = Qt.binding(function() { return height * artShape.aspect });
114− height = Qt.binding(function() { return header.height });
120+ height = Qt.binding(function() { return root.headerHeight });
115 } else {
121 } else {
116 width = Qt.binding(function() { return root.width });
122 width = Qt.binding(function() { return root.width });
117 height = Qt.binding(function() { return width / artShape.aspect });
123 height = Qt.binding(function() { return width / artShape.aspect });
@@ -120,53 +126,58 @@ AbstractButton {
120 }
126 }
121 }
127 }
122
128
123− ShaderEffect {
129+ Loader {
124− id: overlay
130+ id: overlayLoader
125 anchors {
131 anchors {
126 left: artShape.left
132 left: artShape.left
127 right: artShape.right
133 right: artShape.right
128 bottom: artShape.bottom
134 bottom: artShape.bottom
129 }
135 }
136+ active: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
130
137
131− height: header.height
138+ sourceComponent: ShaderEffect {
132− opacity: header.opacity * 0.6
139+ id: overlay
133− visible: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false
134
140
141+ height: headerLoader.item ? headerLoader.item.height : 0
142+ opacity: headerLoader.item ? headerLoader.item.opacity * 0.6 : 0
143+
135− property var source: ShaderEffectSource {
144+ property var source: ShaderEffectSource {
136− id: shaderSource
145+ id: shaderSource
137− sourceItem: artShape
146+ sourceItem: artShape
138− onVisibleChanged: if (visible) scheduleUpdate()
147+ onVisibleChanged: if (visible) scheduleUpdate()
139− live: false
148+ live: false
140− sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
149+ sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height)
141− }
150+ }
142
151
143− vertexShader: "
152+ vertexShader: "
144− uniform highp mat4 qt_Matrix;
153+ uniform highp mat4 qt_Matrix;
145− attribute highp vec4 qt_Vertex;
154+ attribute highp vec4 qt_Vertex;
146− attribute highp vec2 qt_MultiTexCoord0;
155+ attribute highp vec2 qt_MultiTexCoord0;
147− varying highp vec2 coord;
156+ varying highp vec2 coord;
148− void main() {
157+ void main() {
149− coord = qt_MultiTexCoord0;
158+ coord = qt_MultiTexCoord0;
150− gl_Position = qt_Matrix * qt_Vertex;
159+ gl_Position = qt_Matrix * qt_Vertex;
151− }"
160+ }"
152−
161+
153− fragmentShader: "
162+ fragmentShader: "
154− varying highp vec2 coord;
163+ varying highp vec2 coord;
155− uniform sampler2D source;
164+ uniform sampler2D source;
156− uniform lowp float qt_Opacity;
165+ uniform lowp float qt_Opacity;
157− void main() {
166+ void main() {
158− lowp vec4 tex = texture2D(source, coord);
167+ lowp vec4 tex = texture2D(source, coord);
159− gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
168+ gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
160− }"
169+ }"
170+ }
161 }
171 }
162
172
163− CardHeader {
173+ Loader {
164− id: header
174+ id: headerLoader
165− objectName: "cardHeader"
175+ objectName: "cardHeaderLoader"
176+
166 anchors {
177 anchors {
167 top: {
178 top: {
168 if (template) {
179 if (template) {
169− if (template["overlay"]) return overlay.top;
180+ if (template["overlay"]) return overlayLoader.top;
170 if (template["card-layout"] === "horizontal") return artShape.top;
181 if (template["card-layout"] === "horizontal") return artShape.top;
171 }
182 }
172 return artShape.bottom;
183 return artShape.bottom;
@@ -179,29 +190,38 @@ AbstractButton {
179 }
190 }
180 right: parent.right
191 right: parent.right
181 }
192 }
193+ active: cardData && cardData["title"] || cardData && cardData["mascot"] || false
194+
195+ sourceComponent: CardHeader {
196+ id: header
197+ objectName: "cardHeader"
182
198
183− mascot: cardData && cardData["mascot"] || ""
199+ mascot: cardData && cardData["mascot"] || ""
184− title: cardData && cardData["title"] || ""
200+ title: root.title
185− subtitle: cardData && cardData["subtitle"] || ""
201+ subtitle: cardData && cardData["subtitle"] || ""
186
202
187− titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
203+ titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal
188
204
189− opacity: showHeader ? 1 : 0
205+ opacity: showHeader ? 1 : 0
190− inOverlay: root.template && root.template["overlay"] === true
206+ inOverlay: root.template && root.template["overlay"] === true
191− fontColor: inOverlay ? "white" : summary.color
207+ fontColor: inOverlay ? "white" : summary.color
192− useMascotShape: !background.visible && !inOverlay
208+ useMascotShape: !backgroundLoader.active && !inOverlay
209+ headerAlignment: root.headerAlignment
210+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight
211+ fontScale: root.fontScale
193
212
194− Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
213+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
214+ }
195 }
215 }
196
216
197 Label {
217 Label {
198 id: summary
218 id: summary
199 objectName: "summaryLabel"
219 objectName: "summaryLabel"
200 anchors {
220 anchors {
201− top: header.visible ? header.bottom : artShape.bottom
221+ top: headerLoader.active ? headerLoader.bottom : artShape.bottom
202 left: parent.left
222 left: parent.left
203 right: parent.right
223 right: parent.right
204− margins: background.visible ? units.gu(1) : 0
224+ margins: backgroundLoader.active ? units.gu(1) : 0
205 topMargin: 0
225 topMargin: 0
206 }
226 }
207 wrapMode: Text.Wrap
227 wrapMode: Text.Wrap
@@ -211,6 +231,6 @@ AbstractButton {
211 height: text ? implicitHeight : 0
231 height: text ? implicitHeight : 0
212 fontSize: "small"
232 fontSize: "small"
213 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
233 // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated.
214− color: background.visible && background.luminance < 0.7 ? "white" : "grey"
234+ color: backgroundLoader.active && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"
215 }
235 }
216}
236}
qml/Dash/CardCarousel.qml+1−1
@@ -52,7 +52,7 @@ DashRenderer {
52 itemComponent: Card {
52 itemComponent: Card {
53 id: card
53 id: card
54 objectName: "carouselDelegate" + index
54 objectName: "carouselDelegate" + index
55− headerHeight: carousel.headerHeight
55+ fixedHeaderHeight: carousel.headerHeight
56 cardData: model
56 cardData: model
57 template: cardTool.template
57 template: cardTool.template
58 components: cardTool.components
58 components: cardTool.components
qml/Dash/CardFilterGrid.qml+3−2
@@ -45,14 +45,15 @@ DashRenderer {
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
45 collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2)
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
46 delegateCreationBegin: genericFilterGrid.delegateCreationBegin
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
47 delegateCreationEnd: genericFilterGrid.delegateCreationEnd
48− delegate: Item {
48+ delegate: Loader {
49+ asynchronous: true
49 width: filterGrid.cellWidth
50 width: filterGrid.cellWidth
50 height: filterGrid.cellHeight
51 height: filterGrid.cellHeight
51 Card {
52 Card {
52 id: card
53 id: card
53 width: cardTool.cardWidth
54 width: cardTool.cardWidth
54 height: cardTool.cardHeight
55 height: cardTool.cardHeight
55− headerHeight: cardTool.headerHeight
56+ fixedHeaderHeight: cardTool.headerHeight
56 anchors.horizontalCenter: parent.horizontalCenter
57 anchors.horizontalCenter: parent.horizontalCenter
57 objectName: "delegate" + index
58 objectName: "delegate" + index
58 cardData: model
59 cardData: model
qml/Dash/CardHeader.qml+41−31
@@ -19,9 +19,9 @@ import Ubuntu.Components 0.1
19
19
20Item {
20Item {
21 id: root
21 id: root
22− property alias mascot: mascotImage.source
22+ property url mascot: ""
23 property alias title: titleLabel.text
23 property alias title: titleLabel.text
24− property alias subtitle: subtitleLabel.text
24+ property var subtitle
25
25
26 property alias titleWeight: titleLabel.font.weight
26 property alias titleWeight: titleLabel.font.weight
27 property alias titleSize: titleLabel.fontSize
27 property alias titleSize: titleLabel.fontSize
@@ -35,8 +35,8 @@ Item {
35 property bool useMascotShape: true
35 property bool useMascotShape: true
36 property color fontColor: Theme.palette.selected.backgroundText
36 property color fontColor: Theme.palette.selected.backgroundText
37
37
38− visible: mascotImage.status === Image.Ready || title
38+ visible: mascot != "" || title
39− height: row.height > 0 ? row.height + row.margins * 2 : 0
39+ implicitHeight: row.height > 0 ? row.height + row.margins * 2 : 0
40
40
41 Row {
41 Row {
42 id: row
42 id: row
@@ -44,7 +44,7 @@ Item {
44
44
45 property real margins: units.gu(1)
45 property real margins: units.gu(1)
46
46
47− spacing: mascotShape.visible || mascotImage.visible || inOverlay ? margins : 0
47+ spacing: mascotShapeLoader.active || mascotImageLoader.active || inOverlay ? margins : 0
48 anchors {
48 anchors {
49 top: parent.top; left: parent.left; right: parent.right
49 top: parent.top; left: parent.left; right: parent.right
50 margins: margins
50 margins: margins
@@ -52,33 +52,40 @@ Item {
52 rightMargin: spacing
52 rightMargin: spacing
53 }
53 }
54
54
55− UbuntuShape {
55+ Loader {
56− id: mascotShape
56+ id: mascotShapeLoader
57− objectName: "mascotShape"
57+ objectName: "mascotShapeLoader"
58
58
59+ active: useMascotShape && mascotImageLoader.item && mascotImageLoader.item.status === Image.Ready
60+ visible: active
61+ anchors.verticalCenter: parent.verticalCenter
59 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
62 // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels.
60 width: units.gu(6)
63 width: units.gu(6)
61 height: units.gu(5.625)
64 height: units.gu(5.625)
62− anchors.verticalCenter: parent.verticalCenter
63− visible: useMascotShape && image && image.status === Image.Ready
64 readonly property int maxSize: Math.max(width, height) * 4
65 readonly property int maxSize: Math.max(width, height) * 4
65
66
66− image: useMascotShape ? mascotImage : null
67+ sourceComponent: UbuntuShape {
68+ image: mascotImageLoader.item
69+ }
67 }
70 }
68
71
69− Image {
72+ Loader {
70− id: mascotImage
73+ id: mascotImageLoader
71− objectName: "mascotImage"
74+ active: root.mascot != ""
72−
75+ visible: active && !useMascotShape && item.status === Image.Ready
73− width: source ? mascotShape.width : 0
74− height: mascotShape.height
75 anchors.verticalCenter: parent.verticalCenter
76 anchors.verticalCenter: parent.verticalCenter
76− visible: !useMascotShape && status === Image.Ready
77+ sourceComponent: Image {
78+ objectName: "mascotImage"
79+
80+ source: root.mascot
81+ width: source ? mascotShapeLoader.width : 0
82+ height: mascotShapeLoader.height
77
83
78− sourceSize { width: mascotShape.maxSize; height: mascotShape.maxSize }
84+ sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize }
79− fillMode: Image.PreserveAspectCrop
85+ fillMode: Image.PreserveAspectCrop
80− horizontalAlignment: Image.AlignHCenter
86+ horizontalAlignment: Image.AlignHCenter
81− verticalAlignment: Image.AlignVCenter
87+ verticalAlignment: Image.AlignVCenter
88+ }
82 }
89 }
83
90
84 Column {
91 Column {
@@ -100,16 +107,19 @@ Item {
100 color: fontColor
107 color: fontColor
101 }
108 }
102
109
103− Label {
110+ Loader {
104− id: subtitleLabel
111+ active: titleLabel.text && root.subtitle
105− objectName: "subtitleLabel"
106 anchors { left: parent.left; right: parent.right }
112 anchors { left: parent.left; right: parent.right }
113+ sourceComponent: Label {
114+ id: subtitleLabel
115+ objectName: "subtitleLabel"
107− elide: Text.ElideRight
116+ elide: Text.ElideRight
108− fontSize: "small"
117+ fontSize: "small"
109− font.weight: Font.Light
118+ font.weight: Font.Light
110− visible: titleLabel.text && text
111− font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
119+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale)
112− color: fontColor
120+ color: fontColor
121+ text: root.subtitle
122+ }
113 }
123 }
114 }
124 }
115 }
125 }
qml/Dash/GenericScopeView.qml+1−1
@@ -242,7 +242,7 @@ FocusScope {
242 // to the stable position and delete/create items without any reason
242 // to the stable position and delete/create items without any reason
243 if (categoryView.contentY < categoryView.originY) {
243 if (categoryView.contentY < categoryView.originY) {
244 return;
244 return;
245− } else if (categoryView.contentY + categoryView.height > categoryView.contentHeight) {
245+ } else if (categoryView.contentHeight > categoryView.height && categoryView.contentY + categoryView.height > categoryView.contentHeight) {
246 return;
246 return;
247 }
247 }
248
248
tests/qmltests/CMakeLists.txt+1
@@ -35,6 +35,7 @@ add_qml_test(Components PageHeaderLabel)
35add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
35add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
36add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
36add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
37add_qml_test(Dash Card)
37add_qml_test(Dash Card)
38+add_qml_benchmark(Dash CardBenchmark 1000)
38add_qml_test(Dash CardHeader)
39add_qml_test(Dash CardHeader)
39add_qml_test(Dash CardTool)
40add_qml_test(Dash CardTool)
40add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
41add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS})
tests/qmltests/Dash/tst_Card.qml+12−10
@@ -182,11 +182,13 @@ Rectangle {
182 when: windowShown
182 when: windowShown
183
183
184 property Item header: findChild(card, "cardHeader")
184 property Item header: findChild(card, "cardHeader")
185+ property Item headerLoader: findChild(card, "cardHeaderLoader")
185 property Item title: findChild(header, "titleLabel")
186 property Item title: findChild(header, "titleLabel")
186 property Item art: findChild(card, "artShape")
187 property Item art: findChild(card, "artShape")
187 property Item artImage: findChild(card, "artImage")
188 property Item artImage: findChild(card, "artImage")
188 property Item summary: findChild(card, "summaryLabel")
189 property Item summary: findChild(card, "summaryLabel")
189 property Item background: findChild(card, "background")
190 property Item background: findChild(card, "background")
191+ property Item backgroundLoader: findChild(card, "backgroundLoader")
190 property Item backgroundImage: findChild(card, "backgroundImage")
192 property Item backgroundImage: findChild(card, "backgroundImage")
191
193
192 function initTestCase() {
194 function initTestCase() {
@@ -244,8 +246,8 @@ Rectangle {
244 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
246 { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 },
245 { tag: "Horizontal", width: units.gu(38), index: 5 },
247 { tag: "Horizontal", width: units.gu(38), index: 5 },
246 // Make sure card ends with header when there's no summary
248 // Make sure card ends with header when there's no summary
247− { tag: "NoSummary", height: function() { return header.y + header.height }, index: 6 },
249+ { tag: "NoSummary", height: function() { return headerLoader.y + headerLoader.height }, index: 6 },
248− { tag: "HorizontalNoSummary", height: function() { return header.height }, card_layout: "horizontal", index: 6 },
250+ { tag: "HorizontalNoSummary", height: function() { return headerLoader.height }, card_layout: "horizontal", index: 6 },
249 ]
251 ]
250 }
252 }
251
253
@@ -288,7 +290,7 @@ Rectangle {
288 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
290 { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 },
289 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
291 { tag: "VerticalWidth", width: function() { return header.width }, index: 0 },
290 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
292 { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 },
291− { tag: "HorizontalWidth", width: function() { return header.x }, index: 5 },
293+ { tag: "HorizontalWidth", width: function() { return headerLoader.x }, index: 5 },
292 ]
294 ]
293 }
295 }
294
296
@@ -332,7 +334,7 @@ Rectangle {
332 function test_art_layout(data) {
334 function test_art_layout(data) {
333 selector.selectedIndex = data.index;
335 selector.selectedIndex = data.index;
334
336
335− tryCompare(testCase.header, "x", data.left());
337+ tryCompare(testCase.headerLoader, "x", data.left());
336 }
338 }
337
339
338 function test_header_layout_data() {
340 function test_header_layout_data() {
@@ -349,13 +351,13 @@ Rectangle {
349 function test_header_layout(data) {
351 function test_header_layout(data) {
350 selector.selectedIndex = data.index;
352 selector.selectedIndex = data.index;
351
353
352− tryCompareFunction(function() { return testCase.header.y === data.top() }, true);
354+ tryCompareFunction(function() { return testCase.headerLoader.y === data.top() }, true);
353− tryCompareFunction(function() { return testCase.header.x === data.left() }, true);
355+ tryCompareFunction(function() { return testCase.headerLoader.x === data.left() }, true);
354 }
356 }
355
357
356 function test_summary_layout_data() {
358 function test_summary_layout_data() {
357 return [
359 return [
358− { tag: "With header", top: function() { return header.y + header.height }, index: 0 },
360+ { tag: "With header", top: function() { return headerLoader.y + headerLoader.height }, index: 0 },
359 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
361 { tag: "Without header", top: function() { return art.y + art.height }, index: 7 },
360 ]
362 ]
361 }
363 }
@@ -400,7 +402,7 @@ Rectangle {
400
402
401 waitForRendering(card);
403 waitForRendering(card);
402
404
403− tryCompare(background, "visible", data.visible);
405+ tryCompare(backgroundLoader, "active", data.visible);
404
406
405 if (data.hasOwnProperty("color")) {
407 if (data.hasOwnProperty("color")) {
406 tryCompare(background, "color", data.color);
408 tryCompare(background, "color", data.color);
@@ -467,13 +469,13 @@ Rectangle {
467 function test_mascotShape(data) {
469 function test_mascotShape(data) {
468 selector.selectedIndex = data.index;
470 selector.selectedIndex = data.index;
469
471
470− var shape = findChild(card, "mascotShape");
472+ var shape = findChild(card, "mascotShapeLoader");
471 var image = findChild(card, "mascotImage");
473 var image = findChild(card, "mascotImage");
472
474
473 verify(shape, "Could not find shape.");
475 verify(shape, "Could not find shape.");
474 verify(image, "Could not find image.");
476 verify(image, "Could not find image.");
475
477
476− tryCompare(shape, "visible", data.shape);
478+ tryCompare(shape, "active", data.shape);
477 tryCompare(image, "visible", !data.shape);
479 tryCompare(image, "visible", !data.shape);
478 }
480 }
479 }
481 }
tests/qmltests/Dash/tst_CardBenchmark.qmlnew file+94
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import 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 cardData: '
31+ {
32+ "art": "../../tests/qmltests/Dash/artwork/music-player-design.png",
33+ "mascot": "../../tests/qmltests/Dash/artwork/avatar.png",
34+ "title": "foo",
35+ "subtitle": "bar",
36+ "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."
37+ }'
38+
39+ property string currentModel: '{}'
40+ property string cardTitleArtSubtitleMascotSummaryModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot", "summary": "summary" } }'
41+ property string cardTitleArtSubtitleMascotModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle", "mascot": "mascot" } }'
42+ property string cardTitleArtSubtitleModel: '{ "components": { "title": "title", "art": "art", "subtitle": "subtitle" } }'
43+ property string cardTitleArtModel: '{ "components": { "title": "title", "art": "art" } }'
44+ property string cardArtModel: '{ "components": { "art": "art" } }'
45+ property string cardTitleModel: '{ "components": { "title": "title" } }'
46+
47+ CardTool {
48+ id: cardTool
49+ template: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['template'];
50+ components: Helpers.update(JSON.parse(Helpers.defaultLayout), JSON.parse(currentModel))['components'];
51+ viewWidth: units.gu(48)
52+ }
53+
54+ Repeater {
55+ id: cardRepeater
56+ model: 0
57+ Card {
58+ width: cardTool.cardWidth || implicitWidth
59+ height: cardTool.cardHeight || implicitHeight
60+
61+ template: cardTool.template
62+ components: cardTool.components
63+ cardData: Helpers.mapData(root.cardData, components)
64+ }
65+ }
66+
67+ UT.UnityTestCase {
68+ id: testCase
69+ name: "CardBenchmark"
70+
71+ when: windowShown
72+
73+ function init() {
74+ wait(1);
75+ }
76+
77+ function benchmark_time_data() {
78+ return [
79+ { tag: "cardTitleArtSubtitleMascotSummaryModel", model: cardTitleArtSubtitleMascotSummaryModel },
80+ { tag: "cardTitleArtSubtitleMascotModel", model: cardTitleArtSubtitleMascotModel },
81+ { tag: "cardTitleArtSubtitleModel", model: cardTitleArtSubtitleModel },
82+ { tag: "cardTitleArtModel", model: cardTitleArtModel },
83+ { tag: "cardArtModel", model: cardArtModel },
84+ { tag: "cardTitleModel", model: cardTitleModel },
85+ ];
86+ }
87+
88+ function benchmark_time(data) {
89+ currentModel = data.model;
90+ cardRepeater.model = 1;
91+ cardRepeater.model = 0;
92+ }
93+ }
94+}
tests/qmltests/Dash/tst_CardHeader.qml+1−1
@@ -43,7 +43,7 @@ Rectangle {
43
43
44 when: windowShown
44 when: windowShown
45
45
46− property Item mascot: findChild(cardHeader, "mascotShape")
46+ property Item mascot: findChild(cardHeader, "mascotShapeLoader")
47 property Item titleLabel: findChild(cardHeader, "titleLabel")
47 property Item titleLabel: findChild(cardHeader, "titleLabel")
48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
48 property Item subtitleLabel: findChild(cardHeader, "subtitleLabel")
49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")
49 property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel")