Merge lp:~aacid/unity8/dynamic_specialized_cards into lp:unity8
- dynamic_specialized_cards
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Zanetti | ||||
Approved revision: | 909 | ||||
Merged at revision: | 890 | ||||
Proposed branch: | lp:~aacid/unity8/dynamic_specialized_cards | ||||
Merge into: | lp:unity8 | ||||
Diff against target: |
3024 lines (+1590/-714) 48 files modified
debian/unity8-private.install (+1/-1) plugins/CMakeLists.txt (+1/-1) plugins/Dash/CMakeLists.txt (+5/-5) plugins/Dash/CardCreator.js (+518/-0) plugins/Dash/CardCreatorCache.qml (+40/-0) plugins/Dash/plugin.cpp (+2/-2) plugins/Dash/plugin.h (+3/-3) plugins/Dash/qmldir (+3/-2) qml/Dash/Card.qml (+0/-236) qml/Dash/CardCarousel.qml (+13/-10) qml/Dash/CardFilterGrid.qml (+19/-16) qml/Dash/CardHeader.qml (+0/-126) qml/Dash/CardTool.qml (+30/-22) qml/Dash/Previews/PreviewHeader.qml (+86/-9) qml/Dash/ScopeListView.qml (+1/-1) tests/autopilot/unity8/shell/emulators/dash.py (+3/-4) tests/mocks/Unity/fake_categories.cpp (+15/-2) tests/mocks/Unity/fake_resultsmodel.cpp (+1/-0) tests/plugins/CMakeLists.txt (+1/-1) tests/plugins/Dash/CMakeLists.txt (+16/-9) tests/plugins/Dash/cardcreator/1.res (+77/-0) tests/plugins/Dash/cardcreator/1.tst (+3/-0) tests/plugins/Dash/cardcreator/2.res (+115/-0) tests/plugins/Dash/cardcreator/2.tst (+3/-0) tests/plugins/Dash/cardcreator/3.res (+94/-0) tests/plugins/Dash/cardcreator/3.tst (+3/-0) tests/plugins/Dash/cardcreator/4.res (+95/-0) tests/plugins/Dash/cardcreator/4.tst (+3/-0) tests/plugins/Dash/cardcreator/5.res (+137/-0) tests/plugins/Dash/cardcreator/5.tst (+3/-0) tests/plugins/Dash/cardcreatortest.cpp (+91/-0) tests/plugins/Dash/cardcreatortest.qml (+29/-0) tests/plugins/Dash/horizontaljournaltest.qml (+1/-1) tests/plugins/Dash/horizontaljournaltry.qml (+1/-1) tests/plugins/Dash/listviewwithpageheadertest.qml (+1/-1) tests/plugins/Dash/listviewwithpageheadertestsection.qml (+1/-1) tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml (+1/-1) tests/plugins/Dash/organicgridtest.qml (+1/-1) tests/plugins/Dash/organicgridtry.qml (+1/-1) tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml (+1/-1) tests/plugins/Dash/verticaljournaltest.qml (+1/-1) tests/plugins/Dash/verticaljournaltry.qml (+1/-1) tests/qmltests/CMakeLists.txt (+3/-3) tests/qmltests/Dash/Previews/tst_PreviewHeader.qml (+66/-4) tests/qmltests/Dash/tst_Card.qml (+79/-93) tests/qmltests/Dash/tst_CardBenchmark.qml (+10/-7) tests/qmltests/Dash/tst_CardHeader.qml (+0/-116) tests/qmltests/Dash/tst_CardTool.qml (+11/-31) |
||||
To merge this branch: | bzr merge lp:~aacid/unity8/dynamic_specialized_cards | ||||
Related bugs: |
|
||||
Related blueprints: |
Dash component for Unity8, 14.10 tasks
(Undefined)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Zanetti (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Review via email: mp+218089@code.launchpad.net |
Commit message
Create specialized Card code in Javascript instead of having various copied&pasted files
Description of the change
* Are there any related MPs required for this MP to build/function as expected?
None
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* Did you make sure that your branch does not contain spurious tags?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
* If you changed the UI, has there been a design review?
N/A
PS Jenkins bot (ps-jenkins) wrote : | # |
- 885. By Albert Astals Cid
-
just one pragma and missing (C)
- 886. By Albert Astals Cid
-
whitespace pedanticness
- 887. By Albert Astals Cid
-
split the card generating code to a different function
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:886
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
46 +.pragma library
64 +.pragma library
duplicate
===
141 + height: units.gu(8.625)';
not sure if its still valid, but someone somewhen told me not to use units.gu with anything that can't be devided by 0.5.
===
Now that we generate the code on the fly, do we still need things like this?
194 + code += 'Loader { \
288 + code += 'Loader { \
I suppose the loaders have been added before in order to improve performance when everything was still loaded. Seems like unused overhead now, given that the Loader itself won't be in there in the cases where it wouldn't have to load anything.
===
I know this is not final yet, just listing this so you'll have it easier to find them again:
471 +// console.log(code)
===
478 +++ plugins/
Nice one! But I would be curious to know if having the cache as a QHash in C++ might be faster. How often are we calling that cache and how many items will be in there in average? Is it one entry per scope category?
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:887
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
uuhh... the performance is MUCH better. I would go as far as saying even better than with old scopes. Awesome job!
- 888. By Albert Astals Cid
-
Merge
Albert Astals Cid (aacid) wrote : | # |
> 46 +.pragma library
> 64 +.pragma library
>
> duplicate
Gone in r885
> ===
>
> 141 + height: units.gu(8.625)';
>
> not sure if its still valid, but someone somewhen told me not to use units.gu
> with anything that can't be devided by 0.5.
Well, i just moved it around, hmmm, wait actually i didn't, where did that number come from? Let me investigate
> Now that we generate the code on the fly, do we still need things like this?
>
> 194 + code += 'Loader { \
> 288 + code += 'Loader { \
>
> I suppose the loaders have been added before in order to improve performance
> when everything was still loaded. Seems like unused overhead now, given that
> the Loader itself won't be in there in the cases where it wouldn't have to
> load anything.
Yes, we still need them since they are async loaders
> ===
>
> I know this is not final yet, just listing this so you'll have it easier to
> find them again:
>
> 471 +// console.log(code)
This is gone in r887
> ===
> 478 +++ plugins/
>
> Nice one! But I would be curious to know if having the cache as a QHash in C++
> might be faster. How often are we calling that cache and how many items will
> be in there in average? Is it one entry per scope category?
We're calling it every time a category is created, that is not very often, some categories share the "view mode" so they will be having the same "key". About speed, i hope the js backend is using a qhash or similar so it should not really matter.
Albert Astals Cid (aacid) wrote : | # |
> > 141 + height: units.gu(8.625)';
> >
> > not sure if its still valid, but someone somewhen told me not to use
> units.gu
> > with anything that can't be devided by 0.5.
>
> Well, i just moved it around, hmmm, wait actually i didn't, where did that
> number come from? Let me investigate
Ok, so instaead of 8.625 it has to be 7.625 which is the 5.625 + 2 units.gu(1), that if side is "useless" anyway since having an horizontal card and then putting nothing on the horizontal side is kind of silly :D
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:888
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 889. By Albert Astals Cid
-
8.625 -> 7.625
- 890. By Albert Astals Cid
-
Comment on why the hardcoded size and its sillyness
- 891. By Albert Astals Cid
-
move the code that sets headerHeight a bit
Makes it easier to understand and also allows me to add the final else
- 892. By Albert Astals Cid
-
don't set left anchor margin twice
- 893. By Albert Astals Cid
-
renamed
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:893
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 894. By Albert Astals Cid
-
Check more carefully
- 895. By Albert Astals Cid
-
Add some "well known" card creator input->output
- 896. By Albert Astals Cid
-
eol
- 897. By Albert Astals Cid
-
One with overlay
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:896
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:897
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 898. By Albert Astals Cid
-
Add newlines, makes debugging the code when it fails easier
- 899. By Albert Astals Cid
-
Better variable name
- 900. By Albert Astals Cid
-
no need for a variable here
- 901. By Albert Astals Cid
-
Move big chunks of boilerplate out of the main function
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:898
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 902. By Albert Astals Cid
-
Rework header row/column creation
This way we don't open it in one place and close it 100 lines later
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:901
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:902
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
192 +var headerRowCode = 'Row { \n\
Can you please add a comment on top of those describing what %1, %2... are supposed to do.
===
I also find it a bit confusing that sometimes its like this:
propName: %1 \n
and sometimes like this:
%1 \n
Would it be better like this?
anchors: %1 \n
so we could fill it with .arg("{left: foo; right: bar}"); It would restrict it a bit more what can be injected to a narrower defined set.
Michael Zanetti (mzanetti) wrote : | # |
3: /home/mzanetti/
Michael Zanetti (mzanetti) wrote : | # |
running this on the phone, being in the music scope and copying music to the device using adb push I get nasty flickering and those messages:
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
file://
Michael Zanetti (mzanetti) wrote : | # |
flicking through the carousel I get this every time a new delegate is created:
file://
Albert Astals Cid (aacid) wrote : | # |
> 3: /home/mzanetti/
> Dash/cardcreato
You're on a really old revision?
Michael Zanetti (mzanetti) wrote : | # |
file://
after updating to the latest revision (stupid me) the binding loop moved to line 5:1 instead of 1:130. But the rest is all still the same.
- 903. By Albert Astals Cid
-
Document and simplify the %1 replacements of artShapeHolderCode
- 904. By Albert Astals Cid
-
Document and narrow what you can do with the arg replacement in headerColumnCode
- 905. By Albert Astals Cid
-
Document and limit what you can do with subtitleLabelCode substitutions
- 906. By Albert Astals Cid
-
Document summaryLabelCode substitutions
- 907. By Albert Astals Cid
-
document and narrow the rest of substitutions
Albert Astals Cid (aacid) wrote : | # |
> 192 +var headerRowCode = 'Row { \n\
>
> Can you please add a comment on top of those describing what %1, %2... are
> supposed to do.
>
> ===
>
> I also find it a bit confusing that sometimes its like this:
>
> propName: %1 \n
>
> and sometimes like this:
>
> %1 \n
>
> Would it be better like this?
>
> anchors: %1 \n
>
> so we could fill it with .arg("{left: foo; right: bar}"); It would restrict it
> a bit more what can be injected to a narrower defined set.
Done both
Albert Astals Cid (aacid) wrote : | # |
> flicking through the carousel I get this every time a new delegate is created:
>
> file://
> read property of null
Fixed
- 908. By Albert Astals Cid
-
Remove line that creates warnings
I think this came from a wrong copy&paste since it wasn't there in the original code
- 909. By Albert Astals Cid
-
Don't use the .y to calculate height, otherwise we end up in loops here
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:907
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:909
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes. Awesome improvement!
* Did CI run pass? If not, please explain why.
nope... qmluitests job seems broken and I don't have permissions any more to change it. Will contact CI team to get it sorted.
Preview Diff
1 | === modified file 'debian/unity8-private.install' |
2 | --- debian/unity8-private.install 2014-04-09 09:20:53 +0000 |
3 | +++ debian/unity8-private.install 2014-05-07 15:30:47 +0000 |
4 | @@ -1,5 +1,5 @@ |
5 | usr/lib/*/unity8/qml/AccountsService |
6 | -usr/lib/*/unity8/qml/DashViews |
7 | +usr/lib/*/unity8/qml/Dash |
8 | usr/lib/*/unity8/qml/HudClient |
9 | usr/lib/*/unity8/qml/LightDM |
10 | usr/lib/*/unity8/qml/Powerd |
11 | |
12 | === modified file 'plugins/CMakeLists.txt' |
13 | --- plugins/CMakeLists.txt 2013-12-12 16:45:35 +0000 |
14 | +++ plugins/CMakeLists.txt 2014-05-07 15:30:47 +0000 |
15 | @@ -1,7 +1,7 @@ |
16 | add_subdirectory(AccountsService) |
17 | add_subdirectory(HudClient) |
18 | add_subdirectory(LightDM) |
19 | -add_subdirectory(DashViews) |
20 | +add_subdirectory(Dash) |
21 | add_subdirectory(Powerd) |
22 | add_subdirectory(SessionBroadcast) |
23 | add_subdirectory(Ubuntu) |
24 | |
25 | === renamed directory 'plugins/DashViews' => 'plugins/Dash' |
26 | === modified file 'plugins/Dash/CMakeLists.txt' |
27 | --- plugins/DashViews/CMakeLists.txt 2014-01-14 12:51:08 +0000 |
28 | +++ plugins/Dash/CMakeLists.txt 2014-05-07 15:30:47 +0000 |
29 | @@ -30,17 +30,17 @@ |
30 | organicgrid.cpp |
31 | ) |
32 | |
33 | -add_library(DashViews-qml MODULE |
34 | +add_library(Dash-qml MODULE |
35 | ${QMLPLUGIN_SRC} |
36 | ) |
37 | |
38 | -target_link_libraries(DashViews-qml |
39 | +target_link_libraries(Dash-qml |
40 | ${Qt5Gui_LIBRARIES} |
41 | ${Qt5Quick_LIBRARIES} |
42 | ) |
43 | |
44 | -qt5_use_modules(DashViews-qml Qml Quick) |
45 | +qt5_use_modules(Dash-qml Qml Quick) |
46 | |
47 | # export the qmldir qmltypes and plugin files |
48 | -export_qmlfiles(DashViews DashViews) |
49 | -export_qmlplugin(DashViews 0.1 DashViews TARGETS DashViews-qml) |
50 | +export_qmlfiles(Dash Dash) |
51 | +export_qmlplugin(Dash 0.1 Dash TARGETS Dash-qml) |
52 | |
53 | === added file 'plugins/Dash/CardCreator.js' |
54 | --- plugins/Dash/CardCreator.js 1970-01-01 00:00:00 +0000 |
55 | +++ plugins/Dash/CardCreator.js 2014-05-07 15:30:47 +0000 |
56 | @@ -0,0 +1,518 @@ |
57 | +/* |
58 | + * Copyright (C) 2014 Canonical, Ltd. |
59 | + * |
60 | + * This program is free software; you can redistribute it and/or modify |
61 | + * it under the terms of the GNU General Public License as published by |
62 | + * the Free Software Foundation; version 3. |
63 | + * |
64 | + * This program is distributed in the hope that it will be useful, |
65 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
66 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
67 | + * GNU General Public License for more details. |
68 | + * |
69 | + * You should have received a copy of the GNU General Public License |
70 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
71 | + */ |
72 | + |
73 | +.pragma library |
74 | + |
75 | +var kBackgroundLoaderCode = 'Loader {\n\ |
76 | + id: backgroundLoader; \n\ |
77 | + objectName: "backgroundLoader"; \n\ |
78 | + anchors.fill: parent; \n\ |
79 | + asynchronous: root.asynchronous; \n\ |
80 | + visible: status == Loader.Ready; \n\ |
81 | + sourceComponent: UbuntuShape { \n\ |
82 | + objectName: "background"; \n\ |
83 | + radius: "medium"; \n\ |
84 | + color: getColor(0) || "white"; \n\ |
85 | + gradientColor: getColor(1) || color; \n\ |
86 | + anchors.fill: parent; \n\ |
87 | + image: backgroundImage.source ? backgroundImage : null; \n\ |
88 | + property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; \n\ |
89 | + property Image backgroundImage: Image { \n\ |
90 | + objectName: "backgroundImage"; \n\ |
91 | + source: { \n\ |
92 | + if (cardData && typeof cardData["background"] === "string") return cardData["background"]; \n\ |
93 | + else if (template && typeof template["card-background"] === "string") return template["card-background"]; \n\ |
94 | + else return ""; \n\ |
95 | + } \n\ |
96 | + } \n\ |
97 | + function getColor(index) { \n\ |
98 | + if (cardData && typeof cardData["background"] === "object" \n\ |
99 | + && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) { \n\ |
100 | + return cardData["background"]["elements"][index]; \n\ |
101 | + } else if (template && typeof template["card-background"] === "object" \n\ |
102 | + && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) { \n\ |
103 | + return template["card-background"]["elements"][index]; \n\ |
104 | + } else return undefined; \n\ |
105 | + } \n\ |
106 | + } \n\ |
107 | + }\n'; |
108 | + |
109 | +// %1 is used as anchors of artShapeHolder |
110 | +// %2 is used as image width |
111 | +// %3 is used as image height |
112 | +var kArtShapeHolderCode = 'Item { \n\ |
113 | + id: artShapeHolder; \n\ |
114 | + height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; \n\ |
115 | + width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; \n\ |
116 | + anchors { %1 } \n\ |
117 | + Loader { \n\ |
118 | + id: artShapeLoader; \n\ |
119 | + objectName: "artShapeLoader"; \n\ |
120 | + active: cardData && cardData["art"] || false; \n\ |
121 | + asynchronous: root.asynchronous; \n\ |
122 | + visible: status == Loader.Ready; \n\ |
123 | + sourceComponent: UbuntuShape { \n\ |
124 | + id: artShape; \n\ |
125 | + objectName: "artShape"; \n\ |
126 | + radius: "medium"; \n\ |
127 | + readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; \n\ |
128 | + readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; \n\ |
129 | + Component.onCompleted: updateWidthHeightBindings(); \n\ |
130 | + onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); \n\ |
131 | + visible: image.status == Image.Ready; \n\ |
132 | + function updateWidthHeightBindings() { \n\ |
133 | + if (aspectSmallerThanImageAspect) { \n\ |
134 | + width = Qt.binding(function() { return !visible ? 0 : image.width }); \n\ |
135 | + height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); \n\ |
136 | + } else { \n\ |
137 | + width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); \n\ |
138 | + height = Qt.binding(function() { return !visible ? 0 : image.height }); \n\ |
139 | + } \n\ |
140 | + } \n\ |
141 | + image: Image { \n\ |
142 | + objectName: "artImage"; \n\ |
143 | + source: cardData && cardData["art"] || ""; \n\ |
144 | + cache: true; \n\ |
145 | + asynchronous: root.asynchronous; \n\ |
146 | + fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; \n\ |
147 | + readonly property real aspect: implicitWidth / implicitHeight; \n\ |
148 | + width: %2; \n\ |
149 | + height: %3; \n\ |
150 | + } \n\ |
151 | + } \n\ |
152 | + } \n\ |
153 | + }\n'; |
154 | + |
155 | +var kOverlayLoaderCode = 'Loader { \n\ |
156 | + id: overlayLoader; \n\ |
157 | + anchors { \n\ |
158 | + left: artShapeHolder.left; \n\ |
159 | + right: artShapeHolder.right; \n\ |
160 | + bottom: artShapeHolder.bottom; \n\ |
161 | + } \n\ |
162 | + active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; \n\ |
163 | + asynchronous: root.asynchronous; \n\ |
164 | + visible: showHeader && status == Loader.Ready; \n\ |
165 | + sourceComponent: ShaderEffect { \n\ |
166 | + id: overlay; \n\ |
167 | + height: fixedHeaderHeight != -1 ? fixedHeaderHeight : headerHeight; \n\ |
168 | + opacity: 0.6; \n\ |
169 | + property var source: ShaderEffectSource { \n\ |
170 | + id: shaderSource; \n\ |
171 | + sourceItem: artShapeLoader.item; \n\ |
172 | + onVisibleChanged: if (visible) scheduleUpdate(); \n\ |
173 | + live: false; \n\ |
174 | + sourceRect: Qt.rect(0, artShapeLoader.height - overlay.height, artShapeLoader.width, overlay.height); \n\ |
175 | + } \n\ |
176 | + vertexShader: " \n\ |
177 | + uniform highp mat4 qt_Matrix; \n\ |
178 | + attribute highp vec4 qt_Vertex; \n\ |
179 | + attribute highp vec2 qt_MultiTexCoord0; \n\ |
180 | + varying highp vec2 coord; \n\ |
181 | + void main() { \n\ |
182 | + coord = qt_MultiTexCoord0; \n\ |
183 | + gl_Position = qt_Matrix * qt_Vertex; \n\ |
184 | + }"; \n\ |
185 | + fragmentShader: " \n\ |
186 | + varying highp vec2 coord; \n\ |
187 | + uniform sampler2D source; \n\ |
188 | + uniform lowp float qt_Opacity; \n\ |
189 | + void main() { \n\ |
190 | + lowp vec4 tex = texture2D(source, coord); \n\ |
191 | + gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity; \n\ |
192 | + }"; \n\ |
193 | + } \n\ |
194 | + }\n'; |
195 | + |
196 | +// %1 is used as anchors of row |
197 | +// %2 is used as first child of the row |
198 | +// %3 is used as second child of the row |
199 | +var kHeaderRow2Code = 'Row { \n\ |
200 | + id: row; \n\ |
201 | + objectName: "outerRow"; \n\ |
202 | + property real margins: units.gu(1); \n\ |
203 | + spacing: margins; \n\ |
204 | + anchors { %1 } \n\ |
205 | + anchors.right: parent.right; \n\ |
206 | + anchors.margins: margins;\n\ |
207 | + data: [ %2\n\ |
208 | + ,\n\ |
209 | + %3 \n\ |
210 | + ] \n\ |
211 | + }\n'; |
212 | + |
213 | +// %1 is used as anchors of row |
214 | +// %2 is used as first child of the row |
215 | +// %3 is used as second child of the row |
216 | +// %4 is used as third child of the row |
217 | +var kHeaderRow3Code = 'Row { \n\ |
218 | + id: row; \n\ |
219 | + objectName: "outerRow"; \n\ |
220 | + property real margins: units.gu(1); \n\ |
221 | + spacing: margins; \n\ |
222 | + anchors { %1 } \n\ |
223 | + anchors.right: parent.right; \n\ |
224 | + anchors.margins: margins;\n\ |
225 | + data: [ %2\n\ |
226 | + ,\n\ |
227 | + %3 \n\ |
228 | + ,\n\ |
229 | + %4 \n\ |
230 | + ] \n\ |
231 | + }\n'; |
232 | + |
233 | +// %1 is used as first child of the column |
234 | +// %2 is used as second child of the column |
235 | +var kHeaderColumnCode = 'Column { \n\ |
236 | + anchors.verticalCenter: parent.verticalCenter; \n\ |
237 | + spacing: units.dp(2); \n\ |
238 | + width: parent.width - x;\n\ |
239 | + data: [ %1\n\ |
240 | + ,\n\ |
241 | + %2 \n\ |
242 | + ] \n\ |
243 | + }\n'; |
244 | + |
245 | +// %1 is used as anchors of mascotShapeLoader |
246 | +var kMascotShapeLoaderCode = 'Loader { \n\ |
247 | + id: mascotShapeLoader; \n\ |
248 | + objectName: "mascotShapeLoader"; \n\ |
249 | + asynchronous: root.asynchronous; \n\ |
250 | + active: mascotImage.status === Image.Ready; \n\ |
251 | + visible: showHeader && active && status == Loader.Ready; \n\ |
252 | + width: units.gu(6); \n\ |
253 | + height: units.gu(5.625); \n\ |
254 | + sourceComponent: UbuntuShape { image: mascotImage } \n\ |
255 | + anchors { %1 } \n\ |
256 | + }\n'; |
257 | + |
258 | +// %1 is used as anchors of mascotImage |
259 | +// %2 is used as visible of mascotImage |
260 | +var kMascotImageCode = 'Image { \n\ |
261 | + id: mascotImage; \n\ |
262 | + objectName: "mascotImage"; \n\ |
263 | + anchors { %1 } \n\ |
264 | + readonly property int maxSize: Math.max(width, height) * 4; \n\ |
265 | + source: cardData && cardData["mascot"]; \n\ |
266 | + width: units.gu(6); \n\ |
267 | + height: units.gu(5.625); \n\ |
268 | + sourceSize { width: maxSize; height: maxSize } \n\ |
269 | + fillMode: Image.PreserveAspectCrop; \n\ |
270 | + horizontalAlignment: Image.AlignHCenter; \n\ |
271 | + verticalAlignment: Image.AlignVCenter; \n\ |
272 | + visible: %2; \n\ |
273 | + }\n'; |
274 | + |
275 | +// %1 is used as anchors of titleLabel |
276 | +// %1 is used as color of titleLabel |
277 | +// %3 is used as extra condition for visible of titleLabel |
278 | +var kTitleLabelCode = 'Label { \n\ |
279 | + id: titleLabel; \n\ |
280 | + objectName: "titleLabel"; \n\ |
281 | + anchors { %1 } \n\ |
282 | + elide: Text.ElideRight; \n\ |
283 | + fontSize: "small"; \n\ |
284 | + wrapMode: Text.Wrap; \n\ |
285 | + maximumLineCount: 2; \n\ |
286 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\ |
287 | + color: %2; \n\ |
288 | + visible: showHeader %3; \n\ |
289 | + text: root.title; \n\ |
290 | + font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; \n\ |
291 | + horizontalAlignment: root.headerAlignment; \n\ |
292 | + }\n'; |
293 | + |
294 | +// %1 is used as anchors of subtitleLabel |
295 | +// %2 is used as color of subtitleLabel |
296 | +var kSubtitleLabelCode = 'Label { \n\ |
297 | + id: subtitleLabel; \n\ |
298 | + objectName: "subtitleLabel"; \n\ |
299 | + anchors { %1 } \n\ |
300 | + elide: Text.ElideRight; \n\ |
301 | + fontSize: "small"; \n\ |
302 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\ |
303 | + color: %2; \n\ |
304 | + visible: titleLabel.visible && titleLabel.text; \n\ |
305 | + text: cardData && cardData["subtitle"] || ""; \n\ |
306 | + font.weight: Font.Light; \n\ |
307 | + horizontalAlignment: root.headerAlignment; \n\ |
308 | + }\n'; |
309 | + |
310 | +// %1 is used as top anchor of summary |
311 | +// %2 is used as topMargin anchor of summary |
312 | +// %3 is used as color of summary |
313 | +var kSummaryLabelCode = 'Label { \n\ |
314 | + id: summary; \n\ |
315 | + objectName: "summaryLabel"; \n\ |
316 | + anchors { \n\ |
317 | + top: %1; \n\ |
318 | + left: parent.left; \n\ |
319 | + right: parent.right; \n\ |
320 | + margins: units.gu(1); \n\ |
321 | + topMargin: %2; \n\ |
322 | + } \n\ |
323 | + wrapMode: Text.Wrap; \n\ |
324 | + maximumLineCount: 5; \n\ |
325 | + elide: Text.ElideRight; \n\ |
326 | + text: cardData && cardData["summary"] || ""; \n\ |
327 | + height: text ? implicitHeight : 0; \n\ |
328 | + fontSize: "small"; \n\ |
329 | + color: %3; \n\ |
330 | + }\n'; |
331 | + |
332 | +function cardString(template, components) { |
333 | + var code; |
334 | + code = 'AbstractButton { \n\ |
335 | + id: root; \n\ |
336 | + property var template; \n\ |
337 | + property var components; \n\ |
338 | + property var cardData; \n\ |
339 | + property real fontScale: 1.0; \n\ |
340 | + property int headerAlignment: Text.AlignLeft; \n\ |
341 | + property int fixedHeaderHeight: -1; \n\ |
342 | + property size fixedArtShapeSize: Qt.size(-1, -1); \n\ |
343 | + readonly property string title: cardData && cardData["title"] || ""; \n\ |
344 | + property bool asynchronous: true; \n\ |
345 | + property bool showHeader: true; \n\ |
346 | + implicitWidth: childrenRect.width; \n'; |
347 | + |
348 | + var hasArt = components["art"] && components["art"]["field"] || false; |
349 | + var hasSummary = components["summary"] || false; |
350 | + var artAndSummary = hasArt && hasSummary; |
351 | + var isHorizontal = template["card-layout"] === "horizontal"; |
352 | + var hasBackground = !isHorizontal && (template["card-background"] || components["background"] || artAndSummary); |
353 | + var hasTitle = components["title"] || false; |
354 | + var hasMascot = components["mascot"] || false; |
355 | + var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot); |
356 | + var hasSubtitle = components["subtitle"] || false; |
357 | + var hasHeaderRow = hasMascot && hasTitle; |
358 | + |
359 | + if (hasBackground) { |
360 | + code += kBackgroundLoaderCode; |
361 | + } |
362 | + |
363 | + if (hasArt) { |
364 | + code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n'; |
365 | + |
366 | + var widthCode, heightCode; |
367 | + var anchors; |
368 | + if (isHorizontal) { |
369 | + anchors = 'left: parent.left'; |
370 | + if (hasMascot || hasTitle) { |
371 | + widthCode = 'height * artShape.aspect' |
372 | + heightCode = 'headerHeight'; |
373 | + } else { |
374 | + // This side of the else is a bit silly, who wants an horizontal layout without mascot and title? |
375 | + // So we define a "random" height of the image height + 2 gu for the margins |
376 | + widthCode = 'height * artShape.aspect' |
377 | + heightCode = 'units.gu(7.625)'; |
378 | + } |
379 | + } else { |
380 | + anchors = 'horizontalCenter: parent.horizontalCenter;'; |
381 | + widthCode = 'root.width' |
382 | + heightCode = 'width / artShape.aspect'; |
383 | + } |
384 | + |
385 | + code += kArtShapeHolderCode.arg(anchors).arg(widthCode).arg(heightCode); |
386 | + } else { |
387 | + code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n' |
388 | + } |
389 | + |
390 | + if (headerAsOverlay) { |
391 | + code += kOverlayLoaderCode; |
392 | + } |
393 | + |
394 | + var headerVerticalAnchors; |
395 | + if (headerAsOverlay) { |
396 | + headerVerticalAnchors = 'bottom: artShapeHolder.bottom; \n\ |
397 | + bottomMargin: units.gu(1);\n'; |
398 | + } else { |
399 | + if (hasArt) { |
400 | + if (isHorizontal) { |
401 | + headerVerticalAnchors = 'top: artShapeHolder.top; \n\ |
402 | + topMargin: units.gu(1);\n'; |
403 | + } else { |
404 | + headerVerticalAnchors = 'top: artShapeHolder.bottom; \n\ |
405 | + topMargin: units.gu(1);\n'; |
406 | + } |
407 | + } else { |
408 | + headerVerticalAnchors = 'top: parent.top; \n\ |
409 | + topMargin: units.gu(1);\n'; |
410 | + } |
411 | + } |
412 | + var headerLeftAnchor; |
413 | + var headerLeftAnchorHasMagin = false; |
414 | + if (isHorizontal && hasArt) { |
415 | + headerLeftAnchor = 'left: artShapeHolder.right; \n\ |
416 | + leftMargin: units.gu(1);\n'; |
417 | + headerLeftAnchorHasMagin = true; |
418 | + } else { |
419 | + headerLeftAnchor = 'left: parent.left;\n'; |
420 | + } |
421 | + |
422 | + if (hasHeaderRow) { |
423 | + code += 'readonly property int headerHeight: row.height + row.margins * 2;\n' |
424 | + } else if (hasMascot) { |
425 | + code += 'readonly property int headerHeight: mascotImage.height + units.gu(1) * 2;\n' |
426 | + } else if (hasSubtitle) { |
427 | + code += 'readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n' |
428 | + } else if (hasTitle) { |
429 | + code += 'readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2;\n' |
430 | + } else { |
431 | + code += 'readonly property int headerHeight: 0;\n' |
432 | + } |
433 | + |
434 | + var mascotShapeCode = ""; |
435 | + var mascotCode = ""; |
436 | + if (hasMascot) { |
437 | + var useMascotShape = !hasBackground && !headerAsOverlay; |
438 | + var anchors = ""; |
439 | + if (!hasHeaderRow) { |
440 | + anchors += headerLeftAnchor; |
441 | + anchors += headerVerticalAnchors; |
442 | + if (!headerLeftAnchorHasMagin) { |
443 | + anchors += 'leftMargin: units.gu(1);\n' |
444 | + } |
445 | + } else { |
446 | + anchors = "verticalCenter: parent.verticalCenter;" |
447 | + } |
448 | + |
449 | + if (useMascotShape) { |
450 | + mascotShapeCode = kMascotShapeLoaderCode.arg(anchors); |
451 | + } |
452 | + |
453 | + var mascotImageVisible = useMascotShape ? 'false' : 'showHeader'; |
454 | + mascotCode = kMascotImageCode.arg(anchors).arg(mascotImageVisible); |
455 | + } |
456 | + |
457 | + var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"'; |
458 | + |
459 | + var titleSubtitleCode = ""; |
460 | + if (hasTitle) { |
461 | + var color; |
462 | + if (headerAsOverlay) { |
463 | + color = '"white"'; |
464 | + } else if (hasSummary) { |
465 | + color = 'summary.color'; |
466 | + } else if (hasBackground) { |
467 | + color = summaryColorWithBackground; |
468 | + } else { |
469 | + color = '"grey"'; |
470 | + } |
471 | + |
472 | + var titleAnchors; |
473 | + var subtitleAnchors; |
474 | + if (hasMascot && hasSubtitle) { |
475 | + // Using row + column |
476 | + titleAnchors = 'left: parent.left; right: parent.right'; |
477 | + subtitleAnchors = titleAnchors; |
478 | + } else if (hasMascot) { |
479 | + // Using row + label |
480 | + titleAnchors = 'verticalCenter: parent.verticalCenter;\n' |
481 | + } else { |
482 | + if (headerAsOverlay) { |
483 | + // Using anchors to the overlay |
484 | + titleAnchors = 'left: parent.left; \n\ |
485 | + leftMargin: units.gu(1); \n\ |
486 | + right: parent.right; \n\ |
487 | + top: overlayLoader.top; \n\ |
488 | + topMargin: units.gu(1);\n'; |
489 | + } else { |
490 | + // Using anchors to the mascot/parent |
491 | + titleAnchors = "right: parent.right;"; |
492 | + titleAnchors += headerLeftAnchor; |
493 | + titleAnchors += headerVerticalAnchors; |
494 | + } |
495 | + subtitleAnchors = 'left: titleLabel.left; \n\ |
496 | + leftMargin: titleLabel.leftMargin; \n\ |
497 | + right: titleLabel.right; \n\ |
498 | + top: titleLabel.bottom; \n\ |
499 | + topMargin: units.dp(2);\n'; |
500 | + } |
501 | + |
502 | + var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': ''); |
503 | + var titleCode = kTitleLabelCode.arg(titleAnchors).arg(color).arg(titleLabelVisibleExtra); |
504 | + var subtitleCode = ""; |
505 | + if (hasSubtitle) { |
506 | + subtitleCode += kSubtitleLabelCode.arg(subtitleAnchors).arg(color); |
507 | + } |
508 | + |
509 | + if (hasMascot && hasSubtitle) { |
510 | + // If using row + column wrap the code in the column |
511 | + titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(subtitleCode); |
512 | + } else { |
513 | + titleSubtitleCode = titleCode + subtitleCode; |
514 | + } |
515 | + } |
516 | + |
517 | + if (hasHeaderRow) { |
518 | + if (mascotShapeCode != "") { |
519 | + code += kHeaderRow3Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotShapeCode).arg(mascotCode).arg(titleSubtitleCode); |
520 | + } else { |
521 | + code += kHeaderRow2Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotCode).arg(titleSubtitleCode); |
522 | + } |
523 | + } else { |
524 | + code += mascotShapeCode + mascotCode + titleSubtitleCode; |
525 | + } |
526 | + |
527 | + if (hasSummary) { |
528 | + var summaryTopAnchor; |
529 | + if (isHorizontal && hasArt) summaryTopAnchor = "artShapeHolder.bottom"; |
530 | + else if (headerAsOverlay && hasArt) summaryTopAnchor = "artShapeHolder.bottom"; |
531 | + else if (hasHeaderRow) summaryTopAnchor = "row.bottom"; |
532 | + else if (hasMascot) summaryTopAnchor = "mascotImage.bottom"; |
533 | + else if (hasSubtitle) summaryTopAnchor = "subtitleLabel.bottom"; |
534 | + else if (hasTitle) summaryTopAnchor = "titleLabel.bottom"; |
535 | + else if (hasArt) summaryTopAnchor = "artShapeHolder.bottom"; |
536 | + else summaryTopAnchor = "parent.top"; |
537 | + |
538 | + var color; |
539 | + if (hasBackground) { |
540 | + color = summaryColorWithBackground; |
541 | + } else { |
542 | + color = '"grey"'; |
543 | + } |
544 | + |
545 | + var summaryTopMargin = (hasMascot || hasSubtitle ? 'anchors.margins' : '0'); |
546 | + |
547 | + code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color); |
548 | + } |
549 | + |
550 | + if (hasSummary) { |
551 | + code += 'implicitHeight: summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n'; |
552 | + } else if (hasHeaderRow) { |
553 | + code += 'implicitHeight: row.y + row.height + units.gu(1);\n'; |
554 | + } else if (hasMascot) { |
555 | + code += 'implicitHeight: mascotImage.y + mascotImage.height;\n'; |
556 | + } else if (hasSubtitle) { |
557 | + code += 'implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);\n'; |
558 | + } else if (hasTitle) { |
559 | + code += 'implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);\n'; |
560 | + } |
561 | + // Close the AbstractButton |
562 | + code += '}\n'; |
563 | + |
564 | + return code; |
565 | +} |
566 | + |
567 | +function createCardComponent(parent, template, components) { |
568 | + var imports = 'import QtQuick 2.2; \n\ |
569 | + import Ubuntu.Components 0.1; \n\ |
570 | + import Ubuntu.Thumbnailer 0.1;\n'; |
571 | + var card = cardString(template, components); |
572 | + var code = imports + 'Component {\n' + card + '}\n'; |
573 | + return Qt.createQmlObject(code, parent, "createCardComponent"); |
574 | +} |
575 | |
576 | === added file 'plugins/Dash/CardCreatorCache.qml' |
577 | --- plugins/Dash/CardCreatorCache.qml 1970-01-01 00:00:00 +0000 |
578 | +++ plugins/Dash/CardCreatorCache.qml 2014-05-07 15:30:47 +0000 |
579 | @@ -0,0 +1,40 @@ |
580 | +/* |
581 | + * Copyright (C) 2014 Canonical, Ltd. |
582 | + * |
583 | + * This program is free software; you can redistribute it and/or modify |
584 | + * it under the terms of the GNU General Public License as published by |
585 | + * the Free Software Foundation; version 3. |
586 | + * |
587 | + * This program is distributed in the hope that it will be useful, |
588 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
589 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
590 | + * GNU General Public License for more details. |
591 | + * |
592 | + * You should have received a copy of the GNU General Public License |
593 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
594 | + */ |
595 | + |
596 | +pragma Singleton |
597 | +import QtQuick 2.2 |
598 | +import "CardCreator.js" as CardCreator |
599 | + |
600 | +QtObject { |
601 | + id: root |
602 | + |
603 | + property var cache: new Object(); |
604 | + |
605 | + function getCardComponent(template, components) { |
606 | + if (template === undefined || components === undefined) |
607 | + return undefined; |
608 | + |
609 | + var tString = JSON.stringify(template); |
610 | + var cString = JSON.stringify(components); |
611 | + var allString = tString + cString; |
612 | + var component = cache[allString]; |
613 | + if (component === undefined) { |
614 | + component = CardCreator.createCardComponent(root, template, components); |
615 | + cache[allString] = component; |
616 | + } |
617 | + return component; |
618 | + } |
619 | +} |
620 | |
621 | === modified file 'plugins/Dash/plugin.cpp' |
622 | --- plugins/DashViews/plugin.cpp 2014-01-10 16:29:19 +0000 |
623 | +++ plugins/Dash/plugin.cpp 2014-05-07 15:30:47 +0000 |
624 | @@ -24,9 +24,9 @@ |
625 | |
626 | #include <QAbstractItemModel> |
627 | |
628 | -void DashViewsPlugin::registerTypes(const char *uri) |
629 | +void DashPlugin::registerTypes(const char *uri) |
630 | { |
631 | - Q_ASSERT(uri == QLatin1String("DashViews")); |
632 | + Q_ASSERT(uri == QLatin1String("Dash")); |
633 | qmlRegisterType<QAbstractItemModel>(); |
634 | qmlRegisterType<HorizontalJournal>(uri, 0, 1, "HorizontalJournal"); |
635 | qmlRegisterType<ListViewWithPageHeader>(uri, 0, 1, "ListViewWithPageHeader"); |
636 | |
637 | === modified file 'plugins/Dash/plugin.h' |
638 | --- plugins/DashViews/plugin.h 2013-12-12 16:45:35 +0000 |
639 | +++ plugins/Dash/plugin.h 2014-05-07 15:30:47 +0000 |
640 | @@ -15,13 +15,13 @@ |
641 | * |
642 | */ |
643 | |
644 | -#ifndef DASHVIEWS_PLUGIN_H |
645 | -#define DASHVIEWS_PLUGIN_H |
646 | +#ifndef DASH_PLUGIN_H |
647 | +#define DASH_PLUGIN_H |
648 | |
649 | #include <QtQml/QQmlEngine> |
650 | #include <QtQml/QQmlExtensionPlugin> |
651 | |
652 | -class DashViewsPlugin : public QQmlExtensionPlugin |
653 | +class DashPlugin : public QQmlExtensionPlugin |
654 | { |
655 | Q_OBJECT |
656 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
657 | |
658 | === modified file 'plugins/Dash/qmldir' |
659 | --- plugins/DashViews/qmldir 2013-12-12 16:45:35 +0000 |
660 | +++ plugins/Dash/qmldir 2014-05-07 15:30:47 +0000 |
661 | @@ -1,3 +1,4 @@ |
662 | -module DashViews |
663 | -plugin DashViews-qml |
664 | +module Dash |
665 | +plugin Dash-qml |
666 | typeinfo plugin.qmltypes |
667 | +singleton CardCreatorCache 0.1 CardCreatorCache.qml |
668 | |
669 | === removed file 'qml/Dash/Card.qml' |
670 | --- qml/Dash/Card.qml 2014-04-16 11:04:49 +0000 |
671 | +++ qml/Dash/Card.qml 1970-01-01 00:00:00 +0000 |
672 | @@ -1,236 +0,0 @@ |
673 | -/* |
674 | - * Copyright (C) 2013 Canonical, Ltd. |
675 | - * |
676 | - * This program is free software; you can redistribute it and/or modify |
677 | - * it under the terms of the GNU General Public License as published by |
678 | - * the Free Software Foundation; version 3. |
679 | - * |
680 | - * This program is distributed in the hope that it will be useful, |
681 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
682 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
683 | - * GNU General Public License for more details. |
684 | - * |
685 | - * You should have received a copy of the GNU General Public License |
686 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
687 | - */ |
688 | - |
689 | -import QtQuick 2.0 |
690 | -import Ubuntu.Components 0.1 |
691 | -// For image://albumart and image://thumbnailer image providers |
692 | -import Ubuntu.Thumbnailer 0.1 |
693 | - |
694 | -AbstractButton { |
695 | - id: root |
696 | - property var template |
697 | - property var components |
698 | - property var cardData |
699 | - |
700 | - property real fontScale: 1.0 |
701 | - property int headerAlignment: Text.AlignLeft |
702 | - readonly property int headerHeight: headerLoader.item ? headerLoader.item.height : 0 |
703 | - property int fixedHeaderHeight: -1 |
704 | - readonly property string title: cardData && cardData["title"] || "" |
705 | - |
706 | - property bool showHeader: true |
707 | - |
708 | - implicitWidth: childrenRect.width |
709 | - implicitHeight: summary.y + summary.height + (summary.text && backgroundLoader.active ? units.gu(1) : 0) |
710 | - |
711 | - Loader { |
712 | - id: backgroundLoader |
713 | - objectName: "backgroundLoader" |
714 | - |
715 | - readonly property bool artAndSummary: components["art"]["field"] && components["summary"] || false |
716 | - active: template["card-layout"] !== "horizontal" && (template["card-background"] || components["background"] || artAndSummary) |
717 | - anchors.fill: parent |
718 | - |
719 | - sourceComponent: UbuntuShape { |
720 | - objectName: "background" |
721 | - radius: "medium" |
722 | - color: getColor(0) || "white" |
723 | - gradientColor: getColor(1) || color |
724 | - anchors.fill: parent |
725 | - image: backgroundImage.source ? backgroundImage : null |
726 | - |
727 | - property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b |
728 | - |
729 | - property Image backgroundImage: Image { |
730 | - objectName: "backgroundImage" |
731 | - source: { |
732 | - if (cardData && typeof cardData["background"] === "string") return cardData["background"] |
733 | - else if (template && typeof template["card-background"] === "string") return template["card-background"] |
734 | - else return "" |
735 | - } |
736 | - } |
737 | - |
738 | - function getColor(index) { |
739 | - if (cardData && typeof cardData["background"] === "object" |
740 | - && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) { |
741 | - return cardData["background"]["elements"][index]; |
742 | - } else if (template && typeof template["card-background"] === "object" |
743 | - && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) { |
744 | - return template["card-background"]["elements"][index]; |
745 | - } else return undefined; |
746 | - } |
747 | - } |
748 | - } |
749 | - |
750 | - UbuntuShape { |
751 | - id: artShape |
752 | - radius: "medium" |
753 | - objectName: "artShape" |
754 | - anchors.horizontalCenter: template && template["card-layout"] === "horizontal" ? undefined : parent.horizontalCenter |
755 | - anchors.left: template && template["card-layout"] === "horizontal" ? parent.left : undefined |
756 | - visible: cardData && cardData["art"] || false |
757 | - |
758 | - readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1 |
759 | - readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect |
760 | - |
761 | - Component.onCompleted: updateWidthHeightBindings(); |
762 | - onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); |
763 | - |
764 | - function updateWidthHeightBindings() { |
765 | - if (aspectSmallerThanImageAspect) { |
766 | - width = Qt.binding(function() { return !visible ? 0 : image.width }); |
767 | - height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); |
768 | - } else { |
769 | - width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); |
770 | - height = Qt.binding(function() { return !visible ? 0 : image.height }); |
771 | - } |
772 | - } |
773 | - |
774 | - image: Image { |
775 | - objectName: "artImage" |
776 | - source: cardData && cardData["art"] || "" |
777 | - cache: true |
778 | - // FIXME uncomment when having investigated / fixed the crash |
779 | - //sourceSize.width: width > height ? width : 0 |
780 | - //sourceSize.height: height > width ? height : 0 |
781 | - fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop |
782 | - |
783 | - readonly property real aspect: implicitWidth / implicitHeight |
784 | - readonly property bool isHorizontal: template && template["card-layout"] === "horizontal" |
785 | - |
786 | - Component.onCompleted: updateWidthHeightBindings(); |
787 | - onIsHorizontalChanged: updateWidthHeightBindings(); |
788 | - |
789 | - function updateWidthHeightBindings() { |
790 | - if (isHorizontal) { |
791 | - width = Qt.binding(function() { return height * artShape.aspect }); |
792 | - height = Qt.binding(function() { return root.headerHeight }); |
793 | - } else { |
794 | - width = Qt.binding(function() { return root.width }); |
795 | - height = Qt.binding(function() { return width / artShape.aspect }); |
796 | - } |
797 | - } |
798 | - } |
799 | - } |
800 | - |
801 | - Loader { |
802 | - id: overlayLoader |
803 | - anchors { |
804 | - left: artShape.left |
805 | - right: artShape.right |
806 | - bottom: artShape.bottom |
807 | - } |
808 | - active: template && template["overlay"] && artShape.visible && artShape.image.status === Image.Ready || false |
809 | - |
810 | - sourceComponent: ShaderEffect { |
811 | - id: overlay |
812 | - |
813 | - height: headerLoader.item ? headerLoader.item.height : 0 |
814 | - opacity: headerLoader.item ? headerLoader.item.opacity * 0.6 : 0 |
815 | - |
816 | - property var source: ShaderEffectSource { |
817 | - id: shaderSource |
818 | - sourceItem: artShape |
819 | - onVisibleChanged: if (visible) scheduleUpdate() |
820 | - live: false |
821 | - sourceRect: Qt.rect(0, artShape.height - overlay.height, artShape.width, overlay.height) |
822 | - } |
823 | - |
824 | - vertexShader: " |
825 | - uniform highp mat4 qt_Matrix; |
826 | - attribute highp vec4 qt_Vertex; |
827 | - attribute highp vec2 qt_MultiTexCoord0; |
828 | - varying highp vec2 coord; |
829 | - void main() { |
830 | - coord = qt_MultiTexCoord0; |
831 | - gl_Position = qt_Matrix * qt_Vertex; |
832 | - }" |
833 | - |
834 | - fragmentShader: " |
835 | - varying highp vec2 coord; |
836 | - uniform sampler2D source; |
837 | - uniform lowp float qt_Opacity; |
838 | - void main() { |
839 | - lowp vec4 tex = texture2D(source, coord); |
840 | - gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity; |
841 | - }" |
842 | - } |
843 | - } |
844 | - |
845 | - Loader { |
846 | - id: headerLoader |
847 | - objectName: "cardHeaderLoader" |
848 | - |
849 | - anchors { |
850 | - top: { |
851 | - if (template) { |
852 | - if (template["overlay"]) return overlayLoader.top; |
853 | - if (template["card-layout"] === "horizontal") return artShape.top; |
854 | - } |
855 | - return artShape.bottom; |
856 | - } |
857 | - left: { |
858 | - if (template) { |
859 | - if (!template["overlay"] && template["card-layout"] === "horizontal") return artShape.right; |
860 | - } |
861 | - return parent.left; |
862 | - } |
863 | - right: parent.right |
864 | - } |
865 | - active: cardData && cardData["title"] || cardData && cardData["mascot"] || false |
866 | - |
867 | - sourceComponent: CardHeader { |
868 | - id: header |
869 | - objectName: "cardHeader" |
870 | - |
871 | - mascot: cardData && cardData["mascot"] || "" |
872 | - title: root.title |
873 | - subtitle: cardData && cardData["subtitle"] || "" |
874 | - |
875 | - titleWeight: components && components["subtitle"] ? Font.DemiBold : Font.Normal |
876 | - |
877 | - opacity: showHeader ? 1 : 0 |
878 | - inOverlay: root.template && root.template["overlay"] === true |
879 | - fontColor: inOverlay ? "white" : summary.color |
880 | - useMascotShape: !backgroundLoader.active && !inOverlay |
881 | - headerAlignment: root.headerAlignment |
882 | - height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight |
883 | - fontScale: root.fontScale |
884 | - |
885 | - Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } } |
886 | - } |
887 | - } |
888 | - |
889 | - Label { |
890 | - id: summary |
891 | - objectName: "summaryLabel" |
892 | - anchors { |
893 | - top: headerLoader.active ? headerLoader.bottom : artShape.bottom |
894 | - left: parent.left |
895 | - right: parent.right |
896 | - margins: backgroundLoader.active ? units.gu(1) : 0 |
897 | - topMargin: 0 |
898 | - } |
899 | - wrapMode: Text.Wrap |
900 | - maximumLineCount: 5 |
901 | - elide: Text.ElideRight |
902 | - text: cardData && cardData["summary"] || "" |
903 | - height: text ? implicitHeight : 0 |
904 | - fontSize: "small" |
905 | - // TODO karni: Change "grey" to Ubuntu.Components.Palette color once updated. |
906 | - color: backgroundLoader.active && backgroundLoader.item.luminance < 0.7 ? "white" : "grey" |
907 | - } |
908 | -} |
909 | |
910 | === modified file 'qml/Dash/CardCarousel.qml' |
911 | --- qml/Dash/CardCarousel.qml 2014-04-01 14:40:07 +0000 |
912 | +++ qml/Dash/CardCarousel.qml 2014-05-07 15:30:47 +0000 |
913 | @@ -49,21 +49,24 @@ |
914 | property real fontScale: 1 / selectedItemScaleFactor |
915 | property real headerHeight: cardTool.headerHeight / selectedItemScaleFactor |
916 | |
917 | - itemComponent: Card { |
918 | - id: card |
919 | - objectName: "carouselDelegate" + index |
920 | - fixedHeaderHeight: carousel.headerHeight |
921 | - cardData: model |
922 | - template: cardTool.template |
923 | - components: cardTool.components |
924 | + itemComponent: Loader { |
925 | + id: loader |
926 | |
927 | property bool explicitlyScaled |
928 | property var model |
929 | - |
930 | enabled: false |
931 | - showHeader: explicitlyScaled |
932 | |
933 | - fontScale: carousel.fontScale |
934 | + sourceComponent: cardTool.cardComponent |
935 | + onLoaded: { |
936 | + item.objectName = "carouselDelegate" + index; |
937 | + item.fixedHeaderHeight = Qt.binding(function() { return carousel.headerHeight; }); |
938 | + item.height = Qt.binding(function() { return cardTool.cardHeight; }); |
939 | + item.cardData = Qt.binding(function() { return model; }); |
940 | + item.template = Qt.binding(function() { return cardTool.template; }); |
941 | + item.components = Qt.binding(function() { return cardTool.components; }); |
942 | + item.fontScale = Qt.binding(function() { return carousel.fontScale; }); |
943 | + item.showHeader = Qt.binding(function() { return loader.explicitlyScaled; }); |
944 | + } |
945 | } |
946 | } |
947 | } |
948 | |
949 | === modified file 'qml/Dash/CardFilterGrid.qml' |
950 | --- qml/Dash/CardFilterGrid.qml 2014-04-16 15:55:59 +0000 |
951 | +++ qml/Dash/CardFilterGrid.qml 2014-05-07 15:30:47 +0000 |
952 | @@ -45,25 +45,28 @@ |
953 | collapsedRowCount: Math.min(2, cardTool && cardTool.template && cardTool.template["collapsed-rows"] || 2) |
954 | delegateCreationBegin: genericFilterGrid.delegateCreationBegin |
955 | delegateCreationEnd: genericFilterGrid.delegateCreationEnd |
956 | - delegate: Loader { |
957 | - asynchronous: true |
958 | + delegate: Item { |
959 | width: filterGrid.cellWidth |
960 | height: filterGrid.cellHeight |
961 | - Card { |
962 | - id: card |
963 | - width: cardTool.cardWidth |
964 | - height: cardTool.cardHeight |
965 | - fixedHeaderHeight: cardTool.headerHeight |
966 | + Loader { |
967 | + id: loader |
968 | + sourceComponent: cardTool.cardComponent |
969 | anchors.horizontalCenter: parent.horizontalCenter |
970 | - objectName: "delegate" + index |
971 | - cardData: model |
972 | - template: cardTool.template |
973 | - components: cardTool.components |
974 | - |
975 | - headerAlignment: cardTool.headerAlignment |
976 | - |
977 | - onClicked: genericFilterGrid.clicked(index, card.y) |
978 | - onPressAndHold: genericFilterGrid.pressAndHold(index, card.y) |
979 | + onLoaded: { |
980 | + item.objectName = "delegate" + index; |
981 | + item.width = Qt.binding(function() { return cardTool.cardWidth; }); |
982 | + item.height = Qt.binding(function() { return cardTool.cardHeight; }); |
983 | + item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; }); |
984 | + item.cardData = Qt.binding(function() { return model; }); |
985 | + item.template = Qt.binding(function() { return cardTool.template; }); |
986 | + item.components = Qt.binding(function() { return cardTool.components; }); |
987 | + item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; }); |
988 | + } |
989 | + Connections { |
990 | + target: loader.item |
991 | + onClicked: genericFilterGrid.clicked(index, item.y) |
992 | + onPressAndHold: genericFilterGrid.pressAndHold(index, item.y) |
993 | + } |
994 | } |
995 | } |
996 | } |
997 | |
998 | === removed file 'qml/Dash/CardHeader.qml' |
999 | --- qml/Dash/CardHeader.qml 2014-04-02 14:29:21 +0000 |
1000 | +++ qml/Dash/CardHeader.qml 1970-01-01 00:00:00 +0000 |
1001 | @@ -1,126 +0,0 @@ |
1002 | -/* |
1003 | - * Copyright (C) 2013 Canonical, Ltd. |
1004 | - * |
1005 | - * This program is free software; you can redistribute it and/or modify |
1006 | - * it under the terms of the GNU General Public License as published by |
1007 | - * the Free Software Foundation; version 3. |
1008 | - * |
1009 | - * This program is distributed in the hope that it will be useful, |
1010 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1011 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1012 | - * GNU General Public License for more details. |
1013 | - * |
1014 | - * You should have received a copy of the GNU General Public License |
1015 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1016 | - */ |
1017 | - |
1018 | -import QtQuick 2.0 |
1019 | -import Ubuntu.Components 0.1 |
1020 | - |
1021 | -Item { |
1022 | - id: root |
1023 | - property url mascot: "" |
1024 | - property alias title: titleLabel.text |
1025 | - property var subtitle |
1026 | - |
1027 | - property alias titleWeight: titleLabel.font.weight |
1028 | - property alias titleSize: titleLabel.fontSize |
1029 | - |
1030 | - // FIXME: Saviq, used to scale fonts down in Carousel |
1031 | - property real fontScale: 1.0 |
1032 | - |
1033 | - property alias headerAlignment: titleLabel.horizontalAlignment |
1034 | - |
1035 | - property bool inOverlay: false |
1036 | - property bool useMascotShape: true |
1037 | - property color fontColor: Theme.palette.selected.backgroundText |
1038 | - |
1039 | - visible: mascot != "" || title |
1040 | - implicitHeight: row.height > 0 ? row.height + row.margins * 2 : 0 |
1041 | - |
1042 | - Row { |
1043 | - id: row |
1044 | - objectName: "outerRow" |
1045 | - |
1046 | - property real margins: units.gu(1) |
1047 | - |
1048 | - spacing: mascotShapeLoader.active || mascotImageLoader.active || inOverlay ? margins : 0 |
1049 | - anchors { |
1050 | - top: parent.top; left: parent.left; right: parent.right |
1051 | - margins: margins |
1052 | - leftMargin: spacing |
1053 | - rightMargin: spacing |
1054 | - } |
1055 | - |
1056 | - Loader { |
1057 | - id: mascotShapeLoader |
1058 | - objectName: "mascotShapeLoader" |
1059 | - |
1060 | - active: useMascotShape && mascotImageLoader.item && mascotImageLoader.item.status === Image.Ready |
1061 | - visible: active |
1062 | - anchors.verticalCenter: parent.verticalCenter |
1063 | - // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels. |
1064 | - width: units.gu(6) |
1065 | - height: units.gu(5.625) |
1066 | - readonly property int maxSize: Math.max(width, height) * 4 |
1067 | - |
1068 | - sourceComponent: UbuntuShape { |
1069 | - image: mascotImageLoader.item |
1070 | - } |
1071 | - } |
1072 | - |
1073 | - Loader { |
1074 | - id: mascotImageLoader |
1075 | - active: root.mascot != "" |
1076 | - visible: active && !useMascotShape && item.status === Image.Ready |
1077 | - anchors.verticalCenter: parent.verticalCenter |
1078 | - sourceComponent: Image { |
1079 | - objectName: "mascotImage" |
1080 | - |
1081 | - source: root.mascot |
1082 | - width: source ? mascotShapeLoader.width : 0 |
1083 | - height: mascotShapeLoader.height |
1084 | - |
1085 | - sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize } |
1086 | - fillMode: Image.PreserveAspectCrop |
1087 | - horizontalAlignment: Image.AlignHCenter |
1088 | - verticalAlignment: Image.AlignVCenter |
1089 | - } |
1090 | - } |
1091 | - |
1092 | - Column { |
1093 | - objectName: "column" |
1094 | - width: parent.width - x |
1095 | - spacing: units.dp(2) |
1096 | - anchors.verticalCenter: parent.verticalCenter |
1097 | - |
1098 | - Label { |
1099 | - id: titleLabel |
1100 | - objectName: "titleLabel" |
1101 | - anchors { left: parent.left; right: parent.right } |
1102 | - elide: Text.ElideRight |
1103 | - font.weight: Font.Normal |
1104 | - fontSize: "small" |
1105 | - wrapMode: Text.Wrap |
1106 | - maximumLineCount: 2 |
1107 | - font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale) |
1108 | - color: fontColor |
1109 | - } |
1110 | - |
1111 | - Loader { |
1112 | - active: titleLabel.text && root.subtitle |
1113 | - anchors { left: parent.left; right: parent.right } |
1114 | - sourceComponent: Label { |
1115 | - id: subtitleLabel |
1116 | - objectName: "subtitleLabel" |
1117 | - elide: Text.ElideRight |
1118 | - fontSize: "small" |
1119 | - font.weight: Font.Light |
1120 | - font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale) |
1121 | - color: fontColor |
1122 | - text: root.subtitle |
1123 | - } |
1124 | - } |
1125 | - } |
1126 | - } |
1127 | -} |
1128 | |
1129 | === modified file 'qml/Dash/CardTool.qml' |
1130 | --- qml/Dash/CardTool.qml 2014-03-17 11:44:05 +0000 |
1131 | +++ qml/Dash/CardTool.qml 2014-05-07 15:30:47 +0000 |
1132 | @@ -15,6 +15,7 @@ |
1133 | */ |
1134 | |
1135 | import QtQuick 2.0 |
1136 | +import Dash 0.1 |
1137 | |
1138 | /*! |
1139 | \brief Tool for introspecting Card properties. |
1140 | @@ -65,6 +66,8 @@ |
1141 | return layout; |
1142 | } |
1143 | |
1144 | + property var cardComponent: CardCreatorCache.getCardComponent(cardTool.template, cardTool.components); |
1145 | + |
1146 | // FIXME: Saviq |
1147 | // Only way for the card below to actually be laid out completely. |
1148 | // If invisible or in "data" array, some components are not taken into account. |
1149 | @@ -108,7 +111,7 @@ |
1150 | if (template["card-size"] >= 12 && template["card-size"] <= 38) return units.gu(template["card-size"]); |
1151 | return units.gu(18.5); |
1152 | case "grid": |
1153 | - return card.implicitHeight |
1154 | + return cardLoader.item ? cardLoader.item.implicitHeight : 0 |
1155 | case "carousel": |
1156 | return cardWidth / (components ? components["art"]["aspect-ratio"] : 1) |
1157 | case undefined: |
1158 | @@ -122,7 +125,8 @@ |
1159 | /*! |
1160 | type:real \brief Height of the card's header. |
1161 | */ |
1162 | - readonly property alias headerHeight: card.headerHeight |
1163 | + readonly property int headerHeight: cardLoader.item ? cardLoader.item.headerHeight : 0 |
1164 | + readonly property size artShapeSize: cardLoader.item ? cardLoader.item.artShapeSize : 0 |
1165 | |
1166 | /*! |
1167 | \brief Desired alignment of header components. |
1168 | @@ -161,15 +165,8 @@ |
1169 | } |
1170 | } |
1171 | |
1172 | - Card { |
1173 | - id: card |
1174 | - objectName: "cardToolCard" |
1175 | - template: cardTool.template |
1176 | - components: cardTool.components |
1177 | - |
1178 | - width: cardTool.cardWidth || implicitWidth |
1179 | - height: cardTool.cardHeight || implicitHeight |
1180 | - |
1181 | + Loader { |
1182 | + id: cardLoader |
1183 | property var fields: ["art", "mascot", "title", "subtitle", "summary"] |
1184 | property var maxData: { |
1185 | "art": Qt.resolvedUrl("graphics/checkers.png"), |
1186 | @@ -178,19 +175,30 @@ |
1187 | "subtitle": "—", |
1188 | "summary": "—\n—\n—\n—\n—" |
1189 | } |
1190 | - |
1191 | - onComponentsChanged: { |
1192 | - var data = {}; |
1193 | - for (var k in fields) { |
1194 | - var component = components[fields[k]]; |
1195 | - var key = fields[k]; |
1196 | - if ((typeof component === "string" && component.length > 0) || |
1197 | - (typeof component === "object" && component !== null |
1198 | - && typeof component["field"] === "string" && component["field"].length > 0)) { |
1199 | - data[key] = maxData[key]; |
1200 | + sourceComponent: cardTool.cardComponent |
1201 | + onLoaded: { |
1202 | + item.objectName = "cardToolCard"; |
1203 | + item.asynchronous = false; |
1204 | + item.template = Qt.binding(function() { return cardTool.template; }); |
1205 | + item.components = Qt.binding(function() { return cardTool.components; }); |
1206 | + item.width = Qt.binding(function() { return cardTool.cardWidth || item.implicitWidth; }); |
1207 | + item.height = Qt.binding(function() { return cardTool.cardHeight || item.implicitHeight; }); |
1208 | + } |
1209 | + Connections { |
1210 | + target: cardLoader.item |
1211 | + onComponentsChanged: { |
1212 | + var data = {}; |
1213 | + for (var k in cardLoader.fields) { |
1214 | + var component = cardLoader.item.components[cardLoader.fields[k]]; |
1215 | + var key = cardLoader.fields[k]; |
1216 | + if ((typeof component === "string" && component.length > 0) || |
1217 | + (typeof component === "object" && component !== null |
1218 | + && typeof component["field"] === "string" && component["field"].length > 0)) { |
1219 | + data[key] = cardLoader.maxData[key]; |
1220 | + } |
1221 | } |
1222 | + cardLoader.item.cardData = data; |
1223 | } |
1224 | - cardData = data; |
1225 | } |
1226 | } |
1227 | } |
1228 | |
1229 | === modified file 'qml/Dash/Previews/PreviewHeader.qml' |
1230 | --- qml/Dash/Previews/PreviewHeader.qml 2014-03-18 09:37:29 +0000 |
1231 | +++ qml/Dash/Previews/PreviewHeader.qml 2014-05-07 15:30:47 +0000 |
1232 | @@ -15,9 +15,10 @@ |
1233 | */ |
1234 | |
1235 | import QtQuick 2.0 |
1236 | +import Ubuntu.Components 0.1 |
1237 | import "../" |
1238 | |
1239 | -/*! This preview widget shows a header that is the same as the card header |
1240 | +/*! This preview widget shows a header |
1241 | * The title comes in widgetData["title"] |
1242 | * The mascot comes in widgetData["mascot"] |
1243 | * The subtitle comes in widgetData["subtitle"] |
1244 | @@ -28,15 +29,91 @@ |
1245 | |
1246 | height: childrenRect.height |
1247 | |
1248 | - CardHeader { |
1249 | - objectName: "cardHeader" |
1250 | - mascot: root.widgetData["mascot"] || "" |
1251 | - title: root.widgetData["title"] || "" |
1252 | - subtitle: root.widgetData["subtitle"] || "" |
1253 | + Item { |
1254 | + id: headerRoot |
1255 | + objectName: "innerPreviewHeader" |
1256 | + readonly property url mascot: root.widgetData["mascot"] || "" |
1257 | + readonly property string title: root.widgetData["title"] || "" |
1258 | + readonly property string subtitle: root.widgetData["subtitle"] || "" |
1259 | + readonly property color fontColor: "grey" |
1260 | + |
1261 | + implicitHeight: row.height + row.margins * 2 |
1262 | width: parent.width |
1263 | |
1264 | - titleSize: "large" |
1265 | - // TODO Change "grey" to Ubuntu.Components.Palette color once updated. |
1266 | - fontColor: "grey" |
1267 | + Row { |
1268 | + id: row |
1269 | + objectName: "outerRow" |
1270 | + |
1271 | + property real margins: units.gu(1) |
1272 | + |
1273 | + spacing: mascotShapeLoader.active ? margins : 0 |
1274 | + anchors { |
1275 | + top: parent.top; left: parent.left; right: parent.right |
1276 | + margins: margins |
1277 | + leftMargin: spacing |
1278 | + rightMargin: spacing |
1279 | + } |
1280 | + |
1281 | + Loader { |
1282 | + id: mascotShapeLoader |
1283 | + |
1284 | + anchors.verticalCenter: parent.verticalCenter |
1285 | + // TODO karni: Icon aspect-ratio is 8:7.5. Revisit these values to avoid fraction of pixels. |
1286 | + width: units.gu(6) |
1287 | + height: units.gu(5.625) |
1288 | + readonly property int maxSize: Math.max(width, height) * 4 |
1289 | + asynchronous: true |
1290 | + |
1291 | + sourceComponent: UbuntuShape { |
1292 | + objectName: "mascotShape" |
1293 | + visible: image.status === Image.Ready |
1294 | + image: Image { |
1295 | + source: headerRoot.mascot |
1296 | + width: source ? mascotShapeLoader.width : 0 |
1297 | + height: mascotShapeLoader.height |
1298 | + |
1299 | + sourceSize { width: mascotShapeLoader.maxSize; height: mascotShapeLoader.maxSize } |
1300 | + fillMode: Image.PreserveAspectCrop |
1301 | + horizontalAlignment: Image.AlignHCenter |
1302 | + verticalAlignment: Image.AlignVCenter |
1303 | + } |
1304 | + } |
1305 | + } |
1306 | + |
1307 | + Column { |
1308 | + objectName: "column" |
1309 | + width: parent.width - x |
1310 | + spacing: units.dp(2) |
1311 | + anchors.verticalCenter: parent.verticalCenter |
1312 | + |
1313 | + Label { |
1314 | + id: titleLabel |
1315 | + objectName: "titleLabel" |
1316 | + anchors { left: parent.left; right: parent.right } |
1317 | + elide: Text.ElideRight |
1318 | + font.weight: Font.Normal |
1319 | + fontSize: "large" |
1320 | + wrapMode: Text.Wrap |
1321 | + maximumLineCount: 2 |
1322 | + color: headerRoot.fontColor |
1323 | + text: headerRoot.title |
1324 | + } |
1325 | + |
1326 | + Loader { |
1327 | + active: titleLabel.text && headerRoot.subtitle |
1328 | + anchors { left: parent.left; right: parent.right } |
1329 | + sourceComponent: Label { |
1330 | + id: subtitleLabel |
1331 | + objectName: "subtitleLabel" |
1332 | + elide: Text.ElideRight |
1333 | + fontSize: "small" |
1334 | + font.weight: Font.Light |
1335 | + color: headerRoot.fontColor |
1336 | + text: headerRoot.subtitle |
1337 | + } |
1338 | + } |
1339 | + } |
1340 | + } |
1341 | } |
1342 | + |
1343 | } |
1344 | |
1345 | === modified file 'qml/Dash/ScopeListView.qml' |
1346 | --- qml/Dash/ScopeListView.qml 2013-12-12 16:45:35 +0000 |
1347 | +++ qml/Dash/ScopeListView.qml 2014-05-07 15:30:47 +0000 |
1348 | @@ -15,7 +15,7 @@ |
1349 | */ |
1350 | |
1351 | import QtQuick 2.0 |
1352 | -import DashViews 0.1 |
1353 | +import Dash 0.1 |
1354 | |
1355 | ListViewWithPageHeader { |
1356 | maximumFlickVelocity: height * 10 |
1357 | |
1358 | === modified file 'tests/autopilot/unity8/shell/emulators/dash.py' |
1359 | --- tests/autopilot/unity8/shell/emulators/dash.py 2014-04-16 13:43:19 +0000 |
1360 | +++ tests/autopilot/unity8/shell/emulators/dash.py 2014-05-07 15:30:47 +0000 |
1361 | @@ -161,7 +161,7 @@ |
1362 | |
1363 | """ |
1364 | category_element = self._get_category_element(category) |
1365 | - icon = category_element.select_single('Card', title=app_name) |
1366 | + icon = category_element.select_single('AbstractButton', title=app_name) |
1367 | # FIXME some categories need a long press in order to see the preview. |
1368 | # Some categories do not show previews, like recent apps. |
1369 | # --elopio - 2014-1-14 |
1370 | @@ -191,7 +191,7 @@ |
1371 | |
1372 | """ |
1373 | category_element = self._get_category_element(category) |
1374 | - application_cards = category_element.select_many('Card') |
1375 | + application_cards = category_element.select_many('AbstractButton') |
1376 | |
1377 | # sort by y, x |
1378 | application_cards = sorted( |
1379 | @@ -201,8 +201,7 @@ |
1380 | result = [] |
1381 | for card in application_cards: |
1382 | if card.objectName != 'cardToolCard': |
1383 | - card_header = card.select_single('CardHeader') |
1384 | - result.append(card_header.title) |
1385 | + result.append(card.title) |
1386 | return result |
1387 | |
1388 | |
1389 | |
1390 | === modified file 'tests/mocks/Unity/fake_categories.cpp' |
1391 | --- tests/mocks/Unity/fake_categories.cpp 2014-02-25 15:43:42 +0000 |
1392 | +++ tests/mocks/Unity/fake_categories.cpp 2014-05-07 15:30:47 +0000 |
1393 | @@ -108,7 +108,12 @@ |
1394 | case RoleRenderer: |
1395 | { |
1396 | QVariantMap map; |
1397 | - map["category-layout"] = index.row() % 2 == 0 ? "grid" : "carousel"; |
1398 | + if (index.row() % 2 == 0) { |
1399 | + map["category-layout"] = "grid"; |
1400 | + } else { |
1401 | + map["category-layout"] = "carousel"; |
1402 | + map["overlay"] = true; |
1403 | + } |
1404 | map["card-size"] = "small"; |
1405 | return map; |
1406 | } |
1407 | @@ -146,7 +151,14 @@ |
1408 | case RoleRenderer: |
1409 | { |
1410 | QVariantMap map; |
1411 | - map["category-layout"] = index.row() % 2 == 0 ? "grid" : "carousel"; |
1412 | + if (index.row() % 2 == 0) { |
1413 | + map["category-layout"] = "grid"; |
1414 | + } else { |
1415 | + map["category-layout"] = "carousel"; |
1416 | + map["card-size"] = "medium"; |
1417 | + map["collapsed-rows"] = 2; |
1418 | + map["overlay"] = true; |
1419 | + } |
1420 | map["card-size"] = "small"; |
1421 | return map; |
1422 | } |
1423 | @@ -157,6 +169,7 @@ |
1424 | artMap["field"] = "art"; |
1425 | map["art"] = artMap; |
1426 | map["title"] = "HOLA"; |
1427 | + map["subtitle"] = "HOLA"; |
1428 | return map; |
1429 | } |
1430 | case RoleProgressSource: |
1431 | |
1432 | === modified file 'tests/mocks/Unity/fake_resultsmodel.cpp' |
1433 | --- tests/mocks/Unity/fake_resultsmodel.cpp 2014-03-10 11:47:04 +0000 |
1434 | +++ tests/mocks/Unity/fake_resultsmodel.cpp 2014-05-07 15:30:47 +0000 |
1435 | @@ -103,6 +103,7 @@ |
1436 | case RoleArt: |
1437 | return qmlDirectory() + "graphics/applicationIcons/dash.png"; |
1438 | case RoleSubtitle: |
1439 | + return QString("Subtitle.%1.%2").arg(m_categoryId).arg(index.row()); |
1440 | case RoleMascot: |
1441 | case RoleEmblem: |
1442 | case RoleOldPrice: |
1443 | |
1444 | === modified file 'tests/plugins/CMakeLists.txt' |
1445 | --- tests/plugins/CMakeLists.txt 2013-12-12 16:45:35 +0000 |
1446 | +++ tests/plugins/CMakeLists.txt 2014-05-07 15:30:47 +0000 |
1447 | @@ -1,6 +1,6 @@ |
1448 | add_subdirectory(AccountsService) |
1449 | add_subdirectory(LightDM) |
1450 | -add_subdirectory(DashViews) |
1451 | +add_subdirectory(Dash) |
1452 | add_subdirectory(Ubuntu) |
1453 | add_subdirectory(Unity) |
1454 | add_subdirectory(Utils) |
1455 | |
1456 | === renamed directory 'tests/plugins/DashViews' => 'tests/plugins/Dash' |
1457 | === modified file 'tests/plugins/Dash/CMakeLists.txt' |
1458 | --- tests/plugins/DashViews/CMakeLists.txt 2014-04-10 13:49:37 +0000 |
1459 | +++ tests/plugins/Dash/CMakeLists.txt 2014-05-07 15:30:47 +0000 |
1460 | @@ -16,7 +16,7 @@ |
1461 | ${Qt5Quick_INCLUDE_DIRS} |
1462 | ${Qt5Quick_PRIVATE_INCLUDE_DIRS} |
1463 | ${Qt5V8_PRIVATE_INCLUDE_DIR} |
1464 | - ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews |
1465 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash |
1466 | ${CMAKE_CURRENT_BINARY_DIR} |
1467 | ) |
1468 | |
1469 | @@ -28,11 +28,11 @@ |
1470 | macro(add_lvwph_test FILENAME TESTNAME) |
1471 | add_executable(${TESTNAME}TestExec |
1472 | ${FILENAME}test.cpp |
1473 | - ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/listviewwithpageheader.cpp) |
1474 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/listviewwithpageheader.cpp) |
1475 | qt5_use_modules(${TESTNAME}TestExec Test Core Qml) |
1476 | target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES}) |
1477 | |
1478 | - add_binary_qml_test(${TESTNAME} "" "DashViews-qml") |
1479 | + add_binary_qml_test(${TESTNAME} "" "Dash-qml") |
1480 | endmacro() |
1481 | |
1482 | add_lvwph_test(listviewwithpageheader ListViewWithPageHeader) |
1483 | @@ -42,24 +42,24 @@ |
1484 | macro(add_dashview_try_test FILENAME TESTNAME) |
1485 | add_executable(${TESTNAME}TestExec |
1486 | ${FILENAME}test.cpp |
1487 | - ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp |
1488 | - ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp |
1489 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/${FILENAME}.cpp |
1490 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/abstractdashview.cpp |
1491 | ) |
1492 | qt5_use_modules(${TESTNAME}TestExec Test Core Qml) |
1493 | target_link_libraries(${TESTNAME}TestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES}) |
1494 | |
1495 | - add_binary_qml_test(${TESTNAME} "" "DashViews-qml") |
1496 | + add_binary_qml_test(${TESTNAME} "" "Dash-qml") |
1497 | |
1498 | add_executable(${TESTNAME}tryExec |
1499 | ${FILENAME}try.cpp |
1500 | - ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/${FILENAME}.cpp |
1501 | - ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/DashViews/abstractdashview.cpp |
1502 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/${FILENAME}.cpp |
1503 | + ${CMAKE_CURRENT_SOURCE_DIR}/../../../plugins/Dash/abstractdashview.cpp |
1504 | ) |
1505 | qt5_use_modules(${TESTNAME}tryExec Test Core Qml) |
1506 | target_link_libraries(${TESTNAME}tryExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES}) |
1507 | add_custom_target(try${TESTNAME} |
1508 | ${CMAKE_CURRENT_BINARY_DIR}/${TESTNAME}tryExec |
1509 | - DEPENDS ${TESTNAME}tryExec DashViews-qml |
1510 | + DEPENDS ${TESTNAME}tryExec Dash-qml |
1511 | ) |
1512 | endmacro() |
1513 | |
1514 | @@ -67,6 +67,13 @@ |
1515 | add_dashview_try_test(horizontaljournal HorizontalJournal) |
1516 | add_dashview_try_test(organicgrid OrganicGrid) |
1517 | |
1518 | +# CardCreator test |
1519 | +add_executable(CardCreatorTestExec cardcreatortest.cpp) |
1520 | +qt5_use_modules(CardCreatorTestExec Test Core Qml) |
1521 | +target_link_libraries(CardCreatorTestExec ${Qt5Gui_LIBRARIES} ${Qt5Quick_LIBRARIES}) |
1522 | +add_binary_qml_test(CardCreator "" "Dash-qml") |
1523 | + |
1524 | +# plain qml test |
1525 | set(qmltest_DEFAULT_TARGETS qmluitests) |
1526 | set(qmltest_DEFAULT_NO_ADD_TEST TRUE) |
1527 | add_qml_test(. ListViewWithPageHeaderQML IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins) |
1528 | |
1529 | === added directory 'tests/plugins/Dash/cardcreator' |
1530 | === added file 'tests/plugins/Dash/cardcreator/1.res' |
1531 | --- tests/plugins/Dash/cardcreator/1.res 1970-01-01 00:00:00 +0000 |
1532 | +++ tests/plugins/Dash/cardcreator/1.res 2014-05-07 15:30:47 +0000 |
1533 | @@ -0,0 +1,77 @@ |
1534 | +AbstractButton { |
1535 | + id: root; |
1536 | + property var template; |
1537 | + property var components; |
1538 | + property var cardData; |
1539 | + property real fontScale: 1.0; |
1540 | + property int headerAlignment: Text.AlignLeft; |
1541 | + property int fixedHeaderHeight: -1; |
1542 | + property size fixedArtShapeSize: Qt.size(-1, -1); |
1543 | + readonly property string title: cardData && cardData["title"] || ""; |
1544 | + property bool asynchronous: true; |
1545 | + property bool showHeader: true; |
1546 | + implicitWidth: childrenRect.width; |
1547 | +readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1); |
1548 | +Item { |
1549 | + id: artShapeHolder; |
1550 | + height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; |
1551 | + width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; |
1552 | + anchors { horizontalCenter: parent.horizontalCenter; } |
1553 | + Loader { |
1554 | + id: artShapeLoader; |
1555 | + objectName: "artShapeLoader"; |
1556 | + active: cardData && cardData["art"] || false; |
1557 | + asynchronous: root.asynchronous; |
1558 | + visible: status == Loader.Ready; |
1559 | + sourceComponent: UbuntuShape { |
1560 | + id: artShape; |
1561 | + objectName: "artShape"; |
1562 | + radius: "medium"; |
1563 | + readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; |
1564 | + readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; |
1565 | + Component.onCompleted: updateWidthHeightBindings(); |
1566 | + onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); |
1567 | + visible: image.status == Image.Ready; |
1568 | + function updateWidthHeightBindings() { |
1569 | + if (aspectSmallerThanImageAspect) { |
1570 | + width = Qt.binding(function() { return !visible ? 0 : image.width }); |
1571 | + height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); |
1572 | + } else { |
1573 | + width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); |
1574 | + height = Qt.binding(function() { return !visible ? 0 : image.height }); |
1575 | + } |
1576 | + } |
1577 | + image: Image { |
1578 | + objectName: "artImage"; |
1579 | + source: cardData && cardData["art"] || ""; |
1580 | + cache: true; |
1581 | + asynchronous: root.asynchronous; |
1582 | + fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; |
1583 | + readonly property real aspect: implicitWidth / implicitHeight; |
1584 | + width: root.width; |
1585 | + height: width / artShape.aspect; |
1586 | + } |
1587 | + } |
1588 | + } |
1589 | + } |
1590 | +readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2; |
1591 | +Label { |
1592 | + id: titleLabel; |
1593 | + objectName: "titleLabel"; |
1594 | + anchors { right: parent.right;left: parent.left; |
1595 | +top: artShapeHolder.bottom; |
1596 | + topMargin: units.gu(1); |
1597 | + } |
1598 | + elide: Text.ElideRight; |
1599 | + fontSize: "small"; |
1600 | + wrapMode: Text.Wrap; |
1601 | + maximumLineCount: 2; |
1602 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
1603 | + color: "grey"; |
1604 | + visible: showHeader ; |
1605 | + text: root.title; |
1606 | + font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; |
1607 | + horizontalAlignment: root.headerAlignment; |
1608 | + } |
1609 | +implicitHeight: titleLabel.y + titleLabel.height + units.gu(1); |
1610 | +} |
1611 | |
1612 | === added file 'tests/plugins/Dash/cardcreator/1.tst' |
1613 | --- tests/plugins/Dash/cardcreator/1.tst 1970-01-01 00:00:00 +0000 |
1614 | +++ tests/plugins/Dash/cardcreator/1.tst 2014-05-07 15:30:47 +0000 |
1615 | @@ -0,0 +1,3 @@ |
1616 | +template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2} |
1617 | +components: {"art":{"aspect-ratio":1.6,"field":"art","fill-mode":"fit"},"title":{"field":"title"}} |
1618 | +result: 1.res |
1619 | |
1620 | === added file 'tests/plugins/Dash/cardcreator/2.res' |
1621 | --- tests/plugins/Dash/cardcreator/2.res 1970-01-01 00:00:00 +0000 |
1622 | +++ tests/plugins/Dash/cardcreator/2.res 2014-05-07 15:30:47 +0000 |
1623 | @@ -0,0 +1,115 @@ |
1624 | +AbstractButton { |
1625 | + id: root; |
1626 | + property var template; |
1627 | + property var components; |
1628 | + property var cardData; |
1629 | + property real fontScale: 1.0; |
1630 | + property int headerAlignment: Text.AlignLeft; |
1631 | + property int fixedHeaderHeight: -1; |
1632 | + property size fixedArtShapeSize: Qt.size(-1, -1); |
1633 | + readonly property string title: cardData && cardData["title"] || ""; |
1634 | + property bool asynchronous: true; |
1635 | + property bool showHeader: true; |
1636 | + implicitWidth: childrenRect.width; |
1637 | +Loader { |
1638 | + id: backgroundLoader; |
1639 | + objectName: "backgroundLoader"; |
1640 | + anchors.fill: parent; |
1641 | + asynchronous: root.asynchronous; |
1642 | + visible: status == Loader.Ready; |
1643 | + sourceComponent: UbuntuShape { |
1644 | + objectName: "background"; |
1645 | + radius: "medium"; |
1646 | + color: getColor(0) || "white"; |
1647 | + gradientColor: getColor(1) || color; |
1648 | + anchors.fill: parent; |
1649 | + image: backgroundImage.source ? backgroundImage : null; |
1650 | + property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b; |
1651 | + property Image backgroundImage: Image { |
1652 | + objectName: "backgroundImage"; |
1653 | + source: { |
1654 | + if (cardData && typeof cardData["background"] === "string") return cardData["background"]; |
1655 | + else if (template && typeof template["card-background"] === "string") return template["card-background"]; |
1656 | + else return ""; |
1657 | + } |
1658 | + } |
1659 | + function getColor(index) { |
1660 | + if (cardData && typeof cardData["background"] === "object" |
1661 | + && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) { |
1662 | + return cardData["background"]["elements"][index]; |
1663 | + } else if (template && typeof template["card-background"] === "object" |
1664 | + && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) { |
1665 | + return template["card-background"]["elements"][index]; |
1666 | + } else return undefined; |
1667 | + } |
1668 | + } |
1669 | + } |
1670 | +readonly property size artShapeSize: Qt.size(-1, -1); |
1671 | +readonly property int headerHeight: row.height + row.margins * 2; |
1672 | +Row { |
1673 | + id: row; |
1674 | + objectName: "outerRow"; |
1675 | + property real margins: units.gu(1); |
1676 | + spacing: margins; |
1677 | + anchors { top: parent.top; |
1678 | + topMargin: units.gu(1); |
1679 | + left: parent.left; |
1680 | +} |
1681 | + anchors.right: parent.right; |
1682 | + anchors.margins: margins; |
1683 | +data: [ Image { |
1684 | + id: mascotImage; |
1685 | + objectName: "mascotImage"; |
1686 | + anchors { verticalCenter: parent.verticalCenter; } |
1687 | + readonly property int maxSize: Math.max(width, height) * 4; |
1688 | + source: cardData && cardData["mascot"]; |
1689 | + width: units.gu(6); |
1690 | + height: units.gu(5.625); |
1691 | + sourceSize { width: maxSize; height: maxSize } |
1692 | + fillMode: Image.PreserveAspectCrop; |
1693 | + horizontalAlignment: Image.AlignHCenter; |
1694 | + verticalAlignment: Image.AlignVCenter; |
1695 | + visible: showHeader; |
1696 | + } |
1697 | +, |
1698 | +Column { |
1699 | + anchors.verticalCenter: parent.verticalCenter; |
1700 | + spacing: units.dp(2); |
1701 | + width: parent.width - x; |
1702 | + data: [ |
1703 | +Label { |
1704 | + id: titleLabel; |
1705 | + objectName: "titleLabel"; |
1706 | + anchors { left: parent.left; right: parent.right } |
1707 | + elide: Text.ElideRight; |
1708 | + fontSize: "small"; |
1709 | + wrapMode: Text.Wrap; |
1710 | + maximumLineCount: 2; |
1711 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
1712 | + color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"; |
1713 | + visible: showHeader ; |
1714 | + text: root.title; |
1715 | + font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; |
1716 | + horizontalAlignment: root.headerAlignment; |
1717 | + } |
1718 | +, |
1719 | +Label { |
1720 | + id: subtitleLabel; |
1721 | + objectName: "subtitleLabel"; |
1722 | + anchors { left: parent.left; right: parent.right } |
1723 | + |
1724 | + elide: Text.ElideRight; |
1725 | + fontSize: "small"; |
1726 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
1727 | + color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : "grey"; |
1728 | + visible: titleLabel.visible && titleLabel.text; |
1729 | + text: cardData && cardData["subtitle"] || ""; |
1730 | + font.weight: Font.Light; |
1731 | + horizontalAlignment: root.headerAlignment; |
1732 | + } |
1733 | +] |
1734 | +} |
1735 | +] |
1736 | +} |
1737 | +implicitHeight: row.y + row.height + units.gu(1); |
1738 | +} |
1739 | |
1740 | === added file 'tests/plugins/Dash/cardcreator/2.tst' |
1741 | --- tests/plugins/Dash/cardcreator/2.tst 1970-01-01 00:00:00 +0000 |
1742 | +++ tests/plugins/Dash/cardcreator/2.tst 2014-05-07 15:30:47 +0000 |
1743 | @@ -0,0 +1,3 @@ |
1744 | +template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2} |
1745 | +components: {"art":{"aspect-ratio":1,"fill-mode":"crop"},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"}} |
1746 | +result: 2.res |
1747 | |
1748 | === added file 'tests/plugins/Dash/cardcreator/3.res' |
1749 | --- tests/plugins/Dash/cardcreator/3.res 1970-01-01 00:00:00 +0000 |
1750 | +++ tests/plugins/Dash/cardcreator/3.res 2014-05-07 15:30:47 +0000 |
1751 | @@ -0,0 +1,94 @@ |
1752 | +AbstractButton { |
1753 | + id: root; |
1754 | + property var template; |
1755 | + property var components; |
1756 | + property var cardData; |
1757 | + property real fontScale: 1.0; |
1758 | + property int headerAlignment: Text.AlignLeft; |
1759 | + property int fixedHeaderHeight: -1; |
1760 | + property size fixedArtShapeSize: Qt.size(-1, -1); |
1761 | + readonly property string title: cardData && cardData["title"] || ""; |
1762 | + property bool asynchronous: true; |
1763 | + property bool showHeader: true; |
1764 | + implicitWidth: childrenRect.width; |
1765 | +readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1); |
1766 | +Item { |
1767 | + id: artShapeHolder; |
1768 | + height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; |
1769 | + width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; |
1770 | + anchors { horizontalCenter: parent.horizontalCenter; } |
1771 | + Loader { |
1772 | + id: artShapeLoader; |
1773 | + objectName: "artShapeLoader"; |
1774 | + active: cardData && cardData["art"] || false; |
1775 | + asynchronous: root.asynchronous; |
1776 | + visible: status == Loader.Ready; |
1777 | + sourceComponent: UbuntuShape { |
1778 | + id: artShape; |
1779 | + objectName: "artShape"; |
1780 | + radius: "medium"; |
1781 | + readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; |
1782 | + readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; |
1783 | + Component.onCompleted: updateWidthHeightBindings(); |
1784 | + onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); |
1785 | + visible: image.status == Image.Ready; |
1786 | + function updateWidthHeightBindings() { |
1787 | + if (aspectSmallerThanImageAspect) { |
1788 | + width = Qt.binding(function() { return !visible ? 0 : image.width }); |
1789 | + height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); |
1790 | + } else { |
1791 | + width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); |
1792 | + height = Qt.binding(function() { return !visible ? 0 : image.height }); |
1793 | + } |
1794 | + } |
1795 | + image: Image { |
1796 | + objectName: "artImage"; |
1797 | + source: cardData && cardData["art"] || ""; |
1798 | + cache: true; |
1799 | + asynchronous: root.asynchronous; |
1800 | + fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; |
1801 | + readonly property real aspect: implicitWidth / implicitHeight; |
1802 | + width: root.width; |
1803 | + height: width / artShape.aspect; |
1804 | + } |
1805 | + } |
1806 | + } |
1807 | + } |
1808 | +readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin; |
1809 | +Label { |
1810 | + id: titleLabel; |
1811 | + objectName: "titleLabel"; |
1812 | + anchors { right: parent.right;left: parent.left; |
1813 | +top: artShapeHolder.bottom; |
1814 | + topMargin: units.gu(1); |
1815 | +} |
1816 | + elide: Text.ElideRight; |
1817 | + fontSize: "small"; |
1818 | + wrapMode: Text.Wrap; |
1819 | + maximumLineCount: 2; |
1820 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
1821 | + color: "grey"; |
1822 | + visible: showHeader ; |
1823 | + text: root.title; |
1824 | + font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; |
1825 | + horizontalAlignment: root.headerAlignment; |
1826 | + } |
1827 | +Label { |
1828 | + id: subtitleLabel; |
1829 | + objectName: "subtitleLabel"; |
1830 | + anchors { left: titleLabel.left; |
1831 | + leftMargin: titleLabel.leftMargin; |
1832 | + right: titleLabel.right; |
1833 | + top: titleLabel.bottom; |
1834 | + topMargin: units.dp(2); } |
1835 | + elide: Text.ElideRight; |
1836 | + fontSize: "small"; |
1837 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
1838 | + color: "grey"; |
1839 | + visible: titleLabel.visible && titleLabel.text; |
1840 | + text: cardData && cardData["subtitle"] || ""; |
1841 | + font.weight: Font.Light; |
1842 | + horizontalAlignment: root.headerAlignment; |
1843 | + } |
1844 | +implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1); |
1845 | +} |
1846 | |
1847 | === added file 'tests/plugins/Dash/cardcreator/3.tst' |
1848 | --- tests/plugins/Dash/cardcreator/3.tst 1970-01-01 00:00:00 +0000 |
1849 | +++ tests/plugins/Dash/cardcreator/3.tst 2014-05-07 15:30:47 +0000 |
1850 | @@ -0,0 +1,3 @@ |
1851 | +template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2} |
1852 | +components: {"art":{"aspect-ratio":0.75,"field":"art","fill-mode":"crop"},"subtitle":{"field":"price"},"title":{"field":"title"}} |
1853 | +result: 3.res |
1854 | |
1855 | === added file 'tests/plugins/Dash/cardcreator/4.res' |
1856 | --- tests/plugins/Dash/cardcreator/4.res 1970-01-01 00:00:00 +0000 |
1857 | +++ tests/plugins/Dash/cardcreator/4.res 2014-05-07 15:30:47 +0000 |
1858 | @@ -0,0 +1,95 @@ |
1859 | +AbstractButton { |
1860 | + id: root; |
1861 | + property var template; |
1862 | + property var components; |
1863 | + property var cardData; |
1864 | + property real fontScale: 1.0; |
1865 | + property int headerAlignment: Text.AlignLeft; |
1866 | + property int fixedHeaderHeight: -1; |
1867 | + property size fixedArtShapeSize: Qt.size(-1, -1); |
1868 | + readonly property string title: cardData && cardData["title"] || ""; |
1869 | + property bool asynchronous: true; |
1870 | + property bool showHeader: true; |
1871 | + implicitWidth: childrenRect.width; |
1872 | +readonly property size artShapeSize: Qt.size(-1, -1); |
1873 | +readonly property int headerHeight: row.height + row.margins * 2; |
1874 | +Row { |
1875 | + id: row; |
1876 | + objectName: "outerRow"; |
1877 | + property real margins: units.gu(1); |
1878 | + spacing: margins; |
1879 | + anchors { top: parent.top; |
1880 | + topMargin: units.gu(1); |
1881 | + left: parent.left; |
1882 | +} |
1883 | + anchors.right: parent.right; |
1884 | + anchors.margins: margins; |
1885 | +data: [ Loader { |
1886 | + id: mascotShapeLoader; |
1887 | + objectName: "mascotShapeLoader"; |
1888 | + asynchronous: root.asynchronous; |
1889 | + active: mascotImage.status === Image.Ready; |
1890 | + visible: showHeader && active && status == Loader.Ready; |
1891 | + width: units.gu(6); |
1892 | + height: units.gu(5.625); |
1893 | + sourceComponent: UbuntuShape { image: mascotImage } |
1894 | + anchors { verticalCenter: parent.verticalCenter; } |
1895 | + } |
1896 | + |
1897 | +, |
1898 | +Image { |
1899 | + id: mascotImage; |
1900 | + objectName: "mascotImage"; |
1901 | + anchors { verticalCenter: parent.verticalCenter; } |
1902 | + readonly property int maxSize: Math.max(width, height) * 4; |
1903 | + source: cardData && cardData["mascot"]; |
1904 | + width: units.gu(6); |
1905 | + height: units.gu(5.625); |
1906 | + sourceSize { width: maxSize; height: maxSize } |
1907 | + fillMode: Image.PreserveAspectCrop; |
1908 | + horizontalAlignment: Image.AlignHCenter; |
1909 | + verticalAlignment: Image.AlignVCenter; |
1910 | + visible: false; |
1911 | + } |
1912 | + |
1913 | +, |
1914 | +Column { |
1915 | + anchors.verticalCenter: parent.verticalCenter; |
1916 | + spacing: units.dp(2); |
1917 | + width: parent.width - x; |
1918 | +data: [ Label { |
1919 | + id: titleLabel; |
1920 | + objectName: "titleLabel"; |
1921 | + anchors { left: parent.left; right: parent.right } |
1922 | + elide: Text.ElideRight; |
1923 | + fontSize: "small"; |
1924 | + wrapMode: Text.Wrap; |
1925 | + maximumLineCount: 2; |
1926 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
1927 | + color: "grey"; |
1928 | + visible: showHeader ; |
1929 | + text: root.title; |
1930 | + font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; |
1931 | + horizontalAlignment: root.headerAlignment; |
1932 | + } |
1933 | +, |
1934 | +Label { |
1935 | + id: subtitleLabel; |
1936 | + objectName: "subtitleLabel"; |
1937 | + anchors { left: parent.left; right: parent.right } |
1938 | + |
1939 | + elide: Text.ElideRight; |
1940 | + fontSize: "small"; |
1941 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
1942 | + color: "grey"; |
1943 | + visible: titleLabel.visible && titleLabel.text; |
1944 | + text: cardData && cardData["subtitle"] || ""; |
1945 | + font.weight: Font.Light; |
1946 | + horizontalAlignment: root.headerAlignment; |
1947 | + } |
1948 | +] |
1949 | +} |
1950 | +] |
1951 | +} |
1952 | +implicitHeight: row.y + row.height + units.gu(1); |
1953 | +} |
1954 | |
1955 | === added file 'tests/plugins/Dash/cardcreator/4.tst' |
1956 | --- tests/plugins/Dash/cardcreator/4.tst 1970-01-01 00:00:00 +0000 |
1957 | +++ tests/plugins/Dash/cardcreator/4.tst 2014-05-07 15:30:47 +0000 |
1958 | @@ -0,0 +1,3 @@ |
1959 | +template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2} |
1960 | +components: {"art":{"aspect-ratio":1,"fill-mode":"crop"},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"}} |
1961 | +result: 4.res |
1962 | |
1963 | === added file 'tests/plugins/Dash/cardcreator/5.res' |
1964 | --- tests/plugins/Dash/cardcreator/5.res 1970-01-01 00:00:00 +0000 |
1965 | +++ tests/plugins/Dash/cardcreator/5.res 2014-05-07 15:30:47 +0000 |
1966 | @@ -0,0 +1,137 @@ |
1967 | +AbstractButton { |
1968 | + id: root; |
1969 | + property var template; |
1970 | + property var components; |
1971 | + property var cardData; |
1972 | + property real fontScale: 1.0; |
1973 | + property int headerAlignment: Text.AlignLeft; |
1974 | + property int fixedHeaderHeight: -1; |
1975 | + property size fixedArtShapeSize: Qt.size(-1, -1); |
1976 | + readonly property string title: cardData && cardData["title"] || ""; |
1977 | + property bool asynchronous: true; |
1978 | + property bool showHeader: true; |
1979 | + implicitWidth: childrenRect.width; |
1980 | +readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1); |
1981 | +Item { |
1982 | + id: artShapeHolder; |
1983 | + height: root.fixedArtShapeSize.height != -1 ? root.fixedArtShapeSize.height : artShapeLoader.height; |
1984 | + width: root.fixedArtShapeSize.width != -1 ? root.fixedArtShapeSize.width : artShapeLoader.width; |
1985 | + anchors { horizontalCenter: parent.horizontalCenter; } |
1986 | + Loader { |
1987 | + id: artShapeLoader; |
1988 | + objectName: "artShapeLoader"; |
1989 | + active: cardData && cardData["art"] || false; |
1990 | + asynchronous: root.asynchronous; |
1991 | + visible: status == Loader.Ready; |
1992 | + sourceComponent: UbuntuShape { |
1993 | + id: artShape; |
1994 | + objectName: "artShape"; |
1995 | + radius: "medium"; |
1996 | + readonly property real aspect: components !== undefined ? components["art"]["aspect-ratio"] : 1; |
1997 | + readonly property bool aspectSmallerThanImageAspect: aspect < image.aspect; |
1998 | + Component.onCompleted: updateWidthHeightBindings(); |
1999 | + onAspectSmallerThanImageAspectChanged: updateWidthHeightBindings(); |
2000 | + visible: image.status == Image.Ready; |
2001 | + function updateWidthHeightBindings() { |
2002 | + if (aspectSmallerThanImageAspect) { |
2003 | + width = Qt.binding(function() { return !visible ? 0 : image.width }); |
2004 | + height = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.height : width / image.aspect }); |
2005 | + } else { |
2006 | + width = Qt.binding(function() { return !visible ? 0 : image.fillMode === Image.PreserveAspectCrop ? image.width : height * image.aspect }); |
2007 | + height = Qt.binding(function() { return !visible ? 0 : image.height }); |
2008 | + } |
2009 | + } |
2010 | + image: Image { |
2011 | + objectName: "artImage"; |
2012 | + source: cardData && cardData["art"] || ""; |
2013 | + cache: true; |
2014 | + asynchronous: root.asynchronous; |
2015 | + fillMode: components && components["art"]["fill-mode"] === "fit" ? Image.PreserveAspectFit: Image.PreserveAspectCrop; |
2016 | + readonly property real aspect: implicitWidth / implicitHeight; |
2017 | + width: root.width; |
2018 | + height: width / artShape.aspect; |
2019 | + } |
2020 | + } |
2021 | + } |
2022 | + } |
2023 | +Loader { |
2024 | + id: overlayLoader; |
2025 | + anchors { |
2026 | + left: artShapeHolder.left; |
2027 | + right: artShapeHolder.right; |
2028 | + bottom: artShapeHolder.bottom; |
2029 | + } |
2030 | + active: artShapeLoader.active && artShapeLoader.item && artShapeLoader.item.image.status === Image.Ready || false; |
2031 | + asynchronous: root.asynchronous; |
2032 | + visible: showHeader && status == Loader.Ready; |
2033 | + sourceComponent: ShaderEffect { |
2034 | + id: overlay; |
2035 | + height: fixedHeaderHeight != -1 ? fixedHeaderHeight : headerHeight; |
2036 | + opacity: 0.6; |
2037 | + property var source: ShaderEffectSource { |
2038 | + id: shaderSource; |
2039 | + sourceItem: artShapeLoader.item; |
2040 | + onVisibleChanged: if (visible) scheduleUpdate(); |
2041 | + live: false; |
2042 | + sourceRect: Qt.rect(0, artShapeLoader.height - overlay.height, artShapeLoader.width, overlay.height); |
2043 | + } |
2044 | + vertexShader: " |
2045 | + uniform highp mat4 qt_Matrix; |
2046 | + attribute highp vec4 qt_Vertex; |
2047 | + attribute highp vec2 qt_MultiTexCoord0; |
2048 | + varying highp vec2 coord; |
2049 | + void main() { |
2050 | + coord = qt_MultiTexCoord0; |
2051 | + gl_Position = qt_Matrix * qt_Vertex; |
2052 | + }"; |
2053 | + fragmentShader: " |
2054 | + varying highp vec2 coord; |
2055 | + uniform sampler2D source; |
2056 | + uniform lowp float qt_Opacity; |
2057 | + void main() { |
2058 | + lowp vec4 tex = texture2D(source, coord); |
2059 | + gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity; |
2060 | + }"; |
2061 | + } |
2062 | + } |
2063 | +readonly property int headerHeight: titleLabel.height + titleLabel.anchors.topMargin * 2 + subtitleLabel.height + subtitleLabel.anchors.topMargin; |
2064 | +Label { |
2065 | + id: titleLabel; |
2066 | + objectName: "titleLabel"; |
2067 | + anchors { left: parent.left; |
2068 | + leftMargin: units.gu(1); |
2069 | + right: parent.right; |
2070 | + top: overlayLoader.top; |
2071 | + topMargin: units.gu(1); |
2072 | +} |
2073 | + elide: Text.ElideRight; |
2074 | + fontSize: "small"; |
2075 | + wrapMode: Text.Wrap; |
2076 | + maximumLineCount: 2; |
2077 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
2078 | + color: "white"; |
2079 | + visible: showHeader && overlayLoader.active; |
2080 | + text: root.title; |
2081 | + font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal; |
2082 | + horizontalAlignment: root.headerAlignment; |
2083 | + } |
2084 | +Label { |
2085 | + id: subtitleLabel; |
2086 | + objectName: "subtitleLabel"; |
2087 | + anchors { left: titleLabel.left; |
2088 | + leftMargin: titleLabel.leftMargin; |
2089 | + right: titleLabel.right; |
2090 | + top: titleLabel.bottom; |
2091 | + topMargin: units.dp(2); |
2092 | + } |
2093 | + elide: Text.ElideRight; |
2094 | + fontSize: "small"; |
2095 | + font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); |
2096 | + color: "white"; |
2097 | + visible: titleLabel.visible && titleLabel.text; |
2098 | + text: cardData && cardData["subtitle"] || ""; |
2099 | + font.weight: Font.Light; |
2100 | + horizontalAlignment: root.headerAlignment; |
2101 | + } |
2102 | +implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1); |
2103 | +} |
2104 | |
2105 | === added file 'tests/plugins/Dash/cardcreator/5.tst' |
2106 | --- tests/plugins/Dash/cardcreator/5.tst 1970-01-01 00:00:00 +0000 |
2107 | +++ tests/plugins/Dash/cardcreator/5.tst 2014-05-07 15:30:47 +0000 |
2108 | @@ -0,0 +1,3 @@ |
2109 | +template: {"card-layout":"vertical","card-size":"medium","category-layout":"carousel","collapsed-rows":2,"overlay":true} |
2110 | +components: {"art":{"aspect-ratio":1,"field":"art","fill-mode":"crop"},"subtitle":{"field":"artist"},"title":{"field":"title"}} |
2111 | +result: 5.res |
2112 | |
2113 | === added file 'tests/plugins/Dash/cardcreatortest.cpp' |
2114 | --- tests/plugins/Dash/cardcreatortest.cpp 1970-01-01 00:00:00 +0000 |
2115 | +++ tests/plugins/Dash/cardcreatortest.cpp 2014-05-07 15:30:47 +0000 |
2116 | @@ -0,0 +1,91 @@ |
2117 | +/* |
2118 | + * Copyright (C) 2014 Canonical, Ltd. |
2119 | + * |
2120 | + * This program is free software; you can redistribute it and/or modify |
2121 | + * it under the terms of the GNU General Public License as published by |
2122 | + * the Free Software Foundation; version 3. |
2123 | + * |
2124 | + * This program is distributed in the hope that it will be useful, |
2125 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2126 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2127 | + * GNU General Public License for more details. |
2128 | + * |
2129 | + * You should have received a copy of the GNU General Public License |
2130 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2131 | + */ |
2132 | + |
2133 | +#include <QDir> |
2134 | +#include <QQmlEngine> |
2135 | +#include <QQuickItem> |
2136 | +#include <QQuickView> |
2137 | +#include <QtTestGui> |
2138 | + |
2139 | +class CardCreatorTest : public QObject |
2140 | +{ |
2141 | + Q_OBJECT |
2142 | + |
2143 | +private Q_SLOTS: |
2144 | + |
2145 | + void initTestCase() |
2146 | + { |
2147 | + } |
2148 | + |
2149 | + void init() |
2150 | + { |
2151 | + view = new QQuickView(); |
2152 | + view->engine()->addImportPath(BUILT_PLUGINS_DIR); |
2153 | + view->setSource(QUrl::fromLocalFile(DASHVIEWSTEST_FOLDER "/cardcreatortest.qml")); |
2154 | + view->show(); |
2155 | + QTest::qWaitForWindowExposed(view); |
2156 | + } |
2157 | + |
2158 | + void cleanup() |
2159 | + { |
2160 | + delete view; |
2161 | + } |
2162 | + |
2163 | + void testKnownCases() |
2164 | + { |
2165 | + const QString templateString("template: "); |
2166 | + const QString componentsString("components: "); |
2167 | + const QString resultString("result: "); |
2168 | + |
2169 | + const QString testDirPath = DASHVIEWSTEST_FOLDER "/cardcreator/"; |
2170 | + QDir d(testDirPath); |
2171 | + const QStringList testFiles = d.entryList(QStringList() << "*.tst"); |
2172 | + foreach(const QString &testFileName, testFiles) { |
2173 | + qDebug() << testFileName; |
2174 | + QFile testFile(testDirPath + testFileName); |
2175 | + QVERIFY(testFile.open(QIODevice::ReadOnly)); |
2176 | + QTextStream ts(&testFile); |
2177 | + const QStringList lines = ts.readAll().split("\n"); |
2178 | + |
2179 | + QVERIFY(lines[0].startsWith(templateString)); |
2180 | + QVERIFY(lines[1].startsWith(componentsString)); |
2181 | + QVERIFY(lines[2].startsWith(resultString)); |
2182 | + const QString templateJSON = lines[0].mid(templateString.length()); |
2183 | + const QString componentsJSON = lines[1].mid(componentsString.length()); |
2184 | + const QString resultFileName = lines[2].mid(resultString.length()); |
2185 | + |
2186 | + QVariant cardStringResult; |
2187 | + QMetaObject::invokeMethod(view->rootObject(), "cardString", Q_RETURN_ARG(QVariant, cardStringResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON)); |
2188 | + |
2189 | + QFile testResultFile(testDirPath + resultFileName); |
2190 | + QVERIFY(testResultFile.open(QIODevice::ReadOnly)); |
2191 | + QTextStream ts2(&testResultFile); |
2192 | + const QString expectedResult = ts2.readAll(); |
2193 | + QCOMPARE(cardStringResult.toString().simplified(), expectedResult.simplified()); |
2194 | + |
2195 | + QVariant createCardComponentResult; |
2196 | + QMetaObject::invokeMethod(view->rootObject(), "createCardComponent", Q_RETURN_ARG(QVariant, createCardComponentResult), Q_ARG(QVariant, templateJSON), Q_ARG(QVariant, componentsJSON)); |
2197 | + QVERIFY(createCardComponentResult.toBool()); |
2198 | + } |
2199 | + } |
2200 | + |
2201 | +private: |
2202 | + QQuickView *view; |
2203 | +}; |
2204 | + |
2205 | +QTEST_MAIN(CardCreatorTest) |
2206 | + |
2207 | +#include "cardcreatortest.moc" |
2208 | |
2209 | === added file 'tests/plugins/Dash/cardcreatortest.qml' |
2210 | --- tests/plugins/Dash/cardcreatortest.qml 1970-01-01 00:00:00 +0000 |
2211 | +++ tests/plugins/Dash/cardcreatortest.qml 2014-05-07 15:30:47 +0000 |
2212 | @@ -0,0 +1,29 @@ |
2213 | +/* |
2214 | + * Copyright (C) 2014 Canonical, Ltd. |
2215 | + * |
2216 | + * This program is free software; you can redistribute it and/or modify |
2217 | + * it under the terms of the GNU General Public License as published by |
2218 | + * the Free Software Foundation; version 3. |
2219 | + * |
2220 | + * This program is distributed in the hope that it will be useful, |
2221 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2222 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2223 | + * GNU General Public License for more details. |
2224 | + * |
2225 | + * You should have received a copy of the GNU General Public License |
2226 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2227 | + */ |
2228 | + |
2229 | +import QtQuick 2.2 |
2230 | +import "../../../plugins/Dash/CardCreator.js" as CardCreator |
2231 | + |
2232 | +Item { |
2233 | + id: root |
2234 | + function cardString(template, components) { |
2235 | + return CardCreator.cardString(JSON.parse(template), JSON.parse(components)); |
2236 | + } |
2237 | + |
2238 | + function createCardComponent(template, components) { |
2239 | + return CardCreator.createCardComponent(root, JSON.parse(template), JSON.parse(components)) !== null; |
2240 | + } |
2241 | +} |
2242 | |
2243 | === modified file 'tests/plugins/Dash/horizontaljournaltest.qml' |
2244 | --- tests/plugins/DashViews/horizontaljournaltest.qml 2013-12-19 16:02:38 +0000 |
2245 | +++ tests/plugins/Dash/horizontaljournaltest.qml 2014-05-07 15:30:47 +0000 |
2246 | @@ -15,7 +15,7 @@ |
2247 | */ |
2248 | |
2249 | import QtQuick 2.1 |
2250 | -import DashViews 0.1 |
2251 | +import Dash 0.1 |
2252 | |
2253 | Item { |
2254 | |
2255 | |
2256 | === modified file 'tests/plugins/Dash/horizontaljournaltry.qml' |
2257 | --- tests/plugins/DashViews/horizontaljournaltry.qml 2013-12-19 16:02:38 +0000 |
2258 | +++ tests/plugins/Dash/horizontaljournaltry.qml 2014-05-07 15:30:47 +0000 |
2259 | @@ -15,7 +15,7 @@ |
2260 | */ |
2261 | |
2262 | import QtQuick 2.1 |
2263 | -import DashViews 0.1 |
2264 | +import Dash 0.1 |
2265 | |
2266 | Item { |
2267 | id: root |
2268 | |
2269 | === modified file 'tests/plugins/Dash/listviewwithpageheadertest.qml' |
2270 | --- tests/plugins/DashViews/listviewwithpageheadertest.qml 2013-12-13 09:44:17 +0000 |
2271 | +++ tests/plugins/Dash/listviewwithpageheadertest.qml 2014-05-07 15:30:47 +0000 |
2272 | @@ -15,7 +15,7 @@ |
2273 | */ |
2274 | |
2275 | import QtQuick 2.0 |
2276 | -import DashViews 0.1 |
2277 | +import Dash 0.1 |
2278 | |
2279 | Rectangle { |
2280 | width: 300 |
2281 | |
2282 | === modified file 'tests/plugins/Dash/listviewwithpageheadertestsection.qml' |
2283 | --- tests/plugins/DashViews/listviewwithpageheadertestsection.qml 2013-12-13 09:44:17 +0000 |
2284 | +++ tests/plugins/Dash/listviewwithpageheadertestsection.qml 2014-05-07 15:30:47 +0000 |
2285 | @@ -15,7 +15,7 @@ |
2286 | */ |
2287 | |
2288 | import QtQuick 2.0 |
2289 | -import DashViews 0.1 |
2290 | +import Dash 0.1 |
2291 | |
2292 | Rectangle { |
2293 | width: 300 |
2294 | |
2295 | === modified file 'tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml' |
2296 | --- tests/plugins/DashViews/listviewwithpageheadertestsectionexternalmodel.qml 2013-12-13 09:44:17 +0000 |
2297 | +++ tests/plugins/Dash/listviewwithpageheadertestsectionexternalmodel.qml 2014-05-07 15:30:47 +0000 |
2298 | @@ -15,7 +15,7 @@ |
2299 | */ |
2300 | |
2301 | import QtQuick 2.0 |
2302 | -import DashViews 0.1 |
2303 | +import Dash 0.1 |
2304 | |
2305 | Rectangle { |
2306 | width: 300 |
2307 | |
2308 | === modified file 'tests/plugins/Dash/organicgridtest.qml' |
2309 | --- tests/plugins/DashViews/organicgridtest.qml 2014-01-14 12:25:52 +0000 |
2310 | +++ tests/plugins/Dash/organicgridtest.qml 2014-05-07 15:30:47 +0000 |
2311 | @@ -15,7 +15,7 @@ |
2312 | */ |
2313 | |
2314 | import QtQuick 2.1 |
2315 | -import DashViews 0.1 |
2316 | +import Dash 0.1 |
2317 | |
2318 | Item { |
2319 | |
2320 | |
2321 | === modified file 'tests/plugins/Dash/organicgridtry.qml' |
2322 | --- tests/plugins/DashViews/organicgridtry.qml 2014-01-14 12:25:52 +0000 |
2323 | +++ tests/plugins/Dash/organicgridtry.qml 2014-05-07 15:30:47 +0000 |
2324 | @@ -15,7 +15,7 @@ |
2325 | */ |
2326 | |
2327 | import QtQuick 2.1 |
2328 | -import DashViews 0.1 |
2329 | +import Dash 0.1 |
2330 | |
2331 | Item { |
2332 | id: root |
2333 | |
2334 | === modified file 'tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml' |
2335 | --- tests/plugins/DashViews/tst_ListViewWithPageHeaderQML.qml 2014-04-10 13:49:37 +0000 |
2336 | +++ tests/plugins/Dash/tst_ListViewWithPageHeaderQML.qml 2014-05-07 15:30:47 +0000 |
2337 | @@ -16,7 +16,7 @@ |
2338 | |
2339 | import QtQuick 2.0 |
2340 | import QtTest 1.0 |
2341 | -import DashViews 0.1 |
2342 | +import Dash 0.1 |
2343 | |
2344 | Rectangle { |
2345 | width: 300 |
2346 | |
2347 | === modified file 'tests/plugins/Dash/verticaljournaltest.qml' |
2348 | --- tests/plugins/DashViews/verticaljournaltest.qml 2013-12-17 15:02:45 +0000 |
2349 | +++ tests/plugins/Dash/verticaljournaltest.qml 2014-05-07 15:30:47 +0000 |
2350 | @@ -15,7 +15,7 @@ |
2351 | */ |
2352 | |
2353 | import QtQuick 2.1 |
2354 | -import DashViews 0.1 |
2355 | +import Dash 0.1 |
2356 | |
2357 | Item { |
2358 | |
2359 | |
2360 | === modified file 'tests/plugins/Dash/verticaljournaltry.qml' |
2361 | --- tests/plugins/DashViews/verticaljournaltry.qml 2013-12-17 16:35:44 +0000 |
2362 | +++ tests/plugins/Dash/verticaljournaltry.qml 2014-05-07 15:30:47 +0000 |
2363 | @@ -15,7 +15,7 @@ |
2364 | */ |
2365 | |
2366 | import QtQuick 2.1 |
2367 | -import DashViews 0.1 |
2368 | +import Dash 0.1 |
2369 | |
2370 | Item { |
2371 | id: root |
2372 | |
2373 | === modified file 'tests/qmltests/CMakeLists.txt' |
2374 | --- tests/qmltests/CMakeLists.txt 2014-05-05 12:08:16 +0000 |
2375 | +++ tests/qmltests/CMakeLists.txt 2014-05-07 15:30:47 +0000 |
2376 | @@ -35,10 +35,10 @@ |
2377 | add_qml_test(Components ZoomableImage) |
2378 | add_qml_test(Dash Dash IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
2379 | add_qml_test(Dash DashContent IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
2380 | -add_qml_test(Dash Card) |
2381 | -add_qml_benchmark(Dash CardBenchmark 1000) |
2382 | +add_qml_test(Dash Card IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
2383 | +add_qml_benchmark(Dash CardBenchmark 1000 IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
2384 | add_qml_test(Dash CardHeader) |
2385 | -add_qml_test(Dash CardTool) |
2386 | +add_qml_test(Dash CardTool IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
2387 | add_qml_test(Dash GenericScopeView IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}) |
2388 | add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} |
2389 | ${CMAKE_BINARY_DIR}/tests/mocks |
2390 | |
2391 | === modified file 'tests/qmltests/Dash/Previews/tst_PreviewHeader.qml' |
2392 | --- tests/qmltests/Dash/Previews/tst_PreviewHeader.qml 2014-02-07 14:08:40 +0000 |
2393 | +++ tests/qmltests/Dash/Previews/tst_PreviewHeader.qml 2014-05-07 15:30:47 +0000 |
2394 | @@ -24,6 +24,12 @@ |
2395 | width: units.gu(60) |
2396 | height: units.gu(80) |
2397 | |
2398 | + property var origHeaderjson: { |
2399 | + "title": "THE TITLE", |
2400 | + "subtitle": "Something catchy", |
2401 | + "mascot": "../graphics/play_button.png" |
2402 | + } |
2403 | + |
2404 | property var headerjson: { |
2405 | "title": "THE TITLE", |
2406 | "subtitle": "Something catchy", |
2407 | @@ -43,14 +49,70 @@ |
2408 | } |
2409 | |
2410 | UT.UnityTestCase { |
2411 | + id: testCase |
2412 | name: "PreviewHeaderTest" |
2413 | when: windowShown |
2414 | |
2415 | + property Item mascot: findChild(previewHeader, "mascotShape") |
2416 | + property Item outerRow: findChild(previewHeader, "outerRow") |
2417 | + property Item column: findChild(previewHeader, "column") |
2418 | + |
2419 | + function initTestCase() { |
2420 | + verify(typeof testCase.mascot === "object", "Couldn't find mascot object."); |
2421 | + verify(typeof testCase.outerRow === "object", "Couldn't find outerRow object."); |
2422 | + verify(typeof testCase.column === "object", "Couldn't find column object."); |
2423 | + |
2424 | + headerjson.mascot = ""; |
2425 | + headerjson.title = ""; |
2426 | + headerjson.subtitle = ""; |
2427 | + previewHeader.widgetData = headerjson; |
2428 | + } |
2429 | + |
2430 | + function test_mascot_data() { |
2431 | + return [ |
2432 | + { tag: "Empty", source: "", visible: false }, |
2433 | + { tag: "Invalid", source: "bad_path", visible: false }, |
2434 | + { tag: "Valid", source: "../graphics/play_button.png", visible: true }, |
2435 | + ] |
2436 | + } |
2437 | + |
2438 | + function test_mascot(data) { |
2439 | + headerjson.mascot = data.source; |
2440 | + previewHeader.widgetData = headerjson; |
2441 | + |
2442 | + tryCompare(testCase.mascot, "visible", data.visible); |
2443 | + } |
2444 | + |
2445 | + function test_dimensions_data() { |
2446 | + return [ |
2447 | + { tag: "Column width with mascot", object: column, width: previewHeader.width - mascot.width - outerRow.margins * 3, mascot: "artwork/avatar.png" }, |
2448 | + { tag: "Header height", object: previewHeader, height: function() { return outerRow.height + outerRow.margins * 2 } }, |
2449 | + ] |
2450 | + } |
2451 | + |
2452 | + function test_dimensions(data) { |
2453 | + if (data.hasOwnProperty("mascot")) { |
2454 | + headerjson.mascot = data.mascot; |
2455 | + } |
2456 | + previewHeader.widgetData = headerjson; |
2457 | + |
2458 | + if (data.hasOwnProperty("width")) { |
2459 | + tryCompare(data.object, "width", data.width); |
2460 | + } |
2461 | + |
2462 | + if (data.hasOwnProperty("height")) { |
2463 | + tryCompareFunction(function() { return data.object.height === data.height() }, true); |
2464 | + } |
2465 | + } |
2466 | + |
2467 | function test_json() { |
2468 | - var cardHeader = findChild(previewHeader, "cardHeader"); |
2469 | - compare(cardHeader.title, "THE TITLE"); |
2470 | - compare(cardHeader.subtitle, "Something catchy"); |
2471 | - compare(cardHeader.mascot.toString().slice(-24), "graphics/play_button.png"); |
2472 | + headerjson = origHeaderjson; |
2473 | + previewHeader.widgetData = headerjson; |
2474 | + |
2475 | + var innerPreviewHeader = findChild(previewHeader, "innerPreviewHeader"); |
2476 | + compare(innerPreviewHeader.title, "THE TITLE"); |
2477 | + compare(innerPreviewHeader.subtitle, "Something catchy"); |
2478 | + compare(innerPreviewHeader.mascot.toString().slice(-24), "graphics/play_button.png"); |
2479 | } |
2480 | } |
2481 | } |
2482 | |
2483 | === modified file 'tests/qmltests/Dash/tst_Card.qml' |
2484 | --- tests/qmltests/Dash/tst_Card.qml 2014-04-02 14:29:21 +0000 |
2485 | +++ tests/qmltests/Dash/tst_Card.qml 2014-05-07 15:30:47 +0000 |
2486 | @@ -29,8 +29,8 @@ |
2487 | |
2488 | property string cardData: ' |
2489 | { |
2490 | - "art": "../../tests/qmltests/Dash/artwork/music-player-design.png", |
2491 | - "mascot": "../../tests/qmltests/Dash/artwork/avatar.png", |
2492 | + "art": "../../../tests/qmltests/Dash/artwork/music-player-design.png", |
2493 | + "mascot": "../../../tests/qmltests/Dash/artwork/avatar.png", |
2494 | "title": "foo", |
2495 | "subtitle": "bar", |
2496 | "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." |
2497 | @@ -98,21 +98,26 @@ |
2498 | |
2499 | CardTool { |
2500 | id: cardTool |
2501 | - template: card.template |
2502 | - components: card.components |
2503 | + template: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template']; |
2504 | + components: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components']; |
2505 | viewWidth: units.gu(48) |
2506 | } |
2507 | |
2508 | - Card { |
2509 | - id: card |
2510 | + readonly property var card: loader.item |
2511 | + |
2512 | + Loader { |
2513 | + id: loader |
2514 | anchors { top: parent.top; left: parent.left; margins: units.gu(1) } |
2515 | |
2516 | - width: cardTool.cardWidth || implicitWidth |
2517 | - height: cardTool.cardHeight || implicitHeight |
2518 | - |
2519 | - template: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['template']; |
2520 | - components: Helpers.update(JSON.parse(Helpers.defaultLayout), Helpers.tryParse(layoutArea.text, layoutError))['components']; |
2521 | - cardData: Helpers.mapData(dataArea.text, components, dataError) |
2522 | + sourceComponent: cardTool.cardComponent |
2523 | + onLoaded: { |
2524 | + item.template = Qt.binding(function() { return cardTool.template; }); |
2525 | + item.components = Qt.binding(function() { return cardTool.components; }); |
2526 | + item.cardData = Qt.binding(function() { return Helpers.mapData(dataArea.text, cardTool.components, dataError); }); |
2527 | + item.width = Qt.binding(function() { return cardTool.cardWidth || item.implicitWidth; }); |
2528 | + item.height = Qt.binding(function() { return cardTool.cardHeight || item.implicitHeight; }); |
2529 | + item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; }); |
2530 | + } |
2531 | } |
2532 | |
2533 | Rectangle { |
2534 | @@ -181,60 +186,45 @@ |
2535 | |
2536 | when: windowShown |
2537 | |
2538 | - property Item header: findChild(card, "cardHeader") |
2539 | - property Item headerLoader: findChild(card, "cardHeaderLoader") |
2540 | - property Item title: findChild(header, "titleLabel") |
2541 | - property Item art: findChild(card, "artShape") |
2542 | + property Item title: findChild(card, "titleLabel") |
2543 | + property Item subtitle: findChild(card, "subtitleLabel") |
2544 | + property var headerRow: findChild(card, "outerRow") |
2545 | + property var art: findChild(card, "artShape") |
2546 | property Item artImage: findChild(card, "artImage") |
2547 | property Item summary: findChild(card, "summaryLabel") |
2548 | property Item background: findChild(card, "background") |
2549 | property Item backgroundLoader: findChild(card, "backgroundLoader") |
2550 | property Item backgroundImage: findChild(card, "backgroundImage") |
2551 | - |
2552 | - function initTestCase() { |
2553 | - verify(typeof testCase.header === "object", "Couldn't find header object."); |
2554 | - verify(typeof testCase.art === "object", "Couldn't find art object."); |
2555 | - verify(typeof testCase.artImage === "object", "Couldn't find artImage object."); |
2556 | - verify(typeof testCase.summary === "object", "Couldn't find summary object."); |
2557 | - verify(typeof testCase.artImage === "object", "Couldn't find background object."); |
2558 | - verify(typeof testCase.summary === "object", "Couldn't find backgroundImage object."); |
2559 | - } |
2560 | + property Item mascotImage: findChild(card, "mascotImage"); |
2561 | |
2562 | function cleanup() { |
2563 | selector.selectedIndex = -1; |
2564 | } |
2565 | |
2566 | - |
2567 | - function test_header_binding_data() { |
2568 | - return [ |
2569 | - { tag: "Mascot", property: "mascot", value: Qt.resolvedUrl("artwork/avatar.png"), index: 0 }, |
2570 | - { tag: "Title", property: "title", value: "foo", index: 0 }, |
2571 | - { tag: "Subtitle", property: "subtitle", value: "bar", index: 0 }, |
2572 | - ]; |
2573 | - } |
2574 | - |
2575 | - function test_header_binding(data) { |
2576 | - selector.selectedIndex = data.index; |
2577 | - tryCompare(testCase.header, data.property, data.value); |
2578 | - } |
2579 | - |
2580 | function test_card_binding_data() { |
2581 | return [ |
2582 | - { tag: "Art", object: artImage, property: "source", value: Qt.resolvedUrl("artwork/music-player-design.png"), index: 0 }, |
2583 | - { tag: "Summary", object: summary, property: "text", field: "summary", index: 0 }, |
2584 | - { tag: "Fit", object: art, fill: Image.PreserveAspectFit, index: 4 }, |
2585 | + { tag: "Art", object: "artImage", property: "source", value: Qt.resolvedUrl("artwork/music-player-design.png"), index: 0 }, |
2586 | + { tag: "Summary", object: "summary", property: "text", field: "summary", index: 0 }, |
2587 | + { tag: "Fit", object: "art", fill: Image.PreserveAspectFit, index: 4 }, |
2588 | + { tag: "Mascot", object: "mascotImage", property: "source", value: Qt.resolvedUrl("artwork/avatar.png"), index: 0 }, |
2589 | + { tag: "Title", object: "title", property: "text", value: "foo", index: 0 }, |
2590 | + { tag: "Subtitle", object: "subtitle", property: "text", value: "bar", index: 0 }, |
2591 | ]; |
2592 | } |
2593 | |
2594 | function test_card_binding(data) { |
2595 | selector.selectedIndex = data.index; |
2596 | + waitForRendering(card); |
2597 | + |
2598 | + tryCompareFunction(function() { return testCase[data.object] !== null }, true); |
2599 | + var object = testCase[data.object]; |
2600 | |
2601 | if (data.hasOwnProperty('value')) { |
2602 | - tryCompare(data.object, data.property, data.value); |
2603 | + tryCompare(object, data.property, data.value); |
2604 | } |
2605 | |
2606 | if (data.hasOwnProperty('field')) { |
2607 | - tryCompare(data.object, data.property, card.cardData[data.field]); |
2608 | + tryCompare(object, data.property, card.cardData[data.field]); |
2609 | } |
2610 | } |
2611 | |
2612 | @@ -243,31 +233,21 @@ |
2613 | { tag: "Medium", width: units.gu(18.5), index: 0 }, |
2614 | { tag: "Small", width: units.gu(12), index: 1 }, |
2615 | { tag: "Large", width: units.gu(38), index: 2 }, |
2616 | - { tag: "Wide", width: units.gu(18.5), aspect: 0.5, index: 0 }, |
2617 | + { tag: "Wide", width: units.gu(18.5), index: 0 }, |
2618 | { tag: "Horizontal", width: units.gu(38), index: 5 }, |
2619 | // Make sure card ends with header when there's no summary |
2620 | - { tag: "NoSummary", height: function() { return headerLoader.y + headerLoader.height }, index: 6 }, |
2621 | - { tag: "HorizontalNoSummary", height: function() { return headerLoader.height }, card_layout: "horizontal", index: 6 }, |
2622 | + { tag: "NoSummary", height: function() { var cardToolRow = findChild(cardTool, "outerRow"); |
2623 | + return cardToolRow.y + cardToolRow.height + units.gu(1) }, index: 6 }, |
2624 | + { tag: "HorizontalNoSummary", height: function() { return headerRow.height + units.gu(2) }, card_layout: "horizontal", index: 6 }, |
2625 | ] |
2626 | } |
2627 | |
2628 | function test_card_size(data) { |
2629 | - waitForRendering(card); |
2630 | selector.selectedIndex = data.index; |
2631 | |
2632 | - if (data.hasOwnProperty("size")) { |
2633 | - card.template['card-size'] = data.size; |
2634 | - card.templateChanged(); |
2635 | - } |
2636 | - |
2637 | if (data.hasOwnProperty("card_layout")) { |
2638 | - card.template['card-layout'] = data.card_layout; |
2639 | - card.templateChanged(); |
2640 | - } |
2641 | - |
2642 | - if (data.hasOwnProperty("aspect")) { |
2643 | - card.components['art']['aspect-ratio'] = data.aspect; |
2644 | - card.componentsChanged(); |
2645 | + cardTool.template['card-layout'] = data.card_layout; |
2646 | + cardTool.templateChanged(); |
2647 | } |
2648 | |
2649 | if (data.hasOwnProperty("width")) { |
2650 | @@ -288,25 +268,26 @@ |
2651 | { tag: "Large", width: units.gu(38), index: 2 }, |
2652 | { tag: "Wide", height: units.gu(19), size: "large", index: 3 }, |
2653 | { tag: "Fit", height: units.gu(38), size: "large", width: units.gu(19), index: 4 }, |
2654 | - { tag: "VerticalWidth", width: function() { return header.width }, index: 0 }, |
2655 | - { tag: "HorizontalHeight", height: function() { return header.height }, index: 5 }, |
2656 | - { tag: "HorizontalWidth", width: function() { return headerLoader.x }, index: 5 }, |
2657 | + { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) * 2 }, index: 0 }, |
2658 | + { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 }, |
2659 | + { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 }, |
2660 | ] |
2661 | } |
2662 | |
2663 | function test_art_size(data) { |
2664 | selector.selectedIndex = data.index; |
2665 | - |
2666 | if (data.hasOwnProperty("size")) { |
2667 | - card.template['card-size'] = data.size; |
2668 | - card.templateChanged(); |
2669 | + cardTool.template['card-size'] = data.size; |
2670 | + cardTool.templateChanged(); |
2671 | } |
2672 | |
2673 | if (data.hasOwnProperty("aspect")) { |
2674 | - card.components['art']['aspect-ratio'] = data.aspect; |
2675 | - card.componentsChanged(); |
2676 | + cardTool.components['art']['aspect-ratio'] = data.aspect; |
2677 | + cardTool.componentsChanged(); |
2678 | } |
2679 | |
2680 | + waitForRendering(card); |
2681 | + |
2682 | if (data.hasOwnProperty("width")) { |
2683 | if (typeof data.width === "function") { |
2684 | tryCompareFunction(function() { return art.width === data.width() }, true); |
2685 | @@ -326,38 +307,40 @@ |
2686 | |
2687 | function test_art_layout_data() { |
2688 | return [ |
2689 | - { tag: "Vertical", left: function() { return 0 }, index: 0}, |
2690 | - { tag: "Horizontal", left: function() { return art.width }, index: 5 }, |
2691 | + { tag: "Vertical", left: function() { return units.gu(1); }, index: 0}, |
2692 | + { tag: "Horizontal", left: function() { return art.width + units.gu(1); }, index: 5 }, |
2693 | ]; |
2694 | } |
2695 | |
2696 | function test_art_layout(data) { |
2697 | selector.selectedIndex = data.index; |
2698 | + waitForRendering(card); |
2699 | |
2700 | - tryCompare(testCase.headerLoader, "x", data.left()); |
2701 | + tryCompare(headerRow, "x", data.left()); |
2702 | } |
2703 | |
2704 | function test_header_layout_data() { |
2705 | return [ |
2706 | - { tag: "Vertical", top: function() { return art.y + art.height }, |
2707 | - left: function() { return art.x }, index: 0 }, |
2708 | - { tag: "Horizontal", top: function() { return art.y }, |
2709 | - left: function() { return art.x + art.width }, index: 5 }, |
2710 | - { tag: "Overlay", top: function() { return art.y + art.height - header.height }, |
2711 | - left: function() { return art.x }, index: 9 }, |
2712 | + { tag: "Vertical", top: function() { return art.y + art.height + units.gu(1) }, |
2713 | + left: function() { return art.x + units.gu(1) }, index: 0 }, |
2714 | + { tag: "Horizontal", top: function() { return art.y + units.gu(1) }, |
2715 | + left: function() { return art.x + art.width + units.gu(1) }, index: 5 }, |
2716 | + { tag: "Overlay", top: function() { return art.y + art.height - headerRow.height - units.gu(1) }, |
2717 | + left: function() { return art.x + units.gu(1) }, index: 9 }, |
2718 | ] |
2719 | } |
2720 | |
2721 | function test_header_layout(data) { |
2722 | selector.selectedIndex = data.index; |
2723 | + waitForRendering(card); |
2724 | |
2725 | - tryCompareFunction(function() { return testCase.headerLoader.y === data.top() }, true); |
2726 | - tryCompareFunction(function() { return testCase.headerLoader.x === data.left() }, true); |
2727 | + tryCompareFunction(function() { return testCase.headerRow.y === data.top() }, true); |
2728 | + tryCompareFunction(function() { return testCase.headerRow.x === data.left() }, true); |
2729 | } |
2730 | |
2731 | function test_summary_layout_data() { |
2732 | return [ |
2733 | - { tag: "With header", top: function() { return headerLoader.y + headerLoader.height }, index: 0 }, |
2734 | + { tag: "With header", top: function() { return headerRow.y + headerRow.height + units.gu(1); }, index: 0 }, |
2735 | { tag: "Without header", top: function() { return art.y + art.height }, index: 7 }, |
2736 | ] |
2737 | } |
2738 | @@ -365,16 +348,16 @@ |
2739 | function test_summary_layout(data) { |
2740 | selector.selectedIndex = data.index; |
2741 | |
2742 | + waitForRendering(card); |
2743 | + |
2744 | tryCompareFunction(function() { return testCase.summary.y === data.top() }, true); |
2745 | } |
2746 | |
2747 | function test_art_visibility() { |
2748 | selector.selectedIndex = 8; |
2749 | |
2750 | - tryCompare(testCase.artImage, "source", ""); |
2751 | - compare(testCase.art.visible, false); |
2752 | - compare(testCase.art.height, 0); |
2753 | - compare(testCase.art.width, 0); |
2754 | + compare(testCase.artImage, null); |
2755 | + compare(testCase.art, null); |
2756 | } |
2757 | |
2758 | function test_background_data() { |
2759 | @@ -402,7 +385,11 @@ |
2760 | |
2761 | waitForRendering(card); |
2762 | |
2763 | - tryCompare(backgroundLoader, "active", data.visible); |
2764 | + if (data.visible) { |
2765 | + tryCompare(backgroundLoader, "active", true); |
2766 | + } else { |
2767 | + compare(backgroundLoader, null); |
2768 | + } |
2769 | |
2770 | if (data.hasOwnProperty("color")) { |
2771 | tryCompare(background, "color", data.color); |
2772 | @@ -449,13 +436,15 @@ |
2773 | |
2774 | function test_fontColor(data) { |
2775 | selector.selectedIndex = 10; |
2776 | + waitForRendering(card); |
2777 | |
2778 | background.color = data.tag; |
2779 | |
2780 | var fontColor = data.dark ? "grey" : "white"; |
2781 | |
2782 | tryCompareFunction(function() { return Qt.colorEqual(summary.color, fontColor); }, true); |
2783 | - tryCompareFunction(function() { return Qt.colorEqual(header.fontColor, fontColor); }, true); |
2784 | + tryCompareFunction(function() { return Qt.colorEqual(title.color, fontColor); }, true); |
2785 | + tryCompareFunction(function() { return Qt.colorEqual(subtitle.color, fontColor); }, true); |
2786 | } |
2787 | |
2788 | function test_mascotShape_data() { |
2789 | @@ -468,15 +457,12 @@ |
2790 | |
2791 | function test_mascotShape(data) { |
2792 | selector.selectedIndex = data.index; |
2793 | + waitForRendering(card); |
2794 | |
2795 | var shape = findChild(card, "mascotShapeLoader"); |
2796 | - var image = findChild(card, "mascotImage"); |
2797 | - |
2798 | - verify(shape, "Could not find shape."); |
2799 | - verify(image, "Could not find image."); |
2800 | - |
2801 | - tryCompare(shape, "active", data.shape); |
2802 | - tryCompare(image, "visible", !data.shape); |
2803 | + |
2804 | + compare(shape !== null, data.shape); |
2805 | + tryCompare(mascotImage, "visible", !data.shape); |
2806 | } |
2807 | } |
2808 | } |
2809 | |
2810 | === modified file 'tests/qmltests/Dash/tst_CardBenchmark.qml' |
2811 | --- tests/qmltests/Dash/tst_CardBenchmark.qml 2014-04-16 11:20:38 +0000 |
2812 | +++ tests/qmltests/Dash/tst_CardBenchmark.qml 2014-05-07 15:30:47 +0000 |
2813 | @@ -54,13 +54,16 @@ |
2814 | Repeater { |
2815 | id: cardRepeater |
2816 | model: 0 |
2817 | - Card { |
2818 | - width: cardTool.cardWidth || implicitWidth |
2819 | - height: cardTool.cardHeight || implicitHeight |
2820 | - |
2821 | - template: cardTool.template |
2822 | - components: cardTool.components |
2823 | - cardData: Helpers.mapData(root.cardData, components) |
2824 | + Loader { |
2825 | + sourceComponent: cardTool.cardComponent |
2826 | + onLoaded: { |
2827 | + item.objectName = "delegate" + index; |
2828 | + item.width = Qt.binding(function() { return cardTool.cardWidth || implicitWidth; }); |
2829 | + item.height = Qt.binding(function() { return cardTool.cardHeight || implicitHeight; }); |
2830 | + item.cardData = Qt.binding(function() { return Helpers.mapData(root.cardData, cardTool.components); }); |
2831 | + item.template = Qt.binding(function() { return cardTool.template; }); |
2832 | + item.components = Qt.binding(function() { return cardTool.components; }); |
2833 | + } |
2834 | } |
2835 | } |
2836 | |
2837 | |
2838 | === removed file 'tests/qmltests/Dash/tst_CardHeader.qml' |
2839 | --- tests/qmltests/Dash/tst_CardHeader.qml 2014-04-02 14:29:21 +0000 |
2840 | +++ tests/qmltests/Dash/tst_CardHeader.qml 1970-01-01 00:00:00 +0000 |
2841 | @@ -1,116 +0,0 @@ |
2842 | -/* |
2843 | - * Copyright (C) 2013 Canonical, Ltd. |
2844 | - * |
2845 | - * This program is free software; you can redistribute it and/or modify |
2846 | - * it under the terms of the GNU General Public License as published by |
2847 | - * the Free Software Foundation; version 3. |
2848 | - * |
2849 | - * This program is distributed in the hope that it will be useful, |
2850 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2851 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2852 | - * GNU General Public License for more details. |
2853 | - * |
2854 | - * You should have received a copy of the GNU General Public License |
2855 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2856 | - */ |
2857 | - |
2858 | -import QtQuick 2.0 |
2859 | -import QtTest 1.0 |
2860 | -import Ubuntu.Components 0.1 |
2861 | -import Unity.Test 0.1 as UT |
2862 | -import "../../../qml/Dash" |
2863 | - |
2864 | - |
2865 | -Rectangle { |
2866 | - width: units.gu(40) |
2867 | - height: units.gu(72) |
2868 | - color: "lightgrey" |
2869 | - |
2870 | - CardHeader { |
2871 | - id: cardHeader |
2872 | - anchors { left: parent.left; right: parent.right } |
2873 | - } |
2874 | - |
2875 | - Rectangle { |
2876 | - anchors.fill: cardHeader |
2877 | - color: "lightblue" |
2878 | - opacity: 0.5 |
2879 | - } |
2880 | - |
2881 | - UT.UnityTestCase { |
2882 | - id: testCase |
2883 | - name: "CardHeader" |
2884 | - |
2885 | - when: windowShown |
2886 | - |
2887 | - property Item mascot: findChild(cardHeader, "mascotShapeLoader") |
2888 | - property Item titleLabel: findChild(cardHeader, "titleLabel") |
2889 | - property Item subtitleLabel: findChild(cardHeader, "subtitleLabel") |
2890 | - property Item oldPriceLabel: findChild(cardHeader, "oldPriceLabel") |
2891 | - property Item outerRow: findChild(cardHeader, "outerRow") |
2892 | - property Item column: findChild(cardHeader, "column") |
2893 | - |
2894 | - function initTestCase() { |
2895 | - verify(typeof testCase.mascot === "object", "Couldn't find mascot object."); |
2896 | - verify(typeof testCase.titleLabel === "object", "Couldn't find titleLabel object."); |
2897 | - verify(typeof testCase.subtitleLabel === "object", "Couldn't find subtitleLabel object."); |
2898 | - verify(typeof testCase.oldPriceLabel === "object", "Couldn't find oldPriceLabel object."); |
2899 | - } |
2900 | - |
2901 | - function cleanup() { |
2902 | - cardHeader.mascot = ""; |
2903 | - cardHeader.title = ""; |
2904 | - cardHeader.subtitle = ""; |
2905 | - } |
2906 | - |
2907 | - function test_mascot_data() { |
2908 | - return [ |
2909 | - { tag: "Empty", source: "", visible: false }, |
2910 | - { tag: "Invalid", source: "bad_path", visible: false }, |
2911 | - { tag: "Valid", source: Qt.resolvedUrl("artwork/avatar.png"), visible: true }, |
2912 | - ] |
2913 | - } |
2914 | - |
2915 | - function test_mascot(data) { |
2916 | - cardHeader.mascot = data.source; |
2917 | - tryCompare(testCase.mascot, "visible", data.visible); |
2918 | - } |
2919 | - |
2920 | - function test_labels_data() { |
2921 | - return [ |
2922 | - { tag: "Empty", visible: false }, |
2923 | - { tag: "Title only", title: "Foo", visible: true }, |
2924 | - { tag: "Subtitle only", subtitle: "Bar", visible: false }, |
2925 | - { tag: "Both", title: "Foo", subtitle: "Bar", visible: true }, |
2926 | - ] |
2927 | - } |
2928 | - |
2929 | - function test_labels(data) { |
2930 | - cardHeader.title = data.title !== undefined ? data.title : ""; |
2931 | - cardHeader.subtitle = data.subtitle !== undefined ? data.subtitle : ""; |
2932 | - tryCompare(cardHeader, "visible", data.visible); |
2933 | - } |
2934 | - |
2935 | - function test_dimensions_data() { |
2936 | - return [ |
2937 | - { tag: "Column width", object: column, width: cardHeader.width }, |
2938 | - { tag: "Column width with mascot", object: column, width: cardHeader.width - mascot.width - outerRow.margins * 3, mascot: "artwork/avatar.png" }, |
2939 | - { tag: "Header height", object: cardHeader, height: function() { return outerRow.height + outerRow.margins * 2 } }, |
2940 | - ] |
2941 | - } |
2942 | - |
2943 | - function test_dimensions(data) { |
2944 | - if (data.hasOwnProperty("mascot")) { |
2945 | - cardHeader.mascot = data.mascot; |
2946 | - } |
2947 | - |
2948 | - if (data.hasOwnProperty("width")) { |
2949 | - tryCompare(data.object, "width", data.width); |
2950 | - } |
2951 | - |
2952 | - if (data.hasOwnProperty("height")) { |
2953 | - tryCompareFunction(function() { return data.object.height === data.height() }, true); |
2954 | - } |
2955 | - } |
2956 | - } |
2957 | -} |
2958 | |
2959 | === modified file 'tests/qmltests/Dash/tst_CardTool.qml' |
2960 | --- tests/qmltests/Dash/tst_CardTool.qml 2014-03-17 11:44:05 +0000 |
2961 | +++ tests/qmltests/Dash/tst_CardTool.qml 2014-05-07 15:30:47 +0000 |
2962 | @@ -127,26 +127,6 @@ |
2963 | } |
2964 | } |
2965 | } |
2966 | - |
2967 | - Card { |
2968 | - id: card |
2969 | - template: cardTool.template; |
2970 | - components: cardTool.components; |
2971 | - cardData: Helpers.mapData(dataArea.text, components, dataError) |
2972 | - |
2973 | - width: cardTool.cardWidth || implicitWidth |
2974 | - height: cardTool.cardHeight || implicitHeight |
2975 | - |
2976 | - clip: true |
2977 | - headerAlignment: cardTool.headerAlignment |
2978 | - |
2979 | - Rectangle { |
2980 | - anchors.fill: parent |
2981 | - color: "transparent" |
2982 | - border.width: 1 |
2983 | - border.color: "green" |
2984 | - } |
2985 | - } |
2986 | } |
2987 | |
2988 | Rectangle { |
2989 | @@ -257,7 +237,7 @@ |
2990 | id: testCase |
2991 | name: "Card" |
2992 | |
2993 | - property Card internalCard: findChild(cardTool, "cardToolCard") |
2994 | + property var internalCard: findChild(cardTool, "cardToolCard") |
2995 | |
2996 | when: windowShown |
2997 | |
2998 | @@ -272,16 +252,16 @@ |
2999 | |
3000 | function test_card_size_data() { |
3001 | return [ |
3002 | - { tag: "Medium", width: units.gu(18.5), height: function() { return card.height }, index: 0 }, |
3003 | - { tag: "No art", width: units.gu(18.5), height: function() { return card.height }, index: 1 }, |
3004 | - { tag: "No summary", width: units.gu(18.5), height: function() { return card.height }, index: 2 }, |
3005 | - { tag: "Just header", width: units.gu(18.5), height: function() { return card.height }, index: 3 }, |
3006 | - { tag: "Just title", width: units.gu(18.5), height: function() { return card.height }, index: 4 }, |
3007 | - { tag: "Title and subtitle", width: units.gu(18.5), height: function() { return card.height }, index: 5 }, |
3008 | - { tag: "Title and mascot", width: units.gu(18.5), height: function() { return card.height }, index: 6 }, |
3009 | - { tag: "Small", width: units.gu(12), height: function() { return card.height }, index: 7 }, |
3010 | - { tag: "Large", width: units.gu(38), height: function() { return card.height }, index: 8 }, |
3011 | - { tag: "Horizontal", width: units.gu(38), height: function() { return card.height }, index: 9 }, |
3012 | + { tag: "Medium", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 0 }, |
3013 | + { tag: "No art", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 1 }, |
3014 | + { tag: "No summary", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 2 }, |
3015 | + { tag: "Just header", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 3 }, |
3016 | + { tag: "Just title", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 4 }, |
3017 | + { tag: "Title and subtitle", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 5 }, |
3018 | + { tag: "Title and mascot", width: units.gu(18.5), height: function() { return internalCard ? internalCard.height : 0 }, index: 6 }, |
3019 | + { tag: "Small", width: units.gu(12), height: function() { return internalCard ? internalCard.height : 0 }, index: 7 }, |
3020 | + { tag: "Large", width: units.gu(38), height: function() { return internalCard ? internalCard.height : 0 }, index: 8 }, |
3021 | + { tag: "Horizontal", width: units.gu(38), height: function() { return internalCard ? internalCard.height : 0 }, index: 9 }, |
3022 | { tag: "OrganicGrid", width: undefined, height: undefined, index: 0, layout_index: 1}, |
3023 | { tag: "Journal", width: undefined, height: units.gu(20), size: 20, index: 0, layout_index: 2 }, |
3024 | { tag: "OversizedJournal", width: undefined, height: units.gu(18.5), size: 40, index: 0, layout_index: 2 }, |
FAILED: Continuous integration, rev:884 jenkins. qa.ubuntu. com/job/ unity8- ci/2905/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- trusty- touch/599/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- trusty/ 1769/console jenkins. qa.ubuntu. com/job/ unity8- trusty- amd64-ci/ 1426/console jenkins. qa.ubuntu. com/job/ unity8- trusty- armhf-ci/ 1430/console jenkins. qa.ubuntu. com/job/ unity8- trusty- i386-ci/ 1426/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/4913/ console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/2905/ rebuild
http://