on xenial help sign in
Add some "well known" card creator input->output
commitc7482d0590c475aa54d3d279c1ad44d64e449f1c authorAlbert Astals <albert.astals@canonical.com> dateTue 6 May 2014, 12:06 (12 years ago) parent88c8163
11 files changed+142
tests/plugins/Dash/CMakeLists.txt+7 tests/plugins/Dash/cardcreator/1.res+1 tests/plugins/Dash/cardcreator/1.tst+3 tests/plugins/Dash/cardcreator/2.res+1 tests/plugins/Dash/cardcreator/2.tst+3 tests/plugins/Dash/cardcreator/3.res+1 tests/plugins/Dash/cardcreator/3.tst+3 tests/plugins/Dash/cardcreator/4.res+1 tests/plugins/Dash/cardcreator/4.tst+3 tests/plugins/Dash/cardcreatortest.cpp+90 tests/plugins/Dash/cardcreatortest.qml+29
tests/plugins/Dash/CMakeLists.txt+7
@@ -67,6 +67,13 @@ add_dashview_try_test(verticaljournal VerticalJournal)
6767add_dashview_try_test(horizontaljournal HorizontalJournal)
6868add_dashview_try_test(organicgrid OrganicGrid)
6969
70+# CardCreator test
71+add_executable(CardCreatorTestExec cardcreatortest.cpp)
72+qt5_use_modules(CardCreatorTestExec Test Core Qml)
73+target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES})
74+add_binary_qml_test(CardCreator "" "Dash-qml")
75+
76+# plain qml test
7077set(qmltest_DEFAULT_TARGETS qmluitests)
7178set(qmltest_DEFAULT_NO_ADD_TEST TRUE)
7279add_qml_test(. ListViewWithPageHeaderQML IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins)
tests/plugins/Dash/cardcreator/1.resnew file+1
@@ -0,0 +1 @@
1+AbstractButton { id: root; property var template; property var components; property var cardData; property real fontScale: 1.0; property int headerAlignment: Text.AlignLeft; property int fixedHeaderHeight: -1; property size fixedArtShapeSize: Qt.size(-1, -1); readonly property string title: cardData && cardData["title"] || ""; property bool asynchronous: true; property bool showHeader: true; implicitWidth: childrenRect.width; readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);Item { id: artShapeHolder; height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; anchors.horizontalCenter: parent.horizontalCenter; Loader { id: artShapeLoader; objectName: "artShapeLoader"; active: cardData && cardData["art"] || false; asynchronous: root.asynchronous; visible: status == Loader.Ready; sourceComponent: UbuntuShape { id: artShape; objectName: "artShape"; radius: "medium"; readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; Component.onCompleted: updateWidthHeightBindings(); onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); visible: image.status == Image.Ready; function updateWidthHeightBindings() { if (aspectSmallerThanImageAspect) { width = Qt.binding(function() { return !visible ? 0 : image.width }); height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); } else { width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); height = Qt.binding(function() { return !visible ? 0 : image.height }); } } image: Image { objectName: "artImage"; source: cardData && cardData["art"] || ""; cache: true; asynchronous: root.asynchronous; fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; readonly property real aspect: implicitWidth / implicitHeight; width: root.width; height: width / artShape.aspect; } } } }readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2;Label { id: titleLabel; objectName: "titleLabel"; anchors.right: parent.right;anchors.left: parent.left;anchors.top: artShapeHolder.bottom; anchors.topMargin: units.gu(1); elide: Text.ElideRight; fontSize: "small"; wrapMode: Text.Wrap; maximumLineCount: 2; font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); color: "grey"; visible: showHeader ; text: root.title; font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; horizontalAlignment: root.headerAlignment; }implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);}
tests/plugins/Dash/cardcreator/1.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":1.6,"field":"art","fill-mode":"fit"},"title":{"field":"title"}}
3+result: 1.res
tests/plugins/Dash/cardcreator/2.resnew file+1
@@ -0,0 +1 @@
1+AbstractButton { id: root; property var template; property var components; property var cardData; property real fontScale: 1.0; property int headerAlignment: Text.AlignLeft; property int fixedHeaderHeight: -1; property size fixedArtShapeSize: Qt.size(-1, -1); readonly property string title: cardData && cardData["title"] || ""; property bool asynchronous: true; property bool showHeader: true; implicitWidth: childrenRect.width; Loader { id: backgroundLoader; objectName: "backgroundLoader"; anchors.fill: parent; asynchronous: root.asynchronous; visible: status == Loader.Ready; sourceComponent: UbuntuShape { objectName: "background"; radius: "medium"; color: getColor(0) || "white"; gradientColor: getColor(1) || color; anchors.fill: parent; image: backgroundImage.source ? backgroundImage : null; property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; property Image backgroundImage: Image { objectName: "backgroundImage"; source: { if (cardData && typeof cardData["background"] === "string") return cardData["background"]; else if (template && typeof template["card-background"] === "string") return template["card-background"]; else return ""; } } function getColor(index) { if (cardData && typeof cardData["background"] === "object" && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) { return cardData["background"]["elements"][index]; } else if (template && typeof template["card-background"] === "object" && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) { return template["card-background"]["elements"][index]; } else return undefined; } } }readonly property size artShapeSize: Qt.size(-1, -1);readonly property int headerHeight: row.height + row.margins * 2;Row { id: row; objectName: "outerRow"; property real margins: units.gu(1); spacing: margins; anchors.top: parent.top; anchors.topMargin: units.gu(1); anchors.left: parent.left; anchors.right: parent.right; anchors.margins: margins;Image { id: mascotImage; objectName: "mascotImage"; anchors.verticalCenter: parent.verticalCenter; readonly property int maxSize: Math.max(width, height) * 4; source: cardData && cardData["mascot"]; width: units.gu(6); height: units.gu(5.625); sourceSize { width: maxSize; height: maxSize } fillMode: Image.PreserveAspectCrop; horizontalAlignment: Image.AlignHCenter; verticalAlignment: Image.AlignVCenter; visible: showHeader && true; }Column { anchors.verticalCenter: parent.verticalCenter; spacing: units.dp(2); width: parent.width - x;Label { id: titleLabel; objectName: "titleLabel"; anchors { left: parent.left; right: parent.right } elide: Text.ElideRight; fontSize: "small"; wrapMode: Text.Wrap; maximumLineCount: 2; font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"; visible: showHeader ; text: root.title; font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; horizontalAlignment: root.headerAlignment; }Label { id: subtitleLabel; objectName: "subtitleLabel"; anchors { left: parent.left; right: parent.right } elide: Text.ElideRight; fontSize: "small"; font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"; visible: titleLabel.visible && titleLabel.text; text: cardData && cardData["subtitle"] || ""; font.weight: Font.Light; horizontalAlignment: root.headerAlignment; }}}implicitHeight: row.y + row.height + units.gu(1);}
tests/plugins/Dash/cardcreator/2.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":1,"fill-mode":"crop"},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"}}
3+result: 2.res
tests/plugins/Dash/cardcreator/3.resnew file+1
@@ -0,0 +1 @@
1+AbstractButton { id: root; property var template; property var components; property var cardData; property real fontScale: 1.0; property int headerAlignment: Text.AlignLeft; property int fixedHeaderHeight: -1; property size fixedArtShapeSize: Qt.size(-1, -1); readonly property string title: cardData && cardData["title"] || ""; property bool asynchronous: true; property bool showHeader: true; implicitWidth: childrenRect.width; readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);Item { id: artShapeHolder; height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; anchors.horizontalCenter: parent.horizontalCenter; Loader { id: artShapeLoader; objectName: "artShapeLoader"; active: cardData && cardData["art"] || false; asynchronous: root.asynchronous; visible: status == Loader.Ready; sourceComponent: UbuntuShape { id: artShape; objectName: "artShape"; radius: "medium"; readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; Component.onCompleted: updateWidthHeightBindings(); onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); visible: image.status == Image.Ready; function updateWidthHeightBindings() { if (aspectSmallerThanImageAspect) { width = Qt.binding(function() { return !visible ? 0 : image.width }); height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); } else { width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); height = Qt.binding(function() { return !visible ? 0 : image.height }); } } image: Image { objectName: "artImage"; source: cardData && cardData["art"] || ""; cache: true; asynchronous: root.asynchronous; fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; readonly property real aspect: implicitWidth / implicitHeight; width: root.width; height: width / artShape.aspect; } } } }readonly property int headerHeight: subtitleLabel.y + subtitleLabel.height - titleLabel.y + titleLabel.anchors.topMargin * 2 + subtitleLabel.anchors.topMargin;Label { id: titleLabel; objectName: "titleLabel"; anchors.right: parent.right;anchors.left: parent.left;anchors.top: artShapeHolder.bottom; anchors.topMargin: units.gu(1); elide: Text.ElideRight; fontSize: "small"; wrapMode: Text.Wrap; maximumLineCount: 2; font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); color: "grey"; visible: showHeader ; text: root.title; font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; horizontalAlignment: root.headerAlignment; }Label { id: subtitleLabel; objectName: "subtitleLabel"; anchors.left: titleLabel.left; anchors.leftMargin: titleLabel.leftMargin; anchors.right: titleLabel.right; anchors.top: titleLabel.bottom; anchors.topMargin: units.dp(2); elide: Text.ElideRight; fontSize: "small"; font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); color: "grey"; visible: titleLabel.visible && titleLabel.text; text: cardData && cardData["subtitle"] || ""; font.weight: Font.Light; horizontalAlignment: root.headerAlignment; }implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);}
tests/plugins/Dash/cardcreator/3.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":0.75,"field":"art","fill-mode":"crop"},"subtitle":{"field":"price"},"title":{"field":"title"}}
3+result: 3.res
tests/plugins/Dash/cardcreator/4.resnew file+1
@@ -0,0 +1 @@
1+AbstractButton { id: root; property var template; property var components; property var cardData; property real fontScale: 1.0; property int headerAlignment: Text.AlignLeft; property int fixedHeaderHeight: -1; property size fixedArtShapeSize: Qt.size(-1, -1); readonly property string title: cardData && cardData["title"] || ""; property bool asynchronous: true; property bool showHeader: true; implicitWidth: childrenRect.width; readonly property size artShapeSize: Qt.size(-1, -1);readonly property int headerHeight: row.height + row.margins * 2;Row { id: row; objectName: "outerRow"; property real margins: units.gu(1); spacing: margins; anchors.top: parent.top; anchors.topMargin: units.gu(1); anchors.left: parent.left; anchors.right: parent.right; anchors.margins: margins;Loader { id: mascotShapeLoader; objectName: "mascotShapeLoader"; asynchronous: root.asynchronous; active: mascotImage.status === Image.Ready; visible: showHeader && active && status == Loader.Ready; width: units.gu(6); height: units.gu(5.625); sourceComponent: UbuntuShape { image: mascotImage } anchors.verticalCenter: parent.verticalCenter; }Image { id: mascotImage; objectName: "mascotImage"; anchors.verticalCenter: parent.verticalCenter; readonly property int maxSize: Math.max(width, height) * 4; source: cardData && cardData["mascot"]; width: units.gu(6); height: units.gu(5.625); sourceSize { width: maxSize; height: maxSize } fillMode: Image.PreserveAspectCrop; horizontalAlignment: Image.AlignHCenter; verticalAlignment: Image.AlignVCenter; visible: showHeader && false; }Column { anchors.verticalCenter: parent.verticalCenter; spacing: units.dp(2); width: parent.width - x;Label { id: titleLabel; objectName: "titleLabel"; anchors { left: parent.left; right: parent.right } elide: Text.ElideRight; fontSize: "small"; wrapMode: Text.Wrap; maximumLineCount: 2; font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); color: "grey"; visible: showHeader ; text: root.title; font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; horizontalAlignment: root.headerAlignment; }Label { id: subtitleLabel; objectName: "subtitleLabel"; anchors { left: parent.left; right: parent.right } elide: Text.ElideRight; fontSize: "small"; font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); color: "grey"; visible: titleLabel.visible && titleLabel.text; text: cardData && cardData["subtitle"] || ""; font.weight: Font.Light; horizontalAlignment: root.headerAlignment; }}}implicitHeight: row.y + row.height + units.gu(1);}
tests/plugins/Dash/cardcreator/4.tstnew file+3
@@ -0,0 +1,3 @@
1+template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2}
2+components: {"art":{"aspect-ratio":1,"fill-mode":"crop"},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"}}
3+result: 4.res
tests/plugins/Dash/cardcreatortest.cppnew 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+#include <QDir>
18+#include <QQmlEngine>
19+#include <QQuickItem>
20+#include <QQuickView>
21+#include <QtTestGui>
22+
23+class CardCreatorTest : public QObject
24+{
25+ Q_OBJECT
26+
27+private Q_SLOTS:
28+
29+ void initTestCase()
30+ {
31+ }
32+
33+ void init()
34+ {
35+ view = new QQuickView();
36+ view->engine()->addImportPath(BUILT_PLUGINS_DIR);
37+ view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/cardcreatortest.qml"));
38+ view->show();
39+ QTest::qWaitForWindowExposed(view);
40+ }
41+
42+ void cleanup()
43+ {
44+ delete view;
45+ }
46+
47+ void testKnownCases()
48+ {
49+ const QString templateString("template: ");
50+ const QString componentsString("components: ");
51+ const QString resultString("result: ");
52+
53+ const QString testDirPath = DASHVIEWSTEST_FOLDER "/cardcreator/";
54+ QDir d(testDirPath);
55+ const QStringList testFiles = d.entryList(QStringList() << "*.tst");
56+ foreach(const QString &testFileName, testFiles) {
57+ QFile testFile(testDirPath + testFileName);
58+ QVERIFY(testFile.open(QIODevice::ReadOnly));
59+ QTextStream ts(&testFile);
60+ const QStringList lines = ts.readAll().split("\n");
61+
62+ QVERIFY(lines[0].startsWith(templateString));
63+ QVERIFY(lines[1].startsWith(componentsString));
64+ QVERIFY(lines[2].startsWith(resultString));
65+ const QString templateJSON = lines[0].mid(templateString.length());
66+ const QString componentsJSON = lines[1].mid(componentsString.length());
67+ const QString resultFileName = lines[2].mid(resultString.length());
68+
69+ QVariant cardStringResult;
70+ QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
71+
72+ QFile testResultFile(testDirPath + resultFileName);
73+ QVERIFY(testResultFile.open(QIODevice::ReadOnly));
74+ QTextStream ts2(&testResultFile);
75+ const QString expectedResult = ts2.readAll();
76+ QCOMPARE(cardStringResult.toString().simplified(), expectedResult.simplified());
77+
78+ QVariant createCardComponentResult;
79+ QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON));
80+ QVERIFY(createCardComponentResult.toBool());
81+ }
82+ }
83+
84+private:
85+ QQuickView *view;
86+};
87+
88+QTEST_MAIN(CardCreatorTest)
89+
90+#include "cardcreatortest.moc"
tests/plugins/Dash/cardcreatortest.qmlnew file+29
@@ -0,0 +1,29 @@
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 "../../../plugins/Dash/CardCreator.js" as CardCreator
19+
20+Item {
21+ id: root
22+ function cardString(template, components) {
23+ return CardCreator.cardString(JSON.parse(template), JSON.parse(components));
24+ }
25+
26+ function createCardComponent(template, components) {
27+ return CardCreator.createCardComponent(root, JSON.parse(template), JSON.parse(components)) !== null;
28+ }
29+}