@@ -142,10 +142,9 @@ var kOverlayLoaderCode = 'Loader { \n\
142142 } \n\
143143 }\n';
144144
145−// %1 is used as anchors of row
146−// %2 is used as first child of the row
147−// %3 is used as second child of the row
148−var kHeaderRow2Code = 'Row { \n\
145+// multiple row version of HeaderRowCode
146+function kHeaderRowCodeGenerator() {
147+var kHeaderRowCodeTemplate = 'Row { \n\
149148 id: row; \n\
150149 objectName: "outerRow"; \n\
151150 property real margins: units.gu(1); \n\
@@ -153,35 +152,19 @@ var kHeaderRow2Code = 'Row { \n\
153152 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
154153 anchors { %1 } \n\
155154 anchors.right: parent.right; \n\
156− anchors.margins: margins;\n\
157− data: [ %2\n\
158− ,\n\
159− %3 \n\
160− ] \n\
161− }\n';
162−
163−// %1 is used as anchors of row
164−// %2 is used as first child of the row
165−// %3 is used as second child of the row
166−// %4 is used as third child of the row
167−var kHeaderRow3Code = 'Row { \n\
168− id: row; \n\
169− objectName: "outerRow"; \n\
170− property real margins: units.gu(1); \n\
171− spacing: margins; \n\
172− height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
173− anchors { %1 } \n\
174− anchors.right: parent.right; \n\
175− anchors.margins: margins;\n\
176− data: [ %2\n\
177− ,\n\
178− %3 \n\
179− ,\n\
180− %4 \n\
155+ anchors.margins: margins; \n\
156+ anchors.rightMargin: units.gu(0); \n\
157+ data: [ \n\
158+ %2 \n\
181159 ] \n\
182160 }\n';
161+ var args = Array.prototype.slice.call(arguments);
162+ var HeaderRowAnchors = args.shift();
163+ var code = kHeaderRowCodeTemplate.arg(HeaderRowAnchors).arg(args.join(',\n'));
164+ return code;
165+}
183166
184−// multiple column version of kHeaderContainerCode.
167+// multiple item version of kHeaderContainerCode
185168function kHeaderContainerCodeGenerator() {
186169 var headerContainerCodeTemplate = 'Item { \n\
187170 id: headerTitleContainer; \n\
@@ -193,9 +176,9 @@ function kHeaderContainerCodeGenerator() {
193176 ]\n\
194177 }\n';
195178 var args = Array.prototype.slice.call(arguments);
196− var anchors = args.shift();
197− var height = args.shift();
198− var code = headerContainerCodeTemplate.arg(anchors).arg(height).arg(args.join(',\n'));
179+ var headerContainerAnchors = args.shift();
180+ var headerContainerHeight = args.shift();
181+ var code = headerContainerCodeTemplate.arg(headerContainerAnchors).arg(headerContainerHeight).arg(args.join(',\n'));
199182 return code;
200183}
201184
@@ -248,14 +231,14 @@ var kTitleLabelCode = 'Label { \n\
248231 horizontalAlignment: root.headerAlignment; \n\
249232 }\n';
250233
251−// %1 is used as additional anchors of emblem image
252234var kEmblemImageCode = 'Image { \n\
253235 id: emblemImage; \n\
254236 objectName: "emblemImage"; \n\
255237 anchors { \n\
256238 bottom: titleLabel.baseline; \n\
257239 right: parent.right; \n\
258− %1 } \n\
240+ rightMargin: units.gu(1); \n\
241+ } \n\
259242 source: cardData && cardData["emblem"]; \n\
260243 width: height; \n\
261244 height: titleLabel.font.pixelSize; \n\
@@ -289,6 +272,15 @@ var kSubtitleLabelCode = 'Label { \n\
289272 horizontalAlignment: root.headerAlignment; \n\
290273 }\n';
291274
275+// %1 is used as anchors of attributesRow
276+var kAttributesRowCode = 'CardAttributes { \n\
277+ id: attributesRow; \n\
278+ objectName: "attributesRow"; \n\
279+ anchors { %1 } \n\
280+ color: %2; \n\
281+ model: cardData && cardData["attributes"] || undefined; \n\
282+ }\n';
283+
292284// %1 is used as top anchor of summary
293285// %2 is used as topMargin anchor of summary
294286// %3 is used as color of summary
@@ -340,6 +332,7 @@ function cardString(template, components) {
340332 var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
341333 var hasSubtitle = hasTitle && components["subtitle"] || false;
342334 var hasHeaderRow = hasMascot && hasTitle;
335+ var hasAttributes = hasTitle && components["attributes"] || false;
343336
344337 if (hasBackground) {
345338 code += kBackgroundLoaderCode;
@@ -350,9 +343,9 @@ function cardString(template, components) {
350343 code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
351344
352345 var widthCode, heightCode;
353− var anchors;
346+ var artAnchors;
354347 if (isHorizontal) {
355− anchors = 'left: parent.left';
348+ artAnchors = 'left: parent.left';
356349 if (hasMascot || hasTitle) {
357350 widthCode = 'height * artShape.aspect'
358351 heightCode = 'headerHeight + 2 * units.gu(1)';
@@ -363,12 +356,12 @@ function cardString(template, components) {
363356 heightCode = 'units.gu(7.625)';
364357 }
365358 } else {
366− anchors = 'horizontalCenter: parent.horizontalCenter;';
359+ artAnchors = 'horizontalCenter: parent.horizontalCenter;';
367360 widthCode = 'root.width'
368361 heightCode = 'width / artShape.aspect';
369362 }
370363
371− code += kArtShapeHolderCode.arg(anchors).arg(widthCode).arg(heightCode);
364+ code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode);
372365 } else {
373366 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
374367 }
@@ -409,6 +402,14 @@ function cardString(template, components) {
409402 code += 'readonly property int headerHeight: row.height;\n'
410403 } else if (hasMascot) {
411404 code += 'readonly property int headerHeight: mascotImage.height;\n'
405+ } else if (hasAttributes) {
406+ if (hasTitle && hasSubtitle) {
407+ code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin + attributesRow.height + attributesRow.anchors.topMargin;\n'
408+ } else if (hasTitle) {
409+ code += 'readonly property int headerHeight: titleLabel.height + attributesRow.height + attributesRow.anchors.topMargin;\n'
410+ } else {
411+ code += 'readonly property int headerHeight: attributesRow.height;\n'
412+ }
412413 } else if (hasSubtitle) {
413414 code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
414415 } else if (hasTitle) {
@@ -417,49 +418,52 @@ function cardString(template, components) {
417418 code += 'readonly property int headerHeight: 0;\n'
418419 }
419420
420− var mascotShapeCode = "";
421− var mascotCode = "";
421+ var mascotShapeCode = '';
422+ var mascotCode = '';
422423 if (hasMascot) {
423424 var useMascotShape = !hasBackground && !headerAsOverlay;
424− var anchors = "";
425+ var mascotAnchors = '';
425426 if (!hasHeaderRow) {
426− anchors += headerLeftAnchor;
427− anchors += headerVerticalAnchors;
427+ mascotAnchors += headerLeftAnchor;
428+ mascotAnchors += headerVerticalAnchors;
428429 if (!headerLeftAnchorHasMargin) {
429− anchors += 'leftMargin: units.gu(1);\n'
430+ mascotAnchors += 'leftMargin: units.gu(1);\n'
430431 }
431432 } else {
432− anchors = "verticalCenter: parent.verticalCenter;"
433+ mascotAnchors = 'verticalCenter: parent.verticalCenter;'
433434 }
434435
435436 if (useMascotShape) {
436− mascotShapeCode = kMascotShapeLoaderCode.arg(anchors);
437+ mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
437438 }
438439
439440 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
440− mascotCode = kMascotImageCode.arg(anchors).arg(mascotImageVisible);
441+ mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
441442 }
442443
443444 var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey")';
444445
445− var titleSubtitleCode = "";
446+ var titleSubtitleCode = '';
446447 if (hasTitle) {
447− var color;
448+ var titleColor;
448449 if (headerAsOverlay) {
449− color = '"white"';
450+ titleColor = '"white"';
450451 } else if (hasSummary) {
451− color = 'summary.color';
452+ titleColor = 'summary.color';
452453 } else if (hasBackground) {
453− color = summaryColorWithBackground;
454+ titleColor = summaryColorWithBackground;
454455 } else {
455− color = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
456+ titleColor = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
456457 }
457458
458459 var titleAnchors;
459460 var subtitleAnchors;
461+ var attributesAnchors;
460462 var titleRightAnchor;
461463 var titleContainerAnchors;
462464
465+ // GOOD LUCK!
466+
463467 if (hasMascot) {
464468 titleContainerAnchors = 'verticalCenter: parent.verticalCenter; ';
465469 } else {
@@ -476,14 +480,20 @@ function cardString(template, components) {
476480 titleRightAnchor = 'right: parent.right;\n';
477481 }
478482
479− if (hasEmblem || (hasMascot && hasSubtitle)) {
480− // Using titleContainer (and maybe row)
483+ if (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes))) {
484+ // Using headerTitleContainer
481485 titleAnchors = titleRightAnchor;
482− titleAnchors += 'left: parent.left;\n\
483− top: parent.top;';
484− subtitleAnchors = 'right: parent.right;\n\
485− left: parent.left;\n\
486− top: titleLabel.bottom;\n';
486+ titleAnchors += 'left: parent.left; \n\
487+ top: parent.top;';
488+ subtitleAnchors = 'right: parent.right; \n\
489+ left: parent.left; \n\
490+ rightMargin: units.gu(1); \n';
491+ if (hasSubtitle) {
492+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
493+ subtitleAnchors += 'top: titleLabel.bottom;\n';
494+ } else {
495+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
496+ }
487497 } else if (hasMascot) {
488498 // Using row + titleContainer
489499 titleAnchors = 'verticalCenter: parent.verticalCenter;\n';
@@ -501,81 +511,100 @@ function cardString(template, components) {
501511 titleAnchors += headerLeftAnchor;
502512 titleAnchors += headerVerticalAnchors;
503513 if (!headerLeftAnchorHasMargin) {
504− titleAnchors += 'leftMargin: units.gu(1);\n'
514+ titleAnchors += 'leftMargin: units.gu(1);\n';
505515 }
506516 }
507517 subtitleAnchors = 'left: titleLabel.left; \n\
508518 leftMargin: titleLabel.leftMargin; \n\
509− top: titleLabel.bottom;\n';
519+ rightMargin: units.gu(1); \n';
510520 if (hasEmblem) {
511521 // using container
512522 subtitleAnchors += 'right: parent.right; \n';
513523 } else {
514524 subtitleAnchors += 'right: titleLabel.right; \n';
515525 }
526+
527+ if (hasSubtitle) {
528+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
529+ subtitleAnchors += 'top: titleLabel.bottom;\n';
530+ } else {
531+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
532+ }
516533 }
517534
535+ // code for different elements
518536 var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
519− var titleCode;
520− titleCode = kTitleLabelCode.arg(titleAnchors).arg(color).arg(titleLabelVisibleExtra);
521− var subtitleCode = "";
537+ var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra);
538+ var subtitleCode;
539+ var attributesCode;
540+ var emblemCode;
541+
542+ // code for the title container
543+ var containerCode = [];
544+ var containerHeight = 'titleLabel.height';
545+ containerCode.push(titleCode);
522546 if (hasSubtitle) {
523− subtitleCode += kSubtitleLabelCode.arg(subtitleAnchors).arg(color);
547+ subtitleCode = kSubtitleLabelCode.arg(subtitleAnchors).arg(titleColor);
548+ containerCode.push(subtitleCode);
549+ containerHeight += ' + subtitleLabel.height';
524550 }
525−
526− var emblemCode;
527− if (hasMascot) {
528− emblemCode = kEmblemImageCode.arg('');
529− } else {
530− emblemCode = kEmblemImageCode.arg('rightMargin: units.gu(1);');
551+ if (hasEmblem) {
552+ containerCode.push(kEmblemImageCode);
553+ }
554+ if (hasAttributes) {
555+ attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(titleColor);
556+ containerCode.push(kAttributesRowCode.arg(attributesAnchors).arg(titleColor));
557+ containerHeight += ' + attributesRow.height';
531558 }
532− if (hasEmblem && hasSubtitle) {
533− // using container 3
534− titleSubtitleCode = kHeaderContainerCodeGenerator(titleContainerAnchors, 'titleLabel.height + subtitleLabel.height', titleCode, emblemCode, kSubtitleLabelCode.arg(subtitleAnchors).arg(color));
535− } else if (hasEmblem) {
536− // container with emblem
537− titleSubtitleCode = kHeaderContainerCodeGenerator(titleContainerAnchors, 'titleLabel.height', titleCode, emblemCode);
538− } else if (hasMascot && hasSubtitle) {
539− // container with subtitle
540− titleSubtitleCode = kHeaderContainerCodeGenerator(titleContainerAnchors, 'titleLabel.height + subtitleLabel.height', titleCode, subtitleCode);
559+
560+ if (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes))) {
561+ // use container
562+ titleSubtitleCode = kHeaderContainerCodeGenerator(titleContainerAnchors, containerHeight, containerCode);
541563 } else {
542564 // no container
543− titleSubtitleCode = titleCode + subtitleCode;
565+ titleSubtitleCode = titleCode;
566+ if (hasSubtitle) {
567+ titleSubtitleCode += subtitleCode;
568+ }
569+ if (hasAttributes) {
570+ titleSubtitleCode += attributesCode;
571+ }
544572 }
545573 }
546574
547575 if (hasHeaderRow) {
548− if (mascotShapeCode != "") {
549− code += kHeaderRow3Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotShapeCode).arg(mascotCode).arg(titleSubtitleCode);
550− } else {
551− code += kHeaderRow2Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotCode).arg(titleSubtitleCode);
576+ var rowCode = [mascotCode, titleSubtitleCode];
577+ if (mascotShapeCode != '') {
578+ rowCode.unshift(mascotShapeCode);
552579 }
580+ code += kHeaderRowCodeGenerator(headerVerticalAnchors + headerLeftAnchor, rowCode)
553581 } else {
554582 code += mascotShapeCode + mascotCode + titleSubtitleCode;
555583 }
556584
557585 if (hasSummary) {
558586 var summaryTopAnchor;
559− if (isHorizontal && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
560− else if (headerAsOverlay && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
561− else if (hasHeaderRow) summaryTopAnchor = "row.bottom";
562− else if (hasEmblem || (hasMascot && hasSubtitle)) summaryTopAnchor = "headerTitleContainer.bottom";
563− else if (hasMascot) summaryTopAnchor = "mascotImage.bottom";
564− else if (hasSubtitle) summaryTopAnchor = "subtitleLabel.bottom";
565− else if (hasTitle) summaryTopAnchor = "titleLabel.bottom";
566− else if (hasArt) summaryTopAnchor = "artShapeHolder.bottom";
567− else summaryTopAnchor = "parent.top";
568−
569− var color;
587+ if (isHorizontal && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
588+ else if (headerAsOverlay && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
589+ else if (hasHeaderRow) summaryTopAnchor = 'row.bottom';
590+ else if (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes))) summaryTopAnchor = 'headerTitleContainer.bottom';
591+ else if (hasMascot) summaryTopAnchor = 'mascotImage.bottom';
592+ else if (hasAttributes) summaryTopAnchor = 'attributesRow.bottom';
593+ else if (hasSubtitle) summaryTopAnchor = 'subtitleLabel.bottom';
594+ else if (hasTitle) summaryTopAnchor = 'titleLabel.bottom';
595+ else if (hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
596+ else summaryTopAnchor = 'parent.top';
597+
598+ var summaryColor;
570599 if (hasBackground) {
571− color = summaryColorWithBackground;
600+ summaryColor = summaryColorWithBackground;
572601 } else {
573− color = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
602+ summaryColor = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
574603 }
575604
576− var summaryTopMargin = (hasMascot || hasSubtitle ? 'anchors.margins' : '0');
605+ var summaryTopMargin = (hasMascot || hasSubtitle || hasAttributes ? 'anchors.margins' : '0');
577606
578− code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color);
607+ code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);
579608 }
580609
581610 var touchdownAnchors;
@@ -594,6 +623,8 @@ function cardString(template, components) {
594623 code += 'implicitHeight: row.y + row.height + units.gu(1);\n';
595624 } else if (hasMascot) {
596625 code += 'implicitHeight: mascotImage.y + mascotImage.height;\n';
626+ } else if (hasAttributes) {
627+ code += 'implicitHeight: attributesRow.y + attributesRow.height + units.gu(1);\n';
597628 } else if (hasSubtitle) {
598629 code += 'implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
599630 } else if (hasTitle) {
@@ -610,8 +641,10 @@ function cardString(template, components) {
610641function createCardComponent(parent, template, components) {
611642 var imports = 'import QtQuick 2.2; \n\
612643 import Ubuntu.Components 0.1; \n\
613− import Ubuntu.Thumbnailer 0.1;\n';
644+ import Ubuntu.Thumbnailer 0.1;\n\
645+ import Dash 0.1;\n';
614646 var card = cardString(template, components);
615647 var code = imports + 'Component {\n' + card + '}\n';
648+
616649 return Qt.createQmlObject(code, parent, "createCardComponent");
617650}